summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-25 14:32:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-06-25 14:32:10 +0000
commit65a1f0a17cc2d98c4764a852603659e871ff8157 (patch)
treeaea8d07f26643e2bcb1ea54734cb4905eb86122b
parentInitial commit. (diff)
downloadsamhain-65a1f0a17cc2d98c4764a852603659e871ff8157.tar.xz
samhain-65a1f0a17cc2d98c4764a852603659e871ff8157.zip
Adding upstream version 4.1.4.upstream/4.1.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--COPYING349
-rwxr-xr-xInstall.sh781
-rw-r--r--LICENSE339
-rw-r--r--Makefile.in1703
-rw-r--r--README497
-rw-r--r--acconfig.h442
-rw-r--r--aclocal.m42159
-rwxr-xr-xc_bits.sh133
-rwxr-xr-xc_random.sh232
-rwxr-xr-xconfig.guess1420
-rw-r--r--config.h.in1162
-rwxr-xr-xconfig.sub1799
-rwxr-xr-xconfigure13734
-rw-r--r--configure.ac2763
-rw-r--r--depend.dep101
-rw-r--r--depend.sum1
-rw-r--r--deploy.sh.in1094
-rw-r--r--docs/#Changelog#2552
-rw-r--r--docs/BUGS38
-rw-r--r--docs/Changelog2554
-rw-r--r--docs/FAQ.html866
-rw-r--r--docs/HOWTO-client+server-troubleshooting.html452
-rw-r--r--docs/HOWTO-client+server.html441
-rw-r--r--docs/HOWTO-samhain+GnuPG.html415
-rw-r--r--docs/HOWTO-samhain-on-windows.html496
-rw-r--r--docs/HOWTO-write-modules.html771
-rw-r--r--docs/MANUAL-2_4.epubbin0 -> 216377 bytes
-rw-r--r--docs/MANUAL-2_4.html.tarbin0 -> 1372160 bytes
-rw-r--r--docs/MANUAL-2_4.pdfbin0 -> 552599 bytes
-rw-r--r--docs/README497
-rw-r--r--docs/README.LZO136
-rw-r--r--docs/README.UPGRADE113
-rw-r--r--docs/README.gcc_bug49
-rw-r--r--docs/README.sstrip40
-rw-r--r--docs/README.win2K36
-rw-r--r--docs/samhain_german.pdfbin0 -> 116424 bytes
-rw-r--r--docs/sh_mounts.txt59
-rw-r--r--docs/sh_userfiles.txt39
-rw-r--r--dsys/0F571F6C.asc183
-rw-r--r--dsys/comBUILD253
-rw-r--r--dsys/comCHECKSRC120
-rw-r--r--dsys/comCLEAN79
-rw-r--r--dsys/comDOWNLOAD280
-rw-r--r--dsys/comINSTALL643
-rw-r--r--dsys/comUNINSTALL188
-rw-r--r--dsys/funcBUILD251
-rw-r--r--dsys/funcDB311
-rw-r--r--dsys/funcDIALOG354
-rw-r--r--dsys/funcEXE57
-rw-r--r--dsys/funcINSTALL509
-rw-r--r--dsys/funcPRINT84
-rw-r--r--dsys/funcSETUP63
-rw-r--r--dsys/initscript166
-rw-r--r--dsys/postinstall58
-rw-r--r--dsys/preinstall57
-rw-r--r--hp_ux.psf.in75
-rw-r--r--include/CuTest.h138
-rw-r--r--include/bignum.h85
-rw-r--r--include/lzoconf.h379
-rw-r--r--include/minilzo.h96
-rw-r--r--include/rijndael-alg-fst.h44
-rw-r--r--include/rijndael-api-fst.h136
-rw-r--r--include/samhain.h586
-rw-r--r--include/sh_MK.h27
-rw-r--r--include/sh_calls.h104
-rw-r--r--include/sh_cat.h355
-rw-r--r--include/sh_checksum.h27
-rw-r--r--include/sh_database.h16
-rw-r--r--include/sh_dbCheck.h26
-rw-r--r--include/sh_dbCreate.h26
-rw-r--r--include/sh_dbIO.h61
-rw-r--r--include/sh_dbIO_int.h157
-rw-r--r--include/sh_entropy.h28
-rw-r--r--include/sh_error.h206
-rw-r--r--include/sh_error_min.h41
-rw-r--r--include/sh_extern.h162
-rw-r--r--include/sh_fInotify.h13
-rw-r--r--include/sh_fifo.h95
-rw-r--r--include/sh_files.h265
-rw-r--r--include/sh_filter.h35
-rw-r--r--include/sh_getopt.h33
-rw-r--r--include/sh_gpg.h58
-rw-r--r--include/sh_gpg_chksum.h53
-rw-r--r--include/sh_guid.h34
-rw-r--r--include/sh_hash.h205
-rw-r--r--include/sh_html.h83
-rw-r--r--include/sh_ignore.h14
-rw-r--r--include/sh_inotify.h58
-rw-r--r--include/sh_ipvx.h83
-rw-r--r--include/sh_ks.h11
-rw-r--r--include/sh_ks_xor.h11
-rw-r--r--include/sh_log_check.h138
-rw-r--r--include/sh_log_correlate.h28
-rw-r--r--include/sh_log_evalrule.h61
-rw-r--r--include/sh_log_mark.h14
-rw-r--r--include/sh_log_repeat.h14
-rw-r--r--include/sh_logmon.h12
-rw-r--r--include/sh_mail.h64
-rw-r--r--include/sh_mail_int.h48
-rw-r--r--include/sh_mem.h61
-rw-r--r--include/sh_modules.h63
-rw-r--r--include/sh_mounts.h23
-rw-r--r--include/sh_nmail.h20
-rw-r--r--include/sh_portcheck.h13
-rw-r--r--include/sh_prelink.h18
-rw-r--r--include/sh_prelude.h20
-rw-r--r--include/sh_processcheck.h13
-rw-r--r--include/sh_pthread.h180
-rw-r--r--include/sh_readconf.h41
-rw-r--r--include/sh_registry.h13
-rw-r--r--include/sh_restrict.h9
-rw-r--r--include/sh_schedule.h30
-rw-r--r--include/sh_sem.h14
-rw-r--r--include/sh_socket.h30
-rw-r--r--include/sh_srp.h35
-rw-r--r--include/sh_static.h60
-rw-r--r--include/sh_string.h108
-rw-r--r--include/sh_sub.h8
-rw-r--r--include/sh_suidchk.h42
-rw-r--r--include/sh_tiger.h59
-rw-r--r--include/sh_tools.h115
-rw-r--r--include/sh_trace.h47
-rw-r--r--include/sh_unix.h467
-rw-r--r--include/sh_userfiles.h30
-rw-r--r--include/sh_utils.h218
-rw-r--r--include/sh_utmp.h42
-rw-r--r--include/sh_xfer.h124
-rw-r--r--include/slib.h642
-rw-r--r--include/trustfile.h94
-rw-r--r--include/zAVLTree.h82
-rw-r--r--init/samhain.start.in77
-rw-r--r--init/samhain.startFreeBSD.in44
-rw-r--r--init/samhain.startGentoo.in30
-rw-r--r--init/samhain.startHPUX.in116
-rw-r--r--init/samhain.startIRIX.in88
-rwxr-xr-xinit/samhain.startLSB.in127
-rw-r--r--init/samhain.startLinux.in315
-rw-r--r--init/samhain.startMACOSX.in27
-rw-r--r--init/samhain.startSolaris.in80
-rwxr-xr-xinstall-sh250
-rw-r--r--man/samhain.8880
-rw-r--r--man/samhainrc.5776
-rwxr-xr-xmissing188
-rwxr-xr-xmkinstalldirs40
-rw-r--r--rules.deb-light.in113
-rw-r--r--rules.deb.in134
-rw-r--r--samhain-install.sh.in1543
-rw-r--r--samhain.jpgbin0 -> 2897 bytes
-rw-r--r--samhain.spec289
-rw-r--r--samhain.spec.in289
-rw-r--r--samhainrc.aix5.2.0236
-rw-r--r--samhainrc.freebsd709
-rw-r--r--samhainrc.linux753
-rw-r--r--samhainrc.netbsd843
-rw-r--r--samhainrc.solaris684
-rw-r--r--scripts/README99
-rwxr-xr-xscripts/check_samhain.pl.in215
-rwxr-xr-xscripts/chroot.sh131
-rwxr-xr-xscripts/concat.pl69
-rwxr-xr-xscripts/example_pager.pl245
-rwxr-xr-xscripts/example_sms.pl224
-rw-r--r--scripts/foot.html11
-rw-r--r--scripts/head.html72
-rw-r--r--scripts/logrotate24
-rw-r--r--scripts/logrotate.in24
-rwxr-xr-xscripts/makeself/makeself-header.sh365
-rwxr-xr-xscripts/makeself/makeself.sh361
-rw-r--r--scripts/redhat_i386.client.spec.in184
-rwxr-xr-xscripts/samhain.cgi32
-rw-r--r--scripts/samhain.dtd11
-rw-r--r--scripts/samhain.ebuild-light.in92
-rw-r--r--scripts/samhain.ebuild.in98
-rw-r--r--scripts/samhain.logrotator26
-rw-r--r--scripts/samhain.spec.in162
-rw-r--r--scripts/samhain.xsl147
-rwxr-xr-xscripts/samhainadmin.pl.in726
-rwxr-xr-xscripts/yuleadmin.pl.in310
-rw-r--r--sql_init/samhain.mysql.init97
-rw-r--r--sql_init/samhain.oracle.init95
-rw-r--r--sql_init/samhain.postgres.init100
-rw-r--r--src/#sh_unix.c#5710
-rw-r--r--src/CuTest.c350
-rw-r--r--src/bignum.c1919
-rw-r--r--src/cutest_sh_hash.c121
-rw-r--r--src/cutest_sh_tiger0.c460
-rw-r--r--src/cutest_sh_tools.c138
-rw-r--r--src/cutest_sh_unix.c199
-rw-r--r--src/cutest_sh_utils.c532
-rw-r--r--src/cutest_slib.c114
-rw-r--r--src/cutest_zAVLTree.c522
-rw-r--r--src/depend-gen.c417
-rw-r--r--src/dnmalloc.c5619
-rw-r--r--src/encode.c200
-rw-r--r--src/exepack.c350
-rw-r--r--src/exepack_fill.c384
-rw-r--r--src/exepack_mkdata.c248
-rw-r--r--src/kern_head.h.tmp0
-rwxr-xr-xsrc/make-tests.sh75
-rw-r--r--src/minilzo.c2853
-rw-r--r--src/mkhdr.c222
-rw-r--r--src/rijndael-alg-fst.c1235
-rw-r--r--src/rijndael-api-fst.c407
-rw-r--r--src/samhain.c2354
-rw-r--r--src/samhain_setpwd.c515
-rw-r--r--src/samhain_stealth.c464
-rw-r--r--src/sh_audit.c570
-rw-r--r--src/sh_calls.c964
-rw-r--r--src/sh_cat.c702
-rw-r--r--src/sh_checksum.c638
-rw-r--r--src/sh_database.c1853
-rw-r--r--src/sh_dbCheck.c122
-rw-r--r--src/sh_dbCreate.c227
-rw-r--r--src/sh_dbIO.c1807
-rw-r--r--src/sh_entropy.c1055
-rw-r--r--src/sh_err_console.c378
-rw-r--r--src/sh_err_log.c1332
-rw-r--r--src/sh_err_syslog.c240
-rw-r--r--src/sh_error.c1813
-rw-r--r--src/sh_extern.c1703
-rw-r--r--src/sh_fInotify.c725
-rw-r--r--src/sh_fifo.c441
-rw-r--r--src/sh_files.c3359
-rw-r--r--src/sh_filetype.c606
-rw-r--r--src/sh_filter.c300
-rw-r--r--src/sh_getopt.c990
-rw-r--r--src/sh_gpg.c1035
-rw-r--r--src/sh_guid.c376
-rw-r--r--src/sh_hash.c3264
-rw-r--r--src/sh_html.c558
-rw-r--r--src/sh_ignore.c330
-rw-r--r--src/sh_inotify.c1052
-rw-r--r--src/sh_ipvx.c591
-rw-r--r--src/sh_log_check.c1522
-rw-r--r--src/sh_log_correlate.c349
-rw-r--r--src/sh_log_evalrule.c1266
-rw-r--r--src/sh_log_mark.c250
-rw-r--r--src/sh_log_parse_apache.c446
-rw-r--r--src/sh_log_parse_generic.c119
-rw-r--r--src/sh_log_parse_pacct.c354
-rw-r--r--src/sh_log_parse_samba.c104
-rw-r--r--src/sh_log_parse_syslog.c190
-rw-r--r--src/sh_log_repeat.c566
-rw-r--r--src/sh_login_track.c1422
-rw-r--r--src/sh_mail.c2002
-rw-r--r--src/sh_mem.c479
-rw-r--r--src/sh_modules.c193
-rw-r--r--src/sh_mounts.c824
-rw-r--r--src/sh_nmail.c1032
-rw-r--r--src/sh_port2proc.c1080
-rw-r--r--src/sh_portcheck.c2186
-rw-r--r--src/sh_prelink.c278
-rw-r--r--src/sh_prelude.c1470
-rw-r--r--src/sh_processcheck.c1557
-rw-r--r--src/sh_pthread.c323
-rw-r--r--src/sh_readconf.c1512
-rw-r--r--src/sh_registry.c1013
-rw-r--r--src/sh_restrict.c686
-rw-r--r--src/sh_schedule.c454
-rw-r--r--src/sh_sem.c310
-rw-r--r--src/sh_socket.c1401
-rw-r--r--src/sh_srp.c812
-rw-r--r--src/sh_static.c2075
-rw-r--r--src/sh_string.c1055
-rw-r--r--src/sh_sub.c525
-rw-r--r--src/sh_suidchk.c2537
-rw-r--r--src/sh_tiger0.c1866
-rw-r--r--src/sh_tiger1.c349
-rw-r--r--src/sh_tiger1.s5756
-rw-r--r--src/sh_tiger1_64.c498
-rw-r--r--src/sh_tiger2.c561
-rw-r--r--src/sh_tiger2_64.c561
-rw-r--r--src/sh_tools.c2279
-rw-r--r--src/sh_unix.c5709
-rw-r--r--src/sh_userfiles.c438
-rw-r--r--src/sh_utils.c2437
-rw-r--r--src/sh_utmp.c1272
-rw-r--r--src/sh_xfer_client.c1638
-rw-r--r--src/sh_xfer_server.c3778
-rw-r--r--src/sh_xfer_syslog.c481
-rw-r--r--src/simple-bignum.tar.bz2bin0 -> 18434 bytes
-rw-r--r--src/slib.c3195
-rw-r--r--src/sstrip.c538
-rw-r--r--src/t-test0.c482
-rw-r--r--src/t-test1.c684
-rw-r--r--src/trustfile.c1160
-rw-r--r--src/yulectl.c649
-rw-r--r--src/zAVLTree.c608
-rw-r--r--stamp-h.in1
-rw-r--r--stamp-hdep1
-rw-r--r--stealth_template.jpgbin0 -> 7343 bytes
-rw-r--r--test/gnupg/public-key.asc20
-rw-r--r--test/gnupg/pubring.gpgbin0 -> 699 bytes
-rw-r--r--test/gnupg/random_seedbin0 -> 600 bytes
-rw-r--r--test/gnupg/secret-key.asc34
-rw-r--r--test/gnupg/secring.gpgbin0 -> 1363 bytes
-rw-r--r--test/gnupg/trustdb.gpgbin0 -> 1280 bytes
-rwxr-xr-xtest/test.sh862
-rw-r--r--test/test_ext.c.in33
-rwxr-xr-xtest/testcompile.sh860
-rwxr-xr-xtest/testext.sh163
-rwxr-xr-xtest/testhash.sh135
-rwxr-xr-xtest/testit.sh48
-rw-r--r--test/testrc_1273
-rw-r--r--test/testrc_1ext.in187
-rw-r--r--test/testrc_2.in216
-rw-r--r--test/testrc_2.in.asc216
-rwxr-xr-xtest/testrun_1.sh1306
-rwxr-xr-xtest/testrun_1a.sh160
-rwxr-xr-xtest/testrun_1b.sh467
-rwxr-xr-xtest/testrun_1c.sh414
-rwxr-xr-xtest/testrun_1d.sh261
-rwxr-xr-xtest/testrun_1e.sh376
-rwxr-xr-xtest/testrun_1f.sh292
-rw-r--r--test/testrun_1g.sh114
-rw-r--r--test/testrun_1h.sh305
-rwxr-xr-xtest/testrun_2.sh828
-rwxr-xr-xtest/testrun_2a.sh302
-rwxr-xr-xtest/testrun_2b.sh215
-rwxr-xr-xtest/testrun_2c.sh427
-rwxr-xr-xtest/testrun_2d.sh143
-rwxr-xr-xtest/testrun_2e.sh299
-rwxr-xr-xtest/testrun_2f.sh390
-rwxr-xr-xtest/testrun_2g.sh820
-rw-r--r--test/testtiger.txt13
-rwxr-xr-xtest/testtimesrv.sh424
-rw-r--r--yulerc.template336
326 files changed, 190107 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..df08ae7
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,349 @@
+
+SAMHAIN distributed host monitoring system
+------------------------------------------
+
+Copyright (C) 1999-2009 Rainer Wichmann
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+Incorporated code
+-----------------
+
+ (i) Support for the TIGER cryptographic checksum algorithm
+ is provided by the reference implementation, which includes
+ the following statement:
+
+ * Tiger: A Fast New Hash Function
+ *
+ * Ross Anderson and Eli Biham
+ *
+ * Tiger has no usage restrictions nor patents. It can be used freely,
+ * with the reference implementation,
+ * with other implementations or with
+ * a modification to the reference implementation (as long as it still
+ * implements Tiger). We only ask you to let us know about your
+ * implementation and to cite the origin of Tiger and of the reference
+ * implementation.
+ *
+ * The authors' home pages can be found both in
+ * http://www.cs.technion.ac.il/~biham/ and in
+ * http://www.cl.cam.ac.uk/users/rja14/.
+ * The authors' email addresses are biham@cs.technion.ac.il
+ * and rja14@cl.cam.ac.uk.
+
+
+
+ (ii) Support for testing write access by untrusted users
+ to any element in the path of a file is provided by the
+ public domain trustfile library, which includes the following
+ statement:
+
+ * Author information:
+ * Matt Bishop
+ * Department of Computer Science
+ * University of California at Davis
+ * Davis, CA 95616-8562
+ * phone (916) 752-8060
+ * email bishop@cs.ucdavis.edu
+ *
+ * This code is placed in the public domain. I do ask that
+ * you keep my name associated with it, that you not represent
+ * it as written by you, and that you preserve these comments.
+ * This software is provided "as is" and without any guarantees
+ * of any sort.
+
+ (iii) Support for big integer arithmetic is provided by the bignum
+ package (v. 1.2) by Henrik.Johansson@Nexus.Comm.SE,
+ which includes the following statement:
+
+ * Everyone is allowed to distribute this package to anyone
+ * else, as long as all changes are recorded and mentioned.
+ * If you are including this in a commercial product, be sure
+ * to distribute _all_ of the package with the product.
+ *
+ * (...writing more stuff here later, but I guess everyone
+ * knows the approximate contents of it - no warranty, no
+ * charge, and so on. I guess it is like the GNU concept.
+ * Read that for further details...)
+
+ (iv) Support for compression is provided by the (mini) LZO library,
+ which includes the following statement:
+
+ * Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ * Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ * Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ * Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ *
+ * The LZO library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * The LZO library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the LZO library; see the file COPYING.
+ * If not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * Markus F.X.J. Oberhumer
+ * <markus.oberhumer@jk.uni-linz.ac.at>
+ * http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+
+ (v) Support for determining the type of a file system is provided by
+ code from the GNU find(1) utility which includes the following statement:
+
+ /* fstype.c -- determine type of filesystems that files are on
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+
+ /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+
+ (vi) Support for the MD5 hash algorithm is provided by code
+ from busybox which is distributed under the GPL.
+
+ /* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ * according to the definition of MD5 in RFC 1321 from April 1992.
+ * Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ *
+ * NOTE: The canonical source of this file is maintained with the GNU C
+ * Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+ /* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+
+ (vi) Support for the SHA-1 hash algorithm is provided by code
+ from mhash which includes the following statement:
+
+ /* sha.c - Implementation of the Secure Hash Algorithm
+ *
+ * Copyright (C) 1995, A.M. Kuchling
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ * Adapted to pike and some cleanup by Niels Möller.
+ */
+
+ /* $Id: sha1.c,v 1.2 2001/01/24 08:20:29 nmav Exp $ */
+
+ /* SHA: NIST's Secure Hash Algorithm */
+
+ /* Based on SHA code originally posted to sci.crypt by Peter Gutmann
+ in message <30ajo5$oe8@ccu2.auckland.ac.nz>.
+ Modified to test for endianness on creation of SHA objects by AMK.
+ Also, the original specification of SHA was found to have a weakness
+ by NSA/NIST. This code implements the fixed version of SHA.
+ */
+
+ (vii) Support for AVL Trees is provided by code
+ from AVLTree which includes the following statement:
+
+ /* zAVLTree.h: Header file for zAVLTrees.
+ * Copyright (C) 1998,2001 Michael H. Buselli
+ * This is version 0.1.3 (alpha).
+ * Generated from $Id: xAVLTree.h.sh,v 1.5 2001/06/07 06:58:28 cosine Exp $
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * The author of this library can be reached at the following address:
+ * Michael H. Buselli
+ * 30051 N. Waukegan Rd. Apt. 103
+ * Lake Bluff, IL 60044-5412
+ *
+ * Or you can send email to <cosine@cosine.org>.
+ * The official web page for this product is:
+ * http://www.cosine.org/project/AVLTree/
+ */
+
+ (viii) The modules sh_userfiles.c and sh_mounts.c have been
+ contributed by Eircom Net Computer Incident Response Team and
+ are authored by Jerry Connolly and Cian Synnott, respectively.
+
+ They are released under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version:
+
+ "Feel free to GPL those files -
+ they were fully released by our company to the project.
+
+ Cian
+
+ --
+ Cian Synnott
+ Eircom Net Computer Incident Response Team"
+
+ (ix) Enhanced functionality for the SUID check has been
+ contributed with a patch copyright by Rob Rati <rob.rati@motorola.com>.
+ The patch is licensed under the GPL with the following statement:
+
+ "Here is the patch with the aforementioned feature enhancements, and I
+ license all changes within this patch under the GNU Public License (GPL)
+ GNU General Public License as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any later version."
+
+ (x) Unit testing uses the 'cutest' framework by Asim Jalis, (files
+ CuTest.h, CuTest.c, make-tests.sh) which is licensed under the zlib license:
+
+ * Copyright (c) 2003 Asim Jalis
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in
+ * a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+
+ (xi) The dnmalloc library used by samhain is Copyright (C) 2005, Yves Younan,
+ Wouter Joosen and Frank Piessens, and licensed under the LGPL:
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Other
+-----
+
+ Depending on the compilation options used, samhain may use the
+ SRP authentication algorithm (in an independent implementation,
+ without any use of code from the SRP software).
+ The original SRP software contains the following license statement:
+
+ The SRP License
+ ---------------
+
+ SRP and all related technologies are free for both commercial and
+ non-commercial use. They are distributed under a standard
+ X11-style Open Source license which is shown below.
+
+ The SRP distribution contains parts from various freeware
+ packages; these parts fall under both the SRP Open Source license
+ and any existing licenses. Care has been taken to ensure that
+ these licenses are compatible with Open Source distribution,
+ but it is the responsibility of the licensee to comply with these
+ licenses. The file "Copyrights" contains a list of the copyrights
+ incorporated by portions of the software.
+
+ This software is covered under the following copyright:
+
+ /*
+ * Copyright (c) 1997-1999 The Stanford SRP Authentication Project
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * In addition, the following conditions apply:
+ *
+ * 1. Any software that incorporates the SRP authentication technology
+ * must display the following acknowlegment:
+ * "This product uses the 'Secure Remote Password' cryptographic
+ * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
+ *
+ * 2. Any software that incorporates all or part of the SRP distribution
+ * itself must also display the following acknowledgment:
+ * "This product includes software developed by Tom Wu and Eugene
+ * Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
+ *
+ * 3. Redistributions in source or binary form must retain an intact copy
+ * of this copyright notice and list of conditions.
+ */
diff --git a/Install.sh b/Install.sh
new file mode 100755
index 0000000..ff7b0c3
--- /dev/null
+++ b/Install.sh
@@ -0,0 +1,781 @@
+#! /bin/sh
+# Please have a TMP or TMPDIR environment variable if you don't trust /tmp,
+# or don't run this as root.
+#
+# -- partly taken from PureFTPd
+#
+
+VERSION=1.6.4
+
+
+# exits with a custom error message
+bail_error () {
+ echo
+ echo $1
+ echo
+ exit 1
+}
+
+get_config() {
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --$z"
+ done
+}
+
+get_error() {
+ ge_rval=0
+ if cat $tmp 2>&1 | grep Error > /dev/null ; then
+ ge_rval=1
+ fi
+ return ${ge_rval}
+}
+
+
+
+#------------------------------------------------------------
+#
+# Find a 'dialog' program
+#
+#------------------------------------------------------------
+PATH=/usr/local/bin:/usr/local/sbin:$PATH; export PATH
+
+WELCOME=`cat <<EOF
+Welcome to the SAMHAIN configuration tool
+
+This script is meant to make installing SAMHAIN as easy as
+possible. Just read the text below, hit ENTER, and you are
+on your way.
+
+SAMHAIN ships with NO WARRANTY whatsoever, without
+even the implied warranty of merchantability or fitness
+for a particular purpose. The author takes no responsibility
+for the consequences of running this script.
+
+Please send any questions to support@la-samhna.com.
+EOF`
+
+if [ -z "$dialog" ] ; then
+ if [ -n "$DISPLAY" ] ; then
+ Xdialog --msgbox "$WELCOME" 20 75 2> /dev/null && dialog='Xdialog'
+ gauge='--gauge'
+ fi
+fi
+if [ -z "$dialog" ] ; then
+ dialog --msgbox "$WELCOME" 20 75 2> /dev/null && dialog='dialog'
+
+# Workaround for old versions of 'dialog' (Slackware)
+
+ if "$dialog" 2>&1 | grep gauge > /dev/null ; then
+ gauge='--gauge'
+ elif "$dialog" 2>&1 | grep guage > /dev/null ; then
+ gauge='--guage'
+ else
+ gauge=''
+ fi
+fi
+if [ -z "$dialog" ] ; then
+ lxdialog --msgbox "$WELCOME" 20 75 2> /dev/null && dialog='lxdialog'
+fi
+if [ -z "$dialog" ] ; then
+ /usr/src/linux/scripts/lxdialog/lxdialog --msgbox "$WELCOME" 20 75 2> /dev/null && dialog='/usr/src/linux/scripts/lxdialog/lxdialog'
+fi
+
+if [ -z "$dialog" ] ; then
+ bail_error "No \"dialog\" found, GUI installation impossible"
+fi
+
+#------------------------------------------------------------
+#
+# Find a writable temporary directory
+#
+#------------------------------------------------------------
+tempdir=''
+for tmpdir in "$TMP" "$TMPDIR" /tmp /var/tmp; do
+ if [ -z "$tempdir" ] && [ -d "$tmpdir" ] && [ -w "$tmpdir" ]; then
+ tempdir="$tmpdir"
+ fi
+done
+if [ -z "$tempdir" ]; then
+ bail_error "Unable to find a suitable temporary directory"
+fi
+
+# Create a temporary file
+tmp=`mktemp $tempdir/build.gui.XXXXXX`
+if [ $? -ne 0 ]; then
+ bail_error "Cannot create temp file, exiting..."
+fi
+
+trap "rm -f $tmp; exit 1" EXIT SIGHUP SIGINT SIGQUIT SIGSEGV SIGTERM
+
+#------------------------------------------------------------
+#
+# Build config line
+#
+#------------------------------------------------------------
+cfgline='';
+
+$dialog \
+--title "Compile-time options" \
+--backtitle "Samhain $VERSION" \
+--radiolist "Samhain can run as standalone application on a single dektop machine, or as a client/server application for centralized monitoring of many hosts" \
+10 75 3 \
+"disable-network" "Single desktop machine" on \
+"enable-network=client" "Network (client)" off \
+"enable-network=server" "Network (server)" off \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ get_config
+else
+ get_error || bail_error "Your \"dialog\" does not support --radiolist, GUI installation impossible"
+ cfgline="--disable-network"
+fi
+
+cfgtest=`echo $cfgline | grep disable`
+
+
+#------------------------------------------------------------
+#
+# Server options
+#
+#------------------------------------------------------------
+if [ -z $cfgtest ]; then
+
+INET=yes
+HTML="\n /usr/local/var/samhain/samhain.html"
+
+$dialog \
+--backtitle "Samhain $VERSION" \
+--msgbox "You have chosen to build SAMHAIN as a client/server application.\n\nThis requires some additional configuration.\nPlease read the manual if you are not sure\nwhich options are useful or neccessary for you." 10 75
+
+if [ $? = -1 ]; then
+ exit 1
+fi
+
+
+$dialog \
+--title 'Network options' \
+--separate-output \
+--backtitle "Samhain $VERSION" \
+--checklist 'Use SPACE to set/unset. If in doubt, read the manual.' \
+20 75 10 \
+'enable-udp' "Server listens also on 514/udp" off \
+'disable-encrypt' "Disable client/server encryption" off \
+'disable-srp' "Disable SRP client/server authentication" off \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ get_config
+fi
+
+$dialog \
+--title 'Network options' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Server port" 10 75 "49777" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-port=$z"
+ done
+fi
+
+
+$dialog \
+--title 'Network options' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Server address" 10 75 "127.0.0.1" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-logserver=$z"
+ done
+fi
+
+$dialog \
+--title "Network options" \
+--backtitle 'Samhain $VERSION' \
+--inputbox "Backup server address" 10 75 "none" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ if [ "x$z" != "xnone" ]; then
+ cfgline="$cfgline --with-altlogserver=$z"
+ fi
+ done
+fi
+
+# if [ -z $cfgtest ]; then
+fi
+
+os=`uname -s`
+if [ x"$os" = xLinux ]
+then
+ PROC=`uname -m`
+ if [ x"$PROC" = xi686 ] ; then
+ I386_LINUX=yes
+ fi
+ if [ x"$PROC" = xi586 ] ; then
+ I386_LINUX=yes
+ fi
+ if [ x"$PROC" = xi486 ] ; then
+ I386_LINUX=yes
+ fi
+ if [ x"$PROC" = xi386 ] ; then
+ I386_LINUX=yes
+ fi
+fi
+
+$dialog \
+--title 'General options' \
+--separate-output \
+--backtitle "Samhain $VERSION" \
+--checklist 'Use SPACE to set/unset. If in doubt, read the MANUAL.' \
+20 75 10 \
+'enable-static' "Don't link with shared libraries" on \
+'enable-suidcheck' "Check for suid/sgid files" on \
+'enable-login-watch' "Watch for login/logout events" off \
+'enable-ptrace' "Enable anti-debugger code" off \
+'enable-db-reload' "Reload database on SIGHUP" off \
+'enable-xml-log' "Write log in XML format" off \
+'disable-mail' "Compile without built-in mailer" off \
+'disable-external-scripts' "Disable use of external scripts" off \
+'enable-debug' "Compile in debugging code" off \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ get_config
+fi
+
+
+#------------------------------------------------------------
+#
+# Signature options
+#
+#------------------------------------------------------------
+$dialog \
+--title "Signed database and configuration" \
+--backtitle "Samhain $VERSION" \
+--yesno "Samhain can be configured to support PGP signed database\nand configuration files. This requires a working installation\nof GnuPG.\n\nDo you want to use this option ?" \
+10 75 \
+2> $tmp
+
+mtest=$?
+
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+
+
+$dialog \
+--title "Signed database and configuration" \
+--backtitle "Samhain $VERSION" \
+--inputbox "Please enter the full path to gpg (i.e. the GnuPG binary)" \
+10 75 "/usr/bin/gpg" \
+2> $tmp
+
+mtest=$?
+
+if [ $mtest = -1 ]
+then
+ exit 1
+fi
+if [ $mtest = 0 ]
+then
+
+mfile=`cat $tmp`
+for z in $mfile ; do
+ cfgline="$cfgline --with-gpg=$z"
+done
+
+$dialog \
+--title "Signed database and configuration" \
+--backtitle "Samhain $VERSION" \
+--inputbox "Please enter the fingerprint of the key to use (one string, no spaces)" \
+10 75 "6BD9050FD8FC941B43412DCC68B7AB8957548DCD" \
+2> $tmp
+
+mtest=$?
+
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ z=`cat $tmp`
+ cfgline="$cfgline --with-fp=$z"
+fi
+
+
+fi
+# want signed
+fi
+
+#------------------------------------------------------------
+#
+# Stealth options
+#
+#------------------------------------------------------------
+$dialog \
+--title "Stealth options" \
+--backtitle "Samhain $VERSION" \
+--yesno "Samhain has some stealth options to hide its presence.\nDo you want to take advantage of these ?" \
+10 75 \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+
+$dialog \
+--title "Stealth options" \
+--backtitle "Samhain $VERSION" \
+--radiolist "Full stealth mode will hide ascii strings within the binary, and use a config file that is hidden by steganography within an image file. Micro stealth is just strings hiding, without the stego config file." \
+20 75 4 \
+'full' "Enable full stealth mode" off \
+'micro' "Enable micro stealth mode" on \
+'none' "None of both" off \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ mtest=$z
+ done
+else
+ mtest="none"
+fi
+
+if [ "x$mtest" != "xnone" ]; then
+
+if [ "x$mtest" = "xfull" ]; then
+ FULL_STEALTH="yes"
+fi
+
+$dialog \
+--title 'Stealth options' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Please select a number between 128 and 255. This number will be used to obfuscate strings within the binary by xoring them." 10 75 "137" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ mnum=$z
+ done
+else
+ mnum="137"
+fi
+
+if [ "x$FULL_STEALTH" = "xyes" ]; then
+ cfgline="$cfgline --enable-stealth=$mnum"
+else
+ cfgline="$cfgline --enable-micro-stealth=$mnum"
+fi
+
+# if [ "x$mtest" != "xnone" ]; then
+fi
+
+
+$dialog \
+--title 'Stealth options' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Please choose a new name to replace \"samhain\" upon installation" \
+10 75 "samhain" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --enable-install-name=$z"
+ done
+fi
+
+$dialog \
+--title "Stealth options" \
+--backtitle "Samhain $VERSION" \
+--inputbox "You can set a magic string such that command line arguments will be ignored unless the first argument is this magic string, and read from stdin otherwise. If you do not want this, select CANCEL, otherwise choose a string and select OK." \
+10 75 "foo" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --enable-nocl=$z"
+ done
+fi
+
+if [ "x$I386_LINUX" = "xyes" ]; then
+$dialog \
+--title "Stealth options" \
+--backtitle "Samhain $VERSION" \
+--yesno "SAMHAIN can compile and install a kernel module to hide the SAMHAIN daemon process. Do you want that ?"\
+2> $tmp
+
+mtest=$?
+
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ cfgline="$cfgline --enable-khide"
+fi
+
+# f [ "x$I386_LINUX" = "xyes" ]; then
+fi
+
+# want stealth
+fi
+
+#------------------------------------------------------------
+#
+# Paths to configure
+#
+#------------------------------------------------------------
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--radiolist "Do you wish to change the default paths ?\n\nThe default paths are:\n\n /usr/local/sbin all binaries\n /etc/samhainrc configuration file\n /var/lib/samhain/samhain_file data file\n /var/log/samhain_log log file\n /var/run/samhain.pid pid file $HTML" 20 76 5 \
+'usr' "Install binaries in /usr/sbin" off \
+'opt' "Use /opt/samhain, /etc/opt, /var/opt" off \
+'all' "Set paths individually" off \
+'cancel' "Don't change the paths" on \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+#
+# edit paths
+#
+mfile=`cat $tmp`
+for z in $mfile ; do
+ if [ "x$z" = "xopt" ]; then
+ cfgline="$cfgline --prefix=OPT"
+ fi
+ if [ "x$z" = "xusr" ]; then
+ cfgline="$cfgline --prefix=USR"
+ fi
+ if [ "x$z" = "xall" ]; then
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Exec prefix" 10 75 "/usr/local" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --exec-prefix=$z"
+ done
+fi
+
+
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Configuration" 10 75 "/etc/samhainrc" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-config-file=$z"
+ done
+fi
+
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Man pages" 10 75 "/usr/local/share/man" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-mandir=$z"
+ done
+fi
+
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Database" 10 75 "/var/lib/samhain/samhain_data" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-data-file=$z"
+ done
+fi
+
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Log file" 10 75 "/var/log/samhain_log" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-log-file=$z"
+ done
+fi
+
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Lock file" 10 75 "/var/run/samhain.pid" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-pid-file=$z"
+ done
+fi
+
+if [ "x$INET" = "xyes" ]; then
+$dialog \
+--title 'Paths' \
+--backtitle "Samhain $VERSION" \
+--inputbox "Server status" 10 75 "/var/lib/samhain/samhain.html" \
+2> $tmp
+
+mtest=$?
+if [ $mtest = -1 ]; then
+ exit 1
+fi
+if [ $mtest = 0 ]; then
+ mfile=`cat $tmp`
+ for z in $mfile ; do
+ cfgline="$cfgline --with-html-file=$z"
+ done
+fi
+# if [ "x$INET" = "xyes" ]; then
+fi
+
+ fi
+
+done
+# edit paths
+fi
+
+
+if [ ! -f "configure" ] ; then
+ bail_error "Setup problem... try to install manually"
+fi
+
+echo "./configure $cfgline" > Install.log 2>/dev/null
+
+if [ $? != 0 ]; then
+ $dialog --infobox "ERROR writing to \"Install.log\".\n\nAborting." 10 55
+ exit 1
+fi
+
+
+
+if [ "x$KCHECK" = "xyes" ]; then
+ if [ `id -u` != 0 ]; then
+$dialog --msgbox "Compiling with --with-kcheck option (kernel rootkit detection). This\nrequires root privileges for at least one command during compilation,\nbut you are not running this as root. Please expect compilation to fail.\n\nYou need to follow the instructions shown in the \nerror message after failure." 20 75
+ fi
+fi
+
+
+if [ -n "$gauge" ] ; then
+(
+ sfail=0
+ echo 20
+ rm -f config.cache 2> /dev/null
+ echo 30
+ if [ -z "$cfgline2" ]; then
+ ./configure $cfgline >> Install.log 2>&1
+ else
+ ./configure $cfgline --with-checksum="$cfgline2" >> Install.log 2>&1
+ fi
+ cfail=$?
+ echo 50
+ if [ $cfail = 0 ]; then
+ make clean >> Install.log 2>&1
+ cfail=$?
+ else
+ sfail=1
+ fi
+ echo 60
+ if [ $cfail = 0 ]; then
+ make >> Install.log 2>&1
+ cfail=$?
+ else
+ sfail=1
+ fi
+ echo 80
+ if [ $cfail = 0 ]; then
+ make install >> Install.log 2>&1
+ cfail=$?
+ else
+ sfail=1
+ fi
+ echo 100
+ echo cfail=$cfail > $tmp
+ echo sfail=$sfail >> $tmp
+) | $dialog \
+--title 'Compilation and installation' \
+--backtitle "Samhain $VERSION" \
+"$gauge" 'Please wait...' 10 75 10
+else
+ sfail=0
+ rm -f config.cache 2> /dev/null
+ $dialog --infobox "Running configure ..." 4 44
+ if [ -z "$cfgline2" ]; then
+ ./configure $cfgline >> Install.log 2>&1
+ else
+ ./configure $cfgline --with-checksum="$cfgline2" >> Install.log 2>&1
+ fi
+ cfail=$?
+ if [ $cfail = 0 ]; then
+ $dialog --infobox "Running make clean ..." 4 44
+ make clean >> Install.log 2>&1
+ cfail=$?
+ else
+ sfail=1
+ fi
+ if [ $cfail = 0 ]; then
+ $dialog --infobox "Running make ..." 4 44
+ make >> Install.log 2>&1
+ cfail=$?
+ else
+ sfail=1
+ fi
+ if [ $cfail = 0 ]; then
+ $dialog --infobox "Running make install ..." 4 44
+ make install >> Install.log 2>&1
+ cfail=$?
+ else
+ sfail=1
+ fi
+ echo cfail=$cfail > $tmp
+ echo sfail=$sfail >> $tmp
+fi
+
+. $tmp
+
+
+echo "SAMHAIN is now installed on your system." > $tmp
+echo "Please read the documentation to know how to run it." >> $tmp
+
+
+if [ "x$sfail" = "x0" ] ; then
+
+ if [ "x$cfail" = "x0" ] ; then
+ if [ "x${FULL_STEALTH}" = "xyes" ]; then
+ tail -21 Install.log >> $tmp
+ else
+ tail -11 Install.log >> $tmp
+ fi
+ $dialog --title "Build report (use arrow keys to scroll the text box)" \
+--backtitle "Samhain $VERSION installed. PLEASE READ THE MANUAL." \
+--textbox \
+$tmp \
+20 75
+ else
+ $dialog --title "Problem report" \
+--backtitle "Samhain $VERSION: Build failed (see Install.log):" \
+--msgbox \
+"Compilation was successful, but you need to be root in\norder to install the files to the selected prefix.\nPlease run 'make install' as root." \
+10 75
+ fi
+
+else
+
+ MSG=`tail -10 Install.log`
+ $dialog --title "Problem report" \
+--backtitle "Samhain $VERSION: Build failed (see Install.log):" \
+--msgbox "$MSG" 20 75
+
+fi
+
+rm -f $tmp
+
+exit 0
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..684e92b
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,1703 @@
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+# --- boiler-plate stuff ---
+#
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+srcsrc = @srcdir@/src
+srcinc = @srcdir@/include
+top_srcdir = @top_srcdir@
+
+# Don't use VPATH - it's a portability mess
+#
+# VPATH = $(top_srcdir)/src
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+sbindir = @sbindir@
+sysconfdir = @sysconfdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+datarootdir = @datarootdir@
+mytmpdir = @mytmpdir@
+
+configfile = @myconffile@
+mydatafile = @mydatafile@
+mylockfile = @mylockfile@
+mylogfile = @mylogfile@
+
+mydatadir = @mydataroot@
+mylogdir = @mylogdir@
+mylockdir = @mylockdir@
+
+selectconfig = @selectconfig@
+
+top_builddir = .
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL@ -s -m 700
+INSTALL_SHELL = @INSTALL@ -m 700
+INSTALL_DATA = @INSTALL@ -m 600
+INSTALL_MAN = @INSTALL@ -m 644
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_NAME = @install_name@
+INSTALL_DSYS = @INSTALL@ -m 755
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+BUILD_NUM = 1
+
+DEFAULT_MAINTAINER = Nobody Nowhere <nobody@example.com>
+
+VFLAG = @mytclient@
+SETPWD = @setpwd_prg@
+STEGIN = @stegin_prg@
+SAMHAIN = @sh_main_prg@
+YULECTL = @yulectl_prg@
+SADMIN = @samhainadmin_prg@
+XOR_CODE = @xor_code@
+TIGER_SRC = @tiger_src@
+
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+
+
+CC = @CC@
+BUILD_CC = @BUILD_CC@
+# DBGDEF = -pg -DSH_PROFILE=1
+DBGDEF = @mydebugdef@
+DEFS = $(DBGDEF) @DEFS@ -I. -I$(top_srcdir)/include
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS_TRY = @LIBS@
+LIBS_SOCK = @sh_libsocket@
+LIBS_KVM = @sh_libkvm@
+CFLAGS = @CFLAGS@
+CUTEST =
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $(CUTEST)
+LINK = $(CC) $(DBGDEF) -O $(LDFLAGS) -o $@
+
+DESTDIR =
+
+TAR = tar
+GZIP = --best
+
+# For creating a packed client
+#
+CLIENTPASSWD =
+
+.SUFFIXES: # Delete the default suffixes
+
+#
+# --- Files -------
+#
+
+
+HEADERS = samhain.h sh_unix.h sh_utils.h sh_error.h sh_error_min.h sh_files.h \
+ sh_getopt.h sh_readconf.h sh_tiger.h sh_hash.h \
+ sh_mail.h sh_mail_int.h sh_nmail.h sh_filter.h \
+ sh_mem.h sh_entropy.h sh_xfer.h sh_modules.h sh_utmp.h \
+ sh_suidchk.h sh_srp.h sh_fifo.h sh_html.h sh_tools.h \
+ sh_gpg.h sh_cat.h sh_calls.h sh_extern.h sh_database.h sh_trace.h \
+ sh_schedule.h bignum.h trustfile.h slib.h zAVLTree.h \
+ lzoconf.h minilzo.h rijndael-alg-fst.h rijndael-api-fst.h \
+ rijndael-boxes-fst.h sh_socket.h sh_ignore.h sh_prelude.h \
+ sh_mounts.h sh_userfiles.h sh_static.h sh_prelink.h \
+ sh_processcheck.h sh_portcheck.h sh_pthread.h sh_string.h \
+ sh_log_check.h sh_log_evalrule.h sh_log_correlate.h \
+ sh_log_mark.h sh_log_repeat.h sh_inotify.h sh_registry.h sh_ipvx.h \
+ sh_restrict.h sh_sub.h sh_fInotify.h sh_checksum.h \
+ sh_dbIO.h sh_dbIO_int.h sh_guid.h sh_dbCheck.h sh_dbCreate.h \
+ sh_sem.h
+
+
+SOURCES = $(srcsrc)/samhain.c $(srcsrc)/sh_unix.c \
+ $(srcsrc)/sh_utils.c $(srcsrc)/sh_error.c \
+ $(srcsrc)/sh_files.c $(srcsrc)/sh_getopt.c \
+ $(srcsrc)/sh_readconf.c $(srcsrc)/sh_tiger0.c \
+ $(srcsrc)/sh_tiger1.c $(srcsrc)/sh_tiger2.c \
+ $(srcsrc)/sh_tiger1_64.c $(srcsrc)/sh_tiger2_64.c \
+ $(srcsrc)/sh_hash.c $(srcsrc)/sh_mail.c $(srcsrc)/sh_nmail.c \
+ $(srcsrc)/sh_mem.c $(srcsrc)/sh_entropy.c \
+ $(srcsrc)/sh_xfer_client.c $(srcsrc)/sh_xfer_server.c \
+ $(srcsrc)/sh_xfer_syslog.c $(srcsrc)/sh_modules.c \
+ $(srcsrc)/sh_utmp.c $(srcsrc)/sh_login_track.c \
+ $(srcsrc)/sh_suidchk.c $(srcsrc)/sh_srp.c \
+ $(srcsrc)/sh_fifo.c $(srcsrc)/sh_tools.c \
+ $(srcsrc)/sh_html.c $(srcsrc)/sh_gpg.c \
+ $(srcsrc)/sh_cat.c $(srcsrc)/sh_calls.c \
+ $(srcsrc)/sh_extern.c $(srcsrc)/sh_database.c \
+ $(srcsrc)/sh_err_log.c $(srcsrc)/sh_err_console.c \
+ $(srcsrc)/sh_err_syslog.c $(srcsrc)/sh_schedule.c \
+ $(srcsrc)/bignum.c $(srcsrc)/mkhdr.c \
+ $(srcsrc)/samhain_setpwd.c $(srcsrc)/samhain_stealth.c \
+ $(srcsrc)/encode.c $(srcsrc)/sstrip.c \
+ $(srcsrc)/trustfile.c $(srcsrc)/exepack.c \
+ $(srcsrc)/exepack_fill.c $(srcsrc)/exepack_mkdata.c \
+ $(srcsrc)/minilzo.c $(srcsrc)/slib.c \
+ $(srcsrc)/rijndael-alg-fst.c $(srcsrc)/rijndael-api-fst.c \
+ $(srcsrc)/zAVLTree.c $(srcsrc)/bignum.c \
+ $(srcsrc)/sh_socket.c $(srcsrc)/sh_ignore.c \
+ $(srcsrc)/yulectl.c $(srcsrc)/sh_mounts.c \
+ $(srcsrc)/sh_userfiles.c $(srcsrc)/sh_prelude.c \
+ $(srcsrc)/sh_prelink.c $(srcsrc)/sh_static.c \
+ $(srcsrc)/sh_portcheck.c $(srcsrc)/sh_port2proc.c\
+ $(srcsrc)/sh_processcheck.c $(srcsrc)/sh_filter.c \
+ $(srcsrc)/sh_pthread.c $(srcsrc)/sh_string.c \
+ $(srcsrc)/sh_log_parse_syslog.c $(srcsrc)/sh_log_parse_pacct.c \
+ $(srcsrc)/sh_log_parse_samba.c $(srcsrc)/sh_log_parse_generic.c \
+ $(srcsrc)/sh_log_parse_apache.c $(srcsrc)/sh_log_evalrule.c \
+ $(srcsrc)/sh_log_correlate.c $(srcsrc)/sh_log_mark.c \
+ $(srcsrc)/sh_log_check.c $(srcsrc)/dnmalloc.c \
+ $(srcsrc)/sh_inotify.c $(srcsrc)/sh_log_repeat.c \
+ $(srcsrc)/sh_audit.c $(srcsrc)/sh_registry.c \
+ $(srcsrc)/sh_ipvx.c $(srcsrc)/sh_restrict.c \
+ $(srcsrc)/sh_filetype.c $(srcsrc)/sh_sub.c $(srcsrc)/sh_fInotify.c \
+ $(srcsrc)/sh_checksum.c $(srcsrc)/sh_guid.c $(srcsrc)/sh_sem.c \
+ $(srcsrc)/sh_dbIO.c $(srcsrc)/sh_dbCheck.c $(srcsrc)/sh_dbCreate.c \
+ $(srcsrc)/t-test1.c
+
+OBJECTS = sh_files.o sh_tiger0.o sh_tiger2.o sh_tiger2_64.o \
+ samhain.o sh_unix.o sh_utils.o sh_error.o \
+ sh_getopt.o sh_readconf.o sh_filter.o \
+ sh_hash.o sh_mail.o sh_nmail.o sh_mem.o sh_login_track.o \
+ sh_entropy.o sh_modules.o sh_utmp.o \
+ sh_xfer_client.o sh_xfer_server.o sh_xfer_syslog.o \
+ sh_suidchk.o sh_srp.o sh_fifo.o sh_tools.o sh_html.o sh_gpg.o \
+ sh_cat.o sh_calls.o sh_extern.o sh_database.o sh_err_log.o \
+ sh_err_console.o sh_err_syslog.o sh_schedule.o bignum.o \
+ trustfile.o rijndael-alg-fst.o rijndael-api-fst.o slib.o \
+ zAVLTree.o sh_socket.o sh_ignore.o sh_prelude.o \
+ sh_mounts.o sh_userfiles.o sh_prelink.o sh_static.o \
+ sh_processcheck.o sh_portcheck.o sh_port2proc.o \
+ sh_log_parse_syslog.o sh_log_parse_pacct.o sh_log_parse_apache.o \
+ sh_log_parse_samba.o sh_log_evalrule.o sh_log_check.o \
+ sh_log_parse_generic.o \
+ sh_log_correlate.o sh_log_mark.o sh_log_repeat.o \
+ sh_pthread.o sh_string.o sh_inotify.o dnmalloc.o \
+ sh_audit.o sh_registry.o sh_ipvx.o sh_restrict.o \
+ sh_filetype.o sh_sub.o sh_fInotify.o sh_checksum.o \
+ sh_guid.o sh_sem.o sh_dbIO.o sh_dbCheck.o sh_dbCreate.o
+
+
+TESTSUITE = test.sh testcompile.sh testhash.sh testtiger.txt \
+ testtimesrv.sh \
+ testext.sh testrc_1ext.in test_ext.c.in testrun_1d.sh \
+ testrun_1.sh testrun_1a.sh testrun_1b.sh testrun_1c.sh testrc_1 \
+ testrun_2.sh testrun_2a.sh testrun_2b.sh testrc_2.in \
+ testrun_2c.sh testrun_2d.sh
+
+DIST_COMMON = README COPYING LICENSE samhain.jpg \
+samhainrc.linux samhainrc.solaris samhainrc.freebsd samhainrc.aix5.2.0 \
+samhainrc.netbsd yulerc.template \
+Install.sh
+
+DIST_NEEDED = Makefile.in deploy.sh.in samhain-install.sh.in \
+samhain.spec.in rules.deb.in rules.deb-light.in samhain.spec hp_ux.psf.in \
+stealth_template.jpg \
+config.guess config.h.in stamp-h.in config.sub configure \
+configure.ac acconfig.h aclocal.m4 install-sh missing mkinstalldirs \
+c_random.sh c_bits.sh depend.sum depend.dep stamp-hdep
+
+DISTFILES = $(DIST_COMMON) $(DIST_NEEDED) \
+ src include man scripts init docs sql_init test dsys
+
+PROGRAMS = $(SETPWD) $(STEGIN) $(SAMHAIN) $(YULECTL) $(SADMIN)
+
+#----------------------------------------------------------
+#
+# the first target is the default one
+#
+#----------------------------------------------------------
+
+all: $(top_srcdir)/depend.sum $(SETPWD) $(STEGIN) $(SAMHAIN) $(YULECTL) sstrip
+
+
+#----------------------------------------------------------
+#
+# rules for automatic updating of configuration information
+# after changing the configuration files
+#
+#----------------------------------------------------------
+
+$(top_srcdir)/configure: $(top_srcdir)/configure.ac $(top_srcdir)/aclocal.m4
+ cd $(srcdir) && autoconf
+
+# autoheader might not change config.h.in, so touch a stamp file.
+$(top_srcdir)/config.h.in: $(top_srcdir)/stamp-h.in
+ touch $(top_srcdir)/config.h.in
+
+$(top_srcdir)/stamp-h.in: $(top_srcdir)/configure.ac $(top_srcdir)/aclocal.m4
+ cd $(top_srcdir) && autoheader
+ echo timestamp > $(top_srcdir)/stamp-h.in
+
+config.h: stamp-h
+ @sleep 1; \
+ touch config.h
+
+stamp-h: $(top_srcdir)/config.h.in config.status
+ ./config.status
+
+Makefile: $(top_srcdir)/Makefile.in config.status
+ ./config.status
+
+samhain-install.sh: $(top_srcdir)/samhain-install.sh.in config.status
+ ./config.status
+
+config.status: $(top_srcdir)/configure
+ ./config.status --recheck
+
+#----------------------------------------------------------
+#
+# rules for automatic dependency tracking
+#
+#----------------------------------------------------------
+
+
+depend-gen: $(srcsrc)/depend-gen.c
+ @echo "$(BUILD_CC) -I. -o depend-gen $(srcsrc)/depend-gen.c"; \
+ $(BUILD_CC) -I. -o depend-gen $(srcsrc)/depend-gen.c 2>/dev/null || \
+ echo "failed to compile ... hope depend.dep is ok"
+
+# redo if sources change
+#
+$(top_srcdir)/depend.dep: depend-gen $(SOURCES)
+ @echo "update depend.dep ..."; \
+ test -f $(srcdir)/depend.dep || echo > $(srcdir)/depend.dep; \
+ if test -f depend-gen; then \
+ failfiles=""; \
+ for ff in $(SOURCES); do \
+ ./depend-gen -i '$$(srcinc)/' -o $(top_srcdir)/depend.dep $$ff || \
+ failfiles="$${failfiles} $$ff"; \
+ done; \
+ if test x"$${failfiles}" != x; then \
+ echo "--------------------------------------------------------";\
+ echo " depend-gen failed to update depend.dep. You can safely"; \
+ echo " ignore this error, unless you have modified the source"; \
+ echo " files and changed their dependencies."; \
+ echo "--------------------------------------------------------";\
+ else \
+ echo $(srcsrc) > $(top_srcdir)/stamp-dep; \
+ fi; \
+ else \
+ echo "depend-gen not found ... depend.dep not modified"; \
+ fi
+
+# only updated if depencies change
+#
+$(top_srcdir)/depend.sum: $(top_srcdir)/depend.dep
+ @if test -f depend-gen; then \
+ nsum=`./depend-gen -c $(top_srcdir)/depend.dep|awk '{print $$1}'`; \
+ osum=`cat $(top_srcdir)/depend.sum 2>/dev/null`; \
+ if test "x$$osum" != "x$$nsum"; then \
+ echo "update $(top_srcdir)/depend.sum ..."; \
+ echo $$nsum > $(top_srcdir)/depend.sum; \
+ echo timestamp > $(top_srcdir)/stamp-hdep; \
+ fi; \
+ fi;
+
+$(top_srcdir)/stamp-hdep:
+ touch $(top_srcdir)/stamp-hdep && touch $(top_srcdir)/Makefile.in
+
+$(top_srcdir)/Makefile.in: $(top_srcdir)/stamp-hdep
+ @echo "update Makefile.in ..."; \
+ echo "cp Makefile.in Makefile.in.bak"; \
+ cp $(top_srcdir)/Makefile.in $(top_srcdir)/Makefile.in.bak; \
+ if test -f depend-gen; then \
+ failfiles=""; \
+ for ff in $(SOURCES); do \
+ ./depend-gen -i '$$(srcinc)/' -o $(top_srcdir)/Makefile.in $$ff || \
+ failfiles="$${failfiles} $$ff"; \
+ done; \
+ if test x"$${failfiles}" != x; then \
+ echo "--------------------------------------------------------";\
+ echo " depend-gen failed to update Makefile.in. You can safely"; \
+ echo " ignore this error, unless you have modified the source"; \
+ echo " files and changed their dependencies."; \
+ echo "--------------------------------------------------------";\
+ else \
+ echo $(srcsrc) > $(top_srcdir)/stamp-dep; \
+ fi; \
+ fi
+
+# do it manually
+#
+depend: depend-gen
+ @echo "update Makefile.in ..."; \
+ for ff in $(SOURCES); do \
+ ./depend-gen -i '$$(srcinc)/' -o $(top_srcdir)/Makefile.in $$ff; \
+ echo $(srcsrc) > $(top_srcdir)/stamp-dep; \
+ done
+
+
+#----------------------------------------------------------
+#
+# CLEAN rules
+#
+#----------------------------------------------------------
+
+
+# everything created by make
+#
+
+CLEANFILES = encode config_xor.h depend-gen \
+ internal.h sh_MK.h trustfile sstrip samhain mkhdr encode cutest \
+ yule samhain_setpwd samhain_stealth samhainrc yulectl
+
+clean:
+ -rm -f core *.o
+ @-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+
+# everything created by (./configure && make)
+#
+
+DISTCLEANFILES = Makefile samhain.spec sh_gpg_checksum.h sh_gpg_fp.h \
+ init/samhain.startLinux init/samhain.startGentoo \
+ init/samhain.startLSB init/samhain.startFreeBSD \
+ init/samhain.startSolaris init/samhain.startHPUX \
+ init/samhain.startIRIX init/samhain.startMACOSX \
+ deploy.sh sh_MK.h samhain-install.sh sh_gpg_chksum.h sh_gpg_fp.h \
+ rules.deb rules.deb-light src/CuTestMain.c \
+ scripts/samhainadmin.pl scripts/check_samhain.pl \
+ scripts/samhain.ebuild scripts/samhain.ebuild-light \
+ scripts/yuleadmin.pl scripts/logrotate \
+ scripts/redhat_i386.client.spec scripts/samhain.spec hp_ux.psf
+
+TESTCLEANFILES = samhain.build samhain.new yule.html \
+ test_ext test_ext.c test_ext.res testhash.tmp \
+ testrc1.signed testrc_1ext testrc_2 testrc_2.signed \
+ test_dnmalloc
+
+distclean: clean
+ -rm -f config.status config.log configure.lineno config.h config.cache
+ @-test -z "$(TESTCLEANFILES)" || rm -f $(TESTCLEANFILES)
+ @-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+
+#----------------------------------------------------------
+#
+# TEST rules
+#
+#----------------------------------------------------------
+
+test14: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 14 `hostname -f`
+
+test13: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 13 `hostname -f`
+
+test12: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 12 `hostname -f`
+
+test11: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 11 `hostname -f`
+
+test10: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 10 `hostname -f`
+
+test7: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 7
+
+test6: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 6
+
+test5: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 5
+
+test4: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 4
+
+test3: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 3
+
+test2: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 2
+
+test1: test
+ @cd test && TOP_SRCDIR=$(top_srcdir) && \
+ export TOP_SRCDIR && ./test.sh 1
+
+test:
+ @if test -f test; then \
+ :; \
+ else \
+ cp -pr $(top_srcdir)/test .; \
+ cat $(top_srcdir)/test/test.sh | \
+ sed 's%XXXSRCXXX%$(top_srcdir)%' > test/test.sh; \
+ chmod +x test/test.sh; \
+ fi
+
+test_dnmalloc: $(srcsrc)/t-test1.c dnmalloc.o
+ $(COMPILE) $(VFLAG) -o t-test1.o -c $(srcsrc)/t-test1.c; \
+ $(LINK) t-test1.o dnmalloc.o $(LIBS_TRY)
+
+
+#----------------------------------------------------------
+#
+# INSTALL rules
+#
+#----------------------------------------------------------
+
+install: install-program install-man install-data
+ @echo; \
+ echo " You can use 'samhain-install.sh uninstall' for uninstalling"; \
+ echo " i.e. you might consider saving that script for future use";\
+ echo; \
+ echo " Use 'make install-boot' if you want @install_name@ to start on system boot"; \
+ echo
+
+install-light: install-program install-data
+ @echo; \
+ echo " You can use 'samhain-install.sh uninstall' for uninstalling"; \
+ echo " i.e. you might consider saving that script for future use";\
+ echo; \
+ echo " Use 'make install-boot' if you want @install_name@ to start on system boot"; \
+ echo
+
+purge: uninstall-program uninstall-man
+ @echo "./samhain-install.sh --destdir=$(DESTDIR) --force --verbose uninstall-data"; \
+ ./samhain-install.sh --destdir=$(DESTDIR) --force --verbose uninstall-data
+
+remove: uninstall
+
+uninstall: uninstall-program uninstall-man uninstall-data
+ @echo; \
+ echo " Use 'make purge' if you also want to uninstall the configuration file"; \
+ echo " Use 'make uninstall-boot' to uninstall the runlevel scripts"; \
+ echo
+
+#
+# --- boot ---
+#
+install-boot: samhain-install.sh
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose install-boot
+
+
+uninstall-boot: samhain-install.sh
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-boot
+
+#
+# --- program ---
+#
+
+
+install-program: $(PROGRAMS) sstrip
+ @$(mkinstalldirs) $(DESTDIR)$(sbindir)
+ @if test x$(mytmpdir) != x; then \
+ $(mkinstalldirs) $(DESTDIR)$(mytmpdir); \
+ fi
+ @list='$(PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ target=$(DESTDIR)$(sbindir)/`echo $$p|sed 's%samhain%@install_name@%'|sed 's%yule%@install_name@%'|sed 's%.*/%%'`; \
+ extension=`echo $$target|sed 's%.*\.%%'`; \
+ if test x$$extension = x; then \
+ echo " $(INSTALL_PROGRAM) $$p $$target"; \
+ $(INSTALL_PROGRAM) $$p $$target; \
+ chmod 0700 $$target; \
+ echo " ./sstrip $$target"; \
+ ./sstrip $$target; \
+ else \
+ echo " $(INSTALL_SHELL) $$p $$target"; \
+ $(INSTALL_SHELL) $$p $$target; \
+ chmod 0700 $$target; \
+ fi; \
+ else :; fi; \
+ done
+
+uninstall-program:
+ @echo "./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-program";\
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-program
+
+
+#
+# -- data files
+#
+
+install-user:
+ @if test "x@need_user_install@" = x1; then \
+ echo "./samhain-install.sh --destdir=$(DESTDIR) --express --verbose install-user @myident@"; \
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose install-user @myident@; \
+ fi
+ @if test x"$(VFLAG)" = "x-DSH_WITH_SERVER"; then \
+ echo " chown root $(DESTDIR)$(mydatadir)"; \
+ chown root $(DESTDIR)$(mydatadir); \
+ echo " chmod 755 $(DESTDIR)$(mydatadir)"; \
+ chmod 755 $(DESTDIR)$(mydatadir); \
+ echo " chown @myident@ $(DESTDIR)$(configfile)"; \
+ chown @myident@ $(DESTDIR)$(configfile); \
+ if test x"$(mylogdir)" = "x/var/log"; then \
+ if test x"@myident@" = xroot; then \
+ :; \
+ else \
+ echo; \
+ echo " ----------------------------------------------------------------"; \
+ echo " Directory $(mylogdir) (log file) looks like a system directory."; \
+ echo " You may run into problems (need write access for user @myident@)."; \
+ echo " ----------------------------------------------------------------"; \
+ echo; \
+ fi; \
+ else \
+ echo " chown @myident@ $(DESTDIR)$(mylogdir)"; \
+ chown @myident@ $(DESTDIR)$(mylogdir); \
+ fi; \
+ fi
+
+install-data: trustfile
+ @$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+ @$(mkinstalldirs) $(DESTDIR)$(mylockdir)
+ @$(mkinstalldirs) $(DESTDIR)$(mylogdir)
+ @$(mkinstalldirs) $(DESTDIR)$(mydatadir); \
+ chmod 700 $(DESTDIR)$(mydatadir)
+ @if test -f samhainrc.$(selectconfig); then \
+ :; \
+ else \
+ if test -f $(srcdir)/samhainrc.$(selectconfig); then \
+ cp $(srcdir)/samhainrc.$(selectconfig) . ; \
+ fi; \
+ fi; \
+ if test -f yulerc; then \
+ :; \
+ else \
+ if test -f $(srcdir)/yulerc.template; then \
+ cp $(srcdir)/yulerc.template yulerc; \
+ fi; \
+ fi; \
+ if test -f stealth_template.jpg; then \
+ :; \
+ else \
+ if test -f $(srcdir)/stealth_template.jpg; then \
+ cp $(srcdir)/stealth_template.jpg . ; \
+ fi; \
+ fi
+ @if test -d /etc/logrotate.d; then \
+ if test ! -d $(DESTDIR)/etc/logrotate.d; then \
+ $(mkinstalldirs) $(DESTDIR)/etc/logrotate.d; \
+ fi; \
+ if test ! -f $(DESTDIR)/etc/logrotate.d/@install_name@; then \
+ if test -w $(DESTDIR)/etc/logrotate.d; then \
+ cp $(srcdir)/scripts/logrotate $(DESTDIR)/etc/logrotate.d/@install_name@; \
+ else \
+ echo "$(DESTDIR)/etc/logrotate.d not writable"; \
+ fi; \
+ else \
+ echo "$(DESTDIR)/etc/logrotate.d/@install_name@ exists, not overwriting"; \
+ fi; \
+ fi
+ @echo "./samhain-install.sh --destdir=$(DESTDIR) --express --verbose install-data"; \
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose install-data || \
+ echo " ERROR: Failed to install the configuration file to $(DESTDIR)$(configfile). You need to install the configuration file manually."
+ @if test x"$(VFLAG)" = "x-DSH_WITH_SERVER"; then \
+ echo;\
+ echo " -----------------------------------------------------";\
+ echo " The server will run as user @myident@ if started with";\
+ echo " root privileges, otherwise as the user of the parent ";\
+ echo " process (use --enable-identity=USER to change).";\
+ echo;\
+ echo " You may want to use: make install-user";\
+ echo;\
+ echo " - to add the user @myident@ (if not existing already)";\
+ echo " - to chown the data directory $(mydatadir)";\
+ echo " - to chown the log file directory $(mylogdir)";\
+ echo " - to chown the configuration file $(configfile)";\
+ echo " -----------------------------------------------------";\
+ else \
+ if test "x@need_user_install@" = x1; then \
+ echo;\
+ echo " -----------------------------------------------------";\
+ echo " You may want to use: make install-user";\
+ echo;\
+ echo " - to add the user @myident@ (if not existing already)";\
+ echo " -----------------------------------------------------";\
+ fi; \
+ fi
+
+uninstall-data:
+ @echo "./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-data"; \
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-data
+
+#
+# -- man files
+#
+
+install-man:
+ $(mkinstalldirs) $(DESTDIR)$(mandir)/man8
+ $(mkinstalldirs) $(DESTDIR)$(mandir)/man5
+ @if test -f $(top_srcdir)/man/samhain.8 ; then \
+ echo " $(INSTALL_MAN) $(top_srcdir)/man/samhain.8 $(DESTDIR)$(mandir)/man8/@install_name@.8"; \
+ $(INSTALL_MAN) $(top_srcdir)/man/samhain.8 $(DESTDIR)$(mandir)/man8/@install_name@.8; \
+ fi
+ @if test -f $(top_srcdir)/man/samhainrc.5 ; then \
+ echo " $(INSTALL_MAN) $(top_srcdir)/man/samhainrc.5 $(DESTDIR)$(mandir)/man5/@install_name@rc.5"; \
+ $(INSTALL_MAN) $(top_srcdir)/man/samhainrc.5 $(DESTDIR)$(mandir)/man5/@install_name@rc.5; \
+ fi
+
+uninstall-man:
+ @echo "./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-man";\
+ ./samhain-install.sh --destdir=$(DESTDIR) --express --verbose uninstall-man
+
+
+#----------------------------------------------------------
+#
+# BUILD rules
+#
+#----------------------------------------------------------
+
+run: run-light
+
+run-light: all
+ @echo "Building $(PACKAGE)-$(VERSION).run"; \
+ STAGE=$(PACKAGE)-$(VERSION); \
+ mkdir $$STAGE; \
+ if test x"$$?" != x0; then \
+ echo "ERROR ... mkdir $$STAGE failed"; \
+ exit 1; \
+ fi; \
+ $(MAKE) DESTDIR=$$STAGE install-light; \
+ rm -f $$STAGE/@sbindir@/@install_name@_stealth; \
+ echo "#! /bin/sh" > $$STAGE/setup.sh; \
+ if test x$(mytmpdir) != x; then \
+ echo "./mkinstalldirs @mytmpdir@ || exit 1" >> $$STAGE/setup.sh; \
+ fi; \
+ echo "./mkinstalldirs @sbindir@ || exit 1" >> $$STAGE/setup.sh; \
+ echo "./mkinstalldirs @sysconfdir@ || exit 1" >> $$STAGE/setup.sh; \
+ echo "./mkinstalldirs @mylockdir@ || exit 1" >> $$STAGE/setup.sh; \
+ echo "./mkinstalldirs @mylogdir@ || exit 1" >> $$STAGE/setup.sh; \
+ echo "./mkinstalldirs @mydataroot@ || exit 1" >> $$STAGE/setup.sh; \
+ echo "chmod 700 @mydataroot@ || exit 1" >> $$STAGE/setup.sh; \
+ temp=`echo $(sbindir) | sed s,^/,,`; \
+ echo "chown root $$temp/*" >> $$STAGE/setup.sh; \
+ echo "cp -p $$temp/* $(sbindir) || exit 1" >> $$STAGE/setup.sh; \
+ temp=`echo $(sysconfdir) | sed s,^/,,`; \
+ echo "chown root $$temp/*" >> $$STAGE/setup.sh; \
+ configfile=`echo @myconffile@ | sed 's%^REQ_FROM_SERVER%%'`; \
+ echo "test -f $$configfile || cp -p $$temp/* $$configfile" >> $$STAGE/setup.sh; \
+ echo "./samhain-install.sh --express --verbose install-boot || echo 'Cannot install init script'" >> $$STAGE/setup.sh; \
+ cp $(top_srcdir)/mkinstalldirs $$STAGE/; \
+ cp $(top_srcdir)/install-sh $$STAGE/; \
+ cp ./samhain-install.sh $$STAGE/; \
+ cp -r init/ $$STAGE/; \
+ chmod +x $$STAGE/setup.sh; \
+ chmod +x $$STAGE/samhain-install.sh; \
+ chmod +x $$STAGE/mkinstalldirs; \
+ chmod +x $$STAGE/install-sh; \
+ $(top_srcdir)/scripts/makeself/makeself.sh --header $(top_srcdir)/scripts/makeself/makeself-header.sh --nocomp --nomd5 --notemp $$STAGE $(PACKAGE)-$(VERSION).run "$(PACKAGE)_$(VERSION)_self_extracting_installer" ./setup.sh && \
+ rm -r $(PACKAGE)-$(VERSION)
+
+emerge-prepare: dist
+ @echo "Building $(PACKAGE)-$(VERSION)"; \
+ test -f /etc/make.globals && . /etc/make.globals; \
+ test -f /etc/make.conf && . /etc/make.conf; \
+ echo "$(INSTALL_MAN) $(PACKAGE)-$(VERSION).tar.gz $${DISTDIR}/@install_name@-$(VERSION).tar.gz"; \
+ $(INSTALL_MAN) $(PACKAGE)-$(VERSION).tar.gz $${DISTDIR}/@install_name@-$(VERSION).tar.gz; \
+ if test "x$${PORTDIR_OVERLAY}" = "x"; then \
+ COPY_TO="$${PORTDIR}"; \
+ else \
+ COPY_TO="$${PORTDIR_OVERLAY}"; \
+ fi; \
+ $(mkinstalldirs) $${COPY_TO}/app-admin/@install_name@; \
+ echo "$(INSTALL_MAN) scripts/samhain.ebuild $${COPY_TO}/app-admin/@install_name@/@install_name@-$(VERSION).ebuild";\
+ $(INSTALL_MAN) scripts/samhain.ebuild $${COPY_TO}/app-admin/@install_name@/@install_name@-$(VERSION).ebuild; \
+ test -f $${COPY_TO}/app-admin/@install_name@/files/digest-@install_name@-$(VERSION) && rm $${COPY_TO}/app-admin/@install_name@/files/digest-@install_name@-$(VERSION);\
+ ebuild $${COPY_TO}/app-admin/@install_name@/@install_name@-$(VERSION).ebuild digest;
+
+emerge-prepare-light: dist
+ @echo "Building $(PACKAGE)-$(VERSION)"; \
+ test -f /etc/make.globals && . /etc/make.globals; \
+ test -f /etc/make.conf && . /etc/make.conf; \
+ echo "$(INSTALL_MAN) $(PACKAGE)-$(VERSION).tar.gz $${DISTDIR}/@install_name@-$(VERSION).tar.gz"; \
+ $(INSTALL_MAN) $(PACKAGE)-$(VERSION).tar.gz $${DISTDIR}/@install_name@-$(VERSION).tar.gz; \
+ if test "x$${PORTDIR_OVERLAY}" = "x"; then \
+ COPY_TO="$${PORTDIR}"; \
+ else \
+ COPY_TO="$${PORTDIR_OVERLAY}"; \
+ fi; \
+ $(mkinstalldirs) $${COPY_TO}/app-admin/@install_name@; \
+ echo "$(INSTALL_MAN) scripts/samhain.ebuild-light $${COPY_TO}/app-admin/@install_name@/@install_name@-$(VERSION).ebuild";\
+ $(INSTALL_MAN) scripts/samhain.ebuild-light $${COPY_TO}/app-admin/@install_name@/@install_name@-$(VERSION).ebuild; \
+ test -f $${COPY_TO}/app-admin/@install_name@/files/digest-@install_name@-$(VERSION) && rm $${COPY_TO}/app-admin/@install_name@/files/digest-@install_name@-$(VERSION);\
+ ebuild $${COPY_TO}/app-admin/@install_name@/@install_name@-$(VERSION).ebuild digest;
+
+
+tbz2: emerge-prepare
+ @emerge --buildpkgonly @install_name@; \
+ test -f /etc/make.globals && . /etc/make.globals; \
+ test -f /etc/make.conf && . /etc/make.conf; \
+ echo; \
+ echo "@install_name@-$(VERSION).tbz2 should be in $${PKGDIR}/All"; \
+ if test -f $${PKGDIR}/All/@install_name@-$(VERSION).tbz2; then \
+ echo "Package $${PKGDIR}/All/@install_name@-$(VERSION).tbz2 built."; \
+ mv $${PKGDIR}/All/@install_name@-$(VERSION).tbz2 $(PACKAGE)-$(VERSION).tbz2; \
+ rm -f $${PKGDIR}/app-admin/@install_name@-$(VERSION).tbz2; \
+ rm -rf $${PORTAGE_TMPDIR}/portage/@install_name@-$(VERSION); \
+ else \
+ echo "Error ... cannot find package."; \
+ exit 1; \
+ fi; \
+ echo
+
+tbz2-light: emerge-prepare-light
+ @emerge --buildpkgonly @install_name@; \
+ test -f /etc/make.globals && . /etc/make.globals; \
+ test -f /etc/make.conf && . /etc/make.conf; \
+ echo; \
+ if test -f $${PKGDIR}/All/@install_name@-$(VERSION).tbz2; then \
+ echo "Package $${PKGDIR}/All/@install_name@-$(VERSION).tbz2 built."; \
+ mv $${PKGDIR}/All/@install_name@-$(VERSION).tbz2 $(PACKAGE)-$(VERSION).tbz2; \
+ rm -f $${PKGDIR}/app-admin/@install_name@-$(VERSION).tbz2; \
+ rm -rf $${PORTAGE_TMPDIR}/portage/@install_name@-$(VERSION); \
+ else \
+ echo "Error ... cannot find package."; \
+ exit 1; \
+ fi; \
+ echo
+
+emerge:
+ emerge $(PACKAGE);
+
+deb-light:
+ @echo "creating subdirectory debian"; \
+ mkdir -p debian; \
+ cp rules.deb-light debian/rules; \
+ chmod +x debian/rules; \
+ echo $(sbindir) | sed s,^/,, > debian/dirs; \
+ if test x$(mytmpdir) != x; then \
+ echo $(mytmpdir) | sed s,^/,, >> debian/dirs; \
+ fi; \
+ echo $(sysconfdir) | sed s,^/,, >> debian/dirs; \
+ echo etc/init.d >> debian/dirs; \
+ echo $(mydatadir) | sed s,^/,, >> debian/dirs; \
+ echo $(mylogdir) | sed s,^/,, >> debian/dirs; \
+ echo $(mylockdir) | sed s,^/,, >> debian/dirs; \
+ $(MAKE) deb-run
+
+deb:
+ @echo "creating subdirectory debian"; \
+ mkdir -p debian; \
+ cp rules.deb debian/rules; \
+ chmod +x debian/rules; \
+ echo $(sbindir) | sed s,^/,, > debian/dirs; \
+ if test x$(mytmpdir) != x; then \
+ echo $(mytmpdir) | sed s,^/,, >> debian/dirs; \
+ fi; \
+ echo $(sysconfdir) | sed s,^/,, >> debian/dirs; \
+ echo etc/init.d >> debian/dirs; \
+ echo $(mydatadir) | sed s,^/,, >> debian/dirs; \
+ echo $(mylogdir) | sed s,^/,, >> debian/dirs; \
+ echo $(mylockdir) | sed s,^/,, >> debian/dirs; \
+ echo $(mandir)/man5 | sed s,^/,, >> debian/dirs; \
+ echo $(mandir)/man8 | sed s,^/,, >> debian/dirs; \
+ echo usr/share/doc/$(PACKAGE) >> debian/dirs; \
+ echo $(top_srcdir)/README > debian/docs; \
+ echo $(top_srcdir)/test/testtiger.txt >> debian/docs; \
+ echo $(srcsrc)/simple-bignum.tar.bz2 >> debian/docs; \
+ echo $(top_srcdir)/scripts/head.html >> debian/docs; \
+ echo $(top_srcdir)/scripts/foot.html >> debian/docs; \
+ echo $(top_srcdir)/samhain.jpg >> debian/docs; \
+ echo $(top_srcdir)/docs/BUGS >> debian/docs; \
+ echo $(top_srcdir)/docs/HOWTO-client+server.html >> debian/docs; \
+ echo $(top_srcdir)/docs/HOWTO-samhain+GnuPG.html >> debian/docs; \
+ echo $(top_srcdir)/docs/MANUAL-2_4.html.tar >> debian/docs; \
+ echo $(top_srcdir)/docs/MANUAL-2_4.pdf >> debian/docs; \
+ echo $(top_srcdir)/docs/README.gcc_bug >> debian/docs; \
+ echo $(top_srcdir)/docs/README.LZO >> debian/docs; \
+ echo $(top_srcdir)/docs/README.sstrip >> debian/docs; \
+ echo $(top_srcdir)/docs/README.UPGRADE >> debian/docs; \
+ echo $(top_srcdir)/docs/README.win2K >> debian/docs; \
+ $(MAKE) deb-run
+
+deb-run:
+ @maintainer=`gpg --list-secret-keys | grep 'uid ' | cut -d" " -f 5- | sed 's/^ *//' | sed q1`;\
+ if test "x$$maintainer" = x; then \
+ maintainer="$(DEFAULT_MAINTAINER)"; \
+ fi; \
+ echo "$(PACKAGE) ($(VERSION)-$(BUILD_NUM)) stable; urgency=low" > debian/changelog; \
+ echo >> debian/changelog; \
+ echo " * Initial release." >> debian/changelog; \
+ echo >> debian/changelog; \
+ echo " -- $$maintainer `date -R`" >> debian/changelog; \
+ echo >> debian/changelog; \
+ echo "Local variables:" >> debian/changelog; \
+ echo "mode: debian-changelog" >> debian/changelog; \
+ echo "End:" >> debian/changelog; \
+ cp $(top_srcdir)/COPYING debian/copyright; \
+ touch debian/README.debian; \
+ echo "Document: @install_name@-manual" > debian/@install_name@.doc-base; \
+ echo "Title: @install_name@ Manual" >> debian/@install_name@.doc-base; \
+ echo "Author: Rainer Wichmann" >> debian/@install_name@.doc-base; \
+ echo "Abstract: This manual describes what @install_name@ is" >> debian/@install_name@.doc-base; \
+ echo " and how it can be used to check the file integrity of your" >> debian/@install_name@.doc-base; \
+ echo " server." >> debian/@install_name@.doc-base; \
+ echo "Section: System/Security" >> debian/@install_name@.doc-base; \
+ echo >> debian/@install_name@.doc-base; \
+ echo >> debian/@install_name@.doc-base; \
+ echo "Format: Postscript" >> debian/@install_name@.doc-base; \
+ echo "Files: /usr/share/doc/@install_name@/manual.pdf.gz" >> debian/@install_name@.doc-base; \
+ echo >> debian/@install_name@.doc-base; \
+ echo "Format: HTML" >> debian/@install_name@.doc-base; \
+ echo "Index: /usr/share/doc/@install_name@/manual.html/index.html" >> debian/@install_name@.doc-base; \
+ echo "Files: /usr/share/doc/@install_name@/manual.html/*.html" >> debian/@install_name@.doc-base; \
+ if test -f /usr/lib/lsb/install_initd; then \
+ cp init/samhain.startLSB debian/@install_name@.init; \
+ else \
+ cp init/samhain.startLinux debian/@install_name@.init; \
+ fi; \
+ echo "Source: samhain" > debian/control; \
+ echo "Section: admin" >> debian/control; \
+ echo "Priority: optional" >> debian/control; \
+ echo "Maintainer: $$maintainer" >> debian/control; \
+ echo "Standards-Version: 3.2.1" >> debian/control; \
+ echo >> debian/control; \
+ echo "Package: @install_name@" >> debian/control; \
+ echo "Architecture: any" >> debian/control; \
+ echo "Depends: libc6" >> debian/control; \
+ echo "Description: File integrity checker" >> debian/control; \
+ echo " A file integrity checker" >> debian/control; \
+ echo "running debuild -us -uc"; \
+ debuild --preserve-envvar=PASSWORD -us -uc -b; \
+ DEBFILE=`find ../ -follow -maxdepth 1 -cnewer ./debian/control 2>/dev/null | grep '@install_name@_$(VERSION)' | grep '\.deb'`; \
+ if test x"$$DEBFILE" = x; then \
+ echo "Error ... cannot find package file"; \
+ exit 1; \
+ else \
+ echo "Package $$DEBFILE built."; \
+ cp $$DEBFILE ./$(PACKAGE)-$(VERSION)-$(BUILD_NUM).deb; \
+ ln -s ./$(PACKAGE)-$(VERSION)-$(BUILD_NUM).deb ./$(PACKAGE)-$(VERSION).deb; \
+ fi; \
+ echo
+
+#
+# Check samhain.spec
+#
+rpmspec-full:
+ @grep 'install-light' samhain.spec >/dev/null 2>&1; \
+ if test x"$$?" = "x0"; then \
+ echo "Your samhain.spec is from rpm-light. Please run"; \
+ echo " .config.status to re-create the original samhain.spec"; \
+ exit 1; \
+ fi
+
+# when editing the spec file, make an additional blank after 'make'
+# to avoid that it matches on a second processing
+#
+rpmspec-light: samhain.spec
+ @echo "Stripping docs from samhain.spec"; \
+ cat samhain.spec | sed 's,make DESTDIR=$${RPM_BUILD_ROOT} install,make DESTDIR=$${RPM_BUILD_ROOT} install-light,' | sed s,shkeep=yes,shkeep=no, | sed s,%doc.*,, | sed '/logrotate/! { s,%attr.*,, }' > samhain.spec-light; \
+ mv samhain.spec-light samhain.spec
+
+rpm-light: rpmspec-light distrpm
+ rpmbuild -ta ./$(PACKAGE)-$(VERSION).tar.gz;
+ @RPMTOP=`cat ~/.rpmmacros 2>/dev/null | grep '%_topdir' | awk '{ print $$2}'`; \
+ if test x"$$RPMTOP" = x; then RPMTOP=/usr/src; fi; \
+ if ! test -d "$$RPMTOP"; then \
+ RPMTOP=`echo $$HOME/rpmbuild`; \
+ fi; \
+ echo "Searching the RPM package below $$RPMTOP ..."; \
+ RPMFILE=`find $$RPMTOP -follow -maxdepth 4 -cnewer ./samhain.spec 2>/dev/null | grep '@install_name@-$(VERSION)' | grep '\.rpm' | grep -v '\.src\.'`; \
+ echo; \
+ if test x"$$RPMFILE" = x; then \
+ echo "Error ... cannot find package file"; \
+ exit 1; \
+ else \
+ echo "Package $$RPMFILE built."; \
+ echo "Copying it to ./$(PACKAGE)-$(VERSION).rpm"; \
+ cp $$RPMFILE ./$(PACKAGE)-$(VERSION).rpm; \
+ fi; \
+ echo
+
+rpm: rpmspec-full distrpm
+ rpmbuild -ta ./$(PACKAGE)-$(VERSION).tar.gz;
+ @RPMTOP=`cat ~/.rpmmacros 2>/dev/null | grep '%_topdir' | awk '{ print $$2}'`; \
+ if test x"$$RPMTOP" = x; then RPMTOP=/usr/src; fi; \
+ if ! test -d "$$RPMTOP"; then \
+ RPMTOP=`echo $$HOME/rpmbuild`; \
+ fi; \
+ echo "Searching the RPM package below $$RPMTOP ..."; \
+ RPMFILE=`find $$RPMTOP -follow -maxdepth 4 -cnewer ./samhain.spec 2>/dev/null | grep '@install_name@-$(VERSION)' | grep '\.rpm' | grep -v '\.src\.'`; \
+ echo; \
+ if test x"$$RPMFILE" = x; then \
+ echo "Error ... cannot find package file"; \
+ exit 1; \
+ else \
+ echo "Package $$RPMFILE built."; \
+ echo "Copying it to ./$(PACKAGE)-$(VERSION).rpm"; \
+ cp $$RPMFILE ./$(PACKAGE)-$(VERSION).rpm; \
+ fi; \
+ echo
+
+srpm-dist: rpmspec-full samhain.spec
+ @cat samhain.spec | \
+ sed s%\-\-with\-base=.*\,[0123456789]*%% | \
+ sed s%\'\'%% > samhain.spec.m; \
+ mv samhain.spec.m samhain.spec
+ $(MAKE) distrpm
+ rpmbuild -ts ./$(PACKAGE)-$(VERSION).tar.gz
+
+
+srpm: rpmspec-full distrpm
+ rpmbuild -ts ./$(PACKAGE)-$(VERSION).tar.gz
+
+solaris-pkg-light: all
+ @STAGE=/tmp/samhain-pkg-staging; \
+ mkdir $$STAGE; \
+ if test x"$$?" != x0; then \
+ echo "ERROR ... mkdir $$STAGE failed"; \
+ exit 1; \
+ fi; \
+ $(MAKE) DESTDIR=$$STAGE install-light;
+ $(MAKE) solaris-pkg-finish
+
+solaris-pkg: all
+ @STAGE=/tmp/samhain-pkg-staging; \
+ mkdir $$STAGE; \
+ if test x"$$?" != x0; then \
+ echo "ERROR ... mkdir $$STAGE failed"; \
+ exit 1; \
+ fi; \
+ $(MAKE) DESTDIR=$$STAGE install;
+ $(MAKE) solaris-pkg-finish
+
+solaris-pkg-finish:
+ @STAGE=/tmp/samhain-pkg-staging; \
+ $(mkinstalldirs) $$STAGE/etc/init.d; \
+ $(INSTALL_SHELL) init/samhain.startSolaris $$STAGE/etc/init.d/@install_name@; \
+ (echo 'i pkginfo'; pkgproto $$STAGE=/ ) >prototype; \
+ user=`id | sed s,uid=[0123456789]*\(,, | sed s,\).*,,`; \
+ group=`id | sed s,.*gid=[0123456789]*\(,, | sed s,\).*,,`; \
+ cat prototype | grep -v 'none / ' | \
+ sed s,$$user\ $$group,root\ sys,g > prototype.1; \
+ rm -f prototype.2; \
+ while read line; do \
+ echo "$${line}" | egrep '^d none' >/dev/null 2>&1; \
+ if [ $$? = 0 ]; then \
+ dir=`echo "$${line}" | awk '{ print $$3 }'`; \
+ if [ -d "$$dir" ]; then \
+ echo "d none $${dir} ? ? ?" >> prototype.2; \
+ else \
+ echo "$${line}" >> prototype.2; \
+ fi; \
+ else \
+ echo "$${line}" >> prototype.2; \
+ fi; \
+ done < prototype.1; \
+ rm -f prototype && rm prototype.1 && mv prototype.2 prototype; \
+ echo "d none /etc/rc0.d ? ? ?" >> prototype; \
+ echo "d none /etc/rc1.d ? ? ?" >> prototype; \
+ echo "d none /etc/rc3.d ? ? ?" >> prototype; \
+ echo "l none /etc/rc3.d/S99@install_name@=/etc/init.d/@install_name@" >> prototype; \
+ echo "l none /etc/rc0.d/K10@install_name@=/etc/init.d/@install_name@" >> prototype; \
+ echo "l none /etc/rc1.d/K10@install_name@=/etc/init.d/@install_name@" >> prototype; \
+ ARCH=`uname -p`; \
+ PSTAMP=`date '+%c%y%m%d%H%M%S'`; \
+ echo "PKG=@install_name@" > pkginfo; \
+ echo "NAME=file integrity check" >> pkginfo; \
+ echo "VERSION=$(VERSION)" >> pkginfo; \
+ echo "CATEGORY=system" >> pkginfo; \
+ echo "CLASSES=none" >> pkginfo; \
+ echo "VENDOR=http://la-samhna.de/samhain" >> pkginfo; \
+ echo "EMAIL=support@la-samhna.de" >> pkginfo; \
+ echo "ARCH=$$ARCH" >> pkginfo; \
+ echo "PSTAMP=$$PSTAMP" >> pkginfo; \
+ pkgmk -o; \
+ pkgtrans -s /var/spool/pkg /tmp/samhain-pkg-staging/@install_name@.pkg @install_name@; \
+ if test -f /tmp/samhain-pkg-staging/@install_name@.pkg; then \
+ echo; \
+ cp /tmp/samhain-pkg-staging/@install_name@.pkg $(PACKAGE)-$(VERSION).pkg; \
+ echo "Package $(PACKAGE)-$(VERSION).pkg is ready for installation"; \
+ echo "to install, use: pkgadd -n -d $(PACKAGE)-$(VERSION).pkg all"; \
+ echo; \
+ rm -rf /var/spool/pkg/@install_name@ /tmp/samhain-pkg-staging; \
+ else \
+ echo; \
+ echo "**************************************************************"; \
+ echo "Error ... cannot find /tmp/samhain-pkg-staging/@install_name@.pkg."; \
+ echo "Keeping /var/spool/pkg/@install_name@ /tmp/samhain-pkg-staging"; \
+ if test -d /var/spool/pkg; then \
+ echo "**************************************************************"; \
+ else \
+ echo "************** /var/spool/pkg is missing *********************"; \
+ fi; \
+ echo; \
+ exit 1; \
+ fi
+
+depot-prep: all
+ STAGE=/tmp/samhain-pkg-staging; \
+ mkdir $$STAGE; \
+ if test x"$$?" != x0; then \
+ echo "ERROR ... mkdir $$STAGE failed"; \
+ exit 1; \
+ fi; \
+ $(MAKE) DESTDIR=$$STAGE install; \
+ $(MAKE) DESTDIR=$$STAGE install-boot; \
+ cp hp_ux.psf $$STAGE; \
+ mkdir $$STAGE/sc; \
+ echo "#!/sbin/sh" > $$STAGE/sc/configure; \
+ echo "PATH=\$$SW_PATH; export PATH" >> $$STAGE/sc/configure; \
+ echo "chmod 555 /sbin/init.d/samhain; chown bin:bin /sbin/init.d/@install_name@; (cd /sbin; ln -f -s /sbin/init.d/@install_name@ rc2.d/S900@install_name@; ln -f -s /sbin/init.d/@install_name@ rc1.d/K100@install_name@; )" >> $$STAGE/sc/configure; \
+ chmod +x $$STAGE/sc/configure; \
+ echo "#!/sbin/sh" > $$STAGE/sc/unconfigure; \
+ echo "PATH=\$$SW_PATH; export PATH" >> $$STAGE/sc/unconfigure; \
+ echo "rm -f /sbin/rc2.d/S900@install_name@; rm -f /sbin/rc1.d/K100@install_name@" >> $$STAGE/sc/unconfigure; \
+ chmod +x $$STAGE/sc/unconfigure; \
+ echo "#!/sbin/sh" > $$STAGE/sc/preremove; \
+ echo "PATH=\$$SW_PATH; export PATH" >> $$STAGE/sc/preremove; \
+ echo "/sbin/init.d/@install_name@ stop" >> $$STAGE/sc/preremove; \
+ echo "exit 0" >> $$STAGE/sc/preremove; \
+ chmod +x $$STAGE/sc/preremove;
+
+depot: depot-prep
+ (cd /tmp/samhain-pkg-staging && /usr/sbin/swpackage -v -s ./hp_ux.psf -x media_type=tape @ $(PACKAGE)-$(VERSION).depot)
+ cp /tmp/samhain-pkg-staging/$(PACKAGE)-$(VERSION).depot .
+ rm -rf /tmp/samhain-pkg-staging
+
+depot-light: depot
+
+#---------------------------------------------------------------
+
+
+trustfile: $(srcsrc)/trustfile.c config.h
+ $(COMPILE) $(VFLAG) -DSH_IDENT=\"@myident@\" -DTRUST_MAIN -DSL_ALWAYS_TRUSTED=@mytrust@ -o trustfile $(srcsrc)/trustfile.c
+
+sh_MK.h: config.h
+ @echo "creating sh_MK.h"; \
+ echo "#ifndef SH_MK_H" > sh_MK.h; \
+ echo "#define SH_MK_H" >> sh_MK.h; \
+ $(top_srcdir)/c_bits.sh @my_key_1@ MKB >> sh_MK.h; \
+ $(top_srcdir)/c_bits.sh @my_key_2@ MKA >> sh_MK.h; \
+ $(top_srcdir)/c_bits.sh @my_key_3@ MKC >> sh_MK.h; \
+ $(top_srcdir)/c_bits.sh @my_key_4@ MKD >> sh_MK.h; \
+ echo "#endif" >> sh_MK.h
+
+
+sstrip: $(srcsrc)/sstrip.c Makefile
+ $(BUILD_CC) -I. -o sstrip $(srcsrc)/sstrip.c
+
+encode: $(srcsrc)/encode.c Makefile
+ $(BUILD_CC) -I. -o encode $(srcsrc)/encode.c
+
+config_xor.h: config.h encode
+ @echo 'encode $(XOR_CODE) config.h'; \
+ ./encode $(XOR_CODE) config.h; \
+ mv x_config.h config_xor.h
+
+
+$(OBJECTS): encode internal.h config_xor.h
+ @echo "./encode $(XOR_CODE) $(srcsrc)/`echo $@ |sed 's%\.o$$%%'`.c --> x_`echo $@ |sed 's%\.o$$%%'`.c"; \
+ ./encode $(XOR_CODE) $(srcsrc)/`echo $@ |sed 's%\.o$$%%'`.c; \
+ echo "$(COMPILE) $(VFLAG) -o `echo $@ |sed 's%.*/%%'` -c x_`echo $@ |sed 's%\.o$$%%'`.c"; \
+ $(COMPILE) $(VFLAG) -o `echo $@ |sed 's%.*/%%'` -c x_`echo $@ |sed 's%\.o$$%%'`.c && \
+ rm x_`echo $@ |sed 's%\.o$$%%'`.c
+
+sh_tiger_i.o: $(srcsrc)/$(TIGER_SRC) Makefile config_xor.h
+ @echo "$(COMPILE) $(VFLAG) -o sh_tiger_i.o -c $(srcsrc)/$(TIGER_SRC)";\
+ $(COMPILE) $(VFLAG) -o sh_tiger_i.o -c $(srcsrc)/$(TIGER_SRC);
+
+samhain_setpwd: encode config_xor.h $(srcsrc)/samhain_setpwd.c
+ @echo '$(COMPILE) -o samhain_setpwd $(srcsrc)/samhain_setpwd.c'; \
+ ./encode $(XOR_CODE) $(srcsrc)/samhain_setpwd.c; \
+ $(COMPILE) -o samhain_setpwd x_samhain_setpwd.c; \
+ rm x_samhain_setpwd.c
+
+samhain_stealth: encode config_xor.h $(srcsrc)/samhain_stealth.c
+ @echo '$(COMPILE) -o samhain_stealth $(srcsrc)/samhain_stealth.c'; \
+ ./encode $(XOR_CODE) $(srcsrc)/samhain_stealth.c; \
+ $(COMPILE) -o samhain_stealth x_samhain_stealth.c; \
+ rm x_samhain_stealth.c
+
+yulectl: encode config_xor.h $(srcsrc)/yulectl.c
+ @echo '$(COMPILE) -o yulectl $(srcsrc)/yulectl.c $(LIBS_SOCK)'; \
+ ./encode $(XOR_CODE) $(srcsrc)/yulectl.c; \
+ $(COMPILE) -o yulectl x_yulectl.c $(LIBS_SOCK); \
+ rm x_yulectl.c
+
+$(SAMHAIN): internal.h $(OBJECTS) sh_tiger_i.o
+ @-rm -f $(SAMHAIN)
+ @echo "$(LINK) sh_tiger_i.o $(OBJECTS) $(LIBS_TRY)"; \
+ $(LINK) sh_tiger_i.o $(OBJECTS) $(LIBS_TRY)
+
+
+CUTEST_SOURCES = $(srcsrc)/cutest_sh_tools.c \
+ $(srcsrc)/cutest_sh_utils.c \
+ $(srcsrc)/cutest_sh_unix.c \
+ $(srcsrc)/cutest_slib.c \
+ $(srcsrc)/cutest_zAVLTree.c \
+ $(srcsrc)/cutest_sh_hash.c \
+ $(srcsrc)/cutest_sh_tiger0.c
+
+CUTEST_OBJECTS = cutest_sh_tools.o \
+ cutest_sh_utils.o \
+ cutest_sh_unix.o \
+ cutest_slib.o \
+ cutest_zAVLTree.o \
+ cutest_sh_hash.o \
+ cutest_sh_tiger0.o
+
+$(CUTEST_OBJECTS): $(CUTEST_SOURCES) config_xor.h internal.h
+ @echo "./encode $(XOR_CODE) $(srcsrc)/`echo $@ |sed 's%\.o$$%%'`.c --> x_`echo $@ |sed 's%\.o$$%%'`.c"; \
+ ./encode $(XOR_CODE) $(srcsrc)/`echo $@ |sed 's%\.o$$%%'`.c; \
+ echo "$(COMPILE) $(VFLAG) -o `echo $@ |sed 's%.*/%%'` -c x_`echo $@ |sed 's%\.o$$%%'`.c"; \
+ $(COMPILE) $(VFLAG) -o `echo $@ |sed 's%.*/%%'` -c x_`echo $@ |sed 's%\.o$$%%'`.c; \
+ rm x_`echo $@ |sed 's%\.o$$%%'`.c
+
+
+cutest: $(SOURCES) $(CUTEST_SOURCES)
+ @$(MAKE) CUTEST='-DSH_CUTEST=1' intcutest
+
+$(srcsrc)/CuTestMain.c: $(SOURCES) $(CUTEST_SOURCES) $(srcsrc)/make-tests.sh
+ cd $(srcsrc)/ && ./make-tests.sh >CuTestMain.c;
+
+intcutest: internal.h $(OBJECTS) $(CUTEST_OBJECTS) sh_tiger_i.o $(srcsrc)/CuTestMain.c
+ @$(COMPILE) -o CuTestMain.o -c $(srcsrc)/CuTestMain.c; \
+ $(COMPILE) -o CuTest.o -c $(srcsrc)/CuTest.c; \
+ rm -f samhain.o; \
+ ./encode $(XOR_CODE) $(srcsrc)/samhain.c; \
+ $(COMPILE) $(VFLAG) -o samhain.o -c x_samhain.c; \
+ rm x_samhain.c; \
+ $(LINK) sh_tiger_i.o $(CUTEST_OBJECTS) CuTestMain.o CuTest.o $(OBJECTS) $(LIBS_TRY); \
+ test -f ./intcutest && mv ./intcutest ./cutest; \
+ ./cutest
+
+runcutest:
+ gdb ./cutest
+
+
+# For bignum
+internal.h: mkhdr
+ @sleep 1; \
+ ./mkhdr
+
+bignum.o: internal.h
+
+
+# If your compiler can't handle long identifiers (> 6 chars), move the `#' to
+# the other line.
+
+mkhdr: $(srcsrc)/mkhdr.c config.h
+ @echo "$(BUILD_CC) -I. -o mkhdr $(srcsrc)/mkhdr.c"; \
+ sleep 1; \
+ $(BUILD_CC) -I. -o mkhdr $(srcsrc)/mkhdr.c
+
+# $(COMPILE) -DBIG_SHORT_NAMES -o mkhdr $(srcdir)/mkhdr.c
+
+#----------------------------------------------------------
+#
+# EXE PACKER rules
+#
+#----------------------------------------------------------
+
+minilzo.o: $(srcsrc)/minilzo.c $(srcinc)/lzoconf.h $(srcinc)/minilzo.h config.h
+ @echo "$(COMPILE) -DMINILZO_HAVE_CONFIG_H -o minilzo.o -c $(srcsrc)/minilzo.c"; \
+ $(COMPILE) -DMINILZO_HAVE_CONFIG_H -o minilzo.o -c $(srcsrc)/minilzo.c
+
+exepack_mkdata: $(srcsrc)/exepack_mkdata.c $(srcinc)/lzoconf.h $(srcinc)/minilzo.h minilzo.o
+ @echo "$(COMPILE) -o exepack_mkdata.o -c $(srcsrc)/exepack_mkdata.c"; \
+ $(COMPILE) -o exepack_mkdata.o -c $(srcsrc)/exepack_mkdata.c; \
+ echo "$(LINK) exepack_mkdata.o minilzo.o"; \
+ $(LINK) exepack_mkdata.o minilzo.o
+
+#
+# prepare the data to be packed
+#
+exepack.data: $(SAMHAIN) exepack_mkdata sstrip
+ @echo "cp ./$(SAMHAIN) ./samhain.pk.data"; \
+ cp ./$(SAMHAIN) ./samhain.pk.data; \
+ echo "strip ./samhain.pk.data"; \
+ strip ./samhain.pk.data > /dev/null 2>&1 || echo "... is already stripped"; \
+ echo "./sstrip ./samhain.pk.data"; \
+ ./sstrip ./samhain.pk.data > /dev/null 2>&1 || echo "sstrip returned false"; \
+ echo "./exepack_mkdata ./samhain.pk.data ./exepack.data 0"; \
+ ./exepack_mkdata ./samhain.pk.data ./exepack.data 0; \
+ echo "rm -f ./samhain.pk.data"; \
+ rm -f ./samhain.pk.data;
+
+exepack: $(srcsrc)/exepack.c minilzo.o exepack.data
+ @echo "$(COMPILE) -o exepack.o -c $(srcsrc)/exepack.c"; \
+ $(COMPILE) -o exepack.o -c $(srcsrc)/exepack.c; \
+ echo "$(LINK) exepack.o minilzo.o"; \
+ $(LINK) exepack.o minilzo.o;
+
+#
+# this program fills the data section with the binary
+#
+exepack_fill: $(srcsrc)/exepack_fill.c minilzo.o exepack
+ @echo "$(COMPILE) -o exepack_fill.o -c $(srcsrc)/exepack_fill.c"; \
+ $(COMPILE) -o exepack_fill.o -c $(srcsrc)/exepack_fill.c; \
+ echo "$(LINK) exepack_fill.o minilzo.o"; \
+ $(LINK) exepack_fill.o minilzo.o
+
+samhain.pk: $(SAMHAIN) exepack exepack_fill sstrip
+ @echo "cp ./$(SAMHAIN) ./samhain.pk.data"; \
+ cp ./$(SAMHAIN) ./samhain.pk.data; \
+ echo "strip ./samhain.pk.data"; \
+ strip ./samhain.pk.data > /dev/null 2>&1 || echo "... is already stripped"; \
+ echo "./sstrip ./samhain.pk.data"; \
+ ./sstrip ./samhain.pk.data > /dev/null 2>&1 || echo "sstrip returned false"; \
+ test -f exepack.out && rm exepack.out; \
+ echo "./exepack_fill exepack samhain.pk.data exepack.out"; \
+ ./exepack_fill exepack samhain.pk.data exepack.out; \
+ chmod +x exepack.out; \
+ echo "strip exepack.out"; \
+ strip exepack.out > /dev/null 2>&1 || echo "... is already stripped"; \
+ ./sstrip exepack.out > /dev/null 2>&1 || echo "sstrip returned false"; \
+ echo "mv exepack.out samhain.pk"; \
+ rm -f samhain.pk; mv exepack.out samhain.pk
+
+samhain-packed: $(SAMHAIN) samhain_setpwd
+ @echo "samhain_setpwd samhain new $(CLIENTPASSWD)"; \
+ samhain_setpwd samhain new $(CLIENTPASSWD); \
+ echo "rm -f samhain; mv samhain.new samhain"; \
+ rm -f samhain; mv samhain.new samhain; \
+ $(MAKE) samhain.pk; \
+ echo "rm -f samhain; mv samhain.pk samhain"; \
+ rm -f samhain; mv samhain.pk samhain
+
+#----------------------------------------------------------
+#
+# DEPLOY rules
+#
+#----------------------------------------------------------
+
+uninstall-deploy:
+ rm -rf $(mydatadir)/profiles/source
+ rm -rf $(mydatadir)/profiles/archpkg
+ rm -rf $(mydatadir)/profiles/libexec
+ rm -rf $(mydatadir)/profiles/tmp
+ rm -rf $(mydatadir)/profiles/private
+ @if test -f $(sbindir)/deploy.sh; then \
+ old_deploy=`grep 'VERSION2' $(sbindir)/deploy.sh >/dev/null 2>&1 || echo old`; \
+ if test x"$$old_deploy" = xold; then \
+ echo "rm -f $(sbindir)/deploy2.sh"; \
+ rm -f $(sbindir)/deploy2.sh; \
+ else \
+ echo "rm -f $(sbindir)/deploy.sh"; \
+ rm -f $(sbindir)/deploy.sh; \
+ fi; \
+ fi
+
+EXECFILES= comCHECKSRC comDOWNLOAD comBUILD comCLEAN comINSTALL \
+ funcDIALOG funcEXE funcPRINT funcSETUP funcBUILD funcINSTALL \
+ funcDB comUNINSTALL \
+ preinstall postinstall initscript
+
+# $(mydatadir)/profiles/
+# |
+# |
+# |-- source -------------> (tarballs)
+# |
+# |-- configs ------------> (default configs)
+# |
+# |-- archpkg
+# | |
+# | |-- architecture -> (package, setup script)
+# |
+# |-- hosts
+# | |
+# | |-- hostname -----> (config)
+# |
+# |-- libexec ------------> (scripts)
+# |
+# |-- private ------------> (gpg key)
+# |
+# |-- tmp
+#
+install-deploy: deploy.sh samhain_stealth
+ @echo "Creating directory tree under $(mydatadir)/profiles/"; \
+ $(mkinstalldirs) $(sbindir); \
+ $(mkinstalldirs) $(mydatadir)/profiles/source; \
+ $(mkinstalldirs) $(mydatadir)/profiles/configs; \
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/debian_i386; \
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/gentoo_i386; \
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/redhat_i386; \
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/linux_i386; \
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/freebsd_i386;\
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/solaris; \
+ $(mkinstalldirs) $(mydatadir)/profiles/archpkg/aix; \
+ $(mkinstalldirs) $(mydatadir)/profiles/hosts; \
+ $(mkinstalldirs) $(mydatadir)/profiles/libexec; \
+ $(mkinstalldirs) $(mydatadir)/profiles/private; \
+ $(mkinstalldirs) $(mydatadir)/profiles/tmp; \
+ if test -f $(srcdir)/../$(PACKAGE)-$(VERSION).tar.gz.asc; then \
+ if test -f $(srcdir)/../$(PACKAGE)-$(VERSION).tar.gz; then \
+ echo "Installing source tarball"; \
+ $(INSTALL_DATA) $(srcdir)/../$(PACKAGE)-$(VERSION).tar.gz.asc \
+ $(mydatadir)/profiles/source/$(PACKAGE)-$(VERSION).tar.gz.asc; \
+ $(INSTALL_DATA) $(srcdir)/../$(PACKAGE)-$(VERSION).tar.gz \
+ $(mydatadir)/profiles/source/$(PACKAGE)-$(VERSION).tar.gz; \
+ fi; \
+ fi; \
+ echo "Installing default configs"; \
+ test -f $(mydatadir)/profiles/configs/freebsd_i386.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.freebsd \
+ $(mydatadir)/profiles/configs/freebsd_i386.samhainrc; \
+ test -f $(mydatadir)/profiles/configs/debian_i386.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.linux \
+ $(mydatadir)/profiles/configs/debian_i386.samhainrc; \
+ test -f $(mydatadir)/profiles/configs/gentoo_i386.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.linux \
+ $(mydatadir)/profiles/configs/gentoo_i386.samhainrc; \
+ test -f $(mydatadir)/profiles/configs/redhat_i386.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.linux \
+ $(mydatadir)/profiles/configs/redhat_i386.samhainrc; \
+ test -f $(mydatadir)/profiles/configs/linux_i386.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.linux \
+ $(mydatadir)/profiles/configs/linux_i386.samhainrc; \
+ test -f $(mydatadir)/profiles/configs/solaris.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.solaris \
+ $(mydatadir)/profiles/configs/solaris.samhainrc; \
+ test -f $(mydatadir)/profiles/configs/aix.samhainrc || \
+ $(INSTALL_DATA) $(srcdir)/samhainrc.aix5.2.0 \
+ $(mydatadir)/profiles/configs/aix.samhainrc; \
+ if test -f $(mydatadir)/profiles/configs/generic.configure; then \
+ :; \
+ else \
+ SH_FQDN_SYSTEM=`uname -n`; \
+ SH_FQDN_DOMAIN=`grep -i domain /etc/resolv.conf |grep -v "\#" |awk '{print $$2}' |head -1`; \
+ if test -n "$${SH_FQDN_SYSTEM}" -a -n "$${SH_FQDN_DOMAIN}"; then \
+ sh_thishost="$${SH_FQDN_SYSTEM}.$${SH_FQDN_DOMAIN}"; \
+ else \
+ sh_thishost="FQDN_MISSING"; \
+ fi; \
+ outfile=$(mydatadir)/profiles/configs/generic.configure; \
+ echo "'--enable-network=client'" > $$outfile; \
+ echo "'--with-logserver=$${sh_thishost}'" >> $$outfile; \
+ echo "'--with-data-file=REQ_FROM_SERVER/var/lib/samhain/samhain_file'" >> $$outfile; \
+ echo "'--with-config-file=REQ_FROM_SERVER/etc/samhainrc'" >> $$outfile; \
+ echo "'--enable-base=@mykeybase@'" >> $$outfile; \
+ fi; \
+ $(INSTALL_SHELL) $(srcdir)/mkinstalldirs \
+ $(mydatadir)/profiles/libexec; \
+ $(INSTALL_SHELL) $(srcdir)/install-sh \
+ $(mydatadir)/profiles/libexec; \
+ for ff in $(EXECFILES); do \
+ test -f $(srcdir)/dsys/$$ff && $(INSTALL_SHELL) $(srcdir)/dsys/$$ff \
+ $(mydatadir)/profiles/libexec; \
+ done; \
+ $(INSTALL_SHELL) samhain_stealth $(mydatadir)/profiles/libexec; \
+ test -f $(srcdir)/dsys/0F571F6C.asc && $(INSTALL_DATA) $(srcdir)/dsys/0F571F6C.asc \
+ $(mydatadir)/profiles/private; \
+ convert +compress $(srcdir)/stealth_template.jpg stealth_template.ps >/dev/null || \
+ { echo "*"; echo "* 'convert' not found or not working, not installing"; echo "* $(mydatadir)/profiles/private/stealth_template.ps"; echo "* (only required for installing packages built with --enable-stealth)"; echo "*"; }; \
+ if test -f stealth_template.ps; then \
+ if test -f $(mydatadir)/profiles/private/stealth_template.ps; then \
+ :; \
+ else \
+ $(INSTALL_DATA) stealth_template.ps $(mydatadir)/profiles/private; \
+ fi; \
+ fi; \
+ if test -f $(sbindir)/deploy.sh; then \
+ old_deploy=`grep 'VERSION2' $(sbindir)/deploy.sh >/dev/null 2>&1 || echo old`; \
+ if test x"$$old_deploy" = xold; then \
+ echo "*"; echo "* Version 1 of deploy.sh found"; echo "*"; \
+ echo "* Installing $(sbindir)/deploy2.sh"; echo "*"; \
+ $(INSTALL_SHELL) deploy.sh $(sbindir)/deploy2.sh; \
+ else \
+ echo "Installing $(sbindir)/deploy.sh"; \
+ $(INSTALL_SHELL) deploy.sh $(sbindir)/deploy.sh; \
+ fi; \
+ else \
+ echo "Installing $(sbindir)/deploy.sh"; \
+ $(INSTALL_SHELL) deploy.sh $(sbindir)/deploy.sh; \
+ fi
+
+
+#----------------------------------------------------------
+#
+# DISTRIBUTION rules
+#
+#----------------------------------------------------------
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+
+#
+# 1) make distribution tarfile
+# 2) unpack the tarfile into distdir
+# 3) create build and install directories
+# 4) do the build in the build dir, with sources from distdir
+# 5) check (there are no subdirs, thus does nothing)
+# 6) install
+# 7) installcheck (equal to check, does nothing)
+#
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) \
+ && $(MAKE) install
+ -rm -rf $(distdir)
+ -rm -f $(distdir).tar.gz.asc
+ @gpg -a --detach-sign $(distdir).tar.gz; \
+ $(TAR) chof $(distdir).tar $(distdir).tar.gz $(distdir).tar.gz.asc; \
+ rm -f $(distdir).tar.gz; \
+ rm -f $(distdir).tar.gz.asc; \
+ gzip --best $(distdir).tar
+ mv $(distdir).tar.gz $(PACKAGE)_signed-$(VERSION).tar.gz
+ @echo "========================"; \
+ echo "$(PACKAGE)_signed-$(VERSION).tar.gz is ready for distribution"; \
+ echo "========================"
+
+#
+# create a tarfile for the distibution
+#
+distrpm: distdirrpm
+ -chmod -R a+r $(distdir)
+ -rm -rf $(distdir).tar.gz
+ -rm -rf $(distdir).tar
+ $(TAR) chof $(distdir).tar $(distdir)
+ gzip -c --best $(distdir).tar > $(distdir).tar.gz
+ -rm -rf $(distdir)
+
+dist: distdir
+ -chmod -R a+r $(distdir)
+ -rm -rf $(distdir).tar.gz
+ -rm -rf $(distdir).tar
+ $(TAR) chof $(distdir).tar $(distdir)
+ gzip -c --best $(distdir).tar > $(distdir).tar.gz
+ -rm -rf $(distdir)
+
+#
+# create a tarfile for the distibution
+#
+dist-sign: distdir
+ -rm -f $(distdir)/scripts/samhain.ebuild
+ -rm -f $(distdir)/scripts/samhain.ebuild-light
+ -chmod -R a+r $(distdir)
+ -rm -rf $(distdir).tar.gz
+ -rm -rf $(distdir).tar
+ $(TAR) chof $(distdir).tar $(distdir)
+ gzip --best $(distdir).tar
+ -rm -rf $(distdir)
+ -rm -f $(distdir).tar.gz.asc
+ gpg -a --detach-sign $(distdir).tar.gz
+ $(TAR) chof $(distdir).tar $(distdir).tar.gz $(distdir).tar.gz.asc
+ -rm -f $(distdir).tar.gz
+ -rm -f $(distdir).tar.gz.asc
+ gzip --best $(distdir).tar
+ mv $(distdir).tar.gz $(PACKAGE)_signed-$(VERSION).tar.gz
+
+
+#
+# same as dist
+#
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+
+#
+# create distribution directory and copy files into it
+#
+INITFILES=samhain.startIRIX samhain.startFreeBSD samhain.startSolaris \
+samhain.startLSB samhain.startGentoo samhain.startLinux samhain.startHPUX \
+samhain.startIRIX samhain.startMACOSX
+
+SCRIPTFILES=redhat_i386.client.spec check_samhain.pl samhainadmin.pl \
+yuleadmin.pl samhain.ebuild samhain.ebuild-light samhain.spec
+
+distdir: distfilecheck
+ -rm -f $(top_srcdir)/init/*~
+ -rm -f $(top_srcdir)/sql_init/*~
+ -rm -f $(top_srcdir)/dsys/*~
+ -rm -f $(top_srcdir)/docs/*~
+ -rm -f $(top_srcdir)/include/*~
+ -rm -f $(top_srcdir)/src/*~
+ -rm -f $(top_srcdir)/test/*~
+ -rm -f $(top_srcdir)/scripts/*~
+ (cd $(top_srcdir)/init && rm -f $(INITFILES))
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ cp scripts/samhain.spec $(distdir)/samhain.spec; \
+ (cd $(top_srcdir)/scripts && rm -f $(SCRIPTFILES))
+ @for file in $(DISTFILES); do \
+ d=$(top_srcdir); \
+ if test -f $$d/$$file || test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ fi; \
+ done; \
+ rm -f $(distdir)/scripts/*.spec
+
+#
+# as distdir, but don't copy spec file from scripts
+#
+distdirrpm: distfilecheck
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ @if test -f ./samhain.spec; then \
+ :; \
+ else \
+ echo "Error: ./samhain.spec not found, please run configure"; \
+ exit 1; \
+ fi
+ @cp -p samhain.spec $(distdir)/samhain.spec; \
+ for file in $(DISTFILES); do \
+ d=$(top_srcdir); \
+ if test -f $$d/$$file || test -d $$d/$$file; then \
+ if test x"$$file" = "xsamhain.spec"; then \
+ :; \
+ else \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ fi; \
+ fi; \
+ done; \
+ rm -f $(distdir)/scripts/*.spec
+
+
+distfilecheck: $(top_srcdir)/config.h.in $(top_srcdir)/depend.sum
+ @for file in $(DISTFILES); do \
+ d=$(top_srcdir); \
+ if test -f $$d/$$file || test -d $$d/$$file; then \
+ : \
+ else \
+ echo "File not found: $$d/$$file"; \
+ fi; \
+ done
+ @for file in $(SOURCES); do \
+ if test -f $$file; then \
+ : \
+ else \
+ echo "File not found: $$file"; \
+ fi; \
+ done
+
+
+# DO NOT DELETE THIS LINE
+
+
+samhain.o: $(srcsrc)/samhain.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_getopt.h $(srcinc)/sh_readconf.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_restrict.h $(srcinc)/sh_nmail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_mem.h $(srcinc)/sh_xfer.h $(srcinc)/sh_tools.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h $(srcinc)/sh_sem.h sh_MK.h $(srcinc)/sh_schedule.h
+sh_unix.o: $(srcsrc)/sh_unix.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_hash.h $(srcinc)/sh_tools.h $(srcinc)/sh_restrict.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_tiger.h $(srcinc)/sh_prelink.h $(srcinc)/sh_pthread.h $(srcinc)/sh_sem.h $(srcinc)/sh_static.h $(srcinc)/sh_prelude.h $(srcinc)/zAVLTree.h $(srcinc)/sh_ignore.h
+sh_utils.o: $(srcsrc)/sh_utils.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_entropy.h $(srcinc)/sh_pthread.h
+sh_error.o: $(srcsrc)/sh_error.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_database.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_nmail.h $(srcinc)/sh_xfer.h $(srcinc)/sh_prelude.h $(srcinc)/sh_pthread.h $(srcinc)/sh_tools.h $(srcinc)/sh_extern.h $(srcinc)/sh_checksum.h
+sh_files.o: $(srcsrc)/sh_files.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_tiger.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_inotify.h $(srcinc)/zAVLTree.h $(srcinc)/sh_dbIO.h $(srcinc)/CuTest.h
+sh_getopt.o: $(srcsrc)/sh_getopt.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_getopt.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_mail.h $(srcinc)/sh_xfer.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_dbCheck.h $(srcinc)/sh_dbCreate.h $(srcinc)/sh_sem.h $(srcinc)/sh_extern.h
+sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_xfer.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_ignore.h $(srcinc)/sh_database.h $(srcinc)/sh_mail.h $(srcinc)/sh_modules.h $(srcinc)/sh_nmail.h $(srcinc)/sh_prelink.h $(srcinc)/sh_prelude.h $(srcinc)/sh_tiger.h $(srcinc)/sh_tools.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h $(srcinc)/sh_socket.h
+sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h $(srcinc)/sh_checksum.h
+sh_tiger1.o: $(srcsrc)/sh_tiger1.c Makefile config_xor.h
+sh_tiger2.o: $(srcsrc)/sh_tiger2.c Makefile config_xor.h
+sh_tiger1_64.o: $(srcsrc)/sh_tiger1_64.c Makefile config_xor.h
+sh_tiger2_64.o: $(srcsrc)/sh_tiger2_64.c Makefile config_xor.h
+sh_hash.o: $(srcsrc)/sh_hash.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_hash.h $(srcinc)/sh_error.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_ignore.h $(srcinc)/sh_pthread.h $(srcinc)/sh_xfer.h $(srcinc)/sh_hash.h $(srcinc)/sh_checksum.h
+sh_mail.o: $(srcsrc)/sh_mail.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_mail.h $(srcinc)/sh_utils.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_pthread.h $(srcinc)/sh_filter.h $(srcinc)/sh_mail_int.h $(srcinc)/sh_nmail.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_static.h $(srcinc)/sh_tools.h
+sh_mem.o: $(srcsrc)/sh_mem.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_pthread.h
+sh_entropy.o: $(srcsrc)/sh_entropy.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_calls.h $(srcinc)/sh_pthread.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/CuTest.h
+sh_forward.o: $(srcsrc)/sh_forward.c Makefile config_xor.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_forward.h $(srcinc)/sh_srp.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_entropy.h $(srcinc)/sh_html.h $(srcinc)/sh_nmail.h $(srcinc)/sh_socket.h $(srcinc)/sh_static.h $(srcinc)/rijndael-api-fst.h $(srcinc)/sh_readconf.h $(srcinc)/zAVLTree.h $(srcinc)/sh_extern.h
+sh_modules.o: $(srcsrc)/sh_modules.c Makefile config_xor.h $(srcinc)/sh_modules.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utmp.h $(srcinc)/sh_mounts.h $(srcinc)/sh_userfiles.h $(srcinc)/sh_suidchk.h $(srcinc)/sh_processcheck.h $(srcinc)/sh_portcheck.h $(srcinc)/sh_logmon.h $(srcinc)/sh_registry.h $(srcinc)/sh_fInotify.h
+sh_utmp.o: $(srcsrc)/sh_utmp.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_utmp.h $(srcinc)/sh_pthread.h $(srcinc)/sh_inotify.h
+sh_kern.o: $(srcsrc)/sh_kern.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_kern.h sh_ks_xor.h $(srcinc)/sh_unix.h $(srcinc)/sh_hash.h
+sh_suidchk.o: $(srcsrc)/sh_suidchk.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_suidchk.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_schedule.h $(srcinc)/sh_calls.h $(srcinc)/zAVLTree.h
+sh_srp.o: $(srcsrc)/sh_srp.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_mem.h $(srcinc)/sh_utils.h $(srcinc)/sh_srp.h $(srcinc)/bignum.h $(srcinc)/CuTest.h
+sh_fifo.o: $(srcsrc)/sh_fifo.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_fifo.h $(srcinc)/CuTest.h
+sh_tools.o: $(srcsrc)/sh_tools.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error.h $(srcinc)/sh_tools.h $(srcinc)/sh_utils.h $(srcinc)/sh_tiger.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_ipvx.h $(srcinc)/rijndael-api-fst.h $(srcinc)/rijndael-api-fst.h
+sh_html.o: $(srcsrc)/sh_html.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_xfer.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_html.h $(srcinc)/zAVLTree.h
+sh_gpg.o: $(srcsrc)/sh_gpg.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_tiger.h $(srcinc)/sh_static.h $(srcinc)/sh_gpg.h
+sh_cat.o: $(srcsrc)/sh_cat.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_cat.h
+sh_calls.o: $(srcsrc)/sh_calls.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_calls.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_sub.h $(srcinc)/sh_utils.h
+sh_extern.o: $(srcsrc)/sh_extern.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_extern.h $(srcinc)/sh_calls.h $(srcinc)/sh_filter.h $(srcinc)/sh_static.h
+sh_database.o: $(srcsrc)/sh_database.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h
+sh_err_log.o: $(srcsrc)/sh_err_log.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_tiger.h
+sh_err_console.o: $(srcsrc)/sh_err_console.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_sem.h
+sh_err_syslog.o: $(srcsrc)/sh_err_syslog.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h
+sh_schedule.o: $(srcsrc)/sh_schedule.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_schedule.h
+bignum.o: $(srcsrc)/bignum.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/bignum.h
+mkhdr.o: $(srcsrc)/mkhdr.c Makefile config.h
+samhain_setpwd.o: $(srcsrc)/samhain_setpwd.c Makefile config_xor.h
+samhain_stealth.o: $(srcsrc)/samhain_stealth.c Makefile config_xor.h
+encode.o: $(srcsrc)/encode.c Makefile
+sstrip.o: $(srcsrc)/sstrip.c Makefile config.h
+trustfile.o: $(srcsrc)/trustfile.c Makefile config_xor.h $(srcinc)/sh_calls.h $(srcinc)/slib.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h
+exepack.o: $(srcsrc)/exepack.c Makefile config.h $(srcinc)/minilzo.h $(srcinc)/exepack.data
+exepack_fill.o: $(srcsrc)/exepack_fill.c Makefile config.h config.h $(srcinc)/minilzo.h
+exepack_mkdata.o: $(srcsrc)/exepack_mkdata.c Makefile config.h $(srcinc)/minilzo.h
+minilzo.o: $(srcsrc)/minilzo.c Makefile $(srcinc)/minilzo.h
+slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h $(srcinc)/sh_mem.h
+rijndael-alg-fst.o: $(srcsrc)/rijndael-alg-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h
+rijndael-api-fst.o: $(srcsrc)/rijndael-api-fst.c Makefile config_xor.h $(srcinc)/rijndael-api-fst.h
+zAVLTree.o: $(srcsrc)/zAVLTree.c Makefile $(srcinc)/zAVLTree.h
+sh_socket.o: $(srcsrc)/sh_socket.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_socket.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_calls.h $(srcinc)/sh_guid.h $(srcinc)/sh_fifo.h $(srcinc)/sh_utils.h $(srcinc)/sh_utils.h $(srcinc)/zAVLTree.h $(srcinc)/sh_html.h $(srcinc)/sh_tools.h $(srcinc)/CuTest.h
+sh_ignore.o: $(srcsrc)/sh_ignore.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error.h $(srcinc)/CuTest.h
+yulectl.o: $(srcsrc)/yulectl.c Makefile config_xor.h
+sh_mounts.o: $(srcsrc)/sh_mounts.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_mounts.h
+sh_userfiles.o: $(srcsrc)/sh_userfiles.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_modules.h $(srcinc)/sh_userfiles.h $(srcinc)/sh_utils.h $(srcinc)/sh_schedule.h $(srcinc)/sh_error.h $(srcinc)/sh_hash.h $(srcinc)/sh_files.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h
+sh_prelude.o: $(srcsrc)/sh_prelude.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_error_min.h $(srcinc)/sh_prelude.h $(srcinc)/sh_static.h
+kern_head.o: $(srcsrc)/kern_head.c Makefile config.h $(srcinc)/kern_head.h $(srcinc)/kern_head.h
+sh_prelink.o: $(srcsrc)/sh_prelink.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_extern.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h
+sh_static.o: $(srcsrc)/sh_static.c Makefile config_xor.h $(srcinc)/sh_pthread.h
+sh_async.o: $(srcsrc)/sh_async.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h
+sh_processcheck.o: $(srcsrc)/sh_processcheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_modules.h $(srcinc)/sh_processcheck.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_calls.h $(srcinc)/sh_pthread.h $(srcinc)/CuTest.h
+sh_portcheck.o: $(srcsrc)/sh_portcheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_mem.h $(srcinc)/sh_calls.h $(srcinc)/sh_utils.h $(srcinc)/sh_modules.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_ipvx.h $(srcinc)/CuTest.h
+sh_pthread.o: $(srcsrc)/sh_pthread.c Makefile config_xor.h $(srcinc)/sh_pthread.h $(srcinc)/sh_calls.h $(srcinc)/sh_modules.h
+sh_string.o: $(srcsrc)/sh_string.c Makefile config_xor.h $(srcinc)/sh_string.h $(srcinc)/sh_mem.h $(srcinc)/CuTest.h
+dnmalloc.o: $(srcsrc)/dnmalloc.c Makefile config.h
+t-test1.o: $(srcsrc)/t-test1.c Makefile config.h $(srcinc)/malloc.h
+sh_port2proc.o: $(srcsrc)/sh_port2proc.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error_min.h $(srcinc)/sh_pthread.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h
+sh_log_parse_syslog.o: $(srcsrc)/sh_log_parse_syslog.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h
+sh_log_parse_pacct.o: $(srcsrc)/sh_log_parse_pacct.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h
+sh_log_parse_apache.o: $(srcsrc)/sh_log_parse_apache.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h
+sh_log_evalrule.o: $(srcsrc)/sh_log_evalrule.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h $(srcinc)/sh_log_correlate.h $(srcinc)/sh_log_mark.h $(srcinc)/sh_log_repeat.h $(srcinc)/zAVLTree.h
+sh_log_check.o: $(srcsrc)/sh_log_check.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h $(srcinc)/sh_log_correlate.h $(srcinc)/sh_log_mark.h $(srcinc)/sh_log_repeat.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h
+sh_log_parse_samba.o: $(srcsrc)/sh_log_parse_samba.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_string.h
+sh_nmail.o: $(srcsrc)/sh_nmail.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_mem.h $(srcinc)/sh_mail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_string.h $(srcinc)/sh_utils.h $(srcinc)/sh_fifo.h $(srcinc)/sh_filter.h $(srcinc)/sh_mail_int.h $(srcinc)/zAVLTree.h
+sh_filter.o: $(srcsrc)/sh_filter.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_filter.h
+sh_inotify.o: $(srcsrc)/sh_inotify.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_calls.h $(srcinc)/sh_inotify.h $(srcinc)/sh_mem.h $(srcinc)/sh_utils.h $(srcinc)/slib.h $(srcinc)/zAVLTree.h $(srcinc)/sh_calls.h $(srcinc)/sh_inotify.h $(srcinc)/CuTest.h
+sh_log_correlate.o: $(srcsrc)/sh_log_correlate.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h
+sh_log_mark.o: $(srcsrc)/sh_log_mark.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_mem.h $(srcinc)/sh_string.h $(srcinc)/sh_error_min.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h $(srcinc)/zAVLTree.h
+sh_log_repeat.o: $(srcsrc)/sh_log_repeat.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h
+sh_log_parse_generic.o: $(srcsrc)/sh_log_parse_generic.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_log_check.h $(srcinc)/sh_string.h
+sh_login_track.o: $(srcsrc)/sh_login_track.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_string.h $(srcinc)/sh_tools.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_error_min.h $(srcinc)/CuTest.h $(srcinc)/CuTest.h
+sh_audit.o: $(srcsrc)/sh_audit.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_utils.h
+sh_registry.o: $(srcsrc)/sh_registry.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_modules.h $(srcinc)/sh_hash.h $(srcinc)/sh_tiger.h
+sh_ipvx.o: $(srcsrc)/sh_ipvx.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h $(srcinc)/CuTest.h
+sh_restrict.o: $(srcsrc)/sh_restrict.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_string.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h $(srcinc)/CuTest.h
+sh_filetype.o: $(srcsrc)/sh_filetype.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_utils.h
+sh_sub.o: $(srcsrc)/sh_sub.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h
+sh_fInotify.o: $(srcsrc)/sh_fInotify.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_modules.h $(srcinc)/sh_pthread.h $(srcinc)/sh_inotify.h $(srcinc)/sh_unix.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_files.h $(srcinc)/sh_ignore.h
+sh_checksum.o: $(srcsrc)/sh_checksum.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_checksum.h $(srcinc)/sh_utils.h $(srcinc)/CuTest.h
+sh_guid.o: $(srcsrc)/sh_guid.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/CuTest.h
+sh_dbIO.o: $(srcsrc)/sh_dbIO.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_gpg.h $(srcinc)/sh_tiger.h $(srcinc)/sh_xfer.h $(srcinc)/sh_pthread.h $(srcinc)/sh_socket.h $(srcinc)/sh_files.h $(srcinc)/zAVLTree.h
+sh_dbCheck.o: $(srcsrc)/sh_dbCheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_hash.h $(srcinc)/sh_files.h $(srcinc)/sh_tiger.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_pthread.h
+sh_dbCreate.o: $(srcsrc)/sh_dbCreate.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_hash.h $(srcinc)/sh_files.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_pthread.h $(srcinc)/sh_guid.h
+sh_xfer_client.o: $(srcsrc)/sh_xfer_client.c Makefile config_xor.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_xfer.h $(srcinc)/sh_srp.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_entropy.h $(srcinc)/sh_html.h $(srcinc)/sh_nmail.h $(srcinc)/sh_socket.h $(srcinc)/sh_static.h $(srcinc)/rijndael-api-fst.h
+sh_xfer_server.o: $(srcsrc)/sh_xfer_server.c Makefile config_xor.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_xfer.h $(srcinc)/sh_srp.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_entropy.h $(srcinc)/sh_html.h $(srcinc)/sh_nmail.h $(srcinc)/sh_socket.h $(srcinc)/sh_static.h $(srcinc)/sh_guid.h $(srcinc)/rijndael-api-fst.h $(srcinc)/sh_readconf.h $(srcinc)/zAVLTree.h $(srcinc)/sh_extern.h
+sh_xfer_syslog.o: $(srcsrc)/sh_xfer_syslog.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_tools.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h
+sh_xload_client.o: $(srcsrc)/sh_xload_client.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_fifo.h $(srcinc)/sh_guid.h
+sh_sem.o: $(srcsrc)/sh_sem.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_sem.h $(srcinc)/sh_error_min.h
diff --git a/README b/README
new file mode 100644
index 0000000..a512389
--- /dev/null
+++ b/README
@@ -0,0 +1,497 @@
+
+CONTENT OF THIS DOCUMENT
+------------------------
+
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ +++ +++
+ +++ NOTE: The distribution package contains a much more detailed MANUAL +++
+ +++ +++
+ +++ ---- See the docs/ subdirectory ---- +++
+ +++ +++
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ - INSTALL basic install procedure
+
+ - PGP SIGNATURES signing database and config file
+
+ - CLIENT/SERVER how to install and use with client/server mode
+ for distributed host monitoring
+
+ - STEALTH how to install and use with stealth mode enabled
+
+ - USAGE some usage examples
+
+ - CAVEATS what the name says
+
+ - START AT BOOT TIME how to start the daemon during the boot sequence
+
+ - CONFIGURE OPTIONS overview of supported options, and defaults
+
+ - TESTING test suite (also useful to see EXAMPLES)
+
+
+
+
+INSTALL:
+-------
+
+ Unpack the source with:
+
+ gunzip -c samhain-current.tar.gz | tar xvf -
+
+ This will drop two files in your current directory:
+
+ samhain-{version}.tar.gz
+ samhain-{version}.tar.gz.asc
+
+ To check authenticity and integrity of the source code, verify
+ the PGP signature on samhain-{version}.tar.gz
+ (public PGP key for Rainer Wichmann at http://wwwkeys.pgp.net/):
+
+ gpg --verify samhain-{version}.tar.gz.asc samhain-{version}.tar.gz
+
+ Then unpack samhain-{version}.tar.gz:
+
+ gunzip -c samhain-{version}.tar.gz | tar xvf -
+ cd samhain-{version}
+
+ If you have an incarnation of 'dialog' (xdialog, dialog, lxdialog)
+ installed, you can use the GUI install tool:
+
+ ./Install.sh
+
+ Otherwise use the commands:
+
+ ./configure [options]
+ make
+ su root
+ make install
+
+ At least the following executable will be built:
+
+ +++ samhain +++ the monitoring agent, without any
+ client/server support (i.e. local use only)
+
+ Additional executables will be built if you compile in client/server
+ and/or stealth mode (see below).
+
+ The 'make install' target will strip the executable(s), i.e.
+ discard symbols.
+
+ PATHS:
+ -----
+ For configuring the install paths/locations,
+ see the MANUAL.
+
+
+ WARNING:
+ -------
+ Some versions of gcc have a bug that generates incorrect
+ code if strength reducing is enabled.
+ If you modify the compiler flags, always use the -fno-strength-reduce
+ option with gcc, unless you are sure that your compiler does not
+ suffer from the problem (see README.gcc_bug).
+ Also, some gcc versions generate incorrect code unless the
+ -fno-omit-frame-pointer option is used.
+ The -fno-strength-reduce and the -fno-omit-frame-pointer options are
+ enabled by default by the 'configure' script.
+
+PGP SIGNATURES:
+--------------
+ By default, samhain will report on the checksums of the database
+ and configuration files on startup.
+
+ You can always (clear)sign the database (once initialized)
+ with GnuPG, as well as the configuration file
+ (recommended: gpg -a --clearsign --not-dash-escaped FILE).
+
+ However, to have samhain check these signatures, rather than ignoring
+ them, you need GnuPG and you must compile samhain with the option
+
+ ./configure --with-gpg=PATH
+
+ where PATH is the path to the gpg/pgp binary.
+
+ Samhain will invoke gpg only after checking that
+ only trusted users (by default: root and the effective user)
+ have write access to any element in the path.
+
+ The public key for verification must be in the keyring of the
+ effective user (usually root)
+
+ For more security, it is possible to compile in the checksum
+ of the GnuPG executable, and/or the key fingerprint. See
+ the MANUAL for more details.
+
+ The public key will be searched in the gpg home directory
+ (~/.gnupg/) of the effective user (usually root).
+ The key identification and fingerprint will be reported.
+
+CLIENT/SERVER:
+-------------
+
+ samhain supports logging to a central server via TCP/IP.
+ To enable this option, use the ./configure option
+
+ ./configure --enable-network=client|server [more options]
+
+ NOTE: client and server are __distict__ applications, and must be
+ built seperately. By default, installation names and paths are
+ different. Do not blame us if you abuse './configure' options to
+ cause name clashes, if you install both on the same host.
+
+ The following executables are built:
+
+ +++ samhain (client) +++ the monitoring agent,
+ with client code included
+ if --enable-network=client
+
+ +++ yule (server) +++ the log server (no monitoring, just report
+ collecting !!!)
+ if --enable-network=server
+
+ +++ samhain_setpwd +++ a utility program to set the password of
+ a monitoring agent (see man page samhain.8).
+ Use it without options to get help.
+
+
+ To set up a monitoring agent, do the following:
+
+ -- select a (16-digit hexadecimal) password. To generate
+ a random password, you can use:
+
+ ./yule -G
+
+ -- use 'samhain_setpwd samhain <suffix> <password>'
+ to generate an agent 'samhain.suffix' with the selected password
+ (you can rename the agent afterwards, of course)
+
+ -- use 'yule -P password' to compute an entry to register the agent
+
+ -- in the servers's configuration file, insert the computed entry
+ (replace HOSTNAME with the host, on which the agent will run)
+ in the section called [Clients]
+
+ By default, client/server authentication
+ is done with the SRP (Secure Remote Password) protocol.
+
+ It is also possible to store configuration and database files
+ on the server. See the manual for details.
+
+STEALTH:
+-------
+
+ samhain supports a 'stealth' mode of operation, meaning that
+ the program can be run without any obvious trace of its presence
+ on disk. The supplied facilities are more sophisticated than
+ just running the program under a different name,
+ and might thwart efforts using 'standard' Unix commands,
+ but they will not resist a search using dedicated utilities.
+ To enable this mode, use the ./configure option
+
+ ./configure --enable-stealth=XOR_VAL [more options]
+
+ XOR_VAL must be a decimal number in the range 0, 128..255
+ (using 0 will have no effect).
+
+ The runtime executable will contain no printable strings revealing
+ its nature or purpose (strings are xor'ed with XOR_VAL at compile
+ time, and decoded at runtime).
+
+ The configuration file is expected to be
+ a postscript file with _uncompressed_ image data, wherein
+ the configuration data are hidden by steganography.
+ To create a suitable image file from an existing image,
+ you may use e.g. the ImageMagick program 'convert', such as:
+
+ convert +compress ima.jpg ima.ps
+
+ The following additional executable will be built:
+
+ +++ samhain_stealth +++ steganography utility program to hide/extract
+ the configuration file data in/from a
+ postscript file with
+ _uncompressed_ image data.
+ Use it without options to get help.
+
+ Database and log file entries are xor'ed with XOR_VAL to 'mask'
+ printable strings as binary data. No steganography is supported
+ for them, as this would require image files of unreasonable large
+ size.
+ However, if the database/log file is an existing image (say, a .jpg
+ file), the data will be appended to the end of the image data.
+ The image will display normally, and on examination of the file,
+ the add-on data will look like binary (image) data at first sight.
+ The built-in utility to verify and print log file entries
+ will handle this situation transparently.
+
+ To re-name samhain to something unsuspicious, use the configure option
+
+ ./configure --enable-install-name=NAME
+
+ 'make install' will then re-name samhain upon installation. Also,
+ database, log file, and pid file will have 'samhain' replaced by
+ NAME.
+
+
+USAGE EXAMPLES:
+--------------
+
+ Review the default configuration file that comes with the
+ source distribution. Read the man page (samhain.8).
+
+ initialize database: samhain -t init
+
+ check files: samhain -t check
+
+ run as daemon: samhain -t check -D
+
+ report to log server: samhain -t check -D -e warn
+
+ start the log server: yule -S
+
+
+CAVEATS:
+-------
+ Permissions:
+ -----------
+ samhain needs root permissions to check some system files.
+ The log server does not require root permissions, unless
+ you use a privileged port (port number below 1024).
+ If you use --enable-udp to listen on the syslog socket, you need
+ to start the log server with root permissions (it will drop them
+ after binding to the port).
+
+ Trust:
+ -----
+ samhain checks the path to critical files (database, configuration)
+ for write access by untrusted users. By default, only root and
+ the effective user are trusted. More UIDs can be added as a
+ compile options (some systems habe 'bin' as owner of the root
+ directory).
+
+ Integrity:
+ ---------
+ On startup, samhain will report on signatures or checksums of
+ database and configuration files. You better check these reports.
+
+ Both startup and exit will be reported. If you are using samhain
+ as daemon and start it at boot time, you may want to check that
+ startup/exit corresponds with scheduled reboots.
+
+ If the path to the samhain binary is defined in the configuration
+ file, samhain will checksum the binary at startup and compare
+ at program termination. This will minimize the time available
+ for an intruder to modify the binary.
+
+ Mail address:
+ ------------
+ For offsite mail, you may have to set a mail relay host
+ in the configuration file.
+
+START AT BOOT TIME:
+------------------
+ the easy way (supported on Linux, FreeBSD, HP-UX, AIX):
+
+ su root
+ make install-boot
+
+
+
+CONFIGURE OPTIONS:
+-----------------
+
+ -------------------
+ -- basic options --
+ -------------------
+
+ --enable-network Compile with client/server support.
+
+ --enable-udp Enable the server to listen on
+ port 514/udp (syslog).
+
+ --enable-srp Use SRP protocol to authenticate to
+ log server.
+
+ --with-gpg=PATH Use GnuPG to verify database/config.
+ The public key of the effective
+ user (in ~/.gnupg/pubring.gpg)
+ will be used.
+
+ --enable-login-watch Watch for login/logout events.
+
+ --enable-stealth=XOR_VAL Enable stealth mode, and set XOR_VAL.
+ XOR_VAL must be decimal in
+ 0..32 or 127..255
+ and will be used to 'mask' literal
+ strings as binary data.
+ (0 has no effect).
+
+ --enable-micro-stealth=XOR_VAL
+ As --with-stealth, but without
+ steganographic hidden configuration
+ file.
+
+ --enable-nocl=PW Enable command line parsing ONLY if
+ PW is the first argument on the command
+ line. If PW is "" (empty string),
+ command line parsing is completely
+ disabled.
+
+ --enable-base=BASE Set base for one-time pads. Must be
+ ONE string (no space) made of TWO
+ comma-separated integers in the range
+ -2147483648...2147483647.
+ (The default is compile time.)
+ Binaries compiled with different
+ values cannot verify the audit trail(s)
+ of each other.
+ THIS IS IMPORTANT IF YOU COMPILE
+ MULTIPLE TIMES, E.G. ON DIFFERENT
+ HOSTS.
+
+
+ -------------------
+ -- paths --
+ -------------------
+
+ ${install_name} is "samhain" by default
+ (see --with-install-name=NAME )
+
+ configuration: /etc/${install_name}rc
+ state data: /var/lib/${install_name}
+ log file: /var/log/${install_name}_log
+ lock/pid file: /var/run/${install_name}.pid
+
+ mandir: /usr/local/man
+ bindir: /usr/local/sbin/
+
+
+ --exec-prefix=EPREFIX Set sbindir prefix (default
+ is /usr/local, ie. binaries
+ go to /usr/local/sbin)
+
+ --prefix=PREFIX install directory
+ (default is NONE)
+
+ IF PREFIX = USR; then
+
+ configuration: /etc/${install_name}rc
+ state data: /var/lib/${install_name}
+ log file: /var/log/${install_name}_log
+ lock/pid file: /var/run/${install_name}.pid
+
+ mandir: /usr/share/man
+ bindir: /usr/sbin/
+
+ IF PREFIX = OPT; then
+
+ configuration: /etc/opt/${install_name}rc
+ state data: /var/opt/${install_name}/${install_name}
+ log file: /var/opt/${install_name}/${install_name}_log
+ lock/pid file: /var/opt/${install_name}/${install_name}.pid
+
+ mandir: /opt/${install_name}/man
+ bindir: /opt/${install_name}/bin/
+
+ IF PREFIX = (something else); then
+
+ If EPREFIX is not set, it will be set to PREFIX.
+ configuration: PREFIX/etc/${install_name}rc
+ state data: PREFIX/var/lib/${install_name}
+ log file: PREFIX/var/log/${install_name}_log
+ lock/pid file: PREFIX/var/run/${install_name}.pid
+
+ mandir: PREFIX/share/man
+ bindir: PREFIX/sbin/
+
+
+
+ --with-config-file=FILE Set path of configuration file
+ (default is PREFIX/etc/samhainrc)
+
+ --with-data-file=FILE Set path of data file
+ (PREFIX/var/lib/samhain/samhain_file)
+ --with-html-file=FILE Set path of server status html file
+ (PREFIX/var/lib/samhain/samhain.html)
+
+ --with-log-file=FILE Set path of log file
+ (PREFIX/var/log/samhain_log)
+ --with-pid-file=FILE Set path of lock file
+ (PREFIX/var/run/samhain.pid)
+
+ -------------------
+ -- other --
+ -------------------
+
+
+ --with-checksum=CHECKSUM Compile in TIGER checksum of the
+ gpg/pgp binary.
+ CHECKSUM must be the full
+ line output by samhain or GnuPG when
+ computing the checksum.
+
+ --with-fp=FINGERPRINT Compile in public key fingerprint.
+ FINGERPRINT must be without spaces.
+ Only useful in combination with
+ '--with-gpg'.
+ If used, samhain will check the
+ fingerprint, but still report on the
+ used public key.
+
+ --enable-identity=USER Set user when dropping root privileges
+ (default is the user "nobody").
+ Only needed if there is no user
+ 'nobody' on your system
+ (check /etc/passwd)
+
+ --with-port=PORT Set port number for TCP/IP
+ (default is 49777).
+ Only needed if this port is already
+ used by some other application.
+
+ --with-logserver=HOST Set host address for log server
+ (default is NULL).
+ You can set this in the configuration
+ file as well.
+
+ --with-timeserver=HOST Set host address for time server
+ (default is NULL - use own clock).
+ You can set this in the configuration
+ file as well.
+
+ --with-sender=SENDER Set sender for e-mail
+ (default is daemon).
+
+ --enable-xml-log Use XML format for log file.
+
+ --enable-debug Enable extended debugging
+
+ --enable-ptrace Use anti-debugging code.
+
+ --with-trusted=UID Comma-separated list of UID's of
+ users that are always trusted
+ (default is 0 = root).
+ You will need this only if the
+ path to the config file has directories
+ owned neither by 'root' nor by the
+ (effective) user of the program.
+
+
+TESTING:
+-------
+ For testing compilation etc., you may use the test suite:
+
+ ./test/test.sh n [hostname]
+
+ The argument 'n' is the number of the test to run. Some tests require
+ that the (fully qualified) hostname be given as second argument.
+
+ Without options, you will get a short help/usage message, listing
+ each test, its purpose, and the name of the configuration file used.
+ You may want to review the respective configuration file before
+ running a test.
+
+ Also listed are the scripts used for each test. If you have problems
+ getting samhain to run, you may use these scripts as examples.
+
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..eebd346
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,442 @@
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+@TOP@
+
+/* ---- compile options ------------ */
+
+/* Define if you want database support */
+#undef WITH_DATABASE
+
+/* Define if the database is unixODBC */
+#undef WITH_ODBC
+
+/* Define if the database is oracle */
+#undef WITH_ORACLE
+
+/* Define if the database is mysql */
+#undef WITH_MYSQL
+
+/* Define if the database is postgresql */
+#undef WITH_POSTGRES
+
+/* Define if the server may listen on 514/udp */
+#undef INET_SYSLOG
+
+/* Define if you want logfile in XML format */
+#undef SH_USE_XML
+
+/* Define if you want external programs. */
+#undef WITH_EXTERNAL
+
+/* Define if you want to reload the database */
+/* on SIGHUP. */
+#undef RELOAD_DATABASE
+
+/* Define if you want SysV message queue. */
+#undef WITH_MESSAGE_QUEUE
+
+/* Define the mode of the message queue. */
+#undef MESSAGE_QUEUE_MODE
+
+/* Define which users are always trusted. */
+/* default = 0 ( = root) */
+#undef SL_ALWAYS_TRUSTED
+
+/* Define if you want network time. */
+/* default = no */
+#undef HAVE_NTIME
+
+/* The time server host address. */
+/* default = "NULL" */
+#undef DEFAULT_TIMESERVER
+#undef ALT_TIMESERVER
+
+/* Define if you want to use the mail code. */
+/* default = yes */
+#undef SH_WITH_MAIL
+
+/* Define if you want client/server encryption*/
+#undef SH_ENCRYPT
+
+/* Define if you want version 2 encryption */
+#undef SH_ENCRYPT_2
+
+/* Define if you want to watch for login/-out.*/
+/* default = no */
+#undef SH_USE_UTMP
+
+/* Define if you want to check mount options on filesystems */
+/* default = no */
+#undef SH_USE_MOUNTS
+
+/* Define if you want to keep an eye on */
+/* sensitive files that your users own */
+#undef SH_USE_USERFILES
+
+/* Define if you want to watch for suid/sgid */
+/* files */
+#undef SH_USE_SUIDCHK
+
+/* Define if you want to check kernel syscall */
+/* table to detect LKM rootkits. */
+/* default = no */
+#undef SH_USE_KERN
+
+/* Define if you want to use the Kernel */
+/* module to hide samhain. */
+#undef SH_USE_LKM
+
+/* Define if you have a vanilla Kernel */
+/* (2.4 or 2.2) */
+#undef SH_VANILLA_KERNEL
+
+/* Define to the name of the MAGIC_HIDE */
+/* string if you use the Kernel module to */
+/* hide samhain. */
+#undef SH_MAGIC_HIDE
+
+/* Define if you want 'micro' stealth mode. */
+/* default = no */
+#undef SH_STEALTH_MICRO
+
+/* Define if you want to use stealth mode. */
+/* default = no */
+#undef SH_STEALTH
+
+/* Define if you want stealth w/o CL parsing. */
+/* default = no */
+#undef SH_STEALTH_NOCL
+
+/* The magic argv[1] to re-enable CL parsing. */
+/* default = "yes" */
+#undef NOCL_CODE
+
+/* XOR value to hide literal strings. */
+/* default = 0 */
+#undef XOR_CODE
+
+/* The port number for TCP/IP connection. */
+/* default = 49777 */
+#undef SH_DEFAULT_PORT
+
+/* The identity to assume when dropping root */
+/* default = "nobody" */
+#undef DEFAULT_IDENT
+
+/* Directory for tmp files */
+#undef SH_TMPDIR
+
+/* The data root directory. */
+/* default="/var/lib/samhain" */
+#undef DEFAULT_DATAROOT
+
+/* The quarantine directory. */
+/* default="/var/lib/samhain/.quarantine */
+#undef DEFAULT_QDIR
+
+/* The location of the log file. */
+/* default="/var/log/samhain_log" */
+#undef DEFAULT_ERRFILE
+
+/* The directory of the log file. */
+/* default="/var/log" */
+#undef DEFAULT_LOGDIR
+
+/* The location of the pid file. */
+/* default="/var/run/samhain.pid" */
+#undef DEFAULT_ERRLOCK
+
+/* The location of the pid file directory. */
+/* default="/var/run " */
+#undef DEFAULT_PIDDIR
+
+/* The location of the configuration file. */
+/* default="/etc/samhainrc" */
+#undef DEFAULT_CONFIGFILE
+
+/* The location of the checksum data. */
+/* default="/var/lib/samhain/samhain_file" */
+#undef DEFAULT_DATA_FILE
+
+/* The location of the html report. */
+/* default="/var/log/.samhain.html" */
+#undef DEFAULT_HTML_FILE
+
+/* The install directory. */
+/* default="/usr/local/sbin" */
+#undef SH_INSTALL_DIR
+
+/* The install path. */
+/* default="/usr/local/sbin/samhain" */
+#undef SH_INSTALL_PATH
+#undef SH_INSTALL_YULE_PATH
+
+/* The install name. */
+/* default="samhain" */
+#undef SH_INSTALL_NAME
+
+/* The sender name to use. */
+/* default = "daemon" */
+#undef DEFAULT_SENDER
+
+/* The address to send mail to. */
+/* default = "NULL" */
+#undef DEFAULT_MAILADDRESS
+#undef ALT_MAILADDRESS
+
+/* The log server. */
+/* default = "NULL" */
+#undef DEFAULT_LOGSERVER
+#undef ALT_LOGSERVER
+
+/* The console. */
+/* default = "NULL" */
+#undef DEFAULT_CONSOLE
+#undef ALT_CONSOLE
+
+/* The default base for one-time pads. */
+/* default = compile_time,compile_time */
+#undef DEFKEY
+
+/* Define if you want more debug options. */
+/* default = no */
+#undef MEM_DEBUG
+
+/* Define if you want more debug output. */
+/* default = no */
+#undef WITH_TPT
+
+/* Define if you want tracing. */
+/* default = no */
+#undef WITH_TRACE
+
+/* Define if you want slib debug. */
+/* default = no */
+#undef SL_DEBUG
+
+/* Define if you want slib to abort on errors.*/
+/* default = no */
+#undef SL_FAIL_ON_ERROR
+
+/* Define if you want to use SRP authenticaton*/
+#undef USE_SRP_PROTOCOL
+
+/* Define if you want to use GnuPG to */
+/* verify database and configuation file. */
+#undef WITH_GPG
+
+/* The full path to GnuPG */
+#undef DEFAULT_GPG_PATH
+
+/* Define if using the gpg/pgp checksum. */
+#undef HAVE_GPG_CHECKSUM
+
+/* The tiger checksum of the gpg/pgp binary. */
+#undef GPG_HASH
+
+/* Define if you want to compile in the */
+/* public key fingerprint. */
+#undef USE_FINGERPRINT
+
+/* The public key fingerprint. */
+#undef SH_GPG_FP
+
+/* Use ptrace - screw up signal handling. */
+#undef SCREW_IT_UP
+
+/* ---- misc ------------ */
+
+/* Define the package name. */
+#undef PACKAGE
+
+/* Define the package version. */
+#undef VERSION
+
+/* Define to the position of the key (1...8). */
+#undef POS_TF
+
+/* Init key for exepack. */
+#undef EXEPACK_STATE_0
+#undef EXEPACK_STATE_1
+#undef EXEPACK_STATE_2
+
+/* ---- system-specific options ------------ */
+
+/* Define to the address of sys_call_table */
+#undef SH_SYSCALLTABLE
+
+/* Define to use SVR4 statvfs to get filesystem type. */
+#undef FSTYPE_STATVFS
+
+/* Define to use SVR3.2 statfs to get filesystem type. */
+#undef FSTYPE_USG_STATFS
+
+/* Define to use AIX3 statfs to get filesystem type. */
+#undef FSTYPE_AIX_STATFS
+
+/* Define to use 4.3BSD getmntent to get filesystem type. */
+#undef FSTYPE_MNTENT
+
+/* Define to use 4.4BSD and OSF1 statfs to get filesystem type. */
+#undef FSTYPE_STATFS
+
+/* Define to use Ultrix getmnt to get filesystem type. */
+#undef FSTYPE_GETMNT
+
+/* the basic type to which we can cast a uid
+ */
+#undef UID_CAST
+
+/* for ext2fs flags */
+#undef HAVE_EXT2_IOCTLS
+#undef HAVE_STAT_FLAGS
+
+/* obvious */
+#undef HOST_IS_LINUX
+#undef HOST_IS_I86LINUX
+
+/* obvious */
+#undef HOST_IS_CYGWIN
+
+/* obvious */
+#undef HOST_IS_DARWIN
+
+/* obvious */
+#undef HOST_IS_FREEBSD
+
+/* obvious */
+#undef HOST_IS_AIX
+
+/* obvious */
+#undef HOST_IS_SOLARIS
+
+/* obvious */
+#undef HOST_IS_I86SOLARIS
+
+/* obvious */
+#undef HOST_IS_HPUX
+
+/* Define to the name of the random devices. */
+#undef NAME_OF_DEV_RANDOM
+
+#undef NAME_OF_DEV_URANDOM
+
+/* Define if you have long long. */
+#undef HAVE_LONG_LONG
+
+/* Define if short is 32 bits. */
+#undef HAVE_SHORT_32
+
+/* Define if int is 32 bits. */
+#undef HAVE_INT_32
+
+/* Define if long is 32 bits. */
+#undef HAVE_LONG_32
+
+/* Define if long is 64 bits. */
+#undef HAVE_LONG_64
+
+/* Define if UINT64 is 32 bits. */
+#undef UINT64_IS_32
+
+/* Define if you have uint64_t. */
+#undef HAVE_UINT16_T
+
+/* Define if you have uint64_t. */
+#undef HAVE_UINT64_T
+
+/* Define if you have utmpx.h. */
+#undef HAVE_UTMPX_H
+
+/* Define if your struct utmpx has ut_xtime. */
+#undef HAVE_UTXTIME
+
+/* Define if your struct utmp has ut_type. */
+#undef HAVE_UTTYPE
+
+/* Define if your struct utmp has ut_host. */
+#undef HAVE_UTHOST
+
+/* Define if your struct utmp has ut_addr. */
+#undef HAVE_UTADDR
+
+/* Define if your struct utmp has ut_addr_v6 */
+#undef HAVE_UTADDR_V6
+
+/* Define if your includes are broken. */
+#undef HAVE_BROKEN_INCLUDES
+
+/* Define if your getcwd uses 'popen'. */
+#undef HAVE_BROKEN_GETCWD
+
+/* Define if your vsnprintf is broken. */
+#undef HAVE_BROKEN_VSNPRINTF
+
+/* Define if you have va_copy. */
+#undef VA_COPY
+
+/* Define if va_list may be copied as array. */
+#undef VA_COPY_AS_ARRAY
+
+/* Define if you need unix entropy gatherer. */
+#undef HAVE_UNIX_RANDOM
+
+/* Define if you have EGD. */
+#undef HAVE_EGD_RANDOM
+
+/* Define if you have /dev/random. */
+#undef HAVE_URANDOM
+
+/* Soket name for EGD. */
+#undef EGD_SOCKET_NAME
+
+/* Define if your mlock() is broken. */
+#undef HAVE_BROKEN_MLOCK
+
+/* Define the proc f_type. */
+#undef SH_PROC_MAGIC
+
+/* Define if you have statfs. */
+#undef HAVE_STATFS
+
+/* Define if statfs works. */
+#undef STATFS_WORKS
+
+/* Define to long if not defined. */
+#undef ptrdiff_t
+
+@BOTTOM@
+
+/* dont modify this, unless you know what you do
+ */
+#define SRP_GENERATOR_1024 "2"
+#define SRP_MODULUS_1024_1 \
+_("f488fd584e49dbcd20b49de49107366b336c380d451d0f7c88b31c7c5b2d8ef6")
+#define SRP_MODULUS_1024_2 \
+_("f3c923c043f0a55b188d8ebb558cb85d38d334fd7c175743a31d186cde33212c")
+#define SRP_MODULUS_1024_3 \
+_("b52aff3ce1b1294018118d7c84a70a72d686c40319c807297aca950cd9969fab")
+#define SRP_MODULUS_1024_4 \
+_("d00a509b0246d3083d66a45d419f9c7cbd894b221926baaba25ec355e92f78c7")
+
+#define SDG_0RETU _("return.\n")
+#define SDG_TERRO _("ERROR: file=<%s>, line=<%d>, reason=<%s>\n")
+#define SDG_AERRO _("ERROR: file=<%s>, line=<%d>, failed_assertion=<%s>\n")
+#define SDG_AFAIL _("FAILED: file=<%s>, line=<%d>, assertion=<%s>\n")
+#define SDG_ENTER _("enter=<%s>\n")
+#define SDG_RETUR _("return=<%s>.\n")
+#define SDG_ERROR _("error=<%ld>.\n")
+
+#ifdef SH_STEALTH
+char * globber(const char * string);
+#define _(string) globber(string)
+#define N_(string) string
+#else
+#define _(string) string
+#define N_(string) string
+#endif
+
+#endif
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..a2e59a6
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,2159 @@
+dnl aclocal.m4 generated automatically by aclocal 1.3
+
+dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+dnl This Makefile.in is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+#
+# Check to make sure that the build environment is sane.
+#
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[
+AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION"))
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+
+# Define a conditional.
+
+AC_DEFUN([AM_CONDITIONAL],
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi])
+
+
+AC_DEFUN([sh_run_prog],
+[if test "$cross_compiling" = "yes"; then
+ AC_MSG_ERROR([Can not probe non-portable values when cross compiling])
+fi
+cat > conftest.$ac_ext <<EOF
+[#]line __oline__ "configure"
+#include "confdefs.h"
+ifelse(AC_LANG, CPLUSPLUS, [#ifdef __cplusplus
+extern "C" void exit(int);
+#endif
+])
+[$1]
+EOF
+if AC_TRY_EVAL(ac_link) && test -s conftest && $2=`(./conftest 2>/dev/null)`
+then
+dnl Don't remove the temporary files here, so they can be examined.
+ifelse([$3], , :, [$3])
+else
+echo "configure: failed program was:" >&AC_FD_CC
+cat conftest.$ac_ext >&AC_FD_CC
+ifelse([$4], , , [ rm -fr conftest*
+ $4
+])
+fi
+rm -fr conftest* ])
+
+dnl fs type number of the proc filing system
+AC_DEFUN([sh_procfs_id],
+[AC_MSG_CHECKING([f_type of /proc])
+AC_CACHE_VAL([sh_cv_proc_fstype],
+[sh_run_prog(
+changequote(<<, >>)dnl
+<<#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#ifndef Q
+#define __Q(x) #x
+#define Q(x) __Q(x)
+#endif
+int main(void)
+{
+struct statfs fsbuf;
+long ft;
+if (statfs("/", &fsbuf)!=0)
+ exit(1);
+ft=fsbuf.f_type;
+if (statfs("/proc/1", &fsbuf)!=0)
+ exit(1);
+if (ft!=fsbuf.f_type)
+ printf("0x%08lx", fsbuf.f_type);
+else
+ puts("statfs useless");
+exit(0);
+} >>
+changequote([, ]), sh_cv_proc_fstype,, sh_cv_proc_fstype="a fatal error occured")])
+AC_MSG_RESULT($sh_cv_proc_fstype)
+if test "${sh_cv_proc_fstype}" = "a fatal error occured"; then
+ $1=$2
+ $4
+else if test "${sh_cv_proc_fstype}" = "statfs useless"; then
+ $1=$2
+ $4
+else
+ $1=$sh_cv_proc_fstype
+ $3
+fi; fi ])
+
+# Check whether mlock is broken (hpux 10.20 raises a SIGBUS if mlock
+# is not called from uid 0 (not tested whether uid 0 works)
+dnl AC_CHECK_MLOCK
+dnl
+define([AC_CHECK_MLOCK],
+ [ AC_CHECK_FUNCS(mlock)
+ if test "$ac_cv_func_mlock" = "yes"; then
+ AC_MSG_CHECKING(whether mlock is broken)
+ AC_CACHE_VAL(ac_cv_have_broken_mlock,
+ AC_TRY_RUN([
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <sys/mman.h>
+ #include <sys/types.h>
+ #include <fcntl.h>
+
+ int main()
+ {
+ char *pool;
+ int err;
+ long int pgsize = getpagesize();
+
+ pool = malloc( 4096 + pgsize );
+ if( !pool )
+ return 2;
+ pool += (pgsize - ((long int)pool % pgsize));
+
+ err = mlock( pool, 4096 );
+ if( !err || errno == EPERM )
+ return 0; /* okay */
+
+ return 1; /* hmmm */
+ }
+
+ ],
+ ac_cv_have_broken_mlock="no",
+ ac_cv_have_broken_mlock="yes",
+ ac_cv_have_broken_mlock="assume-no"
+ )
+ )
+ if test "$ac_cv_have_broken_mlock" = "yes"; then
+ AC_DEFINE(HAVE_BROKEN_MLOCK)
+ AC_MSG_RESULT(yes)
+ else
+ if test "$ac_cv_have_broken_mlock" = "no"; then
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(assuming no)
+ fi
+ fi
+ fi
+ ])
+
+dnl @synopsis AC_FUNC_VSNPRINTF
+dnl
+dnl Check whether there is a reasonably sane vsnprintf() function installed.
+dnl "Reasonably sane" in this context means never clobbering memory beyond
+dnl the buffer supplied, and having a sensible return value. It is
+dnl explicitly allowed not to NUL-terminate the return value, however.
+dnl
+dnl @version $Id: ac_func_vsnprintf.m4,v 1.1 2001/07/26 02:00:21 guidod Exp $
+dnl @author Gaute Strokkenes <gs234@cam.ac.uk>
+dnl
+AC_DEFUN([SL_CHECK_VSNPRINTF],
+[AC_CACHE_CHECK(for working vsnprintf,
+ ac_cv_func_vsnprintf,
+[AC_TRY_RUN(
+[#include <stdio.h>
+#include <stdarg.h>
+
+int
+doit(char * s, ...)
+{
+ char buffer[32];
+ va_list args;
+ int r;
+
+ buffer[5] = 'X';
+
+ va_start(args, s);
+ r = vsnprintf(buffer, 5, s, args);
+ va_end(args);
+
+ /* -1 is pre-C99, 7 is C99. R.W. 17.01.2003 disallow -1 */
+
+ if (r != 7)
+ exit(1);
+
+ /* We deliberately do not care if the result is NUL-terminated or
+ not, since this is easy to work around like this. */
+
+ buffer[4] = 0;
+
+ /* Simple sanity check. */
+
+ if (strcmp(buffer, "1234"))
+ exit(1);
+
+ if (buffer[5] != 'X')
+ exit(1);
+
+ exit(0);
+}
+
+int
+main(void)
+{
+ doit("1234567");
+ exit(1);
+}], ac_cv_func_vsnprintf=yes, ac_cv_func_vsnprintf=no, ac_cv_func_vsnprintf=no)])
+dnl Note that the default is to be pessimistic in the case
+dnl of cross compilation.
+dnl If you know that the target has a sensible vsnprintf(),
+dnl you can get around this
+dnl by setting ac_func_vsnprintf to yes, as described in the Autoconf manual.
+if test $ac_cv_func_vsnprintf = yes; then
+ :
+else
+ AC_DEFINE(HAVE_BROKEN_VSNPRINTF, 1,
+ [Define if you have a broken version of the `vsnprintf' function.])
+fi
+])# AC_FUNC_VSNPRINTF
+
+dnl SH_CHECK_TYPEDEF(TYPE, HAVE_NAME)
+dnl Check whether a typedef exists and create a #define $2 if it exists
+dnl
+AC_DEFUN([SH_CHECK_TYPEDEF],
+ [ AC_MSG_CHECKING(for $1 typedef)
+ sh_cv_typedef_foo=`echo sh_cv_typedef_$1 | sed -e 's% %_%g'`
+ AC_CACHE_VAL( $sh_cv_typedef_foo,
+ [AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif], [
+ #undef $1
+ int a = sizeof($1);
+ ], sh_cv_typedef=yes, sh_cv_typedef=no )])
+ AC_MSG_RESULT($sh_cv_typedef)
+ if test "$sh_cv_typedef" = yes; then
+ AC_DEFINE([$2], [1], [Define if type is defined in stdint.h or inttypes.h])
+ sh_$2=yes
+ else
+ sh_$2=no
+ fi
+ ])
+
+
+
+dnl **********************
+dnl *** va_copy checks ***
+dnl **********************
+AC_DEFUN([SL_CHECK_VA_COPY],
+[AC_MSG_CHECKING(for va_copy())
+AC_CACHE_VAL(sh_cv_va_copy,[
+ AC_TRY_RUN([
+ #include <stdarg.h>
+ void f (int i, ...) {
+ va_list args1, args2;
+ va_start (args1, i);
+ va_copy (args2, args1);
+ if (va_arg (args2, int) != 42)
+ exit (1);
+ if (va_arg (args1, int) != 42)
+ exit (1);
+ va_end (args1); va_end (args2);
+ }
+ int main() {
+ f (0, 42);
+ return 0;
+ }],
+ sh_cv_va_copy=yes
+ ,
+ sh_cv_va_copy=no
+ ,
+ sh_cv_va_copy=no)
+])
+AC_MSG_RESULT($sh_cv_va_copy)
+AC_MSG_CHECKING(for __va_copy())
+AC_CACHE_VAL(sh_cv___va_copy,[
+ AC_TRY_RUN([
+ #include <stdarg.h>
+ void f (int i, ...) {
+ va_list args1, args2;
+ va_start (args1, i);
+ __va_copy (args2, args1);
+ if (va_arg (args2, int) != 42)
+ exit (1);
+ if (va_arg (args1, int) != 42)
+ exit (1);
+ va_end (args1); va_end (args2);
+ }
+ int main() {
+ f (0, 42);
+ return 0;
+ }],
+ sh_cv___va_copy=yes
+ ,
+ sh_cv___va_copy=no
+ ,
+ sh_cv___va_copy=no)
+])
+AC_MSG_RESULT($sh_cv___va_copy)
+AC_MSG_CHECKING(whether va_lists can be copied by value)
+AC_CACHE_VAL(sh_cv_va_val_copy,[
+ AC_TRY_RUN([
+ #include <stdarg.h>
+ void f (int i, ...) {
+ va_list args1, args2;
+ va_start (args1, i);
+ args2 = args1;
+ if (va_arg (args2, int) != 42)
+ exit (1);
+ if (va_arg (args1, int) != 42)
+ exit (1);
+ va_end (args1); va_end (args2);
+ }
+ int main() {
+ f (0, 42);
+ return 0;
+ }],
+ sh_cv_va_val_copy=yes
+ ,
+ sh_cv_va_val_copy=no
+ ,
+ sh_cv_va_val_copy=no)
+])
+if test "x$sh_cv_va_copy" = "xyes"; then
+ AC_DEFINE(VA_COPY, va_copy)
+else if test "x$sh_cv___va_copy" = "xyes"; then
+ AC_DEFINE(VA_COPY, __va_copy)
+fi
+fi
+if test "x$sh_cv_va_val_copy" = "xno"; then
+ AC_DEFINE(VA_COPY_AS_ARRAY)
+fi
+AC_MSG_RESULT($sh_cv_va_val_copy)
+])
+
+
+dnl SH_INIT_PARSE_ARGS()
+m4_define([SH_INIT_PARSE_ARGS],
+[
+m4_divert_push([PARSE_ARGS])dnl
+
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[[^_$as_cr_alnum]]%_%g"
+
+as_tr_sh="eval sed 'y%*+%pp%;s%[[^_$as_cr_alnum]]%_%g'"
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+AC_SUBST(exec_prefix, NONE)dnl
+no_create=
+no_recursion=
+AC_SUBST(prefix, NONE)dnl
+program_prefix=NONE
+program_suffix=NONE
+AC_SUBST(program_transform_name, [s,x,x,])dnl
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+DESTDIR=
+SH_ENABLE_OPTS="selinux posix-acl asm ssp db-reload xml-log message-queue login-watch process-check port-check mounts-check logfile-monitor userfiles debug ptrace static network udp nocl stealth micro-stealth install-name identity khide suidcheck base largefile mail external-scripts encrypt srp dnmalloc ipv6 shellexpand suid"
+SH_WITH_OPTS="prelude libprelude-prefix database libwrap cflags libs console altconsole timeserver alttimeserver rnd egd-socket port logserver altlogserver kcheck gpg keyid checksum fp recipient sender trusted tmp-dir config-file log-file pid-file state-dir data-file html-file"
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+dnl Use braces instead of parens because sh, perl, etc. also accept them.
+sbindir='${exec_prefix}/sbin'
+sysconfdir='${prefix}/etc'
+localstatedir='${prefix}/var'
+mandir='${prefix}/share/man'
+
+AC_SUBST([sbindir], ['${exec_prefix}/sbin'])dnl
+AC_SUBST([sysconfdir], ['${prefix}/etc'])dnl
+AC_SUBST([localstatedir], ['${prefix}/var'])dnl
+AC_SUBST([mandir], ['${prefix}/share/man'])dnl
+
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+changequote(, )dnl
+ *=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+changequote([, ])dnl
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : "[.*[^-_$as_cr_alnum]]" >/dev/null &&
+ AC_MSG_ERROR([invalid feature name: $ac_feature])
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ ac_enable_check_opt=no
+ for f in ${SH_ENABLE_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_feature}"
+ then
+ ac_enable_check_opt=yes
+ fi
+ done
+ if test x${ac_enable_check_opt} = xno
+ then
+ AC_MSG_ERROR([unrecognized option: $ac_option
+Try `$[0] --help' for more information.])
+ fi
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([[^=]]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : "[.*[^-_$as_cr_alnum]]" >/dev/null &&
+ AC_MSG_ERROR([invalid feature name: $ac_feature])
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ ac_enable_check_opt=no
+ for f in ${SH_ENABLE_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_feature}"
+ then
+ ac_enable_check_opt=yes
+ fi
+ done
+ if test x${ac_enable_check_opt} = xno
+ then
+ AC_MSG_ERROR([unrecognized option: $ac_option
+Try `$[0] --help' for more information.])
+ fi
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix
+ ac_exec_prefix_set="yes"
+ ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg"
+ ac_exec_prefix_set="yes"
+ ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir
+ ac_localstatedir_set="yes"
+ ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg"
+ ac_localstatedir_set="yes"
+ ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir
+ ac_mandir_set="yes"
+ ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg"
+ ac_mandir_set="yes"
+ ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix
+ ac_prefix_set="yes"
+ ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg"
+ ac_prefix_set="yes"
+ ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir
+ ac_sbindir_set="yes"
+ ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg"
+ ac_sbindir_set="yes"
+ ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi | --b)
+ echo "WARNING: bindir will be ignored, use sbindir"
+ ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* \
+ | --bi=* | --b=*)
+ echo "WARNING: bindir will be ignored, use sbindir"
+ ;;
+
+ -datadir | --datadir)
+ echo "WARNING: datadir will be ignored"
+ ;;
+ -datadir=* | --datadir=*)
+ echo "WARNING: datadir will be ignored"
+ ;;
+
+ -includedir | --includedir)
+ echo "WARNING: includedir will be ignored"
+ ;;
+ -includedir=* | --includedir=*)
+ echo "WARNING: includedir will be ignored"
+ ;;
+
+ -infodir | --infodir)
+ echo "WARNING: infodir will be ignored"
+ ;;
+ -infodir=* | --infodir=*)
+ echo "WARNING: infodir will be ignored"
+ ;;
+
+ -libdir | --libdir)
+ echo "WARNING: libdir will be ignored"
+ ;;
+ -libdir=* | --libdir=*)
+ echo "WARNING: libdir will be ignored"
+ ;;
+
+ -libexecdir | --libexecdir)
+ echo "WARNING: libexecdir will be ignored"
+ ;;
+ -libexecdir=* | --libexecdir=*)
+ echo "WARNING: libexecdir will be ignored"
+ ;;
+
+ -sharedstatedir | --sharedstatedir)
+ echo "WARNING: sharedstatedir will be ignored"
+ ;;
+ -sharedstatedir=* | --sharedstatedir=*)
+ echo "WARNING: sharedstatedir will be ignored"
+ ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir
+ ac_sysconfdir_set="yes"
+ ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg"
+ ac_sysconfdir_set="yes"
+ ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ ac_init_version=: ;;
+
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([[^=]]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : "[.*[^-_$as_cr_alnum]]" >/dev/null &&
+ AC_MSG_ERROR([invalid package name: $ac_package])
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ ac_with_check_opt=no
+ for f in ${SH_WITH_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_package}"
+ then
+ ac_with_check_opt=yes
+ fi
+ done
+ if test x${ac_with_check_opt} = xno
+ then
+ AC_MSG_ERROR([unrecognized option: $ac_option
+Try `$[0] --help' for more information.])
+ fi
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : "[.*[^-_$as_cr_alnum]]" >/dev/null &&
+ AC_MSG_ERROR([invalid package name: $ac_package])
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ ac_with_check_opt=no
+ for f in ${SH_WITH_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_package}"
+ then
+ ac_with_check_opt=yes
+ fi
+ done
+ if test x${ac_with_check_opt} = xno
+ then
+ AC_MSG_ERROR([unrecognized option: $ac_option
+Try `$[0] --help' for more information.])
+ fi
+ eval "with_$ac_package=no" ;;
+
+
+ -*) AC_MSG_ERROR([unrecognized option: $ac_option
+Try `$[0] --help' for more information.])
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([[^=]]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : "[.*[^_$as_cr_alnum]]" >/dev/null &&
+ AC_MSG_ERROR([invalid variable name: $ac_envvar])
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ AC_MSG_WARN([you should use --build, --host, --target])
+ expr "x$ac_option" : "[.*[^-._$as_cr_alnum]]" >/dev/null &&
+ AC_MSG_WARN([invalid host type: $ac_option])
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ AC_MSG_ERROR(missing argument to --`echo $ac_prev | sed 's/_/-/g'`)
+fi
+
+# Be sure to have absolute paths.
+for ac_var in prefix exec_prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [[\\/$]]* | ?:[[\\/]]* | NONE | '' | OPT | USR ) ;;
+ *) AC_MSG_ERROR([expected an absolute directory name for --$ac_var: $ac_val]);;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in sbindir sysconfdir localstatedir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [[\\/$]]* | ?:[[\\/]]* ) ;;
+ *) AC_MSG_ERROR([expected an absolute directory name for --$ac_var: $ac_val]);;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ AC_MSG_WARN([If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used.])
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec AS_MESSAGE_FD>/dev/null
+
+m4_divert_pop([PARSE_ARGS])dnl
+])# SH_INIT_PARSE_ARGS
+
+m4_define([SH_INIT_HELP],
+[m4_divert_push([HELP_BEGIN])dnl
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures m4_ifset([AC_PACKAGE_STRING],
+ [AC_PACKAGE_STRING],
+ [this package]) to adapt to many kinds of systems.
+
+Usage: $[0] [[OPTION]]... [[VAR=VALUE]]...
+
+[To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install binaries in \`/usr/local/sbin',
+the config file in \`/etc', manpage in \`/usr/local/share/man', and state
+data in \`/var/lib/INSTALL_NAME' (FSH layout). You can specify other
+FSH compliant layouts with \`--prefix=OPT' or \`--prefix=USR', or you
+can specify a directory with \`--prefix=DIR' to install in \`DIR/sbin',
+\`DIR/etc', etc.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --mandir=DIR man documentation [PREFIX/man]
+
+For even finer tuning, paths can be specified for individual files (see below)
+
+_ACEOF
+
+ cat <<\_ACEOF]
+m4_divert_pop([HELP_BEGIN])dnl
+dnl The order of the diversions here is
+dnl - HELP_BEGIN
+dnl which may be prolongated by extra generic options such as with X or
+dnl AC_ARG_PROGRAM. Displayed only in long --help.
+dnl
+dnl - HELP_CANON
+dnl Support for cross compilation (--build, --host and --target).
+dnl Display only in long --help.
+dnl
+dnl - HELP_ENABLE
+dnl which starts with the trailer of the HELP_BEGIN, HELP_CANON section,
+dnl then implements the header of the non generic options.
+dnl
+dnl - HELP_WITH
+dnl
+dnl - HELP_VAR
+dnl
+dnl - HELP_VAR_END
+dnl
+dnl - HELP_END
+dnl initialized below, in which we dump the trailer (handling of the
+dnl recursion for instance).
+m4_divert_push([HELP_ENABLE])dnl
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+m4_ifset([AC_PACKAGE_STRING],
+[ case $ac_init_help in
+ short | recursive ) echo "Configuration of AC_PACKAGE_STRING:";;
+ esac])
+ cat <<\_ACEOF
+m4_divert_pop([HELP_ENABLE])dnl
+m4_divert_push([HELP_END])dnl
+m4_ifset([AC_PACKAGE_BUGREPORT], [
+Report bugs to <AC_PACKAGE_BUGREPORT>.])
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ _AC_SRCPATHS(["$ac_dir"])
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ AC_MSG_WARN([no configuration information is in $ac_dir])
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+m4_divert_pop([HELP_END])dnl
+])# SH_INIT_HELP
+
+
+
+
+
+
+
+
+# Check whether sa_sigaction works.
+# Rainer Wichmann <support@la-samhna.de>, 2003.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License.
+
+# serial 1
+
+AC_DEFUN([AM_SA_SIGACTION_WORKS],
+ [
+ am_cv_val_SA_SIGACTION=no
+ AC_CHECK_HEADER(signal.h,
+ [
+ AM_SI_USER
+ AM_SA_SIGINFO
+ if test $am_cv_val_SI_USER = yes && test $am_cv_val_SA_SIGINFO = yes
+ then
+ AC_TRY_RUN([
+#include <signal.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+volatile int xnum = 0;
+volatile int xcode = 0;
+jmp_buf Buf;
+int xsig = SIGSEGV;
+
+void sighandler (int xsignam, siginfo_t * xsiginfo, void * xsigadd)
+{
+ static sigset_t x;
+
+ if (xsiginfo == NULL)
+ exit(__LINE__);
+ if (xsiginfo->si_signo != xsignam)
+ exit(__LINE__);
+ ++xnum;
+ xcode = xsiginfo->si_code;
+ sigemptyset (&x);
+ sigprocmask(SIG_SETMASK, &x, NULL);
+ longjmp ( Buf, 1);
+}
+
+int main ()
+{
+ struct sigaction newact;
+
+ newact.sa_sigaction = sighandler;
+ sigemptyset (&newact.sa_mask);
+ newact.sa_flags = SA_SIGINFO;
+ if (0 != sigaction (xsig, &newact, NULL))
+ exit (__LINE__);
+ if(setjmp ( Buf)) {
+ if (xnum > 1)
+ goto Third;
+ goto Second;
+ }
+ memcpy((void *) 0x0, "test", 5);
+ Second:
+ if (xcode == SI_USER)
+ exit (__LINE__);
+ raise(xsig);
+ Third:
+ if (xcode != SI_USER)
+ exit (__LINE__);
+ if (xnum != 2)
+ exit (__LINE__);
+ return (0);
+}], am_cv_val_SA_SIGACTION=yes, am_cv_val_SA_SIGACTION=no, am_cv_val_SA_SIGACTION=no)
+ fi
+ ])
+ AC_MSG_CHECKING([whether sa_sigaction is supported])
+ if test $am_cv_val_SA_SIGACTION = yes
+ then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([SA_SIGACTION_WORKS], 1, [Define if sa_sigaction works])
+ else
+ AC_MSG_RESULT(no)
+ fi
+ ])
+
+# Check whether SI_USER is available in <signal.h>.
+# Rainer Wichmann <support@la-samhna.de>, 2003.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License.
+
+# serial 1
+
+
+AC_DEFUN([AM_SI_USER],
+ [if test $ac_cv_header_signal_h = yes; then
+ AC_CACHE_CHECK([for SI_USER in signal.h], am_cv_val_SI_USER,
+ [AC_TRY_LINK([#include <signal.h>], [return SI_USER],
+ am_cv_val_SI_USER=yes, am_cv_val_SI_USER=no)])
+ if test $am_cv_val_SI_USER = yes; then
+ AC_DEFINE([HAVE_SI_USER], 1, [Define if you have SI_USER])
+ fi
+ fi])
+
+# Check whether SA_SIGINFO is available in <signal.h>.
+# Rainer Wichmann <support@la-samhna.de>, 2003.
+#
+# This file can be copied and used freely without restrictions. It can
+# be used in projects which are not available under the GNU Public License.
+
+# serial 1
+
+
+AC_DEFUN([AM_SA_SIGINFO],
+ [if test $ac_cv_header_signal_h = yes; then
+ AC_CACHE_CHECK([for SA_SIGINFO in signal.h], am_cv_val_SA_SIGINFO,
+ [AC_TRY_LINK([#include <signal.h>], [return SA_SIGINFO],
+ am_cv_val_SA_SIGINFO=yes, am_cv_val_SA_SIGINFO=no)])
+ if test $am_cv_val_SA_SIGINFO = yes; then
+ AC_DEFINE([HAVE_SA_SIGINFO], 1, [Define if you have SA_SIGINFO])
+ fi
+ fi])
+
+dnl
+dnl Useful macros for autoconf to check for ssp-patched gcc
+dnl 1.0 - September 2003 - Tiago Sousa <mirage@kaotik.org>
+dnl 1.1 - August 2006 - Ted Percival <ted@midg3t.net>
+dnl * Stricter language checking (C or C++)
+dnl * Adds GCC_STACK_PROTECT_LIB to add -lssp to LDFLAGS as necessary
+dnl * Caches all results
+dnl * Uses macros to ensure correct ouput in quiet/silent mode
+dnl 1.2 - April 2007 - Ted Percival <ted@midg3t.net>
+dnl * Added GCC_STACK_PROTECTOR macro for simpler (one-line) invocation
+dnl * GCC_STACK_PROTECT_LIB now adds -lssp to LIBS rather than LDFLAGS
+dnl
+dnl About ssp:
+dnl GCC extension for protecting applications from stack-smashing attacks
+dnl http://www.research.ibm.com/trl/projects/security/ssp/
+dnl
+dnl Usage:
+dnl Most people will simply call GCC_STACK_PROTECTOR.
+dnl If you only use one of C or C++, you can save time by only calling the
+dnl macro appropriate for that language. In that case you should also call
+dnl GCC_STACK_PROTECT_LIB first.
+dnl
+dnl GCC_STACK_PROTECTOR
+dnl Tries to turn on stack protection for C and C++ by calling the following
+dnl three macros with the right languages.
+dnl
+dnl GCC_STACK_PROTECT_CC
+dnl checks -fstack-protector with the C compiler, if it exists then updates
+dnl CFLAGS and defines ENABLE_SSP_CC
+dnl
+dnl GCC_STACK_PROTECT_CXX
+dnl checks -fstack-protector with the C++ compiler, if it exists then updates
+dnl CXXFLAGS and defines ENABLE_SSP_CXX
+dnl
+dnl GCC_STACK_PROTECT_LIB
+dnl adds -lssp to LIBS if it is available
+dnl ssp is usually provided as part of libc, but was previously a separate lib
+dnl It does not hurt to add -lssp even if libc provides SSP - in that case
+dnl libssp will simply be ignored.
+dnl
+
+AC_DEFUN([GCC_STACK_PROTECT_LIB],[
+ AC_CACHE_CHECK([whether libssp exists], ssp_cv_lib,
+ [ssp_old_libs="$LIBS"
+ LIBS="$LIBS -lssp"
+ AC_TRY_LINK(,, ssp_cv_lib=yes, ssp_cv_lib=no)
+ LIBS="$ssp_old_libs"
+ ])
+ if test $ssp_cv_lib = yes; then
+ LIBS="$LIBS -lssp"
+ fi
+])
+
+AC_DEFUN([GCC_STACK_PROTECT_CC],[
+ AC_LANG_ASSERT(C)
+ if test "X$CC" != "X"; then
+ AC_CACHE_CHECK([whether ${CC} accepts -fstack-protector-all],
+ ssp_cv_cc,
+ [ssp_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -fstack-protector-all"
+ AC_TRY_COMPILE(,, ssp_cv_cc=yes, ssp_cv_cc=no)
+ CFLAGS="$ssp_old_cflags"
+ ])
+ if test $ssp_cv_cc = no; then
+ AC_CACHE_CHECK([whether ${CC} accepts -fstack-protector],
+ ssp_cv_cc,
+ [ssp_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -fstack-protector"
+ AC_TRY_COMPILE(,, ssp_cv_cc=yes, ssp_cv_cc=no)
+ CFLAGS="$ssp_old_cflags"
+ ])
+ if test $ssp_cv_cc = yes; then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector"
+ LDFLAGS="$LDFLAGS -fstack-protector"
+ AC_DEFINE([ENABLE_SSP_CC], 1, [Define if SSP C support is enabled.])
+ fi
+ else
+ if test $ssp_cv_cc = yes; then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all"
+ LDFLAGS="$LDFLAGS -fstack-protector-all"
+ AC_DEFINE([ENABLE_SSP_CC], 1, [Define if SSP C support is enabled.])
+ fi
+ fi
+ fi
+])
+
+AC_DEFUN([GCC_STACK_PROTECT_CXX],[
+ AC_LANG_ASSERT(C++)
+ if test "X$CXX" != "X"; then
+ AC_CACHE_CHECK([whether ${CXX} accepts -fstack-protector],
+ ssp_cv_cxx,
+ [ssp_old_cxxflags="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS -fstack-protector"
+ AC_TRY_COMPILE(,, ssp_cv_cxx=yes, ssp_cv_cxx=no)
+ CXXFLAGS="$ssp_old_cxxflags"
+ ])
+ if test $ssp_cv_cxx = yes; then
+ CXXFLAGS="$CXXFLAGS -fstack-protector"
+ AC_DEFINE([ENABLE_SSP_CXX], 1, [Define if SSP C++ support is enabled.])
+ fi
+ fi
+])
+
+AC_DEFUN([GCC_STACK_PROTECTOR],[
+ GCC_STACK_PROTECT_LIB
+
+ AC_LANG_PUSH([C])
+ GCC_STACK_PROTECT_CC
+ AC_LANG_POP([C])
+
+ AC_LANG_PUSH([C++])
+ GCC_STACK_PROTECT_CXX
+ AC_LANG_POP([C++])
+])
+
+
+AC_DEFUN([GCC_PIE_CC],[
+ AC_LANG_ASSERT(C)
+ if test "X$CC" != "X"; then
+ AC_CACHE_CHECK([whether ${CC} accepts -pie -fPIE],
+ pie_cv_cc,
+ [pie_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -pie -fPIE"
+ AC_TRY_COMPILE(,, pie_cv_cc=yes, pie_cv_cc=no)
+ CFLAGS="$pie_old_cflags"
+ ])
+ if test $pie_cv_cc = yes; then
+ case "$host_os" in
+ *cygwin*)
+ ;;
+ *)
+ PIE_CFLAGS="-fPIE"
+ PIE_LDFLAGS="-pie"
+ ;;
+ esac
+ fi
+ fi
+])
+
+AC_DEFUN([GCC_STACK_CHECK_CC],[
+ AC_LANG_ASSERT(C)
+ if test "X$CC" != "X"; then
+ AC_CACHE_CHECK([whether ${CC} accepts -fstack-check],
+ stackcheck_cv_cc,
+ [stackcheck_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -fstack-check"
+ AC_TRY_COMPILE(,, stackcheck_cv_cc=yes, stackcheck_cv_cc=no)
+ CFLAGS="$stackcheck_old_cflags"
+ ])
+ if test $stackcheck_cv_cc = yes; then
+ CFLAGS="$CFLAGS -fstack-check"
+ fi
+ fi
+])
+
+AC_DEFUN([GCC_FLAG_CHECK],[
+ AC_LANG_ASSERT(C)
+ if test "X$CC" != "X"; then
+ AC_MSG_CHECKING([whether ${CC} accepts $1])
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror $1"
+ AC_TRY_COMPILE(,, flag_check_cv=yes, flag_check_cv=no)
+ CFLAGS="$saved_cflags"
+
+ if test $flag_check_cv = yes; then
+ CFLAGS="$CFLAGS $1"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+])
+
+AC_DEFUN([SAMHAIN_POSIX],[
+ AC_MSG_CHECKING([whether _POSIX_SOURCE is necessary])
+ AC_TRY_COMPILE([#include <stdio.h>
+void fileno(int);int fdopen(int, char *); ],,
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE([_POSIX_SOURCE],1,[Define if POSIX functions are required])
+ ],
+ [AC_MSG_RESULT(no)])
+])dnl
+
+dnl checks for a known 64 bit programming environment
+dnl AC_RUN_IFELSE(PROGRAM,
+dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE],
+dnl [ACTION-IF-CROSS-COMPILING = RUNTIME-ERROR])
+dnl
+AC_DEFUN([SAMHAIN_PRG_ENV],[
+ AC_MSG_CHECKING([for a known 64 bit programming environment])
+ # Compile and run a program that determines the programming environment
+ AC_RUN_IFELSE([
+ AC_LANG_SOURCE([[
+#include <stdio.h>
+int main(int argc,char **argv)
+{
+ if (argc > 1) {
+#if defined(__arch64__)
+ printf("__arch64__\n");
+#elif defined(__ia64__)
+ printf("__ia64__\n");
+#elif defined(__x86_64__)
+ printf("__x86_64__\n");
+#elif defined(__LP64__)
+ printf("__LP64__\n");
+#elif defined(__64BIT__)
+ printf("__64BIT__\n");
+#elif defined(_LP64)
+ printf("_LP64\n");
+#elif defined(_M_IA64)
+ printf("_M_IA64\n");
+#elif defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)
+ printf("_MIPS_64\n");
+#else
+choke me
+#endif
+ }
+ return 0;
+}
+ ]])
+ ],[
+ # Program compiled and ran, so get version by adding argument.
+ samhain_prg_ENV=`./conftest$ac_exeext x`
+ samhain_64=yes
+ AC_MSG_RESULT([$samhain_prg_ENV])
+ ],[
+ AC_MSG_RESULT([none])
+ ],[
+ AC_MSG_RESULT([none])
+ ])
+])dnl
+
+AC_DEFUN([SAMHAIN_X86_64],[
+ AC_MSG_CHECKING([for x86_64])
+ AC_TRY_RUN([
+int main() {
+__asm__ volatile (
+"movq %rax, %rax"
+);
+return 0;
+}
+ ],
+ [
+ AC_MSG_RESULT(yes)
+ samhain_64=yes
+ tiger_src=sh_tiger1_64.c
+ samhain_64_asm=yes
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ],[
+ AC_MSG_RESULT([no])
+ ])
+])dnl
+
+
+AC_DEFUN([SAMHAIN_64],[
+samhain_64=no
+tiger_src=sh_tiger1.c
+samhain_64_asm=no
+#
+# if sizeof(unsigned long) = 4, try compiler macros for 64bit
+#
+if test "x$ac_cv_sizeof_unsigned_long" = x4; then
+ if test "x$ac_cv_sizeof_unsigned_long_long" = x8; then
+ SAMHAIN_PRG_ENV
+ if test "x$samhain_64" = xyes; then
+ tiger_src=sh_tiger1_64.c
+ fi
+ #
+ # if GCC and __i386__, use precompiled assembler
+ #
+ if test "x$GCC" = xyes; then
+ AC_MSG_CHECKING([for non-apple non-cygwin i386])
+ samhain_i386=no
+ $CC -E -dM - < /dev/null | egrep '__i386__' >/dev/null 2>&1
+ if test $? = 0; then
+ case "$host_os" in
+ *linux*)
+ # apples gcc does not understand the assembly we provide
+ $CC -E -dM - < /dev/null | egrep '(__sun__|__APPLE__|__CYGWIN__)' >/dev/null 2>&1 || samhain_i386=yes
+ ;;
+ *)
+ ;;
+ esac
+ fi
+ AC_MSG_RESULT([$samhain_i386])
+ if test "x$samhain_i386" = xyes; then
+ GCC_PIE_CC
+ if test $pie_cv_cc = yes; then
+ tiger_src=sh_tiger1.s
+ AC_DEFINE([TIGER_32_BIT_S],1,[Define to use tiger 32 bit i386 assembler])
+ fi
+ fi
+ fi
+ #
+ #
+ #
+ else
+ samhain_64=no
+ tiger_src=sh_tiger1.c
+ fi
+else
+ #
+ # sizeof(unsigned long) = 8
+ #
+ tiger_src=sh_tiger1_64.c
+ samhain_64=yes
+ #
+ # check for x86_64 (enables assembly optimizations)
+ #
+ if test "x$GCC" = xyes; then
+ $CC -E -dM - < /dev/null | egrep '__clang__' >/dev/null 2>&1
+ if ! test $? = 0; then
+ case "$host_os" in
+ *linux*)
+ SAMHAIN_X86_64
+ ;;
+ *bsd*)
+ SAMHAIN_X86_64
+ ;;
+ *)
+ SAMHAIN_X86_64
+ ;;
+ esac
+ fi
+ fi
+fi
+if test "x$samhain_64" = xyes; then
+ AC_DEFINE([TIGER_64_BIT],1,[Define to use tiger 64 bit implementation])
+fi
+AC_MSG_CHECKING([for 64 bit environment])
+AC_MSG_RESULT([$samhain_64])
+AC_MSG_CHECKING([for tiger source to use])
+AC_MSG_RESULT([$tiger_src])
+AC_SUBST(tiger_src)
+])dnl
+
+AC_DEFUN([sh_CHECK_POSIX_ACL],
+[
+ AC_CHECK_HEADERS(sys/acl.h)
+ if test $ac_cv_header_sys_acl_h = yes; then
+
+ AC_CHECK_LIB([acl], [acl_get_file], sh_lacl=yes, sh_lacl=no)
+ if test x"$sh_lacl" = xyes; then
+ LIBACL=-lacl
+ else
+ LIBACL=
+ fi
+
+ OLDLIBS="$LIBS"
+ LIBS="$LIBS $LIBACL"
+ AC_CHECK_FUNCS([acl_free acl_get_file acl_get_fd],
+ [sh_facl=yes],[sh_facl=no])
+ LIBS="$OLDLIBS"
+ fi
+
+ if test x"$sh_facl" = xyes; then
+ AC_DEFINE(USE_ACL, 1, [Define if you want ACL support.])
+ LIBS="$LIBS $LIBACL"
+ else
+ if test "x$enable_posix_acl" != xcheck; then
+ AC_MSG_FAILURE([--enable-posix-acl was given, but test for acl support failed])
+ fi
+ fi
+])
+
+AC_DEFUN([sh_CHECK_XATTR],
+[
+ AC_CHECK_HEADERS(attr/xattr.h)
+ if test $ac_cv_header_attr_xattr_h = yes; then
+
+ AC_CHECK_LIB([attr], [getxattr], sh_lattr=yes, sh_lattr=no)
+ if test x"$sh_lattr" = xyes; then
+ LIBATTR=-lattr
+ else
+ LIBATTR=
+ fi
+
+ OLDLIBS="$LIBS"
+ LIBS="$LIBS $LIBATTR"
+ AC_CHECK_FUNCS([getxattr lgetxattr fgetxattr],
+ [sh_fattr=yes],[sh_fattr=no])
+ LIBS="$OLDLIBS"
+ fi
+
+ if test x"$sh_fattr" = xyes; then
+ AC_DEFINE(USE_XATTR, 1, [Define if you want extended attributes support.])
+ LIBS="$LIBS $LIBATTR"
+ else
+ if test "x$enable_selinux" != xcheck; then
+ AC_MSG_FAILURE([--enable-selinux was given, but test for selinux support failed])
+ fi
+ fi
+])
+
+dnl Autoconf macros for libprelude
+dnl $id$
+
+# Modified for LIBPRELUDE -- Yoann Vandoorselaere
+# Modified for LIBGNUTLS -- nmav
+# Configure paths for LIBGCRYPT
+# Shamelessly stolen from the one of XDELTA by Owen Taylor
+# Werner Koch 99-12-09
+
+dnl AM_PATH_LIBPRELUDE([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
+dnl Test for libprelude, and define LIBPRELUDE_PREFIX, LIBPRELUDE_CFLAGS, LIBPRELUDE_PTHREAD_CFLAGS,
+dnl LIBPRELUDE_LDFLAGS, and LIBPRELUDE_LIBS
+dnl
+AC_DEFUN([AM_PATH_LIBPRELUDE],
+[dnl
+dnl Get the cflags and libraries from the libprelude-config script
+dnl
+dnl AC_ARG_WITH(libprelude-prefix,
+dnl [ --with-libprelude-prefix=PFX Prefix where libprelude is installed (optional)],
+dnl libprelude_config_prefix="$withval", libprelude_config_prefix="")
+dnl
+dnl if test x$libprelude_config_prefix != x ; then
+dnl if test x${LIBPRELUDE_CONFIG+set} != xset ; then
+dnl LIBPRELUDE_CONFIG=$libprelude_config_prefix/bin/libprelude-config
+dnl fi
+dnl fi
+dnl
+dnl AC_PATH_PROG(LIBPRELUDE_CONFIG, libprelude-config, no)
+ min_libprelude_version=ifelse([$1], ,0.1.0,$1)
+ AC_MSG_CHECKING(for libprelude - version >= $min_libprelude_version)
+ no_libprelude=""
+ if test "$LIBPRELUDE_CONFIG" = "no" ; then
+ no_libprelude=yes
+ else
+ LIBPRELUDE_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --cflags`
+ LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --pthread-cflags`
+ LIBPRELUDE_LDFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --ldflags`
+ LIBPRELUDE_LIBS=`$LIBPRELUDE_CONFIG $libprelude_config_args --libs`
+ LIBPRELUDE_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --prefix`
+ LIBPRELUDE_CONFIG_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --config-prefix`
+ libprelude_config_version=`$LIBPRELUDE_CONFIG $libprelude_config_args --version`
+
+
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LDFLAGS="$LDFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS"
+ LIBS="$LIBS $LIBPRELUDE_LIBS"
+dnl
+dnl Now check if the installed libprelude is sufficiently new. Also sanity
+dnl checks the results of libprelude-config to some extent
+dnl
+ rm -f conf.libpreludetest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libprelude/prelude.h>
+
+int
+main ()
+{
+ system ("touch conf.libpreludetest");
+
+ if( strcmp( prelude_check_version(NULL), "$libprelude_config_version" ) )
+ {
+ printf("\n*** 'libprelude-config --version' returned %s, but LIBPRELUDE (%s)\n",
+ "$libprelude_config_version", prelude_check_version(NULL) );
+ printf("*** was found! If libprelude-config was correct, then it is best\n");
+ printf("*** to remove the old version of LIBPRELUDE. You may also be able to fix the error\n");
+ printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+ printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+ printf("*** required on your system.\n");
+ printf("*** If libprelude-config was wrong, set the environment variable LIBPRELUDE_CONFIG\n");
+ printf("*** to point to the correct copy of libprelude-config, and remove the file config.cache\n");
+ printf("*** before re-running configure\n");
+ }
+ else if ( strcmp(prelude_check_version(NULL), LIBPRELUDE_VERSION ) )
+ {
+ printf("\n*** LIBPRELUDE header file (version %s) does not match\n", LIBPRELUDE_VERSION);
+ printf("*** library (version %s)\n", prelude_check_version(NULL) );
+ }
+ else
+ {
+ if ( prelude_check_version( "$min_libprelude_version" ) )
+ {
+ return 0;
+ }
+ else
+ {
+ printf("no\n*** An old version of LIBPRELUDE (%s) was found.\n",
+ prelude_check_version(NULL) );
+ printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n",
+ "$min_libprelude_version" );
+ printf("*** LIBPRELUDE is always available from http://www.prelude-ids.org/download/releases.\n");
+ printf("*** \n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the libprelude-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of LIBPRELUDE, but you can also set the LIBPRELUDE_CONFIG environment to point to the\n");
+ printf("*** correct copy of libprelude-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ }
+ return 1;
+}
+],, no_libprelude=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ LDFLAGS="$ac_save_LDFLAGS"
+ fi
+
+ if test "x$no_libprelude" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$2], , :, [$2])
+ else
+ if test -f conf.libpreludetest ; then
+ :
+ else
+ AC_MSG_RESULT(no)
+ fi
+ if test "$LIBPRELUDE_CONFIG" = "no" ; then
+ echo "*** The libprelude-config script installed by LIBPRELUDE could not be found"
+ echo "*** If LIBPRELUDE was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the LIBPRELUDE_CONFIG environment variable to the"
+ echo "*** full path to libprelude-config."
+ else
+ if test -f conf.libpreludetest ; then
+ :
+ else
+ echo "*** Could not run libprelude test program, checking why..."
+ CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS"
+ LIBS="$LIBS $LIBPRELUDE_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libprelude/prelude.h>
+], [ return !!prelude_check_version(NULL); ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding LIBPRELUDE or finding the wrong"
+ echo "*** version of LIBPRELUDE. If it is not finding LIBPRELUDE, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***" ],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means LIBPRELUDE was incorrectly installed"
+ echo "*** or that you have moved LIBPRELUDE since it was installed. In the latter case, you"
+ echo "*** may want to edit the libprelude-config script: $LIBPRELUDE_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ LDFLAGS="$ac_save_LDFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ LIBPRELUDE_CFLAGS=""
+ LIBPRELUDE_LDFLAGS=""
+ LIBPRELUDE_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ rm -f conf.libpreludetest
+ AC_SUBST(LIBPRELUDE_CFLAGS)
+ AC_SUBST(LIBPRELUDE_PTHREAD_CFLAGS)
+ AC_SUBST(LIBPRELUDE_LDFLAGS)
+ AC_SUBST(LIBPRELUDE_LIBS)
+ AC_SUBST(LIBPRELUDE_PREFIX)
+ AC_SUBST(LIBPRELUDE_CONFIG_PREFIX)
+])
+
+
+##### http://autoconf-archive.cryp.to/acx_pthread.html
+#
+# SYNOPSIS
+#
+# ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+# This macro figures out how to build C programs using POSIX threads.
+# It sets the PTHREAD_LIBS output variable to the threads library and
+# linker flags, and the PTHREAD_CFLAGS output variable to any special
+# C compiler flags that are needed. (The user can also force certain
+# compiler flags/libs to be tested by setting these environment
+# variables.)
+#
+# Also sets PTHREAD_CC to any special C compiler that is needed for
+# multi-threaded programs (defaults to the value of CC otherwise).
+# (This is necessary on AIX to use the special cc_r compiler alias.)
+#
+# NOTE: You are assumed to not only compile your program with these
+# flags, but also link it with them as well. e.g. you should link
+# with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+# $LIBS
+#
+# If you are only building threads programs, you may wish to use
+# these variables in your default LIBS, CFLAGS, and CC:
+#
+# LIBS="$PTHREAD_LIBS $LIBS"
+# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+# CC="$PTHREAD_CC"
+#
+# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+# constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+# ACTION-IF-FOUND is a list of shell commands to run if a threads
+# library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+# run it if it is not found. If ACTION-IF-FOUND is not specified, the
+# default action will define HAVE_PTHREAD.
+#
+# Please let the authors know if this macro fails on any platform, or
+# if you have any other suggestions or comments. This macro was based
+# on work by SGJ on autoconf scripts for FFTW (http://www.fftw.org/)
+# (with help from M. Frigo), as well as ac_pthread and hb_pthread
+# macros posted by Alejandro Forero Cuervo to the autoconf macro
+# repository. We are also grateful for the helpful feedback of
+# numerous users.
+#
+# LAST MODIFICATION
+#
+# 2007-07-29
+#
+# COPYLEFT
+#
+# Copyright (c) 2007 Steven G. Johnson <stevenj@alum.mit.edu>
+#
+# This program is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright
+# owner gives unlimited permission to copy, distribute and modify the
+# configure scripts that are the output of Autoconf when processing
+# the Macro. You need not follow the terms of the GNU General Public
+# License when using or distributing such scripts, even though
+# portions of the text of the Macro appear in them. The GNU General
+# Public License (GPL) does govern all other use of the material that
+# constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the
+# Autoconf Macro released by the Autoconf Macro Archive. When you
+# make and distribute a modified version of the Autoconf Macro, you
+# may extend this special exception to the GPL to apply to your
+# modified version as well.
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -pthread)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LDFLAGS="$LDFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ LDFLAGS="$save_LDFLAGS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ # Solaris lossage: default is obsolete semantics for getpwnam_r,
+ # getpwuid_r, getgrgid_r, unless _POSIX_PTHREAD_SEMANTICS is defined
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ *solaris*) flag="-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ # Detect PTHREAD_MUTEX_RECURSIVE
+ AC_MSG_CHECKING([for recursive mutexes])
+ mutex_recursive=no
+ AC_TRY_LINK([
+#define _XOPEN_SOURCE 500
+#include <pthread.h>], [
+pthread_mutexattr_t mta;
+pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+return 0;],[mutex_recursive=yes])
+ if test "x$mutex_recursive" = "xyes"
+ then
+ AC_DEFINE(HAVE_PTHREAD_MUTEX_RECURSIVE,1,[Define if you have recursive mutexes.])
+ fi
+ AC_MSG_RESULT($mutex_recursive)
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+ else
+ PTHREAD_CC=$CC
+ fi
+else
+ PTHREAD_CC="$CC"
+fi
+
+if test x"$acx_pthread_ok" = xyes; then
+ PTHREAD_CFLAGS="${PTHREAD_CFLAGS} -DUSE_MALLOC_LOCK=1"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_LDFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
+
+
+
+
+dnl Copyright © 2004 Loic Dachary <loic@senga.org>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or (at
+dnl your option) any later version.
+dnl
+dnl Use ZLIB_HOME instead of option
+
+AC_DEFUN([CHECK_ZLIB],[
+
+if test "x${ZLIB_HOME}" = "x"; then
+ ZLIB_HOME=/usr/local
+ if test ! -f "${ZLIB_HOME}/include/zlib.h"
+ then
+ ZLIB_HOME=/usr
+ fi
+fi
+
+zlib_found=no
+
+ZLIB_OLD_LDFLAGS=$LDFLAGS
+ZLIB_OLD_CPPFLAGS=$LDFLAGS
+if test "x${ZLIB_HOME}" = "x/usr"; then
+ :
+else
+ LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
+ CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
+fi
+AC_LANG_SAVE
+AC_LANG_C
+AC_CHECK_LIB(z, inflateEnd, [zlib_cv_libz=yes], [zlib_cv_libz=no])
+AC_CHECK_HEADER(zlib.h, [zlib_cv_zlib_h=yes], [zlib_cv_zlib_h=no])
+AC_LANG_RESTORE
+if test "$zlib_cv_libz" = "yes" -a "$zlib_cv_zlib_h" = "yes"
+then
+ #
+ # If both library and header were found, use them
+ #
+ AC_CHECK_LIB(z, inflateEnd)
+ AC_MSG_CHECKING([zlib in ${ZLIB_HOME}])
+ AC_MSG_RESULT(ok)
+ AC_CHECK_FUNCS([compressBound])
+ zlib_found=yes
+else
+ #
+ # If either header or library was not found, revert and bomb
+ #
+ AC_MSG_CHECKING(zlib in ${ZLIB_HOME})
+ LDFLAGS="$ZLIB_OLD_LDFLAGS"
+ CPPFLAGS="$ZLIB_OLD_CPPFLAGS"
+ AC_MSG_RESULT(failed)
+ AC_MSG_WARN([zlib not found in ZLIB_HOME, /usr/local, or /usr])
+fi
+
+])
+
+# SH_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([SH_PROG_LD],
+[
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+else
+ AC_MSG_CHECKING([for ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ with_gnu_ld=yes
+ ;;
+ *)
+ with_gnu_ld=no
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AC_PROG_LD_GNU
+
+# SH_STRFTIME_Z
+# -------------
+# check whether strftime supports %z
+AC_DEFUN([SH_STRFTIME_Z],
+[
+AC_MSG_CHECKING([whether strftime supports %z])
+AC_TRY_RUN([
+#include <time.h>
+#include <string.h>
+int main()
+{
+ struct tm tm;
+ char tt[64];
+ memset(&tm, 0, sizeof(tm));
+ strftime(tt, sizeof(tt), "%z", &tm);
+
+ if (strlen(tt) != 5) return 1;
+ return 0;
+}
+],
+[
+AC_MSG_RESULT([yes])
+AC_DEFINE(HAVE_STRFTIME_Z, 1, [strftime supports %z])
+],
+[
+AC_MSG_RESULT([no])
+],[
+AC_MSG_RESULT([no])
+])])
+
+AC_DEFUN([SH_GCC_VERSION], [
+ GCC_VERSION=""
+ gcc_VERSION_MAJOR=0
+ gcc_VERSION_MINOR=0
+ AC_MSG_CHECKING([for gcc version])
+ if test "x$GCC" = "xyes"
+ then
+ $CC -dumpversion >/dev/null 2>&1
+ if test $? -eq 0
+ then
+ GCC_VERSION=`$CC -dumpversion`
+ gcc_VERSION_MAJOR=`echo $GCC_VERSION | cut -d'.' -f1`
+ gcc_VERSION_MINOR=`echo $GCC_VERSION | cut -d'.' -f2`
+ AC_DEFINE_UNQUOTED(GCC_VERSION_MAJOR, [${gcc_VERSION_MAJOR}], [gcc version major])
+ AC_DEFINE_UNQUOTED(GCC_VERSION_MINOR, [${gcc_VERSION_MINOR}], [gcc version minor])
+ AC_MSG_RESULT([$GCC_VERSION])
+ else
+ AC_MSG_RESULT([$CC -dumpversion working])
+ fi
+ else
+ AC_MSG_RESULT([compiler is not gcc])
+ fi
+])
+
+
+
+dnl *-*wedit:notab*-* Please keep this as the last line.
+
diff --git a/c_bits.sh b/c_bits.sh
new file mode 100755
index 0000000..795abfa
--- /dev/null
+++ b/c_bits.sh
@@ -0,0 +1,133 @@
+#! /bin/sh
+
+
+# get bits of $1
+
+# make sure it fits in 16 bit
+ORIG=`expr $1 \% 65536`
+
+# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+# 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
+
+N=0
+
+N=`expr $ORIG \/ 32768`
+N_16=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_16 1"
+fi
+ORIG=`expr $ORIG \- $N_16 \* 32768`
+
+N=`expr $ORIG / 16384`
+N_15=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_15 1"
+fi
+ORIG=`expr $ORIG \- $N_15 \* 16384`
+
+N=`expr $ORIG \/ 8192`
+N_14=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_14 1"
+fi
+ORIG=`expr $ORIG \- $N_14 \* 8192`
+
+N=`expr $ORIG \/ 4096`
+N_13=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_13 1"
+fi
+ORIG=`expr $ORIG \- $N_13 \* 4096`
+
+N=`expr $ORIG \/ 2048`
+N_12=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_12 1"
+fi
+ORIG=`expr $ORIG \- $N_12 \* 2048`
+
+N=`expr $ORIG \/ 1024`
+N_11=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_11 1"
+fi
+ORIG=`expr $ORIG \- $N_11 \* 1024`
+
+N=`expr $ORIG \/ 512`
+N_10=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_10 1"
+fi
+ORIG=`expr $ORIG \- $N_10 \* 512`
+
+N=`expr $ORIG \/ 256`
+N_09=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_09 1"
+fi
+ORIG=`expr $ORIG \- $N_09 \* 256`
+
+N=`expr $ORIG \/ 128`
+N_08=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_08 1"
+fi
+ORIG=`expr $ORIG \- $N_08 \* 128`
+
+N=`expr $ORIG \/ 64`
+N_07=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_07 1"
+fi
+ORIG=`expr $ORIG \- $N_07 \* 64`
+
+N=`expr $ORIG \/ 32`
+N_06=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_06 1"
+fi
+ORIG=`expr $ORIG \- $N_06 \* 32`
+
+N=`expr $ORIG \/ 16`
+N_05=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_05 1"
+fi
+ORIG=`expr $ORIG \- $N_05 \* 16`
+
+N=`expr $ORIG \/ 8`
+N_04=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_04 1"
+fi
+ORIG=`expr $ORIG \- $N_04 \* 8`
+
+N=`expr $ORIG \/ 4`
+N_03=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_03 1"
+fi
+ORIG=`expr $ORIG \- $N_03 \* 4`
+
+N=`expr $ORIG \/ 2`
+N_02=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_02 1"
+fi
+ORIG=`expr $ORIG \- $N_02 \* 2`
+
+N=`expr $ORIG \/ 1`
+N_01=$N
+if test "x$N" = "x1"; then
+ echo "#define $2_01 1"
+fi
+ORIG=`expr $ORIG \- $N_01 \* 1`
+
+#
+# obsolete
+#
+# echo ${N_01} ${N_02} ${N_03} ${N_04} ${N_05} ${N_06} ${N_07} ${N_08} ${N_09} ${N_10} ${N_11} ${N_12} ${N_13} ${N_14} ${N_15} ${N_16}
+
+exit 0
+
+
diff --git a/c_random.sh b/c_random.sh
new file mode 100755
index 0000000..cc863aa
--- /dev/null
+++ b/c_random.sh
@@ -0,0 +1,232 @@
+#! /bin/sh
+
+# this program collects some entropy from the system
+# into the file "my_random_file" and outputs the 16-bit
+# Unix 'sum' checksum (seems to be the only portable way
+# to get true entropy with a shell script).
+
+# Apparently, on FreeBSD /dev/random does not block (???), must make sure
+# we really got something rather than nothing.
+
+rnd_tst=no
+
+/bin/rm -f ./my_random_file 2>/dev/null
+
+if test -r "/dev/urandom"; then
+ if test -c "/dev/urandom"; then
+ dd if=/dev/urandom ibs=1 count=4 > my_random_file 2>/dev/null
+ nsum=`sum ./my_random_file | awk '{print $1 }' | sed 's%^0*%%g' 2>/dev/null`
+ if test x$nsum != x; then
+ rnd_tst=yes
+ fi
+ fi
+fi
+
+if test x$rnd_tst = xno; then
+ if test -r "/dev/srandom"; then
+ if test -c "/dev/srandom"; then
+ dd if=/dev/srandom ibs=1 count=4 > my_random_file 2>/dev/null
+ nsum=`sum ./my_random_file | awk '{print $1 }' | sed 's%^0*%%g' 2>/dev/null`
+ if test x$nsum != x; then
+ rnd_tst=yes
+ fi
+ fi
+ fi
+fi
+
+if test x$rnd_tst = xno; then
+#
+ touch ./my_random_file
+#
+ if test -r "/usr/ucb/vmstat"; then
+ /usr/ucb/vmstat >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/vmstat"; then
+ /bin/vmstat >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/vmstat"; then
+ /sbin/vmstat >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/vmstat"; then
+ /usr/bin/vmstat >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/vmstat"; then
+ /usr/sbin/vmstat >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/vmstat"; then
+ /usr/local/bin/vmstat >> my_random_file 2>/dev/null
+ fi
+#
+ if test -r "/usr/ucb/netstat"; then
+ /usr/ucb/netstat -n >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/netstat"; then
+ /bin/netstat -n >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/netstat"; then
+ /sbin/netstat -n >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/netstat"; then
+ /usr/bin/netstat -n >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/netstat"; then
+ /usr/sbin/netstat -n >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/netstat"; then
+ /usr/local/bin/netstat -n >> my_random_file 2>/dev/null
+ fi
+#
+#
+ if test -r "/usr/ucb/ps"; then
+ /usr/ucb/ps -ef >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/ps"; then
+ /bin/ps -ef >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/ps"; then
+ /sbin/ps -ef >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/ps"; then
+ /usr/bin/ps -ef >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/ps"; then
+ /usr/sbin/ps -ef >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/ps"; then
+ /usr/local/bin/ps -ef >> my_random_file 2>/dev/null
+ fi
+#
+#
+ if test -r "/usr/ucb/arp"; then
+ /usr/ucb/arp -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/arp"; then
+ /bin/arp -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/arp"; then
+ /sbin/arp -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/arp"; then
+ /usr/bin/arp -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/arp"; then
+ /usr/sbin/arp -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/arp"; then
+ /usr/local/bin/arp -a >> my_random_file 2>/dev/null
+ fi
+#
+#
+ if test -r "/usr/ucb/w"; then
+ /usr/ucb/w >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/w"; then
+ /bin/w >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/w"; then
+ /sbin/w >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/w"; then
+ /usr/bin/w >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/w"; then
+ /usr/sbin/w >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/w"; then
+ /usr/local/bin/w >> my_random_file 2>/dev/null
+ fi
+#
+# Don't use (NFS problems ahead)
+#
+# if test -r "/usr/ucb/df"; then
+# /usr/ucb/df >> my_random_file 2>/dev/null
+# fi
+# if test -r "/bin/df"; then
+# /bin/df >> my_random_file 2>/dev/null
+# fi
+# if test -r "/sbin/df"; then
+# /sbin/df >> my_random_file 2>/dev/null
+# fi
+# if test -r "/usr/bin/df"; then
+# /usr/bin/df >> my_random_file 2>/dev/null
+# fi
+# if test -r "/usr/sbin/df"; then
+# /usr/sbin/df >> my_random_file 2>/dev/null
+# fi
+# if test -r "/usr/local/bin/df"; then
+# /usr/local/bin/df >> my_random_file 2>/dev/null
+# fi
+#
+#
+ if test -r "/usr/ucb/free"; then
+ /usr/ucb/free >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/free"; then
+ /bin/free >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/free"; then
+ /sbin/free >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/free"; then
+ /usr/bin/free >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/free"; then
+ /usr/sbin/free >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/free"; then
+ /usr/local/bin/free >> my_random_file 2>/dev/null
+ fi
+#
+#
+ if test -r "/usr/ucb/uptime"; then
+ /usr/ucb/uptime >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/uptime"; then
+ /bin/uptime >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/uptime"; then
+ /sbin/uptime >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/uptime"; then
+ /usr/bin/uptime >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/uptime"; then
+ /usr/sbin/uptime >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/uptime"; then
+ /usr/local/bin/uptime >> my_random_file 2>/dev/null
+ fi
+#
+#
+ if test -r "/usr/ucb/procinfo"; then
+ /usr/ucb/procinfo -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/bin/procinfo"; then
+ /bin/procinfo -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/sbin/procinfo"; then
+ /sbin/procinfo -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/bin/procinfo"; then
+ /usr/bin/procinfo -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/sbin/procinfo"; then
+ /usr/sbin/procinfo -a >> my_random_file 2>/dev/null
+ fi
+ if test -r "/usr/local/bin/procinfo"; then
+ /usr/local/bin/procinfo -a >> my_random_file 2>/dev/null
+ fi
+#
+ nsum=`sum ./my_random_file | awk '{print $1 }' | sed 's%^0*%%g' 2>/dev/null`
+#
+fi
+
+#
+# 'sum' is portable, but only 16 bit
+#
+
+/bin/rm -f ./my_random_file 2>/dev/null
+
+echo $nsum
+
+
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..1f5c50c
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1420 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-03-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval $set_cc_for_build
+ cat <<-EOF > $dummy.c
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-${LIBC}
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-${LIBC}
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval $set_cc_for_build
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..1637eb5
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,1162 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+
+/* ---- compile options ------------ */
+
+/* Define if you want database support */
+#undef WITH_DATABASE
+
+/* Define if the database is unixODBC */
+#undef WITH_ODBC
+
+/* Define if the database is oracle */
+#undef WITH_ORACLE
+
+/* Define if the database is mysql */
+#undef WITH_MYSQL
+
+/* Define if the database is postgresql */
+#undef WITH_POSTGRES
+
+/* Define if the server may listen on 514/udp */
+#undef INET_SYSLOG
+
+/* Define if you want logfile in XML format */
+#undef SH_USE_XML
+
+/* Define if you want external programs. */
+#undef WITH_EXTERNAL
+
+/* Define if you want to reload the database */
+/* on SIGHUP. */
+#undef RELOAD_DATABASE
+
+/* Define if you want SysV message queue. */
+#undef WITH_MESSAGE_QUEUE
+
+/* Define the mode of the message queue. */
+#undef MESSAGE_QUEUE_MODE
+
+/* Define which users are always trusted. */
+/* default = 0 ( = root) */
+#undef SL_ALWAYS_TRUSTED
+
+/* Define if you want network time. */
+/* default = no */
+#undef HAVE_NTIME
+
+/* The time server host address. */
+/* default = "NULL" */
+#undef DEFAULT_TIMESERVER
+#undef ALT_TIMESERVER
+
+/* Define if you want to use the mail code. */
+/* default = yes */
+#undef SH_WITH_MAIL
+
+/* Define if you want client/server encryption*/
+#undef SH_ENCRYPT
+
+/* Define if you want version 2 encryption */
+#undef SH_ENCRYPT_2
+
+/* Define if you want to watch for login/-out.*/
+/* default = no */
+#undef SH_USE_UTMP
+
+/* Define if you want to check mount options on filesystems */
+/* default = no */
+#undef SH_USE_MOUNTS
+
+/* Define if you want to keep an eye on */
+/* sensitive files that your users own */
+#undef SH_USE_USERFILES
+
+/* Define if you want to watch for suid/sgid */
+/* files */
+#undef SH_USE_SUIDCHK
+
+/* Define if you want to check kernel syscall */
+/* table to detect LKM rootkits. */
+/* default = no */
+#undef SH_USE_KERN
+
+/* Define if you want to use the Kernel */
+/* module to hide samhain. */
+#undef SH_USE_LKM
+
+/* Define if you have a vanilla Kernel */
+/* (2.4 or 2.2) */
+#undef SH_VANILLA_KERNEL
+
+/* Define to the name of the MAGIC_HIDE */
+/* string if you use the Kernel module to */
+/* hide samhain. */
+#undef SH_MAGIC_HIDE
+
+/* Define if you want 'micro' stealth mode. */
+/* default = no */
+#undef SH_STEALTH_MICRO
+
+/* Define if you want to use stealth mode. */
+/* default = no */
+#undef SH_STEALTH
+
+/* Define if you want stealth w/o CL parsing. */
+/* default = no */
+#undef SH_STEALTH_NOCL
+
+/* The magic argv[1] to re-enable CL parsing. */
+/* default = "yes" */
+#undef NOCL_CODE
+
+/* XOR value to hide literal strings. */
+/* default = 0 */
+#undef XOR_CODE
+
+/* The port number for TCP/IP connection. */
+/* default = 49777 */
+#undef SH_DEFAULT_PORT
+
+/* The identity to assume when dropping root */
+/* default = "nobody" */
+#undef DEFAULT_IDENT
+
+/* Directory for tmp files */
+#undef SH_TMPDIR
+
+/* The data root directory. */
+/* default="/var/lib/samhain" */
+#undef DEFAULT_DATAROOT
+
+/* The quarantine directory. */
+/* default="/var/lib/samhain/.quarantine */
+#undef DEFAULT_QDIR
+
+/* The location of the log file. */
+/* default="/var/log/samhain_log" */
+#undef DEFAULT_ERRFILE
+
+/* The directory of the log file. */
+/* default="/var/log" */
+#undef DEFAULT_LOGDIR
+
+/* The location of the pid file. */
+/* default="/var/run/samhain.pid" */
+#undef DEFAULT_ERRLOCK
+
+/* The location of the pid file directory. */
+/* default="/var/run " */
+#undef DEFAULT_PIDDIR
+
+/* The location of the configuration file. */
+/* default="/etc/samhainrc" */
+#undef DEFAULT_CONFIGFILE
+
+/* The location of the checksum data. */
+/* default="/var/lib/samhain/samhain_file" */
+#undef DEFAULT_DATA_FILE
+
+/* The location of the html report. */
+/* default="/var/log/.samhain.html" */
+#undef DEFAULT_HTML_FILE
+
+/* The install directory. */
+/* default="/usr/local/sbin" */
+#undef SH_INSTALL_DIR
+
+/* The install path. */
+/* default="/usr/local/sbin/samhain" */
+#undef SH_INSTALL_PATH
+#undef SH_INSTALL_YULE_PATH
+
+/* The install name. */
+/* default="samhain" */
+#undef SH_INSTALL_NAME
+
+/* The sender name to use. */
+/* default = "daemon" */
+#undef DEFAULT_SENDER
+
+/* The address to send mail to. */
+/* default = "NULL" */
+#undef DEFAULT_MAILADDRESS
+#undef ALT_MAILADDRESS
+
+/* The log server. */
+/* default = "NULL" */
+#undef DEFAULT_LOGSERVER
+#undef ALT_LOGSERVER
+
+/* The console. */
+/* default = "NULL" */
+#undef DEFAULT_CONSOLE
+#undef ALT_CONSOLE
+
+/* The default base for one-time pads. */
+/* default = compile_time,compile_time */
+#undef DEFKEY
+
+/* Define if you want more debug options. */
+/* default = no */
+#undef MEM_DEBUG
+
+/* Define if you want more debug output. */
+/* default = no */
+#undef WITH_TPT
+
+/* Define if you want tracing. */
+/* default = no */
+#undef WITH_TRACE
+
+/* Define if you want slib debug. */
+/* default = no */
+#undef SL_DEBUG
+
+/* Define if you want slib to abort on errors.*/
+/* default = no */
+#undef SL_FAIL_ON_ERROR
+
+/* Define if you want to use SRP authenticaton*/
+#undef USE_SRP_PROTOCOL
+
+/* Define if you want to use GnuPG to */
+/* verify database and configuation file. */
+#undef WITH_GPG
+
+/* The full path to GnuPG */
+#undef DEFAULT_GPG_PATH
+
+/* Define if using the gpg/pgp checksum. */
+#undef HAVE_GPG_CHECKSUM
+
+/* The tiger checksum of the gpg/pgp binary. */
+#undef GPG_HASH
+
+/* Define if you want to compile in the */
+/* public key fingerprint. */
+#undef USE_FINGERPRINT
+
+/* The public key fingerprint. */
+#undef SH_GPG_FP
+
+/* Use ptrace - screw up signal handling. */
+#undef SCREW_IT_UP
+
+/* ---- misc ------------ */
+
+/* Define the package name. */
+#undef PACKAGE
+
+/* Define the package version. */
+#undef VERSION
+
+/* Define to the position of the key (1...8). */
+#undef POS_TF
+
+/* Init key for exepack. */
+#undef EXEPACK_STATE_0
+#undef EXEPACK_STATE_1
+#undef EXEPACK_STATE_2
+
+/* ---- system-specific options ------------ */
+
+/* Define to the address of sys_call_table */
+#undef SH_SYSCALLTABLE
+
+/* Define to use SVR4 statvfs to get filesystem type. */
+#undef FSTYPE_STATVFS
+
+/* Define to use SVR3.2 statfs to get filesystem type. */
+#undef FSTYPE_USG_STATFS
+
+/* Define to use AIX3 statfs to get filesystem type. */
+#undef FSTYPE_AIX_STATFS
+
+/* Define to use 4.3BSD getmntent to get filesystem type. */
+#undef FSTYPE_MNTENT
+
+/* Define to use 4.4BSD and OSF1 statfs to get filesystem type. */
+#undef FSTYPE_STATFS
+
+/* Define to use Ultrix getmnt to get filesystem type. */
+#undef FSTYPE_GETMNT
+
+/* the basic type to which we can cast a uid
+ */
+#undef UID_CAST
+
+/* for ext2fs flags */
+#undef HAVE_EXT2_IOCTLS
+#undef HAVE_STAT_FLAGS
+
+/* obvious */
+#undef HOST_IS_LINUX
+#undef HOST_IS_I86LINUX
+
+/* obvious */
+#undef HOST_IS_CYGWIN
+
+/* obvious */
+#undef HOST_IS_DARWIN
+
+/* obvious */
+#undef HOST_IS_FREEBSD
+
+/* obvious */
+#undef HOST_IS_AIX
+
+/* obvious */
+#undef HOST_IS_SOLARIS
+
+/* obvious */
+#undef HOST_IS_I86SOLARIS
+
+/* obvious */
+#undef HOST_IS_HPUX
+
+/* Define to the name of the random devices. */
+#undef NAME_OF_DEV_RANDOM
+
+#undef NAME_OF_DEV_URANDOM
+
+/* Define if you have long long. */
+#undef HAVE_LONG_LONG
+
+/* Define if short is 32 bits. */
+#undef HAVE_SHORT_32
+
+/* Define if int is 32 bits. */
+#undef HAVE_INT_32
+
+/* Define if long is 32 bits. */
+#undef HAVE_LONG_32
+
+/* Define if long is 64 bits. */
+#undef HAVE_LONG_64
+
+/* Define if UINT64 is 32 bits. */
+#undef UINT64_IS_32
+
+/* Define if you have uint64_t. */
+#undef HAVE_UINT16_T
+
+/* Define if you have uint64_t. */
+#undef HAVE_UINT64_T
+
+/* Define if you have utmpx.h. */
+#undef HAVE_UTMPX_H
+
+/* Define if your struct utmpx has ut_xtime. */
+#undef HAVE_UTXTIME
+
+/* Define if your struct utmp has ut_type. */
+#undef HAVE_UTTYPE
+
+/* Define if your struct utmp has ut_host. */
+#undef HAVE_UTHOST
+
+/* Define if your struct utmp has ut_addr. */
+#undef HAVE_UTADDR
+
+/* Define if your struct utmp has ut_addr_v6 */
+#undef HAVE_UTADDR_V6
+
+/* Define if your includes are broken. */
+#undef HAVE_BROKEN_INCLUDES
+
+/* Define if your getcwd uses 'popen'. */
+#undef HAVE_BROKEN_GETCWD
+
+/* Define if your vsnprintf is broken. */
+#undef HAVE_BROKEN_VSNPRINTF
+
+/* Define if you have va_copy. */
+#undef VA_COPY
+
+/* Define if va_list may be copied as array. */
+#undef VA_COPY_AS_ARRAY
+
+/* Define if you need unix entropy gatherer. */
+#undef HAVE_UNIX_RANDOM
+
+/* Define if you have EGD. */
+#undef HAVE_EGD_RANDOM
+
+/* Define if you have /dev/random. */
+#undef HAVE_URANDOM
+
+/* Soket name for EGD. */
+#undef EGD_SOCKET_NAME
+
+/* Define if your mlock() is broken. */
+#undef HAVE_BROKEN_MLOCK
+
+/* Define the proc f_type. */
+#undef SH_PROC_MAGIC
+
+/* Define if you have statfs. */
+#undef HAVE_STATFS
+
+/* Define if statfs works. */
+#undef STATFS_WORKS
+
+/* Define to long if not defined. */
+#undef ptrdiff_t
+
+
+/* type of arg3 of accept */
+#undef ACCEPT_TYPE_ARG3
+
+/* Define if <sys/acct.h>'s AC_ETIME field is a COMP_T. */
+#undef ACETIME_COMPT
+
+/* Define if <sys/acct.h>'s AC_IO field is a COMP_T. */
+#undef ACIO_COMPT
+
+/* Define if <sys/acct.h>'s AC_MAJFLT field is a COMP_T. */
+#undef ACMAJFLT_COMPT
+
+/* Define if <sys/acct.h>'s AC_MEM field is a COMP_T. */
+#undef ACMEM_COMPT
+
+/* Define if <sys/acct.h>'s AC_MINFLT field is a COMP_T. */
+#undef ACMINFLT_COMPT
+
+/* Define if <sys/acct.h>'s AC_STIME field is a COMP_T. */
+#undef ACSTIME_COMPT
+
+/* Define if <sys/acct.h>'s AC_SWAPS field is a COMP_T. */
+#undef ACSWAPS_COMPT
+
+/* Define if <sys/acct.h>'s AC_UTIME field is a COMP_T. */
+#undef ACUTIME_COMPT
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Debug dnmalloc */
+#undef DNMALLOC_CHECKS
+
+/* Define if SSP C support is enabled. */
+#undef ENABLE_SSP_CC
+
+/* gcc version major */
+#undef GCC_VERSION_MAJOR
+
+/* gcc version minor */
+#undef GCC_VERSION_MINOR
+
+/* Define if <sys/acct.h> has struct acctv2. */
+#undef HAVE_ACCTV2
+
+/* Define if <sys/acct.h> has struct acct_v3. */
+#undef HAVE_ACCT_V3
+
+/* Define if <sys/acct.h> has the AC_ETIME field. */
+#undef HAVE_ACETIME
+
+/* Define if <sys/acct.h> has the AC_IO field. */
+#undef HAVE_ACIO
+
+/* Define to 1 if you have the `acl_free' function. */
+#undef HAVE_ACL_FREE
+
+/* Define to 1 if you have the `acl_get_fd' function. */
+#undef HAVE_ACL_GET_FD
+
+/* Define to 1 if you have the `acl_get_file' function. */
+#undef HAVE_ACL_GET_FILE
+
+/* Define if <sys/acct.h> has the AC_MEM field. */
+#undef HAVE_ACMEM
+
+/* Define if <sys/acct.h> has the AC_STIME field. */
+#undef HAVE_ACSTIME
+
+/* Define if <sys/acct.h> has the AC_UTIME field. */
+#undef HAVE_ACUTIME
+
+/* Define to 1 if you have the <arpa/nameser_compat.h> header file. */
+#undef HAVE_ARPA_NAMESER_COMPAT_H
+
+/* Define to 1 if you have the <arpa/nameser.h> header file. */
+#undef HAVE_ARPA_NAMESER_H
+
+/* Define to 1 if you have the <asm/segment.h> header file. */
+#undef HAVE_ASM_SEGMENT_H
+
+/* Define to 1 if you have the <attr/xattr.h> header file. */
+#undef HAVE_ATTR_XATTR_H
+
+/* Define to 1 if you have the <auparse.h> header file. */
+#undef HAVE_AUPARSE_H
+
+/* Define if you have the auparse lib */
+#undef HAVE_AUPARSE_LIB
+
+/* Define to 1 if you have the `basename' function. */
+#undef HAVE_BASENAME
+
+/* Define if you have a broken version of the `vsnprintf' function. */
+#undef HAVE_BROKEN_VSNPRINTF
+
+/* Define to 1 if you have the `compressBound' function. */
+#undef HAVE_COMPRESSBOUND
+
+/* Define if <sys/acct.h> uses the COMP_T type. */
+#undef HAVE_COMP_T
+
+/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you
+ don't. */
+#undef HAVE_DECL_SYS_SIGLIST
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <elf.h> header file. */
+#undef HAVE_ELF_H
+
+/* Define to 1 if you have the `endpwent' function. */
+#undef HAVE_ENDPWENT
+
+/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */
+#undef HAVE_EXT2FS_EXT2_FS_H
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `fgetxattr' function. */
+#undef HAVE_FGETXATTR
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#undef HAVE_FNMATCH_H
+
+/* Define to 1 if you have the `fpurge' function. */
+#undef HAVE_FPURGE
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getcwd' function. */
+#undef HAVE_GETCWD
+
+/* Define to 1 if you have the `getgrgid_r' function. */
+#undef HAVE_GETGRGID_R
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpeereid' function. */
+#undef HAVE_GETPEEREID
+
+/* Define to 1 if you have the `getpgid' function. */
+#undef HAVE_GETPGID
+
+/* Define to 1 if you have the `getpriority' function. */
+#undef HAVE_GETPRIORITY
+
+/* Define to 1 if you have the `getpwent' function. */
+#undef HAVE_GETPWENT
+
+/* Define to 1 if you have the `getpwnam_r' function. */
+#undef HAVE_GETPWNAM_R
+
+/* Define to 1 if you have the `getpwuid_r' function. */
+#undef HAVE_GETPWUID_R
+
+/* Define to 1 if you have the `getsid' function. */
+#undef HAVE_GETSID
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `getwd' function. */
+#undef HAVE_GETWD
+
+/* Define to 1 if you have the `getxattr' function. */
+#undef HAVE_GETXATTR
+
+/* Define to 1 if you have the <glob.h> header file. */
+#undef HAVE_GLOB_H
+
+/* Define to 1 if you have the <gmp.h> header file. */
+#undef HAVE_GMP_H
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#undef HAVE_GMTIME_R
+
+/* Define to 1 if you have the `hasmntopt' function. */
+#undef HAVE_HASMNTOPT
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the `initgroups' function. */
+#undef HAVE_INITGROUPS
+
+/* Define to 1 if you have the `inotify_init1' function. */
+#undef HAVE_INOTIFY_INIT1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `lgetxattr' function. */
+#undef HAVE_LGETXATTR
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Have GNU gmp library */
+#undef HAVE_LIBGMP
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Have libprelude */
+#undef HAVE_LIBPRELUDE
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <linux/elf.h> header file. */
+#undef HAVE_LINUX_ELF_H
+
+/* Define to 1 if you have the <linux/ext2_fs.h> header file. */
+#undef HAVE_LINUX_EXT2_FS_H
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+#undef HAVE_LINUX_FS_H
+
+/* Define to 1 if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if the type `long double' works and has more range or precision
+ than `double'. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if the type `long double' works and has more range or precision
+ than `double'. */
+#undef HAVE_LONG_DOUBLE_WIDER
+
+/* Define if type is defined in stdint.h or inttypes.h */
+#undef HAVE_LONG_LONG
+
+/* Define if you have 64bit long long */
+#undef HAVE_LONG_LONG_64
+
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `memcmp' function. */
+#undef HAVE_MEMCMP
+
+/* Define to 1 if you have the `memcpy' function. */
+#undef HAVE_MEMCPY
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the `mincore' function. */
+#undef HAVE_MINCORE
+
+/* Define to 1 if you have the `mlock' function. */
+#undef HAVE_MLOCK
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define to 1 if you have the <mysql/mysql.h> header file. */
+#undef HAVE_MYSQL_MYSQL_H
+
+/* Define to 1 if you have the `nanosleep' function. */
+#undef HAVE_NANOSLEEP
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define if <sys/acct.h> has the AC_MINFLT, AC_MAJFLT and AC_SWAPS fields. */
+#undef HAVE_PAGING
+
+/* Define to 1 if you have the <paths.h> header file. */
+#undef HAVE_PATHS_H
+
+/* Define if you have pcre_dfa_exec */
+#undef HAVE_PCRE_DFA_EXEC
+
+/* Define if you have pcre/pcre.h. */
+#undef HAVE_PCRE_PCRE_H
+
+/* Define to 1 if you have the <pgsql/libpq-fe.h> header file. */
+#undef HAVE_PGSQL_LIBPQ_FE_H
+
+/* Define if pmap_getmaps available */
+#undef HAVE_PMAP_GETMAPS
+
+/* Define to 1 if you have the `posix_fadvise' function. */
+#undef HAVE_POSIX_FADVISE
+
+/* Define to 1 if you have the <postgresql/libpq-fe.h> header file. */
+#undef HAVE_POSTGRESQL_LIBPQ_FE_H
+
+/* Define if you have a proc fs */
+#undef HAVE_PROCFS
+
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* Define if you have recursive mutexes. */
+#undef HAVE_PTHREAD_MUTEX_RECURSIVE
+
+/* Define to 1 if you have the `ptrace' function. */
+#undef HAVE_PTRACE
+
+/* Define to 1 if you have the `rand_r' function. */
+#undef HAVE_RAND_R
+
+/* Define to 1 if you have the `readdir_r' function. */
+#undef HAVE_READDIR_R
+
+/* Define to 1 if you have the <regex.h> header file. */
+#undef HAVE_REGEX_H
+
+/* Define to 1 if you have the <rpc/rpcent.h> header file. */
+#undef HAVE_RPC_RPCENT_H
+
+/* Define to 1 if you have the <rpc/rpc.h> header file. */
+#undef HAVE_RPC_RPC_H
+
+/* Define if you have SA_SIGINFO */
+#undef HAVE_SA_SIGINFO
+
+/* Define to 1 if you have the <sched.h> header file. */
+#undef HAVE_SCHED_H
+
+/* Define to 1 if you have the `sched_yield' function. */
+#undef HAVE_SCHED_YIELD
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the `setpriority' function. */
+#undef HAVE_SETPRIORITY
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Define to 1 if you have the `setreuid' function. */
+#undef HAVE_SETREUID
+
+/* Define to 1 if you have the `setrlimit' function. */
+#undef HAVE_SETRLIMIT
+
+/* Define to 1 if you have the `setutent' function. */
+#undef HAVE_SETUTENT
+
+/* Define if you have SI_USER */
+#undef HAVE_SI_USER
+
+/* Define if you have socklen_t */
+#undef HAVE_SOCKLEN_T
+
+/* Have SO_PEERCRED define */
+#undef HAVE_SO_PEERCRED
+
+/* Define to 1 if you have the `statvfs' function. */
+#undef HAVE_STATVFS
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* strftime supports %z */
+#undef HAVE_STRFTIME_Z
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strptime' function. */
+#undef HAVE_STRPTIME
+
+/* Define to 1 if you have the `strsignal' function. */
+#undef HAVE_STRSIGNAL
+
+/* Define to 1 if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Have cmsgcred structure */
+#undef HAVE_STRUCT_CMSGCRED
+
+/* Have fcred structure */
+#undef HAVE_STRUCT_FCRED
+
+/* Have sockcred structure */
+#undef HAVE_STRUCT_SOCKCRED
+
+/* Define to 1 if `f_flags' is a member of `struct statfs'. */
+#undef HAVE_STRUCT_STATFS_F_FLAGS
+
+/* Define if you have the <sys/acct.h> header file. */
+#undef HAVE_SYS_ACCT_H
+
+/* Define to 1 if you have the <sys/acl.h> header file. */
+#undef HAVE_SYS_ACL_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/inotify.h> header file. */
+#undef HAVE_SYS_INOTIFY_H
+
+/* Define to 1 if you have the <sys/ipc.h> header file. */
+#undef HAVE_SYS_IPC_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/msg.h> header file. */
+#undef HAVE_SYS_MSG_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/sem.h> header file. */
+#undef HAVE_SYS_SEM_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/statvfs.h> header file. */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/vfs.h> header file. */
+#undef HAVE_SYS_VFS_H
+
+/* Define to 1 if you have the `ttyname' function. */
+#undef HAVE_TTYNAME
+
+/* Define to 1 if you have the `tzset' function. */
+#undef HAVE_TZSET
+
+/* Define if type is defined in stdint.h or inttypes.h */
+#undef HAVE_UINT16_T
+
+/* Define if type is defined in stdint.h or inttypes.h */
+#undef HAVE_UINT32_T
+
+/* Define if type is defined in stdint.h or inttypes.h */
+#undef HAVE_UINT64_T
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `writev' function. */
+#undef HAVE_WRITEV
+
+/* Define if host OS is 64bit Linux */
+#undef HOST_IS_64LINUX
+
+/* Define if host OS is OPENBSD */
+#undef HOST_IS_OPENBSD
+
+/* Define if host OS is OSF */
+#undef HOST_IS_OSF
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+#undef MAJOR_IN_MKDEV
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+#undef MAJOR_IN_SYSMACROS
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Paranoia level for dnmalloc */
+#undef PARANOIA
+
+/* Argument for ps */
+#undef PSARG
+
+/* Path to ps */
+#undef PSPATH
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* Application is samhain */
+#undef SAMHAIN
+
+/* Define if sa_sigaction works */
+#undef SA_SIGACTION_WORKS
+
+/* Use abort */
+#undef SH_ABORT_ON_ERROR
+
+/* Define if you want to allow suid execution for samhain */
+#undef SH_ALLOW_SUID
+
+/* Define if compiling static */
+#undef SH_COMPILE_STATIC
+
+/* Define if you want shell expansion in configuration file */
+#undef SH_EVAL_SHELL
+
+/* Build with tcp wrapper support */
+#undef SH_USE_LIBWRAP
+
+/* Define if you want to check ports */
+#undef SH_USE_PORTCHECK
+
+/* Define if you want to check processes */
+#undef SH_USE_PROCESSCHECK
+
+/* The size of `char *', as computed by sizeof. */
+#undef SIZEOF_CHAR_P
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `unsigned int', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_INT
+
+/* The size of `unsigned long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* The size of `unsigned long long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG_LONG
+
+/* The size of `unsigned short', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_SHORT
+
+/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+#undef STAT_MACROS_BROKEN
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to use tiger 32 bit i386 assembler */
+#undef TIGER_32_BIT_S
+
+/* Define to use tiger 64 bit implementation */
+#undef TIGER_64_BIT
+
+/* Define to use tiger x86_64 optimized assembly */
+#undef TIGER_OPT_ASM
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define if you want ACL support. */
+#undef USE_ACL
+
+/* Define if you do not want IPv6 */
+#undef USE_IPV4
+
+/* Define if you want the logfile monitor module. */
+#undef USE_LOGFILE_MONITOR
+
+/* Define for registry check */
+#undef USE_REGISTRY_CHECK
+
+/* Define if you want to use the system malloc */
+#undef USE_SYSTEM_MALLOC
+
+/* Define if you want extended attributes support. */
+#undef USE_XATTR
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define if POSIX functions are required */
+#undef _POSIX_SOURCE
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `long' if <sys/types.h> does not define. */
+#undef ptrdiff_t
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+ nothing if this is not supported. Do not define if restrict is
+ supported directly. */
+#undef restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+ __restrict__, even though the corresponding Sun C compiler ends up with
+ "#define restrict _Restrict" or "#define restrict __restrict__" in the
+ previous line. Perhaps some future version of Sun C++ will work with
+ restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* dont modify this, unless you know what you do
+ */
+#define SRP_GENERATOR_1024 "2"
+#define SRP_MODULUS_1024_1 \
+_("f488fd584e49dbcd20b49de49107366b336c380d451d0f7c88b31c7c5b2d8ef6")
+#define SRP_MODULUS_1024_2 \
+_("f3c923c043f0a55b188d8ebb558cb85d38d334fd7c175743a31d186cde33212c")
+#define SRP_MODULUS_1024_3 \
+_("b52aff3ce1b1294018118d7c84a70a72d686c40319c807297aca950cd9969fab")
+#define SRP_MODULUS_1024_4 \
+_("d00a509b0246d3083d66a45d419f9c7cbd894b221926baaba25ec355e92f78c7")
+
+#define SDG_0RETU _("return.\n")
+#define SDG_TERRO _("ERROR: file=<%s>, line=<%d>, reason=<%s>\n")
+#define SDG_AERRO _("ERROR: file=<%s>, line=<%d>, failed_assertion=<%s>\n")
+#define SDG_AFAIL _("FAILED: file=<%s>, line=<%d>, assertion=<%s>\n")
+#define SDG_ENTER _("enter=<%s>\n")
+#define SDG_RETUR _("return=<%s>.\n")
+#define SDG_ERROR _("error=<%ld>.\n")
+
+#ifdef SH_STEALTH
+char * globber(const char * string);
+#define _(string) globber(string)
+#define N_(string) string
+#else
+#define _(string) string
+#define N_(string) string
+#endif
+
+#endif
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..bba4efb
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1799 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-09-11'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..d2da8b2
--- /dev/null
+++ b/configure
@@ -0,0 +1,13734 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="src/samhain.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+mydefargs
+myhtmlfile
+myqdir
+mydataroot
+myrpmdatafile
+mydatafile
+mylockdir
+mylockfile
+mylogdir
+mylogfile
+myrpmconffile
+myconffile
+mytmpdir
+mytrust
+mykeytag
+mykeyid
+mygpg
+mykeybase
+my_key_4
+my_key_3
+my_key_2
+my_key_1
+my_key_B
+my_key_A
+xor_code
+stegin_prg
+INSTALL_NAME
+install_name
+need_user_install
+myident
+nocl_code
+mylogsrv
+myport
+mydebugdef
+HAVE_MYSQL_CONFIG
+LIBPRELUDE_CONFIG_PREFIX
+LIBPRELUDE_PREFIX
+LIBPRELUDE_LIBS
+LIBPRELUDE_LDFLAGS
+LIBPRELUDE_PTHREAD_CFLAGS
+LIBPRELUDE_CFLAGS
+LIBPRELUDE_CONFIG
+PTHREAD_LDFLAGS
+PTHREAD_CFLAGS
+PTHREAD_LIBS
+PTHREAD_CC
+acx_pthread_config
+clmytclient
+mytclient
+sh_main_prg
+samhainadmin_prg
+yulectl_prg
+setpwd_prg
+tiger_src
+sh_libsocket
+selectconfig
+EGREP
+GREP
+cmd_hostname
+AWK
+LN_S
+CPP
+BUILD_CC
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+SET_MAKE
+VERSION
+PACKAGE
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localstatedir
+sysconfdir
+sbindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_largefile
+enable_selinux
+enable_posix_acl
+enable_ssp
+enable_db_reload
+enable_xml_log
+enable_mail
+enable_suid
+enable_shellexpand
+enable_external_scripts
+enable_message_queue
+with_cflags
+with_libs
+with_libwrap
+enable_network
+enable_static
+with_libprelude_prefix
+with_prelude
+with_database
+with_console
+with_altconsole
+with_timeserver
+with_alttimeserver
+enable_login_watch
+enable_mounts_check
+enable_logfile_monitor
+enable_process_check
+enable_port_check
+enable_userfiles
+enable_debug
+enable_asm
+enable_ipv6
+enable_dnmalloc
+enable_ptrace
+with_rnd
+with_egd_socket
+enable_udp
+enable_encrypt
+enable_srp
+with_port
+with_logserver
+with_altlogserver
+enable_nocl
+enable_stealth
+enable_micro_stealth
+enable_install_name
+enable_identity
+enable_suidcheck
+enable_base
+with_gpg
+with_keyid
+with_checksum
+with_fp
+with_recipient
+with_sender
+with_trusted
+with_tmp_dir
+with_config_file
+with_log_file
+with_pid_file
+with_state_dir
+with_data_file
+with_html_file
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+LIBS
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+CPP'
+
+
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+DESTDIR=
+SH_ENABLE_OPTS="selinux posix-acl asm ssp db-reload xml-log message-queue login-watch process-check port-check mounts-check logfile-monitor userfiles debug ptrace static network udp nocl stealth micro-stealth install-name identity khide suidcheck base largefile mail external-scripts encrypt srp dnmalloc ipv6 shellexpand suid"
+SH_WITH_OPTS="prelude libprelude-prefix database libwrap cflags libs console altconsole timeserver alttimeserver rnd egd-socket port logserver altlogserver kcheck gpg keyid checksum fp recipient sender trusted tmp-dir config-file log-file pid-file state-dir data-file html-file"
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+sbindir='${exec_prefix}/sbin'
+sysconfdir='${prefix}/etc'
+localstatedir='${prefix}/var'
+mandir='${prefix}/share/man'
+
+sbindir='${exec_prefix}/sbin'
+sysconfdir='${prefix}/etc'
+localstatedir='${prefix}/var'
+mandir='${prefix}/share/man'
+
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ *=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_feature"
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ ac_enable_check_opt=no
+ for f in ${SH_ENABLE_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_feature}"
+ then
+ ac_enable_check_opt=yes
+ fi
+ done
+ if test x${ac_enable_check_opt} = xno
+ then
+ as_fn_error $? "unrecognized option: $ac_option
+Try \`$0 --help' for more information."
+ fi
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_feature"
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ ac_enable_check_opt=no
+ for f in ${SH_ENABLE_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_feature}"
+ then
+ ac_enable_check_opt=yes
+ fi
+ done
+ if test x${ac_enable_check_opt} = xno
+ then
+ as_fn_error $? "unrecognized option: $ac_option
+Try \`$0 --help' for more information."
+ fi
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix
+ ac_exec_prefix_set="yes"
+ ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg"
+ ac_exec_prefix_set="yes"
+ ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir
+ ac_localstatedir_set="yes"
+ ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg"
+ ac_localstatedir_set="yes"
+ ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir
+ ac_mandir_set="yes"
+ ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg"
+ ac_mandir_set="yes"
+ ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix
+ ac_prefix_set="yes"
+ ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg"
+ ac_prefix_set="yes"
+ ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir
+ ac_sbindir_set="yes"
+ ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg"
+ ac_sbindir_set="yes"
+ ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi | --b)
+ echo "WARNING: bindir will be ignored, use sbindir"
+ ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* \
+ | --bi=* | --b=*)
+ echo "WARNING: bindir will be ignored, use sbindir"
+ ;;
+
+ -datadir | --datadir)
+ echo "WARNING: datadir will be ignored"
+ ;;
+ -datadir=* | --datadir=*)
+ echo "WARNING: datadir will be ignored"
+ ;;
+
+ -includedir | --includedir)
+ echo "WARNING: includedir will be ignored"
+ ;;
+ -includedir=* | --includedir=*)
+ echo "WARNING: includedir will be ignored"
+ ;;
+
+ -infodir | --infodir)
+ echo "WARNING: infodir will be ignored"
+ ;;
+ -infodir=* | --infodir=*)
+ echo "WARNING: infodir will be ignored"
+ ;;
+
+ -libdir | --libdir)
+ echo "WARNING: libdir will be ignored"
+ ;;
+ -libdir=* | --libdir=*)
+ echo "WARNING: libdir will be ignored"
+ ;;
+
+ -libexecdir | --libexecdir)
+ echo "WARNING: libexecdir will be ignored"
+ ;;
+ -libexecdir=* | --libexecdir=*)
+ echo "WARNING: libexecdir will be ignored"
+ ;;
+
+ -sharedstatedir | --sharedstatedir)
+ echo "WARNING: sharedstatedir will be ignored"
+ ;;
+ -sharedstatedir=* | --sharedstatedir=*)
+ echo "WARNING: sharedstatedir will be ignored"
+ ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir
+ ac_sysconfdir_set="yes"
+ ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg"
+ ac_sysconfdir_set="yes"
+ ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ ac_init_version=: ;;
+
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_package"
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ ac_with_check_opt=no
+ for f in ${SH_WITH_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_package}"
+ then
+ ac_with_check_opt=yes
+ fi
+ done
+ if test x${ac_with_check_opt} = xno
+ then
+ as_fn_error $? "unrecognized option: $ac_option
+Try \`$0 --help' for more information."
+ fi
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_package"
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ ac_with_check_opt=no
+ for f in ${SH_WITH_OPTS}
+ do
+ f=`echo $f | sed 's/-/_/g'`
+ if test x${f} = x"${ac_package}"
+ then
+ ac_with_check_opt=yes
+ fi
+ done
+ if test x${ac_with_check_opt} = xno
+ then
+ as_fn_error $? "unrecognized option: $ac_option
+Try \`$0 --help' for more information."
+ fi
+ eval "with_$ac_package=no" ;;
+
+
+ -*) as_fn_error $? "unrecognized option: $ac_option
+Try \`$0 --help' for more information."
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid variable name: $ac_envvar"
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ as_fn_error $? "missing argument to --\`echo $ac_prev | sed 's/_/-/g'\`"
+fi
+
+# Be sure to have absolute paths.
+for ac_var in prefix exec_prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' | OPT | USR ) ;;
+ *) as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val";;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in sbindir sysconfdir localstatedir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val";;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-largefile omit support for large files
+ --enable-selinux support checking selinux attributes
+ --enable-posix-acl support checking posix acls
+ --disable-ssp disable the GCC stack protector
+ --enable-db-reload enable database reload on SIGHUP [no]
+ --enable-xml-log enable XML logfile format [no]
+ --disable-mail disable the internal SMTP mailer
+ --enable-suid allow suid
+ --disable-shellexpand disable shell expansion in config file
+ --disable-external-scripts disable interface to external scripts
+ --enable-message-queue[=MODE] enable SysV message queue [MODE=0700]
+ --enable-network=[client|server] compile client or server [no]
+ --enable-static enable static linking [no]
+ --enable-login-watch watch for login/logout [no]
+ --enable-mounts-check check mount options on filesystems [no]
+ --enable-logfile-monitor monitor logfiles [no]
+ --enable-process-check check processes [no]
+ --enable-port-check check ports [no]
+ --enable-userfiles check for users' config files [no]
+ --enable-debug enable debug options [no]
+ --disable-asm disable asm inline code
+ --disable-ipv6 disable ipv6 support
+ --disable-dnmalloc disable dnmalloc
+ --enable-ptrace use anti-debugger options [no]
+ --enable-udp server can listen on port 514/udp [no]
+ --disable-encrypt disable client/server encryption
+ --disable-srp disable SRP for authentication
+ --enable-nocl=PW no CL parsing unless first CL argument is PW
+ --enable-stealth=XOR_VAL enable stealth mode [no]
+ --enable-micro-stealth=XOR_VAL enable micro stealth mode [no]
+ --enable-install-name=NAME name under which to install [samhain|yule]
+ --enable-identity=USER user if dropping root [daemon]
+ --enable-suidcheck check for suid/sgid files [no]
+ --enable-base=B1,B2 base key (0...2147483647)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-cflags additional flags to pass to compiler
+ --with-libs additional libraries to link with
+ --with-libwrap=PATH Compile in libwrap (TCP Wrappers) support
+ --with-libprelude-prefix=PFX Prefix where libprelude is installed (optional)
+ --with-prelude Prelude IDS support [no]
+ --with-database=[mysql|postgresql|oracle|odbc] database support [no]
+ --with-console=PATH set path to console device [/dev/console]
+ --with-altconsole=PATH set path to second console device [none]
+ --with-timeserver=HOST set host address for time server [none]
+ --with-alttimeserver=HOST set address for backup time server [none]
+ --with-rnd=[egd|unix|dev|default] random number generator [default]
+ --with-egd-socket=NAME EGD socket name
+ --with-port=PORT set port to use for TCP/IP connection [49777]
+ --with-logserver=HOST set host address for log server [none]
+ --with-altlogserver=HOST set address for backup log server [none]
+ --with-gpg=PATH use GnuPG to verify database/config [no]
+ --with-keyid=KEYID specify KeyID (0x...) for GPG/PGP functions [none]
+ --with-checksum=CHKSUM compile in gpg/pgp checksum [yes]
+ --with-fp=FINGERPRINT compile in public key fingerprint [no]
+ --with-recipient=ADDR set recipient(s) for e-mail [none]
+ --with-sender=SENDER set sender for e-mail [daemon]
+ --with-trusted=UID Set uid(s) of trusted users [0]
+ --with-tmp-dir=PFX set directory for temporary files [HOME]
+ --with-config-file=FILE configuration file [/etc/{install_name}rc]
+ --with-log-file=FILE path of log file [/var/log/{install_name}_log]
+ --with-pid-file=FILE set path of pid file [/var/run/{install_name}.pid]
+ --with-state-dir=PFX set state data directory [/var/lib/{install_name}]
+ --with-data-file=FILE set path of data file
+ --with-html-file=FILE set path of html file,
+
+Some influential environment variables:
+ LIBS libraries to link against, e.g. -lintl
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ as_decl_name=`echo $2|sed 's/ *(.*//'`
+ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+ (void) $as_decl_use;
+#else
+ (void) $as_decl_name;
+#endif
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$4=yes"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$4=yes"
+else
+ eval "$4=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$4
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_member
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid; break
+else
+ as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=$ac_mid; break
+else
+ as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid
+else
+ as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ return 1;
+ if (($2) < 0)
+ {
+ long int i = longval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%ld", i);
+ }
+ else
+ {
+ unsigned long int i = ulongval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%lu", i);
+ }
+ /* Do not output a trailing newline, as this causes \r\n confusion
+ on some platforms. */
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+ ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+ fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+
+PACKAGE=samhain
+
+VERSION=4.1.4
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+fi
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+
+
+$as_echo "#define SAMHAIN 1" >>confdefs.h
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test "$host" != "$build"; then
+ for ac_prog in gcc cc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_BUILD_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$BUILD_CC"; then
+ ac_cv_prog_BUILD_CC="$BUILD_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_BUILD_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+BUILD_CC=$ac_cv_prog_BUILD_CC
+if test -n "$BUILD_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_CC" >&5
+$as_echo "$BUILD_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$BUILD_CC" && break
+done
+
+else
+ BUILD_CC=$CC
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld" >&5
+$as_echo_n "checking for ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ with_gnu_ld=yes
+ ;;
+ *)
+ with_gnu_ld=no
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+# Extract the first word of "hostname", so it can be a program name with args.
+set dummy hostname; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_cmd_hostname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $cmd_hostname in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_cmd_hostname="$cmd_hostname" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_cmd_hostname="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+cmd_hostname=$ac_cv_path_cmd_hostname
+if test -n "$cmd_hostname"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cmd_hostname" >&5
+$as_echo "$cmd_hostname" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test "x$GCC" = "xyes"; then
+
+ GCC_VERSION=""
+ gcc_VERSION_MAJOR=0
+ gcc_VERSION_MINOR=0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc version" >&5
+$as_echo_n "checking for gcc version... " >&6; }
+ if test "x$GCC" = "xyes"
+ then
+ $CC -dumpversion >/dev/null 2>&1
+ if test $? -eq 0
+ then
+ GCC_VERSION=`$CC -dumpversion`
+ gcc_VERSION_MAJOR=`echo $GCC_VERSION | cut -d'.' -f1`
+ gcc_VERSION_MINOR=`echo $GCC_VERSION | cut -d'.' -f2`
+
+cat >>confdefs.h <<_ACEOF
+#define GCC_VERSION_MAJOR ${gcc_VERSION_MAJOR}
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define GCC_VERSION_MINOR ${gcc_VERSION_MINOR}
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GCC_VERSION" >&5
+$as_echo "$GCC_VERSION" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC -dumpversion working" >&5
+$as_echo "$CC -dumpversion working" >&6; }
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: compiler is not gcc" >&5
+$as_echo "compiler is not gcc" >&6; }
+ fi
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/ipc.h sys/sem.h sys/msg.h sys/uio.h fcntl.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OS specific issues" >&5
+$as_echo_n "checking for OS specific issues... " >&6; }
+mydebugflag=no
+myneedg3=no
+uid_cast="signed long"
+selectconfig=linux
+mynetbsd=no
+sh_use_lcaps="undef"
+dnmalloc_ok=yes
+sh_use_pie=yes
+enable_asm_ok=yes
+
+case "$host_os" in
+
+ *linux*)
+ sh_use_lcaps="yes"
+ $as_echo "#define HOST_IS_LINUX 1" >>confdefs.h
+
+ $as_echo "#define HAVE_EXT2_IOCTLS 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: use ioctl to get e2fs flags" >&5
+$as_echo "use ioctl to get e2fs flags" >&6; }
+ case "$host_cpu" in
+ i*86*)
+ $as_echo "#define HOST_IS_I86LINUX 1" >>confdefs.h
+
+ ;;
+ x86_64)
+
+$as_echo "#define HOST_IS_64LINUX 1" >>confdefs.h
+
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+
+ *osf*)
+
+$as_echo "#define HOST_IS_OSF 1" >>confdefs.h
+
+ if test "x$GCC" != "xyes"; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ CFLAGS="$CFLAGS -O2 -assume noaligned_objects"
+ myneedg3=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: compiler needs assume noaligned_objects" >&5
+$as_echo "compiler needs assume noaligned_objects" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ fi
+ ;;
+
+ *cygwin*)
+ $as_echo "#define HOST_IS_CYGWIN 1" >>confdefs.h
+
+
+$as_echo "#define USE_REGISTRY_CHECK 1" >>confdefs.h
+
+ dnmalloc_ok=no
+ enable_asm_ok=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no trusted paths, no dnmalloc. no asm optimize" >&5
+$as_echo "no trusted paths, no dnmalloc. no asm optimize" >&6; }
+ ;;
+
+ *darwin*|*apple*)
+ $as_echo "#define HOST_IS_DARWIN 1" >>confdefs.h
+
+ dnmalloc_ok=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: check resource forks, no dnmalloc" >&5
+$as_echo "check resource forks, no dnmalloc" >&6; }
+ ;;
+
+ *freebsd8*|*freebsd9*)
+ $as_echo "#define HOST_IS_FREEBSD 1" >>confdefs.h
+
+ selectconfig=freebsd
+ case "$host_cpu" in
+ amd64|x86_64)
+ dnmalloc_ok=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no dnmalloc" >&5
+$as_echo "no dnmalloc" >&6; }
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ ;;
+ esac
+ ;;
+
+ *freebsd7*)
+ $as_echo "#define HOST_IS_FREEBSD 1" >>confdefs.h
+
+ selectconfig=freebsd
+ case "$host_cpu" in
+ amd64|x86_64)
+ sh_use_pie=no
+ dnmalloc_ok=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no dnmalloc and broken compiler toolchain" >&5
+$as_echo "no dnmalloc and broken compiler toolchain" >&6; }
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ ;;
+ esac
+ ;;
+
+ *freebsd*)
+ $as_echo "#define HOST_IS_FREEBSD 1" >>confdefs.h
+
+ selectconfig=freebsd
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ ;;
+
+ *openbsd*)
+
+$as_echo "#define HOST_IS_OPENBSD 1" >>confdefs.h
+
+ selectconfig=freebsd
+ dnmalloc_ok=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: dnmalloc does not work with pthreads" >&5
+$as_echo "dnmalloc does not work with pthreads" >&6; }
+ ;;
+
+ *netbsd*)
+ mynetbsd=yes
+ selectconfig=netbsd
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: bug with libresolve" >&5
+$as_echo "bug with libresolve" >&6; }
+ ;;
+
+ *solaris*)
+ selectconfig=solaris
+ $as_echo "#define HOST_IS_SOLARIS 1" >>confdefs.h
+
+ case "$host_cpu" in
+ i*86)
+ $as_echo "#define HOST_IS_I86SOLARIS 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: vsnprintf prototype" >&5
+$as_echo "vsnprintf prototype" >&6; }
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ ;;
+ esac
+ if test "x$GCC" != "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g" 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-xO2" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -xO2"
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-Xa" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -Xa"
+ fi
+ LIBS="-lc $LIBS"
+ fi
+ ;;
+
+
+ *sun*)
+ selectconfig=solaris
+ $as_echo "#define HOST_IS_SOLARIS 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ ;;
+
+ *aix*)
+ $as_echo "#define HOST_IS_AIX 1" >>confdefs.h
+
+ selectconfig=aix5.2.0
+ uid_cast="unsigned long"
+ if test "x$GCC" != "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g" 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-O3" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -O3"
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-qstrict" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -qstrict"
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: AIX size_t in the accept call and optimize O3 qstrict" >&5
+$as_echo "AIX size_t in the accept call and optimize O3 qstrict" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: AIX size_t in the accept call" >&5
+$as_echo "AIX size_t in the accept call" >&6; }
+ fi
+ ;;
+
+ *hpux*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: HPUX need _XOPEN_SOURCE_EXTENDED for h_errno" >&5
+$as_echo "HPUX need _XOPEN_SOURCE_EXTENDED for h_errno" >&6; }
+ $as_echo "#define HOST_IS_HPUX 1" >>confdefs.h
+
+ if test "x$GCC" != "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g" 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\+O2" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS +O2"
+ fi
+ fi
+ ;;
+
+ *ultrix*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ULTRIX getcwd uses popen" >&5
+$as_echo "ULTRIX getcwd uses popen" >&6; }
+ $as_echo "#define HAVE_BROKEN_GETCWD 1" >>confdefs.h
+
+ ;;
+
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+ ;;
+esac
+
+
+cat >>confdefs.h <<_ACEOF
+#define UID_CAST ${uid_cast}
+_ACEOF
+
+
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5
+$as_echo_n "checking for $ac_hdr that defines DIR... " >&6; }
+if eval \${$as_ac_Header+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$as_ac_Header=yes"
+else
+ eval "$as_ac_Header=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$as_ac_Header
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' dir; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_opendir+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5
+$as_echo_n "checking for library containing opendir... " >&6; }
+if ${ac_cv_search_opendir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char opendir ();
+int
+main ()
+{
+return opendir ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' x; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_search_opendir=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_opendir+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_opendir+:} false; then :
+
+else
+ ac_cv_search_opendir=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5
+$as_echo "$ac_cv_search_opendir" >&6; }
+ac_res=$ac_cv_search_opendir
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5
+$as_echo_n "checking whether sys/types.h defines makedev... " >&6; }
+if ${ac_cv_header_sys_types_h_makedev+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main ()
+{
+return makedev(0, 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_header_sys_types_h_makedev=yes
+else
+ ac_cv_header_sys_types_h_makedev=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5
+$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; }
+
+if test $ac_cv_header_sys_types_h_makedev = no; then
+ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mkdev_h" = xyes; then :
+
+$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h
+
+fi
+
+
+
+ if test $ac_cv_header_sys_mkdev_h = no; then
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then :
+
+$as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h
+
+fi
+
+
+ fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_time=yes
+else
+ ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5
+$as_echo_n "checking whether stat file-mode macros are broken... " >&6; }
+if ${ac_cv_header_stat_broken+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined S_ISBLK && defined S_IFDIR
+extern char c1[S_ISBLK (S_IFDIR) ? -1 : 1];
+#endif
+
+#if defined S_ISBLK && defined S_IFCHR
+extern char c2[S_ISBLK (S_IFCHR) ? -1 : 1];
+#endif
+
+#if defined S_ISLNK && defined S_IFREG
+extern char c3[S_ISLNK (S_IFREG) ? -1 : 1];
+#endif
+
+#if defined S_ISSOCK && defined S_IFREG
+extern char c4[S_ISSOCK (S_IFREG) ? -1 : 1];
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stat_broken=no
+else
+ ac_cv_header_stat_broken=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5
+$as_echo "$ac_cv_header_stat_broken" >&6; }
+if test $ac_cv_header_stat_broken = yes; then
+
+$as_echo "#define STAT_MACROS_BROKEN 1" >>confdefs.h
+
+fi
+
+ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" "#include <signal.h>
+/* NetBSD declares sys_siglist in unistd.h. */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+"
+if test "x$ac_cv_have_decl_sys_siglist" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SYS_SIGLIST $ac_have_decl
+_ACEOF
+
+
+
+for ac_header in stddef.h libgen.h sched.h malloc.h sys/uio.h \
+ sys/mman.h sys/param.h sys/inotify.h \
+ sys/vfs.h mntent.h \
+ sys/select.h sys/socket.h netinet/in.h \
+ regex.h glob.h fnmatch.h \
+ linux/ext2_fs.h linux/fs.h ext2fs/ext2_fs.h asm/segment.h \
+ elf.h linux/elf.h auparse.h \
+ paths.h arpa/nameser.h arpa/nameser_compat.h \
+ rpc/rpcent.h rpc/rpc.h sys/statvfs.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include <sys/types.h>
+
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ac_fn_c_check_header_mongrel "$LINENO" "utmpx.h" "ac_cv_header_utmpx_h" "$ac_includes_default"
+if test "x$ac_cv_header_utmpx_h" = xyes; then :
+ sh_utmpx="yes"
+else
+ sh_utmpx="no"
+fi
+
+
+if test "x$sh_utmpx" = "xyes"; then
+ $as_echo "#define HAVE_UTMPX_H 1" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_host" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTHOST 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_addr" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTADDR 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_addr_v6" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTADDR_V6 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_xtime" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTXTIME 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_type" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTTYPE 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_addr" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTADDR 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_host" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTHOST 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ut_type" >/dev/null 2>&1; then :
+ $as_echo "#define HAVE_UTTYPE 1" >>confdefs.h
+
+fi
+rm -f conftest*
+
+fi
+
+ac_fn_c_check_header_mongrel "$LINENO" "sys/acct.h" "ac_cv_header_sys_acct_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_acct_h" = xyes; then :
+
+$as_echo "#define HAVE_SYS_ACCT_H /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_utime" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACUTIME /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_utime" >/dev/null 2>&1; then :
+
+$as_echo "#define ACUTIME_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_stime" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACSTIME /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_stime" >/dev/null 2>&1; then :
+
+$as_echo "#define ACSTIME_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_etime" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACETIME /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_etime" >/dev/null 2>&1; then :
+
+$as_echo "#define ACETIME_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_io" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACIO /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_io" >/dev/null 2>&1; then :
+
+$as_echo "#define ACIO_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_mem" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACMEM /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_mem" >/dev/null 2>&1; then :
+
+$as_echo "#define ACMEM_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_minflt" >/dev/null 2>&1; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_majflt" >/dev/null 2>&1; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "ac_swaps" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_PAGING /**/" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_minflt" >/dev/null 2>&1; then :
+
+$as_echo "#define ACMINFLT_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_mayflt" >/dev/null 2>&1; then :
+
+$as_echo "#define ACMAJFLT_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t.*ac_swaps" >/dev/null 2>&1; then :
+
+$as_echo "#define ACSWAPS_COMPT /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "comp_t" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_COMP_T /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct acct_v3" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACCT_V3 /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/acct.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "struct acctv2" >/dev/null 2>&1; then :
+
+$as_echo "#define HAVE_ACCTV2 /**/" >>confdefs.h
+
+fi
+rm -f conftest*
+
+
+
+fi
+
+
+
+
+ac_fn_c_check_member "$LINENO" "struct statfs" "f_flags" "ac_cv_member_struct_statfs_f_flags" "
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+"
+if test "x$ac_cv_member_struct_statfs_f_flags" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STATFS_F_FLAGS 1
+_ACEOF
+
+
+fi
+
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+ enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_sys_largefile_CC=no
+ if test "$GCC" != yes; then
+ ac_save_CC=$CC
+ while :; do
+ # IRIX 6.2 and later do not support large files by default,
+ # so use the C compiler's -n32 option if that helps.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_c_try_compile "$LINENO"; then :
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext
+ CC="$CC -n32"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+ break
+ done
+ CC=$ac_save_CC
+ rm -f conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+ if test "$ac_cv_sys_largefile_CC" != no; then
+ CC=$CC$ac_cv_sys_largefile_CC
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if ${ac_cv_sys_file_offset_bits+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_file_offset_bits=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+ if test $ac_cv_sys_file_offset_bits = unknown; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if ${ac_cv_sys_large_files+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_large_files=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+ fi
+
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether _POSIX_SOURCE is necessary" >&5
+$as_echo_n "checking whether _POSIX_SOURCE is necessary... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+void fileno(int);int fdopen(int, char *);
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+
+for ac_func in strftime
+do :
+ ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
+if test "x$ac_cv_func_strftime" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRFTIME 1
+_ACEOF
+
+else
+ # strftime is in -lintl on SCO UNIX.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for strftime in -lintl" >&5
+$as_echo_n "checking for strftime in -lintl... " >&6; }
+if ${ac_cv_lib_intl_strftime+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lintl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strftime ();
+int
+main ()
+{
+return strftime ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_intl_strftime=yes
+else
+ ac_cv_lib_intl_strftime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_strftime" >&5
+$as_echo "$ac_cv_lib_intl_strftime" >&6; }
+if test "x$ac_cv_lib_intl_strftime" = xyes; then :
+ $as_echo "#define HAVE_STRFTIME 1" >>confdefs.h
+
+LIBS="-lintl $LIBS"
+fi
+
+fi
+done
+
+for ac_func in memcmp memcpy memmove memset getpwent endpwent fpurge \
+ gettimeofday strlcat strlcpy strstr strchr strerror strsignal \
+ seteuid setreuid setresuid lstat getwd getcwd ptrace \
+ usleep setpriority getpeereid nanosleep \
+ strptime basename sched_yield hasmntopt \
+ inet_aton gethostbyname setutent setrlimit gethostname uname \
+ initgroups getpagesize \
+ ttyname fchmod writev mmap tzset \
+ getsid getpriority getpgid statvfs \
+ strerror_r getgrgid_r getpwnam_r getpwuid_r \
+ gmtime_r localtime_r rand_r readdir_r strtok_r \
+ mincore posix_fadvise inotify_init1
+
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ac_fn_c_check_func "$LINENO" "statfs" "ac_cv_func_statfs"
+if test "x$ac_cv_func_statfs" = xyes; then :
+ $as_echo "#define HAVE_STATFS 1" >>confdefs.h
+ statfs="yes"
+else
+ statfs="no"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for va_copy()" >&5
+$as_echo_n "checking for va_copy()... " >&6; }
+if ${sh_cv_va_copy+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+ sh_cv_va_copy=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdarg.h>
+ void f (int i, ...) {
+ va_list args1, args2;
+ va_start (args1, i);
+ va_copy (args2, args1);
+ if (va_arg (args2, int) != 42)
+ exit (1);
+ if (va_arg (args1, int) != 42)
+ exit (1);
+ va_end (args1); va_end (args2);
+ }
+ int main() {
+ f (0, 42);
+ return 0;
+ }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ sh_cv_va_copy=yes
+
+else
+ sh_cv_va_copy=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv_va_copy" >&5
+$as_echo "$sh_cv_va_copy" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __va_copy()" >&5
+$as_echo_n "checking for __va_copy()... " >&6; }
+if ${sh_cv___va_copy+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+ sh_cv___va_copy=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdarg.h>
+ void f (int i, ...) {
+ va_list args1, args2;
+ va_start (args1, i);
+ __va_copy (args2, args1);
+ if (va_arg (args2, int) != 42)
+ exit (1);
+ if (va_arg (args1, int) != 42)
+ exit (1);
+ va_end (args1); va_end (args2);
+ }
+ int main() {
+ f (0, 42);
+ return 0;
+ }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ sh_cv___va_copy=yes
+
+else
+ sh_cv___va_copy=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv___va_copy" >&5
+$as_echo "$sh_cv___va_copy" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether va_lists can be copied by value" >&5
+$as_echo_n "checking whether va_lists can be copied by value... " >&6; }
+if ${sh_cv_va_val_copy+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test "$cross_compiling" = yes; then :
+ sh_cv_va_val_copy=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdarg.h>
+ void f (int i, ...) {
+ va_list args1, args2;
+ va_start (args1, i);
+ args2 = args1;
+ if (va_arg (args2, int) != 42)
+ exit (1);
+ if (va_arg (args1, int) != 42)
+ exit (1);
+ va_end (args1); va_end (args2);
+ }
+ int main() {
+ f (0, 42);
+ return 0;
+ }
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ sh_cv_va_val_copy=yes
+
+else
+ sh_cv_va_val_copy=no
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+
+if test "x$sh_cv_va_copy" = "xyes"; then
+ $as_echo "#define VA_COPY va_copy" >>confdefs.h
+
+else if test "x$sh_cv___va_copy" = "xyes"; then
+ $as_echo "#define VA_COPY __va_copy" >>confdefs.h
+
+fi
+fi
+if test "x$sh_cv_va_val_copy" = "xno"; then
+ $as_echo "#define VA_COPY_AS_ARRAY 1" >>confdefs.h
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv_va_val_copy" >&5
+$as_echo "$sh_cv_va_val_copy" >&6; }
+
+for ac_func in vsnprintf
+do :
+ ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_VSNPRINTF 1
+_ACEOF
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vsnprintf" >&5
+$as_echo_n "checking for working vsnprintf... " >&6; }
+if ${ac_cv_func_vsnprintf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_func_vsnprintf=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+#include <stdarg.h>
+
+int
+doit(char * s, ...)
+{
+ char buffer[32];
+ va_list args;
+ int r;
+
+ buffer[5] = 'X';
+
+ va_start(args, s);
+ r = vsnprintf(buffer, 5, s, args);
+ va_end(args);
+
+ /* -1 is pre-C99, 7 is C99. R.W. 17.01.2003 disallow -1 */
+
+ if (r != 7)
+ exit(1);
+
+ /* We deliberately do not care if the result is NUL-terminated or
+ not, since this is easy to work around like this. */
+
+ buffer[4] = 0;
+
+ /* Simple sanity check. */
+
+ if (strcmp(buffer, "1234"))
+ exit(1);
+
+ if (buffer[5] != 'X')
+ exit(1);
+
+ exit(0);
+}
+
+int
+main(void)
+{
+ doit("1234567");
+ exit(1);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_vsnprintf=yes
+else
+ ac_cv_func_vsnprintf=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vsnprintf" >&5
+$as_echo "$ac_cv_func_vsnprintf" >&6; }
+if test $ac_cv_func_vsnprintf = yes; then
+ :
+else
+
+$as_echo "#define HAVE_BROKEN_VSNPRINTF 1" >>confdefs.h
+
+fi
+
+fi
+done
+
+ for ac_func in mlock
+do :
+ ac_fn_c_check_func "$LINENO" "mlock" "ac_cv_func_mlock"
+if test "x$ac_cv_func_mlock" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_MLOCK 1
+_ACEOF
+
+fi
+done
+
+ if test "$ac_cv_func_mlock" = "yes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mlock is broken" >&5
+$as_echo_n "checking whether mlock is broken... " >&6; }
+ if ${ac_cv_have_broken_mlock+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_have_broken_mlock="assume-no"
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <sys/mman.h>
+ #include <sys/types.h>
+ #include <fcntl.h>
+
+ int main()
+ {
+ char *pool;
+ int err;
+ long int pgsize = getpagesize();
+
+ pool = malloc( 4096 + pgsize );
+ if( !pool )
+ return 2;
+ pool += (pgsize - ((long int)pool % pgsize));
+
+ err = mlock( pool, 4096 );
+ if( !err || errno == EPERM )
+ return 0; /* okay */
+
+ return 1; /* hmmm */
+ }
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_have_broken_mlock="no"
+else
+ ac_cv_have_broken_mlock="yes"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+
+ if test "$ac_cv_have_broken_mlock" = "yes"; then
+ $as_echo "#define HAVE_BROKEN_MLOCK 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ if test "$ac_cv_have_broken_mlock" = "no"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: assuming no" >&5
+$as_echo "assuming no" >&6; }
+ fi
+ fi
+ fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether strftime supports %z" >&5
+$as_echo_n "checking whether strftime supports %z... " >&6; }
+if test "$cross_compiling" = yes; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <time.h>
+#include <string.h>
+int main()
+{
+ struct tm tm;
+ char tt[64];
+ memset(&tm, 0, sizeof(tm));
+ strftime(tt, sizeof(tt), "%z", &tm);
+
+ if (strlen(tt) != 5) return 1;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_STRFTIME_Z 1" >>confdefs.h
+
+
+else
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to get filesystem type" >&5
+$as_echo_n "checking how to get filesystem type... " >&6; }
+fstype=no
+# The order of these tests is important.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/statvfs.h>
+#include <sys/fstyp.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ $as_echo "#define FSTYPE_STATVFS 1" >>confdefs.h
+ fstype=SVR4
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+if test $fstype = no; then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/statfs.h>
+#include <sys/fstyp.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ $as_echo "#define FSTYPE_USG_STATFS 1" >>confdefs.h
+ fstype=SVR3
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi
+if test $fstype = no; then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/statfs.h>
+#include <sys/vmount.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ $as_echo "#define FSTYPE_AIX_STATFS 1" >>confdefs.h
+ fstype=AIX
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi
+if test $fstype = no; then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <mntent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ $as_echo "#define FSTYPE_MNTENT 1" >>confdefs.h
+ fstype=4.3BSD
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi
+if test $fstype = no; then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/mount.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "f_type;" >/dev/null 2>&1; then :
+ $as_echo "#define FSTYPE_STATFS 1" >>confdefs.h
+ fstype=4.4BSD/OSF
+fi
+rm -f conftest*
+
+fi
+if test $fstype = no; then
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ $as_echo "#define FSTYPE_GETMNT 1" >>confdefs.h
+ fstype=Ultrix
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $fstype" >&5
+$as_echo "$fstype" >&6; }
+
+sh_libsocket=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+ LIBS="-lnsl $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5
+$as_echo_n "checking for socket in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_socket+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_socket=yes
+else
+ ac_cv_lib_socket_socket=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5
+$as_echo "$ac_cv_lib_socket_socket" >&6; }
+if test "x$ac_cv_lib_socket_socket" = xyes; then :
+ ac_need_libsocket=1
+else
+ ac_try_nsl=1
+fi
+
+if test x$ac_need_libsocket = x1; then
+ LIBS="$LIBS -lsocket"
+ sh_libsocket="-lsocket"
+fi
+if test x$ac_try_nsl = x1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+ ac_need_libnsl=1
+fi
+
+ if test x$ac_need_libnsl = x1
+ then
+ LIBS="$LIBS -lnsl"
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_search in -lsocket" >&5
+$as_echo_n "checking for res_search in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_res_search+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char res_search ();
+int
+main ()
+{
+return res_search ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_res_search=yes
+else
+ ac_cv_lib_socket_res_search=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_res_search" >&5
+$as_echo "$ac_cv_lib_socket_res_search" >&6; }
+if test "x$ac_cv_lib_socket_res_search" = xyes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dn_skipname in -lresolv" >&5
+$as_echo_n "checking for dn_skipname in -lresolv... " >&6; }
+if ${ac_cv_lib_resolv_dn_skipname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dn_skipname ();
+int
+main ()
+{
+return dn_skipname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_resolv_dn_skipname=yes
+else
+ ac_cv_lib_resolv_dn_skipname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_dn_skipname" >&5
+$as_echo "$ac_cv_lib_resolv_dn_skipname" >&6; }
+if test "x$ac_cv_lib_resolv_dn_skipname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __dn_skipname in -lresolv" >&5
+$as_echo_n "checking for __dn_skipname in -lresolv... " >&6; }
+if ${ac_cv_lib_resolv___dn_skipname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char __dn_skipname ();
+int
+main ()
+{
+return __dn_skipname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_resolv___dn_skipname=yes
+else
+ ac_cv_lib_resolv___dn_skipname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv___dn_skipname" >&5
+$as_echo "$ac_cv_lib_resolv___dn_skipname" >&6; }
+if test "x$ac_cv_lib_resolv___dn_skipname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+ if test x$ac_need_libsocket = x1; then
+ :
+ else
+ LIBS="$LIBS -lsocket"
+ fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for res_search in -lresolv" >&5
+$as_echo_n "checking for res_search in -lresolv... " >&6; }
+if ${ac_cv_lib_resolv_res_search+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char res_search ();
+int
+main ()
+{
+return res_search ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_resolv_res_search=yes
+else
+ ac_cv_lib_resolv_res_search=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_res_search" >&5
+$as_echo "$ac_cv_lib_resolv_res_search" >&6; }
+if test "x$ac_cv_lib_resolv_res_search" = xyes; then :
+
+ LIBS="$LIBS -lresolv"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dn_skipname in -lresolv" >&5
+$as_echo_n "checking for dn_skipname in -lresolv... " >&6; }
+if ${ac_cv_lib_resolv_dn_skipname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dn_skipname ();
+int
+main ()
+{
+return dn_skipname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_resolv_dn_skipname=yes
+else
+ ac_cv_lib_resolv_dn_skipname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_dn_skipname" >&5
+$as_echo "$ac_cv_lib_resolv_dn_skipname" >&6; }
+if test "x$ac_cv_lib_resolv_dn_skipname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __dn_skipname in -lresolv" >&5
+$as_echo_n "checking for __dn_skipname in -lresolv... " >&6; }
+if ${ac_cv_lib_resolv___dn_skipname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char __dn_skipname ();
+int
+main ()
+{
+return __dn_skipname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_resolv___dn_skipname=yes
+else
+ ac_cv_lib_resolv___dn_skipname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv___dn_skipname" >&5
+$as_echo "$ac_cv_lib_resolv___dn_skipname" >&6; }
+if test "x$ac_cv_lib_resolv___dn_skipname" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRESOLV 1
+_ACEOF
+
+ LIBS="-lresolv $LIBS"
+
+fi
+
+
+fi
+
+
+fi
+
+
+for ac_func in getnameinfo getaddrinfo
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+sh_auparse=no
+
+if test "x$ac_cv_header_auparse_h" = "xyes"
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for auparse_find_field in -lauparse" >&5
+$as_echo_n "checking for auparse_find_field in -lauparse... " >&6; }
+if ${ac_cv_lib_auparse_auparse_find_field+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lauparse $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char auparse_find_field ();
+int
+main ()
+{
+return auparse_find_field ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_auparse_auparse_find_field=yes
+else
+ ac_cv_lib_auparse_auparse_find_field=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_auparse_auparse_find_field" >&5
+$as_echo "$ac_cv_lib_auparse_auparse_find_field" >&6; }
+if test "x$ac_cv_lib_auparse_auparse_find_field" = xyes; then :
+
+ LIBS="$LIBS -lauparse"
+ sh_auparse=yes
+
+$as_echo "#define HAVE_AUPARSE_LIB 1" >>confdefs.h
+
+
+fi
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t" >&5
+$as_echo_n "checking for socklen_t... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+ socklen_t x;
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_ARG3 socklen_t
+_ACEOF
+
+
+$as_echo "#define HAVE_SOCKLEN_T 1" >>confdefs.h
+
+
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+ int accept (int, struct sockaddr *, size_t *);
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: size_t" >&5
+$as_echo "size_t" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_ARG3 size_t
+_ACEOF
+
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: int" >&5
+$as_echo "int" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_ARG3 int
+_ACEOF
+
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+# Check whether --enable-selinux was given.
+if test "${enable_selinux+set}" = set; then :
+ enableval=$enable_selinux;
+else
+ enable_selinux=check
+fi
+
+if test "x$enable_selinux" != xno; then
+
+ for ac_header in attr/xattr.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default"
+if test "x$ac_cv_header_attr_xattr_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_ATTR_XATTR_H 1
+_ACEOF
+
+fi
+
+done
+
+ if test $ac_cv_header_attr_xattr_h = yes; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getxattr in -lattr" >&5
+$as_echo_n "checking for getxattr in -lattr... " >&6; }
+if ${ac_cv_lib_attr_getxattr+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lattr $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getxattr ();
+int
+main ()
+{
+return getxattr ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_attr_getxattr=yes
+else
+ ac_cv_lib_attr_getxattr=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_attr_getxattr" >&5
+$as_echo "$ac_cv_lib_attr_getxattr" >&6; }
+if test "x$ac_cv_lib_attr_getxattr" = xyes; then :
+ sh_lattr=yes
+else
+ sh_lattr=no
+fi
+
+ if test x"$sh_lattr" = xyes; then
+ LIBATTR=-lattr
+ else
+ LIBATTR=
+ fi
+
+ OLDLIBS="$LIBS"
+ LIBS="$LIBS $LIBATTR"
+ for ac_func in getxattr lgetxattr fgetxattr
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ sh_fattr=yes
+else
+ sh_fattr=no
+fi
+done
+
+ LIBS="$OLDLIBS"
+ fi
+
+ if test x"$sh_fattr" = xyes; then
+
+$as_echo "#define USE_XATTR 1" >>confdefs.h
+
+ LIBS="$LIBS $LIBATTR"
+ else
+ if test "x$enable_selinux" != xcheck; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "--enable-selinux was given, but test for selinux support failed
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+
+fi
+
+# Check whether --enable-posix-acl was given.
+if test "${enable_posix_acl+set}" = set; then :
+ enableval=$enable_posix_acl;
+else
+ enable_posix_acl=check
+fi
+
+if test "x$enable_posix_acl" != xno; then
+
+ for ac_header in sys/acl.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/acl.h" "ac_cv_header_sys_acl_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_acl_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_ACL_H 1
+_ACEOF
+
+fi
+
+done
+
+ if test $ac_cv_header_sys_acl_h = yes; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for acl_get_file in -lacl" >&5
+$as_echo_n "checking for acl_get_file in -lacl... " >&6; }
+if ${ac_cv_lib_acl_acl_get_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lacl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char acl_get_file ();
+int
+main ()
+{
+return acl_get_file ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_acl_acl_get_file=yes
+else
+ ac_cv_lib_acl_acl_get_file=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_acl_acl_get_file" >&5
+$as_echo "$ac_cv_lib_acl_acl_get_file" >&6; }
+if test "x$ac_cv_lib_acl_acl_get_file" = xyes; then :
+ sh_lacl=yes
+else
+ sh_lacl=no
+fi
+
+ if test x"$sh_lacl" = xyes; then
+ LIBACL=-lacl
+ else
+ LIBACL=
+ fi
+
+ OLDLIBS="$LIBS"
+ LIBS="$LIBS $LIBACL"
+ for ac_func in acl_free acl_get_file acl_get_fd
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ sh_facl=yes
+else
+ sh_facl=no
+fi
+done
+
+ LIBS="$OLDLIBS"
+ fi
+
+ if test x"$sh_facl" = xyes; then
+
+$as_echo "#define USE_ACL 1" >>confdefs.h
+
+ LIBS="$LIBS $LIBACL"
+ else
+ if test "x$enable_posix_acl" != xcheck; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "--enable-posix-acl was given, but test for acl support failed
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double with more range or precision than double" >&5
+$as_echo_n "checking for long double with more range or precision than double... " >&6; }
+if ${ac_cv_type_long_double_wider+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <float.h>
+ long double const a[] =
+ {
+ 0.0L, DBL_MIN, DBL_MAX, DBL_EPSILON,
+ LDBL_MIN, LDBL_MAX, LDBL_EPSILON
+ };
+ long double
+ f (long double x)
+ {
+ return ((x + (unsigned long int) 10) * (-1 / x) + a[0]
+ + (x ? f (x) : 'c'));
+ }
+
+int
+main ()
+{
+static int test_array [1 - 2 * !((0 < ((DBL_MAX_EXP < LDBL_MAX_EXP)
+ + (DBL_MANT_DIG < LDBL_MANT_DIG)
+ - (LDBL_MAX_EXP < DBL_MAX_EXP)
+ - (LDBL_MANT_DIG < DBL_MANT_DIG)))
+ && (int) LDBL_EPSILON == 0
+ )];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_long_double_wider=yes
+else
+ ac_cv_type_long_double_wider=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double_wider" >&5
+$as_echo "$ac_cv_type_long_double_wider" >&6; }
+ if test $ac_cv_type_long_double_wider = yes; then
+
+$as_echo "#define HAVE_LONG_DOUBLE_WIDER 1" >>confdefs.h
+
+ fi
+
+ ac_cv_c_long_double=$ac_cv_type_long_double_wider
+ if test $ac_cv_c_long_double = yes; then
+
+$as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long typedef" >&5
+$as_echo_n "checking for long long typedef... " >&6; }
+ sh_cv_typedef_foo=`echo sh_cv_typedef_long long | sed -e 's% %_%g'`
+ if eval \${$sh_cv_typedef_foo+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+int
+main ()
+{
+
+ #undef long long
+ int a = sizeof(long long);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_cv_typedef=yes
+else
+ sh_cv_typedef=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv_typedef" >&5
+$as_echo "$sh_cv_typedef" >&6; }
+ if test "$sh_cv_typedef" = yes; then
+
+$as_echo "#define HAVE_LONG_LONG 1" >>confdefs.h
+
+ sh_HAVE_LONG_LONG=yes
+ else
+ sh_HAVE_LONG_LONG=no
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint16_t typedef" >&5
+$as_echo_n "checking for uint16_t typedef... " >&6; }
+ sh_cv_typedef_foo=`echo sh_cv_typedef_uint16_t | sed -e 's% %_%g'`
+ if eval \${$sh_cv_typedef_foo+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+int
+main ()
+{
+
+ #undef uint16_t
+ int a = sizeof(uint16_t);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_cv_typedef=yes
+else
+ sh_cv_typedef=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv_typedef" >&5
+$as_echo "$sh_cv_typedef" >&6; }
+ if test "$sh_cv_typedef" = yes; then
+
+$as_echo "#define HAVE_UINT16_T 1" >>confdefs.h
+
+ sh_HAVE_UINT16_T=yes
+ else
+ sh_HAVE_UINT16_T=no
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint32_t typedef" >&5
+$as_echo_n "checking for uint32_t typedef... " >&6; }
+ sh_cv_typedef_foo=`echo sh_cv_typedef_uint32_t | sed -e 's% %_%g'`
+ if eval \${$sh_cv_typedef_foo+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+int
+main ()
+{
+
+ #undef uint32_t
+ int a = sizeof(uint32_t);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_cv_typedef=yes
+else
+ sh_cv_typedef=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv_typedef" >&5
+$as_echo "$sh_cv_typedef" >&6; }
+ if test "$sh_cv_typedef" = yes; then
+
+$as_echo "#define HAVE_UINT32_T 1" >>confdefs.h
+
+ sh_HAVE_UINT32_T=yes
+ else
+ sh_HAVE_UINT32_T=no
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint64_t typedef" >&5
+$as_echo_n "checking for uint64_t typedef... " >&6; }
+ sh_cv_typedef_foo=`echo sh_cv_typedef_uint64_t | sed -e 's% %_%g'`
+ if eval \${$sh_cv_typedef_foo+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+int
+main ()
+{
+
+ #undef uint64_t
+ int a = sizeof(uint64_t);
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_cv_typedef=yes
+else
+ sh_cv_typedef=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_cv_typedef" >&5
+$as_echo "$sh_cv_typedef" >&6; }
+ if test "$sh_cv_typedef" = yes; then
+
+$as_echo "#define HAVE_UINT64_T 1" >>confdefs.h
+
+ sh_HAVE_UINT64_T=yes
+ else
+ sh_HAVE_UINT64_T=no
+ fi
+
+if test "$sh_HAVE_LONG_LONG" = "yes"; then
+ # The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long long" >&5
+$as_echo_n "checking size of unsigned long long... " >&6; }
+if ${ac_cv_sizeof_unsigned_long_long+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long long))" "ac_cv_sizeof_unsigned_long_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_long_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned long long)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_unsigned_long_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG_LONG $ac_cv_sizeof_unsigned_long_long
+_ACEOF
+
+
+ sh_sizeof_unsigned_long_long=`echo "$ac_cv_sizeof_unsigned_long_long" | sed 's%^0-9%%g'`
+ if test "$sh_sizeof_unsigned_long_long" = "8"; then
+
+$as_echo "#define HAVE_LONG_LONG_64 1" >>confdefs.h
+
+ fi
+fi
+
+ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default"
+if test "x$ac_cv_type_ptrdiff_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ptrdiff_t long
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char *" >&5
+$as_echo_n "checking size of char *... " >&6; }
+if ${ac_cv_sizeof_char_p+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char *))" "ac_cv_sizeof_char_p" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_char_p" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (char *)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_char_p=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char_p" >&5
+$as_echo "$ac_cv_sizeof_char_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_CHAR_P $ac_cv_sizeof_char_p
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if ${ac_cv_sizeof_size_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_size_t" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (size_t)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_size_t=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5
+$as_echo_n "checking size of unsigned long... " >&6; }
+if ${ac_cv_sizeof_unsigned_long+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned long)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_unsigned_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned int" >&5
+$as_echo_n "checking size of unsigned int... " >&6; }
+if ${ac_cv_sizeof_unsigned_int+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned int))" "ac_cv_sizeof_unsigned_int" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_int" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned int)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_unsigned_int=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_int" >&5
+$as_echo "$ac_cv_sizeof_unsigned_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_INT $ac_cv_sizeof_unsigned_int
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned short" >&5
+$as_echo_n "checking size of unsigned short... " >&6; }
+if ${ac_cv_sizeof_unsigned_short+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned short))" "ac_cv_sizeof_unsigned_short" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_short" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned short)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_unsigned_short=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_short" >&5
+$as_echo "$ac_cv_sizeof_unsigned_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short
+_ACEOF
+
+
+
+
+sh_sizeof_unsigned_long=`echo "$ac_cv_sizeof_unsigned_long" | sed 's%^0-9%%g'`
+if test "$sh_sizeof_unsigned_long" = "4"; then
+ $as_echo "#define HAVE_LONG_32 1" >>confdefs.h
+
+fi
+if test "$sh_sizeof_unsigned_long" = "8"; then
+ $as_echo "#define HAVE_LONG_64 1" >>confdefs.h
+
+fi
+sh_sizeof_unsigned_int=`echo "$ac_cv_sizeof_unsigned_int" | sed 's%^0-9%%g'`
+if test "$sh_sizeof_unsigned_int" = "4"; then
+ $as_echo "#define HAVE_INT_32 1" >>confdefs.h
+
+fi
+sh_sizeof_unsigned_short=`echo "$ac_cv_sizeof_unsigned_short" | sed 's%^0-9%%g'`
+if test "$sh_sizeof_unsigned_short" = "4"; then
+ $as_echo "#define HAVE_SHORT_32 1" >>confdefs.h
+
+fi
+
+
+samhain_64=no
+tiger_src=sh_tiger1.c
+samhain_64_asm=no
+#
+# if sizeof(unsigned long) = 4, try compiler macros for 64bit
+#
+if test "x$ac_cv_sizeof_unsigned_long" = x4; then
+ if test "x$ac_cv_sizeof_unsigned_long_long" = x8; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a known 64 bit programming environment" >&5
+$as_echo_n "checking for a known 64 bit programming environment... " >&6; }
+ # Compile and run a program that determines the programming environment
+ if test "$cross_compiling" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+#include <stdio.h>
+int main(int argc,char **argv)
+{
+ if (argc > 1) {
+#if defined(__arch64__)
+ printf("__arch64__\n");
+#elif defined(__ia64__)
+ printf("__ia64__\n");
+#elif defined(__x86_64__)
+ printf("__x86_64__\n");
+#elif defined(__LP64__)
+ printf("__LP64__\n");
+#elif defined(__64BIT__)
+ printf("__64BIT__\n");
+#elif defined(_LP64)
+ printf("_LP64\n");
+#elif defined(_M_IA64)
+ printf("_M_IA64\n");
+#elif defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64)
+ printf("_MIPS_64\n");
+#else
+choke me
+#endif
+ }
+ return 0;
+}
+
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ # Program compiled and ran, so get version by adding argument.
+ samhain_prg_ENV=`./conftest$ac_exeext x`
+ samhain_64=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $samhain_prg_ENV" >&5
+$as_echo "$samhain_prg_ENV" >&6; }
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+ if test "x$samhain_64" = xyes; then
+ tiger_src=sh_tiger1_64.c
+ fi
+ #
+ # if GCC and __i386__, use precompiled assembler
+ #
+ if test "x$GCC" = xyes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-apple non-cygwin i386" >&5
+$as_echo_n "checking for non-apple non-cygwin i386... " >&6; }
+ samhain_i386=no
+ $CC -E -dM - < /dev/null | egrep '__i386__' >/dev/null 2>&1
+ if test $? = 0; then
+ case "$host_os" in
+ *linux*)
+ # apples gcc does not understand the assembly we provide
+ $CC -E -dM - < /dev/null | egrep '(__sun__|__APPLE__|__CYGWIN__)' >/dev/null 2>&1 || samhain_i386=yes
+ ;;
+ *)
+ ;;
+ esac
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $samhain_i386" >&5
+$as_echo "$samhain_i386" >&6; }
+ if test "x$samhain_i386" = xyes; then
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -pie -fPIE" >&5
+$as_echo_n "checking whether ${CC} accepts -pie -fPIE... " >&6; }
+if ${pie_cv_cc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pie_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -pie -fPIE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pie_cv_cc=yes
+else
+ pie_cv_cc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$pie_old_cflags"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pie_cv_cc" >&5
+$as_echo "$pie_cv_cc" >&6; }
+ if test $pie_cv_cc = yes; then
+ case "$host_os" in
+ *cygwin*)
+ ;;
+ *)
+ PIE_CFLAGS="-fPIE"
+ PIE_LDFLAGS="-pie"
+ ;;
+ esac
+ fi
+ fi
+
+ if test $pie_cv_cc = yes; then
+ tiger_src=sh_tiger1.s
+
+$as_echo "#define TIGER_32_BIT_S 1" >>confdefs.h
+
+ fi
+ fi
+ fi
+ #
+ #
+ #
+ else
+ samhain_64=no
+ tiger_src=sh_tiger1.c
+ fi
+else
+ #
+ # sizeof(unsigned long) = 8
+ #
+ tiger_src=sh_tiger1_64.c
+ samhain_64=yes
+ #
+ # check for x86_64 (enables assembly optimizations)
+ #
+ if test "x$GCC" = xyes; then
+ $CC -E -dM - < /dev/null | egrep '__clang__' >/dev/null 2>&1
+ if ! test $? = 0; then
+ case "$host_os" in
+ *linux*)
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86_64" >&5
+$as_echo_n "checking for x86_64... " >&6; }
+ if test "$cross_compiling" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int main() {
+__asm__ volatile (
+"movq %rax, %rax"
+);
+return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ samhain_64=yes
+ tiger_src=sh_tiger1_64.c
+ samhain_64_asm=yes
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+ ;;
+ *bsd*)
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86_64" >&5
+$as_echo_n "checking for x86_64... " >&6; }
+ if test "$cross_compiling" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int main() {
+__asm__ volatile (
+"movq %rax, %rax"
+);
+return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ samhain_64=yes
+ tiger_src=sh_tiger1_64.c
+ samhain_64_asm=yes
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+ ;;
+ *)
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for x86_64" >&5
+$as_echo_n "checking for x86_64... " >&6; }
+ if test "$cross_compiling" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int main() {
+__asm__ volatile (
+"movq %rax, %rax"
+);
+return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ samhain_64=yes
+ tiger_src=sh_tiger1_64.c
+ samhain_64_asm=yes
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+ ;;
+ esac
+ fi
+ fi
+fi
+if test "x$samhain_64" = xyes; then
+
+$as_echo "#define TIGER_64_BIT 1" >>confdefs.h
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64 bit environment" >&5
+$as_echo_n "checking for 64 bit environment... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $samhain_64" >&5
+$as_echo "$samhain_64" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tiger source to use" >&5
+$as_echo_n "checking for tiger source to use... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tiger_src" >&5
+$as_echo "$tiger_src" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if ${ac_cv_struct_tm+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+ int *p = &tm.tm_sec;
+ return !p;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_struct_tm=time.h
+else
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct stat has a st_flags field" >&5
+$as_echo_n "checking whether struct stat has a st_flags field... " >&6; }
+if ${e2fsprogs_cv_struct_st_flags+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/stat.h>
+int
+main ()
+{
+struct stat stat; stat.st_flags = 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ e2fsprogs_cv_struct_st_flags=yes
+else
+ e2fsprogs_cv_struct_st_flags=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $e2fsprogs_cv_struct_st_flags" >&5
+$as_echo "$e2fsprogs_cv_struct_st_flags" >&6; }
+if test "$e2fsprogs_cv_struct_st_flags" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether st_flags field is useful" >&5
+$as_echo_n "checking whether st_flags field is useful... " >&6; }
+ if ${e2fsprogs_cv_struct_st_flags_immut+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/stat.h>
+int
+main ()
+{
+struct stat stat; stat.st_flags |= UF_IMMUTABLE;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ e2fsprogs_cv_struct_st_flags_immut=yes
+else
+ e2fsprogs_cv_struct_st_flags_immut=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $e2fsprogs_cv_struct_st_flags_immut" >&5
+$as_echo "$e2fsprogs_cv_struct_st_flags_immut" >&6; }
+ if test "$e2fsprogs_cv_struct_st_flags_immut" = yes; then
+ $as_echo "#define HAVE_STAT_FLAGS 1" >>confdefs.h
+
+ fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct cmsgcred" >&5
+$as_echo_n "checking for struct cmsgcred... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+
+struct cmsgcred cred;
+
+cred.cmcred_pid = 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_have_struct_cmsgcred=yes
+else
+ sh_have_struct_cmsgcred=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_have_struct_cmsgcred" >&5
+$as_echo "$sh_have_struct_cmsgcred" >&6; }
+
+if test x$sh_have_struct_cmsgcred = xyes; then
+
+$as_echo "#define HAVE_STRUCT_CMSGCRED 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct fcred" >&5
+$as_echo_n "checking for struct fcred... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+
+int
+main ()
+{
+
+struct fcred sockcred;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_have_struct_fcred=yes
+else
+ sh_have_struct_fcred=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_have_struct_fcred" >&5
+$as_echo "$sh_have_struct_fcred" >&6; }
+
+if test x$sh_have_struct_fcred = xyes; then
+
+$as_echo "#define HAVE_STRUCT_FCRED 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct sockcred" >&5
+$as_echo_n "checking for struct sockcred... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+
+int
+main ()
+{
+
+struct sockcred sockcred;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_have_struct_sockcred=yes
+else
+ sh_have_struct_sockcred=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_have_struct_sockcred" >&5
+$as_echo "$sh_have_struct_sockcred" >&6; }
+
+if test x$sh_have_struct_sockcred = xyes; then
+
+$as_echo "#define HAVE_STRUCT_SOCKCRED 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SO_PEERCRED" >&5
+$as_echo_n "checking for SO_PEERCRED... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+
+int test = SO_PEERCRED;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sh_have_SO_PEERCRED=yes
+else
+ sh_have_SO_PEERCRED=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sh_have_SO_PEERCRED" >&5
+$as_echo "$sh_have_SO_PEERCRED" >&6; }
+
+if test x$sh_have_SO_PEERCRED = xyes; then
+
+$as_echo "#define HAVE_SO_PEERCRED 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this sort of thing. */
+ typedef int charset[2];
+ const charset cs = { 0, 0 };
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this sort of thing. */
+ char tx;
+ char *t = &tx;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; } bx;
+ struct s *b = &bx; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_bigendian=no
+else
+ ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+ no)
+ ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
+$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
+if ${ac_cv_c_restrict+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_restrict=no
+ # The order here caters to the fact that C++ does not require restrict.
+ for ac_kw in __restrict __restrict__ _Restrict restrict; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+typedef int * int_ptr;
+ int foo (int_ptr $ac_kw ip) {
+ return ip[0];
+ }
+int
+main ()
+{
+int s[1];
+ int * $ac_kw t = s;
+ t[0] = 0;
+ return foo(t)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_restrict=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_restrict" != no && break
+ done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5
+$as_echo "$ac_cv_c_restrict" >&6; }
+
+ case $ac_cv_c_restrict in
+ restrict) ;;
+ no) $as_echo "#define restrict /**/" >>confdefs.h
+ ;;
+ *) cat >>confdefs.h <<_ACEOF
+#define restrict $ac_cv_c_restrict
+_ACEOF
+ ;;
+ esac
+
+
+
+ am_cv_val_SA_SIGACTION=no
+ ac_fn_c_check_header_mongrel "$LINENO" "signal.h" "ac_cv_header_signal_h" "$ac_includes_default"
+if test "x$ac_cv_header_signal_h" = xyes; then :
+
+ if test $ac_cv_header_signal_h = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SI_USER in signal.h" >&5
+$as_echo_n "checking for SI_USER in signal.h... " >&6; }
+if ${am_cv_val_SI_USER+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <signal.h>
+int
+main ()
+{
+return SI_USER
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ am_cv_val_SI_USER=yes
+else
+ am_cv_val_SI_USER=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_val_SI_USER" >&5
+$as_echo "$am_cv_val_SI_USER" >&6; }
+ if test $am_cv_val_SI_USER = yes; then
+
+$as_echo "#define HAVE_SI_USER 1" >>confdefs.h
+
+ fi
+ fi
+ if test $ac_cv_header_signal_h = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SA_SIGINFO in signal.h" >&5
+$as_echo_n "checking for SA_SIGINFO in signal.h... " >&6; }
+if ${am_cv_val_SA_SIGINFO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <signal.h>
+int
+main ()
+{
+return SA_SIGINFO
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ am_cv_val_SA_SIGINFO=yes
+else
+ am_cv_val_SA_SIGINFO=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_val_SA_SIGINFO" >&5
+$as_echo "$am_cv_val_SA_SIGINFO" >&6; }
+ if test $am_cv_val_SA_SIGINFO = yes; then
+
+$as_echo "#define HAVE_SA_SIGINFO 1" >>confdefs.h
+
+ fi
+ fi
+ if test $am_cv_val_SI_USER = yes && test $am_cv_val_SA_SIGINFO = yes
+ then
+ if test "$cross_compiling" = yes; then :
+ am_cv_val_SA_SIGACTION=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <signal.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+volatile int xnum = 0;
+volatile int xcode = 0;
+jmp_buf Buf;
+int xsig = SIGSEGV;
+
+void sighandler (int xsignam, siginfo_t * xsiginfo, void * xsigadd)
+{
+ static sigset_t x;
+
+ if (xsiginfo == NULL)
+ exit(__LINE__);
+ if (xsiginfo->si_signo != xsignam)
+ exit(__LINE__);
+ ++xnum;
+ xcode = xsiginfo->si_code;
+ sigemptyset (&x);
+ sigprocmask(SIG_SETMASK, &x, NULL);
+ longjmp ( Buf, 1);
+}
+
+int main ()
+{
+ struct sigaction newact;
+
+ newact.sa_sigaction = sighandler;
+ sigemptyset (&newact.sa_mask);
+ newact.sa_flags = SA_SIGINFO;
+ if (0 != sigaction (xsig, &newact, NULL))
+ exit (__LINE__);
+ if(setjmp ( Buf)) {
+ if (xnum > 1)
+ goto Third;
+ goto Second;
+ }
+ memcpy((void *) 0x0, "test", 5);
+ Second:
+ if (xcode == SI_USER)
+ exit (__LINE__);
+ raise(xsig);
+ Third:
+ if (xcode != SI_USER)
+ exit (__LINE__);
+ if (xnum != 2)
+ exit (__LINE__);
+ return (0);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ am_cv_val_SA_SIGACTION=yes
+else
+ am_cv_val_SA_SIGACTION=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sa_sigaction is supported" >&5
+$as_echo_n "checking whether sa_sigaction is supported... " >&6; }
+ if test $am_cv_val_SA_SIGACTION = yes
+ then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define SA_SIGACTION_WORKS 1" >>confdefs.h
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+
+
+# Check whether --enable-ssp was given.
+if test "${enable_ssp+set}" = set; then :
+ enableval=$enable_ssp;
+else
+ enable_ssp=yes;
+
+fi
+
+
+if test "x$GCC" = "xyes"; then
+
+ if test x"${enable_ssp}" = xno; then
+ :
+ else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether libssp exists" >&5
+$as_echo_n "checking whether libssp exists... " >&6; }
+if ${ssp_cv_lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ssp_old_libs="$LIBS"
+ LIBS="$LIBS -lssp"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ssp_cv_lib=yes
+else
+ ssp_cv_lib=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ssp_old_libs"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssp_cv_lib" >&5
+$as_echo "$ssp_cv_lib" >&6; }
+ if test $ssp_cv_lib = yes; then
+ LIBS="$LIBS -lssp"
+ fi
+
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -fstack-protector-all" >&5
+$as_echo_n "checking whether ${CC} accepts -fstack-protector-all... " >&6; }
+if ${ssp_cv_cc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ssp_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -fstack-protector-all"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ssp_cv_cc=yes
+else
+ ssp_cv_cc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$ssp_old_cflags"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssp_cv_cc" >&5
+$as_echo "$ssp_cv_cc" >&6; }
+ if test $ssp_cv_cc = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -fstack-protector" >&5
+$as_echo_n "checking whether ${CC} accepts -fstack-protector... " >&6; }
+if ${ssp_cv_cc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ssp_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -fstack-protector"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ssp_cv_cc=yes
+else
+ ssp_cv_cc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$ssp_old_cflags"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssp_cv_cc" >&5
+$as_echo "$ssp_cv_cc" >&6; }
+ if test $ssp_cv_cc = yes; then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector"
+ LDFLAGS="$LDFLAGS -fstack-protector"
+
+$as_echo "#define ENABLE_SSP_CC 1" >>confdefs.h
+
+ fi
+ else
+ if test $ssp_cv_cc = yes; then
+ CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2 -fstack-protector-all"
+ LDFLAGS="$LDFLAGS -fstack-protector-all"
+
+$as_echo "#define ENABLE_SSP_CC 1" >>confdefs.h
+
+ fi
+ fi
+ fi
+
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -pie -fPIE" >&5
+$as_echo_n "checking whether ${CC} accepts -pie -fPIE... " >&6; }
+if ${pie_cv_cc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pie_old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -pie -fPIE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pie_cv_cc=yes
+else
+ pie_cv_cc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$pie_old_cflags"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pie_cv_cc" >&5
+$as_echo "$pie_cv_cc" >&6; }
+ if test $pie_cv_cc = yes; then
+ case "$host_os" in
+ *cygwin*)
+ ;;
+ *)
+ PIE_CFLAGS="-fPIE"
+ PIE_LDFLAGS="-pie"
+ ;;
+ esac
+ fi
+ fi
+
+ fi
+
+fi
+
+
+if test -d "/proc/$$"
+then
+
+$as_echo "#define HAVE_PROCFS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __gmpz_init in -lgmp" >&5
+$as_echo_n "checking for __gmpz_init in -lgmp... " >&6; }
+if ${ac_cv_lib_gmp___gmpz_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgmp $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char __gmpz_init ();
+int
+main ()
+{
+return __gmpz_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_gmp___gmpz_init=yes
+else
+ ac_cv_lib_gmp___gmpz_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmp___gmpz_init" >&5
+$as_echo "$ac_cv_lib_gmp___gmpz_init" >&6; }
+if test "x$ac_cv_lib_gmp___gmpz_init" = xyes; then :
+ sh_have_gmp=yes
+else
+ sh_have_gmp=no
+fi
+
+if test "x${sh_have_gmp}" = xno
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mpz_init in -lgmp" >&5
+$as_echo_n "checking for mpz_init in -lgmp... " >&6; }
+if ${ac_cv_lib_gmp_mpz_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgmp $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mpz_init ();
+int
+main ()
+{
+return mpz_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_gmp_mpz_init=yes
+else
+ ac_cv_lib_gmp_mpz_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmp_mpz_init" >&5
+$as_echo "$ac_cv_lib_gmp_mpz_init" >&6; }
+if test "x$ac_cv_lib_gmp_mpz_init" = xyes; then :
+ sh_have_gmp=yes
+else
+ sh_have_gmp=no
+fi
+
+fi
+if test "x${sh_have_gmp}" = xyes
+then
+ # LIBS="-lgmp $LIBS"
+
+$as_echo "#define HAVE_LIBGMP 1" >>confdefs.h
+
+fi
+for ac_header in gmp.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "gmp.h" "ac_cv_header_gmp_h" "$ac_includes_default"
+if test "x$ac_cv_header_gmp_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GMP_H 1
+_ACEOF
+
+fi
+
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ps" >&5
+$as_echo_n "checking for ps... " >&6; }
+PS=
+for ff in /usr/ucb /bin /usr/bin; do
+ if test -x "$ff/ps"; then
+ PS="$ff/ps"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PS" >&5
+$as_echo "$PS" >&6; }
+ break
+ fi
+done
+if test x$PS = x
+then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Cannot find ps in any of /usr/ucb /bin /usr/bin" "$LINENO" 5
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define PSPATH _("$PS")
+_ACEOF
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to use ps" >&5
+$as_echo_n "checking how to use ps... " >&6; }
+$PS ax >/dev/null 2>&1
+if test $? -eq 0; then
+ case "$host_os" in
+ *openbsd*)
+ one=`$PS akx | wc -l`
+ ;;
+ *)
+ one=`$PS ax | wc -l`
+ ;;
+ esac
+else
+ one=0
+fi
+$PS -e >/dev/null 2>&1
+if test $? -eq 0; then
+ two=`$PS -e | wc -l`
+else
+ two=0
+fi
+if test $one -ge $two
+then
+ case "$host_os" in
+ *openbsd*)
+ PSARG="akx"
+ ;;
+ *)
+ PSARG="ax"
+ ;;
+ esac
+else
+ PSARG="-e"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define PSARG _("$PSARG")
+_ACEOF
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PS $PSARG" >&5
+$as_echo "$PS $PSARG" >&6; }
+
+
+# Check whether --enable-db-reload was given.
+if test "${enable_db_reload+set}" = set; then :
+ enableval=$enable_db_reload;
+ if test "x${enable_db_reload}" = xyes; then
+ $as_echo "#define RELOAD_DATABASE 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-xml-log was given.
+if test "${enable_xml_log+set}" = set; then :
+ enableval=$enable_xml_log;
+ if test "x${enable_xml_log}" = xyes; then
+ $as_echo "#define SH_USE_XML 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+
+# Check whether --enable-mail was given.
+if test "${enable_mail+set}" = set; then :
+ enableval=$enable_mail;
+ if test "x${enable_mail}" = xno; then
+ :
+ else
+ $as_echo "#define SH_WITH_MAIL 1" >>confdefs.h
+
+ fi
+
+else
+ $as_echo "#define SH_WITH_MAIL 1" >>confdefs.h
+
+
+fi
+
+
+# Check whether --enable-suid was given.
+if test "${enable_suid+set}" = set; then :
+ enableval=$enable_suid;
+ if test "x${enable_suid}" = xyes; then
+
+$as_echo "#define SH_ALLOW_SUID 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-shellexpand was given.
+if test "${enable_shellexpand+set}" = set; then :
+ enableval=$enable_shellexpand;
+ if test "x${enable_shellexpand}" = xno; then
+ :
+ else
+
+$as_echo "#define SH_EVAL_SHELL 1" >>confdefs.h
+
+ fi
+
+else
+
+$as_echo "#define SH_EVAL_SHELL 1" >>confdefs.h
+
+
+fi
+
+
+# Check whether --enable-external-scripts was given.
+if test "${enable_external_scripts+set}" = set; then :
+ enableval=$enable_external_scripts;
+ if test "x${enableval}" = xno; then
+ :
+ else
+ $as_echo "#define WITH_EXTERNAL 1" >>confdefs.h
+
+ fi
+
+else
+ $as_echo "#define WITH_EXTERNAL 1" >>confdefs.h
+
+
+fi
+
+
+# Check whether --enable-message-queue was given.
+if test "${enable_message_queue+set}" = set; then :
+ enableval=$enable_message_queue;
+ if test "x${ac_cv_header_sys_msg_h}" = "xyes"; then
+ if test "x${enable_message_queue}" = xyes; then
+ $as_echo "#define WITH_MESSAGE_QUEUE 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define MESSAGE_QUEUE_MODE 0700
+_ACEOF
+
+ elif test "x${enable_message_queue}" != xno; then
+ echo "${enableval}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "With --enable-message-queue=MODE, MODE must be numeric" "$LINENO" 5
+ echo "${enableval}" | \
+ grep '0[0123456789][0123456789][0123456789]' >/dev/null 2>&1 ||
+ as_fn_error $? "With --enable-message-queue=MODE, MODE must be an octal (0nnn) number" "$LINENO" 5
+ $as_echo "#define WITH_MESSAGE_QUEUE 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define MESSAGE_QUEUE_MODE ${enable_message_queue}
+_ACEOF
+
+ fi
+ else
+ echo
+ echo "**********************************************"
+ echo
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: sys/msg.h missing, --enable-message-queue disabled" >&5
+$as_echo "$as_me: WARNING: sys/msg.h missing, --enable-message-queue disabled" >&2;}
+ echo
+ echo "**********************************************"
+ echo
+ fi
+
+
+fi
+
+
+
+# Check whether --with-cflags was given.
+if test "${with_cflags+set}" = set; then :
+ withval=$with_cflags;
+ if test "x$withval" != "xno" ; then
+ CFLAGS="$CFLAGS $withval"
+ fi
+
+
+fi
+
+
+# Check whether --with-libs was given.
+if test "${with_libs+set}" = set; then :
+ withval=$with_libs;
+ if test "x$withval" != "xno" ; then
+ LIBS="$LIBS $withval"
+ fi
+
+
+fi
+
+
+
+#
+# this is from ssh
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libwrap" >&5
+$as_echo_n "checking whether to use libwrap... " >&6; }
+LIBWRAP_LIB=""
+LIBWRAP_INC=""
+
+# Check whether --with-libwrap was given.
+if test "${with_libwrap+set}" = set; then :
+ withval=$with_libwrap; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
+$as_echo "$withval" >&6; }
+ case "$withval" in
+ no)
+ ;;
+ ""|yes)
+ LIBWRAP_LIB="-lwrap"
+ ;;
+ *)
+ if test -d "$withval"; then
+ LIBWRAP_LIB="-L$withval -lwrap"
+ sh_libwrap_inc=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+ LIBWRAP_INC="-I${sh_libwrap_inc}/include"
+ else
+ LIBWRAP_LIB="-lwrap"
+ sh_libwrap_inc=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+ LIBWRAP_INC="-I${sh_libwrap_inc}"
+ fi
+ ;;
+ esac
+ if test -n "$LIBWRAP_LIB"; then
+ # OLDLIBS="$LIBS"
+ LIBS="$LIBWRAP_LIB $LIBS"
+ # OLDCFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $LIBWRAP_INC"
+ ac_fn_c_check_header_mongrel "$LINENO" "tcpd.h" "ac_cv_header_tcpd_h" "$ac_includes_default"
+if test "x$ac_cv_header_tcpd_h" = xyes; then :
+
+else
+ as_fn_error $? "Could not find tcpd.h for libwrap. You need to install tcp_wrappers." "$LINENO" 5
+fi
+
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ #include <tcpd.h>
+ int allow_severity; int deny_severity;
+int
+main ()
+{
+ hosts_access((struct request_info *) 0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define SH_USE_LIBWRAP 1" >>confdefs.h
+
+else
+ as_fn_error $? "Could not find the libwrap library." "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+
+
+
+# Check whether --enable-network was given.
+if test "${enable_network+set}" = set; then :
+ enableval=$enable_network;
+ if test "x$enable_network" = xclient; then
+ mytclient="-DSH_WITH_CLIENT"
+ yulectl_prg=
+ samhainadmin_prg=
+ setpwd_prg="samhain_setpwd"
+ sh_main_prg="samhain"
+ if test "x${sh_have_gmp}" = xyes
+ then
+ LIBS="-lgmp $LIBS"
+ fi
+ elif test "x$enable_network" = xserver; then
+ mytclient="-DSH_WITH_SERVER"
+ yulectl_prg="yulectl"
+ samhainadmin_prg="scripts/samhainadmin.pl"
+ setpwd_prg="samhain_setpwd"
+ sh_main_prg="yule"
+ if test "x${sh_have_gmp}" = xyes
+ then
+ LIBS="-lgmp $LIBS"
+ fi
+ sh_use_lcaps="undef"
+ elif test "x$enable_network" = xno; then
+ mytclient="-DSH_STANDALONE"
+ yulectl_prg=
+ samhainadmin_prg=
+ setpwd_prg=
+ sh_main_prg="samhain"
+ else
+ as_fn_error $? "With --enable-network=WHAT, WHAT must be client, server, or no" "$LINENO" 5
+ fi
+
+else
+
+ mytclient="-DSH_STANDALONE"
+ setpwd_prg=
+ yulectl_prg=
+ samhainadmin_prg=
+ sh_main_prg="samhain"
+
+fi
+
+
+
+
+
+
+
+
+# needed for the rpm spec
+clmytclient=`echo ${mytclient} | sed s%\-%%`
+
+
+sh_no_gcc_static=no
+
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static;
+ if test x$enable_static = xyes; then
+ if test x"$mynetbsd" = xyes
+ then
+ tmp_LIBS=`echo $LIBS | sed 's%\-lresolv%%' `
+ LIBS="${tmp_LIBS}"
+ fi
+ if test x"${sh_auparse}" = xyes
+ then
+ tmp_LIBS=`echo $LIBS | sed 's%\-lauparse%%' `
+ LIBS="${tmp_LIBS}"
+ fi
+
+ if test "x$GCC" = "xyes";
+ then
+ case "$host_os" in
+
+ *solaris*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: option --enable-static ignored on Solaris" >&5
+$as_echo "$as_me: WARNING: option --enable-static ignored on Solaris" >&2;}
+ ;;
+
+ *)
+
+$as_echo "#define SH_COMPILE_STATIC 1" >>confdefs.h
+
+ sh_no_gcc_static=no
+ LDFLAGS="$LDFLAGS -static"
+ ;;
+ esac
+ else
+
+$as_echo "#define SH_COMPILE_STATIC 1" >>confdefs.h
+
+ sh_no_gcc_static=yes
+ case "$host_os" in
+
+ *aix*)
+ LDFLAGS="$LDFLAGS -bnso -bI:/lib/syscalls.exp"
+ ;;
+
+ *hpux*)
+ LDFLAGS="$LDFLAGS -Wl,-a,archive"
+ ;;
+
+ *osf*)
+ LDFLAGS="$LDFLAGS -non_shared"
+ ;;
+
+ *irix*)
+ LDFLAGS="$LDFLAGS -non_shared"
+ ;;
+
+ *sco*)
+ LDFLAGS="$LDFLAGS -dn"
+ ;;
+
+ *sun*)
+ LDFLAGS="$LDFLAGS -Bstatic"
+ ;;
+
+ *solaris*)
+ LDFLAGS="$LDFLAGS -Bstatic"
+ ;;
+
+ *)
+ echo "***********************************************"
+ echo "*"
+ echo "* Don't know how to enable static linking"
+ echo "* with your compiler. Please set the environment"
+ echo "* variable LDFLAGS to:"
+ echo "* ${LDFLAGS} + the static linking flag"
+ echo "* and run configure again"
+ echo "*"
+ echo "***********************************************"
+ ;;
+
+ esac
+ fi
+ fi
+
+
+fi
+
+
+if test x"${mytclient}" = x-DSH_STANDALONE -o x"${mytclient}" = x-DSH_WITH_CLIENT;
+then
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5
+$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_join ();
+int
+main ()
+{
+return pthread_join ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ acx_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5
+$as_echo "$acx_pthread_ok" >&6; }
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
+$as_echo_n "checking whether pthreads work without any flags... " >&6; }
+ ;;
+
+ -pthread)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5
+$as_echo_n "checking whether pthreads work with $flag... " >&6; }
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ -*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5
+$as_echo_n "checking whether pthreads work with $flag... " >&6; }
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ # Extract the first word of "pthread-config", so it can be a program name with args.
+set dummy pthread-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_acx_pthread_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$acx_pthread_config"; then
+ ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_acx_pthread_config="yes"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no"
+fi
+fi
+acx_pthread_config=$ac_cv_prog_acx_pthread_config
+if test -n "$acx_pthread_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5
+$as_echo "$acx_pthread_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5
+$as_echo_n "checking for the pthreads library -l$flag... " >&6; }
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LDFLAGS="$LDFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ acx_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ LIBS="$save_LIBS"
+ LDFLAGS="$save_LDFLAGS"
+ CFLAGS="$save_CFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5
+$as_echo "$acx_pthread_ok" >&6; }
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
+$as_echo_n "checking for joinable pthread attribute... " >&6; }
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+int attr=$attr; return attr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ attr_name=$attr; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5
+$as_echo "$attr_name" >&6; }
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+
+cat >>confdefs.h <<_ACEOF
+#define PTHREAD_CREATE_JOINABLE $attr_name
+_ACEOF
+
+ fi
+
+ # Solaris lossage: default is obsolete semantics for getpwnam_r,
+ # getpwuid_r, getgrgid_r, unless _POSIX_PTHREAD_SEMANTICS is defined
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5
+$as_echo_n "checking if more special flags are required for pthreads... " >&6; }
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ *solaris*) flag="-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT";;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5
+$as_echo "${flag}" >&6; }
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ # Detect PTHREAD_MUTEX_RECURSIVE
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for recursive mutexes" >&5
+$as_echo_n "checking for recursive mutexes... " >&6; }
+ mutex_recursive=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#define _XOPEN_SOURCE 500
+#include <pthread.h>
+int
+main ()
+{
+
+pthread_mutexattr_t mta;
+pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ mutex_recursive=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test "x$mutex_recursive" = "xyes"
+ then
+
+$as_echo "#define HAVE_PTHREAD_MUTEX_RECURSIVE 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $mutex_recursive" >&5
+$as_echo "$mutex_recursive" >&6; }
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ for ac_prog in xlc_r cc_r
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PTHREAD_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PTHREAD_CC"; then
+ ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PTHREAD_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
+if test -n "$PTHREAD_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
+$as_echo "$PTHREAD_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PTHREAD_CC" && break
+done
+test -n "$PTHREAD_CC" || PTHREAD_CC="${CC}"
+
+ else
+ PTHREAD_CC=$CC
+ fi
+else
+ PTHREAD_CC="$CC"
+fi
+
+if test x"$acx_pthread_ok" = xyes; then
+ PTHREAD_CFLAGS="${PTHREAD_CFLAGS} -DUSE_MALLOC_LOCK=1"
+fi
+
+
+
+
+
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+
+$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h
+
+ :
+else
+ acx_pthread_ok=no
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ LDFLAGS="$PTHREAD_CFLAGS $LDFLAGS"
+ CC="$PTHREAD_CC"
+
+
+if test "x${ZLIB_HOME}" = "x"; then
+ ZLIB_HOME=/usr/local
+ if test ! -f "${ZLIB_HOME}/include/zlib.h"
+ then
+ ZLIB_HOME=/usr
+ fi
+fi
+
+zlib_found=no
+
+ZLIB_OLD_LDFLAGS=$LDFLAGS
+ZLIB_OLD_CPPFLAGS=$LDFLAGS
+if test "x${ZLIB_HOME}" = "x/usr"; then
+ :
+else
+ LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
+ CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5
+$as_echo_n "checking for inflateEnd in -lz... " >&6; }
+if ${ac_cv_lib_z_inflateEnd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inflateEnd ();
+int
+main ()
+{
+return inflateEnd ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_inflateEnd=yes
+else
+ ac_cv_lib_z_inflateEnd=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5
+$as_echo "$ac_cv_lib_z_inflateEnd" >&6; }
+if test "x$ac_cv_lib_z_inflateEnd" = xyes; then :
+ zlib_cv_libz=yes
+else
+ zlib_cv_libz=no
+fi
+
+ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = xyes; then :
+ zlib_cv_zlib_h=yes
+else
+ zlib_cv_zlib_h=no
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test "$zlib_cv_libz" = "yes" -a "$zlib_cv_zlib_h" = "yes"
+then
+ #
+ # If both library and header were found, use them
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5
+$as_echo_n "checking for inflateEnd in -lz... " >&6; }
+if ${ac_cv_lib_z_inflateEnd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inflateEnd ();
+int
+main ()
+{
+return inflateEnd ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_inflateEnd=yes
+else
+ ac_cv_lib_z_inflateEnd=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5
+$as_echo "$ac_cv_lib_z_inflateEnd" >&6; }
+if test "x$ac_cv_lib_z_inflateEnd" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+ LIBS="-lz $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking zlib in ${ZLIB_HOME}" >&5
+$as_echo_n "checking zlib in ${ZLIB_HOME}... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+ for ac_func in compressBound
+do :
+ ac_fn_c_check_func "$LINENO" "compressBound" "ac_cv_func_compressBound"
+if test "x$ac_cv_func_compressBound" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_COMPRESSBOUND 1
+_ACEOF
+
+fi
+done
+
+ zlib_found=yes
+else
+ #
+ # If either header or library was not found, revert and bomb
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking zlib in ${ZLIB_HOME}" >&5
+$as_echo_n "checking zlib in ${ZLIB_HOME}... " >&6; }
+ LDFLAGS="$ZLIB_OLD_LDFLAGS"
+ CPPFLAGS="$ZLIB_OLD_CPPFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: zlib not found in ZLIB_HOME, /usr/local, or /usr" >&5
+$as_echo "$as_me: WARNING: zlib not found in ZLIB_HOME, /usr/local, or /usr" >&2;}
+fi
+
+
+fi
+
+if test x$enable_static = xyes; then
+ :
+else
+ if test x$sh_use_pie = xyes; then
+ LDFLAGS="$LDFLAGS $PIE_LDFLAGS"
+ CFLAGS="$CFLAGS $PIE_CFLAGS"
+ fi
+fi
+ac_fn_c_check_func "$LINENO" "pmap_getmaps" "ac_cv_func_pmap_getmaps"
+if test "x$ac_cv_func_pmap_getmaps" = xyes; then :
+
+$as_echo "#define HAVE_PMAP_GETMAPS /**/" >>confdefs.h
+
+fi
+
+
+
+#
+# this is from the snort configure.in
+#
+
+
+
+# Check whether --with-libprelude-prefix was given.
+if test "${with_libprelude_prefix+set}" = set; then :
+ withval=$with_libprelude_prefix; libprelude_config_prefix="$withval"
+else
+ libprelude_config_prefix=""
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use prelude" >&5
+$as_echo_n "checking whether to use prelude... " >&6; }
+
+# Check whether --with-prelude was given.
+if test "${with_prelude+set}" = set; then :
+ withval=$with_prelude;
+ if test "x${withval}" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ if test x$libprelude_config_prefix != x ; then
+ if test x${LIBPRELUDE_CONFIG+set} != xset ; then
+ LIBPRELUDE_CONFIG=$libprelude_config_prefix/bin/libprelude-config
+ fi
+ fi
+
+ # Extract the first word of "libprelude-config", so it can be a program name with args.
+set dummy libprelude-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_LIBPRELUDE_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $LIBPRELUDE_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_LIBPRELUDE_CONFIG="$LIBPRELUDE_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_LIBPRELUDE_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_LIBPRELUDE_CONFIG" && ac_cv_path_LIBPRELUDE_CONFIG="no"
+ ;;
+esac
+fi
+LIBPRELUDE_CONFIG=$ac_cv_path_LIBPRELUDE_CONFIG
+if test -n "$LIBPRELUDE_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBPRELUDE_CONFIG" >&5
+$as_echo "$LIBPRELUDE_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test x"$LIBPRELUDE_CONFIG" = "xno" ; then
+ HAVE_PRELUDE_CONFIG=no
+ else
+ HAVE_PRELUDE_CONFIG=yes
+ fi
+ if test "$HAVE_PRELUDE_CONFIG" = "yes"; then
+ sh_libprelude_version=`$LIBPRELUDE_CONFIG --version`
+ case "$sh_libprelude_version" in
+ 0.8*)
+ as_fn_error $? "You have Libprelude 0.8, which is too old. Version 0.9.6 or higher is required." "$LINENO" 5
+ ;;
+ *)
+ min_libprelude_version=0.9.6
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libprelude - version >= $min_libprelude_version" >&5
+$as_echo_n "checking for libprelude - version >= $min_libprelude_version... " >&6; }
+ no_libprelude=""
+ if test "$LIBPRELUDE_CONFIG" = "no" ; then
+ no_libprelude=yes
+ else
+ LIBPRELUDE_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --cflags`
+ LIBPRELUDE_PTHREAD_CFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --pthread-cflags`
+ LIBPRELUDE_LDFLAGS=`$LIBPRELUDE_CONFIG $libprelude_config_args --ldflags`
+ LIBPRELUDE_LIBS=`$LIBPRELUDE_CONFIG $libprelude_config_args --libs`
+ LIBPRELUDE_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --prefix`
+ LIBPRELUDE_CONFIG_PREFIX=`$LIBPRELUDE_CONFIG $libprelude_config_args --config-prefix`
+ libprelude_config_version=`$LIBPRELUDE_CONFIG $libprelude_config_args --version`
+
+
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LDFLAGS="$LDFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS"
+ LIBS="$LIBS $LIBPRELUDE_LIBS"
+ rm -f conf.libpreludetest
+ if test "$cross_compiling" = yes; then :
+ echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libprelude/prelude.h>
+
+int
+main ()
+{
+ system ("touch conf.libpreludetest");
+
+ if( strcmp( prelude_check_version(NULL), "$libprelude_config_version" ) )
+ {
+ printf("\n*** 'libprelude-config --version' returned %s, but LIBPRELUDE (%s)\n",
+ "$libprelude_config_version", prelude_check_version(NULL) );
+ printf("*** was found! If libprelude-config was correct, then it is best\n");
+ printf("*** to remove the old version of LIBPRELUDE. You may also be able to fix the error\n");
+ printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+ printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+ printf("*** required on your system.\n");
+ printf("*** If libprelude-config was wrong, set the environment variable LIBPRELUDE_CONFIG\n");
+ printf("*** to point to the correct copy of libprelude-config, and remove the file config.cache\n");
+ printf("*** before re-running configure\n");
+ }
+ else if ( strcmp(prelude_check_version(NULL), LIBPRELUDE_VERSION ) )
+ {
+ printf("\n*** LIBPRELUDE header file (version %s) does not match\n", LIBPRELUDE_VERSION);
+ printf("*** library (version %s)\n", prelude_check_version(NULL) );
+ }
+ else
+ {
+ if ( prelude_check_version( "$min_libprelude_version" ) )
+ {
+ return 0;
+ }
+ else
+ {
+ printf("no\n*** An old version of LIBPRELUDE (%s) was found.\n",
+ prelude_check_version(NULL) );
+ printf("*** You need a version of LIBPRELUDE newer than %s. The latest version of\n",
+ "$min_libprelude_version" );
+ printf("*** LIBPRELUDE is always available from http://www.prelude-ids.org/download/releases.\n");
+ printf("*** \n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the libprelude-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of LIBPRELUDE, but you can also set the LIBPRELUDE_CONFIG environment to point to the\n");
+ printf("*** correct copy of libprelude-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ }
+ return 1;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ no_libprelude=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ LDFLAGS="$ac_save_LDFLAGS"
+ fi
+
+ if test "x$no_libprelude" = x ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_LIBPRELUDE 1" >>confdefs.h
+
+ CFLAGS="$CFLAGS $LIBPRELUDE_PTHREAD_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS"
+ LIBS="$LIBS $LIBPRELUDE_LIBS"
+
+ else
+ if test -f conf.libpreludetest ; then
+ :
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ if test "$LIBPRELUDE_CONFIG" = "no" ; then
+ echo "*** The libprelude-config script installed by LIBPRELUDE could not be found"
+ echo "*** If LIBPRELUDE was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the LIBPRELUDE_CONFIG environment variable to the"
+ echo "*** full path to libprelude-config."
+ else
+ if test -f conf.libpreludetest ; then
+ :
+ else
+ echo "*** Could not run libprelude test program, checking why..."
+ CFLAGS="$CFLAGS $LIBPRELUDE_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS"
+ LIBS="$LIBS $LIBPRELUDE_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libprelude/prelude.h>
+
+int
+main ()
+{
+ return !!prelude_check_version(NULL);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding LIBPRELUDE or finding the wrong"
+ echo "*** version of LIBPRELUDE. If it is not finding LIBPRELUDE, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ echo "***"
+else
+ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means LIBPRELUDE was incorrectly installed"
+ echo "*** or that you have moved LIBPRELUDE since it was installed. In the latter case, you"
+ echo "*** may want to edit the libprelude-config script: $LIBPRELUDE_CONFIG"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CFLAGS="$ac_save_CFLAGS"
+ LDFLAGS="$ac_save_LDFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+ LIBPRELUDE_CFLAGS=""
+ LIBPRELUDE_LDFLAGS=""
+ LIBPRELUDE_LIBS=""
+
+ as_fn_error $? "Could not find libprelude (if you are using --enable-static, the static library libprelude.a might be missing)." "$LINENO" 5
+
+ fi
+ rm -f conf.libpreludetest
+
+
+
+
+
+
+
+ ;;
+ esac
+ else
+ as_fn_error $? "Could not find libprelude-config." "$LINENO" 5
+ fi
+ fi
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+
+fi
+
+
+#
+# partly based on the snort configure.in
+#
+
+# Check whether --with-database was given.
+if test "${with_database+set}" = set; then :
+ withval=$with_database;
+ if test x"$enable_xml_log" != xyes; then
+ as_fn_error $? "With --with-database, --enable-xml-log is required as well." "$LINENO" 5
+ fi
+ if test "x${withval}" = "xmysql"; then
+ if test "x$zlib_found" = "x"
+ then
+
+
+if test "x${ZLIB_HOME}" = "x"; then
+ ZLIB_HOME=/usr/local
+ if test ! -f "${ZLIB_HOME}/include/zlib.h"
+ then
+ ZLIB_HOME=/usr
+ fi
+fi
+
+zlib_found=no
+
+ZLIB_OLD_LDFLAGS=$LDFLAGS
+ZLIB_OLD_CPPFLAGS=$LDFLAGS
+if test "x${ZLIB_HOME}" = "x/usr"; then
+ :
+else
+ LDFLAGS="$LDFLAGS -L${ZLIB_HOME}/lib"
+ CPPFLAGS="$CPPFLAGS -I${ZLIB_HOME}/include"
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5
+$as_echo_n "checking for inflateEnd in -lz... " >&6; }
+if ${ac_cv_lib_z_inflateEnd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inflateEnd ();
+int
+main ()
+{
+return inflateEnd ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_inflateEnd=yes
+else
+ ac_cv_lib_z_inflateEnd=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5
+$as_echo "$ac_cv_lib_z_inflateEnd" >&6; }
+if test "x$ac_cv_lib_z_inflateEnd" = xyes; then :
+ zlib_cv_libz=yes
+else
+ zlib_cv_libz=no
+fi
+
+ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = xyes; then :
+ zlib_cv_zlib_h=yes
+else
+ zlib_cv_zlib_h=no
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test "$zlib_cv_libz" = "yes" -a "$zlib_cv_zlib_h" = "yes"
+then
+ #
+ # If both library and header were found, use them
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5
+$as_echo_n "checking for inflateEnd in -lz... " >&6; }
+if ${ac_cv_lib_z_inflateEnd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inflateEnd ();
+int
+main ()
+{
+return inflateEnd ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_inflateEnd=yes
+else
+ ac_cv_lib_z_inflateEnd=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5
+$as_echo "$ac_cv_lib_z_inflateEnd" >&6; }
+if test "x$ac_cv_lib_z_inflateEnd" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+ LIBS="-lz $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking zlib in ${ZLIB_HOME}" >&5
+$as_echo_n "checking zlib in ${ZLIB_HOME}... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+ for ac_func in compressBound
+do :
+ ac_fn_c_check_func "$LINENO" "compressBound" "ac_cv_func_compressBound"
+if test "x$ac_cv_func_compressBound" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_COMPRESSBOUND 1
+_ACEOF
+
+fi
+done
+
+ zlib_found=yes
+else
+ #
+ # If either header or library was not found, revert and bomb
+ #
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking zlib in ${ZLIB_HOME}" >&5
+$as_echo_n "checking zlib in ${ZLIB_HOME}... " >&6; }
+ LDFLAGS="$ZLIB_OLD_LDFLAGS"
+ CPPFLAGS="$ZLIB_OLD_CPPFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: zlib not found in ZLIB_HOME, /usr/local, or /usr" >&5
+$as_echo "$as_me: WARNING: zlib not found in ZLIB_HOME, /usr/local, or /usr" >&2;}
+fi
+
+
+ fi
+ # Extract the first word of "mysql_config", so it can be a program name with args.
+set dummy mysql_config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_HAVE_MYSQL_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$HAVE_MYSQL_CONFIG"; then
+ ac_cv_prog_HAVE_MYSQL_CONFIG="$HAVE_MYSQL_CONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_HAVE_MYSQL_CONFIG="yes"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_HAVE_MYSQL_CONFIG" && ac_cv_prog_HAVE_MYSQL_CONFIG="no"
+fi
+fi
+HAVE_MYSQL_CONFIG=$ac_cv_prog_HAVE_MYSQL_CONFIG
+if test -n "$HAVE_MYSQL_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_MYSQL_CONFIG" >&5
+$as_echo "$HAVE_MYSQL_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "$HAVE_MYSQL_CONFIG" = "yes"; then
+ sh_mysql_libs="`mysql_config --libs`"
+ sh_mysql_libs="`eval echo ${sh_mysql_libs}`"
+ LIBS="$LIBS ${sh_mysql_libs}"
+ sh_mysql_cflags="`mysql_config --cflags`"
+ sh_mysql_cflags="`eval echo ${sh_mysql_cflags}`"
+ CPPFLAGS="$CPPFLAGS ${sh_mysql_cflags}"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MySQL in /usr /usr/local /usr/local/mysql MYSQL_HOME" >&5
+$as_echo_n "checking for MySQL in /usr /usr/local /usr/local/mysql MYSQL_HOME... " >&6; }
+ mysql_directory="/usr /usr/local /usr/local/mysql ${MYSQL_HOME}"
+
+ for i in $mysql_directory; do
+ if test -r $i/include/mysql/mysql.h; then
+ MYSQL_DIR=$i
+ MYSQL_INC_DIR=$i/include
+ # we use AC_CHECK_HEADERS to check for mysql/mysql.h
+ fi
+ done
+ if test -z "$MYSQL_DIR"; then
+ for i in $mysql_directory; do
+ if test -r $i/include/mysql.h; then
+ MYSQL_DIR=$i
+ MYSQL_INC_DIR=$i/include
+ fi
+ done
+ fi
+
+ if test -z "$MYSQL_DIR"; then
+ tmp=""
+ for i in $mysql_directory; do
+ tmp="$tmp $i/include $i/include/mysql"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "mysql headers (mysql.h)"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+ fi
+
+ for i in lib lib/mysql; do
+ str="$MYSQL_DIR/$i/libmysqlclient.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ MYSQL_LIB_DIR="$MYSQL_DIR/$i"
+ break 2
+ fi
+ done
+ done
+
+ if test -z "$MYSQL_LIB_DIR"; then
+ for ff in $mysql_directory; do
+ for i in lib lib/mysql; do
+ str="$ff/$i/libmysqlclient.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ MYSQL_LIB_DIR="$ff/$i"
+ break 3
+ fi
+ done
+ done
+ done
+ fi
+
+ if test -z "$MYSQL_LIB_DIR"; then
+ tmp=""
+ for i in $mysql_directory; do
+ tmp="$i/lib $i/lib/mysql"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "mysql library libmysqlclient"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ LIBS="$LIBS -L${MYSQL_LIB_DIR} -lmysqlclient"
+ # CFLAGS="$CFLAGS -I${MYSQL_INC_DIR}"
+ CPPFLAGS="$CPPFLAGS -I${MYSQL_INC_DIR}"
+ fi
+ $as_echo "#define WITH_MYSQL 1" >>confdefs.h
+
+ $as_echo "#define WITH_DATABASE 1" >>confdefs.h
+
+ if test "x$zlib_found" = "xyes"
+ then
+ LIBS="$LIBS -lz -lm"
+ else
+ echo
+
+ echo " Mysql library was not found or not useable."
+ echo " Possible reasons include:"
+ echo " - an old, incompatible version compiled from source"
+ echo " - on Solaris, libmysql is compiled with the Solaris"
+ echo " compiler, thus the mysql_config script provides"
+ echo " compiler options unsuitable for gcc (move"
+ echo " mysql_config out of your PATH)"
+ echo " For other problems, check config.log for the error"
+ echo " message from the compiler."
+ echo
+ echo " If your mysql libraries are installed in an"
+ echo " unusual place, use --with-libs=-L/path/to/libdirectory"
+ echo " where libdirectory is the directory holding libmysql."
+ if test x"$enable_static" = xyes; then
+ echo " Note that for compiling a static binary, you need"
+ echo " the static libraries, rather than the shared ones."
+ fi
+ echo
+ as_fn_error $? "Could not find libmysql, or it is not useable." "$LINENO" 5
+ fi
+ for ac_header in mysql/mysql.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "mysql/mysql.h" "ac_cv_header_mysql_mysql_h" "$ac_includes_default"
+if test "x$ac_cv_header_mysql_mysql_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_MYSQL_MYSQL_H 1
+_ACEOF
+
+fi
+
+done
+
+ elif test "x${withval}" = "xpostgresql"; then
+ $as_echo "#define WITH_POSTGRES 1" >>confdefs.h
+
+ $as_echo "#define WITH_DATABASE 1" >>confdefs.h
+
+ #
+ PGCONF="no"
+ MY_PATH="${PATH}:/usr/local/bin:/usr/local/pgsql/bin"
+ OLD_IFS="$IFS"
+ IFS=":"
+ for ff in ${MY_PATH}
+ do
+ if test -f "$ff/pg_config"
+ then
+ PGCONF="$ff/pg_config"
+ fi
+ done
+ IFS="${OLD_IFS}"
+ #
+ #
+ if test "x${PGCONF}" = "xno"
+ then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PostgreSQL in /usr/local/pgsql /usr/pgsql /usr/local /usr PGSQL_HOME" >&5
+$as_echo_n "checking for PostgreSQL in /usr/local/pgsql /usr/pgsql /usr/local /usr PGSQL_HOME... " >&6; }
+ pgsql_directory="/usr/local/pgsql /usr/pgsql /usr/local /usr ${PGSQL_HOME}"
+ for i in $pgsql_directory; do
+ if test -r $i/include/pgsql/libpq-fe.h; then
+ PGSQL_INC_DIR=$i/include
+ PGSQL_DIR=$i
+ # use AC_CHECK_HEADERS to check for pgsql/libpq-fe.h
+ fi
+ done
+ if test -z "$PGSQL_DIR"; then
+ for i in $pgsql_directory; do
+ if test -r $i/include/postgresql/libpq-fe.h; then
+ PGSQL_INC_DIR=$i/include
+ PGSQL_DIR=$i
+ fi
+ done
+ fi
+ if test -z "$PGSQL_DIR"; then
+ for i in $pgsql_directory; do
+ if test -r $i/include/libpq-fe.h; then
+ PGSQL_INC_DIR=$i/include
+ PGSQL_DIR=$i
+ fi
+ done
+ fi
+
+ if test -z "$PGSQL_DIR"; then
+ tmp=""
+ for i in $pgsql_directory; do
+ tmp="$tmp $i/include $i/include/pgsql $i/include/postgresql"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "PostgreSQL header file (libpq-fe.h)"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+ fi
+
+ for i in lib lib/pgsql lib/postgresql; do
+ str="$PGSQL_DIR/$i/libpq.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ PGSQL_LIB_DIR="$PGSQL_DIR/$i"
+ break 2
+ fi
+ done
+ done
+
+ if test -z "$PGSQL_LIB_DIR"; then
+ for ff in $pgsql_directory; do
+ for i in lib lib/pgsql lib/postgresql; do
+ str="$ff/$i/libpq.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ PGSQL_LIB_DIR="$ff/$i"
+ break 3
+ fi
+ done
+ done
+ done
+ fi
+
+ if test -z "$PGSQL_LIB_DIR"; then
+ tmp=""
+ for i in $pgsql_directory; do
+ tmp="$i/lib $i/lib/pgsql $i/lib/postgresql"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "postgresql library libpq"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ LIBS="$LIBS -L${PGSQL_LIB_DIR} -lpq -lm"
+ if test x"$enable_static" = xyes; then
+ LIBS="$LIBS -L${PGSQL_LIB_DIR} -lpq -lcrypt -lm"
+ else
+ LIBS="$LIBS -L${PGSQL_LIB_DIR} -lpq -lm"
+ fi
+ # CFLAGS="$CFLAGS -I${PGSQL_INC_DIR}"
+ CPPFLAGS="$CPPFLAGS -I${PGSQL_INC_DIR}"
+ for ac_header in pgsql/libpq-fe.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "pgsql/libpq-fe.h" "ac_cv_header_pgsql_libpq_fe_h" "$ac_includes_default"
+if test "x$ac_cv_header_pgsql_libpq_fe_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PGSQL_LIBPQ_FE_H 1
+_ACEOF
+
+fi
+
+done
+
+ for ac_header in postgresql/libpq-fe.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "postgresql/libpq-fe.h" "ac_cv_header_postgresql_libpq_fe_h" "$ac_includes_default"
+if test "x$ac_cv_header_postgresql_libpq_fe_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_POSTGRESQL_LIBPQ_FE_H 1
+_ACEOF
+
+fi
+
+done
+
+ else
+ pg_lib_dir=`${PGCONF} --libdir`
+ if test x"$enable_static" = xyes; then
+ LIBS="$LIBS -L${pg_lib_dir} -lpq -lcrypt -lm"
+ else
+ LIBS="$LIBS -L${pg_lib_dir} -lpq -lm"
+ fi
+ pg_inc_dir=`${PGCONF} --includedir`
+ # CFLAGS="$CFLAGS -I${pg_inc_dir}"
+ CPPFLAGS="$CPPFLAGS -I${pg_inc_dir}"
+ fi
+ elif test "x${withval}" = "xodbc"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for odbc in /usr /usr/local ODBC_HOME" >&5
+$as_echo_n "checking for odbc in /usr /usr/local ODBC_HOME... " >&6; }
+ odbc_directory="/usr /usr/local"
+
+ for i in $odbc_directory; do
+ if test -r $i/include/sql.h; then
+ if test -r $i/include/sqlext.h; then
+ if test -r $i/include/sqltypes.h; then
+ ODBC_DIR=$i
+ ODBC_INC_DIR=$i/include
+ fi
+ fi
+ fi
+ done
+
+ if test -z "$ODBC_DIR"; then
+ tmp=""
+ for i in $odbc_directory; do
+ tmp="$tmp $i/include"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "odbc headers (sql.h sqlext.h sqltypes.h)"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+ fi
+
+ str="$ODBC_DIR/lib/libodbc.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ ODBC_LIB_DIR="$ODBC_DIR/lib"
+ ODBC_LIB="odbc"
+ fi
+ done
+
+ if test -z "$ODBC_LIB_DIR"; then
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "odbc library (libodbc)"
+ echo " checked in the following places"
+ for i in `echo "$ODBC_DIR/lib"`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ CPPFLAGS="${CPPFLAGS} -I${ODBC_INC_DIR}"
+ LIBS="${LIBS} -L${ODBC_LIB_DIR} -l$ODBC_LIB"
+ $as_echo "#define WITH_ODBC 1" >>confdefs.h
+
+ $as_echo "#define WITH_DATABASE 1" >>confdefs.h
+
+
+ elif test "x${withval}" = "xoracle"; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for oracle in ORACLE_HOME /usr/local /usr" >&5
+$as_echo_n "checking for oracle in ORACLE_HOME /usr/local /usr... " >&6; }
+
+ oracle_directory="/usr /usr/local ${ORACLE_HOME}"
+ for i in $oracle_directory; do
+
+ ff=`find $i -name oci.h 2>/dev/null | tail -1`
+ if test "x$ff" = "x"; then
+ :
+ else
+ ORACLE_INC=`dirname $ff`
+ fi
+
+ fg=`find $i -name libclntsh.so 2>/dev/null | tail -1`
+ if test "x$fg" = "x"; then
+ :
+ else
+ ORACLE_LIB=`dirname $fg`
+ fi
+
+ done
+
+ if test -z "$ORACLE_INC"; then
+
+ tmp=""
+ for i in $oracle_directory; do
+ tmp="$tmp $i"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "OCI header file (oci.h) please define ORACLE_INC directory where oci.h resides"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+
+ elif test -z "$ORACLE_LIB"; then
+
+ tmp=""
+ for i in $oracle_directory; do
+ tmp="$tmp $i"
+ done
+
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" "OCI library file (libclntsh.so) please define ORACLE_LIB directory where libclntsh.so resides"
+ echo " checked in the following places"
+ for i in `echo $tmp`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+
+
+ else
+
+ ORACLE_CPP_FLAGS="-I$ORACLE_INC"
+ ORACLE_LIB_DIR="$ORACLE_LIB"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ORACLE_INC $ORACLE_LIB" >&5
+$as_echo "$ORACLE_INC $ORACLE_LIB" >&6; }
+
+ CPPFLAGS="${CPPFLAGS} ${ORACLE_CPP_FLAGS}"
+
+ ORACLE_LIBS="-lclntsh"
+
+ if test -r $ORACLE_LIB_DIR/libnnz11.so; then
+ ORACLE_LIBS="${ORACLE_LIBS} -lnnz11"
+ fi
+ if test -r $ORACLE_LIB_DIR/libwtc9.so; then
+ ORACLE_LIBS="${ORACLE_LIBS} -lwtc9"
+ elif test -r $ORACLE_LIB_DIR/libwtc8.so; then
+ ORACLE_LIBS="${ORACLE_LIBS} -lwtc8"
+ fi
+ LIBS="${LIBS} -L${ORACLE_LIB_DIR} ${ORACLE_LIBS}"
+ if test "x$GCC" != "xyes"; then
+ CFLAGS="${CFLAGS} -fno-strict-aliasing"
+ fi
+ fi
+ $as_echo "#define WITH_ORACLE 1" >>confdefs.h
+
+ $as_echo "#define WITH_DATABASE 1" >>confdefs.h
+
+
+ else
+ as_fn_error $? "Option --with-database=database used with unsupported database ${withval}" "$LINENO" 5
+ fi
+
+
+fi
+
+
+
+# Check whether --with-console was given.
+if test "${with_console+set}" = set; then :
+ withval=$with_console;
+ if test "x${withval}" != xno; then
+ mycons="$withval"
+ cat >>confdefs.h <<_ACEOF
+#define DEFAULT_CONSOLE _("${mycons}")
+_ACEOF
+
+ fi
+
+fi
+
+
+
+# Check whether --with-altconsole was given.
+if test "${with_altconsole+set}" = set; then :
+ withval=$with_altconsole;
+ if test "x${withval}" != xno; then
+ myaltcons="$withval"
+ else
+ myaltcons="NULL"
+ fi
+
+else
+ myaltcons="NULL"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define ALT_CONSOLE _("${myaltcons}")
+_ACEOF
+
+
+
+# Check whether --with-timeserver was given.
+if test "${with_timeserver+set}" = set; then :
+ withval=$with_timeserver;
+ if test "x${withval}" != xno; then
+ mytimeserv="$withval"
+ $as_echo "#define HAVE_NTIME 1" >>confdefs.h
+
+ else
+ mytimeserv="NULL"
+ fi
+
+else
+ mytimeserv="NULL"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_TIMESERVER _("${mytimeserv}")
+_ACEOF
+
+
+
+# Check whether --with-alttimeserver was given.
+if test "${with_alttimeserver+set}" = set; then :
+ withval=$with_alttimeserver;
+ if test "x${withval}" != xno; then
+ myalttimeserv="$withval"
+ $as_echo "#define HAVE_NTIME 1" >>confdefs.h
+
+ else
+ myalttimeserv="NULL"
+ fi
+
+else
+ myalttimeserv="NULL"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define ALT_TIMESERVER _("${myalttimeserv}")
+_ACEOF
+
+
+# Check whether --enable-login-watch was given.
+if test "${enable_login_watch+set}" = set; then :
+ enableval=$enable_login_watch;
+ if test "x${enable_login_watch}" = xyes; then
+ $as_echo "#define SH_USE_UTMP 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-mounts-check was given.
+if test "${enable_mounts_check+set}" = set; then :
+ enableval=$enable_mounts_check;
+ if test "x${enable_mounts_check}" = xyes; then
+ $as_echo "#define SH_USE_MOUNTS 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-logfile-monitor was given.
+if test "${enable_logfile_monitor+set}" = set; then :
+ enableval=$enable_logfile_monitor;
+ if test "x${enable_logfile_monitor}" = xyes; then
+ ac_fn_c_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default"
+if test "x$ac_cv_header_pcre_h" = xyes; then :
+
+
+$as_echo "#define USE_LOGFILE_MONITOR 1" >>confdefs.h
+
+ LIBS="-lpcre $LIBS"
+
+else
+
+ ac_fn_c_check_header_mongrel "$LINENO" "pcre/pcre.h" "ac_cv_header_pcre_pcre_h" "$ac_includes_default"
+if test "x$ac_cv_header_pcre_pcre_h" = xyes; then :
+
+
+$as_echo "#define USE_LOGFILE_MONITOR 1" >>confdefs.h
+
+
+$as_echo "#define HAVE_PCRE_PCRE_H 1" >>confdefs.h
+
+ LIBS="-lpcre $LIBS"
+
+else
+ as_fn_error $? "The --enable-logfile-monitor option requires libpcre. For compiling the pcre development package is needed." "$LINENO" 5
+
+fi
+
+
+
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcre_dfa_exec in -lpcre" >&5
+$as_echo_n "checking for pcre_dfa_exec in -lpcre... " >&6; }
+if ${ac_cv_lib_pcre_pcre_dfa_exec+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpcre $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pcre_dfa_exec ();
+int
+main ()
+{
+return pcre_dfa_exec ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pcre_pcre_dfa_exec=yes
+else
+ ac_cv_lib_pcre_pcre_dfa_exec=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcre_pcre_dfa_exec" >&5
+$as_echo "$ac_cv_lib_pcre_pcre_dfa_exec" >&6; }
+if test "x$ac_cv_lib_pcre_pcre_dfa_exec" = xyes; then :
+
+
+$as_echo "#define HAVE_PCRE_DFA_EXEC 1" >>confdefs.h
+
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pcre_dfa_exec not available" >&5
+$as_echo "$as_me: WARNING: pcre_dfa_exec not available" >&2;}
+
+fi
+
+ fi
+
+
+fi
+
+
+
+# Check whether --enable-process-check was given.
+if test "${enable_process_check+set}" = set; then :
+ enableval=$enable_process_check;
+ if test "x${enable_process_check}" = xyes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_getparam in -lrt" >&5
+$as_echo_n "checking for sched_getparam in -lrt... " >&6; }
+if ${ac_cv_lib_rt_sched_getparam+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sched_getparam ();
+int
+main ()
+{
+return sched_getparam ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_rt_sched_getparam=yes
+else
+ ac_cv_lib_rt_sched_getparam=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_getparam" >&5
+$as_echo "$ac_cv_lib_rt_sched_getparam" >&6; }
+if test "x$ac_cv_lib_rt_sched_getparam" = xyes; then :
+ sh_lrt=yes
+else
+ sh_lrt=no
+fi
+
+ if test x"$sh_lrt" = xyes; then
+ LIBRT=-lrt
+ else
+ LIBRT=
+ fi
+ LIBS="$LIBS $LIBRT"
+
+$as_echo "#define SH_USE_PROCESSCHECK 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-port-check was given.
+if test "${enable_port_check+set}" = set; then :
+ enableval=$enable_port_check;
+ if test "x${enable_port_check}" = xyes; then
+
+$as_echo "#define SH_USE_PORTCHECK 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-userfiles was given.
+if test "${enable_userfiles+set}" = set; then :
+ enableval=$enable_userfiles;
+ if test "x${enableval}" = "xyes"; then
+ $as_echo "#define SH_USE_USERFILES 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+ enableval=$enable_debug;
+ if test "x${enable_debug}" = "xyes"; then
+ if test "x${mydebugflag}" != "xyes"; then
+ $as_echo "#define MEM_DEBUG 1" >>confdefs.h
+
+ fi
+ $as_echo "#define WITH_TPT 1" >>confdefs.h
+
+ $as_echo "#define SL_DEBUG 1" >>confdefs.h
+
+
+$as_echo "#define DNMALLOC_CHECKS 1" >>confdefs.h
+
+
+$as_echo "#define PARANOIA 0" >>confdefs.h
+
+ $as_echo "#define SL_FAIL_ON_ERROR 1" >>confdefs.h
+
+ if test "x${myneedg3}" = "xyes"; then
+ mydebugdef="-g3"
+ else
+ mydebugdef="-g"
+ fi
+ mydebugit="yes"
+ elif test "x${enable_debug}" = "xgdb"; then
+
+$as_echo "#define SH_ABORT_ON_ERROR 1" >>confdefs.h
+
+ if test "x${myneedg3}" = "xyes"; then
+ mydebugdef="-g3"
+ else
+ mydebugdef="-g"
+ fi
+ mydebugit="yes"
+ fi
+
+
+fi
+
+
+
+if test "x${enable_asm_ok}" = "xyes"; then
+ sh_enable_asm=yes
+else
+ sh_enable_asm=no
+fi
+# Check whether --enable-asm was given.
+if test "${enable_asm+set}" = set; then :
+ enableval=$enable_asm;
+ if test "x${enable_asm}" = xno; then
+ sh_enable_asm=no
+ fi
+
+
+fi
+
+
+if test "x${samhain_64_asm}" = xyes; then
+ if test "x${sh_enable_asm}" = xyes; then
+
+$as_echo "#define TIGER_OPT_ASM 1" >>confdefs.h
+
+ fi
+fi
+
+# Check whether --enable-ipv6 was given.
+if test "${enable_ipv6+set}" = set; then :
+ enableval=$enable_ipv6;
+ if test "x${enable_ipv6}" = xno; then
+
+$as_echo "#define USE_IPV4 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+if test "x${dnmalloc_ok}" = "xyes"; then
+ sh_dnmalloc_enabled=yes
+else
+ sh_dnmalloc_enabled=no
+fi
+
+# Check whether --enable-dnmalloc was given.
+if test "${enable_dnmalloc+set}" = set; then :
+ enableval=$enable_dnmalloc;
+ if test "x${enable_dnmalloc}" = xno; then
+ sh_dnmalloc_enabled=no
+ else
+ sh_dnmalloc_enabled=yes
+ fi
+
+
+fi
+
+
+if test "x$sh_dnmalloc_enabled" = "xyes"; then
+ if test x$enable_static = xyes; then
+ if test "x$sh_no_gcc_static" = "xyes"; then
+ sh_dnmalloc_enabled=no
+ else
+ if test "x$with_gnu_ld" = "xyes"; then
+ LDFLAGS="$LDFLAGS -Wl,--allow-multiple-definition"
+ else
+ sh_dnmalloc_enabled=no
+ fi
+ fi
+ fi
+fi
+
+if test "x${sh_dnmalloc_enabled}" = xno; then
+
+$as_echo "#define USE_SYSTEM_MALLOC 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-ptrace was given.
+if test "${enable_ptrace+set}" = set; then :
+ enableval=$enable_ptrace;
+ if test "x${enable_ptrace}" = xyes; then
+ if test "x$mydebugit" != "xyes"; then
+ $as_echo "#define SCREW_IT_UP 1" >>confdefs.h
+
+ fi
+ fi
+
+
+fi
+
+
+if test "x$GCC" = "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g\ " 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+
+
+
+ if test -z "`echo "$CFLAGS" | grep "\-Wall" 2> /dev/null`" ; then
+ case "$host_os" in
+ *solaris*)
+ CFLAGS="$CFLAGS -Wall -W -Wno-missing-braces "
+ ;;
+ *)
+ CFLAGS="$CFLAGS -Wall -W "
+ ;;
+ esac
+ fi
+
+ if test -z "`echo "$CFLAGS" | grep "\-fstrength\-reduce" 2> /dev/null`"
+ then
+ if test -z "`echo "$CFLAGS" | grep "\-fno\-strength\-reduce" 2> /dev/null`"
+ then
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -fno-strength-reduce" >&5
+$as_echo_n "checking whether ${CC} accepts -fno-strength-reduce... " >&6; }
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror -fno-strength-reduce"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ flag_check_cv=yes
+else
+ flag_check_cv=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$saved_cflags"
+
+ if test $flag_check_cv = yes; then
+ CFLAGS="$CFLAGS -fno-strength-reduce"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+
+ fi
+ fi
+
+ if test -z "`echo "$CFLAGS" | grep "\-fomit\-frame\-pointer" 2> /dev/null`"
+ then
+ if test -z "`echo "$CFLAGS" | grep "\-fno\-omit\-frame\-pointer" 2> /dev/null`"
+ then
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -fno-omit-frame-pointer" >&5
+$as_echo_n "checking whether ${CC} accepts -fno-omit-frame-pointer... " >&6; }
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror -fno-omit-frame-pointer"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ flag_check_cv=yes
+else
+ flag_check_cv=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$saved_cflags"
+
+ if test $flag_check_cv = yes; then
+ CFLAGS="$CFLAGS -fno-omit-frame-pointer"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+
+ fi
+ fi
+
+fi
+
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -Wno-empty-body" >&5
+$as_echo_n "checking whether ${CC} accepts -Wno-empty-body... " >&6; }
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror -Wno-empty-body"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ flag_check_cv=yes
+else
+ flag_check_cv=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$saved_cflags"
+
+ if test $flag_check_cv = yes; then
+ CFLAGS="$CFLAGS -Wno-empty-body"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+
+
+
+
+ if test "X$CC" != "X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} accepts -Wno-invalid-source-encoding" >&5
+$as_echo_n "checking whether ${CC} accepts -Wno-invalid-source-encoding... " >&6; }
+ saved_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS -Werror -Wno-invalid-source-encoding"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ flag_check_cv=yes
+else
+ flag_check_cv=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$saved_cflags"
+
+ if test $flag_check_cv = yes; then
+ CFLAGS="$CFLAGS -Wno-invalid-source-encoding"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which random module to use" >&5
+$as_echo_n "checking which random module to use... " >&6; }
+
+# Check whether --with-rnd was given.
+if test "${with_rnd+set}" = set; then :
+ withval=$with_rnd; use_static_rnd=$withval
+else
+ use_static_rnd=default
+fi
+
+
+if test "$use_static_rnd" = no; then
+ use_static_rnd=default
+fi
+
+case "$use_static_rnd" in
+ egd | dev | unix | default )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_static_rnd" >&5
+$as_echo "$use_static_rnd" >&6; }
+ ;;
+ * )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: invalid argument" >&5
+$as_echo "invalid argument" >&6; }
+ as_fn_error $? "Option --with-rnd=module used with unsupported module ${use_static_rnd}" "$LINENO" 5
+ ;;
+esac
+
+
+# Check whether --with-egd-socket was given.
+if test "${with_egd_socket+set}" = set; then :
+ withval=$with_egd_socket; egd_socket_name="$withval"
+else
+ egd_socket_name=""
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define EGD_SOCKET_NAME _("$egd_socket_name")
+_ACEOF
+
+
+
+try_dev_random=yes
+
+case "$use_static_rnd" in
+dev | default )
+ try_dev_random=yes
+ ;;
+egd)
+ $as_echo "#define HAVE_EGD_RANDOM 1" >>confdefs.h
+
+ try_dev_random=no
+ ;;
+unix)
+ $as_echo "#define HAVE_UNIX_RANDOM 1" >>confdefs.h
+
+ try_dev_random=no
+ ;;
+esac
+
+
+if test "x$try_dev_random" = "xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether /dev/random exists" >&5
+$as_echo_n "checking whether /dev/random exists... " >&6; }
+ if test -r "/dev/srandom" && test -c "/dev/srandom"; then
+ $as_echo "#define HAVE_URANDOM 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define NAME_OF_DEV_RANDOM _("/dev/srandom")
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ if test -r "/dev/urandom" && test -c "/dev/urandom"; then
+ cat >>confdefs.h <<_ACEOF
+#define NAME_OF_DEV_URANDOM _("/dev/urandom")
+_ACEOF
+
+ fi
+ else
+ if test -r "/dev/random" && test -c "/dev/random"; then
+ $as_echo "#define HAVE_URANDOM 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define NAME_OF_DEV_RANDOM _("/dev/random")
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ if test -r "/dev/urandom" && test -c "/dev/urandom"; then
+ cat >>confdefs.h <<_ACEOF
+#define NAME_OF_DEV_URANDOM _("/dev/urandom")
+_ACEOF
+
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ $as_echo "#define HAVE_UNIX_RANDOM 1" >>confdefs.h
+
+ fi
+ fi
+fi
+
+
+# Check whether --enable-udp was given.
+if test "${enable_udp+set}" = set; then :
+ enableval=$enable_udp;
+ if test "x${enable_udp}" = xyes; then
+ $as_echo "#define INET_SYSLOG 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+myencrypt=yes
+# Check whether --enable-encrypt was given.
+if test "${enable_encrypt+set}" = set; then :
+ enableval=$enable_encrypt;
+ if test "x${enable_encrypt}" = xno; then
+ myencrypt=no
+ fi
+
+
+fi
+
+if test "x${myencrypt}" = "xyes"; then
+ $as_echo "#define SH_ENCRYPT 1" >>confdefs.h
+
+ $as_echo "#define SH_ENCRYPT_2 1" >>confdefs.h
+
+fi
+
+sh_use_srp_proto=yes
+# Check whether --enable-srp was given.
+if test "${enable_srp+set}" = set; then :
+ enableval=$enable_srp;
+ if test "x${enable_srp}" = xno; then
+ sh_use_srp_proto=no
+ fi
+
+
+fi
+
+if test "x${sh_use_srp_proto}" = xyes; then
+ $as_echo "#define USE_SRP_PROTOCOL 1" >>confdefs.h
+
+fi
+
+
+# Check whether --with-port was given.
+if test "${with_port+set}" = set; then :
+ withval=$with_port;
+ echo "${withval}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "For --with-port=PORT, PORT must be numeric." "$LINENO" 5
+ myport=${withval}
+
+else
+ myport="49777"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define SH_DEFAULT_PORT ${myport}
+_ACEOF
+
+
+
+
+# Check whether --with-logserver was given.
+if test "${with_logserver+set}" = set; then :
+ withval=$with_logserver;
+ case "$withval" in
+ *.* | localhost)
+ mylogsrv="$withval"
+ ;;
+ *)
+ mylogsrv="$withval"
+ ;;
+ esac
+
+else
+ mylogsrv="NULL"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_LOGSERVER _("${mylogsrv}")
+_ACEOF
+
+
+
+
+# Check whether --with-altlogserver was given.
+if test "${with_altlogserver+set}" = set; then :
+ withval=$with_altlogserver;
+ case "$withval" in
+ *.* | localhost)
+ myaltlogsrv="$withval"
+ ;;
+ *)
+ myaltlogsrv="$withval"
+ ;;
+ esac
+
+else
+ myaltlogsrv="NULL"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define ALT_LOGSERVER _("${myaltlogsrv}")
+_ACEOF
+
+
+
+
+nocl_code=
+xor_code=0
+# Check whether --enable-nocl was given.
+if test "${enable_nocl+set}" = set; then :
+ enableval=$enable_nocl;
+ if test "x${enableval}" != "x"; then
+ $as_echo "#define SH_STEALTH_NOCL 1" >>confdefs.h
+
+ fi
+ if test "x${enableval}" = "xstop" || test "x${enableval}" = "xstart"; then
+ as_fn_error $? "For --enable-nocl=PW start/stop/reload/restart/status are reserved words." "$LINENO" 5
+ fi
+ if test "x${enableval}" = "xreload" || test "x${enableval}" = "xrestart"; then
+ as_fn_error $? "For --enable-nocl=PW start/stop/reload/restart/status are reserved words." "$LINENO" 5
+ fi
+ if test "x${enableval}" = "xstatus"; then
+ as_fn_error $? "For --enable-nocl=PW start/stop/reload/restart/status are reserved words." "$LINENO" 5
+ fi
+ if test "x${enableval}" = "xno"; then
+ as_fn_error $? "With --enable-nocl=PW, the use of --enable-nocl=no is ambiguous." "$LINENO" 5
+ fi
+ nocl_code="${enable_nocl}"
+
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define NOCL_CODE _("${nocl_code}")
+_ACEOF
+
+
+# Check whether --enable-stealth was given.
+if test "${enable_stealth+set}" = set; then :
+ enableval=$enable_stealth; $as_echo "#define SH_STEALTH 1" >>confdefs.h
+
+ if test "x${enableval}" != "xyes"; then
+ echo "${enableval}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "For --enable-stealth=XOR_VAL, XOR_VAL must be numeric." "$LINENO" 5
+ if test "${enableval}" -lt 127 || test "${enableval}" -gt 255; then
+ if test x"${enableval}" = x0
+ then
+ :
+ else
+ as_fn_error $? "For --enable-stealth=XOR_VAL, XOR_VAL must be in the range 127 to 255." "$LINENO" 5
+ fi
+ fi
+ xor_code="${enable_stealth}"
+ else
+ xor_code=0
+ fi
+ stegin_prg="samhain_stealth"
+
+else
+
+ stegin_prg=
+
+
+fi
+
+# Check whether --enable-micro-stealth was given.
+if test "${enable_micro_stealth+set}" = set; then :
+ enableval=$enable_micro_stealth;
+ $as_echo "#define SH_STEALTH 1" >>confdefs.h
+
+ $as_echo "#define SH_STEALTH_MICRO 1" >>confdefs.h
+
+ if test "x${enableval}" != "xyes"; then
+ echo "${enableval}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "For --enable-micro-stealth=XOR_VAL, XOR_VAL must be numeric." "$LINENO" 5
+ if test "${enableval}" -lt 127 || test "${enableval}" -gt 255; then
+ if test x"${enableval}" = x0
+ then
+ :
+ else
+ as_fn_error $? "For --enable-micro-stealth=XOR_VAL, XOR_VAL must be in the range 127 to 255." "$LINENO" 5
+ fi
+ fi
+ xor_code="${enable_micro_stealth}"
+ else
+ xor_code=0
+ fi
+
+
+fi
+
+install_name="samhain"
+INSTALL_NAME="SAMHAIN"
+# Check whether --enable-install-name was given.
+if test "${enable_install_name+set}" = set; then :
+ enableval=$enable_install_name;
+ if test "x${enableval}" != "xyes"; then
+ install_name="${enableval}"
+ INSTALL_NAME=`echo "${enableval}" | tr a-z A-Z`
+ else
+ install_name="${sh_main_prg}"
+ INSTALL_NAME=`echo "${sh_main_prg}" | tr a-z A-Z`
+ fi
+
+else
+
+ install_name="${sh_main_prg}"
+ INSTALL_NAME=`echo "${sh_main_prg}" | tr a-z A-Z`
+
+
+fi
+
+
+
+need_user_install=0
+
+# Check whether --enable-identity was given.
+if test "${enable_identity+set}" = set; then :
+ enableval=$enable_identity;
+ if test x"$enableval" = xno; then
+ myident="daemon"
+ else
+ myident="$enableval"
+ fi
+ echo "${myident}" | grep '[^0123456789]' >/dev/null 2>&1 || \
+ as_fn_error $? "With --enable-identity=USER, please supply a username, not a UID." "$LINENO" 5
+ myident_uid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${myident}:" | awk -F: '{ print $3; }'`
+ if test x"${myident_uid}" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --enable-identity used, user ${myident} will be added upon install." >&5
+$as_echo "$as_me: WARNING: Option --enable-identity used, user ${myident} will be added upon install." >&2;}
+ need_user_install=1
+ fi
+
+else
+
+ for myident in ${install_name} daemon nobody; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for user ${myident}" >&5
+$as_echo_n "checking for user ${myident}... " >&6; }
+ myident_uid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${myident}:" | awk -F: '{ print $3; }'`
+ if test x"${myident_uid}" != x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break;
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ done
+ if test x"${myident_uid}" = x; then
+ myident=${install_name}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-identity: user ${myident} will be added upon install" >&5
+$as_echo "$as_me: WARNING: --enable-identity: user ${myident} will be added upon install" >&2;}
+ need_user_install=1
+ fi
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_IDENT _("${myident}")
+_ACEOF
+
+
+
+
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define XOR_CODE ${xor_code}
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define SH_SYSCALLTABLE ${sh_syscalltable}
+_ACEOF
+
+
+
+exepack_state0=`${srcdir}/c_random.sh 2>/dev/null`
+exepack_state1=`${srcdir}/c_random.sh 2>/dev/null`
+exepack_state2=`${srcdir}/c_random.sh 2>/dev/null`
+
+cat >>confdefs.h <<_ACEOF
+#define EXEPACK_STATE_0 ${exepack_state0}
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define EXEPACK_STATE_1 ${exepack_state1}
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define EXEPACK_STATE_2 ${exepack_state2}
+_ACEOF
+
+
+
+# Check whether --enable-suidcheck was given.
+if test "${enable_suidcheck+set}" = set; then :
+ enableval=$enable_suidcheck;
+ if test "x${enableval}" = "xyes"; then
+ $as_echo "#define SH_USE_SUIDCHK 1" >>confdefs.h
+
+ fi
+
+
+fi
+
+
+
+# Check whether --enable-base was given.
+if test "${enable_base+set}" = set; then :
+ enableval=$enable_base;
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking base key setting" >&5
+$as_echo_n "checking base key setting... " >&6; }
+ my_key_A=`echo ${enableval} | awk 'BEGIN{FS=","}{print $1}'`
+ my_key_B=`echo ${enableval} | awk 'BEGIN{FS=","}{print $2}'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${my_key_A} ${my_key_B}" >&5
+$as_echo "${my_key_A} ${my_key_B}" >&6; }
+ if test "x${my_key_A}" = x; then
+ as_fn_error $? "Option --enable-base=B1,B2 used with invalid first base key (zero length)." "$LINENO" 5
+ fi
+ if test "x${my_key_B}" = x; then
+ as_fn_error $? "Option --enable-base=B1,B2 used with invalid second base key (zero length)." "$LINENO" 5
+ fi
+ echo "${my_key_A}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "For --enable-base=B1,B2, B1 and B2 must be numeric in the range 0 to 2147483647." "$LINENO" 5
+ echo "${my_key_B}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "For --enable-base=B1,B2, B1 and B2 must be numeric in the range 0 to 2147483647." "$LINENO" 5
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking base key setting .. collecting entropy" >&5
+$as_echo_n "checking base key setting .. collecting entropy... " >&6; }
+ my_key_1=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_2=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_3=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_4=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_A=`expr $my_key_1 \* 32767`
+ my_key_A=`echo ${my_key_A} | sed 's%^0*%%g' 2>/dev/null`
+ my_key_A=`expr $my_key_A \+ $my_key_2`
+ my_key_B=`expr $my_key_3 \* 32767`
+ my_key_B=`echo ${my_key_B} | sed 's%^0*%%g' 2>/dev/null`
+ my_key_B=`expr $my_key_B \+ $my_key_4`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${my_key_A} ${my_key_B}" >&5
+$as_echo "${my_key_A} ${my_key_B}" >&6; }
+
+
+fi
+
+
+
+
+my_key_1=`expr $my_key_A \% 65536`
+my_key_2=`expr $my_key_A \/ 65536`
+my_key_3=`expr $my_key_B \% 65536`
+my_key_4=`expr $my_key_B \/ 65536`
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking key position" >&5
+$as_echo_n "checking key position... " >&6; }
+pos_tf_1=`${srcdir}/c_random.sh 2>/dev/null`
+pos_tf_2=`expr $pos_tf_1 \% 8`
+pos_tf=`expr $pos_tf_2 + 1`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${pos_tf}" >&5
+$as_echo "${pos_tf}" >&6; }
+cat >>confdefs.h <<_ACEOF
+#define POS_TF ${pos_tf}
+_ACEOF
+
+
+mykeybase=`echo ${my_key_A},${my_key_B}`
+cat >>confdefs.h <<_ACEOF
+#define DEFKEY ${mykeybase}
+_ACEOF
+
+
+
+
+
+
+# Check whether --with-gpg was given.
+if test "${with_gpg+set}" = set; then :
+ withval=$with_gpg;
+ if test "x${withval}" != "xno"; then
+ if test "x${cross_compiling}" = xyes; then
+ mygpg="${withval}"
+ else
+ if test -f "${withval}"; then
+ mygpg="${withval}"
+ mychk0=`${withval} --load-extension tiger --print-md TIGER192 ${withval} 2>/dev/null`
+ if test "x$?" != "x0"; then
+ mychktest=no
+ for sampre in ./samhain ./yule /usr/local/sbin/samhain /usr/local/bin/samhain /usr/bin/samhain /usr/sbin/samhain /usr/local/sbin/yule /usr/local/bin/yule /usr/bin/yule /usr/sbin/yule; do
+ if test x"${mychktest}" = xyes
+ then
+ :
+ else
+ if test -f ${sampre}
+ then
+ echo "use existing ${sampre} for gpg checksum"
+ mychk0=`${sampre} -H ${withval} 2>/dev/null`
+ if test "x$?" != "x0"; then
+ if test "x${nocl_code}" != "x"; then
+ mychk0=`echo -H ${withval} | ${sampre} ${nocl_code} 2>/dev/null`
+ if test "x$?" != "x0"; then
+ :
+ else
+ mychk="${mychk0}"
+ mychktest=yes
+ fi
+ fi
+ else
+ mychk="${mychk0}"
+ mychktest=yes
+ fi
+ fi
+ fi
+ done
+ if test x${mychktest} = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-gpg: cannot determine TIGER192 checksum of ${withval}" >&5
+$as_echo "$as_me: WARNING: --with-gpg: cannot determine TIGER192 checksum of ${withval}" >&2;}
+ echo "-------------------------------------------------------------"
+ echo " Your gpg binary does not support the TIGER192 checksum, "
+ echo " and I cannot find an existing samhain binary to use instead."
+ echo " You can:"
+ echo " (a) run make to compile a samhain binary, then repeat"
+ echo " ./configure and make"
+ echo " (b) ignore the failure. The checksum of the gpg binary"
+ echo " will not get compiled in, thus allowing an attacker"
+ echo " to replace gpg with a trojan and subverting the gpg"
+ echo " signature verification of configure and database files."
+ echo
+ echo " PLEASE IGNORE THIS MESSAGE IF YOU ALSO USE --with-checksum"
+ echo "-------------------------------------------------------------"
+ fi
+ else
+ mychk="${mychk0}"
+ fi
+ else
+ as_fn_error $? "--with-gpg: cannot find GnuPG PATH=${withval}" "$LINENO" 5
+ fi
+ fi
+ $as_echo "#define WITH_GPG 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define DEFAULT_GPG_PATH _("${mygpg}")
+_ACEOF
+
+
+ fi
+
+
+fi
+
+
+
+
+
+# Check whether --with-keyid was given.
+if test "${with_keyid+set}" = set; then :
+ withval=$with_keyid;
+ if test "x${withval}" != "x"; then
+ echo "${withval}" | awk '{if((length($0)==10)||(length($0)==18)){exit 2}else{exit 0}}' &&
+ as_fn_error $? "--with-keyid:${withval} must be \"0x\" + 8|16 hex digits" "$LINENO" 5
+ echo "${withval}" | grep '[^0][^x][^0123456789ABCDEFabcdef]' >/dev/null 2>&1 &&
+ as_fn_error $? "--with-keyid:${withval} must be \"0x\" + 8|16 hex digits" "$LINENO" 5
+ mykeyid="$withval"
+ mykeytag="--default-key"
+ else
+ mykeyid=""
+ mykeytag=""
+ fi
+
+
+
+
+fi
+
+
+
+
+# Check whether --with-checksum was given.
+if test "${with_checksum+set}" = set; then :
+ withval=$with_checksum;
+ if test "x${withval}" != "xno"; then
+ if test "x${withval}" != "xyes"; then
+ if test "x${mychk}" != "x"; then
+ if test "x${mychk}" != "x${withval}"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-checksum: possible gpg CHKSUM problem" >&5
+$as_echo "$as_me: WARNING: --with-checksum: possible gpg CHKSUM problem" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-checksum: CHKSUM=${withval}" >&5
+$as_echo "$as_me: WARNING: --with-checksum: CHKSUM=${withval}" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-checksum: autodetected=${mychk}" >&5
+$as_echo "$as_me: WARNING: --with-checksum: autodetected=${mychk}" >&2;}
+ fi
+ fi
+ mychk="${withval}"
+ else
+ if test "x${mychk}" = "x"; then
+ as_fn_error $? "Option --with-checksum=CHKSUM: checksum CHKSUM of the gpg binary not specified." "$LINENO" 5
+ fi
+ fi
+ $as_echo "#define HAVE_GPG_CHECKSUM 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define GPG_HASH _("${mychk}")
+_ACEOF
+
+ echo "${mychk}" | sed 's,.*:,,g' | sed 's, ,,g' | sed 's,\(.\),\1:,g' | awk '{ split($0, arr, ":"); m = length($1)/2; print "#ifndef CHKSUM_H"; print "#define CHKSUM_H"; print "char gpgchk[50];"; for (i=1; i <= m; i++) printf "gpgchk[%d] = %c%s%c;\n", i-1, 39, arr[i], 39; printf "gpgchk[48] = %c%c0%c;\n", 39, 92, 39; print "#endif"; }' > sh_gpg_chksum.h
+ fi
+
+else
+
+ if test "x${mygpg}" != "x"; then
+ if test "x${mychk}" != "x"; then
+ $as_echo "#define HAVE_GPG_CHECKSUM 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define GPG_HASH _("${mychk}")
+_ACEOF
+
+ echo "${mychk}" | sed 's,.*:,,g' | sed 's, ,,g' | sed 's,\(.\),\1:,g' | awk '{ split($0, arr, ":"); m = length($1)/2; print "#ifndef CHKSUM_H"; print "#define CHKSUM_H"; print "char gpgchk[50];"; for (i=1; i <= m; i++) printf "gpgchk[%d] = %c%s%c;\n", i-1, 39, arr[i], 39; printf "gpgchk[48] = %c%c0%c;\n", 39, 92, 39; print "#endif"; }' > sh_gpg_chksum.h
+ fi
+ fi
+
+
+fi
+
+
+
+# Check whether --with-fp was given.
+if test "${with_fp+set}" = set; then :
+ withval=$with_fp;
+ if test "x${withval}" != "xno"; then
+ if test "x${withval}" != "xyes"; then
+ withval0=`echo ${withval} | sed 's% %%g'`
+ echo "${withval0}" | \
+ grep '[^0123456789abcdefABCDEF]' >/dev/null 2>&1 &&
+ as_fn_error $? "In option --with-fp=FINGERPRINT, there is an invalid character(s) in FINGERPRINT=${withval0}." "$LINENO" 5
+ sh_len=`echo ${withval0} | wc -c | sed 's% %%g'`
+ sh_len0=`expr ${sh_len} \- 1`
+ if test "x${sh_len0}" = "x40" || test "x${sh_len0}" = "x32"
+ then
+ myfp="${withval0}"
+ $as_echo "#define USE_FINGERPRINT 1" >>confdefs.h
+
+ cat >>confdefs.h <<_ACEOF
+#define SH_GPG_FP _("${myfp}")
+_ACEOF
+
+ echo "${myfp}" | sed 's,.*:,,g' | sed 's, ,,g' | sed 's,\(.\),\1:,g' | awk '{ split($0, arr, ":"); m = length($1)/2; print "#ifndef FINGERPRINT_H"; print "#define FINGERPRINT_H"; printf "char gpgfp[%d];\n", m+1; for (i=1; i <= m; i++) printf "gpgfp[%d] = %c%s%c;\n", i-1, 39, arr[i], 39; printf "gpgfp[%d] = %c%c0%c;\n", m, 39, 92, 39; print "#endif"; }' > sh_gpg_fp.h
+ else
+ as_fn_error $? "In option --with-fp=FINGERPRINT, the length (${sh_len0}) of FINGERPRINT ${withval0} is incorrect." "$LINENO" 5
+ fi
+ else
+ as_fn_error $? "For option --with-fp=FINGERPRINT, FINGERPRINT=yes is invalid, please specify a valid key fingerprint." "$LINENO" 5
+ fi
+ fi
+
+fi
+
+
+
+
+
+# Check whether --with-recipient was given.
+if test "${with_recipient+set}" = set; then :
+ withval=$with_recipient;
+ withval0=`echo ${withval} | sed 's%,% %g'`
+ for sh_item in ${withval0}
+ do
+ case ${sh_item} in
+ *@localhost)
+ ;;
+ *@*.*)
+ sh_tmp=`echo ${sh_item} | awk '{ if ($1 ~ /^[a-zA-Z0-9][a-zA-Z0-9\-_\.]*@[a-zA-Z0-9\-\.]+\.([a-zA-Z]+|[0-9]+)$/) {print 1; } else { print 0}}'`
+ if test "x${sh_tmp}" != "x1"
+ then
+ as_fn_error $? "Option --with-recipient=ADDR used with invalid mail address ${sh_item}." "$LINENO" 5
+ fi
+ ;;
+ *)
+ as_fn_error $? "Option --with-recipient=ADDR used with invalid mail address ${sh_item}." "$LINENO" 5
+ ;;
+ esac
+ done
+ myrcp="$withval0"
+
+else
+ myrcp="NULL"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_MAILADDRESS _("${myrcp}")
+_ACEOF
+
+
+
+
+# Check whether --with-sender was given.
+if test "${with_sender+set}" = set; then :
+ withval=$with_sender;
+ mysender="${withval}"
+
+else
+
+ mysender="daemon"
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_SENDER _("${mysender}")
+_ACEOF
+
+
+
+
+
+# Check whether --with-trusted was given.
+if test "${with_trusted+set}" = set; then :
+ withval=$with_trusted;
+ sh_tmp_test=no
+ sh_tmp=`echo ${withval} | sed 's%,% %g'`
+ for sh_tmp1 in ${sh_tmp}
+ do
+ echo "${sh_tmp1}" | grep '[^0123456789]' >/dev/null 2>&1 &&
+ as_fn_error $? "Option --with-trusted=UID used with non-numeric UID in ${withval}." "$LINENO" 5
+ if test "x${sh_tmp1}" = "x0"
+ then
+ sh_tmp_test=yes
+ fi
+ done
+ if test "x${sh_tmp_test}" = "xno"
+ then
+ withval="0,${withval}"
+ fi
+ mytrust="${withval}"
+
+else
+ mytrust="0"
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define SL_ALWAYS_TRUSTED ${mytrust}
+_ACEOF
+
+
+
+mytmpdir=
+
+
+# Check whether --with-tmp-dir was given.
+if test "${with_tmp_dir+set}" = set; then :
+ withval=$with_tmp_dir;
+ if test "x${cross_compiling}" = xyes; then
+ mytmpdir="$withval"
+ cat >>confdefs.h <<_ACEOF
+#define SH_TMPDIR _("${mytmpdir}")
+_ACEOF
+
+ else
+ if test -d "${withval}"; then
+ mytmpdir="$withval"
+ cat >>confdefs.h <<_ACEOF
+#define SH_TMPDIR _("${mytmpdir}")
+_ACEOF
+
+ else
+ mytmpdir="$withval"
+ cat >>confdefs.h <<_ACEOF
+#define SH_TMPDIR _("${mytmpdir}")
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-tmp-dir: tmp directory ${withval} does not exist" >&5
+$as_echo "$as_me: WARNING: --with-tmp-dir: tmp directory ${withval} does not exist" >&2;}
+ fi
+ fi
+
+
+fi
+
+
+
+
+
+
+if test "x${ac_prefix_set}" = xyes
+then
+ if test "x${exec_prefix}" = xNONE
+ then
+ exec_prefix="${prefix}"
+ fi
+
+ if test "x${prefix}" = xOPT
+ then
+ tmp_sbindir="/opt/${install_name}/bin"
+ tmp_sysconfdir="/etc/opt"
+ tmp_mandir="/opt/${install_name}/man"
+ tmp_localstatedir="/var/opt/${install_name}"
+ elif test "x${prefix}" = xUSR
+ then
+ tmp_sbindir="/usr/sbin"
+ tmp_sysconfdir="/etc"
+ tmp_mandir="/usr/share/man"
+ tmp_localstatedir="/var"
+ else
+ tmp_sbindir=`eval echo ${sbindir}`
+ tmp_sysconfdir=`eval echo ${sysconfdir}`
+ tmp_mandir=`eval echo ${mandir}`
+ tmp_localstatedir=`eval echo ${localstatedir}`
+ fi
+else
+ prefix=""
+ if test "x${ac_exec_prefix_set}" = xyes
+ then
+ tmp_sbindir=`eval echo ${sbindir}`
+ else
+ tmp_sbindir="/usr/local/sbin"
+ fi
+ tmp_sysconfdir="/etc"
+ # share/man -> man (FHS) 11.10.2002
+ tmp_mandir="/usr/local/man"
+ tmp_localstatedir="/var"
+fi
+
+
+if test "x${ac_sbindir_set}" = xyes
+then
+ :
+else
+ sbindir=`eval echo ${tmp_sbindir}`
+fi
+
+
+if test "x${ac_sysconfdir_set}" = xyes
+then
+ :
+else
+ sysconfdir=`eval echo ${tmp_sysconfdir}`
+fi
+
+if test "x${ac_mandir_set}" = xyes
+then
+ :
+else
+ mandir=`eval echo ${tmp_mandir}`
+fi
+
+if test "x${ac_localstatedir_set}" = xyes
+then
+ :
+else
+ localstatedir=`eval echo ${tmp_localstatedir}`
+fi
+
+
+
+
+# Check whether --with-config-file was given.
+if test "${with_config_file+set}" = set; then :
+ withval=$with_config_file;
+ myconffile="${withval}"
+ tmp=`echo ${withval} | sed 's%^REQ_FROM_SERVER%%'`
+ sysconfdir=`echo ${tmp} | sed 's%/[^/][^/]*$%%'`
+ myrpmconffile="${tmp}"
+
+else
+
+ myconffile="${sysconfdir}/${install_name}rc"
+ myrpmconffile="${myconffile}"
+
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_CONFIGFILE _("${myconffile}")
+_ACEOF
+
+
+
+
+
+# Check whether --with-log-file was given.
+if test "${with_log_file+set}" = set; then :
+ withval=$with_log_file;
+ mylogfile="$withval"
+ mylogdir=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+
+else
+
+ if test "x${mytclient}" = "x-DSH_WITH_SERVER"; then
+ mylogfile="${localstatedir}/log/${install_name}/${install_name}_log"
+ mylogdir="${localstatedir}/log/${install_name}"
+ else
+ mylogfile="${localstatedir}/log/${install_name}_log"
+ mylogdir="${localstatedir}/log"
+ fi
+
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ERRFILE _("${mylogfile}")
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_LOGDIR _("${mylogdir}")
+_ACEOF
+
+
+
+
+
+# Check whether --with-pid-file was given.
+if test "${with_pid_file+set}" = set; then :
+ withval=$with_pid_file;
+ mylockfile="$withval"
+ mylockdir=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+
+else
+
+ if test -h /var/run && test -d /run; then
+ mylockfile="/run/${install_name}.pid"
+ mylockdir="/run"
+ else
+ mylockfile="${localstatedir}/run/${install_name}.pid"
+ mylockdir="${localstatedir}/run"
+ fi
+
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_ERRLOCK _("${mylockfile}")
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_PIDDIR _("${mylockdir}")
+_ACEOF
+
+
+
+
+
+# Check whether --with-state-dir was given.
+if test "${with_state_dir+set}" = set; then :
+ withval=$with_state_dir;
+ mydataroot="$withval"
+
+else
+
+ mydataroot="${localstatedir}/lib/${install_name}"
+
+
+fi
+
+
+# Check whether --with-data-file was given.
+if test "${with_data_file+set}" = set; then :
+ withval=$with_data_file;
+ mydatafile="$withval"
+ tmp=`echo ${withval} | sed 's%^REQ_FROM_SERVER%%'`
+ mydataroot=`echo ${tmp} | sed 's%/[^/][^/]*$%%'`
+ myrpmdatafile="${tmp}"
+ if test x"${tmp}" = x
+ then
+ echo "No local path in data file ${withval}"
+ echo "This will not work for initializing the database."
+ if test x"${withval}" = xREQ_FROM_SERVER
+ then
+ echo "It should be REQ_FROM_SERVER/some/local/path"
+ fi
+ as_fn_error $? "Option --with-data-file=FILE used with invalid path ${withval}." "$LINENO" 5
+ fi
+
+else
+
+ mydatafile="${mydataroot}/${install_name}_file"
+ myrpmdatafile="${mydatafile}"
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_DATA_FILE _("${mydatafile}")
+_ACEOF
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_DATAROOT _("${mydataroot}")
+_ACEOF
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_QDIR _("${mydataroot}/.quarantine")
+_ACEOF
+
+
+
+
+
+# Check whether --with-html-file was given.
+if test "${with_html_file+set}" = set; then :
+ withval=$with_html_file;
+ myhtmlfile="$withval"
+
+else
+
+ myhtmlfile="${mylogdir}/${install_name}.html"
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_HTML_FILE _("${myhtmlfile}")
+_ACEOF
+
+
+
+
+mydefargs=$ac_configure_args
+# if test -z "`echo "$mydefargs" | grep "\-\-enable\-static" 2> /dev/null`"
+# then
+# mydefargs="--enable-static $mydefargs"
+# fi
+if test -z "`echo "$mydefargs" | grep "\-\-enable\-base" 2> /dev/null`"
+then
+ mydefargs="--enable-base=${mykeybase} $mydefargs"
+fi
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SH_INSTALL_DIR _("${sbindir}")
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define SH_INSTALL_PATH _("${sbindir}/${install_name}")
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define SH_INSTALL_NAME _("${install_name}")
+_ACEOF
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_config_files="$ac_config_files Makefile samhain-install.sh init/samhain.startLSB init/samhain.startLinux init/samhain.startGentoo init/samhain.startFreeBSD init/samhain.startSolaris init/samhain.startHPUX init/samhain.startIRIX init/samhain.startMACOSX samhain.spec rules.deb rules.deb-light hp_ux.psf scripts/logrotate scripts/samhain.spec scripts/redhat_i386.client.spec scripts/samhain.ebuild scripts/samhain.ebuild-light scripts/samhainadmin.pl scripts/yuleadmin.pl scripts/check_samhain.pl deploy.sh"
+
+ac_config_commands="$ac_config_commands default"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "samhain-install.sh") CONFIG_FILES="$CONFIG_FILES samhain-install.sh" ;;
+ "init/samhain.startLSB") CONFIG_FILES="$CONFIG_FILES init/samhain.startLSB" ;;
+ "init/samhain.startLinux") CONFIG_FILES="$CONFIG_FILES init/samhain.startLinux" ;;
+ "init/samhain.startGentoo") CONFIG_FILES="$CONFIG_FILES init/samhain.startGentoo" ;;
+ "init/samhain.startFreeBSD") CONFIG_FILES="$CONFIG_FILES init/samhain.startFreeBSD" ;;
+ "init/samhain.startSolaris") CONFIG_FILES="$CONFIG_FILES init/samhain.startSolaris" ;;
+ "init/samhain.startHPUX") CONFIG_FILES="$CONFIG_FILES init/samhain.startHPUX" ;;
+ "init/samhain.startIRIX") CONFIG_FILES="$CONFIG_FILES init/samhain.startIRIX" ;;
+ "init/samhain.startMACOSX") CONFIG_FILES="$CONFIG_FILES init/samhain.startMACOSX" ;;
+ "samhain.spec") CONFIG_FILES="$CONFIG_FILES samhain.spec" ;;
+ "rules.deb") CONFIG_FILES="$CONFIG_FILES rules.deb" ;;
+ "rules.deb-light") CONFIG_FILES="$CONFIG_FILES rules.deb-light" ;;
+ "hp_ux.psf") CONFIG_FILES="$CONFIG_FILES hp_ux.psf" ;;
+ "scripts/logrotate") CONFIG_FILES="$CONFIG_FILES scripts/logrotate" ;;
+ "scripts/samhain.spec") CONFIG_FILES="$CONFIG_FILES scripts/samhain.spec" ;;
+ "scripts/redhat_i386.client.spec") CONFIG_FILES="$CONFIG_FILES scripts/redhat_i386.client.spec" ;;
+ "scripts/samhain.ebuild") CONFIG_FILES="$CONFIG_FILES scripts/samhain.ebuild" ;;
+ "scripts/samhain.ebuild-light") CONFIG_FILES="$CONFIG_FILES scripts/samhain.ebuild-light" ;;
+ "scripts/samhainadmin.pl") CONFIG_FILES="$CONFIG_FILES scripts/samhainadmin.pl" ;;
+ "scripts/yuleadmin.pl") CONFIG_FILES="$CONFIG_FILES scripts/yuleadmin.pl" ;;
+ "scripts/check_samhain.pl") CONFIG_FILES="$CONFIG_FILES scripts/check_samhain.pl" ;;
+ "deploy.sh") CONFIG_FILES="$CONFIG_FILES deploy.sh" ;;
+ "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "default":C)
+echo timestamp > stamp-h
+chmod +x samhain-install.sh
+chmod +x scripts/samhainadmin.pl
+chmod +x scripts/yuleadmin.pl
+chmod +x scripts/check_samhain.pl
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+chmod +x deploy.sh
+
+if test "x${cross_compiling}" = xyes
+then
+
+echo "--------------------------------------------------------------"
+echo
+echo "You are using a cross-compiler. The following system dependent"
+echo "values may have been set to default values that may be"
+echo "incorrect for your target system: "
+echo
+echo "ac_cv_c_bigendian bigendian byte order ${ac_cv_c_bigendian}"
+echo "ac_cv_c_long_double long double exists ${ac_cv_c_long_double}"
+echo "ac_cv_sizeof_char_p size of pointer to char ${ac_cv_sizeof_char_p}"
+echo "ac_cv_sizeof_char_p size of size_t ${ac_cv_sizeof_size_t}"
+echo "ac_cv_sizeof_unsigned_int size of unsigned int ${ac_cv_sizeof_unsigned_int}"
+echo "ac_cv_sizeof_unsigned_long size of unsigned long ${ac_cv_sizeof_unsigned_long}"
+echo "ac_cv_sizeof_unsigned_short size of unsigned short ${ac_cv_sizeof_unsigned_short}"
+echo
+echo "If these values are incorrect, change them in the file "
+echo "config.cache and run configure again."
+echo
+echo "--------------------------------------------------------------"
+
+fi
+
+if test x${silent} != xyes
+then
+
+ # A=`eval echo ${sbindir}` ; A=`eval echo ${A}`
+ # B=`eval echo ${myconffile}` ; B=`eval echo ${B}`
+ # C=`eval echo ${mandir}` ; C=`eval echo ${C}`
+ # D=`eval echo ${mylockfile}` ; D=`eval echo ${D}`
+ # E=`eval echo ${mylogfile}` ; E=`eval echo ${E}`
+ # F=`eval echo ${mydataroot}` ; F=`eval echo ${F}`
+
+ echo
+ echo " samhain has been configured as follows:"
+ echo " System binaries: ${sbindir}"
+ echo " Configuration file: ${myconffile}"
+ echo " Manual pages: ${mandir}"
+ echo " Data directory: ${mydataroot}"
+ echo " Database file: ${mydatafile}"
+ echo " PID file: ${mylockfile}"
+ echo " Log file: ${mylogfile}"
+ echo " Base key: ${mykeybase}"
+ if test x"$mykeyid" != x
+ then
+ echo " target GPG/PGP key: ${mykeyid}"
+ fi
+ echo
+ if test x"$mytclient" = x"-DSH_WITH_SERVER"
+ then
+ echo " Selected rc file: yulerc"
+ else
+ echo " Selected rc file: samhainrc.${selectconfig}"
+ fi
+
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..1b3e2ac
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,2763 @@
+dnl We want to override the standard _AC_INIT_PARSE_ARGS
+dnl
+AU_ALIAS([_AC_INIT_PARSE_ARGS], [SH_INIT_PARSE_ARGS])
+AU_ALIAS([_AC_INIT_help], [SH_INIT_HELP])
+
+AC_INIT(src/samhain.c)
+
+
+AC_ARG_VAR([LIBS], [libraries to link against, e.g. -lintl])
+
+dnl
+dnl start
+dnl
+AM_INIT_AUTOMAKE(samhain, 4.1.4)
+AC_DEFINE([SAMHAIN], 1, [Application is samhain])
+AC_CANONICAL_HOST
+
+dnl
+dnl checks for programs
+dnl
+
+AC_PROG_CC
+if test "$host" != "$build"; then
+ AC_CHECK_PROGS(BUILD_CC, gcc cc)
+else
+ BUILD_CC=$CC
+fi
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_AWK
+SH_PROG_LD
+AC_PATH_PROG(cmd_hostname,hostname)
+AC_SUBST(cmd_hostname)
+AC_SUBST(BUILD_CC)
+
+if test "x$GCC" = "xyes"; then
+ SH_GCC_VERSION
+fi
+
+AC_HEADER_STDC
+
+AC_CHECK_HEADERS([sys/ipc.h sys/sem.h sys/msg.h sys/uio.h fcntl.h])
+
+
+AC_MSG_CHECKING([for OS specific issues])
+mydebugflag=no
+myneedg3=no
+uid_cast="signed long"
+selectconfig=linux
+mynetbsd=no
+sh_use_lcaps="undef"
+dnmalloc_ok=yes
+sh_use_pie=yes
+enable_asm_ok=yes
+
+case "$host_os" in
+
+ *linux*)
+ sh_use_lcaps="yes"
+ AC_DEFINE(HOST_IS_LINUX)
+ AC_DEFINE(HAVE_EXT2_IOCTLS)
+ AC_MSG_RESULT([use ioctl to get e2fs flags])
+ case "$host_cpu" in
+ i*86*)
+ AC_DEFINE(HOST_IS_I86LINUX)
+ ;;
+ x86_64)
+ AC_DEFINE([HOST_IS_64LINUX], 1, [Define if host OS is 64bit Linux])
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+
+ *osf*)
+ AC_DEFINE([HOST_IS_OSF], 1, [Define if host OS is OSF])
+ if test "x$GCC" != "xyes"; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ CFLAGS="$CFLAGS -O2 -assume noaligned_objects"
+ myneedg3=yes
+ AC_MSG_RESULT([compiler needs assume noaligned_objects])
+ else
+ AC_MSG_RESULT([none])
+ fi
+ ;;
+
+ *cygwin*)
+ AC_DEFINE(HOST_IS_CYGWIN)
+ AC_DEFINE([USE_REGISTRY_CHECK], 1, [Define for registry check])
+ dnmalloc_ok=no
+ enable_asm_ok=no
+ AC_MSG_RESULT([no trusted paths, no dnmalloc. no asm optimize])
+ ;;
+
+ *darwin*|*apple*)
+ AC_DEFINE(HOST_IS_DARWIN)
+ dnmalloc_ok=no
+ AC_MSG_RESULT([check resource forks, no dnmalloc])
+ ;;
+
+ *freebsd8*|*freebsd9*)
+ AC_DEFINE(HOST_IS_FREEBSD)
+ selectconfig=freebsd
+ case "$host_cpu" in
+ amd64|x86_64)
+ dnmalloc_ok=no
+ AC_MSG_RESULT([no dnmalloc])
+ ;;
+ *)
+ AC_MSG_RESULT([none])
+ ;;
+ esac
+ ;;
+
+ *freebsd7*)
+ AC_DEFINE(HOST_IS_FREEBSD)
+ selectconfig=freebsd
+ case "$host_cpu" in
+ amd64|x86_64)
+ sh_use_pie=no
+ dnmalloc_ok=no
+ AC_MSG_RESULT([no dnmalloc and broken compiler toolchain])
+ ;;
+ *)
+ AC_MSG_RESULT([none])
+ ;;
+ esac
+ ;;
+
+ *freebsd*)
+ AC_DEFINE(HOST_IS_FREEBSD)
+ selectconfig=freebsd
+ AC_MSG_RESULT([none])
+ ;;
+
+ *openbsd*)
+ AC_DEFINE([HOST_IS_OPENBSD], 1, [Define if host OS is OPENBSD])
+ selectconfig=freebsd
+ dnmalloc_ok=no
+ AC_MSG_RESULT([dnmalloc does not work with pthreads])
+ ;;
+
+ *netbsd*)
+ mynetbsd=yes
+ selectconfig=netbsd
+ AC_MSG_RESULT([bug with libresolve])
+ ;;
+
+ *solaris*)
+ selectconfig=solaris
+ AC_DEFINE(HOST_IS_SOLARIS)
+ case "$host_cpu" in
+ i*86)
+ AC_DEFINE(HOST_IS_I86SOLARIS)
+ AC_MSG_RESULT([vsnprintf prototype])
+ ;;
+ *)
+ AC_MSG_RESULT([none])
+ ;;
+ esac
+ if test "x$GCC" != "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g" 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-xO2" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -xO2"
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-Xa" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -Xa"
+ fi
+ LIBS="-lc $LIBS"
+ fi
+ ;;
+
+
+ *sun*)
+ selectconfig=solaris
+ AC_DEFINE(HOST_IS_SOLARIS)
+ AC_MSG_RESULT([none])
+ ;;
+
+ *aix*)
+ AC_DEFINE(HOST_IS_AIX)
+ selectconfig=aix5.2.0
+ uid_cast="unsigned long"
+ if test "x$GCC" != "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g" 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-O3" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -O3"
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\-qstrict" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS -qstrict"
+ fi
+ AC_MSG_RESULT([AIX size_t in the accept call and optimize O3 qstrict])
+ else
+ AC_MSG_RESULT([AIX size_t in the accept call])
+ fi
+ ;;
+
+ *hpux*)
+ AC_MSG_RESULT([HPUX need _XOPEN_SOURCE_EXTENDED for h_errno])
+ AC_DEFINE(HOST_IS_HPUX)
+ if test "x$GCC" != "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g" 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+ if test -z "`echo "$CFLAGS" | grep "\+O2" 2> /dev/null`"; then
+ CFLAGS="$CFLAGS +O2"
+ fi
+ fi
+ ;;
+
+ *ultrix*)
+ AC_MSG_RESULT([ULTRIX getcwd uses popen])
+ AC_DEFINE(HAVE_BROKEN_GETCWD)
+ ;;
+
+ *)
+ AC_MSG_RESULT([none])
+ ;;
+esac
+
+AC_SUBST(selectconfig)
+AC_DEFINE_UNQUOTED(UID_CAST, ${uid_cast})
+
+
+
+dnl *****************************************
+dnl
+dnl checks for header files
+dnl
+dnl *****************************************
+
+AC_HEADER_DIRENT
+AC_HEADER_MAJOR
+AC_HEADER_TIME
+dnl used in minilzo.c
+AC_HEADER_STAT
+AC_DECL_SYS_SIGLIST
+
+AC_CHECK_HEADERS(stddef.h libgen.h sched.h malloc.h sys/uio.h \
+ sys/mman.h sys/param.h sys/inotify.h \
+ sys/vfs.h mntent.h \
+ sys/select.h sys/socket.h netinet/in.h \
+ regex.h glob.h fnmatch.h \
+ linux/ext2_fs.h linux/fs.h ext2fs/ext2_fs.h asm/segment.h \
+ elf.h linux/elf.h auparse.h \
+ paths.h arpa/nameser.h arpa/nameser_compat.h \
+ rpc/rpcent.h rpc/rpc.h sys/statvfs.h,
+ [],
+ [],
+ [#include <sys/types.h>]
+)
+
+
+AC_CHECK_HEADER(utmpx.h, sh_utmpx="yes", sh_utmpx="no")
+if test "x$sh_utmpx" = "xyes"; then
+ AC_DEFINE(HAVE_UTMPX_H)
+ AC_EGREP_HEADER(ut_host, utmpx.h, AC_DEFINE(HAVE_UTHOST) )
+ AC_EGREP_HEADER(ut_addr, utmpx.h, AC_DEFINE(HAVE_UTADDR) )
+ AC_EGREP_HEADER(ut_addr_v6, utmpx.h, AC_DEFINE(HAVE_UTADDR_V6) )
+ AC_EGREP_HEADER(ut_xtime,utmpx.h, AC_DEFINE(HAVE_UTXTIME) )
+ AC_EGREP_HEADER(ut_type, utmpx.h, AC_DEFINE(HAVE_UTTYPE) )
+else
+ AC_EGREP_HEADER(ut_addr, utmp.h, AC_DEFINE(HAVE_UTADDR) )
+ AC_EGREP_HEADER(ut_host, utmp.h, AC_DEFINE(HAVE_UTHOST) )
+ AC_EGREP_HEADER(ut_type, utmp.h, AC_DEFINE(HAVE_UTTYPE) )
+fi
+
+dnl
+dnl figure out where acct.h lives
+dnl and whether fields are int/comp_t
+dnl
+dnl GNU Accounting Utilities
+dnl Copyright (C) 1993, 1996, 1997, 2003, 2005 Free Software Foundation, Inc.
+dnl The GNU Accounting Utilities are free software; you can redistribute
+dnl them and/or modify them under the terms of the GNU General Public
+dnl License as published by the Free Software Foundation; either version
+dnl 2, or (at your option) any later version.
+dnl
+AC_CHECK_HEADER(sys/acct.h,
+ AC_DEFINE(HAVE_SYS_ACCT_H, ,
+ [Define if you have the <sys/acct.h> header file.])
+ AC_HEADER_EGREP(ac_utime, sys/acct.h,
+ AC_DEFINE(HAVE_ACUTIME, ,
+ [Define if <sys/acct.h> has the AC_UTIME field.])
+ AC_HEADER_EGREP(comp_t.*ac_utime, sys/acct.h,
+ AC_DEFINE(ACUTIME_COMPT, ,
+ [Define if <sys/acct.h>'s AC_UTIME field is a COMP_T.]))
+ )
+ AC_HEADER_EGREP(ac_stime, sys/acct.h,
+ AC_DEFINE(HAVE_ACSTIME, ,
+ [Define if <sys/acct.h> has the AC_STIME field.])
+ AC_HEADER_EGREP(comp_t.*ac_stime, sys/acct.h,
+ AC_DEFINE(ACSTIME_COMPT, ,
+ [Define if <sys/acct.h>'s AC_STIME field is a COMP_T.]))
+ )
+ AC_HEADER_EGREP(ac_etime, sys/acct.h,
+ AC_DEFINE(HAVE_ACETIME, ,
+ [Define if <sys/acct.h> has the AC_ETIME field.])
+ AC_HEADER_EGREP(comp_t.*ac_etime, sys/acct.h,
+ AC_DEFINE(ACETIME_COMPT, ,
+ [Define if <sys/acct.h>'s AC_ETIME field is a COMP_T.]))
+ )
+ AC_HEADER_EGREP(ac_io, sys/acct.h,
+ AC_DEFINE(HAVE_ACIO, ,
+ [Define if <sys/acct.h> has the AC_IO field.])
+ AC_HEADER_EGREP(comp_t.*ac_io, sys/acct.h,
+ AC_DEFINE(ACIO_COMPT, ,
+ [Define if <sys/acct.h>'s AC_IO field is a COMP_T.]))
+ )
+ AC_HEADER_EGREP(ac_mem, sys/acct.h,
+ AC_DEFINE(HAVE_ACMEM, ,
+ [Define if <sys/acct.h> has the AC_MEM field.])
+ AC_HEADER_EGREP(comp_t.*ac_mem, sys/acct.h,
+ AC_DEFINE(ACMEM_COMPT, ,
+ [Define if <sys/acct.h>'s AC_MEM field is a COMP_T.]))
+ )
+ AC_HEADER_EGREP(ac_minflt, sys/acct.h,
+ AC_HEADER_EGREP(ac_majflt, sys/acct.h,
+ AC_HEADER_EGREP(ac_swaps, sys/acct.h,
+ AC_DEFINE(HAVE_PAGING, ,
+ [Define if <sys/acct.h> has the AC_MINFLT, AC_MAJFLT and AC_SWAPS fields.])
+ AC_HEADER_EGREP(comp_t.*ac_minflt, sys/acct.h,
+ AC_DEFINE(ACMINFLT_COMPT, ,
+ [Define if <sys/acct.h>'s AC_MINFLT field is a COMP_T.]))
+ AC_HEADER_EGREP(comp_t.*ac_mayflt, sys/acct.h,
+ AC_DEFINE(ACMAJFLT_COMPT, ,
+ [Define if <sys/acct.h>'s AC_MAJFLT field is a COMP_T.]))
+ AC_HEADER_EGREP(comp_t.*ac_swaps, sys/acct.h,
+ AC_DEFINE(ACSWAPS_COMPT, ,
+ [Define if <sys/acct.h>'s AC_SWAPS field is a COMP_T.]))
+ )
+ )
+ )
+ AC_HEADER_EGREP(comp_t, sys/acct.h, AC_DEFINE(HAVE_COMP_T, ,
+ [Define if <sys/acct.h> uses the COMP_T type.]))
+ AC_HEADER_EGREP([struct acct_v3], sys/acct.h, AC_DEFINE(HAVE_ACCT_V3, ,
+ [Define if <sys/acct.h> has struct acct_v3.]))
+ AC_HEADER_EGREP([struct acctv2], sys/acct.h, AC_DEFINE(HAVE_ACCTV2, ,
+ [Define if <sys/acct.h> has struct acctv2.]))
+
+ )
+
+
+dnl need to check because AIX 4.2 does not have it
+dnl
+AC_CHECK_MEMBERS([struct statfs.f_flags],[],[],[
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+])
+
+AC_SYS_LARGEFILE
+
+dnl
+dnl check whether _POSIX_SOURCE is required
+dnl
+SAMHAIN_POSIX
+
+
+dnl *****************************************
+dnl
+dnl Checks for library functions.
+dnl
+dnl *****************************************
+AC_FUNC_STRFTIME
+AC_CHECK_FUNCS(memcmp memcpy memmove memset getpwent endpwent fpurge \
+ gettimeofday strlcat strlcpy strstr strchr strerror strsignal \
+ seteuid setreuid setresuid lstat getwd getcwd ptrace \
+ usleep setpriority getpeereid nanosleep \
+ strptime basename sched_yield hasmntopt \
+ inet_aton gethostbyname setutent setrlimit gethostname uname \
+ initgroups getpagesize \
+ ttyname fchmod writev mmap tzset \
+ getsid getpriority getpgid statvfs \
+ strerror_r getgrgid_r getpwnam_r getpwuid_r \
+ gmtime_r localtime_r rand_r readdir_r strtok_r \
+ mincore posix_fadvise inotify_init1
+)
+AC_CHECK_FUNC(statfs, AC_DEFINE(HAVE_STATFS) statfs="yes", statfs="no")
+SL_CHECK_VA_COPY
+AC_CHECK_FUNCS(vsnprintf, [SL_CHECK_VSNPRINTF])
+AC_CHECK_MLOCK
+SH_STRFTIME_Z
+
+AC_MSG_CHECKING(how to get filesystem type)
+fstype=no
+# The order of these tests is important.
+AC_TRY_CPP([#include <sys/statvfs.h>
+#include <sys/fstyp.h>], AC_DEFINE(FSTYPE_STATVFS) fstype=SVR4)
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/statfs.h>
+#include <sys/fstyp.h>], AC_DEFINE(FSTYPE_USG_STATFS) fstype=SVR3)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/statfs.h>
+#include <sys/vmount.h>], AC_DEFINE(FSTYPE_AIX_STATFS) fstype=AIX)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <mntent.h>], AC_DEFINE(FSTYPE_MNTENT) fstype=4.3BSD)
+fi
+if test $fstype = no; then
+AC_EGREP_HEADER(f_type;, sys/mount.h, AC_DEFINE(FSTYPE_STATFS) fstype=4.4BSD/OSF)
+fi
+if test $fstype = no; then
+AC_TRY_CPP([#include <sys/mount.h>
+#include <sys/fs_types.h>], AC_DEFINE(FSTYPE_GETMNT) fstype=Ultrix)
+fi
+AC_MSG_RESULT($fstype)
+
+sh_libsocket=
+
+dnl Solaris needs -lsocket and -lnsl. Unisys system includes
+dnl gethostbyname in libsocket but needs libnsl for socket.
+AC_CHECK_LIB(nsl, gethostbyname)
+AC_CHECK_LIB(socket, socket, ac_need_libsocket=1, ac_try_nsl=1)
+if test x$ac_need_libsocket = x1; then
+ LIBS="$LIBS -lsocket"
+ sh_libsocket="-lsocket"
+fi
+if test x$ac_try_nsl = x1; then
+ AC_CHECK_LIB(nsl, gethostbyname, ac_need_libnsl=1)
+ if test x$ac_need_libnsl = x1
+ then
+ LIBS="$LIBS -lnsl"
+ fi
+fi
+AC_SUBST(sh_libsocket)
+
+AC_CHECK_LIB(socket, res_search, [
+ AC_CHECK_LIB(resolv, dn_skipname)
+ AC_CHECK_LIB(resolv, __dn_skipname)
+ if test x$ac_need_libsocket = x1; then
+ :
+ else
+ LIBS="$LIBS -lsocket"
+ fi
+ ], [
+ AC_CHECK_LIB(resolv, res_search, [
+ LIBS="$LIBS -lresolv"
+ ], [
+ AC_CHECK_LIB(resolv, dn_skipname)
+ AC_CHECK_LIB(resolv, __dn_skipname)
+ ])
+ ])
+
+AC_CHECK_FUNCS( getnameinfo getaddrinfo )
+
+
+sh_auparse=no
+
+if test "x$ac_cv_header_auparse_h" = "xyes"
+then
+ AC_CHECK_LIB(auparse, auparse_find_field, [
+ LIBS="$LIBS -lauparse"
+ sh_auparse=yes
+ AC_DEFINE(HAVE_AUPARSE_LIB, 1, [Define if you have the auparse lib])
+ ])
+fi
+
+dnl arguments for accept
+
+dnl check for Unix98 socklen_t (found on
+dnl xemacs-patches mailing list, written
+dnl by Martin Buchholz)
+dnl
+dnl On Darwin(MacOSX) socklen_t needs to be
+dnl an int (see accept man page), on all other
+dnl unix systems we need a size_t.
+
+AC_MSG_CHECKING(for socklen_t)
+AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+ socklen_t x;
+], [],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED([ACCEPT_TYPE_ARG3],[socklen_t], [type of arg3 of accept])
+ AC_DEFINE([HAVE_SOCKLEN_T], 1, [Define if you have socklen_t])
+],[
+ AC_TRY_COMPILE([
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+ int accept (int, struct sockaddr *, size_t *);
+ ],[],[
+ AC_MSG_RESULT(size_t)
+ AC_DEFINE_UNQUOTED([ACCEPT_TYPE_ARG3],[size_t], [type of arg3 of accept])
+ ], [
+ AC_MSG_RESULT(int)
+ AC_DEFINE_UNQUOTED([ACCEPT_TYPE_ARG3],[int], [type of arg3 of accept])
+ ]
+ )
+])
+
+dnl *****************************************
+dnl checks for extended attribute or ACL
+dnl support
+dnl *****************************************
+
+AC_ARG_ENABLE([selinux],
+ [AS_HELP_STRING([--enable-selinux], [support checking selinux attributes])],
+ [],
+ [enable_selinux=check])
+if test "x$enable_selinux" != xno; then
+ sh_CHECK_XATTR
+fi
+
+AC_ARG_ENABLE([posix-acl],
+ [AS_HELP_STRING([--enable-posix-acl], [support checking posix acls])],
+ [],
+ [enable_posix_acl=check])
+if test "x$enable_posix_acl" != xno; then
+ sh_CHECK_POSIX_ACL
+fi
+
+dnl *****************************************
+dnl checks for typedefs
+dnl *****************************************
+
+AC_C_LONG_DOUBLE
+SH_CHECK_TYPEDEF(long long, HAVE_LONG_LONG)
+SH_CHECK_TYPEDEF(uint16_t, HAVE_UINT16_T)
+SH_CHECK_TYPEDEF(uint32_t, HAVE_UINT32_T)
+SH_CHECK_TYPEDEF(uint64_t, HAVE_UINT64_T)
+if test "$sh_HAVE_LONG_LONG" = "yes"; then
+ AC_CHECK_SIZEOF(unsigned long long, 4)
+ sh_sizeof_unsigned_long_long=`echo "$ac_cv_sizeof_unsigned_long_long" | sed 's%[^0-9]%%g'`
+ if test "$sh_sizeof_unsigned_long_long" = "8"; then
+ AC_DEFINE(HAVE_LONG_LONG_64, 1, [Define if you have 64bit long long])
+ fi
+fi
+
+AC_CHECK_TYPE(ptrdiff_t, long)
+AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(char *, 4)
+AC_CHECK_SIZEOF(size_t, 4)
+
+AC_CHECK_SIZEOF(unsigned long, 4)
+AC_CHECK_SIZEOF(unsigned int, 4)
+AC_CHECK_SIZEOF(unsigned short, 2)
+
+
+sh_sizeof_unsigned_long=`echo "$ac_cv_sizeof_unsigned_long" | sed 's%[^0-9]%%g'`
+if test "$sh_sizeof_unsigned_long" = "4"; then
+ AC_DEFINE(HAVE_LONG_32)
+fi
+if test "$sh_sizeof_unsigned_long" = "8"; then
+ AC_DEFINE(HAVE_LONG_64)
+fi
+sh_sizeof_unsigned_int=`echo "$ac_cv_sizeof_unsigned_int" | sed 's%[^0-9]%%g'`
+if test "$sh_sizeof_unsigned_int" = "4"; then
+ AC_DEFINE(HAVE_INT_32)
+fi
+sh_sizeof_unsigned_short=`echo "$ac_cv_sizeof_unsigned_short" | sed 's%[^0-9]%%g'`
+if test "$sh_sizeof_unsigned_short" = "4"; then
+ AC_DEFINE(HAVE_SHORT_32)
+fi
+
+dnl
+dnl check for 64 bit programming environment
+dnl
+SAMHAIN_64
+
+
+dnl *****************************************
+dnl checks for structures
+dnl *****************************************
+
+AC_STRUCT_TM
+
+dnl
+dnl from e2fsprogs
+dnl
+AC_MSG_CHECKING(whether struct stat has a st_flags field)
+AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags,
+ AC_TRY_COMPILE([#include <sys/stat.h>],
+ [struct stat stat; stat.st_flags = 0;],
+ [e2fsprogs_cv_struct_st_flags=yes],
+ [e2fsprogs_cv_struct_st_flags=no]))
+AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags)
+if test "$e2fsprogs_cv_struct_st_flags" = yes; then
+ AC_MSG_CHECKING(whether st_flags field is useful)
+ AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags_immut,
+ AC_TRY_COMPILE([#include <sys/stat.h>],
+ [struct stat stat; stat.st_flags |= UF_IMMUTABLE;],
+ [e2fsprogs_cv_struct_st_flags_immut=yes],
+ [e2fsprogs_cv_struct_st_flags_immut=no]))
+ AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags_immut)
+ if test "$e2fsprogs_cv_struct_st_flags_immut" = yes; then
+ AC_DEFINE(HAVE_STAT_FLAGS)
+ fi
+fi
+
+dnl
+dnl from dbus
+dnl
+AC_MSG_CHECKING(for struct cmsgcred)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+],[
+struct cmsgcred cred;
+
+cred.cmcred_pid = 0;
+],sh_have_struct_cmsgcred=yes,sh_have_struct_cmsgcred=no)
+AC_MSG_RESULT($sh_have_struct_cmsgcred)
+
+if test x$sh_have_struct_cmsgcred = xyes; then
+ AC_DEFINE(HAVE_STRUCT_CMSGCRED,1,[Have cmsgcred structure])
+fi
+
+AC_MSG_CHECKING(for struct fcred)
+AC_TRY_COMPILE([
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+],[
+struct fcred sockcred;
+],sh_have_struct_fcred=yes,sh_have_struct_fcred=no)
+AC_MSG_RESULT($sh_have_struct_fcred)
+
+if test x$sh_have_struct_fcred = xyes; then
+ AC_DEFINE(HAVE_STRUCT_FCRED,1,[Have fcred structure])
+fi
+
+AC_MSG_CHECKING(for struct sockcred)
+AC_TRY_COMPILE([
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ucred.h>
+],[
+struct sockcred sockcred;
+],sh_have_struct_sockcred=yes,sh_have_struct_sockcred=no)
+AC_MSG_RESULT($sh_have_struct_sockcred)
+
+if test x$sh_have_struct_sockcred = xyes; then
+ AC_DEFINE(HAVE_STRUCT_SOCKCRED,1,[Have sockcred structure])
+fi
+
+AC_MSG_CHECKING(for SO_PEERCRED)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+],[
+int test = SO_PEERCRED;
+],sh_have_SO_PEERCRED=yes,sh_have_SO_PEERCRED=no)
+AC_MSG_RESULT($sh_have_SO_PEERCRED)
+
+if test x$sh_have_SO_PEERCRED = xyes; then
+ AC_DEFINE(HAVE_SO_PEERCRED,1,[Have SO_PEERCRED define])
+fi
+
+
+dnl *****************************************
+dnl checks for compiler characteristics
+dnl *****************************************
+AC_C_INLINE
+AC_C_CONST
+AC_C_BIGENDIAN
+AC_C_RESTRICT
+
+AM_SA_SIGACTION_WORKS
+
+AC_ARG_ENABLE(ssp,
+ [ --disable-ssp disable the GCC stack protector],
+ [],
+ [enable_ssp=yes;]
+)
+
+if test "x$GCC" = "xyes"; then
+
+ if test x"${enable_ssp}" = xno; then
+ :
+ else
+ GCC_STACK_PROTECT_LIB
+ GCC_STACK_PROTECT_CC
+dnl GCC_STACK_CHECK_CC
+ GCC_PIE_CC
+ fi
+
+fi
+
+dnl *****************************************
+dnl
+dnl checks for system services
+dnl
+dnl *****************************************
+
+dnl
+dnl check for /proc filesystem
+dnl
+if test -d "/proc/$$"
+then
+ AC_DEFINE([HAVE_PROCFS],[1],[Define if you have a proc fs])
+fi
+
+dnl
+dnl check for GNU gmp
+dnl
+AC_CHECK_LIB(gmp, __gmpz_init, [sh_have_gmp=yes], [sh_have_gmp=no])
+if test "x${sh_have_gmp}" = xno
+then
+ AC_CHECK_LIB(gmp, mpz_init, [sh_have_gmp=yes], [sh_have_gmp=no])
+fi
+if test "x${sh_have_gmp}" = xyes
+then
+ # LIBS="-lgmp $LIBS"
+ AC_DEFINE(HAVE_LIBGMP, 1, [Have GNU gmp library])
+fi
+AC_CHECK_HEADERS(gmp.h)
+
+AC_MSG_CHECKING([for ps])
+PS=
+for ff in /usr/ucb /bin /usr/bin; do
+ if test -x "$ff/ps"; then
+ PS="$ff/ps"
+ AC_MSG_RESULT([$PS])
+ break
+ fi
+done
+if test x$PS = x
+then
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([Cannot find ps in any of /usr/ucb /bin /usr/bin])
+fi
+AC_DEFINE_UNQUOTED([PSPATH], _("$PS"), [Path to ps])
+
+AC_MSG_CHECKING([how to use ps])
+$PS ax >/dev/null 2>&1
+if test $? -eq 0; then
+ case "$host_os" in
+ *openbsd*)
+ one=`$PS akx | wc -l`
+ ;;
+ *)
+ one=`$PS ax | wc -l`
+ ;;
+ esac
+else
+ one=0
+fi
+$PS -e >/dev/null 2>&1
+if test $? -eq 0; then
+ two=`$PS -e | wc -l`
+else
+ two=0
+fi
+if test $one -ge $two
+then
+ case "$host_os" in
+ *openbsd*)
+ PSARG="akx"
+ ;;
+ *)
+ PSARG="ax"
+ ;;
+ esac
+else
+ PSARG="-e"
+fi
+AC_DEFINE_UNQUOTED([PSARG], _("$PSARG"), [Argument for ps])
+AC_MSG_RESULT([$PS $PSARG])
+
+dnl *****************************************
+dnl
+dnl enable features
+dnl
+dnl *****************************************
+
+AC_ARG_ENABLE(db-reload,
+ [ --enable-db-reload enable database reload on SIGHUP [[no]]],
+ [
+ if test "x${enable_db_reload}" = xyes; then
+ AC_DEFINE(RELOAD_DATABASE)
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(xml-log,
+ [ --enable-xml-log enable XML logfile format [[no]]],
+ [
+ if test "x${enable_xml_log}" = xyes; then
+ AC_DEFINE(SH_USE_XML)
+ fi
+ ]
+)
+
+
+AC_ARG_ENABLE(mail,
+ [ --disable-mail disable the internal SMTP mailer],
+ [
+ if test "x${enable_mail}" = xno; then
+ :
+ else
+ AC_DEFINE(SH_WITH_MAIL)
+ fi
+ ],
+ [AC_DEFINE(SH_WITH_MAIL)]
+)
+
+AC_ARG_ENABLE(suid,
+ [ --enable-suid allow suid],
+ [
+ if test "x${enable_suid}" = xyes; then
+ AC_DEFINE(SH_ALLOW_SUID, [1], [Define if you want to allow suid execution for samhain])
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(shellexpand,
+ [ --disable-shellexpand disable shell expansion in config file],
+ [
+ if test "x${enable_shellexpand}" = xno; then
+ :
+ else
+ AC_DEFINE(SH_EVAL_SHELL, [1], [Define if you want shell expansion in configuration file])
+ fi
+ ],
+ [AC_DEFINE(SH_EVAL_SHELL, [1], [Define if you want shell expansion in configuration file])]
+)
+
+AC_ARG_ENABLE(external-scripts,
+ [ --disable-external-scripts disable interface to external scripts],
+ [
+ if test "x${enableval}" = xno; then
+ :
+ else
+ AC_DEFINE(WITH_EXTERNAL)
+ fi
+ ],
+ [AC_DEFINE(WITH_EXTERNAL)]
+)
+
+AC_ARG_ENABLE(message-queue,
+ [ --enable-message-queue[[=MODE]] enable SysV message queue [[MODE=0700]]],
+ [
+ if test "x${ac_cv_header_sys_msg_h}" = "xyes"; then
+ if test "x${enable_message_queue}" = xyes; then
+ AC_DEFINE(WITH_MESSAGE_QUEUE)
+ AC_DEFINE_UNQUOTED(MESSAGE_QUEUE_MODE, 0700)
+ elif test "x${enable_message_queue}" != xno; then
+ echo "${enableval}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([With --enable-message-queue=MODE, MODE must be numeric])
+ echo "${enableval}" | \
+ grep ['0[0123456789][0123456789][0123456789]'] >/dev/null 2>&1 ||
+ AC_MSG_ERROR([With --enable-message-queue=MODE, MODE must be an octal (0nnn) number])
+ AC_DEFINE(WITH_MESSAGE_QUEUE)
+ AC_DEFINE_UNQUOTED(MESSAGE_QUEUE_MODE, ${enable_message_queue})
+ fi
+ else
+ echo
+ echo "**********************************************"
+ echo
+ AC_MSG_WARN([sys/msg.h missing, --enable-message-queue disabled])
+ echo
+ echo "**********************************************"
+ echo
+ fi
+ ]
+)
+
+AC_ARG_WITH(cflags,
+ [ --with-cflags additional flags to pass to compiler],
+ [
+ if test "x$withval" != "xno" ; then
+ CFLAGS="$CFLAGS $withval"
+ fi
+ ]
+)
+AC_ARG_WITH(libs,
+ [ --with-libs additional libraries to link with],
+ [
+ if test "x$withval" != "xno" ; then
+ LIBS="$LIBS $withval"
+ fi
+ ]
+)
+
+
+#
+# this is from ssh
+#
+AC_MSG_CHECKING(whether to use libwrap)
+LIBWRAP_LIB=""
+LIBWRAP_INC=""
+AC_ARG_WITH(libwrap,
+[ --with-libwrap[=PATH] Compile in libwrap (TCP Wrappers) support],
+[ AC_MSG_RESULT($withval)
+ case "$withval" in
+ no)
+ ;;
+ ""|yes)
+ LIBWRAP_LIB="-lwrap"
+ ;;
+ *)
+ if test -d "$withval"; then
+ LIBWRAP_LIB="-L$withval -lwrap"
+ changequote(<<, >>)dnl
+ sh_libwrap_inc=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+ LIBWRAP_INC="-I${sh_libwrap_inc}/include"
+ changequote([, ])dnl
+ else
+ LIBWRAP_LIB="-lwrap"
+ changequote(<<, >>)dnl
+ sh_libwrap_inc=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+ LIBWRAP_INC="-I${sh_libwrap_inc}"
+ changequote([, ])dnl
+ fi
+ ;;
+ esac
+ if test -n "$LIBWRAP_LIB"; then
+ # OLDLIBS="$LIBS"
+ LIBS="$LIBWRAP_LIB $LIBS"
+ # OLDCFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $LIBWRAP_INC"
+ AC_CHECK_HEADER(tcpd.h,
+ [],
+ [ AC_MSG_ERROR([Could not find tcpd.h for libwrap. You need to install tcp_wrappers.]) ])
+ AC_TRY_LINK([ #include <tcpd.h>
+ int allow_severity; int deny_severity; ],
+ [ hosts_access((struct request_info *) 0); ],
+ [ AC_DEFINE(SH_USE_LIBWRAP,1,[Build with tcp wrapper support]) ],
+ [ AC_MSG_ERROR([Could not find the libwrap library.]) ])
+ fi ],
+ AC_MSG_RESULT(no)
+)
+
+
+dnl
+dnl NETWORK OPTIONS
+dnl
+AC_ARG_ENABLE(network,
+ [ --enable-network=[[client|server]] compile client or server [[no]]],
+ [
+ if test "x$enable_network" = xclient; then
+ mytclient="-DSH_WITH_CLIENT"
+ yulectl_prg=
+ samhainadmin_prg=
+ setpwd_prg="samhain_setpwd"
+ sh_main_prg="samhain"
+ if test "x${sh_have_gmp}" = xyes
+ then
+ LIBS="-lgmp $LIBS"
+ fi
+dnl AC_CHECK_HEADER(sys/capability.h,
+dnl [AC_CHECK_LIB(cap, cap_get_proc,,sh_use_lcaps="no")],
+dnl [sh_use_lcaps="no"])
+ elif test "x$enable_network" = xserver; then
+ mytclient="-DSH_WITH_SERVER"
+ yulectl_prg="yulectl"
+ samhainadmin_prg="scripts/samhainadmin.pl"
+ setpwd_prg="samhain_setpwd"
+ sh_main_prg="yule"
+ if test "x${sh_have_gmp}" = xyes
+ then
+ LIBS="-lgmp $LIBS"
+ fi
+ sh_use_lcaps="undef"
+ elif test "x$enable_network" = xno; then
+ mytclient="-DSH_STANDALONE"
+ yulectl_prg=
+ samhainadmin_prg=
+ setpwd_prg=
+ sh_main_prg="samhain"
+dnl AC_CHECK_HEADER(sys/capability.h,
+dnl [AC_CHECK_LIB(cap, cap_get_proc,,sh_use_lcaps="no")],
+dnl [sh_use_lcaps="no"])
+ else
+ AC_MSG_ERROR([With --enable-network=WHAT, WHAT must be client, server, or no])
+ fi
+ ],
+ [
+ mytclient="-DSH_STANDALONE"
+ setpwd_prg=
+ yulectl_prg=
+ samhainadmin_prg=
+ sh_main_prg="samhain"
+dnl AC_CHECK_HEADER(sys/capability.h,
+dnl [AC_CHECK_LIB(cap, cap_get_proc,,sh_use_lcaps="no")],
+dnl [sh_use_lcaps="no"])
+ ],
+)
+
+AC_SUBST(setpwd_prg)
+AC_SUBST(yulectl_prg)
+AC_SUBST(samhainadmin_prg)
+AC_SUBST(sh_main_prg)
+AC_SUBST(mytclient)
+
+# needed for the rpm spec
+clmytclient=`echo ${mytclient} | sed s%\-%%`
+AC_SUBST(clmytclient)
+
+sh_no_gcc_static=no
+
+AC_ARG_ENABLE(static,
+ [ --enable-static enable static linking [[no]]],
+ [
+ if test x$enable_static = xyes; then
+ if test x"$mynetbsd" = xyes
+ then
+ tmp_LIBS=`echo $LIBS | sed 's%\-lresolv%%' `
+ LIBS="${tmp_LIBS}"
+ fi
+ if test x"${sh_auparse}" = xyes
+ then
+ tmp_LIBS=`echo $LIBS | sed 's%\-lauparse%%' `
+ LIBS="${tmp_LIBS}"
+ fi
+
+ if test "x$GCC" = "xyes";
+ then
+ case "$host_os" in
+
+ *solaris*)
+ AC_MSG_WARN([option --enable-static ignored on Solaris])
+ ;;
+
+ *)
+ AC_DEFINE(SH_COMPILE_STATIC, 1, [Define if compiling static])
+ sh_no_gcc_static=no
+ LDFLAGS="$LDFLAGS -static"
+ ;;
+ esac
+ else
+ AC_DEFINE(SH_COMPILE_STATIC, 1, [Define if compiling static])
+ sh_no_gcc_static=yes
+ case "$host_os" in
+
+ *aix*)
+ LDFLAGS="$LDFLAGS -bnso -bI:/lib/syscalls.exp"
+ ;;
+
+ *hpux*)
+ LDFLAGS="$LDFLAGS -Wl,-a,archive"
+ ;;
+
+ *osf*)
+ LDFLAGS="$LDFLAGS -non_shared"
+ ;;
+
+ *irix*)
+ LDFLAGS="$LDFLAGS -non_shared"
+ ;;
+
+ *sco*)
+ LDFLAGS="$LDFLAGS -dn"
+ ;;
+
+ *sun*)
+ LDFLAGS="$LDFLAGS -Bstatic"
+ ;;
+
+ *solaris*)
+ LDFLAGS="$LDFLAGS -Bstatic"
+ ;;
+
+ *)
+ echo "***********************************************"
+ echo "*"
+ echo "* Don't know how to enable static linking"
+ echo "* with your compiler. Please set the environment"
+ echo "* variable LDFLAGS to:"
+ echo "* ${LDFLAGS} + the static linking flag"
+ echo "* and run configure again"
+ echo "*"
+ echo "***********************************************"
+ ;;
+
+ esac
+ fi
+ fi
+ ]
+)
+
+if test x"${mytclient}" = x-DSH_STANDALONE -o x"${mytclient}" = x-DSH_WITH_CLIENT;
+then
+dnl For threaded modules
+ ACX_PTHREAD
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ LDFLAGS="$PTHREAD_CFLAGS $LDFLAGS"
+ CC="$PTHREAD_CC"
+dnl For MODI_TXT
+ CHECK_ZLIB()
+fi
+
+if test x$enable_static = xyes; then
+ :
+else
+ if test x$sh_use_pie = xyes; then
+ LDFLAGS="$LDFLAGS $PIE_LDFLAGS"
+ CFLAGS="$CFLAGS $PIE_CFLAGS"
+ fi
+fi
+AC_CHECK_FUNC(pmap_getmaps,
+ AC_DEFINE([HAVE_PMAP_GETMAPS], [], [Define if pmap_getmaps available]), [],[])
+
+
+#
+# this is from the snort configure.in
+#
+AC_DEFUN(FAIL_MESSAGE,[
+ echo
+ echo
+ echo "**********************************************"
+ echo " ERROR: unable to find" $1
+ echo " checked in the following places"
+ for i in `echo $2`; do
+ echo " $i"
+ done
+ echo "**********************************************"
+ echo
+ exit
+])
+
+AC_ARG_WITH(libprelude-prefix,
+ [ --with-libprelude-prefix=PFX Prefix where libprelude is installed (optional)],
+ libprelude_config_prefix="$withval", libprelude_config_prefix="")
+
+AC_MSG_CHECKING(whether to use prelude)
+AC_ARG_WITH(prelude,
+ [ --with-prelude Prelude IDS support [[no]]],
+ [
+ if test "x${withval}" = "xno"; then
+ AC_MSG_RESULT(no)
+ else
+ AC_MSG_RESULT(yes)
+ if test x$libprelude_config_prefix != x ; then
+ if test x${LIBPRELUDE_CONFIG+set} != xset ; then
+ LIBPRELUDE_CONFIG=$libprelude_config_prefix/bin/libprelude-config
+ fi
+ fi
+
+ AC_PATH_PROG(LIBPRELUDE_CONFIG, libprelude-config, no)
+ if test x"$LIBPRELUDE_CONFIG" = "xno" ; then
+ HAVE_PRELUDE_CONFIG=no
+ else
+ HAVE_PRELUDE_CONFIG=yes
+ fi
+dnl AC_CHECK_PROG(HAVE_PRELUDE_CONFIG, libprelude-config, yes, no)
+ if test "$HAVE_PRELUDE_CONFIG" = "yes"; then
+ sh_libprelude_version=`$LIBPRELUDE_CONFIG --version`
+ case "$sh_libprelude_version" in
+ 0.8*)
+ AC_MSG_ERROR([You have Libprelude 0.8, which is too old. Version 0.9.6 or higher is required.])
+ ;;
+ *)
+ AM_PATH_LIBPRELUDE([0.9.6],
+ [
+ AC_DEFINE(HAVE_LIBPRELUDE,1,[Have libprelude])
+ CFLAGS="$CFLAGS $LIBPRELUDE_PTHREAD_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBPRELUDE_LDFLAGS"
+ LIBS="$LIBS $LIBPRELUDE_LIBS"
+ ],
+ [
+ AC_MSG_ERROR([Could not find libprelude (if you are using --enable-static, the static library libprelude.a might be missing).])
+ ])
+ ;;
+ esac
+ else
+ AC_MSG_ERROR([Could not find libprelude-config.])
+ fi
+ fi
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+)
+
+#
+# partly based on the snort configure.in
+#
+AC_ARG_WITH(database,
+ [ --with-database=[[mysql|postgresql|oracle|odbc]] database support [[no]]],
+ [
+ if test x"$enable_xml_log" != xyes; then
+ AC_MSG_ERROR([With --with-database, --enable-xml-log is required as well.])
+ fi
+ if test "x${withval}" = "xmysql"; then
+ if test "x$zlib_found" = "x"
+ then
+ CHECK_ZLIB()
+ fi
+ AC_CHECK_PROG(HAVE_MYSQL_CONFIG, mysql_config, yes, no)
+ if test "$HAVE_MYSQL_CONFIG" = "yes"; then
+ sh_mysql_libs="`mysql_config --libs`"
+ sh_mysql_libs="`eval echo ${sh_mysql_libs}`"
+ LIBS="$LIBS ${sh_mysql_libs}"
+ sh_mysql_cflags="`mysql_config --cflags`"
+ sh_mysql_cflags="`eval echo ${sh_mysql_cflags}`"
+ CPPFLAGS="$CPPFLAGS ${sh_mysql_cflags}"
+ else
+ AC_MSG_CHECKING([for MySQL in /usr /usr/local /usr/local/mysql MYSQL_HOME])
+ mysql_directory="/usr /usr/local /usr/local/mysql ${MYSQL_HOME}"
+
+ for i in $mysql_directory; do
+ if test -r $i/include/mysql/mysql.h; then
+ MYSQL_DIR=$i
+ MYSQL_INC_DIR=$i/include
+ # we use AC_CHECK_HEADERS to check for mysql/mysql.h
+ fi
+ done
+ if test -z "$MYSQL_DIR"; then
+ for i in $mysql_directory; do
+ if test -r $i/include/mysql.h; then
+ MYSQL_DIR=$i
+ MYSQL_INC_DIR=$i/include
+ fi
+ done
+ fi
+
+ if test -z "$MYSQL_DIR"; then
+ tmp=""
+ for i in $mysql_directory; do
+ tmp="$tmp $i/include $i/include/mysql"
+ done
+ FAIL_MESSAGE("mysql headers (mysql.h)", $tmp)
+ fi
+
+ for i in lib lib/mysql; do
+ str="$MYSQL_DIR/$i/libmysqlclient.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ MYSQL_LIB_DIR="$MYSQL_DIR/$i"
+ break 2
+ fi
+ done
+ done
+
+ if test -z "$MYSQL_LIB_DIR"; then
+ for ff in $mysql_directory; do
+ for i in lib lib/mysql; do
+ str="$ff/$i/libmysqlclient.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ MYSQL_LIB_DIR="$ff/$i"
+ break 3
+ fi
+ done
+ done
+ done
+ fi
+
+ if test -z "$MYSQL_LIB_DIR"; then
+ tmp=""
+ for i in $mysql_directory; do
+ tmp="$i/lib $i/lib/mysql"
+ done
+ FAIL_MESSAGE("mysql library libmysqlclient", $tmp)
+ fi
+
+ AC_MSG_RESULT(yes)
+ LIBS="$LIBS -L${MYSQL_LIB_DIR} -lmysqlclient"
+ # CFLAGS="$CFLAGS -I${MYSQL_INC_DIR}"
+ CPPFLAGS="$CPPFLAGS -I${MYSQL_INC_DIR}"
+ fi
+ AC_DEFINE(WITH_MYSQL)
+ AC_DEFINE(WITH_DATABASE)
+ if test "x$zlib_found" = "xyes"
+ then
+ LIBS="$LIBS -lz -lm"
+ else
+ echo
+
+ echo " Mysql library was not found or not useable."
+ echo " Possible reasons include:"
+ echo " - an old, incompatible version compiled from source"
+ echo " - on Solaris, libmysql is compiled with the Solaris"
+ echo " compiler, thus the mysql_config script provides"
+ echo " compiler options unsuitable for gcc (move"
+ echo " mysql_config out of your PATH)"
+ echo " For other problems, check config.log for the error"
+ echo " message from the compiler."
+ echo
+ echo " If your mysql libraries are installed in an"
+ echo " unusual place, use --with-libs=-L/path/to/libdirectory"
+ echo " where libdirectory is the directory holding libmysql."
+ if test x"$enable_static" = xyes; then
+ echo " Note that for compiling a static binary, you need"
+ echo " the static libraries, rather than the shared ones."
+ fi
+ echo
+ AC_MSG_ERROR([Could not find libmysql, or it is not useable.])
+ fi
+ AC_CHECK_HEADERS(mysql/mysql.h)
+ elif test "x${withval}" = "xpostgresql"; then
+ AC_DEFINE(WITH_POSTGRES)
+ AC_DEFINE(WITH_DATABASE)
+ #
+ PGCONF="no"
+ MY_PATH="${PATH}:/usr/local/bin:/usr/local/pgsql/bin"
+ OLD_IFS="$IFS"
+ IFS=":"
+ for ff in ${MY_PATH}
+ do
+ if test -f "$ff/pg_config"
+ then
+ PGCONF="$ff/pg_config"
+ fi
+ done
+ IFS="${OLD_IFS}"
+ #
+ #
+ if test "x${PGCONF}" = "xno"
+ then
+ AC_MSG_CHECKING(for PostgreSQL in /usr/local/pgsql /usr/pgsql /usr/local /usr PGSQL_HOME)
+ pgsql_directory="/usr/local/pgsql /usr/pgsql /usr/local /usr ${PGSQL_HOME}"
+ for i in $pgsql_directory; do
+ if test -r $i/include/pgsql/libpq-fe.h; then
+ PGSQL_INC_DIR=$i/include
+ PGSQL_DIR=$i
+ # use AC_CHECK_HEADERS to check for pgsql/libpq-fe.h
+ fi
+ done
+ if test -z "$PGSQL_DIR"; then
+ for i in $pgsql_directory; do
+ if test -r $i/include/postgresql/libpq-fe.h; then
+ PGSQL_INC_DIR=$i/include
+ PGSQL_DIR=$i
+ fi
+ done
+ fi
+ if test -z "$PGSQL_DIR"; then
+ for i in $pgsql_directory; do
+ if test -r $i/include/libpq-fe.h; then
+ PGSQL_INC_DIR=$i/include
+ PGSQL_DIR=$i
+ fi
+ done
+ fi
+
+ if test -z "$PGSQL_DIR"; then
+ tmp=""
+ for i in $pgsql_directory; do
+ tmp="$tmp $i/include $i/include/pgsql $i/include/postgresql"
+ done
+ FAIL_MESSAGE("PostgreSQL header file (libpq-fe.h)", $tmp)
+ fi
+
+ for i in lib lib/pgsql lib/postgresql; do
+ str="$PGSQL_DIR/$i/libpq.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ PGSQL_LIB_DIR="$PGSQL_DIR/$i"
+ break 2
+ fi
+ done
+ done
+
+ if test -z "$PGSQL_LIB_DIR"; then
+ for ff in $pgsql_directory; do
+ for i in lib lib/pgsql lib/postgresql; do
+ str="$ff/$i/libpq.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ PGSQL_LIB_DIR="$ff/$i"
+ break 3
+ fi
+ done
+ done
+ done
+ fi
+
+ if test -z "$PGSQL_LIB_DIR"; then
+ tmp=""
+ for i in $pgsql_directory; do
+ tmp="$i/lib $i/lib/pgsql $i/lib/postgresql"
+ done
+ FAIL_MESSAGE("postgresql library libpq", $tmp)
+ fi
+
+ AC_MSG_RESULT(yes)
+
+ LIBS="$LIBS -L${PGSQL_LIB_DIR} -lpq -lm"
+ if test x"$enable_static" = xyes; then
+ LIBS="$LIBS -L${PGSQL_LIB_DIR} -lpq -lcrypt -lm"
+ else
+ LIBS="$LIBS -L${PGSQL_LIB_DIR} -lpq -lm"
+ fi
+ # CFLAGS="$CFLAGS -I${PGSQL_INC_DIR}"
+ CPPFLAGS="$CPPFLAGS -I${PGSQL_INC_DIR}"
+ AC_CHECK_HEADERS(pgsql/libpq-fe.h)
+ AC_CHECK_HEADERS(postgresql/libpq-fe.h)
+ else
+ pg_lib_dir=`${PGCONF} --libdir`
+ if test x"$enable_static" = xyes; then
+ LIBS="$LIBS -L${pg_lib_dir} -lpq -lcrypt -lm"
+ else
+ LIBS="$LIBS -L${pg_lib_dir} -lpq -lm"
+ fi
+ pg_inc_dir=`${PGCONF} --includedir`
+ # CFLAGS="$CFLAGS -I${pg_inc_dir}"
+ CPPFLAGS="$CPPFLAGS -I${pg_inc_dir}"
+ fi
+ elif test "x${withval}" = "xodbc"; then
+ AC_MSG_CHECKING(for odbc in /usr /usr/local ODBC_HOME)
+ odbc_directory="/usr /usr/local"
+
+ for i in $odbc_directory; do
+ if test -r $i/include/sql.h; then
+ if test -r $i/include/sqlext.h; then
+ if test -r $i/include/sqltypes.h; then
+ ODBC_DIR=$i
+ ODBC_INC_DIR=$i/include
+ fi
+ fi
+ fi
+ done
+
+ if test -z "$ODBC_DIR"; then
+ tmp=""
+ for i in $odbc_directory; do
+ tmp="$tmp $i/include"
+ done
+ FAIL_MESSAGE("odbc headers (sql.h sqlext.h sqltypes.h)", $tmp)
+ fi
+
+ str="$ODBC_DIR/lib/libodbc.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ ODBC_LIB_DIR="$ODBC_DIR/lib"
+ ODBC_LIB="odbc"
+ fi
+ done
+
+ if test -z "$ODBC_LIB_DIR"; then
+ FAIL_MESSAGE("odbc library (libodbc)", "$ODBC_DIR/lib")
+ fi
+
+ AC_MSG_RESULT(yes)
+ CPPFLAGS="${CPPFLAGS} -I${ODBC_INC_DIR}"
+ LIBS="${LIBS} -L${ODBC_LIB_DIR} -l$ODBC_LIB"
+ AC_DEFINE(WITH_ODBC)
+ AC_DEFINE(WITH_DATABASE)
+
+ elif test "x${withval}" = "xoracle"; then
+
+ AC_MSG_CHECKING(for oracle in ORACLE_HOME /usr/local /usr)
+
+ oracle_directory="/usr /usr/local ${ORACLE_HOME}"
+ for i in $oracle_directory; do
+
+ ff=`find $i -name oci.h 2>/dev/null | tail -1`
+ if test "x$ff" = "x"; then
+ :
+ else
+ ORACLE_INC=`dirname $ff`
+ fi
+
+ fg=`find $i -name libclntsh.so 2>/dev/null | tail -1`
+ if test "x$fg" = "x"; then
+ :
+ else
+ ORACLE_LIB=`dirname $fg`
+ fi
+
+ done
+
+ if test -z "$ORACLE_INC"; then
+
+ tmp=""
+ for i in $oracle_directory; do
+ tmp="$tmp $i"
+ done
+ FAIL_MESSAGE("OCI header file (oci.h) please define ORACLE_INC directory where oci.h resides", $tmp)
+
+ elif test -z "$ORACLE_LIB"; then
+
+ tmp=""
+ for i in $oracle_directory; do
+ tmp="$tmp $i"
+ done
+ FAIL_MESSAGE("OCI library file (libclntsh.so) please define ORACLE_LIB directory where libclntsh.so resides", $tmp)
+
+ else
+
+ ORACLE_CPP_FLAGS="-I$ORACLE_INC"
+ ORACLE_LIB_DIR="$ORACLE_LIB"
+
+ AC_MSG_RESULT([$ORACLE_INC $ORACLE_LIB])
+
+ CPPFLAGS="${CPPFLAGS} ${ORACLE_CPP_FLAGS}"
+
+ ORACLE_LIBS="-lclntsh"
+
+ if test -r $ORACLE_LIB_DIR/libnnz11.so; then
+ ORACLE_LIBS="${ORACLE_LIBS} -lnnz11"
+ fi
+ if test -r $ORACLE_LIB_DIR/libwtc9.so; then
+ ORACLE_LIBS="${ORACLE_LIBS} -lwtc9"
+ elif test -r $ORACLE_LIB_DIR/libwtc8.so; then
+ ORACLE_LIBS="${ORACLE_LIBS} -lwtc8"
+ fi
+ LIBS="${LIBS} -L${ORACLE_LIB_DIR} ${ORACLE_LIBS}"
+ if test "x$GCC" != "xyes"; then
+ CFLAGS="${CFLAGS} -fno-strict-aliasing"
+ fi
+ fi
+ AC_DEFINE(WITH_ORACLE)
+ AC_DEFINE(WITH_DATABASE)
+
+ else
+ AC_MSG_ERROR([Option --with-database=database used with unsupported database ${withval}])
+ fi
+ ]
+)
+
+AC_ARG_WITH(console,
+ [ --with-console=PATH set path to console device [[/dev/console]]],
+ [
+ if test "x${withval}" != xno; then
+ mycons="$withval"
+ AC_DEFINE_UNQUOTED(DEFAULT_CONSOLE, _("${mycons}") )
+ fi
+ ])
+
+AC_ARG_WITH(altconsole,
+ [ --with-altconsole=PATH set path to second console device [[none]]],
+ [
+ if test "x${withval}" != xno; then
+ myaltcons="$withval"
+ else
+ myaltcons="NULL"
+ fi
+ ],
+ [myaltcons="NULL"])
+AC_DEFINE_UNQUOTED(ALT_CONSOLE, _("${myaltcons}") )
+
+AC_ARG_WITH(timeserver,
+ [ --with-timeserver=HOST set host address for time server [[none]]],
+ [
+ if test "x${withval}" != xno; then
+ mytimeserv="$withval"
+ AC_DEFINE(HAVE_NTIME)
+ else
+ mytimeserv="NULL"
+ fi
+ ],
+ mytimeserv="NULL")
+AC_DEFINE_UNQUOTED(DEFAULT_TIMESERVER, _("${mytimeserv}") )
+
+AC_ARG_WITH(alttimeserver,
+ [ --with-alttimeserver=HOST set address for backup time server [[none]]],
+ [
+ if test "x${withval}" != xno; then
+ myalttimeserv="$withval"
+ AC_DEFINE(HAVE_NTIME)
+ else
+ myalttimeserv="NULL"
+ fi
+ ],
+ myalttimeserv="NULL")
+AC_DEFINE_UNQUOTED(ALT_TIMESERVER, _("${myalttimeserv}") )
+
+AC_ARG_ENABLE(login-watch,
+ [ --enable-login-watch watch for login/logout [[no]]],
+ [
+ if test "x${enable_login_watch}" = xyes; then
+ AC_DEFINE(SH_USE_UTMP)
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(mounts-check,
+ [ --enable-mounts-check check mount options on filesystems [[no]]],
+ [
+ if test "x${enable_mounts_check}" = xyes; then
+ AC_DEFINE(SH_USE_MOUNTS)
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(logfile-monitor,
+ [ --enable-logfile-monitor monitor logfiles [[no]]],
+ [
+ if test "x${enable_logfile_monitor}" = xyes; then
+ AC_CHECK_HEADER(pcre.h,
+ [
+ AC_DEFINE(USE_LOGFILE_MONITOR, 1, [Define if you want the logfile monitor module.])
+ LIBS="-lpcre $LIBS"
+ ],
+ [
+ AC_CHECK_HEADER(pcre/pcre.h,
+ [
+ AC_DEFINE(USE_LOGFILE_MONITOR, 1, [Define if you want the logfile monitor module.])
+ AC_DEFINE(HAVE_PCRE_PCRE_H, 1, [Define if you have pcre/pcre.h.])
+ LIBS="-lpcre $LIBS"
+ ],
+ AC_MSG_ERROR([The --enable-logfile-monitor option requires libpcre. For compiling the pcre development package is needed.])
+ )
+ ]
+ )
+ AC_CHECK_LIB(pcre, pcre_dfa_exec, [
+ AC_DEFINE([HAVE_PCRE_DFA_EXEC], 1, [Define if you have pcre_dfa_exec])
+ ], [
+ AC_MSG_WARN([pcre_dfa_exec not available])
+ ])
+ fi
+ ]
+)
+
+
+AC_ARG_ENABLE(process-check,
+ [ --enable-process-check check processes [[no]]],
+ [
+ if test "x${enable_process_check}" = xyes; then
+ AC_CHECK_LIB([rt], [sched_getparam], sh_lrt=yes, sh_lrt=no)
+ if test x"$sh_lrt" = xyes; then
+ LIBRT=-lrt
+ else
+ LIBRT=
+ fi
+ LIBS="$LIBS $LIBRT"
+ AC_DEFINE(SH_USE_PROCESSCHECK, [1], [Define if you want to check processes])
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(port-check,
+ [ --enable-port-check check ports [[no]]],
+ [
+ if test "x${enable_port_check}" = xyes; then
+ AC_DEFINE(SH_USE_PORTCHECK, [1], [Define if you want to check ports])
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(userfiles,
+ [ --enable-userfiles check for users' config files [[no]]],
+ [
+ if test "x${enableval}" = "xyes"; then
+ AC_DEFINE(SH_USE_USERFILES)
+ fi
+ ]
+)
+
+AC_ARG_ENABLE(debug,
+ [ --enable-debug enable debug options [[no]]],
+ [
+ if test "x${enable_debug}" = "xyes"; then
+ if test "x${mydebugflag}" != "xyes"; then
+ AC_DEFINE(MEM_DEBUG)
+ fi
+ AC_DEFINE(WITH_TPT)
+ AC_DEFINE(SL_DEBUG)
+ AC_DEFINE(DNMALLOC_CHECKS, 1, [Debug dnmalloc])
+ AC_DEFINE(PARANOIA, 0, [Paranoia level for dnmalloc])
+ AC_DEFINE(SL_FAIL_ON_ERROR)
+ if test "x${myneedg3}" = "xyes"; then
+ mydebugdef="-g3"
+ else
+ mydebugdef="-g"
+ fi
+ mydebugit="yes"
+ elif test "x${enable_debug}" = "xgdb"; then
+ AC_DEFINE(SH_ABORT_ON_ERROR, 1, [Use abort])
+ if test "x${myneedg3}" = "xyes"; then
+ mydebugdef="-g3"
+ else
+ mydebugdef="-g"
+ fi
+ mydebugit="yes"
+ fi
+ ]
+)
+AC_SUBST(mydebugdef)
+
+if test "x${enable_asm_ok}" = "xyes"; then
+ sh_enable_asm=yes
+else
+ sh_enable_asm=no
+fi
+AC_ARG_ENABLE(asm,
+ [ --disable-asm disable asm inline code],
+ [
+ if test "x${enable_asm}" = xno; then
+ sh_enable_asm=no
+ fi
+ ]
+)
+
+if test "x${samhain_64_asm}" = xyes; then
+ if test "x${sh_enable_asm}" = xyes; then
+ AC_DEFINE([TIGER_OPT_ASM],1,[Define to use tiger x86_64 optimized assembly])
+ fi
+fi
+
+AC_ARG_ENABLE(ipv6,
+ [ --disable-ipv6 disable ipv6 support],
+ [
+ if test "x${enable_ipv6}" = xno; then
+ AC_DEFINE(USE_IPV4,1,[Define if you do not want IPv6])
+ fi
+ ]
+)
+
+if test "x${dnmalloc_ok}" = "xyes"; then
+ sh_dnmalloc_enabled=yes
+else
+ sh_dnmalloc_enabled=no
+fi
+
+AC_ARG_ENABLE(dnmalloc,
+ [ --disable-dnmalloc disable dnmalloc],
+ [
+ if test "x${enable_dnmalloc}" = xno; then
+ sh_dnmalloc_enabled=no
+ else
+ sh_dnmalloc_enabled=yes
+ fi
+ ]
+)
+
+dnl Handle the problem that static linking against libc.a on Linux
+dnl produces the error "multiple definitions of malloc"
+dnl
+if test "x$sh_dnmalloc_enabled" = "xyes"; then
+ if test x$enable_static = xyes; then
+ if test "x$sh_no_gcc_static" = "xyes"; then
+ sh_dnmalloc_enabled=no
+ else
+ if test "x$with_gnu_ld" = "xyes"; then
+ LDFLAGS="$LDFLAGS -Wl,--allow-multiple-definition"
+ else
+ sh_dnmalloc_enabled=no
+ fi
+ fi
+ fi
+fi
+
+if test "x${sh_dnmalloc_enabled}" = xno; then
+ AC_DEFINE(USE_SYSTEM_MALLOC,1,[Define if you want to use the system malloc])
+fi
+
+AC_ARG_ENABLE(ptrace,
+ [ --enable-ptrace use anti-debugger options [[no]]],
+ [
+ if test "x${enable_ptrace}" = xyes; then
+ if test "x$mydebugit" != "xyes"; then
+ AC_DEFINE(SCREW_IT_UP)
+ fi
+ fi
+ ]
+)
+
+dnl
+if test "x$GCC" = "xyes"; then
+ if test ! -z "`echo "$CFLAGS" | grep "\-g\ " 2> /dev/null`" ; then
+ CFLAGS=`echo $CFLAGS | sed 's%\-g%%' `
+ fi
+
+dnl -W is the older name for -Wextra
+
+
+ if test -z "`echo "$CFLAGS" | grep "\-Wall" 2> /dev/null`" ; then
+ case "$host_os" in
+ *solaris*)
+ CFLAGS="$CFLAGS -Wall -W -Wno-missing-braces "
+ ;;
+ *)
+ CFLAGS="$CFLAGS -Wall -W "
+ ;;
+ esac
+ fi
+
+ if test -z "`echo "$CFLAGS" | grep "\-fstrength\-reduce" 2> /dev/null`"
+ then
+ if test -z "`echo "$CFLAGS" | grep "\-fno\-strength\-reduce" 2> /dev/null`"
+ then
+ GCC_FLAG_CHECK([-fno-strength-reduce])
+ fi
+ fi
+
+ if test -z "`echo "$CFLAGS" | grep "\-fomit\-frame\-pointer" 2> /dev/null`"
+ then
+ if test -z "`echo "$CFLAGS" | grep "\-fno\-omit\-frame\-pointer" 2> /dev/null`"
+ then
+ GCC_FLAG_CHECK([-fno-omit-frame-pointer])
+ fi
+ fi
+
+fi
+
+dnl Test whether gcc supports -Wno-empty-body
+dnl Suppresses warnings from glibc pthread_cleanup_pop
+dnl
+GCC_FLAG_CHECK([-Wno-empty-body])
+
+dnl This one is for clang
+dnl
+GCC_FLAG_CHECK([-Wno-invalid-source-encoding])
+
+
+AC_MSG_CHECKING([which random module to use])
+AC_ARG_WITH(rnd,
+ [ --with-rnd=[[egd|unix|dev|default]] random number generator [[default]]],
+[use_static_rnd=$withval], [use_static_rnd=default] )
+
+if test "$use_static_rnd" = no; then
+ use_static_rnd=default
+fi
+
+case "$use_static_rnd" in
+ egd | dev | unix | default )
+ AC_MSG_RESULT($use_static_rnd)
+ ;;
+ * )
+ AC_MSG_RESULT([invalid argument])
+ AC_MSG_ERROR([Option --with-rnd=module used with unsupported module ${use_static_rnd}])
+ ;;
+esac
+
+AC_ARG_WITH(egd-socket,
+ [ --with-egd-socket=NAME EGD socket name],
+ egd_socket_name="$withval", egd_socket_name="" )
+AC_DEFINE_UNQUOTED(EGD_SOCKET_NAME, _("$egd_socket_name") )
+
+dnl
+dnl See whether the user wants to disable checking for /dev/random
+
+try_dev_random=yes
+
+case "$use_static_rnd" in
+dev | default )
+ try_dev_random=yes
+ ;;
+egd)
+ AC_DEFINE(HAVE_EGD_RANDOM)
+ try_dev_random=no
+ ;;
+unix)
+ AC_DEFINE(HAVE_UNIX_RANDOM)
+ try_dev_random=no
+ ;;
+esac
+
+
+if test "x$try_dev_random" = "xyes"; then
+ AC_MSG_CHECKING(whether /dev/random exists)
+ if test -r "/dev/srandom" && test -c "/dev/srandom"; then
+ AC_DEFINE(HAVE_URANDOM)
+ AC_DEFINE_UNQUOTED(NAME_OF_DEV_RANDOM, _("/dev/srandom") )
+ AC_MSG_RESULT(yes)
+ if test -r "/dev/urandom" && test -c "/dev/urandom"; then
+ AC_DEFINE_UNQUOTED(NAME_OF_DEV_URANDOM, _("/dev/urandom") )
+ fi
+ else
+ if test -r "/dev/random" && test -c "/dev/random"; then
+ AC_DEFINE(HAVE_URANDOM)
+ AC_DEFINE_UNQUOTED(NAME_OF_DEV_RANDOM, _("/dev/random") )
+ AC_MSG_RESULT(yes)
+ if test -r "/dev/urandom" && test -c "/dev/urandom"; then
+ AC_DEFINE_UNQUOTED(NAME_OF_DEV_URANDOM, _("/dev/urandom") )
+ fi
+ else
+ AC_MSG_RESULT(no)
+ AC_DEFINE(HAVE_UNIX_RANDOM)
+ fi
+ fi
+fi
+
+
+AC_ARG_ENABLE(udp,
+ [ --enable-udp server can listen on port 514/udp [[no]]],
+ [
+ if test "x${enable_udp}" = xyes; then
+ AC_DEFINE(INET_SYSLOG)
+ fi
+ ]
+)
+
+myencrypt=yes
+AC_ARG_ENABLE(encrypt,
+ [ --disable-encrypt disable client/server encryption],
+ [
+ if test "x${enable_encrypt}" = xno; then
+ myencrypt=no
+ fi
+ ]
+)
+if test "x${myencrypt}" = "xyes"; then
+ AC_DEFINE(SH_ENCRYPT)
+ AC_DEFINE(SH_ENCRYPT_2)
+fi
+
+sh_use_srp_proto=yes
+AC_ARG_ENABLE(srp,
+ [ --disable-srp disable SRP for authentication],
+ [
+ if test "x${enable_srp}" = xno; then
+ sh_use_srp_proto=no
+ fi
+ ]
+)
+if test "x${sh_use_srp_proto}" = xyes; then
+ AC_DEFINE(USE_SRP_PROTOCOL)
+fi
+
+AC_ARG_WITH(port,
+ [ --with-port=PORT set port to use for TCP/IP connection [[49777]]],
+ [
+ echo "${withval}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([For --with-port=PORT, PORT must be numeric.])
+ myport=${withval}
+ ],
+ [myport="49777"])
+AC_DEFINE_UNQUOTED(SH_DEFAULT_PORT, ${myport})
+AC_SUBST(myport)
+
+AC_ARG_WITH(logserver,
+ [ --with-logserver=HOST set host address for log server [[none]]],
+ [
+ case "$withval" in
+ *.* | localhost)
+ mylogsrv="$withval"
+ ;;
+ *)
+ mylogsrv="$withval"
+ ;;
+ esac
+ ],
+ [mylogsrv="NULL"])
+AC_DEFINE_UNQUOTED(DEFAULT_LOGSERVER, _("${mylogsrv}") )
+AC_SUBST(mylogsrv)
+
+AC_ARG_WITH(altlogserver,
+ [ --with-altlogserver=HOST set address for backup log server [[none]]],
+ [
+ case "$withval" in
+ *.* | localhost)
+ myaltlogsrv="$withval"
+ ;;
+ *)
+ myaltlogsrv="$withval"
+ ;;
+ esac
+ ],
+ [myaltlogsrv="NULL"])
+AC_DEFINE_UNQUOTED(ALT_LOGSERVER, _("${myaltlogsrv}"))
+
+
+
+dnl
+dnl STEALTH OPTIONS
+dnl
+nocl_code=
+xor_code=0
+AC_ARG_ENABLE(nocl,
+ [ --enable-nocl=PW no CL parsing unless first CL argument is PW],
+ [
+ if test "x${enableval}" != "x"; then
+ AC_DEFINE(SH_STEALTH_NOCL)
+ fi
+ if test "x${enableval}" = "xstop" || test "x${enableval}" = "xstart"; then
+ AC_MSG_ERROR([For --enable-nocl=PW start/stop/reload/restart/status are reserved words.])
+ fi
+ if test "x${enableval}" = "xreload" || test "x${enableval}" = "xrestart"; then
+ AC_MSG_ERROR([For --enable-nocl=PW start/stop/reload/restart/status are reserved words.])
+ fi
+ if test "x${enableval}" = "xstatus"; then
+ AC_MSG_ERROR([For --enable-nocl=PW start/stop/reload/restart/status are reserved words.])
+ fi
+ if test "x${enableval}" = "xno"; then
+ AC_MSG_ERROR([With --enable-nocl=PW, the use of --enable-nocl=no is ambiguous.])
+ fi
+ nocl_code="${enable_nocl}"
+ ]
+)
+AC_DEFINE_UNQUOTED(NOCL_CODE, _("${nocl_code}") )
+AC_SUBST(nocl_code)
+AC_ARG_ENABLE(stealth,
+ [ --enable-stealth=XOR_VAL enable stealth mode [[no]]],
+ [AC_DEFINE(SH_STEALTH)
+ if test "x${enableval}" != "xyes"; then
+ echo "${enableval}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([For --enable-stealth=XOR_VAL, XOR_VAL must be numeric.])
+ if test "${enableval}" -lt 127 || test "${enableval}" -gt 255; then
+ if test x"${enableval}" = x0
+ then
+ :
+ else
+ AC_MSG_ERROR([For --enable-stealth=XOR_VAL, XOR_VAL must be in the range 127 to 255.])
+ fi
+ fi
+ xor_code="${enable_stealth}"
+ else
+ xor_code=0
+ fi
+ stegin_prg="samhain_stealth"
+ ],
+ [
+ stegin_prg=
+ ]
+)
+AC_ARG_ENABLE(micro-stealth,
+ [ --enable-micro-stealth=XOR_VAL enable micro stealth mode [[no]]],
+ [
+ AC_DEFINE(SH_STEALTH)
+ AC_DEFINE(SH_STEALTH_MICRO)
+ if test "x${enableval}" != "xyes"; then
+ echo "${enableval}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([For --enable-micro-stealth=XOR_VAL, XOR_VAL must be numeric.])
+ if test "${enableval}" -lt 127 || test "${enableval}" -gt 255; then
+ if test x"${enableval}" = x0
+ then
+ :
+ else
+ AC_MSG_ERROR([For --enable-micro-stealth=XOR_VAL, XOR_VAL must be in the range 127 to 255.])
+ fi
+ fi
+ xor_code="${enable_micro_stealth}"
+ else
+ xor_code=0
+ fi
+ ]
+)
+install_name="samhain"
+INSTALL_NAME="SAMHAIN"
+AC_ARG_ENABLE(install-name,
+ [ --enable-install-name=NAME name under which to install [[samhain|yule]]],
+ [
+ if test "x${enableval}" != "xyes"; then
+ install_name="${enableval}"
+ INSTALL_NAME=`echo "${enableval}" | tr [a-z] [A-Z]`
+ else
+ install_name="${sh_main_prg}"
+ INSTALL_NAME=`echo "${sh_main_prg}" | tr [a-z] [A-Z]`
+ fi
+ ],
+ [
+ install_name="${sh_main_prg}"
+ INSTALL_NAME=`echo "${sh_main_prg}" | tr [a-z] [A-Z]`
+ ]
+)
+
+
+need_user_install=0
+
+AC_ARG_ENABLE(identity,
+ [ --enable-identity=USER user if dropping root [[daemon]]],
+ [
+ if test x"$enableval" = xno; then
+ myident="daemon"
+ else
+ myident="$enableval"
+ fi
+ echo "${myident}" | grep ['[^0123456789]'] >/dev/null 2>&1 || \
+ AC_MSG_ERROR([With --enable-identity=USER, please supply a username, not a UID.])
+ myident_uid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${myident}:" | awk -F: '{ print $3; }'`
+ if test x"${myident_uid}" = x; then
+ AC_MSG_WARN([Option --enable-identity used, user ${myident} will be added upon install.])
+ need_user_install=1
+ fi
+ ],
+ [
+ for myident in ${install_name} daemon nobody; do
+ AC_MSG_CHECKING(for user ${myident})
+ myident_uid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${myident}:" | awk -F: '{ print $3; }'`
+ if test x"${myident_uid}" != x; then
+ AC_MSG_RESULT(yes)
+ break;
+ else
+ AC_MSG_RESULT(no)
+ fi
+ done
+ if test x"${myident_uid}" = x; then
+ myident=${install_name}
+ AC_MSG_WARN([--enable-identity: user ${myident} will be added upon install])
+ need_user_install=1
+ fi
+ ])
+AC_DEFINE_UNQUOTED(DEFAULT_IDENT, _("${myident}") )
+AC_SUBST(myident)
+AC_SUBST(need_user_install)
+
+AC_SUBST(install_name)
+AC_SUBST(INSTALL_NAME)
+AC_SUBST(stegin_prg)
+AC_SUBST(xor_code)
+
+AC_DEFINE_UNQUOTED(XOR_CODE, ${xor_code})
+AC_DEFINE_UNQUOTED(SH_SYSCALLTABLE, ${sh_syscalltable})
+
+
+exepack_state0=`${srcdir}/c_random.sh 2>/dev/null`
+exepack_state1=`${srcdir}/c_random.sh 2>/dev/null`
+exepack_state2=`${srcdir}/c_random.sh 2>/dev/null`
+
+AC_DEFINE_UNQUOTED(EXEPACK_STATE_0, ${exepack_state0})
+AC_DEFINE_UNQUOTED(EXEPACK_STATE_1, ${exepack_state1})
+AC_DEFINE_UNQUOTED(EXEPACK_STATE_2, ${exepack_state2})
+
+
+AC_ARG_ENABLE(suidcheck,
+ [ --enable-suidcheck check for suid/sgid files [[no]]],
+ [
+ if test "x${enableval}" = "xyes"; then
+ AC_DEFINE(SH_USE_SUIDCHK)
+ fi
+ ]
+)
+
+
+AC_ARG_ENABLE(base,
+ [ --enable-base=B1,B2 base key (0...2147483647)],
+ [
+ AC_MSG_CHECKING(base key setting)
+ my_key_A=`echo ${enableval} | awk 'BEGIN{FS=","}{print $1}'`
+ my_key_B=`echo ${enableval} | awk 'BEGIN{FS=","}{print $2}'`
+ AC_MSG_RESULT(${my_key_A} ${my_key_B})
+ if test "x${my_key_A}" = x; then
+ AC_MSG_ERROR([Option --enable-base=B1,B2 used with invalid first base key (zero length).])
+ fi
+ if test "x${my_key_B}" = x; then
+ AC_MSG_ERROR([Option --enable-base=B1,B2 used with invalid second base key (zero length).])
+ fi
+ echo "${my_key_A}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([For --enable-base=B1,B2, B1 and B2 must be numeric in the range 0 to 2147483647.])
+ echo "${my_key_B}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([For --enable-base=B1,B2, B1 and B2 must be numeric in the range 0 to 2147483647.])
+ ],
+ [
+ AC_MSG_CHECKING(base key setting .. collecting entropy)
+ my_key_1=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_2=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_3=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_4=`${srcdir}/c_random.sh 2>/dev/null`
+ my_key_A=`expr $my_key_1 \* 32767`
+ my_key_A=`echo ${my_key_A} | sed 's%^0*%%g' 2>/dev/null`
+ my_key_A=`expr $my_key_A \+ $my_key_2`
+ my_key_B=`expr $my_key_3 \* 32767`
+ my_key_B=`echo ${my_key_B} | sed 's%^0*%%g' 2>/dev/null`
+ my_key_B=`expr $my_key_B \+ $my_key_4`
+ AC_MSG_RESULT(${my_key_A} ${my_key_B})
+ ]
+ )
+AC_SUBST(my_key_A)
+AC_SUBST(my_key_B)
+
+dnl low bytes
+my_key_1=`expr $my_key_A \% 65536`
+dnl high bytes
+my_key_2=`expr $my_key_A \/ 65536`
+dnl low bytes
+my_key_3=`expr $my_key_B \% 65536`
+dnl high bytes
+my_key_4=`expr $my_key_B \/ 65536`
+
+dnl echo ${my_key_1} ${my_key_2} ${my_key_3} ${my_key_4}
+
+dnl touch ./sh_MK.h
+dnl echo "#ifndef SH_MK_H" >> ./sh_MK.h
+dnl echo "#define SH_MK_H" >> ./sh_MK.h
+dnl ${srcdir}/c_bits.sh ${my_key_1} MKB >> ./sh_MK.h
+dnl ${srcdir}/c_bits.sh ${my_key_2} MKA >> ./sh_MK.h
+dnl ${srcdir}/c_bits.sh ${my_key_3} MKC >> ./sh_MK.h
+dnl ${srcdir}/c_bits.sh ${my_key_4} MKD >> ./sh_MK.h
+dnl echo "#endif" >> ./sh_MK.h
+AC_SUBST(my_key_1)
+AC_SUBST(my_key_2)
+AC_SUBST(my_key_3)
+AC_SUBST(my_key_4)
+
+AC_MSG_CHECKING(key position)
+pos_tf_1=`${srcdir}/c_random.sh 2>/dev/null`
+pos_tf_2=`expr $pos_tf_1 \% 8`
+pos_tf=`expr $pos_tf_2 + 1`
+AC_MSG_RESULT(${pos_tf})
+AC_DEFINE_UNQUOTED(POS_TF, ${pos_tf} )
+
+mykeybase=`echo ${my_key_A},${my_key_B}`
+AC_DEFINE_UNQUOTED(DEFKEY, ${mykeybase} )
+AC_SUBST(mykeybase)
+
+
+dnl
+dnl GPG/PGP options
+dnl
+
+AC_ARG_WITH(gpg,
+ [ --with-gpg=PATH use GnuPG to verify database/config [[no]]],
+ [
+ if test "x${withval}" != "xno"; then
+ if test "x${cross_compiling}" = xyes; then
+ mygpg="${withval}"
+ else
+ if test -f "${withval}"; then
+ mygpg="${withval}"
+ mychk0=`${withval} --load-extension tiger --print-md TIGER192 ${withval} 2>/dev/null`
+ if test "x$?" != "x0"; then
+ mychktest=no
+ for sampre in ./samhain ./yule /usr/local/sbin/samhain /usr/local/bin/samhain /usr/bin/samhain /usr/sbin/samhain /usr/local/sbin/yule /usr/local/bin/yule /usr/bin/yule /usr/sbin/yule; do
+ if test x"${mychktest}" = xyes
+ then
+ :
+ else
+ if test -f ${sampre}
+ then
+ echo "use existing ${sampre} for gpg checksum"
+ mychk0=`${sampre} -H ${withval} 2>/dev/null`
+ if test "x$?" != "x0"; then
+ if test "x${nocl_code}" != "x"; then
+ mychk0=`echo -H ${withval} | ${sampre} ${nocl_code} 2>/dev/null`
+ if test "x$?" != "x0"; then
+ :
+ else
+ mychk="${mychk0}"
+ mychktest=yes
+ fi
+ fi
+ else
+ mychk="${mychk0}"
+ mychktest=yes
+ fi
+ fi
+ fi
+ done
+ if test x${mychktest} = xno; then
+ AC_MSG_WARN([--with-gpg: cannot determine TIGER192 checksum of ${withval}])
+ echo "-------------------------------------------------------------"
+ echo " Your gpg binary does not support the TIGER192 checksum, "
+ echo " and I cannot find an existing samhain binary to use instead."
+ echo " You can:"
+ echo " (a) run make to compile a samhain binary, then repeat"
+ echo " ./configure and make"
+ echo " (b) ignore the failure. The checksum of the gpg binary"
+ echo " will not get compiled in, thus allowing an attacker"
+ echo " to replace gpg with a trojan and subverting the gpg"
+ echo " signature verification of configure and database files."
+ echo
+ echo " PLEASE IGNORE THIS MESSAGE IF YOU ALSO USE --with-checksum"
+ echo "-------------------------------------------------------------"
+ fi
+ else
+ mychk="${mychk0}"
+ fi
+ else
+ AC_MSG_ERROR([--with-gpg: cannot find GnuPG PATH=${withval}])
+ fi
+ fi
+ AC_DEFINE(WITH_GPG)
+ AC_DEFINE_UNQUOTED(DEFAULT_GPG_PATH, _("${mygpg}") )
+ AC_SUBST(mygpg)
+ fi
+ ]
+)
+
+
+
+AC_ARG_WITH(keyid,
+ [ --with-keyid=KEYID specify KeyID (0x...) for GPG/PGP functions [[none]]],
+ [
+ if test "x${withval}" != "x"; then
+ echo "${withval}" | awk '{if((length($0)==10)||(length($0)==18)){exit 2}else{exit 0}}' &&
+ AC_MSG_ERROR([--with-keyid:${withval} must be "0x" + 8|16 hex digits])
+ echo "${withval}" | grep ['[^0][^x][^0123456789ABCDEFabcdef]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([--with-keyid:${withval} must be "0x" + 8|16 hex digits])
+ mykeyid="$withval"
+ mykeytag="--default-key"
+ else
+ mykeyid=""
+ mykeytag=""
+ fi
+ AC_SUBST(mykeyid)
+ AC_SUBST(mykeytag)
+ ]
+)
+
+dnl AC_ARG_WITH(pgp,
+dnl [ --with-pgp=PATH Use PGP to verify database/config (no).],
+dnl [myppg="$withval"
+dnl AC_DEFINE(WITH_PGP)
+dnl AC_DEFINE_UNQUOTED(DEFAULT_PGP_PATH, _("${myppg}") )
+dnl ])
+
+AC_ARG_WITH(checksum,
+ [ --with-checksum=CHKSUM compile in gpg/pgp checksum [[yes]]],
+ [
+ if test "x${withval}" != "xno"; then
+ if test "x${withval}" != "xyes"; then
+ if test "x${mychk}" != "x"; then
+ if test "x${mychk}" != "x${withval}"; then
+ AC_MSG_WARN([--with-checksum: possible gpg CHKSUM problem])
+ AC_MSG_WARN([--with-checksum: CHKSUM=${withval}])
+ AC_MSG_WARN([--with-checksum: autodetected=${mychk}])
+ fi
+ fi
+ mychk="${withval}"
+ else
+ if test "x${mychk}" = "x"; then
+ AC_MSG_ERROR([Option --with-checksum=CHKSUM: checksum CHKSUM of the gpg binary not specified.])
+ fi
+ fi
+ AC_DEFINE(HAVE_GPG_CHECKSUM)
+ AC_DEFINE_UNQUOTED(GPG_HASH, _("${mychk}") )
+ echo "${mychk}" | sed 's,.*:,,g' | sed 's, ,,g' | sed 's,\(.\),\1:,g' | awk '{ split($0, arr, ":"); m = length($1)/2; print "#ifndef CHKSUM_H"; print "#define CHKSUM_H"; print "char gpgchk[50];"; for (i=1; i <= m; i++) printf "gpgchk[%d] = %c%s%c;\n", i-1, 39, arr[i], 39; printf "gpgchk[48] = %c%c0%c;\n", 39, 92, 39; print "#endif"; }' > sh_gpg_chksum.h
+ fi
+ ],
+ [
+ if test "x${mygpg}" != "x"; then
+ if test "x${mychk}" != "x"; then
+ AC_DEFINE(HAVE_GPG_CHECKSUM)
+ AC_DEFINE_UNQUOTED(GPG_HASH, _("${mychk}") )
+ echo "${mychk}" | sed 's,.*:,,g' | sed 's, ,,g' | sed 's,\(.\),\1:,g' | awk '{ split($0, arr, ":"); m = length($1)/2; print "#ifndef CHKSUM_H"; print "#define CHKSUM_H"; print "char gpgchk[50];"; for (i=1; i <= m; i++) printf "gpgchk[%d] = %c%s%c;\n", i-1, 39, arr[i], 39; printf "gpgchk[48] = %c%c0%c;\n", 39, 92, 39; print "#endif"; }' > sh_gpg_chksum.h
+ fi
+ fi
+ ]
+)
+
+AC_ARG_WITH(fp,
+ [ --with-fp=FINGERPRINT compile in public key fingerprint [[no]]],
+ [
+ if test "x${withval}" != "xno"; then
+ if test "x${withval}" != "xyes"; then
+ withval0=`echo ${withval} | sed 's% %%g'`
+ echo "${withval0}" | \
+ grep ['[^0123456789abcdefABCDEF]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([In option --with-fp=FINGERPRINT, there is an invalid character(s) in FINGERPRINT=${withval0}.])
+ sh_len=`echo ${withval0} | wc -c | sed 's% %%g'`
+ sh_len0=`expr ${sh_len} \- 1`
+ if test "x${sh_len0}" = "x40" || test "x${sh_len0}" = "x32"
+ then
+ myfp="${withval0}"
+ AC_DEFINE(USE_FINGERPRINT)
+ AC_DEFINE_UNQUOTED(SH_GPG_FP, _("${myfp}") )
+ echo "${myfp}" | sed 's,.*:,,g' | sed 's, ,,g' | sed 's,\(.\),\1:,g' | awk '{ split($0, arr, ":"); m = length($1)/2; print "#ifndef FINGERPRINT_H"; print "#define FINGERPRINT_H"; printf "char gpgfp[%d];\n", m+1; for (i=1; i <= m; i++) printf "gpgfp[%d] = %c%s%c;\n", i-1, 39, arr[i], 39; printf "gpgfp[%d] = %c%c0%c;\n", m, 39, 92, 39; print "#endif"; }' > sh_gpg_fp.h
+ else
+ AC_MSG_ERROR([In option --with-fp=FINGERPRINT, the length (${sh_len0}) of FINGERPRINT ${withval0} is incorrect.])
+ fi
+ else
+ AC_MSG_ERROR([For option --with-fp=FINGERPRINT, FINGERPRINT=yes is invalid, please specify a valid key fingerprint.])
+ fi
+ fi
+ ])
+
+
+dnl
+dnl MAIL OPTIONS
+dnl
+
+AC_ARG_WITH(recipient,
+ [ --with-recipient=ADDR set recipient(s) for e-mail [[none]]],
+ [
+ withval0=`echo ${withval} | sed 's%,% %g'`
+ for sh_item in ${withval0}
+ do
+ case ${sh_item} in
+ *@localhost)
+ ;;
+ *@*.*)
+ sh_tmp=`echo ${sh_item} | awk '{ if ($1 ~ [/^[a-zA-Z0-9][a-zA-Z0-9\-_\.]*@[a-zA-Z0-9\-\.]+\.([a-zA-Z]+|[0-9]+)$/]) {print 1; } else { print 0}}'`
+ if test "x${sh_tmp}" != "x1"
+ then
+ AC_MSG_ERROR([Option --with-recipient=ADDR used with invalid mail address ${sh_item}.])
+ fi
+ ;;
+ *)
+ AC_MSG_ERROR([Option --with-recipient=ADDR used with invalid mail address ${sh_item}.])
+ ;;
+ esac
+ done
+ myrcp="$withval0"
+ ],
+ [myrcp="NULL"])
+AC_DEFINE_UNQUOTED(DEFAULT_MAILADDRESS, _("${myrcp}") )
+
+
+AC_ARG_WITH(sender,
+ [ --with-sender=SENDER set sender for e-mail [[daemon]]],
+ [
+ mysender="${withval}"
+ ],
+ [
+ mysender="daemon"
+ ])
+AC_DEFINE_UNQUOTED(DEFAULT_SENDER, _("${mysender}") )
+
+
+dnl
+dnl PATHS
+dnl
+
+AC_ARG_WITH(trusted,
+ [ --with-trusted=UID Set uid(s) of trusted users [[0]]],
+ [
+ sh_tmp_test=no
+ sh_tmp=`echo ${withval} | sed 's%,% %g'`
+ for sh_tmp1 in ${sh_tmp}
+ do
+ echo "${sh_tmp1}" | grep ['[^0123456789]'] >/dev/null 2>&1 &&
+ AC_MSG_ERROR([Option --with-trusted=UID used with non-numeric UID in ${withval}.])
+ if test "x${sh_tmp1}" = "x0"
+ then
+ sh_tmp_test=yes
+ fi
+ done
+ if test "x${sh_tmp_test}" = "xno"
+ then
+ withval="0,${withval}"
+ fi
+ mytrust="${withval}"
+ ],
+ [mytrust="0"] )
+AC_DEFINE_UNQUOTED(SL_ALWAYS_TRUSTED, ${mytrust} )
+AC_SUBST(mytrust)
+
+mytmpdir=
+
+AC_ARG_WITH(tmp-dir,
+ [ --with-tmp-dir=PFX set directory for temporary files [[HOME]]],
+ [
+ if test "x${cross_compiling}" = xyes; then
+ mytmpdir="$withval"
+ AC_DEFINE_UNQUOTED(SH_TMPDIR, _("${mytmpdir}") )
+ else
+ if test -d "${withval}"; then
+ mytmpdir="$withval"
+ AC_DEFINE_UNQUOTED(SH_TMPDIR, _("${mytmpdir}") )
+ else
+ mytmpdir="$withval"
+ AC_DEFINE_UNQUOTED(SH_TMPDIR, _("${mytmpdir}") )
+ AC_MSG_WARN([--with-tmp-dir: tmp directory ${withval} does not exist])
+ fi
+ fi
+ ]
+)
+
+AC_SUBST(mytmpdir)
+
+
+dnl
+dnl PATH DEFAULTS
+dnl
+
+if test "x${ac_prefix_set}" = xyes
+then
+ if test "x${exec_prefix}" = xNONE
+ then
+ exec_prefix="${prefix}"
+ fi
+
+ if test "x${prefix}" = xOPT
+ then
+ tmp_sbindir="/opt/${install_name}/bin"
+ tmp_sysconfdir="/etc/opt"
+ tmp_mandir="/opt/${install_name}/man"
+ tmp_localstatedir="/var/opt/${install_name}"
+ elif test "x${prefix}" = xUSR
+ then
+ tmp_sbindir="/usr/sbin"
+ tmp_sysconfdir="/etc"
+ tmp_mandir="/usr/share/man"
+ tmp_localstatedir="/var"
+ else
+ tmp_sbindir=`eval echo ${sbindir}`
+ tmp_sysconfdir=`eval echo ${sysconfdir}`
+ tmp_mandir=`eval echo ${mandir}`
+ tmp_localstatedir=`eval echo ${localstatedir}`
+ fi
+else
+ prefix=""
+ if test "x${ac_exec_prefix_set}" = xyes
+ then
+ tmp_sbindir=`eval echo ${sbindir}`
+ else
+ tmp_sbindir="/usr/local/sbin"
+ fi
+ tmp_sysconfdir="/etc"
+ # share/man -> man (FHS) 11.10.2002
+ tmp_mandir="/usr/local/man"
+ tmp_localstatedir="/var"
+fi
+
+
+if test "x${ac_sbindir_set}" = xyes
+then
+ :
+else
+ sbindir=`eval echo ${tmp_sbindir}`
+fi
+
+
+if test "x${ac_sysconfdir_set}" = xyes
+then
+ :
+else
+ sysconfdir=`eval echo ${tmp_sysconfdir}`
+fi
+
+if test "x${ac_mandir_set}" = xyes
+then
+ :
+else
+ mandir=`eval echo ${tmp_mandir}`
+fi
+
+if test "x${ac_localstatedir_set}" = xyes
+then
+ :
+else
+ localstatedir=`eval echo ${tmp_localstatedir}`
+fi
+
+
+
+AC_ARG_WITH(config-file,
+ [ --with-config-file=FILE configuration file [[/etc/{install_name}rc]]],
+ [
+ myconffile="${withval}"
+ changequote(<<, >>)dnl
+ tmp=`echo ${withval} | sed 's%^REQ_FROM_SERVER%%'`
+ sysconfdir=`echo ${tmp} | sed 's%/[^/][^/]*$%%'`
+ myrpmconffile="${tmp}"
+ changequote([, ])dnl
+ ],
+ [
+ myconffile="${sysconfdir}/${install_name}rc"
+ myrpmconffile="${myconffile}"
+ ]
+)
+AC_DEFINE_UNQUOTED(DEFAULT_CONFIGFILE, _("${myconffile}") )
+AC_SUBST(myconffile)
+AC_SUBST(myrpmconffile)
+
+AC_ARG_WITH(log-file,
+ [ --with-log-file=FILE path of log file [[/var/log/{install_name}_log]]],
+ [
+ mylogfile="$withval"
+ changequote(<<, >>)dnl
+ mylogdir=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+ changequote([, ])dnl
+ ],
+ [
+ if test "x${mytclient}" = "x-DSH_WITH_SERVER"; then
+ mylogfile="${localstatedir}/log/${install_name}/${install_name}_log"
+ mylogdir="${localstatedir}/log/${install_name}"
+ else
+ mylogfile="${localstatedir}/log/${install_name}_log"
+ mylogdir="${localstatedir}/log"
+ fi
+ ]
+)
+AC_DEFINE_UNQUOTED(DEFAULT_ERRFILE, _("${mylogfile}") )
+AC_DEFINE_UNQUOTED(DEFAULT_LOGDIR, _("${mylogdir}") )
+AC_SUBST(mylogfile)
+AC_SUBST(mylogdir)
+
+AC_ARG_WITH(pid-file,
+ [ --with-pid-file=FILE set path of pid file [[/var/run/{install_name}.pid]]],
+ [
+ mylockfile="$withval"
+ changequote(<<, >>)dnl
+ mylockdir=`echo ${withval} | sed 's%/[^/][^/]*$%%'`
+ changequote([, ])dnl
+ ],
+ [
+ if test -h /var/run && test -d /run; then
+ mylockfile="/run/${install_name}.pid"
+ mylockdir="/run"
+ else
+ mylockfile="${localstatedir}/run/${install_name}.pid"
+ mylockdir="${localstatedir}/run"
+ fi
+ ]
+)
+AC_DEFINE_UNQUOTED(DEFAULT_ERRLOCK, _("${mylockfile}") )
+AC_DEFINE_UNQUOTED(DEFAULT_PIDDIR, _("${mylockdir}") )
+AC_SUBST(mylockfile)
+AC_SUBST(mylockdir)
+
+AC_ARG_WITH(state-dir,
+ [ --with-state-dir=PFX set state data directory [[/var/lib/{install_name}]]],
+ [
+ mydataroot="$withval"
+ ],
+ [
+ mydataroot="${localstatedir}/lib/${install_name}"
+ ]
+ )
+AC_ARG_WITH(data-file,
+ [ --with-data-file=FILE set path of data file],
+ [
+ mydatafile="$withval"
+ changequote(<<, >>)dnl
+ tmp=`echo ${withval} | sed 's%^REQ_FROM_SERVER%%'`
+ mydataroot=`echo ${tmp} | sed 's%/[^/][^/]*$%%'`
+ myrpmdatafile="${tmp}"
+ changequote([, ])dnl
+ if test x"${tmp}" = x
+ then
+ echo "No local path in data file ${withval}"
+ echo "This will not work for initializing the database."
+ if test x"${withval}" = xREQ_FROM_SERVER
+ then
+ echo "It should be REQ_FROM_SERVER/some/local/path"
+ fi
+ AC_MSG_ERROR([Option --with-data-file=FILE used with invalid path ${withval}.])
+ fi
+ ],
+ [
+ mydatafile="${mydataroot}/${install_name}_file"
+ myrpmdatafile="${mydatafile}"
+ ])
+AC_DEFINE_UNQUOTED(DEFAULT_DATA_FILE, _("${mydatafile}") )
+AC_SUBST(mydatafile)
+AC_SUBST(myrpmdatafile)
+
+AC_DEFINE_UNQUOTED(DEFAULT_DATAROOT, _("${mydataroot}") )
+AC_SUBST(mydataroot)
+
+AC_DEFINE_UNQUOTED(DEFAULT_QDIR, _("${mydataroot}/.quarantine") )
+AC_SUBST(myqdir)
+
+
+AC_ARG_WITH(html-file,
+ [ --with-html-file=FILE set path of html file,],
+ [
+ myhtmlfile="$withval"
+ ],
+ [
+ myhtmlfile="${mylogdir}/${install_name}.html"
+ ])
+AC_DEFINE_UNQUOTED(DEFAULT_HTML_FILE, _("${myhtmlfile}") )
+AC_SUBST(myhtmlfile)
+
+
+mydefargs=$ac_configure_args
+# if test -z "`echo "$mydefargs" | grep "\-\-enable\-static" 2> /dev/null`"
+# then
+# mydefargs="--enable-static $mydefargs"
+# fi
+if test -z "`echo "$mydefargs" | grep "\-\-enable\-base" 2> /dev/null`"
+then
+ mydefargs="--enable-base=${mykeybase} $mydefargs"
+fi
+AC_SUBST(mydefargs)
+
+
+AC_DEFINE_UNQUOTED(SH_INSTALL_DIR, _("${sbindir}"))
+AC_DEFINE_UNQUOTED(SH_INSTALL_PATH, _("${sbindir}/${install_name}"))
+AC_DEFINE_UNQUOTED(SH_INSTALL_NAME, _("${install_name}"))
+
+AC_CONFIG_HEADER(config.h)
+
+AC_OUTPUT(
+[
+Makefile
+samhain-install.sh
+init/samhain.startLSB
+init/samhain.startLinux
+init/samhain.startGentoo
+init/samhain.startFreeBSD
+init/samhain.startSolaris
+init/samhain.startHPUX
+init/samhain.startIRIX
+init/samhain.startMACOSX
+samhain.spec
+rules.deb
+rules.deb-light
+hp_ux.psf
+scripts/logrotate
+scripts/samhain.spec
+scripts/redhat_i386.client.spec
+scripts/samhain.ebuild
+scripts/samhain.ebuild-light
+scripts/samhainadmin.pl
+scripts/yuleadmin.pl
+scripts/check_samhain.pl
+deploy.sh
+],
+[
+echo timestamp > stamp-h
+chmod +x samhain-install.sh
+chmod +x scripts/samhainadmin.pl
+chmod +x scripts/yuleadmin.pl
+chmod +x scripts/check_samhain.pl
+]
+)
+
+chmod +x deploy.sh
+
+if test "x${cross_compiling}" = xyes
+then
+
+echo "--------------------------------------------------------------"
+echo
+echo "You are using a cross-compiler. The following system dependent"
+echo "values may have been set to default values that may be"
+echo "incorrect for your target system: "
+echo
+echo "ac_cv_c_bigendian bigendian byte order ${ac_cv_c_bigendian}"
+echo "ac_cv_c_long_double long double exists ${ac_cv_c_long_double}"
+echo "ac_cv_sizeof_char_p size of pointer to char ${ac_cv_sizeof_char_p}"
+echo "ac_cv_sizeof_char_p size of size_t ${ac_cv_sizeof_size_t}"
+echo "ac_cv_sizeof_unsigned_int size of unsigned int ${ac_cv_sizeof_unsigned_int}"
+echo "ac_cv_sizeof_unsigned_long size of unsigned long ${ac_cv_sizeof_unsigned_long}"
+echo "ac_cv_sizeof_unsigned_short size of unsigned short ${ac_cv_sizeof_unsigned_short}"
+echo
+echo "If these values are incorrect, change them in the file "
+echo "config.cache and run configure again."
+echo
+echo "--------------------------------------------------------------"
+
+fi
+
+if test x${silent} != xyes
+then
+
+ # A=`eval echo ${sbindir}` ; A=`eval echo ${A}`
+ # B=`eval echo ${myconffile}` ; B=`eval echo ${B}`
+ # C=`eval echo ${mandir}` ; C=`eval echo ${C}`
+ # D=`eval echo ${mylockfile}` ; D=`eval echo ${D}`
+ # E=`eval echo ${mylogfile}` ; E=`eval echo ${E}`
+ # F=`eval echo ${mydataroot}` ; F=`eval echo ${F}`
+
+ echo
+ echo " samhain has been configured as follows:"
+ echo " System binaries: ${sbindir}"
+ echo " Configuration file: ${myconffile}"
+ echo " Manual pages: ${mandir}"
+ echo " Data directory: ${mydataroot}"
+ echo " Database file: ${mydatafile}"
+ echo " PID file: ${mylockfile}"
+ echo " Log file: ${mylogfile}"
+ echo " Base key: ${mykeybase}"
+ if test x"$mykeyid" != x
+ then
+ echo " target GPG/PGP key: ${mykeyid}"
+ fi
+ echo
+ if test x"$mytclient" = x"-DSH_WITH_SERVER"
+ then
+ echo " Selected rc file: yulerc"
+ else
+ echo " Selected rc file: samhainrc.${selectconfig}"
+ fi
+
+fi
+
diff --git a/depend.dep b/depend.dep
new file mode 100644
index 0000000..4165e81
--- /dev/null
+++ b/depend.dep
@@ -0,0 +1,101 @@
+
+# DO NOT DELETE THIS LINE
+samhain.o: $(srcsrc)/samhain.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_getopt.h $(srcinc)/sh_readconf.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_restrict.h $(srcinc)/sh_nmail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_mem.h $(srcinc)/sh_xfer.h $(srcinc)/sh_tools.h $(srcinc)/sh_hash.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h $(srcinc)/sh_ignore.h $(srcinc)/sh_prelink.h $(srcinc)/sh_sem.h sh_MK.h $(srcinc)/sh_schedule.h
+sh_unix.o: $(srcsrc)/sh_unix.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_hash.h $(srcinc)/sh_tools.h $(srcinc)/sh_restrict.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_tiger.h $(srcinc)/sh_prelink.h $(srcinc)/sh_pthread.h $(srcinc)/sh_sem.h $(srcinc)/sh_static.h $(srcinc)/sh_prelude.h $(srcinc)/zAVLTree.h $(srcinc)/sh_ignore.h
+sh_utils.o: $(srcsrc)/sh_utils.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_entropy.h $(srcinc)/sh_pthread.h
+sh_error.o: $(srcsrc)/sh_error.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_database.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_nmail.h $(srcinc)/sh_xfer.h $(srcinc)/sh_prelude.h $(srcinc)/sh_pthread.h $(srcinc)/sh_tools.h $(srcinc)/sh_extern.h $(srcinc)/sh_checksum.h
+sh_files.o: $(srcsrc)/sh_files.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_tiger.h $(srcinc)/sh_hash.h $(srcinc)/sh_ignore.h $(srcinc)/sh_inotify.h $(srcinc)/zAVLTree.h $(srcinc)/sh_dbIO.h $(srcinc)/CuTest.h
+sh_getopt.o: $(srcsrc)/sh_getopt.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_getopt.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_utils.h $(srcinc)/sh_mail.h $(srcinc)/sh_xfer.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_dbCheck.h $(srcinc)/sh_dbCreate.h $(srcinc)/sh_sem.h $(srcinc)/sh_extern.h
+sh_readconf.o: $(srcsrc)/sh_readconf.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_calls.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_xfer.h $(srcinc)/sh_gpg.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_ignore.h $(srcinc)/sh_database.h $(srcinc)/sh_mail.h $(srcinc)/sh_modules.h $(srcinc)/sh_nmail.h $(srcinc)/sh_prelink.h $(srcinc)/sh_prelude.h $(srcinc)/sh_tiger.h $(srcinc)/sh_tools.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h $(srcinc)/sh_socket.h
+sh_tiger0.o: $(srcsrc)/sh_tiger0.c Makefile config_xor.h $(srcinc)/sh_tiger.h $(srcinc)/sh_unix.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h $(srcinc)/sh_checksum.h
+sh_tiger1.o: $(srcsrc)/sh_tiger1.c Makefile config_xor.h
+sh_tiger2.o: $(srcsrc)/sh_tiger2.c Makefile config_xor.h
+sh_tiger1_64.o: $(srcsrc)/sh_tiger1_64.c Makefile config_xor.h
+sh_tiger2_64.o: $(srcsrc)/sh_tiger2_64.c Makefile config_xor.h
+sh_hash.o: $(srcsrc)/sh_hash.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_hash.h $(srcinc)/sh_error.h $(srcinc)/sh_tiger.h $(srcinc)/sh_gpg.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_ignore.h $(srcinc)/sh_pthread.h $(srcinc)/sh_xfer.h $(srcinc)/sh_hash.h $(srcinc)/sh_checksum.h
+sh_mail.o: $(srcsrc)/sh_mail.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_mail.h $(srcinc)/sh_utils.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_pthread.h $(srcinc)/sh_filter.h $(srcinc)/sh_mail_int.h $(srcinc)/sh_nmail.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_static.h $(srcinc)/sh_tools.h
+sh_mem.o: $(srcsrc)/sh_mem.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_pthread.h
+sh_entropy.o: $(srcsrc)/sh_entropy.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_calls.h $(srcinc)/sh_pthread.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/CuTest.h
+sh_forward.o: $(srcsrc)/sh_forward.c Makefile config_xor.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_forward.h $(srcinc)/sh_srp.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_entropy.h $(srcinc)/sh_html.h $(srcinc)/sh_nmail.h $(srcinc)/sh_socket.h $(srcinc)/sh_static.h $(srcinc)/rijndael-api-fst.h $(srcinc)/sh_readconf.h $(srcinc)/zAVLTree.h $(srcinc)/sh_extern.h
+sh_modules.o: $(srcsrc)/sh_modules.c Makefile config_xor.h $(srcinc)/sh_modules.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utmp.h $(srcinc)/sh_mounts.h $(srcinc)/sh_userfiles.h $(srcinc)/sh_suidchk.h $(srcinc)/sh_processcheck.h $(srcinc)/sh_portcheck.h $(srcinc)/sh_logmon.h $(srcinc)/sh_registry.h $(srcinc)/sh_fInotify.h
+sh_utmp.o: $(srcsrc)/sh_utmp.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_utmp.h $(srcinc)/sh_pthread.h $(srcinc)/sh_inotify.h
+sh_kern.o: $(srcsrc)/sh_kern.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_kern.h sh_ks_xor.h $(srcinc)/sh_unix.h $(srcinc)/sh_hash.h
+sh_suidchk.o: $(srcsrc)/sh_suidchk.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_suidchk.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_unix.h $(srcinc)/sh_files.h $(srcinc)/sh_schedule.h $(srcinc)/sh_calls.h $(srcinc)/zAVLTree.h
+sh_srp.o: $(srcsrc)/sh_srp.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_mem.h $(srcinc)/sh_utils.h $(srcinc)/sh_srp.h $(srcinc)/bignum.h $(srcinc)/CuTest.h
+sh_fifo.o: $(srcsrc)/sh_fifo.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_fifo.h $(srcinc)/CuTest.h
+sh_tools.o: $(srcsrc)/sh_tools.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error.h $(srcinc)/sh_tools.h $(srcinc)/sh_utils.h $(srcinc)/sh_tiger.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_ipvx.h $(srcinc)/rijndael-api-fst.h $(srcinc)/rijndael-api-fst.h
+sh_html.o: $(srcsrc)/sh_html.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_xfer.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_html.h $(srcinc)/zAVLTree.h
+sh_gpg.o: $(srcsrc)/sh_gpg.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_tiger.h $(srcinc)/sh_static.h $(srcinc)/sh_gpg.h
+sh_cat.o: $(srcsrc)/sh_cat.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_cat.h
+sh_calls.o: $(srcsrc)/sh_calls.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_calls.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_sub.h $(srcinc)/sh_utils.h
+sh_extern.o: $(srcsrc)/sh_extern.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_tiger.h $(srcinc)/sh_extern.h $(srcinc)/sh_calls.h $(srcinc)/sh_filter.h $(srcinc)/sh_static.h
+sh_database.o: $(srcsrc)/sh_database.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h
+sh_err_log.o: $(srcsrc)/sh_err_log.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_tiger.h
+sh_err_console.o: $(srcsrc)/sh_err_console.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_utils.h $(srcinc)/sh_sem.h
+sh_err_syslog.o: $(srcsrc)/sh_err_syslog.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h
+sh_schedule.o: $(srcsrc)/sh_schedule.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_schedule.h
+bignum.o: $(srcsrc)/bignum.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/bignum.h
+mkhdr.o: $(srcsrc)/mkhdr.c Makefile config.h
+samhain_setpwd.o: $(srcsrc)/samhain_setpwd.c Makefile config_xor.h
+samhain_stealth.o: $(srcsrc)/samhain_stealth.c Makefile config_xor.h
+encode.o: $(srcsrc)/encode.c Makefile
+sstrip.o: $(srcsrc)/sstrip.c Makefile config.h
+trustfile.o: $(srcsrc)/trustfile.c Makefile config_xor.h $(srcinc)/sh_calls.h $(srcinc)/slib.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h
+exepack.o: $(srcsrc)/exepack.c Makefile config.h $(srcinc)/minilzo.h $(srcinc)/exepack.data
+exepack_fill.o: $(srcsrc)/exepack_fill.c Makefile config.h config.h $(srcinc)/minilzo.h
+exepack_mkdata.o: $(srcsrc)/exepack_mkdata.c Makefile config.h $(srcinc)/minilzo.h
+minilzo.o: $(srcsrc)/minilzo.c Makefile $(srcinc)/minilzo.h
+slib.o: $(srcsrc)/slib.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_calls.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_string.h $(srcinc)/sh_mem.h
+rijndael-alg-fst.o: $(srcsrc)/rijndael-alg-fst.c Makefile config_xor.h $(srcinc)/rijndael-alg-fst.h
+rijndael-api-fst.o: $(srcsrc)/rijndael-api-fst.c Makefile config_xor.h $(srcinc)/rijndael-api-fst.h
+zAVLTree.o: $(srcsrc)/zAVLTree.c Makefile $(srcinc)/zAVLTree.h
+sh_socket.o: $(srcsrc)/sh_socket.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_socket.h $(srcinc)/sh_error.h $(srcinc)/sh_unix.h $(srcinc)/sh_calls.h $(srcinc)/sh_guid.h $(srcinc)/sh_fifo.h $(srcinc)/sh_utils.h $(srcinc)/sh_utils.h $(srcinc)/zAVLTree.h $(srcinc)/sh_html.h $(srcinc)/sh_tools.h $(srcinc)/CuTest.h
+sh_ignore.o: $(srcsrc)/sh_ignore.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error.h $(srcinc)/CuTest.h
+yulectl.o: $(srcsrc)/yulectl.c Makefile config_xor.h
+sh_mounts.o: $(srcsrc)/sh_mounts.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_modules.h $(srcinc)/sh_mounts.h
+sh_userfiles.o: $(srcsrc)/sh_userfiles.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_modules.h $(srcinc)/sh_userfiles.h $(srcinc)/sh_utils.h $(srcinc)/sh_schedule.h $(srcinc)/sh_error.h $(srcinc)/sh_hash.h $(srcinc)/sh_files.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h
+sh_prelude.o: $(srcsrc)/sh_prelude.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_cat.h $(srcinc)/sh_error_min.h $(srcinc)/sh_prelude.h $(srcinc)/sh_static.h
+sh_prelink.o: $(srcsrc)/sh_prelink.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_extern.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h
+sh_static.o: $(srcsrc)/sh_static.c Makefile config_xor.h $(srcinc)/sh_pthread.h
+sh_portcheck.o: $(srcsrc)/sh_portcheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_mem.h $(srcinc)/sh_calls.h $(srcinc)/sh_utils.h $(srcinc)/sh_modules.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_ipvx.h $(srcinc)/CuTest.h
+sh_processcheck.o: $(srcsrc)/sh_processcheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_modules.h $(srcinc)/sh_processcheck.h $(srcinc)/sh_utils.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_calls.h $(srcinc)/sh_pthread.h $(srcinc)/CuTest.h
+sh_prelude_old.o: $(srcsrc)/sh_prelude_old.c Makefile config_xor.h $(srcinc)/slib.h $(srcinc)/sh_mem.h $(srcinc)/sh_cat.h $(srcinc)/sh_error_min.h $(srcinc)/sh_prelude.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h
+sh_pthread.o: $(srcsrc)/sh_pthread.c Makefile config_xor.h $(srcinc)/sh_pthread.h $(srcinc)/sh_calls.h $(srcinc)/sh_modules.h
+kern_head.o: $(srcsrc)/kern_head.c Makefile config.h $(srcinc)/kern_head.h $(srcinc)/kern_head.h
+sh_string.o: $(srcsrc)/sh_string.c Makefile config_xor.h $(srcinc)/sh_string.h $(srcinc)/sh_mem.h $(srcinc)/CuTest.h
+dnmalloc-1.0.beta5-rw.o: $(srcsrc)/dnmalloc-1.0.beta5-rw.c Makefile
+t-test1.o: $(srcsrc)/t-test1.c Makefile config.h $(srcinc)/malloc.h
+dnmalloc-portable.o: $(srcsrc)/dnmalloc-portable.c Makefile config.h
+dnmalloc.o: $(srcsrc)/dnmalloc.c Makefile config.h
+sh_port2proc.o: $(srcsrc)/sh_port2proc.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_error_min.h $(srcinc)/sh_pthread.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h
+sh_log_parse_syslog.o: $(srcsrc)/sh_log_parse_syslog.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h
+sh_log_parse_pacct.o: $(srcsrc)/sh_log_parse_pacct.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h
+sh_log_parse_apache.o: $(srcsrc)/sh_log_parse_apache.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h
+sh_log_evalrule.o: $(srcsrc)/sh_log_evalrule.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h $(srcinc)/sh_log_correlate.h $(srcinc)/sh_log_mark.h $(srcinc)/sh_log_repeat.h $(srcinc)/zAVLTree.h
+sh_log_check.o: $(srcsrc)/sh_log_check.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h $(srcinc)/sh_log_correlate.h $(srcinc)/sh_log_mark.h $(srcinc)/sh_log_repeat.h $(srcinc)/sh_extern.h $(srcinc)/sh_modules.h
+sh_log_parse_samba.o: $(srcsrc)/sh_log_parse_samba.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_log_check.h $(srcinc)/sh_string.h
+sh_nmail.o: $(srcsrc)/sh_nmail.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_mem.h $(srcinc)/sh_mail.h $(srcinc)/sh_tiger.h $(srcinc)/sh_string.h $(srcinc)/sh_utils.h $(srcinc)/sh_fifo.h $(srcinc)/sh_filter.h $(srcinc)/sh_mail_int.h $(srcinc)/zAVLTree.h
+sh_filter.o: $(srcsrc)/sh_filter.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_mem.h $(srcinc)/sh_filter.h
+sh_inotify.o: $(srcsrc)/sh_inotify.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_calls.h $(srcinc)/sh_inotify.h $(srcinc)/sh_mem.h $(srcinc)/sh_utils.h $(srcinc)/slib.h $(srcinc)/zAVLTree.h $(srcinc)/sh_calls.h $(srcinc)/sh_inotify.h $(srcinc)/CuTest.h
+sh_log_correlate.o: $(srcsrc)/sh_log_correlate.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h
+sh_log_mark.o: $(srcsrc)/sh_log_mark.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_mem.h $(srcinc)/sh_string.h $(srcinc)/sh_error_min.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h $(srcinc)/zAVLTree.h
+sh_log_repeat.o: $(srcsrc)/sh_log_repeat.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_string.h $(srcinc)/sh_log_check.h $(srcinc)/sh_log_evalrule.h
+sh_log_parse_generic.o: $(srcsrc)/sh_log_parse_generic.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_log_check.h $(srcinc)/sh_string.h
+sh_login_track.o: $(srcsrc)/sh_login_track.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_string.h $(srcinc)/sh_tools.h $(srcinc)/sh_ipvx.h $(srcinc)/sh_error_min.h $(srcinc)/CuTest.h $(srcinc)/CuTest.h
+sh_audit.o: $(srcsrc)/sh_audit.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_error.h $(srcinc)/sh_extern.h $(srcinc)/sh_utils.h
+sh_registry.o: $(srcsrc)/sh_registry.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_modules.h $(srcinc)/sh_hash.h $(srcinc)/sh_tiger.h
+sh_ipvx.o: $(srcsrc)/sh_ipvx.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_static.h $(srcinc)/sh_pthread.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h $(srcinc)/CuTest.h
+sh_restrict.o: $(srcsrc)/sh_restrict.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_string.h $(srcinc)/sh_utils.h $(srcinc)/sh_restrict.h $(srcinc)/CuTest.h
+sh_filetype.o: $(srcsrc)/sh_filetype.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_mem.h $(srcinc)/sh_error_min.h $(srcinc)/sh_utils.h
+sh_sub.o: $(srcsrc)/sh_sub.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_pthread.h
+sh_fInotify.o: $(srcsrc)/sh_fInotify.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_modules.h $(srcinc)/sh_pthread.h $(srcinc)/sh_inotify.h $(srcinc)/sh_unix.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_files.h $(srcinc)/sh_ignore.h
+sh_checksum.o: $(srcsrc)/sh_checksum.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_checksum.h $(srcinc)/sh_utils.h $(srcinc)/CuTest.h
+sh_guid.o: $(srcsrc)/sh_guid.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/CuTest.h
+sh_dbIO.o: $(srcsrc)/sh_dbIO.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_hash.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_gpg.h $(srcinc)/sh_tiger.h $(srcinc)/sh_xfer.h $(srcinc)/sh_pthread.h $(srcinc)/sh_socket.h $(srcinc)/sh_files.h $(srcinc)/zAVLTree.h
+sh_dbCheck.o: $(srcsrc)/sh_dbCheck.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_unix.h $(srcinc)/sh_utils.h $(srcinc)/sh_hash.h $(srcinc)/sh_files.h $(srcinc)/sh_tiger.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_pthread.h
+sh_dbCreate.o: $(srcsrc)/sh_dbCreate.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_hash.h $(srcinc)/sh_files.h $(srcinc)/sh_dbIO.h $(srcinc)/sh_dbIO_int.h $(srcinc)/sh_pthread.h $(srcinc)/sh_guid.h
+sh_xfer_client.o: $(srcsrc)/sh_xfer_client.c Makefile config_xor.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_xfer.h $(srcinc)/sh_srp.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_entropy.h $(srcinc)/sh_html.h $(srcinc)/sh_nmail.h $(srcinc)/sh_socket.h $(srcinc)/sh_static.h $(srcinc)/rijndael-api-fst.h
+sh_xfer_server.o: $(srcsrc)/sh_xfer_server.c Makefile config_xor.h $(srcinc)/sh_ipvx.h $(srcinc)/samhain.h $(srcinc)/sh_tiger.h $(srcinc)/sh_utils.h $(srcinc)/sh_unix.h $(srcinc)/sh_xfer.h $(srcinc)/sh_srp.h $(srcinc)/sh_fifo.h $(srcinc)/sh_tools.h $(srcinc)/sh_entropy.h $(srcinc)/sh_html.h $(srcinc)/sh_nmail.h $(srcinc)/sh_socket.h $(srcinc)/sh_static.h $(srcinc)/sh_guid.h $(srcinc)/rijndael-api-fst.h $(srcinc)/sh_readconf.h $(srcinc)/zAVLTree.h $(srcinc)/sh_extern.h
+sh_xfer_syslog.o: $(srcsrc)/sh_xfer_syslog.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_tools.h $(srcinc)/sh_utils.h $(srcinc)/sh_ipvx.h
+sh_xload_client.o: $(srcsrc)/sh_xload_client.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_utils.h $(srcinc)/sh_fifo.h $(srcinc)/sh_guid.h
+sh_sem.o: $(srcsrc)/sh_sem.c Makefile config_xor.h $(srcinc)/samhain.h $(srcinc)/sh_sem.h $(srcinc)/sh_error_min.h
diff --git a/depend.sum b/depend.sum
new file mode 100644
index 0000000..10ccfad
--- /dev/null
+++ b/depend.sum
@@ -0,0 +1 @@
+2959213307
diff --git a/deploy.sh.in b/deploy.sh.in
new file mode 100644
index 0000000..3b9c898
--- /dev/null
+++ b/deploy.sh.in
@@ -0,0 +1,1094 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#VERSION2.0
+
+# -----------------------------------------------------------------------
+# Be Bourne compatible
+# -----------------------------------------------------------------------
+
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# -----------------------------------------------------------------------
+# Make sure we support functions (from the autoconf manual)
+# -----------------------------------------------------------------------
+
+SHELL="${SHELL-/bin/sh}"
+if test x"$1" = "x--re-executed"
+then
+ shift
+elif "$SHELL" -c 'foo () { (exit 0); exit 0; }; foo' 2>/dev/null
+then
+ :
+else
+ for cmd in sh bash ash bsh ksh zsh sh5; do
+ X="$PATH:/bin:/usr/bin:/usr/afsws/bin:/usr/ucb";
+ OLD_IFS=${IFS}
+ IFS=':'; export IFS
+ for dir in $X; do
+ shell="$dir/$cmd"
+ if (test -f "$shell" || test -f "$shell.exe")
+ then
+ if "$shell" -c 'foo () { (exit 0); exit 0; }; foo' 2>/dev/null
+ then
+ SHELL="$shell"; export SHELL
+ IFS=${OLD_IFS}; export IFS
+ exec "$shell" "$0" --re-executed ${1+"$@"}
+ fi
+ fi
+ done
+ IFS=${OLD_IFS}; export IFS
+ done
+ echo "-----------------------------------------------------------------"
+ echo "ERROR: Unable to locate a shell interpreter with function support" >&2
+ echo "-----------------------------------------------------------------"
+ { (exit 1); exit 1; }
+fi
+
+# -----------------------------------------------------------------------
+# Test for 'echo -n'
+# -----------------------------------------------------------------------
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,* ) ECHO_N=-n ECHO_C= ;;
+ *) ECHO_N= ECHO_C='\c' ;;
+esac
+
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+#########################################################################
+#
+# Configuration section
+#
+#########################################################################
+
+# -----------------------------------------------------------------------
+# The following part will be cut and saved to ~/.deploy.conf
+# -----------------------------------------------------------------------
+
+#__BEGIN_CUT__
+
+#########################################################################
+#
+# This file is sourced by a Bourne shell script.
+# Thus you need to take care of proper shell syntax.
+#
+#########################################################################
+
+# if you need, you can expand your PATH environment variable here
+# just uncomment and replace /opt/contrib/bin with whatever you need
+#
+# PATH="/opt/contrib/bin:${PATH}"; export PATH
+
+# the base directory of the deployment system
+# CLI option: --basedir=...
+#
+defbasedir="@mydataroot@/profiles"
+
+# the name of the database of installed clients
+# no CLI option
+#
+defdatabase="yulerc.install.db"
+
+# be quiet; 0 = false, 1 = true, 2 = very quiet
+# CLI option: --quiet | --quiet=2
+#
+silent=0;
+
+# assume yes as answer to all prompts and run non-interactively
+# 0 = false, 1 = true
+# CLI option: --yes
+#
+assumeyes=0;
+
+# which 'dialog' to use (e.g. "Xdialog")
+# "no" for plain text; empty ("") lets the program search for dialog
+# CLI option: --dialog=...
+#
+prefdialog=""
+
+# operating system; no default
+# CLI option: --arch=...
+#
+arch=""
+
+# Format for binary packages (run | deb | rpm | tbz2 | solaris-pkg | depot)
+# CLI option: --format=...
+#
+format=""
+
+# logfile; default is none
+# CLI option: --logfile=...
+#
+logfile=""
+
+# The path to the yule (samhain server) executable.
+# CLI option: --yule_exec=...
+#
+yule_exec="@sbindir@/yule"
+
+# The path to the yule (samhain server) configuration file.
+# CLI option: --yule_conf=...
+#
+yule_conf="@sysconfdir@/yulerc"
+
+# The path to the data directory of yule (samhain server).
+# This is the directory where client configuration/database files
+# are stored.
+# CLI option: --yule_data=...
+#
+yule_data="@mydataroot@"
+
+# The temporary directory to use. Default is '/tmp', but some
+# sites may mount this 'noexec'.
+#
+temp_dir="/tmp"
+
+#__END_CUT__
+
+# -----------------------------------------------------------------------
+# Write configuration file to user home directory/Read configuration file
+# -----------------------------------------------------------------------
+
+if test -f ~/.deploy.conf
+then
+ . ~/.deploy.conf
+else
+ #
+ # From the autoconf configure script - search ourselves
+ #
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) old_IFS=$IFS; IFS=:
+ for as_dir in $PATH
+ do
+ IFS=$old_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "ERROR: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ cat "$as_myself" | sed -n -e '/^#__BEGIN_CUT__/,/^#__END_CUT__/ p ' >~/.deploy.conf && {
+ echo
+ echo "-----------------------------------------------------"
+ echo " Configuration file ~/.deploy.conf created"
+ echo " You may want to edit it to adapt it to your needs"
+ echo "-----------------------------------------------------"
+ echo
+ }
+fi
+
+export silent
+export assumeyes
+export arch
+export logfile
+export format
+export yule_exec
+export yule_conf
+export yule_data
+export temp_dir
+
+# dialog
+#
+DIALOG="${prefdialog}";
+export DIALOG
+
+# base directory
+#
+basedir="$defbasedir";
+export basedir
+
+# simulate only; 0 = false, 1 = true
+#
+simulate=0;
+export simulate
+
+# version
+#
+version=2.0;
+export version
+
+# host; no default
+#
+host=
+export host
+
+# hostgroup; empty default
+#
+hostgroup=
+export hostgroup
+
+
+# action; no default
+#
+action=
+export action
+
+# the 'log.lastrun' logfile
+#
+logOpen=0
+export logOpen
+
+
+# source version; default = current
+#
+src_version=""
+export src_version
+
+# checksrc; do you want to delete if PGP signature check fails ?
+#
+cs_delete=0
+export cs_delete
+
+# build; do you want to pack the executable ?
+#
+bd_packed=''
+export bd_packed
+
+bd_user='root'
+export bd_user
+
+# addpath
+#
+bd_addpath=""
+export bd_addpath
+
+# Install; do you want to initialize the database ?
+#
+is_init=y
+export is_init
+
+# Install; do you want to replace the rc.host file ?
+#
+is_rcfile=y
+export is_rcfile
+
+# Install; do you want to start the client ?
+#
+is_startup=y
+export is_startup
+
+# Install; optional local command ?
+#
+local_command=""; export local_command
+
+# Info on packages ?
+#
+showpkg=n
+export showpkg
+
+#########################################################################
+#
+# Help Subroutines
+#
+#########################################################################
+
+# -----------------------------------------------------------------------
+# We cannot source these, because we don't know yet the base directory
+# -----------------------------------------------------------------------
+
+showUNINSTALL() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] uninstall"
+ echo
+ echo "Uninstall the samhain client from the specified host. Can only be"
+ echo "used if the client has been installed with deploy.sh version 2."
+ echo
+ echo "Options:"
+ echo
+ echo " --host=<hostname> The host where you want to uninstall."
+ echo " --tmpdir=<path> Temporary directory to use on the this host."
+ echo
+ { (exit 0); exit 0; }
+}
+
+showINFO() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] info"
+ echo
+ echo "Show info for hosts in client database (default), or for available"
+ echo "binary installer packages."
+ echo
+ echo "Options:"
+ echo
+ echo " --packages Show info on packages."
+ echo
+ { (exit 0); exit 0; }
+}
+
+showCLEAN() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] clean"
+ echo
+ echo "Remove all files that are no longer needed:"
+ echo " - Source tarballs in ${basedir}/source"
+ echo " - Unused installer packages in ${basedir}/archpkg"
+ echo
+ { (exit 0); exit 0; }
+}
+
+showCHECKSRC() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] checksrc"
+ echo
+ echo "Check PGP signatures of source tarballs in the source/ subdirectory"
+ echo "of the deploy system."
+ echo "You must have gpg (GnuPG) in your PATH, and you should have imported"
+ echo "the samhain release PGP key (Key ID 0F571F6C, Rainer Wichmann)."
+ echo "To import the key, simply execute the command"
+ echo "\"gpg --keyserver blackhole.pca.dfn.de --recv-keys 0F571F6C\""
+ echo
+ echo "Options:"
+ echo
+ echo " --delete Delete source tarballs if PGP signature"
+ echo " cannot be verified."
+ echo
+ { (exit 0); exit 0; }
+}
+
+showDOWNLOAD() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] download"
+ echo
+ echo "Download a samhain source tarball from http://www.la-samhna.de,"
+ echo "check its PGP signature, and install it into the source/ subdirectory"
+ echo "of the deploy system."
+ echo "You must have gpg (GnuPG) in your PATH, and you should have imported"
+ echo "the samhain release PGP key (Key ID 0F571F6C, Rainer Wichmann)."
+ echo "To import the key, simply execute the command"
+ echo "\"gpg --keyserver blackhole.pca.dfn.de --recv-keys 0F571F6C\""
+ echo
+ echo "Options:"
+ echo
+ echo " --version=<version> Version of samhain to download. The"
+ echo " default is \"current\" to download the current version."
+ echo
+ { (exit 0); exit 0; }
+}
+
+showBUILD() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] build"
+ echo
+ echo "Copy a source tarball to a build machine, build a binary package, and fetch"
+ echo "the package. Will bail out if not running under ssh-agent. If you are sure"
+ echo "that you don't need ssh-agent, set the environment variable SSH_AGENT_PID"
+ echo "to some arbitrary string before launching the deploy.sh command."
+ echo
+ echo "Options:"
+ echo
+ echo " --host=<hostname> The build host."
+ echo " --arch=<arch> The architecture/operating system to build for."
+ echo " This is used to get the \"./configure\" options from the file"
+ echo " \${basedir}/configs/\${arch}.configure."
+ echo " --version=<version> The version of samhain you want to build."
+ echo " --format=<run|rpm|deb|tbz2|solaris-pkg|depot>"
+ echo " The format of the package. \"run\" is a portable tar"
+ echo " package, \"deb\" is for Debian, \"tbz2\" for Gentoo,"
+ echo " \"rpm\" for any RPM-based Linux, \"solaris-pkg\""
+ echo " for Sun Solaris, and \"depot\" for HP-UX"
+ echo " --packed=<password> The client password, if you want to"
+ echo " create a packed executable. Defaults to empty (don't pack)"
+ echo " --user=<username> Login as <username> to the build host (root)."
+ echo " --add-path=<path> Append 'path' to the PATH variable on the build host."
+ echo " --tmpdir=<path> Temporary directory to use on the build host."
+ { (exit 0); exit 0; }
+}
+
+showINSTALL() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] install"
+ echo
+ echo "Copy a pre-built binary installer package to a remote host, stop the client"
+ echo "running there (if any), install the (new) client, optionally initialize"
+ echo "the file signature database and fetch it from the remote host, update"
+ echo "the server configuration file and reload the server."
+ echo
+ echo "Options:"
+ echo
+ echo " --host=<FQDN> The host where you want to install."
+ echo " --group=<group> Optional group the host belongs to."
+ echo " --arch=<arch> The architecture/operating system of this host."
+ echo " This is used to get the correct binary package."
+ echo " --version=<version> The version of samhain you want to install."
+ echo " --format=<run|rpm|deb|tbz2|solaris-pkg|depot>"
+ echo " The format of the binary package."
+ echo " --yule_exec=<path> The path to the 'yule' executable."
+ echo " --yule_conf=<path> The path to the 'yule' configuration file."
+ echo " --yule_data=<path> The path to the 'yule' data directory."
+ echo " --no-init Do not initialize the file signature database."
+ echo " --no-rcfile Do not replace the rc.host file on server."
+ echo " --no-start Do not start the client after installation."
+ echo " --local=<path> Local command (executed twice: "
+ echo " after config installation and before client startup)."
+ echo " --tmpdir=<path> Temporary directory to use on the this host."
+ { (exit 0); exit 0; }
+}
+
+showUSAGE() {
+ echo "deploy.sh $version"
+ echo "USAGE: deploy.sh [options] command"
+ echo
+ echo "Commands: info | clean | download | checksrc | build | install | uninstall"
+ echo
+ echo "Options:"
+ echo " -h | --help Print general usage information."
+ echo " -h | --help <command> Print usage information for \"command\"."
+ echo " --basedir=<directory> Set the basedir for the deployment system."
+ echo " The default is ${defbasedir}."
+ echo " -q | --quiet Produce output suitable for logging."
+ echo " You can also use -q=# to set the quiet level up to"
+ echo " a maximum of 2. Note that -q=2 implies --yes (see below)."
+ echo " -s | --simulate Perform a simulation of events that"
+ echo " would occur but do not actually change the system."
+ echo " -y | --yes Assume "yes" as answer to"
+ echo " all prompts and run non-interactively."
+ echo " -o <file> | --logfile=<file>"
+ echo " Specify an output file for messages that would go to stdout"
+ echo " otherwise. Has no effect on stderr (error messages)."
+ echo " -d <dialog> | --dialog=<dialog> Specify your preferred \"dialog\""
+ echo " clone (e.g. Xdialog). Use \"no\" to force plain text."
+ if test x"$1" = x
+ then
+ { (exit 0); exit 0; }
+ else
+ { (exit $1); exit $1; }
+ fi
+}
+
+#########################################################################
+#
+# Command line
+#
+#########################################################################
+
+for option
+do
+
+ # If the previous option needs an argument, assign it.
+ #
+ if test -n "$opt_prev"; then
+ eval "$opt_prev=\$option"
+ eval export "$opt_prev"
+ opt_prev=
+ continue
+ fi
+
+ case "$option" in
+ -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case "$option" in
+
+ # Info
+
+ --packages | -packages)
+ showpkg=y; export showpkg;
+ ;;
+
+ # Install
+
+ --yule_exec | -yule_exec | --yule-exec | -yule-exec)
+ opt_prev=yule_exec
+ ;;
+
+ --yule_exec=* | -yule_exec=* | --yule-exec=* | -yule-exec=*)
+ yule_exec="$optarg"; export yule_exec
+ ;;
+
+ --yule_conf | -yule_conf | --yule-conf | -yule-conf)
+ opt_prev=yule_conf
+ ;;
+
+ --yule_conf=* | -yule_conf=* | --yule-conf=* | -yule-conf=*)
+ yule_conf="$optarg"; export yule_conf
+ ;;
+
+ --yule_data | -yule_data | --yule-data | -yule-data)
+ opt_prev=yule_data
+ ;;
+
+ --yule_data=* | -yule_data=* | --yule-data=* | -yule-data=*)
+ yule_data="$optarg"; export yule_data
+ ;;
+
+ --no-init | -no-init)
+ is_init=n; export is_init
+ ;;
+
+ --no-rcfile | -no-rcfile)
+ is_rcfile=n; export is_rcfile
+ ;;
+
+ --no-start | -no-start)
+ is_startup=n; export is_startup
+ ;;
+
+ --local | -local)
+ opt_prev=local_command
+ ;;
+
+ --local=* | -local=*)
+ local_command="$optarg"; export local_command
+ ;;
+
+ --group | -group)
+ opt_prev=hostgroup
+ ;;
+
+ --group=* | -group=*)
+ hostgroup="$optarg"; export hostgroup
+ ;;
+
+ # Build
+
+ --format | -format)
+ opt_prev=format
+ ;;
+
+ --format=* | -format=*)
+ format="$optarg"; export format
+ ;;
+
+ --packed | --pack | -packed | -pack)
+ opt_prev=bd_packed
+ ;;
+
+ --packed=* | -packed=*)
+ bd_packed="$optarg"; export bd_packed
+ ;;
+
+ --user | -user)
+ opt_prev=bd_user
+ ;;
+
+ --user=* | -user=*)
+ bd_user="$optarg"; export bd_user
+ ;;
+
+ --add-path | -add-path | --addpath | -addpath)
+ opt_prev=bd_addpath
+ ;;
+
+ --add-path=* | -add-path=* | --addpath=* | -addpath=*)
+ bd_addpath="$optarg"; export bd_addpath
+ ;;
+
+ # Checksource
+
+ --delete | -delete)
+ cs_delete=1; export cs_delete
+ ;;
+
+ # Download
+
+ --version | -version)
+ opt_prev=src_version
+ ;;
+ --version=* | -version=*)
+ src_version="$optarg"; export src_version
+ ;;
+
+ # Generic
+
+ --basedir | -basedir)
+ opt_prev=basedir
+ ;;
+ --basedir=* | -basedir=*)
+ basedir="$optarg"; export basedir
+ ;;
+
+ --host | -host)
+ opt_prev=host
+ ;;
+ --host=* | -host=*)
+ host="$optarg"; export host
+ ;;
+
+ --arch | -arch)
+ opt_prev=arch
+ ;;
+ --arch=* | -arch=*)
+ arch="$optarg"; export arch
+ ;;
+
+ --tmpdir | -tmpdir)
+ opt_prev=temp_dir
+ ;;
+ --tmpdir=* | -tmpdir=*)
+ temp_dir="$optarg"; export temp_dir
+ ;;
+
+ -o | --logfile | -logfile)
+ opt_prev=logfile
+ ;;
+ -o=* | --logfile=* | -logfile=*)
+ logfile="$optarg"; export logfile
+ ;;
+
+ -h | --h | --help | -help | help)
+ if test $# -gt 1
+ then
+ if test x"$2" = xdownload
+ then
+ showDOWNLOAD
+ elif test x"$2" = xinfo
+ then
+ showINFO
+ elif test x"$2" = xchecksrc
+ then
+ showCHECKSRC
+ elif test x"$2" = xclean
+ then
+ showCLEAN
+ elif test x"$2" = xbuild
+ then
+ showBUILD
+ elif test x"$2" = xinstall
+ then
+ showINSTALL
+ elif test x"$2" = xuninstall
+ then
+ showUNINSTALL
+ else
+ showUSAGE 1
+ fi
+ fi
+ showUSAGE
+ ;;
+
+ -q | --quiet | -quiet | --silent | -silent)
+ if test x"$silent" = x0
+ then
+ silent=1; export silent
+ else
+ silent=2; export silent
+ fi
+ ;;
+ -q=* | --quiet=* | --silent=* | -silent=*)
+ silent="$optarg"; export silent
+ ;;
+
+ -s | --simulate | -simulate | --dry-run | -dry-run | --recon | -recon | --just-print | -just-print | --no-act | -no-act)
+ simulate=1; export simulate
+ ;;
+
+ -y | --yes | -yes)
+ assumeyes=1; export assumeyes
+ ;;
+
+ -d | --dialog | -dialog)
+ opt_prev=DIALOG
+ ;;
+ -d=* | --dialog=* | -dialog=*)
+ DIALOG="$optarg"; export DIALOG
+ ;;
+
+ -*)
+ showUSAGE 1
+ ;;
+
+ clean | download | checksrc | build | install | info | uninstall)
+ action="$option"; export action
+ break ;;
+ esac
+
+done
+
+#########################################################################
+#
+# Subroutines
+#
+#########################################################################
+
+# -----------------------------------------------------------------------
+# Printing/logging Subroutines
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcPRINT
+
+# -----------------------------------------------------------------------
+# Interaction Subroutines
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcDIALOG
+
+# -----------------------------------------------------------------------
+# Setup test Subroutines
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcSETUP
+
+# -----------------------------------------------------------------------
+# Subroutines for determining existence of / path to executables
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcEXE
+
+# -----------------------------------------------------------------------
+# Subroutines for building
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcBUILD
+
+# -----------------------------------------------------------------------
+# Subroutines for installing
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcINSTALL
+
+# -----------------------------------------------------------------------
+# Subroutines for client database
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/funcDB
+
+# -----------------------------------------------------------------------
+# Subroutine for the 'download' command
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/comDOWNLOAD
+
+# -----------------------------------------------------------------------
+# Subroutine for the 'checksrc' command
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/comCHECKSRC
+
+# -----------------------------------------------------------------------
+# Subroutine for the 'clean' command
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/comCLEAN
+
+# -----------------------------------------------------------------------
+# Subroutine for the 'build' command
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/comBUILD
+
+# -----------------------------------------------------------------------
+# Subroutine for the 'install' command
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/comINSTALL
+
+# -----------------------------------------------------------------------
+# Subroutine for the 'install' command
+# -----------------------------------------------------------------------
+. ${basedir}/libexec/comUNINSTALL
+
+
+#########################################################################
+#
+# Main
+#
+#########################################################################
+
+main_exit_status=0
+
+tmpdir=
+
+# Find a dialog clone
+#
+findDIALOG
+
+# Check for basedir and tmpdir
+#
+testSETUP1
+
+# Logfile setup
+#
+exec 5>${basedir}/tmp/logfile.lastrun
+now=`date`
+echo "$now: $0 " ${1+"$@"} >&5
+lastlog="${basedir}/tmp/logfile.lastrun"; export lastlog
+logOpen=1
+
+# Temporary directory/file setup
+#
+tmpD="$tmpdir/build.gui.$$"
+mkdir "$tmpD" || printFATAL "Cannot create temporary directory $tmpD"
+export tmpD
+tmpF="$tmpD/tmpF.$$"
+touch $tmpF || printFATAL "Cannot create temporary file $tmpF"
+export tmpF
+tmpERR="$tmpD/tmpERR.$$"
+echo '0' > $tmpERR || printFATAL "Cannot create temporary file $tmpERR"
+export tmpERR
+
+# Trap exit and cleanup
+#
+trap "exit_status=$?; rm -rf $tmpD; exit ${exit_status};" 0
+trap "(exit 1); exit 1;" 1 2 13 15
+
+# Check for action to perform, and host, if required
+#
+testSETUP2
+
+if test x"$action" = xdownload
+then
+ if test x"$src_version" = x
+ then
+ src_version="current"; export src_version
+ fi
+ #---------------------------------------------------------------------
+ # Vodoo code to tee both stdout and stderr, but keep them seperate.
+ #---------------------------------------------------------------------
+ if test x"$DIALOG" = x
+ then
+ ((commandDOWNLOAD | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ commandDOWNLOAD 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version DOWNLOAD logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+elif test x"$action" = xinfo
+then
+ if test x"${showpkg}" = xn
+ then
+ if test x"$DIALOG" = x
+ then
+ ((dbSHOWHOSTS "${host}" | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ dbSHOWHOSTS "${host}" 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version INFO logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+ else
+ if test x"$DIALOG" = x
+ then
+ ((dbSHOWPKG show | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ dbSHOWPKG show 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version INFO logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+ fi
+elif test x"$action" = xchecksrc
+then
+ if test x"$DIALOG" = x
+ then
+ ((commandCHECKSRC | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ commandCHECKSRC 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version CHECKSRC logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+elif test x"$action" = xclean
+then
+ if test x"$DIALOG" = x
+ then
+ ((commandCLEAN | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ commandCLEAN 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version CLEAN logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+elif test x"$action" = xbuild
+then
+
+ #---------------------------------------------------------------------
+ # Make sure we are running under ssh-agent.
+ #---------------------------------------------------------------------
+ if test x"$SSH_AGENT_PID" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "Not running under ssh-agent, and not running interactive: cannot continue."
+ else
+ promptYESNO "Not running under ssh-agent, continue anyway" "no"
+ test "x$YESNO" = xn && { (exit 0; ); exit 0; }
+ fi
+ fi
+
+ #---------------------------------------------------------------------
+ # Setup.
+ #---------------------------------------------------------------------
+ selBVERSION
+ selBARCH
+ selBFORMAT
+
+ if test x"$DIALOG" = x
+ then
+ ((commandBUILD | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ commandBUILD 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version BUILD logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+
+elif test x"$action" = xinstall
+then
+
+ needEXE ssh scp ssh-agent
+
+ #---------------------------------------------------------------------
+ # Make sure we are running under ssh-agent.
+ #---------------------------------------------------------------------
+ if test x"$SSH_AGENT_PID" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "Not running under ssh-agent, and not running interactive: cannot continue."
+ else
+ promptYESNO "Not running under ssh-agent, continue anyway" "no"
+ test "x$YESNO" = xn && { (exit 0; ); exit 0; }
+ fi
+ fi
+
+ #---------------------------------------------------------------------
+ # Setup.
+ #---------------------------------------------------------------------
+ is_root=`id -u 2>/dev/null`
+ if test "x$?" = x0 && test "x${is_root}" != x0
+ then
+ promptYESNO "You are not root, continue anyway" "no"
+ test "x$YESNO" = xn && { (exit 0; ); exit 0; }
+ else
+ is_root=0
+ fi
+ pathYULE
+ pathYDATA
+ selbinARCH
+ selbinVERSION
+ if test "x${is_init}" = xy
+ then
+ promptYESNO "Initialize database" "yes"
+ is_init=$YESNO
+ fi
+ if test "x${is_rcfile}" = xy
+ then
+ promptYESNO "Replace rc.host file on server" "yes"
+ is_rcfile=$YESNO
+ fi
+ if test "x${is_startup}" = xy
+ then
+ promptYESNO "Start client after installation" "yes"
+ is_startup=$YESNO
+ fi
+ if test -f "${yule_conf}"
+ then
+ :
+ else
+ promptINPUT "Please enter the path to the yule configuration file"
+ yule_conf="$INPUT"; export yule_conf
+ if test -f "${yule_conf}"
+ then
+ :
+ else
+ printFATAL "Cannot find ${yule_conf}"
+ fi
+ fi
+
+ if test x"$DIALOG" = x
+ then
+ ((commandINSTALL | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ commandINSTALL 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version INSTALL logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+
+elif test x"$action" = xuninstall
+then
+
+ needEXE ssh scp ssh-agent
+
+ #---------------------------------------------------------------------
+ # Make sure we are running under ssh-agent.
+ #---------------------------------------------------------------------
+ if test x"$SSH_AGENT_PID" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "Not running under ssh-agent, and not running interactive: cannot continue."
+ else
+ promptYESNO "Not running under ssh-agent, continue anyway" "no"
+ test "x$YESNO" = xn && { (exit 0; ); exit 0; }
+ fi
+ fi
+
+ #---------------------------------------------------------------------
+ # Setup.
+ #---------------------------------------------------------------------
+
+ dbINFO "$host"
+
+ if test x"$?" = x0
+ then
+ if test x"${DB_status}" = "xD2_installed"
+ then
+ :
+ else
+ if test x"${DB_status}" = "xD2_removed"
+ then
+ promptYESNO "Already uninstalled on host $host, continue" "no"
+ test "x$YESNO" = xn && { (exit 0; ); exit 0; }
+ else
+ printFATAL "No deploy version 2 installation on host $host: ${DB_status}"
+ fi
+ fi
+ else
+ printFATAL "Cannot uninstall on host $host"
+ fi
+
+ if test x"$DIALOG" = x
+ then
+ ((commandUNINSTALL | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ else
+ commandUNINSTALL 2>&1 | tee -a "$lastlog" >/dev/null | $DIALOG \
+ --title "deploy.sh $version UNINSTALL logfile" \
+ --backtitle "Logfile: $lastlog" \
+ --tailbox "$lastlog" 19 75
+ fi
+
+fi
+
+if test x"${main_exit_status}" = x0
+then
+ test -f "$tmpERR" && main_exit_status=`cat "$tmpERR" | tr -d '\n'`
+fi
+
+(exit ${main_exit_status}); exit ${main_exit_status};
diff --git a/docs/#Changelog# b/docs/#Changelog#
new file mode 100644
index 0000000..3e7b4ff
--- /dev/null
+++ b/docs/#Changelog#
@@ -0,0 +1,2552 @@
+4.1.4:
+ * fix problems with wildcard pattern re-evaluation:
+ - not stored if no match at startup
+ - only one (the first) stored if same pattern for file and dir
+ * fix problems with directory creation in inotify watched tree
+ - recursive depth not decreased
+ - watched as directory even when recursion depth should drop below zero
+
+4.1.3:
+ * on Cygwin, the AvoidBlock function is now off by default
+ (problem reported by Fred C)
+ * tighter sanity checks in sh_static.c
+ * fix regression with '--enable-static' in sh_static.c
+ (reported by amaiket).
+
+4.1.2:
+ * add options --enable-selinux and --enable-posix-acl for "hard fail"
+ if libraries aren't found (requested feature)
+ * fix wrong policy assignment when inotify is active and change occurs
+ during a reload (reported by Bond)
+ * fix failure to detect open UDP port for some daemons
+ (reported by James)
+ * fix broken 'rpm' and 'rpm-light' makefile targets
+ (reported by Bond)
+ * fix message for self-check
+
+4.1.1:
+ * fix problem with timezone calculation on month rollover for
+ negative timezones (west of GMT; reported by Bond)
+ * fix problem with rotated logfiles when content is always constant,
+ i.e. checksum does not change (reported by Bond).
+ * fix problem with baseline update on FreeBSD and probably other
+ non-GNU/Linux systems (reported by L.Vasiliev)
+ * fix bad check_libwrap() call in sh_xfer_server.c
+ (reported by L.Vasiliev)
+
+4.1.0:
+ * fix quirks with Linux audit support
+ * implement 'silent check' (requested feature)
+ * fix call of self_check for exit on sigterm
+ * fix safe_logger() - uses the logger utility with a non-posix option
+ * fix missing reporting on shell expansion capability in --version
+ * fix missing error message on invalid list for skipchecksum
+ (reported by Bond)
+ * fix missing definition for a sh_dummy_ var on BSD et al.
+ (reported by Andrew)
+
+4.0.0:
+ * fix and document default settings for mounts check
+ * new -w CL option to wait on scan completion
+ * new option ReportCheckflags
+ * enhance testsuite to cover new functionality
+ * implement draft for change control integration:
+ * new database format to store change flags
+ * refactoring of db I/O and client/server code
+ * option StartupLoadDelay
+ * --create-database CL option
+ * --outfile CL option
+ * --binary, --list-filter CL options
+ * --verify-database CL option
+ * yulectl -c DELTA:<uuid> command
+ * option SetDeltaRetryCount
+ * option SetDeltaRetryInterval
+ * update documentation
+ * remove old/unused code
+ * fix compiler warnings with gcc 5.1.0
+ * update config.sub, config.guess
+
+3.1.6 (08-06-2015):
+ * Modify testcompile.sh to remove 'smatch' and use 'clang'
+ instead.
+ * Fix compile problems with clang.
+ * Modify testcompile.sh to remove 'uno' and use 'cppcheck'
+ for static checking
+ * Move AC_CHECK_FUNCS( getnameinfo getaddrinfo ) behind
+ the check for libsocket to have them found on Solaris
+ * Fix IPv4-only bug in bind_addr use in retry_connect()
+ * Add more debug code in connect_port()
+
+3.1.5 (26-03-2015):
+ * Fix IPv6 issue with portcheck (need to be able to specify
+ IPv6 interfaces).
+ * Fix minor issues with bugs in testing code
+ * Add command line option '--server-host' to set the log server
+ * In samhain.startLinux.in start script template, add code to read
+ options from /etc/sysconfig/${NAME} for RedHat
+
+3.1.4 (17-02-2015):
+ * Add non-existent file to the regression test config
+ * Fix erroneous call to sh_hash_init when a missing file
+ is specified in the configuration
+ * Fix buffer allocation for getgrnam_r for large groups
+ (problem reported by Sergio B)
+ * Search RPM in $HOME/rpmbuild if test -d _topdir fails (CentOS
+ recommends '%(echo $HOME)/topdir', reported by E. Taft)
+
+3.1.3 (01-11-2014):
+ * Remove initgroups() from the popen call in unix entropy gatherer
+ * Add error message for update mode if local baseline cannot be found
+
+3.1.2 (07-08-2014):
+ * Fixed incorrect memset in sh_checksum.c (sha256)
+ * Circumvent a gcc compiler bug with inline asm (gcc 4.8)
+ * Allow multiple exclusions for SUID check
+ * Use calloc instead of malloc
+ * Add overflow check in minilzo.c (but the potential integer
+ overflow [CVE-2014-4607,LMS-2014-06-16-1] is irrelevant anyway
+ because the function is never used on external data).
+ * Fixed a minor bug in exepack_fill.c that was unearthed by the minilzo
+ overflow check (the required buffer length information for the check
+ wasn't provided)
+ * Fixed incorrect logic in setting the ALLIGNORE flag (more specific
+ directory / file directives were ignored)
+ * Fix for tickets #358 (repetitive lstat warning about deleted
+ directory) and #359 (reporting of deleted/added top level directory)
+ * Fix a free() on NULL (harmless but avoids spurious warning)
+
+3.1.1 (01-05-2014):
+ * Disable inline asm on Cygwin (issue reported by Erik)
+ * Fix sh_ipvx_is_ipv4 such that numeric hostnames are not
+ incorrectly recognised as IP address (reported by A. Hofland)
+ * Fix sh_ipvx_is_ipv6
+
+3.1.0 (31-10-2013):
+ * Add support for SHA2-256 checksum function
+ * Drop support for --enable-khide on kernel version 3.x and above
+ * Fix IgnoreAdded to anchor regex at beginning of path (reported by
+ R.Lindner)
+ * Add check to detect availability of pmap_getmaps() (missing in
+ static library on recent Linux systems as reported by Ian Baldwin)
+ * Fixes for Ubuntu 13.4:
+ - no error msg for failing stat on /run/user/Username/gvfs in
+ suidcheck
+ - no error message for failing hardlink check on /run/user/Username
+ - eliminate compiler warnings
+ * Add option '--disable-asm' to work around a gcc issue in Debian
+ unstable (reported by micah)
+ * Remove option '-i' from mkitab in samhain-install.sh.in (reported
+ by N. Kerski)
+
+3.0.13 (11-06-2013):
+ * Fix detection of nonfunctional /dev/kmem
+ * Fix race condition in GrowingLogfiles policy that
+ causes spurious reports (problem noticed by J. Daubert)
+
+3.0.12 (16-05-2013):
+ * Fix compiler warning in bignum.c (unused parameter)
+ * Detect if /var/run is a symlink and /run exists
+ * Fix for broken support for audit subsystem (reported
+ by isquish)
+ * Fix for incorrect use of sh_inotify_add_watch_later
+ which causes a steady increase in memory usage
+ (issue reported by Maxime V)
+ * Fix for potential minor memory leak
+ * Fix for bug in negated conditionals for config file
+ (reported by M. Ward)
+
+3.0.11 (08-04-2013):
+ * Fix for compile error on HP-UX (reported by P. Alves)
+ * Propagate ERANGE error from getgrxxx_r (issue raised by C. Feikes)
+ * Fix reconnecting to database for Oracle
+ * Add better logrotate handling for the GrowingLogs policy (search
+ rotated log and verify it, don't report if this succeeds)
+ * Add ability to create debian packages with preset password (use
+ env var PASSWORD)
+ * Add option KernelCheckProc (bool) to suppress kernel /proc test
+ * Add option IgnoreModified to cover transient files that
+ not only get added/deleted but also modified
+
+3.0.10 (13-01-2013):
+ * Revert to previous logic in samhain.c because it will block
+ otherwise (reported by Alexandr Sabitov)
+
+3.0.9 (21-12-2012):
+ * Fixed a Cygwin compile warning
+ * Change logic in samhain.c to make sure inotify doesn't cause
+ excessive full scans
+ * Add option IgnoreTimestampsOnly in Windows registry check (ignore
+ changes if only timestamp has changed)
+ * Fix the probe command (misses clients if their startup message
+ has been missed)
+ * Fix the RPM spec file for --enable-network=client and no password
+ (reported by Mitch St Martin)
+ * Fix build error with Linux audit (reported by Andy Jack)
+ * Fix detection of utmpx.h (reported by D. Thiel)
+
+3.0.8 (01-11-2012):
+ * rename to 3.0.8 for release
+ * useful exit status for samhainadmin.pl --examine
+
+3.0.7a (25-12-2012):
+ * add ability to create RPM with preset password (use
+ env var PASSWORD)
+ * fix the rpm-light makefile target
+ * fix minor bug in samhain_setpwd.c (incorrect error message)
+
+3.0.7 (25-10-2012):
+ * update documentation for prelude
+ * fix configure to properly search for Oracle Instantclient SDK
+ * pass through TNS_ADMIN environment variable for Oracle
+ * optimize audit rules automatically
+ * zero out the html status file at server exit
+ * don't check for assembly optimization unless linux or *BSD
+
+3.0.6 (01-09-2012):
+ * install logrotate script if /etc/logrotate.d is detected
+ * new option --enable-suid for nagios
+ * fix for --enable-ptrace: make the save_tv variable thread specific
+ * fix bug in inotify code which made it follow symlinks (by [anonymous])
+ * fix two missing SH_MUTEX_LOCK(mutex_thread_nolog) (by [anonymous])
+ * fix for 'no such process' message from sh_fInotify_init_internal()
+ (by [anonymous])
+ * fix for --enable-ptrace with threads (by [anonymous])
+ * option SetReportFile for writing out summary after file check
+
+3.0.5 (11-07-2012):
+ * fix xml format templates for registry check
+ * fix database download on registry check init (reported by ldieu)
+
+3.0.4 (01-05-2012):
+ * fix verbosity of message for alerts on already deleted watches
+ (set it to debug - suggested by xrx)
+ * fix extraneous error messages about file not found from
+ sh_fInotify_init_internal() (bug reports by xrx and aj)
+
+3.0.3 (28-03-2012):
+ * fix potential deadlock in sh_ext_popen()
+ * make sure sh_processes_readps cannot hang forever
+ * fix for deadlock if sh_processes_readps hangs
+ * fix for deadlock if suid check and inotify are used together
+ (reported by A. Jack)
+ * fixed problem with samhain_stealth.c (handle input config
+ files that don't end with a newline)
+ * fixed compiler warnings for yulectl.c with stealth
+ * fixed lacking support for O_NOATIME on 64bit linux
+
+3.0.2a (23-02-2012):
+ * Fix compile error on Solaris 10
+
+3.0.2 (16-02-2012):
+ * change sql init scripts to make bigint fields unsigned (problem
+ reported by A. Sabitov)
+ * patch by Andy Jack for issue with the --with-gpg option (hangs with
+ high cpu load at startup)
+ * call ./samhain-install.sh as /bin/sh ./samhain-install.sh in the
+ RPM spec file, because /var might be mounted noexec (reported by GC)
+ * fixed configure.ac for the case that --with-gpg and --enable-nocl are
+ used (./samhain for gpg checksum; problem report by Andy Jack)
+ * fixed a potential NULL pointer dereference in sh_inotify.c on
+ systems where inotify is not available (reported by <anonymous>)
+ * fixed: the config file template mentions (in a comment) the
+ non-existent directive SetLockPath instead of the correct
+ SetLockfilePath (reported by Curtis).
+ * fixed: the definition of O_NOATIME isn't seen in sh_files.c.
+
+3.0.1 (07-12-2011):
+ * fix a memory leak (reported by C. Westlake)
+ * fix an uninitialized variable in the suidcheck code (problem
+ reports by T- Luettgert and Kai)
+ * fix a bug in the port check with --disable-ipv6 (reported
+ by C. Westlake)
+ * fix potential deadlock in sh_files.c (reported by S. Mirolo)
+ * change Makefile.in to stop on compile error rather than at link stage
+ (suggested by S. Mirolo)
+ * fix compile errors caused by missing #define (pthread disabled) and
+ wrong function call (OSX specific code), reported by S. Mirolo
+ * fix warning by the llvm/clang static checker
+ * fix compile issues on freebsd
+ * handle (ignore) SIGPIPE more thoroughly
+ * update config.guess, config.sub
+
+3.0.0a (06-10-2011):
+ * Fix compile-time issues on RHEL5 (reported by Thomas)
+
+3.0.0 (01-11-2011):
+ * Add support for the inotify API
+ * If --disable-shellexpand is used, also disable setting
+ the prelink/ps paths
+ * Fix missing check_mask storage for glob pattern
+ * Add support for integer keys in zAVL
+ * Fix compiler warnings with gcc 4.6.1 (variables that get set
+ but then remain unused)
+ * Add more server-side debugging for IPv6
+ * Make kern_head compile with 3.x kernels
+
+2.8.6 (20-09-2011):
+ * Manual updated.
+ * Added an option LogmonDeadtime to avoid repetitive reporting
+ on correlated events.
+ * Fix problems with timestamp handling in logfile correlation
+ (problem reported by D. Dearmore)
+ * List the policy under which a directory/file is checked
+ * Option to use a textfile with a list of files for update
+ * Fix --enable-db-reload option (reported by David L.)
+ * Fix samhain_kmem compilation, need to compile under chosen
+ name if --enable-install-name is used (reported by David L.)
+ * Fix uninitialized string in error message (reported by mimox)
+
+2.8.5a (16-06-2011):
+ * Fix autolocal.m4 for new configure option
+
+2.8.5 (15-06-2011):
+ * Detect non-working /dev/kmem in configure script, and fix
+ a bug in the samhain_kmem kernel module.
+ * Fix wrong handler for LogmonMarkSeverity (reported by S. Chittenden)
+ * Better protection against the 'intruder on server' scenario
+ pointed out by xrx. Add option to disable shell expansion in
+ configuration files, and check gpg signature earlier.
+ * Support /opt/local/bin in the Unix entropy gatherer (suggestion
+ by Sean Chittenden)
+ * Cache timeserver response for one second (suggestion by
+ Sean Chittenden)
+
+2.8.4a (11-05-2011):
+ * Fix for compile error with --with-prelude
+ (reported by Sean Chittenden), missing regression test added
+ * Fix for compile error with --enable-udp (reported by Sean Chittenden),
+ missing regression test added
+
+2.8.4 (30-04-2011):
+ * Fix another reload bug in the log monitoring module
+ * Add unit tests for IgnoreAdded/IgnoreDeleted configuration directives
+ * Fix deadlock after reload when compiled with --enable-login-watch
+ (reported by M. Teege and O. Cobanoglu)
+ * Fix compile error for samhain_hide.ko with recent kernel
+ * Include patch by J. Graumann to specify the location of the
+ secret keyring with samhainadmin.pl
+ * Fix potential timeout problem in sh_sub_stat_int() and propagate the
+ error (issue reported by mtg)
+ * Add support for X-Forwarded-For in apache logfile parser, add
+ option 'RE{regex}' to insert arbitrary regex
+ * New options PortcheckMinPort, PortcheckMaxPort for the open ports
+ check
+
+2.8.3a (23-03-2011):
+ * Fix two 'label at end of compound statement' errors on FreeBSD
+ (reported by David E. Thiel)
+
+2.8.3 (22-03-2011):
+ * init scripts: load samhain_kmem.ko before samhain starts
+ * slib.c: eliminate mutex from sl_create_ticket()
+ * sh_entropy.c: move pthread usage out of child
+ * sh_hash.c, sh_pthread.c, sh_pthread.h: sh_hash_hashdelete()
+ needs deadlock detection, may be called from within sh_hash_init()
+ via atexit handler on error condition
+ * sh_suidchk.c, sh_calls.c, sh_calls.h: need a nosub version of lstat()
+ to use with relative path after chdir()
+ * samhain.c, sh_calls.c, sh_calls.h: only run (l)stat() in subprocess
+ after reading config file (to allow disabling)
+ * sh_unix.c: run sh_sub_kill() in parent after forking the daemon
+ * fix zeroing of result from getnameinfo() (problem reported by Richard)
+ * fix spurious warnings about unsupported address family (reported
+ by N Silverman)
+ * option to run lstat/stat in subprocess to avoid hanging on NFS mounts
+ (off by default)
+ * fix Windows/Cygwin compile error (reported by A. Schmidt)
+
+2.8.2 (16-02-2011):
+ * add function to skip checksumming
+ * Fix missing check for recursion depth >= 0 if not IgnoreAll
+ * Fix hardcoded path for temp directory in deployment scripts
+ * Fix bad compile on CentOS 4.8 with gcc 4.1.2
+ * Fix minor bug in check_samhain.pl (pointed out by J.-S. Eon long ago)
+
+2.8.1 (17-11-2010):
+ * Document handling of missing files with secondary schedule
+ * Fix incorrect handling of missing files when secondary schedule
+ is used (reported by Sergey)
+ * Fix null pointer dereference in config parse handler for SetMailAlias
+ (reported by Sergey)
+ * Fix incorrect memset() in sh_kern.c (passed struct by value...),
+ reported by Roman and Stefan
+ * Fix 'make install' to create user-defined directory
+ * fix minor issues noticed by T. Luettgert (test code assumes port
+ 0/tcp is unused, wrong ifdef order (without impact on compilation))
+ * fix compile error on AIX 5.3 with --enable-login-watch,
+ reported by M. El Nahass (time.h missing in src/sh_login_track.c)
+
+2.8.0 (01-11-2010):
+ * Support IPv6
+ * Add registry checking
+ * Use auditd records to find out who did it
+
+2.7.2c (23-09-2010):
+ * Fix uppercase hostname problem in client/server communication
+
+
+2.7.2b (05-09-2010):
+ * Fix compile errors on Solaris 10 (reported by A. Saheba)
+
+2.7.2a (23-08-2010):
+ * rewrote rijndaelKeySched() in a more conservative way to fix
+ compile problem on SLES 11.
+
+2.7.2 (16-08-2010):
+ * sh_utils.c: fixed an endianess issue that prevented cross-verification
+ of email signatures (reported by A. Zangerl)
+ * sh_login_track.c: fix compiler warning (ignored return value
+ of fwrite)
+ * sh_readconf.c: fix comparison of SeverityUserX string
+ (reported by max__)
+ * sh_processcheck.c: sh_prochk_set_maxpid: set retval on success
+ (reported by max__)
+ * fixed some compiler warnings on cygwin
+ * sh_extern.c: As reported by T. Luettgert, gcc 4.4.4 on Fedora 13
+ will throw a warning if execve is called with a NULL argv pointer.
+ Need to provide a dummy argp[].
+
+2.7.1 (07-06-2010):
+ * samhain_kmem.c: fix compile problems
+ * fix problems with config file parser: increase max. line length,
+ support quoting/escaping of filenames (as in 'ls --quoting-style=c')
+ * check for pcre_dfa_exec (not available in old versions
+ of libpcre, reported by Shinoj)
+ * patch to allow server to log client reports to prelude
+ (by J. Ventura)
+
+2.7.0a (09-05-2010):
+ * fix /dev/kmem detection (reported by S. Clormann)
+
+2.7.0 (01-05-2010):
+ * sh_utmp.c, sh_login_track.c: additional login checks
+ * sh_unix.c: use SIGTTIN as alternative for SIGABRT
+ (SIGABRT seems not to work on AIX, reported by Peter)
+ * sh_utmp.c: fix compile error without pthreads (inotify_watch used)
+ * sh_kern.c, kern_head.c: fix some 64bit issues
+ * dnmalloc.c: fix compiler warning (ignored ret value)
+ * Fix LSB init script for kernel module
+ * samhain_kmem kernel module for /proc/kmem added
+
+2.6.4 (22-03-2010):
+ * Don't read proc_root_iops in sh_kern.c (Problem report
+ by H. R.)
+ * Logfile check can check output of shell commands
+ * Use data directory as default for logfile checkpoints
+ * Fix broken checkpoint save/restore for logfiles
+
+2.6.3 (10-03-2010):
+ * Fix bug in mail module, recipients incorrectly flagged
+ as aliases, which breaks immediate mail for 'alert'
+ (reported by Jesse)
+
+2.6.2 (28-01-2010):
+ * Makefile.in: fix problem in deploy system caused
+ by adding build number for debs in 2.5.9 (reported
+ by roman)
+ * add option for per-rule email alias in log monitoring
+ module
+ * sh_readconf.c: make keywords case-independent
+ * sh_mail.c: on error, report full reply of mail server
+ * sh_mail.c: report smtp transcript at debug level
+ * make sure mail aliases are not emailed twice, and
+ recipients cannot be defined after aliasing them
+ * handle named pipes in log monitoring module
+ (open in nonblocking mode, ignore read error if empty)
+ * fix bug in the server function to probe for necessity
+ of configuration reload for client
+
+2.6.1b (23-12-2009):
+ * fix missing include for sh_inotify.h in sh_inotify.c
+ (reported by Ack)
+
+2.6.1a (22-12-2009):
+ * fix typo in code for older inotify versions without
+ inotify_init1(), reported by Forll
+
+2.6.1 (21-12-2009):
+ * add a routine to log monitoring module to guess the proper year
+ for timestamps without year (standard syslog)
+ * add feature to automatically detect and report bursts of
+ similar messages in log monitoring module
+ * add feature to check for missing heartbeat messages in
+ log monitoring module
+ * cache UIDs/GIDs to reduce the number of lookups
+ * use inotify to track login/logout (sh_inotify.c, sh_utmp.c)
+ * support event correlation in log monitoring module
+ * make sure host matching is done in a case insensitive way
+ (reported by Tracy)
+ * fix invalid use of mutex_mlock in src/sh_unix.c, function
+ sh_unix_count_mlock() (reported by Remco Landegge).
+
+2.6.0 (01-11-2009):
+ * don't use statvfs() for process checking on FreeBSD
+ * fix bug with parallel compilation of cutest in Makefile
+ * sh_mem.c: fix deadlock in debug-only code
+ * Evaluate glob patterns for each run of file check
+ * Add compile option to disable compiling with SSP
+ * Run SUID check in seperate thread
+ * By default disable scanning ..namedfork/rsrc (deprecated by Apple)
+
+2.5.10 (12-10-2009):
+ * sh_suidchk.c: handle $HOME/.gvfs mount gracefully
+ * slib.c: fix race condition caused by closing a stream and the fd
+
+2.5.9c (01-10-2009):
+ * move stale file record error message closer to problem zone
+ * sh_port2proc.c: fix flawed logic for interpreting /proc/net/udp,tcp
+
+2.5.9b (22-09-2009):
+ * remove stale file record when creating handle, and raise diagnostic
+ error to find origin of stale record
+ * sh_port2proc.c: check /proc/net/upd6 for IPv6-only UDP sockets
+
+2.5.9a (17-09-2009):
+ * fixed a race condition in closing of file handles
+
+2.5.9 (11-09-2009):
+ * added code to generate directory for pid file, since it
+ would get cleaned if /var/run is a tmpfs mount (problem
+ reported by M. Athanasiou)
+ * fixed a bug that prevented reporting of user/executable path
+ for open UDP ports (issue reported by N. Rath)
+ * added more debugging code
+
+2.5.8a (18-08-2009):
+ * fixed a bug in sh_files.c that would prevent samhain from
+ running on MacOS X (reported by David)
+
+2.5.8 (06-08-2009):
+ * fixed a bug in the MX resolver routine which causes it to fail
+ sometimes (issue reported by N. Rath).
+ * fixed deadlock with mutex_listall in sh_nmail_test_recipients() if
+ error occurs within sh_nmail_flush (problem reported by N. Rath)
+
+2.5.7 (21-07-2009):
+ * sh_userfiles.c: set userUids = NULL at reconfiguration (issue
+ reported by U. Melzer)
+ * if available, use %z to print timezone as hour offset from GMT
+ in email date headers (problem reported by NP, solution suggested
+ by TimB).
+ * eliminate C99-style comments (problem reported by
+ venkat)
+ * fix bad variable name for AC_CACHE_CHECK
+ * fix potential deadlock when external programm is called
+ (problem reported by A. Dunkel)
+
+2.5.6 (09-06-2009):
+ * recognize fdesc filesystem on MacOS X for suid check (Problem
+ reported by David)
+
+2.5.5 (01-05-2009):
+ * fix some warnings from gcc 4.4 (strict aliasing)
+ * fix minor memory leak in process check
+ * t-test1.c: change function names because of clashes with an
+ AIX system header file
+ * fix warnings with -fstack-check (too large stack frames)
+ * fix for incorrect handling of hostnames in database insertion
+ (reported by byron)
+
+2.5.4 (04-03-2009):
+ * fix for incorrect input check in SRP implementation (discovered
+ by Thomas Ptacek)
+ * option KernelCheckPCI to switch off check of PCI expansion ROMs
+
+2.5.3 (25-02-2009):
+ * disable dnmalloc on MacOS X, doesn't work properly
+ * stat -> lstat in sh_unix_file_exists (OS X nameforks, report
+ by David)
+ * Fix problem in standalone trustfile, does not work correctly on
+ group-writeable files (reported by David).
+ * Option SetThrottle to throttle throughput for db download
+ * Option SetConnectionTimeout to configure the client connection
+ timeout configurable
+ * Provide getrpcbynumber, getservbyname implementations
+ to avoid dependencies with static linkage
+ * Fix missing sh.host.(system|release|machine) on FreeBSD,
+ reported by D.Lowry
+ * New option SetMailPort to allow setting of SMTP port (patch
+ by lucas sizzo org)
+ * allow POSIX regexes for filters
+ * consolidate filtering code from sh_extern.c, sh_(n)mail.c
+ * rewrite mail subsystem to allow individual filtering
+ for recipients
+ * allow shell expansion for values of config file options
+ * allow list as value for option PortCheckInterface
+ * fix bug in trustfile.c (with slapping on "/../" for symlinks)
+ * lock baseline database upon writing
+
+2.5.2b (29-01-2009):
+ * turn warnings into errors in the compile test suite
+ * fix missing define in sh_portcheck.c to eliminate compiler warning
+ (reported by joerg)
+
+2.5.2a (26-01-2009):
+ * fix problem building deb package (bit rot; reported by joerg)
+
+2.5.2 (22-01-2009):
+ * samhain.c: report module failure with positive offset
+ * sh_database.c: parse numerical fields into ulong
+ * fix regression test script for postgresql
+ * fix regression test script for SELinux/ACL test
+ * fix reporting of user for open ports to prelude
+ * report process pid for open ports
+ * replace _exit() by raise(SIGKILL) b/o pthread problem
+ * new option LooseDirCheck ([false]/true), request by
+ Alexander
+ * improved help output of samhain_stealth (as suggested
+ by Michael Athanasiou)
+ * new option ProcessCheckIsOpenVZ ([false]/true)
+
+2.5.1 (07-12-2008):
+ * workaround for freebsd7 amd64 lossage (compiler toolchain,
+ no mmap to 32bit address space)
+ * samhain-install.sh: check for presence of stealth_template.ps
+ before trying to create it
+ * use -Wno-empty-body if supported to suppress warnings about
+ glibc pthread_cleanup_pop implementation
+ * fix text relocations for i386 in src/sh_tiger1.s
+ * implement server->client SCAN command to initiate file check
+ * implement @if / @else conditionals with more tests in config file
+ * new option SetDropCache to drop checksummed files from cache
+ * report process/user for open ports on FreeBSD (code
+ lifted from FreeBSD sockstat.c)
+ * fix for config reload issue with stealth mode (reported by
+ siim)
+ * add -fstack-protector flags to LDFLAGS
+ * cygwin fix: don't use dnmalloc, doesn't work with pthreads
+ * cygwin fix: make trust check in samhain-install.sh return zero
+ * improved diagnostics for file read errors
+ * fixed script permissions (754 -> 755), reported by Christoph
+ * constness patch by Joe MacDonald
+ * GnuPG key ID patch by Jim Dutton
+ * sh_kern.c: more error checking for reads from kernel
+
+2.5.0 (01-11-2008):
+ * dnmalloc.c: fix inconsistent chunksize on 64bit systems
+ * fix improved error reporting for failed fstat in checksumming
+ * report process/user for open ports (Linux only currently)
+ * fix deadlock on exit in sh_hash_init()
+ * fix --enable-mounts-check for FreeBSD 7.0 (no MNT_NODEV anymore)
+ * log monitoring support
+ * fixed constness in trustfile interface
+ * remove libprelude 0.8 support (obsolete)
+ * sh_forward.c: increase TIME_OUT_DEF to 900 secs
+ * dnmalloc.c: initialize rc in dnmalloc_fork_child(),
+ reported by B. Podlipnik
+
+2.4.6a (09-10-2008):
+ * fix compile problem on Fedora 9 (reported by pierpaolo),
+ 'struct ucred' in sh_socket.c requires _GNU_SOURCE
+
+2.4.6 (27-08-2008):
+ * fix compile failure on win2k/cygwin (sh_unix_mlock prototype),
+ reported by jhamilton
+ * fix potential deadlock with dnmalloc upon fork()
+ * fix non-portable use of 'hostname -f' in regression test suite
+ (reported by Borut Podlipnik)
+
+2.4.5a (18-08-2008):
+ * fix compile problem in dnmalloc.c (remove prototypes for
+ memset/memcpy), problem reported by Juergen Daubert
+
+2.4.5 (07-08-2008):
+ * testscripts: 'chmod -R' -> 'chmod -f -R', since Solaris 10
+ bails out on a chmod on a dangling link
+ * fix bug in check_samhain.pl nagios script (J.-S. Eon)
+ * use the UNO static checker
+ * compile as position independent executable (PIE)
+ * handle EINPROGRESS error (Windows/cygwin issue)
+ * make sure every function uses less than one page of stack
+ (proactive security against gap jumping, Gael Delalleau)
+ * use dnmalloc instead of system malloc
+ (proactive security against heap buffer overflows)
+ * fix dnmalloc bugs and portability problems
+ * check for compressBound, since older zlibs don't have it
+
+2.4.4 (30-04-2008):
+ * sh_database.c: fix maximum size of sql query string, maximum
+ size of strings in struct dbins_
+ * sh_hash.c: fix maximum size of message string
+ * fix typo in the base64 decoder
+ * fix 'make cutest' for parallel compiling
+ * fix compile warnings with -Wstrict-prototypes
+ * sh_static.c: override getgrgid, getpwuid for libacl
+ * fix more warnings about variables clobbered by 'longjmp'
+ or 'vfork' (due to library internal handling of mutexes)
+ * fix configure warning about unused datarootdir
+ * configure.ac: warn, but accept nonexistent tmp dir
+ (Problem reported by Brian)
+ * sh_unix.c: undef P_ALL, P_PID, P_PGID before including
+ sys/wait.h (compile problem reported by Reputation)
+ * syslog function tested ok with Syslog Fuzzer v0.1
+ by Jaime Blasco (c) 2008
+ * slib.c: call fflush when writing trace to file
+ * sh_readconf.c: don't set OnlyStderr to false if gpg (problem
+ reported by Irene Reed)
+ * fix unconditional removal of pid file in atexit handler (bug
+ reported by Brian)
+ * fix invalid free() in sh_unix_checksum_size()
+ * sh_processcheck.c: workaround for stupid OpenBSD bug (returns
+ ENODEV instead of EAGAIN, because fgetc does
+ fcntl(0,F_SETFL,O_NONBLOCK) [ENODEV] internally), problem
+ reported by Roman R.
+ * fix buf that cause incomplete reporting of modified symlink if
+ symlink has changed and both old and new paths are >48 bytes
+ * fix bug that prevented mount check from running in one-shot mode
+ * enable mount check for openbsd
+ * fix processcheck default options and test script for openbsd
+ * option --list-file to list content of file (if saved)
+ * sh_tools.c: use strcasecmp in reverse lookup since DNS is case
+ insensitive (bug reported by Phil)
+ * fill content if MODI_TXT, zlib compress, base64 encode and add
+ as link_path in sh_unix.c; add to report in sh_hash.c
+ * testsuite: add test for gpg fingerprint option
+ * sh_extern.c: add 'CloseCommand' for syntactic sugar,
+ add in testsuite
+
+2.4.3a (12-02-2008):
+ * fix compile error caused by open() with O_CREAT and no third argument
+ (reported by J.-S. Eon)
+
+2.4.3 (31-01-2008):
+ * sh_kern.c: don't require asm/segment.h for kernel check module
+ * use global var with pid of initial thread instead of getpid(),
+ since LinuxThreads returns different value in each thread (problem
+ reported by Steffen Mueller)
+ * sh_kern.c: no inode check for pci rom (creates spurious messages)
+ * slib.c: eliminate prototype for vsnprintf (compile problem reported
+ by eddy_cs)
+ * Makefile.in: fix missing dependency on 'encode' for $(OBJECTS)
+ (reported by Matthias Ehrmann)
+
+2.4.2 (17-01-2008):
+ * fix broken option --with-checksum (reported by halosfan),
+ regression test added
+ * change HP-UX default optimization to +O2 since +O3 breaks
+ cutest unit testing framework
+ * put result vector of rng in skey struct
+ * fix more compiler warnings, and a potential (compiler-dependent)
+ NULL dereference in the unix entropy collector
+ * fix some compiler warnings
+ * use -D_FORTIFY_SOURCE=1 -fstack-protector-all instead
+ of -fstack-protector
+ * always add PTHREAD_CFLAGS to LDFLAGS
+ * sh_tiger0.c: checksum functions return length of file hashed,
+ needed to fix GrowingLogfile bug (researched by
+ siim at p6drad dash teel dot net)
+ * sh_static.c: fix more 'label at end of compound statement'
+ (SH_MUTEX_UNLOCK closing brace; reported anonymously)
+ * make sh_hash.c thread-safe
+ * remove plenty of tiny allocations
+ * improve sh_mem_dump
+ * modify port check to run as thread
+ * new option PortCheckSkip to skip ports
+ * fix unsetting of sh_thread_pause_flag (was too early)
+
+2.4.1a (28-11-2007):
+ * fix overwrite of ErrFlags (functionality bug)
+
+2.4.1 (26-11-2007):
+ * security fix: regression in the seeding routine for the PRNG
+ (detected by C. Mueller)
+ * regression test added for PRNG seeding routine
+ * fix problem with PCI ROM check (spurious messages about modified
+ timestamps, reported by S. Clormann)
+
+2.4.0a (08-11-2007):
+ * fix compile failure with --enable-static (reported by S. Clormann)
+ * fix potential deadlock if SIGHUP is received while suspended
+
+2.4.0 (01-11-2007):
+ * eliminate alarm() for I/O timeout (replaced by select)
+ * use getgrgid_r, getpwnam_r, getpwuid_r, gmtime_r, localtime_r,
+ rand_r, strtok_r if available
+ * protect readdir(), getpwent(), gethostname() with mutexes
+ (readdir_r considered harmful)
+ * make checksum/hash, entropy, rng functions reentrant
+ * use thread-specific conversion buffer for globber()
+ * fixed compile problems and problems with test suite
+ * modify login watch to run as thread
+ * modify process check to run as thread
+
+2.3.8 (03-10-2007):
+ * new option PortCheckIgnore = interface:portlist
+
+2.3.7 (13-09-2007):
+ * Makefile.in: fix 'make deb' target, wrong name of config file
+ written to debian/conffiles (reported by marc)
+ * configure.ac: fix incorrect order of with-prelude, enable-static
+ (libprelude test was always without -static)
+
+2.3.6 (06-09-2007):
+ * added yuleadmin.pl script contributed by Riccardo Murri
+ * fix compile error with -f-stack-protector on some systems (reported
+ by marc); we now check for libssp
+ * fix local DoS attack on BSD systems lacking getpeereid() (reported
+ by Rob Holland).
+ * fix yulectl password reading from $HOME/.yulectl_cred, erroneously
+ rejected passwords with exactly 14 chars (reported by Jerry Brown)
+ * introduce 'fflags' flag for suid files to detect new files already
+ found in regular file check (problem reported by J. Crutchfield);
+ also add regression test to ascertain that files in baseline
+ database are not quarantined erroneously
+ * sh_hash.c: replace check for prefix 'K' with check for not prefix'/'
+ to allow for arbitrary module-specific store/lookup in db
+ * replace 'visited', 'reported', 'allignore' with generic 'fflags' field
+ * sh_cat.c: reduce priority of MSG_TCP_RESET to avoid spamming if
+ port checking is used on same host as server (reported by kadafax)
+ * Install.sh: don't use --separate-output with non-checklist
+ widgets (problem discovered by D. Denton)
+ * sh_gpg.c, sh_userfiles.c: use sh_getpwnam et al. wrappers
+
+2.3.5 (20-06-2007):
+ * sh_portcheck.c: try to tear down connections more gracefully
+ (request by S. Petersen)
+ * fix incorrect handling of files with zero size in GrowingLogFiles
+ (problem reported by S. Petersen)
+ * fix incorrect encoding of null checksums in stealth mode
+ * sh_hash.c: fix repeated printing of acl/attributes in database dump
+ * sh_unix.c: fix option useaclcheck ignored if both useaclcheck and
+ useselinuxcheck are supported
+
+2.3.4 (01-05-2007):
+ * sh_processcheck.c: fix missing init of sh_prochk_res array before
+ check (leads to degrading functionality over time and 'fake pid'
+ warnings; reported by D. Ossenbrueggen and
+ soren dot petersen at musiker dot nu)
+ * sh_processcheck.c: fix memory leak
+ * sh_kern.c: for 2.6.21+ don't check proc_root_lookup (not possible
+ anymore? proc_root_inode.lookup != proc_root_lookup)
+ * sh_extern.c: flush streams before forking (problem if [Prelink]
+ used together with prelude logging, reported by M. deJong)
+ * fixed compilation of kern_head (regression cause by cross-compiling
+ fix; problem reported by S. Clormann)
+ * more typos fixed (reported by John Horne)
+
+2.3.3 (27-03-2007):
+ * fixed typos in configure.ac and manual (reported by John Horne)
+ * don't use mysql_options on x86_64, since libmysql is broken
+ * fixed cross-compiling (patch by Joe MacDonald)
+ * refactor sh_kern.c, sh_suidchk.c
+ * fix bug with leading slashes in linked path of symlinks within
+ the root directory
+ * sh_kern.c: check PCI ROM (Linux), refactor code
+ * move file descriptor closing more towards program startup
+ * kernel check: support OpenBSD 4.0 (wishlist)
+ * fix samhain_hide module (in-)compatibility with recent kernels
+ (reported by Jonny Halfmoon)
+
+2.3.2 (29-01-2007):
+ * fix regression in full stealth mode (incorrect comparison of
+ bytes read vs. maximum capacity), reported by B. Fleming
+
+2.3.1a (21-01-2007):
+ * fix incorrect use of sh_gpg_fill_startup if option --with-fp is used
+ (reported by zeroXten)
+
+2.3.1 (21-01-2007):
+ * fix bug that may cause accidental closure of yule TCP socket
+ (problem reported by B. Masuda)
+ * fix sh_kern.c for kernel 2.6.19 (reported by S. Clormann)
+ * don't use sstrip in 'make deb', since dh_shlibdeps uses objdump
+ (reported by B. Masuda)
+ * rm report.pl from rules.deb.in (reported by B. Masuda)
+ * samhainctl(): longer timeout (bad status reporting at startup,
+ reported by Phil and by Dan Track)
+ * sh_portcheck.c: make connect errors more descriptive
+ * sh_portcheck.c: fix ignored setting of PortCheckActive
+ * sh_processcheck.c: add statvfs, and wrap for EINTR
+ * sh_portcheck.c: add wrappers for EINTR
+ * report user and executable for hidden processes
+ * fix update failure if reportonlyonce = false (reported
+ by D. Strine)
+ * fix compile error in sh_portcheck.c (problem on cygwin
+ reported by J. D. Fiori)
+ * check filenames ending in space (also for utf8 spaces)
+ * check and escape csv formatted db listing
+ * cache results of sl_trustfile_euid()
+ * trustfile: use 4096 for MAXFILENAME, switch to strncpy
+ * CL option -v|--version for info on version and compiled-in options
+
+2.3.0a (01-11-2006):
+ * fix compile failure with portcheck + stealth (reported by lucas)
+
+2.3.0 (01-11-2006):
+ * fix concurrency for inserts in oracle db
+ * add acl_(new|old) to database schema
+ * check for selix attributes and/or posix acl
+ * new option UseSelinuxCheck (bool)
+ * new option UseAclCheck (bool)
+ * regression tests for above
+ * add module to check for open ports
+ * add module to check processes (hidden/fake/missing)
+ * use const char* for argument of module configuration callbacks
+
+2.2.6 (31-10-2006):
+ * fix missing support for MacOX X init script (reported
+ by Daniel Kowalewski)
+ * fix error about non-readable file with no checksum required
+ * fix server warning about 'no server name known'
+ * fix 'make deb' makefile target
+ * fix default export severity for server
+
+2.2.5 (05-10-2006):
+ * fix broken Install.sh, reported by Alexander Kraemer
+ * workaround for glob(3) sillyness on MacOS X (reported by David)
+ * fix for broken resorce fork check (reported by David)
+ * fix for broken compilation on cygwin (reported by Elias)
+
+2.2.4 (03-09-2006):
+ * add regression test for the GrowingLogFiles issue to test suite
+ * fixed sh_unix.c: bug in database init if GrowingLogFiles used
+ with signed database (reported by Timothy Stotts)
+ * bug in manual fixed (incorrect documentation of --enable-user,
+ noticed by M. Brown)
+ * rc.subr compatible init script for FreeBSD/NetBSD
+ * improve routine to find rpm after build
+ * add netbsd rc file from Brian Seklecki (taken from pkgsrc-wip)
+ * fix error in manual (location of lock file)
+ * fix bug with SuidExclude (files in directory were still checked)
+
+2.2.3 (31-07-2006):
+ * fix samhainadmin.pl: check for gpg-agent running if use-agent is set
+ (ticket #28 by anonymous)
+ * fix stealth mode (regression in parser), problem reported by
+ Joschi Kuphal
+ * fix minor typo in sh_database.c (compile problem reported by
+ Joschi Kuphal)
+
+2.2.2 (17-07-2006)
+ * minor fixes for regression test scripts
+ * minor updates to the manual (suggested by Brian A. Seklecki)
+ * fix sh_kern.c, kern_head.c: kernel rootkit detection for 2.6.17+
+ (problem reported by Leonhard Maylein)
+ * fix samhain_hide.c for 2.6.17+: use module_param() if MODULE_PARM
+ is not defined
+
+2.2.1c (11-07-2006)
+ * fix sh_extern.c: sh_ext_add_default() cast to (void) was too early
+ (Solaris 8 build failure reported by Jesse)
+ * fix sh_unix.c: wrong prototype for sh_unix_mlock()
+ if HAVE_BROKEN_MLOCK (AIX 5.2 build failure reported by
+ Jonathan Kaufman)
+
+2.2.1b (20-06-2006):
+ * fix compile error on SuSE 10.1 (reported by Leonhard Maylein)
+
+2.2.1a (15-06-2006):
+ * fix compile error on i686/MacOS X (reported by Andreas Neth)
+
+2.2.1 (13-06-2006):
+ * fix gcc 4 warnings and build failure on x86_64 (debian bug #370808)
+ * fix compiling with Oracle (noticed by Colapinto Giovanni)
+ * fix configure.ac for most recent autoconf version
+ (debian bug #369503)
+ * fix a regression that would make impossible local updates w/clients
+ * fix a few missing '\n' in sh_getopt.c
+ * sh_kern.c: fall back on mmap() if read() fails on /dev/kmem
+ * fix Solaris package creation
+ * recognize Solaris doors and event ports
+ * fix the idmef_inode_t patch: provide required info to avoid stat()
+ * fix bug on database update: fill in dev and rdev fields
+ * fix get_file_infos() in sh_prelude.c: avoid premature return
+ * GCC_STACK_PROTECT_CC: AC_TRY_COMPILE -> AC_TRY_LINK
+ * deploy.sh: allow to set a group for hosts upon installation
+ * patch by Yoann: fix an issue when setting the idmef_inode_t object
+ * fix memory leaks in error paths in sh_prelude.c
+ * fix concurrent inserts with postgres in sh_database.c
+ * code cleanup
+ * fix manual version in spec file, first noticed by Imre Gergely
+
+2.2.0 (01-05-2006):
+ * patch by Jim Simmons for samhainadmin.pl.in
+ * fix testsuite portability problems
+ * fix md5 endianess problem detected on HP-UX 11i / PA-RISC 8700
+ * fix potential NULL dereference in sh_utmp_endutent()
+ * patch by Neil Gorsuch for suidchk.c (do not scan lustre, afs, mmfs)
+ * fix sh_ext_popen (OpenBSD needs non-null argv[0] in execve)
+ * fix make_tests.sh portability (echo '"\n"' does not work on OpenBSD)
+ * fix bug in sh_utils_obscurename (check isascii)
+ * scan h_aliases for FQDN if h_name is not
+ * add copyright/license info to test scripts
+ * add copyright/license info to deployment system scripts
+ * support server-to-server relay
+ * new CL option --server-port
+ * minor improvements in manual
+ * patch by Yoann Vandoorselaere for sh_prelude.c
+ * allow --longopt arg as well as --longopt=arg
+ * verify checksum of growing log files (up to previous size)
+ * rewrite of the test suite
+ * added a bit of unit testing
+ * minor optimizations in various places
+ * optimized implementation of tiger checksum algorithm
+ * read in 64k blocks (faster than 4k)
+ * sh_unix.c, sh_hash.c: support file flags on *BSD, update Linux
+ file attribute code
+ * kern_head: fix compilation of kernel check module on OpenBSD
+ * updated samhainrc.linux, samhainrc.freebsd
+ * sh_unix.c: fix setrlimit (RLIMIT_NOFILE, ..)
+ * sh_files.c: fix missing use of flag_err_info
+ * sh_tiger0.c: remove repetitive use of mlock
+ * slib.c: remove fcntl's from sl_read_timeout (caller sets O_NONBLOCK),
+ add function sl_read_timeout_prep
+
+2.1.3 (13-03-2006):
+ * fix compile problem in slib.c (reported by Lawrence Bowie)
+ * fix bug with combination of one-shot update mode and file check
+ schedule (reportedby Dan Track)
+ * improved the windows howto according to suggestions by
+ Jorge Morgado
+ * fix samhain_hide kernel module for new linux kernel versions
+ * fix minor problem with dead client detection (problem reported
+ by Michal Kustosik)
+
+2.1.2 (10-01-2006):
+ * fix startup error with combination of gpg+prelude
+
+2.1.1a (22-12-2005):
+ * fixed a stupid bug in sh_files.c (break if file = dir)
+
+2.1.1 (21-12-2005):
+ * sh_calls.c: protect sh_calls_set_bind_addr against overriding
+ * comINSTALL, updateDB: use locking
+ * samhainadmin.pl: use locking
+ * fix typos in samhainrc.solaris (noticed by Robby Cauwerts)
+ * improve zAVLSearch (remove redundant strcmp)
+ * use AVL tree in sh_files.c instead of linked list (better scaling)
+ * fix bug with suidcheck (no update/check in one-shot mode with
+ schedule instead of check interval; noticed by R. Rati)
+ * fix for problem with '-t update -i' if daemon mode (problem report
+ by Peter van der Does)
+ * fix for bug in sh_util_ask_update (two returns were required ...)
+
+2.1.0 (31-10-2005):
+ * minor fix for cross-compiling with --with-kcheck
+ * sh_forward.c: handle bad fds in the select() fd sets
+ (reported by hmy)
+ * sh_extern.c: fix debugging code
+ * slib.c, sh_calls.c, sh_calls.h: improve handling of O_NOATIME
+ (reported by Gabor Kiss)
+ * makefile.in: fix for solaris package creation
+ * sh_mail.c, sh_readconf.c: mail filtering options
+ * sh_database.c: Oracle reconnect on connection failure
+ (bug report by Alexander A. Sobyanin)
+ * sh_unix.c: don't purge MYSQL_UNIX_PORT environment variable
+ (problem reported by Peter)
+ * sh_calls.c: fix for a HP-UX accept() problem caused by the gcc4 fix
+ * fixes for gcc 4.0.2 compiler warnings
+ * ability to use daemon mode together with update
+ (wishlist Yoan Vandoorselaere)
+ * fixes for debugging
+
+2.0.10a (22-08-2005):
+ * fix for overlapping directory check specification (reported by Bub)
+
+2.0.10 (21-08-2005):
+ * fix for segfault (free() on a constant string) with libprelude
+ (problem reported by Grae Noble)
+ * upgrade FreeBSD kernel check to 5.4, minor fixes
+ * useful script for users of Linux kernel check
+ (contributed by marc heisterkamp)
+ * documentation improvements (suggested by Brian Seklecki and Robby)
+
+2.0.9 (25-08-2005):
+ * samhain_erase.c: add #define for NULL
+ * sh_suidchk.c: fix incorrect use of escaped filename
+ * sh_prelude.[ch], sh_readconf.c: configurable mapping from
+ samhain severity to prelude severity
+ * sh_unix.h: second arg of gettimeofday should be NULL
+ * sh_files.c: fix checking of directory special file (use specified
+ policy, not that of parent dir, problem found by Brian A. Seklecki)
+ * sh_entropy.c: longer timeout for entropy collector
+ * sh_socket.c, sh_forward.c: allow probing of clients for
+ necessity of configuration reload
+ * yulectl: minor fixes, option -v (verbose), new command PROBE
+ * fix 'File not found' messages for files flagged with IgnoreMissing
+ * sh_database.c: strip newline from oracle error messages
+ * sh_files.c: fix rsrc fork issue with MacOS X Tiger
+ (reported by A. Koren)
+ * never compute checksum if not checked (problem report by D.Hughes)
+ * sh_prelude.c: cleanup and bugfix by Yoann
+ * sh_hash.c: for prelude, make sure mode is supplied with user/group
+ and vice versa
+ * sh_prelude.c: provide proper FileAccess objects (bug
+ report by Mihai Ilinca)
+
+2.0.8 (03-07-2005):
+ * configure.ac: use $LIBPRELUDE_PTHREAD_CFLAGS rather than
+ $LIBPRELUDE_CFLAGS (bugfix by Yoann)
+ * samhain.spec.in: remove support for chkconfig (it's too buggy).
+ Strangely, if invoked as install_initd it behaves sanely ...
+ * src/sh_err_log.c: fix key input (this time for real)
+ * fix --with-altlogserver (bug from 2.0.7b)
+ * remove server socket in start/stop script
+
+2.0.7e (not released):
+ * Makefile.in: introduce a total of 6 sec delay for 'make' utilities
+ that use 1 sec resolution, and consider target out-of-date if
+ timestamp(target) = timestamp(dependency) ...
+ * src/sh_err_log.c: fix key input
+ * another fix for yulectl (use pwent->pw_dir)
+ * dsys/comINSTALL, dsys/comUNINSTALL, dsys/comBUILD: fix PATH
+
+2.0.7d (not released):
+ * one more fix for the spec file (stupid rpm finds tags in comments!!!)
+
+2.0.7c (not released):
+ * test/testrun_1b.sh, test/testrun_2b.sh: use $GPG_PATH
+ * dsys/comINSTALL, dsys/funcDB, dsys/funcINSTALL: some bugfixes
+ * samhain-install.sh.in: fix test -z $verbose
+ * sh_hash.c: speedup database reading
+ * Makefile.in: fix the problem that BSD make would make too much
+ * deploy: yulerc.clients -> yulerc.install.db, provide
+ $defdatabase for backward compatibility
+ * deploy: allow for comma in client_install_date
+
+2.0.7b (not released):
+ * hp_ux.psf.in: fix psf file
+ * dsys/comINSTALL: fix $yule_date -> $yule_data
+ * Makefile.in: fix 'make depot'
+ * sh_tools.c, sh_unix.c: fix detection of open file limit
+ * sh_readconf.c: reset read_mode after reading conf file
+ * yulectl.c: better error messages, use homedir from getpwuid(geteuid)
+ * init/samhain.startLSB.in: fix misleading message in lsb init script
+ * sh_forward.c: better display for nonce u in debug mode
+ * sh_tiger*.c: fix checksum for HP-UX 64bit
+ * samhain.c: don't fetch database twice
+ * configure.ac: accept nodename for --with-logserver=...
+ * samhain_setpwd.c: return proper exit status for samhain_setpwd
+ * respond to SIGTERM on initializing
+ * fix problems with samhainadmin.pl
+ * sh_utils.c: fix bug with AddOKChars (found by Karol)
+
+2.0.7a (not released):
+ * remove 'df' from entropy gatherer (NFS may hang)
+ * modify va_copy check (doesn't work with HP-UX PA64 compiler)
+ * fix compile warnings in sh_database.c
+ * samhain-install.sh.in: check for /usr/bin/false in /etc/shells
+ * fix install-boot on HP-UX
+ * aclocal.m4: fix configure CL parsing to recognize VAR=VALUE
+
+2.0.7 (11-06-2005):
+ * yet another fix for the spec file (use internal dependency generator)
+ * sh_error.c, sh_prelude.c: init libprelude after open fds are closed
+ * error message if queue is full
+ * fix two compiler warnings on HP-UX
+ * fix sh_mail.c for Interix (no resolver routines)
+ * fix sh_unix_initgroups2() if no initgroups() function (bug reported
+ by Geries Handal)
+ * remove references to 'struct timezone' (Interix; problem
+ reported by Geries Handal)
+ * init/stop for prelude on SIGHUP
+ * sh_cat.h: fix a stupid bug with messages classes
+ * manual: new section on nagios (with help from kiarna),
+ more on prelude
+ * sh_prelude.c: cleanup and improvements (Yoann Vandorselaere)
+ * default prelude profile name now is 'samhain' (lowercase)
+ * sh_readconf.c: new option PreludeProfile (by Yoann Vandorselaere)
+ * remove obsolete check for linux/module.h, linux/unistd.h
+ * remove dependency on virtual/glibc in gentoo ebuild
+ (problem reported by Willis Sarka)
+
+2.0.6 (01-03-2005):
+ * sh_prelude.c, configure.ac, aclocal.m4: support for
+ libprelude 0.9 (Yoann Vandoorselaere)
+ * sh_html.c: fix bug with entry.html template (reported by
+ Stephane Sanchez)
+ * Install.sh: fix mandir option (reported by Rodney Smith)
+ * Fixed Linux/64bit bug in definition of EUIDSLOT
+ * New targets 'make depot', 'make depot-light' (HP-UX, untested)
+ * Use sstrip for RPMs and DEBs (automatic stripping disabled)
+ * Fix aclocal.m4 for autoconf 2.59 (missing $ac_cr_alnum et al.,
+ problem noticed by Yoann Vandoorselaere)
+ * Modify samhain.spec.in to disable automatic stripping upon install
+ * Fix deploy.sh + '--enable-gpg', and fix 'make rpm' and 'make deb'
+ for '--with-khide' (problems reported by Mark)
+ * Fix compile error in sh_tools.c on HP-UX 10.20
+ (problem reported by Dennis Boylan)
+ * Runtime configuration of server listening port (wishlist)
+ * Runtime configuration of server listening interface (wishlist)
+ * Ignore SIGTTIN (consistency)
+ * Use SIGTTOU to force file check (wishlist)
+
+2.0.5b (01-04-2005):
+ * Fix build problem b/o timestamp on stamp file
+
+2.0.5a (16-03-2005):
+ * Fix problem with 'make rpm' (reported by Dirk Brümmer)
+
+2.0.5 (02-03-2005):
+ * Fix bug with partial reads from clients in server
+ (bug report by Brian)
+ * Support gpg checksum bootstrap with yule
+ * Support mount option check on HP-UX
+ * For MAIL FROM, use 'example.com' as domain part if
+ hostname is numeric (problem reported by Eric Raymond)
+ * The HOWTO-write-modules has been updated.
+ * Convenience functions to insert data in database have been
+ added.
+ * Use int0x03 only on i386 in sh_derr() (portability problem
+ reported by John Mandeville)
+
+2.0.4 (09-02-2005):
+ * Fixed broken 'make deb' (problem report by olfi)
+ * Fixed minor bug in test scripts (detection of gmake vs. make)
+ * Fixed Tru64/OSF compile warnings (reported by B. Terp)
+ * Normalize list parsing to allow comma, space, and tab as separators
+ * Some more descriptive error messages in kern_head.c
+ * Absolute path to utilities in init/samhain.startLinux.in
+ * Fixed is_root variable in deploy.sh
+ * Fixed 'deploy.sh info'
+ * Fixed 'deploy.sh install' client startup
+ * Fixed 'make tbz': don't remove ebuild scripts in 'make dist'
+ (issue reported by W. Sarky)
+
+2.0.3 (14-12-2004):
+ * Fix CPPFLAGS with mysql/postgresql (repoted by P. Smith)
+ * Fix missing sys/time.h include in slib.c (reported by Jonas)
+ * Workaround for file closing problem with Prelude+GPG
+ * Fixed memory leak with Prelude.
+ * Fixed bug in samhain_stealth (PGP signature not correctly
+ retrieved from hidden configuration; report and patch by V. Tuska)
+ * Added Perl script to concatenate file signature database files
+ * Fix compile error with combination of --enable-nocl and
+ --enable-stealth (reported by Zdenek Polach)
+ * Fix bug in dsys/initscript with --enable-nocl
+ * Fix declaration of sh_kern_timer()
+ * Fix missing Mounts+Userfiles options in appendix of manual
+ * Updated the README (bug report by H. Franzke)
+ * Fix some compiler warnings
+
+2.0.2a (09-11-2004):
+ * Fixed OoM condition when client rc file not found (reported by Eilko)
+
+2.0.2 (08-11-2004):
+ * Fixed buffer overflow in sh_hash_compdata() (only in 'update' code)
+ * Fixed uninitialized variable in sh_mail_msg() (problem reported
+ by Michael Milvich)
+ * Fixed potential NULL pointer dereference in sh_hash_compdata()
+
+2.0.1 (01-11-2004):
+ * Fixed compilation bug reported by jue (--with-kcheck broken).
+ * Fixed start option (bug reported by sanek). Behaviour wrt.
+ environment variables depended on the way the daemon was started.
+
+2.0.0 (31-10-2004):
+ * The deployment system has been rewritten from scratch in
+ a cleaner and more modular and extensible way. Deployment
+ of native packages is supported now.
+ * The build system has been revised. Building outside the source
+ directory is supported now.
+ * Support for checksumming of prelinked executables / libraries
+ has been added.
+ * The configure script now checks for the SSP/ProPolice patch in GCC,
+ and enables it if present.
+ * The install-boot option in samhain-install.sh has been fixed
+ (use absolute paths for sbin utilities).
+ * A nagios plugin (scripts/check_samhain.pl) has been added.
+ * The LSB (Linux Standard Base) init script has been fixed (the output
+ was incorrect).
+ * Fetching of built binary packages has been
+ fixed ($(PACKAGE)->@install_name@).
+ * For files in proc, the timeout has been reduced, and no error
+ messages are issued upon timeout.
+ * A function has been added to print out full details for missing
+ files if encountered while in sh_files().
+ * The reporting for SuidCheck has been fixed (incorrect policy
+ noticed by JiM).
+ * On Linux, SuidCheck does not report on files marked as candidates
+ for mandatory locking (group-id bit set, group-execute bit cleared).
+ * Fix for oracle init script (by Matt Warner)
+
+1.8.12b (11-10-2004):
+ * fix bug in MSG_MSTAMP (%ld -> %lu)
+ * fix bugs in sh_suidchk.c (%ld -> %lu), check fopen for NULL,
+ mkdir mode for quarantine directory
+ * fix the fix for modlist_lock search in System.map
+
+1.8.12a (01-10-2004):
+ * fix bug in samhain-install.sh.in (only occurs on Solaris), reported
+ by J. Roland
+
+1.8.12 (27-09-2004):
+ * fix compile bug with --enable-static + --with-database=postgresql
+ * fix search for modlist_lock in System.map
+ * password auth for yule command socket (request by D. Kocic)
+ * more info about pending/sent commands to clients
+
+1.8.11 (30-08-2004):
+ * fix static linking on Linux by use of replacement routines from
+ uClib - however, this means, there is no NIS support anymore
+ * new option AddOKChars=... to modify the set of characters for
+ filenames considered 'obscure'
+ * new option HardlinkOffset=... to specify an offset from the canonical
+ hardlink count for a directory
+ * fix some warning with HP 11.23 native compiler
+ * fix minor OpenBSD portability problems (EIDRM, compiler warning)
+ * samhainrc.5, samhain.8: updated the man pages
+ * sh_unix.c, sh_files.c: ignore 'no user/group' and 'obscure name'
+ for AllIgnore
+ * sh_kern.c: fix 'update' to display modifications
+ * sh_kern.c: fix bug with IDT check (spurious alerts b/o uninitialized
+ fields)
+ * stealth kernel modules: fix for linux 2.6, fix
+ redefine of KERNEL_VERSION
+ * warn about stealth kernel module problem with 2.6 in manual
+ * sh_unix.c: remove some cruft
+ * fix a typo in the manual (noticed by J. Rubin)
+ * configure.ac: re-order output from libprelude-config (required
+ for static linking - problem reported by E. Neber)
+ * kern_head.h, kern_head.c: fixes for Linux 2.6 kernel
+
+1.8.10b (13-07-2004):
+ * fix incorrect usage of 'retry_msleep()' in sh_kern.c (reported
+ by Pat Smith)
+
+1.8.10a (13-07-2004):
+ * depend-gen.c: fix for FreeBSD 'make' which does not understand
+ the dependencies ... (problem reported by David Thiel)
+
+1.8.10 (13-07-2004):
+ * sh_unix.c/sh_unix.h: fix defaults for 'GrowingLogFiles' policy
+ (bug report by VZoubkov)
+ * fix some warnings (unreachable statement) with HP-UX native compiler
+ * kern_check.c: silence warning about 'sendfile' for 4.10
+ (noticed by Ryan Beasley)
+ * modify depend-gen.c to ignore sh_gpg_chksum.h
+ * add a non-plaintext version of GPG_HASH (sh_gpg_chksum.h)
+ * .. and for fingerprint
+ * sh_suidchk.c: fix some compiler warnings on solaris
+ * allow commas to separate multiple entries in a RedefXXX= directive
+ * replace sleep/usleep with nanosleep wrapper function
+ * replace alarm() for read timeout with select() in sl_read_timeout
+ (should fix bug reported by Scott Kelley)
+ * increase lstat/open timeout to 6 sec
+
+1.8.9 (16-06-2004):
+ * made 'no action specified' error message more informative
+ (suggested by Stephen Gill)
+ * fix memory leak in mysql sh_database_query() (bug report by Dejan)
+ * remove some cruft from the code
+ * sh_files.c: check MacOS X resource forks (idea from Osiris)
+ * sh_files.c: no hardlink check for MacOS X
+ * sh_util_ask_update: fix bug with no terminal in non-interactive mode
+ (report and debug data by Kris Dom)
+ * manual refactored
+ * fix redundant messages when updating with suidcheck
+ * allow interactive update for suid files
+ * don't remove the TZ environment variable to guard against
+ misconfigured hosts
+ * also use gethostname if uname returns possibly truncated name
+ * fix improper file descriptor handling in sh_mail.c (bug report
+ by Alex Weiss)
+ * cleanup MBLK cruft
+ * use SH_ALLOC/SH_FREE in sh_prelude.c
+ * update sstrip to Version 2.0
+
+1.8.8 (25-05-2004):
+ * fix compilation problem on AIX 5.2 (nameser_compat.h; report by
+ Tim Evans and Ian McCulloch)
+ * don't check for trusted paths on Cygwin
+ * add Windows HOWTO written by Kris Dom
+ * kern_check.h: extend FreeBSD syscall table for 5.x
+
+1.8.7a (03-05-2004):
+ * sh_mail.c: fix subject length
+ * sh_mail.c: fix the sh.mailNum.alarm_last fix (report by Kris Dom)
+ * sh_utils.c: sh_util_ask_update(): fix ISO C conformance bug
+ (compile problem reported by Kris Dom)
+
+1.8.7 (01-05-2004):
+ * sh_mail.c: fix incorrect count of sh.mailNum.alarm_last, causing
+ empty mails (introduced with segfault fix in 1.8.6, report
+ by Kris Dom)
+ * sh_utils.c: sh_util_ask_update(): check whether stdin is a terminal,
+ try to reopen on controlling terminal if not
+ * sh_utmp.c: fix order of options (problem report by Uri)
+ * sh_files.c: sh_files_chk(): set tmp = NULL at end of loop
+ (may cause segfault on null dereference for missing files)
+ * sh_unix.c: patch by Marc Schütz (order of sh_unix_getinfo_type,
+ sh_unix_getinfo_attr)
+ * don't use dh_installmanpages in 'make deb' (samhain/yule conflict
+ reported by xavier)
+ * on HP-UX, define _XOPEN_SOURCE_EXTENDED in sh_mail.c and sh_tools.c
+ (suggested by Kris)
+ * include nameser_compat.h in sh_mail.c (for MacOS X,
+ suggestion by jna)
+ * sh_utmp.c: fix time for logout events (reported by Erich
+ van der Velde)
+
+1.8.6 (15-04-2004):
+ * add CL option to set threshold for prelude and RDBMS
+ * sh_mail.c: fix bug with MailSubject option (segfault on NULL pointer
+ dereference; reported by Micha Silver)
+ * fix compiling with --disable-encrypt (reported by Pat Smith)
+ * fix minor problem in scheduler (don't return before all schedules
+ are tested, to set last_exec correctly)
+
+1.8.5 (05-04-2004):
+ * fix bugs in sh_utmp.c (unlinking of list head); may fix an OpenBSD
+ problem (endless loop; report and debugging aid by Joe MacDonald)
+ * fix hardlink check (null dereference in error message, segfaults
+ on solaris - noticed by Bob Bloom)
+ * sh_suidcheck: don't truncate quarantined file if nlink > 1
+ * fix Install.sh (no --seperate-output with --radiolist); patch by
+ Greg Kimberly
+
+1.8.4 (17-03-2004):
+ * add Prelude patch by Patrice Bourgin
+ * add license statement to sh_mounts.c, sh_userfiles.c after
+ receiving a clarifying e-mail from Cian Synnott
+ * support UsePersistent = no for Oracle (problem spotted and fix
+ tested by Michael Somers)
+ * fix bug in samhainadmin.pl
+ * sh_gpg.c: describe type of gpg error (if any)
+ * fix persistent connections with postgresql (reported by
+ Erwin Van de Velde)
+ * prelude: local 'meaning' shadows global in sh_prelude_alert
+ (spotted by David Maciejak)
+ * uname: workaround for cases where nodename would be a possibly
+ truncated FQDN (problem reported by Cian Synnott)
+ * re-write parts of sh_kern.c, store kernel info in baseline database
+ -> no need to recompile after kernel upgrade
+ * modify timeouts in sh_unix_getinfo, add timeout warning
+ * change handling of dangling symlinks (store in db)
+ * fix typo with MSG_FI_OBSC2 (double slash)
+ * remove redundant operation in sh_utils_safe_name
+ * fix occasional random start bytes of long messages in
+ sh_error_string (sl_strlcat -> sl_strlcpy)
+ * provide details for missing files (as for added files)
+ * remove duplicate message for no such group/user
+ * add fixes for samhain.oracle.init (supplied by Michael Somers)
+ * fix date insertion for Oracle (fix by Michael Somers)
+ * manual: fix incorrect statement about RPM (noticed by
+ Lars Kellogg-Stedman)
+
+1.8.3 (02-02-2004):
+ * add a HOWTO-client+server-troubleshooting document
+ * fix another bug with SIGUSR2 (suspend mode)
+ * new option SetBindAddress (--bind-address=...) to force
+ interface for outgoing connections on multi-interface box
+ * don't link against libgmp if not required (i.e. standalone)
+ * test for ext2fs/ext2_fs.h or linux/ext2_fs.h
+ * new make targets 'emerge' and 'tbz2' for gentoo
+ * update rules.deb.in based on the Debian package
+ by Javier Fernandez-Sanguino
+ * updated config.guess, config.sub to version 2002-09-05
+ * external command: report failure only once
+ * console: reset failure status after success
+ * README.UPGRADE: explain 1.7.x <-> 1.8.x client/server compatibility
+ * use persistent connection to database by default
+ * option UsePersistent=no to switch off persistent connection
+
+1.8.2 (19-01-2004):
+ * sh_userfiles.c: new option UserfilesCheckUids (requested)
+ * sh_error.c: server: don't log to logfile before dropping root
+ * new script scripts/samhainadmin.pl (administrative tasks for
+ signed config/database files)
+ * add changes code to log_msg for reports on modified files
+ * change default log threshold to 'mark', as 'none' tends
+ to confuse new users
+ * faster response time for SIGUSR2
+ * revised (mostly backward-compatible) message classes
+ * fix missing check of mailTime in server select loop
+ * add support for libprelude (version 0.8.10)
+ * fix format for MSG_E_GRNULL (reported by Stefan Hudson)
+ * fix Bourne shell incompatibility (export) in samhain-install.sh
+ (first reported by David Thiel)
+ * fix typo in spec file (first reported by Christian Vanguers)
+ * remove some cruft (signal handler, memory handling)
+ * return from sigterm handler, rather than exit directly
+ (re-entrancy problem causes more problems than it's worth)
+
+1.8.1 (03-12-2003):
+ * fix gmp detection (problem pointed out by Nix)
+ * fix/improve the error message if test compiling with mysql fails
+ * new CL option --interactive for interactive db update
+ * fix some compiler warnings from IRIX MIPS compiler
+ * kern_head.h, kern_head.c: option to disable IDT check
+ * kern_head.h, kern_head.c: update kernel syscall table (2.4.20,2.6)
+ * sh_utmp.c: count number of logins (request by Erwin Van De Velde)
+ * change username -> userid, remove (long) userid (bug noticed
+ by Erwin Van De Velde)
+ * emit ADDED message for new SUID/SGID files
+ * add trailing slash to excluded directory if there is none
+
+1.8.0a (04-11-2003):
+ * sh_error.c: remove two debug printf's
+
+1.8.0 (31-10-2003):
+ * manual: make ps file fit on both a4 and letter paper
+ * sh_socket.c, sh_socket.h, sh_forward.c: socket interface
+ to send (quit/reload) commands to clients
+ * sh_forward.c, configure.ac: enable build with libwrap
+ (Wietse Venema's TCP Wrappers library)
+ * sh_ignore.c, sh_ignore.h, sh_files.c, sh_hash.c, sh_readconf.c:
+ new option to suppress messages for new and/or deleted files
+ * samhainrc.aix5.2.0: contributed by Christoph Kiefer
+ * samhain.c: fix compile warning on solaris (noticed by Ian Hunt)
+ * sh_database.c: undef debug code for oracle
+ * samhain.oracle.init: contributed by Joern Michael Krueger
+ * configure.ac, sh_utils.ac, Makefile.in, sh_modules.c,
+ sh_cat.c, sh_cat.h, sh_mounts.c/h, sh_userfiles.c/h:
+ check-mounts and userfiles modules contributed by eircom.net
+ * sh_utils.c: fix off-by-one bug in sh_util_compress()
+ * sh_forward.c, sh_tools.c, configure.ac:
+ version 2 client/server protocol
+ * sh_mail.c: add %S to include severity in subject (user request)
+ * sh_suidchk.c, 1093: fix warning about unused var 'flags' on FreeBSD
+ * samhain.h, sh_unix.h, sh_unix.c: extern inline -> static inline
+ for --enable-ptrace
+ * samhain.c: lower priority for 'uninitialized module' message
+ * sh_entropy.c: lower priority for message if /dev/random blocks and
+ /dev/urandom is available
+ * improved error messages in sh_readconf.c
+ * print system error message for getpwuid, getgrgid
+ * fix missing module init after SIGHUP (noticed by Cian Synnott)
+
+1.7.12 (13-10-2003):
+ * sh_mail.c: fix buffer overflow in mail handler (introduced in 1.7.10)
+ thanks to bug reports by Jason Martin and Matthew P. Cox
+
+1.7.11 (01-09-2003):
+ * samhain.c, samhain.h, sh_unix.c, sh_forward.c, sh_html.h:
+ - change SIG_USR1 to switch between dbg on/off
+ - change SIG_USR2 to switch between suspend on/off
+ - fix CLT_ILLEGAL to actually work
+ - introduce new state CLT_SUSPEND
+ - force reauthentication after suspend
+ * slib.c: change MAXFD from FOPEN_MAX (16) -> 1024
+ * sh_suidchk.c: better AIX fs detection (Christoph)
+ * sh_entropy.c: increase buffer size for unix entropy gatherer
+ (problem reported by D. Danielson)
+ * default config files: add lots of comments, list more options
+ * sh_error.c: set default severities to 'crit'
+ * sh_readconf.c, sh_cat.c, sh_cat.h: stricter check on config
+ file syntax, issue warnings (triggered by C. Kiefer)
+ * Makefile.in: handle depend-gen errors more gracefully
+ * sh_err_console.c: fix bug in enable_msgq (reported by F. Behrens)
+ * configure.ac: workaround for mysql_config weird output
+ (reported by G. Faron)
+ * sh_unix.c, sh_tiger0.c: check IO limit during read of large files
+ * depend-gen.c: close streams before attempting to rename (Cygwin)
+ * Makefile.in: fail gracefully if depend-gen fails
+ * sh_database.c: sh_database_query(postgresql): fixed missing SL_ENTER
+
+1.7.10 (27-07-2003):
+ * FreeBSD init script: define $pidfile (reported by D. Thiel)
+ * sh_unix.c, sh_unix.h: fix compile error on AIX 4.2
+ * sh_schedule.c: fix bad array size
+ * samhain.c: fix pid_t <> int casts
+ * sh_kern.c: fix repetitive messages
+ * configure.ac: try to bootstrap if TIGER192 not supported by gpg,
+ provide a detailed error message
+ * configure.ac: try harder to locate mysql
+ * docs/Changelog: retroactively add release dates, if known
+ * sh_mail.c: fix potential message truncation in mailer
+ * sh_unix.c, samhain.c, samhain.h: make --enable-ptrace more portable
+ * sh_readconf.c: fix segfault (dereference of uninitialized pointer)
+ if --with-gpg and --enable-stealth are used together (reported
+ by Anthony Caetano)
+ * sh_unix.c, samhain.c, sh_calls.c: fix problems with descriptive
+ error messages (larger GLOB_LEN, stat fills aud_err_message)
+
+1.7.9 (30-06-2003):
+ * sh_err_log.c: fix segfault on SIGABRT (dereference of freed memory),
+ problems with SIGABRT noticed by Brian and Alf B Lervåg
+ * deploy.sh.in: fix some bugs (found by Alf B Lervåg)
+ * scripts/chroot.sh: fix typo (found by Alf B Lervåg)
+ * configure.ac (khide): search also for 'd sys_call_table' (noted by
+ cuek_saja)
+ * strip whitespace before checking gpg checksum (noted by D. Thiel)
+ * manual (faq section): explain how to stop console output
+ * Makefile.in: fix re-naming of yule with --enable-install-name
+ * HOWTO-client+server.html: fix typo (noted by xavier renaut)
+ * configure.ac: escape '-' in awk regex (required by GNU awk 3.1.1)
+
+1.7.8 (28-05-2003):
+ * sh_unix.c: new mlock implementation with reference count
+ and page alignment (fix for solaris problem)
+ * kern_head.c: search also for 'xxxxxxxx d sys_call_table'
+ * sh_html.c: write status comment (for Beltane 2)
+ * add CL option --delimited for comma-delimited signature database dump
+ * sh_mail.c: check exit status of push_list to fix counting bug
+ (bug reported by Alan Moore)
+ * configure.ac: add error message to --with-libs
+ * fix spelling of $DAEMON in init script (noted by C. Grigoriu)
+ * fix missing initgroups()
+
+1.7.7 (06-05-2003):
+ * sh_forward.c: fix bug if compiled with --enable-udp, but disabled
+ in config file (found by Andy OBrien)
+ * sh_database.c: sh_database_entry(): size -> c_size (two places)
+ to fix writing of '\0' to arbitrary places :(
+ (problem pointed out by Stefan Giesen)
+ * profiles/*/configopts: fix --with-base -> --enable-base
+
+1.7.6 (24-04-2003):
+ * sh_forward.c, entry.html, head.html: fix/additions by Stefan Giesen
+ * fix samhain_hide for the O(1) scheduler used by RedHat:
+ configure.ac, acconfig.h: check for next_task in struct task_struct
+ samhain_hide.c: use find_task_by_pid if no next_task in task_struct
+ * samhain_erase.c: add MODULE_LICENSE("GPL") to fix warning
+
+1.7.5 (15-04-2003):
+ * sh_cat.c, sh_forward.c, sh_hash.c: fix double 'msg' tag
+ * manual: point out the bmaxdata problem on AIX in faq section
+ * trustfile.c: don't check symlinks (permissions of directory count)
+ * sh_schedule.c: fix problem with daylight saving switchover
+ * sh_samhain.c: close all open fd's >2 before reading the conf file
+ * sh_unix.c: fix dereferenced NULL pointer when exiting on non-existing
+ user
+ * sh_forward.c: fix dereferenced NULL pointer when exiting on udp error
+ * sh_forward.c: place timestamp code before select() timeout handler
+ * fix incorrect class of timestamp messages (conflict with manual)
+ * sh_readconf.c, sh_forward.c: new config option SetStripDomain
+ * configure.ac: add warning if /lib/modules/`uname -r`/build/include
+ not found
+ * samhain_hide.c: adapt for RedHat 2.4 kernel (fetch sys_call_table
+ address from System.map)
+ * sh_err_syslog.c: fix for Solaris
+ * samhain.spec.in: strip REQ_FROM_SERVER from config file install path
+
+1.7.4 (21-03-2003):
+ * configure.ac: fix bug in defargs (--with-base > --enable-base)
+ * aclocal.ac: detect unsupported options
+ * kern_check: add syscalls, skip unused syscalls
+ * fix Manual (--enable.../--with... inconsistency)
+ * add two HOWTOs (signed files, server/client)
+ * moved manual into new subdirectory docs/
+ * add admin scripts by S.Bailey/M.Redinger
+ * option to have a version string in db file
+
+1.7.3 (23-02-2003):
+ * samhain-install.sh: use yule user key for signing on install
+ * fix a bug in sh_err_console.c (attempted write to const char)
+ * sh_gpg.c: if server, always use ~unprivileged_user/.gnupg
+ * Makefile.in: make target 'trustfile' depend on config.h
+ * configure.ac: don't use install_name before it is defined ...
+ * sh_tiger0.c: fix bug in checksum computation introduced in 1.7.2
+ * samhain.c: make sure daemon cannot be forced into 'update' mode
+ * sh_hash.c: remove AIX workaround (AIX has been fixed meanwhile)
+
+1.7.2 (04-02-2003):
+ * sh_kern.c: use sys_call_table address from System.map
+ * fix for reserved SQL keyword 'group'
+ * add AC_SYS_LARGEFILE to configure.ac
+ * allow separate client-specific log files for server
+ * sstrip.c: compile sstrip code only for i386
+ * sh_unix.c: closeall: don't close trace file
+ * slib.c: don't trace sl_is_suid (leads to recursion in trace handler)
+ * samhain-install.sh.in: fix detection of LSB compliant systems
+ * sh_tools.c: get_client_*_file: lstat -> stat to allow symlinks
+ * sh_forward.c: sh_forward_do_write: set O_NONBLOCK for fd
+ (may block otherwise, for no good reason apparently ...)
+ * samhain.spec.in: replace %configure with ./configure
+ * sh_unix.c: re-write signal handling (use __malloc_hook et al. to
+ check whether we are in the middle of a free/malloc/realloc/memalign)
+ * sh_unix.c: use new safe_logger() function to log from signal handler
+ * sh_err_log.c: fix xml
+ *
+ * fix Makefile.in to exit non-zero on compile failure
+ * database init: create index on log_host, entry_status
+ * sh_suidchk.c: fix path building
+ * sh_tiger0.c: read larger blocks
+ * sh_hash.c: cast inode to UINT32
+ * sh_tools.c: check that config/database files size fits in uint
+ * sh_error.c: export flag_err_debug to avoid unnecessary calls
+ * sh_unix.c: save the open() call in sh_unix_getinfo_attr()
+ * profiles/redhat_i386/bootscript: add # description field
+ * deploy.sh.in: set owner + permissions for files in yule_filedir
+ * profiles/debianlinux_i386: fix bootscript
+ * Makefile.in: fix deploy file lists and targets (include init+scripts)
+ * MLOCK GOOD/BAD -> SL_FALSE/SL_TRUE
+ * sh_mail.c: GOOD/BAD -> SL_FALSE/SL_TRUE (AIX sys/param.h)
+ * sh_err_syslog.c: split long messages rather than truncating
+ * sh_error.c: allocate msg to fix truncation limit
+ * sh_unix.c: closeall fd's >= 3 in non-daemon mode (inherited
+ filedescriptors may exceed FOPEN_MAX, causing problems in
+ sl_open_file)
+ * sh_err_console.c: avoid stdio
+ * trustfile: dirz: make swp[] static
+ * slib.c: speed up sl_strlcat
+ * clean up some bad heap allocation (PATH_MAX+(1|2) -> PATH_MAX)
+ * remove some unused code
+ * slib.c: support long long int in the snprintf replacement
+ * configure.ac: new configure macro to check whether sa_sigaction works
+ * Makefile.in: make sstrip, encode dependent on config.h
+
+1.7.1a (08-01-2003):
+ * fix a syntax error in samhain-install.sh.in
+
+1.7.1 (07-01-2003):
+ * search runlevel scripts in ./init or ./
+ * handle all distro-specific Linux runlevel script issues
+ within a single script
+ * support install-boot on Yellow Dog Linux and Slackware
+ * samhain-install.sh: fix a bug for unknown Linux
+ ('"' not closed, DVER not set)
+ * samhain-install.sh: check for /etc/yellowdog-release
+ * sh_database.c: fix missing entry for 'userid' in attr_tab[]
+ * fix debian.rules.in (disable sstrip)
+ * update make targets: 'srpm', 'srpm-dist', 'rpm'
+ * check for zlib if mysql is used
+ * workaround for NetBSD bug with libresolve
+ * fixed problems with spec files
+
+1.7.0 (22-12-2002):
+ * improved spec files (Andre Oliveira da Costa <brblueser@uol.com.br>)
+ * sh_unix.c: fix a dereferenced static pointer in tf_trust_check
+ * runlevel scripts: remove pid file after stop
+ * make the data directory read-only for the daemon
+ * treat 'localhost' specially in MX resolver
+ * sh_err_log.c: set sh.flag.log_start == TRUE after writing </trail>
+ * deploy.sh.in: fix quoting (fix by Simon Bailey)
+ * slib.c: make sl_get_euid et al. behave well if uids not stored
+ * trustfile.c: use euid = uid(SH_IDENT) if server
+ * sh_mail.c: include an MX resolver
+ * Makefile.in: install-user routine for user installation
+ * have yule drop root
+ * sh_tools.c: open_temp use logdir if server
+ * unified options for runlevel script
+ * HP-UX, IRIX runlevel scripts
+ * AIX inittab entry
+
+1.6.6 (13-12-2002):
+ * configure.ac: solaris cc -O2 -> -xO2
+ * sstrip.c: avoid alpha architecture
+ * profiles/solaris/configopts: no --enable-static
+ * sh_forward.c: sh_forward_req_file: copy argument to local array
+
+1.6.5 (04-12-2002):
+ * sh_utmp.c: set userlist = NULL in sh_utmp_end ()
+ * sh_unix.c: do not assume that environ is sane
+ * exit handler: write </trail>
+ * sh_log_file(NULL): test sh.flag.log_start != S_TRUE
+ * FreeBSD rc script does not blindly accept content of pid file
+ * configure.ac: allow 'localhost' for log server
+ * sh_calls.c: retry_connect: ntohs (port)
+ * testrun_2[abc].sh: --with-logserver=localhost for client
+
+1.6.4 (12-11-2002):
+ * sh_tools.c: fix error when escaping '=<'
+ * fix the 'make srpm' target
+ * deploy.sh.in: avoid that client is named 'yule'
+ * define memset to sl_memset
+ * fix type cast of uid_t, gid_t
+
+1.6.3 (31-10-2002):
+ * fix options for Sun/Solaris native compiler
+ * sh_unix.c: MSG_FI_LIST (line 2333): cast theFile->size to fix error
+ * test sstrip on freebsd
+ * default config file for freebsd
+ * make target to build .deb packages
+ * sh_readconf.c: fix bug in error message
+ * samhain.c, sh_suidchk.c: fix initialization of suidchk
+ * samhain-install.sh.in: don't remove config file by default
+ * samhain-install.sh.in: support complete de-installation
+ * samhain-install.sh.in: add support for Gentoo, FreeBSD, and Solaris
+ * samhain-install.sh.in: check more paths
+ * sh_unix.c: fix sys_siglist declaration [NetBSD portability issue]
+ * sh_calls.c: save error message in retry_lstat()
+
+1.6.2 (04-10-2002):
+ * make target to build rpms
+ * update samhain.spec.in, samhain.startRedHat
+ * support DESTDIR, as in 'make DESTDIR=/what/ever install'
+ * explicitely set -fno-omit-frame-pointer b/o gcc bug
+ * mv configure.in to configure.ac to benefit from autoconf wrapper
+ * sh_modules.c, sh_modules.h: add mod_reconf() to run at SIGHUP
+ * slib.c: fix debug messages (no msgs for dlogActive <= 1)
+ * sh_schedule.c, samhain.c, sh_suidchk.c:
+ scheduler may accept multiple schedules
+
+1.6.1 (04-09-2002):
+ * sh_schedule.c: bugfix (executes only after first day)
+ * rm obsolete WITH_TRACE stuff
+ * new dlog() function for debug logging
+ * some more descriptive error messages
+
+1.6.0 (27-08-2002):
+ * omit the -fomit-frame-pointer option (bugs in some gcc versions ?)
+ * sh_error.c: fix escape mode when logging to database
+ * sh_forward.c: fix error (twice escape) in recv_syslog_socket
+ * sh_tools.c: change escape mode for server-received data
+ * sh_mem.c: change ulong -> size_t in sh_mem_malloc()
+ * configure.in: fix localstatedir if --prefix=USR
+ * sh_hash.c: snprintf() -> sl_snprintf()
+
+1.5.5 (07-08-2002):
+ * sh_err_log.c: fix incorrect xml syntax for client messages
+ logged by server
+ * sh_err_log.c: fix incorrect '</trail>' entries on client EXIT
+ * sh_files.c: introduce file_class_next
+ this fixes the problem that a policy for the directory
+ inode erroneously becomes a policy for the directory itself.
+
+1.5.4 (17-07-2002):
+ * sh_hash.c: fix buffer overflow with (micro-)stealth
+ * sh_database.c: set path[] 1024 -> 12288
+ * sh_database.c: set query[] 2048 -> 16383
+ * sh_database.c: set values[] 1024 -> 16383
+ * sh_forward.c: larger limit for message size (16 kB)
+ * trustfile.c: set MAXFILENAME 2048 -> 4096
+ * fixed a bug in the handling of filenames with embedded newlines
+ * sh_files.c: fix missing sh_util_safe_name() in debug output
+ * --with-sender can specify a full address
+ * fix xml log in a backwards compatible way
+
+1.5.3 (03-07-2002):
+ * fix combination of stealth and sql logging
+ * fix some more places where invalid UIDs/GIDs trigger errors
+
+1.5.2 (01-07-2002):
+ * include solaris config file from (sean [at] boran d.o.t com)
+ * test for files/dirz defined twice in the configuration file
+ * option to disable reverse lookup on outbound connections
+ * option to use socket peer as client name (with name resolving)
+ * sh_html.c: fix an HTML bug (twice </head><body>)
+ * sh_suidchk.c: fix warning on AIX b/o dirname()
+ * allow logging server -> syslog if yule is NOT configured to
+ receive syslog messages
+ * define PRIi64 to "lld" if undefined
+ * invalid UIDs: use gid/uid as name, error level SeverityNames
+ * minor fixes for connect_port
+ * sh_hash.c: flush output of db listing before _exit()
+ * configure.in: fix incorrect default ${install_name} for server
+ * configure.in: try harder to find mysql.h / libpq-fe.h
+ * sh_files.c: sh_files_checkdir:
+ closedir() early to not exhaust OPEN_MAX
+
+1.5.1a (30-05-2002):
+ * fix missing LSB init script
+
+1.5.1 (27-05-2002):
+ * fix '-t update' option
+
+1.5.0a (23-05-2002):
+ * fix configure.in
+
+1.5.0 (22-05-2002):
+ * include solaris nosuid patch from (nathoo [at] co d.o.t ru)
+ * similar fix for bsd nosuid
+ * speed up -t update
+ * convert manual to DocBook, distribute html and ps
+ * fix some more problems with configure.in, Makefile.in
+ * fix testsuite, add tests for udp, mysql
+ * MSG_TCP_MSG: host -> remote_host
+ * convert to autoconf 2.53
+ * make c_bits.sh exit with status 0
+ * sh_database.c #include "mysql.h" --> <mysql.h>, ditto libpq-fe.h
+ to avoid dependency tracking problems
+ * samhain.c remove *YULE* #ifdefs
+ * acconfig.h remove *YULE* #undefs
+ * samhain.c: procdirSamhain: lstat --> stat (allow symlink)
+ * configure.in: add checks for correct user input
+ * Makefile.in: add automatic dependency tracking
+ * depend-gen: tool to figure out dependencies
+ * chkconfig comments in redhat start scripts
+
+1.4.8:
+ * sh_database.c: fix missing attr_old, attr_new, (from)host columns
+ * configure.in, Makefile.in: fix an error in the configfile
+ definition with REQ_FROM_SERVER
+ * sh_err_console, sh_err_log: avoid recurrent failure messages
+ * timeout on read from files (/proc)
+ * fix errrors with setjmp/longjmp/alarm
+ * fix memory leak in server (~20 byte/file download in sh_tools, 930)
+ * check gpg signature for files downloaded from server, add a
+ regression test
+ * fix chown in solaris bootscript
+ * provide second scheduler for file check
+ * provide scheduler for file check
+ * provide scheduler for SUID check
+
+1.4.7 (08-04-2002):
+ * make daemon control LSB-compliant (arguments, exit status)
+ * set log_ref = 0 for server messages
+ * boolean option SetDBServerTstamp to disable entering server
+ timestamps for received client messages into database
+ * sh_suidcheck: check for "nosuid" mount option if getmntent is used
+ * fix logrotate script in manual (reported by Scott Worthington)
+ * don't strip numerical IP addresses
+ * check item->status_now != CLT_TOOLONG in client_time_check()
+ * set log_host to client in db client message
+
+1.4.6a (20-03-2002):
+ * define prefix in deploy.sh
+
+1.4.6 (19-03-2002):
+ * modify samhain_hide.c to hide processes on new Linux kernels
+ * better error diagnostics in kern_head.c
+ * fix compile error in all_items ()
+ * check length of install-name in enable-khide (max is 15)
+ * define exec_prefix in deploy.sh.in
+ * make configure a bit more cross-compiler friendly
+
+1.4.5 (07-03-2002):
+ * Make sure missing file is reported even if ptr->reported == S_TRUE
+ because the file has been added.
+ * propagate 'reported' flag from sh_files_checkdir() into file list
+ * close checkfd in sh_gpg_check_file_sign()
+ * sh_derr(): kill(parent, SIGCONT) after ptrace(PT_DETACH,...)
+ * use sh.srvcons.name in dbg() to get debugging info from daemon
+ * option to log file timestamps with localtime instead of GMT
+ * comment out MSG_FI_ADD in sh_dirs_chk () - obsoleted by mandatory
+ sh_files_filecheck(directory) that triggers MSG_FI_ADD in sh_hash.c
+ * set ptr->reported = S_FALSE; for reappeared files in sh_files_chk()
+ to make sure re-disappearing will get reported
+ * new function sh_hash_set_missing() to remove file record
+ without (duplicate) 'missing' message
+ * make sure all items are reported for added files
+ * fix stealth mode with sh_kern (encode sh_ks.h -> sh_ks_xor.h)
+ * clarify in the documentation which gpg options to use for signing
+
+1.4.4 (11-02-2002):
+ * check that parent process has exited before writing PID file
+ * promote MGG_W_CHDIR to SH_ERR_ERR
+ * add error message to sh_unix_testlock
+ * fix missing _() macro in sh_aud_set_functions
+
+1.4.3 (05-02-2002):
+ * don't check attributes for symlinks (may cause device access)
+ * add USE mysql; USE samhain; to samhain.mysql.init
+ * point out the MessageHeader/mysql problem in manual
+ * add -lz to LIBS for mysql
+ * strip after install, avoid double strip
+
+1.4.2 (27-01-2002):
+ * support for EGD
+ * fix some more problems with install-deploy / deploy.sh
+ * fix a bug in profiles/suselinux_i386/bootscript (INSTALL_NAME_)
+ * fixed the 'external logging' test (init rather than none in rc file)
+
+1.4.1:
+ * SuSE: include run level 4+5
+ * install location of hiding kernel modules changed - some insmod
+ variants do not test for /lib/modules/$(uname -r)/module_name.o
+ * new make targets 'install-deploy', 'uninstall-deploy'
+ * fixed make targets 'deploydir', 'deploydirfast'
+ * bail on unsupported CL option in deploy.sh
+ * fix various bugs in deploy.sh
+
+1.4.0 (16-01-2002):
+ * fixed missing 'dirname' on Mac OS X
+ * fixed && tested for/with postgres
+ * 'user=' -> 'userid=' (reserved word in sql)
+ * fix the endianess + size of file database; this changes db format
+ for any non-Linux OS
+ * --enable-old-format for old (V1.3) database format
+ * getopt, samhain.c, samhain.h: option -f to loop if not daemon
+ * sh_hash: list numeric + char data to allow file db update on
+ server side
+ * sh_database: modify handling of integer (long) data
+ * sh_database: datetime in database
+ * sh_database: hash field in database
+ * sh_database: rewrite database insert string construction
+ [use INSERT INTO log (fields) VALUES (values);]
+ * makefile suse 7.x runlevel entries
+
+1.3.7 (06-01-2002):
+ * fix incorrect escape in sh_tools_safe_name
+ * fix sh_error_handle (4. argument) in sh_extern.c
+
+1.3.6c:
+ * fix segfault in sh_database (mysql logging) on solaris
+
+1.3.6b (03-01-2002):
+ * fix syntax error ('==') in Makefile.in
+ * fix configure.in (path for /lib/modules/$(uname -r)/build/include)
+ * fix sh_kern.c (redeclaration of 'j')
+
+1.3.6 (03-01-2002):
+ * sh_kern.c: check integrity of int 80h vector
+ (SucKIT rootkit - Phrack 58)
+ * make sure childs in sh_kern are wait()'ed for
+ * provide start/stop/restart/reload/status interface
+ * fix a potential segfault (dereferenced NULL pointer) in the server
+ * use sh_util_flagval for sh_unix_setdaemon
+ * documentation for logging to SQL database
+ * configure.in: check for -I/lib/modules/$(uname -r)/build/include
+ * fix trustfile.c to ignore invalid users
+ * separate 'make install-samhain' and 'make install-yule'
+ * separate default log/pid/config files for server/client
+ - less problems running server and client on same host
+ * rewrite deploy.sh(.in):
+ - don't use (make|install) if deploying
+ - use command line options
+ - better integrate into server environment
+ - write install db
+ * always write a pidfile if daemon
+ * don't use server's config file as fallback for downloading client
+ * don't overwrite config file when doing 'make install'
+
+1.3.5 (28-12-2001):
+ * fix --enable-message-queue for newer glibc versions
+ * log to SQL database: implemented, but undocumented yet,
+ needs to be tested further
+ * xml: escape received syslog messages
+ * xml: rename 'time' to 'tstamp'
+ * make targets: make [un]install-[boot-]yule
+ (for server-only installation)
+ * fix samhain_hide.c for 2.4 kernel
+ * fix sh_kern for updated samhain_hide.c
+ * new option -j to just list the logfile
+ * sh_getopt.c: recognize -Dt check for -D -t check
+ * sh_tiger0.c: fix compiler warning (memmove) on Solaris
+
+1.3.4 (12-12-2001):
+ * sh_suidchk.c: option to limit files per second
+ * sh_unix.c: option to limit (kilo)bytes per second
+ * sh_hash.c: fix potential problem with '\n' in filename
+ (not backward compatible if there are filenames with '=')
+
+1.3.3 (03-12-2001):
+ * sh_readconf.c, samhain.h, samhain.c, sh_suidchk.c:
+ option SetNiceLevel to set scheduling priority
+ * sh_hash.c: bugfix for database listing on Solaris
+ * taus_seed: bugfix for emergency backup rng seed
+ * sh_util_safe_name: fix for XML
+ * sh_utmp_set_login_activate: use sh_util_flagval
+ * sh_utils.c: sh_util_obscurename: rm 'space' from list
+ * more backtrace macros
+ * sh_util_flagval: fix bug to recognize 1/0
+ * fix test scripts testtimesrv.sh, testext.sh (test.sh 6/5)
+ * rm stray debug fprintf in sh_srp.c
+
+1.3.2 (27-11-2001):
+ * sh_hash.c: fix an error introduced in 1.3.1
+ * set RLIMIT_CORE to RLIM_INFINITY if --enable-debug
+
+1.3.1 (25-11-2001):
+ * slib.c: get backtrace with --enable-debug
+ * sh_unix.c: allow core dumps when --enable-debug
+ * configure.in: fix default message queue permissions
+ * sh_suidchk.c: automatically include suid/sgid files in database
+ * sh_suidchk.c: check all suid/sgid files
+ * sh_hash.c: don't insert duplicates when reading the database
+ * sh_utmp, sh_kern, samhain: fix 1sec offset in timer
+ * sh_unix.c: don't require /dev/random to be non-world-writeable
+ * server: fix segfault in zAVLTree.c if avltree == NULL (no clients)
+ * client: fix segfault on Solaris if path_conf == NULL
+ * testrun_1b.sh: \(^/.*\) -> \(/.*\) for Solaris sed
+
+1.3.0 (31-10-2001):
+ * support compiling with GNU gmp library
+ * set 3 sec timer on client_time_check to avoid excessive (and
+ unnecessary) calls under heavy load
+ * replace sl_strlen with a macro
+ * store client_t structure in AVL tree
+ * database format incompatible with previous format, up the magic#
+ * sh_html.c: cache entry template for speedup
+ * slib.c: reset islong(double) in sl_printf_count
+ * sh_hash.c: report on rdev change
+ * sh_hash.c: print size in 64 bit
+ * sh_hash.c: save in absolute size types
+ * sh_unix.c: get values as appropriate type (time_t, dev_t, ...)
+
+1.2.10:
+ * update MANUAL
+ * sh_unix.c: tiger_hash -> tiger_generic_hash
+ * sh_readcon.c: DigestAlgo option
+ * sh_tiger0.c: add MD5 and SHA1
+ * sh_unix.c: fix minor problem with win2k/cygwin
+
+1.2.9 (17-10-2001):
+ * fix problem with entry template/empty hostname
+ * fix MASK_USER_ (MTM -> ATM)
+ * typo fixed in configure.in (${install_name} -> {install_name})
+ * bugfix group_old -> size_old in XML code
+ * skip armor header in signed files
+
+1.2.8 (29-09-2001):
+ * Mac OS X: in sh_getopt.c, rename table[] to op_table[] to avoid
+ obscure compiler warning
+ * Mac OS X: fix test scripts
+ * Mac OS X: import newest config.guess, config.sub from ftp.gnu.org
+ * implement deadtime in syslog recv code to protect against flooding
+ * sh_err_log: sl_close(fd) if lock|forward fails
+ * compliance with Filesystem Hierarchy Standard -- Version 2.2 final
+ * add policies User0, User1
+ * fix compile problem (FreeBSD) in sh_suidchk.c
+ * macro to check for debugger breakpoints (linux/i386)
+ * check for solaris (does not work) in sh_derr (--enable-ptrace)
+ * option to listen on 514/udp for syslog, drop root
+ irrevocably if compiled thus
+ * use (check_mask & MODI_ATM) to decide whether to reset utime
+ * reset the policy masks on sighup
+ * option to write XML log messages
+ * cleanup of message catalog
+ * modified error messages for BADCONN
+ * error messages for Rijndael
+ * block recursive error messages within sh_error_handler()
+ - would hang the machine ... -
+
+1.2.7:
+ * sh_files, sh_utils: check top level directory
+ * sh_kern, sh_cat, kern_head: check syscall code, fork subprocess
+ for reading from /dev/kmem
+ * include /boot in default samhainrc
+ * change source distribution signing/packaging system
+ * Makefile, README, MANUAL: adhere to file system standard,
+ document new locations
+ * fix a bug in samhain_hide.c
+
+1.2.6:
+ * reset list of trusted users before config file re-read
+ * TrustedUser=... can be a list
+ * fix severity for files missing from IgnoreAll
+
+1.2.5:
+ * include example_pager.pl, example_sms.pl scripts
+ * explain paging/sms setup in docs
+ * allow manual exclusion of a directory in suidcheck
+ * automatically track all file changes
+ * remove missing files from in-memory database
+ * add $(KERN) to DEPLOYFILES
+
+1.2.4:
+ * log IP address for login/logout events, if supported by the OS
+ * release block in globerr (callback)
+
+-------------
+
+1.2.3:
+ * fix problem with reading stealth configuration
+ * fix a few formats in sh_cat.c
+ * always use strncmp for file system type check in sh_suidchk.c
+ (trailing 'fs' may be system specific for some types)
+ * no bare LF in messages (RFC 2822)
+ * no lines longer than 998 chars (RFC 2822)
+ * fix error in testrc_1
+
+1.2.2:
+ * make tmp file directory a compile time option
+ * fix minor bugs in tmp file allocator (potential memory leak,
+ double slash if root directory)
+ * obsolete testpipe script removed
+
+1.2.1:
+ * fix memory alignment in rijndael-api-fst.c: blockEncrypt()
+ * fix byte order in HMAC code (compatibility fix for Linux/HP-UX)
+ * removed a debug fprintf()
+
+1.2.0:
+ * fix a bug in the HMAC implementation (thanks to Cesar Tascon
+ for help in tracking down this one)
+ * module to check the file system for SUID/SGID files
+
+1.1.16 (never released):
+ * fix the recursion depth -1 option as described in the manual
+ * optional database reload on SIGHUP
+ * fix a race condition when checking that /dev/random is a charakter
+ device
+ * redirect stderr to /dev/null for c_random
+ (AIX may segfault in netstat...)
+ * check whether /dev/random is a charakter device in c_random.sh
+ (we know at least one sysadmin who has set up a fake /dev/random ...)
+ * don't give NULL as 2. and 3. arg to execve if not Linux - some
+ Unices (notably Solaris) don't like it
+ * init ptr = NULL in my_malloc (compiler warning)
+ * make the bitmask for tests configureable (suggestion by A. Dunkel)
+ * make the bitmask for tests a static variable
+ * make (database/logfile/lockfile) path configurable
+ (to run multiple instances of samhain from an NFS share - on the
+ wishlist of J. Patton)
+
+1.1.15 (never released):
+ * fix minor error in testcompile.sh (rm test_log only at start)
+ * return from subroutines on sig_terminate == 1
+ (faster exit on SIGTERM)
+ * fix re-configuration of addresses
+ * use sh_util_flagval() in sh_mail_setFlag and sh_kern_set_activate
+ * SysV message queue as compile option
+ * config file option to set console device
+ * removed the pre 1.1.9 code bloat
+ * don't print the LOGKEY to the console
+
+1.1.14:
+ * fix an error in the setup consistency check
+ * make target to uninstall runtime files
+ * trustfile.c: check return code of readlink(), fix off-by-one error
+ * sh_files.c: fix placement of terminator after readlink() call
+ * sh_files.c: fix a missing set_suid()/unset_suid()
+ - suid should work, but is not recommended -
+ * more debug statements in c/s code
+ * avoid re-entry in sh_unix_sigexit
+ * put a block around free() and malloc() in wrapper functions
+ * ditto for glob()/globfree(), regcomp()/regfree(), fdopen()/fclose()
+ - i.e. avoid corrupting the heap from a signal handler -
+
+1.1.13:
+ * optimized the size of the configure script somewhat
+ * modify the compile and hash test scripts
+ * read '\0's in sh_unix_getline
+ * exponential schedule for connection attempts
+ * make stealth working properly with signed files
+ - config file should be signed now before embedding in picture -
+ * fix a race in using signed files
+ * updated err messages for PWNULL, GRNULL
+ * add missing shell script for test 11
+ * add mandatory source file/line info with -p debug
+ * add mandatory source line info with BADCONN
+ * fix a latex error in the manual
+
+1.1.12:
+ * debug output to console if compiled with --enable-debug and
+ running as daemon
+ * make reportonlyonce=true the default
+ * make sure state changes of a file are always reported, even
+ with reportonlyonce=true
+ * Linux kernel modules (samhain_hide, samhain_erase)
+ * fixed incorrect return value of sh_util_flagval
+ * fixed an error in sh_files.c: happens with -t init and first
+ file that is checked does not exist
+ * revised install/uninstall targets in the Makefile
+ * module to check for clobbered kernel syscalls (tested on Linux 2.2)
+ * more diagnostic error messages in sh_gpg.c
+ * more diagnostic error messages in sh_mail.c
+ * error in mail.c fixed
+ (address -> address_list[i] for multiple recipients)
+ * docs updated, better(?) explanation of signed files
+ * skip over path in gpg checksum output
+ * check client name against IP address and FQDN
+ * fix for --disable-* in config file
+ * fixed a server crash (MSG_TCP_OKMSG without arg)
+ if the server is run with debug level output threshold
+ * catch EAGAIN in sh_gpg.c pipe reader
+ * fix the 'external logging' test to make it work on BSD
+ * error message if no local path to init DB
+ * check for i86/Solaris in configure (vsnprintf prototype)
+ * make SRP the default
+
+1.1.11:
+ * make log file verification more convenient
+ * fix problem with message classes in stealth mode
+ * linux: do not try to read file attributes for devices
+ * handle the root directory correctly (avoid "//" in listing)
+ * fix problems with blockin on FIFOs/char dev
+ pointed out by I. Rogalsky (rog@iis.fhg.de)
+ - open in nonblocking mode for read, then set to blocking
+ - open file only if regular
+ * fix alignment in memory profiler
+
+1.1.10:
+ * minor code cleanup
+ * fix an error in trustfile.c (handling of empty/incomplete
+ group entries in /etc/group, bug report by A. Capriotti )
+
+1.1.9:
+ * compatibility option for old behaviour (plain hash instead
+ of HMAC, ECB instead of CBC mode)
+ * use CBC rather than ECB mode for encryption
+ * use HMAC-TIGER for message authentication codes
+ * handle NULL data in sh_tiger_hash
+ * option to set syslog facility (default is LOG_AUTHPRIV)
+ * longer timeout (300 sec) on /dev/random if no /dev/urandom
+ * fix minor output error with stealth option
+ * option not to log names of config/database files on startup
+
+1.1.8:
+ * fix error in syslog routine
+ * fix missing 'test' in configure.in
+ * fix error in replace_tab() in sh_html.c
+ * fix minor memory leak in sh_util_regcmp()
+
+1.1.7:
+ * timeout on read_mbytes (from /dev/random; fallback to /dev/urandom)
+ * fix for FreeBSD: ut_user -> ut_name in sh_utmp.c
+ * fix for Alpha: consider $ac_cv_sizeof_unsigned_int_ in configure.in
+ * fix for Alpha: format string in sh_tiger0.sh
+ * on Linux, now compiles cleanly with
+ -Wall -W -Wstrict-prototypes -Wcast-align
+ * fix problem with recursion depth
+ (pointed out by Vic <hvicha@mail.ru>)
+ * #include "sh_tools.h" in sh_unix.c and fix the
+ --with-timeserver option (reported by Vic <hvicha@mail.ru>)
+ * place read_port(), MSG_TCP_NETRP outside ifdefs
+ * close fd/zero skey before execve
+ * verify client name against socket peer
+ * ... with configureable error priority
+ * use strcmp() rather than strncmp() in search_register()
+ * fix race between lstat() and open() for checksum
+ (reported by dynamo <dynamo@ime.net>,
+ JJohnson <JJohnson@penguincomputing.com>)
+ * enable globbing for filenames
+ * fix Solaris problem: siginfo_t may be NULL
+ * fix missing SL_EBADGID in tf_trust_check
+ * test case for external scripts, fix flushing pipe
+ * fix a typo in sh_ext_type
+ * do an fdexec w/checksum on Linux if calling external program
+ * even safer tmp file creation
+ * allow db update
+ * fix compile options for --enable-debug
+ * fixed a spelling error in the output
+ * test program for full CS support (config/database download)
+ * tell which file is searched for cs download
+
+1.1.6:
+ * fix bug in sh_readconf_line (segfault on erroneous config lines)
+
+1.1.5:
+ * sh_unix.c: sh_unix_getinfo_attr: f -> flags
+ * use gettimeofday as last resort
+1.1.4:
+ * fix AIX compiler warning in sh_forward (cast arg1 of sh_tiger_hash
+ to (char *)
+ * configure: add static link flags for some more os (from tar)
+ * don't strip twice (some stupid systems abort)
+ * fix for reading from /dev/random on non-Linux systems (untested)
+ * sh_mail.c: end all message lines with \r\n
+ * stealth: ignore \r, \"
+ * take out tracing from --enable-debug (presently useless anyway)
+ * fix some remaining cleartext with debug && stealth combined
+ * fixed a small memory leak in sh_err_log.c
+
+1.1.3:
+ * fixed circular logic in taus_seed() (fallback method only)
+ * fix for missing _SC_OPEN_MAX (runaway close())
+
+1.1.2:
+ * implement message classes
+ * let server recognize client message severity and class
+ * secondary log server
+ * keep database in memory (allows to close file
+ if retrieved from server)
+ * encrypt client/server communication
+
+1.1.1:
+ * Compilation problems with native Solaris compiler fixed
+ * fill in euid/ruid variable
+ * manual.pdf --> MANUAL.pdf
+ * debug sh_util_formatted()
+ * http refresh 120sec for server stat page
+ * trace/debug options
+ * fixed problem with utmp.c options
+ * fixed problem with sh_mail_setaddress
+ * option for custom message header
+ * fixed problem in compdata
+ * fixed problem in mail verification
+ * remove eventual trailing '/' in file names
+ * fixed problem with report string for modified files
+ * option to report in full detail
+
+1.1.0:
+ * Move error messages to catalog
+ * Make error message format more uniform
+ * Wrap sytem calls that could be interrupted by signals
+ * Warn on append to database
+ * Option for full details on mod. files
+ * Option to report only once on mod. files
+ * Generally speaking, major modifications with potential new bugs
+
+0.9.5:
+ * sh_hash.c: fixed erroneous checksum for config file
+ * sh_html.c: fixed erroneous timestamp (last)
+ * sh_tools.c: fixed connect_port (set port for cached address)
+ * sh_srp.c: fix for '00' (='\0') in pw
+ (last two fixes by Andreas Piesk)
+
+0.9.4:
+ * samhain.c: fcntl(1, ..) -> fcntl(2, ..)
+ * sh_hash.c: copy 12 instead of 10 byte for c_attributes
+ * 'empty directory' WARN -> INFO
+
+0.9.3:
+ * FreeBSD fixes:
+ - c_random.sh: make sure /dev/random provides something
+ rather than nothing
+ - check for <netinet/in.h> and include it
+ - include <sys/types.h> early
+ - sh_utmp.c: fixed an occurence of ut_user
+ - sh_utmp.c: #ifdef HAVE_UTTYPE static char terminated_line #endif
+ - sh_forward.c: EBADMSG -> ENOMSG
+ * sh_unix.c: check return value of gethostbyname
+ * sh_entropy.c: fallback on /dev/urandom if /dev/random blocks for
+ more than 30 sec
+ * ... and fix the timestamp format ...
+
+0.9.2:
+ * ISO 8601 timestamps
+ * Bugfix in sh_utmp (timestring overwrite)
+ * don't use siginfo_t on Linux (garbage as of 2.2.14)
+ * check for Linux capabilities bug when dropping root
+ * include README for gcc compiler bug (pointed out by A. Piesk)
+ * explicitely set -fno-strength-reduce with gcc
+ * fixed ignoring missing files with the IgnoreAll policy
+
+0.9.1:
+ * more ext2flags (breaks backward database compatibility on Linux)
+ * IgnoreAll policy modified - missing/added files reported with
+ SeverityIgnoreAll (to handle files that may or may not be present)
+ * Check all files, not only regular ones
+ (bug in sh_files, originally introduced because checksum of
+ regular files only is computed)
+
+0.9:
+ * use O_NOATIME if supported
+ * --with-nocl takes argument (PW to re-enable CL parsing)
+ * no daemon mode if initializing database
+ * fixed segfault in yule with 'unknown file type' request
+ * enlarged MAX_GLOBS 24 -> 32 and made the array linear
+ * server uses last registry entry for any given client now
+ * deploy.sh script to deploy clients to remote hosts
+ * enhanced signal handling: SIGUSR1/SIGUSR2/SIGABRT/SIGQUIT/SIGHUP
+ * allow y/Y/n/N for login monitoring (in addition to 0/1)
+ * external logging scripts/programs
+ * trustfile.c: define STICKY on Linux
+ * reset signal mask when initializing
+ * EINTR_RETRY wrapper
+ * slib: sl_read, sl_write EINTR update
+ * use sstrip when installing
+ * more compact database format (breaks backward database compatibility)
+ * larger download packets
+ * TcpFlags unsigned char
+ * cast to (char *) head in write_port
+ * m(un)lock cast to (char *)
+ * (1 << 31) --> (1UL << 31)
+ * support e2fs attributes on Linux
+ * fixes for AIX and Solaris native compilers
+ * fixed Makefile for non-GNU make (pattern rule --> suffix rule)
+
+0.8.1:
+ * fixed 'is_numeric()' return value
+
+0.8:
+ * added option for static compilation
+ * added option for stealth with non-hidden config file
+ * added option for disabling command line parsing
+ * all options can be set in the configuration file now
+ * stealth: xor strings in database file
+ * fixed bug in mailer code ([] in HELO)
+ * print timestamp when asking for key
+ * 'micro' stealth mode (no hidden configuration file)
+ * simplified slib
+ * int->long for uids/gids in trustfile
+ * moved mailkey from data to code
+ * shell script for entropy (stronger default key)
+ * general code cleanup
+ * better error checking in client/server code
+ * detect out-of-sync messages
+ * check state across protocol passes in server
+ * make sure authentication is mutual
+ * file download to client
+ * reserve six file descriptors in server
+ * mlock queue buffer if LOG_KEY
+ * improved robustness in bignum (don't fail on free())
+ * per-directory recursion depths
+ * RFC821 compliance: empty line at end of header, To field, Date field
+ * RFC821 compliance: make e-mail transfer relieable
+ * fix detection of hardlink changes
+ * checksum verification for calling gpg/pgp
+ * CL option '-S' not required for server-only binary
+ * eliminate CL options that may leak privileged information
+ if the program is SUID
+ * skip leading white space in configuration file
+ * allow nested conditionals in configuration file
+ * allow whitespace before and after '=' in configuration file
+ * don't leak file descriptors to child processes
+ * make message transfer relieable
+ * always report error on abnormal termination of connection
+
+0.7:
+ * support for alpha machines
+ * stop TCP logging after exit message
+ * limit connections in server (DoS attacks)
+ * move string handling to slib
+ * move file handling to slib
+ * timestring without space
+ * changed report format
+ * SUID bugfix - use euid when checking logfile ownership
+ * SUID bugfix - get root for lstat()
+ * SUID bugfix - get root for opendir()
+ * store number of hardlinks
+ * send no message if polling empty queue
+ * include tiger 64-bit implementation (portability)
+ * codes for error conditions
+ * mail check: handle multiple, overlapping audit trails
+ * security fix: no append to database if SUID
+ * fix sh_entropy.c (BUFSIZ -> BUF_ENT)
+ * read command line before config file
+ * PGP signing of config/database files
+ * checksum of config file reported
+ * checking for attributes only
+
+0.6:
+ * more syslogish priority specification
+ * fixed segfault in sh_mem_check, apparently this was also
+ the reason for the segfault in atexit()
+ * allow for compilation with SRP authentication
+ * fixed tiger checksum computation
+ * fixed broken logfile verification for second and further audit trails
+ * test program added
+ * documentation improved
+ * sh_forward_make_client: bug fixed in[8]->in[i]
+ * sh_error.h: fixed missing #include <errno.h>
+ * configure.in: fixed missing strerror() test
+ * sh_utmp.c: check logins/logouts
+ * check for missing files
+ * only reset access time if necessary
+ * O_EXCL in open()
+ * limit environment to TZ in execve (sh_entropy.c, not used on Linux)
+ * use trustfile() to determine whether logfile dir is trustworthy
+ * strip head instead of tail for numerical address
+ * store messages in fifo during log server outage
+ * re-init session key after server outage
+
+0.5 (21-12-1999):
+ * added option for mail relay server
+ * own popen() implementation in sh_entropy() (portability)
+ * fixed error in sh_util_basename() (returned NULL for base == "/")
+ * fixed segfault in strlcpy/strlcat (check for src == NULL)
+ * FILENAME_MAX -> PATH_MAX (HP-UX 10.20)
+ * use TIGER for 32-byte compilers (portability)
+ * fixed hash function (do not include stdlib.h)
+ * flush buffer before write in mailer code (IBM AIX 4.1)
+ * make mailer code non-forking
+ * cast argument of is...() to int (portability)
+ * return() after _exit() for braindead compilers (portability)
+ * optionally use inet_addr (portability)
+ * check for broken mlock() (HP-UX 10.20)
+ * minor code cleanups
+ * fixed incorrect size of munlock()'ed memory in sh_error_string()
+ * fixed a buffer overflow in the error printing routine
+ * fixed a buffer overflow in sh_util_safe_name ()
+ * implement SRP session key exchange
+ * implement client/server facility
+ * implement @host/@end construct in configuration file
+ * preferably use uname(), and do gethostbyname() for FQDN
+ * make vernam cipher base numeric
+ * make OnlyStderr private in sh_error
+ * test -e "/dev/random" --> test -r "/dev/random" (portability)
+ * check for libsocket (portability)
+ * add #defines for IPPORT_SMTP, IPPORT_TIMESERVER (portability)
+ * eliminate superfluous /proc test
+ * some unreachable code removed
+ * cast to (byte*) replaced by cast to (word64*) in sh_tiger_hash()
+ * check for setresuid() if no seteuid() (HP-UX 10.20)
+
+0.4 (09-11-1999):
+ * make sure output from /dev/random has no NULL's
+ * one-time pad encryption for emailed keys
+ (better than nothing ...)
+
+0.3 (04-11-1999):
+ * logfile readable for group
+ * verify signatures for any file
+ * signature block in tarball
+ * use select() in time server routine
+ * better protection for session keys (mlock)
+
+0.2:
+ * fixed incorrect man page
+ * fixed incorrect example rc file
+ * recursive error logging should work now
+
+0.1:
+ * initial release -- on Samhain 1999, of course
+
+development start:
+ * probably 29-06-1999
+
diff --git a/docs/BUGS b/docs/BUGS
new file mode 100644
index 0000000..1d089f3
--- /dev/null
+++ b/docs/BUGS
@@ -0,0 +1,38 @@
+AIX:
+---
+
+Samhain must either be compiled as 32bit application, or with the --disable-dnmalloc
+configure flag, because the OS provides no way to enforce usage of 32bit address space.
+
+MacOS X:
+-------
+
+(1) Pointed out by David: static linking is not supported on MacOS X,
+ see http://developer.apple.com/qa/qa2001/qa1118.html
+
+Solaris:
+-------
+
+(1) This was pointed out by rog [at] iis dot fhg dot de (Ingo Rogalsky):
+ "It isn't possible, to link samhain statically with Solaris.
+ This is a Solaris issue (see Sun Infodoc ID12624) and
+ not a samhain problem."
+
+Linux, maybe others:
+-------------------
+
+(1) With gdm (the GNOME display manager), GNOME version 1.2, using the
+ file hiding kernel module (configure option --enable-khide)
+ at system boot may cause problems (keyboard locked up).
+ No problem observed with kdm (the KDE display manager).
+
+ In case of problems, you may need to reboot into single-user mode and
+ edit the boot init script ... it should be noted that on the test
+ system, gdm sometimes locked up the keyboard on other occasions
+ (e.g. after a fsck).
+
+(2) With gcc 2.95.2 (and glibc 2.1.3), it is not possible to use
+ --with-database and --enable-debug at the same time (the code will
+ segfault). This is apparently a compiler bug, and it does not happen
+ with gcc 3.0.
+
diff --git a/docs/Changelog b/docs/Changelog
new file mode 100644
index 0000000..c29cefe
--- /dev/null
+++ b/docs/Changelog
@@ -0,0 +1,2554 @@
+4.1.4:
+ * fix problems with wildcard pattern re-evaluation (reported by
+ A. Ansari):
+ - not stored if no match at startup
+ - only one (the first) stored if same pattern for file and dir
+ * fix problems with directory creation in inotify watched tree
+ (reported by A. Ansari):
+ - recursive depth not decreased
+ - watched as directory even when recursion depth should drop below zero
+
+4.1.3 (19-04-2016):
+ * on Cygwin, the AvoidBlock function is now off by default
+ (problem reported by Fred C)
+ * tighter sanity checks in sh_static.c
+ * fix regression with '--enable-static' in sh_static.c
+ (reported by amaiket).
+
+4.1.2 (21-12-2015):
+ * add options --enable-selinux and --enable-posix-acl for "hard fail"
+ if libraries aren't found (requested feature)
+ * fix wrong policy assignment when inotify is active and change occurs
+ during a reload (reported by Bond)
+ * fix failure to detect open UDP port for some daemons
+ (reported by James)
+ * fix broken 'rpm' and 'rpm-light' makefile targets
+ (reported by Bond)
+ * fix message for self-check
+
+4.1.1 (01-11-2015):
+ * fix problem with timezone calculation on month rollover for
+ negative timezones (west of GMT; reported by Bond)
+ * fix problem with rotated logfiles when content is always constant,
+ i.e. checksum does not change (reported by Bond).
+ * fix problem with baseline update on FreeBSD and probably other
+ non-GNU/Linux systems (reported by L.Vasiliev)
+ * fix bad check_libwrap() call in sh_xfer_server.c
+ (reported by L.Vasiliev)
+
+4.1.0 (24-09-2015):
+ * fix quirks with Linux audit support
+ * implement 'silent check' (requested feature)
+ * fix call of self_check for exit on sigterm
+ * fix safe_logger() - uses the logger utility with a non-posix option
+ * fix missing reporting on shell expansion capability in --version
+ * fix missing error message on invalid list for skipchecksum
+ (reported by Bond)
+ * fix missing definition for a sh_dummy_ var on BSD et al.
+ (reported by Andrew)
+
+4.0.0 (20-07-2015):
+ * fix and document default settings for mounts check
+ * new -w CL option to wait on scan completion
+ * new option ReportCheckflags
+ * enhance testsuite to cover new functionality
+ * implement draft for change control integration:
+ * new database format to store change flags
+ * refactoring of db I/O and client/server code
+ * option StartupLoadDelay
+ * --create-database CL option
+ * --outfile CL option
+ * --binary, --list-filter CL options
+ * --verify-database CL option
+ * yulectl -c DELTA:<uuid> command
+ * option SetDeltaRetryCount
+ * option SetDeltaRetryInterval
+ * update documentation
+ * remove old/unused code
+ * fix compiler warnings with gcc 5.1.0
+ * update config.sub, config.guess
+
+3.1.6 (08-06-2015):
+ * Modify testcompile.sh to remove 'smatch' and use 'clang'
+ instead.
+ * Fix compile problems with clang.
+ * Modify testcompile.sh to remove 'uno' and use 'cppcheck'
+ for static checking
+ * Move AC_CHECK_FUNCS( getnameinfo getaddrinfo ) behind
+ the check for libsocket to have them found on Solaris
+ * Fix IPv4-only bug in bind_addr use in retry_connect()
+ * Add more debug code in connect_port()
+
+3.1.5 (26-03-2015):
+ * Fix IPv6 issue with portcheck (need to be able to specify
+ IPv6 interfaces).
+ * Fix minor issues with bugs in testing code
+ * Add command line option '--server-host' to set the log server
+ * In samhain.startLinux.in start script template, add code to read
+ options from /etc/sysconfig/${NAME} for RedHat
+
+3.1.4 (17-02-2015):
+ * Add non-existent file to the regression test config
+ * Fix erroneous call to sh_hash_init when a missing file
+ is specified in the configuration
+ * Fix buffer allocation for getgrnam_r for large groups
+ (problem reported by Sergio B)
+ * Search RPM in $HOME/rpmbuild if test -d _topdir fails (CentOS
+ recommends '%(echo $HOME)/topdir', reported by E. Taft)
+
+3.1.3 (01-11-2014):
+ * Remove initgroups() from the popen call in unix entropy gatherer
+ * Add error message for update mode if local baseline cannot be found
+
+3.1.2 (07-08-2014):
+ * Fixed incorrect memset in sh_checksum.c (sha256)
+ * Circumvent a gcc compiler bug with inline asm (gcc 4.8)
+ * Allow multiple exclusions for SUID check
+ * Use calloc instead of malloc
+ * Add overflow check in minilzo.c (but the potential integer
+ overflow [CVE-2014-4607,LMS-2014-06-16-1] is irrelevant anyway
+ because the function is never used on external data).
+ * Fixed a minor bug in exepack_fill.c that was unearthed by the minilzo
+ overflow check (the required buffer length information for the check
+ wasn't provided)
+ * Fixed incorrect logic in setting the ALLIGNORE flag (more specific
+ directory / file directives were ignored)
+ * Fix for tickets #358 (repetitive lstat warning about deleted
+ directory) and #359 (reporting of deleted/added top level directory)
+ * Fix a free() on NULL (harmless but avoids spurious warning)
+
+3.1.1 (01-05-2014):
+ * Disable inline asm on Cygwin (issue reported by Erik)
+ * Fix sh_ipvx_is_ipv4 such that numeric hostnames are not
+ incorrectly recognised as IP address (reported by A. Hofland)
+ * Fix sh_ipvx_is_ipv6
+
+3.1.0 (31-10-2013):
+ * Add support for SHA2-256 checksum function
+ * Drop support for --enable-khide on kernel version 3.x and above
+ * Fix IgnoreAdded to anchor regex at beginning of path (reported by
+ R.Lindner)
+ * Add check to detect availability of pmap_getmaps() (missing in
+ static library on recent Linux systems as reported by Ian Baldwin)
+ * Fixes for Ubuntu 13.4:
+ - no error msg for failing stat on /run/user/Username/gvfs in
+ suidcheck
+ - no error message for failing hardlink check on /run/user/Username
+ - eliminate compiler warnings
+ * Add option '--disable-asm' to work around a gcc issue in Debian
+ unstable (reported by micah)
+ * Remove option '-i' from mkitab in samhain-install.sh.in (reported
+ by N. Kerski)
+
+3.0.13 (11-06-2013):
+ * Fix detection of nonfunctional /dev/kmem
+ * Fix race condition in GrowingLogfiles policy that
+ causes spurious reports (problem noticed by J. Daubert)
+
+3.0.12 (16-05-2013):
+ * Fix compiler warning in bignum.c (unused parameter)
+ * Detect if /var/run is a symlink and /run exists
+ * Fix for broken support for audit subsystem (reported
+ by isquish)
+ * Fix for incorrect use of sh_inotify_add_watch_later
+ which causes a steady increase in memory usage
+ (issue reported by Maxime V)
+ * Fix for potential minor memory leak
+ * Fix for bug in negated conditionals for config file
+ (reported by M. Ward)
+
+3.0.11 (08-04-2013):
+ * Fix for compile error on HP-UX (reported by P. Alves)
+ * Propagate ERANGE error from getgrxxx_r (issue raised by C. Feikes)
+ * Fix reconnecting to database for Oracle
+ * Add better logrotate handling for the GrowingLogs policy (search
+ rotated log and verify it, don't report if this succeeds)
+ * Add ability to create debian packages with preset password (use
+ env var PASSWORD)
+ * Add option KernelCheckProc (bool) to suppress kernel /proc test
+ * Add option IgnoreModified to cover transient files that
+ not only get added/deleted but also modified
+
+3.0.10 (13-01-2013):
+ * Revert to previous logic in samhain.c because it will block
+ otherwise (reported by Alexandr Sabitov)
+
+3.0.9 (21-12-2012):
+ * Fixed a Cygwin compile warning
+ * Change logic in samhain.c to make sure inotify doesn't cause
+ excessive full scans
+ * Add option IgnoreTimestampsOnly in Windows registry check (ignore
+ changes if only timestamp has changed)
+ * Fix the probe command (misses clients if their startup message
+ has been missed)
+ * Fix the RPM spec file for --enable-network=client and no password
+ (reported by Mitch St Martin)
+ * Fix build error with Linux audit (reported by Andy Jack)
+ * Fix detection of utmpx.h (reported by D. Thiel)
+
+3.0.8 (01-11-2012):
+ * rename to 3.0.8 for release
+ * useful exit status for samhainadmin.pl --examine
+
+3.0.7a (25-12-2012):
+ * add ability to create RPM with preset password (use
+ env var PASSWORD)
+ * fix the rpm-light makefile target
+ * fix minor bug in samhain_setpwd.c (incorrect error message)
+
+3.0.7 (25-10-2012):
+ * update documentation for prelude
+ * fix configure to properly search for Oracle Instantclient SDK
+ * pass through TNS_ADMIN environment variable for Oracle
+ * optimize audit rules automatically
+ * zero out the html status file at server exit
+ * don't check for assembly optimization unless linux or *BSD
+
+3.0.6 (01-09-2012):
+ * install logrotate script if /etc/logrotate.d is detected
+ * new option --enable-suid for nagios
+ * fix for --enable-ptrace: make the save_tv variable thread specific
+ * fix bug in inotify code which made it follow symlinks (by [anonymous])
+ * fix two missing SH_MUTEX_LOCK(mutex_thread_nolog) (by [anonymous])
+ * fix for 'no such process' message from sh_fInotify_init_internal()
+ (by [anonymous])
+ * fix for --enable-ptrace with threads (by [anonymous])
+ * option SetReportFile for writing out summary after file check
+
+3.0.5 (11-07-2012):
+ * fix xml format templates for registry check
+ * fix database download on registry check init (reported by ldieu)
+
+3.0.4 (01-05-2012):
+ * fix verbosity of message for alerts on already deleted watches
+ (set it to debug - suggested by xrx)
+ * fix extraneous error messages about file not found from
+ sh_fInotify_init_internal() (bug reports by xrx and aj)
+
+3.0.3 (28-03-2012):
+ * fix potential deadlock in sh_ext_popen()
+ * make sure sh_processes_readps cannot hang forever
+ * fix for deadlock if sh_processes_readps hangs
+ * fix for deadlock if suid check and inotify are used together
+ (reported by A. Jack)
+ * fixed problem with samhain_stealth.c (handle input config
+ files that don't end with a newline)
+ * fixed compiler warnings for yulectl.c with stealth
+ * fixed lacking support for O_NOATIME on 64bit linux
+
+3.0.2a (23-02-2012):
+ * Fix compile error on Solaris 10
+
+3.0.2 (16-02-2012):
+ * change sql init scripts to make bigint fields unsigned (problem
+ reported by A. Sabitov)
+ * patch by Andy Jack for issue with the --with-gpg option (hangs with
+ high cpu load at startup)
+ * call ./samhain-install.sh as /bin/sh ./samhain-install.sh in the
+ RPM spec file, because /var might be mounted noexec (reported by GC)
+ * fixed configure.ac for the case that --with-gpg and --enable-nocl are
+ used (./samhain for gpg checksum; problem report by Andy Jack)
+ * fixed a potential NULL pointer dereference in sh_inotify.c on
+ systems where inotify is not available (reported by <anonymous>)
+ * fixed: the config file template mentions (in a comment) the
+ non-existent directive SetLockPath instead of the correct
+ SetLockfilePath (reported by Curtis).
+ * fixed: the definition of O_NOATIME isn't seen in sh_files.c.
+
+3.0.1 (07-12-2011):
+ * fix a memory leak (reported by C. Westlake)
+ * fix an uninitialized variable in the suidcheck code (problem
+ reports by T- Luettgert and Kai)
+ * fix a bug in the port check with --disable-ipv6 (reported
+ by C. Westlake)
+ * fix potential deadlock in sh_files.c (reported by S. Mirolo)
+ * change Makefile.in to stop on compile error rather than at link stage
+ (suggested by S. Mirolo)
+ * fix compile errors caused by missing #define (pthread disabled) and
+ wrong function call (OSX specific code), reported by S. Mirolo
+ * fix warning by the llvm/clang static checker
+ * fix compile issues on freebsd
+ * handle (ignore) SIGPIPE more thoroughly
+ * update config.guess, config.sub
+
+3.0.0a (06-10-2011):
+ * Fix compile-time issues on RHEL5 (reported by Thomas)
+
+3.0.0 (01-11-2011):
+ * Add support for the inotify API
+ * If --disable-shellexpand is used, also disable setting
+ the prelink/ps paths
+ * Fix missing check_mask storage for glob pattern
+ * Add support for integer keys in zAVL
+ * Fix compiler warnings with gcc 4.6.1 (variables that get set
+ but then remain unused)
+ * Add more server-side debugging for IPv6
+ * Make kern_head compile with 3.x kernels
+
+2.8.6 (20-09-2011):
+ * Manual updated.
+ * Added an option LogmonDeadtime to avoid repetitive reporting
+ on correlated events.
+ * Fix problems with timestamp handling in logfile correlation
+ (problem reported by D. Dearmore)
+ * List the policy under which a directory/file is checked
+ * Option to use a textfile with a list of files for update
+ * Fix --enable-db-reload option (reported by David L.)
+ * Fix samhain_kmem compilation, need to compile under chosen
+ name if --enable-install-name is used (reported by David L.)
+ * Fix uninitialized string in error message (reported by mimox)
+
+2.8.5a (16-06-2011):
+ * Fix autolocal.m4 for new configure option
+
+2.8.5 (15-06-2011):
+ * Detect non-working /dev/kmem in configure script, and fix
+ a bug in the samhain_kmem kernel module.
+ * Fix wrong handler for LogmonMarkSeverity (reported by S. Chittenden)
+ * Better protection against the 'intruder on server' scenario
+ pointed out by xrx. Add option to disable shell expansion in
+ configuration files, and check gpg signature earlier.
+ * Support /opt/local/bin in the Unix entropy gatherer (suggestion
+ by Sean Chittenden)
+ * Cache timeserver response for one second (suggestion by
+ Sean Chittenden)
+
+2.8.4a (11-05-2011):
+ * Fix for compile error with --with-prelude
+ (reported by Sean Chittenden), missing regression test added
+ * Fix for compile error with --enable-udp (reported by Sean Chittenden),
+ missing regression test added
+
+2.8.4 (30-04-2011):
+ * Fix another reload bug in the log monitoring module
+ * Add unit tests for IgnoreAdded/IgnoreDeleted configuration directives
+ * Fix deadlock after reload when compiled with --enable-login-watch
+ (reported by M. Teege and O. Cobanoglu)
+ * Fix compile error for samhain_hide.ko with recent kernel
+ * Include patch by J. Graumann to specify the location of the
+ secret keyring with samhainadmin.pl
+ * Fix potential timeout problem in sh_sub_stat_int() and propagate the
+ error (issue reported by mtg)
+ * Add support for X-Forwarded-For in apache logfile parser, add
+ option 'RE{regex}' to insert arbitrary regex
+ * New options PortcheckMinPort, PortcheckMaxPort for the open ports
+ check
+
+2.8.3a (23-03-2011):
+ * Fix two 'label at end of compound statement' errors on FreeBSD
+ (reported by David E. Thiel)
+
+2.8.3 (22-03-2011):
+ * init scripts: load samhain_kmem.ko before samhain starts
+ * slib.c: eliminate mutex from sl_create_ticket()
+ * sh_entropy.c: move pthread usage out of child
+ * sh_hash.c, sh_pthread.c, sh_pthread.h: sh_hash_hashdelete()
+ needs deadlock detection, may be called from within sh_hash_init()
+ via atexit handler on error condition
+ * sh_suidchk.c, sh_calls.c, sh_calls.h: need a nosub version of lstat()
+ to use with relative path after chdir()
+ * samhain.c, sh_calls.c, sh_calls.h: only run (l)stat() in subprocess
+ after reading config file (to allow disabling)
+ * sh_unix.c: run sh_sub_kill() in parent after forking the daemon
+ * fix zeroing of result from getnameinfo() (problem reported by Richard)
+ * fix spurious warnings about unsupported address family (reported
+ by N Silverman)
+ * option to run lstat/stat in subprocess to avoid hanging on NFS mounts
+ (off by default)
+ * fix Windows/Cygwin compile error (reported by A. Schmidt)
+
+2.8.2 (16-02-2011):
+ * add function to skip checksumming
+ * Fix missing check for recursion depth >= 0 if not IgnoreAll
+ * Fix hardcoded path for temp directory in deployment scripts
+ * Fix bad compile on CentOS 4.8 with gcc 4.1.2
+ * Fix minor bug in check_samhain.pl (pointed out by J.-S. Eon long ago)
+
+2.8.1 (17-11-2010):
+ * Document handling of missing files with secondary schedule
+ * Fix incorrect handling of missing files when secondary schedule
+ is used (reported by Sergey)
+ * Fix null pointer dereference in config parse handler for SetMailAlias
+ (reported by Sergey)
+ * Fix incorrect memset() in sh_kern.c (passed struct by value...),
+ reported by Roman and Stefan
+ * Fix 'make install' to create user-defined directory
+ * fix minor issues noticed by T. Luettgert (test code assumes port
+ 0/tcp is unused, wrong ifdef order (without impact on compilation))
+ * fix compile error on AIX 5.3 with --enable-login-watch,
+ reported by M. El Nahass (time.h missing in src/sh_login_track.c)
+
+2.8.0 (01-11-2010):
+ * Support IPv6
+ * Add registry checking
+ * Use auditd records to find out who did it
+
+2.7.2c (23-09-2010):
+ * Fix uppercase hostname problem in client/server communication
+
+
+2.7.2b (05-09-2010):
+ * Fix compile errors on Solaris 10 (reported by A. Saheba)
+
+2.7.2a (23-08-2010):
+ * rewrote rijndaelKeySched() in a more conservative way to fix
+ compile problem on SLES 11.
+
+2.7.2 (16-08-2010):
+ * sh_utils.c: fixed an endianess issue that prevented cross-verification
+ of email signatures (reported by A. Zangerl)
+ * sh_login_track.c: fix compiler warning (ignored return value
+ of fwrite)
+ * sh_readconf.c: fix comparison of SeverityUserX string
+ (reported by max__)
+ * sh_processcheck.c: sh_prochk_set_maxpid: set retval on success
+ (reported by max__)
+ * fixed some compiler warnings on cygwin
+ * sh_extern.c: As reported by T. Luettgert, gcc 4.4.4 on Fedora 13
+ will throw a warning if execve is called with a NULL argv pointer.
+ Need to provide a dummy argp[].
+
+2.7.1 (07-06-2010):
+ * samhain_kmem.c: fix compile problems
+ * fix problems with config file parser: increase max. line length,
+ support quoting/escaping of filenames (as in 'ls --quoting-style=c')
+ * check for pcre_dfa_exec (not available in old versions
+ of libpcre, reported by Shinoj)
+ * patch to allow server to log client reports to prelude
+ (by J. Ventura)
+
+2.7.0a (09-05-2010):
+ * fix /dev/kmem detection (reported by S. Clormann)
+
+2.7.0 (01-05-2010):
+ * sh_utmp.c, sh_login_track.c: additional login checks
+ * sh_unix.c: use SIGTTIN as alternative for SIGABRT
+ (SIGABRT seems not to work on AIX, reported by Peter)
+ * sh_utmp.c: fix compile error without pthreads (inotify_watch used)
+ * sh_kern.c, kern_head.c: fix some 64bit issues
+ * dnmalloc.c: fix compiler warning (ignored ret value)
+ * Fix LSB init script for kernel module
+ * samhain_kmem kernel module for /proc/kmem added
+
+2.6.4 (22-03-2010):
+ * Don't read proc_root_iops in sh_kern.c (Problem report
+ by H. R.)
+ * Logfile check can check output of shell commands
+ * Use data directory as default for logfile checkpoints
+ * Fix broken checkpoint save/restore for logfiles
+
+2.6.3 (10-03-2010):
+ * Fix bug in mail module, recipients incorrectly flagged
+ as aliases, which breaks immediate mail for 'alert'
+ (reported by Jesse)
+
+2.6.2 (28-01-2010):
+ * Makefile.in: fix problem in deploy system caused
+ by adding build number for debs in 2.5.9 (reported
+ by roman)
+ * add option for per-rule email alias in log monitoring
+ module
+ * sh_readconf.c: make keywords case-independent
+ * sh_mail.c: on error, report full reply of mail server
+ * sh_mail.c: report smtp transcript at debug level
+ * make sure mail aliases are not emailed twice, and
+ recipients cannot be defined after aliasing them
+ * handle named pipes in log monitoring module
+ (open in nonblocking mode, ignore read error if empty)
+ * fix bug in the server function to probe for necessity
+ of configuration reload for client
+
+2.6.1b (23-12-2009):
+ * fix missing include for sh_inotify.h in sh_inotify.c
+ (reported by Ack)
+
+2.6.1a (22-12-2009):
+ * fix typo in code for older inotify versions without
+ inotify_init1(), reported by Forll
+
+2.6.1 (21-12-2009):
+ * add a routine to log monitoring module to guess the proper year
+ for timestamps without year (standard syslog)
+ * add feature to automatically detect and report bursts of
+ similar messages in log monitoring module
+ * add feature to check for missing heartbeat messages in
+ log monitoring module
+ * cache UIDs/GIDs to reduce the number of lookups
+ * use inotify to track login/logout (sh_inotify.c, sh_utmp.c)
+ * support event correlation in log monitoring module
+ * make sure host matching is done in a case insensitive way
+ (reported by Tracy)
+ * fix invalid use of mutex_mlock in src/sh_unix.c, function
+ sh_unix_count_mlock() (reported by Remco Landegge).
+
+2.6.0 (01-11-2009):
+ * don't use statvfs() for process checking on FreeBSD
+ * fix bug with parallel compilation of cutest in Makefile
+ * sh_mem.c: fix deadlock in debug-only code
+ * Evaluate glob patterns for each run of file check
+ * Add compile option to disable compiling with SSP
+ * Run SUID check in seperate thread
+ * By default disable scanning ..namedfork/rsrc (deprecated by Apple)
+
+2.5.10 (12-10-2009):
+ * sh_suidchk.c: handle $HOME/.gvfs mount gracefully
+ * slib.c: fix race condition caused by closing a stream and the fd
+
+2.5.9c (01-10-2009):
+ * move stale file record error message closer to problem zone
+ * sh_port2proc.c: fix flawed logic for interpreting /proc/net/udp,tcp
+
+2.5.9b (22-09-2009):
+ * remove stale file record when creating handle, and raise diagnostic
+ error to find origin of stale record
+ * sh_port2proc.c: check /proc/net/upd6 for IPv6-only UDP sockets
+
+2.5.9a (17-09-2009):
+ * fixed a race condition in closing of file handles
+
+2.5.9 (11-09-2009):
+ * added code to generate directory for pid file, since it
+ would get cleaned if /var/run is a tmpfs mount (problem
+ reported by M. Athanasiou)
+ * fixed a bug that prevented reporting of user/executable path
+ for open UDP ports (issue reported by N. Rath)
+ * added more debugging code
+
+2.5.8a (18-08-2009):
+ * fixed a bug in sh_files.c that would prevent samhain from
+ running on MacOS X (reported by David)
+
+2.5.8 (06-08-2009):
+ * fixed a bug in the MX resolver routine which causes it to fail
+ sometimes (issue reported by N. Rath).
+ * fixed deadlock with mutex_listall in sh_nmail_test_recipients() if
+ error occurs within sh_nmail_flush (problem reported by N. Rath)
+
+2.5.7 (21-07-2009):
+ * sh_userfiles.c: set userUids = NULL at reconfiguration (issue
+ reported by U. Melzer)
+ * if available, use %z to print timezone as hour offset from GMT
+ in email date headers (problem reported by NP, solution suggested
+ by TimB).
+ * eliminate C99-style comments (problem reported by
+ venkat)
+ * fix bad variable name for AC_CACHE_CHECK
+ * fix potential deadlock when external programm is called
+ (problem reported by A. Dunkel)
+
+2.5.6 (09-06-2009):
+ * recognize fdesc filesystem on MacOS X for suid check (Problem
+ reported by David)
+
+2.5.5 (01-05-2009):
+ * fix some warnings from gcc 4.4 (strict aliasing)
+ * fix minor memory leak in process check
+ * t-test1.c: change function names because of clashes with an
+ AIX system header file
+ * fix warnings with -fstack-check (too large stack frames)
+ * fix for incorrect handling of hostnames in database insertion
+ (reported by byron)
+
+2.5.4 (04-03-2009):
+ * fix for incorrect input check in SRP implementation (discovered
+ by Thomas Ptacek)
+ * option KernelCheckPCI to switch off check of PCI expansion ROMs
+
+2.5.3 (25-02-2009):
+ * disable dnmalloc on MacOS X, doesn't work properly
+ * stat -> lstat in sh_unix_file_exists (OS X nameforks, report
+ by David)
+ * Fix problem in standalone trustfile, does not work correctly on
+ group-writeable files (reported by David).
+ * Option SetThrottle to throttle throughput for db download
+ * Option SetConnectionTimeout to configure the client connection
+ timeout configurable
+ * Provide getrpcbynumber, getservbyname implementations
+ to avoid dependencies with static linkage
+ * Fix missing sh.host.(system|release|machine) on FreeBSD,
+ reported by D.Lowry
+ * New option SetMailPort to allow setting of SMTP port (patch
+ by lucas sizzo org)
+ * allow POSIX regexes for filters
+ * consolidate filtering code from sh_extern.c, sh_(n)mail.c
+ * rewrite mail subsystem to allow individual filtering
+ for recipients
+ * allow shell expansion for values of config file options
+ * allow list as value for option PortCheckInterface
+ * fix bug in trustfile.c (with slapping on "/../" for symlinks)
+ * lock baseline database upon writing
+
+2.5.2b (29-01-2009):
+ * turn warnings into errors in the compile test suite
+ * fix missing define in sh_portcheck.c to eliminate compiler warning
+ (reported by joerg)
+
+2.5.2a (26-01-2009):
+ * fix problem building deb package (bit rot; reported by joerg)
+
+2.5.2 (22-01-2009):
+ * samhain.c: report module failure with positive offset
+ * sh_database.c: parse numerical fields into ulong
+ * fix regression test script for postgresql
+ * fix regression test script for SELinux/ACL test
+ * fix reporting of user for open ports to prelude
+ * report process pid for open ports
+ * replace _exit() by raise(SIGKILL) b/o pthread problem
+ * new option LooseDirCheck ([false]/true), request by
+ Alexander
+ * improved help output of samhain_stealth (as suggested
+ by Michael Athanasiou)
+ * new option ProcessCheckIsOpenVZ ([false]/true)
+
+2.5.1 (07-12-2008):
+ * workaround for freebsd7 amd64 lossage (compiler toolchain,
+ no mmap to 32bit address space)
+ * samhain-install.sh: check for presence of stealth_template.ps
+ before trying to create it
+ * use -Wno-empty-body if supported to suppress warnings about
+ glibc pthread_cleanup_pop implementation
+ * fix text relocations for i386 in src/sh_tiger1.s
+ * implement server->client SCAN command to initiate file check
+ * implement @if / @else conditionals with more tests in config file
+ * new option SetDropCache to drop checksummed files from cache
+ * report process/user for open ports on FreeBSD (code
+ lifted from FreeBSD sockstat.c)
+ * fix for config reload issue with stealth mode (reported by
+ siim)
+ * add -fstack-protector flags to LDFLAGS
+ * cygwin fix: don't use dnmalloc, doesn't work with pthreads
+ * cygwin fix: make trust check in samhain-install.sh return zero
+ * improved diagnostics for file read errors
+ * fixed script permissions (754 -> 755), reported by Christoph
+ * constness patch by Joe MacDonald
+ * GnuPG key ID patch by Jim Dutton
+ * sh_kern.c: more error checking for reads from kernel
+
+2.5.0 (01-11-2008):
+ * dnmalloc.c: fix inconsistent chunksize on 64bit systems
+ * fix improved error reporting for failed fstat in checksumming
+ * report process/user for open ports (Linux only currently)
+ * fix deadlock on exit in sh_hash_init()
+ * fix --enable-mounts-check for FreeBSD 7.0 (no MNT_NODEV anymore)
+ * log monitoring support
+ * fixed constness in trustfile interface
+ * remove libprelude 0.8 support (obsolete)
+ * sh_forward.c: increase TIME_OUT_DEF to 900 secs
+ * dnmalloc.c: initialize rc in dnmalloc_fork_child(),
+ reported by B. Podlipnik
+
+2.4.6a (09-10-2008):
+ * fix compile problem on Fedora 9 (reported by pierpaolo),
+ 'struct ucred' in sh_socket.c requires _GNU_SOURCE
+
+2.4.6 (27-08-2008):
+ * fix compile failure on win2k/cygwin (sh_unix_mlock prototype),
+ reported by jhamilton
+ * fix potential deadlock with dnmalloc upon fork()
+ * fix non-portable use of 'hostname -f' in regression test suite
+ (reported by Borut Podlipnik)
+
+2.4.5a (18-08-2008):
+ * fix compile problem in dnmalloc.c (remove prototypes for
+ memset/memcpy), problem reported by Juergen Daubert
+
+2.4.5 (07-08-2008):
+ * testscripts: 'chmod -R' -> 'chmod -f -R', since Solaris 10
+ bails out on a chmod on a dangling link
+ * fix bug in check_samhain.pl nagios script (J.-S. Eon)
+ * use the UNO static checker
+ * compile as position independent executable (PIE)
+ * handle EINPROGRESS error (Windows/cygwin issue)
+ * make sure every function uses less than one page of stack
+ (proactive security against gap jumping, Gael Delalleau)
+ * use dnmalloc instead of system malloc
+ (proactive security against heap buffer overflows)
+ * fix dnmalloc bugs and portability problems
+ * check for compressBound, since older zlibs don't have it
+
+2.4.4 (30-04-2008):
+ * sh_database.c: fix maximum size of sql query string, maximum
+ size of strings in struct dbins_
+ * sh_hash.c: fix maximum size of message string
+ * fix typo in the base64 decoder
+ * fix 'make cutest' for parallel compiling
+ * fix compile warnings with -Wstrict-prototypes
+ * sh_static.c: override getgrgid, getpwuid for libacl
+ * fix more warnings about variables clobbered by 'longjmp'
+ or 'vfork' (due to library internal handling of mutexes)
+ * fix configure warning about unused datarootdir
+ * configure.ac: warn, but accept nonexistent tmp dir
+ (Problem reported by Brian)
+ * sh_unix.c: undef P_ALL, P_PID, P_PGID before including
+ sys/wait.h (compile problem reported by Reputation)
+ * syslog function tested ok with Syslog Fuzzer v0.1
+ by Jaime Blasco (c) 2008
+ * slib.c: call fflush when writing trace to file
+ * sh_readconf.c: don't set OnlyStderr to false if gpg (problem
+ reported by Irene Reed)
+ * fix unconditional removal of pid file in atexit handler (bug
+ reported by Brian)
+ * fix invalid free() in sh_unix_checksum_size()
+ * sh_processcheck.c: workaround for stupid OpenBSD bug (returns
+ ENODEV instead of EAGAIN, because fgetc does
+ fcntl(0,F_SETFL,O_NONBLOCK) [ENODEV] internally), problem
+ reported by Roman R.
+ * fix buf that cause incomplete reporting of modified symlink if
+ symlink has changed and both old and new paths are >48 bytes
+ * fix bug that prevented mount check from running in one-shot mode
+ * enable mount check for openbsd
+ * fix processcheck default options and test script for openbsd
+ * option --list-file to list content of file (if saved)
+ * sh_tools.c: use strcasecmp in reverse lookup since DNS is case
+ insensitive (bug reported by Phil)
+ * fill content if MODI_TXT, zlib compress, base64 encode and add
+ as link_path in sh_unix.c; add to report in sh_hash.c
+ * testsuite: add test for gpg fingerprint option
+ * sh_extern.c: add 'CloseCommand' for syntactic sugar,
+ add in testsuite
+
+2.4.3a (12-02-2008):
+ * fix compile error caused by open() with O_CREAT and no third argument
+ (reported by J.-S. Eon)
+
+2.4.3 (31-01-2008):
+ * sh_kern.c: don't require asm/segment.h for kernel check module
+ * use global var with pid of initial thread instead of getpid(),
+ since LinuxThreads returns different value in each thread (problem
+ reported by Steffen Mueller)
+ * sh_kern.c: no inode check for pci rom (creates spurious messages)
+ * slib.c: eliminate prototype for vsnprintf (compile problem reported
+ by eddy_cs)
+ * Makefile.in: fix missing dependency on 'encode' for $(OBJECTS)
+ (reported by Matthias Ehrmann)
+
+2.4.2 (17-01-2008):
+ * fix broken option --with-checksum (reported by halosfan),
+ regression test added
+ * change HP-UX default optimization to +O2 since +O3 breaks
+ cutest unit testing framework
+ * put result vector of rng in skey struct
+ * fix more compiler warnings, and a potential (compiler-dependent)
+ NULL dereference in the unix entropy collector
+ * fix some compiler warnings
+ * use -D_FORTIFY_SOURCE=1 -fstack-protector-all instead
+ of -fstack-protector
+ * always add PTHREAD_CFLAGS to LDFLAGS
+ * sh_tiger0.c: checksum functions return length of file hashed,
+ needed to fix GrowingLogfile bug (researched by
+ siim at p6drad dash teel dot net)
+ * sh_static.c: fix more 'label at end of compound statement'
+ (SH_MUTEX_UNLOCK closing brace; reported anonymously)
+ * make sh_hash.c thread-safe
+ * remove plenty of tiny allocations
+ * improve sh_mem_dump
+ * modify port check to run as thread
+ * new option PortCheckSkip to skip ports
+ * fix unsetting of sh_thread_pause_flag (was too early)
+
+2.4.1a (28-11-2007):
+ * fix overwrite of ErrFlags (functionality bug)
+
+2.4.1 (26-11-2007):
+ * security fix: regression in the seeding routine for the PRNG
+ (detected by C. Mueller)
+ * regression test added for PRNG seeding routine
+ * fix problem with PCI ROM check (spurious messages about modified
+ timestamps, reported by S. Clormann)
+
+2.4.0a (08-11-2007):
+ * fix compile failure with --enable-static (reported by S. Clormann)
+ * fix potential deadlock if SIGHUP is received while suspended
+
+2.4.0 (01-11-2007):
+ * eliminate alarm() for I/O timeout (replaced by select)
+ * use getgrgid_r, getpwnam_r, getpwuid_r, gmtime_r, localtime_r,
+ rand_r, strtok_r if available
+ * protect readdir(), getpwent(), gethostname() with mutexes
+ (readdir_r considered harmful)
+ * make checksum/hash, entropy, rng functions reentrant
+ * use thread-specific conversion buffer for globber()
+ * fixed compile problems and problems with test suite
+ * modify login watch to run as thread
+ * modify process check to run as thread
+
+2.3.8 (03-10-2007):
+ * new option PortCheckIgnore = interface:portlist
+
+2.3.7 (13-09-2007):
+ * Makefile.in: fix 'make deb' target, wrong name of config file
+ written to debian/conffiles (reported by marc)
+ * configure.ac: fix incorrect order of with-prelude, enable-static
+ (libprelude test was always without -static)
+
+2.3.6 (06-09-2007):
+ * added yuleadmin.pl script contributed by Riccardo Murri
+ * fix compile error with -f-stack-protector on some systems (reported
+ by marc); we now check for libssp
+ * fix local DoS attack on BSD systems lacking getpeereid() (reported
+ by Rob Holland).
+ * fix yulectl password reading from $HOME/.yulectl_cred, erroneously
+ rejected passwords with exactly 14 chars (reported by Jerry Brown)
+ * introduce 'fflags' flag for suid files to detect new files already
+ found in regular file check (problem reported by J. Crutchfield);
+ also add regression test to ascertain that files in baseline
+ database are not quarantined erroneously
+ * sh_hash.c: replace check for prefix 'K' with check for not prefix'/'
+ to allow for arbitrary module-specific store/lookup in db
+ * replace 'visited', 'reported', 'allignore' with generic 'fflags' field
+ * sh_cat.c: reduce priority of MSG_TCP_RESET to avoid spamming if
+ port checking is used on same host as server (reported by kadafax)
+ * Install.sh: don't use --separate-output with non-checklist
+ widgets (problem discovered by D. Denton)
+ * sh_gpg.c, sh_userfiles.c: use sh_getpwnam et al. wrappers
+
+2.3.5 (20-06-2007):
+ * sh_portcheck.c: try to tear down connections more gracefully
+ (request by S. Petersen)
+ * fix incorrect handling of files with zero size in GrowingLogFiles
+ (problem reported by S. Petersen)
+ * fix incorrect encoding of null checksums in stealth mode
+ * sh_hash.c: fix repeated printing of acl/attributes in database dump
+ * sh_unix.c: fix option useaclcheck ignored if both useaclcheck and
+ useselinuxcheck are supported
+
+2.3.4 (01-05-2007):
+ * sh_processcheck.c: fix missing init of sh_prochk_res array before
+ check (leads to degrading functionality over time and 'fake pid'
+ warnings; reported by D. Ossenbrueggen and
+ soren dot petersen at musiker dot nu)
+ * sh_processcheck.c: fix memory leak
+ * sh_kern.c: for 2.6.21+ don't check proc_root_lookup (not possible
+ anymore? proc_root_inode.lookup != proc_root_lookup)
+ * sh_extern.c: flush streams before forking (problem if [Prelink]
+ used together with prelude logging, reported by M. deJong)
+ * fixed compilation of kern_head (regression cause by cross-compiling
+ fix; problem reported by S. Clormann)
+ * more typos fixed (reported by John Horne)
+
+2.3.3 (27-03-2007):
+ * fixed typos in configure.ac and manual (reported by John Horne)
+ * don't use mysql_options on x86_64, since libmysql is broken
+ * fixed cross-compiling (patch by Joe MacDonald)
+ * refactor sh_kern.c, sh_suidchk.c
+ * fix bug with leading slashes in linked path of symlinks within
+ the root directory
+ * sh_kern.c: check PCI ROM (Linux), refactor code
+ * move file descriptor closing more towards program startup
+ * kernel check: support OpenBSD 4.0 (wishlist)
+ * fix samhain_hide module (in-)compatibility with recent kernels
+ (reported by Jonny Halfmoon)
+
+2.3.2 (29-01-2007):
+ * fix regression in full stealth mode (incorrect comparison of
+ bytes read vs. maximum capacity), reported by B. Fleming
+
+2.3.1a (21-01-2007):
+ * fix incorrect use of sh_gpg_fill_startup if option --with-fp is used
+ (reported by zeroXten)
+
+2.3.1 (21-01-2007):
+ * fix bug that may cause accidental closure of yule TCP socket
+ (problem reported by B. Masuda)
+ * fix sh_kern.c for kernel 2.6.19 (reported by S. Clormann)
+ * don't use sstrip in 'make deb', since dh_shlibdeps uses objdump
+ (reported by B. Masuda)
+ * rm report.pl from rules.deb.in (reported by B. Masuda)
+ * samhainctl(): longer timeout (bad status reporting at startup,
+ reported by Phil and by Dan Track)
+ * sh_portcheck.c: make connect errors more descriptive
+ * sh_portcheck.c: fix ignored setting of PortCheckActive
+ * sh_processcheck.c: add statvfs, and wrap for EINTR
+ * sh_portcheck.c: add wrappers for EINTR
+ * report user and executable for hidden processes
+ * fix update failure if reportonlyonce = false (reported
+ by D. Strine)
+ * fix compile error in sh_portcheck.c (problem on cygwin
+ reported by J. D. Fiori)
+ * check filenames ending in space (also for utf8 spaces)
+ * check and escape csv formatted db listing
+ * cache results of sl_trustfile_euid()
+ * trustfile: use 4096 for MAXFILENAME, switch to strncpy
+ * CL option -v|--version for info on version and compiled-in options
+
+2.3.0a (01-11-2006):
+ * fix compile failure with portcheck + stealth (reported by lucas)
+
+2.3.0 (01-11-2006):
+ * fix concurrency for inserts in oracle db
+ * add acl_(new|old) to database schema
+ * check for selix attributes and/or posix acl
+ * new option UseSelinuxCheck (bool)
+ * new option UseAclCheck (bool)
+ * regression tests for above
+ * add module to check for open ports
+ * add module to check processes (hidden/fake/missing)
+ * use const char* for argument of module configuration callbacks
+
+2.2.6 (31-10-2006):
+ * fix missing support for MacOX X init script (reported
+ by Daniel Kowalewski)
+ * fix error about non-readable file with no checksum required
+ * fix server warning about 'no server name known'
+ * fix 'make deb' makefile target
+ * fix default export severity for server
+
+2.2.5 (05-10-2006):
+ * fix broken Install.sh, reported by Alexander Kraemer
+ * workaround for glob(3) sillyness on MacOS X (reported by David)
+ * fix for broken resorce fork check (reported by David)
+ * fix for broken compilation on cygwin (reported by Elias)
+
+2.2.4 (03-09-2006):
+ * add regression test for the GrowingLogFiles issue to test suite
+ * fixed sh_unix.c: bug in database init if GrowingLogFiles used
+ with signed database (reported by Timothy Stotts)
+ * bug in manual fixed (incorrect documentation of --enable-user,
+ noticed by M. Brown)
+ * rc.subr compatible init script for FreeBSD/NetBSD
+ * improve routine to find rpm after build
+ * add netbsd rc file from Brian Seklecki (taken from pkgsrc-wip)
+ * fix error in manual (location of lock file)
+ * fix bug with SuidExclude (files in directory were still checked)
+
+2.2.3 (31-07-2006):
+ * fix samhainadmin.pl: check for gpg-agent running if use-agent is set
+ (ticket #28 by anonymous)
+ * fix stealth mode (regression in parser), problem reported by
+ Joschi Kuphal
+ * fix minor typo in sh_database.c (compile problem reported by
+ Joschi Kuphal)
+
+2.2.2 (17-07-2006)
+ * minor fixes for regression test scripts
+ * minor updates to the manual (suggested by Brian A. Seklecki)
+ * fix sh_kern.c, kern_head.c: kernel rootkit detection for 2.6.17+
+ (problem reported by Leonhard Maylein)
+ * fix samhain_hide.c for 2.6.17+: use module_param() if MODULE_PARM
+ is not defined
+
+2.2.1c (11-07-2006)
+ * fix sh_extern.c: sh_ext_add_default() cast to (void) was too early
+ (Solaris 8 build failure reported by Jesse)
+ * fix sh_unix.c: wrong prototype for sh_unix_mlock()
+ if HAVE_BROKEN_MLOCK (AIX 5.2 build failure reported by
+ Jonathan Kaufman)
+
+2.2.1b (20-06-2006):
+ * fix compile error on SuSE 10.1 (reported by Leonhard Maylein)
+
+2.2.1a (15-06-2006):
+ * fix compile error on i686/MacOS X (reported by Andreas Neth)
+
+2.2.1 (13-06-2006):
+ * fix gcc 4 warnings and build failure on x86_64 (debian bug #370808)
+ * fix compiling with Oracle (noticed by Colapinto Giovanni)
+ * fix configure.ac for most recent autoconf version
+ (debian bug #369503)
+ * fix a regression that would make impossible local updates w/clients
+ * fix a few missing '\n' in sh_getopt.c
+ * sh_kern.c: fall back on mmap() if read() fails on /dev/kmem
+ * fix Solaris package creation
+ * recognize Solaris doors and event ports
+ * fix the idmef_inode_t patch: provide required info to avoid stat()
+ * fix bug on database update: fill in dev and rdev fields
+ * fix get_file_infos() in sh_prelude.c: avoid premature return
+ * GCC_STACK_PROTECT_CC: AC_TRY_COMPILE -> AC_TRY_LINK
+ * deploy.sh: allow to set a group for hosts upon installation
+ * patch by Yoann: fix an issue when setting the idmef_inode_t object
+ * fix memory leaks in error paths in sh_prelude.c
+ * fix concurrent inserts with postgres in sh_database.c
+ * code cleanup
+ * fix manual version in spec file, first noticed by Imre Gergely
+
+2.2.0 (01-05-2006):
+ * patch by Jim Simmons for samhainadmin.pl.in
+ * fix testsuite portability problems
+ * fix md5 endianess problem detected on HP-UX 11i / PA-RISC 8700
+ * fix potential NULL dereference in sh_utmp_endutent()
+ * patch by Neil Gorsuch for suidchk.c (do not scan lustre, afs, mmfs)
+ * fix sh_ext_popen (OpenBSD needs non-null argv[0] in execve)
+ * fix make_tests.sh portability (echo '"\n"' does not work on OpenBSD)
+ * fix bug in sh_utils_obscurename (check isascii)
+ * scan h_aliases for FQDN if h_name is not
+ * add copyright/license info to test scripts
+ * add copyright/license info to deployment system scripts
+ * support server-to-server relay
+ * new CL option --server-port
+ * minor improvements in manual
+ * patch by Yoann Vandoorselaere for sh_prelude.c
+ * allow --longopt arg as well as --longopt=arg
+ * verify checksum of growing log files (up to previous size)
+ * rewrite of the test suite
+ * added a bit of unit testing
+ * minor optimizations in various places
+ * optimized implementation of tiger checksum algorithm
+ * read in 64k blocks (faster than 4k)
+ * sh_unix.c, sh_hash.c: support file flags on *BSD, update Linux
+ file attribute code
+ * kern_head: fix compilation of kernel check module on OpenBSD
+ * updated samhainrc.linux, samhainrc.freebsd
+ * sh_unix.c: fix setrlimit (RLIMIT_NOFILE, ..)
+ * sh_files.c: fix missing use of flag_err_info
+ * sh_tiger0.c: remove repetitive use of mlock
+ * slib.c: remove fcntl's from sl_read_timeout (caller sets O_NONBLOCK),
+ add function sl_read_timeout_prep
+
+2.1.3 (13-03-2006):
+ * fix compile problem in slib.c (reported by Lawrence Bowie)
+ * fix bug with combination of one-shot update mode and file check
+ schedule (reportedby Dan Track)
+ * improved the windows howto according to suggestions by
+ Jorge Morgado
+ * fix samhain_hide kernel module for new linux kernel versions
+ * fix minor problem with dead client detection (problem reported
+ by Michal Kustosik)
+
+2.1.2 (10-01-2006):
+ * fix startup error with combination of gpg+prelude
+
+2.1.1a (22-12-2005):
+ * fixed a stupid bug in sh_files.c (break if file = dir)
+
+2.1.1 (21-12-2005):
+ * sh_calls.c: protect sh_calls_set_bind_addr against overriding
+ * comINSTALL, updateDB: use locking
+ * samhainadmin.pl: use locking
+ * fix typos in samhainrc.solaris (noticed by Robby Cauwerts)
+ * improve zAVLSearch (remove redundant strcmp)
+ * use AVL tree in sh_files.c instead of linked list (better scaling)
+ * fix bug with suidcheck (no update/check in one-shot mode with
+ schedule instead of check interval; noticed by R. Rati)
+ * fix for problem with '-t update -i' if daemon mode (problem report
+ by Peter van der Does)
+ * fix for bug in sh_util_ask_update (two returns were required ...)
+
+2.1.0 (31-10-2005):
+ * minor fix for cross-compiling with --with-kcheck
+ * sh_forward.c: handle bad fds in the select() fd sets
+ (reported by hmy)
+ * sh_extern.c: fix debugging code
+ * slib.c, sh_calls.c, sh_calls.h: improve handling of O_NOATIME
+ (reported by Gabor Kiss)
+ * makefile.in: fix for solaris package creation
+ * sh_mail.c, sh_readconf.c: mail filtering options
+ * sh_database.c: Oracle reconnect on connection failure
+ (bug report by Alexander A. Sobyanin)
+ * sh_unix.c: don't purge MYSQL_UNIX_PORT environment variable
+ (problem reported by Peter)
+ * sh_calls.c: fix for a HP-UX accept() problem caused by the gcc4 fix
+ * fixes for gcc 4.0.2 compiler warnings
+ * ability to use daemon mode together with update
+ (wishlist Yoan Vandoorselaere)
+ * fixes for debugging
+
+2.0.10a (22-08-2005):
+ * fix for overlapping directory check specification (reported by Bub)
+
+2.0.10 (21-08-2005):
+ * fix for segfault (free() on a constant string) with libprelude
+ (problem reported by Grae Noble)
+ * upgrade FreeBSD kernel check to 5.4, minor fixes
+ * useful script for users of Linux kernel check
+ (contributed by marc heisterkamp)
+ * documentation improvements (suggested by Brian Seklecki and Robby)
+
+2.0.9 (25-08-2005):
+ * samhain_erase.c: add #define for NULL
+ * sh_suidchk.c: fix incorrect use of escaped filename
+ * sh_prelude.[ch], sh_readconf.c: configurable mapping from
+ samhain severity to prelude severity
+ * sh_unix.h: second arg of gettimeofday should be NULL
+ * sh_files.c: fix checking of directory special file (use specified
+ policy, not that of parent dir, problem found by Brian A. Seklecki)
+ * sh_entropy.c: longer timeout for entropy collector
+ * sh_socket.c, sh_forward.c: allow probing of clients for
+ necessity of configuration reload
+ * yulectl: minor fixes, option -v (verbose), new command PROBE
+ * fix 'File not found' messages for files flagged with IgnoreMissing
+ * sh_database.c: strip newline from oracle error messages
+ * sh_files.c: fix rsrc fork issue with MacOS X Tiger
+ (reported by A. Koren)
+ * never compute checksum if not checked (problem report by D.Hughes)
+ * sh_prelude.c: cleanup and bugfix by Yoann
+ * sh_hash.c: for prelude, make sure mode is supplied with user/group
+ and vice versa
+ * sh_prelude.c: provide proper FileAccess objects (bug
+ report by Mihai Ilinca)
+
+2.0.8 (03-07-2005):
+ * configure.ac: use $LIBPRELUDE_PTHREAD_CFLAGS rather than
+ $LIBPRELUDE_CFLAGS (bugfix by Yoann)
+ * samhain.spec.in: remove support for chkconfig (it's too buggy).
+ Strangely, if invoked as install_initd it behaves sanely ...
+ * src/sh_err_log.c: fix key input (this time for real)
+ * fix --with-altlogserver (bug from 2.0.7b)
+ * remove server socket in start/stop script
+
+2.0.7e (not released):
+ * Makefile.in: introduce a total of 6 sec delay for 'make' utilities
+ that use 1 sec resolution, and consider target out-of-date if
+ timestamp(target) = timestamp(dependency) ...
+ * src/sh_err_log.c: fix key input
+ * another fix for yulectl (use pwent->pw_dir)
+ * dsys/comINSTALL, dsys/comUNINSTALL, dsys/comBUILD: fix PATH
+
+2.0.7d (not released):
+ * one more fix for the spec file (stupid rpm finds tags in comments!!!)
+
+2.0.7c (not released):
+ * test/testrun_1b.sh, test/testrun_2b.sh: use $GPG_PATH
+ * dsys/comINSTALL, dsys/funcDB, dsys/funcINSTALL: some bugfixes
+ * samhain-install.sh.in: fix test -z $verbose
+ * sh_hash.c: speedup database reading
+ * Makefile.in: fix the problem that BSD make would make too much
+ * deploy: yulerc.clients -> yulerc.install.db, provide
+ $defdatabase for backward compatibility
+ * deploy: allow for comma in client_install_date
+
+2.0.7b (not released):
+ * hp_ux.psf.in: fix psf file
+ * dsys/comINSTALL: fix $yule_date -> $yule_data
+ * Makefile.in: fix 'make depot'
+ * sh_tools.c, sh_unix.c: fix detection of open file limit
+ * sh_readconf.c: reset read_mode after reading conf file
+ * yulectl.c: better error messages, use homedir from getpwuid(geteuid)
+ * init/samhain.startLSB.in: fix misleading message in lsb init script
+ * sh_forward.c: better display for nonce u in debug mode
+ * sh_tiger*.c: fix checksum for HP-UX 64bit
+ * samhain.c: don't fetch database twice
+ * configure.ac: accept nodename for --with-logserver=...
+ * samhain_setpwd.c: return proper exit status for samhain_setpwd
+ * respond to SIGTERM on initializing
+ * fix problems with samhainadmin.pl
+ * sh_utils.c: fix bug with AddOKChars (found by Karol)
+
+2.0.7a (not released):
+ * remove 'df' from entropy gatherer (NFS may hang)
+ * modify va_copy check (doesn't work with HP-UX PA64 compiler)
+ * fix compile warnings in sh_database.c
+ * samhain-install.sh.in: check for /usr/bin/false in /etc/shells
+ * fix install-boot on HP-UX
+ * aclocal.m4: fix configure CL parsing to recognize VAR=VALUE
+
+2.0.7 (11-06-2005):
+ * yet another fix for the spec file (use internal dependency generator)
+ * sh_error.c, sh_prelude.c: init libprelude after open fds are closed
+ * error message if queue is full
+ * fix two compiler warnings on HP-UX
+ * fix sh_mail.c for Interix (no resolver routines)
+ * fix sh_unix_initgroups2() if no initgroups() function (bug reported
+ by Geries Handal)
+ * remove references to 'struct timezone' (Interix; problem
+ reported by Geries Handal)
+ * init/stop for prelude on SIGHUP
+ * sh_cat.h: fix a stupid bug with messages classes
+ * manual: new section on nagios (with help from kiarna),
+ more on prelude
+ * sh_prelude.c: cleanup and improvements (Yoann Vandorselaere)
+ * default prelude profile name now is 'samhain' (lowercase)
+ * sh_readconf.c: new option PreludeProfile (by Yoann Vandorselaere)
+ * remove obsolete check for linux/module.h, linux/unistd.h
+ * remove dependency on virtual/glibc in gentoo ebuild
+ (problem reported by Willis Sarka)
+
+2.0.6 (01-03-2005):
+ * sh_prelude.c, configure.ac, aclocal.m4: support for
+ libprelude 0.9 (Yoann Vandoorselaere)
+ * sh_html.c: fix bug with entry.html template (reported by
+ Stephane Sanchez)
+ * Install.sh: fix mandir option (reported by Rodney Smith)
+ * Fixed Linux/64bit bug in definition of EUIDSLOT
+ * New targets 'make depot', 'make depot-light' (HP-UX, untested)
+ * Use sstrip for RPMs and DEBs (automatic stripping disabled)
+ * Fix aclocal.m4 for autoconf 2.59 (missing $ac_cr_alnum et al.,
+ problem noticed by Yoann Vandoorselaere)
+ * Modify samhain.spec.in to disable automatic stripping upon install
+ * Fix deploy.sh + '--enable-gpg', and fix 'make rpm' and 'make deb'
+ for '--with-khide' (problems reported by Mark)
+ * Fix compile error in sh_tools.c on HP-UX 10.20
+ (problem reported by Dennis Boylan)
+ * Runtime configuration of server listening port (wishlist)
+ * Runtime configuration of server listening interface (wishlist)
+ * Ignore SIGTTIN (consistency)
+ * Use SIGTTOU to force file check (wishlist)
+
+2.0.5b (01-04-2005):
+ * Fix build problem b/o timestamp on stamp file
+
+2.0.5a (16-03-2005):
+ * Fix problem with 'make rpm' (reported by Dirk Brümmer)
+
+2.0.5 (02-03-2005):
+ * Fix bug with partial reads from clients in server
+ (bug report by Brian)
+ * Support gpg checksum bootstrap with yule
+ * Support mount option check on HP-UX
+ * For MAIL FROM, use 'example.com' as domain part if
+ hostname is numeric (problem reported by Eric Raymond)
+ * The HOWTO-write-modules has been updated.
+ * Convenience functions to insert data in database have been
+ added.
+ * Use int0x03 only on i386 in sh_derr() (portability problem
+ reported by John Mandeville)
+
+2.0.4 (09-02-2005):
+ * Fixed broken 'make deb' (problem report by olfi)
+ * Fixed minor bug in test scripts (detection of gmake vs. make)
+ * Fixed Tru64/OSF compile warnings (reported by B. Terp)
+ * Normalize list parsing to allow comma, space, and tab as separators
+ * Some more descriptive error messages in kern_head.c
+ * Absolute path to utilities in init/samhain.startLinux.in
+ * Fixed is_root variable in deploy.sh
+ * Fixed 'deploy.sh info'
+ * Fixed 'deploy.sh install' client startup
+ * Fixed 'make tbz': don't remove ebuild scripts in 'make dist'
+ (issue reported by W. Sarky)
+
+2.0.3 (14-12-2004):
+ * Fix CPPFLAGS with mysql/postgresql (repoted by P. Smith)
+ * Fix missing sys/time.h include in slib.c (reported by Jonas)
+ * Workaround for file closing problem with Prelude+GPG
+ * Fixed memory leak with Prelude.
+ * Fixed bug in samhain_stealth (PGP signature not correctly
+ retrieved from hidden configuration; report and patch by V. Tuska)
+ * Added Perl script to concatenate file signature database files
+ * Fix compile error with combination of --enable-nocl and
+ --enable-stealth (reported by Zdenek Polach)
+ * Fix bug in dsys/initscript with --enable-nocl
+ * Fix declaration of sh_kern_timer()
+ * Fix missing Mounts+Userfiles options in appendix of manual
+ * Updated the README (bug report by H. Franzke)
+ * Fix some compiler warnings
+
+2.0.2a (09-11-2004):
+ * Fixed OoM condition when client rc file not found (reported by Eilko)
+
+2.0.2 (08-11-2004):
+ * Fixed buffer overflow in sh_hash_compdata() (only in 'update' code)
+ * Fixed uninitialized variable in sh_mail_msg() (problem reported
+ by Michael Milvich)
+ * Fixed potential NULL pointer dereference in sh_hash_compdata()
+
+2.0.1 (01-11-2004):
+ * Fixed compilation bug reported by jue (--with-kcheck broken).
+ * Fixed start option (bug reported by sanek). Behaviour wrt.
+ environment variables depended on the way the daemon was started.
+
+2.0.0 (31-10-2004):
+ * The deployment system has been rewritten from scratch in
+ a cleaner and more modular and extensible way. Deployment
+ of native packages is supported now.
+ * The build system has been revised. Building outside the source
+ directory is supported now.
+ * Support for checksumming of prelinked executables / libraries
+ has been added.
+ * The configure script now checks for the SSP/ProPolice patch in GCC,
+ and enables it if present.
+ * The install-boot option in samhain-install.sh has been fixed
+ (use absolute paths for sbin utilities).
+ * A nagios plugin (scripts/check_samhain.pl) has been added.
+ * The LSB (Linux Standard Base) init script has been fixed (the output
+ was incorrect).
+ * Fetching of built binary packages has been
+ fixed ($(PACKAGE)->@install_name@).
+ * For files in proc, the timeout has been reduced, and no error
+ messages are issued upon timeout.
+ * A function has been added to print out full details for missing
+ files if encountered while in sh_files().
+ * The reporting for SuidCheck has been fixed (incorrect policy
+ noticed by JiM).
+ * On Linux, SuidCheck does not report on files marked as candidates
+ for mandatory locking (group-id bit set, group-execute bit cleared).
+ * Fix for oracle init script (by Matt Warner)
+
+1.8.12b (11-10-2004):
+ * fix bug in MSG_MSTAMP (%ld -> %lu)
+ * fix bugs in sh_suidchk.c (%ld -> %lu), check fopen for NULL,
+ mkdir mode for quarantine directory
+ * fix the fix for modlist_lock search in System.map
+
+1.8.12a (01-10-2004):
+ * fix bug in samhain-install.sh.in (only occurs on Solaris), reported
+ by J. Roland
+
+1.8.12 (27-09-2004):
+ * fix compile bug with --enable-static + --with-database=postgresql
+ * fix search for modlist_lock in System.map
+ * password auth for yule command socket (request by D. Kocic)
+ * more info about pending/sent commands to clients
+
+1.8.11 (30-08-2004):
+ * fix static linking on Linux by use of replacement routines from
+ uClib - however, this means, there is no NIS support anymore
+ * new option AddOKChars=... to modify the set of characters for
+ filenames considered 'obscure'
+ * new option HardlinkOffset=... to specify an offset from the canonical
+ hardlink count for a directory
+ * fix some warning with HP 11.23 native compiler
+ * fix minor OpenBSD portability problems (EIDRM, compiler warning)
+ * samhainrc.5, samhain.8: updated the man pages
+ * sh_unix.c, sh_files.c: ignore 'no user/group' and 'obscure name'
+ for AllIgnore
+ * sh_kern.c: fix 'update' to display modifications
+ * sh_kern.c: fix bug with IDT check (spurious alerts b/o uninitialized
+ fields)
+ * stealth kernel modules: fix for linux 2.6, fix
+ redefine of KERNEL_VERSION
+ * warn about stealth kernel module problem with 2.6 in manual
+ * sh_unix.c: remove some cruft
+ * fix a typo in the manual (noticed by J. Rubin)
+ * configure.ac: re-order output from libprelude-config (required
+ for static linking - problem reported by E. Neber)
+ * kern_head.h, kern_head.c: fixes for Linux 2.6 kernel
+
+1.8.10b (13-07-2004):
+ * fix incorrect usage of 'retry_msleep()' in sh_kern.c (reported
+ by Pat Smith)
+
+1.8.10a (13-07-2004):
+ * depend-gen.c: fix for FreeBSD 'make' which does not understand
+ the dependencies ... (problem reported by David Thiel)
+
+1.8.10 (13-07-2004):
+ * sh_unix.c/sh_unix.h: fix defaults for 'GrowingLogFiles' policy
+ (bug report by VZoubkov)
+ * fix some warnings (unreachable statement) with HP-UX native compiler
+ * kern_check.c: silence warning about 'sendfile' for 4.10
+ (noticed by Ryan Beasley)
+ * modify depend-gen.c to ignore sh_gpg_chksum.h
+ * add a non-plaintext version of GPG_HASH (sh_gpg_chksum.h)
+ * .. and for fingerprint
+ * sh_suidchk.c: fix some compiler warnings on solaris
+ * allow commas to separate multiple entries in a RedefXXX= directive
+ * replace sleep/usleep with nanosleep wrapper function
+ * replace alarm() for read timeout with select() in sl_read_timeout
+ (should fix bug reported by Scott Kelley)
+ * increase lstat/open timeout to 6 sec
+
+1.8.9 (16-06-2004):
+ * made 'no action specified' error message more informative
+ (suggested by Stephen Gill)
+ * fix memory leak in mysql sh_database_query() (bug report by Dejan)
+ * remove some cruft from the code
+ * sh_files.c: check MacOS X resource forks (idea from Osiris)
+ * sh_files.c: no hardlink check for MacOS X
+ * sh_util_ask_update: fix bug with no terminal in non-interactive mode
+ (report and debug data by Kris Dom)
+ * manual refactored
+ * fix redundant messages when updating with suidcheck
+ * allow interactive update for suid files
+ * don't remove the TZ environment variable to guard against
+ misconfigured hosts
+ * also use gethostname if uname returns possibly truncated name
+ * fix improper file descriptor handling in sh_mail.c (bug report
+ by Alex Weiss)
+ * cleanup MBLK cruft
+ * use SH_ALLOC/SH_FREE in sh_prelude.c
+ * update sstrip to Version 2.0
+
+1.8.8 (25-05-2004):
+ * fix compilation problem on AIX 5.2 (nameser_compat.h; report by
+ Tim Evans and Ian McCulloch)
+ * don't check for trusted paths on Cygwin
+ * add Windows HOWTO written by Kris Dom
+ * kern_check.h: extend FreeBSD syscall table for 5.x
+
+1.8.7a (03-05-2004):
+ * sh_mail.c: fix subject length
+ * sh_mail.c: fix the sh.mailNum.alarm_last fix (report by Kris Dom)
+ * sh_utils.c: sh_util_ask_update(): fix ISO C conformance bug
+ (compile problem reported by Kris Dom)
+
+1.8.7 (01-05-2004):
+ * sh_mail.c: fix incorrect count of sh.mailNum.alarm_last, causing
+ empty mails (introduced with segfault fix in 1.8.6, report
+ by Kris Dom)
+ * sh_utils.c: sh_util_ask_update(): check whether stdin is a terminal,
+ try to reopen on controlling terminal if not
+ * sh_utmp.c: fix order of options (problem report by Uri)
+ * sh_files.c: sh_files_chk(): set tmp = NULL at end of loop
+ (may cause segfault on null dereference for missing files)
+ * sh_unix.c: patch by Marc Schütz (order of sh_unix_getinfo_type,
+ sh_unix_getinfo_attr)
+ * don't use dh_installmanpages in 'make deb' (samhain/yule conflict
+ reported by xavier)
+ * on HP-UX, define _XOPEN_SOURCE_EXTENDED in sh_mail.c and sh_tools.c
+ (suggested by Kris)
+ * include nameser_compat.h in sh_mail.c (for MacOS X,
+ suggestion by jna)
+ * sh_utmp.c: fix time for logout events (reported by Erich
+ van der Velde)
+
+1.8.6 (15-04-2004):
+ * add CL option to set threshold for prelude and RDBMS
+ * sh_mail.c: fix bug with MailSubject option (segfault on NULL pointer
+ dereference; reported by Micha Silver)
+ * fix compiling with --disable-encrypt (reported by Pat Smith)
+ * fix minor problem in scheduler (don't return before all schedules
+ are tested, to set last_exec correctly)
+
+1.8.5 (05-04-2004):
+ * fix bugs in sh_utmp.c (unlinking of list head); may fix an OpenBSD
+ problem (endless loop; report and debugging aid by Joe MacDonald)
+ * fix hardlink check (null dereference in error message, segfaults
+ on solaris - noticed by Bob Bloom)
+ * sh_suidcheck: don't truncate quarantined file if nlink > 1
+ * fix Install.sh (no --seperate-output with --radiolist); patch by
+ Greg Kimberly
+
+1.8.4 (17-03-2004):
+ * add Prelude patch by Patrice Bourgin
+ * add license statement to sh_mounts.c, sh_userfiles.c after
+ receiving a clarifying e-mail from Cian Synnott
+ * support UsePersistent = no for Oracle (problem spotted and fix
+ tested by Michael Somers)
+ * fix bug in samhainadmin.pl
+ * sh_gpg.c: describe type of gpg error (if any)
+ * fix persistent connections with postgresql (reported by
+ Erwin Van de Velde)
+ * prelude: local 'meaning' shadows global in sh_prelude_alert
+ (spotted by David Maciejak)
+ * uname: workaround for cases where nodename would be a possibly
+ truncated FQDN (problem reported by Cian Synnott)
+ * re-write parts of sh_kern.c, store kernel info in baseline database
+ -> no need to recompile after kernel upgrade
+ * modify timeouts in sh_unix_getinfo, add timeout warning
+ * change handling of dangling symlinks (store in db)
+ * fix typo with MSG_FI_OBSC2 (double slash)
+ * remove redundant operation in sh_utils_safe_name
+ * fix occasional random start bytes of long messages in
+ sh_error_string (sl_strlcat -> sl_strlcpy)
+ * provide details for missing files (as for added files)
+ * remove duplicate message for no such group/user
+ * add fixes for samhain.oracle.init (supplied by Michael Somers)
+ * fix date insertion for Oracle (fix by Michael Somers)
+ * manual: fix incorrect statement about RPM (noticed by
+ Lars Kellogg-Stedman)
+
+1.8.3 (02-02-2004):
+ * add a HOWTO-client+server-troubleshooting document
+ * fix another bug with SIGUSR2 (suspend mode)
+ * new option SetBindAddress (--bind-address=...) to force
+ interface for outgoing connections on multi-interface box
+ * don't link against libgmp if not required (i.e. standalone)
+ * test for ext2fs/ext2_fs.h or linux/ext2_fs.h
+ * new make targets 'emerge' and 'tbz2' for gentoo
+ * update rules.deb.in based on the Debian package
+ by Javier Fernandez-Sanguino
+ * updated config.guess, config.sub to version 2002-09-05
+ * external command: report failure only once
+ * console: reset failure status after success
+ * README.UPGRADE: explain 1.7.x <-> 1.8.x client/server compatibility
+ * use persistent connection to database by default
+ * option UsePersistent=no to switch off persistent connection
+
+1.8.2 (19-01-2004):
+ * sh_userfiles.c: new option UserfilesCheckUids (requested)
+ * sh_error.c: server: don't log to logfile before dropping root
+ * new script scripts/samhainadmin.pl (administrative tasks for
+ signed config/database files)
+ * add changes code to log_msg for reports on modified files
+ * change default log threshold to 'mark', as 'none' tends
+ to confuse new users
+ * faster response time for SIGUSR2
+ * revised (mostly backward-compatible) message classes
+ * fix missing check of mailTime in server select loop
+ * add support for libprelude (version 0.8.10)
+ * fix format for MSG_E_GRNULL (reported by Stefan Hudson)
+ * fix Bourne shell incompatibility (export) in samhain-install.sh
+ (first reported by David Thiel)
+ * fix typo in spec file (first reported by Christian Vanguers)
+ * remove some cruft (signal handler, memory handling)
+ * return from sigterm handler, rather than exit directly
+ (re-entrancy problem causes more problems than it's worth)
+
+1.8.1 (03-12-2003):
+ * fix gmp detection (problem pointed out by Nix)
+ * fix/improve the error message if test compiling with mysql fails
+ * new CL option --interactive for interactive db update
+ * fix some compiler warnings from IRIX MIPS compiler
+ * kern_head.h, kern_head.c: option to disable IDT check
+ * kern_head.h, kern_head.c: update kernel syscall table (2.4.20,2.6)
+ * sh_utmp.c: count number of logins (request by Erwin Van De Velde)
+ * change username -> userid, remove (long) userid (bug noticed
+ by Erwin Van De Velde)
+ * emit ADDED message for new SUID/SGID files
+ * add trailing slash to excluded directory if there is none
+
+1.8.0a (04-11-2003):
+ * sh_error.c: remove two debug printf's
+
+1.8.0 (31-10-2003):
+ * manual: make ps file fit on both a4 and letter paper
+ * sh_socket.c, sh_socket.h, sh_forward.c: socket interface
+ to send (quit/reload) commands to clients
+ * sh_forward.c, configure.ac: enable build with libwrap
+ (Wietse Venema's TCP Wrappers library)
+ * sh_ignore.c, sh_ignore.h, sh_files.c, sh_hash.c, sh_readconf.c:
+ new option to suppress messages for new and/or deleted files
+ * samhainrc.aix5.2.0: contributed by Christoph Kiefer
+ * samhain.c: fix compile warning on solaris (noticed by Ian Hunt)
+ * sh_database.c: undef debug code for oracle
+ * samhain.oracle.init: contributed by Joern Michael Krueger
+ * configure.ac, sh_utils.ac, Makefile.in, sh_modules.c,
+ sh_cat.c, sh_cat.h, sh_mounts.c/h, sh_userfiles.c/h:
+ check-mounts and userfiles modules contributed by eircom.net
+ * sh_utils.c: fix off-by-one bug in sh_util_compress()
+ * sh_forward.c, sh_tools.c, configure.ac:
+ version 2 client/server protocol
+ * sh_mail.c: add %S to include severity in subject (user request)
+ * sh_suidchk.c, 1093: fix warning about unused var 'flags' on FreeBSD
+ * samhain.h, sh_unix.h, sh_unix.c: extern inline -> static inline
+ for --enable-ptrace
+ * samhain.c: lower priority for 'uninitialized module' message
+ * sh_entropy.c: lower priority for message if /dev/random blocks and
+ /dev/urandom is available
+ * improved error messages in sh_readconf.c
+ * print system error message for getpwuid, getgrgid
+ * fix missing module init after SIGHUP (noticed by Cian Synnott)
+
+1.7.12 (13-10-2003):
+ * sh_mail.c: fix buffer overflow in mail handler (introduced in 1.7.10)
+ thanks to bug reports by Jason Martin and Matthew P. Cox
+
+1.7.11 (01-09-2003):
+ * samhain.c, samhain.h, sh_unix.c, sh_forward.c, sh_html.h:
+ - change SIG_USR1 to switch between dbg on/off
+ - change SIG_USR2 to switch between suspend on/off
+ - fix CLT_ILLEGAL to actually work
+ - introduce new state CLT_SUSPEND
+ - force reauthentication after suspend
+ * slib.c: change MAXFD from FOPEN_MAX (16) -> 1024
+ * sh_suidchk.c: better AIX fs detection (Christoph)
+ * sh_entropy.c: increase buffer size for unix entropy gatherer
+ (problem reported by D. Danielson)
+ * default config files: add lots of comments, list more options
+ * sh_error.c: set default severities to 'crit'
+ * sh_readconf.c, sh_cat.c, sh_cat.h: stricter check on config
+ file syntax, issue warnings (triggered by C. Kiefer)
+ * Makefile.in: handle depend-gen errors more gracefully
+ * sh_err_console.c: fix bug in enable_msgq (reported by F. Behrens)
+ * configure.ac: workaround for mysql_config weird output
+ (reported by G. Faron)
+ * sh_unix.c, sh_tiger0.c: check IO limit during read of large files
+ * depend-gen.c: close streams before attempting to rename (Cygwin)
+ * Makefile.in: fail gracefully if depend-gen fails
+ * sh_database.c: sh_database_query(postgresql): fixed missing SL_ENTER
+
+1.7.10 (27-07-2003):
+ * FreeBSD init script: define $pidfile (reported by D. Thiel)
+ * sh_unix.c, sh_unix.h: fix compile error on AIX 4.2
+ * sh_schedule.c: fix bad array size
+ * samhain.c: fix pid_t <> int casts
+ * sh_kern.c: fix repetitive messages
+ * configure.ac: try to bootstrap if TIGER192 not supported by gpg,
+ provide a detailed error message
+ * configure.ac: try harder to locate mysql
+ * docs/Changelog: retroactively add release dates, if known
+ * sh_mail.c: fix potential message truncation in mailer
+ * sh_unix.c, samhain.c, samhain.h: make --enable-ptrace more portable
+ * sh_readconf.c: fix segfault (dereference of uninitialized pointer)
+ if --with-gpg and --enable-stealth are used together (reported
+ by Anthony Caetano)
+ * sh_unix.c, samhain.c, sh_calls.c: fix problems with descriptive
+ error messages (larger GLOB_LEN, stat fills aud_err_message)
+
+1.7.9 (30-06-2003):
+ * sh_err_log.c: fix segfault on SIGABRT (dereference of freed memory),
+ problems with SIGABRT noticed by Brian and Alf B Lervåg
+ * deploy.sh.in: fix some bugs (found by Alf B Lervåg)
+ * scripts/chroot.sh: fix typo (found by Alf B Lervåg)
+ * configure.ac (khide): search also for 'd sys_call_table' (noted by
+ cuek_saja)
+ * strip whitespace before checking gpg checksum (noted by D. Thiel)
+ * manual (faq section): explain how to stop console output
+ * Makefile.in: fix re-naming of yule with --enable-install-name
+ * HOWTO-client+server.html: fix typo (noted by xavier renaut)
+ * configure.ac: escape '-' in awk regex (required by GNU awk 3.1.1)
+
+1.7.8 (28-05-2003):
+ * sh_unix.c: new mlock implementation with reference count
+ and page alignment (fix for solaris problem)
+ * kern_head.c: search also for 'xxxxxxxx d sys_call_table'
+ * sh_html.c: write status comment (for Beltane 2)
+ * add CL option --delimited for comma-delimited signature database dump
+ * sh_mail.c: check exit status of push_list to fix counting bug
+ (bug reported by Alan Moore)
+ * configure.ac: add error message to --with-libs
+ * fix spelling of $DAEMON in init script (noted by C. Grigoriu)
+ * fix missing initgroups()
+
+1.7.7 (06-05-2003):
+ * sh_forward.c: fix bug if compiled with --enable-udp, but disabled
+ in config file (found by Andy OBrien)
+ * sh_database.c: sh_database_entry(): size -> c_size (two places)
+ to fix writing of '\0' to arbitrary places :(
+ (problem pointed out by Stefan Giesen)
+ * profiles/*/configopts: fix --with-base -> --enable-base
+
+1.7.6 (24-04-2003):
+ * sh_forward.c, entry.html, head.html: fix/additions by Stefan Giesen
+ * fix samhain_hide for the O(1) scheduler used by RedHat:
+ configure.ac, acconfig.h: check for next_task in struct task_struct
+ samhain_hide.c: use find_task_by_pid if no next_task in task_struct
+ * samhain_erase.c: add MODULE_LICENSE("GPL") to fix warning
+
+1.7.5 (15-04-2003):
+ * sh_cat.c, sh_forward.c, sh_hash.c: fix double 'msg' tag
+ * manual: point out the bmaxdata problem on AIX in faq section
+ * trustfile.c: don't check symlinks (permissions of directory count)
+ * sh_schedule.c: fix problem with daylight saving switchover
+ * sh_samhain.c: close all open fd's >2 before reading the conf file
+ * sh_unix.c: fix dereferenced NULL pointer when exiting on non-existing
+ user
+ * sh_forward.c: fix dereferenced NULL pointer when exiting on udp error
+ * sh_forward.c: place timestamp code before select() timeout handler
+ * fix incorrect class of timestamp messages (conflict with manual)
+ * sh_readconf.c, sh_forward.c: new config option SetStripDomain
+ * configure.ac: add warning if /lib/modules/`uname -r`/build/include
+ not found
+ * samhain_hide.c: adapt for RedHat 2.4 kernel (fetch sys_call_table
+ address from System.map)
+ * sh_err_syslog.c: fix for Solaris
+ * samhain.spec.in: strip REQ_FROM_SERVER from config file install path
+
+1.7.4 (21-03-2003):
+ * configure.ac: fix bug in defargs (--with-base > --enable-base)
+ * aclocal.ac: detect unsupported options
+ * kern_check: add syscalls, skip unused syscalls
+ * fix Manual (--enable.../--with... inconsistency)
+ * add two HOWTOs (signed files, server/client)
+ * moved manual into new subdirectory docs/
+ * add admin scripts by S.Bailey/M.Redinger
+ * option to have a version string in db file
+
+1.7.3 (23-02-2003):
+ * samhain-install.sh: use yule user key for signing on install
+ * fix a bug in sh_err_console.c (attempted write to const char)
+ * sh_gpg.c: if server, always use ~unprivileged_user/.gnupg
+ * Makefile.in: make target 'trustfile' depend on config.h
+ * configure.ac: don't use install_name before it is defined ...
+ * sh_tiger0.c: fix bug in checksum computation introduced in 1.7.2
+ * samhain.c: make sure daemon cannot be forced into 'update' mode
+ * sh_hash.c: remove AIX workaround (AIX has been fixed meanwhile)
+
+1.7.2 (04-02-2003):
+ * sh_kern.c: use sys_call_table address from System.map
+ * fix for reserved SQL keyword 'group'
+ * add AC_SYS_LARGEFILE to configure.ac
+ * allow separate client-specific log files for server
+ * sstrip.c: compile sstrip code only for i386
+ * sh_unix.c: closeall: don't close trace file
+ * slib.c: don't trace sl_is_suid (leads to recursion in trace handler)
+ * samhain-install.sh.in: fix detection of LSB compliant systems
+ * sh_tools.c: get_client_*_file: lstat -> stat to allow symlinks
+ * sh_forward.c: sh_forward_do_write: set O_NONBLOCK for fd
+ (may block otherwise, for no good reason apparently ...)
+ * samhain.spec.in: replace %configure with ./configure
+ * sh_unix.c: re-write signal handling (use __malloc_hook et al. to
+ check whether we are in the middle of a free/malloc/realloc/memalign)
+ * sh_unix.c: use new safe_logger() function to log from signal handler
+ * sh_err_log.c: fix xml
+ *
+ * fix Makefile.in to exit non-zero on compile failure
+ * database init: create index on log_host, entry_status
+ * sh_suidchk.c: fix path building
+ * sh_tiger0.c: read larger blocks
+ * sh_hash.c: cast inode to UINT32
+ * sh_tools.c: check that config/database files size fits in uint
+ * sh_error.c: export flag_err_debug to avoid unnecessary calls
+ * sh_unix.c: save the open() call in sh_unix_getinfo_attr()
+ * profiles/redhat_i386/bootscript: add # description field
+ * deploy.sh.in: set owner + permissions for files in yule_filedir
+ * profiles/debianlinux_i386: fix bootscript
+ * Makefile.in: fix deploy file lists and targets (include init+scripts)
+ * MLOCK GOOD/BAD -> SL_FALSE/SL_TRUE
+ * sh_mail.c: GOOD/BAD -> SL_FALSE/SL_TRUE (AIX sys/param.h)
+ * sh_err_syslog.c: split long messages rather than truncating
+ * sh_error.c: allocate msg to fix truncation limit
+ * sh_unix.c: closeall fd's >= 3 in non-daemon mode (inherited
+ filedescriptors may exceed FOPEN_MAX, causing problems in
+ sl_open_file)
+ * sh_err_console.c: avoid stdio
+ * trustfile: dirz: make swp[] static
+ * slib.c: speed up sl_strlcat
+ * clean up some bad heap allocation (PATH_MAX+(1|2) -> PATH_MAX)
+ * remove some unused code
+ * slib.c: support long long int in the snprintf replacement
+ * configure.ac: new configure macro to check whether sa_sigaction works
+ * Makefile.in: make sstrip, encode dependent on config.h
+
+1.7.1a (08-01-2003):
+ * fix a syntax error in samhain-install.sh.in
+
+1.7.1 (07-01-2003):
+ * search runlevel scripts in ./init or ./
+ * handle all distro-specific Linux runlevel script issues
+ within a single script
+ * support install-boot on Yellow Dog Linux and Slackware
+ * samhain-install.sh: fix a bug for unknown Linux
+ ('"' not closed, DVER not set)
+ * samhain-install.sh: check for /etc/yellowdog-release
+ * sh_database.c: fix missing entry for 'userid' in attr_tab[]
+ * fix debian.rules.in (disable sstrip)
+ * update make targets: 'srpm', 'srpm-dist', 'rpm'
+ * check for zlib if mysql is used
+ * workaround for NetBSD bug with libresolve
+ * fixed problems with spec files
+
+1.7.0 (22-12-2002):
+ * improved spec files (Andre Oliveira da Costa <brblueser@uol.com.br>)
+ * sh_unix.c: fix a dereferenced static pointer in tf_trust_check
+ * runlevel scripts: remove pid file after stop
+ * make the data directory read-only for the daemon
+ * treat 'localhost' specially in MX resolver
+ * sh_err_log.c: set sh.flag.log_start == TRUE after writing </trail>
+ * deploy.sh.in: fix quoting (fix by Simon Bailey)
+ * slib.c: make sl_get_euid et al. behave well if uids not stored
+ * trustfile.c: use euid = uid(SH_IDENT) if server
+ * sh_mail.c: include an MX resolver
+ * Makefile.in: install-user routine for user installation
+ * have yule drop root
+ * sh_tools.c: open_temp use logdir if server
+ * unified options for runlevel script
+ * HP-UX, IRIX runlevel scripts
+ * AIX inittab entry
+
+1.6.6 (13-12-2002):
+ * configure.ac: solaris cc -O2 -> -xO2
+ * sstrip.c: avoid alpha architecture
+ * profiles/solaris/configopts: no --enable-static
+ * sh_forward.c: sh_forward_req_file: copy argument to local array
+
+1.6.5 (04-12-2002):
+ * sh_utmp.c: set userlist = NULL in sh_utmp_end ()
+ * sh_unix.c: do not assume that environ is sane
+ * exit handler: write </trail>
+ * sh_log_file(NULL): test sh.flag.log_start != S_TRUE
+ * FreeBSD rc script does not blindly accept content of pid file
+ * configure.ac: allow 'localhost' for log server
+ * sh_calls.c: retry_connect: ntohs (port)
+ * testrun_2[abc].sh: --with-logserver=localhost for client
+
+1.6.4 (12-11-2002):
+ * sh_tools.c: fix error when escaping '=<'
+ * fix the 'make srpm' target
+ * deploy.sh.in: avoid that client is named 'yule'
+ * define memset to sl_memset
+ * fix type cast of uid_t, gid_t
+
+1.6.3 (31-10-2002):
+ * fix options for Sun/Solaris native compiler
+ * sh_unix.c: MSG_FI_LIST (line 2333): cast theFile->size to fix error
+ * test sstrip on freebsd
+ * default config file for freebsd
+ * make target to build .deb packages
+ * sh_readconf.c: fix bug in error message
+ * samhain.c, sh_suidchk.c: fix initialization of suidchk
+ * samhain-install.sh.in: don't remove config file by default
+ * samhain-install.sh.in: support complete de-installation
+ * samhain-install.sh.in: add support for Gentoo, FreeBSD, and Solaris
+ * samhain-install.sh.in: check more paths
+ * sh_unix.c: fix sys_siglist declaration [NetBSD portability issue]
+ * sh_calls.c: save error message in retry_lstat()
+
+1.6.2 (04-10-2002):
+ * make target to build rpms
+ * update samhain.spec.in, samhain.startRedHat
+ * support DESTDIR, as in 'make DESTDIR=/what/ever install'
+ * explicitely set -fno-omit-frame-pointer b/o gcc bug
+ * mv configure.in to configure.ac to benefit from autoconf wrapper
+ * sh_modules.c, sh_modules.h: add mod_reconf() to run at SIGHUP
+ * slib.c: fix debug messages (no msgs for dlogActive <= 1)
+ * sh_schedule.c, samhain.c, sh_suidchk.c:
+ scheduler may accept multiple schedules
+
+1.6.1 (04-09-2002):
+ * sh_schedule.c: bugfix (executes only after first day)
+ * rm obsolete WITH_TRACE stuff
+ * new dlog() function for debug logging
+ * some more descriptive error messages
+
+1.6.0 (27-08-2002):
+ * omit the -fomit-frame-pointer option (bugs in some gcc versions ?)
+ * sh_error.c: fix escape mode when logging to database
+ * sh_forward.c: fix error (twice escape) in recv_syslog_socket
+ * sh_tools.c: change escape mode for server-received data
+ * sh_mem.c: change ulong -> size_t in sh_mem_malloc()
+ * configure.in: fix localstatedir if --prefix=USR
+ * sh_hash.c: snprintf() -> sl_snprintf()
+
+1.5.5 (07-08-2002):
+ * sh_err_log.c: fix incorrect xml syntax for client messages
+ logged by server
+ * sh_err_log.c: fix incorrect '</trail>' entries on client EXIT
+ * sh_files.c: introduce file_class_next
+ this fixes the problem that a policy for the directory
+ inode erroneously becomes a policy for the directory itself.
+
+1.5.4 (17-07-2002):
+ * sh_hash.c: fix buffer overflow with (micro-)stealth
+ * sh_database.c: set path[] 1024 -> 12288
+ * sh_database.c: set query[] 2048 -> 16383
+ * sh_database.c: set values[] 1024 -> 16383
+ * sh_forward.c: larger limit for message size (16 kB)
+ * trustfile.c: set MAXFILENAME 2048 -> 4096
+ * fixed a bug in the handling of filenames with embedded newlines
+ * sh_files.c: fix missing sh_util_safe_name() in debug output
+ * --with-sender can specify a full address
+ * fix xml log in a backwards compatible way
+
+1.5.3 (03-07-2002):
+ * fix combination of stealth and sql logging
+ * fix some more places where invalid UIDs/GIDs trigger errors
+
+1.5.2 (01-07-2002):
+ * include solaris config file from (sean [at] boran d.o.t com)
+ * test for files/dirz defined twice in the configuration file
+ * option to disable reverse lookup on outbound connections
+ * option to use socket peer as client name (with name resolving)
+ * sh_html.c: fix an HTML bug (twice </head><body>)
+ * sh_suidchk.c: fix warning on AIX b/o dirname()
+ * allow logging server -> syslog if yule is NOT configured to
+ receive syslog messages
+ * define PRIi64 to "lld" if undefined
+ * invalid UIDs: use gid/uid as name, error level SeverityNames
+ * minor fixes for connect_port
+ * sh_hash.c: flush output of db listing before _exit()
+ * configure.in: fix incorrect default ${install_name} for server
+ * configure.in: try harder to find mysql.h / libpq-fe.h
+ * sh_files.c: sh_files_checkdir:
+ closedir() early to not exhaust OPEN_MAX
+
+1.5.1a (30-05-2002):
+ * fix missing LSB init script
+
+1.5.1 (27-05-2002):
+ * fix '-t update' option
+
+1.5.0a (23-05-2002):
+ * fix configure.in
+
+1.5.0 (22-05-2002):
+ * include solaris nosuid patch from (nathoo [at] co d.o.t ru)
+ * similar fix for bsd nosuid
+ * speed up -t update
+ * convert manual to DocBook, distribute html and ps
+ * fix some more problems with configure.in, Makefile.in
+ * fix testsuite, add tests for udp, mysql
+ * MSG_TCP_MSG: host -> remote_host
+ * convert to autoconf 2.53
+ * make c_bits.sh exit with status 0
+ * sh_database.c #include "mysql.h" --> <mysql.h>, ditto libpq-fe.h
+ to avoid dependency tracking problems
+ * samhain.c remove *YULE* #ifdefs
+ * acconfig.h remove *YULE* #undefs
+ * samhain.c: procdirSamhain: lstat --> stat (allow symlink)
+ * configure.in: add checks for correct user input
+ * Makefile.in: add automatic dependency tracking
+ * depend-gen: tool to figure out dependencies
+ * chkconfig comments in redhat start scripts
+
+1.4.8:
+ * sh_database.c: fix missing attr_old, attr_new, (from)host columns
+ * configure.in, Makefile.in: fix an error in the configfile
+ definition with REQ_FROM_SERVER
+ * sh_err_console, sh_err_log: avoid recurrent failure messages
+ * timeout on read from files (/proc)
+ * fix errrors with setjmp/longjmp/alarm
+ * fix memory leak in server (~20 byte/file download in sh_tools, 930)
+ * check gpg signature for files downloaded from server, add a
+ regression test
+ * fix chown in solaris bootscript
+ * provide second scheduler for file check
+ * provide scheduler for file check
+ * provide scheduler for SUID check
+
+1.4.7 (08-04-2002):
+ * make daemon control LSB-compliant (arguments, exit status)
+ * set log_ref = 0 for server messages
+ * boolean option SetDBServerTstamp to disable entering server
+ timestamps for received client messages into database
+ * sh_suidcheck: check for "nosuid" mount option if getmntent is used
+ * fix logrotate script in manual (reported by Scott Worthington)
+ * don't strip numerical IP addresses
+ * check item->status_now != CLT_TOOLONG in client_time_check()
+ * set log_host to client in db client message
+
+1.4.6a (20-03-2002):
+ * define prefix in deploy.sh
+
+1.4.6 (19-03-2002):
+ * modify samhain_hide.c to hide processes on new Linux kernels
+ * better error diagnostics in kern_head.c
+ * fix compile error in all_items ()
+ * check length of install-name in enable-khide (max is 15)
+ * define exec_prefix in deploy.sh.in
+ * make configure a bit more cross-compiler friendly
+
+1.4.5 (07-03-2002):
+ * Make sure missing file is reported even if ptr->reported == S_TRUE
+ because the file has been added.
+ * propagate 'reported' flag from sh_files_checkdir() into file list
+ * close checkfd in sh_gpg_check_file_sign()
+ * sh_derr(): kill(parent, SIGCONT) after ptrace(PT_DETACH,...)
+ * use sh.srvcons.name in dbg() to get debugging info from daemon
+ * option to log file timestamps with localtime instead of GMT
+ * comment out MSG_FI_ADD in sh_dirs_chk () - obsoleted by mandatory
+ sh_files_filecheck(directory) that triggers MSG_FI_ADD in sh_hash.c
+ * set ptr->reported = S_FALSE; for reappeared files in sh_files_chk()
+ to make sure re-disappearing will get reported
+ * new function sh_hash_set_missing() to remove file record
+ without (duplicate) 'missing' message
+ * make sure all items are reported for added files
+ * fix stealth mode with sh_kern (encode sh_ks.h -> sh_ks_xor.h)
+ * clarify in the documentation which gpg options to use for signing
+
+1.4.4 (11-02-2002):
+ * check that parent process has exited before writing PID file
+ * promote MGG_W_CHDIR to SH_ERR_ERR
+ * add error message to sh_unix_testlock
+ * fix missing _() macro in sh_aud_set_functions
+
+1.4.3 (05-02-2002):
+ * don't check attributes for symlinks (may cause device access)
+ * add USE mysql; USE samhain; to samhain.mysql.init
+ * point out the MessageHeader/mysql problem in manual
+ * add -lz to LIBS for mysql
+ * strip after install, avoid double strip
+
+1.4.2 (27-01-2002):
+ * support for EGD
+ * fix some more problems with install-deploy / deploy.sh
+ * fix a bug in profiles/suselinux_i386/bootscript (INSTALL_NAME_)
+ * fixed the 'external logging' test (init rather than none in rc file)
+
+1.4.1:
+ * SuSE: include run level 4+5
+ * install location of hiding kernel modules changed - some insmod
+ variants do not test for /lib/modules/$(uname -r)/module_name.o
+ * new make targets 'install-deploy', 'uninstall-deploy'
+ * fixed make targets 'deploydir', 'deploydirfast'
+ * bail on unsupported CL option in deploy.sh
+ * fix various bugs in deploy.sh
+
+1.4.0 (16-01-2002):
+ * fixed missing 'dirname' on Mac OS X
+ * fixed && tested for/with postgres
+ * 'user=' -> 'userid=' (reserved word in sql)
+ * fix the endianess + size of file database; this changes db format
+ for any non-Linux OS
+ * --enable-old-format for old (V1.3) database format
+ * getopt, samhain.c, samhain.h: option -f to loop if not daemon
+ * sh_hash: list numeric + char data to allow file db update on
+ server side
+ * sh_database: modify handling of integer (long) data
+ * sh_database: datetime in database
+ * sh_database: hash field in database
+ * sh_database: rewrite database insert string construction
+ [use INSERT INTO log (fields) VALUES (values);]
+ * makefile suse 7.x runlevel entries
+
+1.3.7 (06-01-2002):
+ * fix incorrect escape in sh_tools_safe_name
+ * fix sh_error_handle (4. argument) in sh_extern.c
+
+1.3.6c:
+ * fix segfault in sh_database (mysql logging) on solaris
+
+1.3.6b (03-01-2002):
+ * fix syntax error ('==') in Makefile.in
+ * fix configure.in (path for /lib/modules/$(uname -r)/build/include)
+ * fix sh_kern.c (redeclaration of 'j')
+
+1.3.6 (03-01-2002):
+ * sh_kern.c: check integrity of int 80h vector
+ (SucKIT rootkit - Phrack 58)
+ * make sure childs in sh_kern are wait()'ed for
+ * provide start/stop/restart/reload/status interface
+ * fix a potential segfault (dereferenced NULL pointer) in the server
+ * use sh_util_flagval for sh_unix_setdaemon
+ * documentation for logging to SQL database
+ * configure.in: check for -I/lib/modules/$(uname -r)/build/include
+ * fix trustfile.c to ignore invalid users
+ * separate 'make install-samhain' and 'make install-yule'
+ * separate default log/pid/config files for server/client
+ - less problems running server and client on same host
+ * rewrite deploy.sh(.in):
+ - don't use (make|install) if deploying
+ - use command line options
+ - better integrate into server environment
+ - write install db
+ * always write a pidfile if daemon
+ * don't use server's config file as fallback for downloading client
+ * don't overwrite config file when doing 'make install'
+
+1.3.5 (28-12-2001):
+ * fix --enable-message-queue for newer glibc versions
+ * log to SQL database: implemented, but undocumented yet,
+ needs to be tested further
+ * xml: escape received syslog messages
+ * xml: rename 'time' to 'tstamp'
+ * make targets: make [un]install-[boot-]yule
+ (for server-only installation)
+ * fix samhain_hide.c for 2.4 kernel
+ * fix sh_kern for updated samhain_hide.c
+ * new option -j to just list the logfile
+ * sh_getopt.c: recognize -Dt check for -D -t check
+ * sh_tiger0.c: fix compiler warning (memmove) on Solaris
+
+1.3.4 (12-12-2001):
+ * sh_suidchk.c: option to limit files per second
+ * sh_unix.c: option to limit (kilo)bytes per second
+ * sh_hash.c: fix potential problem with '\n' in filename
+ (not backward compatible if there are filenames with '=')
+
+1.3.3 (03-12-2001):
+ * sh_readconf.c, samhain.h, samhain.c, sh_suidchk.c:
+ option SetNiceLevel to set scheduling priority
+ * sh_hash.c: bugfix for database listing on Solaris
+ * taus_seed: bugfix for emergency backup rng seed
+ * sh_util_safe_name: fix for XML
+ * sh_utmp_set_login_activate: use sh_util_flagval
+ * sh_utils.c: sh_util_obscurename: rm 'space' from list
+ * more backtrace macros
+ * sh_util_flagval: fix bug to recognize 1/0
+ * fix test scripts testtimesrv.sh, testext.sh (test.sh 6/5)
+ * rm stray debug fprintf in sh_srp.c
+
+1.3.2 (27-11-2001):
+ * sh_hash.c: fix an error introduced in 1.3.1
+ * set RLIMIT_CORE to RLIM_INFINITY if --enable-debug
+
+1.3.1 (25-11-2001):
+ * slib.c: get backtrace with --enable-debug
+ * sh_unix.c: allow core dumps when --enable-debug
+ * configure.in: fix default message queue permissions
+ * sh_suidchk.c: automatically include suid/sgid files in database
+ * sh_suidchk.c: check all suid/sgid files
+ * sh_hash.c: don't insert duplicates when reading the database
+ * sh_utmp, sh_kern, samhain: fix 1sec offset in timer
+ * sh_unix.c: don't require /dev/random to be non-world-writeable
+ * server: fix segfault in zAVLTree.c if avltree == NULL (no clients)
+ * client: fix segfault on Solaris if path_conf == NULL
+ * testrun_1b.sh: \(^/.*\) -> \(/.*\) for Solaris sed
+
+1.3.0 (31-10-2001):
+ * support compiling with GNU gmp library
+ * set 3 sec timer on client_time_check to avoid excessive (and
+ unnecessary) calls under heavy load
+ * replace sl_strlen with a macro
+ * store client_t structure in AVL tree
+ * database format incompatible with previous format, up the magic#
+ * sh_html.c: cache entry template for speedup
+ * slib.c: reset islong(double) in sl_printf_count
+ * sh_hash.c: report on rdev change
+ * sh_hash.c: print size in 64 bit
+ * sh_hash.c: save in absolute size types
+ * sh_unix.c: get values as appropriate type (time_t, dev_t, ...)
+
+1.2.10:
+ * update MANUAL
+ * sh_unix.c: tiger_hash -> tiger_generic_hash
+ * sh_readcon.c: DigestAlgo option
+ * sh_tiger0.c: add MD5 and SHA1
+ * sh_unix.c: fix minor problem with win2k/cygwin
+
+1.2.9 (17-10-2001):
+ * fix problem with entry template/empty hostname
+ * fix MASK_USER_ (MTM -> ATM)
+ * typo fixed in configure.in (${install_name} -> {install_name})
+ * bugfix group_old -> size_old in XML code
+ * skip armor header in signed files
+
+1.2.8 (29-09-2001):
+ * Mac OS X: in sh_getopt.c, rename table[] to op_table[] to avoid
+ obscure compiler warning
+ * Mac OS X: fix test scripts
+ * Mac OS X: import newest config.guess, config.sub from ftp.gnu.org
+ * implement deadtime in syslog recv code to protect against flooding
+ * sh_err_log: sl_close(fd) if lock|forward fails
+ * compliance with Filesystem Hierarchy Standard -- Version 2.2 final
+ * add policies User0, User1
+ * fix compile problem (FreeBSD) in sh_suidchk.c
+ * macro to check for debugger breakpoints (linux/i386)
+ * check for solaris (does not work) in sh_derr (--enable-ptrace)
+ * option to listen on 514/udp for syslog, drop root
+ irrevocably if compiled thus
+ * use (check_mask & MODI_ATM) to decide whether to reset utime
+ * reset the policy masks on sighup
+ * option to write XML log messages
+ * cleanup of message catalog
+ * modified error messages for BADCONN
+ * error messages for Rijndael
+ * block recursive error messages within sh_error_handler()
+ - would hang the machine ... -
+
+1.2.7:
+ * sh_files, sh_utils: check top level directory
+ * sh_kern, sh_cat, kern_head: check syscall code, fork subprocess
+ for reading from /dev/kmem
+ * include /boot in default samhainrc
+ * change source distribution signing/packaging system
+ * Makefile, README, MANUAL: adhere to file system standard,
+ document new locations
+ * fix a bug in samhain_hide.c
+
+1.2.6:
+ * reset list of trusted users before config file re-read
+ * TrustedUser=... can be a list
+ * fix severity for files missing from IgnoreAll
+
+1.2.5:
+ * include example_pager.pl, example_sms.pl scripts
+ * explain paging/sms setup in docs
+ * allow manual exclusion of a directory in suidcheck
+ * automatically track all file changes
+ * remove missing files from in-memory database
+ * add $(KERN) to DEPLOYFILES
+
+1.2.4:
+ * log IP address for login/logout events, if supported by the OS
+ * release block in globerr (callback)
+
+-------------
+
+1.2.3:
+ * fix problem with reading stealth configuration
+ * fix a few formats in sh_cat.c
+ * always use strncmp for file system type check in sh_suidchk.c
+ (trailing 'fs' may be system specific for some types)
+ * no bare LF in messages (RFC 2822)
+ * no lines longer than 998 chars (RFC 2822)
+ * fix error in testrc_1
+
+1.2.2:
+ * make tmp file directory a compile time option
+ * fix minor bugs in tmp file allocator (potential memory leak,
+ double slash if root directory)
+ * obsolete testpipe script removed
+
+1.2.1:
+ * fix memory alignment in rijndael-api-fst.c: blockEncrypt()
+ * fix byte order in HMAC code (compatibility fix for Linux/HP-UX)
+ * removed a debug fprintf()
+
+1.2.0:
+ * fix a bug in the HMAC implementation (thanks to Cesar Tascon
+ for help in tracking down this one)
+ * module to check the file system for SUID/SGID files
+
+1.1.16 (never released):
+ * fix the recursion depth -1 option as described in the manual
+ * optional database reload on SIGHUP
+ * fix a race condition when checking that /dev/random is a charakter
+ device
+ * redirect stderr to /dev/null for c_random
+ (AIX may segfault in netstat...)
+ * check whether /dev/random is a charakter device in c_random.sh
+ (we know at least one sysadmin who has set up a fake /dev/random ...)
+ * don't give NULL as 2. and 3. arg to execve if not Linux - some
+ Unices (notably Solaris) don't like it
+ * init ptr = NULL in my_malloc (compiler warning)
+ * make the bitmask for tests configureable (suggestion by A. Dunkel)
+ * make the bitmask for tests a static variable
+ * make (database/logfile/lockfile) path configurable
+ (to run multiple instances of samhain from an NFS share - on the
+ wishlist of J. Patton)
+
+1.1.15 (never released):
+ * fix minor error in testcompile.sh (rm test_log only at start)
+ * return from subroutines on sig_terminate == 1
+ (faster exit on SIGTERM)
+ * fix re-configuration of addresses
+ * use sh_util_flagval() in sh_mail_setFlag and sh_kern_set_activate
+ * SysV message queue as compile option
+ * config file option to set console device
+ * removed the pre 1.1.9 code bloat
+ * don't print the LOGKEY to the console
+
+1.1.14:
+ * fix an error in the setup consistency check
+ * make target to uninstall runtime files
+ * trustfile.c: check return code of readlink(), fix off-by-one error
+ * sh_files.c: fix placement of terminator after readlink() call
+ * sh_files.c: fix a missing set_suid()/unset_suid()
+ - suid should work, but is not recommended -
+ * more debug statements in c/s code
+ * avoid re-entry in sh_unix_sigexit
+ * put a block around free() and malloc() in wrapper functions
+ * ditto for glob()/globfree(), regcomp()/regfree(), fdopen()/fclose()
+ - i.e. avoid corrupting the heap from a signal handler -
+
+1.1.13:
+ * optimized the size of the configure script somewhat
+ * modify the compile and hash test scripts
+ * read '\0's in sh_unix_getline
+ * exponential schedule for connection attempts
+ * make stealth working properly with signed files
+ - config file should be signed now before embedding in picture -
+ * fix a race in using signed files
+ * updated err messages for PWNULL, GRNULL
+ * add missing shell script for test 11
+ * add mandatory source file/line info with -p debug
+ * add mandatory source line info with BADCONN
+ * fix a latex error in the manual
+
+1.1.12:
+ * debug output to console if compiled with --enable-debug and
+ running as daemon
+ * make reportonlyonce=true the default
+ * make sure state changes of a file are always reported, even
+ with reportonlyonce=true
+ * Linux kernel modules (samhain_hide, samhain_erase)
+ * fixed incorrect return value of sh_util_flagval
+ * fixed an error in sh_files.c: happens with -t init and first
+ file that is checked does not exist
+ * revised install/uninstall targets in the Makefile
+ * module to check for clobbered kernel syscalls (tested on Linux 2.2)
+ * more diagnostic error messages in sh_gpg.c
+ * more diagnostic error messages in sh_mail.c
+ * error in mail.c fixed
+ (address -> address_list[i] for multiple recipients)
+ * docs updated, better(?) explanation of signed files
+ * skip over path in gpg checksum output
+ * check client name against IP address and FQDN
+ * fix for --disable-* in config file
+ * fixed a server crash (MSG_TCP_OKMSG without arg)
+ if the server is run with debug level output threshold
+ * catch EAGAIN in sh_gpg.c pipe reader
+ * fix the 'external logging' test to make it work on BSD
+ * error message if no local path to init DB
+ * check for i86/Solaris in configure (vsnprintf prototype)
+ * make SRP the default
+
+1.1.11:
+ * make log file verification more convenient
+ * fix problem with message classes in stealth mode
+ * linux: do not try to read file attributes for devices
+ * handle the root directory correctly (avoid "//" in listing)
+ * fix problems with blockin on FIFOs/char dev
+ pointed out by I. Rogalsky (rog@iis.fhg.de)
+ - open in nonblocking mode for read, then set to blocking
+ - open file only if regular
+ * fix alignment in memory profiler
+
+1.1.10:
+ * minor code cleanup
+ * fix an error in trustfile.c (handling of empty/incomplete
+ group entries in /etc/group, bug report by A. Capriotti )
+
+1.1.9:
+ * compatibility option for old behaviour (plain hash instead
+ of HMAC, ECB instead of CBC mode)
+ * use CBC rather than ECB mode for encryption
+ * use HMAC-TIGER for message authentication codes
+ * handle NULL data in sh_tiger_hash
+ * option to set syslog facility (default is LOG_AUTHPRIV)
+ * longer timeout (300 sec) on /dev/random if no /dev/urandom
+ * fix minor output error with stealth option
+ * option not to log names of config/database files on startup
+
+1.1.8:
+ * fix error in syslog routine
+ * fix missing 'test' in configure.in
+ * fix error in replace_tab() in sh_html.c
+ * fix minor memory leak in sh_util_regcmp()
+
+1.1.7:
+ * timeout on read_mbytes (from /dev/random; fallback to /dev/urandom)
+ * fix for FreeBSD: ut_user -> ut_name in sh_utmp.c
+ * fix for Alpha: consider $ac_cv_sizeof_unsigned_int_ in configure.in
+ * fix for Alpha: format string in sh_tiger0.sh
+ * on Linux, now compiles cleanly with
+ -Wall -W -Wstrict-prototypes -Wcast-align
+ * fix problem with recursion depth
+ (pointed out by Vic <hvicha@mail.ru>)
+ * #include "sh_tools.h" in sh_unix.c and fix the
+ --with-timeserver option (reported by Vic <hvicha@mail.ru>)
+ * place read_port(), MSG_TCP_NETRP outside ifdefs
+ * close fd/zero skey before execve
+ * verify client name against socket peer
+ * ... with configureable error priority
+ * use strcmp() rather than strncmp() in search_register()
+ * fix race between lstat() and open() for checksum
+ (reported by dynamo <dynamo@ime.net>,
+ JJohnson <JJohnson@penguincomputing.com>)
+ * enable globbing for filenames
+ * fix Solaris problem: siginfo_t may be NULL
+ * fix missing SL_EBADGID in tf_trust_check
+ * test case for external scripts, fix flushing pipe
+ * fix a typo in sh_ext_type
+ * do an fdexec w/checksum on Linux if calling external program
+ * even safer tmp file creation
+ * allow db update
+ * fix compile options for --enable-debug
+ * fixed a spelling error in the output
+ * test program for full CS support (config/database download)
+ * tell which file is searched for cs download
+
+1.1.6:
+ * fix bug in sh_readconf_line (segfault on erroneous config lines)
+
+1.1.5:
+ * sh_unix.c: sh_unix_getinfo_attr: f -> flags
+ * use gettimeofday as last resort
+1.1.4:
+ * fix AIX compiler warning in sh_forward (cast arg1 of sh_tiger_hash
+ to (char *)
+ * configure: add static link flags for some more os (from tar)
+ * don't strip twice (some stupid systems abort)
+ * fix for reading from /dev/random on non-Linux systems (untested)
+ * sh_mail.c: end all message lines with \r\n
+ * stealth: ignore \r, \"
+ * take out tracing from --enable-debug (presently useless anyway)
+ * fix some remaining cleartext with debug && stealth combined
+ * fixed a small memory leak in sh_err_log.c
+
+1.1.3:
+ * fixed circular logic in taus_seed() (fallback method only)
+ * fix for missing _SC_OPEN_MAX (runaway close())
+
+1.1.2:
+ * implement message classes
+ * let server recognize client message severity and class
+ * secondary log server
+ * keep database in memory (allows to close file
+ if retrieved from server)
+ * encrypt client/server communication
+
+1.1.1:
+ * Compilation problems with native Solaris compiler fixed
+ * fill in euid/ruid variable
+ * manual.pdf --> MANUAL.pdf
+ * debug sh_util_formatted()
+ * http refresh 120sec for server stat page
+ * trace/debug options
+ * fixed problem with utmp.c options
+ * fixed problem with sh_mail_setaddress
+ * option for custom message header
+ * fixed problem in compdata
+ * fixed problem in mail verification
+ * remove eventual trailing '/' in file names
+ * fixed problem with report string for modified files
+ * option to report in full detail
+
+1.1.0:
+ * Move error messages to catalog
+ * Make error message format more uniform
+ * Wrap sytem calls that could be interrupted by signals
+ * Warn on append to database
+ * Option for full details on mod. files
+ * Option to report only once on mod. files
+ * Generally speaking, major modifications with potential new bugs
+
+0.9.5:
+ * sh_hash.c: fixed erroneous checksum for config file
+ * sh_html.c: fixed erroneous timestamp (last)
+ * sh_tools.c: fixed connect_port (set port for cached address)
+ * sh_srp.c: fix for '00' (='\0') in pw
+ (last two fixes by Andreas Piesk)
+
+0.9.4:
+ * samhain.c: fcntl(1, ..) -> fcntl(2, ..)
+ * sh_hash.c: copy 12 instead of 10 byte for c_attributes
+ * 'empty directory' WARN -> INFO
+
+0.9.3:
+ * FreeBSD fixes:
+ - c_random.sh: make sure /dev/random provides something
+ rather than nothing
+ - check for <netinet/in.h> and include it
+ - include <sys/types.h> early
+ - sh_utmp.c: fixed an occurence of ut_user
+ - sh_utmp.c: #ifdef HAVE_UTTYPE static char terminated_line #endif
+ - sh_forward.c: EBADMSG -> ENOMSG
+ * sh_unix.c: check return value of gethostbyname
+ * sh_entropy.c: fallback on /dev/urandom if /dev/random blocks for
+ more than 30 sec
+ * ... and fix the timestamp format ...
+
+0.9.2:
+ * ISO 8601 timestamps
+ * Bugfix in sh_utmp (timestring overwrite)
+ * don't use siginfo_t on Linux (garbage as of 2.2.14)
+ * check for Linux capabilities bug when dropping root
+ * include README for gcc compiler bug (pointed out by A. Piesk)
+ * explicitely set -fno-strength-reduce with gcc
+ * fixed ignoring missing files with the IgnoreAll policy
+
+0.9.1:
+ * more ext2flags (breaks backward database compatibility on Linux)
+ * IgnoreAll policy modified - missing/added files reported with
+ SeverityIgnoreAll (to handle files that may or may not be present)
+ * Check all files, not only regular ones
+ (bug in sh_files, originally introduced because checksum of
+ regular files only is computed)
+
+0.9:
+ * use O_NOATIME if supported
+ * --with-nocl takes argument (PW to re-enable CL parsing)
+ * no daemon mode if initializing database
+ * fixed segfault in yule with 'unknown file type' request
+ * enlarged MAX_GLOBS 24 -> 32 and made the array linear
+ * server uses last registry entry for any given client now
+ * deploy.sh script to deploy clients to remote hosts
+ * enhanced signal handling: SIGUSR1/SIGUSR2/SIGABRT/SIGQUIT/SIGHUP
+ * allow y/Y/n/N for login monitoring (in addition to 0/1)
+ * external logging scripts/programs
+ * trustfile.c: define STICKY on Linux
+ * reset signal mask when initializing
+ * EINTR_RETRY wrapper
+ * slib: sl_read, sl_write EINTR update
+ * use sstrip when installing
+ * more compact database format (breaks backward database compatibility)
+ * larger download packets
+ * TcpFlags unsigned char
+ * cast to (char *) head in write_port
+ * m(un)lock cast to (char *)
+ * (1 << 31) --> (1UL << 31)
+ * support e2fs attributes on Linux
+ * fixes for AIX and Solaris native compilers
+ * fixed Makefile for non-GNU make (pattern rule --> suffix rule)
+
+0.8.1:
+ * fixed 'is_numeric()' return value
+
+0.8:
+ * added option for static compilation
+ * added option for stealth with non-hidden config file
+ * added option for disabling command line parsing
+ * all options can be set in the configuration file now
+ * stealth: xor strings in database file
+ * fixed bug in mailer code ([] in HELO)
+ * print timestamp when asking for key
+ * 'micro' stealth mode (no hidden configuration file)
+ * simplified slib
+ * int->long for uids/gids in trustfile
+ * moved mailkey from data to code
+ * shell script for entropy (stronger default key)
+ * general code cleanup
+ * better error checking in client/server code
+ * detect out-of-sync messages
+ * check state across protocol passes in server
+ * make sure authentication is mutual
+ * file download to client
+ * reserve six file descriptors in server
+ * mlock queue buffer if LOG_KEY
+ * improved robustness in bignum (don't fail on free())
+ * per-directory recursion depths
+ * RFC821 compliance: empty line at end of header, To field, Date field
+ * RFC821 compliance: make e-mail transfer relieable
+ * fix detection of hardlink changes
+ * checksum verification for calling gpg/pgp
+ * CL option '-S' not required for server-only binary
+ * eliminate CL options that may leak privileged information
+ if the program is SUID
+ * skip leading white space in configuration file
+ * allow nested conditionals in configuration file
+ * allow whitespace before and after '=' in configuration file
+ * don't leak file descriptors to child processes
+ * make message transfer relieable
+ * always report error on abnormal termination of connection
+
+0.7:
+ * support for alpha machines
+ * stop TCP logging after exit message
+ * limit connections in server (DoS attacks)
+ * move string handling to slib
+ * move file handling to slib
+ * timestring without space
+ * changed report format
+ * SUID bugfix - use euid when checking logfile ownership
+ * SUID bugfix - get root for lstat()
+ * SUID bugfix - get root for opendir()
+ * store number of hardlinks
+ * send no message if polling empty queue
+ * include tiger 64-bit implementation (portability)
+ * codes for error conditions
+ * mail check: handle multiple, overlapping audit trails
+ * security fix: no append to database if SUID
+ * fix sh_entropy.c (BUFSIZ -> BUF_ENT)
+ * read command line before config file
+ * PGP signing of config/database files
+ * checksum of config file reported
+ * checking for attributes only
+
+0.6:
+ * more syslogish priority specification
+ * fixed segfault in sh_mem_check, apparently this was also
+ the reason for the segfault in atexit()
+ * allow for compilation with SRP authentication
+ * fixed tiger checksum computation
+ * fixed broken logfile verification for second and further audit trails
+ * test program added
+ * documentation improved
+ * sh_forward_make_client: bug fixed in[8]->in[i]
+ * sh_error.h: fixed missing #include <errno.h>
+ * configure.in: fixed missing strerror() test
+ * sh_utmp.c: check logins/logouts
+ * check for missing files
+ * only reset access time if necessary
+ * O_EXCL in open()
+ * limit environment to TZ in execve (sh_entropy.c, not used on Linux)
+ * use trustfile() to determine whether logfile dir is trustworthy
+ * strip head instead of tail for numerical address
+ * store messages in fifo during log server outage
+ * re-init session key after server outage
+
+0.5 (21-12-1999):
+ * added option for mail relay server
+ * own popen() implementation in sh_entropy() (portability)
+ * fixed error in sh_util_basename() (returned NULL for base == "/")
+ * fixed segfault in strlcpy/strlcat (check for src == NULL)
+ * FILENAME_MAX -> PATH_MAX (HP-UX 10.20)
+ * use TIGER for 32-byte compilers (portability)
+ * fixed hash function (do not include stdlib.h)
+ * flush buffer before write in mailer code (IBM AIX 4.1)
+ * make mailer code non-forking
+ * cast argument of is...() to int (portability)
+ * return() after _exit() for braindead compilers (portability)
+ * optionally use inet_addr (portability)
+ * check for broken mlock() (HP-UX 10.20)
+ * minor code cleanups
+ * fixed incorrect size of munlock()'ed memory in sh_error_string()
+ * fixed a buffer overflow in the error printing routine
+ * fixed a buffer overflow in sh_util_safe_name ()
+ * implement SRP session key exchange
+ * implement client/server facility
+ * implement @host/@end construct in configuration file
+ * preferably use uname(), and do gethostbyname() for FQDN
+ * make vernam cipher base numeric
+ * make OnlyStderr private in sh_error
+ * test -e "/dev/random" --> test -r "/dev/random" (portability)
+ * check for libsocket (portability)
+ * add #defines for IPPORT_SMTP, IPPORT_TIMESERVER (portability)
+ * eliminate superfluous /proc test
+ * some unreachable code removed
+ * cast to (byte*) replaced by cast to (word64*) in sh_tiger_hash()
+ * check for setresuid() if no seteuid() (HP-UX 10.20)
+
+0.4 (09-11-1999):
+ * make sure output from /dev/random has no NULL's
+ * one-time pad encryption for emailed keys
+ (better than nothing ...)
+
+0.3 (04-11-1999):
+ * logfile readable for group
+ * verify signatures for any file
+ * signature block in tarball
+ * use select() in time server routine
+ * better protection for session keys (mlock)
+
+0.2:
+ * fixed incorrect man page
+ * fixed incorrect example rc file
+ * recursive error logging should work now
+
+0.1:
+ * initial release -- on Samhain 1999, of course
+
+development start:
+ * probably 29-06-1999
+
diff --git a/docs/FAQ.html b/docs/FAQ.html
new file mode 100644
index 0000000..b34f60c
--- /dev/null
+++ b/docs/FAQ.html
@@ -0,0 +1,866 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html><head>
+<title>Frequently Asked Questions for Samhain</title>
+<meta name="author" content="Rainer Wichmann">
+
+<style type="text/css">
+<!--
+
+html { background: #eee; color: #000; }
+
+body { background: #eee; color: #000; margin: 0; padding: 0;}
+
+div.body {
+ background: #fff; color: #000;
+ margin: 0 1em 0 1em; padding: 1em;
+ font-family: serif;
+ font-size: 1em; line-height: 1.2em;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #aaa;
+}
+
+div.block {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #2d4488;
+}
+
+div.warnblock {
+ background: #b6c5f2; color: #000;
+ background: #ffffcc; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #FF9900;
+}
+
+table {
+ background: #F8F8F8; color: #000;
+ margin: 1em;
+ border-width: 0 0 0 1px;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+th {
+ background: #F8F8FF;
+ border-width: 1px 1px 2px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+
+/* body text, headings, and rules */
+
+p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #206020; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
+h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
+h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
+h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
+h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
+h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
+
+hr {
+ color: transparent; background: transparent;
+ height: 0px; margin: 0.6em 0;
+ border-width: 1px ;
+ border-style: solid;
+ border-color: #999;
+}
+
+/* bulleted lists and definition lists */
+
+ul { margin: 0 1em 0.6em 2em; padding: 0; }
+li { margin: 0.4em 0 0 0; }
+
+dl { margin: 0.6em 1em 0.6em 2em; }
+dt { color: #285577; }
+
+tt { color: #602020; }
+
+/* links */
+
+a.link {
+ color: #33c; background: transparent;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000; background: transparent;
+}
+
+body > a {
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-size: 0.81em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2d5588; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+ -->
+</style></head>
+<body>
+<div class="body">
+<p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a
+ style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/">samhain file integrity
+ scanner</a>&nbsp;|&nbsp;<a style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/s_documentation.html">online
+ documentation</a></p>
+<br><center><h1><a name="FAQ-top">Frequently Asked Questions for Samhain</a></h1></center>
+<br><center><h2>Rainer Wichmann</h2></center>
+<hr>
+<div class="warnblock">
+<ul>
+ <li>If you encounter problems after installing samhain, disable daemon
+ mode and run it in the foreground with
+ <tt>samhain --foreground [more options]</tt> for debugging.</li>
+ <li>If you have problems getting client/server mode to work, please check
+ the <a href="http://www.la-samhna.de/samhain/HOWTO-client+server-troubleshooting.html">HOWTO client+server troubleshooting</a> document.</li>
+</ul>
+</div>
+<p><i>FAQ Revised: Wednesday 14 January 2015 20:41:15</i></p>
+<hr><h2>Table of Contents</h2>
+<dl>
+<dt><b>1. Most frequently</b></dt>
+<dd><ul>
+<li><a href="#Most frequently0">1.1. Owner not trustworthy / Group writeable and member not trustworthy</a></li>
+<li><a href="#Most frequently1">1.2. samhain exits with the message &quot;Untrusted path&quot; for config/log/pid/database files</a></li>
+<li><a href="#Most frequently2">1.3. It does not log anything / Can't stop logging to console</a></li>
+<li><a href="#Most frequently3">1.4. Client cannot self-resolve, but nslookup works fine</a></li>
+<li><a href="#Most frequently4">1.5. Server logs hostname instead of FQDN (or vice versa)</a></li>
+</ul></dd>
+<dt><b>2. Build and install</b></dt>
+<dd><ul>
+<li><a href="#Build and install0">2.1. [Fedora Core] Cannot compile with --enable-khide</a></li>
+<li><a href="#Build and install1">2.2. [Fedora Core] Cannot compile with --with-kcheck</a></li>
+<li><a href="#Build and install2">2.3. &quot;make&quot; loops infinitely !</a></li>
+<li><a href="#Build and install3">2.4. Why does static compiling (<code>--enable-static</code>) on Solaris fail ?</a></li>
+<li><a href="#Build and install4">2.5. Compilation fails with '/usr/bin/ld: cannot find -lnss_files'</a></li>
+<li><a href="#Build and install5">2.6. The executable is corrupted after installation</a></li>
+<li><a href="#Build and install6">2.7. --enable-xml-log has no effect</a></li>
+<li><a href="#Build and install7">2.8. ./install-sh: strip: not found (Solaris)</a></li>
+<li><a href="#Build and install8">2.9. What is sh_tiger1.s?</a></li>
+<li><a href="#Build and install9">2.10. Why does static compiling (<code>--enable-static</code>) on MaxOS X fail ?</a></li>
+<li><a href="#Build and install10">2.11. Why does compiling with MySQL fail on Solaris ?</a></li>
+</ul></dd>
+<dt><b>3. File checking</b></dt>
+<dd><ul>
+<li><a href="#File checking0">3.1. How can I exclude a (sub-)directory ?</a></li>
+<li><a href="#File checking1">3.2. In messages about policy violations, what does the code after POLICY [XYZ]
+mean ?</a></li>
+<li><a href="#File checking2">3.3. Does samhain support prelink ?</a></li>
+<li><a href="#File checking3">3.4. I get error messages about 'subdirectory count != hardlinks'</a></li>
+</ul></dd>
+<dt><b>4. Client/Server</b></dt>
+<dd><ul>
+<li><a href="#Client/Server0">4.1. I don't want to poke a hole into my firewall to let the client connect to the server !</a></li>
+<li><a href="#Client/Server1">4.2. The client sends 127.0.0.1 (or some other numerical address) as its name to the log server</a></li>
+<li><a href="#Client/Server2">4.3. The server wants to send rc.ip-adress rather than rc.fqdn to the client</a></li>
+<li><a href="#Client/Server3">4.4. Cannot resolve client name host=XXX</a></li>
+<li><a href="#Client/Server4">4.5. Cannot resolve socket peer IP for client host=XXX peer=YYY</a></li>
+<li><a href="#Client/Server5">4.6. Reverse lookup of socket peer failed host=XXX peer=YYY obj=ZZZ</a></li>
+<li><a href="#Client/Server6">4.7. No socket peer alias matches client name host=XXX peer=YYY</a></li>
+<li><a href="#Client/Server7">4.8. Session key negotiation failed</a></li>
+<li><a href="#Client/Server8">4.9. Invalid connection attempt: Not in client list</a></li>
+<li><a href="#Client/Server9">4.10. Invalid connection attempt: Session key mismatch</a></li>
+<li><a href="#Client/Server10">4.11. How do I update the file signature database ?</a></li>
+<li><a href="#Client/Server11">4.12. Time limit exceeded</a></li>
+<li><a href="#Client/Server12">4.13. Invalid connection attempt: Signature mismatch</a></li>
+<li><a href="#Client/Server13">4.14. [Server] PANIC .. Address already in use&nbsp; &nbsp;subroutine=bind</a></li>
+</ul></dd>
+<dt><b>5. Email</b></dt>
+<dd><ul>
+<li><a href="#Email0">5.1. Reverse lookup failed</a></li>
+<li><a href="#Email1">5.2. From daemon@example.com</a></li>
+<li><a href="#Email2">5.3. How do I define more than one email addresses ?</a></li>
+</ul></dd>
+<dt><b>6. Misc</b></dt>
+<dd><ul>
+<li><a href="#Misc0">6.1. Error message: &quot;Invalid line XYZ in configuration file&quot;</a></li>
+<li><a href="#Misc1">6.2. Why do I get a local logfile if I log to the server ?</a></li>
+<li><a href="#Misc2">6.3. Why is there no NIS support with a static samhain executable on Linux ?</a></li>
+<li><a href="#Misc3">6.4. Why do I get hundreds of messages about modified CTIME ?</a></li>
+<li><a href="#Misc4">6.5. PANIC &mdash; File not accessible</a></li>
+<li><a href="#Misc5">6.6. How can I avoid error messages for invalid UIDs (no such user) ?</a></li>
+<li><a href="#Misc6">6.7. [Redhat] The /etc/init.d/(samhain|yule) init script hangs</a></li>
+<li><a href="#Misc7">6.8. The /etc/init.d/(samhain|yule) init script exits with: execvp: No such file or directory</a></li>
+<li><a href="#Misc8">6.9. Why am I not receiving the &quot;BEGIN LOGKEY&quot; message by email ?</a></li>
+<li><a href="#Misc9">6.10. Why does console logging fail if I compile with
+ <code>--enable-(micro-)stealth</code> ?</a></li>
+<li><a href="#Misc10">6.11. I need a list for my schedule !</a></li>
+<li><a href="#Misc11">6.12. The hiding kernel module has no effect !</a></li>
+<li><a href="#Misc12">6.13. What does the message &quot;Large lstat/open overhead&quot; mean ?</a></li>
+<li><a href="#Misc13">6.14. What does the message &quot;Device not available path=/dev/random&quot; mean ? I have /dev/random !</a></li>
+<li><a href="#Misc14">6.15. Logging to an external program fails; the program receives no data
+ on stdin !</a></li>
+<li><a href="#Misc15">6.16. SIGILL on AIX</a></li>
+</ul></dd>
+<dt><b>7. Database</b></dt>
+<dd><ul>
+<li><a href="#Database0">7.1. Why are client messages corrupted / incompletely stored in the DB ?</a></li>
+<li><a href="#Database1">7.2. I want / don't want the server timestamps (for client messages) in the SQL database</a></li>
+<li><a href="#Database2">7.3. I don't want the client TIMESTAMP messages in the SQL database</a></li>
+<li><a href="#Database3">7.4. What does the log_ref field mean ?</a></li>
+<li><a href="#Database4">7.5. How can I check what is in the database ?</a></li>
+</ul></dd>
+</dl>
+<hr><h2>1. Most frequently</h2>
+<dl>
+<dt><b><a name="Most frequently0">1.1. Owner not trustworthy / Group writeable and member not trustworthy</a></b></dt>
+<dd>An untrusted user (might be an untrusted group member
+ for group writeable files/directories) owns or can write to an
+ element in the path listed in the error message. This concerns
+ the configuration file, the log file, and the database file.
+ The offending element in the path is identified as obj=/xxx in the
+ error message.
+ To fix the problem, see next entry.<br><br></dd>
+<dt><b><a name="Most frequently1">1.2. samhain exits with the message &quot;Untrusted path&quot; for config/log/pid/database files</a></b></dt>
+<dd>Paths to critical
+ files (e.g. the configuration file) must be writeable by trusted users
+ only.
+ If a path element is group writeable, all group members must be trusted.
+ By default, only <i>root</i> and the (effective) <i>user</i> of
+ the program are trusted. To add trusted users, use the compile time
+ option
+<div class="block"><pre>
+$ ./configure --with-trusted=0,...
+</pre></div>
+ or the configure file option:
+<div class="block"><pre>
+[Misc]
+TrustedUser=username
+</pre></div>
+If the path to the configuration file itself is writeable
+ by other users than <i>root</i> and the
+ <i>effective user</i>
+ these must be defined as trusted already
+ at compile time.<br><br></dd>
+<dt><b><a name="Most frequently2">1.3. It does not log anything / Can't stop logging to console</a></b></dt>
+<dd>(1) There is a section in the manual dealing with
+logging and filtering.<br />
+
+(2) To log to the console:
+<div class="block"><pre>
+$ samhain -p info ...
+</pre></div>
+or in the configuration file:
+<div class="block"><pre>
+[Log]
+PrintSeverity=info
+</pre></div>
+
+To <i>stop</i> logging to the console:
+<div class="block"><pre>
+$ samhain -p none ...
+</pre></div>
+or in the configuration file:
+<div class="block"><pre>
+[Log]
+PrintSeverity=none
+</pre></div>
+Defining <tt>/dev/null</tt> as console device works as well, but
+is a bad idea, because samhain will open the device and write (i.e. it is
+a very inefficient method).<br><br></dd>
+<dt><b><a name="Most frequently3">1.4. Client cannot self-resolve, but nslookup works fine</a></b></dt>
+<dd><ul>
+<li>Nslookup is a program to query Internet domain name servers.
+</li>
+<li>Applications (like samhain) are not supposed to query DNS servers
+ directly. Rather, they are supposed to query the resolver library that:
+ <ul>
+ <li>is provided by the operating system,</li>
+ <li>configured by the system administrator,</li>
+ <li>may use several different method to determine host names, as
+ configured in <tt>/etc/nsswitch.conf</tt>, and</li>
+ <li>usually is configured to give precedence to
+ the <tt>/etc/hosts</tt> file.</li>
+ </ul>
+</li>
+<li>Therefore, whether nslookup gives correct answers may be completely
+ irrelevant. For self-resolving the own hostname, the resolver
+ library probably will use <tt>/etc/hosts</tt>, rather than
+ querying a DNS server.
+</li>
+</ul>
+<p>
+Below you can find some examples of good and bad <tt>/etc/hosts</tt> files:
+</p>
+<div class="block"><pre>
+ # CORRECT
+ #
+ 127.0.0.1 localhost
+ xxx.xxx.xxx.xxx myhost.mydomain.tld myhost
+</pre></div>
+
+<div class="block"><pre>
+ # CORRECT
+ #
+ 127.0.0.1 localhost.localdomain localhost
+ xxx.xxx.xxx.xxx myhost.mydomain.tld myhost
+</pre></div>
+
+<div class="block"><pre>
+ # BAD
+ #
+ 127.0.0.1 myhost.mydomain.tld localhost
+ xxx.xxx.xxx.xxx myhost.mydomain.tld myhost
+</pre></div>
+
+<div class="block"><pre>
+ # BAD
+ #
+ 127.0.0.1 localhost myhost
+ xxx.xxx.xxx.xxx myhost.mydomain.tld myhost
+</pre></div><br><br></dd>
+<dt><b><a name="Most frequently4">1.5. Server logs hostname instead of FQDN (or vice versa)</a></b></dt>
+<dd>The default is to log the hostname only, if you want the FQDN
+then there is an option for the server configuration:
+<div class="block"><pre>
+ [Misc]
+ SetStripDomain = true / false
+</pre></div><br><br></dd>
+</dl>
+<hr><h2>2. Build and install</h2>
+<dl>
+<dt><b><a name="Build and install0">2.1. [Fedora Core] Cannot compile with --enable-khide</a></b></dt>
+<dd>The Fedora Core kernel is patched to unconditionally deny reading
+from /dev/kmem. Compiling the stealth kernel modules is not possible
+under these circumstances.<br><br></dd>
+<dt><b><a name="Build and install1">2.2. [Fedora Core] Cannot compile with --with-kcheck</a></b></dt>
+<dd>The Fedora Core kernel is patched to unconditionally deny reading
+from /dev/kmem. Checking the kernel for the presence of rootkits is
+not possible under these circumstances.<br><br></dd>
+<dt><b><a name="Build and install2">2.3. &quot;make&quot; loops infinitely !</a></b></dt>
+<dd>This may happen (e.g. when building via NFS for multiple architectures)
+ if the relative timestamps in the source directory are
+ wrong (time not in sync on different machines) or some intermediate
+ target is unusable (up-to-date, but built for a different OS). Use
+ &quot;touch * &amp;&amp; make distclean&quot; in the source directory
+ to recover.<br><br></dd>
+<dt><b><a name="Build and install3">2.4. Why does static compiling (<code>--enable-static</code>) on Solaris fail ?</a></b></dt>
+<dd>Ingo Rogalsky has provided the following information: It isn't possible
+ to link Samhain statically with Solaris. This
+ is a Solaris issue (see Sun Infodoc ID12624) and not a samhain problem.<br><br></dd>
+<dt><b><a name="Build and install4">2.5. Compilation fails with '/usr/bin/ld: cannot find -lnss_files'</a></b></dt>
+<dd>For Linux, this is a known problem with --enable-static if you compile
+ in MySQL support. The problem is that the
+ <tt>mysql_config</tt> that comes as part of the MySQL
+ distribution script incorrectly lists dependencies on
+ the libnss_files and libnss_dns libraries which are only available as
+ shared libraries, so the linker cannot find the static libraries.
+
+ You can check this by inspecting the output of
+ <code>mysql_config --libs</code>. The version of
+ <tt>mysql_config</tt> that comes with the RedHat mysql
+ RPM (RedHat 9) does not have this bug; the one distributed by the MySQL
+ people has. You can fix the problem by editing
+ <tt>mysql_config</tt>: search for the
+ <i>client_libs</i> variable, and remove all instances
+ of <i>-lnss_files</i> and <i>-lnss_dns</i>.<br><br></dd>
+<dt><b><a name="Build and install5">2.6. The executable is corrupted after installation</a></b></dt>
+<dd>The executable will get stripped during the installation. On
+ suitable systems (i386 Linux/FreeBSD currently), additionally
+ the &quot;sstrip&quot;
+ utility (copyright 1999 by Brian Raiter, under the GNU GPL)
+ will be used to strip the executable even more, to prevent
+ debugging with the GNU &quot;gdb&quot; debugger.
+ The &quot;strip&quot; utility cannot handle the resulting
+ executable, therefore trying to strip manually after installation
+ will corrupt the executable.<br><br></dd>
+<dt><b><a name="Build and install6">2.7. --enable-xml-log has no effect</a></b></dt>
+<dd>If you have compiled for stealth, you won't see much, because if
+ obfuscated, then both a 'normal' and an XML logfile look,
+ well ... obfuscated. Use <code>samhain -jL /path/to/logfile</code>
+ to view the logfile.<br><br></dd>
+<dt><b><a name="Build and install7">2.8. ./install-sh: strip: not found (Solaris)</a></b></dt>
+<dd>Install the SUNWbtool package.<br><br></dd>
+<dt><b><a name="Build and install8">2.9. What is sh_tiger1.s?</a></b></dt>
+<dd>This is a precompiled assembly file for the i386 architecture
+generated from sh_tiger1.c using gcc 3.4.0 with the following options,
+that were found to generate the fastest code:
+<pre>
+ -O1 -fno-delayed-branch -fexpensive-optimizations -fstrength-reduce
+ -fpeephole2 -fschedule-insns2 -fregmove -frename-registers -fweb
+ -momit-leaf-frame-pointer -funroll-loops
+</pre>
+These options were determined using
+<a href="http://www.coyotegulch.com/products/acovea/">acovea</a> 5.1.1
+by Scott Robert Ladd. The file is provided as precompiled assembly
+because different versions of gcc can have very different performance,
+require different options to compile optimal code, and
+it would be impossible to maintain a library of optimal compile options
+for every version of gcc.<br><br></dd>
+<dt><b><a name="Build and install9">2.10. Why does static compiling (<code>--enable-static</code>) on MaxOS X fail ?</a></b></dt>
+<dd>Static linking is not supported on MacOS X, see
+<a href="http://developer.apple.com/qa/qa2001/qa1118.html">Technical Q&A QA1118</a>.
+This is a MacOS X issue and not a bug in samhain.<br><br></dd>
+<dt><b><a name="Build and install10">2.11. Why does compiling with MySQL fail on Solaris ?</a></b></dt>
+<dd>The reason is often the shell script 'mysql_config' that comes as part
+of MySQL. This script is intended to print appropriate compiler flags for
+compiling applications that use MySQL. Unfortunately, since Sun compiles
+MySQL with the Solaris compiler, this script outputs options for the Solaris
+compiler (i.e. unsuitable for gcc). To solve this problem, you need to move
+this script (i.e. 'mysql_config') out of your PATH before running
+<tt>./configure</tt> (unless of course you are using the Solaris compiler
+rather than gcc).<br><br></dd>
+</dl>
+<hr><h2>3. File checking</h2>
+<dl>
+<dt><b><a name="File checking0">3.1. How can I exclude a (sub-)directory ?</a></b></dt>
+<dd><div class="block"><pre>
+[IgnoreAll]
+dir=-1/ignore/this/subdirectory
+</pre></div><br><br></dd>
+<dt><b><a name="File checking1">3.2. In messages about policy violations, what does the code after POLICY [XYZ]
+mean ?</a></b></dt>
+<dd>This code indicates which items are modified (e.g. C = checksum). You can
+find a description in section 5.4.9 in the user manual. It is there because
+then you can see in the message list of the Beltane web console what has been
+modified, without the need to look at the message in detail.<br><br></dd>
+<dt><b><a name="File checking2">3.3. Does samhain support prelink ?</a></b></dt>
+<dd>Yes. There is a special checking policy [Prelink]. Directories with
+prelinked executables / shared libraries (see /etc/prelink.conf) should be
+placed under this policy, rather than under the [ReadOnly] policy.<br><br></dd>
+<dt><b><a name="File checking3">3.4. I get error messages about 'subdirectory count != hardlinks'</a></b></dt>
+<dd>Some filesystems do not always follow the rule that the number
+of directory
+hardlinks equals the number of subdirectories. E.g. the root directory of
+reiserfs partitions generally seems to have two additional hardlinks.
+To account for such exceptions, you can either switch off the
+hardlink check globally, or specify exceptions:
+<div class="block"><pre>
+[Misc]
+# Switch off hardlink check
+#
+UseHardlinkCheck=no
+</pre></div>
+<div class="block"><pre>
+[Misc]
+# Specify exceptions for the hardlink check
+#
+HardlinkOffset=N:/path
+</pre></div>
+Here, N is the numerical offset (actual - expected hardlinks) for
+'/path'. For multiple exceptions, use
+this options multiple times (note that '/path N:/path2' would itself be a valid
+path, so using the option only once with multiple exceptions on the same line
+would be ambiguous).<br><br></dd>
+</dl>
+<hr><h2>4. Client/Server</h2>
+<dl>
+<dt><b><a name="Client/Server0">4.1. I don't want to poke a hole into my firewall to let the client connect to the server !</a></b></dt>
+<dd>Pat Smith has posted the following solution. On the client, create
+an iptable rule as follows (<i>note: you probably don't need this if you
+configure / compile in 127.0.0.1 as the server address</i>):
+<div class="block"><pre>
+iptables -t nat -A OUTPUT -p tcp -m tcp --dport 49777 -d <i>server-ip</i> -j REDIRECT
+</pre></div>
+
+On the server, create an ssh tunnel for each client outside the firewall:
+
+<div class="block"><pre>
+ssh -f -C -R 49777:localhost:49777 -N <i>client-ip</i>
+</pre></div>
+
+It is necessary that each client has a distinct name, and that the server
+knows the name of the client. With the setup above, each client will appear
+as &quot;localhost&quot; to the server, thus the server
+needs to trust the client name
+as reported by the client itself, and suppress all errors on resolving
+this name to the apparent address. In the server configuration:
+
+<div class="block"><pre>
+[Misc]
+SetClientFromAccept = false
+SeverityLookup = debug
+</pre></div>
+
+Obviously, self-resolving must work on the client machine, otherwise
+you are in trouble (see next issue).<br><br></dd>
+<dt><b><a name="Client/Server1">4.2. The client sends 127.0.0.1 (or some other numerical address) as its name to the log server</a></b></dt>
+<dd>See 'Client cannot self-resolve' in the 'Most frequently' section<br><br></dd>
+<dt><b><a name="Client/Server2">4.3. The server wants to send rc.ip-adress rather than rc.fqdn to the client</a></b></dt>
+<dd>The client self-resolves to its ip address.
+See 'Client cannot self-resolve' in the 'Most frequently' section<br><br></dd>
+<dt><b><a name="Client/Server3">4.4. Cannot resolve client name host=XXX</a></b></dt>
+<dd><div class="block"><pre>
+The server must be able to determine the client name.
+This is because only authenticated connections from registered
+clients are allowed, and
+the server must be able to check the client hostname against the list of
+allowed hosts, and look up the password verifier for that
+host.
+</pre></div>
+There are two different ways to accomplish this. Unfortunately, judging
+from customer feedback as well from common sense, both do not work very well
+with a messed up local DNS (including /etc/hosts files) and/or
+&uuml;berparanoid or misconfigured firewalls (in case of connections
+across one).
+<ul>
+ <li>
+ <p>
+ <i>First method: Determine client name on client, and
+ try to cross-check on server</i>
+ <p>
+ <p>
+ This does not work for a number of people because (1) the
+ <tt>/etc/hosts</tt> file on the client machine has errors
+ (yes, there are plenty machines with a completely
+ messed up <tt>/etc/hosts</tt> file), (2) the
+ server cannot resolve the client address because the local DNS is
+ f***ed up, or (3) the client machine has multiple network interfaces, and
+ the interface used is not the one the client name resolves to.
+ </p>
+ <p>
+ If the client uses the wrong interface on a multi-interface machine,
+ there is a config file option
+ <tt>SetBindAddress=</tt><i>IP address</i>
+ that allows to choose the interface the client will use for
+ outgoing connections.
+ </p>
+ <p>
+ If you want to download the config file from the server, you
+ should instead use the corresponding command line
+ <tt>--bind-address=</tt><i>IP address</i>
+ to select the interface.
+ </p>
+
+ <p>
+ If you encounter problems, you may (1) fix your
+ <tt>/etc/hosts</tt> file(s), (2) fix your local DNS, or
+ (3) switch to the second method.
+ </p>
+ <p>
+ Errors in name resolving/cross-checking can be avoided by setting a
+ very low severity (lower than the logging threshold), e.g.
+ </p>
+ <p>
+ <tt>SeverityLookup=</tt><i>debug</i>
+ </p>
+ <p>
+ in the <i>Misc</i> section of the server configuration,
+ if you prefer running <i>unsafe</i> at any speed
+ instead of fixing the problem (you have been warned). Doing so will
+ allow an attacker to pose as the client.
+ </p>
+ </li>
+ <li>
+ <p><i>Second method: Use address of connecting entity as
+ known to the communication layer</i></p>
+ <p>
+ This has been dropped as default
+ long ago because it may not always be the
+ address of the client machine.
+ To enable this method, use
+ </p>
+ <p>
+ <tt>SetClientFromAccept=</tt><i>true</i>
+ </p>
+ <p>
+ in the <i>Misc</i> section of the server configuration
+ file. If the address cannot be resolved, or reverse lookup of the
+ resolved name fails, <i>no</i> error message will be issued,
+ but the numerical address will be used.
+ </p>
+ </li>
+</ul><br><br></dd>
+<dt><b><a name="Client/Server4">4.5. Cannot resolve socket peer IP for client host=XXX peer=YYY</a></b></dt>
+<dd>See above<br><br></dd>
+<dt><b><a name="Client/Server5">4.6. Reverse lookup of socket peer failed host=XXX peer=YYY obj=ZZZ</a></b></dt>
+<dd>See above<br><br></dd>
+<dt><b><a name="Client/Server6">4.7. No socket peer alias matches client name host=XXX peer=YYY</a></b></dt>
+<dd>See above<br><br></dd>
+<dt><b><a name="Client/Server7">4.8. Session key negotiation failed</a></b></dt>
+<dd>See the document <a href="HOWTO-client+server-troubleshooting.html">HOWTO client+server troubleshooting</a><br><br></dd>
+<dt><b><a name="Client/Server8">4.9. Invalid connection attempt: Not in client list</a></b></dt>
+<dd>See the document <a href="HOWTO-client+server-troubleshooting.html">HOWTO client+server troubleshooting</a><br><br></dd>
+<dt><b><a name="Client/Server9">4.10. Invalid connection attempt: Session key mismatch</a></b></dt>
+<dd>See the document <a href="HOWTO-client+server-troubleshooting.html">HOWTO client+server troubleshooting</a><br><br></dd>
+<dt><b><a name="Client/Server10">4.11. How do I update the file signature database ?</a></b></dt>
+<dd>If you keep the file signature database on the server,
+ the database is supposed to be updated on the server, using the
+ <a href="http://www.la-samhna.de/beltane/">beltane</a>
+ web-based console (currently in beta) and the
+ log messages from the client.
+ <p>
+ Alternatively, you can <code>scp</code> the database
+ to the client, run <code>samhain -t update -l none --foreground</code>
+ (you
+ need to avoid logging because otherwise you will get in conflict with
+ the running samhain daemon), and then <code>scp</code> the
+ database back to the server. Actually, with a properly set up
+ &quot;ssh&quot;, using RSA/DSA authentication
+ and ssh-agent you could write a script to automate this.<br><br></dd>
+<dt><b><a name="Client/Server11">4.12. Time limit exceeded</a></b></dt>
+<dd>The respective client for that this message is generated has not
+ sent anything for some interval of time (default 84600 sec = 1 day).
+ The interval can be set as follows:
+<div class="block"><pre>
+ [Misc]
+ # unit is seconds
+ SetClientTimeLimit=NNN
+</pre></div>
+
+ This feature has the purpose to detect if a client is dead. You
+ might want to ensure that timestamps are sent to the server:
+<div class="block"><pre>
+ [Log]
+ ExportSeverity=mark
+</pre></div>
+ If you don't want to use this feature, set the time limit to some
+ very large value.<br><br></dd>
+<dt><b><a name="Client/Server12">4.13. Invalid connection attempt: Signature mismatch</a></b></dt>
+<dd>Clients sign their messages using a session key negotiated
+ with the server. The message indicates that the server could
+ not verify the signature. This may be caused by a running two
+ instances of samhain on the same client machine, both of them
+ accessing the server (and negotiating different session keys
+ ...). The system will recover automatically from the problem
+ by forcing the failed client to negotiate a fresh session key.<br><br></dd>
+<dt><b><a name="Client/Server13">4.14. [Server] PANIC .. Address already in use&nbsp; &nbsp;subroutine=bind</a></b></dt>
+<dd>The server cannot bind to its port because the port is already used.
+ Maybe you have accidentially already an instance of the
+ server running.<br><br></dd>
+</dl>
+<hr><h2>5. Email</h2>
+<dl>
+<dt><b><a name="Email0">5.1. Reverse lookup failed</a></b></dt>
+<dd>Fix your DNS (reverse lookup: numerical IP address to FQDN, to verify
+ FQDN to numerical IP address).
+<div class="block"><pre>
+Whether &quot;nslookup&quot; works is not very informative, because
+&quot;nslookup&quot; does not use the resolver library of the operating
+system. Therefore,
+it is not exactly the
+best tool for debugging name resolving problems (see the book
+&quot;DNS and bind&quot;).
+</pre></div><br><br></dd>
+<dt><b><a name="Email1">5.2. From daemon@example.com</a></b></dt>
+<dd>samhain fails to resolve the
+ self-address of the host.
+See 'Client cannot self-resolve' in the 'Most frequently' section.<br><br></dd>
+<dt><b><a name="Email2">5.3. How do I define more than one email addresses ?</a></b></dt>
+<dd>Use <tt>SetMailAddress=...</tt> multiple times (upt to eight addresses
+are possible, with at most 63 characters per address):
+<div class="block"><pre>
+[Misc]
+SetMailAddress=aaa@foo.com
+SetMailAddress=bbb@foo.com
+</pre></div><br><br></dd>
+</dl>
+<hr><h2>6. Misc</h2>
+<dl>
+<dt><b><a name="Misc0">6.1. Error message: &quot;Invalid line XYZ in configuration file&quot;</a></b></dt>
+<dd>This message indicates that line XYZ in the configuration file contains
+an unrecognized directive. The primary reasons are:<br />
+
+(a) The directive should be placed into a particular section of the
+configuration file, but the section header is not present (or you forgot
+to uncomment it).<br />
+
+(b) Samhain is compiled without support for this directive.<br />
+
+(c) You have a typo in the directive.<br /><br><br></dd>
+<dt><b><a name="Misc1">6.2. Why do I get a local logfile if I log to the server ?</a></b></dt>
+<dd>Because you can use all log facilities in parallel. You should
+ switch off in the config file what you don't want/need:
+<div class="block"><pre>
+ [Log]
+ # local log file
+ LogSeverity=none
+</pre></div><br><br></dd>
+<dt><b><a name="Misc2">6.3. Why is there no NIS support with a static samhain executable on Linux ?</a></b></dt>
+<dd>Some functions (including NIS) require
+ libraries that are only available as shared libraries
+ with modern GLIBC versions. While you can always compile a static
+ executable, normally it would still open the shared library at runtime.
+ As of version 1.8.11, samhain avoids this by providing replacement
+ functions from uClibc. However, these do not include NIS support.<br><br></dd>
+<dt><b><a name="Misc3">6.4. Why do I get hundreds of messages about modified CTIME ?</a></b></dt>
+<dd>This happens because some
+ backup applications reset the atime/mtime timestamps, which causes
+ the ctime timestamp to be modified (rootkits avoid this by
+ temporarily resetting the system clock to the original ctime ...).
+ <p>
+ To fix this problem, read the manual of your backup application, or
+ redefine the ReadOnly policy to <i>not</i> check
+ the ctime timestamp:
+<div class="block"><pre>
+ [Misc]
+ RedefReadOnly=-CTM
+</pre></div>
+<div class="warnblock"><pre>
+ Order matters - you must <i>first</i> redefine
+ ReadOnly <i>before</i> you use it
+</pre></div><br><br></dd>
+<dt><b><a name="Misc4">6.5. PANIC &mdash; File not accessible</a></b></dt>
+<dd>Most likely permission denied because of unsufficient privileges.<br><br></dd>
+<dt><b><a name="Misc5">6.6. How can I avoid error messages for invalid UIDs (no such user) ?</a></b></dt>
+<dd>Set SeverityNames to a low value
+<div class="block"><pre>
+[EventSeverity]
+SeverityNames=debug
+</pre></div><br><br></dd>
+<dt><b><a name="Misc6">6.7. [Redhat] The /etc/init.d/(samhain|yule) init script hangs</a></b></dt>
+<dd>Redhat uses &quot;initlog&quot; (see
+ <code>man initlog</code>) in initscripts. If it hangs, most probably
+ samhain/yule runs in the foreground rather than as daemon. Set
+ daemon mode in the configuration file:
+<div class="block"><pre>
+[Misc]
+Daemon=yes
+</pre></div><br><br></dd>
+<dt><b><a name="Misc7">6.8. The /etc/init.d/(samhain|yule) init script exits with: execvp: No such file or directory</a></b></dt>
+<dd>Either the program is not installed, or it is not in the PATH (the one
+ used by the init script, which may be different from your PATH).<br><br></dd>
+<dt><b><a name="Misc8">6.9. Why am I not receiving the &quot;BEGIN LOGKEY&quot; message by email ?</a></b></dt>
+<dd>This message (which contains the key to verify the log file) is generated
+ when logging to the log file starts. It has the severity &quot;ALRT&quot;,
+ thus you should make sure that you have set the logging threshold for
+ email correctly to receive it.<br><br></dd>
+<dt><b><a name="Misc9">6.10. Why does console logging fail if I compile with
+ <code>--enable-(micro-)stealth</code> ?</a></b></dt>
+<dd>The default logging options are more &quot;stealthy&quot;. Set the
+ threshold explicitely rather than relying on the default.<br><br></dd>
+<dt><b><a name="Misc10">6.11. I need a list for my schedule !</a></b></dt>
+<dd>You can have the same effect with a list of schedules. See the section
+&quot;Timing file checks&quot; in the manual.<br><br></dd>
+<dt><b><a name="Misc11">6.12. The hiding kernel module has no effect !</a></b></dt>
+<dd>Most probably you compiled using the wrong &quot;System.map&quot; file.<br><br></dd>
+<dt><b><a name="Misc12">6.13. What does the message &quot;Large lstat/open overhead&quot; mean ?</a></b></dt>
+<dd>Your system needs several seconds to proceed from an lstat() system call
+ to an open() system call. This is a tremenduous overhead, and
+ indicates that either your system has a really severe performance problem,
+ or someone tries to slow down samhain.<br><br></dd>
+<dt><b><a name="Misc13">6.14. What does the message &quot;Device not available path=/dev/random&quot; mean ? I have /dev/random !</a></b></dt>
+<dd>/dev/random blocks unless there is some entropy it can deliver. Samhain
+ will time out and fall back on /dev/urandom after some seconds to avoid
+ hanging for a potentially long time. It will try /dev/random again next
+ time it needs entropy.<br><br></dd>
+<dt><b><a name="Misc14">6.15. Logging to an external program fails; the program receives no data
+ on stdin !</a></b></dt>
+<dd>Probably your program is not designed to <i>wait for input</i>, but exits
+ if reading fails (because there is no data <i>yet</i>). You may want to
+ let your program wait for the terminating &quot;[EOF]&quot; line.<br><br></dd>
+<dt><b><a name="Misc15">6.16. SIGILL on AIX</a></b></dt>
+<dd>For each scanned file, samhain needs to
+ store some information in memory (e.g. to recognize changes that have
+ already been reported, and avoid duplicate reports). On AIX, if you are
+ checking a <i>really huge</i> number of files,
+ memory usage may exceed the default limit of 256 MB, and the process may
+ terminate with SIGILL.
+ <p>
+ The problem can be solved by linking with the flag
+ <code>-bmaxdata:0x80000000</code>. This allows the application to
+ access up to 8 segments (where each segment is 256MB).
+ <p>
+ If you are using gcc, you need to use instead
+ the flag <code>-Wl,bmaxdata:0x80000000</code>, which tells
+ gcc to pass on the
+ <i>bmaxdata</i>
+ flag to the AIX linker. You can use the LDFLAGS environment variable to
+ pass linker flags to the configure script:
+<div class="block"><pre>
+ export LDFLAGS="-Wl,bmaxdata:0x80000000"
+</pre></div><br><br></dd>
+</dl>
+<hr><h2>7. Database</h2>
+<dl>
+<dt><b><a name="Database0">7.1. Why are client messages corrupted / incompletely stored in the DB ?</a></b></dt>
+<dd>Because the messages are not in XML format, and therefore incorrectly
+ parsed. The most frequent reasons are:
+<div class="block"><pre>
+ 1.) Your server is compiled with --enable-xml-log, but your client(s)
+ is/are not.
+
+ 2.) In your client or server configuration file, you are using
+ the option for a custom message header, but without paying attention
+ to preserving the XML format.
+</pre></div><br><br></dd>
+<dt><b><a name="Database1">7.2. I want / don't want the server timestamps (for client messages) in the SQL database</a></b></dt>
+<dd><div class="block"><pre>
+[Database]
+SetDBServerTstamp = true/false
+</pre></div>
+
+ This will enable/disable logging of the server timestamp for client
+ messages. The server timestamp will be written to a seperate record,
+ with <i>log_ref</i> set to the value of
+ <i>log_index</i> of the corresponding client message.<br><br></dd>
+<dt><b><a name="Database2">7.3. I don't want the client TIMESTAMP messages in the SQL database</a></b></dt>
+<dd><div class="block"><pre>
+ Sending timestamps from the client allows the server to detect if
+ a client is not running anymore (use SetClientTimeLimit=NNN in the
+ [Misc] section of the server config file to set the number of seconds
+ after which the server will issue an error message if no timestamp has
+ been received).
+</pre></div>
+
+ However, you might not want to log these timestamps to the database
+ (or other log facilities). To filter them, you can use two methods
+ (examples are for the SQL database).
+ The first
+ one has the disadvantage that only messages of
+ severity <i>err</i> or higher will be logged:
+<div class="block"><pre>
+ [Misc]
+ UseClientSeverity=yes
+
+ [Log]
+ DatabaseSeverity=err
+</pre></div>
+
+ The second method is more specific &mdash; log everything not
+ belonging to the STAMP class of messages:
+<div class="block"><pre>
+ [Misc]
+ UseClientClass=yes
+
+ [Log]
+ DatabaseClass=PANIC RUN FIL TCP ERR ENET EINPUT
+</pre></div><br><br></dd>
+<dt><b><a name="Database3">7.4. What does the log_ref field mean ?</a></b></dt>
+<dd>NULL are client messages. Nonzero integer is a server timestamp
+ for a client message (where log_ref indicates the log_index entry
+ number of the corresponding client message). Zero indicates a message
+ by the server itself (e.g. the server's start message).<br><br></dd>
+<dt><b><a name="Database4">7.5. How can I check what is in the database ?</a></b></dt>
+<dd>Use a command line client to login to the database and query it:
+<div class="block"><pre>
+ sh$ mysql -u &lt;user_name&gt; -p &lt;database_name&gt;
+ Enter password: ****
+ mysql&gt; SELECT log_index,log_ref,log_host,log_sev,log_msg,path FROM &lt;table_name&gt; WHERE entry_status = 'NEW' ORDER BY log_index;
+ ....
+ mysql&gt; \q
+</pre></div><br><br></dd>
+</dl>
+<hr>
+
+<p>Copyright (c) 2004 Rainer Wichmann</p>
+
+<p><i>This list of questions and answers was generated by
+<a href="http://www.makefaq.org/">makefaq</a>.</i>
+
+</div>
+</body>
+</html>
diff --git a/docs/HOWTO-client+server-troubleshooting.html b/docs/HOWTO-client+server-troubleshooting.html
new file mode 100644
index 0000000..ec4e555
--- /dev/null
+++ b/docs/HOWTO-client+server-troubleshooting.html
@@ -0,0 +1,452 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>HOWTO client+server troubleshooting</title>
+<style type="text/css">
+<!--
+
+html { background: #eee; color: #000; }
+
+body { background: #eee; color: #000; margin: 0; padding: 0;}
+
+div.body {
+ background: #fff; color: #000;
+ margin: 0 1em 0 1em; padding: 1em;
+ font-family: serif;
+ font-size: 1em; line-height: 1.2em;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #aaa;
+}
+
+div.block {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #2d4488;
+}
+
+div.warnblock {
+ background: #b6c5f2; color: #000;
+ background: #ffffcc; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #FF9900;
+}
+
+table {
+ background: #F8F8F8; color: #000;
+ margin: 1em;
+ border-width: 0 0 0 1px;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+th {
+ background: #F8F8FF;
+ border-width: 1px 1px 2px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+
+/* body text, headings, and rules */
+
+p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #206020; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
+h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
+h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
+h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
+h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
+h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
+
+hr {
+ color: transparent; background: transparent;
+ height: 0px; margin: 0.6em 0;
+ border-width: 1px ;
+ border-style: solid;
+ border-color: #999;
+}
+
+/* bulleted lists and definition lists */
+
+ul { margin: 0 1em 0.6em 2em; padding: 0; }
+li { margin: 0.4em 0 0 0; }
+
+dl { margin: 0.6em 1em 0.6em 2em; }
+dt { color: #285577; }
+
+tt { color: #602020; }
+
+/* links */
+
+a.link {
+ color: #33c; background: transparent;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000; background: transparent;
+}
+
+body > a {
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-size: 0.81em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2d5588; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+ -->
+</style></head>
+
+<body>
+<div class="body">
+<p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a
+ style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/">samhain file integrity
+ scanner</a>&nbsp;|&nbsp;<a style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/s_documentation.html">online
+ documentation</a></p>
+<br><center>
+<h1>Samhain client/server: What can go wrong, and how can you fix it ?</h1>
+</center>
+<br>
+<hr>
+<div class="warnblock">
+<ul>
+ <li>Almost all problems can only be diagnosed correctly by checking the
+ <b>server logs</b>.</li>
+ <li>
+ If the server does not write logs, <b>fix this first</b>. For debugging,
+ stop the server, then run it in the foreground with
+ <tt>yule -p info --foreground</tt>
+ <ul>
+ <li>
+ By default, the server logs to the file
+ <tt>/var/log/yule/yule_log</tt>, and since the server drops
+ root privileges on startup, the directory <tt>/var/log/yule</tt>
+ must be writable for the nonprivileged user the server runs
+ as (the first existing out of: yule, daemon, nobody).
+ </li>
+ <li>
+ Logging to the logfile must be enabled in the
+ <tt>/etc/yulerc</tt> config file (e.g. LogSeverity=mark, or
+ LogSeverity=info for enhanced verbosity).
+ </li>
+ </ul>
+ </li>
+</ul>
+</div>
+<p>
+This document aims to explain how to diagnose and fix common problems that
+may result from misunderstanding or misconfiguration when setting up
+a client/server samhain system. This document is divided in several sections
+more or less corresponding to the different stages when a client
+connects to a server. Each section starts with a brief explanation that
+should provide a basic understanding of what is going on.
+</p>
+<p>
+This document does not discuss <i>how</i> to setup a client/server (for
+this, look into the manual and/or the HOWTO-client+server).
+</p>
+
+<h2><a name="sect1">Table of Contents</a></h2>
+<p>
+<a href="#sect1">Connecting to the server</a><br>
+<a href="#sect2">Authentication</a><br>
+<a href="#sect3">Downloading config/database files</a><br>
+<a href="#sect4">Other connection problems</a><br>
+</p>
+
+<h2><a name="sect1">Connecting to the server</a></h2>
+
+<p>
+Client/server connections are always initiated from the client. The port
+is compiled in (there is a configure option to change the default).
+The default port is 49777.
+</p>
+
+<h3>Problem #1</h3>
+<p>
+The client reports: <b>Connection refused</b>. The server reports nothing.
+</p>
+<p>
+The server is down, listens on the wrong port, or network failure.
+</p>
+
+<h3>Problem #2</h3>
+<p>
+The client reports: <b>Connection error: Connection reset by peer</b>, and
+later also <b>Session key negotiation failed</b>. The server reports:
+<b>msg=&quot;Refused connection from ...&quot; subroutine=&quot;libwrap&quot;</b>.
+</p>
+<p>
+The server is compiled with libwrap (TCP Wrapper) support, and the
+client is either in <tt>/etc/hosts.deny</tt>, or you have set <i>yule: ALL</i>
+in <tt>/etc/hosts.deny</tt>, and forgot to put the client in
+<tt>/etc/hosts.allow</tt>.
+</p>
+<p>
+To fix: make proper entries in <tt>/etc/hosts.allow</tt> and/or
+<tt>/etc/hosts.deny</tt>. There is no need to restart/reload the server.
+</p>
+
+
+<h2><a name="sect2">Authentication</a></h2>
+<p>
+The client has a password that is used to authenticate to the server.
+This password is located within the binary, and is set with the
+<tt>samhain_setpwd</tt> helper application, as explained e.g. in the
+manual or in the Client+Server HOWTO.
+</p><p>
+The server has a list of clients that are allowed to connect, and the
+verifiers corresponding to the passwords of these clients.
+</p>
+<p>
+Upon successful authentication, client and server will negotiate
+a <b>session key</b> that is used for signing further messages
+from the client.
+</p>
+
+<h3>Problem #1</h3>
+
+<p>
+If the password is wrong, the client will report
+<b>Session key negotiation failed</b>. The server will
+report: <b>Invalid connection attempt: Session key mismatch</b>
+</p>
+<p>
+To fix: make sure that the password has in fact been set, that you are
+using the correct executable for the client (the one where the password is
+set), and that the entry in the server config file is the one generated
+for this password (also look out for double entries for this client).
+</p>
+
+<h3>Problem #2</h3>
+
+<p>
+If the client name (as resolved on the server) is wrong, the client
+will report
+<b>Session key negotiation failed</b>. The server will
+report: <b>Invalid connection attempt: Not in client list</b>,
+<i>and</i> it will tell you in the same error message
+what name it has inferred for the connecting
+client (example): <b>client=&quot;client.mydomain.com&quot;</b>.
+</p>
+<p>
+The fix depends on the nature of the problem. In principle, it should be
+sufficient to change the name of the client in the config file entry, which
+isn't really a solution if e.g. the server thinks the client is 'localhost'.
+</p>
+<p>
+There are two different ways to determine the client name.
+Unfortunately, judging
+from customer feedback as well from common sense, both do not work very well
+with a messed up local DNS (including /etc/hosts files) and/or
+&uuml;berparanoid or misconfigured firewalls (in case of connections
+across one).
+</p>
+<ul>
+ <li>
+ <p>
+ <i>First method: Determine client name on client, and
+ try to cross-check on server</i>
+ <p>
+ <p>
+ This does not work for a number of people because
+ <ol>
+ <li>
+ the
+ <tt>/etc/hosts</tt> file on the client machine has errors
+ (yes, there are plenty machines with a completely
+ messed up <tt>/etc/hosts</tt> file),
+ </li>
+ <li>
+ the
+ server cannot resolve the client address because the local DNS is
+ misconfigured, or
+ </li>
+ <li>
+ the client machine has multiple network interfaces, and
+ the interface used is not the one the client name resolves to.
+ </li>
+ </ol>
+ </p>
+
+ <p>
+ If the client uses the wrong interface on a multi-interface machine,
+ there is a config file option
+ <tt>SetBindAddress=</tt><i>IP address</i>
+ that allows to choose the interface the client will use for
+ outgoing connections.
+ </p>
+ <p>
+ If you want to download the config file from the server, you
+ should instead use the corresponding command line option
+ <tt>--bind-address=</tt><i>IP address</i>
+ to select the interface.
+ </p>
+
+ <p>
+ If you encounter problems, you may (1) fix your
+ <tt>/etc/hosts</tt> file(s), (2) fix your local DNS, or
+ (3) switch to the second method.
+ </p>
+ <p>
+ Error messages related to name resolving/cross-checking can be
+ suppressed by setting a
+ very low severity (lower than the logging threshold), e.g.
+ </p>
+ <p>
+ <tt>SeverityLookup=</tt><i>debug</i>
+ </p>
+ <p>
+ in the <i>Misc</i> section of the server configuration,
+ if you prefer running <i>unsafe</i> at any speed
+ instead of fixing the problem (you have been warned). Doing so will
+ allow an attacker to pose as the client.
+ </p>
+ </li>
+ <li>
+ <p><i>Second method: Use address of connecting entity as
+ known to the communication layer</i></p>
+ <p>
+ This has been dropped as default
+ long ago because it may not always be the
+ address of the client machine.
+ To enable this method, use
+ </p>
+ <p>
+ <tt>SetClientFromAccept=</tt><i>true</i>
+ </p>
+ <p>
+ in the <i>Misc</i> section of the server configuration
+ file. If the address cannot be resolved, or reverse lookup of the
+ resolved name fails, <i>no</i> error message will be issued,
+ but the numerical address will be used.
+ </p>
+ </li>
+</ul>
+
+
+<h2><a name="sect3">Downloading config/database files</a></h2>
+
+<p>
+The client does <i>not</i> tell the server the path to the requested
+file - it just tells the <em>type</em> of the file, i.e.
+either a configuration file or a database file. It is entirely the
+responsibility of the server to locate the correct file and send it.
+</p>
+<p>
+The server has a <i>data directory</i>, which by default would be
+<tt>/var/lib/yule</tt>. Here the config/database files should be placed.
+</p>
+<p>
+Configuration files: <tt>rc.</tt><i>client.mydomain.tld</i> or
+simply <tt>rc</tt>
+(this can be used as a catchall file).
+</p>
+<p>
+Database files: <tt>file.</tt><i>client.mydomain.tld</i> or
+simply <tt>file</tt>
+(this can be used as a catchall file).
+</p>
+
+<h3>Problem #1</h3>
+
+<p>
+If the server cannot access the configuration (or database) file, either
+because it does not exist or the server has no read permission, the
+client will report <b>File download failed</b>. The server will
+report: <b>File not accessible</b>, <i>and</i> it will tell you in the
+same report the path where it would have expected the file (example):
+<b>path=&quot;/var/lib/yule/rc.client.mydomain.com&quot;</b>
+</p>
+<p>
+To fix: put the file in the correct location, make sure the permissions
+are ok.
+<ul>
+ <li>
+ Note that <em>the server drops root privileges at startup</em> and
+ runs as an unprivileged user (the first existing out of:
+ yule, daemon, nobody).
+ </li>
+ <li>
+ Also remember that to access a file, at least execute permission is required
+ <em>for every directory in the path</em>.
+ </li>
+</ul>
+</p>
+
+
+<h2><a name="sect4">Other connection problems</a></h2>
+
+<p>
+The server has a table with client names and their session keys. If
+another client process accesses the server from the same host,
+it will negotiate a fresh session key for that host. As a consequence,
+the session key of the first client process will become <i>invalid</i>.
+</p>
+<p>
+Also, the server keeps track of the status of a client. If a client
+process does not announce its termination to the server, the server
+will not expect a <i>startup</i> message, and issue a warning for any
+such message.
+</p>
+
+<h3>Problem #1</h3>
+
+<p>
+The client reports: <b>Invalid connection state</b>. The server reports:
+<b>Invalid connection attempt: Signature mismatch</b>. This is a sign that
+a client has tried to connect using an invalid session key. Most probably,
+another instance of the client is/was started on the respective host.
+</p>
+<p>
+To fix: if you need to have concurrent access to the server,
+suspend the first process with SIGUSR2 before starting the second. Use
+SIGUSR2 again to wake up the first process. Give the process a second or two
+to return into the main event loop and go into suspend mode. Do not just use
+SIGSTOP/SIGCONT: it is important that the client tells the server that
+it will go into suspend.
+</p>
+
+<h3>Problem #2</h3>
+
+<p>
+The server reports:
+<b>Restart without prior exit</b> for a client.
+This is a sign that
+a client has re-started without informing the server about a previous
+termination.
+</p>
+<p>
+This would happen if the client was killed with SIGKILL, or if it terminated
+within the routine to send a message to the server (the routine is
+not re-entrant). You may want to investigate messages logged via another
+logging facility (e.g. the client's local logfile). Of course it <i>may</i>
+also be a segfault, which would be reported via syslog.
+</p>
+
+</div>
+</body>
+</html>
diff --git a/docs/HOWTO-client+server.html b/docs/HOWTO-client+server.html
new file mode 100644
index 0000000..e2d7d8e
--- /dev/null
+++ b/docs/HOWTO-client+server.html
@@ -0,0 +1,441 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>HOWTO client+server</title>
+<style type="text/css">
+<!--
+
+html { background: #eee; color: #000; }
+
+body { background: #eee; color: #000; margin: 0; padding: 0;}
+
+div.body {
+ background: #fff; color: #000;
+ margin: 0 1em 0 1em; padding: 1em;
+ font-family: serif;
+ font-size: 1em; line-height: 1.2em;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #aaa;
+}
+
+div.block {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #2d4488;
+}
+
+div.warnblock {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #FF9900;
+}
+
+table {
+ background: #F8F8F8; color: #000;
+ margin: 1em;
+ border-width: 0 0 0 1px;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+th {
+ background: #F8F8FF;
+ border-width: 1px 1px 2px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+
+/* body text, headings, and rules */
+
+p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #206020; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
+h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
+h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
+h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
+h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
+h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
+
+hr {
+ color: transparent; background: transparent;
+ height: 0px; margin: 0.6em 0;
+ border-width: 1px ;
+ border-style: solid;
+ border-color: #999;
+}
+
+/* bulleted lists and definition lists */
+
+ul { margin: 0 1em 0.6em 2em; padding: 0; }
+li { margin: 0.4em 0 0 0; }
+
+dl { margin: 0.6em 1em 0.6em 2em; }
+dt { color: #285577; }
+
+tt { color: #602020; }
+
+/* links */
+
+a.link {
+ color: #33c; background: transparent;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000; background: transparent;
+}
+
+body > a {
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-size: 0.81em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2d5588; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+ -->
+</style></head>
+
+<body>
+<div class="body">
+<p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a
+ style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/">samhain file integrity
+ scanner</a>&nbsp;|&nbsp;<a style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/s_documentation.html">online
+ documentation</a></p>
+<br><center>
+<h1>Setting up a client/server samhain system</h1>
+</center>
+<br>
+<hr>
+<p>
+This document aims to explain how to set up a client/server
+samhain system, where the client (samhain) runs on one machine to be
+monitored, and sends reports via TCP/IP to a remote server (yule).
+</p>
+<p>
+<b>Please note:</b> the server (yule) does not perform any filesystem and/or
+kernel checks. If you want to perform such checks on the log server host,
+you need to run a samhain client on this host as well.
+</p>
+<p>
+Client and server are
+<b>distict applications</b>, and must be
+built seperately. By default, installation names and paths (e.g.
+the configuration file) are
+different. Do not blame us if you abuse './configure' options to
+cause name clashes, if you install both on the same host.
+</p>
+
+<h2>Introduction</h2>
+<p>
+Samhain can be compiled for remote logging to a central server via a
+secure (AES-encrypted, signed, and authenticated) TCP/IP connection.
+</p><p>
+In addition, both the client configuration file and the file signature
+database can be stored on the server. The client will then pull them from
+the server upon startup.
+</p><p>
+This requires three basic steps:
+</p>
+<ol>
+<li>
+compile and install server and client,
+</li>
+<li>
+establish trust between client and server, and
+</li>
+<li>
+enable remote logging in the client's configuration file.
+</li>
+</ol>
+
+
+<h2>Compiling</h2>
+
+<h3>The server - yule</h3>
+
+<p>
+<b>Note: </b> the server can be started with root privileges (e.g. to use
+a privileged port &lt; 1024), but it will always
+drop root privileges irrevocably
+before accepting any connections, and run as a non-root user. This user
+can be specified explicitely with the <i>configure</i>
+option <tt>--enable-identity=USER</tt>. The default is
+the first existing user
+out of the list <i>yule, daemon, nobody</i>.
+</p>
+
+<pre>
+
+bash$ ./configure --enable-network=server
+bash$ make
+bash$ make install
+
+</pre>
+
+<h3>The client - samhain</h3>
+
+
+<ul>
+<li>
+ <p>
+ If you just want remote logging:
+ </p><p>
+ <tt>&nbsp; &nbsp;./configure --enable-network=client
+ --with-logserver=server.example.com</tt>
+ </p>
+</li>
+<li>
+ <p>
+ If you want configuration and database files on the server:
+ </p><p>
+ <tt>&nbsp; &nbsp;./configure --enable-network=client
+ --with-logserver=server.example.com \<br />
+ &nbsp; &nbsp; &nbsp; &nbsp; --with-config-file=REQ_FROM_SERVER/etc/samhainrc \<br />
+ &nbsp; &nbsp; &nbsp; &nbsp; --with-data-file=REQ_FROM_SERVER/var/lib/samhain/samhain_file</tt>
+ </p>
+</li>
+</ul>
+<p>
+The path after the keyword <tt>REQ_FROM_SERVER</tt> has the following meaning:
+<ul>
+<li>for the configuration file:
+ <ul>
+ <li> if <i>initializing</i>, and the connection to the server
+ fails, samhain will fall back on the local file (if given);
+ </li>
+ <li> if in <i>check mode</i>, it is <i>ignored</i>. Samhain will
+ abort if the connection to the server fails.
+ </li>
+ </ul>
+ Thus, the local path allows you to initialize the database from a local
+ configuration file before the client is known to the server.
+</li>
+<li>for the database file:
+ <ul>
+ <li> if <i>initializing</i>, the database is written to the local file;
+ </li>
+ <li> if in <i>check mode</i>, the local path is <i>ignored</i>. Samhain will
+ abort if the connection to the server fails.
+ </li>
+ </ul>
+ Thus, <i>init</i> (or <i>update</i>) always requires a local file that
+ must be uploaded to the server thereafter. <b>Note</b> that if you
+ use the <b>Beltane</b> web-based frontend, database updates can be performed
+ on the server without ever running an <i>update</i> on the client.
+</li>
+</ul>
+
+<h2>Establishing trust between client and server</h2>
+
+<p>
+By default, samhain uses the SRP (Secure Remote Password) protocol,
+with a password that is <i>embedded in the client binary</i>, and a
+corresponding verifier that is in the <i>server configuration file</i>.
+</p>
+
+<h3>Embedding the password in the client, and register it with the server</h3>
+
+<p>
+To embed the password in the binary, there is a dummy password compiled
+in as placeholder, and a utility <i>samhain_setpwd</i> is provided that
+</p>
+
+<ol>
+<li>
+ takes a password as input,
+</li>
+<li>
+ searches the original binary for the
+ correct place (i.e. the placeholder), and
+</li>
+<li>
+ writes a copy of the original binary, with the placeholder replaced
+ by the password. The original is left untouched. The copy cannot
+ be changed to another password anymore.
+</li>
+</ol>
+
+
+<p>
+For convenience, the server has functions to
+</p>
+
+<ul>
+<li>
+<p>
+generate a random password in the correct format:
+</p><p>
+<tt>&nbsp; &nbsp;sh$ yule -G</tt>
+</p>
+</li>
+<li>
+<p>
+and generate a corresponding entry for the
+server configuration file:
+</p><p>
+ <tt>&nbsp; &nbsp;sh$ yule -P PASSWORD</tt>.
+<p>
+</li>
+<li>
+The generated entry has a string <tt>'HOSTNAME'</tt> that you should
+replace with the fully qualified name of the client. This entry must
+then be placed in the <tt>[Clients]</tt> section of the yule configuration
+file (e.g. <tt>/etc/yulerc</tt>).
+</li>
+<li>
+Finally, you need to tell yule to reload the configuration (send SIGHUP,
+or use <tt>/etc/init.d/yule reload</tt>).
+</li>
+</ul>
+
+
+<h3>Example</h3>
+
+<pre style="background-color:#DDDDDD; color:#000000">
+
+rainer$ ./samhain_setpwd
+
+Usage: samhain_setpwd &lt;filename&gt; &lt;suffix&gt; &lt;new_password&gt;
+
+ This program is a utility that will:
+ - search in the binary executable &lt;filename&gt; for samhain's
+ compiled-in default password,
+ - change it to &lt;new_password&gt;,
+ - and output the modified binary to &lt;filename&gt;.&lt;suffix&gt;
+
+ To allow for non-printable chars, &lt;new_password&gt; must be
+ a 16-digit hexadecimal number (only 0-9,A-F allowed in input),
+ thus corresponding to an 8-byte password.
+
+ Example: 'samhain_setpwd samhain new 4142434445464748'
+ takes the file 'samhain', sets the password to 'ABCDEFGH'
+ ('A' = 41 hex, 'B' = 42 hex, ...) and outputs the result
+ to 'samhain.new'.
+
+rainer$ yule -G
+5B5CDF18CE8D66A3
+
+rainer$ ./samhain_setpwd samhain new 5B5CDF18CE8D66A3
+INFO old password found
+INFO replaced: f7c312aaaa12c3f7 by: 5b5cdf18ce8d66a3
+INFO finished
+
+rainer$ scp ./samhain.new root@client.example.com:/usr/local/sbin/samhain
+samhain 100% |********************************| 592 KB 00:00
+
+rainer$ yule -P 5B5CDF18CE8D66A3
+Client=HOSTNAME@8A542F99C3514499@744C3A3EE8323470D9DAD42E2485BD0B138F6B4116E964\
+A9991A0B0D221E1AADE5800968804B99B494C39E7B9DD5710D18F1E6703D1DB6D6393295E05DF6A\
+6AA8D10BB4A21D7D9DC4901D444500D4EA358C1B44A3E3D44ACEC645F938F790A11AB0D03586143\
+977E2BCE3A2D689445AC89134B409E68F34B0DE8BD8242ADD7C0
+
+rainer$ yule -P 5B5CDF18CE8D66A3 | sed s%HOSTNAME%client.example.com% &gt;&gt; /etc/yulerc
+
+rainer$ tail -2 /etc/yulerc
+[Clients]
+Client=client.example.com@8A542F99C3514499@744C3A3EE8323470D9DAD42E2485BD0B138F
+6B4116E964A9991A0B0D221E1AADE5800968804B99B494C39E7B9DD5710D18F1E6703D1DB6D6393
+295E05DF6A6AA8D10BB4A21D7D9DC4901D444500D4EA358C1B44A3E3D44ACEC645F938F790A11AB
+0D03586143977E2BCE3A2D689445AC89134B409E68F34B0DE8BD8242ADD7C0
+
+rainer$ /etc/init.d/yule reload
+
+</pre>
+
+<p>
+<b>Note 1:</b> the verifier <tt>Client=client.example.com@.....</tt> must be
+in the <b>[Clients]</b> section of the server configuration file. It is
+convenient if this is the last section in the config file, because then
+you can just concatenate the output of <tt>yule -P PASSWORD</tt> to the
+configuration file. This allows for better automatisation with a simple
+script.
+</p>
+<p>
+<b>Note 2:</b> samhain comes with a <b>deploy system</b> that handles
+the deployment of clients, including password embedding and server
+configuration, in a semi-automatic way.
+This deploy system is tested and used in a production system
+of more than 50 machines, and described in detail in Chapt. 10 of the MANUAL.
+</p>
+
+<h2>Enabling remote logging</h2>
+<p>
+Samhain has multiple independent logging facilities (such as a local logfile,
+syslog, e-mail, TCP/IP, etc.) that can be used
+in parallel. You therefore have to specify in the client's configuration
+file, <b>which logging facility</b> you want to use.
+</p>
+<p>
+Selecting logging facilities is done by setting appropriate <b>thresholds</b>
+in the <b>[Log]</b> section of the configuration file: each
+message with a <b>priority</b> exceeding
+the threshold will be logged via the respective facility. Setting
+the threshold to <i>none</i> will disable a facility. For details,
+refer to Chapt. 4 in the MANUAL.
+</p>
+<h3>Example</h3>
+<p>
+To enable remote logging to the server for all messages of
+priority <i>error</i> or higher, use the following directive in the
+client configuration file:
+</p>
+<pre style="background-color:#DDDDDD; color:#000000">
+
+[Log]
+ExportSeverity=err
+
+</pre>
+
+
+<h2>Databases and config files on the server</h2>
+
+<p>
+The client does <i>not</i> tell the server the path to the requested
+file - it just requests a config or a database file. It's entirely the
+responsibility of the server to locate the correct file and send it.
+</p>
+<p>
+The server has a <i>data directory</i>, which by default would be
+<tt>/var/lib/yule</tt>, but depends on your compile options.
+</p>
+<p>
+Config files and baseline databases for clients must be located
+in this directory, and they must be named as follows:
+</p>
+<p>
+Configuration files: <tt>rc.</tt><i>client.mydomain.tld</i> or
+simply <tt>rc</tt>
+(this can be used as a catchall file).
+</p>
+<p>
+Database files: <tt>file.</tt><i>client.mydomain.tld</i> or
+simply <tt>file</tt>
+(this can be used as a catchall file).
+</p>
+</div>
+</body>
+</html>
diff --git a/docs/HOWTO-samhain+GnuPG.html b/docs/HOWTO-samhain+GnuPG.html
new file mode 100644
index 0000000..013327f
--- /dev/null
+++ b/docs/HOWTO-samhain+GnuPG.html
@@ -0,0 +1,415 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>HOWTO samhain+GnuPG</title>
+<style type="text/css">
+<!--
+
+html { background: #eee; color: #000; }
+
+body { background: #eee; color: #000; margin: 0; padding: 0;}
+
+div.body {
+ background: #fff; color: #000;
+ margin: 0 1em 0 1em; padding: 1em;
+ font-family: serif;
+ font-size: 1em; line-height: 1.2em;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #aaa;
+}
+
+div.block {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #2d4488;
+}
+
+div.warnblock {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #FF9900;
+}
+
+table {
+ background: #F8F8F8; color: #000;
+ margin: 1em;
+ border-width: 0 0 0 1px;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+th {
+ background: #F8F8FF;
+ border-width: 1px 1px 2px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+
+/* body text, headings, and rules */
+
+p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #206020; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
+h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
+h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
+h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
+h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
+h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
+
+hr {
+ color: transparent; background: transparent;
+ height: 0px; margin: 0.6em 0;
+ border-width: 1px ;
+ border-style: solid;
+ border-color: #999;
+}
+
+/* bulleted lists and definition lists */
+
+ul { margin: 0 1em 0.6em 2em; padding: 0; }
+li { margin: 0.4em 0 0 0; }
+
+dl { margin: 0.6em 1em 0.6em 2em; }
+dt { color: #285577; }
+
+tt { color: #602020; }
+
+/* links */
+
+a.link {
+ color: #33c; background: transparent;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000; background: transparent;
+}
+
+body > a {
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-size: 0.81em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2d5588; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+ -->
+</style></head>
+
+<body>
+<div class="body">
+<p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a
+ style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/">samhain file integrity
+ scanner</a>&nbsp;|&nbsp;<a style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/s_documentation.html">online
+ documentation</a></p>
+<br><center>
+<h1>Using samhain with GnuPG</h1>
+</center>
+<br>
+<hr>
+<p>
+This document aims to explain how to use samhain with <b>signed configuration
+and database files</b> which are checked by invoking GnuPG.
+</p>
+<h2>Introduction</h2>
+<p>
+Samhain can be compiled to recognize PGP signatures on configuration and
+database files and to invoke GnuPG in order to check such signatures.
+(<b>Note:</b> while the application usually is referred to as <i>GnuPG</i>,
+the executable itself is called <i>gpg</i>).
+</p>
+<p>
+If samhain is compiled with this option, then
+</p>
+
+<ol>
+<li>
+both the <i>configuration file</i>
+and the <i>file signature database</i> must be signed, and
+</li>
+<li>
+for both files the signatures must verify correctly,
+</li>
+<li>
+otherwise samhain will abort.
+</li>
+</ol>
+
+
+<h2>Prerequisites</h2>
+<ul>
+<li>
+<p>
+Obviously you need <i>gpg</i> (GnuPG), and you must
+have created a key pair with:
+</p><p>
+<tt>&nbsp; &nbsp;gpg --gen-key</tt>
+</p><p>
+(it does not really matter which type of key, the defaults are ok).
+</p><p>
+GnuPG uses a public-key algorithm: the key pair consists of
+</p>
+<ul>
+<li>
+a <i>secret key</i> that is
+used for signing and stored in <b>&#126;user/.gnupg/secring.gpg</b>, and
+</li><li>
+a <i>public key</i> used for verifying the signature, and stored in
+<b>&#126;user/.gnupg/pubring.gpg</b>.
+</li>
+</ul>
+<p>
+The secret key obviously should be
+kept secret, while the public key can be published.
+</p>
+</li>
+<li>
+<p>
+You need to compile samhain with support for GnuPG:
+</p><p>
+<tt>&nbsp; &nbsp;./configure --with-gpg=/path/to/gpg [more options]</tt>
+</p><p>
+</li>
+</ul>
+
+<p>
+<b>Note 1:</b> If compiled with support for GnuPG,
+the TIGER192 checksum of the gpg
+executable will be compiled into samhain, and the gpg executable will
+be checksummed (to verify its integrity) before invoking it. If you
+don't like this, you should add the <i>configure</i> option:
+</p><p>
+<tt>&nbsp; &nbsp;--with-checksum=no</tt>
+</p>
+<div class="warnblock">
+<p>
+Compiling in the GnuPG checksum will tie the samhain executable to
+the gpg executable. If you upgrade GnuPG, you will need to re-compile
+samhain. If you don't like this, use <tt>'--with-checksum=no'</tt>.
+</p>
+</div>
+<p>
+<b>Note 2:</b> The mere fact that the signature
+is correct does not prove that it has been signed by <i>you</i> with
+<i>your</i> key - it just proves that it has been signed by <i>somebody</i>.
+Samhain can optionally check the <i>fingerprint</i> of the key that has been
+used to sign the files, to verify that <i>your</i> key has been used
+to sign the file(s). To enable this, use the <i>configure</i> option
+</p><p>
+<tt>&nbsp; &nbsp;--with-fingerprint=FINGERPRINT</tt>
+</p><p>
+where FINGERPRINT is the hexadecimal fingerprint of the key as listed
+with
+</p><p>
+<tt>&nbsp; &nbsp;gpg --fingerprint</tt>
+</p>
+
+<h3>Example</h3>
+
+<pre style="background-color:#DDDDDD; color:#000000">
+
+rainer$ gpg --fingerprint rainer
+pub 1024D/0F571F6C 1999-10-31 Rainer Wichmann
+ Key fingerprint = EF6C EF54 701A 0AFD B86A F4C3 1AAD 26C8 0F57 1F6C
+uid Rainer Wichmann
+sub 1024g/9DACAC30 1999-10-31
+
+rainer$ which gpg
+/usr/bin/gpg
+
+rainer$ ./configure --with-gpg=/usr/bin/gpg --with-fingerprint=EF6CEF54701A0AFDB86AF4C31AAD26C80F571F6C
+
+</pre>
+
+<h2>Signing the files</h2>
+<p>
+The <i>configuration file</i> and the
+<i>file signature database</i>
+(created by running <tt>samhain -t init</tt>) must be signed manually
+using the command:
+</p><p>
+<tt>&nbsp; &nbsp;gpg -a --clearsign --not-dash-escaped /etc/samhainrc</tt><br/>
+<tt>&nbsp; &nbsp;mv /etc/samhainrc.asc /etc/samhainrc</tt>
+</p><p>
+<i>Gpg</i> will create a <i>signed copy</i> of the file,
+named <i>file.asc</i>.
+You need to <b>rename</b> (<tt>cp/mv</tt>) this signed copy
+to the original filename.
+After signing the configuration file, you can initialize the database
+and sign it likewise.
+</p>
+<p>
+<b>Note 1:</b> The installation script will ask you to
+sign the <i>configuration file</i> upon installation.
+</p><p>
+<b>Note 2:</b> The <i>gpg</i> option <tt>--not-dash-escaped</tt>
+does not harm if used with the
+<i>configuration file</i>, but is only required for the
+<i>file signature database</i>.
+</p>
+
+<h3>TIP</h3>
+<p>
+ In the subdirectory <tt>scripts/</tt> of the source directory you will find
+ a Perl script <b>samhainadmin.pl</b> to facilitate some
+ tasks related to the administration of signed configuration and
+ database files (e.g. examine/create/remove signatures).
+ Use with <i>--help</i> to get usage
+ information.
+</p>
+
+<h3>CAVEAT</h3>
+<p>
+ When signing, the option <i>--not-dash-escaped</i> is
+ recommended, because otherwise the database might get corrupted.
+ However, this implies that after a database update,
+ you <i>must</i> remove the old signature first, before
+ re-signing the database. Without 'dash escaping',
+ gpg will not properly handle the old signature.
+ See the tip just above.
+</p>
+
+<h3>Example</h3>
+
+<pre style="background-color:#DDDDDD; color:#000000">
+
+root# gpg -a --clearsign --not-dash-escaped /etc/samhainrc
+
+You need a passphrase to unlock the secret key for
+user: "Rainer Wichmann"
+1024-bit DSA key, ID 0F571F6C, created 1999-10-31
+
+root# mv /etc/samhainrc.asc /etc/samhainrc
+root# samhain -t init
+root# gpg -a --clearsign --not-dash-escaped /var/lib/samhain/samhain_file
+
+You need a passphrase to unlock the secret key for
+user: "Rainer Wichmann"
+1024-bit DSA key, ID 0F571F6C, created 1999-10-31
+
+root# mv /var/lib/samhain/samhain_file.asc /var/lib/samhain/samhain_file
+root# samhain -D -t check
+
+</pre>
+
+<h2>Make samhain verify the signature</h2>
+<p>
+This is the part where some people run into problems. The point is,
+when <i>gpg</i> is invoked by samhain, it must <i>find the public key</i>
+needed for verification. <i>Gpg</i> expects public keys in a file
+located at <b>&#126;user/.gnupg/pubring.gpg</b> where <b>&#126;user</b>
+is the home directory of the user as that <i>gpg</i> is running.
+</p><p>
+It is therefore <i>crucial</i> to include the public key corresponding
+to te secret key used for signing into the correct <b>pubring.gpg</b>
+file (this file can hold many public keys, e.g. of people sending you
+emails signed by them).
+</p><p>
+So which is the correct file? Here we have to consider two seperate
+cases:
+</p>
+<ol>
+<li>The client (or standalone) samhain daemon runs with UID 0 (i.e. root),
+thus the public key must be in <b>&#126;root/.gnupg/pubring.gpg</b>
+</li>
+<li>
+The server (yule) <i>always</i> drops root privileges (if started with), and
+runs as a <i>non-root user</i>. The username to use is compiled in,
+either with the <i>configure</i> option <tt>--enable-identity=USER</tt>,
+or by default as determined by <i>configure</i> (the first existing user
+out of the list <i>yule, daemon, nobody</i>). Thus, the public key
+must be in <b>&#126;root/.gnupg/pubring.gpg</b> (for startup) <i>and</i>
+in <b>&#126;non_root_user/.gnupg/pubring.gpg</b> (for reload with SIGHUP).
+</li>
+</ol>
+<p>
+To import a public key into the public
+keyring (pubring.gpg) of another user, you can do:
+</p><p>
+<tt>&nbsp; &nbsp;gpg --export KEY-ID > filename</tt><br>
+<tt>&nbsp; &nbsp;su another_user</tt><br>
+<tt>&nbsp; &nbsp;gpg --import filename</tt>
+</p>
+<p>
+<b>Note:</b> samhain will invoke <i>gpg</i> with the options:
+</p><p>
+<tt>&nbsp; &nbsp;--status-fd 1 --verify --homedir /homedir/.gnupg --no-tty -</tt>
+</p><p>
+and pipe the configuration/database file into <i>gpg</i>, similar to:
+</p><p>
+<tt>cat filename | /usr/bin/gpg --status-fd 1 --verify --homedir /root/.gnupg --no-tty -</tt>
+</p><p>
+(of course samhain does not invoke cat, or the shell; the example above
+just shows how to do the same from the shell command prompt).
+</p>
+
+<h3>Example for signature check</h3>
+<p>
+If you want to check the signature the same way samhain does, it should look
+like (note the GOODSIG and VALIDSIG keywords in the output):
+</p>
+<pre style="background-color:#DDDDDD; color:#000000">
+
+root# cat /etc/samhainrc | gpg --status-fd 1 --verify --homedir /root/.gnupg --no-tty -
+gpg: Signature made Sat Mar 15 16:08:21 2003 CET using DSA key ID 0F571F6C
+[GNUPG:] SIG_ID 9hQvRhgjWLqyFzVOHi2b0uDmBFo 2003-03-15 1047740901
+[GNUPG:] GOODSIG 1AAD26C80F571F6C Rainer Wichmann
+gpg: Good signature from "Rainer Wichmann"
+gpg: aka "Rainer Wichmann"
+[GNUPG:] VALIDSIG EF6CEF54701A0AFDB86AF4C31AAD26C80F571F6C 2003-03-15 1047740901
+[GNUPG:] TRUST_ULTIMATE
+
+</pre>
+
+<h2>Troubleshooting</h2>
+<p>
+First and foremost, run samhain (or yule) from the command line, in non-daemon
+mode, and with the command-line option <tt>-p debug</tt> for debug-level
+output. This will print
+descriptive information on setup errors and/or relevant output from
+the GnuPG subprocess.
+</p>
+<p>
+Output from the GnuPG subprocess is marked by <b>[GNUPG:]</b>, and
+may show the following errors:
+</p>
+
+<ul>
+<li><b>ERRSIG</b> and/or <b>NO_PUBKEY</b> indicates that gpg did not find
+ the public key to verify the signature. You should import that key
+ into the keyrings of root and (for yule additionaly) the yule user.
+</li>
+<li><b>BADSIG</b> indicates that the public key was found by gpg, but
+ the signature is invalid. Either the file has been modified after
+ signing, or a previous signature has not been removed.
+</li>
+<li><b>NODATA</b> indicates that there is no signed data, i.e. the
+ configuration or database file is not signed at all.
+</li>
+</ul>
+</div>
+</body>
+</html>
diff --git a/docs/HOWTO-samhain-on-windows.html b/docs/HOWTO-samhain-on-windows.html
new file mode 100644
index 0000000..8bd039c
--- /dev/null
+++ b/docs/HOWTO-samhain-on-windows.html
@@ -0,0 +1,496 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>HOWTO Samhain on Windows</title>
+<style type="text/css">
+<!--
+
+html { background: #eee; color: #000; }
+
+body { background: #eee; color: #000; margin: 0; padding: 0;}
+
+div.body {
+ background: #fff; color: #000;
+ margin: 0 1em 0 1em; padding: 1em;
+ font-family: serif;
+ font-size: 1em; line-height: 1.2em;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #aaa;
+}
+
+div.block {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #2d4488;
+}
+
+div.warnblock {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #FF9900;
+}
+
+table {
+ background: #F8F8F8; color: #000;
+ margin: 1em;
+ border-width: 0 0 0 1px;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+th {
+ background: #F8F8FF;
+ border-width: 1px 1px 2px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+
+/* body text, headings, and rules */
+
+p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #206020; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
+h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
+h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
+h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
+h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
+h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
+
+hr {
+ color: transparent; background: transparent;
+ height: 0px; margin: 0.6em 0;
+ border-width: 1px ;
+ border-style: solid;
+ border-color: #999;
+}
+
+/* bulleted lists and definition lists */
+
+ul { margin: 0 1em 0.6em 2em; padding: 0; }
+li { margin: 0.4em 0 0 0; }
+
+dl { margin: 0.6em 1em 0.6em 2em; }
+dt { color: #285577; }
+
+tt { color: #602020; }
+
+/* links */
+
+a.link {
+ color: #33c; background: transparent;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000; background: transparent;
+}
+
+body > a {
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-size: 0.81em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2d5588; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+ -->
+</style></head>
+<body>
+<div class="body">
+<p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a
+ style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/">samhain file integrity
+ scanner</a>&nbsp;|&nbsp;<a style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/s_documentation.html">online
+ documentation</a></p>
+<br><center>
+<h1>Using Samhain on Windows</h1>
+</center>
+<br>
+<hr>
+<p>
+This document aims to explain how to compile and run
+samhain on Windows with the
+<b>Cygwin</b> POSIX emulation layer, and how to install it as a service.
+These instructions have been written by Kris Dom,
+who has tested this on WinXP Professional, with additions by Geries Handal
+and Jorge Morgado.
+</p>
+<div class="block">
+<h3>Interix / Services For UNIX</h3>
+<p>
+Samhain can also be used with Interix/SFU 3.5. Note that in Interix,
+the Windows
+filesystem is referred as <tt>/dev/fs/C</tt>, while in Cygwin it
+is <tt>/cygdrive/c</tt> (both refers to the <tt>C:</tt> drive; other drives
+are analogous).
+</p><p>
+Older versions of samhain would need to be built with
+<tt>./configure&nbsp;--disable-mail</tt> (i.e. without support for email
+logging) because Interix does not provide some of the required functionality
+to build the email module. This issue should be fixed as of samhain
+version 2.0.7 (not tested).<br />
+[Based on information kindly provided by Geries Handal].
+</p>
+</div>
+
+<h2>Cygwin installation procedure to compile samhain</h2>
+
+<h3>Cygwin download</h3>
+
+<ul>
+<li>
+Make a temporary directory to store cygwin installer (e.g. c:\temp\cygwin)
+</li>
+<li>
+Surf to <a href="http://www.cygwin.com">http://www.cygwin.com</a>
+to download cygwin
+</li>
+<li>
+Use the &quot;install or update now (using setup.exe)&quot; to
+download the installer in c:\temp\cygwin
+</li>
+<li>
+Execute &quot;setup.exe&quot; in c:\temp\cygwin
+</li>
+<li>
+Choose the &quot;download from the Internet&quot; option
+</li>
+<li>
+Choose &quot;c:\temp\cygwin&quot; as 'Local Package Directory'
+</li>
+<li>
+Choose an FTP site
+</li>
+<li>
+Click on 'Default' just after 'All' to change the installation type
+from 'Default' to 'Install'. This will most likely install way too much
+stuff but I am not familiar with Cygwin, so this way I know that all libs and
+compilers are installed.
+</li>
+<li>
+Let it download the stuff (there is a lot to download so be patient).
+</li>
+</ul>
+<div class="block">
+<p>
+You don't need to download and install All packages. It is enough to keep
+the Default and then add the following additional packages:
+</p>
+<p>
+ Category Devel -> gcc: C compiler upgrade helper<br/>
+ Category Devel -> make: The GNU version of the 'make' utility<br/>
+ Category Libs -> minires: A simple synchronous non caching stub resolver<br/>
+</p>
+<p>
+When selecting these packages, Cygwin installer will automatically add
+other packages based on their dependencies.
+The package minires is only necessary for a minimal Cygwin installation
+(below). [Kindly pointed out by Jorge Morgado].
+</p>
+</div>
+
+<h3>Cygwin installation</h3>
+
+<ul>
+<li>
+When the download is complete you have the Cygwin software in the
+temporary directory, however, it still needs to be installed.
+</li>
+<li>
+To install, execute the &quot;setup.exe&quot; in &quot;c:\temp\cygwin&quot;
+</li>
+<li>
+Choose the &quot;Install from local directory&quot; option.
+</li>
+<li>
+Choose &quot;C:\Cygwin&quot; as root directory (this will be the Unix '/')
+</li>
+<li>
+Choose the Local Package Directory: &quot;c:\temp\cygwin&quot;
+</li>
+<li>
+Click on 'Default' just after 'All' to change the installation type
+from 'Default' to 'Install'.
+</li>
+<li>
+Let it install Cygwin (this will take some time so be patient).
+</li>
+</ul>
+
+<h3>Samhain install procedure (used 'samhain 1.8.7a' in this procedure)</h3>
+<p>
+(in the following procedure I use my personal preferences)
+</p>
+
+<ul>
+<li>
+Start up Cygwin using the &quot;Cygwin&quot; icon on the desktop (a classic
+Unix environment will be started).
+</li>
+<li>
+Download the 'samhain' gzip/tar (I always put in my home directory)
+</li>
+<li>
+Make directories to install samhain (taking into account the configure
+options):<br />
+&nbsp; &nbsp;<tt>$ mkdir /usr/local/sbin</tt><br />
+&nbsp; &nbsp;<tt>$ mkdir /usr/local/var</tt><br />
+&nbsp; &nbsp;<tt>$ mkdir /usr/local/log</tt><br />
+&nbsp; &nbsp;<tt>$ mkdir /usr/local/tmp</tt><br />
+</li>
+<li>Go to the home directory:<br />
+&nbsp; &nbsp;<tt>$ cd $HOME</tt>
+</li>
+<li>Un-gzip and untar the samhain package:<br />
+&nbsp; &nbsp;<tt>$ gunzip samhain-1.8.7a.tar.gz</tt><br />
+&nbsp; &nbsp;<tt>$ tar xvf samhain-1.8.7a.tar</tt><br />
+</li>
+<li>Go to the samhain directory:<br />
+&nbsp; &nbsp;<tt>$ cd samhain-1.8.7a</tt><br />
+</li>
+<li>Configure:<br />
+&nbsp; &nbsp;<tt>$ ./configure --enable-xml-log=yes --with-tmp-dir=/usr/local/tmp --with-config-file=/usr/local/etc/samhainrc --with-log-file=/usr/local/log/samhain.log --with-pid-file=/usr/local/var/samhain.pid --with-state-dir=/usr/local/var</tt><br />
+<div class="block">
+<p>
+In my experience, the paths given in the 'configure' command should refer to
+the Cygwin filesystem view, i.e. <tt>/cygdrive/c/...</tt>, otherwise
+samhain may not work from a pure DOS shell, and may not run as a Windows
+service [Rainer Wichmann].
+</p>
+</div>
+</li>
+<li>Make the binary:<br />
+&nbsp; &nbsp;<tt>$ make</tt><br />
+</li>
+<li>Install samhain:<br />
+&nbsp; &nbsp;<tt>$ make install</tt><br />
+</li>
+<li>Now configure the &quot;/usr/local/etc/samhainrc&quot; file.<br />
+Remember: &quot;C:\&quot; -&gt; &quot;/cygdrive/c/&quot;
+</li>
+<li>Initialize the samhain local baseline database:<br />
+&nbsp; &nbsp;<tt>$ /usr/local/sbin/samhain -t init</tt><br />
+</li>
+<li>Start it up:<br />
+&nbsp; &nbsp;<tt>$ /usr/local/sbin/samhain -t check</tt><br />
+</li>
+</ul>
+
+
+<h2>Cygwin minimal installation procedure to run samhain</h2>
+
+<ul>
+<li>
+Files needed to create a service (from NT/W2K Resource Kit):
+ <ul>
+ <li>
+ instsrv.exe
+ </li>
+ <li>
+ srvany.exe
+ </li>
+ </ul>
+</li>
+<li>
+First copy these files to the &quot;%winnt%\system32&quot; directory.
+</li>
+<li>
+Files needed to run the 'samhain.exe'. Copy the following .dll from the
+Cygwin setup (c:\Cygwin\bin) to the &quot;%winnt%\system32&quot; directory:
+ <ul>
+ <li>
+ cygwin1.dll
+ </li>
+ <li>
+ cygminires.dll
+ </li>
+ </ul>
+</li>
+<li>
+Files needed from c:\Cygwin\bin to create the /etc/passwd and /etc/group files:
+ <ul>
+ <li>
+ mkpasswd.exe
+ </li>
+ <li>
+ mkgroup.exe
+ </li>
+ </ul>
+<p>
+To generate these files on a minimal Cygwin installation execute - on a
+Windows Command Prompt:
+</p><p>
+&nbsp; &nbsp;<tt>mkdir c:\etc</tt><br />
+&nbsp; &nbsp;<tt>path\to\mkpasswd.exe -l > c:\etc\passwd</tt><br />
+&nbsp; &nbsp;<tt>path\to\mkgroup.exe -l > c:\etc\group</tt>
+</p><p>
+IMPORTANT NOTE: You should re-create these two files, each time the
+Windows users and groups accounts database changes. Failing to do this
+might generate critical log messages (depending on your configuration
+file).
+</p>
+</li>
+<li>
+Create a directory structure for samhain (following the compilation options
+you used)<br />
+&nbsp; &nbsp;- in a DOS box (or via Windows Explorer)<br />
+&nbsp; &nbsp;<tt>mkdir c:\usr</tt><br />
+&nbsp; &nbsp;<tt>mkdir c:\usr\local</tt><br />
+&nbsp; &nbsp;<tt>mkdir c:\usr\local\sbin</tt><br />
+&nbsp; &nbsp;<tt>mkdir c:\usr\local\var</tt><br />
+&nbsp; &nbsp;<tt>mkdir c:\usr\local\tmp</tt><br />
+&nbsp; &nbsp;<tt>mkdir c:\usr\local\log</tt><br />
+&nbsp; &nbsp;<tt>mkdir c:\usr\local\etc</tt><br />
+</li>
+<li>
+Use the &quot;instsrv.exe&quot; binary to create a new service:<br />
+&nbsp; &nbsp;<tt>instsrv.exe samhain c:\windows\system32\srvany.exe</tt><br />
+&nbsp; &nbsp;(this will create a service called &quot;Samhain&quot; that will
+start the &quot;srvany.exe&quot; process).
+</li>
+<li>Now edit the registry to change the startup parameters for the newly
+created service:
+ <ul>
+ <li>regedit</li>
+ <li>HKEY_LOCAL_MACHINE-&gt;SYSTEM-&gt;CurrentControlSet-&gt;Services-&gt;Samhain</li>
+ <li>Add a String value (type: REG_SZ called: &quot;Description&quot;) under the 'Samhain' key</li>
+ <li>Open the newly created &quot;Description&quot; value and fill in a description for the 'Samhain' service</li>
+ <li>Add a key to specify what file the &quot;srvany.exe&quot; process must start:<br />
+ &nbsp; &nbsp;Edit-&gt;New-&gt;Key called &quot;Parameters&quot;
+ </li>
+ <li>Under the newly created &quot;Parameters&quot; key, add a new String
+ value called &quot;Application&quot;.<br />
+ &nbsp; &nbsp;The value for &quot;Application&quot;
+ should be &quot;c:\usr\local\sbin\samhain.exe&quot;.</li>
+ </ul>
+</li>
+<li>
+Make sure that in the &quot;samhainrc&quot; file, you have used
+&quot;/cygdrive/c&quot; to refer to &quot;c:&quot;
+</li>
+<li>
+Initialize the samhain baseline database first:<br />
+&nbsp; &nbsp;<tt>c:\usr\local\sbin\samhain -t init</tt><br />
+</li>
+<li>
+Reboot (it is Windows so ...)
+</li>
+</ul>
+<div class="block">
+<p>
+It seems that start/stop/restart the service does not work if samhain
+is configured to run as a daemon, because the Windows service manager
+cannot track the forked daemon process.
+</p>
+<p>Therefore, if you run Samhain as a Windows service, it might be better
+to configure it as a 'normal' process which does not fork a daemon:
+<ul>
+ <li>
+ Set 'Daemon = no' in the samhainrc configuration file.
+ </li>
+ <li>
+ Edit the key HKEY_LOCAL_MACHINE-&gt;SYSTEM-&gt;CurrentControlSet-&gt;Services-&gt;Samhain->Parameters to add a string value named 'AppParameters', with
+ the value '--forever'.
+ </li>
+</ul>
+[Rainer Wichmann].
+</p>
+</div>
+<p>
+Also see <a href="http://support.microsoft.com/kb/q137890/">http://support.microsoft.com/kb/q137890/</a> for information regarding the creation of a
+user-defined service.
+</p>
+<p>
+Note: the first time I tried to install samhain as an NT service, I first
+installed a default Cygwin on the system. This however made things much more
+complex. I think when there is no Cygwin installed, it is more easy to install
+Samhain as a service.
+</p>
+
+
+<h2>Troubleshooting samhain</h2>
+
+<p>
+[Rainer Wichmann] I had some problems at first getting it to run as a
+Windows service. Some tips:
+<ul>
+ <li>
+ Running samhain from a pure DOS shell (outside the Cygwin environment)
+ helps to identify problems, in particular if it refuses to start
+ as a Windows service.
+ </li>
+ <li>
+ I found it neccessary to put the <tt>cygwin1.dll</tt> DLL into the
+ same directory as the <tt>samhain.exe</tt> executable. Also, you
+ can use the command <tt>ldd ./samhain.exe</tt> to identify further
+ Cygwin-specific DLL that may be required (if any).
+ </li>
+ <li>
+ Also, I found it neccessary to use Cygwin-style paths
+ (<tt>/cygdrive/c/...</tt>) in the './configure ..' command when
+ compiling samhain.
+ </li>
+</ul>
+</p>
+
+<p>
+[Tip from Jorge Morgado] If you, like me, have a Windows server not part of any domain and (for
+security reasons) you even turn off DNS resolution, you might probably get
+the following error when initializing the baseline database:
+</p>
+<pre>
+ --------- sh_unix.c --- 1487 ---------
+ According to uname, your nodename is yourcomputername, but your resolver
+ library cannot resolve this nodename to a FQDN.
+ Rather, it resolves this to yourcomputername.
+ For more information, see the entry about self-resolving under
+ 'Most frequently' in the FAQ that you will find in the docs/ subdirectory
+ ----------------------------------------------
+</pre>
+<p>
+To fix this problem open the Registry Editor and create the following
+entries under the key
+HKLM\System\CurrentControlSet\Services\Tcpip\Parameters
+</p>
+<p>
+<tt>
+Name: Domain<br/>
+Type: REG_SZ<br/>
+Data: your.domain.name
+</tt>
+</p><p>
+<tt>
+Name: NV Domain<br/>
+Type: REG_SZ<br/>
+Data: your.domain.name
+</tt>
+</p><p>
+The NV Domain registry value contains the computer's primary DNS suffix
+while the Domain registry value contains the computer's primary DNS
+domain. This will make the warning message go away.
+</p>
+</div>
+</body>
+</html>
diff --git a/docs/HOWTO-write-modules.html b/docs/HOWTO-write-modules.html
new file mode 100644
index 0000000..a2ace92
--- /dev/null
+++ b/docs/HOWTO-write-modules.html
@@ -0,0 +1,771 @@
+<html>
+<head>
+<title>HOWTO Write Samhain Modules</title>
+<style type="text/css">
+<!--
+
+html { background: #eee; color: #000; }
+
+body { background: #eee; color: #000; margin: 0; padding: 0;}
+
+div.body {
+ background: #fff; color: #000;
+ margin: 0 1em 0 1em; padding: 1em;
+ font-family: serif;
+ font-size: 1em; line-height: 1.2em;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #aaa;
+}
+
+div.block {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #2d4488;
+}
+
+div.warnblock {
+ background: #b6c5f2; color: #000;
+ margin: 1em; padding: 0 1em 0 1em;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #FF9900;
+}
+
+table {
+ background: #F8F8F8; color: #000;
+ margin: 1em;
+ border-width: 0 0 0 1px;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+td {
+ border-width: 0 1px 1px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+th {
+ background: #F8F8FF;
+ border-width: 1px 1px 2px 0;
+ border-style: solid;
+ border-color: #C0C0C0;
+}
+
+
+/* body text, headings, and rules */
+
+p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
+
+h1, h2, h3, h4, h5, h6 {
+ color: #206020; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
+h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
+h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
+h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
+h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
+h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
+
+hr {
+ color: transparent; background: transparent;
+ height: 0px; margin: 0.6em 0;
+ border-width: 1px ;
+ border-style: solid;
+ border-color: #999;
+}
+
+/* bulleted lists and definition lists */
+
+ul { margin: 0 1em 0.6em 2em; padding: 0; }
+li { margin: 0.4em 0 0 0; }
+
+dl { margin: 0.6em 1em 0.6em 2em; }
+dt { color: #285577; }
+
+tt { color: #602020; }
+
+/* links */
+
+a.link {
+ color: #33c; background: transparent;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #000; background: transparent;
+}
+
+body > a {
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-size: 0.81em;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #2d5588; background: transparent;
+ font-family: Optima, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+}
+
+ -->
+</style></head>
+
+<body>
+<div class="body">
+<p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a
+ style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/">samhain file integrity
+ scanner</a>&nbsp;|&nbsp;<a style="text-decoration: none;"
+ href="http://www.la-samhna.de/samhain/s_documentation.html">online
+ documentation</a></p>
+<br><center>
+<h1>Writing modules for samhain</h1>
+</center>
+<br>
+<hr>
+<p>
+This document should help anyone who is sitting down to write a module
+for the samhain host intrusion detection system. We give an overview
+of samhain's structure from the point of view of the module author,
+and describe some of the samhain utility and interface functions
+available. Lastly, we explain how to integrate your module into the
+samhain autoconf build tools.
+</p>
+<h2>Introduction</h2>
+<p>
+Samhain is a rather useful file integrity and host intrusion detection
+system. It is written entirely in C, and much care has been given to
+making it robust and secure. Additionally, it has been written with
+extensibility in mind, and so interfaces for adding user-contributed
+modules have been provided. A module author can easily extend the
+configuration file syntax and have his checking code run on a regular
+basis as one of samhain's internal checks.
+</p>
+
+<h2>Prerequisites</h2>
+<p>
+You'll need to know how to read and write C. You'll need the latest
+source for samhain. You'll need to have read all of samhain's other
+documentation. Finally, if you want to make your module build as part
+of the samhain tree (you do), you'll need GNU's autoconf package.
+</p>
+<h2>An overview of samhain's execution</h2>
+<p>
+Here's what happens when samhain starts:
+<ul>
+ <li>
+ Check if samhain has been called with one of the "init.d" type
+ commands - start, stop, reload, status. If so, these are handled
+ as you might expect. Nice feature.
+ </li>
+ <li>
+ Initialise all global structures and parse command-line options.
+ </li>
+ <li>
+ Read the configuration file. This is handled in sh_readconf_read().
+ This includes attempting to download the file if samhain has been
+ compiled to do so.
+ </li>
+ <li>
+ Drop privileges if server.
+ </li>
+ <li>
+ Test the checksum on the database if client or standalone.
+ </li>
+ <li>
+ Now test if samhain has been compiled as a client or a server.
+ <ul>
+ <li>
+ If server, enter server main loop sh_receive() in
+ sh_forward.c. This is simple enough; apart from checks for
+ signals received, the server just accepts incoming
+ connections, verifies that they are from an authorised
+ client, and logs the message received.
+ </li>
+ <li>
+ If client or standalone, we run the rest of main() in
+ samhain.c, which follows:
+ </li>
+ </ul>
+ </li>
+ <li>
+ Initialise modules - that is, call the mod_init() function on each
+ module. Note that if the module intialisation routine returns a
+ nonzero value, you should also have it free anything that's been
+ allocated by the configuration file reading functions, since this
+ method is always called after an sh_readconf_read(), i.e. when the
+ configuration file is re-read after a SIGHUP.
+ </li>
+ <li>
+ Test the setup that's been read from the configuration - for example,
+ check if any files or directories have been defined twice.
+ </li>
+ <li>
+ Enter the main loop (which runs just once if samhain is not
+ configured as a daemon). Test if any signals have been received,
+ and handle them appropriately:
+ <ul>
+ <li>
+ On reconfiguration (SIGHUP), clear internal file lists etc.
+ and call the mod_reconf() function on each module. This should
+ clean up anything internal to the module before the
+ configuration file is re-read. Then read the configuration
+ file again and set things up as before, including a new call
+ to mod_init().
+ </li>
+ <li>
+ On SIGIOT (SIGABRT), shut down the log-file for a moment
+ to allow for rotation.
+ </li>
+ <li>
+ On SIGQUIT, terminate. Note that any call to exit() will
+ invoke the exit_handler() defined in samhain.c; the first
+ thing this does is to call mod_cleanup() on all modules.
+ Then it cleans up everything else in samhain and exits.
+ </li>
+ <li>
+ On SIGUSR1 turn toggle debugging on/off.
+ </li>
+ <li>
+ On SIGUSR2 suspend the daemon an notify the server to
+ allow a second instance of samhain downloading its
+ configuration file without triggering an alert (restart
+ without exit) on the server.
+ </li>
+ </ul>
+ </li>
+ <li>
+ If it's time to check files, check directories and then files, and
+ then flush the mail queue.
+ </li>
+ <li>
+ Execute modules. For each module, if mod_timer(tcurrent) returns a
+ nonzero value, then execute mod_check().
+ </li>
+ <li>
+ Do various maintenance operations such as logging a timestamp/sending
+ some mail if it's time, seeding/re-seeding the PRNG, etc.
+ </li>
+</ul>
+You'll note that in the text above I refer to a couple of module
+functions - mod_init(), mod_check(), etc. These are function pointers
+that act as hooks for attaching modules to samhain. Next we'll
+describe how they are used.
+</p>
+
+<h2>Samhain's module interface</h2>
+<p>
+Here we'll describe the interface samhain provides to module authors.
+</p>
+
+<h3>The module list</h3>
+<p>
+In sh_modules.h, the following structure is defined:
+</p>
+<pre>
+
+typedef struct mod_type
+{
+ /* The name of the module */
+ char * name;
+
+ /* Set by samhain to 1 on successful initialization, else 0 */
+ int initval;
+
+ /* The initialization function. Return 0 on success. */
+ int (* mod_init) (void);
+
+ /* The timer function. Return 0 if NOT time to check. */
+ int (* mod_timer) (unsigned long tcurrent);
+
+ /* The check function. Return 0 on success. */
+ int (* mod_check) (void);
+
+ /* The cleanup function. Return 0 on success. */
+ int (* mod_cleanup) (void);
+
+ /* The preparation for reconfiguration. Return 0 on success. */
+ int (* mod_reconf) (void);
+
+ /* Section header in config file */
+ char * conf_section;
+
+ /* A table of key/handler_function for config file entries */
+ sh_rconf * conf_table;
+
+} sh_mtype;
+</pre>
+
+<p>
+This is the structure used to hook modules into samhain. There is a
+list of these structures (modList), defined in sh_modules.c,
+containing pointers to the functions to be used for each module
+compiled into samhain. For example,
+</p>
+
+<pre>
+
+sh_mtype modList[] = {
+#ifdef SH_USE_UTMP
+ {
+ N_("UTMP"),
+ 0,
+ sh_utmp_init,
+ sh_utmp_timer,
+ sh_utmp_check,
+ sh_utmp_end,
+ sh_utmp_null,
+
+ N_("[Utmp]"),
+ sh_utmp_table,
+ },
+#endif
+</pre>
+<p>
+is the beginning of that table. The author of the sh_utmp module has
+initialised the structure with the name of the module (note that N_()
+is just a macro used to delimit strings here), a 0 to signify that the
+module has not yet been initialised, and then pointers to _init(),
+_timer(), _check(), _cleanup() and _reconf() functions for the
+module. Finally, the last two structure elements are for configuration
+file parsing: the first is the section heading in the configuration
+file for this module, and the second is a table of type
+</p>
+
+<pre>
+
+typedef struct rconf
+{
+ char * the_opt;
+ int (*func)(char * opt);
+} sh_rconf;
+</pre>
+
+<p>
+(also defined in sh_modules.h). This structure is for storing options
+for this module to be found in the configuration file, as well as the
+functions that will be used to parse them when found. In the sh_utmp
+example above, we can see that this table has been set to
+sh_utmp_table - this is a reference to a list of the Utmp module's
+configuration options declared in sh_utmp.h. It should be clear now
+that one of the changes you will need to make to samhain's source
+files is to include your header file in sh_modules.c and add a modList
+entry like the above.
+</p>
+
+<p>
+For a description of when during samhain's execution these various
+module hooks are called, see the overview above. It would likely be
+helpful to you now to read through the source for one of the modules
+provided with samhain and see the above actually implemented. You
+should also be able to use one of these modules as a template for your
+own.
+</p>
+
+<h3>The message catalogue</h3>
+
+<p>
+Most module authors will want to log messages in their own specified
+format; samhain stores all of its message formats in a "messages
+catalogue" found in sh_cat.h and sh_cat.c. For example, for the
+sh_suidchk module we find the following entries in sh_cat.h, as part
+of an enum:
+</p>
+
+<pre>
+
+#ifdef SH_USE_SUIDCHK
+ MSG_SUID_POLICY,
+ MSG_SUID_FOUND,
+ MSG_SUID_STAT,
+ MSG_SUID_SUMMARY,
+#endif
+</pre>
+
+<p>
+Correspondingly in sh_cat.c we find
+</p>
+
+<pre>
+
+#ifdef SH_USE_SUIDCHK
+ { MSG_SUID_POLICY, SH_ERR_SEVERE, RUN, N_("msg=\"POLICY SUIDCHK %s\" path=\"%s\"") },
+ { MSG_SUID_FOUND, SH_ERR_INFO, RUN, N_("msg=\"Found suid/sgid file\" path=\"%s\"") },
+ { MSG_SUID_STAT, SH_ERR_ERR, ERR, N_("msg=\"stat: %s\" path=\"%s\"") },
+ { MSG_SUID_SUMMARY,SH_ERR_INFO, RUN, N_("msg=\"Checked for SUID programs: %ld files, %ld seconds\"") },
+#endif
+</pre>
+<p>
+as part of the table msg_cat[] of type cat_entry:
+</p>
+<pre>
+
+typedef struct foo_cat_entry {
+ unsigned long id;
+ unsigned long priority;
+ unsigned long class;
+ char * format;
+} cat_entry;
+</pre>
+<p>
+The first member of this structure is the message type's ID, as
+defined in the enum in sh_cat.h. The second is the default priority of
+such messages, defined as in the samhain documentation. The third is
+the class of the message, again defined as in the samhain
+documentation. Finally we have the message format itself, which is a
+printf() style format string.
+</p>
+<p>
+This catalogue is used by the logging functions in samhain; you will
+need to add your own message types and formats to sh_cat.h and
+sh_cat.c. Note that because samhain can be compiled for XML style
+logging, you will actually need to make two entries in sh_cat.c for
+each message; see the file itself for details.
+</p>
+<p>
+Note that there is a generic message format with the ID 'MSG_E_SUBGEN'
+and the default priority 'SH_ERR_ERR'. If you are using this message
+format, then you can log (a) a string, and (b) the name of the subroutine.
+</p>
+<p>
+This completes our description of samhain's module interface.
+</p>
+
+<h2>Samhain's utility functions</h2>
+<p>
+Here we'll describe the main utility functions available to samhain module
+authors.
+</p>
+
+<h3>String wrapping macros</h3>
+
+<p>
+Constant strings should be wrapped in the _(string) macro. Initialisation
+strings that cannot be replaced with a function should be wrapped
+in a N_(string) macro, and the variable thus initialized should be
+wrapped in a _(var) macro whereever used. This is important for the
+'stealth' functionality of samhain.
+</p>
+
+<h3>Logging messages</h3>
+
+<pre>
+#include "sh_error.h"
+
+void sh_error_handle(int severity, char * file, long line, long status,
+ unsigned long msg_id, ...)
+</pre>
+<p>
+This is samhain's logging/reporting function, so the name is a little
+misleading - errors are not the only thing we should handle with
+this. The first four arguments are simple enough: severity is the
+logging severity, defined in the enum ShErrLevel from sh_error.h; file
+and line are the current file and line - usually you'll be using FIL__
+and __LINE__ for these; status is not very important - for module
+authors it'll do to always pass 0 to this. The final named argument is
+msg_id, which should be one of the message IDs defined in sh_cat.h;
+these correspond to message format strings in printf() format, which
+will be interpolated with the following arguments to form the log
+message.
+</p>
+<p>
+The '__LINE__' macro is provided by the C preprocessor. The FIL__ macro
+should be #defined to '_("sourcefile_name")' (see 'String wrapping macros'
+above).
+<p>
+Example of use:
+</p>
+<pre>
+#undef
+#define FIL__ _("sh_mounts.c")
+
+sh_error_handle(ShMountsSevMnt, FIL__, __LINE__, 0, MSG_MNT_MNTMISS,
+ cfgmnt->path);
+</pre>
+<p>
+See cat.c for the definition of MSG_MNT_MNTMISS:
+</p>
+<pre>
+
+{ MSG_MNT_MNTMISS, SH_ERR_WARN, RUN, N_("msg=\"Mount missing\" path=\"%s\"")},
+</pre>
+<p>
+So we print this out at severity ShMountsSevMnt, which in this case is
+a configured value read from the samhain configuration file (see
+sh_mounts.c). If we wanted to print it at the default severity
+(SH_ERR_WARN), we could pass -1 as the severity.
+</p>
+
+<h3>Checking files for modification</h3>
+
+<pre>
+#include "sh_files.h"
+
+int sh_files_pushdir_?? (char * dirName);
+int sh_files_pushfile_?? (char * fileName);
+</pre>
+<p>
+These functions push directories and files onto the stack of those to check
+for the specified policy (see the samhain documentation for further
+information):
+<table>
+ <tr><td> sh_files_pushdir_user0 </td><td>pushes the directory at USER0 </td></tr>
+ <tr><td align=right> ... _user1</td><td align=right>USER1</td></tr>
+ <tr><td align=right> ... _attr</td><td align=right>ATTR</td></tr>
+ <tr><td align=right> ... _ro</td><td align=right>READONLY</td></tr>
+ <tr><td align=right> ... _log</td><td align=right>LOGFILE</td></tr>
+ <tr><td align=right> ... _glog</td><td align=right>GROWING LOGFILE</td></tr>
+ <tr><td align=right> ... _noig</td><td align=right>IGNORE NONE</td></tr>
+ <tr><td align=right> ... _allig</td><td align=right>IGNORE ALL</td></tr>
+</table>
+So if you're writing a module that adds particular files to check, like the
+sh_userfiles module for example, these are the functions to use.
+</p>
+
+<h3>Managing memory</h3>
+
+<pre>
+#include "sh_mem.h"
+
+#define SH_FREE(a) ...
+#define SH_ALLOC(a) ...
+</pre>
+<p>
+These are the macros to use when you're allocating/freeing memory in
+samhain. They do all the error checking/reporting you need, so when
+you get memory from SH_ALLOC you can just get to using it right away.
+</p>
+
+<h3>Parsing strings</h3>
+
+<pre>
+#include "sh_utils.h"
+
+char * sh_util_strdup (const char * str);
+char * sh_util_strsep (char **str, const char *delim);
+char * sh_util_strconcat (const char * arg1, ...);
+
+int sh_util_flagval(char * c, int * fval);
+int sh_util_isnum (char *str);
+
+#include "slib.h"
+
+int sl_strlcpy (char * dst, const char * src, size_t siz);
+int sl_strlcat (char * dst, const char * src, size_t siz);
+int sl_snprintf(char *str, size_t n, const char *format, ... );
+</pre>
+<p>
+These functions are the samhain internal functions for string
+handling. The first three act like their C library counterparts,
+except using samhain's memory management functions and error
+checking. sh_util_flagval converts the passed string into a truth
+value - the value is stored in <b>fval</b> as 1 or 0 - and returns 0
+on success, -1 on failure. sh_util_isnum just checks if the passed
+string is all numeric.
+</p>
+<p>
+The functions sl_strlcpy and sl_strlcat work similar to the C library
+strncpy/strncat functions, except that the destination string is always
+null terminated, and the third argument must be the full length of the
+destination buffer, <i>not</i> the remaining space. On success, the
+return value is 0.
+</p>
+<p>
+The function sl_snprintf provides either the system snprintf, or a replacement,
+if the system has no or a buggy snprintf.
+</p>
+
+<h3>Tracing execution</h3>
+
+<pre>
+#include "slib.h"
+
+#define SL_ENTER(s) ...
+#define SL_RETURN(retval, s) ...
+</pre>
+<p>
+These macros are for tracing execution through samhain functions. You
+should use SL_ENTER with the name of the function for each function
+entered, and SL_RETURN with the return value and the name of the
+function for each exit if you want to maintain compatibility with the
+rest of samhain.
+</p>
+
+<h3>Executing external programs (popen)</h3>
+
+<pre>
+#include "sh_extern.h"
+
+
+sh_tas_t task;
+/* Prepare task */
+sh_ext_tas_init(&task);
+sh_ext_tas_command(&task, char * command);
+sh_ext_tas_add_argv(&task, char * val);
+sh_ext_tas_add_envv (&task, char * environment_variable, char * value);
+
+int sh_ext_popen(&task);
+int sh_ext_pclose(&task);
+</pre>
+<p>
+To prepare a task to run, use 'sh_ext_tas_init' to initialise the task
+structure. With 'sh_ext_tas_command' the command (absolute path) is set,
+with 'sh_ext_tas_add_argv' command line options are added. Environment
+variables can be set with 'sh_ext_tas_add_envv'.
+</p>
+<p>
+To open for read, set &quot;task.rw = 'r';&quot;, to open for write
+use &quot;task.rw = 'w';&quot;.
+</p>
+<p>
+To run the task with privileges dropped to another UID, set
+&quot;task.privileged = 0;&quot; and task.run_user_uid, task.run_user_gid
+to the desired UID/GID.
+</p>
+<p>
+To verify the checksum of the called executable, set
+task.checksum[KEY_LEN+1] to the TIGER192 checksum of the executable.
+</p>
+<p>
+After successful execution of sh_ext_popen (return status 0),
+task.pipe is the stream opened for read or write, and task.pipeFD
+its associated file descriptor.
+</p>
+
+<h3>Inserting arbitrary data into the baseline database</h3>
+<pre>
+
+#include "sh_hash.c"
+
+void sh_hash_push2db (char * key, unsigned long val1,
+ unsigned long val2, unsigned long val3,
+ unsigned char * str, int size);
+
+char * sh_hash_db2pop (char * key, unsigned long * val1,
+ unsigned long * val2, unsigned long * val3,
+ int * size);
+</pre>
+<p>
+The baseline database has a fixed record format. To enter data, these need
+to be prepared in the required format. To retrieve the data, the
+'filepath' is used as key (if your data is not a file, you would provide
+a dummy pathname as key). For convenience, the two functions noted below
+are provided.
+</p>
+<p>
+When checking files, samhain will walk the database to find files that
+are in the database, but have been deleted from the disk. If you enter
+data, you need to mark it as such by using a key that
+starts with something else but '/', otherwise samhain will complain
+if it has not been checked during the file check.
+</p>
+<pre>
+
+#include "sh_hash.c"
+
+void sh_hash_push2db (char * key, unsigned long val1,
+ unsigned long val2, unsigned long val3,
+ unsigned char * str, int size);
+
+char * sh_hash_db2pop (char * key, unsigned long * val1,
+ unsigned long * val2, unsigned long * val3,
+ int * size);
+</pre>
+<p>
+To insert data, use 'sh_hash_push2db'. You can insert up to three long
+integers (val1, val2, val3) and/or a binary string of length size
+(max. (PATH_MAX-1)/2). As noted
+above, you need to supply a key (stored as the 'filepath', which should
+start with a character different from '/'). To retrieve data, you can use
+'sh_hash_db2pop'. The return value is either NULL (if no string was
+stored under this key), or the stored string (length returned in 'size').
+</p>
+<p>
+A string to store may consist of any characters, including NULLs, and
+need not be NULL terminated. The returned string is
+always NULL terminated (the terminating NULL is not included in 'size'),
+and should be freed with SH_FREE() if not required anymore.
+</p>
+<p>
+If the key is not found in the database, <b>size</b> is set to -1.
+</p>
+
+<h2>Incorporating modules into the samhain build</h2>
+<p>
+This is a somewhat secondary but important part of writing a module
+for samhain:
+how to incorporate it into the samhain configuration and build process.
+This just involves hacking the autoconf and makefile setup to include your
+module. We'll present this file-by-file.
+</p>
+<h3>Makefile.in</h3>
+<p>
+You need to add a few bits to this file. First, add your header,
+source and object filenames to the HEADERS, SOURCES and OBJECTS
+variables. Then add your header to the dependencies for sh_modules.o
+and ./sh_modules.o. Finally add dependency lines for your module
+object file sh_whatever.o and ./sh_whatever.o, modelling them on the
+other module object dependency lines.
+</p>
+<h3>acconfig.h</h3>
+<p>
+The config.h.in will be generated from this file by 'autoheader'.
+You just need to add a line like
+<pre>
+#undef SH_USE_MOUNTS
+</pre>
+that will be defined by the ./configure code if the user specifies
+the module as enabled.
+</p>
+<h3>aclocal.m4</h3>
+<p>
+This file is used by 'autoconf' to help generate ./configure. You need to add
+your module's ./configure option to the SH_ENABLE_OPTS variable; for example,
+to add the option --enable-mounts-check, we added the string 'mounts-check' to
+this variable.
+</p>
+<h3>configure.ac</h3>
+This is the other file used by 'autoconf' to generate ./configure. You need to
+add an AC_ARG_ENABLE call to this file, along the lines of those for other
+modules. For example, we added
+<pre>
+AC_ARG_ENABLE(mounts-check,
+ [ --enable-mounts-check check mount options on filesystems [[no]
+]],
+ [
+ if test "x${enable_mounts_check}" = xyes; then
+ AC_DEFINE(SH_USE_MOUNTS)
+ fi
+ ]
+)
+</pre>
+for the sh_mounts module. This causes the #undef from acconfig.h above
+to be defined when ./configure is run with the --enable-mounts-check argument.
+</p>
+This is all that you need. Once you've done the above, you'll need to
+run 'autoheader' and 'autoconfig' to generate config.h.in and the
+./configure script. Then your module will build as part of the samhain
+source.
+</p>
+
+<h2>Conclusion</h2>
+<p>
+Armed with the above information, any proficient C programmer should
+be able to adapt and extend samhain to do whatever it is they need. We
+hope that this document has been reasonably clear, easy to follow and
+useful; please feel free to update it for clarity, accuracy and
+completeness and resubmit it to the samhain project.
+</p>
+<p>
+This document was written by the eircom.net Computer Incident Response Team.
+Updated with CSS by Rainer Wichmann.
+</p>
+</div>
+</body>
+</html>
diff --git a/docs/MANUAL-2_4.epub b/docs/MANUAL-2_4.epub
new file mode 100644
index 0000000..2e5d3c7
--- /dev/null
+++ b/docs/MANUAL-2_4.epub
Binary files differ
diff --git a/docs/MANUAL-2_4.html.tar b/docs/MANUAL-2_4.html.tar
new file mode 100644
index 0000000..b5fea43
--- /dev/null
+++ b/docs/MANUAL-2_4.html.tar
Binary files differ
diff --git a/docs/MANUAL-2_4.pdf b/docs/MANUAL-2_4.pdf
new file mode 100644
index 0000000..c83b2bd
--- /dev/null
+++ b/docs/MANUAL-2_4.pdf
Binary files differ
diff --git a/docs/README b/docs/README
new file mode 100644
index 0000000..a512389
--- /dev/null
+++ b/docs/README
@@ -0,0 +1,497 @@
+
+CONTENT OF THIS DOCUMENT
+------------------------
+
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ +++ +++
+ +++ NOTE: The distribution package contains a much more detailed MANUAL +++
+ +++ +++
+ +++ ---- See the docs/ subdirectory ---- +++
+ +++ +++
+ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ - INSTALL basic install procedure
+
+ - PGP SIGNATURES signing database and config file
+
+ - CLIENT/SERVER how to install and use with client/server mode
+ for distributed host monitoring
+
+ - STEALTH how to install and use with stealth mode enabled
+
+ - USAGE some usage examples
+
+ - CAVEATS what the name says
+
+ - START AT BOOT TIME how to start the daemon during the boot sequence
+
+ - CONFIGURE OPTIONS overview of supported options, and defaults
+
+ - TESTING test suite (also useful to see EXAMPLES)
+
+
+
+
+INSTALL:
+-------
+
+ Unpack the source with:
+
+ gunzip -c samhain-current.tar.gz | tar xvf -
+
+ This will drop two files in your current directory:
+
+ samhain-{version}.tar.gz
+ samhain-{version}.tar.gz.asc
+
+ To check authenticity and integrity of the source code, verify
+ the PGP signature on samhain-{version}.tar.gz
+ (public PGP key for Rainer Wichmann at http://wwwkeys.pgp.net/):
+
+ gpg --verify samhain-{version}.tar.gz.asc samhain-{version}.tar.gz
+
+ Then unpack samhain-{version}.tar.gz:
+
+ gunzip -c samhain-{version}.tar.gz | tar xvf -
+ cd samhain-{version}
+
+ If you have an incarnation of 'dialog' (xdialog, dialog, lxdialog)
+ installed, you can use the GUI install tool:
+
+ ./Install.sh
+
+ Otherwise use the commands:
+
+ ./configure [options]
+ make
+ su root
+ make install
+
+ At least the following executable will be built:
+
+ +++ samhain +++ the monitoring agent, without any
+ client/server support (i.e. local use only)
+
+ Additional executables will be built if you compile in client/server
+ and/or stealth mode (see below).
+
+ The 'make install' target will strip the executable(s), i.e.
+ discard symbols.
+
+ PATHS:
+ -----
+ For configuring the install paths/locations,
+ see the MANUAL.
+
+
+ WARNING:
+ -------
+ Some versions of gcc have a bug that generates incorrect
+ code if strength reducing is enabled.
+ If you modify the compiler flags, always use the -fno-strength-reduce
+ option with gcc, unless you are sure that your compiler does not
+ suffer from the problem (see README.gcc_bug).
+ Also, some gcc versions generate incorrect code unless the
+ -fno-omit-frame-pointer option is used.
+ The -fno-strength-reduce and the -fno-omit-frame-pointer options are
+ enabled by default by the 'configure' script.
+
+PGP SIGNATURES:
+--------------
+ By default, samhain will report on the checksums of the database
+ and configuration files on startup.
+
+ You can always (clear)sign the database (once initialized)
+ with GnuPG, as well as the configuration file
+ (recommended: gpg -a --clearsign --not-dash-escaped FILE).
+
+ However, to have samhain check these signatures, rather than ignoring
+ them, you need GnuPG and you must compile samhain with the option
+
+ ./configure --with-gpg=PATH
+
+ where PATH is the path to the gpg/pgp binary.
+
+ Samhain will invoke gpg only after checking that
+ only trusted users (by default: root and the effective user)
+ have write access to any element in the path.
+
+ The public key for verification must be in the keyring of the
+ effective user (usually root)
+
+ For more security, it is possible to compile in the checksum
+ of the GnuPG executable, and/or the key fingerprint. See
+ the MANUAL for more details.
+
+ The public key will be searched in the gpg home directory
+ (~/.gnupg/) of the effective user (usually root).
+ The key identification and fingerprint will be reported.
+
+CLIENT/SERVER:
+-------------
+
+ samhain supports logging to a central server via TCP/IP.
+ To enable this option, use the ./configure option
+
+ ./configure --enable-network=client|server [more options]
+
+ NOTE: client and server are __distict__ applications, and must be
+ built seperately. By default, installation names and paths are
+ different. Do not blame us if you abuse './configure' options to
+ cause name clashes, if you install both on the same host.
+
+ The following executables are built:
+
+ +++ samhain (client) +++ the monitoring agent,
+ with client code included
+ if --enable-network=client
+
+ +++ yule (server) +++ the log server (no monitoring, just report
+ collecting !!!)
+ if --enable-network=server
+
+ +++ samhain_setpwd +++ a utility program to set the password of
+ a monitoring agent (see man page samhain.8).
+ Use it without options to get help.
+
+
+ To set up a monitoring agent, do the following:
+
+ -- select a (16-digit hexadecimal) password. To generate
+ a random password, you can use:
+
+ ./yule -G
+
+ -- use 'samhain_setpwd samhain <suffix> <password>'
+ to generate an agent 'samhain.suffix' with the selected password
+ (you can rename the agent afterwards, of course)
+
+ -- use 'yule -P password' to compute an entry to register the agent
+
+ -- in the servers's configuration file, insert the computed entry
+ (replace HOSTNAME with the host, on which the agent will run)
+ in the section called [Clients]
+
+ By default, client/server authentication
+ is done with the SRP (Secure Remote Password) protocol.
+
+ It is also possible to store configuration and database files
+ on the server. See the manual for details.
+
+STEALTH:
+-------
+
+ samhain supports a 'stealth' mode of operation, meaning that
+ the program can be run without any obvious trace of its presence
+ on disk. The supplied facilities are more sophisticated than
+ just running the program under a different name,
+ and might thwart efforts using 'standard' Unix commands,
+ but they will not resist a search using dedicated utilities.
+ To enable this mode, use the ./configure option
+
+ ./configure --enable-stealth=XOR_VAL [more options]
+
+ XOR_VAL must be a decimal number in the range 0, 128..255
+ (using 0 will have no effect).
+
+ The runtime executable will contain no printable strings revealing
+ its nature or purpose (strings are xor'ed with XOR_VAL at compile
+ time, and decoded at runtime).
+
+ The configuration file is expected to be
+ a postscript file with _uncompressed_ image data, wherein
+ the configuration data are hidden by steganography.
+ To create a suitable image file from an existing image,
+ you may use e.g. the ImageMagick program 'convert', such as:
+
+ convert +compress ima.jpg ima.ps
+
+ The following additional executable will be built:
+
+ +++ samhain_stealth +++ steganography utility program to hide/extract
+ the configuration file data in/from a
+ postscript file with
+ _uncompressed_ image data.
+ Use it without options to get help.
+
+ Database and log file entries are xor'ed with XOR_VAL to 'mask'
+ printable strings as binary data. No steganography is supported
+ for them, as this would require image files of unreasonable large
+ size.
+ However, if the database/log file is an existing image (say, a .jpg
+ file), the data will be appended to the end of the image data.
+ The image will display normally, and on examination of the file,
+ the add-on data will look like binary (image) data at first sight.
+ The built-in utility to verify and print log file entries
+ will handle this situation transparently.
+
+ To re-name samhain to something unsuspicious, use the configure option
+
+ ./configure --enable-install-name=NAME
+
+ 'make install' will then re-name samhain upon installation. Also,
+ database, log file, and pid file will have 'samhain' replaced by
+ NAME.
+
+
+USAGE EXAMPLES:
+--------------
+
+ Review the default configuration file that comes with the
+ source distribution. Read the man page (samhain.8).
+
+ initialize database: samhain -t init
+
+ check files: samhain -t check
+
+ run as daemon: samhain -t check -D
+
+ report to log server: samhain -t check -D -e warn
+
+ start the log server: yule -S
+
+
+CAVEATS:
+-------
+ Permissions:
+ -----------
+ samhain needs root permissions to check some system files.
+ The log server does not require root permissions, unless
+ you use a privileged port (port number below 1024).
+ If you use --enable-udp to listen on the syslog socket, you need
+ to start the log server with root permissions (it will drop them
+ after binding to the port).
+
+ Trust:
+ -----
+ samhain checks the path to critical files (database, configuration)
+ for write access by untrusted users. By default, only root and
+ the effective user are trusted. More UIDs can be added as a
+ compile options (some systems habe 'bin' as owner of the root
+ directory).
+
+ Integrity:
+ ---------
+ On startup, samhain will report on signatures or checksums of
+ database and configuration files. You better check these reports.
+
+ Both startup and exit will be reported. If you are using samhain
+ as daemon and start it at boot time, you may want to check that
+ startup/exit corresponds with scheduled reboots.
+
+ If the path to the samhain binary is defined in the configuration
+ file, samhain will checksum the binary at startup and compare
+ at program termination. This will minimize the time available
+ for an intruder to modify the binary.
+
+ Mail address:
+ ------------
+ For offsite mail, you may have to set a mail relay host
+ in the configuration file.
+
+START AT BOOT TIME:
+------------------
+ the easy way (supported on Linux, FreeBSD, HP-UX, AIX):
+
+ su root
+ make install-boot
+
+
+
+CONFIGURE OPTIONS:
+-----------------
+
+ -------------------
+ -- basic options --
+ -------------------
+
+ --enable-network Compile with client/server support.
+
+ --enable-udp Enable the server to listen on
+ port 514/udp (syslog).
+
+ --enable-srp Use SRP protocol to authenticate to
+ log server.
+
+ --with-gpg=PATH Use GnuPG to verify database/config.
+ The public key of the effective
+ user (in ~/.gnupg/pubring.gpg)
+ will be used.
+
+ --enable-login-watch Watch for login/logout events.
+
+ --enable-stealth=XOR_VAL Enable stealth mode, and set XOR_VAL.
+ XOR_VAL must be decimal in
+ 0..32 or 127..255
+ and will be used to 'mask' literal
+ strings as binary data.
+ (0 has no effect).
+
+ --enable-micro-stealth=XOR_VAL
+ As --with-stealth, but without
+ steganographic hidden configuration
+ file.
+
+ --enable-nocl=PW Enable command line parsing ONLY if
+ PW is the first argument on the command
+ line. If PW is "" (empty string),
+ command line parsing is completely
+ disabled.
+
+ --enable-base=BASE Set base for one-time pads. Must be
+ ONE string (no space) made of TWO
+ comma-separated integers in the range
+ -2147483648...2147483647.
+ (The default is compile time.)
+ Binaries compiled with different
+ values cannot verify the audit trail(s)
+ of each other.
+ THIS IS IMPORTANT IF YOU COMPILE
+ MULTIPLE TIMES, E.G. ON DIFFERENT
+ HOSTS.
+
+
+ -------------------
+ -- paths --
+ -------------------
+
+ ${install_name} is "samhain" by default
+ (see --with-install-name=NAME )
+
+ configuration: /etc/${install_name}rc
+ state data: /var/lib/${install_name}
+ log file: /var/log/${install_name}_log
+ lock/pid file: /var/run/${install_name}.pid
+
+ mandir: /usr/local/man
+ bindir: /usr/local/sbin/
+
+
+ --exec-prefix=EPREFIX Set sbindir prefix (default
+ is /usr/local, ie. binaries
+ go to /usr/local/sbin)
+
+ --prefix=PREFIX install directory
+ (default is NONE)
+
+ IF PREFIX = USR; then
+
+ configuration: /etc/${install_name}rc
+ state data: /var/lib/${install_name}
+ log file: /var/log/${install_name}_log
+ lock/pid file: /var/run/${install_name}.pid
+
+ mandir: /usr/share/man
+ bindir: /usr/sbin/
+
+ IF PREFIX = OPT; then
+
+ configuration: /etc/opt/${install_name}rc
+ state data: /var/opt/${install_name}/${install_name}
+ log file: /var/opt/${install_name}/${install_name}_log
+ lock/pid file: /var/opt/${install_name}/${install_name}.pid
+
+ mandir: /opt/${install_name}/man
+ bindir: /opt/${install_name}/bin/
+
+ IF PREFIX = (something else); then
+
+ If EPREFIX is not set, it will be set to PREFIX.
+ configuration: PREFIX/etc/${install_name}rc
+ state data: PREFIX/var/lib/${install_name}
+ log file: PREFIX/var/log/${install_name}_log
+ lock/pid file: PREFIX/var/run/${install_name}.pid
+
+ mandir: PREFIX/share/man
+ bindir: PREFIX/sbin/
+
+
+
+ --with-config-file=FILE Set path of configuration file
+ (default is PREFIX/etc/samhainrc)
+
+ --with-data-file=FILE Set path of data file
+ (PREFIX/var/lib/samhain/samhain_file)
+ --with-html-file=FILE Set path of server status html file
+ (PREFIX/var/lib/samhain/samhain.html)
+
+ --with-log-file=FILE Set path of log file
+ (PREFIX/var/log/samhain_log)
+ --with-pid-file=FILE Set path of lock file
+ (PREFIX/var/run/samhain.pid)
+
+ -------------------
+ -- other --
+ -------------------
+
+
+ --with-checksum=CHECKSUM Compile in TIGER checksum of the
+ gpg/pgp binary.
+ CHECKSUM must be the full
+ line output by samhain or GnuPG when
+ computing the checksum.
+
+ --with-fp=FINGERPRINT Compile in public key fingerprint.
+ FINGERPRINT must be without spaces.
+ Only useful in combination with
+ '--with-gpg'.
+ If used, samhain will check the
+ fingerprint, but still report on the
+ used public key.
+
+ --enable-identity=USER Set user when dropping root privileges
+ (default is the user "nobody").
+ Only needed if there is no user
+ 'nobody' on your system
+ (check /etc/passwd)
+
+ --with-port=PORT Set port number for TCP/IP
+ (default is 49777).
+ Only needed if this port is already
+ used by some other application.
+
+ --with-logserver=HOST Set host address for log server
+ (default is NULL).
+ You can set this in the configuration
+ file as well.
+
+ --with-timeserver=HOST Set host address for time server
+ (default is NULL - use own clock).
+ You can set this in the configuration
+ file as well.
+
+ --with-sender=SENDER Set sender for e-mail
+ (default is daemon).
+
+ --enable-xml-log Use XML format for log file.
+
+ --enable-debug Enable extended debugging
+
+ --enable-ptrace Use anti-debugging code.
+
+ --with-trusted=UID Comma-separated list of UID's of
+ users that are always trusted
+ (default is 0 = root).
+ You will need this only if the
+ path to the config file has directories
+ owned neither by 'root' nor by the
+ (effective) user of the program.
+
+
+TESTING:
+-------
+ For testing compilation etc., you may use the test suite:
+
+ ./test/test.sh n [hostname]
+
+ The argument 'n' is the number of the test to run. Some tests require
+ that the (fully qualified) hostname be given as second argument.
+
+ Without options, you will get a short help/usage message, listing
+ each test, its purpose, and the name of the configuration file used.
+ You may want to review the respective configuration file before
+ running a test.
+
+ Also listed are the scripts used for each test. If you have problems
+ getting samhain to run, you may use these scripts as examples.
+
diff --git a/docs/README.LZO b/docs/README.LZO
new file mode 100644
index 0000000..9d13643
--- /dev/null
+++ b/docs/README.LZO
@@ -0,0 +1,136 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+
+
+ ============================================================================
+ miniLZO -- mini subset of the LZO real-time data compression library
+ ============================================================================
+
+ Author : Markus Franz Xaver Johannes Oberhumer
+ <markus.oberhumer@jk.uni-linz.ac.at>
+ http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ Version : 1.06
+ Date : 29-Nov-1999
+
+ I've created miniLZO for projects where it is inconvenient to
+ include (or require) the full LZO source code just because you
+ want to add a little bit of data compression to your application.
+
+ miniLZO implements the LZO1X-1 compressor and both the standard and
+ safe LZO1X decompressor. Apart from fast compression it also useful
+ for situations where you want to use pre-compressed data files (which
+ must have been compressed with LZO1X-999).
+
+ miniLZO consists of one C source file and two header files:
+ minilzo.c
+ minilzo.h
+ lzoconf.h
+
+ To use miniLZO just copy these files into your source directory, add
+ minilzo.c to your Makefile and #include minilzo.h from your program.
+ Note: you also must distribute this file (`README.LZO') with your project.
+
+ minilzo.o compiles to about 6 kB (using gcc or Watcom C on a i386), and
+ the sources are about 14 kB when packed with zip - so there's no more
+ excuse that your application doesn't support data compression :-)
+
+ For more information, documentation, example programs and other support
+ files (like Makefiles and build scripts) please download the full LZO
+ package from
+ http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+
+ Have fun,
+ Markus
+
+
+ P.S. minilzo.c is generated automatically from the LZO sources and
+ therefore functionality is completely identical
+
+
+ Appendix A: building miniLZO
+ ----------------------------
+ miniLZO is written such a way that it should compile and run
+ out-of-the-box on most machines.
+
+ If you are running on a very unusual architecture and lzo_init() fails then
+ you should first recompile with `-DLZO_DEBUG' to see what causes the failure.
+ The most probable case is something like `sizeof(char *) != sizeof(long)'.
+ After identifying the problem you can compile by adding some defines
+ like `-DSIZEOF_CHAR_P=8' to your Makefile.
+
+ The best solution is (of course) using Autoconf - if your project uses
+ Autoconf anyway just add `-DMINILZO_HAVE_CONFIG_H' to your compiler
+ flags when compiling minilzo.c. See the LZO distribution for an example
+ how to set up configure.in.
+
+
+ Appendix B: list of public functions available in miniLZO
+ ---------------------------------------------------------
+ Library initialization
+ lzo_init()
+
+ Compression
+ lzo1x_1_compress()
+
+ Decompression
+ lzo1x_decompress()
+ lzo1x_decompress_safe()
+
+ Checksum functions
+ lzo_adler32()
+
+ Version functions
+ lzo_version()
+ lzo_version_string()
+ lzo_version_date()
+
+ Portable (but slow) string functions
+ lzo_memcmp()
+ lzo_memcpy()
+ lzo_memmove()
+ lzo_memset()
+
+
+ Appendix C: suggested macros for `configure.in' when using Autoconf
+ -------------------------------------------------------------------
+ Checks for typedefs and structures
+ AC_CHECK_TYPE(ptrdiff_t,long)
+ AC_TYPE_SIZE_T
+ AC_CHECK_SIZEOF(unsigned short)
+ AC_CHECK_SIZEOF(unsigned)
+ AC_CHECK_SIZEOF(unsigned long)
+ AC_CHECK_SIZEOF(char *)
+ AC_CHECK_SIZEOF(ptrdiff_t)
+ AC_CHECK_SIZEOF(size_t)
+
+ Checks for compiler characteristics
+ AC_C_CONST
+
+ Checks for library functions
+ AC_CHECK_FUNCS(memcmp memcpy memmove memset)
+
+
+ Appendix D: Copyright
+ ---------------------
+ LZO and miniLZO are Copyright (C) 1996-1999
+ Markus Franz Xaver Johannes Oberhumer
+
+ LZO and miniLZO are distributed under the terms of the GNU General
+ Public License (GPL). See the file COPYING.
+
+ Special licenses for commercial and other applications which
+ are not willing to accept the GNU General Public License
+ are available by contacting the author.
+
+
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.3ia
+Charset: noconv
+
+iQCVAwUBOEK5Km10fyLu8beJAQE2oAQAovSZ1KDXJKdbfUmGHhRAoU/BdQXydYKr
+tGDtC0i8EfC2cjrbJANbZq8GQM0PMZSAgyW9/BaUmRZ/d5pxpF0eBBpUp87i/ZM6
+BoPE3uu7Rwu05SSR3FRFe1lCrMDn/yHkyV9T+DUY6XaBLONdaPh7BayQ93MnCFoD
+9gs3grhALsM=
+=uuXN
+-----END PGP SIGNATURE-----
diff --git a/docs/README.UPGRADE b/docs/README.UPGRADE
new file mode 100644
index 0000000..608ca4b
--- /dev/null
+++ b/docs/README.UPGRADE
@@ -0,0 +1,113 @@
+to 4.0.0 and higher: if you use "ReportCheckflags = yes" (off by default),
+ you need to change the database scheme:
+
+ -- mysql:
+ ALTER TABLE samhain.log ADD COLUMN checkflags_old BIGINT UNSIGNED;
+ ALTER TABLE samhain.log ADD COLUMN checkflags_new BIGINT UNSIGNED;
+
+ -- postgres:
+ ALTER TABLE samhain.log ADD COLUMN checkflags_old NUMERIC(20);
+ ALTER TABLE samhain.log ADD COLUMN checkflags_new NUMERIC(20);
+
+ --oracle:
+ ALTER TABLE samhain.log ADD checkflags_old NUMBER(20);
+ ALTER TABLE samhain.log ADD checkflags_new NUMBER(20);
+
+to 2.8.0 and higher: samhain supports IPv6 now, which means that the
+ size of the 'ip' column in the database must be increased from
+ VARCHAR(16) to VARCHAR(46).
+
+ BE SURE TO MAKE A BACKUP BEFORE THIS!
+
+ -- mysql: alter table samhain.log modify ip VARCHAR(46);
+
+ -- postgresql: alter table samhain.log alter column ip type varchar(46);
+
+ -- oracle: alter table samhain.log modify ip VARCHAR2(46);
+
+
+to 2.4.4 and higher: it is possible now to store the full content of
+ small files in the baseline database. To support this feature with
+ logging to an RDBMS, the DB schema for Oracle needs to be adjusted
+ by converting the link_old, link_new columns from VARCHAR2 to CLOB:
+
+ -- Oracle:
+ ALTER TABLE samhain.log ADD tmp_name CLOB;
+ UPDATE samhain.log SET tmp_name=link_old;
+ ALTER TABLE samhain.log DROP COLUMN link_old;
+ ALTER TABLE samhain.log RENAME COLUMN tmp_name to link_old;
+
+ ALTER TABLE samhain.log ADD tmp_name CLOB;
+ UPDATE samhain.log SET tmp_name=link_new;
+ ALTER TABLE samhain.log DROP COLUMN link_new;
+ ALTER TABLE samhain.log RENAME COLUMN tmp_name to link_new;
+
+ -- Samhain server (yule): if you are logging to the RDBMS via
+ the server (yule), as recommended, you need to also upgrade the
+ server, because earlier versions had a too restrictive limit on
+ the maximum length of an SQL query.
+
+
+to 2.3.3 and higher: a bug has been fixed that resulted in an additional
+ slash at the beginning of the linked path of symlinks in the root
+ directory (symlinks in other directories were not affected)
+
+ -- this may cause spurious warnings about modified links, if you check
+ against a database created with an earlier version of samhain
+
+from lower to 2.3.x: the database scheme has changed slightly.
+ To upgrade, use the following SQL commands in the command-line
+ client of your database:
+
+ -- MySQL:
+ ALTER TABLE samhain.log ADD COLUMN acl_old BLOB;
+ ALTER TABLE samhain.log ADD COLUMN acl_new BLOB;
+
+ -- PostgreSQL:
+ ALTER TABLE samhain.log ADD COLUMN acl_old TEXT;
+ ALTER TABLE samhain.log ADD COLUMN acl_new TEXT;
+
+ -- Oracle:
+ ALTER TABLE samhain.log ADD acl_old VARCHAR2(4000);
+ ALTER TABLE samhain.log ADD acl_new VARCHAR2(4000);
+ DROP TRIGGER trigger_on_log;
+
+
+
+since 2.2.0: server-to-server relay is possible
+
+ -- this implies that problems will arise if your server is misconfigured
+ to connect to itself (SetExportSeverity is explicitely set
+ to a threshold different from 'none', and the logserver is set to
+ localhost). The server may deadlock in this case.
+
+
+
+since 2.1.0: update and daemon mode can be combined
+
+ -- this implies that '-t update' will start a daemon process if running as
+ daemon is the default specified in the config file. use '--foreground'
+ to avoid starting a daemon process
+
+
+
+from 1.7.x to 1.8.x: client/server encryption protocol has been enhanced
+
+ -- 1.7.x clients can connect to a 1.8.x server
+
+ -- 1.8.x clients can only connect to a 1.7.x server, if they
+ are built with --enable-encrypt=1
+
+
+
+from 1.6.x to 1.7.x: things to watch out for
+
+ -- the log server drops root privileges after startup; it needs a logfile
+ directory with write access for the unprivileged user now
+
+ -- the PID file does not double as lock for the log file anymore; the
+ log file has its own lock now (same path, with .lock appended)
+
+ -- by default, the HTML status page of the server is in the log directory
+ now; this allows to make the data directory read-only for the server
+
diff --git a/docs/README.gcc_bug b/docs/README.gcc_bug
new file mode 100644
index 0000000..1330528
--- /dev/null
+++ b/docs/README.gcc_bug
@@ -0,0 +1,49 @@
+
+GCC Compiler Bug
+----------------
+
+Reference: http://boudicca.tux.org/hypermail/linux-kernel/2000week05/0983.html
+
+From: Johan Kullstam (kullstam@ne.mediaone.net)
+Date: Thu Jan 27 2000 - 18:00:28 EST
+
+Horst von Brand <vonbrand@sleipnir.valparaiso.cl> writes:
+
+> My question in this vein would be the -fno-strength-reduce. The gcc bug
+> that placed this in the kernel was in gcc-2.7.2, and was worked around in
+> 2.7.2.3 by just making this option unconditional. Both 2.2.15pre4 and
+> 2.3.41pre2 at least demand gcc-2.7.2.3 as minimal version.
+
+just when you thought it was safe to go into the water...
+
+strength-reduction is broken again in gcc-2.95.2 (aka the current
+release). i'm not sure about what versions actually do work.
+
+for fun, try this one out. cut and paste the program bug.c.
+
+$ gcc -O2 bug.c -o b0
+$ gcc -O2 -fno-strength-reduce bug.c -o b1
+
+run b1. notice it finish immediately.
+now run b0. notice how b0 never terminates (until you ^C it).
+
+
+-- bug.c -----------------------------------------
+static void bug(int size, int tries)
+{
+ int i;
+ int num = 0;
+
+ while (num < size)
+ {
+ for (i = 1; i < tries; i++) num++;
+ }
+}
+
+int main()
+{
+ bug(5, 10);
+ return 0;
+}
+-- bug.c -----------------------------------------
+
diff --git a/docs/README.sstrip b/docs/README.sstrip
new file mode 100644
index 0000000..b96c171
--- /dev/null
+++ b/docs/README.sstrip
@@ -0,0 +1,40 @@
+sstrip is a small utility that removes the contents at the end of an
+ELF file that are not part of the program's memory image.
+
+Most ELF executables are built with both a program header table and a
+section header table. However, only the former is required in order
+for the OS to load, link and execute a program. sstrip attempts to
+extract the ELF header, the program header table, and its contents,
+leaving everything else in the bit bucket. It can only remove parts of
+the file that occur at the end, after the parts to be saved. However,
+this almost always includes the section header table, and occasionally
+a few random sections that are not used when running a program.
+
+It should be noted that the GNU bfd library is (understandably)
+dependent on the section header table as an index to the file's
+contents. Thus, an executable file that has no section header table
+cannot be used with gdb, objdump, or any other program based upon the
+bfd library, at all. In fact, the program will not even recognize the
+file as a valid executable. (This limitation is noted in the source
+code comments for bfd, and is marked "FIXME", so this may change at
+some future date. However, I would imagine that it is a pretty
+low-priority item, as executables without a section header table are
+rare in the extreme.) This probably also explains why strip doesn't
+offer the option to do this.
+
+Shared library files may also have their section header table removed.
+Such a library will still function; however, it will no longer be
+possible for a compiler to link a new program against it.
+
+As an added bonus, sstrip also tries to removes trailing zero bytes
+from the end of the file. (This normally cannot be done with an
+executable that has a section header table.)
+
+sstrip is a very simplistic program. It depends upon the common
+practice of putting the parts of the file that contribute to the
+memory image at the front, and the remaining material at the end. This
+permits it to discard the latter material without affecting file
+offsets and memory addresses in what remains. However, the ELF
+standard permits files to be organized in almost any order. So
+although this procedure usually works in practice, it is not meant to
+be taken too seriously.
diff --git a/docs/README.win2K b/docs/README.win2K
new file mode 100644
index 0000000..4a04347
--- /dev/null
+++ b/docs/README.win2K
@@ -0,0 +1,36 @@
+
+Using SAMHAIN on Win2K
+----------------------
+
+samhain builds and runs on Win2K (and maybe other M$ products) with
+the (free, GPL) Cygwin environment.
+Fabio Paracchini <fparacchini at alteanet dot it> writes:
+
+(UPDATE: note that some configure options have changed since this has been
+ written. Check the manual and/or run './configure --help' for
+ available options.)
+
+ The configuration I'm testing now is a server on OpenBSD 2.8 and a client on
+ W2K, using the latest Cygwin. I was able to compile the client on a W2K
+ Cygwin development machine using those configuration flags:
+
+ --enable-static
+ --enable-network
+ --with-tmp-dir=/tmp
+ --with-data-file=REQ_FROM_SERVER/samhain.db
+ --with-config-file=REQ_FROM_SERVER/etc/samhainrc
+ --with-logserver=x.x.x.x
+ --with-lock-file=/cygdrive/c/samhain.lck
+ --with-log-file=/cygdrive/c/samhain.log
+
+ I was able to successfully compile and sign the executable, upload to the
+ production server with the cygwin1.dll in the same directory and run both
+ samhain -t init and samhain -t check.
+
+ If you need a stealthy configuration you could change lock & log file to
+ something more obscure, only pay attention that in Cygwin if you need to
+ access drive C: you have to prefix your path with /cygdrive/c.
+
+ The configuration is kept on the server where Yule runs; I registered the
+ client and I'm in the process of tuning the exceptions for the files
+ modified by Windows.
diff --git a/docs/samhain_german.pdf b/docs/samhain_german.pdf
new file mode 100644
index 0000000..45cd6ed
--- /dev/null
+++ b/docs/samhain_german.pdf
Binary files differ
diff --git a/docs/sh_mounts.txt b/docs/sh_mounts.txt
new file mode 100644
index 0000000..4bfe121
--- /dev/null
+++ b/docs/sh_mounts.txt
@@ -0,0 +1,59 @@
+Documentation for sh_mounts, the samhain "Mounts" module.
+---------------------------------------------------------
+sh_mounts implements functionality we had in a policy-checking Perl script we
+have here at eircom; basically, all it does is ensure that certain mounts are
+there (for example, /, /tmp, /var, /usr, /home) and that certain options are
+specified on those mounts (for example noexec,nosuid on /tmp).
+
+All quite simple. It wouldn't be too hard to extend this module somewhat, to
+report any NFS mounts found, for example, or to test that _only_ the mounts
+specified are mounted on the machine.
+
+Here's a bit for the manual:
+
+<Begin manual entry>
+
+Checking mounted filesystem policies
+------------------------------------
+samhain can be compiled to check if certain filesystems are mounted, and if they
+are mounted with the appropriate options. This module currently supports Linux,
+Solaris and FreeBSD. The configuration of the module is done in the Mounts
+section of the configuration file:
+
+-------->8---------
+
+[Mounts]
+#
+# Activate (0 is off).
+#
+MountCheckActive=1
+
+#
+# Interval between checks.
+#
+MountCheckInterval=7200
+
+#
+# Logging severities. We have two checks: to see if a mount is there, and to
+# see if it is mounted with the correct options.
+#
+SeverityMountMissing=warn
+SeverityOptionMissing=warn
+
+#
+# Mounts to check for, followed by lists of options to check on them.
+#
+checkmount=/
+checkmount=/var
+checkmount=/usr
+checkmount=/tmp noexec,nosuid,nodev
+checkmount=/home noexec,nosuid,nodev
+
+-------->8---------
+
+<End manual entry>
+
+The module is enabled as part of the compilation of samhain by specifying
+--enable-mounts-check
+
+This module by the eircom.net Computer Incident Response Team
diff --git a/docs/sh_userfiles.txt b/docs/sh_userfiles.txt
new file mode 100644
index 0000000..cc3ad3f
--- /dev/null
+++ b/docs/sh_userfiles.txt
@@ -0,0 +1,39 @@
+Checking sensitive files owned by users.
+------------------------------------
+samhain can be compiled to support checking of files that are specified
+as being relative to the a user's home directory. It is intended to
+detect interference with files that influence process behaviour such as
+.profile
+It simply adds the appropriate file entries to the main samhain list, at
+the specified alerting level.
+
+
+-------->8---------
+
+[UserFiles]
+#
+# Activate (0 is off).
+#
+UserfilesActive=1
+
+#
+# Files to check for under each $HOME
+# A specific level can be specified.
+# The allowed values are:
+# allignore
+# attributes
+# logfiles
+# loggrow
+# noignore
+# readonly
+# user0
+# user1
+#
+#Ê The default is noignore
+UserfilesName=.login noignore
+UserfilesName=.profile readonly
+UserfilesName=.ssh/authorized_keys
+
+-------->8---------
+
+This module by the eircom.net Computer Incident Response Team.
diff --git a/dsys/0F571F6C.asc b/dsys/0F571F6C.asc
new file mode 100644
index 0000000..a7c6721
--- /dev/null
+++ b/dsys/0F571F6C.asc
@@ -0,0 +1,183 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.1 (GNU/Linux)
+
+mQGiBDgcfd0RBADvXitAL1gCXw1yOJsPWJdU6wbgqMWqfMbkFGRiLZut/rwbN3x/
+ch8sF+hptcQGH4Hhe25+1WkSO1KO81j6ZQZqhYNHogE3IFsv1TK7vX0r81ZRjinM
+koQ69kWw+elp1vcLCwHzHDB8MhV3eI3jpQcGgpsRVq4uEumyGfI1v6AUfwCg+RIj
+aGtvyxFH2UsSUVNaM/008v8D/R56I6qLcixxuWrHUhZBNaiQ0I70PWo92uLHwSvF
+dnSnkpUc4BvTeq4PVuId6e3LdeonG4OW8jWFK0/9OE+ubuZYJdOmuv+3BzPOktZy
+9Cf8QwHpUvQ/c9S5MrIOsFdQAOj6rQvlA7OmnidyW4+MA3IYp8bwq5dx6sHcAy7o
+0RBSBADpf5eWfni8Awfcwq7yyGgJFhAAgkoDKAHBj4OepVKhcnCe8+78VpqWtZ9p
+e45AL/5nhl6CceWWZfCYXgv2Zm8CUnUwxb6XKuGOGJagtRT9d0fQFeEXFlSPE5HA
+JCXkhbcQpZq1YzyjKMeExBfM5w4XaEhfQ652pjXQieyWETjd17QtUmFpbmVyIFdp
+Y2htYW5uIDxyd2ljaG1hbm5AaHMudW5pLWhhbWJ1cmcuZGU+iFUEExECABUFAjgc
+fd0DCwoDAxUDAgMWAgECF4AACgkQGq0myA9XH2y7FwCdEIZRr4gI9vlS7DgcS8mY
+FjveBncAoLiNO3tE00J4r6LEWm4IpYYUiRUFiQEcBBMBAgAGBQI+UjZjAAoJEAbp
+c/N5kkHBNjwH/138Qk7NcZT2ar5t4MOyaHM7gaIOaywZHXaGEx7wrvpmD3ImoerE
+psp19+JqOfzhgpGI8Z37nh+HR5vIYERrMrIBLoHMwyNkJxqRiqNVfZ3AxpZWvKTl
+AJlwIvPGF6FfR2f05Lvaw06UoOLpIjmzb8rXQ6bvbqSXtgUEU+pmwfjQOPidwNjW
+ovUTkCpv2LWQxwapYgOZilne+7Zad+nf/asCGfqL9V9WIblrwoFkSlP13UwF4j5f
+m7iTM9ZAXFUUFvarN2Mz0RP4+58rceb6bRM+agL+dpd5AqgwBgtGYmeO/G4/E/WY
+PYBLTh+ZbupmvykgdnKR0E0w72KXnLg11M2JARwEEwECAAYFAj5SNakACgkQBz/7
+hK/ULUUktggAgbbW4uM9B8jQeavzdMmV3WiF2owqr1MiS+oiWKBK3U6O0xJP5G9Q
+h5Zj80NEdopDV0G8z1KOFn4v4SMlzSjvq6938end+zvgaPGEGaE94iHp5aI6TMhF
+ezmbM2MfNphfn2yxmzQefEj8VaJbi+du4n1YmnkMJDkpw+6927/99Sj3A0jNvUxC
+B5YM9K/t6xI89qlKZlCDHjgEHARAxNWRyE5YSqRkXWgxcHPKkF1oKifD4/eNyQw2
+OZnRTFRsk28uEJTysnjsiIUbP13LR6m1VfZQrEpk0RjnlGKVRwy42WWDnOsCXOnM
+Sy2+a9gYa+ayCGI+NTuUUecvZ7VVxKCHIYhGBBMRAgAGBQI+UjYnAAoJEA86uzhI
+KF65WpIAn0p+PQe7WaHp15qul2E7AoDD7uuzAJ486FDSWZi92crLJNPnyPi9HXbi
+DIhGBBMRAgAGBQI+S5Q1AAoJEBwB7TX3s/Rm2QcAn2zwg7uup1JMGqTxSaQ+sjWR
+0vEqAJ9xvhAZMOrk51/6T7Oq/DzaZGwT3IhGBBARAgAGBQI4XqDdAAoJEB3kOh0g
+CZVMC8cAn04Ph20EZH5vbPvVQN9+KdketxyHAKCIhQvT2DiNsadeI7fQwRssLn7a
+xohGBBMRAgAGBQI+S5NzAAoJEG48dKkHK3yJ8/YAnRTCT5OhC9jPOxL26UKTF/YT
+t46kAJ9WI3vfQrbKgu32s6E5UTgQS/U4hokBHAQTAQIABgUCPlIpcQAKCRB4oTZL
+RAPrMfOcCACxIuPyBAxDIDvP3xWzMdlN4AhLIQ1myMHlwA7X90RVKW+saR+gU3QI
+hBVahKfC7OEXhH/dCft1c64Vy3lZT5vl9W6m0ZukdVSKTVKZYaRk+iGej3+zzD8W
+CzwDvMvkDGa1/VuOZDvx3byj866/L3Y4n8Qa+66KkqNG3sMgjOfMoxGTvZuxL3Zz
+YdQWUovd9KcmOl7etDB8rhkz4cBPxXxcIbDhDPJNgDoViby4Bgs1nmfvhPq+RNvK
+fKysRo9XYWfTRjwqicSMhSTRdgMS1GHCMY3U183p+njorU9gxvxmZhxzop41vwh2
+ps6CVpUo9u+fpiDkfWeZIBzdl6+pz8TkiQEcBBMBAgAGBQI+S5OYAAoJEH641Vr2
+yhx/sVIH/3MXz2dFzTze2eM9jj8DMJhM6wsuXIxKnGxl7Vd0i/T3jlh+UAQBueHz
+KtsmyE7xZ8OnoBfC9U4+ypyuKdnd0oULOTChDpY2a0Dv4gp4HZGoO3BR1qcf7LFy
+3Ibn37siiJ4WmvgqPx9v1sFZAr+rKeSqhxnD7+GosbyD7qNQTATsorAMgYAdWCAC
+MsnLdP0K7yTW3X4JGgnRNjVJbYkFVC/j3qedT/Or0iUDDZdzID+vxxlwxa8Y+UTS
+wR75IPJEw7UObjQMdUixwUsb04rCI5CtPvMdO7nSvC1RvfP5TTSY5Ypu7bO6ArMT
+iYQfWhz2YCE/ikB8jeT6OovpqXiSKFaInAQTAQIABgUCPkuS/gAKCRCMWj5dyq7Z
+nSSwBAC2Zbo6lkfoq+ZPYj4hXs+C83aaVwEDEY4MqcEONPlt5tno6Tipt1aE7utf
+aCT2az5qLcns4cb+UckchEfcqmJc3+YTX97h6Iz55OsFYIXtUkYyys7Q3VmSqDZg
+Xz2N3YGBR0ttRk/qTNd3BoIWzdlqaLFfkFf5EgdIO5UIB8KPLYkBHAQQAQIABgUC
+PnHPRAAKCRB7Id4BrmYkJQOVCACpVqEZXDSU/LA1B1y7OtbQvuLOBqkKYvJ6QY+b
+SUnQA4pIWm1tZuGXckuo7Th/2zUqu+Jthso6zNRzz+FXIPOamHVRqxjbihPCsLA7
+1MfVax7shaXswrHbKDt4Ou9834+KY2/G7XFdym2IezSeOrmsSicgQNsqdOIlmgMX
+YaG/4ddRvbB4V5PomPCz+tKDALXrkRoiS2akyfMgwsMOo9xfXA6j6bHJwHjar6eD
+ZiWcG24KXbiRYsyXw8v/piuG6rer7VuTFuaJwEAUvZYxAvFtISmxDAysHKwHXK1g
+ijK3Dh0JSkZrEH3LofAzRtcw+MQUkiD5sBDJ0E6QOr9bk14FiEYEEBECAAYFAj5x
+0GwACgkQhfcxbPQmVn3FQACg1wSQt5mdfpwN74PFs6SVpoQ3kFMAoNJORjgHXFyF
+Gc+2DXq1KFXEUKAtiQEcBBMBAgAGBQI+cc0RAAoJEO67Mb58Bv0ljgYH/RVSwmd+
+BufOXhZNfozT8p2M6xVgsEQ1nzdHtAVo+tr00xyHHwLQj1phDXSZtK1iRvLY6GXg
+Dp0VAGjkjUilR8adfT7uvgu9br32zCx7EZkAOQXp51tPWnD4JDcWB0adJEWwfVo9
++abC/84/Xy0c+IOdNLEePLxlYlezynXTCEgTXMeeROKOQMog/vB8obNi3rYjUKC/
+eypJCuMtmnLKhHhbezvJMy+N10iWajpOYInQLP+uee48/ytmbnb+8klx8j3rJ1Ew
+r4KU+7ewm2eHPzJl1xCbuqePoxciptgtjdwtmGQH+VHDPRAcF+FfoNtF1Fc1p6+8
+7qznfNJoLHWsde+JARwEEwECAAYFAj5xzSAACgkQKBTThimyUAFD9gf/RUY5fwxN
+Qv2N2bnSqmisUEx8XrOGGmzPNKvL1TdIwcc+votQ98nOBEv6De17+HD/jPVD3ReS
+71sB1gI5/Duni5h8nx2L2siQxOqNE2YI2oSn8f4ign91ruFSEwPR+nFUDtbuMk4C
+0df16i7asVXiKq3GW7Tv20iXnTvjQZCVSFtXxU00pdtmf0FpRSPp7YonQMLv6vCH
+iZ6j74kkn4+EwroXmWF5nb9/HZOJiZnTv6+vGpFYiI/gAGkOA4SBipUWm2B2E4AV
+MTo2MeXe+/wbirL43PDiG2kbeet7KH5M+/BTceUjl0alIFeZizYaluvouWo7NahA
+MLz89pUD25hpl4hGBBIRAgAGBQI+dJKeAAoJEI47c57dK8ydsAoAmwXDmPsbM0Ao
+0VkY1q8anK5lhJMqAKDQOIimB3yzFt7koY9MUgFgHX77rYhGBBARAgAGBQI+hde4
+AAoJEHFOxoebS5syXOMAn3xCJVsb0IRb42q25sLpHVXvc8+TAJ9Q3RBxdagtPVPx
+m58Uf4bhGLuBdohGBBMRAgAGBQI+iDOzAAoJEJJVvZ/mhE25CQYAn0j2H3sUfjao
+iTML5QF057ZfwzwoAKDBulEh0SChQQ2KbHdlpAVP+Io+U4g/AwUQPtSY59vSRfyz
+sqEsEQIDSQCfVPYWXSS2qbCI0BZm1jNI/D3WndIAoLmDomrFc+B+9Hp6id8B8kxy
+/IRdiEYEEBECAAYFAj74SAgACgkQ36XkltcZWyKb6ACg6XOdq03pvSlA0AqBZLQV
+wmeItVcAnRpHJt7znvfrxPpI4vfnkRR1Lt/yiEYEExECAAYFAj+f3koACgkQxcDF
+xyGNGNeCuwCfRP034939xTTTLWp+hQUE/O6NfbIAoJ7IbYA3YQmfDQukotNGypzH
+uo1aiEYEExECAAYFAkBbXgcACgkQ01u8mbx9Agqs9QCfTRKAxpfPhFz0kL2cODz6
+Eo/TbMUAoIyztog7I3BTwu22eTPv6pXUTQEliEYEExECAAYFAkBbJ/0ACgkQSvFU
+KpY6VLBbHwCdHlFGr+t5aNg9SWqFfLs2N38awXkAoIW0bSz0MOPCkUHtY1o+wfjo
+J+DPiEYEExECAAYFAkBqj9AACgkQECqmVFXwdrOgIgCeNTva96TnQPlkIcpRE2hs
+oHITahAAoIEk77c6+Cr9CsS46WGvf1ePJW0yiEYEExECAAYFAkBytVYACgkQGyfX
+UvpJphr6dwCgkB330qWc6xjgounXSXbCvR7Dry4An3MzbcU/YS/OH7IBZMopWJbo
+Vr6KiEYEExECAAYFAkByunAACgkQA5e1oKh+NRxEmgCbBOyZmLeti3aysxi6yYEz
+JRkBGe4AmgPMOK8nxNjqa2KTrvsdH+XJSnGOiEYEExECAAYFAkB0A6AACgkQzAoJ
+I8gDfT8aMgCcCqTKT9sTVsk6UYIvYB6aBbmQIvYAn1gYeX6HTIo4+CfPC2c6bc80
+iO+ViEYEExECAAYFAkB0ZUsACgkQr/RnCw96jQEetgCgnJatrM9Co+6JunHUl58L
+PswEAdAAoIFqNka9tvPrk8ZOJkfxJJEujrIgiEYEEBECAAYFAkCKrbQACgkQ9yNf
+So1Tr57J0wCfdZB/pGW/wyjHP2rpEQ/xV8bc/94AoKnbj0KC+glYM3pDOwjKbEZH
+/WAfiEYEEhECAAYFAkBzpsUACgkQ78vN/2HwW4wcDwCfYPlVzDJ0jfI+mMR+tHP8
+n6Guj98An252IGC/eIB1I4nCi5TqqeVEvIeZtChSYWluZXIgV2ljaG1hbm4gPHJ3
+aWNobWFubkBsYS1zYW1obmEuZGU+iFYEExECABYFAjoDPmkECwoEAwMVAwIDFgIB
+AheAAAoJEBqtJsgPVx9sNHAAoOPNgUXL+qRFyHU8wyDEeOHWALErAJoD2eIs0r7R
+4UH+q+3J+v2EDbrHQYkBHAQTAQIABgUCPlI2awAKCRAG6XPzeZJBwcA2B/4sQlDm
+NMykYdYPY/MZ2b/O6S/2rZts+W3htjMEMvSzTM96koCJEpJCaHbmMehqZGUh/V97
+oj4+rTfeKtKQBSVaBU2Bj8Zy2YjlqBUs2ShilVMR14RSOgmKr8FSvJVSegWf62T+
+yFisLZdhQMTImSkKMB2oWkZPS9Su9dtk7j9gfHKwPIx3O8MCNf2dnaksHCpUMa3o
+AcXBZprMYE31zbrre2pi9E1jRFyq2zr0Ywkw1/LO4GUi3Zstg1gffLEku+ZpIBaw
+NH+WO+kkfoNmS03Ffxoo+Y5LLXAkm/dfn/KsbVy/WKHCiXfhWnyAxGxZhUAcgMwW
+VFcN53kQ1Twq8S3HiQEcBBMBAgAGBQI+UjWwAAoJEAc/+4Sv1C1FzQUH/j03htOj
+wiBSi/S3KcRCjrX9gem3RwCVTVbOKoGhAuA2cd45ZlT3E1ivvPAg2MzNzGQt1Fai
+CsQ/3Xy/1JzfnwVijHGXDZFrV7/ZClA4sj/bO36KNSoVNHeE7n1dsrfd1N2s9WgT
+JkB/LdRCcTqiUubxy+pWghdAEpSOAO/KacxhZ9Bbf1cjOcWJBbMWZSMLBTddUCcx
+cxzi3hpIfNOjwuZwYWlIe7KLI6YdjrdNUQZHPBTivTiZMzQ2kc7jPoSS/h5s9cvo
+hLa/9QqARih0V+ilTl8RFwYuPFWvIy4aTCSHWkzYO110KiLhz54Z1P0z5nWe/IfS
+XJRFgrAd2xKkpd+IRgQTEQIABgUCPlI2TwAKCRAPOrs4SCheuVwuAJ9q/3m2ZuG/
+RpbNISA1zTi1239CbwCghqx5M2MClODQ4YRF+I/be6j8ub+IRQQTEQIABgUCPkuU
+OgAKCRAcAe0197P0Zp3gAJjpxPKU0GFcYhaE/ED/jI+h65HKAJwOwYPmGuU4dR3I
+nN+iHBnqY/9s2ohGBBMRAgAGBQI+S5N5AAoJEG48dKkHK3yJd5sAnjIKbVSpWM6v
+aEYdrWKF55rlXwo1AJ99RNP00MRpBa7IiVcXBR3KOurRsIkBHAQTAQIABgUCPlIp
+eAAKCRB4oTZLRAPrMUAfCADAz95sXsxdUYAS+jejVuf1EYA+5TEgSIi5uhSOlgdu
+WyUAzGuWSplc6kjoqwysUmnwthJON5Y4DSIes5YsDs93k+X0bZxDkzghqiFU5LWE
+266bN7MvWmYXh7DfAz3V262dqa2IvvxSHtxmiYLPn5mZ2pLsXnWYTZUBZ4BSdArB
+t0pfHOOjZaixqfK7DYzyripm9259552aYOrmso8lSnAq2a+ekD9tQ9e2m8gkPbei
+5sF1kawoYkyedEr+r4j0h1Sf24LVJinLPnavtDGUynt+v0NobzqBUHgI5lnSmlDt
+WWUU23YvAko73aJwlW1cDkRfcsR+TdA+IiECbFcipOd1iQEcBBMBAgAGBQI+S5Op
+AAoJEH641Vr2yhx/sN0H/1kWbhVnnkqC1LvOdqP9bx7S3UDUkQw0xEf1DC2lUALV
+zioDt9PvarRh47bcaUis+x/9k9AYsPFDhBiYPYek6VcxT86LPVUKz/gELOmHNcAq
+3aUl35NKC97JVxYqMix1+hS8UY+m5zezSDdLAz1G8UKZ1d6tx3daikOPzKmpIY50
+wMBdA3jITr6J4eWZ/ptfL0GDdlXFOVKFURMIn6t5AAjKdqQHYySxhuWn+S3QQxDz
+Ulv9vAUW4VS+6lzWB1thmRxwawbfJ+05kO/hGD+alWiJxyW/PXRwEiqdVzAIIocM
+mHmGtEIONcNyRdjIsDIyZTMavFJOE0hMHftp8a7vbTuInAQTAQIABgUCPkuTAwAK
+CRCMWj5dyq7ZncE6A/9tzn5ZST0cgPqQEywAcTeQeja7Qxxl7/CJ3gHqnK8eZu2D
+MmSINdRgPjDknn9hWhKu2aDjfhl/a/sIbD8cHtvWza0Z9a12tZZ5+kDOand/U3rn
+RLRUO8MnhLxHif5vEtQvC54jxmpOl05J2o5QT0pFs9BHW3tDGlR4CWPrwUC2W4kB
+HAQQAQIABgUCPnHPTAAKCRB7Id4BrmYkJaWCB/41LdB1IdcPLraASItBLqfKb46+
+fOoU1teYrM3J7zE5r1z79Mu7slT5JRP3i5iD+TjbqDI4LitZ2lrbmGTI/uQ0R9T8
+PBWcs+SBroVCDziCO2nTVQldvqtmXCx0Rpu8iZacKotEz9nVQxouUiskgNn/v0p2
+Ng1gUK5g3CripcYXUpkEpmYkyTYAbokeeKsF3cCe9czVT9l/nB/OJIus31eKa8x0
+9+1EMdu/GJIxa/tDQh7vkNKSP09qtKrCsSxzpfmwIj1PBTT8oDkBkheuTaKTTWPE
+0jWP3aNMTHZUkLpRVNf1htus7utSm1O+W6hTYQLL0OPMylBTWZ33vN2Nb0fliEYE
+EBECAAYFAj5x0HIACgkQhfcxbPQmVn3c8ACgyIVKF4Fjl2vCc3VgAcPvNZ8p5lYA
+nj2/t1pja5FPd89R7I1ZS4Ctb12uiQEcBBMBAgAGBQI+cc0VAAoJEO67Mb58Bv0l
+t48IAIWzONERcs+QPNZ3NbMU3Um5s43XxZcql6mOIc0I7eBLl/bn+UTh4F5PuAbh
+mgTkVR5l9KF1PKswHfbzYxDSGTYqSXOCXRnbU4sByoSaV6xlGJAM9ivi/vEom6uE
+v6pQEZslNDNt4IfYx35+8WLhjXb7OM0HF5ZqpLqXF5BGAYGx9vDKs4SEo5HNslTT
+q1JgDMJNXKVyQxOAewICq+VaqbztwGf8nhcNz5Di4G5IbKi6BKOvlkPt4TkRsppJ
+Gq+1rAM6Fh34FqaKshuubOuoZwXKrmMHGEYgoE7XLXW5998GmE4dZh8fO7iaPjH4
+3f/qcmn5joko+HQw9visZymSxgiJARwEEwECAAYFAj5xzSQACgkQKBTThimyUAFv
+NQgAthIAnR7+dtVcrH51R4J+8Li30yi04E0VGLhJ6KnGCpzv8eSp2HMiaRe1JAss
+Zy7S+dpcL6MDjcYR6HaNP49V9RtTfiARFgZWQ6SD5nOdmMe3Nb6kmfYnZO3YHwiW
+NXtncNHHnvSS1bDM5o3hitEPHvnQbOB/k6BpilsKzPl/bvRa8hT1/b4hQjhmv5Hf
+LxI6suLyOqz6ESWL2enFXTmthOOAan0yLkhLNvIsHZue3Kd7OP7+7uzmCF+mEIL7
+eL9EheCa+4hWUEltdEdBtX5kcgJdTJQZZCuyz7aZ1JSZwr0G+4x6K5J9WAzI7BzI
+TD0rZ0LSOilyuDTYQChRDJPe8ohGBBIRAgAGBQI+dJKhAAoJEI47c57dK8ydmcAA
+oJa36CvpFHhq9VH0BRAgk6whGRFpAJ9J+VP1AmA3tjmzV3R7Ls5TMJRs4YhGBBAR
+AgAGBQI+hyNZAAoJEHFOxoebS5syxQEAn0XqPZdIJqSzqFq7ElQMK7khAxuwAKCA
+qlcHbWvhqxN7mAmC/wfYebKbZ4hGBBMRAgAGBQI+iDO2AAoJEJJVvZ/mhE25bioA
+ni6Vz0lqdlCdJG9KpeWUGtPcwUFDAJ9281Qpt6+9PW5TJOrcBO7OJW8UIokBHAQT
+AQIABgUCPsoYKQAKCRAcU5jLRuk3pDzVB/wP5SA6Dq168ItTQoOhNmx4k4sm5sJP
+bbPPFOKjYhPjnBKSNmU2l+Z4lNrI9BxEhTwGCc3NpTV8E7G5I6PtWaeTgFgdd2B/
+eZCSui82yQmBOh/CFk5WW8deB4Bd4MDCCjhx2nZz7ivB0Dv9FlMyLqChjARrJQGD
+u2XfAvYyXhW+4UNOPI0D/SkJgeCRoVQi8ASbgt6SlHn7wkdvrDltJy1CfbqiYBr3
+Y5TG4JaGceW8vfMCEdbw21MxPK/nP08J7ES5oMRcFHCA82+TvuCOErOnq/naPqHC
+vjpbpLqYl5qtv8cN7kV/eb/sAXBL41AM0bQoM/KY7Bv/Qldk0R7w/4XmiD8DBRA+
+1Jj029JF/LOyoSwRAmdiAJ4iGUh4PlFl2QLC2HBdOk+gnZdFSQCeOTZ5bFIRg0YU
+OCpuvgkifys5L2mIRgQQEQIABgUCPvhICgAKCRDfpeSW1xlbIibpAKCfTI1e8MXw
+BbGPVPYGPEWfF5Dl2wCffBaai8FxqWhzHRek00rxLgEqCfiIRgQSEQIABgUCP51G
+YwAKCRAdqzxE2iYyGBerAJ9utXaBGuKbOLW1N3EAFVPUsMl1pwCeJWmBUvaZ6Z18
+UitAdRn+c3tcEE2IRgQTEQIABgUCP5/eRgAKCRDFwMXHIY0Y17qSAKCoOhCWYphZ
+tuwgAiglspzyXyUPGgCg0Fjhhq8KfNQujv5LJEKgP5EUrv6IRgQTEQIABgUCQFsn
++QAKCRBK8VQqljpUsEajAKCRBtUxFnh+w5YdYU971cbT54sQQACfVg1gozhfClAw
+XhPGML85ne/WatuIRgQTEQIABgUCQFteAwAKCRDTW7yZvH0CCn+BAJ4959iKUXvk
+dYpmtNKZyulsCGj9ygCgxA8Qo/1WffxrWeCnL9jK106qkMuIRgQTEQIABgUCQGqP
+yAAKCRAQKqZUVfB2s5CAAKCYZGG8v9mlYwGZd62fLcuqh28kvgCcCzpEb0xQaoTV
+Y1LdcKlnrQyLg9qIRgQTEQIABgUCQHK1UwAKCRAbJ9dS+kmmGjF1AKCdX/0pvL7J
+Q9QIpk37clvuTjdk9ACfW5CPmsBTo4QebFLvrXjPA2BS2OyIRgQTEQIABgUCQHK6
+ZgAKCRADl7WgqH41HMhvAKCHhiRvXGhAd7DS5nvCURhUde6/QgCfZQgEtHFSLhpj
+KacnyMkg6xF2dSeIRgQTEQIABgUCQHQDnQAKCRDMCgkjyAN9P+W9AJ9OQZ3++gB1
+KDNRxmsj/W/KHLQ2SQCdHUEhkuCKURe7upjXUOhExaIKTdKIRgQTEQIABgUCQHRl
+RwAKCRCv9GcLD3qNAWt5AJ9t8EbD+ZoZP6ZcJRIH0byTXSvaIACgtcC7OUBQayGD
+eKpkyyTpUTTJFpyIRgQQEQIABgUCQIqtrgAKCRD3I19KjVOvnhkdAKCLJygVD/kJ
+lQWaJkxgU5ykneSklQCeN8508dGDEY0gmq+uJPtdgDCusy6IRgQSEQIABgUCQHOm
+twAKCRDvy83/YfBbjGClAJ9kF+WHOy0ctth6wvisP04IH8YCBwCeLYt5p8KLLZ9v
+T/+kn5KNrNmZJay5AQ0EOBx96RAEAMnQiAMYTglVoIciiw5l0YIuE/Uh4KSPhf1X
+TY4CqZrjpv56QSlhndyM5Q9vhC/bpnzMCl4A1YCb2MPMO5QYD1URI13KkG7HX6hz
+eW/ANfs/DJ6o1odOu3deSIzgb/TEqLV6rr7IcY/hkn3IuAiBCrMR/3kKx5AkyKOQ
+ZNsd40sHAAMFA/4jrzq9HoWmeEFG25U7s43NvoDFtrlt8IaS/BVdVCx599yT+BPT
+RmwRfpkV7TAKghgXp0SKYgo1Bp6tdyymTiZ8Ly14CUiuPYBOBifjsFoeVXWj1arW
+FmmQWd4d59scGoITMh39f0XTxpgGjVVxNbdqSMS+khzP5acQ27DsFMbtMIhGBBgR
+AgAGBQI4HH3pAAoJEBqtJsgPVx9stTUAnikTmI5ST+k6VhT2gltex+sDmr6NAJoC
+qkfo4qjAQCyqTx5Eg3NKuxafqQ==
+=jITK
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/dsys/comBUILD b/dsys/comBUILD
new file mode 100644
index 0000000..71a934f
--- /dev/null
+++ b/dsys/comBUILD
@@ -0,0 +1,253 @@
+#########################################################################
+#
+# Subroutine for the 'build' command
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+commandBUILD() {
+ printINFO "About to run \"$action\""
+
+ if test -d "${basedir}/archpkg/${arch}"
+ then
+ :
+ else
+ if test -d "${basedir}/archpkg"
+ then
+ if test x"$simulate" = x0
+ then
+ mkdir "${basedir}/archpkg/${arch}"
+ else
+ printINFO "mkdir ${basedir}/archpkg/${arch}"
+ fi
+ else
+ if test x"$simulate" = x0
+ then
+ mkdir "${basedir}/archpkg" && mkdir "${basedir}/archpkg/${arch}"
+ else
+ printINFO "mkdir ${basedir}/archpkg && mkdir ${basedir}/archpkg/${arch}"
+ fi
+ fi
+ fi
+
+ if test -f "${basedir}/configs/${arch}.configure"
+ then
+ :
+ else
+ printFATAL "Configure options file ${basedir}/configs/${arch}.configure not found."
+ fi
+
+ local_test=`cat "${basedir}/configs/${arch}.configure" | tr -d '\n' | egrep "^ *'?--with-logserver=FQDN_MISSING"`
+ if test x"${local_test}" = x
+ then
+ :
+ else
+ printFATAL "Your configuration file has a bad --with-logserver option."
+ fi
+
+ if test x"$bd_packed" = x
+ then
+ printINFO "Building version: ${src_version}, host: ${host}, os: ${arch}, format: ${format}"
+ else
+ printINFO "Building version: ${src_version}, host: ${host}, os: ${arch}, format: ${format}, packed: password=${bd_packed}"
+ fi
+
+ tmpdir=`eval echo "${temp_dir}/sh_${src_version}_${arch}_${format}_$$"`
+
+ #---------------------------------------------------------------------
+ # Create temporary build directory on build host.
+ #---------------------------------------------------------------------
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "${bd_user}" "${host}" '(umask 0077; mkdir "'${tmpdir}'")'
+ else
+ printINFO "ssh -x -l ${bd_user} ${host} (umask 0077; mkdir ${tmpdir})"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not create temporary build directory on host ${host}."
+ else
+ printLOG "Build directory ${tmpdir} created on host ${host}"
+ fi
+
+ #---------------------------------------------------------------------
+ # Copy source tarball to build host.
+ #---------------------------------------------------------------------
+ if test x"$simulate" = x0
+ then
+ rm -f "${basedir}/tmp/samhain-${src_version}.tar"
+ gunzip -c "${basedir}/source/samhain-${src_version}.tar.gz" > "${basedir}/tmp/samhain-${src_version}.tar"
+ else
+ printINFO "rm -f ${basedir}/tmp/samhain-${src_version}.tar"
+ printINFO "gunzip -c ${basedir}/source/samhain-${src_version}.tar.gz > ${basedir}/tmp/samhain-${src_version}.tar"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not gunzip source to ${basedir}/tmp/samhain-${src_version}.tar."
+ fi
+
+ if test x"$simulate" = x0
+ then
+ if test x"$silent" = x0
+ then
+ scp "${basedir}/tmp/samhain-${src_version}.tar" "${bd_user}@${host}:${tmpdir}/"
+ else
+ scp -q "${basedir}/tmp/samhain-${src_version}.tar" "${bd_user}@${host}:${tmpdir}/"
+ fi
+ else
+ if test x"$silent" = x0
+ then
+ printINFO "scp ${basedir}/tmp/samhain-${src_version}.tar ${bd_user}@${host}:${tmpdir}/"
+ else
+ printINFO "scp -q ${basedir}/tmp/samhain-${src_version}.tar ${bd_user}@${host}:${tmpdir}/"
+ fi
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not copy source to host ${host}."
+ else
+ printINFO "Source copied to host ${host}."
+ fi
+
+ #---------------------------------------------------------------------
+ # Build the package.
+ #---------------------------------------------------------------------
+ if test x"$silent" = x0
+ then
+ config_com='./configure'
+ else
+ config_com='./configure --silent'
+ fi
+
+ if test -f "${basedir}/configs/${arch}.configure"
+ then
+ while read line
+ do
+ if test -z "`echo $line | awk '/^#/'`"
+ then
+ nline=`echo ${line} | tr -d '\n'`
+ config_com="${config_com} ${nline}"
+ fi
+ done <"${basedir}/configs/${arch}.configure"
+ else
+ printFATAL "Configure options file ${basedir}/configs/${arch}.configure not found."
+ fi
+
+ printINFO "configure command is ${config_com}"
+ if test x"$bd_packed" = x
+ then
+ command="make clean"
+ else
+ command="make CLIENTPASSWD=${bd_packed} samhain-packed"
+ fi
+
+
+ command=`eval echo $command`;
+
+ if test x"$simulate" = x0
+ then
+ if test $silent -lt 2
+ then
+ ssh -x -l "${bd_user}" "${host}" /bin/sh -c \''(PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${PATH}:${bd_addpath}'" && export PATH && cd "'${tmpdir}'" && tar -xf "'samhain-${src_version}.tar'" && cd "'samhain-${src_version}'" && eval "'${config_com}'" && eval "'${command}'" && make "'${format}-light'")'\'
+ else
+ ssh -x -l "${bd_user}" "${host}" /bin/sh -c \''(PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${PATH}:${bd_addpath}'" && export PATH && cd "'${tmpdir}'" && tar -xf "'samhain-${src_version}.tar'" && cd "'samhain-${src_version}'" && eval "'${config_com}'" && eval "'${command}'" && make "'${format}-light'") >/dev/null'\'
+ fi
+ else
+ if test $silent -lt 2
+ then
+ printINFO "ssh -x -l ${bd_user} ${host} /bin/sh -c '(PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:\${PATH}:${bd_addpath} && export PATH && cd ${tmpdir} && tar -xf samhain-${src_version}.tar && cd samhain-${src_version} && eval ${config_com} && eval ${command} && make ${format}-light)'"
+ else
+ printINFO "ssh -x -l ${bd_user} ${host} /bin/sh -c '(PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:\${PATH}:${bd_addpath} && export PATH && cd ${tmpdir} && tar -xf samhain-${src_version}.tar && cd samhain-${src_version} && eval ${config_com} && eval ${command} && make ${format}-light) >/dev/null'"
+ fi
+ fi
+
+ if test x"$?" != x0
+ then
+ printFATAL "Could not build package on host ${host}."
+ else
+ printINFO "Source compiled."
+ fi
+
+ #---------------------------------------------------------------------
+ # Fetch package and remove temporary build directory on build host.
+ #---------------------------------------------------------------------
+ realformat=`echo $format | sed s,solaris-,,`
+
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "${bd_user}" "${host}" '(cat "'${tmpdir}/samhain-${src_version}/samhain-install.sh'")' >"${basedir}/archpkg/${arch}/install-${src_version}.${realformat}"
+ else
+ printINFO "ssh -x -l ${bd_user} ${host} (cat ${tmpdir}/samhain-${src_version}/samhain-install.sh) >${basedir}/archpkg/${arch}/install-${src_version}.${realformat}"
+ fi
+
+ if test x"$?" != x0
+ then
+ printFATAL "Could not fetch samhain-install.sh script from host ${host}."
+ fi
+ chmod +x "${basedir}/archpkg/${arch}/install-${src_version}.${realformat}"
+
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "${bd_user}" "${host}" '(cat "'${tmpdir}/samhain-${src_version}/samhain-${src_version}.${realformat}'" && rm -rf "'${tmpdir}'")' >"${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}"
+ else
+ printINFO "ssh -x -l ${bd_user} ${host} (cat ${tmpdir}/samhain-${src_version}/samhain-${src_version}.${realformat} && rm -rf ${tmpdir}) >${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not fetch package samhain-${src_version}.${realformat} from host ${host}."
+ else
+ printLOG "Build directory ${tmpdir} deleted on host ${host}."
+ fi
+ chmod +x "${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}"
+
+ if test x"$simulate" = x0
+ then
+ pkgsize=`ls -l "${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}" | awk '{print $5}'`
+ if test "x$pkgsize" = "x0"; then
+ printFATAL "Returned package file is empty."
+ fi
+ else
+ printINFO "ls -l ${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat} | awk '{print $5}'"
+ fi
+
+ # >> Save password
+ #
+ if test x"$bd_packed" = x
+ then
+ :
+ else
+ if test x"$simulate" = x0
+ then
+ echo "$bd_packed" >"${basedir}/archpkg/${arch}/PASSWD-${src_version}.${realformat}"
+ fi
+ fi
+
+ # >> Save configure options
+ #
+ if test x"$simulate" = x0
+ then
+ cp "${basedir}/configs/${arch}.configure" "${basedir}/archpkg/${arch}/configure-${src_version}.${realformat}"
+ else
+ printINFO "cp ${basedir}/configs/${arch}.configure ${basedir}/archpkg/${arch}/configure-${src_version}.${realformat}"
+ fi
+
+ printLOG "New package: ${arch}/samhain-${src_version}.${realformat}."
+}
+
diff --git a/dsys/comCHECKSRC b/dsys/comCHECKSRC
new file mode 100644
index 0000000..32d4464
--- /dev/null
+++ b/dsys/comCHECKSRC
@@ -0,0 +1,120 @@
+#########################################################################
+#
+# Subroutine for the 'checksrc' command
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+commandCHECKSRC() {
+ printINFO "About to run \"$action\""
+
+ needEXE ls gpg
+
+
+ cd "${basedir}/source" || printFATAL "could not cd to ${basedir}/source"
+
+ LIST=`ls samhain*.tar.gz 2>/dev/null`
+ if test x$? != x0
+ then
+ printINFO "No sources available."
+ fi
+
+ for ff in $LIST
+ do
+ sh_version=`echo "$ff" | sed 's/.*samhain\-//g' | sed 's/\.tar\.gz//g'`
+ if test x"${sh_version}" = x
+ then
+ printFATAL "Cannot determine version for $ff"
+ fi
+
+ if test "$ff" != "samhain-${sh_version}.tar.gz"
+ then
+ printFATAL "Version number not correctly extracted from $ff"
+ fi
+
+ if test -f "samhain-${sh_version}.tar.gz.asc"
+ then
+ :
+ else
+ printWARNING "No detached signature for $ff found"
+ if test x"$cs_delete" = x1
+ then
+ if test x"$simulate" = x0
+ then
+ printLOG "REMOVE $ff: No detached signature found."
+ rm -f "$ff"
+ else
+ printLOG "REMOVE $ff: No detached signature found."
+ printINFO "rm -f $ff"
+ fi
+ else
+ printLOG "BAD: $ff (no signature)"
+ fi
+ continue
+ fi
+
+ sig_lines=`(LANG="C"; gpg --status-fd 1 --verify "samhain-${sh_version}.tar.gz.asc" "samhain-${sh_version}.tar.gz" 2>/dev/null)`
+ sig_ok=`echo ${sig_lines} | grep 'GOODSIG'`
+ sig_nokey=`echo ${sig_lines} | grep 'NO_PUBKEY'`
+
+ if test x"${sig_nokey}" != x
+ then
+ printWARNING "Public key (ID 0F571F6C) not found, trying to import it."
+ gpg --import ${basedir}/private/0F571F6C.asc 2>&5
+ sig_lines=`(LANG="C"; gpg --status-fd 1 --verify "samhain-${sh_version}.tar.gz.asc" "samhain-${sh_version}.tar.gz" 2>/dev/null)`
+ sig_ok=`echo ${sig_lines} | grep 'GOODSIG'`
+ sig_nokey=`echo ${sig_lines} | grep 'NO_PUBKEY'`
+ fi
+
+ if test x"${sig_nokey}" != x
+ then
+ printFATAL "Importing public key failed."
+ fi
+
+ if test x"${sig_ok}" = x
+ then
+ printWARNING "File $ff has no good signature"
+ if test x"$cs_delete" = x1
+ then
+ if test x"$simulate" = x0
+ then
+ printLOG "REMOVE $ff: No good signature found."
+ rm -f "$ff"
+ else
+ printLOG "REMOVE $ff: No good signature found."
+ printINFO "rm -f $ff"
+ fi
+ else
+ printLOG "BAD: $ff (invalid signature)"
+ fi
+ continue
+ fi
+ printLOG "OK: $ff"
+
+ done
+
+ if test x"$cs_delete" = x1
+ then
+ printLOG "Checked sources in ${basedir}/source/ (delete=on)"
+ else
+ printLOG "Checked sources in ${basedir}/source/ (delete=off)"
+ fi
+ return 0
+}
diff --git a/dsys/comCLEAN b/dsys/comCLEAN
new file mode 100644
index 0000000..f757ab9
--- /dev/null
+++ b/dsys/comCLEAN
@@ -0,0 +1,79 @@
+#########################################################################
+#
+# Subroutine for the 'clean' command
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+commandCLEAN() {
+ printINFO "About to run \"$action\""
+
+ cd "${basedir}/source" || printFATAL "could not cd to ${basedir}/source"
+
+ LIST=`ls samhain*.tar.gz 2>/dev/null`
+ if test x$? != x0
+ then
+ printINFO "No sources available."
+ fi
+
+ for ff in $LIST
+ do
+ sh_version=`echo "$ff" | sed 's/.*samhain\-//g' | sed 's/\.tar\.gz//g'`
+ if test x"${sh_version}" = x
+ then
+ printFATAL "Cannot determine version for $ff"
+ fi
+
+ if test "$ff" != "samhain-${sh_version}.tar.gz"
+ then
+ printFATAL "Version number not correctly extracted from $ff"
+ fi
+
+ if test -f "samhain-${sh_version}.tar.gz.asc"
+ then
+ printINFO "REMOVE samhain-${sh_version}.tar.gz.asc"
+ if test x"$simulate" = x0
+ then
+ rm -f "samhain-${sh_version}.tar.gz.asc"
+ else
+ printINFO "rm -f samhain-${sh_version}.tar.gz.asc"
+ fi
+ fi
+
+ if test -f "samhain-${sh_version}.tar.gz"
+ then
+ printINFO "REMOVE samhain-${sh_version}.tar.gz"
+ if test x"$simulate" = x0
+ then
+ rm -f "samhain-${sh_version}.tar.gz"
+ else
+ printINFO "rm -f samhain-${sh_version}.tar.gz"
+ fi
+ fi
+ done
+
+ printLOG "Cleaned sources in ${basedir}/source/"
+
+ dbSHOWPKG dontshow delete
+
+ printLOG "Cleaned unused packages in ${basedir}/archpkg/"
+
+ return 0
+}
diff --git a/dsys/comDOWNLOAD b/dsys/comDOWNLOAD
new file mode 100644
index 0000000..7c448d7
--- /dev/null
+++ b/dsys/comDOWNLOAD
@@ -0,0 +1,280 @@
+#########################################################################
+#
+# Subroutine for the 'download' command
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+commandDOWNLOAD() {
+ printINFO "About to run \"$action\" for samhain version \"$src_version\""
+
+ needEXE du gunzip tar gpg
+
+
+ if test x"$simulate" = x0
+ then
+ cd "${basedir}/tmp" || printFATAL "could not cd to ${basedir}/tmp"
+ rm -f "samhain-${src_version}.tar.gz"
+ else
+ #
+ # -- Simulate only: print what would be done
+ #
+ printINFO "cd ${basedir}/tmp"
+ printINFO "rm -f samhain-${src_version}.tar.gz"
+ fi
+
+ command=""
+
+ if test -z "$command"
+ then
+ findEXE wget
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1="--quiet"
+ opt2="-O"
+ opt3="-"
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ findEXE curl
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1="--silent"
+ opt2="--show-error"
+ opt3="--fail"
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ findEXE lynx
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1="-source"
+ opt2=""
+ opt3=""
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ findEXE links
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1="-source"
+ opt2=""
+ opt3=""
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ findEXE lwp-request
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1=""
+ opt2=""
+ opt3=""
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ findEXE fetch
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1="-q"
+ opt2="-o"
+ opt3="-"
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ findEXE fget
+ if test -n "$EXECUTABLE"
+ then
+ command="$EXECUTABLE"
+ opt1=""
+ opt2=""
+ opt3=""
+ fi
+ fi
+
+ if test -z "$command"
+ then
+ printFATAL "No wget, curl, lynx, links, lwp-request, fetch, fget in your \$PATH, cannot download"
+ fi
+
+ if test x"${src_version}" = xcurrent
+ then
+ location="http://la-samhna.de/samhain/samhain-current.tar.gz"
+ if test -f /usr/bin/md5sum && test -f /bin/hostname
+ then
+ #
+ # for testing
+ #
+ dl_tmp_hna=`/bin/hostname -f 2>/dev/null`
+ dl_tmp_md5=`echo "x${dl_tmp_hna}" | md5sum`
+ if test x"$dl_tmp_md5" = "xc5f41bf28a7baf12c763f1be27a9b863"
+ then
+ location="http://localhost/samhain-current.tar.gz"
+ fi
+ fi
+ else
+ location="http://la-samhna.de/archive/samhain_signed-${src_version}.tar.gz"
+ if test -f /usr/bin/md5sum && test -f /bin/hostname
+ then
+ #
+ # for testing
+ #
+ dl_tmp_hna=`/bin/hostname -f 2>/dev/null`
+ dl_tmp_md5=`echo "x${dl_tmp_hna}" | /usr/bin/md5sum 2>/dev/null`
+ if test x"$dl_tmp_md5" = "xc5f41bf28a7baf12c763f1be27a9b863"
+ then
+ location="http://localhost/samhain_signed-${src_version}.tar.gz"
+ fi
+ fi
+ fi
+
+
+ printINFO "Executing $command $opt1 $opt2 $opt3 $location"
+
+ if test x"$simulate" = x0
+ then
+ eval "$command" "$opt1" "$opt2" "$opt3" "$location" 1>"samhain-${src_version}.tar.gz" 2>/dev/null
+ else
+ printINFO "$command" "$opt1" "$opt2" "$opt3" "$location" 1>"samhain-${src_version}.tar.gz"
+ printINFO "du -s -k samhain-${src_version}.tar.gz | awk '{ print $1 }'"
+ printLOG "Downloaded to samhain-${src_version}.tar.gz (XXX kB)"
+ printINFO "gunzip -c samhain-${src_version}.tar.gz | tar -tvf - "
+ printINFO "Source in tarball is version X.X.X"
+ printINFO "Unpacking to ${tmpD}"
+ printINFO "cd ${tmpD}"
+ printINFO "gunzip -c ${basedir}/tmp/samhain-${src_version}.tar.gz | tar -xf -"
+ printINFO "rm -f ${basedir}/tmp/samhain-${src_version}.tar.gz"
+ printINFO "Checking PGP signature"
+ printINFO "(LANG=C; gpg --status-fd 1 --verify samhain-X.X.X.tar.gz.asc samhain-X.X.X.tar.gz 2>&1 | grep 'GOODSIG')"
+ printINFO "cp samhain-X.X.X.tar.gz.asc samhain-X.X.X.tar.gz ${basedir}/source"
+ printLOG "Installed samhain (X.X.X) source"
+ return 0
+ fi
+
+ if test -f "samhain-${src_version}.tar.gz"
+ then
+ :
+ else
+ printFATAL "failed: $command $location"
+ fi
+
+ size=`du -s -k "samhain-${src_version}.tar.gz" | awk '{ print $1 }'`
+
+ if test $size -lt 100
+ then
+ rm -f "samhain-${src_version}.tar.gz"
+ printFATAL "failed: $command $location"
+ else
+ printLOG "Downloaded to samhain-${src_version}.tar.gz (${size} kB)"
+ fi
+
+ files=`gunzip -c "samhain-${src_version}.tar.gz" | tar -tvf - 2>/dev/null`
+ sig=`echo $files | egrep ' samhain.*tar\.gz\.asc$' 2>/dev/null`
+ sig_version=`echo $files | egrep ' samhain.*tar\.gz\.asc$' 2>/dev/null | sed 's/.*samhain\-//g' | sed 's/\.tar\.gz\.asc//g'`
+ if test x"$sig" = x
+ then
+ rm -f "samhain-${src_version}.tar.gz"
+ printFATAL "downloaded file does not contain a PGP signature"
+ fi
+
+ if test x"${sig_version}" = x
+ then
+ rm -f "samhain-${src_version}.tar.gz"
+ printFATAL "cannot determine samhain version from downloaded file"
+ fi
+
+ if test x"${src_version}" != xcurrent
+ then
+ if test x"${src_version}" != x"${sig_version}"
+ then
+ rm -f "samhain-${src_version}.tar.gz"
+ printFATAL "downloaded version (${sig_version}) != requested version (${src_version})"
+ fi
+ fi
+
+ printINFO "Source in tarball is version ${sig_version}"
+ printINFO "Unpacking to ${basedir}/source"
+
+ cd "${tmpD}" || {
+ rm -f "${basedir}/tmp/samhain-${src_version}.tar.gz"
+ printFATAL "could not cd to ${tmpD}"
+ }
+
+ gunzip -c "${basedir}/tmp/samhain-${src_version}.tar.gz" | tar -xf -
+
+ rm -f "${basedir}/tmp/samhain-${src_version}.tar.gz"
+
+ if test -f "samhain-${sig_version}.tar.gz"
+ then
+ if test -f "samhain-${sig_version}.tar.gz.asc"
+ then
+ :
+ else
+ printFATAL "not found in source: PGP signature samhain-${sig_version}.tar.gz.asc"
+ fi
+ else
+ printFATAL "not found in source: samhain-${sig_version}.tar.gz"
+ fi
+
+
+ printINFO "Checking PGP signature"
+ sig_lines=`(LANG="C"; gpg --status-fd 1 --verify "samhain-${sig_version}.tar.gz.asc" "samhain-${sig_version}.tar.gz" 2>/dev/null)`
+ sig_ok=`echo ${sig_lines} | grep 'GOODSIG'`
+
+ sig_nokey=`echo ${sig_lines} | grep 'NO_PUBKEY'`
+
+ if test x"${sig_nokey}" != x
+ then
+ printWARNING "Public key (ID 0F571F6C) not found, trying to import it."
+ gpg --import ${basedir}/private/0F571F6C.asc 2>&5
+ sig_ok=`(LANG="C"; gpg --status-fd 1 --verify "samhain-${sig_version}.tar.gz.asc" "samhain-${sig_version}.tar.gz" 2>/dev/null | grep 'GOODSIG')`
+ fi
+
+ if test x"${sig_ok}" = x
+ then
+ (LANG="C"; gpg --verify "samhain-${sig_version}.tar.gz.asc" "samhain-${sig_version}.tar.gz")
+ printFATAL "no good signature"
+ fi
+
+ cp "samhain-${sig_version}.tar.gz" "samhain-${sig_version}.tar.gz.asc" \
+ ${basedir}/source/ || \
+ printFATAL "failed: cp samhain-${sig_version}.tar.gz samhain-${sig_version}.tar.gz.asc ${basedir}/source/"
+
+ printLOG "Installed samhain source (version=${sig_version})"
+
+ return 0
+}
diff --git a/dsys/comINSTALL b/dsys/comINSTALL
new file mode 100644
index 0000000..97a2c01
--- /dev/null
+++ b/dsys/comINSTALL
@@ -0,0 +1,643 @@
+#########################################################################
+#
+# Subroutine for the 'install' command
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+commandINSTALL() {
+
+ printINFO "About to run \"$action\" on host \"$host\""
+ #
+ # configuration options we should know about
+ #
+ is_packed=0
+ is_nocl="start"
+ is_xor="no"
+
+
+ if test -f "${basedir}/configs/${arch}.configure"
+ then
+ :
+ else
+ printFATAL "Configure options ${basedir}/configs/${arch}.configure missing."
+ fi
+
+ if test -f "${basedir}/configs/${arch}.samhainrc"
+ then
+ :
+ else
+ printFATAL "Configuration file ${basedir}/configs/${arch}.samhainrc missing."
+ fi
+
+ realformat=`echo $format | sed s,solaris-,,`; export realformat
+
+ if test -f "${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}"
+ then
+ :
+ else
+ printFATAL "Binary package OS: ${arch}, version: ${src_version}, format ${format} does not exist."
+ fi
+
+ if test -f "${basedir}/archpkg/${arch}/install-${src_version}.${realformat}"
+ then
+ :
+ else
+ printFATAL "Binary package OS: ${arch}, version: ${src_version}, format ${format} is incomplete and cannot be installed."
+ fi
+
+
+ if test -f "${basedir}/archpkg/${arch}/PASSWD-${src_version}.${realformat}"
+ then
+ printINFO "Binary package OS: ${arch}, version: ${src_version}, format ${format} is packed."
+ is_packed=1
+ is_passwd=`cat "${basedir}/archpkg/${arch}/PASSWD-${src_version}.${realformat}" | tr -d '\n'`
+ else
+ is_passwd=`eval "${yule_exec}" -G`
+ if test x$? != x0
+ then
+ printFATAL "Could not generate password. Is yule in your PATH ?"
+ fi
+ fi
+
+ if test -f "${basedir}/configs/${arch}.preinstall"
+ then
+ cp "${basedir}/configs/${arch}.preinstall" "${tmpD}/preinstall" || \
+ printFATAL "Could not copy ${basedir}/configs/${arch}.preinstall to ${tmpD}/preinstall"
+ is_preinstall_full="${tmpD}/preinstall"
+ else
+ is_preinstall_full="${basedir}/libexec/preinstall"
+ fi
+
+ if test -f "${basedir}/configs/${arch}.postinstall"
+ then
+ cp "${basedir}/configs/${arch}.postinstall" "${tmpD}/postinstall" || \
+ printFATAL "Could not copy ${basedir}/configs/${arch}.postinstall to ${tmpD}/postinstall"
+ is_postinstall_full="${tmpD}/postinstall"
+ else
+ is_postinstall_full="${basedir}/libexec/postinstall"
+ fi
+
+ if test -f "${basedir}/configs/${arch}.initscript"
+ then
+ cp "${basedir}/configs/${arch}.initscript" "${tmpD}/initscript" || \
+ printFATAL "Could not copy ${basedir}/configs/${arch}.initscript to ${tmpD}/initscript"
+ is_initscript_full="${tmpD}/initscript"
+ else
+ is_initscript_full="${basedir}/libexec/initscript"
+ fi
+
+ #---------------------------------------------------------------------
+ # Get important configuration options.
+ #---------------------------------------------------------------------
+
+ getconfopts "${basedir}/archpkg/${arch}/configure-${src_version}.${realformat}" || printFATAL "Could not check config file ${basedir}/archpkg/${arch}/configure-${src_version}.${realformat}"
+
+
+ #---------------------------------------------------------------------
+ # Prepare the configuration file
+ #---------------------------------------------------------------------
+
+ if test -f "${basedir}/hosts/${host}/${arch}.samhainrc"
+ then
+ hostconfig="${basedir}/hosts/${host}/${arch}.samhainrc"
+ elif test -f "${basedir}/hosts/${host}/samhainrc"
+ then
+ hostconfig="${basedir}/hosts/${host}/samhainrc"
+ else
+ hostconfig="${basedir}/configs/${arch}.samhainrc"
+ fi
+
+ test -f "${hostconfig}" || printFATAL "Configuration file ${hostconfig} missing."
+
+ # Handle the '--enable-stealth' option
+ #
+ if test x"${is_xor}" = xno
+ then
+ :
+ else
+ test -f "${basedir}/private/stealth_template.ps" || \
+ printFATAL "${basedir}/private/stealth_template.ps not available."
+ ${basedir}/libexec/samhain_stealth -o "${hostconfig}" >/dev/null ||\
+ printFATAL "Problem reading ${hostconfig}".
+ ccount=`${basedir}/libexec/samhain_stealth -o "${hostconfig}" 2>&1 | awk '{ print $1 }'`
+ ${basedir}/libexec/samhain_stealth -i "${basedir}/private/stealth_template.ps" >/dev/null || \
+ printFATAL "Problem reading ${basedir}/private/stealth_template.ps"
+ mcount=`${basedir}/libexec/samhain_stealth -i "${basedir}/private/stealth_template.ps" 2>&1 | awk '{ print $7 }'`
+
+ if test ${mcount} -lt ${ccount}
+ then
+ printFATAL "Configuration file ${hostconfig} too big."
+ fi
+
+ cp "${basedir}/private/stealth_template.ps" "$tmpD" || \
+ printFATAL "Could not copy ${basedir}/private/stealth_template.ps to ${tmpD}/"
+ ${basedir}/libexec/samhain_stealth -s "${tmpD}/stealth_template.ps" "${hostconfig}" >/dev/null
+ if test "x$?" = x0
+ then
+ printINFO "Configuration file hidden into stealth_template.ps"
+ hostconfig="${tmpD}/stealth_template.ps"
+ else
+ printFATAL "Could not run ${basedir}/libexec/samhain_stealth -s ${tmpD}/stealth_template.ps ${hostconfig}"
+ fi
+ fi
+
+ rm -f "${tmpD}/prepared_samhainrc"
+ cp "${hostconfig}" "${tmpD}/prepared_samhainrc" || \
+ printFATAL "Could not copy ${hostconfig} to ${tmpD}/prepared_samhainrc"
+ hostconfig="${tmpD}/prepared_samhainrc"
+
+ #---------------------------------------------------------------------
+ # Create temporary directory on host.
+ #---------------------------------------------------------------------
+
+ tmpdir=`eval echo "${temp_dir}/sh_${src_version}_${arch}_${format}_$$"`
+
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" '(umask 0077; mkdir "'${tmpdir}'")'
+ else
+ printINFO "ssh -x -l root ${host} (umask 0077; mkdir ${tmpdir})"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not create temporary directory ${tmpdir} on host ${host}."
+ else
+ printLOG "Directory ${tmpdir} created on host ${host}."
+ fi
+
+ #---------------------------------------------------------------------
+ # Copy to host.
+ #---------------------------------------------------------------------
+ if test x"$simulate" = x0
+ then
+ if test x"$silent" = x0
+ then
+ scp "${is_initscript_full}" "${is_preinstall_full}" "${is_postinstall_full}" "${hostconfig}" "${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}" "${basedir}/archpkg/${arch}/install-${src_version}.${realformat}" "root@${host}:${tmpdir}/"
+ else
+ scp -q "${is_initscript_full}" "${is_preinstall_full}" "${is_postinstall_full}" "${hostconfig}" "${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat}" "${basedir}/archpkg/${arch}/install-${src_version}.${realformat}" "root@${host}:${tmpdir}/"
+ fi
+ else
+ if test x"$silent" = x0
+ then
+ printINFO "scp ${is_initscript_full} ${is_preinstall_full} ${is_postinstall_full} ${hostconfig} ${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat} ${basedir}/archpkg/${arch}/install-${src_version}.${realformat} root@${host}:${tmpdir}/"
+ else
+ printINFO "scp -q ${is_initscript_full} ${is_preinstall_full} ${is_postinstall_full} ${hostconfig} ${basedir}/archpkg/${arch}/samhain-${src_version}.${realformat} ${basedir}/archpkg/${arch}/install-${src_version}.${realformat} root@${host}:${tmpdir}/"
+ fi
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not copy package to host ${host}."
+ else
+ printINFO "Package copied to host ${host}."
+ fi
+
+ #---------------------------------------------------------------------
+ # Run preinstall script.
+ #---------------------------------------------------------------------
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" '(cd "'${tmpdir}'" && cp "'install-${src_version}.${realformat}'" samhain-install.sh && chmod +x samhain-install.sh && chmod +x preinstall && ./preinstall)'
+ else
+ printINFO "ssh -x -l root ${host} (cd ${tmpdir} && cp install-${src_version}.${realformat} samhain-install.sh && chmod +x samhain-install.sh && chmod +x preinstall && ./preinstall)"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not run preinstall script on host ${host}."
+ else
+ printLOG "Preinstall script executed on host ${host}"
+ fi
+
+ #---------------------------------------------------------------------
+ # Install.
+ #---------------------------------------------------------------------
+
+ if test "x$format" = "xrun"; then
+ is_command="/bin/sh"
+ elif test "x$format" = "xdeb"; then
+ is_command="dpkg --install --force-downgrade --force-confnew"
+ elif test "x$format" = "xrpm"; then
+ is_command="rpm --upgrade --quiet --oldpackage"
+ elif test "x$format" = "xtbz2"; then
+ is_command="emerge -K"
+ elif test "x$format" = "xsolaris-pkg"; then
+ is_command="pkgadd -n -d"
+ elif test "x$format" = "xdepot"; then
+ is_command="/usr/sbin/swinstall -x fix_explicit_directories=false -v -s "
+ else
+ printFATAL "Don't know how to install package format ${format}"
+ fi
+
+ if test "x$format" = "xdepot"
+ then
+ tmp_iname=`/bin/sh ${basedir}/archpkg/${arch}/install-${src_version}.${realformat} --print-config name`
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && PATH="'/usr/local/sbin:/usr/sbin:/sbin:$PATH'" && export PATH && eval "'${is_command}'" "'${tmpdir}/samhain-${src_version}.${realformat}'" "'${tmp_iname}'") >/dev/null '\'
+ else
+ printINFO "ssh -x -l root ${host} /bin/sh -c '(cd ${tmpdir} && eval ${is_command} ${tmpdir}/samhain-${src_version}.${realformat} ${tmp_iname})'"
+ fi
+ elif test "x$format" = "xsolaris-pkg"
+ then
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH'" && export PATH && eval "'${is_command}'" "'samhain-${src_version}.${realformat} all'") >/dev/null '\'
+ else
+ printINFO "ssh -x -l root ${host} /bin/sh -c '(cd ${tmpdir} && eval ${is_command} samhain-${src_version}.${realformat}) all'"
+ fi
+ elif test "x$format" = "xtbz2"
+ then
+ # Gentoo is a PITA
+ #
+ tmp_iname=`/bin/sh ${basedir}/archpkg/${arch}/install-${src_version}.${realformat} --print-config name`
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH'" && export PATH && cp "'samhain-${src_version}.${realformat}'" "'/usr/portage/packages/All/${tmp_iname}-${src_version}.tbz2'" && eval "'${is_command}'" "'${tmp_iname}-${src_version}.${realformat}'") >/dev/null '\'
+ else
+ printINFO "ssh -x -l root ${host} /bin/sh -c '(cd ${tmpdir} && cp samhain-${src_version}.${realformat} /usr/portage/packages/${tmp_iname}-${src_version}.tbz2 && eval ${is_command} ${tmp_iname}-${src_version}.${realformat})'"
+ fi
+ else
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH'" && export PATH && eval "'${is_command}'" "'samhain-${src_version}.${realformat}'") >/dev/null '\'
+ else
+ printINFO "ssh -x -l root ${host} /bin/sh -c '(cd ${tmpdir} && eval ${is_command} samhain-${src_version}.${realformat})'"
+ fi
+ fi
+
+ if test x"$?" != x0
+ then
+ printFATAL "Could not install package on host ${host}."
+ else
+ printLOG "Package installed on host ${host}"
+ fi
+
+
+ #---------------------------------------------------------------------
+ # Run postinstall script to fix the client password.
+ #---------------------------------------------------------------------
+ if test x"$simulate" = x0
+ then
+ if test "x${is_packed}" = "x0"
+ then
+ ssh -x -l "root" "${host}" '(cd "'${tmpdir}'" && chmod +x postinstall && ./postinstall "'${is_passwd}'") >/dev/null'
+ else
+ # Dummy argument
+ ssh -x -l "root" "${host}" '(cd "'${tmpdir}'" && chmod +x postinstall && ./postinstall DUMMY ) >/dev/null'
+ fi
+ else
+ if test "x${is_packed}" = "x0"
+ then
+ printINFO "ssh -x -l root ${host} (cd ${tmpdir} && chmod +x postinstall && ./postinstall ${is_passwd})"
+ else
+ # Dummy argument
+ printINFO "ssh -x -l root ${host} (cd ${tmpdir} && chmod +x postinstall && ./postinstall DUMMY )"
+ fi
+ fi
+
+ if test x"$?" != x0
+ then
+ printFATAL "Could not run postinstall script on host ${host}."
+ else
+ printLOG "Postinstall script executed on host ${host}"
+ fi
+
+ #---------------------------------------------------------------------
+ # Update the rc file
+ #---------------------------------------------------------------------
+
+ if test "x${is_rcfile}" = xy
+ then
+ mytest_file=`ls -1 "${yule_data}/rc*" 2>/dev/null | tail -n 1 2>/dev/null`
+ if test "x$mytest_file" = x; then
+ rcfile_perm=640;
+ xgid=`(cat /etc/group; ypcat group) 2>/dev/null |\
+ grep "^samhain:" | awk -F: '{ print $3; }'`
+ if test "x$xgid" = x; then
+ rcfile_owner=`ls -ld ${yule_data} | awk '{print $3 }'`
+ rcfile_group=`ls -ld ${yule_data} | awk '{print $4 }'`
+ else
+ rcfile_owner=`ls -ld ${yule_data} | awk '{print $3 }'`
+ rcfile_group=samhain
+ fi
+ else
+ mytest_file=`basename $mytest_file`
+ rcfile_perm=`ls -l "${yule_data}/${mytest_file}" | \
+ awk '{ u= substr($1,2,3); g=substr($1,5,3); o=substr($1,8,3); \
+ gsub("-","",u); gsub("-","",g); gsub("-","",o); \
+ print "u=" u ",g=" g ",o=" o; }'`
+ rcfile_perm=`echo ${rcfile_perm} | sed s%g=,%g-rwx,% | sed s%,o=$%,o-rwx%`
+ rcfile_owner=`ls -l "${yule_data}/${mytest_file}" | \
+ awk '{print $3 }'`
+ rcfile_group=`ls -l "${yule_data}/${mytest_file}" | \
+ awk '{print $4 }'`
+ fi
+
+ if test -f "${hostconfig}"
+ then
+ if test x"$simulate" = x0
+ then
+ ageFILE "${yule_data}/rc.${host}" || printFATAL "Could not backup ${yule_data}/rc.${host}."
+ cp "${hostconfig}" "${yule_data}/rc.${host}" || printFATAL "Could not copy ${hostconfig} to ${yule_data}/rc.${host}"
+ chown ${rcfile_owner}:${rcfile_group} "${yule_data}/rc.${host}" || printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${yule_data}/rc.${host}"
+ chmod ${rcfile_perm} "${yule_data}/rc.${host}" || printFATAL "Could not chmod ${rcfile_perm} ${yule_data}/rc.${host}"
+ else
+ printINFO "Backup existing ${yule_data}/rc.${host}"
+ printINFO "Copy ${hostconfig} to ${yule_data}/rc.${host}"
+ fi
+ else
+ printFATAL "${hostconfig} is missing."
+ fi
+ printLOG "Server-side config file ${yule_data}/rc.${host} copied from ${hostconfig}."
+ fi
+
+ #---------------------------------------------------------------------
+ # Server entry and restart
+ #---------------------------------------------------------------------
+
+ instlock="${yule_conf}.lockdir";
+ trap "rm -rf ${instlock}" 1 2 13 15
+
+ if test x"$simulate" = x0
+ then
+ #
+ # A lockfile will not work, because 'root' can write anyway.
+ # However, 'mkdir' an existing directory will fail even for root
+ #
+ until (umask 222; mkdir "${instlock}") 2>/dev/null # test & set
+ do
+ printINFO "Waiting for lock"
+ sleep 1
+ done
+ fi
+
+ Replace=`"${yule_exec}" -P "${is_passwd}" | sed s%HOSTNAME%${host}%g`
+ if test "x$Replace" = x
+ then
+ rm -rf "${instlock}"
+ printFATAL "Could not execute ${yule_exec} -P ${is_passwd}."
+ fi
+ SearchString="Client=${host}@"
+ Seen=n
+ echo >"$tmpF" || printFATAL "Cannot write new server configuration."
+ while read line
+ do
+ if test "x$Seen" = xn
+ then
+ echo "$line" >>"$tmpF"
+ if test -n "`echo $line | awk '/^\[Clients\]/'`"
+ then
+ Seen=y
+ echo "$Replace" >>"$tmpF"
+ if [ $? -ne 0 ]; then
+ rm -rf "${instlock}"
+ printFATAL "Cannot write new server configuration."
+ fi
+ fi
+ else
+ if test -n "`echo $line | awk '/^'${SearchString}'/'`"
+ then
+ :
+ else
+ echo "$line" >>"$tmpF"
+ if [ $? -ne 0 ]; then
+ rm -rf "${instlock}"
+ printFATAL "Cannot write new server configuration."
+ fi
+ fi
+ fi
+ done <"${yule_conf}"
+
+ rcfile_perm=`ls -l "${yule_conf}" | \
+ awk '{ u= substr($1,2,3); g=substr($1,5,3); o=substr($1,8,3); \
+ gsub("-","",u); gsub("-","",g); gsub("-","",o); \
+ print "u=" u ",g=" g ",o=" o; }'`
+ rcfile_perm=`echo ${rcfile_perm} | sed s%g=,%g-rwx,% | sed s%,o=$%,o-rwx%`
+ rcfile_owner=`ls -l "${yule_conf}" | \
+ awk '{print $3 }'`
+ rcfile_group=`ls -l "${yule_conf}" | \
+ awk '{print $4 }'`
+
+ if test x"$simulate" = x0
+ then
+ ageFILE "${yule_conf}"
+ if [ $? -ne 0 ]; then
+ rm -rf "${instlock}"
+ printFATAL "Could not backup ${yule_conf}"
+ fi
+
+ rm -f "${yule_conf}" && cp "$tmpF" "${yule_conf}"
+ if [ $? -ne 0 ]; then
+ rm -rf "${instlock}"
+ printFATAL "Could not write new server config. Backup is ${yule_conf}.1"
+ fi
+
+ chown ${rcfile_owner}:${rcfile_group} "${yule_conf}"
+ if [ $? -ne 0 ]; then
+ rm -rf "${instlock}"
+ printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${yule_conf}"
+ fi
+
+ chmod ${rcfile_perm} "${yule_conf}"
+ if [ $? -ne 0 ]; then
+ rm -rf "${instlock}"
+ printFATAL "Could not chmod ${rcfile_perm} ${yule_conf}"
+ fi
+ else
+ printINFO "Backup and update ${yule_conf}"
+ fi
+
+ if test "x${local_command}" = x
+ then
+ :
+ else
+ if test x"$simulate" = x0
+ then
+ eval "${local_command}" "${host}" "${arch}" "${basedir}" "${yule_data}" "first"
+ else
+ printINFO "eval ${local_command} ${host} ${arch} ${basedir} ${yule_data} first"
+ fi
+ fi
+
+ yule_name=`basename "${yule_exec}"`
+
+ if test x"$simulate" = x0
+ then
+ if test -f "/etc/init.d/${yule_name}"
+ then
+ eval "/etc/init.d/${yule_name}" reload
+ if test x"$?" != x0
+ then
+ printWARNING "Could not reload server using: /etc/init.d/${yule_name} reload."
+ fi
+ else
+ eval "${yule_exec}" reload
+ if test x"$?" != x0
+ then
+ printWARNING "Could not reload server using: ${yule_exec} reload."
+ fi
+ fi
+ #
+ # wait for the server to pick up the new configuration
+ #
+ sleep 5
+ #
+ rm -rf "${instlock}"
+ else
+ printINFO "Reloading server configuration."
+ fi
+
+ printLOG "Server configuration updated and reloaded."
+
+
+ #---------------------------------------------------------------------
+ # Write/update client database
+ #---------------------------------------------------------------------
+
+ SH_NAME=`/bin/sh ${basedir}/archpkg/${arch}/install-${src_version}.${realformat} --print-config name`; export SH_NAME
+ SH_PREFIX=`/bin/sh ${basedir}/archpkg/${arch}/install-${src_version}.${realformat} --print-config prefix`; export SH_PREFIX
+
+ if test x"$simulate" = x0
+ then
+ updateDB
+ else
+ printINFO "Updating client database."
+ fi
+
+ #---------------------------------------------------------------------
+ # Initialize and fetch database
+ #---------------------------------------------------------------------
+
+ if test "x${is_init}" = xy
+ then
+ if test x"$simulate" = x0
+ then
+ if test x"$silent" != x0
+ then
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && chmod +x initscript && ./initscript ${is_nocl} >/dev/null 2>&1 )'\'
+ else
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && chmod +x initscript && ./initscript ${is_nocl} >/dev/null 2>&1 )'\'
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not initialize database on host ${host}."
+ else
+ printLOG "Database initialized on host ${host}"
+ fi
+ scp -q "root@${host}:${tmpdir}/data" "$tmpD" || \
+ printFATAL "Could not retrieve database file root@${host}:${tmpdir}/data"
+ else
+ printINFO "ssh -x -l root ${host} /bin/sh -c '(cd ${tmpdir} && chmod +x initscript && ./initscript ${is_nocl})'"
+ printLOG "Database initialized on host ${host}"
+ printINFO "scp -q root@${host}:${tmpdir}/data $tmpD"
+ fi
+
+ mytest_file=`ls -1 "${yule_data}/file*" 2>/dev/null | tail -n 1 2>/dev/null`
+ if test "x$mytest_file" = x; then
+ rcfile_perm=640;
+ xgid=`(cat /etc/group; ypcat group) 2>/dev/null |\
+ grep "^samhain:" | awk -F: '{ print $3; }'`
+ if test "x$xgid" = x; then
+ rcfile_owner=`ls -ld ${yule_data} | awk '{print $3 }'`
+ rcfile_group=`ls -ld ${yule_data} | awk '{print $4 }'`
+ else
+ rcfile_owner=`ls -ld ${yule_data} | awk '{print $3 }'`
+ rcfile_group=samhain
+ fi
+ else
+ mytest_file=`basename $mytest_file`
+ rcfile_perm=`ls -l "${yule_data}/${mytest_file}" | \
+ awk '{ u= substr($1,2,3); g=substr($1,5,3); o=substr($1,8,3); \
+ gsub("-","",u); gsub("-","",g); gsub("-","",o); \
+ print "u=" u ",g=" g ",o=" o; }'`
+ rcfile_perm=`echo ${rcfile_perm} | sed s%g=,%g-rwx,% | sed s%,o=$%,o-rwx%`
+ rcfile_owner=`ls -l "${yule_data}/${mytest_file}" | \
+ awk '{print $3 }'`
+ rcfile_group=`ls -l "${yule_data}/${mytest_file}" | \
+ awk '{print $4 }'`
+ fi
+
+ if test x"$simulate" = x0
+ then
+ if test -f "$tmpD/data"
+ then
+ ageFILE "${yule_data}/file.${host}" || printFATAL "Could not backup ${yule_conf}."
+ mv "$tmpD/data" "${yule_data}/file.${host}" || printFATAL "Could not move database file to ${yule_data}/file.${host}"
+ chown ${rcfile_owner}:${rcfile_group} "${yule_data}/file.${host}" || printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${yule_data}/file.${host}"
+ chmod ${rcfile_perm} "${yule_data}/file.${host}" || printFATAL "Could not chmod ${rcfile_perm} ${yule_data}/file.${host}"
+ else
+ printFATAL "Database file not downloaded from host ${host}"
+ fi
+ else
+ printINFO "Backup and replace ${yule_data}/file.${host}"
+ fi
+ fi
+
+ #---------------------------------------------------------------------
+ # Start up.
+ #---------------------------------------------------------------------
+
+ if test "x${local_command}" = x
+ then
+ :
+ else
+ if test x"$simulate" = x0
+ then
+ eval "${local_command}" "${host}" "${arch}" "${basedir}" "${yule_data}" "second"
+ else
+ printINFO "eval ${local_command} ${host} ${arch} ${basedir} ${yule_data} second"
+ fi
+ fi
+
+ if test "x${is_startup}" = xy
+ then
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" '(cd "'${tmpdir}'" && chmod +x initscript && eval "'./initscript ${is_nocl} start'")'
+ else
+ printINFO "Starting remote client now."
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not start client on host ${host}."
+ else
+ printLOG "Client started on host ${host}."
+ fi
+ fi
+
+ #---------------------------------------------------------------------
+ # Clean up.
+ #---------------------------------------------------------------------
+
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" '(rm -rf "'${tmpdir}'")'
+ else
+ printINFO "ssh -x -l root ${host} (rm -rf ${tmpdir})"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not remove temporary directory ${tmpdir} on host ${host}."
+ else
+ printLOG "Directory ${tmpdir} deleted on host ${host}."
+ fi
+
+}
+
diff --git a/dsys/comUNINSTALL b/dsys/comUNINSTALL
new file mode 100644
index 0000000..1f51508
--- /dev/null
+++ b/dsys/comUNINSTALL
@@ -0,0 +1,188 @@
+#########################################################################
+#
+# Subroutine for the 'uninstall' command
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+commandUNINSTALL() {
+
+ printINFO "About to run \"$action\" on host \"$host\""
+
+ format=`setupFORMAT ${DB_version}`
+ realformat="$format"
+
+ src_version=`setupVERSION ${DB_version}`
+
+ test -f "${basedir}/archpkg/${DB_arch}/install-${DB_version}" || \
+ printFATAL "Install script ${DB_arch}/install-${DB_version} not found"
+
+ name=`/bin/sh "${basedir}/archpkg/${DB_arch}/install-${DB_version}" '--print-config' 'name'`
+
+ test x"$name" = x"${DB_name}" || \
+ printFATAL "Client database and installer files are inconsistent"
+
+ arch="${DB_arch}"
+
+ #---------------------------------------------------------------------
+ # Uninstall.
+ #---------------------------------------------------------------------
+
+ if test "x$format" = "xrun"; then
+ is_command="./samhain-install.sh --force --express purge"
+ target="uninstall"
+ elif test "x$format" = "xdeb"; then
+ is_command="dpkg --purge"
+ target="${DB_name}"
+ elif test "x$format" = "xrpm"; then
+ is_command="rpm --erase"
+ target="${DB_name}"
+ elif test "x$format" = "xtbz2"; then
+ is_command="emerge unmerge"
+ target="${DB_name}"
+ elif test "x$realformat" = "xpkg"; then
+ is_command="pkgremove"
+ target="${DB_name}"
+ elif test "x$realformat" = "xdepot"; then
+ is_command="/usr/sbin/swremove"
+ target="${DB_name}"
+ else
+ printFATAL "Don't know how to uninstall package format ${format}"
+ fi
+
+ if test x"$silent" = x0
+ then
+ is_rmboot="./samhain-install.sh --force --express uninstall-boot"
+ else
+ is_rmboot="./samhain-install.sh --force --express --verbose uninstall-boot"
+ fi
+
+ #---------------------------------------------------------------------
+ # Create temporary directory on host.
+ #---------------------------------------------------------------------
+
+ tmpdir=`eval echo "${temp_dir}/sh_${src_version}_${arch}_${format}_$$"`
+
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" '(umask 0077; mkdir "'${tmpdir}'")'
+ else
+ printINFO "ssh -x -l root ${host} (umask 0077; mkdir ${tmpdir})"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not create temporary directory ${tmpdir} on host ${host}."
+ else
+ printLOG "Directory ${tmpdir} created on host ${host}."
+ fi
+
+ #---------------------------------------------------------------------
+ # Copy to host.
+ #---------------------------------------------------------------------
+
+ if test -f "${basedir}/configs/${arch}.initscript"
+ then
+ cp "${basedir}/configs/${arch}.initscript" "${tmpD}/initscript" || \
+ printFATAL "Could not copy ${basedir}/configs/${arch}.initscript to ${tmpD}/initscript"
+ is_initscript_full="${tmpD}/initscript"
+ else
+ is_initscript_full="${basedir}/libexec/initscript"
+ fi
+
+ if test x"$simulate" = x0
+ then
+ if test x"$silent" = x0
+ then
+ scp "${is_initscript_full}" "${basedir}/archpkg/${arch}/install-${src_version}.${format}" "root@${host}:${tmpdir}/"
+ else
+ scp -q "${is_initscript_full}" "${basedir}/archpkg/${arch}/install-${src_version}.${format}" "root@${host}:${tmpdir}/"
+ fi
+ else
+ if test x"$silent" = x0
+ then
+ printINFO "scp ${is_initscript_full} ${basedir}/archpkg/${arch}/install-${src_version}.${format} root@${host}:${tmpdir}/"
+ else
+ printINFO "scp -q ${is_initscript_full} ${basedir}/archpkg/${arch}/install-${src_version}.${format} root@${host}:${tmpdir}/"
+ fi
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not copy uninstall script to host ${host}."
+ else
+ printINFO "Script copied to host ${host}."
+ fi
+
+
+ #---------------------------------------------------------------------
+ # Run uninstall script.
+ #---------------------------------------------------------------------
+ if test x"$simulate" = x0
+ then
+ #
+ # No, this is not a bug; the first 'start' argument to 'initscript'
+ # is a required dummy argument.
+ #
+ if test x"$silent" = x0
+ then
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH'" && export PATH && cp "'install-${src_version}.${format}'" samhain-install.sh && chmod +x samhain-install.sh && chmod +x initscript && ./initscript start stop; eval "'${is_command}'" "'${target}'"; eval "'${is_rmboot}'")'\'
+ else
+ ssh -x -l "root" "${host}" /bin/sh -c \''(cd "'${tmpdir}'" && PATH="'/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH'" && export PATH && cp "'install-${src_version}.${format}'" samhain-install.sh && chmod +x samhain-install.sh && chmod +x initscript && ./initscript start stop; eval "'${is_command}'" "'${target}'"; eval "'${is_rmboot}'") >/dev/null'\'
+ fi
+ else
+ printINFO "ssh -x -l root ${host} (cd ${tmpdir} && && PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:\$PATH && export PATH cp install-${src_version}.${realformat} samhain-install.sh && chmod +x samhain-install.sh && chmod +x initscript && ./initscript start stop; eval "${is_command}" "${target}"; eval "${is_rmboot}")"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not complete uninstall on host ${host}."
+ else
+ printLOG "Uninstall executed on host ${host}"
+ fi
+
+ #---------------------------------------------------------------------
+ # Clean up.
+ #---------------------------------------------------------------------
+
+ if test x"$simulate" = x0
+ then
+ ssh -x -l "root" "${host}" '(rm -rf "'${tmpdir}'")'
+ else
+ printINFO "ssh -x -l root ${host} (rm -rf ${tmpdir})"
+ fi
+ if test x"$?" != x0
+ then
+ printFATAL "Could not remove temporary directory ${tmpdir} on host ${host}."
+ else
+ printLOG "Directory ${tmpdir} deleted on host ${host}."
+ fi
+
+ #---------------------------------------------------------------------
+ # Write/update client database
+ #---------------------------------------------------------------------
+
+ SH_NAME="$name"; export SH_NAME
+ SH_PREFIX=`/bin/sh ${basedir}/archpkg/${DB_arch}/install-${DB_version} --print-config prefix`; export SH_PREFIX
+
+ if test x"$simulate" = x0
+ then
+ updateDB D2_removed
+ else
+ printINFO "Updating client database."
+ fi
+}
diff --git a/dsys/funcBUILD b/dsys/funcBUILD
new file mode 100644
index 0000000..6226141
--- /dev/null
+++ b/dsys/funcBUILD
@@ -0,0 +1,251 @@
+#########################################################################
+#
+# Subroutine for bulding from source
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#------------------------------------------------------------------------
+# List available sources
+#------------------------------------------------------------------------
+listSRC() {
+
+
+ OKSRCLIST=""; export OKSRCLIST
+
+ echo > $tmpF;
+
+ needEXE ls gpg
+
+ cd "${basedir}/source" || printFATAL "could not cd to ${basedir}/source"
+
+ LIST=`ls samhain*.tar.gz 2>/dev/null`
+
+ if test x"$LIST" = x
+ then
+ printFATAL "No source tarball found in ${basedir}/source. Please use 'deploy.sh download'."
+ fi
+
+ for ff in $LIST
+ do
+ sh_version=`echo "$ff" | sed 's/.*samhain\-//g' | sed 's/\.tar\.gz//g'`
+ if test x"${sh_version}" = x
+ then
+ printFATAL "Cannot determine version for $ff"
+ fi
+
+ if test "$ff" != "samhain-${sh_version}.tar.gz"
+ then
+ printFATAL "Version number not correctly extracted from $ff"
+ fi
+
+ if test -f "samhain-${sh_version}.tar.gz.asc"
+ then
+ :
+ else
+ printWARNING "No detached signature for $ff found"
+ continue
+ fi
+
+ sig_lines=`(LANG="C"; gpg --status-fd 1 --verify "samhain-${sh_version}.tar.gz.asc" "samhain-${sh_version}.tar.gz" 2>/dev/null)`
+ sig_ok=`echo ${sig_lines} | grep 'GOODSIG'`
+ sig_nokey=`echo ${sig_lines} | grep 'NO_PUBKEY'`
+
+ if test x"${sig_nokey}" != x
+ then
+ printWARNING "Public key (ID 0F571F6C) not found, trying to import it."
+ gpg --import ${basedir}/private/0F571F6C.asc 2>&5
+ sig_lines=`(LANG="C"; gpg --status-fd 1 --verify "samhain-${sh_version}.tar.gz.asc" "samhain-${sh_version}.tar.gz" 2>/dev/null)`
+ sig_ok=`echo ${sig_lines} | grep 'GOODSIG'`
+ sig_nokey=`echo ${sig_lines} | grep 'NO_PUBKEY'`
+ fi
+
+ if test x"${sig_nokey}" != x
+ then
+ printFATAL "Importing public key failed."
+ fi
+
+ if test x"${sig_ok}" = x
+ then
+ printWARNING "File $ff has no good signature"
+ continue
+ fi
+
+ if test x"$1" = x
+ then
+ OKSRCLIST="$OKSRCLIST ${sh_version}"
+ else
+ if test x"$1" = x"${sh_version}"
+ then
+ OKSRCLIST="${sh_version}"
+ return 0
+ fi
+ fi
+ done
+
+ if test x"$OKSRCLIST" = x
+ then
+ printFATAL "No source tarball found. Please use 'deploy.sh download'."
+ fi
+
+ for dd in $OKSRCLIST
+ do
+ echo $dd >> "$tmpF"
+ done
+
+ OKSRCLIST=`cat "$tmpF" | sort -r | sed 9q`
+ export OKSRCLIST
+
+ rm -f "$tmpF" && touch "$tmpF"
+ echo $OKSRCLIST > "$tmpF"
+
+ return 0
+}
+
+selBVERSION() {
+ #---------------------------------------------------------------------
+ # Select version to build
+ #---------------------------------------------------------------------
+ if test x"$src_version" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "No version selected, aborting."
+ fi
+
+ promptINFO "Checking which versions are available"
+
+ ((listSRC | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ OKSRCLIST=`cat "$tmpF"`
+ n=0
+ for word in $OKSRCLIST
+ do
+ n=`expr $n + 1`
+ eval part$n="$word"
+ done
+
+ command="promptMENU 'Please select version to build' "
+ for word in $OKSRCLIST
+ do
+ command="$command '${word}'"
+ done
+ eval ${command}
+ m=$?
+ if test x$m = x1
+ then
+ (exit 0); exit 0;
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ src_version="$MENU"; export src_version
+ fi
+
+ else
+ ((listSRC "$src_version" | tee -a "$lastlog") 6>&1 1>&2 2>&6 | \
+ tee -a "$lastlog") 6>&1 1>&2 2>&6
+ fi
+}
+
+selBARCH() {
+ #---------------------------------------------------------------------
+ # Select arch to build
+ #---------------------------------------------------------------------
+ if test x"$arch" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "No operating system selected, aborting."
+ fi
+ cd "$basedir"/configs || printFATAL "Cannot cd to $basedir/configs !"
+ LIST=`ls *.configure 2>/dev/null`
+ if test x"$LIST" = x
+ then
+ printFATAL "No config files found in ${basedir}/configs."
+ fi
+
+ n=0
+ command="promptMENU 'Please select operating system of build host' "
+ ALIST=""
+ FLIST=""
+ for ff in $LIST
+ do
+ n=`expr $n + 1`
+ osp=`echo $ff | sed s/\.configure//`
+ ALIST="$ALIST $osp"
+ FLIST="$FLIST $osp"
+ if test $n -lt 8
+ then
+ command="$command '${osp}'"
+ fi
+ done
+ command="$command other"
+
+ eval ${command}
+ m=$?
+ if test x$m = x1
+ then
+ (exit 0); exit 0;
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ arch="$MENU"; export arch
+ if test x"$arch" = xother
+ then
+ promptINPUT "Please select operating system of build host from $FLIST or enter new one"
+ if test x$m = x1
+ then
+ (exit 0); exit 0;
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ found=`echo $FLIST | sed -n /$INPUT/p 2>/dev/null`
+ if test x"$found" = x
+ then
+ printLOG "Copy configuration for $INPUT from generic"
+ cp generic.configure "${INPUT}.configure"
+ fi
+ arch="$INPUT"; export arch
+ fi
+ fi
+ fi
+
+ fi
+ # arch selected or exited
+}
+
+selBFORMAT() {
+ if test x"$format" = x
+ then
+ promptMENU "Please select format of binary package" "run" "rpm" "deb" "tbz2" "solaris-pkg" "depot"
+ if test x$m = x1
+ then
+ (exit 0); exit 0
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ format="$MENU"; export format
+ fi
+ fi
+}
diff --git a/dsys/funcDB b/dsys/funcDB
new file mode 100644
index 0000000..8713b09
--- /dev/null
+++ b/dsys/funcDB
@@ -0,0 +1,311 @@
+#########################################################################
+#
+# More subroutines for client DB
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+DBFTEST=0
+
+dbSETFLAG() {
+ case "$line" in
+ *\</client\>*)
+ DBFTEST=0;
+ return 0;
+ ;;
+
+ *\<client_host\>${DB_host}\</client_host\>*)
+ DBFTEST=1;
+ return 1;
+ ;;
+
+ *)
+ return ${DBFTEST};
+ ;;
+ esac
+}
+
+
+DB_arch=""; export DB_arch;
+DB_status=""; export DB_status;
+DB_version=""; export DB_version;
+DB_date=""; export DB_date;
+DB_name=""; export DB_name;
+
+dbINFO() {
+
+ if test "x$1" = x
+ then
+ printFATAL "No host specified, aborting"
+ else
+ DB_host="$1"
+ fi
+
+ DB_arch=""; export DB_arch;
+ DB_status=""; export DB_status;
+ DB_version=""; export DB_version;
+ DB_date=""; export DB_date;
+ DB_name=""; export DB_name;
+
+ if test x"$DATABASE" = x
+ then
+ DATABASE="${basedir}/${defdatabase}"
+ fi
+
+ if test -f "${DATABASE}"
+ then
+ SStr1=`grep '<yule_db>' "${DATABASE}"`
+ if test "x${SStr1}" != "x"
+ then
+
+ SStr2=`grep "<client_host>${DB_host}</client_host>" "${DATABASE}"`
+
+ SStr3=
+
+ if test "x${SStr2}" != "x"
+ then
+ exec 3<&0 <"${DATABASE}"
+ while
+ read line
+ do
+ # for some reason, var=xx only works in a function call (why?)
+ #
+ # here we test if we are still in the same client block
+ # (set_flag will return 0 for </client> and following)
+ dbSETFLAG "$line"
+
+ if test "x$?" = "x1"
+ then
+ case "$line" in
+ *\<client_os_machine\>*\</client_os_machine\>)
+ DB_arch=`echo "$line" | sed '/^\(.*\)<client_os_machine>\([0-9a-zA-Z_-]*\)<\/client_os_machine>\(.*\)$/{ s//\2/; q; }'`
+ export DB_arch
+ ;;
+
+ *\<client_install_status\>*\</client_install_status\>)
+ DB_status=`echo "$line" | sed '/^\(.*\)<client_install_status>\([0-9a-zA-Z_-]*\)<\/client_install_status>\(.*\)$/{ s//\2/; q; }'`
+ export DB_status
+ ;;
+
+ *\<client_install_date\>*\</client_install_date\>)
+ DB_date=`echo "$line" | sed '/^\(.*\)<client_install_date>\([ 0-9a-zA-Z_.:,-]*\)<\/client_install_date>\(.*\)$/{ s//\2/; q; }'`
+ export DB_date
+ ;;
+
+ *\<client_install_name\>*\</client_install_name\>)
+ DB_name=`echo "$line" | sed '/^\(.*\)<client_install_name>\([0-9a-zA-Z_-]*\)<\/client_install_name>\(.*\)$/{ s//\2/; q; }'`
+ export DB_name
+ ;;
+
+ *\<client_install_prefix\>*\</client_install_prefix\>)
+ ;;
+
+ *\<client_install_version\>*\</client_install_version\>)
+ DB_version=`echo "$line" | sed '/^\(.*\)<client_install_version>\([0-9a-zA-Z_.-]*\)<\/client_install_version>\(.*\)$/{ s//\2/; q; }'`
+ export DB_version
+ ;;
+
+ *)
+ ;;
+
+ esac
+ else
+ :
+ fi
+ done
+ exec 0<&3 3<&-
+ return 0
+ else
+ printINFO "Host ${DB_host} not found in client database"
+ return 1
+ fi
+ else
+ printINFO "Client database ${DATABASE} in bad shape"
+ return 1
+ fi
+ else
+ printINFO "Client database ${DATABASE} not available"
+ return 1
+ fi
+}
+
+DB_hostlist=""; export DB_hostlist
+
+dbHOSTLIST() {
+
+ DB_hostlist=""; export DB_hostlist
+
+ if test x"$DATABASE" = x
+ then
+ DATABASE="${basedir}/${defdatabase}"
+ fi
+
+ if test -f "${DATABASE}"
+ then
+ DB_hostlist=`cat "${DATABASE}" | grep 'client_host' | sed '/^\(.*\)<client_host>\([0-9a-zA-Z.-]*\)<\/client_host>\(.*\)$/{ s//\2/; }' | sort`
+ export DB_hostlist
+ return 0
+ else
+ printINFO "Client database ${DATABASE} not available"
+ return 1
+ fi
+}
+
+dbSHOWHOSTS() {
+
+ if test "x$1" = x
+ then
+ dbHOSTLIST
+ else
+ DB_hostlist="$1"
+ fi
+
+ if test "x$?" = x1
+ then
+ printLOG "No known hosts - database unavailable"
+ fi
+ if test "x${DB_hostlist}" = x
+ then
+ printLOG "No known hosts - database unavailable, empty, or corrupt"
+ fi
+
+ for ff in ${DB_hostlist}
+ do
+ dbINFO "$ff"
+
+
+ if test "x$?" = x1
+ then
+ :
+ else
+ test -z "${DB_date}" && DB_date="INDEF"
+ test -z "${DB_arch}" && DB_arch="INDEF"
+ test -z "${DB_version}" && DB_version="INDEF"
+
+ tmp_status="-"
+ if test "x$DB_status" = xinstalled
+ then
+ tmp_status="o"
+ elif test "x$DB_status" = xD2_installed
+ then
+ tmp_status="i"
+ elif test "x$DB_status" = xD2_removed
+ then
+ tmp_status="u"
+ fi
+ out=`echo | awk '{ printf "%1s %14s %-11s %19s %s\n", "'"${tmp_status}"'", "'"${DB_arch}"'", "'"${DB_version}"'", "'"${DB_date}"'", "'"${ff}"'" }'`
+ printINFO "${out}"
+ fi
+ done
+}
+
+
+dbSHOWPKG() {
+
+ delete=no
+ show=no
+
+ if test x"$1" = xshow
+ then
+ show=yes
+ fi
+ if test x"$2" = xdelete
+ then
+ delete=yes
+ fi
+
+ cd "${basedir}/archpkg" || printFATAL "Cannot cd to ${basedir}/archpkg"
+
+ dbHOSTLIST
+
+ if test x"$DATABASE" = x
+ then
+ DATABASE="${basedir}/${defdatabase}"
+ fi
+
+ LIST=`ls`
+ this_dir=`pwd`
+
+ for dd in $LIST
+ do
+ if test -d "$dd"
+ then
+ cd "$dd"
+
+ PKGLIST=`ls samhain-* 2>/dev/null`
+
+ for ff in $PKGLIST
+ do
+ if test -f "$ff"
+ then
+ version=`echo "$ff" | sed -e 's%samhain-%%'`
+
+ tmp_status="-"
+
+ grep "$version" "${DATABASE}" >/dev/null 2>&1
+ if test "x$?" = x0
+ then
+ for hh in ${DB_hostlist}
+ do
+ dbINFO "$hh"
+ if test x"${DB_arch}" = x"${dd}" && \
+ test x"${DB_version}" = x"${version}"
+ then
+ tmp_status="-"
+ if test "x$DB_status" = xinstalled
+ then
+ tmp_status="o"
+ elif test "x$DB_status" = xD2_installed
+ then
+ tmp_status="i"
+ fi
+ break
+ fi
+ done
+ else
+ tmp_status="-"
+ fi
+
+ if test x"${show}" = xyes
+ then
+ printINFO "${tmp_status} ${dd}/${version}"
+ fi
+
+ if test x"${delete}" = xyes && test x"${tmp_status}" = "x-"
+ then
+ printLOG "REMOVE ${dd}/${version}"
+
+ if test x"$simulate" = x0
+ then
+ rm -f "samhain-${version}"
+ rm -f "install-${version}"
+ rm -f "configure-${version}"
+ else
+ printINFO "rm -f ${dd}/samhain-${version}"
+ printINFO "rm -f ${dd}/install-${version}"
+ printINFO "rm -f ${dd}/configure-${version}"
+ fi
+ fi
+ fi
+ done
+ cd "${this_dir}"
+ fi
+ done
+}
diff --git a/dsys/funcDIALOG b/dsys/funcDIALOG
new file mode 100644
index 0000000..ac504c8
--- /dev/null
+++ b/dsys/funcDIALOG
@@ -0,0 +1,354 @@
+#########################################################################
+#
+# Interaction Subroutines
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# print without newline
+#
+printASK() {
+ echo $ECHO_N "$@ $ECHO_C"
+}
+
+# find a 'dialog' program
+#
+findDIALOG() {
+
+ if test x"$DIALOG" = xno
+ then
+ DIALOG=""; return 0
+ elif test -n "$DIALOG"
+ then
+ return 0
+ fi
+
+ PATH=/usr/local/bin:/usr/local/sbin:$PATH; export PATH
+ X="$PATH"
+ progs="dialog";
+ OLD_IFS=${IFS}
+ IFS=':'; export IFS
+ for dir in $X; do
+ for dia in $progs; do
+ dialog="$dir/$dia"
+ if (test -f "$dialog" || test -f "$dialog.exe")
+ then
+ if "$dialog" 2>&1 | grep tailbox >/dev/null 2>&1
+ then
+ IFS=${OLD_IFS}; export IFS
+ DIALOG="$dialog"; export DIALOG
+ return 0
+ fi
+ fi
+ done
+ done
+ IFS=${OLD_IFS}; export IFS
+ DIALOG=""; export DIALOG
+}
+
+
+# prompt user for yes/no
+#
+promptYESNO() {
+ if test $# -lt 1
+ then
+ printFATAL "promptYESNO: insufficient arguments"
+ fi
+
+ if test $silent -gt 1
+ then
+ YESNO=y; export YESNO
+ return 0
+ fi
+
+ DEFAULT=""
+ case "$2" in
+ [yY]|[yY][eE][sS])
+ DEFAULT=y ;;
+ [nN]|[nN][oO])
+ DEFAULT=n ;;
+ esac
+
+ YESNO=""
+
+ if test -n "$DIALOG"
+ then
+
+ if test x"$assumeyes" = x1
+ then
+ YESNO="$DEFAULT"; export YESNO
+ return 0
+ fi
+
+ "$DIALOG" --title "deploy.sh $version" --yesno "$1" 10 75 2>"$tmpF"
+ mtest=$?
+ if test x"$mtest" = "x-1"
+ then
+ printFATAL "promptYESNO: something went wrong"
+ elif test x"$mtest" = x0
+ then
+ YESNO=y
+ else
+ YESNO=n
+ fi
+ else
+ while :
+ do
+ if test x"$DEFAULT" = xy
+ then
+ printASK "$1 (Y/n) ?"
+ elif test x"$DEFAULT" = xn
+ then
+ printASK "$1 (N/y) ?"
+ else
+ printASK "$1 (y/n) ?"
+ fi
+
+ if test x"$assumeyes" = x1
+ then
+ YESNO="$DEFAULT"; export YESNO
+ echo "$DEFAULT"
+ return 0
+ fi
+
+ read YESNO
+ if test -z "$YESNO"
+ then
+ YESNO="$DEFAULT"
+ fi
+
+ case "$YESNO" in
+ [yY]|[yY][eE][sS])
+ YESNO=y; break ;;
+ [nN]|[nN][oO])
+ YESNO=n; break ;;
+ *)
+ YESNO="" ;;
+ esac
+ done
+ fi
+ export YESNO
+ return 0
+}
+
+# get user input from tmp file
+#
+getINPUT() {
+ INPUT=`cat $tmpF`
+ export INPUT
+ return 0
+}
+
+# info box
+#
+promptINFO() {
+ if test $# -lt 1
+ then
+ printFATAL "promptINPUT: insufficient arguments"
+ fi
+
+ if test x"$silent" != x0
+ then
+ return 0
+ fi
+
+ if test -n "$DIALOG"
+ then
+ "$DIALOG" --title "deploy.sh $version" --sleep 2 --infobox "$1" 8 75
+ else
+ echo $1
+ fi
+ return 0
+}
+
+# prompt user for input
+#
+promptINPUT() {
+ if test $# -lt 1
+ then
+ printFATAL "promptINPUT: insufficient arguments"
+ fi
+
+ if test $assumeyes -gt 0
+ then
+ printFATAL "promptINPUT: user interaction required"
+ fi
+
+ INPUT=""
+ DEFAULT="$2"
+
+ if test -n "$DIALOG"
+ then
+ "$DIALOG" --title "deploy.sh $version" --inputbox "$1" 16 75 "$2" 2>"$tmpF"
+ mtest=$?
+ if test x"$mtest" = "x1"
+ then
+ # cancel button
+ (exit 0); exit 0;
+ fi
+ if test x"$mtest" = "x-1"
+ then
+ printFATAL "promptINPUT: something went wrong"
+ else
+ getINPUT
+ fi
+ else
+
+ while :
+ do
+ if test -z "$DEFAULT"
+ then
+ printASK "$1 ?"
+ else
+ printASK "$1 ? $DEFAULT"
+ fi
+
+ read INPUT
+
+ if test -z "$INPUT"
+ then
+ if test -n "$DEFAULT"
+ then
+ locINPUT="$DEFAULT"
+ break
+ fi
+ elif test -n "$INPUT"
+ then
+ break
+ fi
+ done
+ export INPUT
+ fi
+ return 0
+}
+
+# get MENU from tmp file
+#
+getMENU() {
+ MENU=`cat $tmpF`
+ export MENU
+ return 0
+}
+
+# prompt user for options from menu
+#
+promptMENU() {
+ if test $# -lt 2
+ then
+ printFATAL "promptMENU: insufficient arguments"
+ fi
+
+ if test $assumeyes -gt 0
+ then
+ printFATAL "promptMENU: user interaction required"
+ fi
+
+ TITLE="$1"
+ shift
+
+ if test -n "$DIALOG"
+ then
+ #command="'$DIALOG' '--title' \\'deploy.sh $version\\' '--backtitle'"
+ #command="$command \'$TITLE\' '--menu' \'$TITLE\' '16' '75' '$#'"
+
+ argc=$#
+ if test $argc -gt 7
+ then
+ argc=7
+ fi
+
+ command="'$1' '' 'on'"
+ shift
+
+ for item
+ do
+ command="$command '$item' '' 'off'"
+ done
+
+ command="$command "
+
+ # printFATAL "$command"
+ eval $DIALOG '--title' \'deploy.sh $version\' '--backtitle' \'$TITLE\' '--radiolist' \'$TITLE\' '16' '75' $argc $command 2>"$tmpF"
+
+ mtest=$?
+
+ if test x"$mtest" = "x1"
+ then
+ # cancel button
+ (exit 0); exit 0;
+ fi
+ if test x"$mtest" = "x-1"; then
+ printFATAL "promptMENU: something went wrong"
+ else
+ getMENU
+ fi
+ else
+
+ MENU=""
+ INPUT=""
+
+ while :
+ do
+ clear
+ echo
+ echo "$TITLE"
+ echo
+ echo " 1) $1"
+ test -n "$2" && echo " 2) $2"
+ test -n "$3" && echo " 3) $3"
+ test -n "$4" && echo " 4) $4"
+ test -n "$5" && echo " 5) $5"
+ test -n "$6" && echo " 6) $6"
+ test -n "$7" && echo " 7) $7"
+ test -n "$8" && echo " 8) $8"
+ test -n "$9" && echo " 9) $9"
+ echo
+ printASK "Please enter your choice: "
+
+ read INPUT
+
+ if echo "$INPUT" | grep '[^0123456789]' >/dev/null 2>&1
+ then
+ :
+ elif test $INPUT -gt $#
+ then
+ :
+ else
+ break
+ fi
+ done
+
+ case "$INPUT" in
+ 1) MENU="$1"; break ;;
+ 2) MENU="$2"; break ;;
+ 3) MENU="$3"; break ;;
+ 4) MENU="$4"; break ;;
+ 5) MENU="$5"; break ;;
+ 6) MENU="$6"; break ;;
+ 7) MENU="$7"; break ;;
+ 8) MENU="$8"; break ;;
+ 9) MENU="$9"; break ;;
+ esac
+
+ export MENU
+ fi
+ return 0
+}
+
diff --git a/dsys/funcEXE b/dsys/funcEXE
new file mode 100644
index 0000000..17f1e39
--- /dev/null
+++ b/dsys/funcEXE
@@ -0,0 +1,57 @@
+#########################################################################
+#
+# Subroutines for determining existence of / path to executables
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+findEXE() {
+ if test $# -lt 1
+ then
+ printFATAL "findEXE: insufficient arguments"
+ fi
+
+ X="$PATH";
+ prog="$1";
+ OLD_IFS=${IFS}
+ IFS=':'; export IFS
+ for dir in $X; do
+ exe="$dir/$1"
+ if (test -f "$exe" || test -f "${exe}.exe")
+ then
+ EXECUTABLE="$exe"; export EXECUTABLE
+ IFS=${OLD_IFS}; export IFS
+ return 0
+ fi
+ done
+ IFS=${OLD_IFS}; export IFS
+ printINFO "Command $1 not found in \$PATH"
+ EXECUTABLE=""; export EXECUTABLE
+}
+
+needEXE() {
+ # printINFO "Checking for $@"
+ for arg
+ do
+ findEXE "$arg"
+ test -z "$EXECUTABLE" && printFATAL "Need \"$arg\" in \$PATH"
+ done
+ return 0
+}
diff --git a/dsys/funcINSTALL b/dsys/funcINSTALL
new file mode 100644
index 0000000..1e7f3d1
--- /dev/null
+++ b/dsys/funcINSTALL
@@ -0,0 +1,509 @@
+#########################################################################
+#
+# Subroutines for installing
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+getconfopts () {
+ fconf="$1"
+
+ if test -f "$fconf"
+ then
+ #
+ # check if readable
+ #
+ cat "$fconf" >/dev/null 2>&1 || return 1
+ #
+ # empty string if no --enable-nocl=..., else password
+ #
+ is_nocl=`cat "$fconf" | tr -d '\n' | egrep "^ *'?--enable-nocl=" | sed -e "s%^ *%%" | sed -e "s%^'%%" | sed -e "s%^--enable-nocl=%%" | sed -e "s% *$%%" | sed -e "s%'$%%"`
+ if test x"${is_nocl}" = x
+ then
+ is_nocl="start"
+ else
+ printINFO "Option --enable-nocl=${is_nocl} used."
+ fi
+ #
+ #
+ #
+ is_xor=`cat "$fconf" | tr -d '\n' | egrep "^ *'?--enable-stealth=" | sed -e "s%^ *%%" | sed -e "s%^'%%" | sed -e "s%^--enable-nocl=%%" | sed -e "s% *$%%" | sed -e "s%'$%%"`
+ if test x"${is_xor}" = x
+ then
+ is_xor="no"
+ else
+ printINFO "Option --enable-stealth=${is_xor} used."
+ fi
+ return 0
+ else
+ return 1
+ fi
+}
+
+writerecord () {
+ IDATE=`date +"%Y-%m-%d %H:%M:%S"`
+ echo " <client>"
+ echo " <client_host>${host}</client_host>"
+ echo " <client_group>${hostgroup}</client_group>"
+ echo " <client_os_machine>${arch}</client_os_machine>"
+ echo " <client_install_status>${install_entry}</client_install_status>"
+ echo " <client_install_date>${IDATE}</client_install_date>"
+ echo " <client_install_name>${SH_NAME}</client_install_name>"
+ echo " <client_install_prefix>${SH_PREFIX}</client_install_prefix>"
+ echo " <client_install_version>${src_version}.${realformat}</client_install_version>"
+ echo " </client>"
+}
+
+FTEST=0
+
+set_flag () {
+ case "$line" in
+ *\</client\>*)
+ FTEST=0;
+ return 0;
+ ;;
+
+ *\<client_host\>${host}\</client_host\>*)
+ FTEST=1;
+ return 1;
+ ;;
+
+ *)
+ return ${FTEST};
+ ;;
+ esac
+}
+
+
+#------------------------------------------------------------------------
+# Update client db
+#------------------------------------------------------------------------
+updateDB() {
+
+ if test "x$1" = x
+ then
+ install_entry="D2_installed"
+ else
+ install_entry="$1"
+ fi
+ export install_entry
+
+ if test x"$DATABASE" = x
+ then
+ DATABASE="${basedir}/${defdatabase}"
+ fi
+
+ updlock="${DATABASE}.lockdir"
+ trap "rm -rf ${updlock}" 1 2 13 15
+
+ #
+ # A lockfile will not work, because 'root' can write anyway.
+ # However, 'mkdir' an existing directory will fail even for root
+ #
+ until (umask 222; mkdir "${updlock}") 2>/dev/null # test & set
+ do
+ printINFO "Waiting for lock"
+ sleep 1
+ done
+
+
+ IDATE=`date +"%Y-%m-%d %H:%M:%S"`
+ rm -f "$tmpF"; touch "$tmpF"
+
+ if test -f "$DATABASE"; then
+ rcfile_perm=`ls -l "${DATABASE}" | \
+ awk '{ u= substr($1,2,3); g=substr($1,5,3); o=substr($1,8,3); \
+ gsub("-","",u); gsub("-","",g); gsub("-","",o); \
+ print "u=" u ",g=" g ",o=" o; }'`
+ rcfile_perm=`echo ${rcfile_perm} | sed s%g=,%g-rwx,% | sed s%,o=$%,o-rwx%`
+ rcfile_owner=`ls -l "${DATABASE}" | \
+ awk '{print $3 }'`
+ rcfile_group=`ls -l "${DATABASE}" | \
+ awk '{print $4 }'`
+ else
+ rcfile_perm=640;
+ rcfile_owner=`ls -ld ${basedir} | awk '{print $3 }'`
+ rcfile_group=`ls -ld ${basedir} | awk '{print $4 }'`
+ fi
+
+
+ if test -f "${DATABASE}"
+ then
+ SStr1=`grep '<yule_db>' "${DATABASE}"`
+ if test "x${SStr1}" != "x"
+ then
+
+ SStr2=`grep "<client_host>${host}</client_host>" "${DATABASE}"`
+
+ SStr3=
+
+ if test "x${SStr2}" != "x"
+ then
+ # REPLACE
+
+ printINFO "Replace ${host} in ${DATABASE}"
+
+ exec 3<&0 <"${DATABASE}"
+ while
+ read line
+ do
+ # for some reason, var=xx only works in a function call (why?)
+ #
+ # here we test if we are still in the same client block
+ # (set_flag will return 0 for </client> and following)
+ set_flag "$line"
+
+ if test "x$?" = "x1"
+ then
+ #
+ # Write the full entry when client_os_machine is found
+ #
+ case "$line" in
+ *\<client_os_machine\>*\</client_os_machine\>)
+ echo " <client_group>${hostgroup}</client_group>" >>"${tmpF}"
+ echo " <client_os_machine>${arch}</client_os_machine>" >>"${tmpF}"
+ echo " <client_install_status>${install_entry}</client_install_status>" >>"${tmpF}"
+ echo " <client_install_date>${IDATE}</client_install_date>" >>"${tmpF}"
+ echo " <client_install_name>${SH_NAME}</client_install_name>" >>"${tmpF}"
+ echo " <client_install_prefix>${SH_PREFIX}</client_install_prefix>" >>"${tmpF}"
+ echo " <client_install_version>${src_version}.${realformat}</client_install_version>" >>"${tmpF}"
+ ;;
+
+ *\<client_group\>*\</client_group\>)
+ :
+ ;;
+
+ *\<client_install_status\>*\</client_install_status\>)
+ :
+ ;;
+
+ *\<client_install_date\>*\</client_install_date\>)
+ :
+ ;;
+
+ *\<client_install_name\>*\</client_install_name\>)
+ :
+ ;;
+
+ *\<client_install_prefix\>*\</client_install_prefix\>)
+ :
+ ;;
+
+ *\<client_install_version\>*\</client_install_version\>)
+ :
+ ;;
+
+ *)
+ echo "$line" >>"${tmpF}"
+ ;;
+
+ esac
+ else
+ echo "$line" >>"${tmpF}"
+ fi
+
+ done
+ exec 0<&3 3<&-
+ cp "${tmpF}" "${DATABASE}"
+ else
+ # WRITE NEW CLIENT RECORD
+
+ printINFO "Write record for ${host} in ${DATABASE}"
+
+ exec 3<&0 <"${DATABASE}"
+ while
+ read line
+ do
+ if test "x$line" = "x<yule_db>"
+ then
+ echo "$line" >>"${tmpF}"
+ writerecord >>"${tmpF}"
+ else
+ echo "$line" >>"${tmpF}"
+ fi
+ done
+ exec 0<&3 3<&-
+ cp "${tmpF}" "${DATABASE}"
+ fi
+ else
+ # COMPLAIN
+ printLOG "File ${DATABASE} exists, but has wrong format";
+ fi
+ else
+ # WRITE XML FROM SCRATCH
+ printINFO "Write ${DATABASE} from scratch"
+ echo '<?xml version="1.0" encoding="ISO-8859-1"?>' >"${tmpF}"
+ echo '<!DOCTYPE yule_db SYSTEM "http://la-samhna.de/yule_db-0.2.dtd">' \
+ >>"${tmpF}"
+ echo "<yule_db>" >>"${tmpF}"
+ writerecord >>"${tmpF}"
+ echo "</yule_db>" >>"${tmpF}"
+ cp "${tmpF}" "${DATABASE}"
+ fi
+
+ chown ${rcfile_owner}:${rcfile_group} "${DATABASE}"
+ if [ $? -ne 0 ]; then
+ rm -rf "${updlock}"
+ printFATAL "Could not chown ${rcfile_owner}:${rcfile_group} ${DATABASE}"
+ fi
+ chmod ${rcfile_perm} "${DATABASE}"
+ if [ $? -ne 0 ]; then
+ rm -rf "${updlock}"
+ printFATAL "Could not chmod ${rcfile_perm} ${DATABASE}"
+ fi
+
+ rm -rf "${updlock}"
+}
+
+
+ageFILE() {
+ file="$1"
+
+ if test -f "${file}"
+ then
+ test -f "${file}.9" && { rm -f "${file}.9" || printFATAL "rm -f ${file}.9 failed."; }
+ test -f "${file}.8" && { mv "${file}.8" "${file}.9" || printFATAL "mv ${file}.8 ${file}.9 failed."; }
+ test -f "${file}.7" && { mv "${file}.7" "${file}.8" || printFATAL "mv ${file}.7 ${file}.8 failed."; }
+ test -f "${file}.6" && { mv "${file}.6" "${file}.7" || printFATAL "mv ${file}.6 ${file}.7 failed."; }
+ test -f "${file}.5" && { mv "${file}.5" "${file}.6" || printFATAL "mv ${file}.5 ${file}.6 failed."; }
+ test -f "${file}.4" && { mv "${file}.4" "${file}.5" || printFATAL "mv ${file}.4 ${file}.5 failed."; }
+ test -f "${file}.3" && { mv "${file}.3" "${file}.4" || printFATAL "mv ${file}.3 ${file}.4 failed."; }
+ test -f "${file}.2" && { mv "${file}.2" "${file}.3" || printFATAL "mv ${file}.2 ${file}.3 failed."; }
+ test -f "${file}.1" && { mv "${file}.1" "${file}.2" || printFATAL "mv ${file}.1 ${file}.2 failed."; }
+ test -f "${file}" && { mv "${file}" "${file}.1" || printFATAL "mv ${file} ${file}.1 failed."; }
+ fi
+ return 0;
+}
+
+#------------------------------------------------------------------------
+# The path to yule data
+#------------------------------------------------------------------------
+pathYDATA() {
+ if test "x${yule_data}" = x
+ then
+ promptINPUT "Please enter the path to your yule executable"
+ yule_data="$INPUT"; export yule_data
+ fi
+ if test -d "${yule_data}"
+ then
+ :
+ else
+ printFATAL "Path to yule data directory not given."
+ fi
+}
+
+#------------------------------------------------------------------------
+# The path to yule
+#------------------------------------------------------------------------
+pathYULE() {
+
+ if test "x${yule_exec}" = x
+ then
+ findEXE yule
+ if test -n "$EXECUTABLE"
+ then
+ yule_exec="$EXECUTABLE"
+ export yule_exec
+ fi
+ else
+ if test -f "${yule_exec}"
+ then
+ :
+ else
+ yule_exec=""
+ findEXE yule
+ if test -n "$EXECUTABLE"
+ then
+ yule_exec="$EXECUTABLE"
+ export yule_exec
+ fi
+ fi
+ fi
+ if test "x${yule_exec}" = x
+ then
+ promptINPUT "Please enter the path to your yule executable"
+ yule_exec="$INPUT"; export yule_exec
+ fi
+ if test -f "${yule_exec}"
+ then
+ if "${yule_exec}" --help 2>&1 | grep qualified >/dev/null 2>&1
+ then
+ :
+ else
+ printFATAL "${yule_exec} is not Yule, or not executable."
+ fi
+ else
+ printFATAL "Path to yule executable directory not given."
+ fi
+}
+
+#------------------------------------------------------------------------
+# Select operating system
+#------------------------------------------------------------------------
+selbinARCH() {
+ #---------------------------------------------------------------------
+ # Select arch to build
+ #---------------------------------------------------------------------
+ if test x"$arch" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "No operating system selected, aborting."
+ fi
+ cd "$basedir/archpkg" || printFATAL "Cannot cd to $basedir/archpkg !"
+ LIST=`ls 2>/dev/null`
+ if test x"$LIST" = x
+ then
+ printFATAL "No OS directories found in ${basedir}/archpkg."
+ fi
+
+ n=0
+ command="promptMENU 'Please select operating system of host' "
+ ALIST=""
+ FLIST=""
+ for ff in $LIST
+ do
+ haspkg=`ls $ff/samhain-* 2>/dev/null`
+ if test x"$haspkg" = x
+ then
+ :
+ else
+ n=`expr $n + 1`
+ osp="$ff"
+ ALIST="$ALIST $ff"
+ FLIST="$FLIST $ff"
+ if test $n -lt 8
+ then
+ command="$command '${ff}'"
+ fi
+ fi
+ done
+ if test $n -ge 8
+ then
+ command="$command other"
+ fi
+
+ eval ${command}
+ m=$?
+ if test x$m = x1
+ then
+ (exit 0); exit 0;
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ arch="$MENU"; export arch
+ if test x"$arch" = xother
+ then
+ promptINPUT "Please select operating system of host from $FLIST"
+ if test x$m = x1
+ then
+ (exit 0); exit 0;
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ found=`echo $FLIST | sed -n /$INPUT/p 2>/dev/null`
+ if test x"$found" = x
+ then
+ printFATAL "There is no package for $INPUT"
+ fi
+ arch="$INPUT"; export arch
+ fi
+ fi
+ fi
+ fi
+ # arch selected or exited
+}
+
+selbinVERSION() {
+
+ OKVERLIST=""
+
+ #---------------------------------------------------------------------
+ # Select version
+ #---------------------------------------------------------------------
+ if test x"$src_version" = x
+ then
+ if test x"$assumeyes" = x1
+ then
+ printFATAL "No version selected, aborting."
+ fi
+ cd "${basedir}/archpkg/${arch}" || printFATAL "Cannot cd to ${basedir}/archpkg/${arch} !"
+ LIST=`ls samhain-* 2>/dev/null`
+ if test x"$LIST" = x
+ then
+ printFATAL "No binary package found in ${basedir}/archpkg/${arch}."
+ fi
+
+ # --------------------------------------------------
+ # Build a list of ${version}.${format}
+ # --------------------------------------------------
+
+ for ff in $LIST
+ do
+ sh_version=`echo "$ff" | sed 's/samhain\-//g'`
+ if test -f "install-${sh_version}"
+ then
+ OKVERLIST="$OKVERLIST ${sh_version}"
+ fi
+ done
+
+ rm -f "$tmpF" && touch "$tmpF"
+
+ for dd in $OKVERLIST
+ do
+ echo "$dd" >>"$tmpF"
+ done
+
+ OKVERLIST=`cat "$tmpF" | sort -r`
+
+ rm -f "$tmpF" && touch "$tmpF"
+
+ command="promptMENU 'Please select version to install' "
+ for word in $OKVERLIST
+ do
+ command="$command '${word}'"
+ done
+
+ eval ${command}
+ m=$?
+ if test x$m = x1
+ then
+ (exit 0); exit 0;
+ elif test x$m = "x-1"
+ then
+ printFATAL "Something went wrong !"
+ else
+ first_version="$MENU";
+ fi
+
+ src_version=`echo ${first_version} | sed s%\.run%% | sed s%\.rpm%% | sed s%\.deb%% | sed s%\.tbz2%% | sed s%\.depot%% | sed s%\.pkg%%`
+ export src_version
+
+ format=`echo ${first_version} | sed '/^\(.*\)\.\([0-9a-zA-Z]*\)$/{ s//\2/; q; }'`
+ if test "x$format" = xpkg
+ then
+ format="solaris-pkg"
+ fi
+ export format
+
+ fi
+}
diff --git a/dsys/funcPRINT b/dsys/funcPRINT
new file mode 100644
index 0000000..51f7ce8
--- /dev/null
+++ b/dsys/funcPRINT
@@ -0,0 +1,84 @@
+#########################################################################
+#
+# Printing/logging Subroutines
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# Fatal error
+#
+printFATAL() {
+ printERROR ${1+"$@"}
+ main_exit_status=1
+ echo '1' > "$tmpERR"
+ (exit 1); exit 1;
+}
+
+# Print a message to stderr
+#
+printERROR() {
+ echo "ERROR:" ${1+"$@"} >&2
+}
+
+# Print a message to stderr
+#
+printWARNING() {
+ echo "WARNING:" ${1+"$@"} >&2
+}
+
+# Print a message to stdout
+#
+printLOG() {
+ if test $silent -lt 2
+ then
+ now=`date`
+ if test -z "$logfile"
+ then
+ if test x"$simulate" = x0
+ then
+ echo "${now}:" ${1+"$@"}
+ else
+ echo "${now}: (simulate)" ${1+"$@"}
+ fi
+ else
+ if test x"$simulate" = x0
+ then
+ echo "${now}:" ${1+"$@"} >"$logfile"
+ else
+ echo "${now}: (simulate)" ${1+"$@"} >"$logfile"
+ fi
+ fi
+ fi
+}
+
+# Print a message to stdout
+#
+printINFO() {
+ if test x"$silent" = x0
+ then
+ if test x"$simulate" = x0
+ then
+ echo ${1+"$@"}
+ else
+ echo "(simulate)" ${1+"$@"}
+ fi
+ fi
+}
+
diff --git a/dsys/funcSETUP b/dsys/funcSETUP
new file mode 100644
index 0000000..a24b6ac
--- /dev/null
+++ b/dsys/funcSETUP
@@ -0,0 +1,63 @@
+#########################################################################
+#
+# Setup test Subroutines
+#
+#########################################################################
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# test setup
+#
+testSETUP1() {
+ test -d "$basedir" || printFATAL "Basedir $basedir does not exist"
+ test -d "$basedir/tmp" || printFATAL "Tmpdir $basedir/tmp does not exist"
+ tmpdir="$basedir/tmp"; export tmpdir
+ return 0
+}
+
+# test setup
+#
+testSETUP2() {
+ test -z "$action" &&
+ {
+ promptMENU "Which action do you want to perform" "install" "build" "download" "checksrc" "clean" "info" "uninstall";
+ action="$MENU"; export action;
+ }
+ if (test x"$action" = xbuild || test x"$action" = xinstall || test x"$action" = xuninstall)
+ then
+ test -z "$host" &&
+ {
+ promptINPUT "On which host do you want to $action";
+ host="$INPUT"; export host;
+ }
+ fi
+ return 0
+}
+
+setupFORMAT() {
+
+ tmp_format=`echo "${1}" | sed '/^\(.*\)\.\([0-9a-zA-Z]*\)$/{ s//\2/; q; }'`
+ echo "${tmp_format}"
+}
+
+setupVERSION() {
+ tmp_version=`echo ${DB_version} | sed s%\.run%% | sed s%\.rpm%% | sed s%\.depot%% | sed s%\.deb%% | sed s%\.tbz2%% | sed s%\.pkg%%`
+ echo "${tmp_version}"
+
+}
diff --git a/dsys/initscript b/dsys/initscript
new file mode 100644
index 0000000..45a8021
--- /dev/null
+++ b/dsys/initscript
@@ -0,0 +1,166 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+startup=no
+
+# arg1: the --enable-nocl=password password (use 'start' for none)
+# arg2(optional): if 'startup', start the client and exit
+#
+#
+# 'nocl' is used to handle the --enable-nocl=password option. 'start' is a
+# reserved word, hence cannot be the password.
+# We are called with one argument, which may be 'start' to indicate that
+# the --enable-nocl=password option is not used.
+#
+if test "x$1" = x
+then
+ nocl=start
+else
+ nocl="$1"
+fi
+
+if test "x$2" = x
+then
+ command="data"
+else
+ command="$2"
+fi
+
+name=`./samhain-install.sh --print-config name`
+sbin=`./samhain-install.sh --print-config sbin_dir`
+
+# execute and exit for start|stop|restart|reload|status, else fallthrough
+case $command in
+ start | stop)
+ MONIT=""
+ test -f /usr/local/bin/monit && MONIT="/usr/local/bin/monit"
+ if test x"$MONIT" = x
+ then
+ test -f /usr/bin/monit && MONIT="/usr/bin/monit"
+ if test x"$MONIT" = x
+ then
+ :
+ else
+ zz=`/usr/bin/monit status | grep ${name}`
+ if test x"$zz" = x
+ then
+ :
+ else
+ ${MONIT} "${command}" "${name}"
+ exit 0
+ fi
+ fi
+ fi
+
+ retval=0
+
+ if test -f /etc/init.d/${name}
+ then
+ /etc/init.d/${name} ${command}
+ retval=$?
+ elif test -f /etc/rc.d/init.d/${name}
+ then
+ /etc/rc.d/init.d/${name} ${command}
+ retval=$?
+ elif test -f "$sbin/$name"
+ then
+ $sbin/$name ${command}
+ retval=$?
+ else
+ exit 1
+ fi
+ if test x"$command" = xstop
+ then
+ exit 0
+ fi
+ exit $retval
+ ;;
+
+ reload | restart | status )
+ if test -f /etc/init.d/${name}
+ then
+ /etc/init.d/${name} ${command}
+ elif test -f /etc/rc.d/init.d/${name}
+ then
+ /etc/rc.d/init.d/${name} ${command}
+ elif test -f "$sbin/$name"
+ then
+ $sbin/$name ${command}
+ else
+ exit 1
+ fi
+ exit $?
+ ;;
+
+ *)
+ ;;
+esac
+
+data=`./samhain-install.sh --print-config data_file`
+ddir=`./samhain-install.sh --print-config data_dir`
+
+remfile=no
+remdir=no
+
+if test -d "$ddir"
+then
+ test -f "$data" || remfile=yes
+else
+ ./samhain-install.sh --mkinstalldirs "$ddir"
+ remdir=yes
+fi
+
+if test -f "$sbin/$name"
+then
+ if test -f "$data"
+ then
+ rm "$data" || exit 1
+ fi
+
+ if test x"$nocl" = xstart
+ then
+ $sbin/$name -t init -p err
+ else
+ echo '-t init -p err' | $sbin/$name "$nocl"
+ fi
+else
+ echo "$sbin/$name not found" >&2
+ exit 1
+fi
+
+if test -f "$data"
+then
+ cp "$data" ./data
+else
+ echo "$data not found" >&2
+ exit 1
+fi
+
+if test x"$remdir" = xyes
+then
+ rm -rf "$ddir"
+elif test x"$remfile" = xyes
+then
+ rm -f "$data"
+fi
+
+exit 0
+
diff --git a/dsys/postinstall b/dsys/postinstall
new file mode 100644
index 0000000..bd478d2
--- /dev/null
+++ b/dsys/postinstall
@@ -0,0 +1,58 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+name=`./samhain-install.sh --print-config name`
+sbin=`./samhain-install.sh --print-config sbin_dir`
+rcfi=`./samhain-install.sh --print-config config_file`
+passwd=$1
+
+setpwd="./${name}_setpwd"
+
+# Install the prepared configuration file.
+#
+test -f ./prepared_samhainrc || exit 1
+./samhain-install.sh --install-sh -m 600 ./prepared_samhainrc "$rcfi" || exit 1
+
+# Gentoo noise
+#
+rm -f /etc/init.d/._cfg????_${name}
+rm -f /etc/._cfg????_${name}rc
+
+# Set the password within the executable.
+#
+if test "x${passwd}" = "xDUMMY"
+then
+ rm -f "$sbin/${name}_setpwd"
+else
+ current=`pwd`
+ cd "$sbin" || exit 1
+ eval "$setpwd" "$name" new "$passwd" || exit 1
+ if test -f "${name}.new"
+ then
+ rm "$name" || exit 1
+ mv "${name}.new" "$name" || exit 1
+ rm -f "./${name}_setpwd"
+ fi
+ cd "$current"
+fi
+
+exit 0
+
diff --git a/dsys/preinstall b/dsys/preinstall
new file mode 100644
index 0000000..4563668
--- /dev/null
+++ b/dsys/preinstall
@@ -0,0 +1,57 @@
+#! /bin/sh
+#
+# Copyright Rainer Wichmann (2005)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+name=`./samhain-install.sh --print-config name`
+sbin=`./samhain-install.sh --print-config sbin_dir`
+
+MONIT=""
+test -f /usr/local/bin/monit && MONIT="/usr/local/bin/monit"
+if test x"$MONIT" = x
+then
+ test -f /usr/bin/monit && MONIT="/usr/bin/monit"
+ if test x"$MONIT" = x
+ then
+ :
+ else
+ zz=`/usr/bin/monit status | grep ${name}`
+ if test x"$zz" = x
+ then
+ :
+ else
+ ${MONIT} stop "${name}"
+ exit 0
+ fi
+ fi
+fi
+
+if test -f /etc/init.d/${name}
+then
+ /etc/init.d/${name} stop
+elif test -f /etc/rc.d/init.d/${name}
+then
+ /etc/rc.d/init.d/${name} stop
+else
+ if test -f $sbin/$name
+ then
+ $sbin/$name stop
+ fi
+fi
+
+exit 0
diff --git a/hp_ux.psf.in b/hp_ux.psf.in
new file mode 100644
index 0000000..6140ba6
--- /dev/null
+++ b/hp_ux.psf.in
@@ -0,0 +1,75 @@
+# PSF
+depot
+ layout_version 1.0
+# Product definition:
+product
+ tag @install_name@
+ revision @VERSION@
+ is_patch false
+ title @install_name@ Client
+ description "Client for the @install_name@ system"
+ machine_type *
+ os_name HP-UX
+ os_release ?.11.*
+ os_version ?
+ directory /
+ is_locatable false
+
+# Dummy for configure warning
+# datarootdir = @datarootdir@
+
+# Specify a checkremove script that executes during the
+# swremove analysis phase. (This script prevents the
+# removal of the SD product and returns an ERROR.
+# checkremove scripts/checkremove.sd
+
+ configure ./sc/configure
+ unconfigure ./sc/unconfigure
+ preremove ./sc/preremove
+
+ # Fileset definitions:
+ fileset
+ tag basic
+ title Core system
+ revision @VERSION@
+ file_permissions -m 0700 -o root -g sys
+ #
+ # Files:
+#
+ directory ./sbin/init.d=/sbin/init.d
+ file -m 0555 -o bin -g bin @install_name@
+#
+ directory .@prefix@=@prefix@
+ file -m 0555 -o bin -g bin .
+#
+ directory .@sysconfdir@=@sysconfdir@
+ file -v -m 0600 @install_name@rc
+ file -m 0555 -o bin -g bin .
+#
+ directory .@sbindir@=@sbindir@
+ file *
+ file -m 0555 -o bin -g bin .
+ file -m 0750 -o bin -g bin @install_name@
+#
+ directory .@mydataroot@=@mydataroot@
+ file -m 0555 -o bin -g bin .
+#
+ directory .@mylogdir@=@mylogdir@
+ file -m 0755 -o adm -g adm .
+#
+ directory .@mylockdir@=@mylockdir@
+ file -m 0555 -o bin -g bin .
+ end
+ # Manpage fileset definitions:
+ #fileset
+ # tag man
+ # title Manual pages for samhain
+ # revision 2.05
+ # directory .@mandir@/man8=@mandir@/man8
+ # file *
+ # directory .@mandir@/man5=@mandir@/man5
+ # file *
+ #end
+ #man
+end
+#
diff --git a/include/CuTest.h b/include/CuTest.h
new file mode 100644
index 0000000..5eb6102
--- /dev/null
+++ b/include/CuTest.h
@@ -0,0 +1,138 @@
+/*******************
+
+LICENSE
+
+Copyright (c) 2003 Asim Jalis
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in
+a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+
+**********************/
+
+#ifndef CU_TEST_H
+#define CU_TEST_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+
+/* CuString */
+
+char* CuStrAlloc(int size);
+char* CuStrCopy(const char* old);
+
+#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE)))
+
+#define HUGE_STRING_LEN 8192
+#define STRING_MAX 256
+#define STRING_INC 256
+
+typedef struct
+{
+ int length;
+ int size;
+ char* buffer;
+} CuString;
+
+void CuStringInit(CuString* str);
+CuString* CuStringNew(void);
+void CuStringRead(CuString* str, const char* path);
+void CuStringAppend(CuString* str, const char* text);
+void CuStringAppendChar(CuString* str, char ch);
+void CuStringAppendFormat(CuString* str, const char* format, ...);
+void CuStringInsert(CuString* str, const char* text, int pos);
+void CuStringResize(CuString* str, int newSize);
+
+/* CuTest */
+
+typedef struct CuTest CuTest;
+
+typedef void (*TestFunction)(CuTest *);
+
+struct CuTest
+{
+ const char* name;
+ TestFunction function;
+ int failed;
+ int ran;
+ const char* message;
+ jmp_buf *jumpBuf;
+};
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function);
+CuTest* CuTestNew(const char* name, TestFunction function);
+void CuTestRun(CuTest* tc);
+
+/* Internal versions of assert functions -- use the public versions */
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message);
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition);
+void CuAssertStrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ const char* expected, const char* actual);
+void CuAssertIntEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ int expected, int actual);
+void CuAssertDblEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ double expected, double actual, double delta);
+void CuAssertPtrEquals_LineMsg(CuTest* tc,
+ const char* file, int line, const char* message,
+ void* expected, void* actual);
+
+/* public assert functions */
+
+#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms))
+#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond))
+#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond))
+
+#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl))
+#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl))
+#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac))
+#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac))
+
+#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL))
+#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL))
+
+/* CuSuite */
+
+#define MAX_TEST_CASES 1024
+
+#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST))
+
+typedef struct
+{
+ int count;
+ CuTest* list[MAX_TEST_CASES];
+ int failCount;
+
+} CuSuite;
+
+
+void CuSuiteInit(CuSuite* testSuite);
+CuSuite* CuSuiteNew(void);
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase);
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2);
+void CuSuiteRun(CuSuite* testSuite);
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary);
+void CuSuiteDetails(CuSuite* testSuite, CuString* details);
+
+#endif /* CU_TEST_H */
diff --git a/include/bignum.h b/include/bignum.h
new file mode 100644
index 0000000..298594c
--- /dev/null
+++ b/include/bignum.h
@@ -0,0 +1,85 @@
+#ifndef _BIGNUM_H_
+#define _BIGNUM_H_
+
+#include "internal.h"
+
+typedef struct big_struct bignum;
+
+#define BIG_SIGN_0 0
+#define BIG_SIGN_PLUS 1
+#define BIG_SIGN_MINUS -1
+
+#define BIG_OK 0
+#define BIG_MEMERR 1
+#define BIG_DIV_ZERO 2
+#define BIG_ARGERR 3
+
+#ifdef BIG_SHORT_NAMES
+#define big_set_big big_sb
+#define big_set_long big_sl
+#define big_set_ulong big_usl
+#define big_string big_rs
+#define big_leqp big_lq
+#define big_expt big_x
+#endif
+
+/* External variables to take care about when using the bignums */
+typedef int bigerr_t;
+extern int big_errno;
+extern char *big_end_string;
+
+/* External functions to enable use of bignums */
+extern bigerr_t big_init_pkg(void);
+extern void big_release_pkg(void);
+
+extern bigerr_t big_create(bignum *a);
+extern void big_destroy(bignum *a);
+
+extern unsigned long big_bitcount(bignum *a);
+
+extern bigerr_t big_set_big(bignum *a, bignum *b);
+extern void big_set_long(long n, bignum *a);
+extern void big_set_ulong(unsigned long n, bignum *a);
+extern bigerr_t big_set_string(char *numstr, int base, bignum *a);
+
+extern int big_long(bignum *a, long *n);
+extern int big_ulong(bignum *a, unsigned long *n);
+extern char *big_string(bignum *a, int base);
+
+extern int big_sign(bignum *a);
+extern bigerr_t big_abs(bignum *a, bignum *b);
+
+extern bigerr_t big_negate(bignum *a, bignum *b);
+
+extern int big_compare(bignum *a, bignum *b);
+extern int big_lessp(bignum *a, bignum *b);
+extern int big_leqp(bignum *a, bignum *b);
+extern int big_equalp(bignum *a, bignum *b);
+extern int big_geqp(bignum *a, bignum *b);
+extern int big_greaterp(bignum *a, bignum *b);
+
+extern int big_zerop(bignum *a);
+extern int big_evenp(bignum *a);
+extern int big_oddp(bignum *a);
+
+extern bigerr_t big_add(bignum *a, bignum *b, bignum *c);
+extern bigerr_t big_sub(bignum *a, bignum *b, bignum *c);
+
+extern bigerr_t big_mul(bignum *a, bignum *b, bignum *c);
+
+extern bigerr_t big_trunc(bignum *a, bignum *b, bignum *c, bignum *r);
+extern bigerr_t big_floor(bignum *a, bignum *b, bignum *c, bignum *r);
+extern bigerr_t big_ceil(bignum *a, bignum *b, bignum *c, bignum *r);
+extern bigerr_t big_round(bignum *a, bignum *b, bignum *c, bignum *r);
+
+extern bigerr_t big_random(bignum *a, bignum *b);
+
+extern bigerr_t big_expt(bignum *a, unsigned long z, bignum *x);
+extern bigerr_t big_exptmod(bignum *a_in, bignum *z_in, bignum *n, bignum *x);
+extern bigerr_t big_gcd(bignum *a, bignum *b, bignum *g);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* _BIGNUM_H_ */
diff --git a/include/lzoconf.h b/include/lzoconf.h
new file mode 100644
index 0000000..3ccdeab
--- /dev/null
+++ b/include/lzoconf.h
@@ -0,0 +1,379 @@
+/* lzoconf.h -- configuration for the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+
+ The LZO library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus.oberhumer@jk.uni-linz.ac.at>
+ http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ */
+
+
+#ifndef __LZOCONF_H
+#define __LZOCONF_H
+
+#define LZO_VERSION 0x1060
+
+/*
+ * Unfortunately, these are somewhat counterproductive, as
+ * there should be no strings in the compiled executable.
+ * - Rainer Wichmann, 26. July 2000 -
+ *
+ * #define LZO_VERSION_STRING "1.06"
+ * #define LZO_VERSION_DATE "Nov 29 1999"
+ */
+#define LZO_VERSION_STRING ""
+#define LZO_VERSION_DATE ""
+
+
+/* internal Autoconf configuration file - only used when building LZO */
+#if defined(LZO_HAVE_CONFIG_H)
+# include <config.h>
+#endif
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+// LZO requires a conforming <limits.h>
+************************************************************************/
+
+#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
+# error "invalid CHAR_BIT"
+#endif
+#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
+# error "check your compiler installation"
+#endif
+#if (USHRT_MAX < 1 ) || (UINT_MAX < 1) || (ULONG_MAX < 1)
+# error "your limits.h macros are broken"
+#endif
+
+/* workaround a cpp bug under hpux 10.20 */
+#define LZO_0xffffffffL 4294967295ul
+
+
+/***********************************************************************
+// architecture defines
+************************************************************************/
+
+#if !defined(__LZO_WIN) && !defined(__LZO_DOS) && !defined(__LZO_OS2)
+# if defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+# define __LZO_WIN
+# elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
+# define __LZO_WIN
+# elif defined(__NT__) || defined(__NT_DLL__) || defined(__WINDOWS_386__)
+# define __LZO_WIN
+# elif defined(__DOS__) || defined(__MSDOS__) || defined(MSDOS)
+# define __LZO_DOS
+# elif defined(__OS2__) || defined(__OS2V2__) || defined(OS2)
+# define __LZO_OS2
+# elif defined(__palmos__)
+# define __LZO_PALMOS
+# elif defined(__TOS__) || defined(__atarist__)
+# define __LZO_TOS
+# endif
+#endif
+
+#if (UINT_MAX < LZO_0xffffffffL)
+# if defined(__LZO_WIN)
+# define __LZO_WIN16
+# elif defined(__LZO_DOS)
+# define __LZO_DOS16
+# elif defined(__LZO_PALMOS)
+# define __LZO_PALMOS16
+# elif defined(__LZO_TOS)
+# define __LZO_TOS16
+# elif defined(__C166__)
+# else
+# error "16-bit target not supported - contact me for porting hints"
+# endif
+#endif
+
+#if !defined(__LZO_i386)
+# if defined(__LZO_DOS) || defined(__LZO_WIN16)
+# define __LZO_i386
+# elif defined(__i386__) || defined(__386__) || defined(_M_IX86)
+# define __LZO_i386
+# endif
+#endif
+
+#if defined(__LZO_STRICT_16BIT)
+# if (UINT_MAX < LZO_0xffffffffL)
+# include <lzo16bit.h>
+# endif
+#endif
+
+
+/***********************************************************************
+// integral and pointer types
+************************************************************************/
+
+/* Integral types with 32 bits or more */
+#if !defined(LZO_UINT32_MAX)
+# if (UINT_MAX >= LZO_0xffffffffL)
+ typedef unsigned int lzo_uint32;
+ typedef int lzo_int32;
+# define LZO_UINT32_MAX UINT_MAX
+# define LZO_INT32_MAX INT_MAX
+# define LZO_INT32_MIN INT_MIN
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+ typedef unsigned long lzo_uint32;
+ typedef long lzo_int32;
+# define LZO_UINT32_MAX ULONG_MAX
+# define LZO_INT32_MAX LONG_MAX
+# define LZO_INT32_MIN LONG_MIN
+# else
+# error "lzo_uint32"
+# endif
+#endif
+
+/* lzo_uint is used like size_t */
+#if !defined(LZO_UINT_MAX)
+# if (UINT_MAX >= LZO_0xffffffffL)
+ typedef unsigned int lzo_uint;
+ typedef int lzo_int;
+# define LZO_UINT_MAX UINT_MAX
+# define LZO_INT_MAX INT_MAX
+# define LZO_INT_MIN INT_MIN
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+ typedef unsigned long lzo_uint;
+ typedef long lzo_int;
+# define LZO_UINT_MAX ULONG_MAX
+# define LZO_INT_MAX LONG_MAX
+# define LZO_INT_MIN LONG_MIN
+# else
+# error "lzo_uint"
+# endif
+#endif
+
+
+/* Memory model that allows to access memory at offsets of lzo_uint. */
+#if !defined(__LZO_MMODEL)
+# if (LZO_UINT_MAX <= UINT_MAX)
+# define __LZO_MMODEL
+# elif defined(__LZO_DOS16) || defined(__LZO_WIN16)
+# define __LZO_MMODEL __huge
+# define LZO_999_UNSUPPORTED
+# elif defined(__LZO_PALMOS16) || defined(__LZO_TOS16)
+# define __LZO_MMODEL
+# else
+# error "__LZO_MMODEL"
+# endif
+#endif
+
+/* no typedef here because of const-pointer issues */
+#define lzo_byte unsigned char __LZO_MMODEL
+#define lzo_bytep unsigned char __LZO_MMODEL *
+#define lzo_charp char __LZO_MMODEL *
+#define lzo_voidp void __LZO_MMODEL *
+#define lzo_shortp short __LZO_MMODEL *
+#define lzo_ushortp unsigned short __LZO_MMODEL *
+#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
+#define lzo_int32p lzo_int32 __LZO_MMODEL *
+#define lzo_uintp lzo_uint __LZO_MMODEL *
+#define lzo_intp lzo_int __LZO_MMODEL *
+#define lzo_voidpp lzo_voidp __LZO_MMODEL *
+#define lzo_bytepp lzo_bytep __LZO_MMODEL *
+
+typedef int lzo_bool;
+
+#ifndef lzo_sizeof_dict_t
+# define lzo_sizeof_dict_t sizeof(lzo_bytep)
+#endif
+
+
+/***********************************************************************
+// function types
+************************************************************************/
+
+/* linkage */
+#if !defined(__LZO_EXTERN_C)
+# ifdef __cplusplus
+# define __LZO_EXTERN_C extern "C"
+# else
+# define __LZO_EXTERN_C extern
+# endif
+#endif
+
+/* calling conventions */
+#if !defined(__LZO_CDECL)
+# if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+# define __LZO_CDECL __far __cdecl
+# elif defined(__LZO_i386) && defined(_MSC_VER)
+# define __LZO_CDECL __cdecl
+# elif defined(__LZO_i386) && defined(__WATCOMC__)
+# define __LZO_CDECL __near __cdecl
+# else
+# define __LZO_CDECL
+# endif
+#endif
+#if !defined(__LZO_ENTRY)
+# define __LZO_ENTRY __LZO_CDECL
+#endif
+
+/* DLL export information */
+#if !defined(__LZO_EXPORT1)
+# define __LZO_EXPORT1
+#endif
+#if !defined(__LZO_EXPORT2)
+# define __LZO_EXPORT2
+#endif
+
+/* calling convention for C functions */
+#if !defined(LZO_PUBLIC)
+# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_ENTRY
+#endif
+#if !defined(LZO_EXTERN)
+# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
+#endif
+#if !defined(LZO_PRIVATE)
+# define LZO_PRIVATE(_rettype) static _rettype __LZO_ENTRY
+#endif
+
+/* cdecl calling convention for assembler functions */
+#if !defined(LZO_PUBLIC_CDECL)
+# define LZO_PUBLIC_CDECL(_rettype) \
+ __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
+#endif
+#if !defined(LZO_EXTERN_CDECL)
+# define LZO_EXTERN_CDECL(_rettype) __LZO_EXTERN_C LZO_PUBLIC_CDECL(_rettype)
+#endif
+
+
+typedef int
+(__LZO_ENTRY *lzo_compress_t) ( const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem );
+
+typedef int
+(__LZO_ENTRY *lzo_decompress_t) ( const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem );
+
+typedef int
+(__LZO_ENTRY *lzo_optimize_t) ( lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem );
+
+typedef int
+(__LZO_ENTRY *lzo_compress_dict_t)(const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem,
+ const lzo_byte *dict, lzo_uint dict_len );
+
+typedef int
+(__LZO_ENTRY *lzo_decompress_dict_t)(const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem,
+ const lzo_byte *dict, lzo_uint dict_len );
+
+
+/* a progress indicator callback function */
+typedef void (__LZO_ENTRY *lzo_progress_callback_t) (lzo_uint, lzo_uint);
+
+
+/***********************************************************************
+// error codes and prototypes
+************************************************************************/
+
+/* Error codes for the compression/decompression functions. Negative
+ * values are errors, positive values will be used for special but
+ * normal events.
+ */
+#define LZO_E_OK 0
+#define LZO_E_ERROR (-1)
+#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */
+#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */
+#define LZO_E_INPUT_OVERRUN (-4)
+#define LZO_E_OUTPUT_OVERRUN (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN (-6)
+#define LZO_E_EOF_NOT_FOUND (-7)
+#define LZO_E_INPUT_NOT_CONSUMED (-8)
+
+
+/* lzo_init() should be the first function you call.
+ * Check the return code !
+ *
+ * lzo_init() is a macro to allow checking that the library and the
+ * compiler's view of various types are consistent.
+ */
+#define lzo_init() __lzo_init2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
+ (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
+ (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
+ (int)sizeof(lzo_compress_t))
+LZO_EXTERN(int) __lzo_init2(unsigned,int,int,int,int,int,int,int,int,int);
+
+/* version functions (useful for shared libraries) */
+LZO_EXTERN(unsigned) lzo_version(void);
+LZO_EXTERN(const char *) lzo_version_string(void);
+LZO_EXTERN(const char *) lzo_version_date(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
+
+/* string functions */
+LZO_EXTERN(int)
+lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
+
+/* checksum functions */
+LZO_EXTERN(lzo_uint32)
+lzo_adler32(lzo_uint32 _adler, const lzo_byte *_buf, lzo_uint _len);
+LZO_EXTERN(lzo_uint32)
+lzo_crc32(lzo_uint32 _c, const lzo_byte *_buf, lzo_uint _len);
+
+/* memory allocation functions */
+LZO_EXTERN(lzo_bytep) lzo_alloc(lzo_uint _nelems, lzo_uint _size);
+LZO_EXTERN(lzo_bytep) lzo_malloc(lzo_uint _size);
+LZO_EXTERN(void) lzo_free(lzo_voidp _ptr);
+
+extern lzo_bytep (__LZO_ENTRY *lzo_alloc_hook) (lzo_uint,lzo_uint);
+extern void (__LZO_ENTRY *lzo_free_hook) (lzo_voidp);
+
+/* misc. */
+LZO_EXTERN(lzo_bool) lzo_assert(int _expr);
+LZO_EXTERN(int) _lzo_config_check(void);
+typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
+typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
+
+/* align a char pointer on a boundary that is a multiple of `size' */
+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
+#define LZO_PTR_ALIGN_UP(_ptr,_size) \
+ ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
+
+/* deprecated - only for backward compatibility */
+#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
diff --git a/include/minilzo.h b/include/minilzo.h
new file mode 100644
index 0000000..dca0025
--- /dev/null
+++ b/include/minilzo.h
@@ -0,0 +1,96 @@
+/* minilzo.h -- mini subset of the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+
+ The LZO library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus.oberhumer@jk.uni-linz.ac.at>
+ http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ */
+
+/*
+ * NOTE:
+ * the full LZO package can be found at
+ * http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ */
+
+
+#ifndef __MINILZO_H
+#define __MINILZO_H
+
+#define MINILZO_VERSION 0x1060
+
+#ifdef __LZOCONF_H
+# error "you cannot use both LZO and miniLZO"
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "lzoconf.h"
+
+#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
+# error "version mismatch in header files"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* Memory required for the wrkmem parameter.
+ * When the required size is 0, you can also pass a NULL pointer.
+ */
+
+#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
+#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
+#define LZO1X_MEM_DECOMPRESS (0)
+
+
+/* compression */
+LZO_EXTERN(int)
+lzo1x_1_compress ( const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem );
+
+/* decompression */
+LZO_EXTERN(int)
+lzo1x_decompress ( const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem /* NOT USED */ );
+
+/* safe decompression with overrun testing */
+LZO_EXTERN(int)
+lzo1x_decompress_safe ( const lzo_byte *src, lzo_uint src_len,
+ lzo_byte *dst, lzo_uint *dst_len,
+ lzo_voidp wrkmem /* NOT USED */ );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
diff --git a/include/rijndael-alg-fst.h b/include/rijndael-alg-fst.h
new file mode 100644
index 0000000..2be67e0
--- /dev/null
+++ b/include/rijndael-alg-fst.h
@@ -0,0 +1,44 @@
+/* $NetBSD: rijndael-alg-fst.h,v 1.4 2005/12/11 12:20:52 christos Exp $ */
+/* $KAME: rijndael-alg-fst.h,v 1.5 2003/07/15 10:47:16 itojun Exp $ */
+/**
+ * rijndael-alg-fst.h
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RIJNDAEL_ALG_FST_H
+#define __RIJNDAEL_ALG_FST_H
+
+#define RIJNDAEL_MAXKC (256/32)
+#define RIJNDAEL_MAXKB (256/8)
+#define RIJNDAEL_MAXNR 14
+
+#ifdef SH_ENCRYPT
+
+int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]);
+void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]);
+
+/* SH_ENCRYPT */
+#endif
+#endif /* __RIJNDAEL_ALG_FST_H */
diff --git a/include/rijndael-api-fst.h b/include/rijndael-api-fst.h
new file mode 100644
index 0000000..e0a9834
--- /dev/null
+++ b/include/rijndael-api-fst.h
@@ -0,0 +1,136 @@
+/* $NetBSD: rijndael-api-fst.h,v 1.8 2007/01/21 23:00:08 cbiere Exp $ */
+
+/**
+ * rijndael-api-fst.h
+ *
+ * @version 2.9 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Acknowledgements:
+ *
+ * We are deeply indebted to the following people for their bug reports,
+ * fixes, and improvement suggestions to this implementation. Though we
+ * tried to list all contributions, we apologise in advance for any
+ * missing reference.
+ *
+ * Andrew Bales <Andrew.Bales@Honeywell.com>
+ * Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
+ * John Skodon <skodonj@webquill.com>
+ */
+
+#ifndef __RIJNDAEL_API_FST_H
+#define __RIJNDAEL_API_FST_H
+
+/* Blocksize: 16 * 8 = 128; 128 * 1 = 128 */
+#define B_SIZ 16
+#define BNUM 1
+
+
+#if defined(UINT32)
+typedef unsigned char u8;
+typedef UINT32 u32;
+#else
+
+typedef unsigned char u8;
+#if defined(HAVE_INT_32)
+typedef unsigned int u32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long u32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short u32;
+#else
+#error "No 32 bit integer type found"
+#endif
+
+#endif
+
+#include "rijndael-alg-fst.h"
+
+/* Generic Defines */
+#define DIR_ENCRYPT 0 /* Are we encrpyting? */
+#define DIR_DECRYPT 1 /* Are we decrpyting? */
+#define MODE_ECB 1 /* Are we ciphering in ECB mode? */
+#define MODE_CBC 2 /* Are we ciphering in CBC mode? */
+#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#define BITSPERBLOCK 128 /* Default number of bits in a cipher block */
+
+/* Error Codes */
+#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */
+#define BAD_KEY_MAT -2 /* Key material not of correct length */
+#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */
+#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */
+#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */
+#define BAD_BLOCK_LENGTH -6
+#define BAD_CIPHER_INSTANCE -7
+#define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */
+#define BAD_OTHER -9 /* Unknown error */
+
+/* Algorithm-specific Defines */
+#define RIJNDAEL_MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */
+#define RIJNDAEL_MAX_IV_SIZE 16 /* # bytes needed to represent an IV */
+
+#ifdef SH_ENCRYPT
+
+/* Typedefs */
+
+typedef unsigned char BYTE;
+
+/* The structure for key information */
+typedef struct {
+ u32 rk[4*(RIJNDAEL_MAXNR + 1)]; /* key schedule */
+ u32 ek[4*(RIJNDAEL_MAXNR + 1)]; /* CFB1 key schedule (encryption only) */
+ BYTE direction; /* Key used for encrypting or decrypting? */
+ int keyLen; /* Length of the key */
+ char keyMaterial[RIJNDAEL_MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */
+ int Nr; /* key-length-dependent number of rounds */
+} keyInstance;
+
+/* The structure for cipher information */
+typedef struct { /* changed order of the components */
+ u32 IV[RIJNDAEL_MAX_IV_SIZE / sizeof(u32)];
+ /* A possible Initialization Vector for ciphering */
+ BYTE mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
+} cipherInstance;
+
+/* Function prototypes */
+
+int rijndael_makeKey(keyInstance *, BYTE, int, const char *);
+
+int rijndael_cipherInit(cipherInstance *, BYTE, const char *);
+
+int rijndael_blockEncrypt(cipherInstance *, keyInstance *, const BYTE *, int, BYTE *);
+
+int rijndael_padEncrypt(cipherInstance *, keyInstance *, const BYTE *, int, BYTE *);
+
+int rijndael_blockDecrypt(cipherInstance *, keyInstance *, const BYTE *, int, BYTE *);
+
+int rijndael_padDecrypt(cipherInstance *, keyInstance *, const BYTE *, int, BYTE *);
+
+/* SH_ENCRYPT */
+#endif
+#endif /* __RIJNDAEL_API_FST_H */
diff --git a/include/samhain.h b/include/samhain.h
new file mode 100644
index 0000000..fa34103
--- /dev/null
+++ b/include/samhain.h
@@ -0,0 +1,586 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SAMHAIN_H
+#define SAMHAIN_H
+
+#include <sys/types.h>
+#include "slib.h"
+
+#ifdef SH_ENCRYPT
+#include "rijndael-api-fst.h"
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+#define SH_GNUC_SENTINEL __attribute__((__sentinel__))
+#else
+#define SH_GNUC_SENTINEL
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#undef SH_GNUC_PURE
+#define SH_GNUC_PURE __attribute__((pure))
+#undef SH_GNUC_CONST
+#define SH_GNUC_CONST __attribute__((const))
+#undef SH_GNUC_NORETURN
+#define SH_GNUC_NORETURN __attribute__((noreturn))
+#undef SH_GNUC_MALLOC
+#define SH_GNUC_MALLOC __attribute__((malloc))
+#else
+#undef SH_GNUC_PURE
+#define SH_GNUC_PURE
+#undef SH_GNUC_CONST
+#define SH_GNUC_CONST
+#undef SH_GNUC_NORETURN
+#define SH_GNUC_NORETURN
+#undef SH_GNUC_MALLOC
+#define SH_GNUC_MALLOC
+#endif
+
+/**************************************************
+ *
+ * STANDARD DEFINES
+ *
+ **************************************************/
+
+/* IPv6 */
+#if defined(HAVE_GETNAMEINFO) && defined(HAVE_GETADDRINFO)
+
+#if defined(SH_COMPILE_STATIC) && defined(__linux__)
+#undef USE_IPVX
+#define SH_SOCKMAX 1
+#else
+
+#if defined(USE_IPV4)
+#undef USE_IPVX
+#else
+#define USE_IPVX 1
+#endif
+
+#define SH_SOCKMAX 8
+#endif
+
+#else
+#undef USE_IPVX
+#define SH_SOCKMAX 1
+#endif
+
+/* end IPv6 */
+
+/* Standard buffer sizes.
+ * IPv6 is 8 groups of 4 hex digits seperated by colons.
+ */
+#define SH_IP_BUF 48
+#define SH_MINIBUF 64
+#define SH_BUFSIZE 1024
+#define SH_MAXBUF 4096
+#define SH_PATHBUF 256
+#define SH_MSG_BUF 64512
+
+#define SH_ERRBUF_SIZE 64
+
+/* MAX_PATH_STORE must be >= KEY_LEN
+ */
+#define MAX_PATH_STORE 12287
+
+/* Sizes for arrays (user, group, timestamp).
+ */
+#define SOCKPASS_MAX 14
+#define USER_MAX 20
+#define GROUP_MAX 20
+#define TIM_MAX 32
+
+#define CMODE_SIZE 11
+
+#define ATTRBUF_SIZE 16
+#define ATTRBUF_USED 12
+
+/* The number of bytes in a key,
+ * the number of chars in its hex repesentation,
+ * and the block size of the hash algorithm.
+ */
+#define KEY_BYT 24
+#define KEY_LEN 48
+#define KEY_BLOCK 24
+#define KEYBUF_SIZE (KEY_LEN+1)
+
+/* The length of the compiled-in password.
+ */
+#define PW_LEN 8
+
+#undef S_TRUE
+#define S_TRUE 1
+#undef S_FALSE
+#define S_FALSE 0
+
+#undef GOOD
+#define GOOD S_TRUE
+#undef BAD
+#define BAD S_FALSE
+
+#define SH_SILENT_FULL 2
+#define SH_SILENT_STD 1
+
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#if !defined(HAVE_UINT16_T)
+#define UINT16 unsigned short
+#else
+#define UINT16 uint16_t
+#endif
+
+#if !defined(HAVE_UINT32_T)
+
+/* An unsigned integer guaranteed to be 32 bit.
+ */
+#if defined(HAVE_INT_32)
+#define UINT32 unsigned int
+#define SINT32 int
+#elif defined(HAVE_LONG_32)
+#define UINT32 unsigned long
+#define SINT32 long
+#elif defined(HAVE_SHORT_32)
+#define UINT32 unsigned short
+#define SINT32 short
+#else
+#error "No 32 bit integer type found"
+#endif
+
+#else
+#define UINT32 uint32_t
+#define SINT32 int32_t
+
+#endif
+
+#if !defined(HAVE_UINT64_T)
+
+#ifdef HAVE_LONG_LONG_64
+#define UINT64 unsigned long long
+#else
+#ifdef HAVE_LONG_64
+#define UINT64 unsigned long
+#else
+#error "no 64bit type found"
+#endif
+#endif
+
+#else
+#define UINT64 uint64_t
+#endif
+
+
+
+#define UBYTE unsigned char
+
+enum {
+ SH_TIGER192 = 0,
+ SH_SHA1 = 1,
+ SH_MD5 = 2,
+ SH_SHA256 = 3
+};
+
+
+enum {
+ SH_CHECK_NONE = 0,
+ SH_CHECK_INIT = 1,
+ SH_CHECK_CHECK = 2
+};
+
+#define SH_MOD_THREAD 1
+#define SH_MOD_ACTIVE 0
+#define SH_MOD_FAILED -1
+#define SH_MOD_OFFSET 10
+
+/* Flags for file status
+ */
+#define SH_FFLAG_ALLIGNORE (1<<0)
+#define SH_FFLAG_VISITED (1<<1)
+#define SH_FFLAG_CHECKED (1<<3)
+#define SH_FFLAG_REPORTED (1<<3)
+#define SH_FFLAG_SUIDCHK (1<<4)
+#define SH_FFLAG_ENOENT (1<<5)
+
+#define SH_FFLAG_ALLIGNORE_SET(a) (((a) & SH_FFLAG_ALLIGNORE) != 0)
+#define SET_SH_FFLAG_ALLIGNORE(a) ((a) |= SH_FFLAG_ALLIGNORE)
+#define CLEAR_SH_FFLAG_ALLIGNORE(a) ((a) &= ~SH_FFLAG_ALLIGNORE)
+
+#define SH_FFLAG_VISITED_SET(a) (((a) & SH_FFLAG_VISITED) != 0)
+#define SET_SH_FFLAG_VISITED(a) ((a) |= SH_FFLAG_VISITED)
+#define CLEAR_SH_FFLAG_VISITED(a) ((a) &= ~SH_FFLAG_VISITED)
+
+#define SH_FFLAG_CHECKED_SET(a) (((a) & SH_FFLAG_VISITED) != 0)
+#define SET_SH_FFLAG_CHECKED(a) ((a) |= SH_FFLAG_VISITED)
+#define CLEAR_SH_FFLAG_CHECKED(a) ((a) &= ~SH_FFLAG_VISITED)
+
+#define SH_FFLAG_REPORTED_SET(a) (((a) & SH_FFLAG_REPORTED) != 0)
+#define SET_SH_FFLAG_REPORTED(a) ((a) |= SH_FFLAG_REPORTED)
+#define CLEAR_SH_FFLAG_REPORTED(a) ((a) &= ~SH_FFLAG_REPORTED)
+
+#define SH_FFLAG_SUIDCHK_SET(a) (((a) & SH_FFLAG_SUIDCHK) != 0)
+#define SET_SH_FFLAG_SUIDCHK(a) ((a) |= SH_FFLAG_SUIDCHK)
+#define CLEAR_SH_FFLAG_SUIDCHK(a) ((a) &= ~SH_FFLAG_SUIDCHK)
+
+#define SH_FFLAG_ENOENT_SET(a) (((a) & SH_FFLAG_ENOENT) != 0)
+#define SET_SH_FFLAG_ENOENT(a) ((a) |= SH_FFLAG_ENOENT)
+#define CLEAR_SH_FFLAG_ENOENT(a) ((a) &= ~SH_FFLAG_ENOENT)
+
+/* Flags for inotify
+ */
+#define SH_INOTIFY_USE (1<<0)
+#define SH_INOTIFY_DOSCAN (1<<1)
+#define SH_INOTIFY_NEEDINIT (1<<2)
+#define SH_INOTIFY_INSCAN (1<<3)
+#define SH_INOTIFY_IFUSED(a) if ((sh.flag.inotify & SH_INOTIFY_USE) != 0) { a }
+
+
+/**************************************************
+ *
+ * TYPEDEFS
+ *
+ **************************************************/
+
+enum {
+ SH_LEVEL_READONLY = 1,
+ SH_LEVEL_LOGFILES = 2,
+ SH_LEVEL_LOGGROW = 3,
+ SH_LEVEL_NOIGNORE = 4,
+ SH_LEVEL_ALLIGNORE = 5,
+ SH_LEVEL_ATTRIBUTES = 6,
+ SH_LEVEL_USER0 = 7,
+ SH_LEVEL_USER1 = 8,
+ SH_LEVEL_USER2 = 9,
+ SH_LEVEL_USER3 = 10,
+ SH_LEVEL_USER4 = 11,
+ SH_LEVEL_PRELINK = 12
+};
+
+typedef struct {
+ time_t alarm_interval;
+ time_t alarm_last;
+} sh_timer_t;
+
+typedef struct {
+ char path[SH_PATHBUF];
+ char hash[KEY_LEN+1];
+} sh_sh_df;
+
+typedef struct {
+ char user[USER_MAX];
+ char group[GROUP_MAX];
+ char home[SH_PATHBUF];
+ uid_t uid;
+ gid_t gid;
+} sh_sh_user;
+
+typedef struct {
+ char name[SH_PATHBUF]; /* local hostname */
+ char system[SH_MINIBUF]; /* system */
+ char release[SH_MINIBUF]; /* release */
+ char machine[SH_MINIBUF]; /* machine */
+} sh_sh_local;
+
+typedef struct {
+ char name[SH_PATHBUF];
+ char alt[SH_PATHBUF];
+} sh_sh_remote;
+
+typedef struct {
+ unsigned long bytes_hashed; /* bytes last check */
+ unsigned long bytes_speed; /* bytes/sec last check */
+ unsigned long mail_success; /* mails sent */
+ unsigned long mail_failed; /* mails not sent */
+ time_t time_start; /* start last check */
+ time_t time_check; /* time last check */
+ unsigned long dirs_checked; /* #dirs last check */
+ unsigned long files_checked; /* #files last check */
+ unsigned long files_report; /* #file reports */
+ unsigned long files_error; /* #file access error */
+ unsigned long files_nodir; /* #file not a directory*/
+} sh_sh_stat;
+
+typedef struct {
+ int exit; /* exit value */
+ int checkSum; /* whether to init/check checksums */
+ int update; /* update db */
+ int opts; /* reading cl options */
+ int started; /* finished with startup stuff */
+ int isdaemon; /* daemon or not */
+ int loop; /* go in loop even if not daemon */
+ int nice; /* desired nicety */
+ int isserver; /* server or not */
+ int islocked; /* BAD if logfile not locked */
+ int smsg; /* GOOD if end message sent */
+ int log_start; /* TRUE if new audit trail */
+ int reportonce; /* TRUE if bad files only once rep.*/
+ int fulldetail; /* TRUE if full details requested */
+ int client_severity; /* TRUE if client severity used */
+ int client_class; /* TRUE if client class used */
+ int hidefile; /* TRUE if file not shown in log */
+ int inotify; /* Flags for inotify */
+ int audit;
+ unsigned long aud_mask;
+} sh_sh_flag;
+
+typedef struct {
+
+ char prg_name[8];
+
+ UINT64 pid;
+
+ sh_sh_df exec;
+ sh_sh_df conf;
+ sh_sh_df data;
+
+ sh_sh_user real;
+ sh_sh_user effective;
+ sh_sh_user run;
+
+ sh_sh_local host;
+
+ sh_sh_remote srvtime;
+ sh_sh_remote srvmail;
+ sh_sh_remote srvexport;
+ sh_sh_remote srvcons;
+ sh_sh_remote srvlog;
+
+ sh_sh_stat statistics;
+ sh_sh_flag flag;
+
+#ifdef SH_STEALTH
+ unsigned long off_data;
+#endif
+
+ sh_timer_t mailNum;
+ sh_timer_t mailTime;
+ sh_timer_t fileCheck;
+
+ int looptime; /* timing for main loop */
+ /*@null@*//*@out@*/ char * timezone;
+
+ int delayload;
+
+#ifdef SCREW_IT_UP
+ int sigtrap_max_duration;
+#endif
+
+ char * outpath;
+} sh_struct;
+
+
+extern volatile int sig_raised;
+extern volatile int sig_urgent;
+extern volatile int sig_debug_switch; /* SIGUSR1 */
+extern volatile int sig_suspend_switch; /* SIGUSR2 */
+extern volatile int sh_global_suspend_flag;
+extern volatile int sig_fresh_trail; /* SIGIOT */
+extern volatile int sh_thread_pause_flag;
+extern volatile int sig_config_read_again; /* SIGHUP */
+extern volatile int sig_terminate; /* SIGQUIT */
+extern volatile int sig_termfast; /* SIGTERM */
+extern volatile int sig_force_check; /* SIGTTOU */
+extern volatile int sig_force_silent; /* SIGTSTP */
+extern volatile int sh_global_check_silent;
+extern volatile int sh_load_delta_flag;
+
+extern long int eintr__result;
+
+extern int sh_argc_store;
+extern char ** sh_argv_store;
+
+#include "sh_calls.h"
+
+
+typedef struct {
+ char sh_sockpass[2*SOCKPASS_MAX+2];
+ char sigkey_old[KEY_LEN+1];
+ char sigkey_new[KEY_LEN+1];
+ char mailkey_old[KEY_LEN+1];
+ char mailkey_new[KEY_LEN+1];
+ char crypt[KEY_LEN+1];
+ char session[KEY_LEN+1];
+ char vernam[KEY_LEN+1];
+ int mlock_failed;
+
+ char pw[PW_LEN];
+
+ char poolv[KEY_BYT];
+ int poolc;
+
+ int rngI;
+ UINT32 rng0[3];
+ UINT32 rng1[3];
+ UINT32 rng2[3];
+
+ UINT32 res_vec[6];
+
+ UINT32 ErrFlag[2];
+
+#ifdef SH_ENCRYPT
+ /*@out@*/ keyInstance keyInstE;
+ /*@out@*/ keyInstance keyInstD;
+#endif
+} sh_key_t;
+
+extern sh_struct sh;
+/*@null@*/ extern sh_key_t *skey;
+
+/**************************************************
+ *
+ * macros
+ *
+ **************************************************/
+
+#if defined(SH_ABORT_ON_ERROR)
+#define SH_ABORT abort()
+#else
+#define SH_ABORT
+#endif
+
+
+
+/* The semantics of the built-in are that it is expected that expr == const
+ * for __builtin_expect ((expr), const)
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define SH_LIKELY(expr) (__builtin_expect((expr), 1))
+#define SH_UNLIKELY(expr) (__builtin_expect((expr), 0))
+#else
+#define SH_LIKELY(expr) (expr)
+#define SH_UNLIKELY(expr) (expr)
+#endif
+
+/* signal-safe log function
+ */
+int safe_logger (int thesignal, int method, char * details);
+void safe_fatal (const char * details, const char *f, int l);
+
+#define SH_VALIDATE_EQ(a,b) \
+ do { \
+ if ((a) != (b)) safe_fatal(#a " != " #b, FIL__, __LINE__);\
+ } while (0)
+
+#define SH_VALIDATE_NE(a,b) \
+ do { \
+ if ((a) == (b)) safe_fatal(#a " == " #b, FIL__, __LINE__);\
+ } while (0)
+
+#define SH_VALIDATE_GE(a,b) \
+ do { \
+ if ((a) < (b)) safe_fatal(#a " < " #b, FIL__, __LINE__);\
+ } while (0)
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#ifdef USE_SUID
+#define MLOCK(a, b) \
+ if ((skey != NULL) && skey->mlock_failed == S_FALSE){ \
+ (void) sl_set_suid(); \
+ if (sh_unix_mlock(FIL__, __LINE__, a, b) < 0) skey->mlock_failed = S_TRUE; \
+ (void) sl_unset_suid(); }
+#else
+#define MLOCK(a, b) \
+ if ((skey != NULL) && skey->mlock_failed == S_FALSE){ \
+ if (sh_unix_mlock(FIL__, __LINE__, a, b) < 0) skey->mlock_failed = S_TRUE; }
+#endif
+#else
+#define MLOCK(a, b) \
+ ;
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#ifdef USE_SUID
+#define MUNLOCK(a, b) \
+ if ((skey != NULL) && skey->mlock_failed == S_FALSE){ \
+ (void) sl_set_suid(); \
+ (void) sh_unix_munlock( a, b );\
+ (void) sl_unset_suid(); }
+#else
+#define MUNLOCK(a, b) \
+ if ((skey != NULL) && skey->mlock_failed == S_FALSE){ \
+ (void) sh_unix_munlock( a, b ); }
+#endif
+#else
+#define MUNLOCK(a, b) \
+ ;
+#endif
+
+#ifdef SH_STEALTH
+void sh_do_encode (char * str, int len);
+#define sh_do_decode sh_do_encode
+#endif
+
+/* #if defined(SCREW_IT_UP)
+ * extern volatile int sh_not_traced;
+ * inline int sh_sigtrap_prepare();
+ * inline int sh_derr();
+ * #endif
+ */
+
+#if defined(SCREW_IT_UP) && (defined(__FreeBSD__) || defined(__linux__)) && defined(__i386__)
+#define BREAKEXIT(expr) \
+ do { \
+ int ixi; \
+ for (ixi = 0; ixi < 8; ++ixi) { \
+ if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
+ _exit(EXIT_FAILURE); \
+ } \
+ } \
+ while (1 == 0)
+#else
+#define BREAKEXIT(expr)
+#endif
+
+
+
+#include "sh_cat.h"
+#include "sh_trace.h"
+#include "sh_mem.h"
+
+#endif
+
+/* CRIT: */
+/* NEW_CLIENT <client> */
+/* BAD_CLIENT <client> -- <details> */
+/* ERR_CLIENT <client> -- <details> */
+
+/* ALERT: */
+/* LOG_KEY samhain|yule <key> */
+/* STARTUP samhain|yule -- user <username> */
+/* EXIT samhain|yule */
+/* GOODSIG <file> <user> */
+/* FP_KEY <fingerprint> */
+/* GOODSIG_DAT <file> <user> */
+/* FP_KEY_DAT <fingerprint> */
+/* TIGER_CFG <file> <checksum> */
+/* TIGER_DAT <file> <checksum> */
+
+/* PANIC -- <details> */
+/* ERROR -- <details> */
+
+/* Policy */
+/* POLICY <code> <file> */
+/* <code> = MISSING || ADDED || NOT_A_DIRECTORY || <policy> */
+
+
+
diff --git a/include/sh_MK.h b/include/sh_MK.h
new file mode 100644
index 0000000..f504852
--- /dev/null
+++ b/include/sh_MK.h
@@ -0,0 +1,27 @@
+#ifndef SH_MK_H
+#define SH_MK_H
+#define MKB_16 1
+#define MKB_14 1
+#define MKB_13 1
+#define MKB_12 1
+#define MKB_11 1
+#define MKB_10 1
+#define MKB_09 1
+#define MKB_08 1
+#define MKB_06 1
+#define MKB_05 1
+#define MKB_04 1
+#define MKB_03 1
+#define MKA_08 1
+#define MKA_02 1
+#define MKA_01 1
+#define MKC_16 1
+#define MKC_15 1
+#define MKC_08 1
+#define MKC_06 1
+#define MKC_05 1
+#define MKC_01 1
+#define MKD_15 1
+#define MKD_07 1
+#define MKD_06 1
+#endif
diff --git a/include/sh_calls.h b/include/sh_calls.h
new file mode 100644
index 0000000..7af5e08
--- /dev/null
+++ b/include/sh_calls.h
@@ -0,0 +1,104 @@
+#ifndef SH_CALLS_H
+#define SH_CALLS_H
+
+#define AUD_CHDIR (1UL << 0)
+#define AUD_CHMOD (1UL << 1)
+#define AUD_CHOWN (1UL << 2)
+#define AUD_CREAT (1UL << 3)
+#define AUD_DUP (1UL << 4)
+#define AUD_EXEC (1UL << 5)
+#define AUD_EXIT (1UL << 6)
+#define AUD_FORK (1UL << 7)
+#define AUD_KILL (1UL << 8)
+#define AUD_LINK (1UL << 9)
+#define AUD_MKDIR (1UL << 10)
+#define AUD_MKFIFO (1UL << 11)
+#define AUD_OPEN (1UL << 12)
+#define AUD_PIPE (1UL << 13)
+#define AUD_RENAME (1UL << 14)
+#define AUD_RMDIR (1UL << 15)
+#define AUD_SETGID (1UL << 16)
+#define AUD_SETUID (1UL << 17)
+#define AUD_UNLINK (1UL << 18)
+#define AUD_UTIME (1UL << 19)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <utime.h>
+
+/*@-fixedformalarray@*/
+
+#include "config_xor.h"
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#undef SH_GNUC_NORETURN
+#define SH_GNUC_NORETURN __attribute__((noreturn))
+#else
+#undef SH_GNUC_NORETURN
+#define SH_GNUC_NORETURN
+#endif
+
+
+/* Set aud functions
+ */
+int sh_aud_set_functions(const char * str_s);
+
+#ifdef SH_IPVX_H
+long int retry_accept(const char * file, int line,
+ int fd, struct sh_sockaddr *serv_addr, int * addrlen);
+#endif
+
+void sh_calls_enable_sub();
+int sh_calls_set_sub (const char * str);
+
+long int retry_stat (const char * file, int line,
+ const char *file_name, struct stat *buf);
+long int retry_fstat(const char * file, int line,
+ int filed, struct stat *buf);
+long int retry_lstat_ns(const char * file, int line,
+ const char *file_name, struct stat *buf);
+long int retry_lstat(const char * file, int line,
+ const char *file_name, struct stat *buf);
+long int retry_fcntl(const char * file, int line,
+ int fd, int cmd, long arg);
+
+long int retry_msleep (int sec, int millisec);
+
+long int retry_sigaction(const char * file, int line,
+ int signum, const struct sigaction *act,
+ struct sigaction *oldact);
+
+int sh_calls_set_bind_addr (const char *);
+long int retry_connect(const char * file, int line,
+ int fd, struct sockaddr *serv_addr, int addrlen);
+
+long int retry_aud_dup2 (const char * file, int line, int fd, int fd2);
+long int retry_aud_execve (const char * file, int line,
+ const char *dateiname, char * argv[],
+ char *envp[]);
+long int retry_aud_dup (const char * file, int line,
+ int fd);
+long int retry_aud_chdir (const char * file, int line,
+ const char *path);
+long int retry_aud_unlink (const char * file, int line,
+ char * path);
+long int retry_aud_utime (const char * file, int line,
+ char * path, struct utimbuf *buf);
+
+long int aud_open (const char * file, int line, int privs,
+ const char *pathname, int flags, mode_t mode);
+long int aud_open_noatime (const char * file, int line, int privs,
+ const char *pathname, int flags, mode_t mode,
+ int * o_noatime);
+/*@noreturn@*/
+void aud_exit (const char * file, int line, int fd) SH_GNUC_NORETURN;
+/*@noreturn@*/
+void aud__exit (const char * file, int line, int fd) SH_GNUC_NORETURN;
+pid_t aud_fork (const char * file, int line);
+int aud_pipe (const char * file, int line, int modus[2]);
+int aud_setuid (const char * file, int line, uid_t uid);
+int aud_setgid (const char * file, int line, gid_t gid);
+long int aud_kill (const char * file, int line, pid_t pid, int sig);
+
+#endif
diff --git a/include/sh_cat.h b/include/sh_cat.h
new file mode 100644
index 0000000..0096206
--- /dev/null
+++ b/include/sh_cat.h
@@ -0,0 +1,355 @@
+
+#ifndef SH_CAT_H
+#define SH_CAT_H
+
+typedef struct foo_cat_entry {
+ unsigned long id;
+ unsigned long priority;
+ unsigned long class;
+ const char * format;
+} cat_entry;
+
+extern cat_entry msg_cat[];
+
+extern const char * class_cat[];
+
+#define AUD 0
+#define PANIC 1
+#define RUN 2
+#define FIL 3
+#define TCP 4
+#define ERR 5
+#define STAMP 6
+#define ENET 7
+#define EINPUT 8
+#define EVENT 9
+#define START 10
+#define LOGKEY 11
+#define OTHER_CLA ((1 << RUN)|(1 << FIL)|(1 << TCP))
+#define RUN_NEW ((1 << RUN)|(1 << EVENT)|(1 << START)|(1 << LOGKEY))
+#define FIL_NEW ((1 << FIL)|(1 << EVENT))
+#define ERROR_CLA ((1 << ERR)|(1 << PANIC)|(1 << ENET)|(1 << EINPUT))
+
+#define SH_CLA_RAW_MAX 12
+#define SH_CLA_MAX 16
+
+
+#if 0
+enum {
+ SH_CLA_AUD = (1 << 0),
+ SH_CLA_PANIC = (1 << 1),
+ SH_CLA_RUN = (1 << 2),
+ SH_CLA_FIL = (1 << 3),
+ SH_CLA_TCP = (1 << 4),
+ SH_CLA_ERR = (1 << 5),
+ SH_CLA_STAMP = (1 << 6),
+ SH_CLA_ENET = (1 << 7),
+ SH_CLA_EINPUT = (1 << 8)
+};
+#endif
+
+enum {
+ MSG_EXIT_ABORTS,
+ MSG_START_SRV,
+
+ MSG_EXIT_ABORT1,
+ MSG_EXIT_NORMAL,
+ MSG_START_KEY_MAIL,
+ MSG_START_KEY,
+ MSG_START_0H,
+ MSG_START_1H,
+ MSG_START_2H,
+ MSG_START_GH,
+ MSG_START_GH2,
+ MSG_SUSPEND,
+
+ MSG_MLOCK,
+ MSG_W_SIG,
+ MSG_W_CHDIR,
+
+ MSG_MOD_FAIL,
+ MSG_MOD_OK,
+ MSG_MOD_EXEC,
+
+ MSG_RECONF,
+ MSG_CHECK_0,
+ MSG_CHECK_1,
+ MSG_CHECK_2,
+ MSG_STAMP,
+
+ MSG_D_START,
+ MSG_D_DSTART,
+ MSG_D_FAIL,
+ MSG_D_DELTAOK,
+ MSG_D_DELTAFAIL,
+
+#ifndef HAVE_URANDOM
+ MSG_ENSTART,
+ MSG_ENEXEC,
+ MSG_ENFAIL,
+ MSG_ENTOUT,
+ MSG_ENCLOS,
+ MSG_ENCLOS1,
+ MSG_ENREAD,
+#endif
+
+#ifdef SH_USE_SUIDCHK
+ MSG_SUID_POLICY,
+ MSG_SUID_FOUND,
+ MSG_SUID_SUMMARY,
+ MSG_SUID_QREPORT,
+ MSG_SUID_ERROR,
+#endif
+
+#ifdef SH_USE_UTMP
+ MSG_UT_CHECK,
+
+ MSG_UT_LG1X,
+ MSG_UT_LG2X,
+ MSG_UT_LG3X,
+
+ MSG_UT_LG1A,
+ MSG_UT_LG1B,
+
+ MSG_UT_LG2A,
+ MSG_UT_LG2B,
+
+ MSG_UT_LG3A,
+ MSG_UT_LG3B,
+ MSG_UT_LG3C,
+ MSG_UT_ROT,
+
+ MSG_UT_BAD,
+ MSG_UT_FIRST,
+ MSG_UT_OUTLIER,
+#endif
+
+#ifdef SH_USE_PROCESSCHECK
+ MSG_PCK_CHECK,
+ MSG_PCK_OK,
+ MSG_PCK_P_HIDDEN,
+ MSG_PCK_HIDDEN,
+ MSG_PCK_FAKE,
+ MSG_PCK_MISS,
+#endif
+
+#ifdef SH_USE_PORTCHECK
+ MSG_PORT_MISS,
+ MSG_PORT_NEW,
+ MSG_PORT_RESTART,
+ MSG_PORT_NEWPORT,
+#endif
+
+#ifdef SH_USE_MOUNTS
+ MSG_MNT_CHECK,
+ MSG_MNT_MEMLIST,
+ MSG_MNT_MNTMISS,
+ MSG_MNT_OPTMISS,
+#endif
+
+#ifdef SH_USE_USERFILES
+ MSG_USERFILES_SUMMARY,
+#endif
+
+#ifdef USE_LOGFILE_MONITOR
+ MSG_LOGMON_CHKS,
+ MSG_LOGMON_CHKE,
+ MSG_LOGMON_MISS,
+ MSG_LOGMON_EOPEN,
+ MSG_LOGMON_EREAD,
+ MSG_LOGMON_REP,
+ MSG_LOGMON_SUM,
+ MSG_LOGMON_COR,
+ MSG_LOGMON_MARK,
+ MSG_LOGMON_BURST,
+#endif
+
+#ifdef USE_REGISTRY_CHECK
+ MSG_REG_MISS,
+ MSG_REG_NEW,
+ MSG_REG_CHANGE,
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+ MSG_FI_TOOLATE,
+ MSG_FI_CSUM,
+ MSG_FI_DSUM,
+ MSG_FI_CHK,
+ MSG_FI_NULL,
+ MSG_FI_FAIL,
+ MSG_FI_GLOB,
+ MSG_FI_COLL,
+ MSG_FI_DOUBLE,
+ MSG_FI_2LONG,
+ MSG_FI_2LONG2,
+ MSG_FI_NOPATH,
+ MSG_FI_DLNK,
+ MSG_FI_RDLNK,
+ MSG_FI_NOGRP,
+ MSG_FI_NOUSR,
+ MSG_FI_STAT,
+ MSG_FI_OBSC,
+ MSG_FI_OBSC2,
+ MSG_FI_LIST,
+ MSG_FI_LLNK,
+ MSG_FI_MISS,
+ /* #ifdef SH_USE_XML */
+ MSG_FI_MISS2,
+ MSG_FI_ADD2,
+ /* #endif */
+ MSG_FI_ADD,
+ MSG_FI_CHAN,
+ MSG_FI_NODIR,
+ MSG_FI_DBEX,
+#endif
+
+ MSG_TCP_NETRP,
+
+#ifndef SH_STANDALONE
+#ifdef INET_SYSLOG
+ MSG_INET_SYSLOG,
+ MSG_ERR_SYSLOG,
+#endif
+
+ MSG_TCP_MISMATCH,
+ MSG_TCP_MISENC,
+ MSG_TCP_NONAME,
+ MSG_TCP_UNEXP,
+ MSG_TCP_EFIL,
+ MSG_TCP_NOCONF,
+ MSG_TCP_NOAUTH,
+ MSG_TCP_CONF,
+ MSG_TCP_AUTH,
+ MSG_TCP_FOK,
+ MSG_TCP_FBAD,
+ MSG_TCP_ECONN,
+ MSG_TCP_EZERO,
+ MSG_TCP_EBGN,
+
+ MSG_TCP_CREG,
+ MSG_TCP_FAUTH,
+ MSG_TCP_TIMOUT,
+
+ MSG_TCP_RESCLT,
+ MSG_TCP_RESPEER,
+ MSG_TCP_LOOKERS,
+ MSG_TCP_LOOKUP,
+
+ MSG_TCP_TIMEXC,
+ MSG_TCP_NOCLT,
+ MSG_TCP_BADCONN,
+ MSG_TCP_FFILE ,
+ MSG_TCP_NFILE ,
+ MSG_TCP_FINV ,
+ MSG_TCP_OKFILE,
+ MSG_TCP_OKMSG,
+ MSG_TCP_MSG,
+ MSG_TCP_NEW,
+ MSG_TCP_ILL,
+ MSG_TCP_SYNC,
+ MSG_TCP_RESET,
+ MSG_TCP_CNEW,
+ MSG_E_HTML,
+#endif
+
+
+ MSG_E_AUTH,
+ MSG_ACCESS,
+ MSG_TRUST,
+ MSG_NOACCESS,
+ MSG_P_NODATA,
+
+
+#ifndef MEM_DEBUG
+ MSG_E_MNULL,
+ MSG_E_MMEM,
+#else
+ MSG_MSTAMP,
+ MSG_MSTAMP2,
+ MSG_E_MNULL,
+ MSG_E_MMEM,
+ MSG_E_MREC,
+ MSG_E_MOVER,
+ MSG_E_MUNDER,
+ MSG_E_NOTFREE,
+#endif
+
+ MSG_E_TRUST,
+ MSG_E_HASH,
+ MSG_E_ACCESS,
+ MSG_E_READ,
+ MSG_E_NOTREG,
+ MSG_E_TIMEOUT,
+ MSG_NODEV,
+ MSG_LOCKED,
+ MSG_PIDFILE,
+ MSG_NOEXEC,
+ MSG_ES_ENT,
+ MSG_ES_KEY1,
+ MSG_ES_KEY2,
+ MSG_E_GPG,
+ MSG_E_GPG_FP,
+ MSG_E_GPG_CHK,
+ MSG_E_SUBGEN,
+ MSG_E_SUBGPATH,
+ MSG_E_UNLNK,
+ MSG_E_REGEX,
+ MSG_E_OPENDIR,
+ MSG_E_TRUST1,
+ MSG_E_TRUST2,
+ MSG_E_PWNULL,
+ MSG_E_PWLONG,
+ MSG_E_GRNULL,
+
+ MSG_E_NET,
+ MSG_E_NETST,
+ MSG_E_NETST1,
+ MSG_E_NLOST,
+ MSG_E_NEST,
+
+ MSG_EINVALHEAD,
+ MSG_EINVALCONF,
+ MSG_EINVALS,
+ MSG_EINVALL,
+ MSG_EINVALD,
+ MSG_EINVALDD,
+
+ MSG_SRV_FAIL,
+ MSG_QUEUE_FULL,
+
+ MSG_AUD_OPEN,
+ MSG_AUD_DUP,
+ MSG_AUD_PIPE,
+ MSG_AUD_FORK,
+ MSG_AUD_EXIT,
+ MSG_AUD_SETUID,
+ MSG_AUD_SETGID,
+ MSG_AUD_UTIME,
+ MSG_AUD_EXEC,
+ MSG_AUD_CHDIR,
+ MSG_AUD_UNLINK,
+ MSG_AUD_KILL,
+
+ MSG_ERR_OPEN,
+ MSG_ERR_DUP,
+ MSG_ERR_PIPE,
+ MSG_ERR_FORK,
+ MSG_ERR_SETUID,
+ MSG_ERR_SETGID,
+ MSG_ERR_UTIME,
+ MSG_ERR_EXEC,
+ MSG_ERR_CHDIR,
+ MSG_ERR_UNLINK,
+ MSG_ERR_KILL,
+
+ MSG_ERR_SIGACT,
+ MSG_ERR_CONNECT,
+ MSG_ERR_ACCEPT,
+ MSG_ERR_LSTAT,
+ MSG_ERR_FSTAT,
+ MSG_ERR_STAT,
+ MSG_ERR_FCNTL
+};
+
+#endif
diff --git a/include/sh_checksum.h b/include/sh_checksum.h
new file mode 100644
index 0000000..1f99bb0
--- /dev/null
+++ b/include/sh_checksum.h
@@ -0,0 +1,27 @@
+#ifndef SH_CHECKSUM_H
+#define SH_CHECKSUM_H
+
+typedef unsigned char sha2_byte ;
+typedef UINT32 sha2_word32;
+typedef UINT64 sha2_word64;
+
+
+#define SHA256_BLOCK_LENGTH 64
+#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8)
+#define SHA256_DIGEST_LENGTH 32
+#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1)
+
+typedef struct _SHA256_CTX {
+ sha2_word32 state[8];
+ sha2_word64 bitcount;
+ sha2_byte buffer[SHA256_BLOCK_LENGTH];
+} SHA256_CTX;
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Update(SHA256_CTX*, const sha2_byte*, size_t);
+void SHA256_Final(sha2_byte[SHA256_DIGEST_LENGTH], SHA256_CTX*);
+char* SHA256_End(SHA256_CTX*, char[KEYBUF_SIZE]);
+char* SHA256_Data(const sha2_byte*, size_t, char[KEYBUF_SIZE]);
+char* SHA256_Base2Hex(char * b64digest, char * hexdigest);
+char * SHA256_ReplaceBaseByHex(const char * str, char * before, char after);
+#endif
diff --git a/include/sh_database.h b/include/sh_database.h
new file mode 100644
index 0000000..71ae8f0
--- /dev/null
+++ b/include/sh_database.h
@@ -0,0 +1,16 @@
+#ifndef SH_DATABASE_H
+#define SH_DATABASE_H
+
+void sh_database_reset(void);
+int sh_database_insert (char * message);
+
+int sh_database_use_persistent (const char * str);
+
+int sh_database_set_database (const char * str);
+int sh_database_set_table (const char * str);
+int sh_database_set_host (const char * str);
+int sh_database_set_user (const char * str);
+int sh_database_set_password (const char * str);
+int sh_database_add_to_hash (const char * str);
+int set_enter_wrapper (const char * str);
+#endif
diff --git a/include/sh_dbCheck.h b/include/sh_dbCheck.h
new file mode 100644
index 0000000..847ae28
--- /dev/null
+++ b/include/sh_dbCheck.h
@@ -0,0 +1,26 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_DBCHECK_H
+#define SH_DBCHECK_H
+
+int sh_dbCheck_verify (const char * db_file);
+
+#endif
diff --git a/include/sh_dbCreate.h b/include/sh_dbCreate.h
new file mode 100644
index 0000000..39d2aaa
--- /dev/null
+++ b/include/sh_dbCreate.h
@@ -0,0 +1,26 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_DBCREATE_H
+#define SH_DBCREATE_H
+
+int sh_dbCreate (const char * path);
+
+#endif
diff --git a/include/sh_dbIO.h b/include/sh_dbIO.h
new file mode 100644
index 0000000..bbb316a
--- /dev/null
+++ b/include/sh_dbIO.h
@@ -0,0 +1,61 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_DBIO_H
+#define SH_DBIO_H
+
+
+
+/* Read one line, trim newline. Return char count, or -1 on error or eof.
+ */
+int sh_dbIO_getline (FILE * fd, char * line, const size_t sizeofline);
+
+/* Read given database file for listing
+ */
+int sh_dbIO_list_db (const char * db_file);
+
+/* Write single record to database
+ */
+void sh_dbIO_data_write (file_type * buf, char * fileHash);
+
+/* Write whole default database
+ */
+int sh_dbIO_writeout_update ();
+
+/* write database to given path
+ */
+int sh_dbIO_writeout_to_path(const char * path);
+
+/* write database to stdout
+ */
+int sh_dbIO_writeout_stdout (const char * str);
+
+/* version string for database
+ */
+int sh_dbIO_version_string(const char * str);
+
+/* Load a delta database
+ */
+int sh_dbIO_load_delta();
+
+int sh_dbIO_list_binary (const char * c);
+int sh_dbIO_list_filter (const char * c);
+
+#endif
diff --git a/include/sh_dbIO_int.h b/include/sh_dbIO_int.h
new file mode 100644
index 0000000..7dfd01d
--- /dev/null
+++ b/include/sh_dbIO_int.h
@@ -0,0 +1,157 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_DBIO_INT_H
+#define SH_DBIO_INT_H
+
+#define SH_DEADFILE 0x44454144
+
+typedef struct store_info_old {
+
+ UINT32 mode;
+ UINT32 linkmode;
+
+ UINT64 dev;
+ UINT64 rdev;
+
+ UINT32 hardlinks;
+ UINT32 ino;
+
+ UINT64 size;
+ UINT64 atime;
+ UINT64 mtime;
+ UINT64 ctime;
+
+ UINT32 owner;
+ UINT32 group;
+
+ UINT32 attributes;
+
+ char c_attributes[ATTRBUF_SIZE]; /* 16 = 2*UINT64 */
+
+ unsigned short mark;
+ char c_owner[USER_MAX+2];
+ char c_group[GROUP_MAX+2];
+ char c_mode[CMODE_SIZE];
+ char checksum[KEY_LEN+1];
+
+} sh_filestore_old_t;
+
+typedef struct store_info {
+
+ UINT32 mode;
+ UINT32 linkmode;
+
+ UINT64 dev;
+ UINT64 rdev;
+
+ UINT32 hardlinks;
+ UINT32 ino;
+
+ UINT64 size;
+ UINT64 atime;
+ UINT64 mtime;
+ UINT64 ctime;
+
+ UINT32 owner;
+ UINT32 group;
+
+ UINT32 attributes;
+
+ char c_attributes[ATTRBUF_SIZE]; /* 16 = 2*UINT64 */
+
+ unsigned short mark;
+ char c_owner[USER_MAX+2];
+ char c_group[GROUP_MAX+2];
+ char c_mode[CMODE_SIZE];
+ char checksum[KEY_LEN+1];
+
+ /* If 'checkflags' is elsewhere, the compiler would still use
+ * a 6-byte padding to align the whole struct to an 8-byte boundary.
+ * ipad, opad: make explicit what the compiler does on a 64-byte system.
+ */
+ char ipad[2];
+ UINT32 checkflags;
+ char opad[4];
+
+} sh_filestore_t;
+
+typedef struct file_info {
+ sh_filestore_t theFile;
+ char * fullpath;
+ char * linkpath;
+ char * attr_string;
+ int fflags;
+ unsigned long modi_mask;
+ struct file_info * next;
+} sh_file_t;
+
+//* must fit an int */
+#define TABSIZE 65536
+
+/* must fit an unsigned short */
+/* changed for V0.8, as the */
+/* database format has changed */
+/* changed again for V0.9 */
+/* #define REC_MAGIC 19 */
+/* changed again for V1.3 */
+/* #define REC_MAGIC 20 */
+/* changed again for V1.4 */
+/* #define REC_MAGIC 21 */
+#define OLD_REC_MAGIC 21
+/* changed again for V3.2 */
+#define REC_MAGIC 22
+
+#define REC_FLAGS_ATTR (1<<8)
+#define REC_FLAGS_MASK 0xFF00
+
+/* Insert into database table
+ */
+void hashinsert (sh_file_t * tab[TABSIZE], sh_file_t * s);
+
+/* Internal conversion function
+ */
+file_type * sh_hash_create_ft (const sh_file_t * p, char * fileHash);
+
+/* Print what's in the link path
+ */
+int sh_hash_printcontent(char * linkpath);
+
+/* List database entry
+ */
+void sh_hash_list_db_entry (sh_file_t * p);
+
+/* get the location of the default/main database table
+ */
+sh_file_t ** get_default_data_table();
+
+/* Write whole database
+ */
+int sh_dbIO_writeout(sh_file_t * mtab[TABSIZE], const char * outpath, int truncate);
+
+/* Load from the default source into hash table 'tab'
+ */
+int sh_dbIO_load_db(sh_file_t * tab[TABSIZE]);
+
+/* Load from the file 'filepath' into hash table 'tab'
+ */
+int sh_dbIO_load_db_file(sh_file_t * tab[TABSIZE], const char * filepath);
+
+#endif
diff --git a/include/sh_entropy.h b/include/sh_entropy.h
new file mode 100644
index 0000000..f97ad6f
--- /dev/null
+++ b/include/sh_entropy.h
@@ -0,0 +1,28 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SH_ENTROPY_H
+#define SH_ENTROPY_H
+
+/* Deliver nbytes Bytes of system entropy (= noise).
+ * Returns 0 on success, -1 on failure.
+ */
+int sh_entropy(int nbytes, char * nbuf);
+
+#endif
diff --git a/include/sh_error.h b/include/sh_error.h
new file mode 100644
index 0000000..f7a7041
--- /dev/null
+++ b/include/sh_error.h
@@ -0,0 +1,206 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* Public interface for error routines
+ */
+#ifndef SH_ERROR_H
+#define SH_ERROR_H
+
+#include "sh_error_min.h"
+
+
+enum {
+ SH_ERR_T_START = 0,
+
+ /* 1-13 = SH_LEVEL_XXX */
+
+ SH_ERR_T_RO = SH_LEVEL_READONLY,
+ SH_ERR_T_LOGS = SH_LEVEL_LOGFILES,
+ SH_ERR_T_GLOG = SH_LEVEL_LOGGROW,
+ SH_ERR_T_NOIG = SH_LEVEL_NOIGNORE,
+ SH_ERR_T_ALLIG = SH_LEVEL_ALLIGNORE,
+ SH_ERR_T_ATTR = SH_LEVEL_ATTRIBUTES,
+ SH_ERR_T_USER0 = SH_LEVEL_USER0,
+ SH_ERR_T_USER1 = SH_LEVEL_USER1,
+ SH_ERR_T_USER2 = SH_LEVEL_USER2,
+ SH_ERR_T_USER3 = SH_LEVEL_USER3,
+ SH_ERR_T_USER4 = SH_LEVEL_USER4,
+ SH_ERR_T_PRELINK = SH_LEVEL_PRELINK,
+
+ SH_ERR_T_DIR = 13,
+ SH_ERR_T_FILE = 14,
+ SH_ERR_T_NAME = 15,
+
+ SH_ERR_T_END = 16
+};
+
+
+typedef struct _errFlags {
+ int debug;
+ int HaveLog;
+
+ int loglevel;
+ int loglevel_temp;
+ int printlevel;
+ int maillevel;
+ int exportlevel;
+ int sysloglevel;
+ int externallevel;
+ int databaselevel;
+
+ int log_class;
+ int print_class;
+ int mail_class;
+ int export_class;
+ int syslog_class;
+ int external_class;
+ int database_class;
+
+ /* HAVE_LIBPRELUDE */
+ int preludelevel;
+ int prelude_class;
+
+} blurb_errFlags;
+
+extern int ShDFLevel[SH_ERR_T_END];
+
+/* set mask for message class
+ */
+int sh_error_log_mask (const char * c);
+int sh_error_print_mask (const char * c);
+int sh_error_mail_mask (const char * c);
+int sh_error_export_mask (const char * c);
+int sh_error_syslog_mask (const char * c);
+int sh_error_external_mask (const char * c);
+int sh_error_database_mask (const char * c);
+int sh_error_prelude_mask (const char * c);
+
+
+int sh_error_verify (const char * s);
+int sh_error_logverify_mod (const char * s); /* just list, don't verify */
+int sh_error_logverify (const char * s);
+
+void sh_error_dbg_switch(void);
+
+#ifdef SH_WITH_SERVER
+
+void sh_error_set_peer(const char * str);
+#ifdef HAVE_LIBPRELUDE
+void sh_error_set_peer_ip(const char * str);
+#endif
+int set_flag_sep_log (const char * str);
+#endif
+
+/* init or re-init log facilities that need it
+ */
+void sh_error_fixup(void);
+
+/* only to stderr (GOOD/BAD)
+ */
+void sh_error_only_stderr (int flag);
+
+/* facilities unsafe for closeall()
+ */
+void sh_error_enable_unsafe (int flag);
+
+/* set syslog facility
+ */
+int sh_log_set_facility (const char * c);
+
+/* map heartbeat messages
+ */
+int sh_log_set_stamp_priority (const char * c);
+
+/* define message header
+ */
+int sh_error_ehead (/*@null@*/const char * s);
+
+/* set level for error logging
+ */
+int sh_error_setlog(const char * str_s);
+
+/* set severity levels
+ */
+int sh_error_set_iv (int iv, const char * severity_s);
+
+/* set priorities
+ */
+int sh_error_set_level(const char * str_s, int *facility);
+
+/* set level for TCP export
+ */
+int sh_error_setexport(const char * str_s);
+
+/* set level for syslog
+ */
+int sh_error_set_syslog (const char * flag_s);
+
+/* set level for printing
+ */
+int sh_error_setprint(const char * flag_s);
+
+/* set severity for external
+ */
+int sh_error_set_external (const char * str_s);
+
+/* set severity for external
+ */
+int sh_error_set_database (const char * str_s);
+
+/* set severity for external
+ */
+int sh_error_set_prelude (const char * str_s);
+
+
+/* set level for mailing
+ */
+int sh_error_setseverity (const char * flag);
+
+/* set debug level
+ */
+int sh_error_setdebug (char * debug_s);
+
+/* switch on/off log to file temporarily
+ */
+void sh_error_logoff(void);
+void sh_error_logrestore(void);
+
+/* short errfile
+ */
+void sh_efile_report();
+int sh_efile_path(const char * str);
+int sh_efile_group(const char * str);
+
+/* (re)set the console device(s)
+ */
+int sh_log_set_console (const char * address);
+void reset_count_dev_console(void);
+
+/* close the message queue [no-op if !defined(WITH_MESSAGE_QUEUE)]
+ */
+void close_ipc (void);
+
+#ifdef WITH_MESSAGE_QUEUE
+/* enable message queue
+ */
+int enable_msgq(const char * foo);
+#endif
+
+#endif
diff --git a/include/sh_error_min.h b/include/sh_error_min.h
new file mode 100644
index 0000000..b9b784c
--- /dev/null
+++ b/include/sh_error_min.h
@@ -0,0 +1,41 @@
+#ifndef SH_ERROR_MIN_H
+#define SH_ERROR_MIN_H
+
+/* Level of severity
+ */
+typedef enum {
+
+ SH_ERR_ALL = (1 << 0), /* debug */
+ SH_ERR_INFO = (1 << 1), /* info */
+ SH_ERR_NOTICE = (1 << 2), /* notice */
+ SH_ERR_WARN = (1 << 3), /* warning */
+ SH_ERR_STAMP = (1 << 4), /* mark */
+ SH_ERR_ERR = (1 << 5), /* error */
+ SH_ERR_SEVERE = (1 << 6), /* crit */
+ SH_ERR_FATAL = (1 << 7), /* alert */
+
+ SH_ERR_NOT = (1 << 8),
+ SH_ERR_INET = (1 << 9),
+ SH_ERR_MAX = (1 << 9)
+ } ShErrLevel;
+
+/* this function should be called to report an error
+ */
+void sh_error_handle (int flag, const char * file, long line,
+ long errnum, unsigned long msg_index, ...);
+
+/* this function should be called to (only) send mail
+ */
+void sh_error_mail (const char * alias, int sev,
+ const char * file, long line,
+ long status, unsigned long msg_id, ...);
+
+/* convert a string to a numeric priority
+ */
+int sh_error_convert_level (const char * str_s);
+
+/* error messages
+ */
+char * sh_error_message (int tellme, char * str, size_t len);
+
+#endif
diff --git a/include/sh_extern.h b/include/sh_extern.h
new file mode 100644
index 0000000..64a0a99
--- /dev/null
+++ b/include/sh_extern.h
@@ -0,0 +1,162 @@
+#ifndef SH_EXTERN_H
+#define SH_EXTERN_H
+
+#include <stdarg.h>
+
+typedef struct
+{
+ char * command;
+ int argc;
+ char * argv[32];
+ int envc;
+ char * envv[32];
+ char checksum[KEY_LEN + 1];
+#if 0
+ uid_t trusted_users[32];
+#endif
+ uid_t run_user_uid;
+ gid_t run_user_gid;
+ int privileged;
+
+ int pipeFD;
+ SL_TICKET pipeTI;
+ pid_t pid;
+ FILE * pipe;
+ char rw;
+ int exit_status;
+ int fork_twice;
+
+ int com_fd;
+ SL_TICKET com_ti;
+
+} sh_tas_t;
+
+
+/*
+ * -- generic safe popen; returns 0 on success, -1 otherwise
+ */
+int sh_ext_popen (sh_tas_t * task);
+
+/*
+ * -- generic simple safe popen; returns 0 on success, -1 otherwise,
+ * executes shell command
+ */
+int sh_ext_popen_init (sh_tas_t * task, const char * command, char * argv0, ...) SH_GNUC_SENTINEL;
+
+/*
+ * -- Execute command, return first line of output
+ */
+int sh_ext_system (char * command, char * argv0, ...) SH_GNUC_SENTINEL;
+
+/*
+ * -- Execute command, return first line of output
+ */
+char * sh_ext_popen_str (const char * command);
+
+/*
+ * -- close the pipe, clear and return task->exit_status
+ */
+int sh_ext_pclose (sh_tas_t * task);
+
+/*
+ * -- add CL argument, return # of arguments
+ */
+int sh_ext_tas_add_argv(sh_tas_t * tas, const char * val);
+/*
+ * -- remove last CL argument
+ */
+int sh_ext_tas_rm_argv(sh_tas_t * tas);
+/*
+ * -- add environment variable, return # of variables
+ */
+int sh_ext_tas_add_envv(sh_tas_t * tas, const char * key, const char * val);
+/*
+ * -- set command
+ */
+void sh_ext_tas_command(sh_tas_t * tas, const char * command);
+/*
+ * -- initialize task structure
+ */
+void sh_ext_tas_init (sh_tas_t * tas);
+/*
+ * -- free task structure
+ */
+void sh_ext_tas_free(sh_tas_t * tas);
+
+
+#if defined(WITH_EXTERNAL)
+
+/*
+ * -- start a new external command, and add it to the list
+ */
+int sh_ext_setcommand(const char * cmd);
+
+/*
+ * -- explicitely close a command
+ */
+int sh_ext_close_command (const char * str);
+
+/*
+ * -- clean up the command list
+ */
+int sh_ext_cleanup(void);
+
+/*
+ * -- set deadtime
+ */
+int sh_ext_deadtime (const char * str);
+
+/*
+ * -- add keywords to the OR filter
+ */
+int sh_ext_add_or (const char * str);
+
+/*
+ * -- add keywords to the AND filter
+ */
+int sh_ext_add_and (const char * str);
+
+/*
+ * -- add keywords to the NOT filter
+ */
+int sh_ext_add_not (const char * str);
+
+/*
+ * -- add keywords to the CL argument list
+ */
+int sh_ext_add_argv (const char * str);
+
+/*
+ * -- add a path to the environment
+ */
+int sh_ext_add_default (const char * str);
+
+/*
+ * -- add an environment variable
+ */
+int sh_ext_add_environ (const char * str);
+
+/*
+ * -- define type
+ */
+int sh_ext_type (const char * str);
+
+/*
+ * -- define checksum
+ */
+int sh_ext_checksum (const char * str);
+
+/*
+ * -- choose privileges
+ */
+int sh_ext_priv (const char * c);
+
+/*
+ * -- execute external script/program
+ */
+int sh_ext_execute (char t1, char t2, char t3, /*@null@*/char * message,
+ size_t msg_siz);
+
+#endif
+
+#endif
diff --git a/include/sh_fInotify.h b/include/sh_fInotify.h
new file mode 100644
index 0000000..d468a56
--- /dev/null
+++ b/include/sh_fInotify.h
@@ -0,0 +1,13 @@
+
+#ifndef SH_F_INOTIFY_H
+#define SH_F_INOTIFY_H
+
+int sh_fInotify_init(struct mod_type * arg);
+int sh_fInotify_timer(time_t tcurrent);
+int sh_fInotify_run(void);
+int sh_fInotify_reconf(void);
+int sh_fInotify_cleanup(void);
+
+extern sh_rconf sh_fInotify_table[];
+
+#endif
diff --git a/include/sh_fifo.h b/include/sh_fifo.h
new file mode 100644
index 0000000..fdea169
--- /dev/null
+++ b/include/sh_fifo.h
@@ -0,0 +1,95 @@
+
+#ifndef SH_FIFO_H
+#define SH_FIFO_H
+
+/*****************************************************
+ *
+ * the maximum number of entries the fifo will hold
+ * - additional entries are simply not accepted -
+ *
+ *****************************************************/
+
+#define SH_FIFO_MAX 16384
+
+/*****************************************************
+ *
+ * the type definitions for the fifo
+ *
+ *****************************************************/
+
+struct dlist {
+ struct dlist * next;
+ char * data;
+ char * s_xtra;
+ int i_xtra;
+ int transact;
+ struct dlist * prev;
+};
+
+typedef struct fifo_str {
+ struct dlist * head_ptr;
+ struct dlist * tail_ptr;
+ int fifo_cts;
+} SH_FIFO;
+
+#define SH_FIFO_INITIALIZER { NULL, NULL, 0 }
+
+/*****************************************************
+ *
+ * fifo functions
+ *
+ *****************************************************/
+
+/* Initialize the list.
+ *
+ */
+#define fifo_init(fifo_p) { (fifo_p)->fifo_cts = 0; (fifo_p)->head_ptr = NULL; \
+ (fifo_p)->tail_ptr = NULL; }
+
+
+/* Push an item on the head of the list.
+ *
+ * Returns: -1 if the list is full, 0 on success
+ */
+int push_list (SH_FIFO * fifo, const char * indat, int in_i, const char * in_str);
+#define sh_fifo_push(a, b) push_list((a), (b), 0, NULL)
+
+/* Push an item on the tail of the list.
+ *
+ * Returns: -1 if the list is full, 0 on success
+ */
+int push_tail_list (SH_FIFO * fifo, const char * indat, int in_i, const char * in_str);
+#define sh_fifo_push_tail(a, b) push_tail_list((a), (b), 0, NULL)
+
+/* pop an item from the tail of the list
+ *
+ * Returns: NULL if the list is empty,
+ * freshly allocated memory on success (should be free'd by caller)
+ */
+char * pop_list (SH_FIFO * fifo);
+#define sh_fifo_pop(a) pop_list((a))
+
+/* ---- Special functions -------------------------------------------------*/
+
+/* This is for eMail where different recipients may be eligible for *
+ * different subsets of messages. We need to delete all that were sent *
+ * to all intended recipients, and keep all with at least one failure. */
+
+/* Iterate over list and check for each if it is valid for 'tag';
+ * i.e. (item->s_extra == tag). If yes, add to the returned string.
+ * If (okNull == False) then item->s_xtra must be defined
+ */
+sh_string * tag_list (SH_FIFO * fifo, char * tag,
+ int(*check)(int, const char*, const char*, const void*),
+ const void * info, int okNull);
+
+/* Flag all tagged as candidate to keep */
+void rollback_list (SH_FIFO * fifo);
+/* Flag all tagged as candidate to delete */
+void mark_list (SH_FIFO * fifo);
+/* Remove all flags */
+void reset_list (SH_FIFO * fifo);
+/* Delete all marked for delete that are not flagged for keep */
+int commit_list (SH_FIFO * fifo);
+
+#endif
diff --git a/include/sh_files.h b/include/sh_files.h
new file mode 100644
index 0000000..c51c68e
--- /dev/null
+++ b/include/sh_files.h
@@ -0,0 +1,265 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SH_FILES_H
+#define SH_FILES_H
+
+void sh_audit_mark (const char * file);
+void sh_audit_commit ();
+void sh_audit_delete_all ();
+char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, char * result, size_t rsize);
+
+struct sh_dirent {
+ char * sh_d_name;
+ struct sh_dirent * next;
+};
+
+/* Fix the check flags
+ */
+void sh_files_fixup_mask (int class, unsigned long * check_flags);
+
+/* Dequote a filename in the config file
+ */
+char * sh_files_parse_input(const char * str_s, size_t * len);
+
+/* Check whether a file is in the config
+ */
+char * sh_files_findfile(const char * path);
+
+/* Find the most specific directory in the config
+ */
+char * sh_files_find_mostspecific_dir(const char * path);
+
+/* free a directory listing
+ */
+void kill_sh_dirlist (struct sh_dirent * dirlist);
+
+#ifdef NEED_ADD_DIRENT
+/* add an entry to a directory listing
+ */
+struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry,
+ struct sh_dirent * dirlist);
+#endif
+
+/* register exceptions to hardlink check
+ */
+int sh_files_hle_reg (const char * str);
+
+/* Check for new files/dirs matching configured glob patterns.
+ */
+void sh_files_check_globPatterns();
+
+/* Check for new files (only) matching configured glob patterns.
+ */
+void sh_files_check_globFilePatterns();
+
+/* check the setup
+ */
+int sh_files_test_setup (void);
+
+/* check if allignore
+ */
+int sh_files_is_allignore (char * str);
+
+/* activate hardlink check
+ */
+int sh_files_check_hardlinks (const char * opt);
+
+/* check rsrc fork (Mac OS X)
+ */
+int sh_files_use_rsrc(const char * str);
+
+/* set recursion depth
+ */
+int sh_files_setrec (void);
+
+/* report only once
+ */
+int sh_files_reportonce(const char * c);
+
+/* report full details
+ */
+int sh_files_fulldetail(const char * c);
+
+/* reset the 'checked' flag
+ */
+void sh_dirs_reset(void);
+
+/* reset the 'checked' flag
+ */
+void sh_files_reset(void);
+
+/* set maximum recursion level
+ */
+int sh_files_setrecursion (const char * flag_s);
+
+/* select a directory stack 2=Two, else One (standard)
+ */
+int set_dirList (int which);
+
+/* push a directory on the stack USER0
+ */
+int sh_files_pushdir_user0 (const char * dirName);
+
+/* push a directory on the stack USER1
+ */
+int sh_files_pushdir_user1 (const char * dirName);
+
+/* push a directory on the stack USER2
+ */
+int sh_files_pushdir_user2 (const char * dirName);
+
+/* push a directory on the stack USER3
+ */
+int sh_files_pushdir_user3 (const char * dirName);
+
+/* push a directory on the stack USER4
+ */
+int sh_files_pushdir_user4 (const char * dirName);
+
+/* push a directory on the stack PRELINK
+ */
+int sh_files_pushdir_prelink (const char * dirName);
+
+/* push a directory on the stack ATTR
+ */
+int sh_files_pushdir_attr (const char * dirName);
+
+/* push a directory on the stack READONLY
+ */
+int sh_files_pushdir_ro (const char * dirName);
+
+/* push a directory on the stack LOGFILE
+ */
+int sh_files_pushdir_log (const char * dirName);
+
+/* push a directory on the stack GROWING LOGFILE
+ */
+int sh_files_pushdir_glog (const char * dirName);
+
+/* push a directory on the stack IGNORE NONE
+ */
+int sh_files_pushdir_noig (const char * dirName);
+
+/* push a directory on the stack IGNORE ALL
+ */
+int sh_files_pushdir_allig (const char * dirName);
+
+
+/* push a file on the stack USER0
+ */
+int sh_files_pushfile_user0 (const char * dirName);
+
+/* push a file on the stack USER1
+ */
+int sh_files_pushfile_user1 (const char * dirName);
+
+/* push a file on the stack USER2
+ */
+int sh_files_pushfile_user2 (const char * dirName);
+
+/* push a file on the stack USER3
+ */
+int sh_files_pushfile_user3 (const char * dirName);
+
+/* push a file on the stack USER4
+ */
+int sh_files_pushfile_user4 (const char * dirName);
+
+/* push a file on the stack PRELINK
+ */
+int sh_files_pushfile_prelink (const char * dirName);
+
+/* push a file on the stack ATTR
+ */
+int sh_files_pushfile_attr (const char * dirName);
+
+/* push a file on the stack READONLY
+ */
+int sh_files_pushfile_ro (const char * dirName);
+
+/* push a file on the stack LOGFILE
+ */
+int sh_files_pushfile_log (const char * dirName);
+
+/* push a file on the stack GROWING LOGFILE
+ */
+int sh_files_pushfile_glog (const char * dirName);
+
+/* push a file on the stack IGNORE NONE
+ */
+int sh_files_pushfile_noig (const char * dirName);
+
+/* push a file on the stack IGNORE ALL
+ */
+int sh_files_pushfile_allig (const char * dirName);
+
+
+/* check directories on the stack
+ */
+unsigned long sh_dirs_chk (int which);
+
+/* check files on the stack
+ */
+unsigned long sh_files_chk (void);
+
+int sh_files_delglobstack (void);
+
+int sh_files_deldirstack (void);
+
+int sh_files_delfilestack (void);
+
+/* redefine policies
+ */
+int sh_files_redef_user0(const char * str);
+int sh_files_redef_user1(const char * str);
+int sh_files_redef_user2(const char * str);
+int sh_files_redef_user3(const char * str);
+int sh_files_redef_user4(const char * str);
+int sh_files_redef_prelink(const char * str);
+int sh_files_redef_readonly(const char * str);
+int sh_files_redef_loggrow(const char * str);
+int sh_files_redef_logfiles(const char * str);
+int sh_files_redef_attributes(const char * str);
+int sh_files_redef_noignore(const char * str);
+int sh_files_redef_allignore(const char * str);
+
+ShFileType sh_files_filecheck (int class, unsigned long check_flags,
+ const char * dirName,
+ const char * infileName,
+ int * reported,
+ int rsrcflag);
+
+int sh_files_checkdir (int iclass, unsigned long check_flags,
+ int idepth, char * iname,
+ char * relativeName);
+
+int sh_files_search_file(char * name, int * class,
+ unsigned long *check_flags, int * reported);
+int sh_files_search_dir(char * name, int * class,
+ unsigned long *check_flags, int *reported,
+ int * rdepth);
+void sh_files_set_file_reported(const char * name);
+void sh_files_clear_file_reported(const char * name);
+
+#endif
+
+
+
+
diff --git a/include/sh_filter.h b/include/sh_filter.h
new file mode 100644
index 0000000..6626a06
--- /dev/null
+++ b/include/sh_filter.h
@@ -0,0 +1,35 @@
+#ifndef SH_FILTER_H
+#define SH_FILTER_H
+
+/* Filtering
+ */
+
+#define SH_FILT_NUM 32
+#define SH_FILT_OR 0
+#define SH_FILT_AND 1
+#define SH_FILT_NOT 2
+#define SH_FILT_INIT { 0, { NULL }, 0, { NULL }, 0, { NULL }}
+
+/* Pattern storage is of type void since it may be a char*
+ * or a regex_t*
+ */
+typedef struct _sh_filter_type
+{
+ int for_c;
+ void * for_v[SH_FILT_NUM];
+ int fand_c;
+ void * fand_v[SH_FILT_NUM];
+ int fnot_c;
+ void * fnot_v[SH_FILT_NUM];
+
+} sh_filter_type;
+
+int sh_filter_add (const char * str, sh_filter_type * filter, int type);
+
+void sh_filter_free (sh_filter_type * filter);
+
+int sh_filter_filter (const char * message, sh_filter_type * filter);
+
+sh_filter_type * sh_filter_alloc(void);
+
+#endif
diff --git a/include/sh_getopt.h b/include/sh_getopt.h
new file mode 100644
index 0000000..7f1bacf
--- /dev/null
+++ b/include/sh_getopt.h
@@ -0,0 +1,33 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SH_GETOPT_H
+#define SH_GETOPT_H
+
+
+int sh_getopt_get (int argc, char * argv[]);
+
+#endif
+
+
+
+
+
+
+
diff --git a/include/sh_gpg.h b/include/sh_gpg.h
new file mode 100644
index 0000000..c6a1394
--- /dev/null
+++ b/include/sh_gpg.h
@@ -0,0 +1,58 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if (defined(WITH_GPG) || defined(WITH_PGP))
+
+#ifndef SH_GPG_H
+#define SH_GPG_H
+
+#define SIG_CONF 1
+#define SIG_DATA 2
+
+/* Top level function to verify file.
+ */
+SL_TICKET sh_gpg_extract_signed(SL_TICKET fd);
+
+/* this function exits if configuration file
+ * and/or database cannot be verified; otherwise returns 0
+ */
+int sh_gpg_check_sign (long file, int what);
+
+/* log successful startup
+ */
+void sh_gpg_log_startup (void);
+
+#endif
+
+/* #ifdef WITH_GPG */
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/include/sh_gpg_chksum.h b/include/sh_gpg_chksum.h
new file mode 100644
index 0000000..e5c31f0
--- /dev/null
+++ b/include/sh_gpg_chksum.h
@@ -0,0 +1,53 @@
+#ifndef CHKSUM_H
+#define CHKSUM_H
+char gpgchk[50];
+gpgchk[0] = '4';
+gpgchk[1] = '0';
+gpgchk[2] = '7';
+gpgchk[3] = '8';
+gpgchk[4] = '4';
+gpgchk[5] = '6';
+gpgchk[6] = '0';
+gpgchk[7] = '1';
+gpgchk[8] = '7';
+gpgchk[9] = '5';
+gpgchk[10] = 'D';
+gpgchk[11] = '0';
+gpgchk[12] = '1';
+gpgchk[13] = 'B';
+gpgchk[14] = '4';
+gpgchk[15] = '4';
+gpgchk[16] = 'B';
+gpgchk[17] = '5';
+gpgchk[18] = 'E';
+gpgchk[19] = '3';
+gpgchk[20] = 'A';
+gpgchk[21] = '4';
+gpgchk[22] = '0';
+gpgchk[23] = 'E';
+gpgchk[24] = '4';
+gpgchk[25] = '4';
+gpgchk[26] = '0';
+gpgchk[27] = '1';
+gpgchk[28] = '6';
+gpgchk[29] = '3';
+gpgchk[30] = '3';
+gpgchk[31] = '3';
+gpgchk[32] = 'C';
+gpgchk[33] = 'F';
+gpgchk[34] = '3';
+gpgchk[35] = 'C';
+gpgchk[36] = '5';
+gpgchk[37] = '6';
+gpgchk[38] = 'A';
+gpgchk[39] = '7';
+gpgchk[40] = 'A';
+gpgchk[41] = 'B';
+gpgchk[42] = 'D';
+gpgchk[43] = '9';
+gpgchk[44] = '1';
+gpgchk[45] = '9';
+gpgchk[46] = '6';
+gpgchk[47] = '6';
+gpgchk[48] = '\0';
+#endif
diff --git a/include/sh_guid.h b/include/sh_guid.h
new file mode 100644
index 0000000..7f256d0
--- /dev/null
+++ b/include/sh_guid.h
@@ -0,0 +1,34 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_GUID_H
+#define SH_GUID_H
+
+
+#define SH_UUID_BUF 37
+
+char * sh_uuid_generate_random(char * out, size_t len);
+
+/* return 0 if it looks like a uuid
+ */
+int sh_uuid_check(const char * in);
+
+#endif
+
diff --git a/include/sh_hash.h b/include/sh_hash.h
new file mode 100644
index 0000000..5c36509
--- /dev/null
+++ b/include/sh_hash.h
@@ -0,0 +1,205 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_HASH_H
+#define SH_HASH_H
+
+#include <limits.h>
+
+#include "samhain.h"
+#include "sh_unix.h"
+#include "sh_error.h"
+
+/* the report_checkflags flag
+ */
+int get_report_checkflags();
+
+/* whether to report checkflags
+ */
+int set_report_checkflags(const char * c);
+
+/* convert to policy string
+ */
+const char * sh_hash_getpolicy(int class);
+
+/* format a uint64
+ */
+char * sh_hash_size_format(void);
+
+/* report on a missing file
+ */
+int hashreport_missing( char *fullpath, int level);
+
+/* remove internal db record for a file (checks for some flags).
+ */
+void sh_hash_remove (const char * path);
+
+/* remove internal db record for a file
+ */
+void sh_hash_remove_unconditional (const char * path);
+
+/* Insert a "null" record in-memory (representing a missing file).
+ */
+void sh_hash_insert_null(char * str);
+
+#ifdef SH_DBIO_INT_H
+/* Check for "null" record
+ */
+int sh_hash_is_null_record(sh_filestore_t * theFile);
+#endif
+
+/* Dont report on ctm/mtm change for directories
+ */
+int sh_hash_loosedircheck(const char * str);
+
+/* List database content for a single file
+ */
+int set_list_file (const char * c);
+
+/* Set the path of that file
+ */
+char * get_list_file();
+
+/* List database content with full detail
+ */
+int set_full_detail (const char * c);
+
+/* List database content with full detail, comma delimited
+ */
+int set_list_delimited (const char * c);
+
+/* Read the database from disk.
+ */
+void sh_hash_init (void);
+
+/* Check init status
+ */
+int sh_hash_get_initialized();
+
+/* Read the database from disk and fill sh.data.hash with checksum.
+ */
+void sh_hash_init_and_checksum();
+
+/* Set status to 'database is read in'.
+ */
+void sh_hash_set_initialized();
+
+/* Check whether a file is present in the database.
+ */
+int sh_hash_have_it (const char * newname);
+
+/* Get a file if it is present in the database.
+ * If fileHash != NULL also return checksum.
+ */
+int sh_hash_get_it (const char * newname, file_type * tmpFile, char * fileHash);
+
+/* Delete the database from memory.
+ */
+void sh_hash_hashdelete (void);
+
+/* Insert a file into the database.
+ */
+void sh_hash_pushdata (file_type * buf, char * fileHash);
+
+/* reset sh_hash_pushdata to use 'update' in daemon mode
+ */
+void sh_hash_pushdata_reset (void);
+
+/* Insert a file into the in-memory database.
+ */
+void sh_hash_pushdata_memory (file_type * theFile, char * fileHash);
+
+/* Get file flags from in-memory database
+ */
+int sh_hash_getflags (char * filename);
+
+/* Set file flags in in-memory database
+ */
+int sh_hash_setflags (char * filename, int flags);
+
+/* Set a file flag in in-memory database
+ */
+void sh_hash_set_flag (char * filename, int flag);
+
+/* Unset a file flag in in-memory database
+ */
+void sh_hash_clear_flag (char * filename, int flag_to_set);
+
+/* Compare a file with its status in the database.
+ */
+int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
+ char * policy_override, int severity_override);
+
+/* Search for files in the database that have been deleted from disk.
+ */
+void sh_hash_unvisited (ShErrLevel level);
+
+/* Search for unvisited entries in the database, custom error handler.
+ */
+void sh_hash_unvisited_custom (char prefix, void(*handler)(const char * key));
+
+/* Set a file's status to 'visited'. This is required for
+ * files that should be ignored, and may be present in the
+ * database, but not on disk.
+ */
+int sh_hash_set_visited (char * newname);
+
+/* As above, but only set the 'visited' flag
+ */
+int sh_hash_set_visited_true (char * newname);
+
+/* cause the record to be deleted without a 'missing' message
+ */
+int sh_hash_set_missing (char * newname);
+
+/* Make a complete directory tree invisible
+ */
+int hash_remove_tree (char * s);
+
+/* Make every entry visible
+ */
+int hash_full_tree (void);
+
+/* Insert data.
+ * 'key' -> path
+ * 'str' -> binary with size 'size'
+ */
+struct store2db {
+ UINT64 val0;
+ UINT64 val1;
+ UINT64 val2;
+ UINT64 val3;
+ char checksum[KEY_LEN+1];
+ unsigned char * str;
+ int size;
+};
+
+void sh_hash_push2db (const char * key, struct store2db * save);
+
+
+/* Retrieve data
+ */
+char * sh_hash_db2pop (const char * key, struct store2db * get);
+
+
+/* Write out database
+ */
+int sh_hash_writeout(void);
+#endif
diff --git a/include/sh_html.h b/include/sh_html.h
new file mode 100644
index 0000000..eee0b47
--- /dev/null
+++ b/include/sh_html.h
@@ -0,0 +1,83 @@
+#ifndef SH_HTML_H
+#define SH_HTML_H
+
+#ifdef SH_WITH_SERVER
+
+
+#define CLT_INACTIVE 0
+#define CLT_STARTED 1
+#define CLT_ILLEGAL 2
+#define CLT_FAILED 3
+#define CLT_EXITED 4
+#define CLT_PANIC 5
+#define CLT_POLICY 6
+#define CLT_FILE 7
+#define CLT_MSG 8
+#define CLT_TOOLONG 9
+#define CLT_SUSPEND 10
+#define CLT_CHECK 11
+#define CLT_MAX 12
+
+/************************
+char * clt_stat[] = {
+ N_("Inactive"),
+ N_("Started"),
+ N_("ILLEGAL"),
+ N_("FAILED"),
+ N_("Exited"),
+ N_("PANIC"),
+ N_("POLICY"),
+ N_("File transfer"),
+ N_("Message"),
+ N_("TIMEOUT_EXCEEDED"),
+};
+**************************/
+
+extern char * clt_stat[];
+
+#ifdef SH_ENCRYPT
+#include "rijndael-api-fst.h"
+#endif
+
+/* --- client status ---
+ */
+typedef struct client_entry {
+ char * hostname;
+ char * salt;
+ char * verifier;
+ char session_key[KEY_LEN+1];
+ time_t session_key_timer;
+ time_t last_connect;
+ int exit_flag;
+ int dead_flag;
+ int encf_flag;
+ int ency_flag;
+ int ivst_flag;
+ int status_now;
+ int status_arr[CLT_MAX];
+ char timestamp[CLT_MAX][TIM_MAX];
+#ifdef SH_ENCRYPT
+ keyInstance keyInstE;
+ keyInstance keyInstD;
+#endif
+} client_t;
+
+/* --- server status ---
+ */
+typedef struct _s_stat {
+ time_t start;
+ time_t last;
+ int conn_open;
+ int conn_max;
+ long conn_total;
+} s_stat;
+
+extern s_stat server_status;
+
+/* write html report. Expects (client_t *) inptr.
+ */
+int sh_html_write(void * inptr);
+
+#endif
+
+#endif
diff --git a/include/sh_ignore.h b/include/sh_ignore.h
new file mode 100644
index 0000000..daf8cce
--- /dev/null
+++ b/include/sh_ignore.h
@@ -0,0 +1,14 @@
+#ifndef SH_IGNORE_H
+#define SH_IGNORE_H
+
+int sh_ignore_add_del (const char * addpath);
+int sh_ignore_add_new (const char * addpath);
+int sh_ignore_add_mod (const char * addpath);
+
+int sh_ignore_chk_del (const char * chkpath);
+int sh_ignore_chk_new (const char * chkpath);
+int sh_ignore_chk_mod (const char * chkpath);
+
+int sh_ignore_clean (void);
+
+#endif
diff --git a/include/sh_inotify.h b/include/sh_inotify.h
new file mode 100644
index 0000000..3c3a3f1
--- /dev/null
+++ b/include/sh_inotify.h
@@ -0,0 +1,58 @@
+#ifndef SH_INOTIFY_H
+#define SH_INOTIFY_H
+
+#define SH_INOTIFY_MAX 128
+
+typedef struct
+{
+ void * list_of_watches;
+ void * dormant_watches;
+
+ /*
+ int watch[SH_INOTIFY_MAX];
+ int flag[SH_INOTIFY_MAX];
+ char * file[SH_INOTIFY_MAX];
+ */
+
+ int count;
+ int max_count;
+} sh_watches;
+
+/* #define SH_INOTIFY_INITIALIZER { { 0 }, { 0 }, { NULL}, 0, 0 } */
+
+#define SH_INOTIFY_INITIALIZER { NULL, NULL, 0, 0 }
+
+#define SH_INOTIFY_FILE 0
+#define SH_INOTIFY_DIR 1
+
+int sh_inotify_wait_for_change(char * filename, sh_watches * watches,
+ int * errnum, int waitsec);
+
+int sh_inotify_rm_watch (sh_watches * watches, sh_watches * save, int wd);
+
+int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum,
+ int class, unsigned long check_flags, int type, int rdepth);
+
+int sh_inotify_add_watch_later(const char * filename, sh_watches * watches,
+ int * errnum,
+ int class, unsigned long check_flags,
+ int type, int rdepth);
+
+char * sh_inotify_pop_dormant(sh_watches * watches, int * class,
+ unsigned long * check_flags, int * type, int * rdepth);
+
+void sh_inotify_purge_dormant(sh_watches * watches);
+void sh_inotify_remove(sh_watches * watches);
+void sh_inotify_init(sh_watches * watches);
+void sh_inotify_close();
+
+char * sh_inotify_search_item(sh_watches * watches, int watch,
+ int * class, unsigned long * check_flags,
+ int * type, int * rdepth);
+ssize_t sh_inotify_read(char * buffer, size_t count);
+ssize_t sh_inotify_read_timeout(char * buffer, size_t count, int timeout);
+int sh_inotify_recheck_watches (sh_watches * watches, sh_watches * save);
+
+#define SH_INOTIFY_ERROR(a) (a != 0)
+
+#endif
diff --git a/include/sh_ipvx.h b/include/sh_ipvx.h
new file mode 100644
index 0000000..4231044
--- /dev/null
+++ b/include/sh_ipvx.h
@@ -0,0 +1,83 @@
+#ifndef SH_IPVX_H
+#define SH_IPVX_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#if defined(USE_IPVX)
+#define SH_SSP_LEN(a) ((a)->ss_family == AF_INET) ? \
+ sizeof(struct sockaddr_in) : \
+ sizeof(struct sockaddr_in6)
+
+#define SH_SS_LEN(a) ((a).ss_family == AF_INET) ? \
+ sizeof(struct sockaddr_in) : \
+ sizeof(struct sockaddr_in6)
+#else
+#define SH_SSP_LEN(a) sizeof(struct sockaddr_in)
+#define SH_SS_LEN(a) sizeof(struct sockaddr_in)
+#endif
+
+struct sh_sockaddr {
+ int ss_family;
+
+ struct sockaddr_in sin;
+#if defined(USE_IPVX)
+ struct sockaddr_in6 sin6;
+#endif
+};
+
+/* Cast a sockaddress
+ */
+struct sockaddr * sh_ipvx_sockaddr_cast (struct sh_sockaddr * ss);
+
+/* Compare with any_address
+ */
+int sh_ipvx_isany (struct sh_sockaddr * a);
+
+/* Compare two addresses
+ */
+int sh_ipvx_cmp(struct sh_sockaddr * a, struct sh_sockaddr * b);
+
+/* Set the port
+ */
+int sh_ipvx_set_port(struct sh_sockaddr * ss, int port);
+
+/* Get the port
+ */
+int sh_ipvx_get_port(struct sockaddr * ss, int sa_family);
+
+/* Save a sockaddress
+ */
+void sh_ipvx_save(struct sh_sockaddr * ss, int sa_family, struct sockaddr * sa);
+
+/* Ascii numerical sockaddress
+ */
+char * sh_ipvx_print_sockaddr (struct sockaddr * sa, int sa_family);
+
+/* Determine whether the given address is numeric
+ */
+int sh_ipvx_is_numeric (const char * addr);
+
+/* Convert a network address to an ascii numeric address
+ */
+int sh_ipvx_ntoa (char * name, size_t name_size, struct sh_sockaddr * ss);
+
+/* Convert an ascii numeric address to a network address
+ */
+int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss);
+
+/* Try to find canonical hostname
+ */
+char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen);
+
+/* Convert address to hostname
+ */
+char * sh_ipvx_addrtoname(struct sh_sockaddr * ss);
+
+/* Try a reverse lookup
+ */
+int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss);
+#endif
diff --git a/include/sh_ks.h b/include/sh_ks.h
new file mode 100644
index 0000000..bf98c51
--- /dev/null
+++ b/include/sh_ks.h
@@ -0,0 +1,11 @@
+#ifndef SH_KERN_CALLS_H
+#define SH_KERN_CALLS_H
+
+/* Dummy header. */
+
+typedef struct _sh_syscall_t {
+ unsigned long addr;
+ char * name;
+} sh_syscall_t;
+
+#endif
diff --git a/include/sh_ks_xor.h b/include/sh_ks_xor.h
new file mode 100644
index 0000000..bf98c51
--- /dev/null
+++ b/include/sh_ks_xor.h
@@ -0,0 +1,11 @@
+#ifndef SH_KERN_CALLS_H
+#define SH_KERN_CALLS_H
+
+/* Dummy header. */
+
+typedef struct _sh_syscall_t {
+ unsigned long addr;
+ char * name;
+} sh_syscall_t;
+
+#endif
diff --git a/include/sh_log_check.h b/include/sh_log_check.h
new file mode 100644
index 0000000..0ef2b25
--- /dev/null
+++ b/include/sh_log_check.h
@@ -0,0 +1,138 @@
+#ifndef SH_LOGCHECK_H
+#define SH_LOGCHECK_H
+
+#include <sys/types.h>
+#include <time.h>
+
+/* Convert a struct tm to unix timestamp with caching
+ */
+time_t conv_timestamp (struct tm * btime,
+ struct tm * old_tm, time_t * old_time);
+
+/* Definition of a log record entry, to be returned from parsing function.
+ */
+#define PID_INVALID 0
+struct sh_logrecord
+{
+ char * filename;
+ sh_string * host;
+ sh_string * timestr;
+ pid_t pid;
+ time_t timestamp;
+ sh_string * message;
+};
+
+#define SH_LOGFILE_MOVED (1<<0)
+#define SH_LOGFILE_REWIND (1<<1)
+#define SH_LOGFILE_PIPE (1<<2)
+#define SH_LOGFILE_NOFILE (1<<3)
+
+struct sh_logfile
+{
+ FILE * fp;
+ int flags;
+ char * filename;
+ dev_t device_id;
+ ino_t inode;
+ fpos_t offset;
+
+ /* Info for the parser, e.g. a regular expression
+ */
+ void * fileinfo;
+
+ /* Callback function to read the next record
+ */
+ sh_string * (*get_record) (sh_string * record,
+ struct sh_logfile * logfile);
+
+ /* Callback function to parse the record into standard format
+ */
+ struct sh_logrecord * (*parse_record)(sh_string * logline, void * fileinfo);
+
+ struct sh_logfile * next;
+};
+
+/* Generic callback function to parse fileinfo.
+ */
+void * sh_eval_fileinfo_generic(char * str);
+
+/* Generic parser info.
+ */
+struct sh_logrecord * sh_parse_generic (sh_string * logline, void * fileinfo);
+
+
+/****************************************************************
+ **
+ ** Parsing and reading functions
+ **/
+
+/* Open file, position at stored offset. */
+int sh_open_for_reader (struct sh_logfile * logfile);
+
+/* Simple line reader for executed shell command */
+sh_string * sh_command_reader (sh_string * record,
+ struct sh_logfile * logfile);
+
+/* Wrapper for sh_command_reader */
+sh_string * sh_read_shell (sh_string * record, struct sh_logfile * logfile);
+
+/* Parses a shell command reply. */
+struct sh_logrecord * sh_parse_shell (sh_string * logline, void * fileinfo);
+
+/* Simple line reader. */
+sh_string * sh_default_reader (sh_string * record,
+ struct sh_logfile * logfile);
+
+/* Continued line reader. */
+sh_string * sh_cont_reader (sh_string * record,
+ struct sh_logfile * logfile, char * cont);
+
+/* Binary reader */
+sh_string * sh_binary_reader (void * s, size_t size, struct sh_logfile * logfile);
+
+/* Parses a syslog-style line. */
+struct sh_logrecord * sh_parse_syslog (sh_string * logline, void * fileinfo);
+
+/* Format info for apache log. */
+void * sh_eval_fileinfo_apache(char * str);
+
+/* Parses a apache-style line. */
+struct sh_logrecord * sh_parse_apache (sh_string * logline, void * fileinfo);
+
+/* Get a pacct record */
+sh_string * sh_read_pacct (sh_string * record, struct sh_logfile * logfile);
+
+/* Parses a pacct record. */
+struct sh_logrecord * sh_parse_pacct (sh_string * logline, void * fileinfo);
+
+/* Get a samba record */
+sh_string * sh_read_samba (sh_string * record, struct sh_logfile * logfile);
+
+/* Parses a samba record. */
+struct sh_logrecord * sh_parse_samba (sh_string * logline, void * fileinfo);
+
+
+/**
+*****************************************************************/
+
+int sh_get_hidepid();
+int sh_set_hidepid(const char *s);
+
+#define SH_MAX_LCODE_SIZE 16
+
+struct sh_logfile_type
+{
+ char code[SH_MAX_LCODE_SIZE];
+
+ /* read callback */
+ /*@null@*/sh_string * (*get_record) (sh_string * record,
+ struct sh_logfile * logfile);
+ /* parsing callback */
+ struct sh_logrecord * (*parse_record)(sh_string * logline, void * fileinfo);
+
+ /* evaluate fileinfo */
+ void * (*eval_fileinfo)(char * str);
+};
+
+
+#endif
diff --git a/include/sh_log_correlate.h b/include/sh_log_correlate.h
new file mode 100644
index 0000000..9c22014
--- /dev/null
+++ b/include/sh_log_correlate.h
@@ -0,0 +1,28 @@
+#ifndef SH_LOG_CORRELATE_H
+#define SH_LOG_CORRELATE_H
+
+/* Clean up everything.
+ */
+void sh_keep_destroy();
+
+/* Add an event
+ */
+int sh_keep_add(sh_string * label, unsigned long delay, time_t last);
+
+/* Add an event sequence matching rule
+ */
+int sh_keep_match_add(const char * str, const char * queue, const char * pattern);
+
+/* Delete the list of event sequence matching rules
+ */
+void sh_keep_match_del();
+
+/* Try to find correlated events
+ */
+void sh_keep_match();
+
+/* Deadtime for a correlation rule
+ */
+int sh_keep_deadtime (const char * str);
+
+#endif
diff --git a/include/sh_log_evalrule.h b/include/sh_log_evalrule.h
new file mode 100644
index 0000000..1b7ccae
--- /dev/null
+++ b/include/sh_log_evalrule.h
@@ -0,0 +1,61 @@
+#ifndef SH_EVALRULE_H
+#define SH_EVALRULE_H
+
+/* Clean up everything.
+ */
+void sh_eval_cleanup();
+
+/* Define a new reporting queue, str := label:interval:(report|sum):severity
+ */
+int sh_eval_qadd (const char * str);
+
+/* Add a new rule, str := queue:regex
+ * If there is an open group, add it to its rules.
+ * ..else, add it to the currently open host (open the
+ * default host, if there is no open one)
+ */
+int sh_eval_radd (const char * str);
+
+/* Open a new host group definition.
+ */
+int sh_eval_hadd (const char * str);
+/*
+ * End the host definition
+ */
+int sh_eval_hend (const char * str);
+
+
+/* Open a new group definition. If a host is currently open,
+ * the new group will automatically be added to that host.
+ */
+int sh_eval_gadd (const char * str);
+/*
+ * End the group definition
+ */
+int sh_eval_gend (const char * str);
+
+/* Process a single log record
+ */
+int sh_eval_process_msg(struct sh_logrecord * record);
+
+enum policies {
+ EVAL_REPORT,
+ EVAL_SUM
+};
+
+struct sh_qeval /* Queue with definitions */
+{
+ sh_string * label;
+ enum policies policy;
+ int severity;
+ sh_string * alias;
+ time_t interval; /* if EVAL_SUM, interval */
+ struct sh_qeval * next;
+};
+
+struct sh_qeval * sh_log_find_queue(const char * str);
+
+int sh_log_lookup_severity(const char * str);
+sh_string * sh_log_lookup_alias(const char * str);
+
+#endif
diff --git a/include/sh_log_mark.h b/include/sh_log_mark.h
new file mode 100644
index 0000000..acc0375
--- /dev/null
+++ b/include/sh_log_mark.h
@@ -0,0 +1,14 @@
+#ifndef SH_LOG_MARK_H
+#define SH_LOG_MARK_H
+
+void sh_log_mark_destroy();
+
+int sh_log_mark_add (const char * label, time_t interval, const char * qlabel);
+
+void sh_log_mark_update (sh_string * label, time_t timestamp);
+
+void sh_log_mark_check();
+
+int sh_log_set_mark_severity (const char * str);
+
+#endif
diff --git a/include/sh_log_repeat.h b/include/sh_log_repeat.h
new file mode 100644
index 0000000..d241877
--- /dev/null
+++ b/include/sh_log_repeat.h
@@ -0,0 +1,14 @@
+#ifndef SH_LOG_REPEAT_H
+#define SH_LOG_REPEAT_H
+
+int sh_repeat_set_trigger (const char * str);
+
+int sh_repeat_set_queue (const char * str);
+
+int sh_repeat_set_cron (const char * str);
+
+int sh_repeat_message_check (const sh_string * host,
+ const sh_string * msg,
+ time_t ltime);
+
+#endif
diff --git a/include/sh_logmon.h b/include/sh_logmon.h
new file mode 100644
index 0000000..6195877
--- /dev/null
+++ b/include/sh_logmon.h
@@ -0,0 +1,12 @@
+#ifndef SH_LOGMON_H
+#define SH_LOGMON_H
+
+extern sh_rconf sh_log_check_table[];
+
+int sh_log_check_init (struct mod_type * arg);
+int sh_log_check_timer(time_t tcurrent);
+int sh_log_check_check(void);
+int sh_log_check_reconf(void);
+int sh_log_check_cleanup(void);
+
+#endif
diff --git a/include/sh_mail.h b/include/sh_mail.h
new file mode 100644
index 0000000..88752a1
--- /dev/null
+++ b/include/sh_mail.h
@@ -0,0 +1,64 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SH_MAIL_H
+#define SH_MAIL_H
+
+#define MAIL_IMMEDIATE 1
+#define MAIL_LATER 0
+
+/* set a relay server
+ */
+int sh_mail_set_relay (const char * str_s);
+
+/* send to all recpts. in one mail
+ */
+int sh_mail_setFlag (const char * str);
+
+/* set the subject string
+ */
+int set_mail_subject (const char * str);
+
+/* test mailbox
+ */
+int sh_mail_sigverify (const char * s);
+
+/* maximum number of mail attempts
+ */
+#define SH_MAX_FAIL 48
+
+int sh_mail_setNum (const char * str);
+
+int sh_mail_setaddress (const char * address);
+void reset_count_dev_mail(void);
+int sh_mail_setaddress_int (const char * address);
+
+/* call if not urgent
+ */
+int sh_mail_pushstack (int severity, const char * msg, const char * alias);
+
+/* Set the port to use (default 25)
+ */
+int sh_mail_set_port (const char * str);
+
+/* set sender of mail
+ */
+int sh_mail_set_sender (const char *str);
+
+#endif
diff --git a/include/sh_mail_int.h b/include/sh_mail_int.h
new file mode 100644
index 0000000..b2da61a
--- /dev/null
+++ b/include/sh_mail_int.h
@@ -0,0 +1,48 @@
+#ifndef SH_MAIL_INT_H
+#define SH_MAIL_INT_H
+
+extern int sh_mail_all_in_one;
+
+/* MX Resolver Struct
+ */
+typedef struct mx_ {
+ int pref;
+ char * address;
+} mx;
+
+typedef struct dnsrep_ {
+ int count;
+ mx * reply;
+} dnsrep;
+
+int free_mx (dnsrep * answers);
+
+/* adress struct
+ */
+struct alias {
+ sh_string * recipient;
+ struct alias * recipient_list;
+ dnsrep * mx_list;
+ int severity;
+ short send_mail;
+ short isAlias;
+ sh_filter_type * mail_filter;
+ struct alias * next;
+ struct alias * all_next;
+};
+
+extern struct alias * all_recipients;
+
+int sh_mail_msg (const char * message);
+
+/* Per recipient mail key
+ */
+
+int sh_nmail_get_mailkey (const char * alias, char * buf, size_t bufsiz,
+ time_t * id_audit);
+
+SH_MUTEX_EXTERN(mutex_listall);
+SH_MUTEX_EXTERN(mutex_fifo_mail);
+extern SH_FIFO * fifo_mail;
+
+#endif
diff --git a/include/sh_mem.h b/include/sh_mem.h
new file mode 100644
index 0000000..0449942
--- /dev/null
+++ b/include/sh_mem.h
@@ -0,0 +1,61 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_MEM_H
+#define SH_MEM_H
+
+
+#ifdef MEM_DEBUG
+
+void sh_mem_openf (char * file, int fd);
+void sh_mem_closef (int fd);
+void sh_mem_check (void);
+void sh_mem_dump (void);
+void sh_mem_free (void * a, char * file, int line);
+void * sh_mem_malloc (size_t size, char * file, int line);
+void sh_mem_stat (void);
+
+#define SH_FREE(a) sh_mem_free((a), FIL__, __LINE__)
+#define SH_ALLOC(a) sh_mem_malloc((a), FIL__, __LINE__)
+#define SH_OALLOC(a,b,c) sh_mem_malloc((a), (b), (c))
+
+#else
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#undef SH_GNUC_MALLOC
+#define SH_GNUC_MALLOC __attribute__((malloc))
+#else
+#undef SH_GNUC_MALLOC
+#define SH_GNUC_MALLOC
+#endif
+
+void sh_mem_free (/*@only@*//*@out@*//*@null@*/ void * a);
+/*@only@*//*@notnull@*/void * sh_mem_malloc (size_t size) SH_GNUC_MALLOC;
+
+#define SH_FREE(a) sh_mem_free(a)
+#define SH_ALLOC(a) sh_mem_malloc(a)
+#define SH_OALLOC(a,b,c) ((void) (b), \
+ (void) (c), \
+ sh_mem_malloc(a)) \
+
+#endif
+
+/* #ifndef SH_MEM_H */
+#endif
diff --git a/include/sh_modules.h b/include/sh_modules.h
new file mode 100644
index 0000000..e75ad50
--- /dev/null
+++ b/include/sh_modules.h
@@ -0,0 +1,63 @@
+
+#ifndef SH_MODULE_H
+#define SH_MODULE_H
+
+#include "sh_pthread.h"
+
+enum
+ {
+ SH_MODFL_NOTIMER = (1 << 0),
+ SH_MODFL_NEEDPAUSED = (1 << 1),
+ SH_MODFL_ISPAUSED = (1 << 2)
+ };
+
+
+typedef struct rconf
+{
+ char * the_opt;
+ int (*func)(const char * opt);
+} sh_rconf;
+
+typedef struct mod_type
+{
+ /* The name of the module */
+ char * name;
+
+ /* Set by samhain to 1 on successful initialization, else 0 */
+ int initval;
+
+ /* Flags: SH_MOD_NOTIMER */
+ int flags;
+
+ /* The initialization function. Return 0 on success. */
+ int (* mod_init) (struct mod_type * arg);
+
+ /* The timer function. Return 0 if NOT time to check. */
+ int (* mod_timer) (time_t tcurrent);
+
+ /* The check function. Return 0 on success. */
+ /* Return nonzero on fatal error or if module is disabled. */
+ int (* mod_check) (void);
+
+ /* The cleanup function. Return 0 on success. */
+ int (* mod_cleanup) (void);
+
+ /* The preparation for reconfiguration. Return 0 on success. */
+ int (* mod_reconf) (void);
+
+ /* Section header in config file */
+ char * conf_section;
+
+ /* A table of key/handler_function for config file entries */
+ sh_rconf * conf_table;
+
+ SH_MUTEX(mod_mutex);
+
+} sh_mtype;
+
+
+extern sh_mtype modList[];
+
+
+/* #ifndef SH_MODULE_H */
+#endif
diff --git a/include/sh_mounts.h b/include/sh_mounts.h
new file mode 100644
index 0000000..6ed50ff
--- /dev/null
+++ b/include/sh_mounts.h
@@ -0,0 +1,23 @@
+/*
+ * File: sh_mounts.h
+ * Desc: A module for Samhain; checks for mounts present and options on them.
+ * Auth: Cian Synnott <cian.synnott@eircom.net>
+ */
+
+#ifndef SH_MOUNTS_H
+#define SH_MOUNTS_H
+
+#include "sh_modules.h"
+
+#ifdef SH_USE_MOUNTS
+int sh_mounts_init (struct mod_type * arg);
+int sh_mounts_timer (time_t tcurrent);
+int sh_mounts_check (void);
+int sh_mounts_cleanup (void);
+int sh_mounts_reconf (void);
+
+extern sh_rconf sh_mounts_table[];
+#endif
+
+/* #ifndef SH_MOUNTS_H */
+#endif
diff --git a/include/sh_nmail.h b/include/sh_nmail.h
new file mode 100644
index 0000000..2800af8
--- /dev/null
+++ b/include/sh_nmail.h
@@ -0,0 +1,20 @@
+#ifndef SH_NMAIL_H
+#define SH_NMAIL_H
+
+int sh_nmail_pushstack (int level, const char * message,
+ const char * alias);
+int sh_nmail_msg (int level, const char * message,
+ const char * alias);
+int sh_nmail_flush ();
+void sh_nmail_free();
+
+int sh_nmail_set_severity (const char * str);
+int sh_nmail_add_not (const char * str);
+int sh_nmail_add_and (const char * str);
+int sh_nmail_add_or (const char * str);
+
+int sh_nmail_close_recipient(const char * str);
+int sh_nmail_add_compiled_recipient(const char * str);
+int sh_nmail_add_recipient(const char * str);
+int sh_nmail_add_alias(const char * str);
+#endif
diff --git a/include/sh_portcheck.h b/include/sh_portcheck.h
new file mode 100644
index 0000000..44a0823
--- /dev/null
+++ b/include/sh_portcheck.h
@@ -0,0 +1,13 @@
+
+#ifndef SH_PORTCHECK_H
+#define SH_PORTCHECK_H
+
+int sh_portchk_init(struct mod_type * arg);
+int sh_portchk_timer(time_t tcurrent);
+int sh_portchk_check(void);
+int sh_portchk_reconf(void);
+int sh_portchk_cleanup(void);
+
+extern sh_rconf sh_portchk_table[];
+
+#endif
diff --git a/include/sh_prelink.h b/include/sh_prelink.h
new file mode 100644
index 0000000..5842a35
--- /dev/null
+++ b/include/sh_prelink.h
@@ -0,0 +1,18 @@
+#ifndef SH_PRELINK_H
+#define SH_PRELINK_H
+
+/* path: full path to file;
+ * file_hash: allocated storage for checksum;
+ * alert_timeout: timeout for read
+ */
+int sh_prelink_run (char * path, char * file_hash, int alert_timeout, unsigned long mask);
+
+/* return S_TRUE if ELF file, S_FALSE otherwise
+ */
+int sh_prelink_iself (SL_TICKET fd, off_t size, int alert_timeout, char * path);
+
+/* configuration
+ */
+int sh_prelink_set_path (const char * str);
+int sh_prelink_set_hash (const char * str);
+#endif
diff --git a/include/sh_prelude.h b/include/sh_prelude.h
new file mode 100644
index 0000000..a00c4d0
--- /dev/null
+++ b/include/sh_prelude.h
@@ -0,0 +1,20 @@
+#ifndef SH_PRELUDE_H
+#define SH_PRELUDE_H
+
+void sh_prelude_reset(void);
+void sh_prelude_stop(void);
+int sh_prelude_init(void);
+
+int sh_prelude_set_profile(const char *arg);
+
+int sh_prelude_alert (int priority, int class, char * message,
+ long msgflags, unsigned long msgid, char * inet_peer_ip);
+
+/* map severity levels
+ */
+int sh_prelude_map_info (const char * str);
+int sh_prelude_map_low (const char * str);
+int sh_prelude_map_medium (const char * str);
+int sh_prelude_map_high (const char * str);
+
+#endif
diff --git a/include/sh_processcheck.h b/include/sh_processcheck.h
new file mode 100644
index 0000000..533e6bd
--- /dev/null
+++ b/include/sh_processcheck.h
@@ -0,0 +1,13 @@
+
+#ifndef SH_PROCESSCHECK_H
+#define SH_PROCESSCHECK_H
+
+int sh_prochk_init(struct mod_type * arg);
+int sh_prochk_timer(time_t tcurrent);
+int sh_prochk_check(void);
+int sh_prochk_reconf(void);
+int sh_prochk_cleanup(void);
+
+extern sh_rconf sh_prochk_table[];
+
+#endif
diff --git a/include/sh_pthread.h b/include/sh_pthread.h
new file mode 100644
index 0000000..c354252
--- /dev/null
+++ b/include/sh_pthread.h
@@ -0,0 +1,180 @@
+#ifndef SH_PTHREAD_H
+#define SH_PTHREAD_H
+
+#ifdef HAVE_PTHREAD
+
+#include <pthread.h>
+
+#define SH_MUTEX(M) pthread_mutex_t M
+#define SH_MUTEX_INIT(M,I) pthread_mutex_t M = I
+#define SH_MUTEX_STATIC(M,I) static pthread_mutex_t M = I
+#define SH_MUTEX_EXTERN(M) extern pthread_mutex_t M
+
+#define SH_SETSIGMASK(A, B, C) sh_pthread_setsigmask(A,B,C)
+
+int sh_pthread_setsigmask(int how, const void *set, void *oldset);
+
+/* pthread_mutex_unlock() has the wrong type (returns int), so
+ * we need to wrap it in this function.
+ */
+extern void sh_pthread_mutex_unlock (void *arg);
+
+#define SH_MUTEX_LOCK(M) \
+ do { \
+ int oldtype; \
+ int executeStack = 1; \
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); \
+ pthread_cleanup_push(sh_pthread_mutex_unlock, (void*)&(M));\
+ pthread_mutex_lock(&(M))
+
+#define SH_MUTEX_TRYLOCK(M) \
+ do { \
+ int oldtype; \
+ volatile int executeStack = 0; \
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); \
+ pthread_cleanup_push(sh_pthread_mutex_unlock, (void*)&(M));\
+ if (0 == pthread_mutex_trylock(&(M))) { \
+ executeStack = 1
+
+#define SH_MUTEX_TRYLOCK_UNLOCK(M) \
+ } \
+ pthread_cleanup_pop(executeStack); \
+ pthread_setcanceltype(oldtype, NULL); \
+ } while (0)
+
+#define SH_MUTEX_UNLOCK(M) \
+ pthread_cleanup_pop(executeStack); \
+ pthread_setcanceltype(oldtype, NULL); \
+ } while (0)
+
+#define SH_MUTEX_LOCK_UNSAFE(M) pthread_mutex_lock(&(M))
+#define SH_MUTEX_TRYLOCK_UNSAFE(M) pthread_mutex_trylock(&(M))
+#define SH_MUTEX_UNLOCK_UNSAFE(M) pthread_mutex_unlock(&(M))
+
+
+/*
+ * ---- Recursive mutex ----
+ */
+#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
+
+#define SH_MUTEX_RECURSIVE(M) \
+static pthread_mutex_t M; \
+static void M ## _init (void) \
+{ \
+ pthread_mutexattr_t mta; \
+ pthread_mutexattr_init(&mta); \
+ pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); \
+ pthread_mutex_init(&(M), &mta); \
+ pthread_mutexattr_destroy(&mta); \
+ return; \
+} \
+static pthread_once_t M ## _initialized = PTHREAD_ONCE_INIT
+
+#define SH_MUTEX_RECURSIVE_INIT(M) \
+(void) pthread_once(&(M ## _initialized), (M ## _init))
+
+#define SH_MUTEX_RECURSIVE_LOCK(M) \
+ do { \
+ int oldtype; \
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); \
+ pthread_cleanup_push(sh_pthread_mutex_unlock, (void*)&(M));\
+ pthread_mutex_lock(&(M))
+
+#define SH_MUTEX_RECURSIVE_UNLOCK(M) \
+ pthread_cleanup_pop(1); \
+ pthread_setcanceltype(oldtype, NULL); \
+ } while (0)
+
+#else
+/* !defined(PTHREAD_MUTEX_RECURSIVE) */
+ struct sh_RMutex {
+
+ pthread_mutex_t lock;
+ unsigned int held;
+ unsigned int waiters;
+ pthread_t tid;
+ pthread_cond_t cv;
+};
+
+void sh_RMutexLock(struct sh_RMutex * tok);
+void sh_RMutexUnlock(void * arg);
+void sh_InitRMutex(struct sh_RMutex * tok);
+
+#define SH_MUTEX_RECURSIVE(M) \
+static struct sh_RMutex M; \
+static void M ## _init (void) \
+{ \
+ sh_InitRMutex(&(M)); \
+ return; \
+} \
+static pthread_once_t M ## _initialized = PTHREAD_ONCE_INIT
+
+#define SH_MUTEX_RECURSIVE_INIT(M) \
+(void) pthread_once(&(M ## _initialized), (M ## _init))
+
+#define SH_MUTEX_RECURSIVE_LOCK(M) \
+ do { \
+ int oldtype; \
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); \
+ pthread_cleanup_push(sh_RMutexUnlock, (void*)&(M)); \
+ sh_RMutexLock(&(M))
+
+#define SH_MUTEX_RECURSIVE_UNLOCK(M) \
+ pthread_cleanup_pop(1); \
+ pthread_setcanceltype(oldtype, NULL); \
+ } while (0)
+
+#endif
+/*
+ * ---- Global mutexes ----
+ */
+SH_MUTEX_EXTERN(mutex_skey);
+SH_MUTEX_EXTERN(mutex_resolv);
+SH_MUTEX_EXTERN(mutex_pwent);
+SH_MUTEX_EXTERN(mutex_readdir);
+/* Prevent threads from logging while we are in suspend */
+SH_MUTEX_EXTERN(mutex_thread_nolog);
+
+/*
+ * ---- Initialize thread-specific conversion area ----
+ */
+extern int sh_g_thread(void);
+
+
+/*
+ * ---- Functions for threaded modules ----
+ */
+int sh_pthread_create(void *(*start_routine)(void*), void *arg);
+int sh_pthread_cancel_all(void);
+void sh_threaded_module_reconf(void *arg);
+void * sh_threaded_module_run(void *arg);
+
+#else
+
+#define SH_SETSIGMASK(A, B, C) sh_pthread_setsigmask(A,B,C)
+
+int sh_pthread_setsigmask(int how, const void *set, void *oldset);
+
+#define PTHREAD_MUTEX_INITIALIZER NULL
+#define SH_MUTEX(M) void *SH_MUTEX_DUMMY_ ## M
+#define SH_MUTEX_INIT(M,I) extern void *SH_MUTEX_DUMMY_ ## M
+#define SH_MUTEX_STATIC(M,I) extern void *SH_MUTEX_DUMMY_ ## M
+#define SH_MUTEX_EXTERN(M) extern void *SH_MUTEX_DUMMY_ ## M
+#define SH_MUTEX_LOCK(M) ((void)0)
+#define SH_MUTEX_TRYLOCK(M) ((void)0)
+#define SH_MUTEX_UNLOCK(M) ((void)0)
+#define SH_MUTEX_TRYLOCK_UNLOCK(M) ((void)0)
+#define SH_MUTEX_LOCK_UNSAFE(M) ((void)0)
+#define SH_MUTEX_TRYLOCK_UNSAFE(M) (0)
+#define SH_MUTEX_UNLOCK_UNSAFE(M) ((void)0)
+
+#define SH_MUTEX_RECURSIVE(M) extern void *SH_MUTEX_DUMMY_ ## M
+#define SH_MUTEX_RECURSIVE_INIT(M) ((void)0)
+#define SH_MUTEX_RECURSIVE_LOCK(M) ((void)0)
+#define SH_MUTEX_RECURSIVE_UNLOCK(M) ((void)0)
+
+/* #ifdef HAVE_PTHREAD */
+#endif
+
+/* #ifndef SH_PTHREAD_H */
+#endif
diff --git a/include/sh_readconf.h b/include/sh_readconf.h
new file mode 100644
index 0000000..5006607
--- /dev/null
+++ b/include/sh_readconf.h
@@ -0,0 +1,41 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+#ifndef SH_READCONFIG_H
+#define SH_READCONFIG_H
+
+/* set the config file
+ */
+int sh_readconf_setcfgfile (char * filename);
+
+/* read the configuration file
+ */
+int sh_readconf_read (void);
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/include/sh_registry.h b/include/sh_registry.h
new file mode 100644
index 0000000..92a4751
--- /dev/null
+++ b/include/sh_registry.h
@@ -0,0 +1,13 @@
+
+#ifndef SH_REGISTRY_H
+#define SH_REGISTRY_H
+
+int sh_reg_check_init(struct mod_type * arg);
+int sh_reg_check_timer(time_t tcurrent);
+int sh_reg_check_run(void);
+int sh_reg_check_reconf(void);
+int sh_reg_check_cleanup(void);
+
+extern sh_rconf sh_reg_check_table[];
+
+#endif
diff --git a/include/sh_restrict.h b/include/sh_restrict.h
new file mode 100644
index 0000000..8b3ac3f
--- /dev/null
+++ b/include/sh_restrict.h
@@ -0,0 +1,9 @@
+#ifndef SH_RESTRICT_H
+#define SH_RESTRICT_H
+
+int sh_restrict_define(const char * str);
+void sh_restrict_purge ();
+int sh_restrict_this(const char * path, UINT64 size, UINT64 perm, SL_TICKET fh);
+int sh_restrict_add_ftype(const char * str);
+
+#endif
diff --git a/include/sh_schedule.h b/include/sh_schedule.h
new file mode 100644
index 0000000..02ebb51
--- /dev/null
+++ b/include/sh_schedule.h
@@ -0,0 +1,30 @@
+#ifndef SH_SCHEDULE_H
+#define SH_SCHEDULE_H
+
+/************************************************
+ *
+ * Scheduler class - public definitions
+ *
+ ************************************************/
+
+typedef struct sh_schedule_ {
+ int max[5];
+ int min[5];
+ int step[5];
+ int min_step;
+ time_t last_exec;
+ int first;
+ struct sh_schedule_ * next;
+} sh_schedule_t;
+
+/* This function parses a crontab-like schedule and fills a
+ * sh_schedule_t structure provided by the caller.
+ */
+int create_sched (const char * ssched, sh_schedule_t * isched);
+
+/* This function returns 1 if the scheduled event should be executed,
+ * else 0
+ */
+int test_sched (sh_schedule_t * isched);
+
+#endif
diff --git a/include/sh_sem.h b/include/sh_sem.h
new file mode 100644
index 0000000..6c1fc34
--- /dev/null
+++ b/include/sh_sem.h
@@ -0,0 +1,14 @@
+#ifndef SH_SEM_H
+#define SH_SEM_H
+
+#define SH_SEM_LOCK -1
+#define SH_SEM_UNLOCK 1
+
+void sh_sem_open();
+void sh_sem_trylock();
+void sh_sem_lock();
+void sh_sem_unlock(long val);
+void sh_sem_close();
+
+int sh_sem_wait(const char * wait);
+#endif
diff --git a/include/sh_socket.h b/include/sh_socket.h
new file mode 100644
index 0000000..683f3c0
--- /dev/null
+++ b/include/sh_socket.h
@@ -0,0 +1,30 @@
+#ifndef SH_SOCKET_H
+#define SH_SOCKET_H
+
+/* 63 (cmd) + 1 (':') + 63 (host) + 1 ('\0') + 81
+ */
+#define SH_MAXMSG 209
+#define SH_MAXMSGLEN 64
+
+#if defined (SH_WITH_CLIENT)
+char * sh_socket_get_uuid(int * errflag, unsigned int * count, time_t * last);
+int sh_socket_store_uuid(const char * cmd);
+int sh_socket_return_uuid(const char * uuid, unsigned int count, time_t last);
+void sh_socket_server_cmd(const char * srvcmd);
+int set_delta_retry_interval(const char * str);
+int set_delta_retry_count(const char * str);
+#endif
+
+#if defined (SH_WITH_SERVER)
+
+
+int sh_socket_open_int (void);
+int sh_socket_remove (void);
+char * sh_socket_check(const char * client_name);
+int sh_socket_poll(void);
+void sh_socket_add2reload (const char * clt);
+
+#endif
+
+
+#endif
diff --git a/include/sh_srp.h b/include/sh_srp.h
new file mode 100644
index 0000000..074b29f
--- /dev/null
+++ b/include/sh_srp.h
@@ -0,0 +1,35 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+void sh_srp_x (char * salt, char * password);
+int sh_srp_make_a (void);
+char * sh_srp_M (char * x1, char * x2, char * x3, char * buf, size_t size);
+
+char * sh_srp_verifier (void);
+int sh_srp_check_zero (char * AB_str);
+
+int sh_srp_init(void);
+void sh_srp_exit(void);
+char * sh_srp_A (void);
+char * sh_srp_B (char * verifier);
+char * sh_srp_S_c (char * u_str, char * B_str);
+char * sh_srp_S_s (char * u_str, char * A_str, char * v_str);
+
+
diff --git a/include/sh_static.h b/include/sh_static.h
new file mode 100644
index 0000000..0f06ee7
--- /dev/null
+++ b/include/sh_static.h
@@ -0,0 +1,60 @@
+#ifndef SH_STATIC_H
+#define SH_STATIC_H
+
+#include "config_xor.h"
+
+#if defined(SH_COMPILE_STATIC) && defined(__linux__)
+
+#ifdef SH_NEED_PWD_GRP
+int sh_initgroups(const char *user, gid_t gid);
+struct group * sh_getgrent(void);
+struct passwd * sh_getpwent(void);
+void sh_endgrent(void);
+void sh_setgrent(void);
+void sh_endpwent(void);
+void sh_setpwent(void);
+struct group * sh_getgrnam(const char *name);
+int sh_getgrnam_r(const char *name, struct group *gbuf,
+ char *buf, size_t buflen, struct group **gbufp);
+
+struct passwd * sh_getpwnam(const char *name);
+int sh_getpwnam_r(const char *name, struct passwd *pwbuf,
+ char *buf, size_t buflen, struct passwd **pwbufp);
+
+struct group * sh_getgrgid(gid_t gid);
+int sh_getgrgid_r(gid_t gid, struct group *gbuf,
+ char *buf, size_t buflen, struct group **gbufp);
+
+struct passwd * sh_getpwuid(uid_t uid);
+int sh_getpwuid_r(uid_t uid, struct passwd *pwbuf,
+ char *buf, size_t buflen, struct passwd **pwbufp);
+
+#endif
+
+#ifdef SH_NEED_GETHOSTBYXXX
+struct hostent * sh_gethostbyaddr (const void *addr, socklen_t len, int type);
+struct hostent * sh_gethostbyname(const char *name);
+#endif
+
+#else
+
+#define sh_initgroups initgroups
+#define sh_getgrnam getgrnam
+#define sh_getgrnam_r getgrnam_r
+#define sh_getgrgid getgrgid
+#define sh_getgrgid_r getgrgid_r
+#define sh_getpwnam getpwnam
+#define sh_getpwnam_r getpwnam_r
+#define sh_getpwuid getpwuid
+#define sh_getpwuid_r getpwuid_r
+#define sh_getpwent getpwent
+#define sh_endpwent endpwent
+#define sh_setpwent setpwent
+
+#define sh_gethostbyaddr gethostbyaddr
+#define sh_gethostbyname gethostbyname
+
+#endif
+
+#endif
+
diff --git a/include/sh_string.h b/include/sh_string.h
new file mode 100644
index 0000000..a0da6c2
--- /dev/null
+++ b/include/sh_string.h
@@ -0,0 +1,108 @@
+#ifndef SH_STRING_H
+#define SH_STRING_H
+
+#include <stdio.h>
+
+/* String definition and utility functions.
+ */
+typedef struct sh_str_struct
+{
+ char * str; /* always NULL terminated */
+ size_t len; /* without terminating \0 */
+ size_t siz; /* size of allocated buffer */
+} sh_string;
+
+sh_string * sh_string_new(size_t size);
+void sh_string_destroy(sh_string ** s);
+#define sh_string_str(a) ((a)->str)
+#define sh_string_len(a) ((a)->len)
+
+/* concat string to sh_string
+ */
+sh_string * sh_string_cat_lchar(sh_string * s, const char * str, size_t len);
+
+/* add char array to end of string */
+sh_string * sh_string_add_from_char(sh_string * s, const char * str);
+
+/* set sh_string from string
+ */
+sh_string * sh_string_set_from_char(sh_string * s, const char * str);
+
+/* create new sh_string from array of given length
+ */
+sh_string * sh_string_new_from_lchar(const char * str, size_t len);
+
+#define sh_string_copy(a) ((a) ? sh_string_new_from_lchar(((a)->str), ((a)->len)) : NULL)
+#define sh_string_add(a,b) ((a && b) ? sh_string_cat_lchar((a), ((b)->str), ((b)->len)) : NULL)
+
+/* create new sh_string from three arrays of given length
+ */
+sh_string * sh_string_new_from_lchar3(const char * str1, size_t len1,
+ const char * str2, size_t len2,
+ const char * str3, size_t len3);
+
+/* Truncate to desired length.
+ */
+sh_string * sh_string_truncate(sh_string * s, size_t len);
+
+/* If requested increase is zero, increase by default amount.
+ */
+sh_string * sh_string_grow(sh_string * s, size_t increase);
+
+/* Read a string from a file, with maxlen. Return 0 on EOF,
+ * -1 on error, and -2 if a line exceeds maxlen.
+ */
+size_t sh_string_read(sh_string * s, FILE * fp, size_t maxlen);
+
+/* Read a string from a file, with maxlen. Return 0 on EOF,
+ * -1 on error, and -2 if a line exceeds maxlen.
+ * If 'cont' != NULL, continuation lines starting with a char
+ * in 'cont' are concatenated.
+ */
+size_t sh_string_read_cont(sh_string * s, FILE * fp, size_t maxlen, char *cont);
+
+/* Split array at delim in at most nfields fields.
+ * Empty fields are returned as empty (zero-length) strings.
+ * Leading and trailing WS are removed from token.
+ * The number of fields is returned in 'nfields', their
+ * lengths in 'lengths'.
+ * A single delimiter will return two empty fields.
+ */
+char ** split_array(char *line, unsigned int * nfields,
+ char delim, size_t * lengths);
+
+/* Split array at whitespace in at most nfields fields.
+ * Multiple whitespaces are collapsed.
+ * Empty fields are returned as empty (zero-length) strings.
+ * The number of fields is returned in nfields.
+ * An empty string will return zero fields.
+ * If nfields < actual fields, last string will be remainder.
+ */
+char ** split_array_ws(char *line, unsigned int * nfields, size_t * lengths);
+
+/* Same as above, but split on [space, tab, comma]
+ */
+char ** split_array_list(char *line, unsigned int * nfields, size_t * lengths);
+
+/* Same as above, but split on delimiter list (token)
+ */
+char ** split_array_token (char *line,
+ unsigned int * nfields, size_t * lengths,
+ const char * token);
+
+/* Return a split_array_list() of a list contained in 'PREFIX\s*( list ).*'
+ */
+char ** split_array_braced (char *line, const char * prefix,
+ unsigned int * nfields, size_t * lengths);
+
+/* Replaces fields in s with 'replacement'. Fields are given
+ * in the ordered array ovector, comprising ovecnum pairs
+ * ovector[i], ovector[i+1] which list offset of first char
+ * of field, offset of first char after field (this is how
+ * the pcre library does it).
+ */
+sh_string * sh_string_replace(const sh_string * s,
+ const int * ovector, int ovecnum,
+ const char * replacement, size_t rlen);
+
+#endif
diff --git a/include/sh_sub.h b/include/sh_sub.h
new file mode 100644
index 0000000..41ee202
--- /dev/null
+++ b/include/sh_sub.h
@@ -0,0 +1,8 @@
+#ifndef SH_SUB_H
+#define SH_SUB_H
+
+void sh_kill_sub ();
+int sh_sub_stat (const char *path, struct stat *buf);
+int sh_sub_lstat (const char *path, struct stat *buf);
+
+#endif
diff --git a/include/sh_suidchk.h b/include/sh_suidchk.h
new file mode 100644
index 0000000..d6885b7
--- /dev/null
+++ b/include/sh_suidchk.h
@@ -0,0 +1,42 @@
+
+#ifndef SH_SUIDCHK_H
+#define SH_SUIDCHK_H
+
+#include "sh_modules.h"
+
+#ifdef SH_USE_SUIDCHK
+int sh_suidchk_init (struct mod_type * arg);
+int sh_suidchk_timer (time_t tcurrent);
+int sh_suidchk_check (void);
+int sh_suidchk_end (void);
+int sh_suidchk_reconf (void);
+
+int sh_suidchk_set_activate (const char * c);
+int sh_suidchk_set_severity (const char * c);
+int sh_suidchk_set_timer (const char * c);
+int sh_suidchk_set_schedule (const char * c);
+int sh_suidchk_set_exclude (const char * c);
+int sh_suidchk_set_fps (const char * c);
+int sh_suidchk_set_yield (const char * c);
+int sh_suidchk_set_nosuid (const char * c);
+int sh_suidchk_set_quarantine (const char * c);
+int sh_suidchk_set_qmethod (const char * c);
+int sh_suidchk_set_qdelete (const char * c);
+
+
+extern sh_rconf sh_suidchk_table[];
+
+/* Quarantine Methods
+ */
+typedef enum {
+
+ SH_Q_DELETE = 0, /* delete */
+ SH_Q_CHANGEPERM = 1, /* remove suid/sgid permissions */
+ SH_Q_MOVE = 2 /* move */
+ } ShQuarantineMethod;
+
+
+#endif
+
+/* #ifndef SH_SUIDCHK_H */
+#endif
diff --git a/include/sh_tiger.h b/include/sh_tiger.h
new file mode 100644
index 0000000..d1894c4
--- /dev/null
+++ b/include/sh_tiger.h
@@ -0,0 +1,59 @@
+
+#ifndef SH_TIGER_H
+#define SH_TIGER_H
+
+#include "config_xor.h"
+#include "slib.h"
+#include "samhain.h"
+
+typedef long int TigerType;
+
+#define TIGER_FILE -1
+#define TIGER_DATA -2
+
+/****************
+typedef long int TigerType;
+typedef enum {
+ TIGER_FILE,
+ TIGER_FD,
+ TIGER_DATA
+} TigerType;
+*****************/
+
+#define TIGER_NOLIM ((UINT64)-1)
+
+/* the checksum function
+ */
+char * sh_tiger_hash (const char * filename, TigerType what,
+ UINT64 Length, char * out, size_t len);
+
+/* NEW Thu Oct 18 19:59:08 CEST 2001
+ */
+int sh_tiger_hashtype (const char * c);
+char * sh_tiger_generic_hash (char * filename, TigerType what,
+ UINT64 * Length, int timeout,
+ char * out, size_t len);
+
+UINT32 * sh_tiger_hash_uint32 (char * filename,
+ TigerType what,
+ UINT64 Length, UINT32 * out, size_t len);
+
+/* get the type of hash function used
+ * 0 = tiger192, 1 = sha1, 2 = md5
+ */
+int sh_tiger_get_hashtype (void);
+
+/* set the hash fuction in use in the mask
+ */
+void sh_tiger_get_mask_hashtype(unsigned long * mask);
+
+
+/* reset the hash function to the one in the mask
+ */
+void sh_tiger_set_hashtype_mask(unsigned long mask);
+
+/* GnuPG-like format, returns allocated memory
+ */
+/*@owned@*/ char * sh_tiger_hash_gpg (const char * filename, TigerType what,
+ UINT64 Length);
+#endif
diff --git a/include/sh_tools.h b/include/sh_tools.h
new file mode 100644
index 0000000..794851f
--- /dev/null
+++ b/include/sh_tools.h
@@ -0,0 +1,115 @@
+#ifndef SH_TOOLS_H
+#define SH_TOOLS_H
+
+#define SH_DO_WRITE 0
+#define SH_DO_READ 1
+
+/* protocols
+ */
+#define SH_PROTO_SRP (1 << 0)
+#define SH_PROTO_IVA (1 << 1)
+#define SH_PROTO_MSG (1 << 2)
+#define SH_PROTO_BIG (1 << 3)
+#define SH_PROTO_END (1 << 4)
+#define SH_PROTO_EN1 (1 << 5)
+#define SH_PROTO_EN2 (1 << 6)
+#define SH_PROTO_ENC (SH_PROTO_EN1|SH_PROTO_EN2)
+#define SH_MASK_ENC (SH_PROTO_ENC|SH_PROTO_EN2)
+
+#ifdef SH_ENCRYPT
+/* returns pointer to errbuf
+ */
+char * errorExplain (int err_num, char * errbuf, size_t len);
+#endif
+
+/* Returns non-zero if interface exists
+ */
+int sh_tools_iface_is_present(char *str);
+
+/* returns allocated buffer
+ */
+char * sh_tools_safe_name(const char * str, int flag);
+
+int connect_port (char * address, int port,
+ char * ecall, int * errnum, char * errmsg, int errsiz);
+int connect_port_2 (char * address1, char * address2, int port,
+ char * ecall, int * errnum, char * errmsg, int errsiz);
+void delete_cache(void);
+
+/* returns pointer to errbuf
+ */
+char * sh_tools_errmessage (int tellme, char * errbuf, size_t len);
+
+
+void sh_tools_show_header (unsigned char * head, char sign);
+
+#if defined (SH_WITH_SERVER)
+
+unsigned char sh_tools_probe_store(unsigned char protocol, int * probe_flag);
+
+int get_open_max (void);
+
+void put_header (/*@out@*/unsigned char * head, const int protocol,
+ unsigned long * length, char * u);
+
+int check_request_s (char * have, char * need, char * clt);
+int check_request_nerr (char * have, char * need);
+
+/* returns allocated buffer
+ */
+char * hash_me (char * key, char * buf, int buflen);
+int sh_tools_hash_vfy(char * key, char * buf, int buflen);
+
+/* returns allocated buffer
+ */
+char * get_client_conf_file (const char * peer, unsigned long * length);
+
+/* returns allocated buffer
+ */
+char * get_client_data_file (const char * peer, unsigned long * length);
+
+/* returns allocated buffer
+ */
+char * get_client_uuid_file (const char * peer, unsigned long * length, const char * uuid);
+#endif
+
+
+unsigned long read_port (int sockfd, char *buf, unsigned long nbytes,
+ int * w_error, int timeout);
+
+
+#if defined (SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+void sh_tools_probe_reset();
+
+unsigned long write_port (int sockfd, char *buf, unsigned long nbytes,
+ int * w_error, int timeout);
+
+int check_request (char * have, char * need);
+int check_request_nerr (char * have, char * need);
+
+void get_header (unsigned char * head, unsigned long * bytes, char * u);
+void put_header (unsigned char * head, int protocol,
+ unsigned long * length, char * u);
+
+/*
+ SL_TICKET open_tmp (void);
+ int close_tmp (SL_TICKET fd);
+ int rewind_tmp (SL_TICKET fd);
+*/
+
+void sh_tools_server_cmd(const char * srvcmd);
+
+int hash_check(char * key,
+ char * buf, int buflen);
+
+int sh_tools_hash_add(char * key, char * buf, int buflen);
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER) || defined(SH_STEALTH) || defined(WITH_GPG) || defined(WITH_PGP)
+SL_TICKET open_tmp (void);
+int close_tmp (SL_TICKET fd);
+int rewind_tmp (SL_TICKET fd);
+#endif
+
+#endif
diff --git a/include/sh_trace.h b/include/sh_trace.h
new file mode 100644
index 0000000..7bd902c
--- /dev/null
+++ b/include/sh_trace.h
@@ -0,0 +1,47 @@
+#ifndef SH_TRACE_H
+#define SH_TRACE_H
+
+
+/* This file should be included via samhain.h only.
+ */
+
+#ifdef SL_DEBUG
+#define ASSERT(expr, expr1) \
+ if (!(expr)) \
+ { \
+ fprintf(stderr, \
+ SDG_AERRO, \
+ FIL__, __LINE__, expr1 ); \
+ abort(); \
+ }
+
+
+#define ASSERT_RET(expr, expr1, rr) \
+ if (!(expr)) \
+ { \
+ fprintf(stderr, \
+ SDG_AERRO, \
+ FIL__, __LINE__, expr1 ); \
+ TPT(( (-1), FIL__, __LINE__, SDG_0RETU)) \
+ return (rr); \
+ }
+#else
+#define ASSERT(expr, expr1)
+
+#define ASSERT_RET(expr, expr1, rr) \
+ if (!(expr)) return (rr);
+#endif
+
+
+#ifdef SL_DEBUG
+#define TX1(expr1) \
+ fprintf(stderr, \
+ SDG_TERRO, \
+ FIL__, __LINE__, expr1 );
+#else
+#define TX1(expr1)
+#endif
+
+/* #ifndef SH_TRACE_H */
+#endif
+
diff --git a/include/sh_unix.h b/include/sh_unix.h
new file mode 100644
index 0000000..a5a4ceb
--- /dev/null
+++ b/include/sh_unix.h
@@ -0,0 +1,467 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+
+#ifndef SH_UNIX_H
+#define SH_UNIX_H
+
+/* For PATH_MAX */
+#include <limits.h>
+#if !defined(PATH_MAX)
+#define PATH_MAX 1024
+#endif
+
+#include <unistd.h>
+#include "samhain.h"
+#include "sh_error.h"
+
+
+typedef enum {
+ SH_ISLOG,
+ SH_ISFILE,
+ SH_ISDIR,
+ SH_ISDATA
+} ShOpenType;
+
+typedef enum {
+ SH_DATA_RAW,
+ SH_DATA_LINE
+} ShDataType;
+
+typedef enum {
+ SH_FILE_REGULAR,
+ SH_FILE_SYMLINK,
+ SH_FILE_DIRECTORY,
+ SH_FILE_CDEV,
+ SH_FILE_BDEV,
+ SH_FILE_FIFO,
+ SH_FILE_SOCKET,
+ SH_FILE_DOOR,
+ SH_FILE_PORT,
+ SH_FILE_UNKNOWN
+} ShFileType;
+
+/* -- Attributes to check. --
+ */
+
+/* checksum */
+#define MODI_CHK (1 << 0)
+/* link */
+#define MODI_LNK (1 << 1)
+/* inode */
+#define MODI_INO (1 << 2)
+
+/* user */
+#define MODI_USR (1 << 3)
+/* group */
+#define MODI_GRP (1 << 4)
+/* mtime */
+#define MODI_MTM (1 << 5)
+
+/* ctime */
+#define MODI_CTM (1 << 6)
+/* atime */
+#define MODI_ATM (1 << 7)
+/* size */
+#define MODI_SIZ (1 << 8)
+
+/* file mode */
+#define MODI_MOD (1 << 9)
+/* hardlinks */
+#define MODI_HLN (1 << 10)
+/* device type */
+#define MODI_RDEV (1 << 11)
+
+/* size may grow */
+#define MODI_SGROW (1 << 12)
+/* use prelink */
+#define MODI_PREL (1 << 13)
+/* get content */
+#define MODI_TXT ((1 << 14)|MODI_CHK)
+#define MODI_TXT_ENABLED(a) (((a)&(1 << 14))!=0)
+
+/* get audit record */
+#define MODI_AUDIT (1 << 15)
+#define MODI_AUDIT_ENABLED(a) (((a)&(1 << 15))!=0)
+/* do not check */
+#define MODI_NOCHECK (1 << 16)
+/* do not check */
+#define MODI_ALLIGNORE (1 << 17)
+
+#define MODI_TIGER192 0x01000000UL
+#define MODI_SHA1 0x02000000UL
+#define MODI_MD5 0x03000000UL
+#define MODI_SHA256 0x04000000UL
+#define MODI_HASHTYPE 0x0F000000UL
+
+#define MODI_INIT 0xD0000000UL
+#define MODI_INITIALIZED(a) (((a) & 0xF0000000UL) == MODI_INIT)
+
+#define MODI_SET(a, b) ((a) |= (b))
+#define MODI_CLEAR(a, b) ((a) &= ~(b))
+#define MODI_ISSET(a, b) (((a) & (b)) != 0)
+
+#define SH_TXT_MAX 9200
+
+#define MASK_ALLIGNORE_ 0
+extern unsigned long mask_ALLIGNORE;
+#define MASK_ATTRIBUTES_ (MODI_MOD|MODI_USR|MODI_GRP|MODI_RDEV)
+extern unsigned long mask_ATTRIBUTES;
+#define MASK_LOGFILES_ (MASK_ATTRIBUTES_|MODI_HLN|MODI_LNK|MODI_INO)
+extern unsigned long mask_LOGFILES;
+#define MASK_LOGGROW_ (MASK_LOGFILES_|MODI_SIZ|MODI_SGROW|MODI_CHK)
+extern unsigned long mask_LOGGROW;
+#define MASK_READONLY_ (MASK_LOGFILES_|MODI_CHK|MODI_SIZ|MODI_MTM|MODI_CTM)
+extern unsigned long mask_READONLY;
+#define MASK_NOIGNORE_ (MASK_LOGFILES_|MODI_CHK|MODI_SIZ|MODI_ATM|MODI_MTM)
+extern unsigned long mask_NOIGNORE;
+#define MASK_USER_ (MASK_READONLY_|MODI_ATM)
+extern unsigned long mask_USER0;
+extern unsigned long mask_USER1;
+extern unsigned long mask_USER2;
+extern unsigned long mask_USER3;
+extern unsigned long mask_USER4;
+/* like READONLY, but without MTM,CTM,SIZ,INO, and with PREL)
+ */
+#define MASK_PRELINK_ (MASK_ATTRIBUTES_|MODI_HLN|MODI_LNK|MODI_CHK|MODI_PREL)
+extern unsigned long mask_PRELINK;
+
+typedef struct file_struct {
+ unsigned long check_flags;
+ int file_reported;
+ char fullpath[PATH_MAX];
+ ShFileType type;
+ dev_t dev;
+ ino_t ino;
+ mode_t mode;
+ nlink_t hardlinks;
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ unsigned long attributes;
+ char c_attributes[ATTRBUF_SIZE];
+#endif
+ char c_mode[CMODE_SIZE];
+ uid_t owner;
+ char c_owner[USER_MAX+2];
+ gid_t group;
+ char c_group[GROUP_MAX+2];
+ dev_t rdev;
+ off_t size;
+ unsigned long blksize;
+ unsigned long blocks;
+ time_t atime;
+ time_t mtime;
+ time_t ctime;
+
+ char * link_path;
+ mode_t linkmode;
+ char link_c_mode[11];
+ int linkisok;
+ char * attr_string;
+} file_type;
+
+extern int sh_unix_check_selinux;
+extern int sh_unix_check_acl;
+
+/* destroy userid cache
+ */
+void sh_userid_destroy ();
+
+/* --- run a command, securely ---
+ */
+int sh_unix_run_command (const char * str);
+
+/* Ignore SIGPIPE
+ */
+void sh_unix_ign_sigpipe();
+
+/* mlock utilities
+ */
+int sh_unix_mlock(const char * file, int line, void * addr, size_t len);
+int sh_unix_munlock(void * addr, size_t len);
+int sh_unix_count_mlock(void);
+/* public for unit tests */
+int sh_unix_pagesize(void);
+unsigned long sh_unix_lookup_page(void * in_addr, size_t len, int * num_pages);
+
+/* chroot directory
+ */
+int sh_unix_set_chroot(const char * str);
+
+/* whether to use localtime for file timesatams in logs
+ */
+int sh_unix_uselocaltime (const char * c);
+
+/* whether to perform selinux/acl checks
+ */
+#ifdef USE_XATTR
+int sh_unix_setcheckselinux (const char * c);
+#endif
+#ifdef USE_ACL
+int sh_unix_setcheckacl (const char * c);
+#endif
+
+/* set I/O limit
+ */
+int sh_unix_set_io_limit (const char * c);
+void sh_unix_io_pause (void);
+
+/* get file type
+ */
+int sh_unix_get_ftype(char * fullpath);
+
+/* reset masks for policies
+ */
+int sh_unix_maskreset(void);
+
+/* return true if database is remote
+ */
+int file_is_remote (void);
+
+/* return the path to the configuration/database file
+ */
+char * file_path(char what, char flag);
+
+/* return current time as unsigned long
+ */
+unsigned long sh_unix_longtime (void);
+
+/* close all files >= fd, except possibly one
+ */
+void sh_unix_closeall (int fd, int except, int inchild);
+
+/* Check whether directory for pid file exists
+ */
+int sh_unix_check_piddir (char * pidpath);
+
+/* write lock for filename
+ */
+int sh_unix_write_lock_file(char * filename);
+
+/* rm lock(s) for log file(s)
+ */
+int sh_unix_rm_lock_file(char * filename);
+
+/* write the PID file
+ */
+int sh_unix_write_pid_file(void);
+
+/* rm the PID file
+ */
+int sh_unix_rm_pid_file(void);
+
+
+/* checksum of own binary
+ */
+int sh_unix_self_hash (const char * c);
+
+/* return BAD on failure
+ */
+int sh_unix_self_check (void);
+
+/* add a trusted user to the list
+ */
+int tf_add_trusted_user(const char *);
+
+/* check a file
+ */
+int tf_trust_check (const char * file, int mode);
+
+/* initialize group vector
+ */
+#ifdef HOST_IS_OSF
+int sh_unix_initgroups ( char * in_user, gid_t in_gid);
+#else
+int sh_unix_initgroups (const char * in_user, gid_t in_gid);
+#endif
+int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid);
+
+/* set the timeserver address
+ */
+int sh_unix_settimeserver (const char * address);
+void reset_count_dev_time(void);
+
+/* lock the key
+ */
+void sh_unix_memlock(void);
+
+/* deamon mode
+ */
+int sh_unix_setdeamon (const char * dummy);
+int sh_unix_setnodeamon(const char * dummy);
+
+/* Test whether file exists
+ */
+int sh_unix_file_exists(char * path);
+
+/* test whether file exists with proper attributes
+ */
+int sh_unix_device_readable(int fd);
+
+/* local host
+ */
+void sh_unix_localhost(void);
+
+/* check whether /proc exists and is a proc filesystem
+ */
+int sh_unix_test_proc(void);
+
+/* check whether a directory is secure
+ * (no symlink in path, not world-writeable)
+ */
+/* int sh_unix_is_secure_dir (ShErrLevel level, char * tmp); */
+
+/* check whether there's a rotated log with the correct inode and checksum
+ */
+int sh_check_rotated_log (const char * path,
+ UINT64 old_size, UINT64 old_inode, const char * old_hash, unsigned long mask);
+
+/* obtain file info
+ */
+int sh_unix_getinfo (int level, const char * filename, file_type * theFile,
+ char * fileHash, int flagrel);
+
+/* read file, return length read
+ */
+int sh_unix_getline (SL_TICKET fd, char * line, int sizeofline);
+
+/* call with goDaemon == 1 to make daemon process
+ */
+int sh_unix_init(int goDaemon);
+
+/* for local time use thetime = 0, returns pointer to buffer
+ */
+char * sh_unix_time (time_t thetime, char * buffer, size_t len);
+
+/* convert to GMT time, returns pointer to buffer
+ */
+char * sh_unix_gmttime (time_t thetime, char * buffer, size_t len);
+
+/* effective user info
+ */
+int sh_unix_getUser (void);
+
+/* get home directory, , returns pointer to out
+ */
+char * sh_unix_getUIDdir (int level, uid_t uid, char * out, size_t len);
+
+/* get a group GID
+ */
+long sh_group_to_gid (const char * g, int * fail);
+
+#ifdef HAVE_GETTIMEOFDAY
+unsigned long sh_unix_notime (void);
+#endif
+
+/* check whether a directory
+ */
+int sh_unix_isdir (char * dirName, int level);
+
+#ifdef SH_STEALTH
+int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len);
+void sh_unix_xor_code (char * str, int len);
+#endif
+
+#if defined(SCREW_IT_UP)
+/* for raise()
+ */
+#include <signal.h>
+#include <errno.h>
+
+void sh_sigtrap_handler (int signum);
+
+#ifdef HAVE_GETTIMEOFDAY
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+#endif
+
+struct sh_sigtrap_variables {
+ int not_traced;
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval save_tv;
+#endif
+};
+
+struct sh_sigtrap_variables * sh_sigtrap_variables_get();
+
+int sh_sigtrap_max_duration_set (const char * str);
+
+static inline
+int sh_sigtrap_prepare()
+{
+ struct sigaction act_trap;
+ int val_retry;
+ act_trap.sa_handler = &sh_sigtrap_handler; /* signal action */
+ act_trap.sa_flags = 0; /* init sa_flags */
+ sigemptyset ( &act_trap.sa_mask ); /* set an empty mask */
+ do {
+ val_retry = sigaction(SIGTRAP, &act_trap, NULL);
+ } while (val_retry < 0 && errno == EINTR);
+ return 0;
+}
+
+/*@unused@*/ static inline
+int sh_derr(void)
+{
+ struct sh_sigtrap_variables * sigtrap_variables;
+ sigtrap_variables = sh_sigtrap_variables_get();
+ if (sigtrap_variables == NULL) {
+ /* Perhaps, its better to not die, and to continue using Samhain,
+ even if this part does not work. */
+ return (0);
+ }
+
+ sigtrap_variables->not_traced = 0;
+
+#ifdef HAVE_GETTIMEOFDAY
+ gettimeofday(&sigtrap_variables->save_tv, NULL);
+#endif
+
+ /* raise() sends to same thread, like pthread_kill(pthread_self(), sig);
+ */
+ raise(SIGTRAP);
+
+ if (sigtrap_variables->not_traced == 0)
+ _exit(5);
+
+ sigtrap_variables->not_traced = 0;
+ return (0);
+}
+
+#else
+
+/*@unused@*/ static inline
+int sh_derr(void)
+{
+ return 0;
+}
+/* #if defined(SCREW_IT_UP) */
+#endif
+
+#endif
+
+
diff --git a/include/sh_userfiles.h b/include/sh_userfiles.h
new file mode 100644
index 0000000..6e80175
--- /dev/null
+++ b/include/sh_userfiles.h
@@ -0,0 +1,30 @@
+/*
+ * File: sh_userfiles.h
+ * Desc: A module for Samhain; adds files in user directories to the check list
+ * Auth: Jerry Connolly <jerry.connolly@eircom.net>
+ */
+
+#ifndef SH_USERFILES_H
+#define SH_USERFILES_H
+
+#ifdef SH_USE_USERFILES
+int sh_userfiles_init (struct mod_type * arg);
+int sh_userfiles_timer (time_t tcurrent);
+int sh_userfiles_check (void);
+int sh_userfiles_end (void);
+int sh_userfiles_cleanup (void);
+int sh_userfiles_reconf (void);
+
+int sh_userfiles_set_uid (const char * str);
+int sh_userfiles_add_file(const char *c);
+int sh_userfiles_set_interval(const char *c);
+int sh_userfiles_set_active(const char *c);
+int sh_userfiles_check_internal(void);
+
+extern sh_rconf sh_userfiles_table[];
+
+
+#endif
+
+/* #ifndef SH_USERFILES_H */
+#endif
diff --git a/include/sh_utils.h b/include/sh_utils.h
new file mode 100644
index 0000000..2f4519c
--- /dev/null
+++ b/include/sh_utils.h
@@ -0,0 +1,218 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#ifndef SH_UTILS_H
+#define SH_UTILS_H
+
+#include <stdarg.h>
+
+#include "slib.h"
+
+#include "sh_error.h"
+#include "sh_unix.h"
+
+#define S_FMT_STRING 1
+#define S_FMT_ULONG 2
+#define S_FMT_TIME 3
+#define S_FMT_LONG 4
+
+
+typedef struct ft_struc {
+ char fchar;
+ int type;
+ unsigned long data_ulong;
+ long data_long;
+ char *data_str;
+} st_format;
+
+/* returns allocated string
+ */
+char * sh_util_formatted (const char * fmt, st_format * ftab);
+
+typedef struct sh_timeout_struct {
+ UINT64 time_last;
+ UINT64 time_dist;
+ int flag_ok;
+} SH_TIMEOUT;
+
+int sh_util_timeout_check (SH_TIMEOUT * sh_timer);
+
+/* This is a maximally equidistributed combined Tausworthe
+ * generator.
+ */
+UINT32 taus_get (void);
+double taus_get_double (void *vstate); /* fast */
+int taus_seed (void);
+
+/* returns allocated memory
+ */
+char * sh_util_strdup (const char * str) SH_GNUC_MALLOC;
+char * sh_util_strdup_track (const char * str,
+ char * file, int line) SH_GNUC_MALLOC;
+
+/* returns allocated memory
+ */
+char * sh_util_strdup_l (const char * str, size_t len) SH_GNUC_MALLOC;
+
+/* returns pointer within str
+ */
+char * sh_util_strsep (char **str, const char *delim);
+
+/* compactify verbose acl text, returns allocated memory
+ */
+char * sh_util_acl_compact (char * buf, ssize_t len);
+
+/* set signature type HASH-TIGER/HMAC-TIGER
+ */
+int sh_util_sigtype (const char * c);
+
+/* compute a signature
+ */
+char * sh_util_siggen (char * hexkey,
+ char * text, size_t textlen,
+ char * sigbuf, size_t sigbuflen);
+
+/* eval boolean input
+ */
+int sh_util_flagval(const char * c, int * fval);
+
+/* ask if a file should be updated (returns S_TRUE/S_FALSE)
+ */
+int sh_util_ask_update(const char * path);
+int sh_util_set_interactive(const char * str);
+int sh_util_update_file (const char * str);
+
+/* don't log output files
+ */
+int sh_util_hidesetup(const char * c);
+
+/* valif utf-8 string
+ */
+int sh_util_valid_utf8 (const unsigned char * str);
+
+/* filenames are utf8
+ */
+int sh_util_obscure_utf8 (const char * c);
+
+/* exceptions to obscure name check
+ */
+int sh_util_obscure_ok (const char * str);
+
+/* output a hexchar[2]; i2h must be char[2]
+ */
+char * sh_util_charhex( unsigned char c, char * i2h );
+
+/* read a hexchar, return int value (0-15)
+ */
+int sh_util_hexchar( char c ) SH_GNUC_CONST;
+
+/* change verifier
+ */
+int sh_util_set_newkey (const char * str);
+
+/* server mode
+ */
+int sh_util_setserver (const char * dummy);
+
+/* a simple compressor
+ */
+size_t sh_util_compress (char * dest, char * src, size_t dest_size);
+
+/* an even simpler en-/decoder
+ */
+void sh_util_encode (char * data, char * salt, int mode, char fill);
+
+/* copy len ( < 4) bytes from (char *) (long src) to (char *) dest,
+ * determine the four LSB's and use them (independent of sizeof(long))
+ */
+void sh_util_cpylong (char * dest, const char * src, int len );
+
+/* set timer for main loop
+ */
+int sh_util_setlooptime (const char * str);
+
+/* whether init or check the database
+ */
+int sh_util_setchecksum (const char * str);
+
+/* compare an in_string against a regular expression regex_str
+ return GOOD on successful match
+*/
+int sh_util_regcmp (char * regex_str, char * in_str);
+
+
+/* returns freshly allocated memory, return value should be free'd.
+ * Argument list must be NULL terminated.
+ */
+char * sh_util_strconcat (const char * arg1, ...) SH_GNUC_MALLOC SH_GNUC_SENTINEL;
+
+/* check if string is numeric only
+ */
+int sh_util_isnum (const char *str) SH_GNUC_PURE;
+
+/* init a key w/random string
+ */
+int sh_util_keyinit (char * buf, long size);
+
+
+/* returns freshly allocated memory, return value should be free'd
+ */
+char * sh_util_dirname(const char * fullpath);
+
+/* returns freshly allocated memory, return value should be free'd
+ */
+char * sh_util_safe_name (const char * name) SH_GNUC_MALLOC SH_GNUC_PURE;
+
+char * sh_util_safe_name_keepspace (const char * name) SH_GNUC_MALLOC SH_GNUC_PURE;
+
+/* check max size of printf result string
+ */
+int sh_util_printf_maxlength (const char * fmt, va_list vl);
+
+/* check for obscure filenames
+ */
+int sh_util_obscurename (ShErrLevel level, const char * name, int flag);
+
+/* returns freshly allocated memory, return value should be free'd
+ */
+char * sh_util_basename(const char * fullpath);
+
+/* required size (including terminating NULL) for string of strlen l
+ */
+#define SH_B64_SIZ(l) (1 + ((((l) + 2) / 3) * 4))
+
+/* return len of encoded string
+ */
+size_t sh_util_base64_enc (unsigned char * out, const unsigned char * instr,
+ size_t lin);
+
+/* return allocated encoded string in out, return its len
+ */
+size_t sh_util_base64_enc_alloc (char **out, const char *in, size_t inlen);
+
+/* return len of decoded string
+ */
+size_t sh_util_base64_dec (unsigned char *out, const unsigned char *in, size_t lin);
+
+/* return allocated decoded string in out, return its len
+ */
+size_t sh_util_base64_dec_alloc (unsigned char **out, const unsigned char *in, size_t lin);
+
+#endif
diff --git a/include/sh_utmp.h b/include/sh_utmp.h
new file mode 100644
index 0000000..c46d841
--- /dev/null
+++ b/include/sh_utmp.h
@@ -0,0 +1,42 @@
+
+#ifndef SH_UTMP_H
+#define SH_UTMP_H
+
+#include "sh_modules.h"
+
+#ifdef SH_USE_UTMP
+int sh_utmp_init (struct mod_type * arg);
+int sh_utmp_timer (time_t tcurrent);
+int sh_utmp_check (void);
+int sh_utmp_end (void);
+int sh_utmp_reconf (void);
+
+int sh_utmp_set_login_activate (const char * c);
+int sh_utmp_set_login_solo (const char * c);
+int sh_utmp_set_login_multi (const char * c);
+int sh_utmp_set_logout_good (const char * c);
+int sh_utmp_set_login_timer (const char * c);
+
+extern sh_rconf sh_utmp_table[];
+
+/* >> Login tracking << */
+
+/* 'yes', 'no', 'paranoid' */
+int sh_login_set_siglevel (const char * c);
+
+/* 'yes', 'no', 'domain' */
+int sh_login_set_checklevel (const char * c);
+
+/* 'always' 'never' workdays(..) sunday(..) */
+int sh_login_set_def_allow (const char * c);
+
+/* user:'always' 'never' workdays(..) */
+int sh_login_set_user_allow (const char * c);
+
+/* Reset everything to defaults. */
+void sh_login_reset (void);
+
+#endif
+
+/* #ifndef SH_UTMP_H */
+#endif
diff --git a/include/sh_xfer.h b/include/sh_xfer.h
new file mode 100644
index 0000000..f4d6108
--- /dev/null
+++ b/include/sh_xfer.h
@@ -0,0 +1,124 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef SH_XFER_H
+#define SH_XFER_H
+
+#ifndef SH_STANDALONE
+int sh_xfer_set_strip (const char * str);
+#endif
+
+/* generate a random password
+ */
+int sh_xfer_create_password (const char * dummy);
+
+/* set timeout for active client connections
+ */
+int sh_xfer_set_timeout (const char * c);
+
+/* set time limit after which client is reported dead
+ */
+int sh_xfer_set_time_limit(const char * str);
+
+/* error level for lookup failure
+ */
+int sh_xfer_lookup_level (const char * c);
+
+/* create client entry for given password
+ */
+int sh_xfer_make_client (const char * str);
+
+/* set port to which we connect
+ */
+int sh_xfer_server_port (const char * str);
+
+#ifdef SH_WITH_SERVER
+
+#ifdef INET_SYSLOG
+int set_syslog_active(const char * c);
+#endif
+
+/* create socket and start listening
+ */
+void create_server_tcp_socket (void);
+
+/* whether to use client address as known to the communication layer
+ * and set by accept()
+ */
+int set_socket_peer (const char * c);
+
+/* whether to use client severity
+ */
+int sh_xfer_use_clt_sev (const char * c);
+
+/* whether to use client class
+ */
+int sh_xfer_use_clt_class (const char * c);
+
+/* server port
+ */
+int sh_xfer_set_port(const char * c);
+
+/* server interface
+ */
+int sh_xfer_set_interface(const char * c);
+
+/* a wrapper function
+ */
+void sh_xfer_html_write(void);
+
+/* register a client
+ */
+int sh_xfer_register_client (const char * str);
+
+/* start server
+ */
+void sh_xfer_start_server(void);
+
+/* free() everything
+ */
+void sh_xfer_free_all (void);
+
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+/* talk to server
+ */
+long sh_xfer_report (char * errmsg);
+
+/* set log server
+ */
+int sh_xfer_set_logserver (const char * address);
+void reset_count_dev_server(void);
+#endif
+
+#ifdef SH_WITH_CLIENT
+
+/* Throttle file download
+ */
+int sh_xfer_set_throttle_delay (const char * c);
+
+/* request file from server. file may be "CONF" or "DATA" or a UUID.
+ */
+long sh_xfer_request_file (const char * file);
+
+#endif
+
+#endif
+
diff --git a/include/slib.h b/include/slib.h
new file mode 100644
index 0000000..9ca3608
--- /dev/null
+++ b/include/slib.h
@@ -0,0 +1,642 @@
+/* --------------------------------------------------------------
+ *
+ * The developement of this library has been stimulated by reading
+ * a paper on 'Robust Programming' by Matt Bishop, although
+ * not all of his ideas might be implemented in the same
+ * strictness as discussed in the paper.
+ *
+ * --------------------------------------------------------------
+ */
+
+#ifndef SL_SLIB_H
+#define SL_SLIB_H
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+
+#include "config_xor.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "sh_string.h"
+
+/****************
+
+ -- Defined in config.h. --
+
+ #ifndef _(string)
+ #define _(string) string
+ #endif
+
+ #ifndef N_(string)
+ #define N_(string) string
+ #endif
+
+*****************/
+
+
+/* --------------------------------------------------------------
+ *
+ * Typedefs, global variables, macros.
+ *
+ * --------------------------------------------------------------
+ */
+
+extern long int sl_errno; /* Global error variable. */
+
+
+/* The ticketing system; used to hide internals from the
+ * programmer.
+ */
+typedef long int SL_TICKET; /* Unique ID for opened files. */
+
+
+/*
+ * TRUE, FALSE
+ */
+#if !defined(S_TRUE)
+#define S_TRUE 1
+#define S_FALSE 0
+#endif
+
+#define SH_GRBUF_SIZE 4096
+#define SH_PWBUF_SIZE 32768
+
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#undef SL_GNUC_CONST
+#define SL_GNUC_CONST __attribute__((const))
+#else
+#undef SL_GNUC_CONST
+#define SL_GNUC_CONST
+#endif
+
+/*
+ * The following macros are provided:
+ *
+ * SL_ISERROR(x) TRUE if return status of 'x' is an error code.
+ * SL_REQUIRE(x, xstr) Abort if 'x' is false.
+ * SL_ENTER(s) Trace entry in function 's'.
+ * SL_RETURN(x, s) Trace return from function 's'.
+ */
+
+
+/*
+ * The error codes.
+ */
+#define SL_ENONE 0
+
+#define SL_ENULL -1024 /* Invalid use of NULL pointer. */
+#define SL_ERANGE -1025 /* Argument out of range. */
+#define SL_ETRUNC -1026 /* Result truncated. */
+#define SL_EREPEAT -1027 /* Illegal repeated use of function. */
+
+#define SL_EINTERNAL -1028 /* Internal error. */
+#define SL_ETICKET -1029 /* Bad ticket. */
+#define SL_EBADFILE -1030 /* File access error. Check errno. */
+#define SL_EBOGUS -1031 /* Bogus file. */
+#define SL_EMEM -1032 /* Out of memory. */
+#define SL_EUNLINK -1033 /* Unlink error. Check errno. */
+#define SL_EREWIND -1034 /* Rewind error. Check errno. */
+#define SL_EFORWARD -1035 /* Forward error. Check errno. */
+#define SL_EREAD -1036 /* Read error. Check errno. */
+#define SL_EWRITE -1037 /* Write error. Check errno. */
+#define SL_ESYNC -1038 /* Write error. Check errno. */
+
+#define SL_EBADNAME -1040 /* Invalid name. */
+#define SL_ESTAT -1041 /* stat of file failed. Check errno. */
+#define SL_EFSTAT -1042 /* fstat of file failed. Check errno. */
+
+#define SL_EBADUID -1050 /* Owner not trustworthy. */
+#define SL_EBADGID -1051 /* Group writeable and not trustworthy.*/
+#define SL_EBADOTH -1052 /* World writeable. */
+
+#define SL_TOOMANY -1053 /* Too many open files */
+#define SL_TIMEOUT -1054 /* Timeout in read */
+
+#define SL_EISDIR -1055 /* Is a directory */
+
+#define SL_EINTERNAL01 -1061 /* Internal error. */
+#define SL_EINTERNAL02 -1062 /* Internal error. */
+#define SL_EINTERNAL03 -1063 /* Internal error. */
+#define SL_EINTERNAL04 -1064 /* Internal error. */
+#define SL_EINTERNAL05 -1065 /* Internal error. */
+#define SL_EINTERNAL06 -1066 /* Internal error. */
+#define SL_EINTERNAL07 -1067 /* Internal error. */
+#define SL_EINTERNAL08 -1068 /* Internal error. */
+#define SL_EINTERNAL09 -1069 /* Internal error. */
+#define SL_EINTERNAL10 -1070 /* Internal error. */
+#define SL_EINTERNAL11 -1071 /* Internal error. */
+#define SL_EINTERNAL12 -1072 /* Internal error. */
+
+/*
+ * All int functions return SL_NONE on success.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ int dlog (int flag, const char * file, int line, const char *fmt, ...);
+
+ char * sl_get_errmsg(void);
+
+ /* ----------------------------------------------------------------
+ *
+ * Heap consistency routines
+ *
+ * ---------------------------------------------------------------- */
+
+ int sl_test_heap(void);
+
+ /* ----------------------------------------------------------------
+ *
+ * Capability routines
+ *
+ * ---------------------------------------------------------------- */
+
+ extern int sl_useCaps;
+
+ int sl_drop_cap (void);
+ int sl_drop_cap_sub(void);
+ int sl_get_cap_sub(void);
+ int sl_drop_cap_qdel(void);
+ int sl_get_cap_qdel(void);
+
+ /* ----------------------------------------------------------------
+ *
+ * String handling routines
+ *
+ * ---------------------------------------------------------------- */
+
+ /*
+ * A memset that does not get optimized away
+ */
+ void *sl_memset(void *s, int c, size_t n);
+#if !defined(SH_REAL_SET)
+#undef memset
+#define memset sl_memset
+#endif
+
+ /*
+ * Copy src to dst. siz is the length of dst.
+ */
+ int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz);
+
+ /*
+ * Append src to dst. siz is the length of dst.
+ */
+ int sl_strlcat(char * dst, /*@null@*/const char *src, size_t siz);
+
+ /*
+ * An implementation of vsnprintf. va_start/va_end are in the caller
+ * function.
+ */
+ int sl_vsnprintf(char *str, size_t n,
+ const char *format, va_list vl );
+
+ /*
+ * An implementation of snprintf.
+ */
+ int sl_snprintf(char *str, size_t n,
+ const char *format, ... );
+
+ /*
+ * A robust drop-in replacement of strncpy. strlcpy is preferable.
+ */
+ char * sl_strncpy(/*@out@*/char *dst, const char *src, size_t size);
+
+ /*
+ * Robust strncat.
+ */
+ char * sl_strncat(char *dst, const char *src, size_t n);
+
+ /*
+ * strstr
+ */
+ char * sl_strstr (const char * haystack, const char * needle);
+
+ /*
+ * robust strn[case]cmp replacement
+ */
+ int sl_strncmp(const char * a, const char * b, size_t n);
+
+ int sl_strncasecmp(const char * a, const char * b, size_t n);
+
+ /*
+ * robust strcmp replacement
+ */
+ int sl_strcmp(const char * a, const char * b);
+
+ /*
+ * robust strcasecmp replacement
+ */
+ int sl_strcasecmp(const char * one, const char * two);
+
+ /*
+ * robust strlen replacement
+ */
+#define sl_strlen(arg) ((arg == NULL) ? 0 : (strlen(arg)))
+
+ /* ----------------------------------------------------------------
+ *
+ * Privilege handling routines
+ *
+ * ---------------------------------------------------------------- */
+
+ /*
+ * ONE OF THE FOLLOWING THREE FUNCTIONS
+ * SHOULD BE CALLED BEFORE ANY OTHER OF THE
+ * UID HANDLING FUNCTIONS.
+ */
+ int sl_policy_get_user(const char *username); /* drop SUID to <username> */
+ int sl_policy_get_real(char *username); /* drop privs to <username> */
+ int sl_policy_get_root(void); /* drop SUID to root */
+
+ /*
+ * If not using one of the above, use this function,
+ * and then call sh_unset_suid().
+ * This function saves the uid's.
+ * It calls abort() on error.
+ */
+ int sl_save_uids(void);
+
+ /*
+ * This function returns the saved euid.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_get_euid(/*@out@*/uid_t * ret);
+ uid_t sl_ret_euid(void);
+
+ /*
+ * This function returns the saved egid.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_get_egid(/*@out@*/gid_t * ret);
+
+ /*
+ * This function returns the saved current ruid.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_get_ruid(/*@out@*/uid_t * ret);
+
+ /*
+ * This function returns the saved current rgid.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_get_rgid(gid_t * ret);
+
+ /*
+ * This function returns the saved original ruid.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_get_ruid_orig(uid_t * ret);
+
+ /*
+ * This function returns the saved original rgid.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_get_rgid_orig(gid_t * ret);
+
+ /*
+ * This function returns true if the program is SUID.
+ * It calls abort() if the uid's are not saved already.
+ */
+ int sl_is_suid(void);
+
+ /*
+ * This function sets the effective uid
+ * to the saved effective uid.
+ */
+ int sl_set_suid (void);
+
+ /*
+ * This function sets the effective uid to the real uid.
+ */
+ int sl_unset_suid (void);
+
+ /*
+ * This function drops SUID privileges irrevocably.
+ */
+ int sl_drop_privileges(void);
+
+ /* ----------------------------------------------------------------
+ *
+ * File handling routines
+ *
+ * ---------------------------------------------------------------- */
+
+#define SL_OFILE_SIZE 32
+
+ char * sl_check_badfd();
+ char * sl_check_stale();
+
+ /* Create a file record for an open file
+ */
+ SL_TICKET sl_make_ticket (const char * ofile, int oline,
+ int fd, const char * filename, FILE * stream);
+
+ /* Get the pointer to a stream. If none exists yet, open it
+ */
+ FILE * sl_stream (SL_TICKET ticket, char * mode);
+
+ /* Open for writing.
+ */
+ SL_TICKET sl_open_write (const char * ofile, int oline,
+ const char * fname, int priviledge_mode);
+
+ /* Open for reading.
+ */
+ SL_TICKET sl_open_read (const char * ofile, int oline,
+ const char * fname, int priviledge_mode);
+
+ /* Drop from cach when closing
+ */
+ int sl_set_drop_cache(const char * str);
+
+ /* Open for reading w/minimum checking.
+ */
+ SL_TICKET sl_open_fastread (const char * ofile, int oline,
+ const char * fname, int priviledge_mode);
+
+ /* Open for read and write.
+ */
+ SL_TICKET sl_open_rdwr (const char * ofile, int oline,
+ const char * fname, int priviledge_mode);
+
+ /* Open for read and write, fail if file exists.
+ */
+ SL_TICKET sl_open_safe_rdwr (const char * ofile, int oline,
+ const char * fname, int priv);
+
+ /* Open for write, truncate.
+ */
+ SL_TICKET sl_open_write_trunc (const char * ofile, int oline,
+ const char * fname, int priviledge_mode);
+
+ /* Open for read and write, truncate.
+ */
+ SL_TICKET sl_open_rdwr_trunc (const char * ofile, int oline,
+ const char * fname, int priviledge_mode);
+
+ /* Initialize the content sh_string.
+ */
+ int sl_init_content (SL_TICKET ticket, size_t size);
+
+ /* Get the (pointer to) the content sh_string.
+ */
+ sh_string * sl_get_content (SL_TICKET ticket);
+
+ /* Lock file (uses fcntl F_SETLK).
+ */
+ int sl_lock (SL_TICKET ticket);
+
+ /* Close file.
+ */
+ int sl_close (SL_TICKET ticket);
+
+ /* Close file descriptor.
+ */
+ int sl_close_fd (const char * file, int line, int fd);
+
+ /* Close stream.
+ */
+ int sl_fclose (const char * file, int line, FILE * fp);
+
+ /* Unlink file.
+ */
+ int sl_unlink (SL_TICKET ticket);
+
+ /* Rewind file.
+ */
+ int sl_rewind (SL_TICKET ticket);
+
+ /* Seek file.
+ */
+ int sl_seek (SL_TICKET ticket, off_t off_data);
+
+ /* Forward file.
+ */
+ int sl_forward (SL_TICKET ticket);
+
+ /* Sync file.
+ */
+ int sl_sync (SL_TICKET ticket);
+
+ /* Read file.
+ */
+ int sl_read (SL_TICKET ticket, void * buf, size_t count);
+
+ int sl_read_timeout_prep (SL_TICKET ticket);
+
+ int sl_read_timeout_fd (int fd, void * buf,
+ size_t count, int timeout, int is_nonblocking);
+
+ int sl_read_timeout (SL_TICKET ticket, void * buf,
+ size_t count, int timeout, int is_nonblocking);
+
+ int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count);
+
+ /* Write file.
+ */
+ int sl_write (SL_TICKET ticket, const void * msg, long nbytes);
+
+ /* Write file, terminate with newline.
+ */
+ int sl_write_line (SL_TICKET ticket, const void * msg, long nbytes);
+
+ /* As above, but only for non-constant strings.
+ */
+ int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes);
+
+ /* Drop all metadata for file descriptors >= fd.
+ */
+ int sl_dropall(int fd, int except);
+ int sl_dropall_dirty(int fd, int except); /* don't deallocate */
+
+ /* Check whether file is trustworthy.
+ */
+ int sl_trustfile(const char * path, uid_t * ok, uid_t * bad);
+
+ /* Check whether file is trustworthy.
+ */
+ int sl_trustfile_euid(const char * filename, uid_t euid);
+
+ /* purge list of trusted users
+ */
+ int sl_trust_purge_user (void);
+
+ /* Add a trusted user.
+ */
+ int sl_trust_add_user (uid_t pwid);
+
+ /* Get error string.
+ */
+ char * sl_error_string(int errorcode);
+
+ /* Get error file.
+ */
+ char * sl_trust_errfile(void);
+
+ /* Overflow tests
+ */
+ int sl_ok_muli (int a, int b) SL_GNUC_CONST;
+ int sl_ok_divi (int a, int b) SL_GNUC_CONST;
+ int sl_ok_addi (int a, int b) SL_GNUC_CONST;
+ int sl_ok_subi (int a, int b) SL_GNUC_CONST;
+
+ int sl_ok_muls (size_t a, size_t b) SL_GNUC_CONST;
+ int sl_ok_adds (size_t a, size_t b) SL_GNUC_CONST;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Privilege modes for file access.
+ */
+#define SL_YESPRIV 0x33
+#define SL_NOPRIV 0x34
+
+/* Suitable for Linux
+ */
+#define MAXFILENAME 4096
+
+
+/*
+ * This macro is TRUE if (x) < 0.
+ */
+#define SL_ISERROR(x) ((long)(x) < 0)
+
+#if defined(WITH_TPT)
+#define TPT(arg) dlog arg ;
+#else
+#define TPT(arg)
+#endif
+
+
+/*
+ * The 'require' macro.
+ */
+#define SL_REQUIRE(assertion, astext) \
+do { \
+ /*@i@*/ if (assertion) ; \
+ else { \
+ dlog(0, FIL__, __LINE__, SDG_AFAIL, \
+ FIL__, __LINE__, astext); \
+ _exit(EXIT_FAILURE); \
+ } \
+} while (0)
+
+
+/*
+ * The enter macro. Prints the trace if TRACE is on.
+ */
+extern int slib_do_trace;
+extern int slib_trace_fd;
+
+#if defined(SL_DEBUG)
+#define SL_ENTER(s) sl_stack_push(s, FIL__, __LINE__);
+#else
+#define SL_ENTER(s) if (slib_do_trace != 0) sl_trace_in(s, FIL__, __LINE__);
+#endif
+
+/*
+ * The return macro.
+ */
+#if defined(SL_DEBUG)
+#ifndef S_SPLINT_S
+#define SL_RETURN(x, s) \
+do { \
+ sl_stack_pop(s, FIL__, __LINE__); \
+ return(x); \
+} while(0)
+#else
+/*@notfunction@*/
+#define SL_RETURN(x, s) return(x);
+#endif /* S_SPLINT_S */
+#else
+#ifndef S_SPLINT_S
+#define SL_RETURN(x, s) \
+do { \
+ if (slib_do_trace != 0) \
+ sl_trace_out(s, FIL__, __LINE__); \
+ return(x); \
+} while(0)
+#else
+/*@notfunction@*/
+#define SL_RETURN(x, s) return(x);
+#endif /* S_SPLINT_S */
+#endif /* SL_RETURN macro */
+
+#if defined(SL_DEBUG)
+#define SL_RET0(s) \
+do { \
+ sl_stack_pop(s, FIL__, __LINE__); \
+ return; \
+} while(0)
+#else
+#ifndef S_SPLINT_S
+#define SL_RET0(s) \
+do { \
+ if (slib_do_trace != 0) \
+ sl_trace_out(s, FIL__, __LINE__); \
+ return; \
+} while(0)
+#else
+/*@notfunction@*/
+#define SL_RET0(s) return;
+#endif /* S_SPLINT_S */
+#endif /* SL_RETURN macro */
+
+#if defined(SL_DEBUG)
+void sl_stack_push(char * c, char * file, int line);
+void sl_stack_pop(char * c, char * file, int line);
+void sl_stack_print(void);
+#endif
+void sl_trace_in (const char * str, const char * file, int line);
+void sl_trace_out (const char * str, const char * file, int line);
+int sl_trace_file (const char * str);
+int sl_trace_use (const char * str);
+
+
+
+
+/*
+ * The internal return macro. Sets sl_errno to the return value.
+ */
+
+#if defined(SL_DEBUG)
+#define SL_IRETURN(x, s) \
+do { \
+ if((long)(x) < 0) { \
+ TPT((0, FIL__, __LINE__, SDG_ERROR, (long)(x))) \
+ sl_errno=(x); \
+ } \
+ sl_stack_pop(s, FIL__, __LINE__); \
+ if (1) return(x); \
+} while(0)
+#else
+#define SL_IRETURN(x, s) \
+do { \
+ if ((long)(x) < 0) sl_errno=(x); \
+ if (slib_do_trace) \
+ sl_trace_out(s, FIL__, __LINE__); \
+ if (1) return(x); \
+} while(0)
+
+#endif /* SL_IRETURN macro */
+
+
+
+/* slib.h */
+#endif
+
+
+
+
diff --git a/include/trustfile.h b/include/trustfile.h
new file mode 100644
index 0000000..8c2cf3d
--- /dev/null
+++ b/include/trustfile.h
@@ -0,0 +1,94 @@
+/*
+ * This is the header file for the trust function
+ *
+ * Author information:
+ * Matt Bishop
+ * Department of Computer Science
+ * University of California at Davis
+ * Davis, CA 95616-8562
+ * phone (916) 752-8060
+ * email bishop@cs.ucdavis.edu
+ *
+ * This code is placed in the public domain. I do ask that
+ * you keep my name associated with it, that you not represent
+ * it as written by you, and that you preserve these comments.
+ * This software is provided "as is" and without any guarantees
+ * of any sort.
+ */
+/*
+ * trustfile return codes
+ */
+#define TF_ERROR -1 /* can't check -- error */
+#define TF_NO 0 /* file isn't trustworthy */
+#define TF_YES 1 /* file is trustworthy */
+
+/*
+ * error codes
+ */
+#define TF_BADFILE 1 /* file name illegal */
+#define TF_BADNAME 2 /* name not valid (prob. ran out of room) */
+#define TF_BADSTAT 3 /* stat of file failed (see errno for why) */
+#define TF_NOROOM 4 /* not enough allocated space */
+
+/*
+ * untrustworthy codes
+ */
+#define TF_BADUID 10 /* owner nmot trustworthy */
+#define TF_BADGID 11 /* group writeable and member not trustworthy */
+#define TF_BADOTH 12 /* anyone can write it */
+
+/*
+ * the basic constant -- what is the longest path name possible?
+ * It should be at least the max path length as defined by system
+ * + 4 ("/../") + max file name length as defined by system; this
+ * should rarely fail (I rounded it up to 2048)
+ */
+#define MAXFILENAME 2048
+
+/*
+ * function declaration
+ *
+ * #ifdef __STDC__
+ * extern int trustfile(char *, int *, int *);
+ * #else
+ * extern int trustfile();
+ * #endif
+ */
+/*
+ * these are useful global variables
+ *
+ * first set: who you gonna trust, by default?
+ * if the user does not specify a trusted or untrusted set of users,
+ * all users are considered untrusted EXCEPT:
+ * UID 0 -- root as root can do anything on most UNIX systems, this
+ * seems reasonable
+ * tf_euid -- programmer-selectable UID
+ * if the caller specifies a specific UID by putting
+ * it in this variable, it will be trusted; this is
+ * typically used to trust the effective UID of the
+ * process (note: NOT the real UID, which will cause all
+ * sorts of problems!) By default, this is set to -1,
+ * so if it's not set, root is the only trusted user
+ */
+extern uid_t tf_euid; /* space for EUID of process */
+
+/*
+ * second set: how do you report problems?
+ * tf_errno on return when an error has occurred, this is set
+ * to the code indicating the reason for the error:
+ * TF_BADFILE passed NULL for pointer to file name
+ * TF_BADNAME could not expand to full path name
+ * TF_BADSTAT stat failed; usu. file doesn't exist
+ * TF_BADUID owner untrusted
+ * TF_BADGID group untrusted & can write
+ * TF_BADOTH anyone can write
+ * the value is preserved across calls where no error
+ * occurs, just like errno(2)
+ * tf_path if error occurs and a file name is involved, this
+ * contains the file name causing the problem
+ */
+extern char tf_path[MAXFILENAME]; /* error path for trust function */
+
+extern uid_t rootonly[];
+extern int EUIDSLOT;
+
diff --git a/include/zAVLTree.h b/include/zAVLTree.h
new file mode 100644
index 0000000..21cfe9a
--- /dev/null
+++ b/include/zAVLTree.h
@@ -0,0 +1,82 @@
+/*
+ * zAVLTree.h: Header file for zAVLTrees.
+ * Copyright (C) 1998,2001 Michael H. Buselli
+ * This is version 0.1.3 (alpha).
+ * Generated from $Id: xAVLTree.h.sh,v 1.5 2001/06/07 06:58:28 cosine Exp $
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The author of this library can be reached at the following address:
+ * Michael H. Buselli
+ * 30051 N. Waukegan Rd. Apt. 103
+ * Lake Bluff, IL 60044-5412
+ *
+ * Or you can send email to <cosine@cosine.org>.
+ * The official web page for this product is:
+ * http://www.cosine.org/project/AVLTree/
+ */
+
+#ifndef _ZAVLTREE_H_
+#define _ZAVLTREE_H_
+
+/* typedef the keytype */
+typedef const void * zAVLKey;
+
+/* Comparison function for strings is strcmp(). */
+/* #define zAVLKey_cmp(tree, a, b) (strcmp((a), (b))) */
+
+#define zAVL_KEY_STRING 0
+#define zAVL_KEY_INT 1
+
+
+typedef struct _zAVLNode {
+ zAVLKey key;
+ long depth;
+ void *item;
+ struct _zAVLNode *parent;
+ struct _zAVLNode *left;
+ struct _zAVLNode *right;
+} zAVLNode;
+
+
+typedef struct {
+ zAVLNode *top;
+ long count;
+ zAVLKey (*getkey)(const void *item);
+ int keytype;
+} zAVLTree;
+
+
+typedef struct {
+ const zAVLTree *avltree;
+ const zAVLNode *curnode;
+} zAVLCursor;
+
+
+extern zAVLTree *zAVLAllocTree (zAVLKey (*getkey)(void const *item), int keytype);
+extern void zAVLFreeTree (zAVLTree *avltree, void (freeitem)(void *item));
+extern int zAVLInsert (zAVLTree *avltree, void *item);
+extern void *zAVLSearch (zAVLTree const *avltree, zAVLKey key);
+extern int zAVLDelete (zAVLTree *avltree, zAVLKey key);
+extern void *zAVLFirst (zAVLCursor *avlcursor, zAVLTree const *avltree);
+extern void *zAVLNext (zAVLCursor *avlcursor);
+
+extern char * zAVL_string_get (zAVLTree * tree, const char * key);
+/* uses strdup to insert a copy */
+extern int zAVL_string_set (zAVLTree ** tree, const char * key);
+extern void zAVL_string_reset (zAVLTree * tree);
+extern void zAVL_string_del (zAVLTree * tree, const char * key);
+
+#endif
diff --git a/init/samhain.start.in b/init/samhain.start.in
new file mode 100644
index 0000000..92d54ba
--- /dev/null
+++ b/init/samhain.start.in
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# This file is public domain and comes with NO WARRANTY of any kind
+# samhain deamon start/stop script.
+
+# This should be put in /etc/init.d (at least on machines SYSV R4
+# based systems) and linked to /etc/rc3.d/S99samhain. When this is done
+# the samhain daemon will be started when the machine is started.
+
+PATH=/sbin:/usr/bin:/usr/sbin:/bin
+basedir=/
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+
+samhain_daemon_user=root # Run samhain as this user.
+ # If you use this, uncomment one of
+ # the su rows below.
+
+export PATH
+
+mode=$1
+
+# The following test may be removed if this script isn't to be run as root.
+if test ! -w /
+then
+ echo "$0: this script must be run as root ... fatal error"
+ exit 1
+fi
+
+
+# Safeguard (relative paths, core dumps..)
+cd $basedir
+
+case "$mode" in
+ 'start')
+ # Start deamon
+ if test -x ${bindir}/samhain
+ then
+ if test -x /sbin/startproc
+ then
+ # use startproc if available
+ startproc ${bindir}/samhain -t check -D
+ else
+ # For Linux
+ su -c -- $samhain_daemon_user $bindir/samhain -t check -D
+ # For sun
+ # su $samhain_daemon_user $bindir/samhain -t check -D
+ fi
+ else
+ echo "Can't execute ${bindir}/samhain"
+ fi
+ ;;
+
+
+ 'stop')
+ if test -x ${bindir}/samhain
+ then
+ if test -x /sbin/killproc
+ then
+ # alternatively use the command below, if you have 'killproc'
+ killproc -TERM ${bindir}/samhain
+ else
+ # Stop deamon - no PID file available, so search for the pid
+ SH_PID=`ps aux | grep samhain | grep -v grep | awk '{print $2}'`
+ kill ${SH_PID}
+ fi
+ fi
+ ;;
+
+ *)
+ # usage
+ echo "usage: $0 start|stop"
+ exit 1
+ ;;
+esac
diff --git a/init/samhain.startFreeBSD.in b/init/samhain.startFreeBSD.in
new file mode 100644
index 0000000..4a18f08
--- /dev/null
+++ b/init/samhain.startFreeBSD.in
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# PROVIDE: @install_name@
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name="@install_name@"
+rcvar=`set_rcvar`
+
+pidfile="@mylockfile@"
+
+# there are no required_files in general,
+# as they might be downloaded from the server
+#
+# required_files="@myconffile@ @mydatafile@"
+
+extra_commands="reload"
+stop_postcmd="remove_stale_files"
+
+command="@sbindir@/@install_name@"
+
+is_set()
+{
+ eval "[ -n \"\${$1+X}\" ]"
+}
+
+remove_stale_files()
+{
+ if test -f @mylockfile@; then
+ /bin/rm -f @mylockfile@
+ fi
+ /bin/rm -f @mylockdir@/${name}.sock
+}
+
+load_rc_config "$name"
+
+if ! is_set ${rcvar}; then
+ eval "${rcvar}=YES"
+fi
+
+run_rc_command "$1"
+
diff --git a/init/samhain.startGentoo.in b/init/samhain.startGentoo.in
new file mode 100644
index 0000000..fb45ec9
--- /dev/null
+++ b/init/samhain.startGentoo.in
@@ -0,0 +1,30 @@
+#!/sbin/runscript
+
+opts="depend start stop reload"
+
+depend() {
+ need clock hostname logger
+}
+
+start() {
+ ebegin "Starting @install_name@"
+ /sbin/start-stop-daemon --start --quiet --exec @sbindir@/@install_name@
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping @install_name@"
+ /sbin/start-stop-daemon --stop --quiet --retry 15 --exec @sbindir@/@install_name@
+ rm -f @mylockfile@
+ eend $?
+}
+
+reload() {
+ if [ ! -f @mylockfile@ ]; then
+ eerror "@install_name@ isn't running"
+ return 1
+ fi
+ ebegin "Reloading configuration"
+ kill -HUP `cat @mylockfile@` &>/dev/null
+ eend $?
+}
diff --git a/init/samhain.startHPUX.in b/init/samhain.startHPUX.in
new file mode 100644
index 0000000..482c9e8
--- /dev/null
+++ b/init/samhain.startHPUX.in
@@ -0,0 +1,116 @@
+#!/sbin/sh
+
+# Allowed exit values
+#
+# 0 = success
+# 1 = failure
+# 2 = skip
+# 3 = reboot (now)
+
+# stdin is redirected from /dev/null
+# stderr, stdout are redirected to /etc/rc.log file (checklist mode)
+# or console (raw mode)
+
+# /usr, /var, /opt my not be available until run state 2
+
+PATH=/usr/sbin:/usr/bin:/sbin
+export PATH
+
+rval=0
+
+DAEMON=@sbindir@/@install_name@
+NAME=@install_name@
+
+run_the_command() {
+ if test -f /etc/rc.config
+ then
+ . /etc/rc.config
+ else
+ echo "ERROR: /etc/rc.config defaults file MISSING"
+ fi
+ if test "x${CONTROL_@install_name@}" = x0
+ then
+ rval=2
+ else
+ ${DAEMON} $1 2>/dev/null
+ ERRNUM=$?
+ if test x"$ERRNUM" != x0
+ then
+ echo "EXIT CODE: ${ERRNUM}"
+ rval=1
+ fi
+ fi
+}
+
+log_stat_msg () {
+case "$1" in
+ 0)
+ echo "Service $NAME: Running";
+ break;
+ ;;
+ 1)
+ echo "Service $NAME: Stopped and /var/run pid file exists";
+ break;
+ ;;
+ 3)
+ echo "Service $NAME: Stopped";
+ break;
+ ;;
+ *)
+ echo "Service $NAME: Status unknown";
+ break;
+ ;;
+esac
+}
+
+
+case "$1" in
+ 'start_msg')
+ echo "Starting the $NAME subsystem"
+ ;;
+
+ 'stop_msg')
+ echo "Stopping the $NAME subsystem"
+ ;;
+
+ 'start')
+ run_the_command start
+ exit $rval
+ ;;
+
+ stop)
+ run_the_command stop
+ #
+ # Remove a stale lockfile, if found
+ #
+ if test -f @mylockfile@; then
+ /bin/rm -f @mylockfile@
+ fi
+ /bin/rm -f @mylockdir@/${NAME}.sock
+ exit $rval
+ ;;
+
+ restart)
+ run_the_command restart
+ exit $rval
+ ;;
+
+ reload|force-reload)
+ run_the_command reload
+ exit $rval
+ ;;
+
+ status)
+ ${DAEMON} status
+ ERRNUM=$?
+ log_stat_msg ${ERRNUM}
+ exit ${ERRNUM}
+ ;;
+
+ *)
+ echo "Usage: @install_name@ {start_msg|stop_msg|start|stop|restart|reload|status}"
+ exit 1
+ ;;
+esac
+
+exit $rval
diff --git a/init/samhain.startIRIX.in b/init/samhain.startIRIX.in
new file mode 100644
index 0000000..2bcab17
--- /dev/null
+++ b/init/samhain.startIRIX.in
@@ -0,0 +1,88 @@
+#! /bin/sh
+
+
+PATH=/usr/sbin:/usr/bin:/sbin
+export PATH
+
+rval=0
+
+DAEMON=@sbindir@/@install_name@
+NAME=@install_name@
+
+if /sbin/chkconfig verbose; then
+ verbose=1
+else
+ verbose=0
+fi
+
+log_stat_msg () {
+case "$1" in
+ 0)
+ echo "Service $NAME: Running";
+ break;
+ ;;
+ 1)
+ echo "Service $NAME: Stopped and /var/run pid file exists";
+ break;
+ ;;
+ 3)
+ echo "Service $NAME: Stopped";
+ break;
+ ;;
+ *)
+ echo "Service $NAME: Status unknown";
+ break;
+ ;;
+esac
+}
+
+case "$1" in
+
+ 'start')
+ test $verbose = 1 && echo "Starting $NAME"
+ $DAEMON start
+ rval=$?
+ exit $rval
+ ;;
+
+ stop)
+ test $verbose = 1 && echo "Stopping $NAME"
+ $DAEMON stop
+ rval=$?
+ #
+ # Remove a stale lockfile, if found
+ #
+ if test -f @mylockfile@; then
+ /bin/rm -f @mylockfile@
+ fi
+ exit $rval
+ ;;
+
+ restart)
+ test $verbose = 1 && echo "Restarting $NAME"
+ $DAEMON restart
+ rval=$?
+ exit $rval
+ ;;
+
+ reload|force-reload)
+ test $verbose = 1 && echo "Reloading $NAME"
+ $DAEMON reload
+ rval=$?
+ exit $rval
+ ;;
+
+ status)
+ ${DAEMON} status
+ ERRNUM=$?
+ log_stat_msg ${ERRNUM}
+ exit ${ERRNUM}
+ ;;
+
+ *)
+ echo "Usage: @install_name@ {start|stop|restart|reload}"
+ exit 1
+ ;;
+esac
+
+exit $rval
diff --git a/init/samhain.startLSB.in b/init/samhain.startLSB.in
new file mode 100755
index 0000000..2f23f99
--- /dev/null
+++ b/init/samhain.startLSB.in
@@ -0,0 +1,127 @@
+#! /bin/sh
+
+### BEGIN INIT INFO
+# Provides: @install_name@
+# Required-Start: $syslog $network
+# Required-Stop: $syslog $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Keep an eye on stuff
+# Description: Keep an eye on stuff
+### END INIT INFO
+
+
+# source function library
+if test -f /lib/lsb/init-functions; then
+. /lib/lsb/init-functions
+else
+ echo "File /lib/lsb/init-functions not found"
+ exit 5
+fi
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+DAEMON=@sbindir@/@install_name@
+NAME=@install_name@
+
+if test ! -f ${DAEMON}; then
+ log_failure_msg "Service $NAME is not installed"
+ exit 5
+fi
+
+if test "x$2" != "x" && test "x$1" != "xstatus"; then
+ log_failure_msg "Excess arguments $@"
+ exit 2
+fi
+
+log_sh_msg () {
+case "$1" in
+ 0)
+ log_success_msg "Service $NAME $2"
+ break;
+ ;;
+ 1)
+ log_failure_msg "Service $NAME: Error"
+ break;
+ ;;
+ 4)
+ log_failure_msg "Service $NAME: Permission denied"
+ break;
+ ;;
+ 5)
+ log_failure_msg "Service $NAME is not installed"
+ break;
+ ;;
+ 7)
+ log_failure_msg "Service $NAME is not running"
+ break;
+ ;;
+ *)
+ log_failure_msg "Service $NAME: Error"
+ break;
+ ;;
+esac
+}
+
+log_stat_msg () {
+case "$1" in
+ 0)
+ echo "Service $NAME: Running";
+ break;
+ ;;
+ 1)
+ echo "Service $NAME: Stopped and /var/run pid file exists";
+ break;
+ ;;
+ 3)
+ echo "Service $NAME: Stopped";
+ break;
+ ;;
+ *)
+ echo "Service $NAME: Status unknown";
+ break;
+ ;;
+esac
+}
+
+case "$1" in
+ start)
+ ${DAEMON} start
+ ERRNUM=$?
+ SH_ACT="started"
+ ;;
+ stop)
+ ${DAEMON} stop
+ ERRNUM=$?
+ if test -f @mylockfile@; then
+ /bin/rm -f @mylockfile@
+ fi
+ if test -S @mylockdir@/${NAME}.sock; then
+ /bin/rm -f @mylockdir@/${NAME}.sock
+ fi
+ SH_ACT="stopped"
+ ;;
+ restart)
+ ${DAEMON} restart
+ ERRNUM=$?
+ SH_ACT="restarted"
+ ;;
+ reload|force-reload)
+ ${DAEMON} reload
+ ERRNUM=$?
+ SH_ACT="reloaded"
+ ;;
+ status)
+ ${DAEMON} status
+ ERRNUM=$?
+ log_stat_msg ${ERRNUM}
+ exit ${ERRNUM}
+ ;;
+ *)
+ log_warning_msg "Usage: @install_name@ {start|stop|restart|(force-)reload|status}"
+ exit 2
+ ;;
+esac
+
+log_sh_msg ${ERRNUM} "${SH_ACT}"
+exit ${ERRNUM}
diff --git a/init/samhain.startLinux.in b/init/samhain.startLinux.in
new file mode 100644
index 0000000..81c5e92
--- /dev/null
+++ b/init/samhain.startLinux.in
@@ -0,0 +1,315 @@
+#!/bin/bash
+
+# chkconfig: 2345 99 10
+# description: File Integrity Checking Daemon
+#
+# processname: @install_name@
+# config : @myconffile@
+# logfile : @mylogfile@
+# database: @mydatafile@
+#
+
+### BEGIN INIT INFO
+# Provides: @install_name@
+# Required-Start: $syslog $network
+# Required-Stop: $syslog $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Keep an eye on stuff
+# Description: Keep an eye on stuff
+### END INIT INFO
+
+# For Debian
+#
+FLAGS="defaults 99 10"
+
+NAME=@install_name@
+DAEMON=@sbindir@/@install_name@
+RETVAL=0
+VERBOSE=yes
+PIDFILE=@mylockfile@
+
+if [ -x $DAEMON ]; then
+ :
+else
+ echo "${0}: executable ${DAEMON} not found"
+ exit 0
+fi
+
+# Sort out sourcing in the distribution specific library functions
+# and the command to run them.
+if [ -f /etc/redhat-release ]; then
+ . /etc/init.d/functions
+ DISTRO=redhat
+elif [ -f /etc/mandrake-release ]; then
+ . /etc/init.d/functions
+ DISTRO=redhat
+elif [ -f /etc/yellowdog-release ]; then
+ . /etc/init.d/functions
+ DISTRO=redhat
+elif [ -f /etc/SuSE-release ]; then
+ . /etc/rc.config
+ . /etc/rc.status
+ # Determine the base and follow a runlevel link name.
+ base=${0##*/}
+ link=${base#*[SK][0-9][0-9]}
+ # Force execution if not called by a runlevel directory.
+ test $link = $base && START_@INSTALL_NAME@=yes
+ # Check whether START_@INSTALL_NAME@ is in /etc/rc.config
+ # If yes, abort unless its value is 'yes'
+ if test "x${START_@INSTALL_NAME@}" != "x"; then
+ test "${START_@INSTALL_NAME@}" = yes || exit 0
+ fi
+ return=$rc_done
+ DISTRO=suse
+elif [ -f /etc/debian_version ]; then
+ # . /etc/default/rcS
+ set -e
+ DISTRO=debian
+elif [ -f /etc/slackware-version ]; then
+ # . /etc/rc.d/rc.sysvinit
+ DISTRO=generic
+else
+ DISTRO=generic
+fi
+
+debian_end()
+{
+ if [ $RETVAL -eq 0 ];
+ then
+ echo "."
+ else
+ echo " failed."
+ fi
+}
+
+# Generic function "a la Red Hat"
+MOVE_TO_COL="echo -en \\033[60G"
+SETCOLOR_SUCCESS="echo -en \\033[1;32m"
+SETCOLOR_FAILURE="echo -en \\033[1;31m"
+SETCOLOR_NORMAL="echo -en \\033[0;39m"
+
+echo_success() {
+ $MOVE_TO_COL
+ echo -n "[ "
+ $SETCOLOR_SUCCESS
+ echo -n "OK"
+ $SETCOLOR_NORMAL
+ echo -n " ]"
+ echo -ne "\r"
+ echo ""
+}
+
+echo_failure() {
+ $MOVE_TO_COL
+ echo -n "["
+ $SETCOLOR_FAILURE
+ echo -n "FAILED"
+ $SETCOLOR_NORMAL
+ echo -n "]"
+ echo -ne "\r"
+ echo ""
+}
+
+
+# echo OK in green if is success, FAILED in red is failed
+generic_end()
+{
+ if [ $RETVAL -eq 0 ];
+ then
+ echo_success
+ else
+ echo_failure
+ fi
+}
+
+log_stat_msg () {
+case "$1" in
+ 0)
+ echo "Service $NAME: Running";
+ ;;
+ 1)
+ echo "Service $NAME: Stopped and /var/run pid file exists";
+ ;;
+ 3)
+ echo "Service $NAME: Stopped";
+ ;;
+ *)
+ echo "Service $NAME: Status unknown";
+ ;;
+esac
+}
+
+
+case "$1" in
+ start)
+ #
+ # Remove a stale PID file, if found
+ #
+ if test -f ${PIDFILE}; then
+ /bin/rm -f ${PIDFILE}
+ fi
+ #
+ case "$DISTRO" in
+ debian)
+ echo -n "Starting ${NAME}"
+ ( /sbin/start-stop-daemon --start --oknodo --quiet --exec $DAEMON )
+ RETVAL=$?
+ debian_end
+ ;;
+ redhat)
+ if [ -f /etc/sysconfig/${NAME} ]; then
+ . /etc/sysconfig/${NAME}
+ fi
+ echo -n $"Starting ${NAME}: "
+ if [ -n "$OPTIONS" ]; then
+ daemon $DAEMON $OPTIONS
+ else
+ daemon $DAEMON
+ fi
+ RETVAL=$?
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/${NAME}
+ echo
+ ;;
+ suse)
+ echo -n "Starting service ${NAME}"
+ /sbin/startproc $DAEMON
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ return=$rc_done
+ else
+ return=$rc_failed
+ fi
+ echo -e "$return"
+ ;;
+ *)
+ echo -n "Starting ${NAME} ... "
+ $DAEMON start
+ RETVAL=$?
+ generic_end
+ ;;
+ esac
+ exit $RETVAL
+ ;;
+
+ stop)
+ case "$DISTRO" in
+ debian)
+ echo -n "Stopping $NAME"
+ ( /sbin/start-stop-daemon --stop --oknodo --quiet --exec $DAEMON )
+ RETVAL=$?
+ debian_end
+ ;;
+ redhat)
+ echo -n $"Stopping ${NAME}: "
+ killproc ${NAME}
+ RETVAL=$?
+ rm -f /var/lock/subsys/${NAME}
+ echo
+ ;;
+ suse)
+ echo -n "Shutting down service ${NAME}"
+ /sbin/killproc -TERM $DAEMON
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ return=$rc_done
+ else
+ return=$rc_failed
+ fi
+ echo -e "$return"
+ ;;
+ *)
+ if test x"$VERBOSE" != xno; then
+ echo -n "Stopping ${NAME} ... "
+ fi
+ $DAEMON stop
+ RETVAL=$?
+ generic_end
+ ;;
+ esac
+ #
+ # Remove a stale PID file, if found
+ #
+ if test -f ${PIDFILE}; then
+ /bin/rm -f ${PIDFILE}
+ fi
+ if test -S @mylockdir@/${NAME}.sock; then
+ /bin/rm -f @mylockdir@/${NAME}.sock
+ fi
+ ;;
+
+ restart)
+ $0 stop
+ sleep 3
+ $0 start
+ RETVAL=$?
+ ;;
+
+ reload|force-reload)
+ case "$DISTRO" in
+ debian)
+ echo -n "Reloading $NAME configuration files"
+ ( /sbin/start-stop-daemon --stop --signal 1 --quiet --exec $DAEMON )
+ RETVAL=$?
+ debian_end
+ ;;
+ redhat)
+ echo -n $"Reloading ${NAME} configuration: "
+ killproc ${NAME} -HUP
+ RETVAL=$?
+ echo
+ ;;
+ suse)
+ echo -n "Reload service ${NAME}"
+ /sbin/killproc -HUP $DAEMON
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ return=$rc_done
+ else
+ return=$rc_failed
+ fi
+ echo -e "$return"
+ ;;
+ *)
+ echo -n "Reloading ${NAME} ... "
+ $DAEMON reload
+ RETVAL=$?
+ generic_end
+ ;;
+ esac
+ ;;
+
+ status)
+ case "$DISTRO" in
+ redhat)
+ status ${NAME}
+ exit $?
+ ;;
+ suse)
+ echo -n "Checking for service ${NAME}: "
+ /sbin/checkproc $DAEMON
+ RETVAL=$?
+ if [ $RETVAL -eq 0 ]; then
+ return="OK"
+ else
+ return="No process"
+ fi
+ echo "$return"
+ exit $RETVAL
+ ;;
+ *)
+ $DAEMON status
+ ERRNUM=$?
+ log_stat_msg ${ERRNUM}
+ exit ${ERRNUM}
+ ;;
+ esac
+ ;;
+
+ *)
+ echo "$0 usage: {start|stop|status|restart|reload}"
+ exit 1
+ ;;
+esac
+
+exit $RETVAL
diff --git a/init/samhain.startMACOSX.in b/init/samhain.startMACOSX.in
new file mode 100644
index 0000000..ea76a93
--- /dev/null
+++ b/init/samhain.startMACOSX.in
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. /etc/rc.common
+
+StartService() {
+
+ ConsoleMessage "Starting service @install_name@."
+ @sbindir@/@install_name@ start
+
+}
+
+StopService() {
+
+ ConsoleMessage "Stopping service @install_name@."
+ @sbindir@/@install_name@ stop
+
+}
+
+RestartService() {
+
+ ConsoleMessage "Restarting service @install_name@."
+ @sbindir@/@install_name@ restart
+
+}
+
+
+RunService "$1"
diff --git a/init/samhain.startSolaris.in b/init/samhain.startSolaris.in
new file mode 100644
index 0000000..bbc3c42
--- /dev/null
+++ b/init/samhain.startSolaris.in
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+SBINDIR=@sbindir@
+NAME=@install_name@
+
+if [ ! -f ${SBINDIR}/${NAME} ]; then
+ exit 0
+fi
+
+
+log_stat_msg() {
+case "$1" in
+ 0)
+ echo "Service $NAME: Running";
+ break;
+ ;;
+ 1)
+ echo "Service $NAME: Stopped and /var/run pid file exists";
+ break;
+ ;;
+ 3)
+ echo "Service $NAME: Stopped";
+ break;
+ ;;
+ *)
+ echo "Service $NAME: Status unknown";
+ break;
+ ;;
+esac
+}
+
+
+case "$1" in
+ start)
+ echo "${NAME} starting."
+ ;;
+ stop)
+ echo "${NAME} stopping."
+ ;;
+ restart)
+ echo "${NAME} restarting."
+ ;;
+ reload|force-reload)
+ echo "${NAME} reloading."
+ ;;
+ status)
+ ${SBINDIR}/${NAME} $1
+ ERRNUM=$?
+ log_stat_msg ${ERRNUM}
+ exit ${ERRNUM}
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|reload|status}"
+ exit 1
+ ;;
+esac
+
+${SBINDIR}/${NAME} $1
+
+status=$?
+
+
+if [ $status != 0 ]; then
+ echo $status
+ exit 1
+fi
+
+case "$1" in
+ stop)
+ if test -f @mylockfile@; then
+ /bin/rm -f @mylockfile@
+ fi
+ /bin/rm -f @mylockdir@/${NAME}.sock
+ ;;
+ *)
+ exit 0
+ ;;
+esac
+
+exit 0
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..e843669
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,250 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/man/samhain.8 b/man/samhain.8
new file mode 100644
index 0000000..c02280f
--- /dev/null
+++ b/man/samhain.8
@@ -0,0 +1,880 @@
+.TH SAMHAIN 8 "26 June 2015" "" "Samhain manual"
+.SH NAME
+samhain \- check file integrity
+.SH SYNOPSIS
+.SS "INITIALIZING, UPDATING, AND CHECKING"
+.PP
+
+.B samhain
+{
+.I \-t init|\-\-set\-checksum\-test=init
+} [\-\-init2stdout] [\-r DEPTH|\-\-recursion=DEPTH] [log-options]
+
+.B samhain
+{
+.I \-t update|\-\-set\-checksum\-test=update
+} [\-D | \-\-daemon | \-\-foreground] [\-\-forever] [\-r DEPTH|\-\-recursion=DEPTH] [log-options]
+
+.B samhain
+{
+.I \-t check|\-\-set\-checksum\-test=check
+} [\-D | \-\-daemon | \-\-foreground] [\-\-forever] [\-r DEPTH,\-\-recursion=DEPTH] [log-options]
+
+.B samhain
+[ \-p threshold ] {
+.I \-\-verify\-database=database
+}
+
+.B samhain
+[ \-p threshold ] {
+.I \-\-create\-database=file\-list
+}
+
+
+
+.SS "LISTING THE DATABASE"
+.PP
+
+.B samhain
+[\-a | \-\-full\-detail]
+[\-\-delimited]
+[\-\-binary]
+[\-\-list\-filter=file]
+\-d
+.IR file |
+.RI \-\-list\-database= file
+
+.SS "VERIFYING AN AUDIT TRAIL"
+.PP
+
+.B samhain
+[\-j | \-\-just\-list]
+\-L
+.IR logfile |
+.RI \-\-verify\-log= logfile
+
+.B samhain
+\-M
+.IR mailbox |
+.RI \-\-verify\-mail= mailbox
+
+
+.SS "MISCELLANEOUS"
+.PP
+
+.B samhain
+.RI \-\-server\-port= portnumber
+
+.B samhain
+\-H
+.I string
+|
+.RI \-\-hash\-string= string
+
+.B samhain
+\-c | \-\-copyright
+
+.B samhain
+\-v | \-\-version
+
+.B samhain
+\-h | \-\-help
+
+.B samhain
+\-V key@/path/to/executable | \-\-add\-key=key@/path/to/executable
+
+.SS "SERVER STARTUP"
+.PP
+
+.B yule
+[\-q | \-\-qualified]
+[
+.RI \-\-chroot= chrootdir ]
+[\-D | \-\-daemon | \-\-foreground]
+[log-options]
+
+.SS "SERVER MISCELLANEOUS"
+.PP
+
+.B yule
+[\-P
+.I password
+|
+.RI \-\-password= password ]
+
+.B yule
+[\-G | \-\-gen-password]
+
+.SS "LOG OPTIONS"
+.PP
+
+[\-s
+.I threshold
+|
+.RI \-\-set\-syslog\-severity= threshold ]
+[\-l
+.I threshold
+|
+.RI \-\-set\-log\-severity= threshold ]
+[\-m
+.I threshold
+|
+.RI \-\-set\-mail\-severity= threshold ]
+[\-e
+.I threshold
+|
+.RI \-\-set\-export\-severity= threshold ]
+[\-p
+.I threshold
+|
+.RI \-\-set\-print\-severity= threshold ]
+[\-x
+.I threshold
+|
+.RI \-\-set\-external\-severity= threshold ]
+[
+.RI \-\-set\-prelude\-severity= threshold ]
+[
+.RI \-\-set\-database\-severity= threshold ]
+[
+.RI \-\-enable\-trace ]
+[
+.RI \-\-trace\-logfile= tracefile ]
+
+
+
+.SH WARNING
+.PP
+The information in this man page is not always up to date.
+The authoritative documentation is the user manual.
+
+.SH DESCRIPTION
+.PP
+.B samhain
+is a file integrity / intrusion detection system both for single hosts
+and networks.
+It consists of a monitoring application
+.RB ( samhain )
+running on
+individual hosts, and (optionally) a central log server
+.RB ( yule ).
+Currently, samhain can monitor the
+integrity of files/directories, and (optionally) also
+check for kernel rootkits
+(Linux and FreeBSD only), search the disk for SUID/SGID,
+and watch for login/logout events.
+.PP
+.B samhain/yule
+can log by email, to a tamper-resistant, signed log file,
+to syslog, to the Prelude IDS, to a MySQL/PostgreSQL/Oracle database,
+and/or to stdout
+.RI ( /dev/console
+if run as daemon).
+.B samhain/yule
+can run as a daemon, and can use a time server instead of the host's
+system clock. Most of the functionality is defined by a
+configuration file that is read at startup.
+.PP
+Most options of these usually would be set in the configuration file.
+Options given on the command line will override
+those in the configuration file.
+
+.SS "OPTIONS FOR INITIALIZING, UPDATING, AND CHECKING"
+.PP
+
+.B samhain
+.I "\-t init, \-\-set\-checksum-test=init"
+.RI [ options ]
+
+Initialize the database of file signatures. The path to the
+database is compiled in, and initializing will
+.B append
+to the respective file (or create it, if it does not exist).
+.B "It is ok to append to e.g. a JPEG image, but it is an error"
+.B "to append to an already existing file signature database."
+.PP
+.TP
+[\-\-init2stdout]
+Write the database to stdout.
+.TP
+[\-r DEPTH|\-\-recursion=DEPTH]
+Set the (global) recursion depth.
+
+.PP
+.B samhain
+.I "\-t update, \-\-set\-checksum-test=update"
+.RI [ options ]
+
+Update the database of file signatures. The path to the
+database is compiled in, and updating will
+.B overwrite
+the database, starting from the start of the database (which may not be
+identical to the start of the file \- see above).
+.PP
+.TP
+[\-r DEPTH|\-\-recursion=DEPTH]
+Set the (global) recursion depth.
+.TP
+[\-D|\-\-daemon]
+Run as daemon. File checks are performed as specified by the timing
+options in the configuration file. Updates are saved after each file check.
+.TP
+[\-\-foreground]
+Run in the foreground. This will cause samhain to exit after the update,
+unless the option
+.I "\-\-forever"
+is used.
+.TP
+[\-\-forever]
+If not running as daemon, do not exit after finishing the update, but
+loop forever, and perform checks with corresponding database updates
+according to the timing options in the
+configuration file.
+.TP
+[\-i|\-\-interactive]
+Run update in interactive mode.
+.TP
+[\-\-listfile=PATH]
+Run the update with a list of 'good' filepaths given in file (one path per line).
+
+
+.PP
+.B samhain
+.I "\-t check, \-\-set\-checksum-test=check"
+.RI [ options ]
+
+Check the filesystem against the database of file signatures.
+The path to the database is compiled in.
+.PP
+.TP
+[\-r DEPTH|\-\-recursion=DEPTH]
+Set the (global) recursion depth.
+.TP
+[\-D|\-\-daemon]
+Run as daemon. File checks are performed as specified by the timing
+options in the configuration file.
+.TP
+[\-\-foreground]
+Run in the foreground. This will cause samhain to exit after the file check,
+unless the option
+.I "\-\-forever"
+is used.
+.TP
+[\-\-forever]
+If not running as daemon, do not exit after finishing the check, but
+loop forever, and perform checks according to the timing options in the
+configuration file.
+
+.PP
+.B samhain
+[ \-p\ threshold ]
+.I "\-\-verify\-database=database"
+
+Check the filesystem against the database given as argument,
+and exit with an appropriate exit status. The configuration file
+will
+.B not
+be read.
+
+.PP
+.B samhain
+[ \-p\ threshold ]
+.I "\-\-create\-database=file\-list"
+
+Initialize a database from the given file list.
+The configuration file
+will
+.B not
+be read. The policy used will be
+.I ReadOnly.
+File content will be stored for a file
+if its path in the list is preceded with a
+.B +
+sign.
+
+.SS "OPTIONS FOR LISTING THE DATABASE"
+.PP
+
+.B samhain
+[\-a | \-\-full\-detail]
+[\-\-delimited]
+\-d
+.IR file |
+.RI \-\-list\-database= file
+
+List the entries in the file signature database in a
+.B ls \-l
+like format.
+.PP
+.TP
+[\-a | \-\-full\-detail]
+List all informations for each file, not only those you would get
+with ls \-l. Must precede the \-d option.
+.TP
+[\-\-delimited]
+List all informations for each file, in a comma-separated format.
+Must precede the \-d option.
+.TP
+[\-\-binary]
+List data in the binary format of the database, thus writing another
+database.
+Must precede the \-d option.
+.TP
+.RI [\-\-list\-filter= file ]
+Filter the output of the database listing by a list of files given
+in a text file. Together with \-\-binary this allows to write a
+partial database. Must precede the \-d option.
+.TP
+.RI [\-\-list\-file= file ]
+List the literal content of the given file as stored in the database.
+Content is not stored by default, must be enabled in the runtime
+configuration file. Must precede the \-d option.
+
+.SS "OPTIONS TO VERIFY AN AUDIT TRAIL"
+.PP
+
+These options will only work, if the executable used for verifying the
+audit trail is compiled with the same \-\-enable\-base=... option as the
+executable of the reporting process.
+
+.B samhain
+[\-j | \-\-just\-list]
+\-L
+.IR logfile |
+.RI \-\-verify\-log= logfile
+
+Verify the integrity of a signed logfile. The signing key is
+auto\-generated on startup, and sent by email.
+.B samhain
+will ask for the key. Instead of entering the key, you can also enter
+the path to the mailbox holding the respective email message.
+.PP
+.TP
+[\-j | \-\-just\-list]
+Just list the logfile, do not verify it. This option must come
+.BR first .
+It is mainly intended for listing the content of an obfuscated logfile, if
+.B samhain
+is compiled with the
+.B stealth
+option.
+
+.B samhain
+\-M
+.IR mailbox |
+.RI \-\-verify\-mail= mailbox
+
+Verify the integrity of the email reports from samhain. All reports must be
+in the same file.
+
+.SS "MISCELLANEOUS OPTIONS"
+.PP
+
+.B samhain
+.RI \-\-server\-port= portnumber
+
+Choose the port on the server host to which the client will connect.
+
+.B samhain
+\-H
+.I string
+|
+.RI \-\-hash\-string= string
+
+Compute the TIGER192 checksum of a string. If the string starts with
+a '/', it is considered as a pathname, and the checksum of the corresponding
+file will be computed.
+
+.B samhain
+\-c | \-\-copyright
+
+Print the copyright statement.
+
+.B samhain
+\-v | \-\-version
+
+Show version and compiled-in options.
+
+.B samhain
+\-h | \-\-help
+
+Print supported command line options (depending on compilation options).
+
+.B samhain
+\-V key@/path/to/executable | \-\-add\-key=key@/path/to/executable
+
+See the section "SECURITY" below.
+
+.SS "SERVER STARTUP OPTIONS"
+.PP
+
+.B yule
+[\-q | \-\-qualified]
+[
+.RI \-\-chroot= chrootdir ]
+[\-D | \-\-daemon | \-\-foreground]
+[log-options]
+
+Start the server, which is named
+.B yule
+by default. If the server is started with superuser privileges,
+it will drop them after startup.
+.PP
+.TP
+[\-q | \-\-qualified]
+Log client hostnames with fully qualified path. The default is to
+log only the leftmost domain label (i.e. the hostname).
+.TP
+[
+.RI \-\-chroot= chrootdir ]
+Chroot to the listed directory after startup.
+.TP
+[\-D | \-\-daemon]
+Run as daemon.
+.TP
+[\-\-foreground]
+Run in the foreground.
+
+
+.SS "MISCELLANEOUS SERVER OPTIONS"
+.PP
+
+.B yule
+[\-G | \-\-gen-password]
+
+Generate a random 8\-byte password and print it out in hexadecimal notation.
+
+
+.B yule
+[\-P
+.I password
+|
+.RI \-\-password= password ]
+
+Use the given
+.I password
+and generate an entry suitable for the [Clients] section of the
+configuration file.
+
+.SS "LOGGING OPTIONS"
+.PP
+
+Depending on the compilation options, some logging facilities may not
+be available in your executable.
+.PP
+.TP
+.I "\-s threshold, \-\-set\-syslog\-severity=threshold"
+Set the threshold for logging events via syslogd(8).
+Possible values are
+.IR debug ,
+.IR info ,
+.IR notice ,
+.IR warn ,
+.IR mark ,
+.IR err ,
+.IR crit ,
+.IR alert ,
+and
+.IR none .
+By default, everything equal to and above the threshold will be logged.
+Time stamps have the priority
+.IR warn ,
+system\-level errors have the priority
+.IR err ,
+and important start\-up messages the priority
+.IR alert .
+The signature key for the log file will never be logged to syslog or the
+log file itself.
+.TP
+.I "\-l threshold, \-\-set\-log\-severity=threshold"
+Set the threshold for logging events to the log file.
+.TP
+.I "\-m threshold, \-\-set\-mail\-severity=threshold"
+Set the threshold for logging events via e\-mail.
+.TP
+.I "\-e threshold, \-\-set\-export\-severity=threshold"
+Set the threshold for forwarding events via TCP to a log server.
+.TP
+.I "\-x threshold, \-\-set\-extern\-severity=threshold"
+Set the threshold for calling external logging programs/scripts (if any are
+defined in the configuration file).
+.TP
+.I "\-p threshold, \-\-set\-print\-severity=threshold"
+Set the threshold for logging events to stdout.
+If
+.B samhain
+runs as a daemon, this is redirected to /dev/console.
+.TP
+.I "\-\-set\-prelude\-severity=threshold"
+Set the threshold for logging events to the Prelude IDS.
+.TP
+.I "\-\-set\-database\-severity=threshold"
+Set the threshold for logging events to the MySQL/PostgreSQL/Oracle
+database.
+
+
+
+.SH SIGNALS
+.TP
+.I SIGUSR1
+Switch on/off maximum verbosity for console output.
+.TP
+.I SIGUSR2
+Suspend/continue the process, and
+(on suspend) send a message
+to the server. This message has the same priority as timestamps.
+This signal
+allows to run
+.I samhain -t init -e none
+on the client
+to regenerate the database, with download of the configuration file
+from the server, while the daemon is suspended (normally you would get
+errors because of concurrent access to the server by two processes from
+the
+.IR "same host" ")."
+.TP
+.I SIGHUP
+Reread the configuration file.
+.TP
+.I SIGTERM
+Terminate.
+.TP
+.I SIGQUIT
+Terminate after processing all pending requests from clients.
+.TP
+.I SIGABRT
+Unlock the log file, pause for three seconds, then proceed,
+eventually re-locking the log file and starting a fresh audit trail
+on next access.
+.TP
+.I SIGTTOU
+Force a file check (only client/standalone, and only in daemon mode).
+
+
+.SH DATABASE
+The database (default name
+.IR samhain_file )
+is a binary file, which can be created or updated using the
+.B \-t
+.I init
+or the
+.B \-t
+.I update
+option.
+If you use
+.B \-t
+.IR init ,
+you need to
+.I remove
+the old database first,
+otherwise the new version will be
+.I appended
+to the old one.
+The file may be (clear text) signed by PGP/GnuPG.
+.br
+It is recommended to use GnuPG with the options
+.B gpg
+.I -a --clearsign --not-dash-escaped
+.br
+.B samhain
+will check the signature, if compiled with support for that.
+.PP
+At startup
+.B samhain
+will compute the checksum of the database, and verify it for
+each further access. This checksum is not stored on disk (i.e. is lost
+after program termination), as there is no secure way to store it.
+
+.SH LOG FILE
+.PP
+Each entry in the log file has the format
+.BR "Severity : [Timestamp] Message" ,
+where the timestamp may be obtained from a time server rather than from
+the system clock, if
+.B samhain
+has been compiled with support for this.
+Each entry is followed by a
+.IR signature ,
+which is computed as
+.BR "Hash(Entry Key_N)" ,
+and
+.B Key_N
+is computed as
+.BR "Hash(Key_N\-1)" ,
+i.e. only knowledge of the first signature key in this chain allows to
+verify the integrity of the log file. This first key is autogenerated
+and e\-mailed to the designated recipient.
+.PP
+The default name of the log file is
+.IR samhain_log .
+To prevent multiple instances of
+.B samhain
+from writing to the same log file, the log file is locked by creating a
+.IR "lock file" ,
+which is normally deleted at program termination.
+The default name of the
+.I "lock file"
+is
+.IR samhain.lock .
+If
+.B samhain
+is terminated abnormally, i.e. with kill \-9,
+a stale lock file might remain, but usually
+.B samhain
+will be able to recognize that and remove the stale lock file
+on the next startup.
+.PP
+.SH EMAIL
+.PP
+E\-mails are sent (using built-in SMTP code)
+to one recipient only.
+The subject line contains timestamp
+and hostname, which are repeated in the message body.
+The body of the mail contains a line with a
+.I signature
+similar to that in the log file, computed from the message and a
+key. The key is iterated by a hash chain, and the initial
+key is revealed in the first email sent.
+Obviously, you have to believe that this first e\-mail is
+authentical ...
+.PP
+.SH CLIENT/SERVER USAGE
+.PP
+To monitor several machines, and collecting data by a central log server,
+.B samhain
+may be compiled as a client/server application. The log server
+.RB ( yule )
+will accept connection
+requests from registered clients only. With each client, the server will first
+engage in a challenge/response protocol for
+.I authentication
+of the client and
+.I establishing
+a
+.IR "session key" .
+.PP
+This protocol requires on the client side a
+.IR "password" ,
+and on the server side a
+.IR "verifier"
+that is computed from the
+.IR "password" .
+.PP
+To
+.I register
+a client, simply do the following:
+.br
+First, with the included utility program
+.B samhain_setpwd
+re\-set the compiled\-in default password of the
+client executable to your preferred
+value (with no option, a short usage help is printed).
+To allow for non-printable chars, the new value
+must be given as a 16\-digit hexadecimal string
+(only 0123456789ABCDEF in string), corresponding to an 8-byte password.
+.br
+Second, after re\-setting the password in the client executable,
+you can use the server's convenience function
+.B yule
+.B \-P
+.I password
+that will take as input the (16\-digit hex) password,
+compute the corresponding verifier, and outputs a default configuration file
+entry to register the client.
+.br
+Third, in the configuration file for the server, under the [Clients] section,
+enter
+the suggested registration entry of the form
+.IR "Client=hostname@salt@verifier" ,
+where
+.I hostname
+must be the (fully qualified) hostname of the machine on
+which the client will run.
+.B "Don't forget to reload the server configuration thereafter."
+.PP
+If a connection attempt is made, the server will lookup the entry for
+the connecting host, and use the corresponding value for the
+.I verifier
+to engage in the session key exchange. Failure to verify the client's
+response(s) will result in aborting the connection.
+.PP
+.SH STEALTH
+.PP
+.B samhain
+may be compiled with support for a
+.I stealth
+mode of operation, meaning that
+the program can be run without any obvious trace of its presence
+on disk. The supplied facilities are simple - they are more
+sophisticated than just running the program under a different name,
+and might thwart efforts using 'standard' Unix commands,
+but they will not resist a search using dedicated utilities.
+.PP
+In this mode, the runtime executable will hold no
+printable strings, and the configuration file is expected to be
+a postscript file with
+.I uncompressed
+image data, wherein
+the configuration data are hidden by steganography.
+To create such a file from an existing image, you may use e.g.
+the program
+.BR convert (1),
+which is part of the
+.BR ImageMagick (1)
+package, such as:
+.B "convert +compress"
+.IR "ima.jpg ima.ps" .
+.PP
+To hide/extract the configuration data within/from the postscript file,
+a utility program
+.B samhain_stealth
+is provided.
+Use it without options to get help.
+.PP
+Database and log file may be e.g. existing image files, to which
+data are appended, xor'ed with some constant to mask them as binary data.
+.PP
+The user is responsible by herself for re-naming the compiled
+executable(s) to unsuspicious names, and choosing (at compile time)
+likewise unsuspicious names for config file, database, and log (+lock) file.
+.PP
+.SH SECURITY
+.PP
+For security reasons,
+.B samhain
+will not write log or data files in a directory, remove the lock file,
+or read the configuration file, if any element
+in the path is owned or writeable by an untrusted user (including
+group-writeable files with untrusted users in the group, and world-writeable
+files).
+.br
+.I root
+and the
+.I effective
+user are always trusted. You can add more users in the configuration file.
+.PP
+Using a
+.I "numerical host address"
+in the e\-mail address is more secure than
+using the hostname (does not require
+DNS lookup).
+.PP
+If you use a
+.I precompiled
+.B samhain
+executable (e.g. from a
+binary distribution), in principle a prospective intruder could easily
+obtain a copy of the executable and analyze it in advance. This will
+enable her/him to generate fake audit trails and/or generate
+a trojan for this particular binary distribution.
+.br
+For this reason, it is possible for the user to add more key material into
+the binary executable. This is done with the command:
+.PP
+.BI "samhain " \-\-add\-key=key@/path/to/executable
+.PP
+This will read the file
+.I /path/to/executable, add the key
+.I key,
+which should not contain a '@' (because it has a special meaning, separating
+key from path), overwrite any key previously set by this command, and
+write the new binary to the location
+.I /path/to/executable.out
+(i.e. with .out appended). You should then copy the new binary to the location
+of the old one (i.e. overwrite the old one).
+.PP
+.B Note that using a precompiled samhain executable from a binary
+.B package distribution is not recommended unless you add in key material as
+.B described here.
+
+.PP
+.SH NOTES
+.PP
+For initializing the key(s),
+.I "/dev/random"
+is used, if available. This is a
+device supplying cryptographically strong
+(non-deterministic) random noise. Because it is slow,
+.B samhain
+might appear to hang at startup. Doing some random things
+(performing rain dances, spilling coffee, hunting the mouse) might speed up
+things. If you do not have
+.IR "/dev/random" ,
+lots of statistics from
+.BR vmstat (8)
+and the like will be pooled and mixed by a hash function.
+.PP
+Some hosts might check whether the sender of the mail is valid.
+Use only
+.I "login names"
+for the sender.
+.br
+For sending mails, you may need to set a relay host for the sender domain
+in the configuration file.
+.PP
+.SH BUGS
+.PP
+Whoever has the original signature key may change the log file and send fake
+e\-mails. The signature keys are e\-mailed at program startup
+with a one\-time pad encryption.
+This should be safe against an eavesdropper on the network,
+but not against someone with read access to the binary,
+.I if
+she has caught
+the e\-mail.
+.PP
+.SH FILES
+.PP
+.I /etc/samhainrc
+.br
+.I /usr/local/man/man8/samhain.8
+.br
+.I /usr/local/man/man5/samhainrc.5
+.br
+.I /var/log/samhain_log
+.br
+.I /var/lib/samhain/samhain_file
+.br
+.I /var/lib/samhain/samhain.html
+.br
+.I /var/run/samhain.pid
+
+.SH SEE ALSO
+.PP
+.BR samhainrc (5)
+
+.SH AUTHOR
+.PP
+Rainer Wichmann (http://la\-samhna.de)
+.SH BUG REPORTS
+.PP
+If you find a bug in
+.BR samhain ,
+please send electronic mail to
+.IR support@la\-samhna.de .
+Please include your operating system and its revision, the version of
+.BR samhain ,
+what C compiler you used to compile it, your 'configure' options, and
+any information that you deem helpful.
+.PP
+.SH COPYING PERMISSIONS
+.PP
+Copyright (\(co) 1999, 2004 Rainer Wichmann
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual page provided the copyright notice and this permission
+notice are preserved on all copies.
+.ig
+Permission is granted to process this file through troff and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual page).
+..
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual page under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+
+
diff --git a/man/samhainrc.5 b/man/samhainrc.5
new file mode 100644
index 0000000..b30e67c
--- /dev/null
+++ b/man/samhainrc.5
@@ -0,0 +1,776 @@
+.TH SAMHAINRC 5 "Jul 29, 2004" "" "samhainrc manual"
+.SH NAME
+samhainrc \- samhain(8) configuration file
+
+.SH WARNING
+.PP
+The information in this man page is not always up to date.
+The authoritative documentation is the user manual.
+
+.SH DESCRIPTION
+.PP
+The configuration file for
+.BR samhain (8)
+is named
+.I samhainrc
+and located in
+.I /etc
+by default.
+.PP
+It contains several sections, indicated by headings in square brackets.
+Each section may hold zero or more
+.BI key= value
+pairs. Blank lines and lines starting with '#' are comments.
+Everything before the first section and after an
+.I "[EOF]"
+is ignored. The file may be (clear text) signed by PGP/GnuPG, and
+.B samhain
+may invoke GnuPG to check the signature
+if compiled with support for it.
+.PP
+Conditional inclusion of entries for some host(s) is
+supported via any number of
+.BI @ hostname /@ end
+directives.
+.BI @ hostname
+and
+.BI @ end
+must each be on separate lines. Lines in between will only be
+read if
+.I "hostname"
+(which may be a regular expression) matches the local host.
+.PP
+Likewise, conditional inclusion of entries based on system type is
+supported via any number of
+.BI $ sysname:release:machine /$ end
+directives.
+.br
+.I "sysname:release:machine"
+can be inferred from
+.I "uname -srm"
+and may be a regular expression.
+.PP
+Filenames/directories to check may be wildcard patterns.
+.PP
+Options given on the command line will override
+those in the configuration file.
+The recognized sections in the configuration file are as follows:
+.PP
+Boolean options can be set with any of 1|true|yes or 0|false|no.
+.TP
+.I "[ReadOnly]"
+This section may contain
+.br
+.BI file= PATH
+and
+.br
+.BI dir= [depth]PATH
+entries for files and directories to check. All modifications except access
+times will be reported for these files.
+.I [depth] (use without brackets)
+is an optional parameter to define a per\-directory recursion
+depth.
+.TP
+.I "[LogFiles]"
+As above, but modifications of timestamps, file size, and signature will
+be ignored.
+.TP
+.I "[GrowingLogFiles]"
+As above, but modifications of file size will only be ignored if the size has
+.IR increased .
+.TP
+.I "[Attributes]"
+As above, but only modifications of ownership and access permissions
+will be checked.
+.TP
+.I "[IgnoreAll]"
+As above, but report no modifications for
+these files/directories. Access failures
+will still be reported.
+.TP
+.I "[IgnoreNone]"
+As above, but report all modifications for these files/directories,
+including access time.
+.TP
+.I "[User0]"
+.TP
+.I "[User1]"
+.TP
+.I "[User2]"
+.TP
+.I "[User3]"
+.TP
+.I "[User4]"
+These are reserved for user-defined policies.
+.TP
+.I "[Prelink]"
+For prelinked executables / libraries or directories holding them.
+.TP
+.I "[Log]"
+This section defines the filtering rules for logging.
+It may contain the following entries:
+.br
+.BI MailSeverity= val
+where the threshold value
+.I val
+may be one of
+.IR debug ,
+.IR info ,
+.IR notice ,
+.IR warn ,
+.IR mark ,
+.IR err ,
+.IR crit ,
+.IR alert ,
+or
+.IR none .
+By default, everything equal to and above the threshold will be logged.
+The specifiers
+.IR * ,
+.IR ! ,
+and
+.I =
+are interpreted as 'all', 'all but', and 'only', respectively (like
+in the Linux version of syslogd(8)).
+Time stamps have the priority
+.IR warn ,
+system\-level errors have the priority
+.IR err ,
+and important start\-up messages the priority
+.IR alert .
+The signature key for the log file will never be logged to syslog or the
+log file itself.
+For failures to verify file integrity, error levels are defined
+in the next section.
+.br
+.BI PrintSeverity= val,
+.br
+.BI LogSeverity= val,
+.br
+.BI ExportSeverity= val,
+.br
+.BI ExternalSeverity= val,
+.br
+.BI PreludeSeverity= val,
+.br
+.BI DatabaseSeverity= val,
+and
+.br
+.BI SyslogSeverity= val
+set the thresholds for logging via stdout (or
+.IR /dev/console ),
+log file, TCP forwarding, calling external programs,
+and
+.BR syslog (3).
+.TP
+.I "[EventSeverity]"
+.BI SeverityReadOnly= val,
+.br
+.BI SeverityLogFiles= val,
+.br
+.BI SeverityGrowingLogs= val,
+.br
+.BI SeverityIgnoreNone= val,
+.br
+.BI SeverityIgnoreAll= val,
+.br
+.BI SeverityPrelink= val,
+.br
+.BI SeverityUser0= val,
+.br
+.BI SeverityUser1= val,
+.br
+.BI SeverityUser2= val,
+.br
+.BI SeverityUser3= val,
+and
+.br
+.BI SeverityUser4= val
+define the error levels for failures to verify the integrity of
+files/directories of the respective types. I.e. if such a file shows
+unexpected modifications, an error of level
+.I val
+will be generated, and logged to all facilities with a threshold of at least
+.IR val .
+.br
+.BI SeverityFiles= val
+sets the error level for file access problems, and
+.br
+.BI SeverityDirs= val
+for directory access problems.
+.br
+.BI SeverityNames= val
+sets the error level for obscure file names
+(e.g. non\-printable characters), and for files
+with invalid UIDs/GIDs.
+.TP
+.I "[External]"
+.BI OpenCommand= path
+Start the definition of an external logging program|script.
+.br
+.BI SetType= log|srv
+Type/purpose of program (log for logging).
+.br
+.BI SetCommandline= list
+Command line options.
+.br
+.BI SetEnviron= KEY=val
+Environment for external program.
+.br
+.BI SetChecksum= val
+Checksum of the external program (checked before invoking).
+.br
+.BI SetCredentials= username
+User as who the program will run.
+.br
+.BI SetFilterNot= list
+Words not allowed in message.
+.br
+.BI SetFilterAnd= list
+Words required (ALL) in message.
+.br
+.BI SetFilterOr= list
+Words required (at least one) in message.
+.br
+.BI SetDeadtime= seconds
+Time between consecutive calls.
+.TP
+.I "[Utmp]"
+Configuration for watching login/logout events.
+.br
+.BI LoginCheckActive= 0|1
+Switch off/on login/logout reporting.
+.br
+.BI LoginCheckInterval= val
+Interval (seconds) between checks for login/logout events.
+.br
+.BI SeverityLogin= val
+.br
+.BI SeverityLoginMulti= val
+.br
+.BI SeverityLogout= val
+Severity levels for logins, multiple logins
+by same user, and logouts.
+.TP
+.I "[SuidCheck]"
+Settings for finding SUID/SGID files on disk.
+.br
+.BI SuidCheckActive= 0|1
+Switch off/on the check.
+.br
+.BI SuidCheckExclude= path
+ A directory (and its subdirectories)
+ to exclude from the check. Only one directory can be specified this way.
+.br
+.BI SuidCheckSchedule= schedule
+Crontab-like schedule for checks.
+.br
+.BI SeveritySuidCheck= severity
+Severity for events.
+.br
+.BI SuidCheckFps= fps
+Limit files per seconds for SUID check.
+.br
+.BI SuidCheckNosuid= 0|1
+Check filesystems mounted as nosuid. Defaults to not.
+.br
+.BI SuidCheckQuarantineFiles= 0|1
+Whether to quarantine files. Defaults to not.
+.br
+.BI SuidCheckQuarantineMethod= 0|1|2
+Quarantine method. Delete = 1, remove suid/sgid flags = 1, move to quarantine directory = 2. Defaults to 1 (remove suid/sgid flags).
+.br
+.BI
+.TP
+.I "[Mounts]"
+Configuration for checking mounts.
+.br
+.BI MountCheckActive= 0|1
+Switch off/on this module.
+.br
+.BI MountCheckInterval= seconds
+ The interval between checks (default 300).
+.br
+.BI SeverityMountMissing= severity
+Severity for reports on missing mounts.
+.br
+.BI SeverityOptionMissing= severity
+Severity for reports on missing mount options.
+.br
+.BI CheckMount= path
+[mount_options]
+.br
+Mount point to check. Mount options must be given as
+comma-separated list, separated by a blank from the preceding mount point.
+.TP
+.I "[UserFiles]"
+Configuration for checking paths relative to user home directories.
+.br
+.BI UserFilesActive= 0|1
+Switch off/on this module.
+.br
+.BI UserFilesName= filename
+policy
+.br
+Files to check for under each $HOME. Allowed values for 'policy'
+are: allignore, attributes, logfiles, loggrow, noignore (default),
+readonly, user0, user1, user2, user3, and user4.
+.br
+.BI UserFilesCheckUids= uid_list
+A list of UIDs where we want to check. The default
+is all. Ranges (e.g. 100-500) are allowed. If there is an open range (e.g.
+1000-), it must be last in the list.
+.TP
+.I "[ProcessCheck]"
+Settings for finding hidden/fake,required processes on the local host.
+.br
+.BI ProcessCheckActive= 0|1
+Switch off/on the check.
+.br
+.BI ProcessCheckInterval= seconds
+ The interval between checks (default 300).
+.br
+.BI SeverityProcessCheck= severity
+Severity for events (default crit).
+.br
+.BI ProcessCheckMinPID= pid
+The minimum PID to check (default 0).
+.br
+.BI ProcessCheckMaxPID= pid
+The maximum PID to check (default 32767).
+.br
+.BI ProcessCheckPSPath= path
+The path to ps (autodetected at compile time).
+.br
+.BI ProcessCheckPSArg= argument
+The argument to ps (autodetected at compile time).
+Must yield PID in first column.
+.br
+.BI ProcessCheckExists= regular_expression
+Check for existence of a process matching the given regular expression.
+.TP
+.I "[PortCheck]"
+Settings for checking open ports on the local host.
+.br
+.BI PortCheckActive= 0|1
+Switch off/on the check.
+.br
+.BI PortCheckInterval= seconds
+ The interval between checks (default 300).
+.br
+.BI PortCheckUDP= yes|no
+Whether to check UPD ports as well (default yes).
+.br
+.BI SeverityPortCheck= severity
+Severity for events (default crit).
+.br
+.BI PortCheckInterface= ip_address
+Additional interface to check.
+.br
+.BI PortCheckOptional= ip_address:list
+Ports that may, but need not be open. The ip_address is the one
+of the interface, the list must be
+comma or whitespace separated, each item must be (port|service)/protocol,
+e.g. 22/tcp,nfs/tcp/nfs/udp.
+.br
+.BI PortCheckRequired= ip_address:list
+Ports that are required to be open. The ip_address is the one
+of the interface, the list must be
+comma or whitespace separated, each item must be (port|service)/protocol,
+e.g. 22/tcp,nfs/tcp/nfs/udp.
+.TP
+.I "[Database]"
+Settings for
+.I logging
+to a database.
+.br
+.BI SetDBHost= db_host
+Host where the DB server runs (default: localhost).
+Should be a numeric IP address for PostgreSQL.
+.br
+.BI SetDBName= db_name
+Name of the database (default: samhain).
+.br
+.BI SetDBTable= db_table
+Name of the database table (default: log).
+.br
+.BI SetDBUser= db_user
+Connect as this user (default: samhain).
+.br
+.BI SetDBPassword= db_password
+Use this password (default: none).
+.br
+.BI SetDBServerTstamp= true|false
+Log server timestamp for client messages (default: true).
+.br
+.BI UsePersistent= true|false
+Use a persistent connection (default: true).
+.TP
+.I "[Misc]"
+.BI Daemon= no|yes
+Detach from controlling terminal to become a daemon.
+.br
+.BI MessageHeader= format
+Costom format for message header. Replacements:
+.I %F
+source file name,
+.I %L
+source file line,
+.I %S
+severity,
+.I %T
+timestamp,
+.I %C
+message class.
+.br
+.BI VersionString= string
+Set version string to include in file signature database
+(along with hostname and date).
+.br
+.BI SetReverseLookup= true|false
+If false, skip reverse lookups when connecting to a host known by name
+rather than IP address.
+.br
+.BI HideSetup= yes|no
+Don't log name of config/database files on startup.
+.br
+.BI SyslogFacility= facility
+Set the syslog facility to use. Default is LOG_AUTHPRIV.
+.br
+.BI MACType= HASH-TIGER|HMAC-TIGER
+Set type of message authentication code (HMAC).
+Must be identical on client and server.
+.br
+.BI StartupLoadDelay= val
+Defines the interval (in seconds) to wait after startup before
+loading the databse from the server. Default is no wait.
+.br
+.BI SetLoopTime= val
+Defines the interval (in seconds) for timestamps.
+.br
+.BI SetConsole= device
+Set the console device (default /dev/console).
+.br
+.BI MessageQueueActive= 1|0
+Whether to use a SysV IPC message queue.
+.br
+.BI PreludeMapToInfo= list of severities
+The severities (see section
+.IR [Log] )
+that should be mapped to impact
+severity
+.I info
+in prelude.
+.br
+.BI PreludeMapToLow= list of severities
+The severities (see section
+.IR [Log] )
+that should be mapped to impact
+severity
+.I low
+in prelude.
+.br
+.BI PreludeMapToMedium= list of severities
+The severities (see section
+.IR [Log] )
+that should be mapped to impact
+severity
+.I medium
+in prelude.
+.br
+.BI PreludeMapToHigh= list of severities
+The severities (see section
+.IR [Log] )
+that should be mapped to impact
+severity
+.I high
+in prelude.
+.br
+.BI SetMailTime= val
+defines the maximum interval (in seconds) between succesive e\-mail reports.
+Mail might be empty if there are no events to report.
+.br
+.BI SetMailNum= val
+defines the maximum number of messages that are stored before e\-mailing them.
+Messages of highest priority are always sent immediately.
+.br
+.BI SetMailAddress= username @ host
+sets the recipient address for mailing.
+.I "No aliases should be used."
+For security, you should prefer a numerical host address.
+.br
+.BI SetMailRelay= server
+sets the hostname for the mail relay server (if you need one).
+If no relay server is given, mail is sent directly to the host given in the
+mail address, otherwise it is sent to the relay server, who should
+forward it to the given address.
+.br
+.BI SetMailSubject= val
+defines a custom format for the subject of an email message.
+.br
+.BI SetMailSender= val
+defines the sender for the 'From:' field of a message.
+.br
+.BI SetMailFilterAnd= list
+defines a list of strings all of which must match a message, otherwise
+it will not be mailed.
+.br
+.BI SetMailFilterOr= list
+defines a list of strings at least one of which must match a message, otherwise
+it will not be mailed.
+.br
+.BI SetMailFilterNot= list
+defines a list of strings none of which should match a message, otherwise
+it will not be mailed.
+.br
+.BI SamhainPath= /path/to/binary
+sets the path to the samhain binary. If set, samhain will checksum
+its own binary both on startup and termination, and compare both.
+.br
+.BI SetBindAddress= IP_address
+The IP address (i.e. interface on multi-interface box) to use
+for outgoing connections.
+.br
+.BI SetTimeServer= server
+sets the hostname for the time server.
+.br
+.BI TrustedUser= name|uid
+Add a user to the set of trusted users (root and the effective user
+are always trusted. You can add up to 7 more users).
+.br
+.BI SetLogfilePath= AUTO|/path
+Path to logfile (AUTO to tack hostname on compiled-in path).
+.br
+.BI SetLockfilePath= AUTO|/path
+Path to lockfile (AUTO to tack hostname on compiled-in path).
+.TP
+.B Standalone or client only
+.br
+.BI SetNiceLevel= -19..19
+Set scheduling priority during file check.
+.br
+.BI SetIOLimit= bps
+Set IO limits (kilobytes per second) for file check.
+.br
+.BI SetFilecheckTime= val
+Defines the interval (in seconds) between succesive file checks.
+.br
+.BI FileCheckScheduleOne= schedule
+Crontab-like schedule for file checks. If used,
+.I SetFilecheckTime
+is ignored.
+.br
+.BI UseHardlinkCheck= yes|no
+Compare number of hardlinks to number of subdirectories for directories.
+.br
+.BI HardlinkOffset= N:/path
+Exception (use multiple times for multiple
+exceptions). N is offset (actual - expected hardlinks) for /path.
+.br
+.BI AddOKChars= N1,N2,..
+List of additional acceptable characters (byte value(s)) for the check for
+weird filenames. Nn may be hex (leading '0x': 0xNN), octal
+(leading zero: 0NNN), or decimal.
+Use
+.I all
+for all.
+.br
+.BI FilenamesAreUTF8= yes|no
+Whether filenames are UTF-8 encoded (defaults to no). If yes, filenames
+are checked for invalid UTF-8 encoding and for ending in invisible characters.
+.br
+.BI IgnoreAdded= path_regex
+Ignore if this file/directory is added/created.
+.br
+.BI IgnoreMissing= path_regex
+Ignore if this file/directory is missing/deleted.
+.br
+.BI ReportOnlyOnce= yes|no
+Report only once on a modified file (default yes).
+.br
+.BI ReportFullDetail= yes|no
+Report in full detail on modified files (not only modified items).
+.br
+.BI UseLocalTime= yes|no
+Report file timestamps in local time rather than GMT (default no).
+Do not use this with Beltane.
+.br
+.BI ChecksumTest= {init|update|check|none}
+defines whether to initialize/update the database or verify files against it.
+If 'none', you should supply the required option on the command line.
+.br
+.BI SetPrelinkPath= path
+Path of the prelink executable (default /usr/sbin/prelink).
+.br
+.BI SetPrelinkChecksum= checksum
+TIGER192 checksum of the prelink executable (no default).
+.br
+.BI SetLogServer= server
+sets the hostname for the log server.
+.br
+.BI SetServerPort= portnumber
+sets the port on the server to connect to.
+.br
+.BI SetDatabasePath= AUTO|/path
+Path to database (AUTO to tack hostname on compiled-in path).
+.br
+.BI DigestAlgo= SHA1|MD5
+Use SHA1 or MD5 instead of the TIGER checksum (default: TIGER192).
+.br
+.BI RedefReadOnly= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the ReadOnly policy.
+Tests are: CHK (checksum), TXT (store literal content), LNK (link),
+HLN (hardlink), INO (inode), USR (user), GRP (group), MTM (mtime),
+ATM (atime), CTM (ctime), SIZ (size), RDEV (device numbers)
+and/or MOD (file mode).
+.br
+.BI RedefAttributes= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the Attributes policy.
+.br
+.BI RedefLogFiles= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the LogFiles policy.
+.br
+.BI RedefGrowingLogFiles= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the GrowingLogFiles policy.
+.br
+.BI RedefIgnoreAll= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the IgnoreAll policy.
+.br
+.BI RedefIgnoreNone= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the IgnoreNone policy.
+.br
+.BI RedefUser0= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the User0 policy.
+.br
+.BI RedefUser1= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the User1 policy.
+.br
+.BI RedefUser2= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the User2 policy.
+.br
+.BI RedefUser3= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the User3 policy.
+.br
+.BI RedefUser4= +/-XXX,+/-YYY,...
+Add or subtract tests XXX from the User4 policy.
+.TP
+.B Server Only
+.br
+.BI SetUseSocket= yes|no
+If unset, do not open the command socket. The default is no.
+.br
+.BI SetSocketAllowUid= UID
+Which user can connect to the command socket. The default is 0 (root).
+.br
+.BI SetSocketPassword= password
+Password (max. 14 chars, no '@') for password-based authentication on the
+command socket (only if the OS does not support passing
+credentials via sockets).
+.br
+.BI SetChrootDir= path
+If set, chroot to this directory after startup.
+.br
+.BI SetStripDomain= yes|no
+Whether to strip the domain from the client hostname when
+logging client messages (default: yes).
+.br
+.BI SetClientFromAccept= true|false
+If true, use client address as known to the communication layer. Else
+(default) use client name as claimed by the client, try to verify against
+the address known to the communication layer, and accept
+(with a warning message) even if this fails.
+.br
+.BI UseClientSeverity= yes|no
+Use the severity of client messages.
+.br
+.BI UseClientClass= yes|no
+Use the class of client messages.
+.br
+.BI SetServerPort= number
+The port that the server should use for listening (default is 49777).
+.br
+.BI SetServerInterface= IPaddress
+The IP address (i.e. interface on multi-interface box) that the
+server should use for listening (default is all). Use INADDR_ANY to reset
+to all.
+.br
+.BI SeverityLookup= severity
+Severity of the message on client address != socket peer.
+.br
+.BI UseSeparateLogs= true|false
+If true, messages from different clients will be logged to separate
+log files (the name of the client will be appended to the name of the main
+log file to construct the logfile name).
+.br
+.BI SetClientTimeLimit= seconds
+The maximum time between client messages. If exceeded, a warning will
+be issued (the default is 86400 sec = 1 day).
+.br
+.BI SetUDPActive= yes|no
+yule 1.2.8+: Also listen on 514/udp (syslog).
+
+
+.TP
+.I "[Clients]"
+This section is only relevant if
+.B samhain
+is run as a log server for clients running on another (or the same) machine.
+.br
+.BI Client= hostname @ salt @ verifier
+registers a client at host
+.I hostname
+(fully qualified hostname required) for access to the
+log server.
+Log entries from unregistered clients will not be accepted.
+To generate a salt and a valid verifier, use the command
+.B "samhain -P"
+.IR "password" ,
+where
+.I password
+is the password of the client. A simple utility program
+.B samhain_setpwd
+is provided to re\-set the compiled\-in default password of the client
+executable to a user\-defined
+value.
+.TP
+.I "[EOF]"
+An optional end marker. Everything below is ignored.
+
+.SH SEE ALSO
+.PP
+.BR samhain (8)
+
+.SH AUTHOR
+.PP
+Rainer Wichmann (http://la\-samhna.de)
+
+.SH BUG REPORTS
+.PP
+If you find a bug in
+.BR samhain ,
+please send electronic mail to
+.IR support@la\-samhna.de .
+Please include your operating system and its revision, the version of
+.BR samhain ,
+what C compiler you used to compile it, your 'configure' options, and
+anything else you deem helpful.
+
+.SH COPYING PERMISSIONS
+.PP
+Copyright (\(co) 2000, 2004, 2005 Rainer Wichmann
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual page provided the copyright notice and this permission
+notice are preserved on all copies.
+.ig
+Permission is granted to process this file through troff and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual page).
+..
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual page under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
diff --git a/missing b/missing
new file mode 100755
index 0000000..3cb774e
--- /dev/null
+++ b/missing
@@ -0,0 +1,188 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.ac'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.ac'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.ac'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER([^):]*:\([^)]*\)).*/\1/p' configure.ac`
+ if test -z "$files"; then
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^):]*\)).*/\1/p' configure.ac`
+ test -z "$files" || files="$files.in"
+ else
+ files=`echo "$files" | sed -e 's/:/ /g'`
+ fi
+ test -z "$files" && files="config.h.in"
+ touch $files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.ac'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print \
+ | sed 's/^\(.*\).am$/touch \1.in/' \
+ | sh
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 0000000..a01481b
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.10 1996/05/03 07:37:52 friedman Exp $
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/rules.deb-light.in b/rules.deb-light.in
new file mode 100644
index 0000000..6b372d5
--- /dev/null
+++ b/rules.deb-light.in
@@ -0,0 +1,113 @@
+#!/usr/bin/make -f
+# Samhain debian/rules
+# GNU copyright 20001 to 2003 by Javier Fernandez-Sanguino
+# based on
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+# Modified to use mydefargs by Rainer Wichmann.
+#
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=4
+
+package=@install_name@
+
+# CAVEAT: including the --enable-base= option is for packages to be
+# distributed INTERNALLY on your network, NOT for packages
+# to be distributed to THIRD PARTIES
+
+build: build-stamp
+build-stamp:
+ dh_testdir
+ @top_srcdir@/configure @mydefargs@
+ $(MAKE)
+ echo '#!/bin/sh' > ./sstrip
+ echo 'echo "*** SSTRIP DISABLED ***"' >> ./sstrip
+ if ! test x$(PASSWORD) = x; then \
+ if test -f samhain_setpwd; then \
+ ./samhain_setpwd samhain new $(PASSWORD); \
+ rm samhain; \
+ mv samhain.new samhain; \
+ fi; \
+ fi
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+ -[ -f Makefile ] && $(MAKE) distclean
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ $(MAKE) install-light install-boot DESTDIR=`pwd`/debian/@install_name@
+ # $(MAKE) install-light install-boot DESTDIR=`pwd`/debian/tmp
+
+ # However, remove the rc.d links
+ -rm -rf `pwd`/debian/tmp/etc/rc?.d
+
+ # Remove samhain_stealth for light install
+ -rm -f `pwd`/debian/tmp/@sbindir@/@install_name@_stealth
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# dh_testversion
+ dh_testdir
+ dh_testroot
+ dh_installdebconf
+ # dh_installdocs
+ dh_installmenu
+ dh_installinit -- defaults 19
+ [ -f debian/@install_name@.postinst.debhelper ] && \
+ cd debian && \
+ cat @install_name@.postinst.debhelper | \
+ sed 's%/etc/init.d/@install_name@ start%:%' > postinst.tmp && \
+ mv postinst.tmp @install_name@.postinst.debhelper
+ [ -f debian/@install_name@.postinst.debhelper ] && \
+ cd debian && \
+ cat @install_name@.postinst.debhelper | \
+ sed 's%invoke-rc.d @install_name@ start%:%' > postinst.tmp && \
+ mv postinst.tmp @install_name@.postinst.debhelper
+ [ -f debian/@install_name@.prerm.debhelper ] && \
+ cd debian && \
+ cat @install_name@.prerm.debhelper | \
+ sed 's%/etc/init.d/@install_name@ stop%/etc/init.d/@install_name@ stop || echo service @install_name@ already stopped%' > prerm.tmp && \
+ mv prerm.tmp @install_name@.prerm.debhelper
+ [ -f debian/@install_name@.prerm.debhelper ] && \
+ cd debian && \
+ cat @install_name@.prerm.debhelper | \
+ sed 's%invoke-rc.d @install_name@ stop%invoke-rc.d @install_name@ stop || echo service @install_name@ already stopped%' > prerm.tmp && \
+ mv prerm.tmp @install_name@.prerm.debhelper
+ # dh_installmanpages
+ # dh_installchangelogs @top_srcdir@/docs/Changelog
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+
+define checkdir
+ test -f debian/rules
+endef
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
+
diff --git a/rules.deb.in b/rules.deb.in
new file mode 100644
index 0000000..32cc550
--- /dev/null
+++ b/rules.deb.in
@@ -0,0 +1,134 @@
+#!/usr/bin/make -f
+# Samhain debian/rules
+# GNU copyright 20001 to 2003 by Javier Fernandez-Sanguino
+# based on
+# Sample debian/rules that uses debhelper.
+# GNU copyright 1997 to 1999 by Joey Hess.
+# Modified to use mydefargs by Rainer Wichmann.
+#
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# This is the debhelper compatability version to use.
+export DH_COMPAT=4
+
+package=@install_name@
+
+# CAVEAT: including the --enable-base= option is for packages to be
+# distributed INTERNALLY on your network, NOT for packages
+# to be distributed to THIRD PARTIES
+
+build: build-stamp
+build-stamp:
+ dh_testdir
+ @top_srcdir@/configure @mydefargs@
+ $(MAKE)
+ echo '#!/bin/sh' > ./sstrip
+ echo 'echo "*** SSTRIP DISABLED ***"' >> ./sstrip
+ if ! test x$(PASSWORD) = x; then \
+ if test -f samhain_setpwd; then \
+ ./samhain_setpwd samhain new $(PASSWORD); \
+ rm samhain; \
+ mv samhain.new samhain; \
+ fi; \
+ fi
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+ rm -f build-stamp
+ -[ -f Makefile ] && $(MAKE) distclean
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ # Fix the permissions
+ #chmod o-rX `pwd`/debian/tmp/var/log/samhain \
+ # `pwd`/debian/tmp/var/run/samhain \
+ # `pwd`/debian/tmp/var/lib/samhain \
+ # `pwd`/debian/tmp/etc/samhain
+
+ # $(MAKE) install install-boot DESTDIR=`pwd`/debian/tmp
+ $(MAKE) install install-boot DESTDIR=`pwd`/debian/@install_name@
+
+ # However, remove the rc.d links
+ -rm -rf `pwd`/debian/tmp/etc/rc?.d
+
+ # install -m 755 encode `pwd`/debian/tmp/usr/bin/samhain_encode
+
+ # install -m 644 profiles/debianlinux_i386/samhainrc `pwd`/debian/tmp@myconffile@
+ # install -m 644 debian/samhain.logrotate `pwd`/debian/tmp/etc/logrotate.d/samhain
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# dh_testversion
+ dh_testdir
+ dh_testroot
+ dh_installdebconf
+ dh_installdocs
+ [ -f debian/@install_name@/usr/share/doc/@install_name@/MANUAL-2_4.html.tar ] && \
+ cd debian/@install_name@/usr/share/doc/@install_name@ && \
+ tar xf MANUAL-2_4.html.tar && mv MANUAL-2_4 manual.html && \
+ rm -f MANUAL-2_4.html.tar && \
+ mv MANUAL-2_4.pdf manual.pdf
+ dh_installexamples @top_srcdir@/scripts/example_pager.pl \
+ @top_srcdir@/scripts/example_sms.pl \
+ @top_srcdir@/scripts/concat.pl \
+ @top_srcdir@/scripts/samhain.logrotator \
+ @top_srcdir@/scripts/samhainadmin.pl \
+ @top_srcdir@/scripts/check_samhain.pl \
+ @top_srcdir@/yulerc.template \
+ @top_srcdir@/samhainrc.linux
+ dh_installmenu
+ dh_installinit -- defaults 19
+ [ -f debian/@install_name@.postinst.debhelper ] && \
+ cd debian && \
+ cat @install_name@.postinst.debhelper | \
+ sed 's%/etc/init.d/@install_name@ start%:%' > postinst.tmp && \
+ mv postinst.tmp @install_name@.postinst.debhelper
+ [ -f debian/@install_name@.postinst.debhelper ] && \
+ cd debian && \
+ cat @install_name@.postinst.debhelper | \
+ sed 's%invoke-rc.d @install_name@ start%:%' > postinst.tmp && \
+ mv postinst.tmp @install_name@.postinst.debhelper
+ [ -f debian/@install_name@.prerm.debhelper ] && \
+ cd debian && \
+ cat @install_name@.prerm.debhelper | \
+ sed 's%/etc/init.d/@install_name@ stop%/etc/init.d/@install_name@ stop || echo service @install_name@ already stopped%' > prerm.tmp && \
+ mv prerm.tmp @install_name@.prerm.debhelper
+ [ -f debian/@install_name@.prerm.debhelper ] && \
+ cd debian && \
+ cat @install_name@.prerm.debhelper | \
+ sed 's%invoke-rc.d @install_name@ stop%invoke-rc.d @install_name@ stop || echo service @install_name@ already stopped%' > prerm.tmp && \
+ mv prerm.tmp @install_name@.prerm.debhelper
+ # dh_installmanpages
+ dh_installchangelogs @top_srcdir@/docs/Changelog
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+
+define checkdir
+ test -f debian/rules
+endef
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
+
diff --git a/samhain-install.sh.in b/samhain-install.sh.in
new file mode 100644
index 0000000..195dfe1
--- /dev/null
+++ b/samhain-install.sh.in
@@ -0,0 +1,1543 @@
+#! /bin/sh
+
+purge=
+verbose=
+express=
+force=
+act=
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+sbindir=@sbindir@
+samhain=@install_name@
+mandir=@mandir@
+
+sysconfdir=@sysconfdir@
+configfile=@myconffile@
+
+pid_file=@mylockfile@
+pid_dir=@mylockdir@
+
+data_root=@mydataroot@
+mydatafile=@mydatafile@
+
+mylogfile=@mylogfile@
+mylogdir=@mylogdir@
+
+myhtmlfile=@myhtmlfile@
+
+datarootdir=@datarootdir@
+
+INSTALL_SHELL="$0 --install-sh -m 700"
+INSTALL_DATA="$0 --install-sh -m 600"
+
+mkinstalldirs="$0 --mkinstalldirs"
+
+
+DESTDIR=
+user=
+
+#
+# Only call rmdir with an absolute path
+#
+SH_RMDIR=echo
+SPATH="/bin:/usr/bin:/sbin:/usr/sbin"
+OLD_IFS=${IFS}
+IFS=':'; export IFS
+for ff in ${SPATH}; do
+ if test -x $ff/rmdir; then
+ SH_RMDIR=`eval echo ${ff}/rmdir`
+ fi
+done
+IFS=${OLD_IFS}; export IFS
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+
+if [ x"$1" = x ]
+then
+ echo 'samhain-install.sh [--destdir=DESTDIR][--verbose][--express][--force] action'
+ echo 'action = install-boot|install-data|install-user'
+ echo ' uninstall|purge|uninstall-boot'
+ echo ' uninstall-data|uninstall-man|uninstall-program'
+ echo 'samhain-install.sh --print-config <item>'
+ echo 'item = name | basekey | prefix | exec_prefix | sbin_dir | man_dir'
+ echo ' config_dir | config_file | pid_dir | log_dir | log_file'
+ echo ' data_dir | data_file'
+ exit 1
+fi
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -v|--verbose) verbose=yes
+ shift
+ continue;;
+
+ -e|--express) express=yes
+ shift
+ continue;;
+
+ -f|--force) force=yes
+ shift
+ continue;;
+
+ -d) shift
+ DESTDIR="$1"
+ if test "x${DESTDIR}" = "x/"; then
+ DESTDIR=
+ fi
+ shift
+ continue;;
+
+ --destdir=*) DESTDIR=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'`
+ if test "x${DESTDIR}" = "x/"; then
+ DESTDIR=
+ fi
+ shift
+ continue;;
+
+ --install-sh)
+ shift
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
+ # ----- END OF INSTALL-SH -----
+ ;;
+
+ --mkinstalldirs)
+ shift
+ # mkinstalldirs --- make directory hierarchy
+ # Author: Noah Friedman <friedman@prep.ai.mit.edu>
+ # Created: 1993-05-16
+ # Public domain
+ # $Id: mkinstalldirs,v 1.10 1996/05/03 07:37:52 friedman Exp $
+ errstatus=0
+ for file
+ do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+ done
+ exit $errstatus
+ # mkinstalldirs ends here
+ ;;
+
+ install-deploy)
+ if test -f ./samhainrc.USEME
+ then
+ tmpconfigfile=`echo ${configfile} | sed 's%^REQ_FROM_SERVER%%'`
+ if test x"${tmpconfigfile}" = x
+ then
+ echo " No local path for configfile defined."
+ exit 0
+ else
+ cp samhainrc.USEME "${tmpconfigfile}" && chmod 0600 "${tmpconfigfile}"
+ fi
+ fi
+ if test -f postinstall.USEME
+ then
+ /bin/sh ./postinstall.USEME
+ fi
+ exit 0
+ ;;
+
+ print-config|--print-config)
+ shift
+ pwhat=$1
+ if test x"$1" = x
+ then
+ echo "$0: Missing argument to print-config"
+ exit 1
+ fi
+ case $pwhat in
+ basekey)
+ echo "@mykeybase@"
+ ;;
+
+ prefix)
+ echo $prefix
+ ;;
+
+ exec_prefix)
+ echo $exec_prefix
+ ;;
+
+ sbin_dir)
+ echo $sbindir
+ ;;
+
+ name)
+ echo $samhain
+ ;;
+
+ man_dir)
+ echo $mandir
+ ;;
+
+ config_dir)
+ echo $sysconfdir
+ ;;
+
+ config_file)
+ echo $configfile | sed 's%^REQ_FROM_SERVER%%'
+ ;;
+
+ pid_file)
+ echo ${pid_file}
+ ;;
+
+ pid_dir)
+ echo ${pid_dir}
+ ;;
+
+ data_dir)
+ echo @mydataroot@
+ ;;
+
+ data_file)
+ echo @mydatafile@ | sed 's%^REQ_FROM_SERVER%%'
+ ;;
+
+ log_file)
+ echo @mylogfile@
+ ;;
+
+ log_dir)
+ echo @mylogdir@
+ ;;
+
+ *)
+ echo "$0: Unknown item \"$pwhat\""
+ exit 1
+ ;;
+ esac
+ exit 0
+ ;;
+
+ install-user)
+ act=user
+ shift
+ user=$1
+ break;;
+
+ install-boot)
+ act=boot
+ break;;
+
+ uninstall-boot)
+ act=uboot
+ break;;
+
+ install-data)
+ act=data
+ break;;
+
+ uninstall-data)
+ act=udata
+ break;;
+
+ uninstall-man)
+ act=uman
+ break;;
+
+ uninstall-program)
+ act=uprogram
+ break;;
+
+ uninstall | remove | purge)
+ opts=
+ test x"$verbose" = "xyes" && opts="$opts --verbose"
+ test x"$express" = "xyes" && opts="$opts --express"
+ test x"$force" = "xyes" && opts="$opts --force"
+ test x"$DESTDIR" = "x" || opts="$opts --destdir=$DESTDIR"
+ test x"$1" = "xpurge" && purge=yes
+ echo "$0 $opts uninstall-program"
+ eval $0 $opts uninstall-program
+ echo "$0 $opts uninstall-man"
+ eval $0 $opts uninstall-man
+ if test x"$force" = "x"; then
+ test "x$purge" = xyes && opts="$opts --force"
+ fi
+ echo "$0 $opts uninstall-data"
+ eval $0 $opts uninstall-data
+ echo
+ echo " To uninstall the runlevel scripts, use $0 $opts uninstall-boot"
+ echo
+ exit 0
+ ;;
+ *)
+ echo "Unknown option $1"
+ exit 1
+ ;;
+
+ esac
+done
+
+if test x"$act" = xuser
+then
+
+# -- the routines for installing a new user are adapted from
+# the OpenPKG bootstrap installation script, which is distributed
+# under the following license:
+
+## Shell-based package for OpenPKG BINARY bootstrap installation
+## Copyright (c) 2000-2002 Cable & Wireless Deutschland GmbH
+## Copyright (c) 2000-2002 The OpenPKG Project <http://www.openpkg.org/>
+## Copyright (c) 2000-2002 Ralf S. Engelschall <rse@engelschall.com>
+##
+## Permission to use, copy, modify, and distribute this software for
+## any purpose with or without fee is hereby granted, provided that
+## the above copyright notice and this permission notice appear in all
+## copies.
+##
+## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+## SUCH DAMAGE.
+
+ if test x"$user" = x
+ then
+ echo "**ERROR**: No username specified"
+ exit 1
+ fi
+
+ s=`uname -s 2>/dev/null` || s='Unknown'
+ r=`uname -r 2>/dev/null` || r='0.0'
+ platform="${s}/${r}"
+
+ if test x"$user" = xnobody; then
+ case "$platform" in
+ HP-UX/* )
+ group="nogroup"
+ ;;
+ *)
+ group="nobody"
+ ;;
+ esac
+ else
+ group="$user"
+ fi
+ shell=/bin/false
+ if test -f /etc/shells
+ then
+ grep "^/usr/bin/false" /etc/shells >/dev/null 2>&1 && shell=/usr/bin/false
+ grep "^/bin/nologin" /etc/shells >/dev/null 2>&1 && shell=/bin/nologin
+ grep "^/sbin/nologin" /etc/shells >/dev/null 2>&1 && shell=/sbin/nologin
+ fi
+ home="${data_root}"
+
+ xuid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${user}:" | awk -F: '{ print $3; }'`
+ if test "x$xuid" = x
+ then
+ # seek for a reasonable uid/gid pair
+ xuid=1000
+ ok=0
+ while test "x$ok" = x0
+ do
+ eval "u_exists=\$u_exists_$xuid"
+ if test "x$u_exists" = x
+ then
+ u_exists=`(cat /etc/passwd; ypcat passwd) 2>/dev/null | grep "^[^:]*:[^:]*:$xuid:"`
+ fi
+ eval "g_exists=\$g_exists_$xuid"
+ if test "x$g_exists" = x
+ then
+ g_exists=`(cat /etc/group; ypcat group) 2>/dev/null | grep "^[^:]*:[^:]*:$xuid:"`
+ fi
+ if [ "x$u_exists" = x -a "x$g_exists" = x ]; then
+ ok=1
+ break
+ fi
+ xuid=`expr $xuid + 1`
+ done
+ eval "u_exists_$xuid=yes"
+ eval "g_exists_$xuid=yes"
+ else
+ # user exists
+ xgid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${user}:" | awk -F: '{ print $4; }'`
+ fi
+
+ if test "x$xgid" = x
+ then
+ xgid=`(cat /etc/group; ypcat group) 2>/dev/null |\
+ grep "^${group}:" | awk -F: '{ print $3; }'`
+ fi
+
+ if test "x$xgid" = x
+ then
+ xgid="$xuid"
+ g_exists=no
+ else
+ g_exists=yes
+ fi
+
+ uid=$xuid
+ gid=$xgid
+
+ if test -f /etc/shells
+ then
+ exists=`cat /etc/shells 2>/dev/null | grep "^$shell"`
+ if test "x$exists" = x; then
+ echo "${shell}" >>/etc/shells
+ test -z "$verbose" || echo " Added ${shell} to /etc/shells"
+ fi
+ fi
+
+ exists=`(cat /etc/passwd; ypcat passwd) 2>/dev/null | grep "^$user:"`
+ if test x"$exists" = x; then
+ # add entry to passwd database
+ realname="$user"
+ case "$platform" in
+ FreeBSD/* | NetBSD/* | OpenBSD/* )
+ file=/etc/master.passwd
+ entry="${user}:*:${uid}:${gid}::0:0:${realname}:${home}:${shell}"
+ update="(PATH=\$PATH:/usr/sbin; pwd_mkdb -p /etc/master.passwd)"
+ break
+ ;;
+ Linux/* | GNU/kFreeBSD/* | GNU/* )
+ file=/etc/passwd
+ entry="${user}:*:${uid}:${gid}:${realname}:${home}:${shell}"
+ update="(PATH=\$PATH:/usr/sbin; pwconv)"
+ break
+ ;;
+ SunOS/5.* )
+ file=/etc/passwd
+ entry="${user}:*:${uid}:${gid}:${realname}:${home}:${shell}"
+ update="(PATH=\$PATH:/usr/sbin; pwconv)"
+ break
+ ;;
+ OSF1/V5.* )
+ file=/etc/passwd
+ entry="${user}:*:${uid}:${gid}:${realname}:${home}:${shell}"
+ update="(PATH=\$PATH:/usr/sbin; mkpasswd /etc/passwd)"
+ break
+ ;;
+ HP-UX/* )
+ file=/etc/passwd
+ entry="${user}:*:${uid}:${gid}:${realname}:${home}:${shell}"
+ update=":"
+ break
+ ;;
+ IRIX*/* )
+ file=/etc/passwd
+ entry="${user}:*:${uid}:${gid}:${realname}:${home}:${shell}"
+ update=":"
+ break
+ ;;
+ *)
+ echo "install-user: Unsupported system $platform"
+ echo "Please add user $user / group $group manually"
+ echo " and re-run make install-user"
+ exit 1
+ ;;
+ esac
+ cp $file $file.bak && \
+ (grep -v '^+:' $file.bak; echo $entry; grep '^+:' $file.bak) >$file
+ rm -f $file.bak >/dev/null 2>&1
+ eval $update
+ test -z "$verbose" || echo " Added user: ${user} uid: ${uid} shell: ${shell}"
+ else
+ test -z "$verbose" || echo " User ${user} exists already"
+ fi
+
+ # check whether group already exists
+ # FIXME
+ exists=`(cat /etc/group; ypcat group) 2>/dev/null | grep "^$group:"`
+ if test x"$exists" = x
+ then
+ #
+ # user has a valid GID
+ #
+ if test g_exists = xyes; then
+ exists=yes
+ fi
+ fi
+ if test x"$exists" = x
+ then
+ # add entry to group database
+ file=/etc/group
+ entry="${group}:*:${gid}:${user}"
+ cp $file $file.bak && \
+ (grep -v '^+:' $file.bak; echo $entry; grep '^+:' $file.bak) >$file
+ rm -f $file.bak >/dev/null 2>&1
+ test -z "$verbose" || echo " Added group: ${group} gid: ${gid} user: ${user}"
+ fi
+
+ exit 0
+fi
+
+if test x"$act" = xboot || test x"$act" = xuboot
+then
+ s=`uname -s 2>/dev/null` || s='Unknown'
+ r=`uname -r 2>/dev/null` || r='0.0'
+ platform="${s}/${r}"
+
+ case "$platform" in
+ Darwin/*)
+ DVER="MACOSX"
+ test -z "$verbose" || echo "MacOS X system detected"
+ rc_main="/Library/StartupItems/${samhain}"
+ ${mkinstalldirs} ${rc_main}
+ rc_dirz=
+ rc_inst="(cd /Library/StartupItems/${samhain} && echo '{' >StartupParameters.plist && echo ' Description = \"@install_name@\";' >>StartupParameters.plist && echo ' Provides = (\"@install_name@\");' >>StartupParameters.plist && echo ' Requires = (\"Network\");' >>StartupParameters.plist && echo ' OrderPreference = \"Last\";' >>StartupParameters.plist && echo '}' >>StartupParameters.plist && chmod 644 StartupParameters.plist; )"
+ rc_uinst="rm -rf /Library/StartupItems/@install_name@"
+ ;;
+
+ IRIX*/*)
+ DVER="IRIX"
+ test -z "$verbose" || echo " IRIX system detected"
+ rc_main=${DESTDIR}/etc/init.d
+ rc_dirz=
+ rc_inst="chmod 755 /etc/init.d/@install_name@; chown root /etc/init.d/@install_name@; chkconfig -f @install_name@ on; (cd /etc; ln -f -s init.d/@install_name@ rc2.d/S99@install_name@; ln -f -s init.d/@install_name@ rc0.d/K10@install_name@; )"
+ rc_uinst="rm -f /etc/init.d/@install_name@; rm -f /etc/rc2.d/S99@install_name@; rm -f /etc/rc0.d/K10@install_name@; chkconfig @install_name@ off"
+ ;;
+
+ AIX/*)
+ DVER="AIX"
+ test -z "$verbose" || echo " AIX system detected"
+ ln -f -s @sbindir@/@install_name@ samhain.startAIX
+ rc_main=@sbindir@
+ rc_dirz=
+ rc_inst="/usr/sbin/mkitab '@install_name@:2:wait:@sbindir@/@install_name@ start >/dev/console 2>&1'"
+ rc_uinst="/usr/sbin/rmitab @install_name@"
+ ;;
+
+ HP-UX/*)
+ DVER="HPUX"
+ test -z "$verbose" || echo " HP-UX system detected"
+ rc_main=${DESTDIR}/sbin/init.d
+ rc_dirz=
+ rc_inst="chmod 555 /sbin/init.d/@install_name@; chown bin:bin /sbin/init.d/@install_name@; (cd /sbin && ln -f -s /sbin/init.d/@install_name@ rc2.d/S900@install_name@ && ln -f -s /sbin/init.d/@install_name@ rc1.d/K100@install_name@; )"
+ rc_uinst="rm -f /sbin/init.d/@install_name@; rm -f /sbin/rc2.d/S900@install_name@; rm -f /sbin/rc1.d/K100@install_name@"
+ ;;
+
+ OpenBSD/*)
+ test -z "$verbose" || echo " OpenBSD system detected"
+ grep '^## begin @install_name@' /etc/rc.local >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ RCLOCALTMP=`mktemp /etc/rc.local.XXXXXXXXXX` || exit 1
+ sed "/^## begin @install_name@/,/^## end @install_name@/d" /etc/rc.local >$RCLOCALTMP || exit 1
+ cat $RCLOCALTMP >/etc/rc.local || exit 1
+ rm -f $RCLOCALTMP || exit 1
+ if test x"$act" = xuboot; then
+ echo " uninstalling from /etc/rc.local completed"
+ fi
+ fi
+ if test x"$act" = xboot; then
+ echo "## begin @install_name@" >>/etc/rc.local || exit 1
+ echo "if [ -x @sbindir@/@install_name@ ]; then" >>/etc/rc.local || exit 1
+ echo " @sbindir@/@install_name@ start" >>/etc/rc.local || exit 1
+ echo "fi" >>/etc/rc.local || exit 1
+ echo "## end @install_name@" >>/etc/rc.local || exit 1
+ echo " installing to /etc/rc.local completed"
+ fi
+ exit 0
+ ;;
+
+ NetBSD/*)
+ test -z "$verbose" || echo " NetBSD system detected"
+ if test -f /etc/rc.subr; then
+ DVER="FreeBSD"
+ rc_main=${DESTDIR}/etc/rc.d
+ rc_dirz=
+ rc_inst="chmod 755 /etc/rc.d/@install_name@"
+ rc_uinst="rm -f /etc/rc.d/@install_name@"
+ else
+ echo "${0}: unsupported platform ${platform} (too old)"
+ exit 1
+ fi
+ ;;
+
+ FreeBSD/* )
+ test -z "$verbose" || echo " FreeBSD system detected"
+ if test -f /etc/rc.subr; then
+ DVER="FreeBSD"
+ rc_main=${DESTDIR}/etc/rc.d
+ rc_dirz=
+ rc_inst="chmod 755 /etc/rc.d/@install_name@"
+ rc_uinst="rm -f /etc/rc.d/@install_name@"
+ else
+ DVER="Solaris"
+ rc_main=${DESTDIR}/usr/local/etc/rc.d
+ rc_dirz=
+ rc_inst="mv /usr/local/etc/rc.d/@install_name@ /usr/local/etc/rc.d/@install_name@.sh && chmod 755 /usr/local/etc/rc.d/@install_name@.sh"
+ rc_uinst="rm -f /usr/local/etc/rc.d/@install_name@.sh"
+ fi
+ if test x"$act" = xboot
+ then
+ if [ ! -d ${rc_main} ]; then
+ test x"$act" = xboot && mkdir ${rc_main}
+ fi
+ if test "x$DVER" = "xSolaris"; then
+ ( . /etc/defaults/rc.conf
+ . /etc/rc.conf
+ found=0
+ for p in ${local_startup-x}; do
+ if test "x$p" = "x${rc_main}"; then
+ found=1
+ break
+ fi
+ done
+ if test "x$found" = x0; then
+ cp -p /etc/rc.conf /etc/rc.conf.bak
+ (
+ grep -v local_startup /etc/rc.conf.bak
+ echo "local_startup=\"${rc_main} $local_startup\""
+ ) >/etc/rc.conf
+ fi
+ )
+ fi
+ fi
+ ;;
+
+ SunOS/5.* )
+ DVER="Solaris"
+ DVER_REAL="Solaris"
+ test -z "$verbose" || echo " Solaris system detected"
+ rc_dirz=
+ rc_main=${DESTDIR}/etc/init.d
+ rc_inst="chmod 755 ${DESTDIR}/etc/init.d/@install_name@; chown root:sys ${DESTDIR}/etc/init.d/@install_name@; (cd ${DESTDIR}/etc; ln init.d/@install_name@ rc3.d/S99@install_name@; ln init.d/@install_name@ rc0.d/K10@install_name@; ln init.d/@install_name@ rc1.d/K10@install_name@; )"
+ rc_uinst="rm -f ${DESTDIR}/etc/init.d/@install_name@; rm -f ${DESTDIR}/etc/rc0.d/K10@install_name@; rm -f ${DESTDIR}/etc/rc1.d/K10@install_name@; rm -f ${DESTDIR}/etc/rc3.d/S99@install_name@"
+ ;;
+
+ Linux/* | GNU/kFreeBSD* | GNU/* )
+ rlv="2 3 4 5"
+ linkopt="-f -s"
+ # find rc directories
+ if test -f /usr/lib/lsb/install_initd && test -d /etc/init.d
+ then
+ test -z "$verbose" || echo " Linux Standard Base system detected"
+ DVER=LSB
+ if test x"$DESTDIR" = x
+ then
+ rc_main=/etc/init.d
+ rc_dirz=
+ rc_inst="/usr/lib/lsb/install_initd /etc/init.d/@install_name@"
+ rc_uinst="/usr/lib/lsb/remove_initd /etc/init.d/@install_name@"
+ else
+ rc_inst=
+ rc_uinst=
+ rc_main=${DESTDIR}/etc/init.d
+ rc_dirz=
+ # test -d /etc/init.d/rc2.d && rc_dirz=${DESTDIR}/etc/init.d/rc
+ # test -d /etc/rc.d/rc2.d && rc_dirz=${DESTDIR}/etc/rc.d/rc
+ # test -d /etc/rc2.d && rc_dirz=${DESTDIR}/etc/rc
+ fi
+ elif test -f /etc/SuSE-release
+ then
+ test -z "$verbose" || echo " SuSE system detected"
+ DVER="Linux"
+ rc_inst=
+ rc_uinst=
+ if test -d /sbin/init.d && test -d /sbin/init.d/rc2.d
+ then
+ test -z "$verbose" || echo " SuSE 6.x system detected"
+ rc_main=${DESTDIR}/sbin/init.d
+ rc_dirz=${DESTDIR}/sbin/init.d/rc
+ elif test -d /etc/init.d && test -d /etc/init.d/rc2.d
+ then
+ test -z "$verbose" || echo " SuSE 7.x or newer detected"
+ rc_main=${DESTDIR}/etc/init.d
+ rc_dirz=${DESTDIR}/etc/init.d/rc
+ else
+ echo "${0}: unknown system"
+ exit 1
+ fi
+ elif test -d /sbin/init.d && test -d /sbin/init.d/rc2.d
+ then
+ DVER="Linux"
+ rc_inst=
+ rc_uinst=
+ test -z "$verbose" || echo " SuSE 5.x system detected"
+ rc_main=${DESTDIR}/sbin/init.d
+ rc_dirz=${DESTDIR}/sbin/init.d/rc
+ elif test -f /etc/debian_version
+ then
+ DVER="Linux"
+ test -z "$verbose" || echo " Debian based system detected"
+ if test x"$DESTDIR" = x
+ then
+ rc_main=/etc/init.d
+ rc_dirz=
+ rc_uinst="/usr/sbin/update-rc.d -f @install_name@ remove"
+ rc_inst="/usr/sbin/update-rc.d @install_name@ defaults 99 10"
+ else
+ rc_inst=
+ rc_uinst=
+ rc_main=${DESTDIR}/etc/init.d
+ # rc_dirz=${DESTDIR}/etc/rc
+ rc_dirz=
+ fi
+ elif test -f /etc/redhat-release
+ then
+ DVER="Linux"
+ test -z "$verbose" || echo " Redhat based system detected"
+ rc_uinst=
+ rc_inst=
+ rc_main=${DESTDIR}/etc/rc.d/init.d
+ rc_dirz=${DESTDIR}/etc/rc.d/rc
+ elif test -f /etc/mandrake-release
+ then
+ DVER="Linux"
+ test -z "$verbose" || echo " Mandrake based system detected"
+ rc_uinst=
+ rc_inst=
+ rc_main=${DESTDIR}/etc/rc.d/init.d
+ rc_dirz=${DESTDIR}/etc/rc.d/rc
+ elif test -f /etc/yellowdog-release
+ then
+ DVER="Linux"
+ test -z "$verbose" || echo " Yellow Dog based system detected"
+ rc_uinst=
+ rc_inst=
+ rc_main=${DESTDIR}/etc/rc.d/init.d
+ rc_dirz=${DESTDIR}/etc/rc.d/rc
+ elif test -f /etc/slackware-version && test -f /etc/rc.d/rc.sysvinit
+ then
+ DVER="Linux"
+ test -z "$verbose" || echo " Slackware based system detected"
+ rc_uinst=
+ rc_inst=
+ rc_main=${DESTDIR}/etc/rc.d
+ rc_dirz=${DESTDIR}/etc/rc.d/rc
+ elif test -f /etc/gentoo-release
+ then
+ DVER="Gentoo"
+ test -z "$verbose" || echo " Gentoo based system detected"
+ rc_uinst="/sbin/rc-update del @install_name@"
+ rc_inst="/sbin/rc-update add @install_name@ default"
+ rc_main=${DESTDIR}/etc/init.d
+ rc_dirz=
+ else
+ echo "${0}: unknown Linux distribution"
+ rc_uinst=
+ rc_inst=
+ rc_main=
+ rc_dirz=
+ for ff in /etc/rc.d/init.d /etc/init.d /sbin/init.d; do
+ if test -d $ff; then
+ rc_main="$ff"
+ break
+ fi
+ done
+ for fg in /etc/rc.d/rc2.d /etc/rc2.d /sbin/init.d/rc2.d; do
+ if test -d $fg; then
+ rc_dirz="`echo $fg | sed -e 's,2.*,,'`"
+ break
+ fi
+ done
+ if [ x"${rc_dirz}" = x ]; then
+ echo "${0}: no install directory for runlevel scripts found"
+ exit 1
+ fi
+ if [ x"${rc_main}" = x ]; then
+ echo "${0}: no install directory for runlevel scripts found"
+ exit 1
+ fi
+ DVER="Linux"
+ rc_main="${DESTDIR}${rc_main}"
+ rc_dirz="${DESTDIR}${rc_dirz}"
+ fi
+ ;;
+
+ *)
+ echo "${0}: unsupported platform ${platform}"
+ exit 1
+ ;;
+ esac
+
+ if test x"${rc_main}" = x
+ then
+ echo "${0}: no install directory for runlevel scripts found"
+ exit 1
+ fi
+
+ if test x"${act}" = xboot
+ then
+
+ startscript=NONE
+ if test -f init/samhain.start${DVER}
+ then
+ startscript=`eval echo init/samhain.start${DVER}`
+ elif test -f samhain.start${DVER}
+ then
+ startscript=`eval echo samhain.start${DVER}`
+ else
+ echo "${0}: cannot find samhain.start${DVER} in ./ or ./init"
+ exit 1
+ fi
+
+ if test "x${startscript}" = xNONE; then
+ echo "${0}: cannot find samhain.start${DVER} in ./ or ./init"
+ exit 1
+ else
+ if test -f ${rc_main}/${samhain} && test x"$force" != xyes
+ then
+ echo " ${rc_main}/${samhain} exists ... not overwritten (or use --force)"
+ else
+ if test x"$DESTDIR" = x
+ then
+ :
+ else
+ ${mkinstalldirs} ${rc_main}
+ #
+ if test x"${DVER_REAL}" = xSolaris; then
+ ${mkinstalldirs} ${DESTDIR}/etc/rc0.d
+ ${mkinstalldirs} ${DESTDIR}/etc/rc1.d
+ ${mkinstalldirs} ${DESTDIR}/etc/rc3.d
+ fi
+ #
+ fi
+ test -z "$verbose" || echo " ${INSTALL_SHELL} ${startscript} ${rc_main}/${samhain}"
+ if test -f "@INSTALL@"; then
+ ${INSTALL_SHELL} ${startscript} ${rc_main}/${samhain}
+ else
+ cp ${startscript} ${rc_main}/${samhain} && chmod 0700 ${rc_main}/${samhain}
+ fi
+ fi
+ fi
+
+
+ if test x"${rc_dirz}" != x
+ then
+ for ff in $rlv
+ do
+ if test x"${DESTDIR}" = x
+ then
+ rldir="${rc_dirz}${ff}.d/"
+ test -z "$verbose" || echo " cd ${rldir} && ln ${linkopt} ${rc_main}/${samhain} S99${samhain}"
+ (cd ${rldir} && ln ${linkopt} ${rc_main}/${samhain} S99${samhain})
+ test -z "$verbose" || echo " cd ${rldir} && ln ${linkopt} ${rc_main}/${samhain} K10${samhain}"
+ (cd ${rldir} && ln ${linkopt} ${rc_main}/${samhain} K10${samhain})
+ else
+ :
+ # ${mkinstalldirs} ${rc_dirz}${ff}.d
+ fi
+
+
+ done
+ fi
+
+ if test x"${rc_inst}" != x
+ then
+ if test x"${DESTDIR}" = x
+ then
+ test -z "$verbose" || echo " ${rc_inst}"
+ eval ${rc_inst}
+ fi
+ fi
+ echo "installing init scripts completed"
+ fi
+
+ if test x"${act}" = xuboot
+ then
+ if test x"${rc_uinst}" != x
+ then
+ test -z "$verbose" || echo " ${rc_uinst}"
+ echo
+ eval ${rc_uinst}
+ fi
+
+ if test x"${rc_dirz}" != x
+ then
+ for ff in $rlv
+ do
+ test -z "$verbose" || echo " rm -f ${rc_dirz}${ff}.d/S99${samhain}"
+ rm -f ${rc_dirz}${ff}.d/S99${samhain}
+ test -z "$verbose" || echo " rm -f ${rc_dirz}${ff}.d/S99${samhain}"
+ rm -f ${rc_dirz}${ff}.d/K10${samhain}
+ done
+ fi
+
+ test -z "$verbose" || echo " rm -f ${rc_main}/${samhain}"
+ rm -f ${rc_main}/${samhain}
+
+ echo " uninstalling init scripts completed"
+ fi
+
+ # boot_install|boot_uninstall completed
+ exit 0
+fi
+
+if test x"${act}" = xuprogram
+then
+ PROGRAMS="@setpwd_prg@ @stegin_prg@ @yulectl_prg@ @sh_main_prg@ @samhainadmin_prg@"
+ for p in $PROGRAMS; do
+ test -z "$verbose" || echo " rm -f ${DESTDIR}${sbindir}/`echo $p|sed 's%samhain%@install_name@%'|sed 's%yule%@install_name@%'|sed 's%.*/%%'`"
+ rm -f ${DESTDIR}${sbindir}/`echo $p|sed 's%samhain%@install_name@%'|sed 's%yule%@install_name@%'|sed 's%.*/%%'`
+ done
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${sbindir} ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${sbindir} >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+ exit 0
+fi
+
+if test x"${act}" = xuman
+then
+ test -z "$verbose" || echo " rm -f ${DESTDIR}${mandir}/man8/@install_name@.8"
+ rm -f ${DESTDIR}${mandir}/man8/@install_name@.8
+ test -z "$verbose" || echo " rm -f ${DESTDIR}${mandir}/man5/@install_name@rc.5"
+ rm -f ${DESTDIR}${mandir}/man5/@install_name@rc.5
+
+ OLD_IFS=${IFS}
+ IFS=':'; export IFS
+ for ff in ${MANPATH}; do
+ if test x"$ff/man8" = x"${DESTDIR}${mandir}/man8"; then
+ echo " man directory ${DESTDIR}${mandir} is in your MANPATH"
+ echo " -- will not try to remove"
+ IFS=${OLD_IFS}; export IFS
+ exit 0
+ fi
+ done
+ IFS=${OLD_IFS}; export IFS
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${mandir}/man8 ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${mandir}/man8 >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${mandir}/man5 ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${mandir}/man5 >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${mandir} ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${mandir} >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+ exit 0
+fi
+
+if test x"${act}" = xudata
+then
+ test -z "$verbose" || echo " rm -f ${DESTDIR}`echo ${mydatafile}|sed s%REQ_FROM_SERVER%%`"
+ rm -f ${DESTDIR}`echo ${mydatafile}|sed s%REQ_FROM_SERVER%%`
+ test -z "$verbose" || echo " rm -f ${DESTDIR}${pid_file}"
+ rm -f ${DESTDIR}${pid_file}
+ test -z "$verbose" || echo " rm -f ${DESTDIR}${mylogfile}"
+ rm -f ${DESTDIR}${mylogfile}
+ test -z "$verbose" || echo " rm -f ${DESTDIR}${myhtmlfile}"
+ rm -f ${DESTDIR}${myhtmlfile}
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${pid_dir} ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${pid_dir} >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${mylogdir} ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${mylogdir} >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${data_root} ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${data_root} >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+
+ if test -d /etc/logrotate.d; then
+ if test -f /etc/logrotate.d/@install_name@; then
+ test -z "$verbose" || echo $ECHO_N " rm -f /etc/logrotate.d/@install_name@ ... $ECHO_C"
+ rm -f /etc/logrotate.d/@install_name@;
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed"
+ fi
+ fi
+ fi
+
+ if test x"$force" = "xyes"
+ then
+ test -z "$verbose" || echo " rm -f ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%`"
+ rm -f ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%`
+ elif test x"$purge" = "xyes"
+ then
+ test -z "$verbose" || echo " rm -f ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%`"
+ rm -f ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%`
+ elif test x"$express" = x; then
+ echo " Do you want to remove the configuration file [y/n] ?"
+ while [ "1" = "1" ]; do
+ read ff
+ case "$ff" in
+ Y* | y* )
+ test -z "$verbose" || echo " rm -f ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%`"
+ rm -f ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%`
+ break
+ ;;
+ N* | n* )
+ test -z "$verbose" || echo " ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%` NOT removed"
+ break
+ ;;
+ *)
+ echo " Enter y[es] or n[o]"
+ ;;
+ esac
+ done
+ else
+ test -z "$verbose" || echo " NOT REMOVED: config file ${DESTDIR}`echo ${configfile}|sed s%REQ_FROM_SERVER%%` (use --force to remove)"
+ fi
+
+ test -z "$verbose" || echo $ECHO_N " ${SH_RMDIR} ${DESTDIR}${sysconfdir} ... $ECHO_C"
+ ${SH_RMDIR} ${DESTDIR}${sysconfdir} >/dev/null 2>&1
+ if test x$? = x0; then
+ test -z "$verbose" || echo "${ECHO_T}done"
+ else
+ test -z "$verbose" || echo "${ECHO_T}failed (not empty ?)"
+ fi
+
+ exit 0
+fi
+
+if test x"${act}" = xdata
+then
+ STEGIN=@stegin_prg@
+ CONVERT=
+
+ GPGPATH=@mygpg@
+ TARGETKEYID=@mykeyid@
+ KEYTAG=@mykeytag@
+
+ NTEST=@mytclient@
+
+ if test x"${NTEST}" = "x-DSH_WITH_SERVER"
+ then
+ RCFILE=yulerc
+ if test -f $RCFILE
+ then
+ :
+ else
+ if test -f yulerc.template
+ then
+ cp yulerc.template $RCFILE
+ fi
+ fi
+ else
+ RCFILE=samhainrc
+ IN_RCFILE=samhainrc.@selectconfig@
+
+ if test -f ${RCFILE}
+ then
+ :
+ else
+ if test -f ${IN_RCFILE}
+ then
+ test -z "$verbose" || echo " cp ${IN_RCFILE} ${RCFILE}"
+ cp ${IN_RCFILE} ${RCFILE}
+ fi
+ fi
+ fi
+
+ if test -f $RCFILE
+ then
+ :
+ else
+ echo "${0}: cannot find configuration file $RCFILE"
+ exit 1
+ fi
+
+ if test x"${GPGPATH}" != x
+ then
+ echo
+ echo "You need to sign the config file now"
+ echo
+ test -z "$verbose" || echo " ${GPGPATH} -a ${KEYTAG} ${TARGETKEYID} --clearsign $RCFILE"
+ if test x"${NTEST}" = "x-DSH_WITH_SERVER"
+ then
+ myident_uid=`(cat /etc/passwd; ypcat passwd) 2>/dev/null |\
+ grep "^${samhain}:" | awk -F: '{ print $3; }'`
+ if test x"${myident_uid}" != x
+ then
+ DOT_GNUPG=`eval echo ~${samhain}/.gnupg`
+ test -z "$verbose" || echo " using --homedir ${DOT_GNUPG}"
+ ${GPGPATH} --homedir ${DOT_GNUPG} -a ${KEYTAG} ${TARGETKEYID} --clearsign $RCFILE
+ else
+ ${GPGPATH} -a ${KEYTAG} ${TARGETKEYID} --clearsign $RCFILE
+ fi
+ else
+ ${GPGPATH} -a ${KEYTAG} ${TARGETKEYID} --clearsign $RCFILE
+ fi
+
+ if test -f ${RCFILE}.asc
+ then
+ test -z "$verbose" || echo " mv -f ${RCFILE}.asc samhainrc.pre"
+ mv -f ${RCFILE}.asc samhainrc.pre
+ else
+ echo "**********************************************************"
+ echo
+ echo "${0}: ERROR: cannot find signed file ${RCFILE}.asc"
+ echo
+ echo " --- You need to sign the configuration file ---"
+ echo
+ echo "**********************************************************"
+ cp ${RCFILE} samhainrc.pre
+ fi
+ else
+ test -z "$verbose" || echo " cp $RCFILE samhainrc.pre"
+ cp $RCFILE samhainrc.pre
+ fi
+
+ if test x"${STEGIN}" != x
+ then
+ test -z "$verbose" || echo " searching for ImageMagick convert utility"
+ OPATH=${PATH}
+ PATH="/usr/local/bin:/usr/X11R6/bin:"${PATH}
+
+ OIFS=${IFS}
+ IFS=":"
+
+ for dd in ${PATH}
+ do
+ if test -f "${dd}/convert"
+ then
+ "${dd}/convert" --help | grep ImageMagick >/dev/null 2>&1 && \
+ CONVERT="${dd}/convert"
+ test -z "$verbose" || echo " CONVERT=${dd}/convert"
+ fi
+ done
+
+ IFS=${OIFS}
+
+ if test -f stealth_template.ps
+ then
+ PATH=${OPATH}
+ else
+ if test x"${CONVERT}" = x
+ then
+ echo "${0}: cannot find ImageMagick convert utility in PATH=${PATH}"
+ exit 1
+ fi
+
+ PATH=${OPATH}
+
+ if test -f stealth_template.jpg
+ then
+ test -z "$verbose" || echo " ${CONVERT} +compress stealth_template.jpg stealth_template.ps"
+ "${CONVERT}" +compress stealth_template.jpg stealth_template.ps
+ else
+ echo "${0}: cannot find file stealth_template.jpg"
+ exit 1
+ fi
+ fi
+
+
+ if test -f stealth_template.ps
+ then
+ :
+ else
+ echo "${0}: file stealth_template.ps not created"
+ exit 1
+ fi
+
+ if test -f samhainrc.pre
+ then
+ :
+ else
+ echo "${0}: cannot find configuration file samhainrc.pre"
+ exit 1
+ fi
+
+ if test -f ./samhain_stealth
+ then
+ :
+ else
+ echo "${0}: cannot find utility ./samhain_stealth"
+ exit 1
+ fi
+
+ ccount=`./samhain_stealth -o samhainrc.pre 2>&1 | awk '{ print $1 }'`
+ mcount=`./samhain_stealth -i stealth_template.ps 2>&1 | awk '{ print $7 }'`
+
+ if test ${mcount} -lt ${ccount}
+ then
+ echo "${0}: configuration file samhainrc too big,"
+ echo " need a larger image stealth_template.jpg to store"
+ exit 1
+ fi
+
+ test -z "$verbose" || echo " ./samhain_stealth -s stealth_template.ps samhainrc.pre"
+ ./samhain_stealth -s stealth_template.ps samhainrc.pre
+
+ test -z "$verbose" || echo " mv -f stealth_template.ps samhainrc.install"
+ mv -f stealth_template.ps samhainrc.install
+ else
+ test -z "$verbose" || echo " mv -f samhainrc.pre samhainrc.install"
+ mv -f samhainrc.pre samhainrc.install
+ fi
+
+ tmp_configfile=`echo ${configfile} | sed 's%^REQ_FROM_SERVER%%'`
+
+ if test x"${tmp_configfile}" = x
+ then
+ echo " No local configfile to install."
+ exit 0
+ fi
+
+ if test -f ${DESTDIR}${tmp_configfile} && test x"$force" = x
+ then
+ echo " ${DESTDIR}${tmp_configfile} exists ... not overwritten (or use --force)"
+ else
+ test -z "$verbose" || echo " ${INSTALL_DATA} samhainrc.install ${DESTDIR}${tmp_configfile}"
+ ${INSTALL_DATA} samhainrc.install ${DESTDIR}${tmp_configfile}
+ fi
+
+ if test x"${NTEST}" = "x-DSH_WITH_SERVER"
+ then
+ test -z "$verbose" || echo " chown @myident@ ${DESTDIR}${tmp_configfile}"
+ chown @myident@ ${DESTDIR}${tmp_configfile}
+ fi
+
+ #
+ # Changed: don't check if DESTDIR is set, as these are not
+ # the true install locations anyway
+ #
+ if test -f trustfile && test x"${DESTDIR}" = x
+ then
+ test -z "$verbose" || echo " checking whether paths are trustworthy"
+ RESULT=`./trustfile ${DESTDIR}${tmp_configfile} 2>&1`
+ if test x$? != x0
+ then
+ echo
+ ./trustfile ${DESTDIR}${tmp_configfile}
+ echo
+ else
+ test -z "$verbose" || echo " configuration file ${DESTDIR}${tmp_configfile} ... OK"
+ fi
+
+ RESULT=`./trustfile ${DESTDIR}${pid_dir} >/dev/null 2>&1`
+ if test x$? != x0
+ then
+ echo
+ ./trustfile ${DESTDIR}${pid_dir}
+ echo
+ else
+ test -z "$verbose" || echo " state directory ${DESTDIR}${pid_dir} ... OK"
+ fi
+
+ RESULT=`./trustfile ${DESTDIR}${mylogdir} >/dev/null 2>&1`
+ if test x$? != x0
+ then
+ echo
+ ./trustfile ${DESTDIR}${mylogdir}
+ echo
+ else
+ test -z "$verbose" || echo " state directory ${DESTDIR}${mylogdir} ... OK"
+ fi
+
+ RESULT=`./trustfile ${DESTDIR}${data_root} >/dev/null 2>&1`
+ if test x$? != x0
+ then
+ echo
+ ./trustfile ${DESTDIR}${data_root}
+ echo
+ else
+ test -z "$verbose" || echo " data directory ${DESTDIR}${data_root} ... OK"
+ fi
+ fi
+ # install_data
+ exit 0
+fi
+
+
diff --git a/samhain.jpg b/samhain.jpg
new file mode 100644
index 0000000..23e1c58
--- /dev/null
+++ b/samhain.jpg
Binary files differ
diff --git a/samhain.spec b/samhain.spec
new file mode 100644
index 0000000..41e2b43
--- /dev/null
+++ b/samhain.spec
@@ -0,0 +1,289 @@
+#
+# Accepted parameters for 'rpmbuild':
+#
+# --with tests - make tests before building
+
+Summary: File integrity and host-based IDS
+Name: samhain
+Version: 4.1.4
+Release: 1
+License: GPL
+Group: System Environment/Base
+Source: samhain-%{version}.tar.gz
+BuildRoot: %{_tmppath}/samhain-%{version}-root
+Packager: Andre Oliveira da Costa <brblueser@uol.com.br>
+Provides: %{name}
+Requires(pre): shadow-utils
+
+# dummy (fix configure warning)
+# datarootdir = @datarootdir@
+
+# no quotes here - aparently will be expanded literally
+
+%define password %(echo $PASSWORD)
+
+%define withpwd_prg xDSH_STANDALONE
+%define withstg_prg x
+
+# disable automatic stripping of binaries upon installation
+%define __spec_install_post %{nil}
+# required because DeadRat wants to package some debug info otherwise
+# (this debug info would be created by debug_install_post called
+# from spec_install_post)
+%define debug_package %{nil}
+# Use internal dependency generator rather than external helpers?
+%define _use_internal_dependency_generator 0
+
+%description
+samhain is an open source file integrity and host-based intrusion
+detection system for Linux and Unix. It can run as a daemon process, and
+and thus can remember file changes -- contrary to a tool that runs from
+cron, if a file is modified you will get only one report, while
+subsequent checks of that file will ignore the modification as it is
+already reported (unless the file is modified again).
+
+samhain can optionally be used as client/server system to provide
+centralized monitoring for multiple host. Logging to a (MySQL or
+PostgreSQL) database is supported.
+
+NOTE: for security reasons, if you distribute binary executables to
+third parties you should point out the use of the --add-key option to
+modify the key material within the executable.
+This spec file is intended to facilitate installation on YOUR system.
+If you use this spec file to build a SRPM for distribution to third parties,
+make sure to remove the --enable-base configure option below.
+
+%prep
+%setup -q -n samhain-%{version}
+
+%build
+%if %{?_with_tests:1}%{!?_with_tests:0}
+# test installation (test #7 is only included if --with gpg has been
+# specified)
+for i in `seq 6` %{?_with_gpg:7}; do ./test/test.sh $i; done
+%endif
+#
+# configure with the user-supplied arguments to './configure'
+#
+./configure --enable-base=6365215,1343398076
+make
+%if "%{withpwd_prg}" == "xDSH_WITH_CLIENT"
+%if 0%{?password}
+ ./samhain_setpwd samhain new %{password}
+ mv samhain samhain.old
+ mv samhain.new samhain
+%endif
+%endif
+
+
+%install
+rm -rf ${RPM_BUILD_ROOT}
+# sstrip shouldn't be used since binaries will be stripped later
+## cat << EOF > sstrip
+## #!/bin/sh
+## echo "*** SSTRIP DISABLED ***"
+## EOF
+make DESTDIR=${RPM_BUILD_ROOT} install
+# copy script files to /var/lib/samhain so that we can use them right
+# after the package is installed
+#
+install -m 700 samhain-install.sh init/samhain.startLinux init/samhain.startLSB ${RPM_BUILD_ROOT}/var/lib/samhain
+#
+# file list (helpful advice from Lars Kellogg-Stedman)
+#
+echo "/usr/local/sbin/samhain" > sh_file_list
+find %{buildroot}/lib/modules \! -type d -print | \
+ sed 's,%{buildroot},,' >> sh_file_list
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%pre
+if test "xsamhain" = "xyule"
+then
+ getent group samhain >/dev/null || groupadd -r samhain
+ getent passwd yule >/dev/null || \
+ useradd -r -g samhain -d /var/lib/samhain -s /sbin/nologin \
+ -c "samhain server daemon" yule
+
+fi
+exit 0
+
+%post
+if test "x@sh_lkm@" = x; then
+ :
+else
+ if test -f /sbin/depmod; then
+ /sbin/depmod -a
+ fi
+fi
+if [ "$1" -ge 1 ]; then
+ # Activate boot-time start up
+ cd /var/lib/samhain
+ /bin/sh ./samhain-install.sh --verbose install-boot
+ rm -f ./samhain.startLSB
+ rm -f ./samhain.startLinux
+ if [ -f /usr/local/sbin/samhain_stealth ]; then
+ rm -f samhain-install.sh
+ fi
+ shkeep=yes
+ if test x"$shkeep" = xno; then
+ rm -f ./samhain-install.sh
+ rm -f /usr/local/sbin/samhain_stealth
+ fi
+fi
+if [ "$1" = 1 ]; then
+ if test -f /usr/lib/lsb/install_initd; then
+ /usr/lib/lsb/install_initd /etc/init.d/samhain
+ fi
+fi
+
+%if "%{name}" != "yule"
+cat << EOF
+
+Samhain is installed but is NOT running yet, and the database of
+file signatures is NOT initialized yet. Read the documentation,
+review configuration files, and then (i) initialize it
+(/usr/local/sbin/samhain -t init)
+and (ii) start it manually
+(/usr/local/sbin/samhain start).
+
+It is configured to start automatically on the next boot for runlevels
+[2-5].
+
+EOF
+%endif
+%if "%{name}" == "yule"
+cat << EOF
+
+Yule is installed but is NOT running yet, read the documentation,
+review configuration files, and then start it
+(/usr/local/sbin/yule)
+
+It is configured to start automatically on the next boot for runlevels
+[2-5].
+
+EOF
+%endif
+
+%preun
+# stop running instance of samhain, if any
+if [ -f /run/%{name}.pid ]; then
+ /usr/local/sbin/samhain stop
+fi
+if [ "$1" = 0 ]; then
+ # remove boot-time scripts and links
+ cd /var/lib/samhain
+ if [ -f ./samhain-install.sh ]; then
+ /bin/sh ./samhain-install.sh --verbose uninstall-boot
+ else
+ if test -f /usr/lib/lsb/remove_initd; then
+ /usr/lib/lsb/remove_initd /etc/init.d/samhain
+ fi
+ rm -f /etc/init.d/samhain
+ fi
+fi
+
+
+
+%files -f sh_file_list
+%defattr(-,root,root)
+%dir /run
+%dir /var/log
+%doc docs/BUGS COPYING docs/Changelog
+%doc LICENSE docs/FAQ.html docs/HOWTO* docs/MANUAL-2_4.* docs/README*
+/var/lib/samhain
+%if "%{withstg_prg}" == "xsamhain_stealth"
+ /usr/local/sbin/samhain_stealth
+%endif
+%if "%{withpwd_prg}" == "xDSH_WITH_CLIENT"
+ /usr/local/sbin/samhain_setpwd
+%endif
+%if "%{withpwd_prg}" == "xDSH_WITH_SERVER"
+ /usr/local/sbin/samhainctl
+ %exclude /usr/local/sbin/samhain_setpwd
+%endif
+%attr(644,root,root) /usr/local/man/man5/samhain*
+%attr(644,root,root) /usr/local/man/man8/samhain*
+%attr(644,root,root) /etc/logrotate.d/samhain
+%if "%{name}" == "yule"
+%attr(750,root,samhain) /var/lib/samhain
+%attr(750,yule,samhain) /var/log
+%endif
+%config(noreplace) /etc/samhainrc
+
+%changelog
+* Tue Oct 23 2012 Rainer Wichmann
+- fixes for yule installation
+
+* Tue May 16 2006 Rainer Wichmann
+- fix manual version, noticed by Imre Gergely
+
+* Tue Apr 05 2005 Rainer Wichmann
+- disable automatic stripping, use sstrip
+
+* Thu Mar 17 2005 Rainer Wichmann
+- fixes for enable-khide
+
+* Wed Oct 20 2004 Rainer Wichmann
+- more fixes for client/server detection
+- fix for samhain_stealth
+
+* Sun Aug 15 2004 Rainer Wichmann
+- fix detection of client/server
+
+* Sat Jun 19 2004 Rainer Wichmann
+- replace ./test.sh $i with make test$i
+- add logic for rpm-light (remove some more files after install)
+- make postun posix compliant (avoid empty argument list for rm -f)
+
+* Wed Dec 31 2003 Stijn Jonker <sjcjonker@sjc.nl>
+- Fixed correctly build of yule-*-rpm
+- Fixed excluding of yule_setpwd, and including of yulectl on yule build
+- Fixed including of samhain_setpwd in samhain client build
+- Above changes required for correct build in newer rpms,
+ with defaults for abort on unpacked files due to
+ %_unpackaged_files_terminate_build 1 setting
+- Fixed installation text for yule, not to display samhain text
+- Added /sbin/chkconfig install_name on to enable the rc scripts
+
+* Thu Dec 11 2003 Christian Vanguers <cva at molis dot be>
+- Fixed typo in samhain.spec
+- Compiled on RedHat Enterprise Linux ES 3
+
+* Thu Mar 26 2003 Rainer Wichmann
+- strip REQ_FROM_SERVER in config file path (%config(noreplace) ...)
+
+* Sun Jan 12 2003 Rainer Wichmann <support at la-samhna dot de>
+- replace %configure with ./configure
+
+* Tue Dec 24 2002 Rainer Wichmann <support at la-samhna dot de>
+- backported applicable changes to samhain.spec.in
+- warn user that database must be initialized
+- fix version of MANUAL in '%files'
+- test for chkconfig, use only if found
+
+* Sun Dec 22 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.7.0
+- fixed typo with _usr macro on ./configure
+- stops running samhain before uninstall
+- implemented conditionals to allow proper uninstalls/upgrades
+- 'BuildPreReq: gpg' is considered only if '--with gpg' is provided
+- run 'chkconfig' to activate samhain after installation
+- warn user that samhain must be manually started after
+ install/upgrade
+
+* Fri Dec 20 2002 Rainer Wichmann <support at la-samhna dot de>
+- backported to samhain.spec.in (take over user's choices from configure)
+- also save samhain.startLSB and samhain.startSuSE for install-boot
+
+* Thu Dec 19 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- optional parameters '--with gpg' and '--with tests'
+- use of pre-defined macros whenever possible
+
+* Wed Dec 18 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- Fixed installation process, avoiding hardcoded paths on the binaries
+ (thks to samhain's author Rainer Wichmann)
+
+* Mon Dec 16 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- First attempt to build from sources
+
diff --git a/samhain.spec.in b/samhain.spec.in
new file mode 100644
index 0000000..d73ea55
--- /dev/null
+++ b/samhain.spec.in
@@ -0,0 +1,289 @@
+#
+# Accepted parameters for 'rpmbuild':
+#
+# --with tests - make tests before building
+
+Summary: File integrity and host-based IDS
+Name: @install_name@
+Version: @VERSION@
+Release: 1
+License: GPL
+Group: System Environment/Base
+Source: samhain-%{version}.tar.gz
+BuildRoot: %{_tmppath}/samhain-%{version}-root
+Packager: Andre Oliveira da Costa <brblueser@uol.com.br>
+Provides: %{name}
+Requires(pre): shadow-utils
+
+# dummy (fix configure warning)
+# datarootdir = @datarootdir@
+
+# no quotes here - aparently will be expanded literally
+
+%define password %(echo $PASSWORD)
+
+%define withpwd_prg x@clmytclient@
+%define withstg_prg x@stegin_prg@
+
+# disable automatic stripping of binaries upon installation
+%define __spec_install_post %{nil}
+# required because DeadRat wants to package some debug info otherwise
+# (this debug info would be created by debug_install_post called
+# from spec_install_post)
+%define debug_package %{nil}
+# Use internal dependency generator rather than external helpers?
+%define _use_internal_dependency_generator 0
+
+%description
+@install_name@ is an open source file integrity and host-based intrusion
+detection system for Linux and Unix. It can run as a daemon process, and
+and thus can remember file changes -- contrary to a tool that runs from
+cron, if a file is modified you will get only one report, while
+subsequent checks of that file will ignore the modification as it is
+already reported (unless the file is modified again).
+
+@install_name@ can optionally be used as client/server system to provide
+centralized monitoring for multiple host. Logging to a (MySQL or
+PostgreSQL) database is supported.
+
+NOTE: for security reasons, if you distribute binary executables to
+third parties you should point out the use of the --add-key option to
+modify the key material within the executable.
+This spec file is intended to facilitate installation on YOUR system.
+If you use this spec file to build a SRPM for distribution to third parties,
+make sure to remove the --enable-base configure option below.
+
+%prep
+%setup -q -n samhain-%{version}
+
+%build
+%if %{?_with_tests:1}%{!?_with_tests:0}
+# test installation (test #7 is only included if --with gpg has been
+# specified)
+for i in `seq 6` %{?_with_gpg:7}; do ./test/test.sh $i; done
+%endif
+#
+# configure with the user-supplied arguments to './configure'
+#
+./configure @mydefargs@
+make
+%if "%{withpwd_prg}" == "xDSH_WITH_CLIENT"
+%if 0%{?password}
+ ./samhain_setpwd samhain new %{password}
+ mv samhain samhain.old
+ mv samhain.new samhain
+%endif
+%endif
+
+
+%install
+rm -rf ${RPM_BUILD_ROOT}
+# sstrip shouldn't be used since binaries will be stripped later
+## cat << EOF > sstrip
+## #!/bin/sh
+## echo "*** SSTRIP DISABLED ***"
+## EOF
+make DESTDIR=${RPM_BUILD_ROOT} install
+# copy script files to /var/lib/samhain so that we can use them right
+# after the package is installed
+#
+install -m 700 samhain-install.sh init/samhain.startLinux init/samhain.startLSB ${RPM_BUILD_ROOT}@mydataroot@
+#
+# file list (helpful advice from Lars Kellogg-Stedman)
+#
+echo "@sbindir@/@install_name@" > sh_file_list
+find %{buildroot}/lib/modules \! -type d -print | \
+ sed 's,%{buildroot},,' >> sh_file_list
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%pre
+if test "x@install_name@" = "xyule"
+then
+ getent group samhain >/dev/null || groupadd -r samhain
+ getent passwd yule >/dev/null || \
+ useradd -r -g samhain -d @mydataroot@ -s /sbin/nologin \
+ -c "samhain server daemon" yule
+
+fi
+exit 0
+
+%post
+if test "x@sh_lkm@" = x; then
+ :
+else
+ if test -f /sbin/depmod; then
+ /sbin/depmod -a
+ fi
+fi
+if [ "$1" -ge 1 ]; then
+ # Activate boot-time start up
+ cd @mydataroot@
+ /bin/sh ./samhain-install.sh --verbose install-boot
+ rm -f ./samhain.startLSB
+ rm -f ./samhain.startLinux
+ if [ -f @sbindir@/@install_name@_stealth ]; then
+ rm -f samhain-install.sh
+ fi
+ shkeep=yes
+ if test x"$shkeep" = xno; then
+ rm -f ./samhain-install.sh
+ rm -f @sbindir@/@install_name@_stealth
+ fi
+fi
+if [ "$1" = 1 ]; then
+ if test -f /usr/lib/lsb/install_initd; then
+ /usr/lib/lsb/install_initd /etc/init.d/@install_name@
+ fi
+fi
+
+%if "%{name}" != "yule"
+cat << EOF
+
+Samhain is installed but is NOT running yet, and the database of
+file signatures is NOT initialized yet. Read the documentation,
+review configuration files, and then (i) initialize it
+(@sbindir@/samhain -t init)
+and (ii) start it manually
+(@sbindir@/samhain start).
+
+It is configured to start automatically on the next boot for runlevels
+[2-5].
+
+EOF
+%endif
+%if "%{name}" == "yule"
+cat << EOF
+
+Yule is installed but is NOT running yet, read the documentation,
+review configuration files, and then start it
+(@sbindir@/yule)
+
+It is configured to start automatically on the next boot for runlevels
+[2-5].
+
+EOF
+%endif
+
+%preun
+# stop running instance of samhain, if any
+if [ -f @mylockdir@/%{name}.pid ]; then
+ @sbindir@/@install_name@ stop
+fi
+if [ "$1" = 0 ]; then
+ # remove boot-time scripts and links
+ cd @mydataroot@
+ if [ -f ./samhain-install.sh ]; then
+ /bin/sh ./samhain-install.sh --verbose uninstall-boot
+ else
+ if test -f /usr/lib/lsb/remove_initd; then
+ /usr/lib/lsb/remove_initd /etc/init.d/@install_name@
+ fi
+ rm -f /etc/init.d/@install_name@
+ fi
+fi
+
+
+
+%files -f sh_file_list
+%defattr(-,root,root)
+%dir @mylockdir@
+%dir @mylogdir@
+%doc docs/BUGS COPYING docs/Changelog
+%doc LICENSE docs/FAQ.html docs/HOWTO* docs/MANUAL-2_4.* docs/README*
+@mydataroot@
+%if "%{withstg_prg}" == "xsamhain_stealth"
+ @sbindir@/@install_name@_stealth
+%endif
+%if "%{withpwd_prg}" == "xDSH_WITH_CLIENT"
+ @sbindir@/@install_name@_setpwd
+%endif
+%if "%{withpwd_prg}" == "xDSH_WITH_SERVER"
+ @sbindir@/@install_name@ctl
+ %exclude @sbindir@/@install_name@_setpwd
+%endif
+%attr(644,root,root) @mandir@/man5/@install_name@*
+%attr(644,root,root) @mandir@/man8/@install_name@*
+%attr(644,root,root) /etc/logrotate.d/@install_name@
+%if "%{name}" == "yule"
+%attr(750,root,samhain) @mydataroot@
+%attr(750,yule,samhain) @mylogdir@
+%endif
+%config(noreplace) @myrpmconffile@
+
+%changelog
+* Tue Oct 23 2012 Rainer Wichmann
+- fixes for yule installation
+
+* Tue May 16 2006 Rainer Wichmann
+- fix manual version, noticed by Imre Gergely
+
+* Tue Apr 05 2005 Rainer Wichmann
+- disable automatic stripping, use sstrip
+
+* Thu Mar 17 2005 Rainer Wichmann
+- fixes for enable-khide
+
+* Wed Oct 20 2004 Rainer Wichmann
+- more fixes for client/server detection
+- fix for samhain_stealth
+
+* Sun Aug 15 2004 Rainer Wichmann
+- fix detection of client/server
+
+* Sat Jun 19 2004 Rainer Wichmann
+- replace ./test.sh $i with make test$i
+- add logic for rpm-light (remove some more files after install)
+- make postun posix compliant (avoid empty argument list for rm -f)
+
+* Wed Dec 31 2003 Stijn Jonker <sjcjonker@sjc.nl>
+- Fixed correctly build of yule-*-rpm
+- Fixed excluding of yule_setpwd, and including of yulectl on yule build
+- Fixed including of samhain_setpwd in samhain client build
+- Above changes required for correct build in newer rpms,
+ with defaults for abort on unpacked files due to
+ %_unpackaged_files_terminate_build 1 setting
+- Fixed installation text for yule, not to display samhain text
+- Added /sbin/chkconfig install_name on to enable the rc scripts
+
+* Thu Dec 11 2003 Christian Vanguers <cva at molis dot be>
+- Fixed typo in samhain.spec
+- Compiled on RedHat Enterprise Linux ES 3
+
+* Thu Mar 26 2003 Rainer Wichmann
+- strip REQ_FROM_SERVER in config file path (%config(noreplace) ...)
+
+* Sun Jan 12 2003 Rainer Wichmann <support at la-samhna dot de>
+- replace %configure with ./configure
+
+* Tue Dec 24 2002 Rainer Wichmann <support at la-samhna dot de>
+- backported applicable changes to samhain.spec.in
+- warn user that database must be initialized
+- fix version of MANUAL in '%files'
+- test for chkconfig, use only if found
+
+* Sun Dec 22 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.7.0
+- fixed typo with _usr macro on ./configure
+- stops running samhain before uninstall
+- implemented conditionals to allow proper uninstalls/upgrades
+- 'BuildPreReq: gpg' is considered only if '--with gpg' is provided
+- run 'chkconfig' to activate samhain after installation
+- warn user that samhain must be manually started after
+ install/upgrade
+
+* Fri Dec 20 2002 Rainer Wichmann <support at la-samhna dot de>
+- backported to samhain.spec.in (take over user's choices from configure)
+- also save samhain.startLSB and samhain.startSuSE for install-boot
+
+* Thu Dec 19 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- optional parameters '--with gpg' and '--with tests'
+- use of pre-defined macros whenever possible
+
+* Wed Dec 18 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- Fixed installation process, avoiding hardcoded paths on the binaries
+ (thks to samhain's author Rainer Wichmann)
+
+* Mon Dec 16 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- First attempt to build from sources
+
diff --git a/samhainrc.aix5.2.0 b/samhainrc.aix5.2.0
new file mode 100644
index 0000000..c9c0e07
--- /dev/null
+++ b/samhainrc.aix5.2.0
@@ -0,0 +1,236 @@
+#####################################################################
+#
+# AIX 5.2.0 configuration file for Samhain.
+#
+####################################################################
+#
+# Date : 23.10.2003
+# Author : Christoph Kiefer (chkiefer@intergga.ch)
+# Comment : Samhain client configuration file. Should work
+# for AIX 5.1.0. The Samhain version is 1.7.12
+# This configuration fits MY needs, YOU will
+# probably have to modify it.
+#
+# Changes : Date Name Remarks
+# 23.10.2003 Christoph Kiefer Initial Version
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#', ';' or '//' are ignored
+# -- boolean options can be Yes/No or True/False or 1/0
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+# SETUP for file system checking:
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) Section [EventSeverity]:
+# To each policy, you can assign a severity (further below).
+# (iii) Section [Log]:
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#####################################################################
+
+#####################################################################
+#
+# Files are defined with: file = /absolute/path
+#
+# Directories are defined with: dir = /absolute/path
+# or with an optional recursion depth (N <= 99): dir = N/absolute/path
+#
+# Directory inodes are checked. If you only want to check files
+# in a directory, but not the directory inode itself, use (e.g.):
+#
+# [ReadOnly]
+# dir = /some/directory
+# [IgnoreAll]
+# file = /some/directory
+#
+# You can use shell-style globbing patterns, like: file = /path/foo*
+#
+######################################################################
+
+[Misc]
+MessageHeader=""
+RedefLogFiles=-INO
+SetFilecheckTime=3600
+SetLoopTime=3600
+SetRecursionLevel=99
+DigestAlgo=SHA1
+ChecksumTest=check
+SetTimeServer=localhost
+ReportFullDetail=no
+Daemon=yes
+HideSetup=yes
+ReportOnlyOnce=yes
+UseLocalTime=yes
+
+## The Prelude-IDS profile to use for reporting
+## default value is "samhain"
+#
+# PreludeProfile = samhain
+
+## Map these samhain severities to impact severity 'info' severity
+#
+# PreludeMapToInfo =
+
+## Map these samhain severities to impact severity 'low' severity
+#
+# PreludeMapToLow = debug info
+
+## Map these samhain severities to impact severity 'medium' severity
+#
+# PreludeMapToMedium = notice warn err
+
+## Map these samhain severities to impact severity 'high' severity
+#
+# PreludeMapToHigh = crit alert
+
+[IgnoreAll]
+dir=-1/etc/objrepos
+dir=-1/etc/vg
+dir=-1/dev/.SRC-unix
+dir=-1/dev/pts
+dir=-1/opt
+dir=-1/tmp
+dir=-1/usr/share/lib/objrepos
+dir=-1/usr/share/man
+dir=-1/var/adm/cron
+dir=-1/var/tmp
+file=/dev/log*
+
+[Attributes]
+file=/etc/lpp/diagnostics/data/*
+file=/audit/auditb
+file=/dev
+# file=/etc/bootpd.dump
+file=/etc/bootptab
+file=/etc/inittab
+file=/etc/xtab
+dir=/dev
+dir=/usr/dt
+dir=/usr/lib/instl
+dir=/usr/lib/lpd
+dir=/usr/lib/mh
+dir=/usr/lib/sa
+dir=/usr/lpp
+
+[LogFiles]
+file=/etc/rmtab
+file=/etc/security/failedlogin
+file=/etc/security/lastlog
+file=/etc/security/portlog
+file=/etc/utmp
+# file=/smit.log
+file=/var/adm/*log*
+file=/var/adm/ras/*log*
+file=/var/adm/wtmp
+file=/var/log/*log*
+
+[IgnoreNone]
+file=/etc/tsh_profile
+
+[ReadOnly]
+dir=/etc/security/ldap
+file=/etc/*.cnf
+file=/etc/*conf*
+file=/etc/aliases
+file=/etc/dumpdates
+file=/etc/environment
+file=/etc/exports
+file=/etc/filesystems
+file=/etc/ftpusers
+file=/etc/group
+file=/etc/hosts*
+file=/etc/motd
+file=/etc/passwd
+file=/etc/profile
+file=/etc/protocols
+file=/etc/publickey
+file=/etc/rc.*
+file=/etc/rpc
+file=/etc/security/acl
+file=/etc/security/environ
+file=/etc/security/group
+file=/etc/security/limits
+file=/etc/security/login.cfg
+file=/etc/security/passwd
+file=/etc/security/roles
+file=/etc/security/smitacl.*
+file=/etc/security/user*
+file=/etc/sendmail.cf
+file=/etc/services
+file=/etc/sudoers
+file=/etc/swapspaces
+file=/etc/vfs
+# file=/smit.script
+dir=/etc/mail
+dir=/etc/rc.d
+dir=/etc/security/audit
+dir=/home/root
+dir=/sbin
+dir=/usr/X11R6
+dir=/usr/bin
+dir=/usr/ccs
+dir=/usr/etc
+dir=/usr/include
+dir=/usr/lib/boot
+dir=/usr/lib/methods
+dir=/usr/lib/microcode
+dir=/usr/lib/security
+dir=/usr/lib/smit
+dir=/usr/local/bin
+dir=/usr/sbin
+dir=/usr/share
+dir=/usr/ucb
+
+[EventSeverity]
+SeverityAttributes=crit
+SeverityDirs=err
+SeverityFiles=err
+SeverityGrowingLogs=warn
+SeverityIgnoreNone=crit
+SeverityLogFiles=crit
+SeverityReadOnly=crit
+SeverityIgnoreAll=info
+SeverityNames=info
+
+[Log]
+ExportClass=RUN FIL PANIC ERR ENET EINPUT
+LogSeverity=none
+MailSeverity=none
+PrintSeverity=none
+ExportSeverity=warn
+SyslogSeverity=warn
+
+## Logging to a Prelude-IDS
+##
+# PreludeSeverity = crit
+
+[SuidCheck]
+SuidCheckExclude=/proc
+SuidCheckActive=1
+SuidCheckInterval=1800
+SuidCheckFps=250
+#SuidCheckYield=no
+SeveritySuidCheck=alert
+#SuidCheckQuarantineFiles=yes
+#SuidCheckQuarantineMethod=0
+# SuidCheckQuarantineDelete = yes
+
+
+[Utmp]
+LoginCheckActive=1
+LoginCheckInterval=30
+SeverityLogin=info
+SeverityLogout=info
+SeverityLoginMulti=warn
+
+[EOF]
diff --git a/samhainrc.freebsd b/samhainrc.freebsd
new file mode 100644
index 0000000..844cf46
--- /dev/null
+++ b/samhainrc.freebsd
@@ -0,0 +1,709 @@
+#####################################################################
+#
+# FreeBSD Configuration file for samhain.
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#', ';' or '//' are ignored
+# -- boolean options can be Yes/No or True/False or 1/0
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+# SETUP for file system checking:
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) Section [EventSeverity]:
+# To each policy, you can assign a severity (further below).
+# (iii) Section [Log]:
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#####################################################################
+
+#####################################################################
+#
+# Files are defined with: file = /absolute/path
+#
+# Directories are defined with: dir = /absolute/path
+# or with an optional recursion depth (N <= 99): dir = N/absolute/path
+#
+# Directory inodes are checked. If you only want to check files
+# in a directory, but not the directory inode itself, use (e.g.):
+#
+# [ReadOnly]
+# dir = /some/directory
+# [IgnoreAll]
+# file = /some/directory
+#
+# You can use shell-style globbing patterns, like: file = /path/foo*
+#
+######################################################################
+
+[Misc]
+##
+## Add or subtract tests from the policies
+## - if you want to change their definitions,
+## you need to do that before using the policies
+##
+# RedefReadOnly = (no default)
+# RedefAttributes=(no default)
+# RedefLogFiles=(no default)
+# RedefGrowingLogFiles=(no default)
+# RedefIgnoreAll=(no default)
+# RedefIgnoreNone=(no default)
+# RedefUser0=(no default)
+# RedefUser1=(no default)
+
+#
+# --------- / --------------
+#
+
+[ReadOnly]
+dir = 0/
+
+[Attributes]
+file = /
+file = /proc
+file = /entropy
+file = /tmp
+file = /var
+
+#
+# --------- /dev -----------
+#
+
+[Attributes]
+dir = 99/dev
+
+[IgnoreAll]
+file = /dev/ttyp?
+
+[Misc]
+##
+## pseudo terminals are created/removed as needed
+##
+IgnoreAdded = /dev/(p|t)typ.*
+IgnoreMissing = /dev/(p|t)typ.*
+
+
+#
+# --------- /etc -----------
+#
+
+[ReadOnly]
+##
+## for these files, only access time is ignored
+##
+dir = 99/etc
+
+
+#
+# --------- /boot -----------
+#
+
+[ReadOnly]
+dir = 99/boot
+
+#
+# --------- /bin, /sbin -----------
+#
+
+[ReadOnly]
+dir = 99/bin
+dir = 99/sbin
+
+#
+# --------- /lib -----------
+#
+
+[ReadOnly]
+dir = 99/lib
+
+#
+# --------- /libexec -----------
+#
+
+[ReadOnly]
+dir = 99/libexec
+
+#
+# --------- /rescue -----------
+#
+
+[ReadOnly]
+dir = 99/rescue
+
+#
+# --------- /root -----------
+#
+
+[Attributes]
+##
+## for these files, only changes in permissions and ownership are checked
+##
+dir = 99/root
+
+#
+# --------- /stand -----------
+#
+
+[ReadOnly]
+dir = 99/stand
+
+#
+# --------- /usr -----------
+#
+
+[ReadOnly]
+dir = 99/usr
+
+[Attributes]
+dir = /usr/.snap
+dir = /usr/share/man/cat?
+file = /usr/compat/linux/etc
+file = /usr/compat/linux/etc/ld.so.cache
+
+[IgnoreAll]
+dir = -1/usr/home
+
+#
+# --------- /var -----------
+#
+
+[Attributes]
+
+dir = 0/var
+
+[LogFiles]
+##
+## for these files, changes in signature, timestamps, and size are ignored
+##
+
+file=/var/run/utmp
+
+[GrowingLogFiles]
+##
+## For these files, changes in signature, timestamps, and increase in size
+## are ignored. Logfile rotation will cause a report because of shrinking
+## size and different inode.
+##
+dir = 99/var/log
+
+[Attributes]
+#
+# rotated logs will change inode
+#
+file = /var/log/*.[0-9].bz2
+file = /var/log/*.[0-9].log
+file = /var/log/*.[0-9]
+file = /var/log/*.[0-9][0-9]
+file = /var/log/*.old
+
+file = /var/log/sendmail.st
+
+
+[Misc]
+#
+# Various naming schemes for rotated logs
+#
+IgnoreAdded = /var/log/.*\.[0-9]+$
+IgnoreAdded = /var/log/.*\.[0-9]+\.gz$
+IgnoreAdded = /var/log/.*\.[0-9]+\.bz2$
+IgnoreAdded = /var/log/.*\.[0-9]+\.log$
+
+
+[IgnoreNone]
+##
+## for these files, all modifications (even access time) are reported
+## - you may create some interesting-looking file (like /etc/safe_passwd),
+## just to watch whether someone will access it ...
+##
+
+
+
+[User0]
+[User1]
+## User0 and User1 are sections for files/dirs with user-definable checking
+## (see the manual)
+
+[EventSeverity]
+##
+## Here you can assign severities to policy violations.
+## If this severity exceeds the treshold of a log facility (see below),
+## a policy violation will be logged to that facility.
+##
+
+#
+# Severity for verification failures.
+#
+# SeverityReadOnly=crit
+# SeverityLogFiles=crit
+# SeverityGrowingLogs=crit
+# SeverityIgnoreNone=crit
+# SeverityAttributes=crit
+# SeverityUser0=crit
+# SeverityUser1=crit
+
+## We have a file in IgnoreAll that might or might not be present.
+## Setting the severity to 'info' prevents messages about deleted/new file.
+##
+# SeverityIgnoreAll=crit
+SeverityIgnoreAll=info
+
+## Files : file access problems
+# SeverityFiles=crit
+
+## Dirs : directory access problems
+# SeverityDirs=crit
+
+## Names : suspect (non-printable) characters in a pathname
+# SeverityNames=crit
+
+[Log]
+##
+## Switch on/OFF log facilities and set their threshold severity
+##
+## Values: debug, info, notice, warn, mark, err, crit, alert, none.
+## 'mark' is used for timestamps.
+##
+## Use 'none' to SWITCH OFF a log facility
+##
+## By default, everything equal to and above the threshold is logged.
+## The specifiers '*', '!', and '=' are interpreted as
+## 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+## at least on Linux). Examples:
+## MailSeverity=*
+## MailSeverity=!warn
+## MailSeverity==crit
+
+## E-mail
+##
+# MailSeverity=none
+
+## Console
+##
+# PrintSeverity=info
+
+## Logfile
+##
+# LogSeverity=mark
+
+## Syslog
+##
+# SyslogSeverity=none
+
+## Remote server (yule)
+##
+# ExportSeverity=none
+
+## External script or program
+##
+# ExternalSeverity = none
+
+## Logging to a database
+##
+# DatabaseSeverity = none
+
+## Logging to a Prelude-IDS
+##
+# PreludeSeverity = crit
+
+
+#####################################################
+#
+# Optional modules
+#
+#####################################################
+
+# [SuidCheck]
+##
+## --- Check the filesystem for SUID/SGID binaries
+##
+
+## Switch on
+#
+# SuidCheckActive = yes
+
+## Interval for check (seconds)
+#
+# SuidCheckInterval = 7200
+
+## Alternative: crontab-like schedule
+#
+# SuidCheckSchedule = NULL
+
+## Directory to exclude
+#
+# SuidCheckExclude = NULL
+
+## Limit on files per second (0 == no limit)
+#
+# SuidCheckFps = 0
+
+## Alternative: yield after every file
+#
+# SuidCheckYield = no
+
+## Severity of a detection
+#
+# SeveritySuidCheck = crit
+
+## Quarantine SUID/SGID files if found
+#
+# SuidCheckQuarantineFiles = yes
+
+## Method for Quarantining files:
+# 0 - Delete the file.
+# 1 - Remove SUID/SGID permissions from file.
+# 2 - Move SUID/SGID file to quarantine dir.
+#
+# SuidCheckQuarantineMethod = 0
+
+## For method 1 and 3, really delete instead of truncating
+#
+# SuidCheckQuarantineDelete = yes
+
+
+# [Utmp]
+##
+## --- Logging of login/logout events
+##
+
+## Switch on/off
+#
+# LoginCheckActive = True
+
+## Severity for logins, multiple logins, logouts
+#
+# SeverityLogin=info
+# SeverityLoginMulti=warn
+# SeverityLogout=info
+
+## Interval for login/logout checks
+#
+# LoginCheckInterval = 300
+
+
+# [Database]
+##
+## --- Logging to a relational database
+##
+
+## Database name
+#
+# SetDBName = samhain
+
+## Database table
+#
+# SetDBTable = log
+
+## Database user
+#
+# SetDBUser = samhain
+
+## Database password
+#
+# SetDBPassword = (default: none)
+
+## Database host
+#
+# SetDBHost = localhost
+
+## Log the server timestamp for received messages
+#
+# SetDBServerTstamp = True
+
+## Use a persistent connection
+#
+# UsePersistent = True
+
+
+# [External]
+##
+## Interface to call external scripts/programs for logging
+##
+
+## The absolute path to the command
+## - Each invocation of this directive will end the definition of the
+## preceding command, and start the definition of
+## an additional, new command
+#
+# OpenCommand = (no default)
+
+## Type (log or srv)
+## - log for log messages, srv for messages received by the server
+#
+# SetType = log
+
+## The command (full command line) to execute
+#
+# SetCommandLine = (no default)
+
+## The environment (KEY=value; repeat for more)
+#
+# SetEnviron = TZ=(your timezone)
+
+## The TIGER192 checksum (optional)
+#
+# SetChecksum = (no default)
+
+## User who runs the command
+#
+# SetCredentials = (default: samhain process uid)
+
+## Words not allowed in message
+#
+# SetFilterNot = (none)
+
+## Words required (ALL of them)
+#
+# SetFilterAnd = (none)
+
+## Words required (at least one)
+#
+# SetFilterOr = (none)
+
+## Deadtime between consecutive calls
+#
+# SetDeadtime = 0
+
+## Add default environment (HOME, PATH, SHELL)
+#
+# SetDefault = no
+
+
+
+#####################################################
+#
+# Miscellaneous configuration options
+#
+#####################################################
+
+[Misc]
+
+## whether to become a daemon process
+## (this is not honoured on database initialisation)
+#
+# Daemon = no
+Daemon = yes
+
+# whether to test signature of files (init/check/none)
+# - if 'none', then we have to decide this on the command line -
+#
+# ChecksumTest = none
+ChecksumTest=check
+
+# Set nice level (-19 to 19, see 'man nice'),
+# and I/O limit (kilobytes per second; 0 == off)
+# to reduce load on host.
+#
+# SetNiceLevel = 0
+# SetIOLimit = 0
+
+## The version string to embed in file signature databases
+#
+# VersionString = NULL
+
+## Interval between time stamp messages
+#
+# SetLoopTime = 60
+SetLoopTime = 600
+
+## Interval between file checks
+#
+# SetFileCheckTime = 600
+SetFileCheckTime = 7200
+
+## Alternative: crontab-like schedule
+#
+# FileCheckScheduleOne = NULL
+
+## Alternative: crontab-like schedule(2)
+#
+# FileCheckScheduleTwo = NULL
+
+## Report only once on modified files
+## Setting this to 'FALSE' will generate a report for any policy
+## violation (old and new ones) each time the daemon checks the file system.
+#
+# ReportOnlyOnce = True
+
+## Report in full detail
+#
+# ReportFullDetail = False
+
+## Report file timestamps in local time rather than GMT
+#
+# UseLocalTime = No
+
+## The console device (can also be a file or named pipe)
+## - There are two console devices. Accordingly, you can use
+## this directive a second time to set the second console device.
+## If you have not defined the second device at compile time,
+## and you don't want to use it, then:
+## setting it to /dev/null is less effective than just leaving
+## it alone (setting to /dev/null will waste time by opening
+## /dev/null and writing to it)
+#
+# SetConsole = /dev/console
+
+## Activate the SysV IPC message queue
+#
+# MessageQueueActive = False
+
+
+## If false, skip reverse lookup when connecting to a host known
+## by name rather than IP address (i.e. trust the DNS)
+#
+# SetReverseLookup = True
+
+
+## --- E-Mail ---
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# SetMailTime = 86400
+
+## Maximum number of mails to queue
+#
+# SetMailNum = 10
+
+## Recipient (max. 8)
+#
+# SetMailAddress=root@localhost
+
+## Mail relay (IP address)
+#
+# SetMailRelay = NULL
+
+## Custom subject format
+#
+# MailSubject = NULL
+
+## --- end E-Mail ---
+
+
+## Path to the executable. If set, will be checksummed after startup
+## and before exit.
+#
+# SamhainPath = (no default)
+
+
+## The IP address of the log server
+#
+# SetLogServer = (default: compiled-in)
+
+## The IP address of the time server
+#
+# SetTimeServer = (default: compiled-in)
+
+## Trusted Users (comma delimited list of user names)
+#
+# TrustedUser = (no default; this adds to the compiled-in list)
+
+## Path to the file signature database
+#
+# SetDatabasePath = (default: compiled-in)
+
+## Path to the log file
+#
+# SetLogfilePath = (default: compiled-in)
+
+## Path to the PID file
+#
+# SetLockfilePath = (default: compiled-in)
+
+
+## The digest/checksum/hash algorithm
+#
+# DigestAlgo = TIGER192
+
+
+## Custom format for message header.
+## CAREFUL if you use XML logfile format.
+##
+## %S severity
+## %T timestamp
+## %C class
+##
+## %F source file
+## %L source line
+#
+# MessageHeader="%S %T "
+
+
+## Don't log path to config/database file on startup
+#
+# HideSetup = False
+
+## The syslog facility, if you log to syslog
+#
+# SyslogFacility = LOG_AUTHPRIV
+SyslogFacility=LOG_LOCAL2
+
+## The message authentication method
+## - If you change this, you *must* change it
+## on client *and* server
+#
+# MACType = HMAC-TIGER
+
+
+## The Prelude-IDS profile to use for reporting
+## default value is "samhain"
+#
+# PreludeProfile = samhain
+
+## Map these samhain severities to impact severity 'info' severity
+#
+# PreludeMapToInfo =
+
+## Map these samhain severities to impact severity 'low' severity
+#
+# PreludeMapToLow = debug info
+
+## Map these samhain severities to impact severity 'medium' severity
+#
+# PreludeMapToMedium = notice warn err
+
+## Map these samhain severities to impact severity 'high' severity
+#
+# PreludeMapToHigh = crit alert
+
+# everything below is ignored
+[EOF]
+
+#####################################################################
+# This would be the proper syntax for parts that should only be
+# included for certain hosts.
+# You may enclose anything in a @HOSTNAME/@end bracket, as long as the
+# result still has the proper syntax for the config file.
+# You may have any number of @HOSTNAME/@end brackets.
+# HOSTNAME should be the fully qualified 'official' name
+# (e.g. 'nixon.watergate.com', not 'nixon'), no aliases.
+# No IP number - except if samhain cannot determine the
+# fully qualified hostname.
+#
+# @HOSTNAME
+# file=/foo/bar
+# @end
+#
+# These are two examples for conditional inclusion/exclusion
+# of a machine based on the output from 'uname -srm'
+# $Linux:2.*.7:i666
+# file=/foo/bar3
+# $end
+#
+# !$Linux:2.*.7:i686
+# file=/foo/bar2
+# $end
+#
+#####################################################################
diff --git a/samhainrc.linux b/samhainrc.linux
new file mode 100644
index 0000000..02906bb
--- /dev/null
+++ b/samhainrc.linux
@@ -0,0 +1,753 @@
+#####################################################################
+#
+# Configuration file template for samhain.
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#', ';' or '//' are ignored
+# -- boolean options can be Yes/No or True/False or 1/0
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+#
+# SETUP for file system checking:
+#
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) Section [EventSeverity]:
+# To each policy, you can assign a severity (further below).
+# (iii) Section [Log]:
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+
+#####################################################################
+#
+# Files are defined with: file = /absolute/path
+#
+# Directories are defined with: dir = /absolute/path
+# or with an optional recursion depth (N <= 99): dir = N/absolute/path
+#
+# Directory inodes are checked. If you only want to check files
+# in a directory, but not the directory inode itself, use (e.g.):
+#
+# [ReadOnly]
+# dir = /some/directory
+# [IgnoreAll]
+# file = /some/directory
+#
+# You can use shell-style globbing patterns, like: file = /path/foo*
+#
+######################################################################
+
+[Misc]
+##
+## Add or subtract tests from the policies
+## - if you want to change their definitions,
+## you need to do that before using the policies
+##
+# RedefReadOnly = (no default)
+# RedefAttributes=(no default)
+# RedefLogFiles=(no default)
+# RedefGrowingLogFiles=(no default)
+# RedefIgnoreAll=(no default)
+# RedefIgnoreNone=(no default)
+
+# RedefUser0=(no default)
+# RedefUser1=(no default)
+
+#
+# --------- / --------------
+#
+
+[ReadOnly]
+dir = 0/
+
+[Attributes]
+file = /tmp
+file = /dev
+file = /media
+file = /proc
+file = /sys
+
+#
+# --------- /etc -----------
+#
+
+[ReadOnly]
+##
+## for these files, only access time is ignored
+##
+dir = 99/etc
+
+[Attributes]
+##
+## check permission and ownership
+##
+file = /etc/mtab
+file = /etc/adjtime
+file = /etc/motd
+file = /etc/lvm/.cache
+
+# On Ubuntu, these are in /var/lib rather than /etc
+file = /etc/cups/certs
+file = /etc/cups/certs/0
+
+# managed by fstab-sync on Fedora Core
+file = /etc/fstab
+
+# modified when booting
+file = /etc/sysconfig/hwconf
+
+# There are files in /etc that might change, thus changing the directory
+# timestamps. Put it here as 'file', and in the ReadOnly section as 'dir'.
+
+file = /etc
+
+#
+# --------- /boot -----------
+#
+
+[ReadOnly]
+dir = 99/boot
+
+#
+# --------- /bin, /sbin -----------
+#
+
+[ReadOnly]
+dir = 99/bin
+dir = 99/sbin
+
+#
+# --------- /lib -----------
+#
+
+[ReadOnly]
+dir = 99/lib
+
+#
+# --------- /dev -----------
+#
+
+[Attributes]
+dir = 99/dev
+
+[IgnoreAll]
+##
+## pseudo terminals are created/removed as needed
+##
+dir = -1/dev/pts
+
+# dir = -1/dev/.udevdb
+
+file = /dev/ppp
+
+#
+# --------- /usr -----------
+#
+
+[ReadOnly]
+dir = 99/usr
+
+#
+# --------- /var -----------
+#
+
+[ReadOnly]
+dir = 99/var
+
+[IgnoreAll]
+dir = -1/var/cache
+dir = -1/var/backups
+dir = -1/var/games
+dir = -1/var/gdm
+dir = -1/var/lock
+dir = -1/var/mail
+dir = -1/var/run
+dir = -1/var/spool
+dir = -1/var/tmp
+dir = -1/var/lib/texmf
+dir = -1/var/lib/scrollkeeper
+
+
+[Attributes]
+
+dir = /var/lib/nfs
+dir = /var/lib/pcmcia
+
+# /var/lib/rpm changes if packets are installed;
+# /var/lib/rpm/__db.00[123] even more frequently
+file = /var/lib/rpm/__db.00?
+
+file = /var/lib/acpi-support/vbestate
+file = /var/lib/alsa/asound.state
+file = /var/lib/apt/lists/lock
+file = /var/lib/apt/lists/partial
+file = /var/lib/cups/certs
+file = /var/lib/cups/certs/0
+file = /var/lib/dpkg/lock
+file = /var/lib/gdm
+file = /var/lib/gdm/.cookie
+file = /var/lib/gdm/.gdmfifo
+file = /var/lib/gdm/:0.Xauth
+file = /var/lib/gdm/:0.Xservers
+file = /var/lib/logrotate/status
+file = /var/lib/mysql
+file = /var/lib/mysql/ib_logfile0
+file = /var/lib/mysql/ibdata1
+file = /var/lib/slocate
+file = /var/lib/slocate/slocate.db
+file = /var/lib/slocate/slocate.db.tmp
+file = /var/lib/urandom
+file = /var/lib/urandom/random-seed
+file = /var/lib/random-seed
+file = /var/lib/xkb
+
+
+[GrowingLogFiles]
+##
+## For these files, changes in signature, timestamps, and increase in size
+## are ignored. Logfile rotation will cause a report because of shrinking
+## size and different inode.
+##
+dir = 99/var/log
+
+[Attributes]
+#
+# rotated logs will change inode
+#
+file = /var/log/*.[0-9].gz
+file = /var/log/*.[0-9].log
+file = /var/log/*.[0-9]
+file = /var/log/*.old
+file = /var/log/*/*.[0-9].gz
+file = /var/log/*/*.[0-9][0-9].gz
+file = /var/log/*/*.log.[0-9]
+
+[Misc]
+#
+# Various naming schemes for rotated logs
+#
+IgnoreAdded = /var/log/.*\.[0-9]+$
+IgnoreAdded = /var/log/.*\.[0-9]+\.gz$
+IgnoreAdded = /var/log/.*\.[0-9]+\.log$
+#
+# Subdirectories
+#
+IgnoreAdded = /var/log/[[:alnum:]]+/.*\.[0-9]+$
+IgnoreAdded = /var/log/[[:alnum:]]+/.*\.[0-9]+\.gz$
+IgnoreAdded = /var/log/[[:alnum:]]+/.*\.[0-9]+\.log$
+#
+IgnoreAdded = /var/lib/slocate/slocate.db.tmp
+IgnoreMissing = /var/lib/slocate/slocate.db.tmp
+
+#
+# --------- other policies -----------
+#
+
+[IgnoreNone]
+##
+## for these files, all modifications (even access time) are reported
+## - you may create some interesting-looking file (like /etc/safe_passwd),
+## just to watch whether someone will access it ...
+##
+
+[Prelink]
+##
+## Use for prelinked files or directories holding them
+##
+
+
+[User0]
+[User1]
+## User0 and User1 are sections for files/dirs with user-definable checking
+## (see the manual)
+
+
+
+[EventSeverity]
+##
+## Here you can assign severities to policy violations.
+## If this severity exceeds the treshold of a log facility (see below),
+## a policy violation will be logged to that facility.
+##
+## Severity for verification failures.
+##
+# SeverityReadOnly=crit
+# SeverityLogFiles=crit
+# SeverityGrowingLogs=crit
+# SeverityIgnoreNone=crit
+# SeverityAttributes=crit
+# SeverityUser0=crit
+# SeverityUser1=crit
+# SeverityIgnoreAll=crit
+
+
+## Files : file access problems
+# SeverityFiles=crit
+
+## Dirs : directory access problems
+# SeverityDirs=crit
+
+## Names : suspect (non-printable) characters in a pathname
+# SeverityNames=crit
+
+[Log]
+##
+## Switch on/OFF log facilities and set their threshold severity
+##
+## Values: debug, info, notice, warn, mark, err, crit, alert, none.
+## 'mark' is used for timestamps.
+##
+##
+## Use 'none' to SWITCH OFF a log facility
+##
+## By default, everything equal to and above the threshold is logged.
+## The specifiers '*', '!', and '=' are interpreted as
+## 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+## at least on Linux). Examples:
+## MailSeverity=*
+## MailSeverity=!warn
+## MailSeverity==crit
+
+## E-mail
+##
+# MailSeverity=none
+
+## Console
+##
+# PrintSeverity=info
+
+## Logfile
+##
+# LogSeverity=mark
+
+## Syslog
+##
+# SyslogSeverity=none
+
+## Remote server (yule)
+##
+# ExportSeverity=none
+
+## External script or program
+##
+# ExternalSeverity = none
+
+## Logging to a database
+##
+# DatabaseSeverity = none
+
+## Logging to a Prelude-IDS
+##
+# PreludeSeverity = crit
+
+
+
+#####################################################
+#
+# Optional modules
+#
+#####################################################
+
+# [SuidCheck]
+##
+## --- Check the filesystem for SUID/SGID binaries
+##
+
+## Switch on
+#
+# SuidCheckActive = yes
+
+## Interval for check (seconds)
+#
+# SuidCheckInterval = 7200
+
+## Alternative: crontab-like schedule
+#
+# SuidCheckSchedule = NULL
+
+## Directory to exclude
+#
+# SuidCheckExclude = NULL
+
+## Limit on files per second (0 == no limit)
+#
+# SuidCheckFps = 0
+
+## Alternative: yield after every file
+#
+# SuidCheckYield = no
+
+## Severity of a detection
+#
+# SeveritySuidCheck = crit
+
+## Quarantine SUID/SGID files if found
+#
+# SuidCheckQuarantineFiles = yes
+
+## Method for Quarantining files:
+# 0 - Delete or truncate the file.
+# 1 - Remove SUID/SGID permissions from file.
+# 2 - Move SUID/SGID file to quarantine dir.
+#
+# SuidCheckQuarantineMethod = 0
+
+## For method 1 and 3, really delete instead of truncating
+#
+# SuidCheckQuarantineDelete = yes
+
+
+# [Utmp]
+##
+## --- Logging of login/logout events
+##
+
+## Switch on/off
+#
+# LoginCheckActive = True
+
+## Severity for logins, multiple logins, logouts
+#
+# SeverityLogin=info
+# SeverityLoginMulti=warn
+# SeverityLogout=info
+
+## Interval for login/logout checks
+#
+# LoginCheckInterval = 300
+
+
+# [Database]
+##
+## --- Logging to a relational database
+##
+
+## Database name
+#
+# SetDBName = samhain
+
+## Database table
+#
+# SetDBTable = log
+
+## Database user
+#
+# SetDBUser = samhain
+
+## Database password
+#
+# SetDBPassword = (default: none)
+
+## Database host
+#
+# SetDBHost = localhost
+
+## Log the server timestamp for received messages
+#
+# SetDBServerTstamp = True
+
+## Use a persistent connection
+#
+# UsePersistent = True
+
+# [External]
+##
+## Interface to call external scripts/programs for logging
+##
+
+## The absolute path to the command
+## - Each invocation of this directive will end the definition of the
+## preceding command, and start the definition of
+## an additional, new command
+#
+# OpenCommand = (no default)
+
+## Type (log or rv)
+## - log for log messages, srv for messages received by the server
+#
+# SetType = log
+
+## The command (full command line) to execute
+#
+# SetCommandLine = (no default)
+
+## The environment (KEY=value; repeat for more)
+#
+# SetEnviron = TZ=(your timezone)
+
+## The TIGER192 checksum (optional)
+#
+# SetChecksum = (no default)
+
+## User who runs the command
+#
+# SetCredentials = (default: samhain process uid)
+
+## Words not allowed in message
+#
+# SetFilterNot = (none)
+
+## Words required (ALL of them)
+#
+# SetFilterAnd = (none)
+
+## Words required (at least one)
+#
+# SetFilterOr = (none)
+
+## Deadtime between consecutive calls
+#
+# SetDeadtime = 0
+
+## Add default environment (HOME, PATH, SHELL)
+#
+# SetDefault = no
+
+
+#####################################################
+#
+# Miscellaneous configuration options
+#
+#####################################################
+
+[Misc]
+
+## whether to become a daemon process
+## (this is not honoured on database initialisation)
+#
+# Daemon = no
+Daemon = yes
+
+## whether to test signature of files (init/check/none)
+## - if 'none', then we have to decide this on the command line -
+#
+# ChecksumTest = none
+ChecksumTest=check
+
+## Set nice level (-19 to 19, see 'man nice'),
+## and I/O limit (kilobytes per second; 0 == off)
+## to reduce load on host.
+#
+# SetNiceLevel = 0
+# SetIOLimit = 0
+
+## The version string to embed in file signature databases
+#
+# VersionString = NULL
+
+## Interval between time stamp messages
+#
+# SetLoopTime = 60
+SetLoopTime = 600
+
+## Interval between file checks
+#
+# SetFileCheckTime = 600
+SetFileCheckTime = 7200
+
+## Alternative: crontab-like schedule
+#
+# FileCheckScheduleOne = NULL
+
+## Alternative: crontab-like schedule(2)
+#
+# FileCheckScheduleTwo = NULL
+
+## Report only once on modified files
+## Setting this to 'FALSE' will generate a report for any policy
+## violation (old and new ones) each time the daemon checks the file system.
+#
+# ReportOnlyOnce = True
+
+## Report in full detail
+#
+# ReportFullDetail = False
+
+## Report file timestamps in local time rather than GMT
+#
+# UseLocalTime = No
+
+## The console device (can also be a file or named pipe)
+## - There are two console devices. Accordingly, you can use
+## this directive a second time to set the second console device.
+## If you have not defined the second device at compile time,
+## and you don't want to use it, then:
+## setting it to /dev/null is less effective than just leaving
+## it alone (setting to /dev/null will waste time by opening
+## /dev/null and writing to it)
+#
+# SetConsole = /dev/console
+
+## Activate the SysV IPC message queue
+#
+# MessageQueueActive = False
+
+
+## If false, skip reverse lookup when connecting to a host known
+## by name rather than IP address (i.e. trust the DNS)
+#
+# SetReverseLookup = True
+
+## --- E-Mail ---
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# SetMailTime = 86400
+
+## Maximum number of mails to queue
+#
+# SetMailNum = 10
+
+## Recipient (max. 8)
+#
+# SetMailAddress=root@localhost
+
+## Mail relay (IP address)
+#
+# SetMailRelay = NULL
+
+## Custom subject format
+#
+# MailSubject = NULL
+
+## --- end E-Mail ---
+
+## Path to the prelink executable
+#
+# SetPrelinkPath = /usr/sbin/prelink
+
+## TIGER192 checksum of the prelink executable
+#
+# SetPrelinkChecksum = (no default)
+
+
+## Path to the executable. If set, will be checksummed after startup
+## and before exit.
+#
+# SamhainPath = (no default)
+
+
+## The IP address of the log server
+#
+# SetLogServer = (default: compiled-in)
+
+## The IP address of the time server
+#
+# SetTimeServer = (default: compiled-in)
+
+## Trusted Users (comma delimited list of user names)
+#
+# TrustedUser = (no default; this adds to the compiled-in list)
+
+## Path to the file signature database
+#
+# SetDatabasePath = (default: compiled-in)
+
+## Path to the log file
+#
+# SetLogfilePath = (default: compiled-in)
+
+## Path to the PID file
+#
+# SetLockfilePath = (default: compiled-in)
+
+
+## The digest/checksum/hash algorithm
+#
+# DigestAlgo = TIGER192
+
+
+## Custom format for message header.
+## CAREFUL if you use XML logfile format.
+##
+## %S severity
+## %T timestamp
+## %C class
+##
+## %F source file
+## %L source line
+#
+# MessageHeader="%S %T "
+
+
+## Don't log path to config/database file on startup
+#
+# HideSetup = False
+
+## The syslog facility, if you log to syslog
+#
+# SyslogFacility = LOG_AUTHPRIV
+SyslogFacility=LOG_LOCAL2
+
+## The message authentication method
+## - If you change this, you *must* change it
+## on client *and* server
+#
+# MACType = HMAC-TIGER
+
+
+## The Prelude-IDS profile to use for reporting
+## default value is "samhain"
+#
+# PreludeProfile = samhain
+
+## Map these samhain severities to impact severity 'info' severity
+#
+# PreludeMapToInfo =
+
+## Map these samhain severities to impact severity 'low' severity
+#
+# PreludeMapToLow = debug info
+
+## Map these samhain severities to impact severity 'medium' severity
+#
+# PreludeMapToMedium = notice warn err
+
+## Map these samhain severities to impact severity 'high' severity
+#
+# PreludeMapToHigh = crit alert
+
+
+## everything below is ignored
+[EOF]
+
+#####################################################################
+# This would be the proper syntax for parts that should only be
+# included for certain hosts.
+# You may enclose anything in a @HOSTNAME/@end bracket, as long as the
+# result still has the proper syntax for the config file.
+# You may have any number of @HOSTNAME/@end brackets.
+# HOSTNAME should be the fully qualified 'official' name
+# (e.g. 'nixon.watergate.com', not 'nixon'), no aliases.
+# No IP number - except if samhain cannot determine the
+# fully qualified hostname.
+#
+# @HOSTNAME
+# file=/foo/bar
+# @end
+#
+# These are two examples for conditional inclusion/exclusion
+# of a machine based on the output from 'uname -srm'
+# $Linux:2.*.7:i666
+# file=/foo/bar3
+# $end
+#
+# !$Linux:2.*.7:i686
+# file=/foo/bar2
+# $end
+#
+#####################################################################
diff --git a/samhainrc.netbsd b/samhainrc.netbsd
new file mode 100644
index 0000000..f3172b0
--- /dev/null
+++ b/samhainrc.netbsd
@@ -0,0 +1,843 @@
+#
+# From pkgsrc-wip, Author: Brian Seklecki
+#
+
+[Misc]
+RedefUser0=+INO, +SIZ, +RDEV, +CHK, -MOD, -MTM, -ATM, -CTM, -GRP, -USR
+
+# The new Samhain behavior is to check the checksum up the last-known size of
+# the file, but *yes*, the inode will change when it becomes rotated and the size
+# will get reset to a lesser value (in which case the check should know to passively
+# fail)
+RedefGrowingLogFiles=-INO, -SIZ, +CHK, -MTM, -ATM, -CTM
+
+#
+# --------- / --------------
+#
+
+[ReadOnly]
+dir = 99/
+
+# This covers the contents of / including: /boot, /bin, /sbin, /lib, /libexec,
+# /rescue, /root, /altroot, /usr, /var, /stand, /mnt, /tmp, /proc, /kern (Even
+# though /usr and /var will recieve overrides)
+
+[Attributes]
+file = /proc
+file = /kern
+
+[IgnoreAll]
+dir=-1/proc
+dir=-1/kern
+
+#
+# --------- /tmp -----------
+#
+[Attributes]
+file=/tmp
+[IgnoreAll]
+dir=-1/tmp
+
+
+
+#
+# --------- /root --------------
+#
+
+# Per section 5.4.2.1 of the manual, Rule #5, there are lock file written here
+# that changes the mtime/ctime of the dir, so we want to watch perms/ownership,
+# ignore ctime/mtime/size, etc., but still watch the critical files inside.
+# Note: in theory, /root should never change if you use sudo(8) w/o "-H"
+[ReadOnly]
+dir=/root/.gnupg
+[Attributes]
+file=/root/.gnupg
+file=/root/.gnupg/random_seed
+
+#
+# --------- /dev -----------
+#
+
+[Attributes]
+dir = 99/dev
+
+# User0 will be for /dev/tty* and other devices where Owner/Group/Mode can
+# change but the Inode/Size/Device/Checksum should not change.
+
+[User0]
+file=/dev/tty*
+file=/dev/pty*
+
+#
+# --------- /etc -----------
+#
+
+[ReadOnly]
+##
+## for these files, only access time is ignored
+##
+dir = 99/etc
+
+
+# If you're running dhclient(8), resolv.conf will get re-written at renewal
+# time so pray that he dhcpd(8) on your network doesn't get owned.
+# Crytpo-signed DHCP traffic would be too much to ask from ISC, but maybe
+# not from the OpenBSD hack
+
+[Attributes]
+file=/etc/dhclient.conf
+
+# If you run CUPS, /etc/printcap gets re-written if you have
+# "Browsing On" and "Printcap /etc/printcap" in cupsd.conf(5)
+[Attributes]
+file=/etc/printcap
+
+
+#
+# --------- /usr -----------
+#
+
+# note about the following two: this reduced the size
+# of the database greatly
+
+#
+# --------- /usr/pkgsrc -----------
+#
+
+# Leave this uncommented if you CVS update your pkgsrc
+# periodically/automatically. If you do not, comment it
+# out and you should be informed about any unauthorized
+# modifications to pkgsrc (which is an attack vector)
+
+[IgnoreAll]
+dir=-1/usr/pkgsrc
+
+#
+# --------- /usr/src -----------
+#
+
+# Leave this uncommented if you CVS update your src
+# periodically/automatically. If you do not, comment it
+# out and you should be informed about any unauthorized
+# modifications to src (which is an attack vector)
+
+
+[IgnoreAll]
+dir=-1/usr/src
+
+
+#
+# --------- /usr/home (/home) -----------
+#
+
+
+# /home may be a symlink to /usr/home on a stock system, but most admins cane
+# that shit. [Attributes] could be replaced here by [ReadOnly] if we wanted to
+# know about new users being added (on systems where there are no new users)
+
+[Attributes]
+file = /home
+[IgnoreAll]
+dir = -1/home
+
+#
+# --------- /usr/compat/linux/etc -----------
+#
+
+# You're basically compromising your system by enabling Linux emulation anyway
+
+[Attributes]
+file = /usr/compat/linux/etc
+file = /usr/compat/linux/etc/ld.so.cache
+
+#
+# --------- /usr/compat/linux/proc -----------
+#
+
+# Uncomment if you have Linux Emulation/Compat Installed/Setup/Mounted
+[Attributes]
+file=/emul/linux/proc
+[IgnoreAll]
+dir=-1/emul/linux/proc
+
+
+#
+# --------- /var/run -----------
+#
+
+# New PID files may come, and PID files may go (as services on a system change),
+# but then probably a database rebuild will occur. But at the time of the
+# database init, we should consider everything in here subject to change
+# (checksum, times, size) during a daemon restart, but everything else stays
+# the same.
+
+# If you have periodic scripts that HUP daemons, the PID should be unachanged.
+# However, force-restarts will be a new PID, so consider this
+
+[Attributes]
+dir=99/var/run
+
+[Misc]
+# Ignore sudo(8) TTY/PTY "Tickets" if you use sudo
+IgnoreMissing = /var/run/sudo/[[:alnum:]]{1,9}/(p|t)ty.*$
+IgnoreAdded = /var/run/sudo/[[:alnum:]]{1,9}/(p|t)ty.*$
+
+#
+# --------- /var/(spool|queue|etc.) -----------
+#
+
+[Attributes]
+file=/var/cron/tabs
+file=/var/spool/mqueue
+file=/var/spool/clientmqueue
+file=/var/mail
+file=/var/tmp
+
+#
+# --------- /var/at -----------
+#
+
+# As deep as /var/at/ will be watched by 99/
+
+[Attributes]
+file=/var/at/spool
+file=/var/at/jobs
+
+#
+# --------- /var/db -----------
+#
+
+# Some files are written directly into /var/db
+[Attributes]
+file=/var/db
+
+[Attributes]
+# Updatedb per /etc/periodic.d/weekly/310.locate (FreeBSD) or /etc/weekly (NetBSD)
+file=/var/db/locate.database
+
+[Misc]
+# this file comes and goes with portaudit(1)/portversion(1)/pkg_version(1)
+# Other is ISC DHCLIENT related
+IgnoreAdded=/var/db/(pkgdb.fixme|dhclient.leases.*)
+IgnoreMissing=/var/db/(pkgdb.fixme|dhclient.leases.*)
+
+
+#
+# --------- /var/db/mysql -----------
+#
+
+# The same for MySQL, except it's probably owned by the time you get done
+# installing it.
+
+[Attributes]
+file=/var/db/mysql
+[IgnoreAll]
+dir=-1/var/db/mysql
+
+####################################################################
+# The next three entries depend on your security paranoia policy about
+# SRC and PORTSs trees, etc. Remember, Ports is the only default attack
+# vector against FreeBSD machines.
+####################################################################
+
+
+#
+# --------- /var/db/pkg -----------
+#
+
+# This database directory gets updated if a cvsup(8)/cvs(8)/sup(8) update
+# occurs to a Pkgsrc source tree and then "pkgdb(8) -fu" is run.
+
+[Attributes]
+file=/var/db/pkg
+[IgnoreAll]
+dir=-1/var/db/pkg
+
+
+#
+# --------- /var/db/entropy -----------
+#
+[Attributes]
+file=/var/db/entropy
+[IgnoreAll]
+dir=-1/var/db/entropy
+
+#
+# --------- /var/msgs -----------
+#
+
+[Attributes]
+dir=-1/var/msgs
+
+#
+# --------- /var/backups -----------
+#
+
+# /etc/daily /etc/security write old revisions of system
+# critical files into here daily
+[Attributes]
+dir=-1/var/backups
+
+#
+# --------- /var/log -----------
+#
+
+# Keep this section in sync with:
+# * /etc/newsyslog.conf
+# * /etc/syslogd.conf OR:
+# * /usr/pkg/etc/syslog-ng/syslog-ng.conf
+
+# For these files, changes in signature, timestamps, and increase in size
+# are ignored, however:
+# Per discussion on the forum, this behavior change is needed due to the behavior
+# of newsyslog(8) rotation method File sizes will get smaller, inodes will change
+# as they rotate.
+
+# NOTES ON LOG ROTATION BEHAVIOR:
+# See comments about modifications to [GrowingLogFiles] to ignore INODE changes
+# As newsyslog(8)/newsyslog.conf(5) has the default behavior of:
+# - First move logfile.log to logfile.log.0
+# - then bzip2 -v9 logfile.log.0
+# - then touch(1) logfile.log
+# - then HUP if applicable & reopen the new file (new inode)
+# - Therefore, Ignore Singature, Size (if grow), and Inode changes
+# But also, there's [IgnoreMissing] regexp to account for log file pruing from
+# the filesystem, and [IgnoreAdded] for the first Nth rotations of the logfile
+# per newsyslog.conf(5)
+
+
+# NetBSD defaults
+[Misc]
+IgnoreAdded = /var/log/(cron|xferlog|messages|maillog|secure|pflog|sendmail\.st|kerberos\.log|authlog|aculog|wtmp|wtmpx)\.[0-9](\.bz2|\.gz)?$
+IgnoreMissing= /var/log/(cron|xferlog|messages|maillog|secure|pflog|sendmail\.st|kerberos\.log|authlog|aculog|wtmp|wtmpx)\.[0-9](\.bz2|\.gz)?$
+
+# Local services you may need to account for
+IgnoreAdded = /var/log/(snmpd\.log|postgresq\.log|samhain\.log|httpd-error\.log|httpd-access\.log|httpd-ssl_request\.log)\.[0-9](\.bz2|\.gz)?$
+IgnoreMissing = /var/log/(snmpd\.log|postgresq\.log|samhain\.log|httpd-error\.log|httpd-access\.log|httpd-ssl_request\.log)\.[0-9](\.bz2|\.gz)?$
+
+[Attributes]
+dir=99/var/log
+
+# NetBSD Stock Defaults
+[GrowingLogFiles]
+File = /var/log/aculog
+File = /var/log/authlog
+File = /var/log/cron
+File = /var/log/kerberos.log
+File = /var/log/lpd-errs
+File = /var/log/maillog
+File = /var/log/messages
+File = /var/log/secure
+File = /var/log/wtmp
+File = /var/log/wtmpx
+File = /var/log/xferlog
+File = /var/log/pflog
+
+[Attributes]
+# A binary-type logfile (Screw sendmail!)
+File = /var/log/sendmail.st
+
+# NetBSD gzip(1)'s by default but newsyslog.conf(5) has bzip2 support
+[Attributes]
+File = /var/log/*.[0-9].gz
+#File = /var/log/*.[0-9].bz2
+
+#
+# --------- makewhatis(8) -----------
+#
+
+# Account for updated whatis(8) database given manpath.conf(5)/man.conf(5)
+#and manpath(1)
+
+[Attributes]
+file=/usr/pkg/man/whatis.db
+file=/usr/pkg/man
+file=/usr/share/man/whatis.db
+file=/usr/share/man
+
+##############################################
+######## END FILE SECTION ####################
+##############################################
+
+[EventSeverity]
+
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+SeverityUser0=crit
+SeverityUser1=crit
+
+## We have a file in IgnoreAll that might or might not be present.
+## Setting the severity to 'info' prevents messages about deleted/new file.
+##
+# SeverityIgnoreAll=crit
+SeverityIgnoreAll=info
+
+## Files : file access problems
+SeverityFiles=info
+
+## Dirs : directory access problems
+SeverityDirs=info
+
+## Names : suspect (non-printable) characters in a pathname
+SeverityNames=crit
+
+[Log]
+## Values: debug, info, notice, warn, mark, err, crit, alert, none.
+## 'mark' is used for timestamps.
+##
+## Use 'none' to SWITCH OFF a log facility
+##
+## By default, everything equal to and above the threshold is logged.
+## The specifiers '*', '!', and '=' are interpreted as
+## 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+## at least on Linux). Examples:
+## MailSeverity=*
+## MailSeverity=!warn
+## MailSeverity==crit
+
+## E-mail
+##
+MailSeverity=warn
+
+## Console
+##
+PrintSeverity=notice
+
+## Logfile
+##
+LogSeverity=info
+
+## Syslog
+##
+# Syslog logging is redundant at this time
+#
+#SyslogSeverity=notice
+
+## Remote server (yule)
+##
+# ExportSeverity=none
+
+## External script or program
+##
+# ExternalSeverity = none
+
+## Logging to a database
+##
+# DatabaseSeverity = none
+
+## Logging to a Prelude-IDS
+##
+# PreludeSeverity = crit
+
+
+#####################################################
+#
+# Optional modules
+#
+#####################################################
+
+#[SuidCheck]
+##
+## --- Check the filesystem for SUID/SGID binaries
+##
+
+## Switch on
+#
+#SuidCheckActive = yes
+
+## Interval for check (seconds)
+#
+#SuidCheckInterval = 5400
+
+## Alternative: crontab-like schedule
+#
+#SuidCheckSchedule = NULL
+
+## Directory to exclude
+#
+# SuidCheckExclude = NULL
+
+## Limit on files per second (0 == no limit)
+#
+# SuidCheckFps = 0
+
+## Alternative: yield after every file
+#
+# SuidCheckYield = no
+
+## Severity of a detection
+#
+# SeveritySuidCheck = crit
+
+## Quarantine SUID/SGID files if found
+#
+# SuidCheckQuarantineFiles = yes
+
+## Method for Quarantining files:
+# 0 - Delete the file.
+# 1 - Remove SUID/SGID permissions from file.
+# 2 - Move SUID/SGID file to quarantine dir.
+#
+# SuidCheckQuarantineMethod = 0
+
+## For method 1 and 3, really delete instead of truncating
+#
+# SuidCheckQuarantineDelete = yes
+
+#[Mounts]
+#MountCheckActive=1
+#MountCheckInterval=7200
+#SeverityMountMissing=crit
+#SeverityOptionMissing=crit
+#
+#checkmount=/
+#checkmount=/dev
+#checkmount=/usr
+#checkmount=/var
+#checkmount=/var/log
+#checkmount=/opt
+#checkmount=/export
+#checkmount=/tmp
+
+
+
+ #[Utmp]
+##
+## --- Logging of login/logout events
+##
+
+## Switch on/off
+#
+#LoginCheckActive = True
+
+## Severity for logins, multiple logins, logouts
+#
+#SeverityLogin=info
+#SeverityLoginMulti=crit
+#SeverityLogout=info
+
+## Interval for login/logout checks
+#
+#LoginCheckInterval = 300
+
+
+# [Database]
+##
+## --- Logging to a relational database
+##
+
+## Database name
+#
+# SetDBName = samhain
+
+## Database table
+#
+# SetDBTable = log
+
+## Database user
+#
+# SetDBUser = samhain
+
+## Database password
+#
+# SetDBPassword = (default: none)
+
+## Database host
+#
+# SetDBHost = localhost
+
+## Log the server timestamp for received messages
+#
+# SetDBServerTstamp = True
+
+## Use a persistent connection
+#
+# UsePersistent = True
+
+
+# [External]
+##
+## Interface to call external scripts/programs for logging
+##
+
+## The absolute path to the command
+## - Each invocation of this directive will end the definition of the
+## preceding command, and start the definition of
+## an additional, new command
+#
+# OpenCommand = (no default)
+
+## Type (log or srv)
+## - log for log messages, srv for messages received by the server
+#
+# SetType = log
+
+## The command (full command line) to execute
+#
+# SetCommandLine = (no default)
+
+## The environment (KEY=value; repeat for more)
+#
+# SetEnviron = TZ=(your timezone)
+
+## The TIGERpkg checksum (optional)
+#
+# SetChecksum = (no default)
+
+## User who runs the command
+#
+# SetCredentials = (default: samhain process uid)
+
+## Words not allowed in message
+#
+# SetFilterNot = (none)
+
+## Words required (ALL of them)
+#
+# SetFilterAnd = (none)
+
+## Words required (at least one)
+#
+# SetFilterOr = (none)
+
+## Deadtime between consecutive calls
+#
+# SetDeadtime = 0
+
+## Add default environment (HOME, PATH, SHELL)
+#
+# SetDefault = no
+
+
+
+#####################################################
+#
+# Miscellaneous configuration options
+#
+#####################################################
+
+[Misc]
+
+## whether to become a daemon process
+## (this is not honoured on database initialisation)
+#
+# Daemon = no
+Daemon = yes
+
+# whether to test signature of files (init/check/none)
+# - if 'none', then we have to decide this on the command line -
+#
+# ChecksumTest = none
+ChecksumTest=check
+
+# Set nice level (-19 to 19, see 'man nice'),
+# and I/O limit (kilobytes per second; 0 == off)
+# to reduce load on host.
+#
+SetNiceLevel = 19
+# SetIOLimit = 0
+
+## The version string to embed in file signature databases
+#
+# VersionString = NULL
+
+## Interval between time stamp messages
+#
+# SetLoopTime = 60
+SetLoopTime = 7200
+
+## Interval between file checks
+#
+# SetFileCheckTime = 600
+SetFileCheckTime = 43200
+
+## Alternative: crontab-like schedule
+#
+# FileCheckScheduleOne = NULL
+
+## Alternative: crontab-like schedule(2)
+#
+# FileCheckScheduleTwo = NULL
+
+## Report only once on modified files
+## Setting this to 'FALSE' will generate a report for any policy
+## violation (old and new ones) each time the daemon checks the file system.
+#
+ReportOnlyOnce = True
+
+## Report in full detail
+#
+ReportFullDetail = True
+
+## Report file timestamps in local time rather than GMT
+#
+UseLocalTime = Yes
+
+## The console device (can also be a file or named pipe)
+## - There are two console devices. Accordingly, you can use
+## this directive a second time to set the second console device.
+## If you have not defined the second device at compile time,
+## and you don't want to use it, then:
+## setting it to /dev/null is less effective than just leaving
+## it alone (setting to /dev/null will waste time by opening
+## /dev/null and writing to it)
+#
+# SetConsole = /dev/console
+
+## Activate the SysV IPC message queue
+#
+# MessageQueueActive = False
+
+
+## If false, skip reverse lookup when connecting to a host known
+## by name rather than IP address (i.e. trust the DNS)
+#
+SetReverseLookup = True
+
+
+## --- E-Mail ---
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# SetMailTime = 86400
+
+## Maximum number of mails to queue
+#
+# SetMailNum = 10
+
+## Recipient (max. 8)
+#
+#SetMailAddress=infosec@noc.myorg.tld
+
+## Mail relay (IP address)
+#
+SetMailRelay = 127.0.0.1
+
+## Custom subject format
+#
+MailSubject = Synchrotone Samhain: %S
+SetMailSender = samhain@synchrotone.pgh.pub.collaborativefusion.com
+
+## --- end E-Mail ---
+
+
+## Path to the executable. If set, will be checksummed after startup
+## and before exit.
+#
+SamhainPath = /usr/pkg/sbin/samhain
+
+## The IP address of the log server
+#
+# SetLogServer = (default: compiled-in)
+
+## The IP address of the time server
+#
+# SetTimeServer = (default: compiled-in)
+
+## Trusted Users (comma delimited list of user names)
+#
+# TrustedUser = (no default; this adds to the compiled-in list)
+
+## Path to the file signature database
+#
+SetDatabasePath = /usr/pkg/var/samhain/samhain.db
+
+## Path to the log file
+#
+# SetLogfilePath = (default: compiled-in)
+
+## Path to the PID file
+#
+# SetLockfilePath = (default: compiled-in)
+
+
+## The digest/checksum/hash algorithm (default: TIGER192; others: MD5, SHA1)
+#
+# DigestAlgo = TIGER192
+
+
+## Custom format for message header.
+## CAREFUL if you use XML logfile format.
+##
+## %S severity
+## %T timestamp
+## %C class
+##
+## %F source file
+## %L source line
+#
+# MessageHeader="%S %T "
+
+
+## Don't log path to config/database file on startup
+#
+# HideSetup = False
+
+## The syslog facility, if you log to syslog
+#
+# SyslogFacility = LOG_AUTHPRIV
+SyslogFacility=LOG_LOCAL2
+
+## The message authentication method
+## - If you change this, you *must* change it
+## on client *and* server
+#
+# MACType = HMAC-TIGER
+
+
+## The Prelude-IDS profile to use for reporting
+## default value is "samhain"
+#
+# PreludeProfile = samhain
+
+## Map these samhain severities to impact severity 'info' severity
+#
+# PreludeMapToInfo =
+
+## Map these samhain severities to impact severity 'low' severity
+#
+# PreludeMapToLow = debug info
+
+## Map these samhain severities to impact severity 'medium' severity
+#
+# PreludeMapToMedium = notice warn err
+
+## Map these samhain severities to impact severity 'high' severity
+#
+# PreludeMapToHigh = crit alert
+
+# everything below is ignored
+[EOF]
+
+#####################################################################
+# This would be the proper syntax for parts that should only be
+# included for certain hosts.
+# You may enclose anything in a @HOSTNAME/@end bracket, as long as the
+# result still has the proper syntax for the config file.
+# You may have any number of @HOSTNAME/@end brackets.
+# HOSTNAME should be the fully qualified 'official' name
+# (e.g. 'nixon.watergate.com', not 'nixon'), no aliases.
+# No IP number - except if samhain cannot determine the
+# fully qualified hostname.
+#
+# @HOSTNAME
+# file=/foo/bar
+# @end
+#
+# These are two examples for conditional inclusion/exclusion
+# of a machine based on the output from 'uname -srm'
+# $Linux:2.*.7:i666
+# file=/foo/bar3
+# $end
+#
+# !$Linux:2.*.7:i686
+# file=/foo/bar2
+# $end
+#
+#####################################################################
diff --git a/samhainrc.solaris b/samhainrc.solaris
new file mode 100644
index 0000000..b0a7a21
--- /dev/null
+++ b/samhainrc.solaris
@@ -0,0 +1,684 @@
+#####################################################################
+#
+# SOLARIS Configuration file for samhain.
+#
+# Based on a contribution by Sean Boran (sean [at] boran d.o.t com)
+#
+# HISTORY:
+# 16.Aug.03 rw add plenty of comments
+# 24.Jun.02 rw remove linux stuff, clean up a bit
+# 06.Jun.02 sb <3>, add LOTS more Solaris stuff. Also and comment at bottom
+# of this file.
+# 03.Jun.02 sb Separate Linux & Solaris
+# 24.Apr.02 sb Use Samhain v.15 template and tune for Solaris.
+#
+# To do: logs /var/adm/messages and /var/cron/log are
+# pruned weekly.
+#####################################################################
+#
+# -- empty lines and lines starting with '#', ';' or '//' are ignored
+# -- boolean options can be Yes/No or True/False or 1/0
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+# SETUP for file system checking:
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) Section [EventSeverity]:
+# To each policy, you can assign a severity (further below).
+# (iii) Section [Log]:
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#####################################################################
+
+#####################################################################
+#
+# Files are defined with: file = /absolute/path
+#
+# Directories are defined with: dir = /absolute/path
+# or with an optional recursion depth (N <= 99): dir = N/absolute/path
+#
+# Directory inodes are checked. If you only want to check files
+# in a directory, but not the directory inode itself, use (e.g.):
+#
+# [ReadOnly]
+# dir = /some/directory
+# [IgnoreAll]
+# file = /some/directory
+#
+# You can use shell-style globbing patterns, like: file = /path/foo*
+#
+######################################################################
+
+[Misc]
+##
+## Add or subtract tests from the policies
+## - if you want to change their definitions,
+## you need to do that before using the policies
+##
+# RedefReadOnly = (no default)
+# RedefAttributes=(no default)
+# RedefLogFiles=(no default)
+# RedefGrowingLogFiles=(no default)
+# RedefIgnoreAll=(no default)
+# RedefIgnoreNone=(no default)
+# RedefUser0=(no default)
+# RedefUser1=(no default)
+
+
+[Attributes]
+##
+## for these files, only changes in permissions and ownership are checked
+##
+
+file=/etc/ssh/ssh_random_seed
+file=/etc/resolv.conf
+# There are files in /etc that might change, thus changing the directory
+# timestamps. Put it here as 'file', and in the ReadOnly section as 'dir'.
+file=/etc
+
+file=/etc/skip/randseed
+file=/etc/cron.d/FIFO
+file=/etc/devlink.tab
+file=/etc/.syslog_door
+file=/etc/syslog.pid
+file=/etc/.name_service_door
+file=/etc/mnttab
+file=/etc/cron.d
+file=/etc/mail
+file=/etc/inet
+dir=/secure/tmp
+dir=/etc/sysevent
+dir=/usr/local/imap/spool/user
+dir=/usr/local/imap/proc
+dir=/usr/local/imap/quota
+dir=/usr/local/qmail/queue
+dir=/usr/local/qmail/alias/Mailbox
+dir=/usr/tmp
+dir=/usr/aset/tmp
+dir=/usr/oasys/tmp
+dir=/var/spool/lp/tmp
+dir=/var/tmp
+dir=/var/dt/tmp
+dir=/tmp
+dir=/etc/osa
+
+[LogFiles]
+##
+## for these files, changes in signature, timestamps, and size are ignored
+##
+#file=/var/run/utmp
+file=/etc/motd
+file=/var/cron/log
+file=/var/adm/wtmpx
+file=/var/adm/wtmp
+file=/var/adm/utmpx
+file=/var/adm/lastlog
+
+[GrowingLogFiles]
+##
+## for these files, changes in signature, timestamps, and increase in size
+## are ignored
+##
+
+file=/var/adm/messages
+
+
+
+[IgnoreAll]
+##
+## for these files, no modifications are reported
+##
+
+file=/etc/utmppipe
+file=/usr/dt/bin/ttsnoop
+file=/dev/mem
+dir=/etc/saf
+# dir=/secure/tmp
+dir=/usr/share/man
+dir=/usr/share/lib/terminfo
+dir=/usr/demo
+dir=/usr/lib/adb
+dir=/usr/local/man
+dir=/usr/local/doc
+dir=/usr/dt/share/man
+dir=/usr/openwin/lib/locale
+dir=/usr/openwin/share/man
+dir=/usr/openwin/share/src
+dir=/usr/openwin/lib/X11/fonts
+dir=/var/snort
+dir=/var/log/snort
+dir=/etc/snort/rules
+dir=/opt/oracle/doc
+dir=/usr/dt/share/examples
+dir=/opt/SUNWebnfs/javadoc
+dir=/usr/local/mysql/var
+dir=/jumpstart/Flash
+dir=/jumpstart/OS
+dir=/jumpstart/Patches
+dir=/etc/opt/SUNWicg/SunScreen/.active
+dir=/etc/opt/SUNWicg/SunScreen/.old
+
+
+[IgnoreNone]
+##
+## for these files, all modifications (even access time) are reported
+## - you may create some interesting-looking file (like /etc/safe_passwd),
+## just to watch whether someone will access it ...
+##
+
+
+[ReadOnly]
+##
+## for these files, only access time is ignored
+##
+dir=/usr/bin
+dir=/usr/sbin
+dir=/usr/lib
+
+# SuSE (old) has the boot init scripts in /sbin/init.d/*,
+# so we go 3 levels deep
+dir=3/sbin
+
+# RedHat and Debian have the bootinit scripts in /etc/init.d/* or /etc/rc.d/*,
+# so we go 3 levels deep there too
+dir=3/etc
+
+# Various directories / files that may include / be SUID/SGID binaries
+#
+dir=/usr/openwin/bin
+dir=/usr/dt/bin
+#dir=/opt/install
+dir=/opt/OBSDssh
+
+
+dir=/root
+
+# Critical devices
+
+file=/dev/dsk
+file=/dev/rdsk
+file=/dev/null
+file=/dev/zero
+
+[User0]
+[User1]
+## User0 and User1 are sections for files/dirs with user-definable checking
+## (see the manual)
+
+[EventSeverity]
+##
+## Here you can assign severities to policy violations.
+## If this severity exceeds the treshold of a log facility (see below),
+## a policy violation will be logged to that facility.
+
+# Severity for verification failures.
+#
+# SeverityReadOnly=crit
+# SeverityLogFiles=crit
+# SeverityGrowingLogs=crit
+# SeverityIgnoreNone=crit
+# SeverityAttributes=crit
+# SeverityUser0=crit
+# SeverityUser1=crit
+
+# We have a file in IgnoreAll that might or might not be present.
+# Setting the severity to 'info' prevents messages about deleted/new file.
+#
+# SeverityIgnoreAll=crit
+SeverityIgnoreAll=info
+
+# Files : file access problems
+# SeverityFiles=crit
+
+# Dirs : directory access problems
+# SeverityDirs=crit
+
+# Names : suspect (non-printable) characters in a pathname
+# SeverityNames=crit
+
+[Log]
+##
+## Switch on/OFF log facilities and set their threshold severity
+##
+## Values: debug, info, notice, warn, mark, err, crit, alert, none.
+## 'mark' is used for timestamps.
+##
+## Use 'none' to SWITCH OFF a log facility
+##
+## By default, everything equal to and above the threshold is logged.
+## The specifiers '*', '!', and '=' are interpreted as
+## 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+## at least on Linux). Examples:
+## MailSeverity=*
+## MailSeverity=!warn
+## MailSeverity==crit
+
+## E-mail
+##
+# MailSeverity=none
+
+## Console
+##
+# PrintSeverity=info
+
+## Logfile
+##
+# LogSeverity=mark
+
+## Syslog
+##
+# SyslogSeverity=none
+
+## Remote server (yule)
+##
+# ExportSeverity=none
+
+## External script or program
+##
+# ExternalSeverity = none
+
+## Logging to a database
+##
+# DatabaseSeverity = none
+
+## Logging to a Prelude-IDS
+##
+# PreludeSeverity = crit
+
+
+#####################################################
+#
+# Optional modules
+#
+#####################################################
+
+# [SuidCheck]
+##
+## --- Check the filesystem for SUID/SGID binaries
+##
+
+## Switch on
+#
+# SuidCheckActive = yes
+
+## Interval for check (seconds)
+#
+# SuidCheckInterval = 7200
+
+## Alternative: crontab-like schedule
+#
+# SuidCheckSchedule = NULL
+
+## Directory to exclude
+#
+# SuidCheckExclude = NULL
+
+## Limit on files per second (0 == no limit)
+#
+# SuidCheckFps = 0
+
+## Alternative: yield after every file
+#
+# SuidCheckYield = no
+
+## Severity of a detection
+#
+# SeveritySuidCheck = crit
+
+## Quarantine SUID/SGID files if found
+#
+# SuidCheckQuarantineFiles = yes
+
+## Method for Quarantining files:
+# 0 - Delete the file.
+# 1 - Remove SUID/SGID permissions from file.
+# 2 - Move SUID/SGID file to quarantine dir.
+#
+# SuidCheckQuarantineMethod = 0
+
+## For method 1 and 3, really delete instead of truncating
+#
+
+# [Utmp]
+##
+## --- Logging of login/logout events
+##
+
+## Switch on/off
+#
+# LoginCheckActive = True
+
+## Severity for logins, multiple logins, logouts
+#
+# SeverityLogin=info
+# SeverityLoginMulti=warn
+# SeverityLogout=info
+
+## Interval for login/logout checks
+#
+# LoginCheckInterval = 300
+
+
+# [Database]
+##
+## --- Logging to a relational database
+##
+
+## Database name
+#
+# SetDBName = samhain
+
+## Database table
+#
+# SetDBTable = log
+
+## Database user
+#
+# SetDBUser = samhain
+
+## Database password
+#
+# SetDBPassword = (default: none)
+
+## Database host
+#
+# SetDBHost = localhost
+
+## Log the server timestamp for received messages
+#
+# SetDBServerTstamp = True
+
+## Use a persistent connection
+#
+# UsePersistent = True
+
+# [External]
+##
+## Interface to call external scripts/programs for logging
+##
+
+## The absolute path to the command
+## - Each invocation of this directive will end the definition of the
+## preceding command, and start the definition of
+## an additional, new command
+#
+# OpenCommand = (no default)
+
+## Type (log or rv)
+## - log for log messages, srv for messages received by the server
+#
+# SetType = log
+
+## The command (full command line) to execute
+#
+# SetCommandLine = (no default)
+
+## The environment (KEY=value; repeat for more)
+#
+# SetEnviron = TZ=(your timezone)
+
+## The TIGER192 checksum (optional)
+#
+# SetChecksum = (no default)
+
+## User who runs the command
+#
+# SetCredentials = (default: samhain process uid)
+
+## Words not allowed in message
+#
+# SetFilterNot = (none)
+
+## Words required (ALL of them)
+#
+# SetFilterAnd = (none)
+
+## Words required (at least one)
+#
+# SetFilterOr = (none)
+
+## Deadtime between consecutive calls
+#
+# SetDeadtime = 0
+
+## Add default environment (HOME, PATH, SHELL)
+#
+# SetDefault = no
+
+
+
+
+#####################################################
+#
+# Miscellaneous configuration options
+#
+#####################################################
+
+[Misc]
+
+## whether to become a daemon process
+## (this is not honoured on database initialisation)
+#
+# Daemon = no
+Daemon = yes
+
+## whether to test signature of files (init/check/none)
+## - if 'none', then we have to decide this on the command line -
+#
+# ChecksumTest = none
+ChecksumTest=check
+
+## Set nice level (-19 to 19, see 'man nice'),
+## and I/O limit (kilobytes per second; 0 == off)
+## to reduce load on host.
+#
+# SetNiceLevel = 0
+# SetIOLimit = 0
+
+## The version string to embed in file signature databases
+#
+# VersionString = NULL
+
+## Interval between time stamp messages
+#
+# SetLoopTime = 60
+SetLoopTime = 600
+
+## Interval between file checks
+#
+# SetFileCheckTime = 600
+SetFileCheckTime = 7200
+
+## Alternative: crontab-like schedule
+#
+# FileCheckScheduleOne = NULL
+
+## Alternative: crontab-like schedule(2)
+#
+# FileCheckScheduleTwo = NULL
+
+## Report only once on modified files
+## Setting this to 'FALSE' will generate a report for any policy
+## violation (old and new ones) each time the daemon checks the file system.
+#
+# ReportOnlyOnce = True
+
+## Report in full detail
+#
+# ReportFullDetail = False
+
+## Report file timestamps in local time rather than GMT
+#
+# UseLocalTime = No
+
+## The console device (can also be a file or named pipe)
+## - There are two console devices. Accordingly, you can use
+## this directive a second time to set the second console device.
+## If you have not defined the second device at compile time,
+## and you don't want to use it, then:
+## setting it to /dev/null is less effective than just leaving
+## it alone (setting to /dev/null will waste time by opening
+## /dev/null and writing to it)
+#
+# SetConsole = /dev/console
+
+## Activate the SysV IPC message queue
+#
+# MessageQueueActive = False
+
+
+## If false, skip reverse lookup when connecting to a host known
+## by name rather than IP address (i.e. trust the DNS)
+#
+# SetReverseLookup = True
+
+## --- E-Mail ---
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# SetMailTime = 86400
+
+## Maximum number of mails to queue
+#
+# SetMailNum = 10
+
+## Recipient (max. 8)
+#
+# SetMailAddress=root@localhost
+
+## Mail relay (IP address)
+#
+# SetMailRelay = NULL
+
+## Custom subject format
+#
+# MailSubject = NULL
+
+## --- end E-Mail ---
+
+
+## Path to the executable. If set, will be checksummed after startup
+## and before exit.
+#
+# SamhainPath = (no default)
+
+
+## The IP address of the log server
+#
+# SetLogServer = (default: compiled-in)
+
+## The IP address of the time server
+#
+# SetTimeServer = (default: compiled-in)
+
+## Trusted Users (comma delimited list of user names)
+#
+# TrustedUser = (no default; this adds to the compiled-in list)
+
+## Path to the file signature database
+#
+# SetDatabasePath = (default: compiled-in)
+
+## Path to the log file
+#
+# SetLogfilePath = (default: compiled-in)
+
+## Path to the PID file
+#
+# SetLockfilePath = (default: compiled-in)
+
+
+## The digest/checksum/hash algorithm
+#
+# DigestAlgo = TIGER192
+
+
+## Custom format for message header.
+## CAREFUL if you use XML logfile format.
+##
+## %S severity
+## %T timestamp
+## %C class
+##
+## %F source file
+## %L source line
+#
+# MessageHeader="%S %T "
+
+
+## Don't log path to config/database file on startup
+#
+# HideSetup = False
+
+## The syslog facility, if you log to syslog
+#
+# SyslogFacility = LOG_AUTHPRIV
+SyslogFacility=LOG_LOCAL2
+
+## The message authentication method
+## - If you change this, you *must* change it
+## on client *and* server
+#
+# MACType = HMAC-TIGER
+
+## The Prelude-IDS profile to use for reporting
+## default value is "samhain"
+#
+# PreludeProfile = samhain
+
+## Map these samhain severities to impact severity 'info' severity
+#
+# PreludeMapToInfo =
+
+## Map these samhain severities to impact severity 'low' severity
+#
+# PreludeMapToLow = debug info
+
+## Map these samhain severities to impact severity 'medium' severity
+#
+# PreludeMapToMedium = notice warn err
+
+## Map these samhain severities to impact severity 'high' severity
+#
+# PreludeMapToHigh = crit alert
+
+# everything below is ignored
+[EOF]
+
+#####################################################################
+# This would be the proper syntax for parts that should only be
+# included for certain hosts.
+# You may enclose anything in a @HOSTNAME/@end bracket, as long as the
+# result still has the proper syntax for the config file.
+# You may have any number of @HOSTNAME/@end brackets.
+# HOSTNAME should be the fully qualified 'official' name
+# (e.g. 'nixon.watergate.com', not 'nixon'), no aliases.
+# No IP number - except if samhain cannot determine the
+# fully qualified hostname.
+#
+# @HOSTNAME
+# file=/foo/bar
+# @end
+#
+# These are two examples for conditional inclusion/exclusion
+# of a machine based on the output from 'uname -srm'
+# $Linux:2.*.7:i666
+# file=/foo/bar3
+# $end
+#
+# !$Linux:2.*.7:i686
+# file=/foo/bar2
+# $end
+#
+#####################################################################
diff --git a/scripts/README b/scripts/README
new file mode 100644
index 0000000..5c12c7b
--- /dev/null
+++ b/scripts/README
@@ -0,0 +1,99 @@
+
+
+This directory contains miscellaneous useful scripts, some of them contributed
+by various users. Additions and/or improvements are welcome.
+
+chroot.sh: prepare chroot environment for the log server
+---------
+
+ Usage: chroot.sh <chroot_directory>
+
+ Tested on Debian Linux. Your mileage may vary.
+ After running the script, review <chroot_directory>/etc/passwd
+ to replace passwords with a *, and to fix the
+ path to the home directory of the yule user.
+ If using a signed configuration file, you need
+ a working copy of GnuPG inside the chroot jail.
+
+ This script will probably fail on systems other than Linux,
+ mainly because of the mknod commands to create devices
+ in the chroot jail.
+
+ NO WARRANTY !!!
+
+samhainadmin.pl
+---------------
+
+ Perform various tasks useful if you are using signed configuration
+ and database files.
+
+ Run 'samhainadmin.pl -h' for usage instructions.
+
+yuleadmin.pl
+------------
+
+ Perl script (by Riccardo Murri) to list, add, and remove clients
+ from the yulerc file.
+
+ Run 'yuleadmin.pl -h' for usage instructions.
+
+check_samhain.pl
+----------------
+
+ Nagios plugin for samhain. Will execute samhain and report results
+ in the way expected by nagios. Drop this into your nagios/libexec/
+ directory.
+
+samhain.logrotator: logrotate script
+------------------
+
+ This is a logrotate script (contributed by Simon Bailey)
+
+concat.pl
+---------
+
+ Concatenate samhain file signature databases and write the resulting
+ database file to stdout. Does not work on signed or otherwise modified
+ file signature databases.
+
+samhain.{cgi|dtd|xsl}: display XML logfile in XML capable browser
+--------------------- (works with Mozilla 1.2, possibly Mozilla 1.0, IE 6)
+
+ Usage: 1. review samhain.cgi (see remarks in file)
+ 2. drop samhain.cgi, samhain.dtd, samhain.xsl in some
+ directory on your webserver
+ 3. use .htaccess to protect access to that directory
+ 4. point your browser at samhain.cgi
+
+ You may need to rename samhain.cgi to samhain.php if you use
+ mod_php. Also, you will certainly need to edit the path to the
+ logfile in samhain.cgi.
+
+ CAVEAT: There is no built-in access restriction (use .htaccess to
+ password-protect the directory).
+
+ The XSL stylesheet is based on a contribution by Olivier Salaun.
+
+
+samhain.spec: RPM spec file for building a vanilla single-host RPM
+------------
+
+ Contributed by Andre Oliveira da Costa <brblueser@uol.com.br>
+
+ This is a spec file to produce a vanilla single-host samhain RPM
+ (no fancy options, standard directory layout :).
+
+ Accepted parameters for 'rpmbuild':
+
+ --with gpg - enables gpg support
+ --with tests - make tests before building
+
+redhat_i386.client.spec: RPM spec file for building a RedHat client RPM
+------------
+
+ Contributed by Philipp Stadler <philipp@stadler.priv.at>
+
+ Does not install documentation or local config file.
+
+
+
diff --git a/scripts/check_samhain.pl.in b/scripts/check_samhain.pl.in
new file mode 100755
index 0000000..01d98b8
--- /dev/null
+++ b/scripts/check_samhain.pl.in
@@ -0,0 +1,215 @@
+#!/usr/bin/perl -w
+
+# check_samhain.pl - check to see how many policy violations are reported
+# by the samhain file integrity checker.
+#
+# Copyright Rainer Wichmann (2004, 2012)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+############################################################################
+
+# -------------------------------------------------------------------[ Uses ]--
+
+use strict;
+use Getopt::Long;
+use vars qw($PROGNAME $SAMHAIN $opt_V $opt_h $opt_v $verbose $opt_w $opt_c $opt_t $status $msg $state $retval);
+use lib "/usr/local/nagios/libexec" ;
+use utils qw(%ERRORS &print_revision);
+
+#my $TIMEOUT = 15;
+#my %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
+#sub print_revision ($$);
+
+# ----------------------------------------------------[ Function Prototypes ]--
+
+sub print_help ();
+sub print_usage ();
+sub process_arguments ();
+
+# ------------------------------------------------------------[ Environment ]--
+
+$ENV{'PATH'}='';
+$ENV{'BASH_ENV'}='';
+$ENV{'ENV'}='';
+
+# -----------------------------------------------------------------[ Global ]--
+
+$PROGNAME = "check_@install_name@";
+$SAMHAIN = "@sbindir@/@install_name@";
+
+# ----------------------------------------------------------------[ options ]--
+
+Getopt::Long::Configure('bundling');
+$status = process_arguments();
+if ($status){
+ print "ERROR: processing arguments\n";
+ exit $ERRORS{"UNKNOWN"};
+}
+
+# ----------------------------------------------------------------[ timeout ]--
+
+$SIG{'ALRM'} = sub {
+ print ("ERROR: timed out waiting for $SAMHAIN\n");
+ exit $ERRORS{"WARNING"};
+};
+alarm($opt_t);
+
+# ----------------------------------------------------------[ start samhain ]--
+
+if ( defined $SAMHAIN && -x $SAMHAIN ) {
+ if (! open (SHPIPE, "$SAMHAIN -t check --foreground -p err -s none -l none -m none 2>&1 | " ) ) {
+ print "ERROR: could not popen $SAMHAIN \n";
+ exit $ERRORS{'UNKNOWN'};
+ }
+}else{
+ print "ERROR: Could not find samhain executable!\n";
+ exit $ERRORS{'UNKNOWN'};
+}
+
+# ---------------------------------------------------------[ read from pipe ]--
+
+$status = 0;
+
+while (<SHPIPE>) {
+ if (/POLICY/) {
+ ++$status;
+ print $_ if $verbose;
+ }
+}
+
+if ($status < $opt_w) {
+ $msg = "OK: $status policy violations (threshold $opt_w/$opt_c)";
+ $state = $ERRORS{'OK'};
+} elsif ($status >= $opt_w && $status < $opt_c) {
+ $msg = "WARNING: $status policy violations (threshold w=$opt_w)";
+ $state = $ERRORS{'WARNING'};
+} else {
+ $msg = "CRITICAL: $status policy violations (threshold c=$opt_c)";
+ $state = $ERRORS{'CRITICAL'};
+}
+
+# -------------------------------------------------------------[ close pipe ]--
+
+close (SHPIPE);
+
+# declare an error if we also get a non-zero return code from samhain
+
+if ( $? ) {
+ $retval = $? / 256;
+ if ( $! ) {
+ print "Error closing $SAMHAIN: $!\n" if $verbose;
+ } else {
+ print "$SAMHAIN returned exit status $retval\n" if $verbose;
+ }
+ if ($state == $ERRORS{"CRITICAL"}) {
+ $state = $ERRORS{"CRITICAL"};
+ } else {
+ print "ERROR: $SAMHAIN exit status $retval\n";
+ exit $ERRORS{'UNKNOWN'};
+ }
+}
+
+# -------------------------------------------------------------------[ exit ]--
+
+print "$msg | 'policy violations'=$status;$opt_w;$opt_c\n";
+exit $state;
+
+
+# ------------------------------------------------------------[ Subroutines ]--
+
+sub process_arguments(){
+ GetOptions
+ ("V" => \$opt_V, "version" => \$opt_V,
+ "h" => \$opt_h, "help" => \$opt_h,
+ "v" => \$opt_v, "verbose" => \$opt_v,
+ "w=i" => \$opt_w, "warning=i" => \$opt_w,
+ "c=i" => \$opt_c, "critical=i" => \$opt_c,
+ "t=i" => \$opt_t, "timeout=i" => \$opt_t
+ );
+
+ if ($opt_V) {
+ print_revision($PROGNAME,'$Revision: 1.1 $ ');
+ exit $ERRORS{'OK'};
+ }
+
+ if ($opt_h) {
+ print_help();
+ exit $ERRORS{'OK'};
+ }
+
+ if (defined $opt_v ){
+ $verbose = $opt_v;
+ }
+
+ unless (defined $opt_t) {
+ $opt_t = $utils::TIMEOUT ; # default timeout
+ # $opt_t = $TIMEOUT ;
+ }
+
+ unless (defined $opt_w) {
+ $opt_w = 1;
+ }
+
+ unless (defined $opt_c) {
+ $opt_c = 1;
+ }
+
+ if ( $opt_w > $opt_c) {
+ print "Warning cannot be greater than Critical!\n";
+ exit $ERRORS{'UNKNOWN'};
+ }
+
+ return $ERRORS{'OK'};
+}
+
+sub print_usage () {
+ print "Usage: $PROGNAME [-w <warn>] [-c <crit>] [-t <timeout>]\n";
+}
+
+sub print_help () {
+ print_revision($PROGNAME, '1.1');
+ print "Copyright (c) 2004,2012 Rainer Wichmann
+
+This plugin checks the number of policy violations reported by the
+samhain file intgrity checker
+
+";
+ print_usage();
+ print "
+-w, --warning=INTEGER
+ Minimum number of policy violations for which a WARNING status will result
+-c, --critical=INTEGER
+ Minimum number of policy violations for which a CRITICAL status will result
+-t, --timeout=SECONDS
+ The number of seconds after which a the plugin will timeout
+-v, --verbose
+ Verbose output
+-h, --help
+ Show this help message
+-V, --version
+ Show the version of the plugin
+
+";
+}
+
+#sub print_revision ($$) {
+# my $commandName = shift;
+# my $pluginRevision = shift;
+# $pluginRevision =~ s/^\$Revision: //;
+# $pluginRevision =~ s/ \$\s*$//;
+# print "$commandName (@PACKAGE@ @VERSION@) $pluginRevision\n";
+#}
diff --git a/scripts/chroot.sh b/scripts/chroot.sh
new file mode 100755
index 0000000..b58903f
--- /dev/null
+++ b/scripts/chroot.sh
@@ -0,0 +1,131 @@
+#! /bin/sh
+
+# NOTE: tested on Debian Linux
+#
+# NO WARRANTY - may or may not work on your system
+#
+
+# Copyright Rainer Wichmann (2003)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+CHROOT=$1
+
+SYSTEM=`uname -s`
+
+if test "x$SYSTEM" = xLinux; then
+ :
+else
+ echo "This script will fail on systems other than Linux,"
+ echo "mainly because of the mknod commands to create devices"
+ echo "in the chroot jail."
+ exit 1
+fi
+
+if test "x$CHROOT" = x; then
+ echo "Usage: chroot.sh chroot_dir"
+ echo "Purpose: prepare a chroot jail for yule"
+ echo
+ echo "NOTE: tested on Debian Linux"
+ echo "NO WARRANTY - may or may not work on your system"
+ exit 1
+fi
+
+#
+# Link configuration file
+#
+echo " Link configuration file:"
+echo " ln -s ${CHROOT}/etc/yulerc /etc/yulerc"
+
+ln -s -f ${CHROOT}/etc/yulerc /etc/yulerc
+echo
+
+
+#
+# Create passwd file
+#
+echo " Create passwd file"
+echo " grep root /etc/passwd > ${CHROOT}/etc/passwd"
+echo " grep daemon /etc/passwd >> ${CHROOT}/etc/passwd"
+echo " grep yule /etc/passwd >> ${CHROOT}/etc/passwd"
+
+grep root /etc/passwd > ${CHROOT}/etc/passwd
+grep daemon /etc/passwd >> ${CHROOT}/etc/passwd
+grep yule /etc/passwd >> ${CHROOT}/etc/passwd
+echo
+
+
+#
+# Create group file
+#
+echo " Create group file"
+echo " grep root /etc/group > ${CHROOT}/etc/group"
+echo " grep daemon /etc/group >> ${CHROOT}/etc/group"
+echo " grep yule /etc/group >> ${CHROOT}/etc/group"
+
+grep root /etc/group > ${CHROOT}/etc/group
+grep daemon /etc/group >> ${CHROOT}/etc/group
+grep yule /etc/group >> ${CHROOT}/etc/group
+echo
+
+#
+# Create devices
+#
+echo " Create devices"
+echo " mkdir ${CHROOT}/dev"
+echo " mknod -m 444 ${CHROOT}/dev/urandom c 1 9"
+echo " mknod -m 666 ${CHROOT}/dev/random c 1 8"
+echo " mknod -m 666 ${CHROOT}/dev/null c 1 3"
+echo " mknod -m 666 ${CHROOT}/dev/null c 1 5"
+
+mkdir ${CHROOT}/dev
+mknod -m 444 ${CHROOT}/dev/urandom c 1 9
+mknod -m 666 ${CHROOT}/dev/random c 1 8
+mknod -m 666 ${CHROOT}/dev/null c 1 3
+mknod -m 666 ${CHROOT}/dev/zero c 1 5
+echo
+
+#
+# DNS
+#
+echo " Copy files for DNS"
+echo " cp -p /etc/nsswitch.conf ${CHROOT}/etc/"
+echo " cp -p /etc/hosts ${CHROOT}/etc/"
+echo " cp -p /etc/host.conf ${CHROOT}/etc/"
+echo " cp -p /etc/resolv.conf ${CHROOT}/etc/"
+echo " cp -p /etc/services ${CHROOT}/etc/"
+echo " cp -p /etc/protocols ${CHROOT}/etc/"
+
+cp -p /etc/nsswitch.conf ${CHROOT}/etc/
+cp -p /etc/hosts ${CHROOT}/etc/
+cp -p /etc/host.conf ${CHROOT}/etc/
+cp -p /etc/resolv.conf ${CHROOT}/etc/
+cp -p /etc/services ${CHROOT}/etc/
+cp -p /etc/protocols ${CHROOT}/etc/
+
+echo "----------------------------------------------------"
+echo
+echo " You may want to review ${CHROOT}/etc/passwd"
+echo " to replace passwords with a *, and to fix the"
+echo " path to the home directory of the yule user."
+echo
+echo " If using a signed configuration file, you need"
+echo " a working copy of GnuPG inside the chroot jail."
+echo
+echo "----------------------------------------------------"
+ \ No newline at end of file
diff --git a/scripts/concat.pl b/scripts/concat.pl
new file mode 100755
index 0000000..f093850
--- /dev/null
+++ b/scripts/concat.pl
@@ -0,0 +1,69 @@
+#! /usr/bin/perl
+
+# Copyright Rainer Wichmann (2004)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+use warnings;
+use strict;
+
+my $fno = 0;
+my $file = '';
+my @last2 = ();
+my $line = '';
+
+sub usage () {
+ print "Usage: concat.pl <list_of_database_files>\n\n";
+ print " Will concatenate samhain file signature database files\n";
+ print " and print to stdout.\n";
+ print " Does not work on signed or otherwise modified\n";
+ print " file signature databases.\n";
+}
+
+if ($#ARGV < 0) { # must be at least one file
+ usage();
+ exit 1;
+} elsif ($ARGV[0] =~ /^-h$/ || $ARGV[0] =~ /^--?help$/) {
+ usage();
+ exit 0;
+}
+
+
+for $file (@ARGV) {
+ open FH, "< $file" or die "Cannot open $file: $!";
+ if ($fno != 0) { # search and read past the start-of-file marker
+ while (<FH>) {
+ last if ($_ =~ /^\[SOF\]$/);
+ }
+ }
+ @last2 = ();
+ while (<FH>) {
+ push @last2, $_;
+ if (@last2 > 2) {
+ $line = shift @last2;
+ print $line;
+ }
+ }
+ close FH;
+ ++$fno;
+}
+
+# last two lines of last file
+$line = shift @last2;
+print $line;
+$line = shift @last2;
+print $line;
diff --git a/scripts/example_pager.pl b/scripts/example_pager.pl
new file mode 100755
index 0000000..b6745e5
--- /dev/null
+++ b/scripts/example_pager.pl
@@ -0,0 +1,245 @@
+#!/usr/bin/perl -w
+#
+#
+# Simple program to connect to:
+# http://www2.pagemart.com/cgi-bin/rbox/pglpage-cgi
+# and send a page.
+#
+# Modified 10/21/99 Will O'Brien willo@savvis.net
+# Originally Written by David Allen s2mdalle@titan.vcu.edu
+# http://opop.nols.com/
+#
+#
+# Modified by R. Wichmann (read message from stdin)
+# <support@la-samhna.de>
+#
+# - added config variables
+# - read MESSAGE from STDIN
+#
+# This file is released under the terms of the GNU General Public License.
+# Please see http://www.gnu.org for more details.
+#
+# This program still beta, but working better.
+#
+# Changelog:
+# 10/21/99: Modified original code and get paging to function.
+# 10/22/99: Fixed Error checking. Checks PIN length, outputs failure message.
+#
+# REQUIRES MODULES: strict and IO::Socket
+#
+# USAGE FROM COMMAND LINE: echo "message" | example_pager.pl PAGER_PIN
+# Where PAGER_PIN is the PIN of the pager you want to send MESSAGE to.
+#
+# This program will send the page using
+# www.pagemart.com/cgi-bin/rbox/pglpage-cgi
+# and will store the response in LASTRESPONSE.html when the server replies.
+#
+# If you are looking at this program for examples of code to make it work,
+# check out the page{} subroutine below - it is the meat of this program.
+##############################################################################
+
+# use Socket; # INET
+use strict;
+use IO::Socket; # Socket work
+
+my $pagerid = shift;
+
+########################## -- BEGIN CONFIGURATION --
+
+## set to 1 for verbose output
+my $verbose = 1;
+
+## set to 1 if you want to save response
+my $save_response = 1;
+
+## set to 1 to enable sending
+my $really_send = 0;
+
+########################### -- END CONFIGURATION --
+
+# previous
+#my $MESSAGE = join(' ', @ARGV);
+
+my $MESSAGE='';
+undef $/;
+$MESSAGE=<STDIN>;
+$MESSAGE =~ s/\[EOF\]//g;
+
+die "Usage: echo \"message\" \| example_pager.pl PAGER_ID\n\n"
+ unless $pagerid;
+die "Usage: echo \"message\" \| example_pager.pl PAGER_ID\n\n"
+ unless $MESSAGE;
+
+page($pagerid, $MESSAGE);
+
+if ($verbose) { print "Done.\n"; }
+exit(0);
+
+############################################################################
+
+sub page{
+ my ($name, $text) = @_;
+ my $TRUNCATED = 0;
+ my $PAGE = ""; # The text sent to www.pagemart.com - appended later.
+
+ $pagerid = $name;
+
+ if ($verbose) { print STDERR "Processing pager ID...\n"; }
+ # Eliminate everything but numbers from the pager id
+ $pagerid =~ s/[^0-9]//g;
+
+ # Check the pager id length and so on.
+ if( (((length($pagerid)) < 7)) || ((length($pagerid)) > 10) )
+ {
+ if ($verbose) {
+ die "Bad pager ID number. A pager id number is 7 or 10 numbers.\n";
+ }
+ else {
+ exit (1);
+ }
+ }
+
+ if ($verbose) {
+ die "No message specified.\n" unless $text;
+ }
+ else {
+ exit (1) unless $text;
+ }
+
+
+ # This is the format of the message we're going to send via the TCP
+ # socket
+ # POST /cgi-bin/rbox/pglpage-cgi HTTP/1.0
+ # User-Agent: Myprogram/1.00
+ # Accept: */*
+ # Content-length: 35
+ # Content-type: application/x-www-form-urlencoded
+ #
+ # pin2=6807659&message1=stuff+and+nonsense
+
+ if ($verbose) { print STDERR "Processing text of message...\n"; }
+ # A bit of string pre-processing
+ chomp $text;
+ my $strdelim = "\r\n"; # At the end of each line.
+
+ # Compress the text a bit - eliminate redundant characters - this
+ # helps a lot for pages that have multiple spaces and so on.
+ $text =~s/\n/ /g; # Linefeeds are spaces
+ $text =~s/\r//g; # No carriage returns
+ $text =~s/\s+/ /g; # Multiple whitespace -> one space.
+
+ if(length($text)>=200)
+ {
+ $TRUNCATED = "True";
+ $text = substr($text, 0, 199); # 200 Character maximum
+ }
+
+ my $encodedmessage = urlencode($text);
+
+ # The length of the request has to be TOTAL QUERY. If it's just
+ # the length of the string you're sending, it will truncate the
+ # hell out of the page. So the pager number is length($pagerid)
+ # of course the length of the message, and add the length of the
+ # parameter flags, (PIN= and ?MSSG=) and you're done.
+
+ my $xxmsg = "pin2=$pagerid&";
+ $xxmsg .= "PAGELAUNCHERID=1&";
+ $xxmsg .= $encodedmessage;
+
+ # my $pagelen=length($encodedmessage)+length("pin2=?message1=")+
+ # length($pagerid)+;
+
+ my $pagelen = length($xxmsg);
+
+ # Build the text we send to the server
+ $PAGE = "POST /cgi-bin/rbox/pglpage-cgi HTTP/1.0$strdelim";
+ $PAGE .= "User-Agent: Pagent/5.4$strdelim";
+ $PAGE .= "Referer: http://www.weblinkwireless.com/productsnservices/sendingmessage/pssm-sendamessage.html$strdelim";
+ $PAGE .= "Accept: */*$strdelim";
+ $PAGE .= "Content-length: $pagelen$strdelim";
+ $PAGE .= "Content-type: application/x-www-form-urlencoded$strdelim";
+ $PAGE .= "$strdelim";
+ # $PAGE .= "pin2=$pagerid&message1=".$encodedmessage;
+ $PAGE .= $xxmsg;
+
+ if ($verbose) {
+ print STDERR "Sending message...\n\n";
+ print STDERR "$PAGE\n\n";
+ }
+
+
+ my $document='';
+
+ if ($really_send)
+ {
+ # Now we send our data.
+ # Note that this is just quick and dirty, so I'm using a perl module
+ # to do the network dirty work for me.
+ my $sock = IO::Socket::INET->new(PeerAddr => 'www2.pagemart.com',
+ PeerPort => 'http(80)',
+ Proto => 'tcp');
+
+ if ($verbose) {
+ die "Cannot create socket : $!" unless $sock;
+ }
+ else {
+ exit (1) unless $sock;
+ }
+ $sock->autoflush();
+ $sock->print("$PAGE");
+
+ $document = join('', $sock->getlines());
+ }
+ else
+ {
+ $document = " really_send was set to 0, page NOT sent";
+ }
+
+ if ($save_response)
+ {
+ if ($verbose)
+ {
+ print STDERR "Saving response to tmp.html...\n\n";
+ }
+ my $status = 0;
+ open(TMP,">tmp.html") or $status=1;
+ print TMP "$document\n" unless $status;
+ close TMP unless $status;
+ }
+
+ if($document =~ m/NOT/g)
+ {
+ if ($verbose)
+ {
+ print STDERR "Page not sent. There was an error. \n";
+ print STDERR "See tmp.html for what the server sent back to me.\n";
+ }
+ exit(0);
+ } # End if
+ else
+ {
+ if ($verbose)
+ {
+ $document =~ m/(\d{1,4}) character message out of/g;
+ print STDERR "Page sent successfully to $pagerid.\n";
+ }
+ exit(0);
+ } # End else
+} # End sub page
+
+
+############################################################################
+
+sub urlencode{
+ my $text = shift;
+ my $input = $text;
+
+ chomp $input;
+
+ # Translate all non-letter non-number characters into their %HEX_VAL
+ # and return that string.
+ $input =~ s/([^a-zA-Z0-9-_\.\/])/uc sprintf("%%%02x",ord($1))/eg;
+ $input =~ s/%20/+/g;
+
+ return $input;
+} # End sub urlencode
diff --git a/scripts/example_sms.pl b/scripts/example_sms.pl
new file mode 100755
index 0000000..abe9c27
--- /dev/null
+++ b/scripts/example_sms.pl
@@ -0,0 +1,224 @@
+#!/usr/bin/perl -w
+
+use strict;
+use IO::Socket; # Socket work
+
+###############################################################################
+##
+## example_sms.pl -- simple example script to send
+## an SMS message via a web cgi
+## Works with German pitcom powered free SMS sites
+## - find one and look at the page source to set the
+## pitcom variables (see below)
+## - note that pitcom checks the referer, thus you should
+## take care to set the proper value
+##
+## NOTE: while the 'big names' have implemented measures to prevent
+## the use of automated scripts, and disallow such scripts
+## explicitely in their TOS (Terms of Service), this is not
+## neccesarily true for smaller websites.
+##
+## An example for the latter are German websites providing free
+## SMS (to German nets only) powered by pitcom.
+## With a suitable query, you may find such sites on (e.g.) Google.
+## At the time of the writing of this script, the sites I found did not
+## disallow the use of scripts, but check for yourself if you are
+## using this.
+##
+## usage: example_sms.pl [NR]
+## <NR> destination phone number
+## message is read from STDIN
+##
+## (c) R. Wichmann <support@la-samhna.de> Tue Jul 17 CEST 2001
+## Released under the Gnu Public License version 2.0 or later
+## adapted from archpage ( (c) Rob Muhlestein )
+## and mpage.pl ( (c) David Allen <s2mdalle@titan.vcu.edu> )
+##
+
+########################## -- BEGIN CONFIGURATION --
+
+## set to default phone number
+ my $NR = '<default phone number>';
+
+## set to sender
+ #my $VON = '<default sender>';
+ my $VON = 'stupsel';
+
+## set to URL of form page
+ my $REFERER = '<default referer>';
+
+## set to cgi script URL without 'http://domain';
+ my $PAGE = '<default cgi URL>';
+
+## set to domain where cgi script lives;
+ my $DOMAIN = '<default domain>';
+
+## set to 1 if you want to save response
+ my $save_response = 1;
+
+## set to 1 for verbose output
+ my $verbose = 1;
+
+## set to 1 to enable sending
+ my $really_send = 0;
+
+
+## The PITCOM variables
+
+#my $ID = '<id>'; # gateway-ID
+#my $WERBUNG = '<advertisement>'; # advertisement
+#my $QUITTUNG = '<return page>'; # return page
+#my $USER = '<customer>'; # customer
+#my $LIST = '0'; # message type
+
+########################## -- END CONFIGURATION --
+
+$NR = $ARGV[0] if $ARGV[0];
+
+my $message='';
+undef $/;
+$message=<STDIN>;
+
+$message =~ s/\[EOF\]//g;
+
+## URL encode and remove line breaks
+$message =~ s/\n/ /g;
+$message =~ s/\r//g;
+$message =~s/\s+/ /g; # Multiple whitespace -> one space
+
+$message =~ s/([^a-zA-Z0-9-_\.\/])/uc sprintf("%%%02x",ord($1))/eg;
+$message =~ s/%20/+/g;
+
+$WERBUNG =~ s/([^a-zA-Z0-9-_\.\/])/uc sprintf("%%%02x",ord($1))/eg;
+$WERBUNG =~ s/%20/+/g;
+$QUITTUNG =~ s/([^a-zA-Z0-9-_\.\/])/uc sprintf("%%%02x",ord($1))/eg;
+$QUITTUNG =~ s/%20/+/g;
+$USER =~ s/([^a-zA-Z0-9-_\.\/])/uc sprintf("%%%02x",ord($1))/eg;
+$USER =~ s/%20/+/g;
+
+## truncate
+my $maxChars = 153 - length($WERBUNG) - length($VON);
+
+if(length($message) >= $maxChars)
+{
+ $message = substr($message, 0, $maxChars);
+}
+
+
+my $NR1 = substr($NR, 0, 4);
+my $NR2 = substr($NR, 4, length($NR)-4);
+
+my $msglen = length($message);
+
+my $overhead = "ID=$ID&";
+$overhead .= "WERBUNG=$WERBUNG&";
+$overhead .= "QUITTUNG=$QUITTUNG&";
+$overhead .= "USER=$USER&";
+$overhead .= "LIST=$LIST&";
+$overhead .= "NR1=$NR1&";
+$overhead .= "NR2=$NR2&";
+$overhead .= "VON=$VON&";
+$overhead .= "MESSAGE=$message&";
+$overhead .= "CNT=$msglen";
+
+my $smslen = length($overhead);
+
+my $llim = "\r\n"; # At the end of each line.
+
+my $SMS = "POST $PAGE HTTP/1.0$llim";
+$SMS .= "User-Agent: EvilGenius/1.0$llim";
+$SMS .= "Referer: $REFERER$llim";
+$SMS .= "Accept: */*$llim";
+$SMS .= "Content-length: $smslen$llim";
+$SMS .= "Content-type: application/x-www-form-urlencoded$llim";
+$SMS .= "$llim";
+$SMS .= "$overhead";
+
+if ($verbose)
+{
+ print STDERR " Sending message...\n\n";
+ print STDERR "$SMS\n\n";
+}
+
+my $document='';
+
+if ($really_send)
+{
+ my $sock = IO::Socket::INET->new(PeerAddr => $DOMAIN,
+ PeerPort => 'http(80)',
+ Proto => 'tcp');
+
+
+ if ($verbose)
+ {
+ die "Cannot create socket : $!" unless $sock;
+ }
+ else
+ {
+ exit (1) unless $sock;
+ }
+
+ $sock->autoflush();
+ $sock->print("$SMS");
+
+ $document = join('', $sock->getlines());
+}
+else
+{
+ $document = " really_send was set to 0, SMS not sent";
+}
+
+if ($save_response)
+{
+ if ($verbose)
+ {
+ print STDERR "Saving response to tmp.html...\n\n";
+ }
+ my $status = 0;
+ open(TMP,">tmp.html") or $status=1;
+ print TMP "$document\n" unless $status;
+ close TMP unless $status;
+}
+
+if ($document =~ m/SMS wird versendet/g)
+{
+ if ($verbose)
+ {
+ print STDERR " SMS successfully sent to $NR.\n";
+ }
+ exit (0);
+}
+else
+{
+ if ($verbose)
+ {
+ print STDERR " SMS not sent. There was an error.\n";
+ print STDERR " Use save_response = 1 to save the response to\n";
+ print STDERR " tmp.html in order to see what the server sent back.\n";
+ }
+ exit (1);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/foot.html b/scripts/foot.html
new file mode 100644
index 0000000..5a3e88a
--- /dev/null
+++ b/scripts/foot.html
@@ -0,0 +1,11 @@
+
+ </table>
+
+ </td></tr>
+ </table>
+
+ </td></tr>
+ </table>
+</center>
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/scripts/head.html b/scripts/head.html
new file mode 100644
index 0000000..1af3b75
--- /dev/null
+++ b/scripts/head.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Server status</title>
+<meta http-equiv="refresh" content="120; URL=./yule.html">
+<style type="text/css">
+<!--
+ .Inactive, .PANIC, .TIMEOUT_EXCEEDED {
+ border-style:none;
+ border-width:thin;
+ background:#ff9933;
+ color:000000;
+ padding-left:5px;
+ }
+ -->
+</style>
+</head>
+<body bgcolor="#FFFFFF" text="#000000"
+ link="#770000" vlink="#000000" alink="#FF0000">
+
+ <table border=0 cellpadding="0" cellspacing="3" width="100% ">
+ <tr><td>
+
+ <img src="./samhain.jpg" ALT="S A M H A I N" height="48"
+ width="240" border="0" >
+
+ </td></tr>
+ </table>
+ <h1>Server Status</h1>
+
+ <table border=0 cellpadding="0" cellspacing="3" width="100% ">
+ <tr><td valign="top" >
+
+ <table border=0 cellpadding="0" cellspacing="0" width="100% ">
+ <tr><td bgcolor="#777777" valign="top" >
+
+ <table border="0" cellpadding="5" cellspacing="2"
+ width="100% " align="center">
+ <tr><td valign="top" bgcolor="#ffffff">
+
+ Current time: %T <br>
+ Startup time: %S <br>
+ </td></tr>
+ <tr><td valign="top" bgcolor="#ffffff">
+ Connections: (maximum %M simultaneously) <br>
+ open %O <br>
+ total %A <br>
+ </td></tr>
+ <tr><td valign="top" bgcolor="#ffffff">
+ Last connection: %L
+
+ </td></tr>
+ </table>
+
+ </td></tr>
+ </table>
+
+ </td></tr>
+ </table>
+
+
+ <h1>Clients</h1>
+
+ <center>
+ <table border=0 cellpadding="0" cellspacing="3" width="100% ">
+ <tr><td valign="top" >
+
+ <table border=0 cellpadding="0" cellspacing="0" width="100% ">
+ <tr><td bgcolor="#777777" valign="top" >
+
+ <table border="0" cellpadding="5" cellspacing="2"
+ width="100% " align="center" bgcolor="#ffffff">
diff --git a/scripts/logrotate b/scripts/logrotate
new file mode 100644
index 0000000..3ec6505
--- /dev/null
+++ b/scripts/logrotate
@@ -0,0 +1,24 @@
+/var/log/samhain_log {
+ weekly
+ rotate 52
+ nocreate
+ missingok
+ compress
+
+ prerotate
+ if test -f /run/samhain.pid; then \
+ PIN=`cat /run/samhain.pid`; \
+ /bin/kill -TTIN $PIN; \
+ sleep 1; \
+ AA=0; \
+ while test "x$AA" != "x120"; do \
+ AA=$(( AA + 1 )); \
+ if test -f /var/log/samhain_log.lock; then \
+ sleep 1; \
+ else \
+ break; \
+ fi \
+ done; \
+ fi
+ endscript
+}
diff --git a/scripts/logrotate.in b/scripts/logrotate.in
new file mode 100644
index 0000000..a0ad9bd
--- /dev/null
+++ b/scripts/logrotate.in
@@ -0,0 +1,24 @@
+@mylogfile@ {
+ weekly
+ rotate 52
+ nocreate
+ missingok
+ compress
+
+ prerotate
+ if test -f @mylockfile@; then \
+ PIN=`cat @mylockfile@`; \
+ /bin/kill -TTIN $PIN; \
+ sleep 1; \
+ AA=0; \
+ while test "x$AA" != "x120"; do \
+ AA=$(( AA + 1 )); \
+ if test -f @mylogfile@.lock; then \
+ sleep 1; \
+ else \
+ break; \
+ fi \
+ done; \
+ fi
+ endscript
+} \ No newline at end of file
diff --git a/scripts/makeself/makeself-header.sh b/scripts/makeself/makeself-header.sh
new file mode 100755
index 0000000..901fb01
--- /dev/null
+++ b/scripts/makeself/makeself-header.sh
@@ -0,0 +1,365 @@
+cat << EOF > "$archname"
+#!/bin/sh
+# This script was generated using Makeself $MS_VERSION
+CRCsum="$CRCsum"
+MD5="$MD5sum"
+TMPROOT=\${TMPDIR:=/tmp}
+
+label="$LABEL"
+script="$SCRIPT"
+scriptargs="$SCRIPTARGS"
+targetdir="$archdirname"
+filesizes="$filesizes"
+keep=$KEEP
+
+print_cmd_arg=""
+if type printf > /dev/null; then
+ print_cmd="printf"
+elif test -x /usr/ucb/echo; then
+ print_cmd="/usr/ucb/echo"
+else
+ print_cmd="echo"
+fi
+
+MS_Printf()
+{
+ \$print_cmd \$print_cmd_arg "\$1"
+}
+
+MS_Progress()
+{
+ while read a; do
+ MS_Printf .
+ done
+}
+
+MS_dd()
+{
+ blocks=\`expr \$3 / 1024\`
+ bytes=\`expr \$3 % 1024\`
+ dd if="\$1" ibs=\$2 skip=1 obs=1024 conv=sync 2> /dev/null | \\
+ { test \$blocks -gt 0 && dd ibs=1024 obs=1024 count=\$blocks ; \\
+ test \$bytes -gt 0 && dd ibs=1 obs=1024 count=\$bytes ; } 2> /dev/null
+}
+
+MS_Help()
+{
+ cat << EOH >&2
+Makeself version $MS_VERSION
+ 1) Getting help or info about \$0 :
+ \$0 --help Print this message
+ \$0 --info Print embedded info : title, default target directory, embedded script ...
+ \$0 --lsm Print embedded lsm entry (or no LSM)
+ \$0 --list Print the list of files in the archive
+ \$0 --check Checks integrity of the archive
+
+ 2) Running \$0 :
+ \$0 [options] [--] [additional arguments to embedded script]
+ with following options (in that order)
+ --confirm Ask before running embedded script
+ --noexec Do not run embedded script
+ --keep Do not erase target directory after running
+ the embedded script
+ --nox11 Do not spawn an xterm
+ --nochown Do not give the extracted files to the current user
+ --target NewDirectory Extract in NewDirectory
+ --tar arg1 [arg2 ...] Access the contents of the archive through the tar command
+ -- Following arguments will be passed to the embedded script
+EOH
+}
+
+MS_Check()
+{
+ OLD_PATH=\$PATH
+ PATH=\${GUESS_MD5_PATH:-"\$OLD_PATH:/bin:/usr/bin:/sbin:/usr/local/ssl/bin:/usr/local/bin:/opt/openssl/bin"}
+ MD5_PATH=\`exec 2>&-; which md5sum || type md5sum\`
+ MD5_PATH=\${MD5_PATH:-\`exec 2>&-; which md5 || type md5\`}
+ PATH=\$OLD_PATH
+ MS_Printf "Verifying archive integrity..."
+ offset=\`head -n $SKIP "\$1" | wc -c | tr -d " "\`
+ verb=\$2
+ i=1
+ for s in \$filesizes
+ do
+ crc=\`echo \$CRCsum | cut -d" " -f\$i\`
+ if test -x "\$MD5_PATH"; then
+ md5=\`echo \$MD5 | cut -d" " -f\$i\`
+ if test \$md5 = "00000000000000000000000000000000"; then
+ test x\$verb = xy && echo " \$1 does not contain an embedded MD5 checksum." >&2
+ else
+ md5sum=\`MS_dd "\$1" \$offset \$s | "\$MD5_PATH" | cut -b-32\`;
+ if test "\$md5sum" != "\$md5"; then
+ echo "Error in MD5 checksums: \$md5sum is different from \$md5" >&2
+ exit 2
+ else
+ test x\$verb = xy && MS_Printf " MD5 checksums are OK." >&2
+ fi
+ crc="0000000000"; verb=n
+ fi
+ fi
+ if test \$crc = "0000000000"; then
+ test x\$verb = xy && echo " \$1 does not contain a CRC checksum." >&2
+ else
+ sum1=\`MS_dd "\$1" \$offset \$s | cksum | awk '{print \$1}'\`
+ if test "\$sum1" = "\$crc"; then
+ test x\$verb = xy && MS_Printf " CRC checksums are OK." >&2
+ else
+ echo "Error in checksums: \$sum1 is different from \$crc"
+ exit 2;
+ fi
+ fi
+ i=\`expr \$i + 1\`
+ offset=\`expr \$offset + \$s\`
+ done
+ echo " All good."
+}
+
+UnTAR()
+{
+ tar \$1vf - 2>&1 || { echo Extraction failed. > /dev/tty; kill -15 \$$; }
+}
+
+finish=true
+xterm_loop=
+nox11=$NOX11
+copy=$COPY
+ownership=y
+verbose=n
+
+initargs="\$@"
+
+while true
+do
+ case "\$1" in
+ -h | --help)
+ MS_Help
+ exit 0
+ ;;
+ --info)
+ echo Identification: "\$label"
+ echo Target directory: "\$targetdir"
+ echo Uncompressed size: $USIZE KB
+ echo Compression: $COMPRESS
+ echo Date of packaging: $DATE
+ echo Built with Makeself version $MS_VERSION on $OSTYPE
+ echo Build command was: "$MS_COMMAND"
+ if test x\$script != x; then
+ echo Script run after extraction:
+ echo " " \$script \$scriptargs
+ fi
+ if test x"$copy" = xcopy; then
+ echo "Archive will copy itself to a temporary location"
+ fi
+ if test x"$KEEP" = xy; then
+ echo "directory \$targetdir is permanent"
+ else
+ echo "\$targetdir will be removed after extraction"
+ fi
+ exit 0
+ ;;
+ --dumpconf)
+ echo LABEL=\"\$label\"
+ echo SCRIPT=\"\$script\"
+ echo SCRIPTARGS=\"\$scriptargs\"
+ echo archdirname=\"$archdirname\"
+ echo KEEP=$KEEP
+ echo COMPRESS=$COMPRESS
+ echo filesizes=\"\$filesizes\"
+ echo CRCsum=\"\$CRCsum\"
+ echo MD5sum=\"\$MD5\"
+ echo OLDUSIZE=$USIZE
+ echo OLDSKIP=`expr $SKIP + 1`
+ exit 0
+ ;;
+ --lsm)
+cat << EOLSM
+EOF
+eval "$LSM_CMD"
+cat << EOF >> "$archname"
+EOLSM
+ exit 0
+ ;;
+ --list)
+ echo Target directory: \$targetdir
+ offset=\`head -n $SKIP "\$0" | wc -c | tr -d " "\`
+ for s in \$filesizes
+ do
+ MS_dd "\$0" \$offset \$s | eval "$GUNZIP_CMD" | UnTAR t
+ offset=\`expr \$offset + \$s\`
+ done
+ exit 0
+ ;;
+ --tar)
+ offset=\`head -n $SKIP "\$0" | wc -c | tr -d " "\`
+ arg1="\$2"
+ shift 2
+ for s in \$filesizes
+ do
+ MS_dd "\$0" \$offset \$s | eval "$GUNZIP_CMD" | tar "\$arg1" - \$*
+ offset=\`expr \$offset + \$s\`
+ done
+ exit 0
+ ;;
+ --check)
+ MS_Check "\$0" y
+ exit 0
+ ;;
+ --confirm)
+ verbose=y
+ shift
+ ;;
+ --noexec)
+ script=""
+ shift
+ ;;
+ --keep)
+ keep=y
+ shift
+ ;;
+ --target)
+ keep=y
+ targetdir=\${2:-.}
+ shift 2
+ ;;
+ --nox11)
+ nox11=y
+ shift
+ ;;
+ --nochown)
+ ownership=n
+ shift
+ ;;
+ --xwin)
+ finish="echo Press Return to close this window...; read junk"
+ xterm_loop=1
+ shift
+ ;;
+ --phase2)
+ copy=phase2
+ shift
+ ;;
+ --)
+ shift
+ break ;;
+ -*)
+ echo Unrecognized flag : "\$1" >&2
+ MS_Help
+ exit 1
+ ;;
+ *)
+ break ;;
+ esac
+done
+
+case "\$copy" in
+copy)
+ SCRIPT_COPY="\$TMPROOT/makeself\$\$"
+ echo "Copying to a temporary location..." >&2
+ cp "\$0" "\$SCRIPT_COPY"
+ chmod +x "\$SCRIPT_COPY"
+ cd "\$TMPROOT"
+ exec "\$SCRIPT_COPY" --phase2
+ ;;
+phase2)
+ finish="\$finish ; rm -f \$0"
+ ;;
+esac
+
+if test "\$nox11" = "n"; then
+ if tty -s; then # Do we have a terminal?
+ :
+ else
+ if test x"\$DISPLAY" != x -a x"\$xterm_loop" = x; then # No, but do we have X?
+ if xset q > /dev/null 2>&1; then # Check for valid DISPLAY variable
+ GUESS_XTERMS="xterm rxvt dtterm eterm Eterm kvt konsole aterm"
+ for a in \$GUESS_XTERMS; do
+ if type \$a >/dev/null 2>&1; then
+ XTERM=\$a
+ break
+ fi
+ done
+ chmod a+x \$0 || echo Please add execution rights on \$0
+ if test \`echo "\$0" | cut -c1\` = "/"; then # Spawn a terminal!
+ exec \$XTERM -title "\$label" -e "\$0" --xwin "\$initargs"
+ else
+ exec \$XTERM -title "\$label" -e "./\$0" --xwin "\$initargs"
+ fi
+ fi
+ fi
+ fi
+fi
+
+if test "\$targetdir" = "."; then
+ tmpdir="."
+else
+ if test "\$keep" = y; then
+ echo "Creating directory \$targetdir" >&2
+ tmpdir="\$targetdir"
+ else
+ tmpdir="\$TMPROOT/selfgz\$\$"
+ fi
+ mkdir -p \$tmpdir || {
+ echo 'Cannot create target directory' \$tmpdir >&2
+ echo 'You should try option --target OtherDirectory' >&2
+ eval \$finish
+ exit 1
+ }
+fi
+
+location="\`pwd\`"
+if test x\$SETUP_NOCHECK != x1; then
+ MS_Check "\$0"
+fi
+offset=\`head -n $SKIP "\$0" | wc -c | tr -d " "\`
+
+if test x"\$verbose" = xy; then
+ MS_Printf "About to extract $USIZE KB in \$tmpdir ... Proceed ? [Y/n] "
+ read yn
+ if test x"\$yn" = xn; then
+ eval \$finish; exit 1
+ fi
+fi
+
+MS_Printf "Uncompressing \$label"
+res=3
+if test "\$keep" = n; then
+ trap 'echo Signal caught, cleaning up >&2; cd \$TMPROOT; /bin/rm -rf \$tmpdir; eval \$finish; exit 15' 1 2 3 15
+fi
+
+for s in \$filesizes
+do
+ if MS_dd "\$0" \$offset \$s | eval "$GUNZIP_CMD" | ( cd "\$tmpdir"; UnTAR x ) | MS_Progress; then
+ if test x"\$ownership" = xy; then
+ (PATH=/usr/xpg4/bin:\$PATH; cd "\$tmpdir"; chown -R \`id -u\` .; chgrp -R \`id -g\` .)
+ fi
+ else
+ echo
+ echo "Unable to decompress \$0" >&2
+ eval \$finish; exit 1
+ fi
+ offset=\`expr \$offset + \$s\`
+done
+echo
+
+cd "\$tmpdir"
+res=0
+if test x"\$script" != x; then
+ if test x"\$verbose" = xy; then
+ MS_Printf "OK to execute: \$script \$scriptargs \$* ? [Y/n] "
+ read yn
+ if test x"\$yn" = x -o x"\$yn" = xy -o x"\$yn" = xY; then
+ eval \$script \$scriptargs \$*; res=\$?;
+ fi
+ else
+ eval \$script \$scriptargs \$*; res=\$?
+ fi
+ if test \$res -ne 0; then
+ test x"\$verbose" = xy && echo "The program '\$script' returned an error code (\$res)" >&2
+ fi
+fi
+if test "\$keep" = n; then
+ cd \$TMPROOT
+ /bin/rm -rf \$tmpdir
+fi
+eval \$finish; exit \$res
+EOF
diff --git a/scripts/makeself/makeself.sh b/scripts/makeself/makeself.sh
new file mode 100755
index 0000000..0859fd0
--- /dev/null
+++ b/scripts/makeself/makeself.sh
@@ -0,0 +1,361 @@
+#!/bin/sh
+#
+# Makeself version 2.1.x
+# by Stephane Peter <megastep@megastep.org>
+#
+# $Id: makeself.sh,v 1.44 2004/04/23 18:28:48 megastep Exp $
+#
+# Utility to create self-extracting tar.gz archives.
+# The resulting archive is a file holding the tar.gz archive with
+# a small Shell script stub that uncompresses the archive to a temporary
+# directory and then executes a given script from withing that directory.
+#
+# Makeself home page: http://www.megastep.org/makeself/
+#
+# Version 2.0 is a rewrite of version 1.0 to make the code easier to read and maintain.
+#
+# Version history :
+# - 1.0 : Initial public release
+# - 1.1 : The archive can be passed parameters that will be passed on to
+# the embedded script, thanks to John C. Quillan
+# - 1.2 : Package distribution, bzip2 compression, more command line options,
+# support for non-temporary archives. Ideas thanks to Francois Petitjean
+# - 1.3 : More patches from Bjarni R. Einarsson and Francois Petitjean:
+# Support for no compression (--nocomp), script is no longer mandatory,
+# automatic launch in an xterm, optional verbose output, and -target
+# archive option to indicate where to extract the files.
+# - 1.4 : Improved UNIX compatibility (Francois Petitjean)
+# Automatic integrity checking, support of LSM files (Francois Petitjean)
+# - 1.5 : Many bugfixes. Optionally disable xterm spawning.
+# - 1.5.1 : More bugfixes, added archive options -list and -check.
+# - 1.5.2 : Cosmetic changes to inform the user of what's going on with big
+# archives (Quake III demo)
+# - 1.5.3 : Check for validity of the DISPLAY variable before launching an xterm.
+# More verbosity in xterms and check for embedded command's return value.
+# Bugfix for Debian 2.0 systems that have a different "print" command.
+# - 1.5.4 : Many bugfixes. Print out a message if the extraction failed.
+# - 1.5.5 : More bugfixes. Added support for SETUP_NOCHECK environment variable to
+# bypass checksum verification of archives.
+# - 1.6.0 : Compute MD5 checksums with the md5sum command (patch from Ryan Gordon)
+# - 2.0 : Brand new rewrite, cleaner architecture, separated header and UNIX ports.
+# - 2.0.1 : Added --copy
+# - 2.1.0 : Allow multiple tarballs to be stored in one archive, and incremental updates.
+# Added --nochown for archives
+# Stopped doing redundant checksums when not necesary
+# - 2.1.1 : Work around insane behavior from certain Linux distros with no 'uncompress' command
+# Cleaned up the code to handle error codes from compress. Simplified the extraction code.
+# - 2.1.2 : Some bug fixes. Use head -n to avoid problems.
+# - 2.1.3 : Bug fixes with command line when spawning terminals.
+# Added --tar for archives, allowing to give arbitrary arguments to tar on the contents of the archive.
+# Added --noexec to prevent execution of embedded scripts.
+# Added --nomd5 and --nocrc to avoid creating checksums in archives.
+# Added command used to create the archive in --info output.
+# Run the embedded script through eval.
+#
+# (C) 1998-2004 by Stéphane Peter <megastep@megastep.org>
+#
+# This software is released under the terms of the GNU GPL
+# Please read the license at http://www.gnu.org/copyleft/gpl.html
+#
+
+MS_VERSION=2.1.3
+
+# Procedures
+
+MS_Usage()
+{
+ echo "Usage: $0 [params] archive_dir file_name label [startup_script] [args]"
+ echo "params can be one or more of the following :"
+ echo " --version | -v : Print out Makeself version number and exit"
+ echo " --help | -h : Print out this help message"
+ echo " --gzip : Compress using gzip (default if detected)"
+ echo " --bzip2 : Compress using bzip2 instead of gzip"
+ echo " --compress : Compress using the UNIX 'compress' command"
+ echo " --nocomp : Do not compress the data"
+ echo " --notemp : The archive will create archive_dir in the"
+ echo " current directory and uncompress in ./archive_dir"
+ echo " --copy : Upon extraction, the archive will first copy itself to"
+ echo " a temporary directory"
+ echo " --append : Append more files to an existing Makeself archive"
+ echo " The label and startup scripts will then be ignored"
+ echo " --current : Files will be extracted to the current directory."
+ echo " Implies --notemp."
+ echo " --nomd5 : Don't calculate an MD5 for archive"
+ echo " --nocrc : Don't calculate a CRC for archive"
+ echo " --header file : Specify location of the header script"
+ echo " --follow : Follow the symlinks in the archive"
+ echo " --nox11 : Disable automatic spawn of a xterm"
+ echo " --nowait : Do not wait for user input after executing embedded"
+ echo " program from an xterm"
+ echo " --lsm file : LSM file describing the package"
+ echo
+ echo "Do not forget to give a fully qualified startup script name"
+ echo "(i.e. with a ./ prefix if inside the archive)."
+ exit 1
+}
+
+# Default settings
+if type gzip 2>&1 > /dev/null; then
+ COMPRESS=gzip
+else
+ COMPRESS=Unix
+fi
+KEEP=n
+CURRENT=n
+NOX11=n
+APPEND=n
+COPY=none
+TAR_ARGS=cvf
+HEADER=`dirname $0`/makeself-header.sh
+
+# LSM file stuff
+LSM_CMD="echo No LSM. >> \"\$archname\""
+
+while true
+do
+ case "$1" in
+ --version | -v)
+ echo Makeself version $MS_VERSION
+ exit 0
+ ;;
+ --bzip2)
+ COMPRESS=bzip2
+ shift
+ ;;
+ --gzip)
+ COMPRESS=gzip
+ shift
+ ;;
+ --compress)
+ COMPRESS=Unix
+ shift
+ ;;
+ --nocomp)
+ COMPRESS=none
+ shift
+ ;;
+ --notemp)
+ KEEP=y
+ shift
+ ;;
+ --copy)
+ COPY=copy
+ shift
+ ;;
+ --current)
+ CURRENT=y
+ KEEP=y
+ shift
+ ;;
+ --header)
+ HEADER="$2"
+ shift 2
+ ;;
+ --follow)
+ TAR_ARGS=cvfh
+ shift
+ ;;
+ --nox11)
+ NOX11=y
+ shift
+ ;;
+ --nowait)
+ shift
+ ;;
+ --nomd5)
+ NOMD5=y
+ shift
+ ;;
+ --nocrc)
+ NOCRC=y
+ shift
+ ;;
+ --append)
+ APPEND=y
+ shift
+ ;;
+ --lsm)
+ LSM_CMD="cat \"$2\" >> \"\$archname\""
+ shift 2
+ ;;
+ -h | --help)
+ MS_Usage
+ ;;
+ -*)
+ echo Unrecognized flag : "$1"
+ MS_Usage
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+archdir="$1"
+archname="$2"
+MS_COMMAND="$0 $*"
+
+if test "$APPEND" = y; then
+ if test $# -lt 2; then
+ MS_Usage
+ fi
+
+ # Gather the info from the original archive
+ OLDENV=`sh "$archname" --dumpconf`
+ if test $? -ne 0; then
+ echo "Unable to update archive: $archname" >&2
+ exit 1
+ else
+ eval "$OLDENV"
+ fi
+else
+ if test "$KEEP" = n -a $# = 3; then
+ echo "ERROR: Making a temporary archive with no embedded command does not make sense!" >&2
+ echo
+ MS_Usage
+ fi
+ # We don't really want to create an absolute directory...
+ if test "$CURRENT" = y; then
+ archdirname="."
+ else
+ archdirname=`basename "$1"`
+ fi
+
+ if test $# -lt 3; then
+ MS_Usage
+ fi
+
+ LABEL="$3"
+ SCRIPT="$4"
+ test x$SCRIPT = x || shift 1
+ shift 3
+ SCRIPTARGS="$*"
+fi
+
+if test "$KEEP" = n -a "$CURRENT" = y; then
+ echo "ERROR: It is A VERY DANGEROUS IDEA to try to combine --notemp and --current." >&2
+ exit 1
+fi
+
+case $COMPRESS in
+gzip)
+ GZIP_CMD="gzip -c9"
+ GUNZIP_CMD="gzip -cd"
+ ;;
+bzip2)
+ GZIP_CMD="bzip2 -9"
+ GUNZIP_CMD="bzip2 -d"
+ ;;
+Unix)
+ GZIP_CMD="compress -cf"
+ GUNZIP_CMD="exec 2>&-; uncompress -c || test \\\$? -eq 2 || gzip -cd"
+ ;;
+none)
+ GZIP_CMD="cat"
+ GUNZIP_CMD="cat"
+ ;;
+esac
+
+tmpfile="${TMPDIR:=/tmp}/mkself$$"
+
+if test -f $HEADER; then
+ oldarchname="$archname"
+ archname="$tmpfile"
+ # Generate a fake header to count its lines
+ SKIP=0
+ . $HEADER
+ SKIP=`cat "$tmpfile" |wc -l`
+ # Get rid of any spaces
+ SKIP=`expr $SKIP`
+ rm -f "$tmpfile"
+ echo Header is $SKIP lines long >&2
+
+ archname="$oldarchname"
+else
+ echo "Unable to open header file: $HEADER" >&2
+ exit 1
+fi
+
+echo
+
+if test "$APPEND" = n; then
+ if test -f "$archname"; then
+ echo "WARNING: Overwriting existing file: $archname" >&2
+ fi
+fi
+
+test -d "$archdir" || { echo "Error: $archdir does not exist."; rm -f "$tmpfile"; exit 1; }
+
+USIZE=`du -ks $archdir | cut -f1`
+DATE=`LC_ALL=C date`
+
+echo About to compress $USIZE KB of data...
+echo Adding files to archive named \"$archname\"...
+(cd "$archdir"; tar $TAR_ARGS - * | eval "$GZIP_CMD" ) >> "$tmpfile" || { echo Aborting; rm -f "$tmpfile"; exit 1; }
+echo >> "$tmpfile" >&- # try to close the archive
+
+fsize=`cat "$tmpfile" | wc -c | tr -d " "`
+
+# Compute the checksums
+
+md5sum=00000000000000000000000000000000
+crcsum=0000000000
+
+if test "$NOCRC" = y; then
+ echo "skipping crc at user request"
+else
+ crcsum=`cat "$tmpfile" | cksum | sed -e 's/ /Z/' -e 's/ /Z/' | cut -dZ -f1`
+ echo "CRC: $crcsum"
+fi
+
+# Try to locate a MD5 binary
+OLD_PATH=$PATH
+PATH=${GUESS_MD5_PATH:-"$OLD_PATH:/bin:/usr/bin:/sbin:/usr/local/ssl/bin:/usr/local/bin:/opt/openssl/bin"}
+MD5_PATH=`type -p md5sum`
+MD5_PATH=${MD5_PATH:-`type -p md5`}
+PATH=$OLD_PATH
+
+if test "$NOMD5" = y; then
+ echo "skipping md5sum at user request"
+else
+ if test -x "$MD5_PATH"; then
+ md5sum=`cat "$tmpfile" | "$MD5_PATH" | cut -b-32`;
+ echo "MD5: $md5sum"
+ else
+ echo "MD5: none, md5sum binary not found"
+ fi
+fi
+
+if test "$APPEND" = y; then
+ mv "$archname" "$archname".bak || exit
+
+ # Prepare entry for new archive
+ filesizes="$filesizes $fsize"
+ CRCsum="$CRCsum $crcsum"
+ MD5sum="$MD5sum $md5sum"
+ USIZE=`expr $USIZE + $OLDUSIZE`
+ # Generate the header
+ . $HEADER
+ # Append the original data
+ tail -n +$OLDSKIP "$archname".bak >> "$archname"
+ # Append the new data
+ cat "$tmpfile" >> "$archname"
+
+ chmod +x "$archname"
+ rm -f "$archname".bak
+ echo Self-extractible archive \"$archname\" successfully updated.
+else
+ filesizes="$fsize"
+ CRCsum="$crcsum"
+ MD5sum="$md5sum"
+
+ # Generate the header
+ . $HEADER
+
+ # Append the compressed tar data after the stub
+ echo
+ cat "$tmpfile" >> "$archname"
+ chmod +x "$archname"
+ echo Self-extractible archive \"$archname\" successfully created.
+fi
+rm -f "$tmpfile"
diff --git a/scripts/redhat_i386.client.spec.in b/scripts/redhat_i386.client.spec.in
new file mode 100644
index 0000000..2f73141
--- /dev/null
+++ b/scripts/redhat_i386.client.spec.in
@@ -0,0 +1,184 @@
+#
+# Accepted parameters for 'rpmbuild':
+#
+# --with tests - make tests before building
+
+Summary: File integrity and host-based IDS
+Name: samhain-client
+Version: @VERSION@
+Release: 5
+License: GPL
+Group: System Environment/Base
+Source: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/samhain-client-%{version}-root
+Packager: Andre Oliveira da Costa <brblueser@uol.com.br>
+Provides: %{name}
+
+
+%description
+samhain is an open source file integrity and host-based intrusion
+detection system for Linux and Unix. It can run as a daemon process, and
+and thus can remember file changes -- contrary to a tool that runs from
+cron, if a file is modified you will get only one report, while
+subsequent checks of that file will ignore the modification as it is
+already reported (unless the file is modified again).
+
+samhain can optionally be used as client/server system to provide
+centralized monitoring for multiple host. Logging to a (MySQL or
+PostgreSQL) database is supported.
+
+NOTE: for security reasons, if you distribute binary executables to
+third parties you should point out the use of the --add-key option to
+modify the key material within the executable.
+This spec file is intended to facilitate installation on YOUR system.
+If you use this spec file to build a SRPM for distribution to third parties,
+make sure to remove the --enable-base configure option below.
+
+%prep
+%setup -q
+
+%build
+%if %{?_with_tests:1}%{!?_with_tests:0}
+# test installation (test #7 is only included if --with gpg has been
+# specified)
+for i in `seq 6` %{?_with_gpg:7}; do ./test/test.sh $i; done
+%endif
+#
+#./configure --prefix=%{_usr} \
+# --sysconfdir=%{_sysconfdir} \
+# --localstatedir=%{_localstatedir} \
+# --mandir=%{_mandir}
+#
+./configure '--enable-network=client' \
+ '--with-port=@myport@' \
+ '--with-logserver=@mylogsrv@' \
+ '--with-data-file=REQ_FROM_SERVER/etc/samclient.data' \
+ '--with-config-file=REQ_FROM_SERVER/etc/samclient.conf' \
+ '--with-kcheck=/boot/System.map' \
+ '--enable-khide=/boot/System.map' \
+ '--enable-suidcheck' \
+ '--enable-static' \
+ '--enable-login-watch' \
+ '--enable-ptrace' \
+ '--enable-db-reload' \
+ '--enable-base=@my_key_A@,@my_key_B@' \
+ '--enable-xml-log'
+
+make
+
+%install
+rm -rf ${RPM_BUILD_ROOT}
+# sstrip shouldn't be used since binaries will be stripped later
+cat << EOF > sstrip
+#!/bin/sh
+echo "*** SSTRIP DISABLED ***"
+EOF
+make DESTDIR=${RPM_BUILD_ROOT} install
+# copy script files to /var/lib/samhain so that we can use them right
+# after the package is installed
+install -m 700 samhain-install.sh init/samhain.startLinux init/samhain.startLSB ${RPM_BUILD_ROOT}/etc
+install -m 640 -o 0 -g 0 samhain_kmem.ko ${RPM_BUILD_ROOT}/lib/modules/`uname -r`/samhain_kmem.ko
+install -m 640 -o 0 -g 0 samhain_hide.ko ${RPM_BUILD_ROOT}/lib/modules/`uname -r`/samhain_hide.ko
+install -m 700 -o 0 -g 0 samhain_setpwd ${RPM_BUILD_ROOT}/usr/local/sbin/samhain_setpwd
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%post
+if [ "$1" = 1 ]; then
+ # Activate boot-time start up
+ cd /etc
+ ./samhain-install.sh --verbose install-boot
+ if test -f /sbin/chkconfig; then
+ /sbin/chkconfig --add samhain
+ fi
+fi
+rm -rf /etc/samclient.conf
+rm -rf /etc/samhain.startLinux
+rm -rf /etc/samhain.startLSB
+
+cat << EOF
+
+Samhain is installed but is NOT running yet, and the database of
+file signatures is NOT initialized yet. Read the documentation,
+review configuration files, and then (i) initialize it
+(/usr/local/sbin/samhain -t init)
+and (ii) start it manually
+(/usr/local/sbin/samhain start).
+
+It is configured to start automatically on the next boot for runlevels
+[2-5].
+
+EOF
+
+%preun
+# stop running instance of samhain, if any
+if [ -f /var/run/%{name}.pid ]; then
+ /usr/local/sbin/samhain stop
+fi
+if [ "$1" = 0 ]; then
+ # remove boot-time scripts and links
+ cd /etc
+ ./samhain-install.sh --verbose uninstall-boot
+fi
+
+
+
+%files
+%defattr(-,root,root)
+%dir /var/run
+%dir /var/log
+#%doc docs/BUGS COPYING docs/Changelog
+#%doc LICENSE docs/HOWTO* docs/MANUAL-2_4.* docs/README*
+/etc
+/usr/local/sbin/samhain
+/usr/local/sbin/samhain_setpwd
+/lib/modules
+%attr(644,root,root) /etc/logrotate.d/@install_name@
+#%attr(644,root,root) /usr/local/man/man5/samhain*
+#%attr(644,root,root) /usr/local/man/man8/samhain*
+#%config(noreplace) REQ_FROM_SERVER/etc/samclient.conf
+
+%changelog
+* Thu Apr 3 2003 Rainer Wichmann <support at la-samhna dot de>
+- adapt for configure
+
+* Wed Mar 26 2003 Philipp Stadler <philipp@stadler.priv.at>
+- add samhain modules installation
+- stops installation of documentation to server
+- replace %config entry for /etc/samclient.conf
+- remove samhain.startLinux and samhain.startLSB after installation
+
+* Sun Jan 12 2003 Rainer Wichmann <support at la-samhna dot de>
+- replace %configure with ./configure
+
+* Tue Dec 24 2002 Rainer Wichmann <support at la-samhna dot de>
+- backported applicable changes to samhain.spec.in
+- warn user that database must be initialized
+- fix version of MANUAL in '%files'
+- test for chkconfig, use only if found
+
+* Sun Dec 22 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.7.0
+- fixed typo with _usr macro on ./configure
+- stops running samhain before uninstall
+- implemented conditionals to allow proper uninstalls/upgrades
+- 'BuildPreReq: gpg' is considered only if '--with gpg' is provided
+- run 'chkconfig' to activate samhain after installation
+- warn user that samhain must be manually started after
+ install/upgrade
+
+* Fri Dec 20 2002 Rainer Wichmann <support at la-samhna dot de>
+- backported to samhain.spec.in (take over user's choices from configure)
+- also save samhain.startLSB and samhain.startSuSE for install-boot
+
+* Thu Dec 19 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- optional parameters '--with gpg' and '--with tests'
+- use of pre-defined macros whenever possible
+
+* Wed Dec 18 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- Fixed installation process, avoiding hardcoded paths on the binaries
+ (thks to samhain's author Rainer Wichmann)
+
+* Mon Dec 16 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- First attempt to build from sources
+
diff --git a/scripts/samhain.cgi b/scripts/samhain.cgi
new file mode 100755
index 0000000..023a374
--- /dev/null
+++ b/scripts/samhain.cgi
@@ -0,0 +1,32 @@
+#! /usr/local/bin/php
+<?php
+ header("Content-type: text/xml; charset=iso-8859-1");
+
+ /* IF YOU ARE USING MOD_PHP, DELETE FIRST LINE (#! /usr/...)
+ * ELSE: SET CORRECT PATH TO PHP
+ */
+
+ echo "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
+ echo "<!DOCTYPE samhain SYSTEM \"samhain.dtd\">\n";
+ echo "<?xml-stylesheet type=\"text/xsl\" href=\"samhain.xsl\" ?>\n";
+ echo "\n";
+ echo "<logs>\n";
+ $machine = $HTTP_POST_VARS["machine"];
+ print "<req_machine>$machine</req_machine>\n";
+ $date = $HTTP_POST_VARS["date"];
+ print "<req_date>$date</req_date>\n";
+
+ /* INSERT PATH TO YOUR LOGFILE !!!
+ */
+ readfile("/var/log/yule/yule.log");
+
+ /* INSERT PATH TO YOUR PID FILE !!!
+ * The final </trail> is only written when the
+ * daemon exits, threfore we need to supply it here.
+ */
+ if (TRUE == file_exists("/var/run/yule.pid")) {
+ echo "</trail>\n";
+ fi
+
+ echo "</logs>\n";
+?>
diff --git a/scripts/samhain.dtd b/scripts/samhain.dtd
new file mode 100644
index 0000000..7e702dd
--- /dev/null
+++ b/scripts/samhain.dtd
@@ -0,0 +1,11 @@
+<!ELEMENT logs (trail|req_machine|req_date)+>
+<!ELEMENT req_machine (#PCDATA)>
+<!ELEMENT req_date (#PCDATA)>
+<!ELEMENT trail (log)+>
+<!ELEMENT log (log|sig)>
+<!ELEMENT sig (#PCDATA)>
+<!ATTLIST log
+ sev CDATA #REQUIRED
+ tstamp CDATA #REQUIRED
+ msg CDATA #REQUIRED
+> \ No newline at end of file
diff --git a/scripts/samhain.ebuild-light.in b/scripts/samhain.ebuild-light.in
new file mode 100644
index 0000000..2b09cdb
--- /dev/null
+++ b/scripts/samhain.ebuild-light.in
@@ -0,0 +1,92 @@
+# Copyright 2004 Rainer Wichmann
+# Distributed under the terms of the GNU General Public License v2
+
+inherit eutils
+
+MY_P="${PN}_signed-${PV}"
+SLOT="0"
+LICENSE="GPL-2"
+DESCRIPTION="Samhain is a file integrity checker with optional central logging"
+
+# This is a fake URI that allows us to do a 'make dist' and copy
+# the file to distdir.
+# The proper URI would be http://www.la-samhna.de/archive/${MY_P}.tar.gz,
+# but this would force us to do a 'make dist-sign' ...
+# Apparently, portage cannot handle the file:// scheme,
+# and not every user might be prepared to create a signed tarball.
+#
+# SRC_URI="http://www.la-samhna.de/archive/${MY_P}.tar.gz"
+SRC_URI="http://www.la-samhna.de/archive/${P}.tar.gz"
+
+
+HOMEPAGE="http://www.la-samhna.de/samhain/"
+
+KEYWORDS="x86"
+
+IUSE=""
+
+DEPEND="app-arch/gzip
+ app-arch/tar"
+# mysql? (>=dev-db/mysql-3.23.58)"
+RDEPEND=""
+
+src_unpack() {
+ unpack ${A}
+ cd ${WORKDIR}
+ if test -f ${P}.tar.gz; then
+ gunzip -c ${P}.tar.gz | tar xf - || die
+ cd ${P}
+ elif test -d "samhain-${PV}"; then
+ mv "samhain-${PV}" "@install_name@-${PV}"
+ fi
+}
+
+src_compile() {
+ local myconf="--with-trusted=0,250"
+
+# myconf="$myconf --enable-mounts-check"
+# myconf="$myconf --enable-userfiles"
+
+# use mysql && myconf="$myconf --with-database=mysql"
+# use postgres && myconf="$myconf --with-database=postgresql"
+
+# econf \
+# --with-pid-file=/var/run/${PN}.pid \
+# --with-state-dir=/var/lib/${PN} \
+# --with-log-file=/var/log/${PN}.log \
+
+ ./configure ${myconf} @mydefargs@ || die
+ emake || die
+
+ echo '#!/bin/sh' > ./sstrip
+ echo 'echo "*** SSTRIP DISABLED ***"' >> ./sstrip
+}
+
+src_install() {
+ make DESTDIR=${D} install-light || die
+ make DESTDIR=${D} install-boot || die
+
+ rm -f ${D}/@sbindir@/@install_name@_stealth
+}
+
+pkg_prerm() {
+ rc-update del @install_name@
+ einfo "Stopping service @install_name@"
+ test -f /etc/init.d/@install_name@ && /etc/init.d/@install_name@ stop
+ sleep 3
+}
+
+pkg_postinst() {
+ rc-update add @install_name@ default
+ einfo
+ einfo "@install_name@ is installed but is NOT running yet, and the database"
+ einfo "of file signatures is NOT initialized yet."
+ einfo
+ einfo "You need to run \"@install_name@ -t init\" to initialize "
+ einfo "the baseline database of file signatures."
+ einfo
+ einfo "After initializing the database, you can start @install_name@"
+ einfo "with \"/etc/init.d/@install_name@ start\". It is configured to start"
+ einfo "automatically on the next boot for runlevel \"default\""
+}
+
diff --git a/scripts/samhain.ebuild.in b/scripts/samhain.ebuild.in
new file mode 100644
index 0000000..635a746
--- /dev/null
+++ b/scripts/samhain.ebuild.in
@@ -0,0 +1,98 @@
+# Copyright 2004 Rainer Wichmann
+# Distributed under the terms of the GNU General Public License v2
+
+inherit eutils
+
+MY_P="${PN}_signed-${PV}"
+SLOT="0"
+LICENSE="GPL-2"
+DESCRIPTION="Samhain is a file integrity checker with optional central logging"
+
+# This is a fake URI that allows us to do a 'make dist' and copy
+# the file to distdir.
+# The proper URI would be http://www.la-samhna.de/archive/${MY_P}.tar.gz,
+# but this would force us to do a 'make dist-sign' ...
+# Apparently, portage cannot handle the file:// scheme,
+# and not every user might be prepared to create a signed tarball.
+#
+# SRC_URI="http://www.la-samhna.de/archive/${MY_P}.tar.gz"
+SRC_URI="http://www.la-samhna.de/archive/${P}.tar.gz"
+
+
+HOMEPAGE="http://www.la-samhna.de/samhain/"
+
+KEYWORDS="x86"
+
+IUSE=""
+
+DEPEND="app-arch/gzip
+ app-arch/tar"
+# mysql? (>=dev-db/mysql-3.23.58)"
+RDEPEND=""
+
+src_unpack() {
+ unpack ${A}
+ cd ${WORKDIR}
+ if test -f ${P}.tar.gz; then
+ gunzip -c ${P}.tar.gz | tar xf - || die
+ cd ${P}
+ elif test -d "samhain-${PV}"; then
+ mv "samhain-${PV}" "@install_name@-${PV}"
+ fi
+}
+
+src_compile() {
+ local myconf="--with-trusted=0,250"
+
+# myconf="$myconf --enable-mounts-check"
+# myconf="$myconf --enable-userfiles"
+
+# use mysql && myconf="$myconf --with-database=mysql"
+# use postgres && myconf="$myconf --with-database=postgresql"
+
+# econf \
+# --with-pid-file=/var/run/${PN}.pid \
+# --with-state-dir=/var/lib/${PN} \
+# --with-log-file=/var/log/${PN}.log \
+
+ ./configure ${myconf} @mydefargs@ || die
+ emake || die
+
+ echo '#!/bin/sh' > ./sstrip
+ echo 'echo "*** SSTRIP DISABLED ***"' >> ./sstrip
+}
+
+src_install() {
+ make DESTDIR=${D} install || die
+ make DESTDIR=${D} install-boot || die
+
+ dodoc docs/BUGS COPYING docs/Changelog LICENSE docs/README \
+ docs/README.UPGRADE docs/sh_mounts.txt docs/sh_userfiles.txt \
+ docs/MANUAL-2_4.ps docs/MANUAL-2_4.html.tar
+
+ dohtml docs/HOWTO-client+server.html docs/HOWTO-samhain+GnuPG.html \
+ docs/HOWTO-write-modules.html docs/HOWTO-samhain-on-windows.html \
+ docs/HOWTO-client+server-troubleshooting.html docs/FAQ.html
+}
+
+pkg_prerm() {
+ rc-update del @install_name@
+ einfo "Stopping service @install_name@"
+ test -f /etc/init.d/@install_name@ && /etc/init.d/@install_name@ stop
+ sleep 3
+}
+
+pkg_postinst() {
+ rc-update add @install_name@ default
+ einfo
+ einfo "@install_name@ is installed but is NOT running yet, and the database"
+ einfo "of file signatures is NOT initialized yet."
+ einfo
+ einfo "You need to run \"@install_name@ -t init\" to initialize "
+ einfo "the baseline database of file signatures."
+ einfo
+ einfo "After initializing the database, you can start @install_name@ "
+ einfo "with \"/etc/init.d/@install_name@ start\". It is configured to start"
+ einfo "automatically on the next boot for runlevel \"default\""
+}
+
diff --git a/scripts/samhain.logrotator b/scripts/samhain.logrotator
new file mode 100644
index 0000000..b6d82d9
--- /dev/null
+++ b/scripts/samhain.logrotator
@@ -0,0 +1,26 @@
+/var/log/samhain_log {
+ size=1M
+ nocreate
+ compress
+ mail root@mail
+ maillast
+ rotate 5
+
+ prerotate
+ if test -f /var/run/samhain.pid; then \
+ PIN=`cat /var/run/samhain.pid`; \
+ /bin/kill -ABRT $PIN; \
+ sleep 1; \
+ AA=0; \
+ while test "x$AA" != "x120"; do \
+ let "AA = $AA + 1"; \
+ if test -f /var/run/samhain.pid; then \
+ sleep 1; \
+ else \
+ break; \
+ fi \
+ done; \
+ fi
+ endscript
+
+
diff --git a/scripts/samhain.spec.in b/scripts/samhain.spec.in
new file mode 100644
index 0000000..70bf68c
--- /dev/null
+++ b/scripts/samhain.spec.in
@@ -0,0 +1,162 @@
+#
+# Accepted parameters for 'rpmbuild':
+#
+# --with gpg - enables gpg support
+# --with tests - make tests before building
+
+Summary: File integrity and host-based IDS
+Name: samhain
+Version: @VERSION@
+Release: 1
+License: GPL
+Group: System Environment/Base
+Source: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+Packager: Andre Oliveira da Costa <brblueser@uol.com.br>
+Provides: %{name}
+%if %{?_with_gpg:1}%{!?_with_gpg:0}
+BuildPreReq: gpg
+%endif
+
+%description
+samhain is an open source file integrity and host-based intrusion
+detection system for Linux and Unix. It can run as a daemon process, and
+and thus can remember file changes -- contrary to a tool that runs from
+cron, if a file is modified you will get only one report, while
+subsequent checks of that file will ignore the modification as it is
+already reported (unless the file is modified again).
+
+samhain can optionally be used as client/server system to provide
+centralized monitoring for multiple host. Logging to a (MySQL or
+PostgreSQL) database is supported.
+
+This package contains only the single host version.
+
+%prep
+%setup -q -n samhain-%{version}
+
+%build
+%if %{?_with_tests:1}%{!?_with_tests:0}
+# test installation (test #7 is only included if --with gpg has been
+# specified)
+for i in `seq 6` %{?_with_gpg:7}; do ./test/test.sh $i; done
+%endif
+./configure --prefix=%{_usr} \
+ --sbindir=%{_sbindir} \
+ --sysconfdir=%{_sysconfdir} \
+ --localstatedir=%{_localstatedir} \
+ --mandir=%{_mandir} \
+%{?_with_gpg: --with-gpg=`type -p gpg`}
+
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+# sstrip shouldn't be used since binaries will be stripped later
+cat << EOF > sstrip
+#!/bin/sh
+echo "*** SSTRIP DISABLED ***"
+EOF
+make DESTDIR=${RPM_BUILD_ROOT} install
+# copy script files to /var/lib/samhain so that we can use them right
+# after the package is installed
+install -m 700 samhain-install.sh init/samhain.startLinux init/samhain.startLSB ${RPM_BUILD_ROOT}%{_localstatedir}/lib/%{name}
+
+%clean
+rm -rf ${RPM_BUILD_ROOT}
+
+%post
+if [ "$1" = 1 ]; then
+ # Activate boot-time start up
+ cd %{_localstatedir}/lib/%{name}
+ /bin/sh ./samhain-install.sh --verbose install-boot
+ if test -f /sbin/chkconfig; then
+ /sbin/chkconfig --add samhain
+ /sbin/chkconfig samhain on
+ fi
+fi
+cat << EOF
+
+Samhain is installed but is NOT running yet, and the database of
+file signatures is NOT initialized yet. Read the documentation,
+review configuration files, and then (i) initialize it
+(%{_sbindir}/samhain -t init)
+and (ii) start it manually
+(%{_sysconfdir}/init.d/samhain start).
+
+It is configured to start automatically on the next boot for runlevels
+[2-5].
+
+EOF
+
+
+%preun
+# stop running instance of samhain, if any
+if [ -f %{_localstatedir}/run/%{name}.pid ]; then
+ %{_sysconfdir}/init.d/samhain stop
+fi
+if [ "$1" = 0 ]; then
+ # remove boot-time scripts and links
+ cd %{_localstatedir}/lib/samhain
+ if [ -f ./samhain-install.sh ]; then
+ /bin/sh ./samhain-install.sh --verbose uninstall-boot
+ else
+ if [ -f /sbin/chkconfig ]; then
+ /sbin/chkconfig samhain off
+ /sbin/chkconfig --del samhain
+ fi
+ fi
+fi
+
+
+%files
+%defattr(-,root,root)
+%dir %{_localstatedir}/run
+%dir %{_localstatedir}/log
+%doc docs/BUGS COPYING docs/Changelog
+%doc LICENSE docs/HOWTO* docs/MANUAL-2_4.* docs/README*
+%{_localstatedir}/lib/%{name}
+%{_sbindir}/%{name}
+%attr(644,root,root) %{_mandir}/man5/samhain*
+%attr(644,root,root) %{_mandir}/man8/samhain*
+%attr(644,root,root) /etc/logrotate.d/@install_name@
+%config(noreplace) %{_sysconfdir}/samhainrc
+
+%changelog
+* Sat Jun 19 2004 Rainer Wichmann
+- replace ./test.sh $i with make test$i
+
+* Sat Jan 03 2004 Rainer Wichmann
+- Use /sbin/chkconfig as in ../samhain.spec.in
+
+* Thu Dec 11 2003 Christian Vanguers <cva at molis dot be>
+- Fixed typo in samhain.spec
+
+* Tue Dec 24 2002 Rainer Wichmann
+- warn user that database must be initialized
+- fix version of MANUAL in '%files'
+- test for chkconfig, use only if found
+
+* Sun Dec 22 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.7.0
+- fixed typo with _usr macro on ./configure
+- stops running samhain before uninstall
+- implemented conditionals to allow proper uninstalls/upgrades
+- 'BuildPreReq: gpg' is considered only if '--with gpg' is provided
+- run 'chkconfig' to activate samhain after installation
+- warn user that samhain must be manually started after
+ install/upgrade
+
+* Fri Dec 20 2002 Rainer Wichmann
+- use 'configure' to set version string
+- use standard macros for paths
+
+* Thu Dec 19 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- optional parameters '--with gpg' and '--with tests'
+- use of pre-defined macros whenever possible
+
+* Wed Dec 18 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- Fixed installation process, avoiding hardcoded paths on the binaries
+ (thks to samhain's author Rainer Wichmann)
+
+* Mon Dec 16 2002 Andre Oliveira da Costa <brblueser@uol.com.br> 1.6.6
+- First attempt to build from sources
diff --git a/scripts/samhain.xsl b/scripts/samhain.xsl
new file mode 100644
index 0000000..621ac1c
--- /dev/null
+++ b/scripts/samhain.xsl
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output
+ method="html"
+ indent="yes"
+ encoding="ISO-8859-1"
+/>
+
+<xsl:variable name="date1" select="string(/logs/req_date)" />
+<xsl:variable name="machine1" select="string(/logs/req_machine)" />
+
+<xsl:template match="/">
+<html>
+ <head>
+ <title>Samhain Log</title>
+ </head>
+ <body bgcolor="black" text="white" link="0077CC" vlink="0077CC" alink="FFFFFF">
+ <center>
+ <table bgcolor="777777" border="0" cellpadding="0" cellspacing="0">
+ <tr><td><img src="samhain.png"/></td></tr>
+ <tr><td><center><h1>Logs Samhain</h1></center></td></tr>
+ </table><br/>
+ <hr/>
+ <table bgcolor="black" border="0" cellpadding="0" cellspacing="0">
+ <form action="samhain.cgi" method="post">
+ <tr>
+ <td>Date: <input type="text" name="date">
+ <xsl:attribute name="value">
+ <xsl:value-of select="$date1" />
+ </xsl:attribute>
+ </input>
+ </td>
+ <td>Machine: <input type="text" name="machine">
+ <xsl:attribute name="value">
+ <xsl:value-of select="$machine1" />
+ </xsl:attribute>
+ </input>
+ </td>
+ <td><input type="submit" value="afficher"/></td>
+ </tr>
+ </form>
+ </table><br/>
+ <hr/>
+ <table bgcolor="222222" border="1" cellpadding="1" cellspacing="5">
+ <tr bgcolor="777777">
+ <td>TYPE D'ALERTE</td>
+ <td>CHEMIN</td>
+ <td>MESSAGE</td>
+ <td>DATE</td>
+ <td>MACHINE</td>
+ </tr>
+ <xsl:apply-templates />
+ </table>
+ <hr/>
+ </center>
+ </body>
+</html>
+</xsl:template>
+
+<xsl:template match="sig">
+</xsl:template>
+
+<xsl:template match="req_date">
+</xsl:template>
+
+<xsl:template match="req_machine">
+</xsl:template>
+
+<xsl:template match="log">
+ <tr>
+ <xsl:variable name="sev1" select="@sev"/>
+ <xsl:if test='$sev1="ALRT"'>
+ <td bgcolor="orange"><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="MARK"'>
+ <td bgcolor="blue"><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="CRIT"'>
+ <td bgcolor="red"><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="WARN"'>
+ <td><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="INFO"'>
+ <td><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="NOTE"'>
+ <td><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="DEBG"'>
+ <td><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test='$sev1="RCVT"'>
+ <td bgcolor="green"><xsl:value-of select="@sev"/></td>
+ <td><xsl:value-of select="log@path"/></td>
+ <td><xsl:value-of select="log@msg"/></td>
+ <td><xsl:value-of select="log@tstamp"/></td>
+ <td><xsl:value-of select="@remote_host"/></td>
+ </xsl:when>
+ <xsl:otherwise>
+ <td><xsl:value-of select="@path"/></td>
+ <td><xsl:value-of select="@msg"/></td>
+ <td><xsl:value-of select="@tstamp"/></td>
+ <td><xsl:value-of select="@host"/></td>
+ </xsl:otherwise>
+ </xsl:choose>
+ </tr>
+</xsl:template>
+
+<xsl:template match="trail/log">
+ <xsl:if test='starts-with(@remote_host,$machine1)'>
+ <xsl:if test='starts-with(@tstamp,$date1)'>
+ <tr>
+ <xsl:variable name="sev1" select="@sev"/>
+ <xsl:if test='$sev1="ALRT"'>
+ <td bgcolor="orange"><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="MARK"'>
+ <td bgcolor="blue"><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:if test='$sev1="CRIT"'>
+ <td bgcolor="red"><xsl:value-of select="@sev"/></td>
+ </xsl:if>
+ <xsl:choose>
+ <xsl:when test='$sev1="RCVT"'>
+ <td bgcolor="green"><xsl:value-of select="@sev"/></td>
+ <td><xsl:value-of select="log@path"/></td>
+ <td><xsl:value-of select="log@msg"/></td>
+ <td><xsl:value-of select="log@tstamp"/></td>
+ <td><xsl:value-of select="@remote_host"/></td>
+ </xsl:when>
+ <xsl:otherwise>
+ <td><xsl:value-of select="@path"/></td>
+ <td><xsl:value-of select="@msg"/></td>
+ <td><xsl:value-of select="@tstamp"/></td>
+ <td><xsl:value-of select="@remote_host"/></td>
+ </xsl:otherwise>
+ </xsl:choose>
+ </tr>
+ <xsl:apply-templates/>
+ </xsl:if>
+ </xsl:if>
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/scripts/samhainadmin.pl.in b/scripts/samhainadmin.pl.in
new file mode 100755
index 0000000..661c267
--- /dev/null
+++ b/scripts/samhainadmin.pl.in
@@ -0,0 +1,726 @@
+#! /usr/bin/perl
+
+# Copyright Rainer Wichmann (2004)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+use warnings;
+use strict;
+use Getopt::Long;
+use File::Basename;
+use File::Copy;
+use File::stat;
+use File::Temp qw/ tempfile tempdir unlink0 /;
+use IO::Handle;
+use Fcntl qw(:DEFAULT :flock);
+use Tie::File;
+
+# Do I/O to the data file in binary mode (so it
+# wouldn't complain about invalid UTF-8 characters).
+use bytes;
+
+File::Temp->safe_level( File::Temp::HIGH );
+
+my %opts = ();
+my $action;
+my $file1;
+my $file2;
+my $passphrase;
+my $secretkeyring;
+my $return_from_sign = 0;
+my $no_print_examine = 0;
+my $no_remove_lock = 0;
+my $base = basename($0);
+
+my $cfgfile = "@myconffile@";
+my $datafile = "@mydatafile@";
+my $daemon = "@sbindir@/@install_name@";
+my $gpg = "@mygpg@";
+
+my $TARGETKEYID = "@mykeyid@";
+my $KEYTAG = "@mykeytag@";
+
+$cfgfile =~ s/^REQ_FROM_SERVER//;
+$datafile =~ s/^REQ_FROM_SERVER//;
+
+$gpg = "gpg" if ($gpg eq "");
+
+sub check_gpg_agent() {
+ my $gpgconf = "$ENV{'HOME'}/.gnupg/gpg.conf";
+
+ if (!-f "$gpgconf") {
+ $gpgconf = "$ENV{'HOME'}/.gnupg/options";
+ }
+
+ if (-f $gpgconf) {
+
+ my @array = ();
+ tie @array, 'Tie::File', $gpgconf or die "Cannot tie ${gpgconf}: $!";
+ my @grep = grep(/^\s*use-agent/, @array);
+
+ # print "matches = $#grep\n";
+
+ if ($#grep >= 0)
+ {
+ if (exists $ENV{'GPG_AGENT_INFO'})
+ {
+ my $socke = $ENV{'GPG_AGENT_INFO'};
+ $socke =~ s/:.*//;
+
+ # print "socke = $socke\n";
+
+ if (! -S $socke)
+ {
+ print "--------------------------------------------------\n";
+ print "\n";
+ print " GPG is set to use gpg-agent, but GPG agent is";
+ print " not running, though GPG_AGENT_INFO is defined.\n\n";
+ print " Please restart gpg-agent, or remove the use-agent\n";
+ print " option from ${gpgconf} and unset GPG_AGENT_INFO\n\n";
+ print "--------------------------------------------------\n";
+ print "\n";
+ exit 1;
+ }
+ }
+ else
+ {
+ print "--------------------------------------------------\n";
+ print "\n";
+ print " GPG is set to use gpg-agent, but ";
+ print " GPG_AGENT_INFO is not defined.\n\n";
+ print " Please start gpg-agent, or remove the use-agent\n";
+ print " option from ${gpgconf}\n\n";
+ print "--------------------------------------------------\n";
+ print "\n";
+ exit 1;
+ }
+ }
+ untie @array;
+ }
+}
+
+
+sub usage() {
+ print "Usage:\n";
+ print " $base { -m F | --create-cfgfile } [options] [in.cfgfile]\n";
+ print " Sign the configuration file. If in.cfgfile is given, sign it\n";
+ print " and install it as configuration file.\n\n";
+
+ print " $base { -m f | --print-cfgfile } [options] \n";
+ print " Print the configuration file to stdout. Signatures are removed.\n\n";
+
+ print " $base { -m D | --create-datafile } [options] [in.datafile]\n";
+ print " Sign the database file. If in.datafile is given, sign it\n";
+ print " and install it as database file.\n\n";
+
+ print " $base { -m d | --print-datafile } [options] \n";
+ print " Print the database file to stdout. Signatures are removed. Use\n";
+ print " option --list to list files in database rather than printing the raw file.\n\n";
+
+ print " $base { -m R | --remove-signature } [options] file1 [file2 ...]\n";
+ print " Remove cleartext signature from input file(s). The file\n";
+ print " is replaced by the non-signed file.\n\n";
+
+ print " $base { -m E | --sign } [options] file1 [file2 ...]\n";
+ print " Sign file(s) with a cleartext signature. The file\n";
+ print " is replaced by the signed file.\n\n";
+
+ print " $base { -m e | --examine } [options] file1 [file2 ...]\n";
+ print " Report signature status of file(s).\n\n";
+
+ print " $base { -m G | --generate-keys } [options] \n";
+ print " Generate a PGP keypair to use for signing.\n\n";
+
+ print "Options:\n";
+ print " -c cfgfile --cfgfile cfgfile\n";
+ print " Select an alternate configuration file.\n\n";
+
+ print " -d datafile --datafile datafile\n";
+ print " Select an alternate database file.\n\n";
+
+ print " -p passphrase --passphrase passphrase\n";
+ print " Set the passphrase for gpg. By default, gpg will ask.\n\n";
+
+ print " -s gnupg_homedir --secretkeyring gnupg_homedir\n";
+ print " Select an alternate gpg homedirectory to locate the secret keyring.\n";
+ print " Will use '$ENV{'HOME'}/.gnupg/' by default.\n\n";
+
+ print " -k keyid --keyid keyid\n";
+ print " Select the keyid to use for signing.\n\n";
+
+ print " -l --list\n";
+ print " List the files in database rather than printing the raw file.\n\n";
+
+ print " -v --verbose\n";
+ print " Verbose output.\n\n";
+ return;
+}
+
+sub check_gpg_uid () {
+ if (0 != $>) {
+ print "--------------------------------------------------\n";
+ print "\n";
+ print " You are not root. Please remember that samhain/yule\n";
+ print " will use the public keyring of root to verify a signature.\n";
+ print "\n";
+ print "--------------------------------------------------\n";
+ } else {
+ if (!("@yulectl_prg@" =~ //)) {
+ print "--------------------------------------------------\n";
+ print "\n";
+ print " Please remember that yule will drop root after startup. Signature\n";
+ print " verification on SIGHUP will fail if you do not import the public key\n";
+ print " into the keyring of the non-root yule user.\n";
+ print "\n";
+ print "--------------------------------------------------\n";
+ }
+ }
+}
+
+sub check_gpg_sign () {
+ if ( defined($secretkeyring)) {
+ if ( (!-d "$secretkeyring")){
+ print "--------------------------------------------------\n";
+ print "\n";
+ print " Secret keyring $secretkeyring not found!\n";
+ print "\n";
+ print " Please check the path/name of the alternate secret keyring.\n";
+ print "\n";
+ print "--------------------------------------------------\n";
+ print "\n";
+ exit;
+ }
+ } else {
+ if ( (!-d "$ENV{'HOME'}/.gnupg") || (!-e "$ENV{'HOME'}/.gnupg/secring.gpg")) {
+ print "--------------------------------------------------\n";
+ print "\n";
+ if (!-d "$ENV{'HOME'}/.gnupg") {
+ print " Directory \$HOME/.gnupg not found!\n";
+ } else {
+ print " Secret keyring \$HOME/.gnupg/secring.gpg not found!\n";
+ }
+ print "\n";
+ print " This indicates that you have never created a \n";
+ print " public/private keypair, and thus cannot sign.\n";
+ print " \n";
+ print " Please use $0 --generate-keys or gpg --gen-key\n";
+ print " to generate a public/private keypair first.\n";
+ print "\n";
+ print "--------------------------------------------------\n";
+ print "\n";
+ exit;
+ }
+ }
+}
+
+sub check_gpg_verify () {
+ if ( (!-d "$ENV{'HOME'}/.gnupg") || (!-e "$ENV{'HOME'}/.gnupg/pubring.gpg")) {
+ print "--------------------------------------------------\n";
+ print "\n";
+ if (!-d "$ENV{'HOME'}/.gnupg") {
+ print " Directory \$HOME/.gnupg not found!\n";
+ } else {
+ print " Public keyring \$HOME/.gnupg/pubring.gpg not found!\n";
+ }
+ print "\n";
+ print " This indicates that you have never used gpg before \n";
+ print " and/or have no public keys to verify signatures.\n";
+ print " \n";
+ print " Please use 'gpg --export key_id' to export the public\n";
+ print " signing key of the user who is signing the\n";
+ print " configuration/database files.\n\n";
+ print " Then you can use 'gpg --import keyfile' to import the key\n";
+ print " into this user's public keyring.\n";
+ print "\n";
+ print "--------------------------------------------------\n";
+ print "\n";
+ exit;
+ }
+}
+
+
+sub generate () {
+ my $command = "$gpg --homedir $ENV{'HOME'}/.gnupg --gen-key";
+ check_gpg_uid();
+ system ($command) == 0
+ or die "system $command failed: $?";
+ exit;
+}
+
+sub examine () {
+ my $iscfg = 0;
+ my $have_fp = 0;
+ my $have_sig = 0;
+ my $message = '';
+ my $retval = 9;
+ my $fh;
+ my $filename;
+
+ if (!($file1 =~ /^\-$/)) {
+ die ("Cannot open $file1 for read: $!") unless ((-e $file1) && (-r _));
+ }
+ open FIN, "<$file1" or die "Cannot open $file1 for read: $!";
+
+ my $dir = tempdir( CLEANUP => 1 );
+ $filename = $dir . "/exa_jhfdbilw." . $$;
+ open $fh, ">$filename" or die "Cannot open $filename";
+ autoflush $fh 1;
+
+ while (<FIN>) {
+ print $fh $_;
+ if ($_ =~ /^\s*\[Misc\]/) {
+ $iscfg = 1;
+ }
+ }
+ if ($iscfg == 1) {
+ $message .= "File $file1 is a configuration file\n\n";
+ } else {
+ $message .= "File $file1 is a database file\n\n";
+ }
+
+
+ my $command = "$gpg --homedir $ENV{'HOME'}/.gnupg --status-fd 1 ";
+ $command .= "--verbose " if (defined($opts{'v'}));
+ $command .= "--verify $filename ";
+ if (defined($opts{'v'})) {
+ $command .= "2>&1";
+ } else {
+ $command .= "2>/dev/null";
+ }
+
+ print STDOUT "Using: $command\n\n" if (defined($opts{'v'}));
+ open GPGIN, "$command |" or die "Cannot fork: $!";
+
+ while (<GPGIN>) {
+ if ($_ =~ /^\[GNUPG:\] GOODSIG ([0-9A-F]+) (.*)$/) {
+ $message .= "GOOD signature with key: $1\n";
+ $message .= "Key owner: $2\n";
+ $have_sig = 1;
+ $retval = 0;
+ }
+ if ($_ =~ /^\[GNUPG:\] VALIDSIG ([0-9A-F]+) ([0-9\-]+)\s/) {
+ $message .= "Key fingerprint: $1\n";
+ $message .= "Signature generated on: $2\n\n";
+ $have_fp = 1;
+ $message .= "This file is signed with a valid signature.\n"
+ if ($have_sig == 1);
+ $have_sig = 1;
+ $have_fp = 1;
+ }
+ if ($_ =~ /^\[GNUPG:\] NODATA 1/) {
+ $message .= "NO signature found.\n\n";
+ $message .= "This file is not signed !!!\n";
+ $have_sig = 1;
+ $have_fp = 1;
+ $retval = 2;
+ }
+ if ($_ =~ /^\[GNUPG:\] BADSIG ([0-9A-F]+) (.*)$/) {
+ $message .= "BAD signature with key: $1\n";
+ $message .= "Key owner: $2\n\n";
+ $message .= "This file is signed with an invalid signature !!!\n";
+ $have_sig = 1;
+ $have_fp = 1;
+ $retval = 1;
+ }
+ if ($_ =~ /^\[GNUPG:\] NO_PUBKEY ([0-9A-F]+)/) {
+ $message .= "NOT CHECKED signature with key: $1\n\n";
+ $message .= "The signature of this file cannot be checked: no public key available !!!\n";
+ $have_sig = 1;
+ $have_fp = 1;
+ $retval = 1;
+ }
+ print STDOUT $_ if (defined($opts{'v'}));
+ }
+ close (GPGIN);
+ print STDOUT "\n" if (defined($opts{'v'}));
+ if ($have_sig == 0) {
+ $message .= "NO valid signature found\n";
+ }
+ elsif ($have_fp == 0) {
+ $message .= "NO fingerprint found\n";
+ }
+ close (FIN);
+ if ($no_print_examine == 0) {
+ print STDOUT $message;
+ }
+ unlink0( $fh, $filename ) or die "Cannot unlink $filename safely";
+ return $retval;
+}
+
+sub remove () {
+ my $bodystart = 1;
+ my $sigstart = 0;
+ my $sigend = 0;
+ my $filename = "";
+ my $fh;
+ my $stats;
+
+ open FH, "<$file1" or die "Cannot open file $file1 for read: $!";
+ if (!($file1 =~ /^\-$/)) {
+ flock(FH, LOCK_EX) unless ($no_remove_lock == 1);
+ my $dir = tempdir( CLEANUP => 1 ) or die "Tempdir failed";
+ $filename = $dir . "/rem_iqegBCQb." . $$;
+ open $fh, ">$filename" or die "Cannot open $filename";
+ $stats = stat($file1);
+ # ($fh, $filename) = tempfile(UNLINK => 1);
+ } else {
+ open $fh, ">$file1" or die "Cannot open file $file1 for write: $!";
+ }
+ autoflush $fh 1;
+ while (<FH>) {
+ if ($_ =~ /^-----BEGIN PGP SIGNED MESSAGE-----/) {
+ $sigstart = 1;
+ $bodystart = 0;
+ next;
+ } elsif (($sigstart == 1) && ($_ =~ /^\s+$/)) {
+ $sigstart = 0;
+ $bodystart = 1;
+ next;
+ } elsif ($_ =~ /^-----BEGIN PGP SIGNATURE-----/) {
+ $bodystart = 0;
+ $sigend = 1;
+ next;
+ } elsif (($sigend == 1) && ($_ =~ /^-----END PGP SIGNATURE-----/)) {
+ $sigend = 0;
+ $bodystart = 1;
+ next;
+ }
+ if ($bodystart == 1) {
+ print $fh $_;
+ }
+ }
+ if (!($file1 =~ /^\-$/)) {
+ copy("$filename", "$file1")
+ or die "Copy $filename to $file1 failed: $!";
+ chmod $stats->mode, $file1;
+ chown $stats->uid, $stats->gid, $file1;
+ flock(FH, LOCK_UN) unless ($no_remove_lock == 1);
+ close FH;
+ }
+ unlink0( $fh, $filename ) or die "Cannot unlink $filename safely";
+ return;
+}
+
+sub print_cfgfile () {
+ my $bodystart = 0;
+ my $sigstart = 0;
+
+ if (!defined($file2)) {
+ $file2 = '-';
+ }
+
+ open FH, "<$file1" or die "Cannot open file $file1 for read: $!";
+ open FO, ">$file2" or die "Cannot open file $file2 for write: $!";
+ while (<FH>) {
+ if ($_ =~ /^-----BEGIN PGP SIGNED MESSAGE-----/) {
+ $sigstart = 1;
+ next;
+ } elsif (($sigstart == 1) && ($_ =~ /^\s+$/)) {
+ $sigstart = 0;
+ $bodystart = 1;
+ next;
+ } elsif ($_ =~ /^-----BEGIN PGP SIGNATURE-----/) {
+ $bodystart = 0;
+ exit;
+ }
+ if ($bodystart == 1) {
+ print FO $_;
+ }
+ }
+ exit;
+}
+sub print_datafile () {
+ die ("Cannot find program $daemon")
+ unless (-e $daemon);
+ if (defined($opts{'v'})) {
+ open FH, "$daemon --full-detail -d $datafile |"
+ or die "Cannot open datafile $datafile for read: $!";
+ } else {
+ open FH, "$daemon -d $datafile |"
+ or die "Cannot open datafile $datafile for read: $!";
+ }
+ while (<FH>) {
+ print $_;
+ }
+ exit;
+}
+
+sub sign_file () {
+
+ my $fileout = '';
+ my $bodystart = 1;
+ my $sigstart = 0;
+ my $sigend = 0;
+ my $stats;
+ my $fh1;
+ my $filename1;
+ my $flag1 = 0;
+
+ check_gpg_uid();
+ check_gpg_agent();
+
+ if (!defined($file2)) {
+ $file2 = $file1;
+ }
+
+ if ($file1 =~ /^\-$/) {
+ my $dir = tempdir( CLEANUP => 1 ) or die "Tempdir failed";
+ $filename1 = $dir . "/sig_vs8827sd." . $$;
+ open $fh1, ">$filename1" or die "Cannot open $filename1";
+ $flag1 = 1;
+ # my ($fh1, $filename1) = tempfile(UNLINK => 1);
+
+ while (<STDIN>) {
+ if ($_ =~ /^-----BEGIN PGP SIGNED MESSAGE-----/) {
+ $sigstart = 1;
+ $bodystart = 0;
+ next;
+ } elsif (($sigstart == 1) && ($_ =~ /^\s+$/)) {
+ $sigstart = 0;
+ $bodystart = 1;
+ next;
+ } elsif ($_ =~ /^-----BEGIN PGP SIGNATURE-----/) {
+ $bodystart = 0;
+ $sigend = 1;
+ next;
+ } elsif (($sigend == 1) && ($_ =~ /^-----END PGP SIGNATURE-----/)) {
+ $sigend = 0;
+ $bodystart = 1;
+ next;
+ }
+ if ($bodystart == 1) {
+ print $fh1 $_;
+ }
+ #
+ # print $fh1 $_;
+ #
+ }
+ $file1 = $filename1;
+ $fileout = '-';
+ } else {
+ open (LOCKFILE, "<$file1") or die "Cannot open $file1: $!";
+ flock(LOCKFILE, LOCK_EX);
+ $no_print_examine = 1;
+ $no_remove_lock = 1;
+ if (examine() < 2) {
+ remove();
+ }
+ $fileout = $file1 . ".asc";
+ $stats = stat($file1)
+ or die "No file $file1: $!";
+ }
+
+ if (defined($passphrase)) {
+ local $SIG{PIPE} = 'IGNORE';
+ my $command = "$gpg --homedir $ENV{'HOME'}/.gnupg --passphrase-fd 0 -a ${KEYTAG} ${TARGETKEYID} --clearsign -o $fileout --not-dash-escaped ";
+ $command .= "--secret-keyring $secretkeyring " if (defined($opts{'s'}));
+ $command .= "$file1";
+ open (FH, "|$command") or die "can't fork: $!";
+ print FH "$passphrase" or die "can't write: $!";
+ close FH or die "can't close: status=$?";
+ } else {
+ my $command = "$gpg --homedir $ENV{'HOME'}/.gnupg -a ${KEYTAG} ${TARGETKEYID} --clearsign -o $fileout --not-dash-escaped ";
+ $command .= "--secret-keyring $secretkeyring " if (defined($opts{'s'}));
+ $command .= "$file1";
+ system("$command") == 0
+ or die "system $command failed: $?";
+ }
+
+ if (!($fileout =~ /^\-$/)) {
+ my $st_old = stat($file1)
+ or die "No file $file1: $!";
+ my $st_new = stat($fileout)
+ or die "No file $fileout: $!";
+ die ("Signed file is smaller than unsigned file")
+ unless ($st_new->size > $st_old->size);
+ move("$fileout", "$file2")
+ or die "Move $fileout to $file2 failed: $!";
+ chmod $stats->mode, $file2;
+ chown $stats->uid, $stats->gid, $file2;
+ flock(LOCKFILE, LOCK_UN);
+ }
+
+ if ($flag1 == 1) {
+ unlink0( $fh1, $filename1 ) or die "Cannot unlink $filename1 safely";
+ }
+ if ($return_from_sign == 1) {
+ return;
+ }
+ exit;
+}
+
+Getopt::Long::Configure ("posix_default");
+Getopt::Long::Configure ("bundling");
+# Getopt::Long::Configure ("debug");
+
+GetOptions (\%opts, 'm=s', 'h|help', 'v|verbose', 'l|list',
+ 'c|cfgfile=s',
+ 'd|datafile=s',
+ 'p|passphrase=s',
+ 's|secretkeyring=s',
+ 'k|keyid=s',
+ 'create-cfgfile', # -m F
+ 'print-cfgfile', # -m f
+ 'create-datafile', # -m D
+ 'print-datafile', # -m d
+ 'remove-signature',# -m R
+ 'sign', # -m E
+ 'examine', # -m e
+ 'generate-keys'); # -m G
+
+if (defined ($opts{'h'})) {
+ usage();
+ exit;
+}
+
+if (defined($opts{'k'})) {
+ $TARGETKEYID = $opts{'k'};
+ $KEYTAG = "--default-key";
+}
+if (defined($opts{'c'})) {
+ $cfgfile = $opts{'c'};
+}
+if (defined($opts{'d'})) {
+ $datafile = $opts{'d'};
+}
+if (defined($opts{'p'})) {
+ $passphrase = $opts{'p'};
+}
+if (defined($opts{'s'})) {
+ $secretkeyring = $opts{'s'};
+}
+
+if (defined ($opts{'m'}) && ($opts{'m'} =~ /[FfDdREeG]{1}/) ) {
+ $action = $opts{'m'};
+}
+elsif (defined ($opts{'create-cfgfile'})) {
+ $action = 'F';
+}
+elsif (defined ($opts{'print-cfgfile'})) {
+ $action = 'f';
+}
+elsif (defined ($opts{'create-datafile'})) {
+ $action = 'D';
+}
+elsif (defined ($opts{'print-datafile'})) {
+ $action = 'd';
+}
+elsif (defined ($opts{'remove-signature'})) {
+ $action = 'R';
+}
+elsif (defined ($opts{'sign'})) {
+ $action = 'E';
+}
+elsif (defined ($opts{'examine'})) {
+ $action = 'e';
+}
+elsif (defined ($opts{'generate-keys'})) {
+ $action = 'G';
+}
+else {
+ usage();
+ die ("No valid action specified !");
+}
+
+if (defined($ARGV[0])) {
+ $file1 = $ARGV[0];
+}
+if (defined($ARGV[1])) {
+ $file2 = $ARGV[1];
+}
+
+
+if (($action =~ /[REe]{1}/) && !defined($file1)) {
+ usage();
+ die("Option -m $action requires a filename (or '-' for stdio)\n");
+}
+
+if ($action =~ /^F$/) {
+ if (!defined($file1)) {
+ $file1 = $cfgfile;
+ }
+ $file2 = $cfgfile;
+ sign_file ();
+}
+
+if ($action =~ /^D$/) {
+ if (!defined($file1)) {
+ $file1 = $datafile;
+ }
+ $file2 = $datafile;
+ sign_file ();
+}
+
+if ($action =~ /^R$/) {
+ # $file1 defined
+ my $i = 0;
+ while (defined($ARGV[$i])) {
+ $file1 = $ARGV[$i];
+ remove ();
+ ++$i;
+ }
+}
+
+if ($action =~ /^E$/) {
+ # $file1 defined
+ # default: $file2 = $file1
+ check_gpg_sign();
+ my $i = 0;
+ while (defined($ARGV[$i])) {
+ $file1 = $ARGV[$i];
+ $file2 = $file1;
+ $return_from_sign = 1;
+ sign_file ();
+ ++$i;
+ }
+}
+
+if ($action =~ /^e$/) {
+ # $file1 defined
+ # default: $file2 = stdout
+ check_gpg_verify();
+ my $i = 0;
+ my $ret = 0;
+ while (defined($ARGV[$i])) {
+ print "\n";
+ $file1 = $ARGV[$i];
+ $ret += examine ();
+ ++$i;
+ print "\n--------------------------------\n" if (defined($ARGV[$i]));
+ }
+ exit($ret);
+}
+
+if ($action =~ /^f$/) {
+ $file1 = $cfgfile;
+ $file2 = "-";
+ print_cfgfile ();
+}
+
+if ($action =~ /^d$/) {
+ # $file1 irrelevant
+ if (defined($opts{'l'})) {
+ print_datafile ();
+ } else {
+ $file1 = $datafile;
+ $file2 = "-";
+ print_cfgfile ();
+ }
+}
+
+
+
diff --git a/scripts/yuleadmin.pl.in b/scripts/yuleadmin.pl.in
new file mode 100755
index 0000000..d63e960
--- /dev/null
+++ b/scripts/yuleadmin.pl.in
@@ -0,0 +1,310 @@
+#! /usr/bin/perl
+
+# Copyright (c) 2007 Riccardo Murri <riccardo.murri@gmail.com>
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+use warnings;
+use strict;
+use Getopt::Long;
+use File::Basename;
+use File::Copy;
+use File::Temp qw/ tempfile /;
+use IO::File;
+
+# Do I/O to the data file in binary mode (so it
+# wouldn't complain about invalid UTF-8 characters).
+use bytes;
+
+File::Temp->safe_level( File::Temp::HIGH );
+
+my %opts = ();
+my $outfile;
+my $verbose;
+my $base = basename($0);
+
+#my $cfgfile = "yulerc";
+#my $yule = "./yule";
+#my $gpg = "/usr/bin/gpg";
+
+my $cfgfile = "@myconffile@";
+my $yule = "@sbindir@/@install_name@";
+my $gpg = "@mygpg@";
+
+$cfgfile =~ s/^REQ_FROM_SERVER//;
+
+$gpg = "gpg" if ($gpg eq "");
+
+sub usage() {
+ print <<__END_OF_TEXT__
+Usage:
+ $base { -a | --add } [options] HOSTNAME [PASSWORD]
+ Add client HOSTNAME to configuration file. If PASSWORD is
+ omitted, it is read from stdin. If HOSTNAME already exists
+ in the configuration file, an error is given.
+
+ $base { -d | --delete } [options] HOSTNAME
+ Remove client HOSTNAME from configuration file.
+
+ $base { -l | --list } [options]
+ List clients in the yule configuration file.
+
+ $base { -r | --replace } [options] HOSTNAME [PASSWORD]
+ Replace password of existing client HOSTNAME in configuration file.
+ If PASSWORD is omitted, it is read from stdin. If HOSTNAME does not
+ already exist in the configuration file, an error is given.
+
+ $base { -u | --update } [options] HOSTNAME [PASSWORD]
+ Add client HOSTNAME to config file or replace its password with a new one.
+ If PASSWORD is omitted, it is read from stdin.
+
+Options:
+ -c CFGFILE --cfgfile CFGFILE
+ Select an alternate configuration file. (default: $cfgfile)
+
+ -o OUTFILE --output OUTFILE
+ Write modified configuration to OUTFILE. If this option is
+ omitted, $base will rename the original configuration file
+ to '$cfgfile.BAK' and overwrite it with the modified content.
+
+ -Y YULECMD --yule YULECMD
+ Use command YULECMD to generate the client key from the password.
+ (default: $yule)
+
+ -v --verbose
+ Verbose output.
+
+__END_OF_TEXT__
+;
+ return;
+}
+
+
+## subroutines
+
+sub read_clients ($) {
+ my $cfgfile = shift || '-';
+ my %clients;
+
+ open INPUT, "<$cfgfile"
+ or die ("Cannot read configuration file '$cfgfile'. Aborting");
+
+ my $section;
+ while (<INPUT>) {
+ # skip comment and blank lines
+ next if m{^\s*#};
+ next if m{^\s*$};
+
+ # match section headers
+ $section = $1 if m{^\s*\[([a-z0-9 ]+)\]}i;
+
+ # ok, list matching lines
+ if ($section =~ m/Clients/) {
+ if (m{^\s*Client=}i) {
+ chomp;
+ s{^\s*Client=}{}i;
+ my ($client, $key) = split /@/,$_,2;
+
+ $clients{lc($client)} = $key;
+ }
+ }
+ }
+
+ close INPUT;
+ return \%clients;
+}
+
+
+sub write_clients ($$$) {
+ my $cfgfile_in = shift || '-';
+ my $cfgfile_out = shift || $cfgfile_in;
+ my $clients = shift;
+
+ my @lines;
+ my $in_clients_section;
+
+ # copy-pass input file
+ my $section = '';
+ open INPUT, "<$cfgfile_in"
+ or die ("Cannot read configuration file '$cfgfile_in'. Aborting");
+ while (<INPUT>) {
+ # match section headers
+ if (m{^\s*\[([a-z0-9 ]+)\]}i) {
+ if ($in_clients_section and ($section ne $1)) {
+ # exiting [Clients] section, output remaining ones
+ foreach my $hostname (keys %{$clients}) {
+ push @lines,
+ 'Client=' . $hostname . '@'
+ . $clients->{lc($hostname)} . "\n";
+ delete $clients->{lc($hostname)};
+ }
+ }
+ # update section title
+ $section = $1;
+ if ($section =~ m/Clients/i) {
+ $in_clients_section = 1;
+ } else {
+ $in_clients_section = 0;
+ }
+ }
+
+ # process entries in [Clients] section
+ if ($in_clients_section) {
+ if (m{^\s*Client=}i) {
+ my ($hostname, undef) = split /@/,$_,2;
+ $hostname =~ s{^\s*Client=}{}i;
+ if (defined($clients->{lc($hostname)})) {
+ # output (possibly) modified key
+ $_ = 'Client=' . $hostname . '@' . $clients->{lc($hostname)} . "\n";
+ delete $clients->{lc($hostname)};
+ }
+ else {
+ # client deleted, skip this line from output
+ $_ = '';
+ }
+ }
+ }
+
+ # copy input to output
+ push @lines, $_;
+ }
+ close INPUT;
+
+ # if end-of-file reached within [Clients] section, output remaining ones
+ if ($in_clients_section) {
+ foreach my $hostname (keys %{$clients}) {
+ push @lines, 'Client=' . $hostname . '@'
+ . $clients->{lc($hostname)} . "\n";
+ }
+ }
+
+ # if necessary, replace input file with output file
+ if ($cfgfile_in eq $cfgfile_out) {
+ copy($cfgfile_in, $cfgfile_in . '.BAK')
+ or die("Cannot backup config file '$cfgfile_in'. Aborting");
+ }
+ open OUTPUT, ">$cfgfile_out"
+ or die ("Cannot write to file '$cfgfile_out'. Aborting");
+ # overwrite config file line by line
+ foreach my $line (@lines) { print OUTPUT $line; }
+ close OUTPUT;
+}
+
+
+sub new_client_key ($) {
+ my $password = shift;
+ my $yulecmd = shift || $yule;
+
+ my (undef, $key) = split /@/, `$yulecmd -P $password`, 2;
+ chomp $key;
+ return $key;
+}
+
+
+## main
+
+Getopt::Long::Configure ("posix_default");
+Getopt::Long::Configure ("bundling");
+# Getopt::Long::Configure ("debug");
+
+GetOptions (\%opts,
+ 'Y|yule=s',
+ 'a|add',
+ 'c|cfgfile=s',
+ 'd|delete',
+ 'h|help',
+ 'l|list',
+ 'o|output=s',
+ 'r|replace',
+ 'u|update',
+ 'v|verbose',
+ );
+
+if (defined ($opts{'h'})) {
+ usage();
+ exit;
+}
+
+if (defined($opts{'c'})) {
+ $cfgfile = $opts{'c'};
+ $outfile = $cfgfile unless defined($outfile);
+}
+if (defined($opts{'Y'})) {
+ $yule = $opts{'Y'};
+}
+if (defined($opts{'v'})) {
+ $verbose = 1;
+}
+if (defined($opts{'o'})) {
+ $outfile = $opts{'o'};
+}
+
+if (defined($opts{'l'})) {
+ # list contents
+ my $clients = read_clients($cfgfile);
+
+ foreach my $client (keys %{$clients}) {
+ print "$client";
+ print " ${$clients}{$client}" if $verbose;
+ print "\n";
+ }
+}
+elsif (defined($opts{'a'})
+ or defined($opts{'u'})
+ or defined($opts{'r'})) {
+ # add HOSTNAME
+ my $hostname = $ARGV[0]
+ or die("Actions --add/--replace/--update require at least argument HOSTNAME. Aborting");
+
+ my $password;
+ if (defined($ARGV[1])) {
+ $password = uc($ARGV[1]);
+ } else {
+ $password = uc(<STDIN>);
+ # remove leading and trailing space
+ $password =~ s{\s*}{}g;
+ }
+ # sanity check
+ die ("Argument PASSWORD must be a 16-digit hexadecimal string. Aborting")
+ unless ($password =~ m/[[:xdigit:]]{16}/);
+
+ my $add = defined($opts{'a'});
+ my $replace = defined($opts{'r'});
+
+ my $clients = read_clients($cfgfile);
+ die ("Client '$hostname' already present in config file - cannot add. Aborting")
+ if ($add and defined(${$clients}{$hostname}));
+ die ("Client '$hostname' not already present in config file - cannot replace. Aborting")
+ if ($replace and not defined(${$clients}{$hostname}));
+
+ $clients->{$hostname} = new_client_key($password)
+ or die ("Cannot get key for the given password. Aborting");
+ write_clients($cfgfile, $outfile, $clients);
+}
+elsif (defined($opts{'d'})) {
+ # remove HOSTNAME
+ my $hostname = $ARGV[0]
+ or die("Action --delete requires one argument HOSTNAME. Aborting");
+
+ my $clients = read_clients($cfgfile);
+ delete ${$clients}{$hostname};
+ write_clients($cfgfile, $outfile, $clients);
+}
+else {
+ usage();
+ die ("You must specify one of --list, --add or --remove options. Aborting");
+}
diff --git a/sql_init/samhain.mysql.init b/sql_init/samhain.mysql.init
new file mode 100644
index 0000000..f852384
--- /dev/null
+++ b/sql_init/samhain.mysql.init
@@ -0,0 +1,97 @@
+CREATE DATABASE samhain;
+USE mysql;
+INSERT INTO db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv) VALUES ('localhost','samhain','','N','Y','N','N','N','N');
+USE samhain;
+CREATE TABLE samhain.log (
+ log_index BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
+ log_ref BIGINT UNSIGNED NULL,
+ log_host VARCHAR(64) NOT NULL DEFAULT "localhost",
+ INDEX ix_log_host (log_host),
+ log_time DATETIME NOT NULL,
+ log_sev ENUM("DEBG","INFO","NOTE","WARN","MARK","ERRO","CRIT","ALRT","RCVT") NOT NULL,
+ log_msg BLOB,
+
+ log_hash VARCHAR(32) NOT NULL,
+ KEY ix_hash (log_hash),
+
+ entry_status VARCHAR(16) NOT NULL DEFAULT "NEW",
+ INDEX ix_entry_status (entry_status),
+
+ path BLOB,
+ userid VARCHAR(8),
+ grp VARCHAR(8),
+ program VARCHAR(8),
+ subroutine VARCHAR(16),
+ status VARCHAR(12),
+ hash VARCHAR(50),
+ path_data BLOB,
+ hash_data VARCHAR(50),
+ key_uid VARCHAR(64),
+ key_uid_data VARCHAR(64),
+ key_id VARCHAR(16),
+ module VARCHAR(8),
+ return_code INTEGER,
+ syscall VARCHAR(16),
+ ip VARCHAR(46),
+ tty VARCHAR(16),
+ peer VARCHAR(64),
+ fromhost VARCHAR(64),
+ obj BLOB,
+ interface VARCHAR(64),
+ time VARCHAR(64),
+ dir BLOB,
+ linked_path BLOB,
+ port INTEGER,
+ service VARCHAR(64),
+ facility VARCHAR(32),
+ priority VARCHAR(32),
+ syslog_msg BLOB,
+
+ mode_old VARCHAR(16),
+ mode_new VARCHAR(16),
+ attr_old VARCHAR(16),
+ attr_new VARCHAR(16),
+
+ device_old VARCHAR(16),
+ device_new VARCHAR(16),
+ owner_old VARCHAR(9),
+ owner_new VARCHAR(9),
+ group_old VARCHAR(9),
+ group_new VARCHAR(9),
+ ctime_old DATETIME,
+ ctime_new DATETIME,
+ atime_old DATETIME,
+ atime_new DATETIME,
+ mtime_old DATETIME,
+ mtime_new DATETIME,
+ chksum_old VARCHAR(50),
+ chksum_new VARCHAR(50),
+ link_old BLOB,
+ link_new BLOB,
+
+ size_old BIGINT UNSIGNED,
+ size_new BIGINT UNSIGNED,
+ hardlinks_old BIGINT UNSIGNED,
+ hardlinks_new BIGINT UNSIGNED,
+ inode_old BIGINT UNSIGNED,
+ inode_new BIGINT UNSIGNED,
+
+ imode_old BIGINT UNSIGNED,
+ imode_new BIGINT UNSIGNED,
+ iattr_old BIGINT UNSIGNED,
+ iattr_new BIGINT UNSIGNED,
+ idevice_old BIGINT UNSIGNED,
+ idevice_new BIGINT UNSIGNED,
+ iowner_old BIGINT UNSIGNED,
+ iowner_new BIGINT UNSIGNED,
+ igroup_old BIGINT UNSIGNED,
+ igroup_new BIGINT UNSIGNED,
+ checkflags_old BIGINT UNSIGNED,
+ checkflags_new BIGINT UNSIGNED,
+
+
+ acl_old BLOB,
+ acl_new BLOB
+
+ );
+
diff --git a/sql_init/samhain.oracle.init b/sql_init/samhain.oracle.init
new file mode 100644
index 0000000..fd3eba9
--- /dev/null
+++ b/sql_init/samhain.oracle.init
@@ -0,0 +1,95 @@
+CREATE SEQUENCE log_log_index_seq START WITH 1;
+CREATE TABLE log (
+ log_index INTEGER NOT NULL,
+ log_ref NUMBER(20) NULL,
+ log_host VARCHAR2(64) DEFAULT 'localhost' NOT NULL,
+ log_time DATE NOT NULL,
+ log_sev VARCHAR2(4) NOT NULL,
+ log_msg VARCHAR2(4000),
+ log_hash VARCHAR2(32),
+ entry_status VARCHAR2(16) DEFAULT 'NEW' NOT NULL,
+ path CLOB,
+ userid VARCHAR2(8),
+ grp VARCHAR2(8),
+ program VARCHAR2(8),
+ subroutine VARCHAR2(16),
+ status VARCHAR2(12),
+ hash VARCHAR2(50),
+ path_data VARCHAR2(4000),
+ hash_data VARCHAR2(50),
+ key_uid VARCHAR2(64),
+ key_uid_data VARCHAR2(64),
+ key_id VARCHAR2(16),
+ module VARCHAR2(8),
+ return_code INTEGER,
+ syscall VARCHAR2(16),
+ ip VARCHAR2(46),
+ tty VARCHAR2(16),
+ peer VARCHAR2(64),
+ fromhost VARCHAR2(64),
+ obj VARCHAR2(4000),
+ interface VARCHAR2(64),
+ time VARCHAR2(64),
+ dir CLOB,
+ linked_path CLOB,
+ port INTEGER,
+ service VARCHAR2(64),
+ facility VARCHAR2(32),
+ priority VARCHAR2(32),
+ syslog_msg VARCHAR2(4000),
+ mode_old VARCHAR2(16),
+ mode_new VARCHAR2(16),
+ attr_old VARCHAR2(16),
+ attr_new VARCHAR2(16),
+ device_old VARCHAR2(16),
+ device_new VARCHAR2(16),
+ owner_old VARCHAR2(9),
+ owner_new VARCHAR2(9),
+ group_old VARCHAR2(9),
+ group_new VARCHAR2(9),
+ ctime_old VARCHAR2(25),
+ ctime_new VARCHAR2(25),
+ atime_old VARCHAR2(25),
+ atime_new VARCHAR2(25),
+ mtime_old VARCHAR2(25),
+ mtime_new VARCHAR2(25),
+ chksum_old VARCHAR2(50),
+ chksum_new VARCHAR2(50),
+ link_old CLOB,
+ link_new CLOB,
+ size_old NUMBER(20),
+ size_new NUMBER(20),
+ hardlinks_old NUMBER(20),
+ hardlinks_new NUMBER(20),
+ inode_old NUMBER(20),
+ inode_new NUMBER(20),
+ imode_old NUMBER(20),
+ imode_new NUMBER(20),
+ iattr_old NUMBER(20),
+ iattr_new NUMBER(20),
+ idevice_old NUMBER(20),
+ idevice_new NUMBER(20),
+ iowner_old NUMBER(20),
+ iowner_new NUMBER(20),
+ igroup_old NUMBER(20),
+ igroup_new NUMBER(20),
+ checkflags_old NUMBER(20),
+ checkflags_new NUMBER(20),
+ acl_old VARCHAR2(4000),
+ acl_new VARCHAR2(4000)
+ );
+
+CREATE UNIQUE INDEX log_log_index_key on log (log_index);
+
+CREATE INDEX ix_hash ON log (log_hash);
+
+CREATE INDEX ix_log_host ON log (log_host);
+CREATE INDEX ix_log_ref ON log (log_ref);
+CREATE INDEX ix_entry_status ON log (entry_status);
+
+GRANT INSERT ON log TO samhain;
+GRANT ALTER ON log_log_index_seq TO samhain;
+GRANT SELECT ON log_log_index_seq TO samhain;
+
+
+
diff --git a/sql_init/samhain.postgres.init b/sql_init/samhain.postgres.init
new file mode 100644
index 0000000..ae42c27
--- /dev/null
+++ b/sql_init/samhain.postgres.init
@@ -0,0 +1,100 @@
+CREATE SEQUENCE log_log_index_seq START 1;
+CREATE TABLE log (
+ log_index INTEGER NOT NULL,
+ log_ref BIGINT NULL,
+ log_host VARCHAR(64) NOT NULL DEFAULT 'localhost',
+ log_time TIMESTAMP NOT NULL,
+ log_sev VARCHAR(4) NOT NULL,
+ log_msg TEXT,
+
+ log_hash VARCHAR(32),
+
+ entry_status VARCHAR(16) NOT NULL DEFAULT 'NEW',
+
+ path TEXT,
+ userid VARCHAR(8),
+ grp VARCHAR(8),
+ program VARCHAR(8),
+ subroutine VARCHAR(16),
+ status VARCHAR(12),
+ hash VARCHAR(50),
+ path_data TEXT,
+ hash_data VARCHAR(50),
+ key_uid VARCHAR(64),
+ key_uid_data VARCHAR(64),
+ key_id VARCHAR(16),
+ module VARCHAR(8),
+ return_code INTEGER,
+ syscall VARCHAR(16),
+ ip VARCHAR(46),
+ tty VARCHAR(16),
+ peer VARCHAR(64),
+ fromhost VARCHAR(64),
+ obj TEXT,
+ interface VARCHAR(64),
+ time VARCHAR(64),
+ dir TEXT,
+ linked_path TEXT,
+ port INTEGER,
+ service VARCHAR(64),
+ facility VARCHAR(32),
+ priority VARCHAR(32),
+ syslog_msg TEXT,
+
+ mode_old VARCHAR(16),
+ mode_new VARCHAR(16),
+ attr_old VARCHAR(16),
+ attr_new VARCHAR(16),
+
+ device_old VARCHAR(16),
+ device_new VARCHAR(16),
+ owner_old VARCHAR(9),
+ owner_new VARCHAR(9),
+ group_old VARCHAR(9),
+ group_new VARCHAR(9),
+ ctime_old TIMESTAMP,
+ ctime_new TIMESTAMP,
+ atime_old TIMESTAMP,
+ atime_new TIMESTAMP,
+ mtime_old TIMESTAMP,
+ mtime_new TIMESTAMP,
+ chksum_old VARCHAR(50),
+ chksum_new VARCHAR(50),
+ link_old TEXT,
+ link_new TEXT,
+
+ size_old NUMERIC(20),
+ size_new NUMERIC(20),
+ hardlinks_old NUMERIC(20),
+ hardlinks_new NUMERIC(20),
+ inode_old NUMERIC(20),
+ inode_new NUMERIC(20),
+
+ imode_old NUMERIC(20),
+ imode_new NUMERIC(20),
+ iattr_old NUMERIC(20),
+ iattr_new NUMERIC(20),
+ idevice_old NUMERIC(20),
+ idevice_new NUMERIC(20),
+ iowner_old NUMERIC(20),
+ iowner_new NUMERIC(20),
+ igroup_old NUMERIC(20),
+ igroup_new NUMERIC(20),
+ checkflags_old NUMERIC(20),
+ checkflags_new NUMERIC(20),
+
+ acl_old TEXT,
+ acl_new TEXT
+ );
+
+
+CREATE UNIQUE INDEX log_log_index_key on log (log_index);
+CREATE INDEX ix_hash ON log (log_hash);
+
+CREATE INDEX ix_log_host ON log (log_host);
+CREATE INDEX ix_entry_status ON log (entry_status);
+
+GRANT INSERT ON log TO samhain;
+GRANT UPDATE ON log_log_index_seq TO samhain;
+GRANT SELECT ON log_log_index_seq TO samhain;
+
diff --git a/src/#sh_unix.c# b/src/#sh_unix.c#
new file mode 100644
index 0000000..695d46f
--- /dev/null
+++ b/src/#sh_unix.c#
@@ -0,0 +1,5710 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <unistd.h>
+/* need to undef these, since the #define's may be picked up from
+ * linux/wait.h, and will clash with a typedef in sys/wait.h
+ */
+#undef P_ALL
+#undef P_PID
+#undef P_PGID
+#include <sys/wait.h>
+
+/*********************
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+**********************/
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_unix.h"
+#include "sh_utils.h"
+#include "sh_mem.h"
+#include "sh_hash.h"
+#include "sh_tools.h"
+#include "sh_restrict.h"
+#include "sh_ipvx.h"
+#include "sh_tiger.h"
+#include "sh_prelink.h"
+#include "sh_pthread.h"
+#include "sh_sem.h"
+
+/* moved here from far below
+ */
+#include <netdb.h>
+
+#define SH_NEED_PWD_GRP
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+#if defined(S_IFLNK) && !defined(S_ISLNK)
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#else
+#if !defined(S_ISLNK)
+#define S_ISLNK(mode) (0)
+#endif
+#endif
+
+#if defined(S_IFSOCK) && !defined(S_ISSOCK)
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#else
+#if !defined(S_ISSOCK)
+#define S_ISSOCK(mode) (0)
+#endif
+#endif
+
+#if defined(S_IFDOOR) && !defined(S_ISDOOR)
+#define S_ISDOOR(mode) (((mode) & S_IFMT) == S_IFDOOR)
+#else
+#if !defined(S_ISDOOR)
+#define S_ISDOOR(mode) (0)
+#endif
+#endif
+
+#if defined(S_IFPORT) && !defined(S_ISPORT)
+#define S_ISPORT(mode) (((mode) & S_IFMT) == S_IFPORT)
+#else
+#if !defined(S_ISPORT)
+#define S_ISPORT(mode) (0)
+#endif
+#endif
+
+#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
+
+#undef FIL__
+#define FIL__ _("sh_unix.c")
+
+unsigned long mask_PRELINK = MASK_PRELINK_;
+unsigned long mask_USER0 = MASK_USER_;
+unsigned long mask_USER1 = MASK_USER_;
+unsigned long mask_USER2 = MASK_USER_;
+unsigned long mask_USER3 = MASK_USER_;
+unsigned long mask_USER4 = MASK_USER_;
+unsigned long mask_ALLIGNORE = MASK_ALLIGNORE_;
+unsigned long mask_ATTRIBUTES = MASK_ATTRIBUTES_;
+unsigned long mask_LOGFILES = MASK_LOGFILES_;
+unsigned long mask_LOGGROW = MASK_LOGGROW_;
+unsigned long mask_READONLY = MASK_READONLY_;
+unsigned long mask_NOIGNORE = MASK_NOIGNORE_;
+
+
+extern char **environ;
+
+int sh_unix_maskreset()
+{
+ mask_PRELINK = MASK_PRELINK_;
+ mask_USER0 = MASK_USER_;
+ mask_USER1 = MASK_USER_;
+ mask_USER2 = MASK_USER_;
+ mask_USER3 = MASK_USER_;
+ mask_USER4 = MASK_USER_;
+ mask_ALLIGNORE = MASK_ALLIGNORE_;
+ mask_ATTRIBUTES = MASK_ATTRIBUTES_;
+ mask_LOGFILES = MASK_LOGFILES_;
+ mask_LOGGROW = MASK_LOGGROW_;
+ mask_READONLY = MASK_READONLY_;
+ mask_NOIGNORE = MASK_NOIGNORE_;
+ return 0;
+}
+
+
+#ifdef SYS_SIGLIST_DECLARED
+/* extern const char * const sys_siglist[]; */
+#else
+char * sh_unix_siglist (int signum)
+{
+ switch (signum)
+ {
+#ifdef SIGHUP
+ case SIGHUP:
+ return _("Hangup");
+#endif
+#ifdef SIGINT
+ case SIGINT:
+ return _("Interrupt");
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT:
+ return _("Quit");
+#endif
+#ifdef SIGILL
+ case SIGILL:
+ return _("Illegal instruction");
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP:
+ return _("Trace/breakpoint trap");
+#endif
+#ifdef SIGABRT
+ case SIGABRT:
+ return _("IOT trap/Abort");
+#endif
+#ifdef SIGBUS
+ case SIGBUS:
+ return _("Bus error");
+#endif
+#ifdef SIGFPE
+ case SIGFPE:
+ return _("Floating point exception");
+#endif
+#ifdef SIGUSR1
+ case SIGUSR1:
+ return _("User defined signal 1");
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV:
+ return _("Segmentation fault");
+#endif
+#ifdef SIGUSR2
+ case SIGUSR2:
+ return _("User defined signal 2");
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE:
+ return _("Broken pipe");
+#endif
+#ifdef SIGALRM
+ case SIGALRM:
+ return _("Alarm clock");
+#endif
+#ifdef SIGTERM
+ case SIGTERM:
+ return _("Terminated");
+#endif
+#ifdef SIGSTKFLT
+ case SIGSTKFLT:
+ return _("Stack fault");
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD:
+ return _("Child exited");
+#endif
+#ifdef SIGCONT
+ case SIGCONT:
+ return _("Continued");
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP:
+ return _("Stopped");
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP:
+ return _("Stop typed at tty");
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN:
+ return _("Stopped (tty input)");
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU:
+ return _("Stopped (tty output)");
+#endif
+#ifdef SIGURG
+ case SIGURG:
+ return _("Urgent condition");
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU:
+ return _("CPU time limit exceeded");
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ:
+ return _("File size limit exceeded");
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM:
+ return _("Virtual time alarm");
+#endif
+#ifdef SIGPROF
+ case SIGPROF:
+ return _("Profile signal");
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH:
+ return _("Window size changed");
+#endif
+#ifdef SIGIO
+ case SIGIO:
+ return _("Possible I/O");
+#endif
+#ifdef SIGPWR
+ case SIGPWR:
+ return _("Power failure");
+#endif
+#ifdef SIGUNUSED
+ case SIGUNUSED:
+ return _("Unused signal");
+#endif
+ }
+ return _("Unknown");
+}
+#endif
+
+
+/* Log from within a signal handler without using any
+ * functions that are not async signal safe.
+ *
+ * This is the safe_itoa helper function.
+ */
+char * safe_itoa(int i, char * str, int size)
+{
+ unsigned int u;
+ int iisneg = 0;
+ char *p = &str[size-1];
+
+ *p = '\0';
+ if (i < 0) {
+ iisneg = 1;
+ u = ((unsigned int)(-(1+i))) + 1;
+ } else {
+ u = i;
+ }
+ do {
+ --p;
+ *p = '0' + (u % 10);
+ u /= 10;
+ } while (u && (p != str));
+ if ((iisneg == 1) && (p != str)) {
+ --p;
+ *p = '-';
+ }
+ return p;
+}
+
+/* Log from within a signal handler without using any
+ * functions that are not async signal safe.
+ *
+ * This is the safe_logger function.
+ * Arguments: signal (signal number), method (0=logger, 1=stderr), thepid (pid)
+ */
+extern int OnlyStderr;
+
+int safe_logger (int thesignal, int method, char * details)
+{
+ unsigned int i = 0;
+ int status = -1;
+ struct stat buf;
+ pid_t newpid;
+ char str[128];
+ char * p;
+
+ char l0[64], l1[64], l2[64], l3[64];
+ char a0[32];
+ char e0[128];
+ char msg[128];
+
+ char * locations[] = { NULL, NULL, NULL, NULL, NULL };
+ char * envp[] = { NULL, NULL };
+ char * argp[] = { NULL, NULL, NULL };
+
+ pid_t thepid = getpid();
+
+ if ((sh.flag.isdaemon == S_FALSE) || (OnlyStderr == S_TRUE))
+ method = 1;
+
+ /* seems that solaris cc needs this way of initializing ...
+ */
+ locations[0] = l0;
+ locations[1] = l1;
+ locations[2] = l2;
+ locations[3] = l3;
+
+ envp[0] = e0;
+ argp[0] = a0;
+
+ sl_strlcpy(msg, _("samhain["), 128);
+ p = safe_itoa((int) thepid, str, 128);
+ if (p && *p)
+ sl_strlcat(msg, p, 128);
+ if (thesignal == 0)
+ {
+ if (details == NULL) {
+ sl_strlcat(msg, _("]: out of memory"), 128);
+ } else {
+ sl_strlcat(msg, _("]: "), 128);
+ sl_strlcat(msg, details, 128);
+ }
+ }
+ else
+ {
+ sl_strlcat(msg, _("]: exit on signal "), 128);
+ p = safe_itoa(thesignal, str, 128);
+ if (p && *p)
+ sl_strlcat(msg, p, 128);
+ }
+
+ if (method == 1) {
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+ int retval = 0;
+ do {
+ retval = write(STDERR_FILENO, msg, strlen(msg));
+ } while (retval < 0 && errno == EINTR);
+ do {
+ retval = write(STDERR_FILENO, "\n", 1);
+ } while (retval < 0 && errno == EINTR);
+ return 0;
+ }
+
+ sl_strlcpy (l0, _("/usr/bin/logger"), 64);
+ sl_strlcpy (l1, _("/usr/sbin/logger"), 64);
+ sl_strlcpy (l2, _("/usr/ucb/logger"), 64);
+ sl_strlcpy (l3, _("/bin/logger"), 64);
+
+ sl_strlcpy (a0, _("logger"), 32);
+ sl_strlcpy (e0,
+ _("PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/ucb:/usr/local/bin"),
+ 128);
+
+ while (locations[i] != NULL) {
+ status = stat(locations[i], &buf);
+ if (status == 0)
+ break;
+ ++i;
+ }
+
+ if (locations[i] != NULL) {
+ argp[1] = msg;
+ newpid = fork();
+ if (newpid == 0) {
+ execve(locations[i], argp, envp);
+ _exit(1);
+ }
+ else if (newpid > 0) {
+ waitpid(newpid, &status, WUNTRACED);
+ }
+ }
+ return 0;
+}
+
+void safe_fatal (const char * details,
+ const char * file, int line)
+{
+ char msg[128];
+ char str[128];
+ char * p;
+ int thesignal = 0;
+ int method = 0;
+
+ p = safe_itoa((int) line, str, 128);
+ sl_strlcpy(msg, _("FATAL: "), 128);
+ sl_strlcat(msg, file, 128);
+ sl_strlcat(msg, ": ", 128);
+ if (p && (*p)) {
+ sl_strlcat(msg, p , 128);
+ sl_strlcat(msg, ": ", 128);
+ }
+ sl_strlcat(msg, details, 128);
+ (void) safe_logger (thesignal, method, msg);
+
+ close_ipc ();
+ raise(SIGKILL);
+}
+
+extern char sh_sig_msg[64];
+
+volatile int immediate_exit_normal = 0;
+
+#if defined(SA_SIGACTION_WORKS)
+static
+void sh_unix_sigexit (int mysignal, siginfo_t * signal_info, void * signal_add)
+#else
+static
+void sh_unix_sigexit (int mysignal)
+#endif
+{
+
+#if defined(SA_SIGACTION_WORKS)
+ if (signal_info != NULL && signal_info->si_code == SI_USER &&
+ mysignal != SIGTERM && mysignal != SIGINT)
+ {
+ return;
+ }
+
+ /* avoid compiler warning (unused var)
+ */
+ (void) signal_add;
+#endif
+
+ /*
+ * Block re-entry
+ */
+ if (immediate_exit_normal > 0)
+ {
+ ++immediate_exit_normal;
+ if ((skey != NULL) && (immediate_exit_normal == 2))
+ memset (skey, '\0', sizeof(sh_key_t));
+ if (immediate_exit_normal == 2)
+ {
+ int val_return;
+
+ do {
+ val_return = chdir ("/");
+ } while (val_return < 0 && errno == EINTR);
+
+ close_ipc ();
+ safe_logger (mysignal, 0, NULL);
+ }
+ raise(SIGKILL);
+ }
+ else
+ {
+ immediate_exit_normal = 1;
+ }
+
+#ifdef SYS_SIGLIST_DECLARED
+ strncpy (sh_sig_msg, sys_siglist[mysignal], 40);
+#else
+ strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40);
+#endif
+ sh_sig_msg[63] = '\0';
+
+ ++sig_raised;
+ ++sig_urgent;
+ sig_termfast = 1;
+ return;
+}
+
+volatile int immediate_exit_fast = 0;
+
+#if defined(SA_SIGACTION_WORKS)
+static
+void sh_unix_sigexit_fast (int mysignal, siginfo_t * signal_info,
+ void * signal_add)
+#else
+static
+void sh_unix_sigexit_fast (int mysignal)
+#endif
+{
+#if defined(SL_DEBUG) && (defined(USE_SYSTEM_MALLOC) || !defined(USE_MALLOC_LOCK))
+ int retval;
+#endif
+
+#if defined(SA_SIGACTION_WORKS)
+ if (signal_info != NULL && signal_info->si_code == SI_USER)
+ {
+ return;
+ }
+#endif
+
+ /* avoid compiler warning (unused var)
+ */
+#if defined(SA_SIGACTION_WORKS)
+ (void) signal_add;
+#endif
+
+ /* Check whether the heap is ok; otherwise _exit
+ */
+#if !defined(SL_DEBUG) || (!defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK))
+ ++immediate_exit_fast;
+ if (skey != NULL && immediate_exit_fast < 2)
+ memset (skey, '\0', sizeof(sh_key_t));
+ if (immediate_exit_fast < 2)
+ safe_logger (mysignal, 0, NULL);
+ raise(SIGKILL);
+#else
+
+ /* debug code
+ */
+ if (immediate_exit_fast == 1)
+ {
+ ++immediate_exit_fast;
+ if (skey != NULL)
+ memset (skey, '\0', sizeof(sh_key_t));
+ close_ipc ();
+ safe_logger (mysignal, 0, NULL);
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+ raise(SIGFPE);
+ }
+ else if (immediate_exit_fast == 2)
+ {
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+ raise(SIGFPE);
+ }
+ else if (immediate_exit_fast != 0)
+ {
+ raise(SIGKILL);
+ }
+
+ ++immediate_exit_fast;
+
+ /* The FPE|BUS|SEGV|ILL signals leave the system in an undefined
+ * state, thus it is best to exit immediately.
+ */
+#ifdef SYS_SIGLIST_DECLARED
+ strncpy (sh_sig_msg, sys_siglist[mysignal], 40);
+#else
+ strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40);
+#endif
+ sh_sig_msg[63] = '\0';
+
+ sl_stack_print();
+
+ /* Try to push out an error message.
+ */
+ sh_error_handle ((-1), FIL__, __LINE__, mysignal, MSG_EXIT_NORMAL,
+ sh.prg_name, sh_sig_msg);
+
+ if (skey != NULL)
+ memset (skey, '\0', sizeof(sh_key_t));
+ close_ipc ();
+
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+
+ raise(SIGFPE);
+#endif
+}
+
+
+static
+void sh_unix_sigaction (int mysignal)
+{
+ ++sig_raised;
+#ifdef SIGUSR1
+ if (mysignal == SIGUSR1)
+ sig_debug_switch = 1;
+#endif
+#ifdef SIGUSR2
+ if (mysignal == SIGUSR2)
+ {
+ ++sig_suspend_switch;
+ ++sig_urgent;
+ }
+#endif
+#ifdef SIGHUP
+ if (mysignal == SIGHUP)
+ sig_config_read_again = 1;
+#endif
+#ifdef SIGTTOU
+ if (mysignal == SIGTTOU) {
+ sig_force_check = 1; sh_sem_trylock(); }
+#endif
+#ifdef SIGTSTP
+ if (mysignal == SIGTSTP) {
+ sig_force_check = 1; sig_force_silent = 1; sh_sem_trylock(); }
+#endif
+#ifdef SIGTTIN
+ if (mysignal == SIGTTIN)
+ sig_fresh_trail = 1;
+#endif
+#ifdef SIGABRT
+ if (mysignal == SIGABRT)
+ sig_fresh_trail = 1;
+#endif
+#ifdef SIGQUIT
+ if (mysignal == SIGQUIT)
+ sig_terminate = 1;
+#endif
+#ifdef SIGTERM
+ if (mysignal == SIGTERM)
+ {
+ strncpy (sh_sig_msg, _("Terminated"), 40);
+ sig_termfast = 1;
+ ++sig_urgent;
+ }
+#endif
+
+ return;
+}
+
+void sh_unix_ign_sigpipe()
+{
+ struct sigaction ignact;
+
+ ignact.sa_handler = SIG_IGN; /* signal action */
+ sigemptyset( &ignact.sa_mask ); /* set an empty mask */
+ ignact.sa_flags = 0; /* init sa_flags */
+
+#ifdef SIGPIPE
+ retry_sigaction(FIL__, __LINE__, SIGPIPE, &ignact, NULL);
+#endif
+
+ return;
+}
+static
+void sh_unix_siginstall (int goDaemon)
+{
+ struct sigaction act, act_fast, act2, oldact, ignact;
+#if defined (SH_WITH_SERVER)
+ (void) goDaemon;
+#endif
+
+ SL_ENTER(_("sh_unix_siginstall"));
+
+ ignact.sa_handler = SIG_IGN; /* signal action */
+ sigemptyset( &ignact.sa_mask ); /* set an empty mask */
+ ignact.sa_flags = 0; /* init sa_flags */
+
+#if defined(SA_SIGACTION_WORKS)
+ act.sa_sigaction = &sh_unix_sigexit; /* signal action */
+#else
+ act.sa_handler = &sh_unix_sigexit; /* signal action */
+#endif
+
+ sigfillset ( &act.sa_mask ); /* set a full mask */
+
+
+ /* Block all but deadly signals.
+ */
+#ifdef SIGILL
+ sigdelset ( &act.sa_mask, SIGILL );
+#endif
+#ifndef SL_DEBUG
+#ifdef SIGFPE
+ sigdelset ( &act.sa_mask, SIGFPE );
+#endif
+#endif
+#ifdef SIGSEGV
+ sigdelset ( &act.sa_mask, SIGSEGV );
+#endif
+#ifdef SIGBUS
+ sigdelset ( &act.sa_mask, SIGBUS );
+#endif
+
+#if defined(SA_SIGACTION_WORKS)
+ act_fast.sa_sigaction = &sh_unix_sigexit_fast; /* signal action */
+#else
+ act_fast.sa_handler = &sh_unix_sigexit_fast; /* signal action */
+#endif
+
+ sigfillset ( &act_fast.sa_mask ); /* set a full mask */
+
+#ifdef SIGILL
+ sigdelset ( &act_fast.sa_mask, SIGILL );
+#endif
+#ifndef SL_DEBUG
+#ifdef SIGFPE
+ sigdelset ( &act_fast.sa_mask, SIGFPE );
+#endif
+#endif
+#ifdef SIGSEGV
+ sigdelset ( &act_fast.sa_mask, SIGSEGV );
+#endif
+#ifdef SIGBUS
+ sigdelset ( &act_fast.sa_mask, SIGBUS );
+#endif
+
+
+ /* Use siginfo to verify origin of signal, if possible.
+ */
+#if defined(SA_SIGACTION_WORKS)
+ act.sa_flags = SA_SIGINFO;
+ act_fast.sa_flags = SA_SIGINFO;
+#else
+ act.sa_flags = 0;
+ act_fast.sa_flags = 0;
+#endif
+
+ /* Do not block the signal from being received in its handler ...
+ * (is this a good or a bad idea ??).
+ */
+#if defined(SA_NOMASK)
+ act_fast.sa_flags |= SA_NOMASK;
+#elif defined(SA_NODEFER)
+ act_fast.sa_flags |= SA_NODEFER;
+#endif
+
+
+ act2.sa_handler = &sh_unix_sigaction; /* signal action */
+ sigemptyset( &act2.sa_mask ); /* set an empty mask */
+ act2.sa_flags = 0; /* init sa_flags */
+
+ /* signals to control the daemon */
+
+#ifdef SIGHUP
+ retry_sigaction(FIL__, __LINE__, SIGHUP, &act2, &oldact);
+#endif
+#ifdef SIGABRT
+ retry_sigaction(FIL__, __LINE__, SIGABRT, &act2, &oldact);
+#endif
+#ifdef SIGUSR1
+ retry_sigaction(FIL__, __LINE__, SIGUSR1, &act2, &oldact);
+#endif
+#ifdef SIGUSR2
+ retry_sigaction(FIL__, __LINE__, SIGUSR2, &act2, &oldact);
+#endif
+#ifdef SIGQUIT
+ retry_sigaction(FIL__, __LINE__, SIGQUIT, &act2, &oldact);
+#endif
+#ifdef SIGTERM
+ retry_sigaction(FIL__, __LINE__, SIGTERM, &act, &oldact);
+#endif
+
+ /* fatal signals that may cause termination */
+
+#ifdef SIGILL
+ retry_sigaction(FIL__, __LINE__, SIGILL, &act_fast, &oldact);
+#endif
+#ifndef SL_DEBUG
+#ifdef SIGFPE
+ retry_sigaction(FIL__, __LINE__, SIGFPE, &act_fast, &oldact);
+#endif
+#endif
+#ifdef SIGSEGV
+ retry_sigaction(FIL__, __LINE__, SIGSEGV, &act_fast, &oldact);
+#endif
+#ifdef SIGBUS
+ retry_sigaction(FIL__, __LINE__, SIGBUS, &act_fast, &oldact);
+#endif
+
+ /* other signals */
+
+#ifdef SIGINT
+ retry_sigaction(FIL__, __LINE__, SIGINT, &act, &oldact);
+#endif
+#ifdef SIGPIPE
+ retry_sigaction(FIL__, __LINE__, SIGPIPE, &ignact, &oldact);
+#endif
+#ifdef SIGALRM
+ retry_sigaction(FIL__, __LINE__, SIGALRM, &ignact, &oldact);
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+#ifdef SIGTTOU
+ if (goDaemon == 1)
+ retry_sigaction(FIL__, __LINE__, SIGTTOU, &act2, &oldact);
+ else
+ retry_sigaction(FIL__, __LINE__, SIGTTOU, &ignact, &oldact);
+#endif
+#ifdef SIGTSTP
+ if (goDaemon == 1)
+ retry_sigaction(FIL__, __LINE__, SIGTSTP, &act2, &oldact);
+ else
+ retry_sigaction(FIL__, __LINE__, SIGTSTP, &ignact, &oldact);
+#endif
+#ifdef SIGTTIN
+ if (goDaemon == 1)
+ retry_sigaction(FIL__, __LINE__, SIGTTIN, &act2, &oldact);
+ else
+ retry_sigaction(FIL__, __LINE__, SIGTTIN, &ignact, &oldact);
+#endif
+#else
+#ifdef SIGTSTP
+ retry_sigaction(FIL__, __LINE__, SIGTSTP, &ignact, &oldact);
+#endif
+#ifdef SIGTTOU
+ retry_sigaction(FIL__, __LINE__, SIGTTOU, &ignact, &oldact);
+#endif
+#ifdef SIGTTIN
+ retry_sigaction(FIL__, __LINE__, SIGTTIN, &ignact, &oldact);
+#endif
+#endif
+
+#ifdef SIGTRAP
+#if !defined(SCREW_IT_UP)
+ retry_sigaction(FIL__, __LINE__, SIGTRAP, &act, &oldact);
+#endif
+#endif
+
+#ifdef SIGPOLL
+ retry_sigaction(FIL__, __LINE__, SIGPOLL, &ignact, &oldact);
+#endif
+#if defined(SIGPROF) && !defined(SH_PROFILE)
+ retry_sigaction(FIL__, __LINE__, SIGPROF, &ignact, &oldact);
+#endif
+#ifdef SIGSYS
+ retry_sigaction(FIL__, __LINE__, SIGSYS, &act, &oldact);
+#endif
+#ifdef SIGURG
+ retry_sigaction(FIL__, __LINE__, SIGURG, &ignact, &oldact);
+#endif
+#if defined(SIGVTALRM) && !defined(SH_PROFILE)
+ retry_sigaction(FIL__, __LINE__, SIGVTALRM, &ignact, &oldact);
+#endif
+#ifdef SIGXCPU
+ retry_sigaction(FIL__, __LINE__, SIGXCPU, &act, &oldact);
+#endif
+#ifdef SIGXFSZ
+ retry_sigaction(FIL__, __LINE__, SIGXFSZ, &act, &oldact);
+#endif
+
+#ifdef SIGEMT
+ retry_sigaction(FIL__, __LINE__, SIGEMT, &ignact, &oldact);
+#endif
+#ifdef SIGSTKFLT
+ retry_sigaction(FIL__, __LINE__, SIGSTKFLT, &act, &oldact);
+#endif
+#ifdef SIGIO
+ retry_sigaction(FIL__, __LINE__, SIGIO, &ignact, &oldact);
+#endif
+#ifdef SIGPWR
+ retry_sigaction(FIL__, __LINE__, SIGPWR, &act, &oldact);
+#endif
+
+#ifdef SIGLOST
+ retry_sigaction(FIL__, __LINE__, SIGLOST, &ignact, &oldact);
+#endif
+#ifdef SIGUNUSED
+ retry_sigaction(FIL__, __LINE__, SIGUNUSED, &ignact, &oldact);
+#endif
+
+ SL_RET0(_("sh_unix_siginstall"));
+}
+
+/* ---------------------------------------------------------------- */
+
+/* checksum the own binary
+ */
+int sh_unix_self_hash (const char * c)
+{
+ char message[512];
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_unix_self_hash"));
+
+ if (c == NULL)
+ {
+ sh.exec.path[0] = '\0';
+ SL_RETURN((0), _("sh_unix_self_hash"));
+ }
+ sl_strlcpy(sh.exec.path, c, SH_PATHBUF);
+
+ sl_strlcpy(sh.exec.hash,
+ sh_tiger_hash (c, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ sl_snprintf(message, 512, _("%s has checksum: %s"),
+ sh.exec.path, sh.exec.hash);
+ message[511] = '\0';
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ message, _("sh_unix_self_hash"));
+ if (0 == sl_strcmp(sh.exec.hash, SH_KEY_NULL ))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Could not checksum my own executable because of the\nfollowing error: %s: %s\n\nPossible reasons include:\n Wrong path in configure file option SamhainPath=/path/to/executable\n No read permission for the effective UID: %d\n"),
+ sh.exec.path, sl_get_errmsg(), (int) sl_ret_euid());
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_NOACCESS,
+ (long) sh.real.uid, c);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ SL_RETURN((0), _("sh_unix_self_hash"));
+}
+
+int sh_unix_self_check ()
+{
+ char newhash[KEY_LEN+1];
+ char message[512];
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_unix_self_check"));
+ if (sh.exec.path[0] == '\0')
+ SL_RETURN((0), _("sh_unix_self_check"));
+
+ sl_strlcpy(newhash,
+ sh_tiger_hash (sh.exec.path, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ if (0 == sl_strncmp(sh.exec.hash, newhash, KEY_LEN))
+ {
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Checksum ok"), _("sh_unix_self_check"));
+ SL_RETURN((0), _("sh_unix_self_check"));
+ }
+
+ if (0 == sl_strncmp(SH_KEY_NULL, newhash, KEY_LEN))
+ {
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Could not read samhain executable"), _("sh_unix_self_check"));
+ SL_RETURN((0), _("sh_unix_self_check"));
+ }
+
+ dlog(1, FIL__, __LINE__,
+ _("The checksum of the executable: %s has changed since startup (%s -> %s).\n"),
+ sh.exec.path, sh.exec.hash, newhash);
+
+ sl_snprintf(message, 512,
+ _("The checksum of %s has changed since startup (%s -> %s)"),
+ sh.exec.path, sh.exec.hash, newhash);
+ message[511] = '\0';
+
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ message, _("sh_unix_self_check"));
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_E_AUTH,
+ sh.exec.path);
+ SL_RETURN((-1), _("sh_unix_self_check"));
+}
+
+
+/* ---------------------------------------------------------------- */
+
+long sh_group_to_gid (const char * g, int * fail)
+{
+ struct group * w;
+ gid_t gid = 0;
+ int status = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct group grp;
+ char * buffer;
+ static size_t gbufsize = SH_GRBUF_SIZE;
+#endif
+
+ *fail = -1;
+
+ if (g)
+ {
+ size_t i;
+ size_t len = strlen(g);
+
+ *fail = 0;
+
+ for (i = 0; i < len; ++i)
+ {
+ char c = g[i];
+
+ if (!isdigit((int) c))
+ goto is_a_name;
+ }
+ return atol(g);
+
+ is_a_name:
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+
+ buffer = SH_ALLOC(gbufsize);
+ status = sh_getgrnam_r(g, &grp, buffer, gbufsize, &w);
+
+ if ((status == ERANGE) && (w == NULL))
+ {
+ if (S_TRUE == sl_ok_adds( gbufsize, SH_GRBUF_SIZE ))
+ {
+ SH_FREE(buffer);
+ gbufsize += SH_GRBUF_SIZE;
+ goto is_a_name;
+ }
+ }
+
+#else
+
+ errno = 0;
+ w = sh_getgrnam(g);
+ status = errno;
+
+#endif
+
+ if ((status == ERANGE) && (w == NULL))
+ {
+ static int seen = 0;
+
+ if (seen == 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("sh_group_to_gid"), (long) -1, _("line too long in group entry"));
+ ++seen;
+ }
+ *fail = -1;
+ }
+ else if (w == NULL)
+ {
+ char * tmp = sh_util_strdup(g);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("sh_group_to_gid"), tmp);
+ SH_FREE(tmp);
+ *fail = -1;
+ }
+ else
+ {
+ gid = w->gr_gid;
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+
+ return gid;
+}
+
+/* ---------------------------------------------------------------- */
+
+
+/* added Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann */
+static int tf_add_trusted_user_int(const char * c)
+{
+ struct passwd * w;
+ int count;
+ uid_t pwid = (uid_t)-1;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+
+ SL_ENTER(_("tf_add_trusted_user_int"));
+
+ /* First check for a user name.
+ */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwnam_r(c, &pwd, buffer, SH_PWBUF_SIZE, &w);
+#else
+ w = sh_getpwnam(c);
+#endif
+
+ if ((w != NULL) && ((pwid = w->pw_uid) > 0))
+ goto succe;
+
+ /* Failed, so check for a numerical value.
+ */
+ pwid = strtol(c, (char **)NULL, 10);
+ if (pwid > 0 && pwid < 65535)
+ goto succe;
+
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("add trusted user"), c);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN((-1), _("tf_add_trusted_user_int"));
+
+ succe:
+ count = sl_trust_add_user(pwid);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN((count), _("tf_add_trusted_user_int"));
+}
+
+int tf_add_trusted_user(const char * c)
+{
+ int i;
+ char * q;
+ char * p = sh_util_strdup (c);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+#endif
+
+ SL_ENTER(_("tf_add_trusted_user"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ q = strtok_r(p, ", \t", &saveptr);
+#else
+ q = strtok(p, ", \t");
+#endif
+ if (!q)
+ {
+ SH_FREE(p);
+ SL_RETURN((-1), _("tf_add_trusted_user"));
+ }
+ while (q)
+ {
+ i = tf_add_trusted_user_int(q);
+ if (SL_ISERROR(i))
+ {
+ SH_FREE(p);
+ SL_RETURN((i), _("tf_add_trusted_user"));
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ q = strtok_r(NULL, ", \t", &saveptr);
+#else
+ q = strtok(NULL, ", \t");
+#endif
+ }
+ SH_FREE(p);
+ SL_RETURN((0), _("tf_add_trusted_user"));
+}
+
+extern uid_t sl_trust_baduid(void);
+extern gid_t sl_trust_badgid(void);
+
+#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__)
+int tf_trust_check (const char * file, int mode)
+{
+ (void) file;
+ (void) mode;
+ return 0;
+}
+#else
+int tf_trust_check (const char * file, int mode)
+{
+ char * tmp;
+ char * tmp2;
+ char * p;
+ int status;
+ int level;
+ uid_t ff_euid = (uid_t) -1;
+
+ SL_ENTER(_("tf_trust_check"));
+
+ if (mode == SL_YESPRIV)
+ sl_get_euid(&ff_euid);
+ else
+ sl_get_ruid(&ff_euid);
+
+#if defined(SH_WITH_SERVER)
+ if (0 == sl_ret_euid()) /* privileges not dropped yet */
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ struct passwd * tempres;
+ sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
+#endif
+
+ if (!tempres)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("User %s does not exist. Please add the user to your system.\n"),
+ DEFAULT_IDENT);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ else
+ {
+ ff_euid = tempres->pw_uid;
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+#endif
+
+ status = sl_trustfile_euid(file, ff_euid);
+
+ if ( SL_ENONE != status)
+ {
+ if (status == SL_ESTAT)
+ level = SH_ERR_ALL;
+ else
+ level = SH_ERR_ERR;
+
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ if (p && *p != '\0')
+ {
+ tmp2 = sh_util_safe_name (sl_trust_errfile());
+ sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST2,
+ sl_error_string(status), tmp, tmp2);
+ SH_FREE(tmp2);
+ }
+ else
+ {
+ sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST1,
+ sl_error_string(status), tmp);
+ }
+ SH_FREE(tmp);
+
+ if (status == SL_EBADUID || status == SL_EBADGID ||
+ status == SL_EBADOTH || status == SL_ETRUNC ||
+ status == SL_EINTERNAL )
+ {
+ switch (status) {
+ case SL_EINTERNAL:
+ dlog(1, FIL__, __LINE__,
+ _("An internal error occured in the trustfile function.\n"));
+ break;
+ case SL_ETRUNC:
+ tmp = sh_util_safe_name (file);
+ dlog(1, FIL__, __LINE__,
+ _("A filename truncation occured in the trustfile function.\nProbably the normalized filename for %s\nis too long. This may be due e.g. to deep or circular softlinks.\n"),
+ tmp);
+ SH_FREE(tmp);
+ break;
+ case SL_EBADOTH:
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ dlog(1, FIL__, __LINE__,
+ _("The path element: %s\nin the filename: %s is world writeable.\n"),
+ p, tmp);
+ SH_FREE(tmp);
+ break;
+ case SL_EBADUID:
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ dlog(1, FIL__, __LINE__,
+ _("The owner (UID = %ld) of the path element: %s\nin the filename: %s\nis not in the list of trusted users.\nTo fix the problem, you can:\n - run ./configure again with the option --with-trusted=0,...,UID\n where UID is the UID of the untrusted user, or\n - use the option TrustedUser=UID in the configuration file.\n"),
+ (UID_CAST)sl_trust_baduid(), p, tmp);
+ SH_FREE(tmp);
+ break;
+ case SL_EBADGID:
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ dlog(1, FIL__, __LINE__,
+ _("The path element: %s\nin the filename: %s\nis group writeable (GID = %ld), and at least one of the group\nmembers (UID = %ld) is not in the list of trusted users.\nTo fix the problem, you can:\n - run ./configure again with the option --with-trusted=0,...,UID\n where UID is the UID of the untrusted user, or\n - use the option TrustedUser=UID in the configuration file.\n"),
+ p, tmp, (UID_CAST)sl_trust_badgid(),
+ (UID_CAST)sl_trust_baduid());
+ SH_FREE(tmp);
+ break;
+ default:
+ break;
+ }
+
+ SL_RETURN((-1), _("tf_trust_check"));
+ }
+ }
+
+ SL_RETURN((0), _("tf_trust_check"));
+}
+#endif
+
+#ifdef HAVE_INITGROUPS
+#ifdef HOST_IS_OSF
+int sh_unix_initgroups ( char * in_user, gid_t in_gid)
+#else
+int sh_unix_initgroups (const char * in_user, gid_t in_gid)
+#endif
+{
+ int status = -1;
+ status = sh_initgroups (in_user, in_gid);
+ if (status < 0)
+ {
+ if (errno == EPERM)
+ return 0;
+ if (errno == EINVAL)
+ return 0;
+ return -1;
+ }
+ return 0;
+}
+#else
+int sh_unix_initgroups (const char * in_user, gid_t in_gid)
+{
+ (void) in_user;
+ (void) in_gid;
+ return 0;
+}
+#endif
+
+#ifdef HAVE_INITGROUPS
+char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
+int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid)
+{
+ int status = -1;
+ char user[SH_MINIBUF];
+
+ SL_ENTER(_("sh_unix_initgroups2"));
+
+ if (NULL == sh_unix_getUIDname (SH_ERR_ERR, in_pid, user, sizeof(user)))
+ SL_RETURN((-1), _("sh_unix_initgroups2"));
+ status = sh_initgroups (user, in_gid);
+ if (status < 0)
+ {
+ if (errno == EPERM)
+ status = 0;
+ if (errno == EINVAL)
+ status = 0;
+ }
+ SL_RETURN((status), _("sh_unix_initgroups2"));
+}
+#else
+int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid)
+{
+ (void) in_pid;
+ (void) in_gid;
+ return 0;
+}
+#endif
+
+void sh_unix_closeall (int fd, int except, int inchild)
+{
+ int fdx = fd;
+#ifdef _SC_OPEN_MAX
+ int fdlimit = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ int fdlimit = OPEN_MAX;
+#else
+ int fdlimit = _POSIX_OPEN_MAX;
+#endif
+#endif
+
+ SL_ENTER(_("sh_unix_closeall"));
+
+ /* can't happen - so fix it :-(
+ */
+ if (fdlimit < 0)
+ fdlimit = 20; /* POSIX lower limit */
+
+ if (fdlimit > 65536)
+ fdlimit = 65536;
+
+ if (!inchild)
+ sl_dropall (fdx, except);
+ else
+ sl_dropall_dirty (fdx, except);
+
+ /* Close everything from fd (inclusive) up to fdlimit (exclusive).
+ */
+ while (fd < fdlimit)
+ {
+ if (fd == except)
+ fd++;
+ else if (slib_do_trace != 0 && fd == slib_trace_fd)
+ fd++;
+ else
+ sl_close_fd(FIL__, __LINE__, fd++);
+ }
+
+ SL_RET0(_("sh_unix_closeall"));
+}
+
+static void sh_unix_setlimits(void)
+{
+ struct rlimit limits;
+
+ SL_ENTER(_("sh_unix_setlimits"));
+
+ limits.rlim_cur = RLIM_INFINITY;
+ limits.rlim_max = RLIM_INFINITY;
+
+#ifdef RLIMIT_CPU
+ setrlimit (RLIMIT_CPU, &limits);
+#endif
+#ifdef RLIMIT_FSIZE
+ setrlimit (RLIMIT_FSIZE, &limits);
+#endif
+#ifdef RLIMIT_DATA
+ setrlimit (RLIMIT_DATA, &limits);
+#endif
+#ifdef RLIMIT_STACK
+ setrlimit (RLIMIT_STACK, &limits);
+#endif
+#ifdef RLIMIT_RSS
+ setrlimit (RLIMIT_RSS, &limits);
+#endif
+#ifdef RLIMIT_NPROC
+ setrlimit (RLIMIT_NPROC, &limits);
+#endif
+#ifdef RLIMIT_MEMLOCK
+ setrlimit (RLIMIT_MEMLOCK, &limits);
+#endif
+
+#if !defined(SL_DEBUG)
+ /* no core dumps
+ */
+ limits.rlim_cur = 0;
+ limits.rlim_max = 0;
+#ifdef RLIMIT_CORE
+ setrlimit (RLIMIT_CORE, &limits);
+#endif
+#else
+#ifdef RLIMIT_CORE
+ setrlimit (RLIMIT_CORE, &limits);
+#endif
+#endif
+
+ limits.rlim_cur = 1024;
+ limits.rlim_max = 1024;
+
+#if defined(RLIMIT_NOFILE)
+ setrlimit (RLIMIT_NOFILE, &limits);
+#elif defined(RLIMIT_OFILE)
+ setrlimit (RLIMIT_OFILE, &limits);
+#endif
+
+ SL_RET0(_("sh_unix_setlimits"));
+}
+
+static void sh_unix_copyenv(void)
+{
+ char ** env0 = environ;
+ char ** env1;
+ int envlen = 0;
+ size_t len;
+
+ SL_ENTER(_("sh_unix_copyenv"));
+
+ while (env0 != NULL && env0[envlen] != NULL) {
+ /* printf("%2d: %s\n", envlen, env0[envlen]); */
+ ++envlen;
+ }
+ ++envlen;
+
+ /* printf("-> %2d: slots allocated\n", envlen); */
+ env1 = calloc(1,sizeof(char *) * envlen); /* only once */
+ if (env1 == NULL)
+ {
+ fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
+ SL_RET0(_("sh_unix_copyenv"));
+ }
+ env0 = environ;
+ envlen = 0;
+
+ while (env0 != NULL && env0[envlen] != NULL) {
+ len = strlen(env0[envlen]) + 1;
+ env1[envlen] = calloc(1,len); /* only once */
+ if (env1[envlen] == NULL)
+ {
+ int i;
+ fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
+ for (i = 0; i < envlen; ++i) free(env1[len]);
+ free(env1);
+ SL_RET0(_("sh_unix_copyenv"));
+ }
+ sl_strlcpy(env1[envlen], env0[envlen], len);
+ ++envlen;
+ }
+ env1[envlen] = NULL;
+
+ environ = env1;
+ SL_RET0(_("sh_unix_copyenv"));
+}
+
+/* delete all environment variables
+ */
+static void sh_unix_zeroenv(void)
+{
+ char * c;
+ char ** env;
+
+ SL_ENTER(_("sh_unix_zeroenv"));
+
+ sh_unix_copyenv();
+ env = environ;
+
+ while (env != NULL && *env != NULL) {
+ c = strchr ((*env), '=');
+#ifdef WITH_MYSQL
+ /*
+ * Skip the MYSQL_UNIX_PORT environment variable; MySQL may need it.
+ */
+ if (0 == sl_strncmp((*env), _("MYSQL_UNIX_PORT="), 16))
+ {
+ ++(env);
+ continue;
+ }
+ if (0 == sl_strncmp((*env), _("MYSQL_TCP_PORT="), 15))
+ {
+ ++(env);
+ continue;
+ }
+ if (0 == sl_strncmp((*env), _("MYSQL_HOME="), 11))
+ {
+ ++(env);
+ continue;
+ }
+#endif
+#ifdef WITH_ORACLE
+ /*
+ * Skip the ORACLE_HOME and TNS_ADMIN environment variables;
+ * Oracle may need them.
+ */
+ if (0 == sl_strncmp((*env), _("ORACLE_HOME="), 12))
+ {
+ ++(env);
+ continue;
+ }
+ if (0 == sl_strncmp((*env), _("TNS_ADMIN="), 10))
+ {
+ ++(env);
+ continue;
+ }
+#endif
+ /*
+ * Skip the TZ environment variable.
+ */
+ if (0 == sl_strncmp((*env), _("TZ="), 3))
+ {
+ ++(env);
+ continue;
+ }
+ ++(env);
+ if (c != NULL)
+ {
+ ++c;
+ while ((*c) != '\0') {
+ (*c) = '\0';
+ ++c;
+ }
+ }
+ }
+
+#ifdef HAVE_TZSET
+ tzset();
+#endif
+
+ SL_RET0(_("sh_unix_zeroenv"));
+}
+
+
+static void sh_unix_resettimer(void)
+{
+ struct itimerval this_timer;
+
+ SL_ENTER(_("sh_unix_resettimer"));
+
+ this_timer.it_value.tv_sec = 0;
+ this_timer.it_value.tv_usec = 0;
+
+ this_timer.it_interval.tv_sec = 0;
+ this_timer.it_interval.tv_usec = 0;
+
+ setitimer(ITIMER_REAL, &this_timer, NULL);
+#if !defined(SH_PROFILE)
+ setitimer(ITIMER_VIRTUAL, &this_timer, NULL);
+ setitimer(ITIMER_PROF, &this_timer, NULL);
+#endif
+
+ SL_RET0(_("sh_unix_resettimer"));
+}
+
+static void sh_unix_resetsignals(void)
+{
+ int sig_num;
+#ifdef NSIG
+ int max_sig = NSIG;
+#else
+ int max_sig = 255;
+#endif
+ int test;
+ int status;
+ struct sigaction act;
+#if !defined(SH_PROFILE)
+ struct sigaction oldact;
+#endif
+
+ sigset_t set_proc;
+
+ SL_ENTER(_("sh_unix_resetsignals"));
+ /*
+ * Reset the current signal mask (inherited from parent process).
+ */
+
+ sigfillset(&set_proc);
+
+ do {
+ errno = 0;
+ test = SH_SETSIGMASK(SIG_UNBLOCK, &set_proc, NULL);
+ } while (test < 0 && errno == EINTR);
+
+ /*
+ * Reset signal handling.
+ */
+
+ act.sa_handler = SIG_DFL; /* signal action */
+ sigemptyset( &act.sa_mask ); /* set an empty mask */
+ act.sa_flags = 0; /* init sa_flags */
+
+ for (sig_num = 1; sig_num <= max_sig; ++sig_num)
+ {
+#if !defined(SH_PROFILE)
+ test = retry_sigaction(FIL__, __LINE__, sig_num, &act, &oldact);
+#else
+ test = 0;
+#endif
+ if ((test == -1) && (errno != EINVAL))
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ status = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_SIG,
+ sh_error_message (status, errbuf, sizeof(errbuf)), sig_num);
+ }
+ }
+
+ SL_RET0(_("sh_unix_resetsignals"));
+}
+
+/* Get the local hostname (FQDN)
+ */
+static char * sh_tolower (char * s)
+{
+ char * ret = s;
+ if (s)
+ {
+ for (; *s; ++s)
+ {
+ *s = tolower((unsigned char) *s);
+ }
+ }
+ return ret;
+}
+
+
+#include <sys/socket.h>
+
+/* Required for BSD
+ */
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <arpa/inet.h>
+
+const char * sh_unix_h_name (struct hostent * host_entry)
+{
+ char ** p;
+ if (strchr(host_entry->h_name, '.')) {
+ return host_entry->h_name;
+ } else {
+ for (p = host_entry->h_aliases; *p; ++p) {
+ if (strchr(*p, '.'))
+ return *p;
+ }
+ }
+ return host_entry->h_name;
+}
+
+/* uname() on FreeBSD is broken, because the 'nodename' buf is too small
+ * to hold a valid (leftmost) domain label.
+ */
+#if defined(HAVE_UNAME) && !defined(HOST_IS_FREEBSD)
+#include <sys/utsname.h>
+void sh_unix_localhost()
+{
+ struct utsname buf;
+ int i;
+ unsigned int ddot;
+ int len;
+ char * p;
+ char hostname[256];
+ char numeric[SH_IP_BUF];
+ char * canonical;
+
+
+ SL_ENTER(_("sh_unix_localhost"));
+
+ (void) uname (&buf);
+ /* flawfinder: ignore */ /* ff bug, ff sees system() */
+ sl_strlcpy (sh.host.system, buf.sysname, SH_MINIBUF);
+ sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF);
+ sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF);
+
+ /* Workaround for cases where nodename could be
+ * a truncated FQDN.
+ */
+ if (strlen(buf.nodename) == (sizeof(buf.nodename)-1))
+ {
+ p = strchr(buf.nodename, '.');
+ if (NULL != p) {
+ *p = '\0';
+ sl_strlcpy(hostname, buf.nodename, 256);
+ } else {
+#ifdef HAVE_GETHOSTNAME
+ if (0 != gethostname(hostname, 256))
+ {
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("nodename returned by uname may be truncated"),
+ _("sh_unix_localhost"));
+ sl_strlcpy (hostname, buf.nodename, 256);
+ }
+ else
+ {
+ hostname[255] = '\0';
+ }
+#else
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("nodename returned by uname may be truncated"),
+ _("sh_unix_localhost"));
+ sl_strlcpy(hostname, buf.nodename, 256);
+#endif
+ }
+ }
+ else
+ {
+ sl_strlcpy(hostname, buf.nodename, 256);
+ }
+
+ canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric));
+
+ if (canonical == NULL)
+ {
+ sl_strlcpy (sh.host.name, hostname, SH_PATHBUF);
+ sh_tolower (sh.host.name);
+ }
+ else
+ {
+ sl_strlcpy (sh.host.name, canonical, SH_PATHBUF);
+ SH_FREE(canonical);
+ }
+
+ /* check whether it looks like a FQDN
+ */
+ len = sl_strlen(sh.host.name);
+ ddot = 0;
+ for (i = 0; i < len; ++i)
+ if (sh.host.name[i] == '.') ++ddot;
+
+ if (ddot == 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ sl_strlcpy (sh.host.name, numeric, SH_PATHBUF);
+ SL_RET0(_("sh_unix_localhost"));
+ }
+
+ if (sh_ipvx_is_numeric(sh.host.name))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ }
+
+ SL_RET0(_("sh_unix_localhost"));
+}
+
+#else
+
+/*
+ * --FreeBSD code
+ */
+#if defined(HAVE_UNAME)
+#include <sys/utsname.h>
+#endif
+void sh_unix_localhost()
+{
+#if defined(HAVE_UNAME)
+ struct utsname buf;
+#endif
+ int i;
+ int ddot;
+ int len;
+ char hostname[1024];
+ char numeric[SH_IP_BUF];
+ char * canonical;
+
+ SL_ENTER(_("sh_unix_localhost"));
+
+#if defined(HAVE_UNAME)
+ (void) uname (&buf);
+ /* flawfinder: ignore */ /* ff bug, ff sees system() */
+ sl_strlcpy (sh.host.system, buf.sysname, SH_MINIBUF);
+ sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF);
+ sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF);
+#endif
+
+ (void) gethostname (hostname, 1024);
+ hostname[1023] = '\0';
+
+ canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric));
+
+ if (canonical == NULL)
+ {
+ sl_strlcpy (sh.host.name, hostname, SH_PATHBUF);
+ sh_tolower (sh.host.name);
+ }
+ else
+ {
+ sl_strlcpy (sh.host.name, canonical, SH_PATHBUF);
+ SH_FREE(canonical);
+ }
+
+ /* check whether it looks like a FQDN
+ */
+ len = sl_strlen(sh.host.name);
+ ddot = 0;
+ for (i = 0; i < len; ++i)
+ if (sh.host.name[i] == '.') ++ddot;
+ if (ddot == 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ sl_strlcpy (sh.host.name, numeric, SH_PATHBUF);
+ SL_RET0(_("sh_unix_localhost"));
+ }
+
+ if (sh_ipvx_is_numeric(sh.host.name))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ }
+
+ SL_RET0(_("sh_unix_localhost"));
+}
+#endif
+
+
+void sh_unix_memlock()
+{
+ SL_ENTER(_("sh_unix_memlock"));
+
+ /* do this before dropping privileges
+ */
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ if (skey->mlock_failed == S_FALSE)
+ {
+ if ( (-1) == sh_unix_mlock( FIL__, __LINE__,
+ (char *) skey, sizeof (sh_key_t)) )
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ skey->mlock_failed = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+ }
+#else
+ if (skey->mlock_failed == S_FALSE)
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ skey->mlock_failed = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+#endif
+
+ SL_RET0(_("sh_unix_memlock"));
+}
+
+#ifdef SH_WITH_SERVER
+char * chroot_dir = NULL;
+
+int sh_unix_set_chroot(const char * str)
+{
+ size_t len;
+ static int block = 0;
+
+ if (block == 1)
+ return 0;
+
+ if (str && *str == '/')
+ {
+ len = strlen(str) + 1;
+ chroot_dir = calloc(1,strlen(str) + 1); /* only once */
+ if (!chroot_dir)
+ {
+ fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
+ return 1;
+ }
+ sl_strlcpy(chroot_dir, str, len);
+ block = 1;
+ return 0;
+ }
+ return 1;
+}
+
+int sh_unix_chroot(void)
+{
+ int status;
+
+ if (chroot_dir != NULL)
+ {
+ status = retry_aud_chdir(FIL__, __LINE__, chroot_dir);
+ if ( (-1) == status )
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ status = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR,
+ sh_error_message (status, errbuf, sizeof(errbuf)), chroot_dir);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ /* flawfinder: ignore */
+ return (chroot(chroot_dir));
+ }
+ return 0;
+}
+/* #ifdef SH_WITH_SERVER */
+#else
+int sh_unix_chroot(void) { return 0; }
+#endif
+
+/* daemon mode
+ */
+static int block_setdeamon = 0;
+
+int sh_unix_setdeamon(const char * dummy)
+{
+ int res = 0;
+
+ SL_ENTER(_("sh_unix_setdeamon"));
+
+ if (block_setdeamon != 0)
+ SL_RETURN((0),_("sh_unix_setdeamon"));
+
+ if (dummy == NULL)
+ sh.flag.isdaemon = S_TRUE;
+ else
+ res = sh_util_flagval (dummy, &sh.flag.isdaemon);
+
+ if (sh.flag.opts == S_TRUE)
+ block_setdeamon = 1;
+
+ SL_RETURN(res, _("sh_unix_setdeamon"));
+}
+#if defined(HAVE_LIBPRELUDE)
+#include "sh_prelude.h"
+#endif
+
+int sh_unix_setnodeamon(const char * dummy)
+{
+ int res = 0;
+
+ SL_ENTER(_("sh_unix_setnodeamon"));
+
+ if (block_setdeamon != 0)
+ SL_RETURN((0),_("sh_unix_setmodeamon"));
+
+ if (dummy == NULL)
+ sh.flag.isdaemon = S_FALSE;
+ else
+ res = sh_util_flagval (dummy, &sh.flag.isdaemon);
+
+ if (sh.flag.opts == S_TRUE)
+ block_setdeamon = 1;
+
+ SL_RETURN(res, _("sh_unix_setnodeamon"));
+}
+
+int sh_unix_init(int goDaemon)
+{
+ int status;
+ uid_t uid;
+ pid_t oldpid = getpid();
+#if defined(SH_WITH_SERVER)
+ extern int sh_socket_open_int (void);
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+
+ extern void sh_kill_sub();
+
+ SL_ENTER(_("sh_unix_init"));
+
+ /* fork twice, exit the parent process
+ */
+ if (goDaemon == 1) {
+
+ switch (aud_fork(FIL__, __LINE__)) {
+ case 0: break; /* child process continues */
+ case -1: SL_RETURN((-1),_("sh_unix_init")); /* error */
+ default: /* parent process exits */
+ sh_kill_sub();
+ aud__exit(FIL__, __LINE__, 0);
+ }
+
+ /* Child processes do not inherit page locks across a fork.
+ * Error in next fork would return in this (?) thread of execution.
+ */
+ sh_unix_memlock();
+
+ setsid(); /* should not fail */
+ sh.pid = (UINT64) getpid();
+
+ switch (aud_fork(FIL__, __LINE__)) {
+ case 0: break; /* child process continues */
+ case -1: SL_RETURN((-1),_("sh_unix_init")); /* error */
+ default: /* parent process exits */
+ sh_kill_sub();
+ aud__exit(FIL__, __LINE__, 0);
+ }
+
+ /* Child processes do not inherit page locks across a fork.
+ */
+ sh_unix_memlock();
+ sh.pid = (UINT64) getpid();
+
+ } else {
+ setsid(); /* should not fail */
+ }
+
+ /* set working directory
+ */
+#ifdef SH_PROFILE
+ status = 0;
+#else
+ status = retry_aud_chdir(FIL__, __LINE__, "/");
+#endif
+ if ( (-1) == status )
+ {
+ status = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR,
+ sh_error_message (status, errbuf, sizeof(errbuf)), "/");
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* reset timers
+ */
+ sh_unix_resettimer();
+
+ /* signal handlers
+ */
+ sh_unix_resetsignals();
+#if defined(SCREW_IT_UP)
+ sh_sigtrap_prepare();
+#endif
+ sh_unix_siginstall (goDaemon);
+
+ /* set file creation mask
+ */
+ (void) umask (0); /* should not fail */
+
+ /* set resource limits to maximum, and
+ * core dump size to zero
+ */
+ sh_unix_setlimits();
+
+ /* zero out the environment (like PATH='\0')
+ */
+ sh_unix_zeroenv();
+
+ if (goDaemon == 1)
+ {
+ /* Close first tree file descriptors
+ */
+ sl_close_fd (FIL__, __LINE__, 0); /* if running as daemon */
+ sl_close_fd (FIL__, __LINE__, 1); /* if running as daemon */
+ sl_close_fd (FIL__, __LINE__, 2); /* if running as daemon */
+
+ /* Enable full error logging
+ */
+ sh_error_only_stderr (S_FALSE);
+
+ /* open first three streams to /dev/null
+ */
+ status = aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 0);
+ if (status < 0)
+ {
+ status = errno;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ sh_error_message(status, errbuf, sizeof(errbuf)), _("open"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ status = retry_aud_dup(FIL__, __LINE__, 0);
+ if (status >= 0)
+ retry_aud_dup(FIL__, __LINE__, 0);
+
+ if (status < 0)
+ {
+ status = errno;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ sh_error_message(status, errbuf, sizeof(errbuf)), _("dup"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ sh_error_enable_unsafe (S_TRUE);
+#if defined(HAVE_LIBPRELUDE)
+ sh_prelude_reset ();
+#endif
+
+ /* --- wait until parent has exited ---
+ */
+ while (1 == 1)
+ {
+ errno = 0;
+ if (0 > aud_kill (FIL__, __LINE__, oldpid, 0) && errno == ESRCH)
+ {
+ break;
+ }
+ retry_msleep(0, 1);
+ }
+
+ /* write PID file
+ */
+ status = sh_unix_write_pid_file();
+ if (status < 0)
+ {
+ sl_get_euid(&uid);
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_PIDFILE,
+ (long) uid, sh.srvlog.alt);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+#if defined(SH_WITH_SERVER)
+ sh_socket_open_int ();
+#endif
+ }
+ else
+ {
+ sh_error_enable_unsafe (S_TRUE);
+#if defined(HAVE_LIBPRELUDE)
+ sh_prelude_reset ();
+#endif
+#if defined(SH_WITH_SERVER)
+ sh_socket_open_int ();
+#endif
+ }
+
+ /* chroot (this is a no-op if no chroot dir is specified
+ */
+ status = sh_unix_chroot();
+ if (status < 0)
+ {
+ status = errno;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ sh_error_message(status, errbuf, sizeof(errbuf)), _("chroot"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* drop capabilities
+ */
+ sl_drop_cap();
+
+ SL_RETURN((0),_("sh_unix_init"));
+}
+
+/* --- run a command, securely --- */
+
+int sh_unix_run_command (const char * str)
+{
+ pid_t pid;
+ char * arg[4];
+ char * env[5];
+ char * path = sh_util_strdup(_("/bin/sh"));
+
+ int status = -1;
+
+ arg[0] = sh_util_strdup(_("/bin/sh"));
+ arg[1] = sh_util_strdup(_("-c"));
+ arg[2] = sh_util_strdup(str);
+ arg[3] = NULL;
+
+ env[0] = sh_util_strdup(_("PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb"));
+ env[1] = sh_util_strdup(_("SHELL=/bin/sh"));
+ env[2] = sh_util_strdup(_("IFS= \t\n"));
+ if (getenv("TZ")) { /* flawfinder: ignore */
+ char * tz = sh_util_strdup(getenv("TZ")); /* flawfinder: ignore */
+ size_t tzlen = strlen(tz);
+ if (S_TRUE == sl_ok_adds (4, tzlen)) {
+ env[3] = SH_ALLOC(4+tzlen);
+ sl_strlcpy(env[3], "TZ=", 4);
+ sl_strlcat(env[3], tz , 4+tzlen);
+ } else {
+ env[3] = NULL;
+ }
+ } else {
+ env[3] = NULL;
+ }
+ env[4] = NULL;
+
+ pid = fork();
+
+ if (pid == (pid_t)(-1))
+ {
+ return -1;
+ }
+
+ else if (pid == 0) /* child */
+ {
+ memset(skey, 0, sizeof(sh_key_t));
+ (void) umask(S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
+ sh_unix_closeall (3, -1, S_TRUE); /* in child process */
+ execve(path, arg, env);
+ _exit(EXIT_FAILURE);
+ }
+
+ else /* parent */
+ {
+ int r;
+
+ while((r = waitpid(pid, &status, WUNTRACED)) != pid && r != -1) ;
+
+#if !defined(USE_UNO)
+ if (r == -1 || !WIFEXITED(status))
+ {
+ status = -1;
+ }
+ else
+ {
+ status = WEXITSTATUS(status);
+ }
+#endif
+ }
+
+ return status;
+}
+
+/********************************************************
+ *
+ * TIME
+ *
+ ********************************************************/
+
+/* Figure out the time offset of the current timezone
+ * in a portable way.
+ */
+char * t_zone(const time_t * xx)
+{
+ struct tm aa;
+ struct tm bb;
+
+ struct tm * aptr;
+ struct tm * bptr;
+
+ int sign = 0;
+ int diff = 0;
+ int hh, mm;
+ static char tz[64];
+
+ SL_ENTER(_("t_zone"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
+ aptr = gmtime_r (xx, &aa);
+#else
+ aptr = gmtime(xx);
+ if (aptr)
+ memcpy (&aa, aptr, sizeof(struct tm));
+#endif
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ bptr = localtime_r (xx, &bb);
+#else
+ bptr = localtime(xx);
+ if (bptr)
+ memcpy (&bb, bptr, sizeof(struct tm));
+#endif
+
+ if (bptr && aptr)
+ {
+ /* Check for datum wrap-around.
+ */
+ if ((aa.tm_mday == 1) && (aa.tm_mday < bb.tm_mday) && (aa.tm_hour < bb.tm_hour))
+ sign = ( 1);
+ else if (aa.tm_year < bb.tm_year)
+ sign = (-1);
+ else if (aa.tm_mon < bb.tm_mon)
+ sign = (-1);
+ else if (aa.tm_mday < bb.tm_mday)
+ sign = (-1);
+ else if (bb.tm_year < aa.tm_year)
+ sign = ( 1);
+ else if (bb.tm_mon < aa.tm_mon)
+ sign = ( 1);
+ else if (bb.tm_mday < aa.tm_mday)
+ sign = ( 1);
+
+ diff = aa.tm_hour * 60 + aa.tm_min;
+ diff = (bb.tm_hour * 60 + bb.tm_min) - diff;
+ diff = diff - (sign * 24 * 60); /* datum wrap-around correction */
+ hh = diff / 60;
+ mm = diff - (hh * 60);
+ sprintf (tz, _("%+03d%02d"), hh, mm); /* known to fit */
+ }
+ else
+ {
+ sprintf (tz, _("%+03d%02d"), 0, 0);
+ }
+ SL_RETURN(tz, _("t_zone"));
+}
+
+unsigned long sh_unix_longtime ()
+{
+ return ((unsigned long)time(NULL));
+}
+
+#ifdef HAVE_GETTIMEOFDAY
+unsigned long sh_unix_notime ()
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ return ((unsigned long)(tv.tv_sec + tv.tv_usec * 10835 + getpid() + getppid()));
+
+}
+#endif
+
+static int count_dev_time = 0;
+
+void reset_count_dev_time(void)
+{
+ count_dev_time = 0;
+ return;
+}
+
+int sh_unix_settimeserver (const char * address)
+{
+
+ SL_ENTER(_("sh_unix_settimeserver"));
+
+ if (address != NULL && count_dev_time < 2
+ && sl_strlen(address) < SH_PATHBUF)
+ {
+ if (count_dev_time == 0)
+ sl_strlcpy (sh.srvtime.name, address, SH_PATHBUF);
+ else
+ sl_strlcpy (sh.srvtime.alt, address, SH_PATHBUF);
+
+ ++count_dev_time;
+ SL_RETURN((0), _("sh_unix_settimeserver"));
+ }
+ SL_RETURN((-1), _("sh_unix_settimeserver"));
+}
+
+
+#ifdef HAVE_NTIME
+#define UNIXEPOCH 2208988800UL /* difference between Unix time and net time
+ * The UNIX EPOCH starts in 1970.
+ */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#endif
+
+/* Timeserver service. */
+/* define is missing on HP-UX 10.20 */
+#ifndef IPPORT_TIMESERVER
+#define IPPORT_TIMESERVER 37
+#endif
+
+char * sh_unix_time (time_t thetime, char * buffer, size_t len)
+{
+
+ int status;
+ char AsciiTime[81]; /* local time */
+ time_t time_now;
+ struct tm * time_ptr;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ struct tm time_tm;
+#endif
+#ifdef SH_USE_XML
+ static char deftime[] = N_("0000-00-00T00:00:00"); /* default time */
+#else
+ static char deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */
+#endif
+
+#ifdef HAVE_NTIME
+ int fd; /* network file descriptor */
+ u_char net_time[4]; /* remote time in network format */
+ static int failerr = 0; /* no net time */
+ int fail = 0; /* no net time */
+ int errflag;
+ char errmsg[256];
+ char error_call[SH_MINIBUF];
+ int error_num;
+#endif
+
+ SL_ENTER(_("sh_unix_time"));
+
+#ifdef HAVE_NTIME
+ if (thetime == 0)
+ {
+ if (sh.srvtime.name[0] == '\0')
+ {
+ fail = 1;
+ (void) time (&time_now);
+ }
+ else /* have a timeserver address */
+ {
+ /* don't call timeserver more than once per second */
+ static time_t time_old = 0;
+ time_t time_new;
+ static time_t time_saved = 0;
+ (void) time (&time_new);
+ if ((time_new == time_old) && (time_saved != 0))
+ {
+ time_now = time_saved;
+ goto end;
+ }
+ time_old = time_new;
+
+
+ fd = connect_port_2 (sh.srvtime.name, sh.srvtime.alt,
+ IPPORT_TIMESERVER,
+ error_call, &error_num, errmsg, sizeof(errmsg));
+ if (fd >= 0)
+ {
+ if (4 != read_port (fd, (char *) net_time, 4, &errflag, 2))
+ {
+ fail = 1;
+ sh_error_handle ((-1), FIL__, __LINE__, errflag,
+ MSG_E_NLOST,
+ _("time"), sh.srvtime.name);
+ }
+ sl_close_fd(FIL__, __LINE__, fd);
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, error_num,
+ MSG_E_NET, errmsg, error_call,
+ _("time"), sh.srvtime.name);
+ fail = 1;
+ }
+
+ if (fail == 0)
+ {
+ unsigned long ltmp;
+ UINT32 ttmp;
+ memcpy(&ttmp, net_time, sizeof(UINT32)); ltmp = ttmp;
+ time_now = ntohl(ltmp) - UNIXEPOCH;
+ time_saved = time_now;
+
+ if (failerr == 1) {
+ failerr = 0;
+ sh_error_handle ((-1), FIL__, __LINE__, 0,
+ MSG_E_NEST,
+ _("time"), sh.srvtime.name);
+ }
+ }
+ else
+ {
+ (void) time (&time_now);
+ time_saved = 0;
+
+ if (failerr == 0)
+ {
+ failerr = 1;
+ sh_error_handle ((-1), FIL__, __LINE__, errflag,
+ MSG_SRV_FAIL,
+ _("time"), sh.srvtime.name);
+ }
+ }
+ end:
+ ; /* 'label at end of compound statement' */
+ }
+ }
+ else
+ {
+ time_now = thetime;
+ }
+
+ /* #ifdef HAVE_NTIME */
+#else
+
+ if (thetime == 0)
+ {
+ (void) time (&time_now);
+ }
+ else
+ {
+ time_now = thetime;
+ }
+
+ /* #ifdef HAVE_NTIME */
+#endif
+
+ if (time_now == (-1) )
+ {
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN(buffer, _("sh_unix_time"));
+ }
+ else
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&time_now, &time_tm);
+#else
+ time_ptr = localtime (&time_now);
+#endif
+ }
+ if (time_ptr != NULL)
+ {
+ status = strftime (AsciiTime, sizeof(AsciiTime),
+#ifdef SH_USE_XML
+ _("%Y-%m-%dT%H:%M:%S%%s"),
+#else
+ _("[%Y-%m-%dT%H:%M:%S%%s]"),
+#endif
+ time_ptr);
+
+ sl_snprintf(buffer, len, AsciiTime, t_zone(&time_now));
+
+ if ( (status == 0) || (status == sizeof(AsciiTime)) )
+ {
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN( buffer, _("sh_unix_time"));
+ }
+ else
+ {
+ SL_RETURN(buffer, _("sh_unix_time"));
+ }
+ }
+
+ /* last resort
+ */
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN( buffer, _("sh_unix_time"));
+}
+
+static int sh_unix_use_localtime = S_FALSE;
+
+/* whether to use localtime for file timestamps in logs
+ */
+int sh_unix_uselocaltime (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_unix_uselocaltime"));
+ i = sh_util_flagval(c, &(sh_unix_use_localtime));
+
+ SL_RETURN(i, _("sh_unix_uselocaltime"));
+}
+
+char * sh_unix_gmttime (time_t thetime, char * buffer, size_t len)
+{
+
+ int status;
+
+ struct tm * time_ptr;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
+ struct tm time_tm;
+#endif
+ char AsciiTime[81]; /* GMT time */
+#ifdef SH_USE_XML
+ static char deftime[] = N_("0000-00-00T00:00:00"); /* default time */
+#else
+ static char deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */
+#endif
+
+ SL_ENTER(_("sh_unix_gmttime"));
+
+ if (sh_unix_use_localtime == S_FALSE)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
+ time_ptr = gmtime_r (&thetime, &time_tm);
+#else
+ time_ptr = gmtime (&thetime);
+#endif
+ }
+ else
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&thetime, &time_tm);
+#else
+ time_ptr = localtime (&thetime);
+#endif
+ }
+ if (time_ptr != NULL)
+ {
+ status = strftime (AsciiTime, 80,
+#ifdef SH_USE_XML
+ _("%Y-%m-%dT%H:%M:%S"),
+#else
+ _("[%Y-%m-%dT%H:%M:%S]"),
+#endif
+ time_ptr);
+
+ if ( (status == 0) || (status == 80) )
+ sl_strlcpy(buffer, _(deftime), len);
+ else
+ sl_strlcpy(buffer, AsciiTime, len);
+ SL_RETURN( buffer, _("sh_unix_gmttime"));
+ }
+
+ /* last resort
+ */
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN( buffer, _("sh_unix_gmttime"));
+}
+
+
+char * sh_unix_getUIDdir (int level, uid_t uid, char * out, size_t len)
+{
+ struct passwd * tempres;
+ int status = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_unix_getUIDdir"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ errno = 0;
+ tempres = sh_getpwuid(uid);
+ status = errno;
+#endif
+
+ if (tempres == NULL) {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("completely missing"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( NULL, _("sh_unix_getUIDdir"));
+ }
+
+ if (tempres->pw_dir != NULL) {
+ sl_strlcpy(out, tempres->pw_dir, len);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( out, _("sh_unix_getUIDdir"));
+ } else {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("pw_dir"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( NULL, _("sh_unix_getUIDdir"));
+ }
+}
+
+/* ------------------- Caching ----------------*/
+#include "zAVLTree.h"
+
+#define CACHE_GID 0
+#define CACHE_UID 1
+
+struct user_id {
+ char * name;
+ uid_t id;
+ struct user_id * next;
+};
+
+static struct user_id * uid_list = NULL;
+static struct user_id * gid_list = NULL;
+
+SH_MUTEX_STATIC(mutex_cache, PTHREAD_MUTEX_INITIALIZER);
+
+static void sh_userid_free(struct user_id * item)
+{
+ while (item)
+ {
+ struct user_id * user = item;
+ item = item->next;
+
+ SH_FREE(user->name);
+ SH_FREE(user);
+ }
+ return;
+}
+
+void sh_userid_destroy ()
+{
+ struct user_id * tmp_uid;
+ struct user_id * tmp_gid;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_cache);
+ tmp_gid = gid_list;
+ gid_list = NULL;
+ tmp_uid = uid_list;
+ uid_list = NULL;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_cache);
+
+ sh_userid_free(tmp_uid);
+ sh_userid_free(tmp_gid);
+ return;
+}
+
+static void sh_userid_additem(struct user_id * list, struct user_id * item)
+{
+ if (list)
+ {
+ while (list && list->next)
+ list = list->next;
+ list->next = item;
+ }
+ return;
+}
+
+static void sh_userid_add(uid_t id, char * username, int which)
+{
+ size_t len;
+ struct user_id * user = SH_ALLOC(sizeof(struct user_id));
+
+ if (username)
+ len = strlen(username) + 1;
+ else
+ len = 1;
+
+ user->name = SH_ALLOC(len);
+ user->id = id;
+ if (username)
+ sl_strlcpy(user->name, username, len);
+ else
+ user->name[0] = '\0';
+ user->next = NULL;
+
+ SH_MUTEX_LOCK(mutex_cache);
+ if (which == CACHE_UID)
+ {
+ if (!uid_list)
+ uid_list = user;
+ else
+ sh_userid_additem(uid_list, user);
+ }
+ else
+ {
+ if (!gid_list)
+ gid_list = user;
+ else
+ sh_userid_additem(gid_list, user);
+ }
+ SH_MUTEX_UNLOCK(mutex_cache);
+
+ return;
+}
+
+static char * sh_userid_search(struct user_id * list, uid_t id)
+{
+ while (list)
+ {
+ if (list->id == id)
+ return list->name;
+ list = list->next;
+ }
+ return NULL;
+}
+
+static char * sh_userid_get (uid_t id, int which, char * out, size_t len)
+{
+ char * user = NULL;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_cache);
+ if (which == CACHE_UID)
+ user = sh_userid_search(uid_list, id);
+ else
+ user = sh_userid_search(gid_list, id);
+ if (user)
+ {
+ sl_strlcpy(out, user, len);
+ user = out;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_cache);
+
+ return user;
+}
+
+/* --------- end caching code --------- */
+
+char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len)
+{
+ struct passwd * tempres;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+ int status = 0;
+ char errbuf[SH_ERRBUF_SIZE];
+ char * tmp;
+
+ SL_ENTER(_("sh_unix_getUIDname"));
+
+ tmp = sh_userid_get(uid, CACHE_UID, out, len);
+
+ if (tmp)
+ {
+ if (tmp[0] != '\0')
+ {
+ SL_RETURN( out, _("sh_unix_getUIDname"));
+ }
+ else
+ {
+ SL_RETURN( NULL, _("sh_unix_getUIDname"));
+ }
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ errno = 0;
+ tempres = sh_getpwuid(uid);
+ status = errno;
+#endif
+
+ if (tempres == NULL)
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("completely missing"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ sh_userid_add(uid, NULL, CACHE_UID);
+ SL_RETURN( NULL, _("sh_unix_getUIDname"));
+ }
+
+
+ if (tempres->pw_name != NULL)
+ {
+
+ sl_strlcpy(out, tempres->pw_name, len);
+ sh_userid_add(uid, out, CACHE_UID);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN( out, _("sh_unix_getUIDname"));
+ }
+ else
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("pw_user"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( NULL, _("sh_unix_getUIDname"));
+ }
+ /* notreached */
+}
+
+char * sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len)
+{
+ struct group * tempres;
+ int status = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ struct group grp;
+ char * buffer;
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+ char * tmp;
+
+ SL_ENTER(_("sh_unix_getGIDname"));
+
+ tmp = sh_userid_get((uid_t)gid, CACHE_GID, out, len);
+
+ if (tmp)
+ {
+ if (tmp[0] != '\0')
+ {
+ SL_RETURN( out, _("sh_unix_getGIDname"));
+ }
+ else
+ {
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ buffer = SH_ALLOC(SH_GRBUF_SIZE);
+ status = sh_getgrgid_r(gid, &grp, buffer, SH_GRBUF_SIZE, &tempres);
+#else
+ errno = 0;
+ tempres = sh_getgrgid(gid);
+ status = errno;
+#endif
+
+ if (status == ERANGE)
+ {
+ static int seen = 0;
+
+ if (seen == 0)
+ {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getgrgid"), (long) gid, _("line too long in group entry"));
+ ++seen;
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ sh_userid_add(gid, NULL, CACHE_GID);
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+
+ if (tempres == NULL)
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getgrgid"), (long) gid, _("completely missing"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ sh_userid_add(gid, NULL, CACHE_GID);
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+
+ if (tempres->gr_name != NULL)
+ {
+
+ sl_strlcpy(out, tempres->gr_name, len);
+ sh_userid_add((uid_t)gid, out, CACHE_GID);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN( out, _("sh_unix_getGIDname"));
+ }
+ else
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getgrgid"), (long) gid, _("gr_name"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+ /* notreached */
+}
+
+int sh_unix_getUser ()
+{
+ char * p;
+ uid_t seuid, sruid;
+ char user[USER_MAX];
+ char dir[SH_PATHBUF];
+
+ SL_ENTER(_("sh_unix_getUser"));
+
+ seuid = geteuid();
+
+ sh.effective.uid = seuid;
+
+ p = sh_unix_getUIDdir (SH_ERR_ERR, seuid, dir, sizeof(dir));
+
+ if (p == NULL)
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ else
+ {
+ if (sl_strlen(p) >= SH_PATHBUF) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
+ _("getpwuid"), (long) seuid, _("pw_home"));
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ } else {
+ sl_strlcpy ( sh.effective.home, p, SH_PATHBUF);
+ }
+ }
+
+ sruid = getuid();
+
+ sh.real.uid = sruid;
+
+ p = sh_unix_getUIDname (SH_ERR_ERR, sruid, user, sizeof(user));
+ if (p == NULL)
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ else
+ {
+ if (sl_strlen(p) >= USER_MAX) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
+ _("getpwuid"), (long) sruid, _("pw_user"));
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ } else {
+ sl_strlcpy ( sh.real.user, p, USER_MAX);
+ }
+ }
+
+ p = sh_unix_getUIDdir (SH_ERR_ERR, sruid, dir, sizeof(dir));
+
+ if (p == NULL)
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ else
+ {
+ if (sl_strlen(p) >= SH_PATHBUF) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
+ _("getpwuid"), (long) sruid, _("pw_home"));
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ } else {
+ sl_strlcpy ( sh.real.home, p, SH_PATHBUF);
+ }
+ }
+
+ SL_RETURN((0), _("sh_unix_getUser"));
+
+ /* notreached */
+}
+
+
+int sh_unix_getline (SL_TICKET fd, char * line, int sizeofline)
+{
+ register int count;
+ register int n = 0;
+ char c;
+
+ SL_ENTER(_("sh_unix_getline"));
+
+ if (sizeofline < 2) {
+ line[0] = '\0';
+ SL_RETURN((0), _("sh_unix_getline"));
+ }
+
+ --sizeofline;
+
+ while (n < sizeofline) {
+
+ count = sl_read (fd, &c, 1);
+
+ /* end of file
+ */
+ if (count < 1) {
+ line[n] = '\0';
+ n = -1;
+ break;
+ }
+
+ if (/* c != '\0' && */ c != '\n') {
+ line[n] = c;
+ ++n;
+ } else if (c == '\n') {
+ if (n > 0) {
+ line[n] = '\0';
+ break;
+ } else {
+ line[n] = '\n'; /* get newline only if only char on line */
+ ++n;
+ line[n] = '\0';
+ break;
+ }
+ } else {
+ line[n] = '\0';
+ break;
+ }
+
+ }
+
+
+ line[sizeofline] = '\0'; /* make sure line is terminated */
+ SL_RETURN((n), _("sh_unix_getline"));
+}
+
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+/**************************************************************
+ *
+ * --- FILE INFO ---
+ *
+ **************************************************************/
+
+#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS)
+
+#if defined(__linux__)
+
+/* --- Determine ext2fs file attributes. ---
+ */
+#include <sys/ioctl.h>
+#if defined(HAVE_EXT2FS_EXT2_FS_H)
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+
+/* __linux__ includes */
+#endif
+
+static
+int sh_unix_getinfo_attr (char * name,
+ unsigned long * flags,
+ char * c_attr,
+ int fd, struct stat * buf)
+{
+
+/* TAKEN FROM:
+ *
+ * lsattr.c - List file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+#ifdef HAVE_STAT_FLAGS
+
+ SL_ENTER(_("sh_unix_getinfo_attr"));
+
+ *flags = 0;
+
+ /* cast to void to avoid compiler warning about unused parameters */
+ (void) fd;
+ (void) name;
+
+#ifdef UF_NODUMP
+ if (buf->st_flags & UF_NODUMP) {
+ *flags |= UF_NODUMP;
+ c_attr[0] = 'd';
+ }
+#endif
+#ifdef UF_IMMUTABLE
+ if (buf->st_flags & UF_IMMUTABLE) {
+ *flags |= UF_IMMUTABLE;
+ c_attr[1] = 'i';
+ }
+#endif
+#ifdef UF_APPEND
+ if (buf->st_flags & UF_APPEND) {
+ *flags |= UF_APPEND;
+ c_attr[2] = 'a';
+ }
+#endif
+#ifdef UF_NOUNLINK
+ if (buf->st_flags & UF_NOUNLINK) {
+ *flags |= UF_NOUNLINK;
+ c_attr[3] = 'u';
+ }
+#endif
+#ifdef UF_OPAQUE
+ if (buf->st_flags & UF_OPAQUE) {
+ *flags |= UF_OPAQUE;
+ c_attr[4] = 'o';
+ }
+#endif
+#ifdef SF_ARCHIVED
+ if (buf->st_flags & SF_ARCHIVED) {
+ *flags |= SF_ARCHIVED;
+ c_attr[5] = 'R';
+ }
+
+#endif
+#ifdef SF_IMMUTABLE
+ if (buf->st_flags & SF_IMMUTABLE) {
+ *flags |= SF_IMMUTABLE;
+ c_attr[6] = 'I';
+ }
+#endif
+#ifdef SF_APPEND
+ if (buf->st_flags & SF_APPEND) {
+ *flags |= SF_APPEND;
+ c_attr[7] = 'A';
+ }
+#endif
+#ifdef SF_NOUNLINK
+ if (buf->st_flags & SF_NOUNLINK) {
+ *flags |= SF_NOUNLINK;
+ c_attr[8] = 'U';
+ }
+#endif
+
+ /* ! HAVE_STAT_FLAGS */
+#else
+
+#ifdef HAVE_EXT2_IOCTLS
+ int /* fd, */ r, f;
+
+ SL_ENTER(_("sh_unix_getinfo_attr"));
+
+ *flags = 0;
+ (void) buf;
+
+ /* open() -> aud_open() R.Wichmann
+ fd = aud_open (FIL__, __LINE__, SL_YESPRIV, name, O_RDONLY|O_NONBLOCK, 0);
+ */
+
+ if (fd == -1 || name == NULL)
+ SL_RETURN(-1, _("sh_unix_getinfo_attr"));
+
+
+ r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);
+ /* sl_close_fd (FIL__, __LINE__, fd); */
+
+ if (r == -1)
+ SL_RETURN(-1, _("sh_unix_getinfo_attr"));
+
+ if (f == 0)
+ SL_RETURN(0, _("sh_unix_getinfo_attr"));
+
+ *flags = f;
+
+/* ! HAVE_EXT2_IOCTLS */
+#else
+
+ SL_ENTER(_("sh_unix_getinfo_attr"));
+
+ *flags = 0; /* modified by R.Wichmann */
+
+/* ! HAVE_EXT2_IOCTLS */
+#endif
+/*
+ * END
+ *
+ * lsattr.c - List file attributes on an ext2 file system
+ */
+
+ if (*flags == 0)
+ goto theend;
+
+#ifdef EXT2_SECRM_FL
+ if ( (*flags & EXT2_SECRM_FL) != 0 ) c_attr[0] = 's';
+#endif
+#ifdef EXT2_UNRM_FL
+ if ( (*flags & EXT2_UNRM_FL) != 0 ) c_attr[1] = 'u';
+#endif
+#ifdef EXT2_SYNC_FL
+ if ( (*flags & EXT2_SYNC_FL) != 0 ) c_attr[2] = 'S';
+#endif
+#ifdef EXT2_IMMUTABLE_FL
+ if ( (*flags & EXT2_IMMUTABLE_FL) != 0) c_attr[3] = 'i';
+#endif
+#ifdef EXT2_APPEND_FL
+ if ( (*flags & EXT2_APPEND_FL) != 0 ) c_attr[4] = 'a';
+#endif
+#ifdef EXT2_NODUMP_FL
+ if ( (*flags & EXT2_NODUMP_FL) != 0 ) c_attr[5] = 'd';
+#endif
+#ifdef EXT2_NOATIME_FL
+ if ( (*flags & EXT2_NOATIME_FL) != 0) c_attr[6] = 'A';
+#endif
+#ifdef EXT2_COMPR_FL
+ if ( (*flags & EXT2_COMPR_FL) != 0 ) c_attr[7] = 'c';
+#endif
+
+#ifdef EXT2_TOPDIR_FL
+ if ( (*flags & EXT2_TOPDIR_FL) != 0 ) c_attr[8] = 'T';
+#endif
+#ifdef EXT2_DIRSYNC_FL
+ if ( (*flags & EXT2_DIRSYNC_FL) != 0 ) c_attr[9] = 'D';
+#endif
+#ifdef EXT2_NOTAIL_FL
+ if ( (*flags & EXT2_NOTAIL_FL) != 0 ) c_attr[10] = 't';
+#endif
+#ifdef EXT2_JOURNAL_DATA_FL
+ if ( (*flags & EXT2_JOURNAL_DATA_FL) != 0) c_attr[11] = 'j';
+#endif
+
+ theend:
+ /* ext2 */
+#endif
+
+ c_attr[12] = '\0';
+
+ SL_RETURN(0, _("sh_unix_getinfo_attr"));
+}
+
+/* defined(__linux__) || defined(HAVE_STAT_FLAGS) */
+#endif
+
+/* determine file type
+ */
+static
+int sh_unix_getinfo_type (struct stat * buf,
+ ShFileType * type,
+ char * c_mode)
+{
+ SL_ENTER(_("sh_unix_getinfo_type"));
+
+ if ( S_ISREG(buf->st_mode) ) {
+ (*type) = SH_FILE_REGULAR;
+ c_mode[0] = '-';
+ }
+ else if ( S_ISLNK(buf->st_mode) ) {
+ (*type) = SH_FILE_SYMLINK;
+ c_mode[0] = 'l';
+ }
+ else if ( S_ISDIR(buf->st_mode) ) {
+ (*type) = SH_FILE_DIRECTORY;
+ c_mode[0] = 'd';
+ }
+ else if ( S_ISCHR(buf->st_mode) ) {
+ (*type) = SH_FILE_CDEV;
+ c_mode[0] = 'c';
+ }
+ else if ( S_ISBLK(buf->st_mode) ) {
+ (*type) = SH_FILE_BDEV;
+ c_mode[0] = 'b';
+ }
+ else if ( S_ISFIFO(buf->st_mode) ) {
+ (*type) = SH_FILE_FIFO;
+ c_mode[0] = '|';
+ }
+ else if ( S_ISSOCK(buf->st_mode) ) {
+ (*type) = SH_FILE_SOCKET;
+ c_mode[0] = 's';
+ }
+ else if ( S_ISDOOR(buf->st_mode) ) {
+ (*type) = SH_FILE_DOOR;
+ c_mode[0] = 'D';
+ }
+ else if ( S_ISPORT(buf->st_mode) ) {
+ (*type) = SH_FILE_PORT;
+ c_mode[0] = 'P';
+ }
+ else {
+ (*type) = SH_FILE_UNKNOWN;
+ c_mode[0] = '?';
+ }
+
+ SL_RETURN(0, _("sh_unix_getinfo_type"));
+}
+
+int sh_unix_get_ftype(char * fullpath)
+{
+ char c_mode[CMODE_SIZE];
+ struct stat buf;
+ ShFileType type;
+ int res;
+
+ SL_ENTER(_("sh_unix_get_ftype"));
+
+ res = retry_lstat(FIL__, __LINE__, fullpath, &buf);
+
+ if (res < 0)
+ SL_RETURN(SH_FILE_UNKNOWN, _("sh_unix_getinfo_type"));
+
+ sh_unix_getinfo_type (&buf, &type, c_mode);
+
+ SL_RETURN(type, _("sh_unix_get_ftype"));
+}
+
+
+static
+int sh_unix_getinfo_mode (struct stat *buf,
+ unsigned int * mode,
+ char * c_mode)
+{
+
+ SL_ENTER(_("sh_unix_getinfo_mode"));
+
+ (*mode) = buf->st_mode;
+
+ /* make 'ls'-like string */
+
+ if ( (buf->st_mode & S_IRUSR) != 0 ) c_mode[1] = 'r';
+ if ( (buf->st_mode & S_IWUSR) != 0 ) c_mode[2] = 'w';
+ if ( (buf->st_mode & S_IXUSR) != 0 ) {
+ if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 's';
+ else c_mode[3] = 'x';
+ } else {
+ if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 'S';
+ }
+
+ if ( (buf->st_mode & S_IRGRP) != 0 ) c_mode[4] = 'r';
+ if ( (buf->st_mode & S_IWGRP) != 0 ) c_mode[5] = 'w';
+ if ( (buf->st_mode & S_IXGRP) != 0 ) {
+ if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 's';
+ else c_mode[6] = 'x';
+ } else {
+ if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 'S';
+ }
+
+ if ( (buf->st_mode & S_IROTH) != 0 ) c_mode[7] = 'r';
+ if ( (buf->st_mode & S_IWOTH) != 0 ) c_mode[8] = 'w';
+#ifdef S_ISVTX /* not POSIX */
+ if ( (buf->st_mode & S_IXOTH) != 0 ) {
+ if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 't';
+ else c_mode[9] = 'x';
+ } else {
+ if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 'T';
+ }
+#else
+ if ( (buf->st_mode & S_IXOTH) != 0 ) c_mode[9] = 'x';
+#endif
+
+ SL_RETURN(0, _("sh_unix_getinfo_mode"));
+}
+
+
+long IO_Limit = 0;
+
+void sh_unix_io_pause ()
+{
+ long runtime;
+ float someval;
+ unsigned long sometime;
+
+ if (IO_Limit == 0)
+ {
+ return;
+ }
+ else
+ {
+ runtime = (long) (time(NULL) - sh.statistics.time_start);
+
+ if (runtime > 0 && (long)(sh.statistics.bytes_hashed/runtime) > IO_Limit)
+ {
+ someval = sh.statistics.bytes_hashed - (IO_Limit * runtime);
+ someval /= (float) IO_Limit;
+ if (someval < 1.0)
+ {
+ someval *= 1000; /* milliseconds in a second */
+ sometime = (unsigned long) someval;
+ retry_msleep(0, sometime);
+ }
+ else
+ {
+ sometime = (unsigned long) someval;
+ retry_msleep (sometime, 0);
+ }
+ }
+ }
+ return;
+}
+
+int sh_unix_set_io_limit (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_unix_set_io_limit"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val < 0)
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("set I/O limit"), c);
+
+ val = (val < 0 ? 0 : val);
+
+ IO_Limit = val * 1024;
+ SL_RETURN( 0, _("sh_unix_set_io_limit"));
+}
+
+/* obtain file info
+ */
+extern int flag_err_debug;
+
+#include "sh_ignore.h"
+
+int sh_unix_checksum_size (char * filename, off_t size, int is_max_size,
+ char * fileHash, int alert_timeout, SL_TICKET fd, unsigned long mask)
+{
+ file_type * tmpFile;
+ int status;
+
+ SL_ENTER(_("sh_unix_checksum_size"));
+
+ tmpFile = SH_ALLOC(sizeof(file_type));
+ tmpFile->link_path = NULL;
+
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ /* lookup file in database */
+ if (is_max_size == S_TRUE) {
+ status = sh_hash_get_it (filename, tmpFile, NULL);
+ if ((status != 0) || (tmpFile->size > size)) {
+ goto out;
+ }
+ } else {
+ tmpFile->size = size;
+ }
+ }
+ else
+ {
+ tmpFile->size = size;
+ }
+
+ /* if last <= current get checksum */
+ if (tmpFile->size <= size)
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 local_length = (UINT64) (tmpFile->size < 0 ? 0 : tmpFile->size);
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(mask);
+ sl_strlcpy(fileHash,
+ sh_tiger_generic_hash (filename, fd, &(local_length),
+ alert_timeout, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ /* return */
+ if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
+ SH_FREE(tmpFile);
+ SL_RETURN( 0, _("sh_unix_checksum_size"));
+ }
+
+ out:
+ if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
+ SH_FREE(tmpFile);
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ SL_RETURN( -1, _("sh_unix_checksum_size"));
+}
+
+/********************************************************
+ * Search rotated logfile
+ */
+extern char * sh_rotated_log_search(const char * path, struct stat * buf);
+
+int sh_check_rotated_log (const char * path,
+ UINT64 old_size, UINT64 old_inode, const char * old_hash, unsigned long mask)
+{
+ struct stat obuf;
+ UINT64 length_nolim = TIGER_NOLIM;
+ int retval = S_FALSE;
+
+ if (old_size != length_nolim)
+ {
+ char hashbuf[KEYBUF_SIZE];
+ char * rotated_file;
+
+ obuf.st_ino = old_inode;
+ rotated_file = sh_rotated_log_search(path, &obuf);
+
+ if (rotated_file && (0 != strcmp(path, rotated_file)))
+ {
+ SL_TICKET fd = sl_open_fastread (FIL__, __LINE__, rotated_file, SL_YESPRIV);
+ if (!SL_ISERROR(fd))
+ {
+ sh_unix_checksum_size (rotated_file, old_size, S_FALSE,
+ hashbuf, 120 /* alert_timeout */, fd, mask);
+
+ sl_close(fd);
+
+ if (strncmp (old_hash, hashbuf, KEY_LEN) == 0) {
+ retval = S_TRUE;
+ }
+ }
+ SH_FREE(rotated_file);
+ }
+ }
+ return retval;
+}
+
+
+int sh_unix_check_selinux = S_FALSE;
+int sh_unix_check_acl = S_FALSE;
+
+#ifdef USE_ACL
+
+#include <sys/acl.h>
+static char * sh_unix_getinfo_acl (char * path, int fd, struct stat * buf)
+{
+ /* system.posix_acl_access, system.posix_acl_default
+ */
+ char * out = NULL;
+ char * collect = NULL;
+ char * tmp;
+ char * out_compact;
+ ssize_t len;
+ acl_t result;
+
+ SL_ENTER(_("sh_unix_getinfo_acl"));
+
+ result = (fd == -1) ?
+ acl_get_file (path, ACL_TYPE_ACCESS) :
+ acl_get_fd (fd);
+
+ if (result)
+ {
+ out = acl_to_text (result, &len);
+ if (out && (len > 0)) {
+ out_compact = sh_util_acl_compact (out, len);
+ acl_free(out);
+ if (out_compact)
+ {
+ collect = sh_util_strconcat (_("acl_access:"), out_compact, NULL);
+ SH_FREE(out_compact);
+ }
+ }
+ acl_free(result);
+ }
+
+
+ if ( S_ISDIR(buf->st_mode) )
+ {
+ result = acl_get_file (path, ACL_TYPE_DEFAULT);
+
+ if (result)
+ {
+ out = acl_to_text (result, &len);
+ if (out && (len > 0)) {
+ out_compact = sh_util_acl_compact (out, len);
+ acl_free(out);
+ if (out_compact) {
+ if (collect) {
+ tmp = sh_util_strconcat (_("acl_default:"),
+ out_compact, ":", collect, NULL);
+ SH_FREE(collect);
+ }
+ else {
+ tmp = sh_util_strconcat (_("acl_default:"), out_compact, NULL);
+ }
+ SH_FREE(out_compact);
+ collect = tmp;
+ }
+ }
+ acl_free(result);
+ }
+ }
+
+ SL_RETURN((collect),_("sh_unix_getinfo_acl"));
+}
+#endif
+
+#ifdef USE_XATTR
+
+#include <attr/xattr.h>
+static char * sh_unix_getinfo_xattr_int (char * path, int fd, char * name)
+{
+ char * out = NULL;
+ char * tmp = NULL;
+ size_t size = 256;
+ ssize_t result;
+
+ SL_ENTER(_("sh_unix_getinfo_xattr_int"));
+
+ out = SH_ALLOC(size);
+
+ result = (fd == -1) ?
+ lgetxattr (path, name, out, size-1) :
+ fgetxattr (fd, name, out, size-1);
+
+ if (result == -1 && errno == ERANGE)
+ {
+ SH_FREE(out);
+ result = (fd == -1) ?
+ lgetxattr (path, name, NULL, 0) :
+ fgetxattr (fd, name, NULL, 0);
+ size = result + 1;
+ out = SH_ALLOC(size);
+ result = (fd == -1) ?
+ lgetxattr (path, name, out, size-1) :
+ fgetxattr (fd, name, out, size-1);
+ }
+
+ if ((result > 0) && ((size_t)result < size))
+ {
+ out[size-1] = '\0';
+ tmp = out;
+ }
+ else
+ {
+ SH_FREE(out);
+ }
+
+ SL_RETURN((tmp),_("sh_unix_getinfo_xattr_int"));
+}
+
+
+static char * sh_unix_getinfo_xattr (char * path, int fd, struct stat * buf)
+{
+ /* system.posix_acl_access, system.posix_acl_default, security.selinux
+ */
+ char * tmp;
+ char * out = NULL;
+ char * collect = NULL;
+
+ SL_ENTER(_("sh_unix_getinfo_xattr"));
+
+#ifdef USE_ACL
+ /*
+ * we need the acl_get_fd/acl_get_file functions, getxattr will only
+ * yield the raw bytes
+ */
+ if (sh_unix_check_acl == S_TRUE)
+ {
+ out = sh_unix_getinfo_acl(path, fd, buf);
+
+ if (out)
+ {
+ collect = out;
+ }
+ }
+#else
+ (void) buf;
+#endif
+
+ if (sh_unix_check_selinux == S_TRUE)
+ {
+ out = sh_unix_getinfo_xattr_int(path, fd, _("security.selinux"));
+
+ if (out)
+ {
+ if (collect) {
+ tmp = sh_util_strconcat(_("selinux:"), out, ":", collect, NULL);
+ SH_FREE(collect);
+ }
+ else {
+ tmp = sh_util_strconcat(_("selinux:"), out, NULL);
+ }
+ SH_FREE(out);
+ collect = tmp;
+ }
+ }
+
+ SL_RETURN((collect),_("sh_unix_getinfo_xattr"));
+}
+#endif
+
+#ifdef USE_XATTR
+int sh_unix_setcheckselinux (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_unix_setcheckselinux"));
+ i = sh_util_flagval(c, &(sh_unix_check_selinux));
+
+ SL_RETURN(i, _("sh_unix_setcheckselinux"));
+}
+#endif
+
+#ifdef USE_ACL
+int sh_unix_setcheckacl (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_unix_setcheckacl"));
+ i = sh_util_flagval(c, &(sh_unix_check_acl));
+
+ SL_RETURN(i, _("sh_unix_setcheckacl"));
+}
+#endif
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+
+static void * sh_dummy_filename;
+static void * sh_dummy_tmp;
+static void * sh_dummy_tmp2;
+
+int sh_unix_getinfo (int level, const char * filename, file_type * theFile,
+ char * fileHash, int policy)
+{
+ char timestr[81];
+ long runtim;
+ struct stat buf;
+ struct stat lbuf;
+ struct stat fbuf;
+ volatile int stat_return;
+ volatile int stat_errno = 0;
+
+ ShFileType type;
+ unsigned int mode;
+ char * tmp;
+ char * tmp2;
+
+ char * linknamebuf;
+ volatile int linksize;
+
+ extern int get_the_fd (SL_TICKET ticket);
+
+ volatile SL_TICKET rval_open;
+ volatile int err_open = 0;
+
+ volatile int fd;
+ volatile int fstat_return;
+ volatile int fstat_errno = 0;
+ volatile int try = 0;
+
+ sh_string * content = NULL;
+
+ time_t tend;
+ time_t tstart;
+
+
+ char * path = NULL;
+
+ volatile int alert_timeout = 120;
+
+ path = theFile->fullpath;
+
+ SL_ENTER(_("sh_unix_getinfo"));
+
+ if (!MODI_INITIALIZED(theFile->check_flags))
+ {
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Uninitialized check mask"), _("sh_unix_getinfo"),
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ SL_RETURN((-1),_("sh_unix_getinfo"));
+ }
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_filename = (void *) &filename;
+ sh_dummy_tmp = (void *) &tmp;
+ sh_dummy_tmp2 = (void *) &tmp2;
+
+ /* --- Stat the file, and get checksum. ---
+ */
+ tstart = time(NULL);
+
+ stat_return = retry_lstat (FIL__, __LINE__,
+ path /* theFile->fullpath */, &buf);
+
+ if (stat_return)
+ stat_errno = errno;
+
+ theFile->link_path = NULL;
+
+ try_again:
+
+ fd = -1;
+ fstat_return = -1;
+ rval_open = -1;
+
+ if (stat_return == 0 && S_ISREG(buf.st_mode))
+ {
+ rval_open = sl_open_fastread (FIL__, __LINE__,
+ path /* theFile->fullpath */, SL_YESPRIV);
+ if (SL_ISERROR(rval_open))
+ {
+ char * stale = sl_check_stale();
+
+ if (stale)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, err_open, MSG_E_SUBGEN,
+ stale, _("sh_unix_getinfo_open"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (errno == EBADF && try == 0) /* obsolete, but we keep this, just in case */
+ {
+ ++try;
+ goto try_again;
+ }
+ err_open = errno;
+ }
+
+ alert_timeout = 120; /* this is per 8K block now ! */
+
+ if (path[1] == 'p' && path[5] == '/' && path[2] == 'r' &&
+ path[3] == 'o' && path[4] == 'c' && path[0] == '/')
+ {
+ /* seven is magic */
+ alert_timeout = 7;
+ }
+
+ fd = get_the_fd(rval_open);
+ }
+
+ tend = time(NULL);
+
+ /* An unprivileged user may slow lstat/open to a crawl
+ * with clever path/symlink setup
+ */
+ if ((tend - tstart) > (time_t) /* 60 */ 6)
+ {
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_TOOLATE,
+ (long)(tend - tstart), tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ }
+
+ if (fd >= 0)
+ {
+ fstat_return = retry_fstat (FIL__, __LINE__, fd, &fbuf);
+
+ if (fstat_return)
+ {
+ char * stale;
+
+ fstat_errno = errno;
+
+ stale = sl_check_stale();
+
+ if (stale)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, fstat_errno,
+ MSG_E_SUBGEN,
+ stale, _("sh_unix_getinfo_fstat"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (try == 0) /* obsolete, but we keep this, just in case */
+ {
+ ++try;
+ sl_close(rval_open);
+ goto try_again;
+ }
+ }
+ }
+ else
+ {
+ fd = -1;
+ }
+
+
+ /* --- case 1: lstat failed ---
+ */
+ if (stat_return != 0)
+ {
+ stat_return = errno;
+ if (!SL_ISERROR(rval_open))
+ sl_close(rval_open);
+ if (sh.flag.checkSum == SH_CHECK_INIT ||
+ (sh_hash_have_it (theFile->fullpath) >= 0 &&
+ (!SH_FFLAG_REPORTED_SET(theFile->file_reported))))
+ {
+ if (S_FALSE == sh_ignore_chk_del(theFile->fullpath)) {
+ int flags = sh_hash_getflags (theFile->fullpath);
+
+ if ((flags >= 0) && (flags & SH_FFLAG_ENOENT) == 0) {
+ char errbuf[SH_ERRBUF_SIZE];
+ uid_t euid;
+ (void) sl_get_euid(&euid);
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT,
+ _("lstat"),
+ sh_error_message (stat_errno, errbuf, sizeof(errbuf)),
+ (long) euid,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ sh_hash_set_flag (theFile->fullpath, SH_FFLAG_ENOENT);
+ }
+ }
+ }
+ SL_RETURN((-1),_("sh_unix_getinfo"));
+ }
+
+ /* --- case 2: not a regular file ---
+ */
+ else if (! S_ISREG(buf.st_mode))
+ {
+ if (fileHash != NULL)
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+
+ /* --- case 3a: a regular file, fstat ok ---
+ */
+ else if (fstat_return == 0 &&
+ buf.st_mode == fbuf.st_mode &&
+ buf.st_ino == fbuf.st_ino &&
+ buf.st_uid == fbuf.st_uid &&
+ buf.st_gid == fbuf.st_gid &&
+ buf.st_dev == fbuf.st_dev )
+ {
+ if (fileHash != NULL)
+ {
+ if ((theFile->check_flags & MODI_CHK) == 0 ||
+ sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size,
+ (UINT64) fbuf.st_mode, rval_open))
+ {
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else if ((theFile->check_flags & MODI_PREL) != 0 &&
+ S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size,
+ alert_timeout, theFile->fullpath))
+ {
+ if (0 != sh_prelink_run (theFile->fullpath,
+ fileHash, alert_timeout, theFile->check_flags))
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 length_current = TIGER_NOLIM;
+
+ if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX))
+ {
+ sl_init_content (rval_open, fbuf.st_size);
+ }
+
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags);
+ sl_strlcpy(fileHash,
+ sh_tiger_generic_hash (theFile->fullpath,
+ rval_open, &length_current,
+ alert_timeout,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ content = sl_get_content(rval_open);
+ content = sh_string_copy(content);
+
+ if ((theFile->check_flags & MODI_SGROW) != 0)
+ {
+ /* Update size so it matches the one for which the checksum
+ has been computed */
+ fbuf.st_size = length_current;
+ buf.st_size = fbuf.st_size;
+ sl_rewind(rval_open);
+ sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE,
+ &fileHash[KEY_LEN + 1],
+ alert_timeout, rval_open, theFile->check_flags);
+ }
+ }
+ }
+ }
+
+ /* --- case 3b: a regular file, fstat ok, but different ---
+ */
+ else if (fstat_return == 0 && S_ISREG(fbuf.st_mode))
+ {
+ memcpy (&buf, &fbuf, sizeof( struct stat ));
+
+ if (fileHash != NULL)
+ {
+ if ((theFile->check_flags & MODI_CHK) == 0 ||
+ sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size,
+ (UINT64) fbuf.st_mode, rval_open))
+ {
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else if (policy == SH_LEVEL_PRELINK &&
+ S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size,
+ alert_timeout, theFile->fullpath))
+ {
+ if (0 != sh_prelink_run (theFile->fullpath,
+ fileHash, alert_timeout, theFile->check_flags))
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 length_current = TIGER_NOLIM;
+
+ if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX))
+ {
+ sl_init_content (rval_open, fbuf.st_size);
+ }
+
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags);
+ sl_strlcpy(fileHash,
+ sh_tiger_generic_hash (theFile->fullpath, rval_open,
+ &length_current,
+ alert_timeout,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN + 1);
+
+ content = sl_get_content(rval_open);
+ content = sh_string_copy(content);
+
+ if ((theFile->check_flags & MODI_SGROW) != 0)
+ {
+ /* Update size so it matches the one for which the checksum
+ has been computed */
+ fbuf.st_size = length_current;
+ buf.st_size = fbuf.st_size;
+ sl_rewind(rval_open);
+ sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE,
+ &fileHash[KEY_LEN + 1],
+ alert_timeout, rval_open, theFile->check_flags);
+ }
+ }
+ }
+ }
+
+ /* --- case 4: a regular file, fstat failed ---
+ */
+
+ else /* fstat_return != 0 or !S_ISREG(fbuf.st_mode) or open() failed */
+ {
+ uid_t euid;
+
+ if (fileHash != NULL)
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+
+ if ((theFile->check_flags & MODI_CHK) != 0)
+ {
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+
+
+ if (fd >= 0 && fstat_return != 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ (void) sl_get_euid(&euid);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT,
+ _("fstat"),
+ sh_error_message (fstat_errno, errbuf, sizeof(errbuf)),
+ (long) euid,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else if (fd >= 0 && !S_ISREG(fbuf.st_mode))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, fstat_errno,
+ MSG_E_NOTREG, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ char errbuf2[SH_ERRBUF_SIZE];
+ sl_strlcpy(errbuf, sl_error_string(rval_open), sizeof(errbuf));
+ sh_error_message(err_open, errbuf2, sizeof(errbuf2));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, err_open,
+ MSG_E_READ, errbuf, errbuf2, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_FREE(tmp2);
+ }
+ }
+
+
+ /* --- Determine file type. ---
+ */
+ memset (theFile->c_mode, '-', CMODE_SIZE-1);
+ theFile->c_mode[CMODE_SIZE-1] = '\0';
+
+ memset (theFile->link_c_mode, '-', CMODE_SIZE-1);
+ theFile->link_c_mode[CMODE_SIZE-1] = '\0';
+
+ sh_unix_getinfo_type (&buf, &type, theFile->c_mode);
+ theFile->type = type;
+
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+
+ /* --- Determine file attributes. ---
+ */
+ memset (theFile->c_attributes, '-', ATTRBUF_SIZE);
+ theFile->c_attributes[ATTRBUF_USED] = '\0';
+ theFile->attributes = 0;
+
+#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS)
+ if (theFile->c_mode[0] != 'c' && theFile->c_mode[0] != 'b' &&
+ theFile->c_mode[0] != 'l' )
+ sh_unix_getinfo_attr(theFile->fullpath,
+ &theFile->attributes, theFile->c_attributes,
+ fd, &buf);
+#endif
+#endif
+
+#if defined(USE_XATTR) && defined(USE_ACL)
+ if (sh_unix_check_selinux == S_TRUE || sh_unix_check_acl == S_TRUE)
+ theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf);
+#elif defined(USE_XATTR)
+ if (sh_unix_check_selinux == S_TRUE)
+ theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf);
+#elif defined(USE_ACL)
+ if (sh_unix_check_acl == S_TRUE)
+ theFile->attr_string = sh_unix_getinfo_acl (theFile->fullpath, fd, &buf);
+#else
+ theFile->attr_string = NULL;
+#endif
+
+ if (!SL_ISERROR(rval_open))
+ sl_close(rval_open);
+
+
+ /* --- I/O limit. ---
+ */
+ if (IO_Limit > 0)
+ {
+ runtim = (long) (time(NULL) - sh.statistics.time_start);
+
+ if (runtim > 0 && (long)(sh.statistics.bytes_hashed/runtim) > IO_Limit)
+ retry_msleep(1, 0);
+ }
+
+ /* --- Determine permissions. ---
+ */
+ sh_unix_getinfo_mode (&buf, &mode, theFile->c_mode);
+
+ /* --- Trivia. ---
+ */
+ theFile->dev = buf.st_dev;
+ theFile->ino = buf.st_ino;
+ theFile->mode = buf.st_mode;
+ theFile->hardlinks = buf.st_nlink;
+ theFile->owner = buf.st_uid;
+ theFile->group = buf.st_gid;
+ theFile->rdev = buf.st_rdev;
+ theFile->size = buf.st_size;
+ theFile->blksize = (unsigned long) buf.st_blksize;
+ theFile->blocks = (unsigned long) buf.st_blocks;
+ theFile->atime = buf.st_atime;
+ theFile->mtime = buf.st_mtime;
+ theFile->ctime = buf.st_ctime;
+
+
+ /* --- Owner and group. ---
+ */
+
+ if (NULL == sh_unix_getGIDname(SH_ERR_ALL, buf.st_gid, theFile->c_group, GROUP_MAX+1)) {
+
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+
+ if (policy == SH_LEVEL_ALLIGNORE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT,
+ MSG_FI_NOGRP,
+ (long) buf.st_gid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT,
+ MSG_FI_NOGRP,
+ (long) buf.st_gid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_FREE(tmp2);
+ sl_snprintf(theFile->c_group, GROUP_MAX+1, "%d", (long) buf.st_gid);
+ }
+
+
+ if (NULL == sh_unix_getUIDname(SH_ERR_ALL, buf.st_uid, theFile->c_owner, USER_MAX+1)) {
+
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+
+ if (policy == SH_LEVEL_ALLIGNORE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT,
+ MSG_FI_NOUSR,
+ (long) buf.st_uid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT,
+ MSG_FI_NOUSR,
+ (long) buf.st_uid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_FREE(tmp2);
+ sl_snprintf(theFile->c_owner, USER_MAX+1, "%d", (long) buf.st_uid);
+ }
+
+ /* --- Output the file. ---
+ */
+ if (flag_err_debug == S_TRUE)
+ {
+ tmp2 = sh_util_safe_name ((filename == NULL) ?
+ theFile->fullpath : filename);
+ (void) sh_unix_time(theFile->mtime, timestr, sizeof(timestr));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LIST,
+ theFile->c_mode,
+ theFile->hardlinks,
+ theFile->c_owner,
+ theFile->c_group,
+ (unsigned long) theFile->size,
+ timestr,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ }
+
+ /* --- Check for links. ---
+ */
+ if (theFile->c_mode[0] == 'l')
+ {
+ linknamebuf = SH_ALLOC(PATH_MAX);
+
+ /* flawfinder: ignore */
+ linksize = readlink (theFile->fullpath, linknamebuf, PATH_MAX-1);
+
+ if (linksize < (PATH_MAX-1) && linksize >= 0)
+ linknamebuf[linksize] = '\0';
+ else
+ linknamebuf[PATH_MAX-1] = '\0';
+
+ if (linksize < 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ linksize = errno;
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, linksize, MSG_FI_RDLNK,
+ sh_error_message (linksize, errbuf, sizeof(errbuf)), tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ SH_FREE(linknamebuf);
+ theFile->link_path = sh_util_strdup("-");
+ SL_RETURN((-1),_("sh_unix_getinfo"));
+ }
+
+ if (linknamebuf[0] == '/')
+ {
+ theFile->link_path = sh_util_strdup (linknamebuf);
+ }
+ else
+ {
+ tmp = sh_util_dirname(theFile->fullpath);
+ if (tmp) {
+ theFile->link_path = SH_ALLOC(PATH_MAX);
+ sl_strlcpy (theFile->link_path, tmp, PATH_MAX);
+ SH_FREE(tmp);
+ } else {
+ theFile->link_path = SH_ALLOC(PATH_MAX);
+ theFile->link_path[0] = '\0';
+ }
+ /*
+ * Only attach '/' if not root directory. Handle "//", which
+ * according to POSIX is implementation-defined, and may be
+ * different from "/" (however, three or more '/' will collapse
+ * to one).
+ */
+ tmp = theFile->link_path; while (*tmp == '/') ++tmp;
+ if (*tmp != '\0')
+ {
+ sl_strlcat (theFile->link_path, "/", PATH_MAX);
+ }
+ sl_strlcat (theFile->link_path, linknamebuf, PATH_MAX);
+ }
+
+ /* stat the link
+ */
+ stat_return = retry_lstat (FIL__, __LINE__, theFile->link_path, &lbuf);
+
+ /* check for error
+ */
+ if (stat_return != 0)
+ {
+ stat_return = errno;
+ tmp = sh_util_safe_name (theFile->fullpath);
+ tmp2 = sh_util_safe_name (theFile->link_path);
+ if (stat_return != ENOENT)
+ {
+ uid_t euid;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ (void) sl_get_euid(&euid);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, stat_return,
+ MSG_FI_STAT,
+ _("lstat (link target)"),
+ sh_error_message (stat_return,errbuf, sizeof(errbuf)),
+ (long) euid,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ /* a dangling link -- everybody seems to have plenty of them
+ */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DLNK,
+ tmp, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ theFile->linkisok = BAD;
+ SH_FREE(tmp);
+ SH_FREE(tmp2);
+ SH_FREE(linknamebuf);
+ /*
+ * changed Tue Feb 10 16:16:13 CET 2004:
+ * add dangling symlinks into database
+ * SL_RETURN((-1),_("sh_unix_getinfo"));
+ */
+ theFile->linkmode = 0;
+ SL_RETURN((0),_("sh_unix_getinfo"));
+ }
+
+ theFile->linkisok = GOOD;
+
+
+ /* --- Determine file type. ---
+ */
+ sh_unix_getinfo_type (&lbuf, &type, theFile->link_c_mode);
+ theFile->type = type;
+
+ /* --- Determine permissions. ---
+ */
+ sh_unix_getinfo_mode (&lbuf, &mode, theFile->link_c_mode);
+ theFile->linkmode = lbuf.st_mode;
+
+ /* --- Output the link. ---
+ */
+ if (theFile->linkisok == GOOD)
+ {
+ tmp2 = sh_util_safe_name (linknamebuf);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LLNK,
+ theFile->link_c_mode, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ }
+ SH_FREE(linknamebuf);
+ }
+ else /* not a link, theFile->c_mode[0] != 'l' */
+ {
+ if (content)
+ {
+#ifdef HAVE_LIBZ
+ unsigned long clen;
+ unsigned char * compressed;
+#ifdef HAVE_COMPRESSBOUND
+ clen = compressBound(sh_string_len(content));
+#else
+ if (sh_string_len(content) > 10*SH_TXT_MAX)
+ clen = SH_TXT_MAX;
+ else
+ clen = 13 + (int)(1.0001*sh_string_len(content));
+#endif
+ compressed = SH_ALLOC(clen);
+ if (Z_OK == compress(compressed, &clen,
+ (unsigned char *) sh_string_str(content),
+ sh_string_len(content)))
+ {
+ if (clen < SH_TXT_MAX)
+ {
+ sh_util_base64_enc_alloc (&(theFile->link_path),
+ (char *) compressed, clen);
+ }
+ else
+ {
+ char tmsg[128];
+ char * tpath = sh_util_safe_name (theFile->fullpath);
+ sl_snprintf(tmsg, sizeof(tmsg),
+ _("compressed file too large (%lu bytes)"),
+ clen);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, -1,
+ MSG_E_SUBGPATH, tmsg,
+ _("sh_unix_getinfo"), tpath);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tpath);
+ }
+ }
+ SH_FREE(compressed);
+#endif
+ sh_string_destroy(&content);
+ }
+ }
+ SL_RETURN((0),_("sh_unix_getinfo"));
+}
+
+/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+int sh_unix_unlock(char * lockfile, char * flag)
+{
+ int error = 0;
+
+ SL_ENTER(_("sh_unix_unlock"));
+
+ if (sh.flag.isdaemon == S_FALSE && flag == NULL)
+ SL_RETURN((0),_("sh_unix_unlock"));
+
+ /* --- Logfile is not locked to us. ---
+ */
+ if (sh.flag.islocked == BAD && flag != NULL)
+ SL_RETURN((-1),_("sh_unix_unlock"));
+
+ /* --- Check whether the directory is secure. ---
+ */
+ if (0 != tf_trust_check (lockfile, SL_YESPRIV))
+ SL_RETURN((-1),_("sh_unix_unlock"));
+
+ /* --- Delete the lock file. ---
+ */
+ error = retry_aud_unlink (FIL__, __LINE__, lockfile);
+
+ if (error == 0)
+ {
+ if (flag != NULL)
+ sh.flag.islocked = BAD; /* not locked anymore */
+ }
+ else if (flag != NULL)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ error = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_UNLNK,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ lockfile);
+ SL_RETURN((-1),_("sh_unix_unlock"));
+ }
+ SL_RETURN((0),_("sh_unix_unlock"));
+}
+
+int sh_unix_check_piddir (char * pidpath)
+{
+ static struct stat buf;
+ int status = 0;
+ char * pid_dir;
+
+ SL_ENTER(_("sh_unix_check_piddir"));
+
+ pid_dir = sh_util_dirname (pidpath);
+
+ status = retry_lstat (FIL__, __LINE__, pid_dir, &buf);
+
+ if (status < 0 && errno == ENOENT)
+ {
+ status = mkdir (pid_dir, 0777);
+ if (status < 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ _("Cannot create PID directory"),
+ _("sh_unix_check_piddir"));
+ SH_FREE(pid_dir);
+ SL_RETURN((-1),_("sh_unix_check_piddir"));
+ }
+ }
+ else if (!S_ISDIR(buf.st_mode))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ _("Path of PID directory refers to a non-directory object"),
+ _("sh_unix_check_piddir"));
+ SH_FREE(pid_dir);
+ SL_RETURN((-1),_("sh_unix_check_piddir"));
+ }
+ SH_FREE(pid_dir);
+ SL_RETURN((0),_("sh_unix_check_piddir"));
+}
+
+int sh_unix_lock (char * lockfile, char * flag)
+{
+ int filed;
+ int errnum;
+ char myPid[64];
+ SL_TICKET fd;
+ extern int get_the_fd (SL_TICKET ticket);
+
+ SL_ENTER(_("sh_unix_lock"));
+
+ sprintf (myPid, "%ld\n", (long) sh.pid); /* known to fit */
+
+ if (flag == NULL) /* PID file, check for directory */
+ {
+ if (0 != sh_unix_check_piddir (lockfile))
+ {
+ SL_RETURN((-1),_("sh_unix_lock"));
+ }
+ }
+
+ fd = sl_open_safe_rdwr (FIL__, __LINE__,
+ lockfile, SL_YESPRIV); /* fails if file exists */
+
+ if (!SL_ISERROR(fd))
+ {
+ errnum = sl_write (fd, myPid, sl_strlen(myPid));
+ filed = get_the_fd(fd);
+ fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ sl_close (fd);
+
+ if (!SL_ISERROR(errnum))
+ {
+ if (flag != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_lock"));
+ }
+ }
+
+ TPT((0, FIL__, __LINE__, _("msg=<open pid file failed>\n")));
+ if (flag != NULL)
+ sh.flag.islocked = BAD;
+ SL_RETURN((-1),_("sh_unix_lock"));
+
+ /* notreached */
+}
+
+
+/* check whether file is locked
+ */
+int sh_unix_test_and_lock (char * filename, char * lockfile)
+{
+ static struct stat buf;
+ int status = 0;
+
+
+ SL_TICKET fd;
+ char line_in[128];
+
+ SL_ENTER(_("sh_unix_test_and_lock"));
+
+ status = retry_lstat (FIL__, __LINE__, lockfile, &buf);
+
+ /* --- No lock file found, try to lock. ---
+ */
+
+ if (status < 0 && errno == ENOENT)
+ {
+ if (0 == sh_unix_lock (lockfile, filename))
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot create PID file (1)") : _("Cannot create lock file (1)"),
+ _("sh_unix_test_and_lock"));
+ SL_RETURN((-1),_("sh_unix_test_and_lock"));
+ }
+ }
+ else if (status == 0 && buf.st_size == 0)
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ sh_unix_unlock (lockfile, filename);
+ if (filename != NULL)
+ sh.flag.islocked = BAD;
+ if (0 == sh_unix_lock (lockfile, filename))
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot create PID file (2)") : _("Cannot create lock file (2)"),
+ _("sh_unix_test_and_lock"));
+ SL_RETURN((-1),_("sh_unix_test_and_lock"));
+ }
+ }
+
+ /* --- Check on lock. ---
+ */
+
+ if (status >= 0)
+ {
+ fd = sl_open_read (FIL__, __LINE__, lockfile, SL_YESPRIV);
+ if (SL_ISERROR(fd))
+ sh_error_handle ((-1), FIL__, __LINE__, fd,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot open PID file for read") : _("Cannot open lock file for read"),
+ _("sh_unix_test_and_lock"));
+ }
+ else
+ fd = -1;
+
+ if (!SL_ISERROR(fd))
+ {
+ /* read the PID in the lock file
+ */
+ status = sl_read (fd, line_in, sizeof(line_in));
+ line_in[sizeof(line_in)-1] = '\0';
+
+ /* convert to numeric
+ */
+ if (status > 0)
+ {
+ errno = 0;
+ status = strtol(line_in, (char **)NULL, 10);
+ if (errno == ERANGE || status <= 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Bad PID in PID file") : _("Bad PID in lock file"),
+ _("sh_unix_test_and_lock"));
+
+ status = -1;
+ }
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot read PID file") : _("Cannot read lock file"),
+ _("sh_unix_test_and_lock"));
+ }
+ sl_close(fd);
+
+ if (status > 0 && (unsigned int) status == sh.pid)
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+
+
+ /* --- Check whether the process exists. ---
+ */
+ if (status > 0)
+ {
+ errno = 0;
+ status = aud_kill (FIL__, __LINE__, status, 0);
+
+ /* Does not exist, so remove the stale lock
+ * and create a new one.
+ */
+ if (status < 0 && errno == ESRCH)
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ if (0 != sh_unix_unlock(lockfile, filename) && (filename !=NULL))
+ sh.flag.islocked = BAD;
+ else
+ {
+ if (0 == sh_unix_lock (lockfile, filename))
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot create PID file (3)") : _("Cannot create lock file (3)"),
+ _("sh_unix_test_and_lock"));
+ }
+ if (filename != NULL)
+ sh.flag.islocked = BAD;
+ }
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot remove stale PID file, PID may be a running process") : _("Cannot remove stale lock file, PID may be a running process"),
+ _("sh_unix_test_and_lock"));
+ if (filename != NULL)
+ sh.flag.islocked = BAD;
+ }
+ }
+ }
+ SL_RETURN((-1),_("sh_unix_testlock"));
+}
+
+/* write the PID file
+ */
+int sh_unix_write_pid_file()
+{
+ return sh_unix_test_and_lock(NULL, sh.srvlog.alt);
+}
+
+/* write lock for filename
+ */
+int sh_unix_write_lock_file(char * filename)
+{
+ size_t len;
+ int res;
+ char * lockfile;
+
+ if (filename == NULL)
+ return (-1);
+
+ len = sl_strlen(filename);
+ if (sl_ok_adds(len, 6))
+ len += 6;
+ lockfile = SH_ALLOC(len);
+ sl_strlcpy(lockfile, filename, len);
+ sl_strlcat(lockfile, _(".lock"), len);
+ res = sh_unix_test_and_lock(filename, lockfile);
+ SH_FREE(lockfile);
+ return res;
+}
+
+/* rm lock for filename
+ */
+int sh_unix_rm_lock_file(char * filename)
+{
+ size_t len;
+ int res;
+ char * lockfile;
+
+ if (filename == NULL)
+ return (-1);
+
+ len = sl_strlen(filename);
+ if (sl_ok_adds(len, 6))
+ len += 6;
+ lockfile = SH_ALLOC(len);
+ sl_strlcpy(lockfile, filename, len);
+ sl_strlcat(lockfile, _(".lock"), len);
+
+ res = sh_unix_unlock(lockfile, filename);
+ SH_FREE(lockfile);
+ return res;
+}
+
+/* rm lock for filename
+ */
+int sh_unix_rm_pid_file()
+{
+ return sh_unix_unlock(sh.srvlog.alt, NULL);
+}
+
+/* Test whether file exists
+ */
+int sh_unix_file_exists(char * path)
+{
+ struct stat buf;
+
+ SL_ENTER(_("sh_unix_file_exists"));
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &buf))
+ SL_RETURN( S_TRUE, _("sh_unix_file_exists"));
+ else
+ SL_RETURN( S_FALSE, _("sh_unix_file_exists"));
+}
+
+
+/* Test whether file exists, is a character device, and allows read
+ * access.
+ */
+int sh_unix_device_readable(int fd)
+{
+ struct stat buf;
+
+ SL_ENTER(_("sh_unix_device_readable"));
+
+ if (retry_fstat(FIL__, __LINE__, fd, &buf) == -1)
+ SL_RETURN( (-1), _("sh_unix_device_readable"));
+ else if ( S_ISCHR(buf.st_mode) && 0 != (S_IROTH & buf.st_mode) )
+ SL_RETURN( (0), _("sh_unix_device_readable"));
+ else
+ SL_RETURN( (-1), _("sh_unix_device_readable"));
+}
+
+static char preq[16];
+
+/* return true if database is remote
+ */
+int file_is_remote ()
+{
+ static int init = 0;
+ struct stat buf;
+
+ SL_ENTER(_("file_is_remote"));
+
+ if (init == 0)
+ {
+ sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16);
+ ++init;
+ }
+ if (0 == sl_strncmp (sh.data.path, preq, 15))
+ {
+ if (sh.data.path[15] != '\0') /* should be start of path */
+ {
+ if (0 == stat(&(sh.data.path[15]), &buf))
+ {
+ SL_RETURN( S_FALSE, _("file_is_remote"));
+ }
+ else
+ {
+ char * tmp = sh_util_safe_name (&(sh.data.path[15]));
+ sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGPATH,
+ _("No local baseline database at expected path"),
+ _("file_is_remote"),
+ tmp);
+ SH_FREE(tmp);
+ }
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN,
+ _("No local baseline database path known"),
+ _("file_is_remote"));
+ }
+ SL_RETURN( S_TRUE, _("file_is_remote"));
+ }
+ SL_RETURN( S_FALSE, _("file_is_remote"));
+}
+
+/* Return the path to the configuration/database file.
+ */
+char * file_path(char what, char flag)
+{
+ static int init = 0;
+
+ SL_ENTER(_("file_path"));
+
+ if (init == 0)
+ {
+ sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16);
+ ++init;
+ }
+
+ switch (what)
+ {
+
+ case 'C':
+ if (0 == sl_strncmp (sh.conf.path, preq, 15))
+ {
+#if defined(SH_WITH_SERVER)
+ if (sh.flag.isserver == S_TRUE && sl_strlen(sh.conf.path) == 15)
+ SL_RETURN( NULL, _("file_path"));
+ if (sh.flag.isserver == S_TRUE)
+ SL_RETURN( &(sh.conf.path[15]), _("file_path"));
+#endif
+ if (flag == 'R')
+ SL_RETURN( preq, _("file_path"));
+ if (flag == 'I')
+ {
+ if (sl_strlen(sh.conf.path) == 15)
+ SL_RETURN( NULL, _("file_path"));
+ else
+ SL_RETURN( &(sh.conf.path[15]), _("file_path"));
+ }
+ SL_RETURN ( preq, _("file_path"));
+ }
+ else
+ SL_RETURN( sh.conf.path, _("file_path"));
+ /* break; *//* unreachable */
+
+ case 'D':
+ if (0 == sl_strncmp (sh.data.path, preq, 15))
+ {
+ if (flag == 'R')
+ SL_RETURN( preq, _("file_path"));
+ if (flag == 'W' && sl_strlen(sh.data.path) == 15)
+ SL_RETURN (NULL, _("file_path"));
+ if (flag == 'W')
+ SL_RETURN( &(sh.data.path[15]), _("file_path"));
+ }
+ else
+ SL_RETURN( sh.data.path, _("file_path"));
+ break;
+
+ default:
+ SL_RETURN( NULL, _("file_path"));
+ }
+
+ return NULL; /* notreached */
+}
+/************************************************/
+/**** Mlock Utilities ****/
+/************************************************/
+
+#include <limits.h>
+
+int sh_unix_pagesize()
+{
+ int pagesize = 4096;
+#if defined(_SC_PAGESIZE)
+ pagesize = sysconf(_SC_PAGESIZE);
+#elif defined(_SC_PAGE_SIZE)
+ pagesize = sysconf(_SC_PAGE_SIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ pagesize = getpagesize();
+#elif defined(PAGESIZE)
+ pagesize = PAGESIZE;
+#endif
+
+ return ((pagesize > 0) ? pagesize : 4096);
+}
+
+typedef struct sh_page_lt {
+ unsigned long page_start;
+ int page_refcount;
+ char file[64];
+ int line;
+ struct sh_page_lt * next;
+} sh_page_l;
+
+sh_page_l * sh_page_locked = NULL;
+volatile int page_locking = 0;
+
+unsigned long sh_unix_lookup_page (void * in_addr, size_t len, int * num_pages)
+{
+ int pagesize = sh_unix_pagesize();
+ unsigned long addr = (unsigned long) in_addr;
+
+ unsigned long pagebase;
+ unsigned long pagediff;
+ unsigned long pagenum = addr / pagesize;
+
+ SL_ENTER(_("sh_unix_lookup_page"));
+#if 0
+ fprintf(stderr, "mlock: --> base %ld, pagenum: %ld\n",
+ addr, pagenum);
+#endif
+
+ /* address of first page
+ */
+ pagebase = pagenum * pagesize;
+
+ /* number of pages
+ */
+ pagediff = (addr + len) - pagebase;
+ pagenum = pagediff / pagesize;
+ if (pagenum * pagesize < pagediff)
+ ++pagenum;
+
+#if 0
+ fprintf(stderr, "mlock: --> pagebase %ld, pagediff %ld, (addr + len) %ld\n",
+ pagebase, pagediff, (addr + len));
+#endif
+
+ *num_pages = pagenum;
+ SL_RETURN((pagebase), _("sh_unix_lookup_page"));
+}
+
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+
+SH_MUTEX_STATIC(mutex_mlock,PTHREAD_MUTEX_INITIALIZER);
+
+int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len)
+{
+ int num_pages;
+ int status = 0;
+ int pagesize;
+ sh_page_l * page_list;
+ unsigned long addr;
+#ifdef TEST_MLOCK
+ int i = 0;
+#endif
+
+ SL_ENTER(_("sh_unix_mlock"));
+
+ /* There's no cancellation point here, except if tracing is on
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
+
+ page_list = sh_page_locked;
+
+ if (0 != page_locking)
+ {
+ status = -1;
+ goto exit_mlock;
+ }
+
+ page_locking = 1;
+
+ pagesize = sh_unix_pagesize();
+ addr = sh_unix_lookup_page (in_addr, len, &num_pages);
+
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: addr %ld, base %ld, pages: %d, length %d\n",
+ (unsigned long) in_addr, addr, num_pages, len);
+#endif
+
+ /* increase refcount of locked pages
+ * addr is first page; num_pages is #(consecutive pages) to lock
+ */
+
+ while ((page_list != NULL) && (num_pages > 0))
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: check page %d: %ld [%d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+ if (page_list->page_start == addr)
+ {
+ page_list->page_refcount += 1;
+ num_pages -= 1;
+ addr += pagesize;
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: found page %d: %ld [%d], next page %ld\n",
+ i, page_list->page_start, page_list->page_refcount, addr);
+#endif
+ }
+#ifdef TEST_MLOCK
+ ++i;
+#endif
+ page_list = page_list->next;
+ }
+
+ /* mlock some more pages, if needed
+ */
+ while (num_pages > 0)
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: lock page %d: mlock %ld [num_pages %d]\n",
+ i, addr, num_pages);
+ ++i;
+#endif
+ page_list = SH_ALLOC(sizeof(sh_page_l));
+ page_list->page_start = addr;
+ page_list->page_refcount = 1;
+ sl_strlcpy(page_list->file, file, 64);
+ page_list->line = line;
+ status = mlock( (void *) addr, pagesize);
+ if (status != 0)
+ {
+#ifdef TEST_MLOCK
+ char errbuf[SH_ERRBUF_SIZE];
+ fprintf(stderr, "mlock: error: %s\n",
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+#endif
+ SH_FREE(page_list);
+ page_locking = 0;
+ goto exit_mlock;
+ }
+ page_list->next = sh_page_locked;
+ sh_page_locked = page_list;
+ num_pages -= 1;
+ addr += pagesize;
+ }
+ page_locking = 0;
+
+ exit_mlock:
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
+
+ SL_RETURN((status), _("sh_unix_mlock"));
+}
+#else
+int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len)
+{
+ (void) file; (void) line;
+ (void) in_addr; (void) len;
+ return -1;
+}
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+int sh_unix_munlock (void * in_addr, size_t len)
+{
+ int num_pages;
+ int unlocked;
+ int status;
+ int pagesize;
+ sh_page_l * page_list;
+ sh_page_l * page_last;
+ unsigned long addr;
+
+ int test_count;
+ int test_status;
+ int test_pages;
+
+#ifdef TEST_MLOCK
+ int i = 0;
+#endif
+
+ SL_ENTER(_("sh_unix_munlock"));
+
+ /* There's no cancellation point here, except if tracing is on
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
+
+ unlocked = 0;
+ status = 0;
+ page_list = sh_page_locked;
+
+ if (0 != page_locking)
+ {
+ status = -1;
+ goto exit_munlock;
+ }
+ page_locking = 1;
+
+ pagesize = sh_unix_pagesize();
+ addr = sh_unix_lookup_page (in_addr, len, &num_pages);
+
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: in_addr %ld, addr %ld, pages: %d, length %d\n",
+ (unsigned long) in_addr, addr, num_pages, len);
+#endif
+
+ test_pages = num_pages;
+
+ /* reduce refcount of locked pages
+ * addr is first page; num_pages is #(consecutive pages) to lock
+ */
+ while ((page_list != NULL) && (num_pages > 0))
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: page %d: %ld [%d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+
+ test_status = 0;
+ for (test_count = 0; test_count < test_pages; ++test_count)
+ {
+ if (page_list->page_start == (addr + (test_count * pagesize)))
+ {
+ test_status = 1;
+ break;
+ }
+ }
+
+ if (test_status == 1)
+ {
+ page_list->page_refcount -= 1;
+ if (page_list->page_refcount == 0)
+ {
+ status = munlock ( (void *) addr, pagesize);
+ ++unlocked;
+ }
+ num_pages -= 1;
+#ifdef TEST_MLOCK
+ fprintf(stderr,
+ "munlock: page %d: %ld [refcount %d], refcount reduced\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+ }
+#ifdef TEST_MLOCK
+ ++i;
+#endif
+ page_list = page_list->next;
+ }
+
+#ifdef TEST_MLOCK
+ i = 0;
+#endif
+
+ if (unlocked > 0)
+ {
+ page_list = sh_page_locked;
+ page_last = sh_page_locked;
+
+ while ((page_list != NULL) && (unlocked > 0))
+ {
+ if (page_list->page_refcount == 0)
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: remove page %d: %ld [refcount %d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+ if (page_last != page_list)
+ {
+ page_last->next = page_list->next;
+ SH_FREE(page_list);
+ page_list = page_last->next;
+ }
+ else
+ {
+ page_last = page_list->next;
+ if (page_list == sh_page_locked)
+ sh_page_locked = page_list->next;
+ SH_FREE(page_list);
+ page_list = page_last;
+ }
+ --unlocked;
+ }
+ else
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: skip page %d: %ld [refcount %d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+
+ page_last = page_list;
+ page_list = page_list->next;
+ }
+#ifdef TEST_MLOCK
+ ++i;
+#endif
+ }
+ }
+
+ page_locking = 0;
+
+ exit_munlock:
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
+ SL_RETURN((status), _("sh_unix_munlock"));
+}
+#else
+int sh_unix_munlock (void * in_addr, size_t len)
+{
+ (void) in_addr; (void) len;
+ return -1;
+}
+#endif
+
+int sh_unix_count_mlock()
+{
+ unsigned int i = 0;
+ char str[32][64];
+ sh_page_l * page_list;
+
+ SL_ENTER(_("sh_unix_count_mlock"));
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ /* There's no cancellation point here, except if tracing is on
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
+#endif
+
+ page_list = sh_page_locked;
+
+ while (page_list != NULL)
+ {
+#ifdef WITH_TPT
+ if (i < 32)
+ sl_snprintf(str[i], 64, _("file: %s line: %d page: %d"),
+ page_list->file, page_list->line, i+1);
+#endif
+ page_list = page_list->next;
+ ++i;
+ }
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
+#endif
+
+#ifdef WITH_TPT
+ {
+ unsigned int j = 0;
+ while (j < i && j < 32)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, j, MSG_E_SUBGEN,
+ str[j], _("sh_unix_count_mlock"));
+ ++j;
+ }
+ }
+#endif
+
+ sl_snprintf(str[0], 64, _("%d pages locked"), i);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, i, MSG_E_SUBGEN,
+ str[0], _("sh_unix_count_mlock"));
+ SL_RETURN((i), _("sh_unix_count_mlock"));
+}
+
+/************************************************/
+/************************************************/
+/**** Stealth Utilities ****/
+/************************************************/
+/************************************************/
+#ifdef SH_STEALTH
+
+void sh_unix_xor_code (char * str, int len)
+{
+ register int i;
+
+ for (i = 0; i < len; ++i) str[i] ^= (char) XOR_CODE;
+ return;
+}
+
+#if !defined(SH_STEALTH_MICRO)
+
+
+int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len,
+ unsigned long * bytes_read);
+unsigned long first_hex_block(SL_TICKET fd, unsigned long * max);
+
+/*
+ * --- Get hidden data from a block of hex data. ---
+ */
+int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len)
+{
+ int add_off = 0, llen;
+ static unsigned long off_data = 0;
+ static unsigned long max_data = 0;
+ static unsigned long bytes_read = 0;
+ static int stealth_init = BAD;
+
+ SL_ENTER(_("sh_unix_getline_stealth"));
+
+ if (str == NULL)
+ {
+ off_data = 0;
+ max_data = 0;
+ bytes_read = 0;
+ stealth_init = BAD;
+ SL_RETURN(0, _("sh_unix_getline_stealth"));
+ }
+
+ /* --- Initialize. ---
+ */
+ if (stealth_init == BAD)
+ {
+ off_data = first_hex_block(fd, &max_data);
+ if (off_data == 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The stealth config file does not contain any steganographically\nhidden data. This file must be an image file in _uncompressed_\npostscript format.\nTo hide data in it, use:\n samhain_stealth -s postscript_file orig_config_file\n mv postscript_file /path/to/config/file\n"));
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_P_NODATA,
+ _("Stealth config file."));
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ stealth_init = GOOD;
+ max_data += off_data;
+ }
+
+ /* --- Seek to proper position. ---
+ */
+ if (bytes_read >= max_data || add_off < 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The capacity of the container image file for the stealth config file seems to be too small. Your config file is likely truncated.\n"));
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_P_NODATA,
+ _("Stealth config file."));
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ sl_seek(fd, off_data);
+
+ /* --- Read one line. ---
+ */
+ add_off = hideout_hex_block(fd, (unsigned char *) str, len, &bytes_read);
+ off_data += add_off;
+
+ llen = sl_strlen(str);
+ SL_RETURN(llen, _("sh_unix_getline_stealth"));
+}
+
+int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len,
+ unsigned long * bytes_read)
+{
+
+ register int i, j, k;
+ unsigned char c, e;
+ register int num;
+ unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+ unsigned long here = 0;
+ unsigned long retval = 0;
+ unsigned long bread = 0;
+
+ SL_ENTER(_("hideout_hex_block"));
+
+ ASSERT_RET((len > 1), _("len > 1"), (0));
+
+ --len;
+
+ i = 0;
+ while (i < len)
+ {
+ for (j = 0; j < 8; ++j)
+ {
+
+ /* --- Get a low byte, modify, read back. ---
+ */
+ for (k = 0; k < 2; ++k)
+ {
+ /* -- Skip whitespace. ---
+ */
+ c = ' ';
+ do {
+ do {
+ num = sl_read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0)
+ ++here;
+ else if (num == 0)
+ SL_RETURN((0), _("hideout_hex_block"));
+ else
+ SL_RETURN((-1), _("hideout_hex_block"));
+ } while (c == '\n' || c == '\t' || c == '\r' ||
+ c == ' ');
+ }
+
+
+ /* --- e is the value of the low byte. ---
+ */
+ e = (unsigned char) sh_util_hexchar( c );
+ if ((e & mask[7]) != 0) /* bit is set */
+ str[i] |= mask[j];
+ else /* bit is not set */
+ str[i] &= ~mask[j];
+
+ bread += 1;
+ }
+ if (str[i] == '\n') break;
+ ++i;
+ }
+
+ if (i != 0)
+ str[i] = '\0';
+ else
+ str[i+1] = '\0'; /* keep newline and terminate */
+ retval += here;
+ *bytes_read += (bread/8);
+
+ SL_RETURN(retval, _("hideout_hex_block"));
+}
+
+/* --- Get offset of first data block. ---
+ */
+unsigned long first_hex_block(SL_TICKET fd, unsigned long * max)
+{
+ unsigned int i;
+ long num = 1;
+ unsigned long lnum;
+ char c;
+ int nothex = 0;
+ unsigned long retval = 0;
+ unsigned int this_line = 0;
+ char theline[SH_BUFSIZE];
+
+ SL_ENTER(_("first_hex_block"));
+
+ *max = 0;
+
+ while (1)
+ {
+ theline[0] = '\0';
+ this_line = 0;
+ c = '\0';
+ while (c != '\n' && this_line < (sizeof(theline)-1))
+ {
+ do {
+ num = sl_read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0)
+ theline[this_line] = c;
+ else
+ SL_RETURN((0), _("first_hex_block"));
+ ++this_line;
+ }
+ theline[this_line] = '\0';
+
+ /* not only 'newline' */
+ if (this_line > 60)
+ {
+ nothex = 0;
+ i = 0;
+ while (nothex == 0 && i < (this_line-1))
+ {
+ if (! isxdigit((int)theline[i])) nothex = 1;
+ ++i;
+ }
+ if (nothex == 1) retval += this_line;
+ }
+ else
+ {
+ nothex = 1;
+ retval += this_line;
+ }
+
+ if (nothex == 0)
+ {
+ *max = 0;
+ do {
+ do {
+ num = sl_read (fd, theline, SH_BUFSIZE);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0)
+ {
+ lnum = (unsigned long) num;
+ for (i = 0; i < lnum; ++i)
+ {
+ c = theline[i];
+ if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
+ ;
+ else if (!isxdigit((int)c))
+ break;
+ else
+ *max += 1;
+ }
+ }
+ } while (num > 0);
+
+ *max /= 16;
+ SL_RETURN((retval), _("first_hex_block"));
+ }
+
+ }
+ /* SL_RETURN((0), _("first_hex_block")); *//* unreachable */
+}
+
+ /* if !defined(SH_STEALTH_MICRO) */
+#endif
+
+ /* ifdef SH_STEALTH */
+#endif
+
+/*
+ * anti-debugger code
+ */
+#if defined(SCREW_IT_UP)
+
+#if defined(HAVE_PTHREAD)
+
+static pthread_key_t gSigtrapVariables_key;
+static pthread_once_t gSigtrapVariables_key_once = PTHREAD_ONCE_INIT;
+
+static inline void make_gSigtrapVariables_key()
+{
+ (void) pthread_key_create(&gSigtrapVariables_key, free);
+}
+
+struct sh_sigtrap_variables * sh_sigtrap_variables_get()
+{
+ void * ptr;
+
+ (void) pthread_once(&gSigtrapVariables_key_once, make_gSigtrapVariables_key);
+
+ ptr = pthread_getspecific(gSigtrapVariables_key);
+ if (ptr == NULL) {
+ ptr = calloc(1,sizeof(struct sh_sigtrap_variables));
+ if (ptr == NULL) {
+ return NULL;
+ }
+ (void) pthread_setspecific(gSigtrapVariables_key, ptr);
+ }
+
+ return (struct sh_sigtrap_variables *) ptr;
+}
+
+/* !defined(HAVE_PTHREAD) */
+#else
+
+static struct sh_sigtrap_variables global_sigtrap_variables;
+struct sh_sigtrap_variables * sh_sigtrap_variables_get()
+{
+ return &global_sigtrap_variables;
+}
+
+#endif
+
+int sh_sigtrap_max_duration_set (const char * str)
+{
+ /* For security (prevent reloading with larger value)
+ * this value can only be set once.
+ */
+ static int once = 0;
+ int i;
+
+ SL_ENTER(_("sh_sigtrap_max_duration_set"));
+
+ i = atoi (str);
+
+ if (i >= 0 && once == 0)
+ {
+ sh.sigtrap_max_duration = i;
+ once = 1;
+ }
+ else
+ {
+ SL_RETURN ((-1), _("sh_sigtrap_max_duration_set"));
+ }
+ SL_RETURN( (0), _("sh_sigtrap_max_duration_set"));
+}
+
+void sh_sigtrap_handler (int signum)
+{
+ struct sh_sigtrap_variables * sigtrap_variables;
+ sigtrap_variables = sh_sigtrap_variables_get();
+ if (sigtrap_variables == NULL) {
+ /* Perhaps, it's better to not die, and to continue using Samhain,
+ even if this part does not work. */
+ return;
+ }
+
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+ long difftv;
+
+ gettimeofday(&tv, NULL);
+ difftv = (tv.tv_sec - sigtrap_variables->save_tv.tv_sec) * 1000000 +
+ (tv.tv_usec - sigtrap_variables->save_tv.tv_usec);
+ if (difftv > sh.sigtrap_max_duration)
+ raise(SIGKILL);
+ }
+#endif
+
+ sigtrap_variables->not_traced = signum;
+ /* cppcheck-suppress memleak */
+ return;
+}
+#endif
diff --git a/src/CuTest.c b/src/CuTest.c
new file mode 100644
index 0000000..c1884da
--- /dev/null
+++ b/src/CuTest.c
@@ -0,0 +1,350 @@
+/*******************
+
+LICENSE
+
+Copyright (c) 2003 Asim Jalis
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software in
+a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not
+be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+
+**********************/
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+
+#include "CuTest.h"
+
+/*-------------------------------------------------------------------------*
+ * CuStr
+ *-------------------------------------------------------------------------*/
+
+char* CuStrAlloc(int size)
+{
+ char* newStr = (char*) malloc( sizeof(char) * (size) );
+ return newStr;
+}
+
+char* CuStrCopy(const char* old)
+{
+ int len = strlen(old);
+ char* newStr = CuStrAlloc(len + 1);
+ strcpy(newStr, old);
+ return newStr;
+}
+
+/*-------------------------------------------------------------------------*
+ * CuString
+ *-------------------------------------------------------------------------*/
+
+void CuStringInit(CuString* str)
+{
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ if (str->buffer)
+ str->buffer[0] = '\0';
+ else
+ {
+ perror("CuStringInit");
+ _exit (EXIT_FAILURE);
+ }
+}
+
+CuString* CuStringNew(void)
+{
+ CuString* str = (CuString*) malloc(sizeof(CuString));
+ str->length = 0;
+ str->size = STRING_MAX;
+ str->buffer = (char*) malloc(sizeof(char) * str->size);
+ if (str->buffer)
+ str->buffer[0] = '\0';
+ else
+ {
+ perror("CuStringNew");
+ _exit (EXIT_FAILURE);
+ }
+ return str;
+}
+
+void CuStringResize(CuString* str, int newSize)
+{
+ str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize);
+ str->size = newSize;
+}
+
+void CuStringAppend(CuString* str, const char* text)
+{
+ int length;
+
+ if (text == NULL) {
+ text = "NULL";
+ }
+
+ length = strlen(text);
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ str->length += length;
+ strcat(str->buffer, text);
+}
+
+void CuStringAppendChar(CuString* str, char ch)
+{
+ char text[2];
+ text[0] = ch;
+ text[1] = '\0';
+ CuStringAppend(str, text);
+}
+
+void CuStringAppendFormat(CuString* str, const char* format, ...)
+{
+ va_list argp;
+ char buf[2048];
+ va_start(argp, format);
+ vsnprintf(buf, sizeof(buf), format, argp);
+ va_end(argp);
+ CuStringAppend(str, buf);
+}
+
+void CuStringInsert(CuString* str, const char* text, int pos)
+{
+ int length = strlen(text);
+ if (pos > str->length)
+ pos = str->length;
+ if (str->length + length + 1 >= str->size)
+ CuStringResize(str, str->length + length + 1 + STRING_INC);
+ memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1);
+ str->length += length;
+ memcpy(str->buffer + pos, text, length);
+}
+
+/*-------------------------------------------------------------------------*
+ * CuTest
+ *-------------------------------------------------------------------------*/
+
+void CuTestInit(CuTest* t, const char* name, TestFunction function)
+{
+ t->name = CuStrCopy(name);
+ t->failed = 0;
+ t->ran = 0;
+ t->message = NULL;
+ t->function = function;
+ t->jumpBuf = NULL;
+}
+
+CuTest* CuTestNew(const char* name, TestFunction function)
+{
+ CuTest* tc = CU_ALLOC(CuTest);
+ CuTestInit(tc, name, function);
+ return tc;
+}
+
+void CuTestRun(CuTest* tc)
+{
+ jmp_buf buf;
+ tc->jumpBuf = &buf;
+ if (setjmp(buf) == 0)
+ {
+ tc->ran = 1;
+ (tc->function)(tc);
+ }
+ tc->jumpBuf = 0;
+}
+
+static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string)
+{
+ char buf[256];
+
+ snprintf(buf, sizeof(buf), "%s:%d: ", file, line);
+ CuStringInsert(string, buf, 0);
+
+ tc->failed = 1;
+ tc->message = string->buffer;
+ if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0);
+}
+
+void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message)
+{
+ CuString string;
+
+ CuStringInit(&string);
+ if (message2 != NULL)
+ {
+ CuStringAppend(&string, message2);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, message);
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition)
+{
+ if (condition) return;
+ CuFail_Line(tc, file, line, NULL, message);
+}
+
+void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ const char* expected, const char* actual)
+{
+ CuString string;
+ if ((expected == NULL && actual == NULL) ||
+ (expected != NULL && actual != NULL &&
+ strcmp(expected, actual) == 0))
+ {
+ return;
+ }
+
+ CuStringInit(&string);
+ if (message != NULL)
+ {
+ CuStringAppend(&string, message);
+ CuStringAppend(&string, ": ");
+ }
+ CuStringAppend(&string, "expected <");
+ CuStringAppend(&string, expected);
+ CuStringAppend(&string, "> but was <");
+ CuStringAppend(&string, actual);
+ CuStringAppend(&string, ">");
+ CuFailInternal(tc, file, line, &string);
+}
+
+void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ int expected, int actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected <%d> but was <%d>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ double expected, double actual, double delta)
+{
+ char buf[STRING_MAX];
+#define SH_FABS(a) (((a) < 0) ? -(a) : (a))
+ if (SH_FABS(expected - actual) <= delta) return;
+ sprintf(buf, "expected <%lf> but was <%lf>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message,
+ void* expected, void* actual)
+{
+ char buf[STRING_MAX];
+ if (expected == actual) return;
+ sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual);
+ CuFail_Line(tc, file, line, message, buf);
+}
+
+
+/*-------------------------------------------------------------------------*
+ * CuSuite
+ *-------------------------------------------------------------------------*/
+
+void CuSuiteInit(CuSuite* testSuite)
+{
+ testSuite->count = 0;
+ testSuite->failCount = 0;
+}
+
+CuSuite* CuSuiteNew(void)
+{
+ CuSuite* testSuite = CU_ALLOC(CuSuite);
+ CuSuiteInit(testSuite);
+ return testSuite;
+}
+
+void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase)
+{
+ assert(testSuite->count < MAX_TEST_CASES);
+ testSuite->list[testSuite->count] = testCase;
+ testSuite->count++;
+}
+
+void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2)
+{
+ int i;
+ for (i = 0 ; i < testSuite2->count ; ++i)
+ {
+ CuTest* testCase = testSuite2->list[i];
+ CuSuiteAdd(testSuite, testCase);
+ }
+}
+
+void CuSuiteRun(CuSuite* testSuite)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuTestRun(testCase);
+ if (testCase->failed) { testSuite->failCount += 1; }
+ }
+}
+
+void CuSuiteSummary(CuSuite* testSuite, CuString* summary)
+{
+ int i;
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ CuStringAppend(summary, testCase->failed ? "F" : ".");
+ }
+ CuStringAppend(summary, "\n\n");
+}
+
+void CuSuiteDetails(CuSuite* testSuite, CuString* details)
+{
+ int i;
+ int failCount = 0;
+
+ if (testSuite->failCount == 0)
+ {
+ int passCount = testSuite->count - testSuite->failCount;
+ const char* testWord = passCount == 1 ? "test" : "tests";
+ CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord);
+ }
+ else
+ {
+ if (testSuite->failCount == 1)
+ CuStringAppend(details, "There was 1 failure:\n");
+ else
+ CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount);
+
+ for (i = 0 ; i < testSuite->count ; ++i)
+ {
+ CuTest* testCase = testSuite->list[i];
+ if (testCase->failed)
+ {
+ failCount++;
+ CuStringAppendFormat(details, "%d) %s: %s\n",
+ failCount, testCase->name, testCase->message);
+ }
+ }
+ CuStringAppend(details, "\n!!!FAILURES!!!\n");
+
+ CuStringAppendFormat(details, "Runs: %d ", testSuite->count);
+ CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount);
+ CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount);
+ }
+}
diff --git a/src/bignum.c b/src/bignum.c
new file mode 100644
index 0000000..bd1bd71
--- /dev/null
+++ b/src/bignum.c
@@ -0,0 +1,1919 @@
+/* Implementation of bignums by Henrik.Johansson@Nexus.Comm.SE in 1991
+ * version 1.2
+ */
+
+/* Modifications in this file (Nov 1999, Rainer Wichmann):
+ * - a few compiler warnings fixed:
+ * gcc insists on 'if ( ( b_eq_qr = ((b == q) || (b == r)) ) )'
+ * instead of 'if ( b_eq_qr = ((b == q) || (b == r)) )'
+ * - code that is not used in samhain is #defined out by:
+ * #if (defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER))
+ * or
+ * #ifdef UNUSED_CODE
+ * - the error message (error_string[]) is enclosed in N_(),_() macros
+ * - the following four #includes have been added
+ */
+#include "config_xor.h"
+
+
+#include <string.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#include "samhain.h"
+#include "bignum.h"
+
+
+#if (!defined(HAVE_LIBGMP) || !defined(HAVE_GMP_H)) && (defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER))
+
+#define DIGIT BIGNUM_DIGIT
+#define DIGIT2 BIGNUM_TWO_DIGITS
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#endif
+#ifndef FALSE
+#define FALSE (1 != 1)
+#endif
+
+
+#define MIN_ALLOC ((sizeof(long) / sizeof(DIGIT)) << 1)
+
+/* Don't expect the "sign" field to have the right value (BIG_SIGN_0) at
+ * all times, so compare real content of bignum with zerop.
+ * Maybe it would be better to be sure at all times that the sign is right?
+ */
+#define zerop(BIG) ((*(BIG)->dp == 0) && ((BIG)->dgs_used == 1))
+#define uonep(BIG) ((*(BIG)->dp == 1) && ((BIG)->dgs_used == 1))
+#define NEGATE_SIGN(SGN) (-(SGN))
+
+#define DIGIT_BITS BIGNUM_DIGIT_BITS
+#define DIGIT2_BITS BIGNUM_TWO_DIGITS_BITS
+
+#define DIGIT_PART(N) ((DIGIT)((N) & ((((DIGIT2)1) << DIGIT_BITS) - 1)))
+#define RESULT_MINUSP(RES) (((RES) & ((DIGIT2)1 << (DIGIT2_BITS - 1))) != 0)
+#define SHIFT_DIGIT_DOWN(N) (DIGIT_PART((N) >> DIGIT_BITS))
+#define SHIFT_DIGIT_UP(N) ((DIGIT2)((N) << DIGIT_BITS))
+
+#define DIGIT_BASE (((DIGIT2)1) << DIGIT_BITS)
+#define MAX_DIGIT ((((DIGIT2)1) << DIGIT_BITS) - 1)
+
+#define uint unsigned int
+#define ulong unsigned long
+
+char *last_string = NULL;
+char *big_end_string = NULL;
+
+ulong length_last_string;
+static char big_base_digits1[] =
+N_("00112233445566778899AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz");
+static char error_string[] = N_("(big_errno != 0, something has gone wrong)");
+static char big_base_digits[73] = "\0";
+
+bignum big_one;
+bignum tmp_string, tmp_add, tmp_mul, tmp_q, tmp_r, tmp_rand, tmp_round;
+DIGIT *tmp_digits;
+ulong tmp_ulong;
+
+/* #define COUNT_ALLOC */
+#ifdef COUNT_ALLOC
+ulong dgs_alloc = 0, digits_freed = 0;
+#endif
+
+int big_errno = BIG_OK;
+
+double log2tbl[] =
+{
+ -1.0, -1.0,
+ 1.000000000000000, 1.584961891174317, 2.000000000000002, 2.321928024291994,
+ 2.584960937500003, 2.807353973388675, 3.000000000000004, 3.169923782348637,
+ 3.321928024291997, 3.459430694580083, 3.584960937500005, 3.700439453125006,
+ 3.807353973388678, 3.906888961791999, 4.000000000000014, 4.087459564208999,
+ 4.169921875000016, 4.247924804687517, 4.321926116943377, 4.392314910888691,
+ 4.459430694580098, 4.523559570312520, 4.584960937500021, 4.643856048584007,
+ 4.700439453125023, 4.754886627197290, 4.807353973388697, 4.857978820800807,
+ 4.906887054443386, 4.954193115234403, 5.000000000000028, 5.044391632080107,
+ 5.087459564209015, 5.129280090332062, 5.169921875000032
+};
+
+struct digit_blocks
+{
+ int digCnt;
+ DIGIT dig_base;
+} big_block[37]; /* The code uses index 2 to 36 */
+
+
+/* ----------------------------------------------------------------------
+ * All static utility functions are placed first in this file.
+ */
+
+#ifndef HAVE_STRCHR
+static char * strchr (char * str_ptr, char ch)
+{
+ do
+ {
+ if (*str_ptr == ch)
+ {
+ return str_ptr;
+ }
+ } while (*str_ptr++ != '\0');
+ return NULL;
+}
+#endif
+
+#if 0
+
+extern int printf();
+
+static void
+print_digits(prefix, a)
+char *prefix;
+bignum *a;
+{
+ unsigned long i;
+ ulong tmp;
+
+ printf("%s", prefix);
+ if (a->sign == BIG_SIGN_MINUS)
+ {
+ printf("- ");
+ }
+ else
+ {
+ if (a->sign == BIG_SIGN_PLUS)
+ {
+ printf("+ ");
+ }
+ else
+ {
+ printf("+/- ");
+ }
+ }
+ for (i = a->dgs_used - 1; i > 0; i--)
+ {
+ tmp = a->dp[i];
+ printf("%lu, ", tmp);
+ }
+ tmp = *a->dp;
+ printf("%lu\n", tmp);
+}
+
+#else
+
+#define print_digits(prefix, big) /* */
+
+#endif
+
+static void
+init_digit_blocks(void)
+{
+ uint digcnt, base;
+ DIGIT maxdigit, curdigit, tmp;
+
+ for (base = 2; base <= 36; base++)
+ {
+ tmp = ((1 << (DIGIT_BITS - 1)) / base);
+ maxdigit = tmp * 2;
+ curdigit = 1;
+ digcnt = 0;
+ while (curdigit < maxdigit)
+ {
+ digcnt++;
+ curdigit *= base;
+ }
+ big_block[base].digCnt = digcnt;
+ big_block[base].dig_base = curdigit;
+ }
+}
+
+#ifdef COUNT_ALLOC
+static void
+free_digits(DIGIT * dp, ulong count)
+{
+ /* Mar 4 2000 R. Wichmann: check for dp == NULL */
+ if (!dp)
+ return;
+ digits_freed += count;
+ free((char *)dp);
+ dp = NULL;
+}
+#else
+/* June 5 2000 R. Wichmann: check for dp == NULL */
+/* #define free_digits(DP,CNT) free((char *)DP) */
+static void
+free_digits(DIGIT * dp, ulong count)
+{
+ /* Mar 4 2000 R. Wichmann: check for dp == NULL */
+ if (!dp)
+ return;
+ (void) count;
+ free((char *)dp);
+ dp = NULL;
+}
+#endif
+
+static DIGIT *
+allocate_digits(ulong alloclen)
+{
+ DIGIT *digit_ptr;
+
+ if (big_errno != BIG_OK)
+ {
+ return NULL;
+ }
+#ifdef COUNT_ALLOC
+ dgs_alloc += alloclen;
+#endif
+ digit_ptr = calloc(alloclen, sizeof(DIGIT));
+ if (digit_ptr == NULL)
+ {
+ big_errno = BIG_MEMERR;
+ return NULL;
+ }
+ return digit_ptr;
+}
+
+static bigerr_t
+newsize(DIGIT **dp_p, ulong *cursize_p, ulong minsz, ulong newsz)
+{
+ if (*cursize_p >= minsz)
+ {
+ return big_errno;
+ }
+ free_digits(*dp_p, *cursize_p);
+ if (newsz < MIN_ALLOC)
+ {
+ newsz = MIN_ALLOC;
+ }
+ if ((*dp_p = allocate_digits(newsz)) == NULL)
+ {
+ return big_errno;
+ }
+ *cursize_p = newsz;
+ return big_errno;
+}
+
+/* `memcpy' uses an `int' as counter. If an int can't hold a big enough
+ * counter, then `digits_cpy' becomes a function (and a little slower,
+ * probably. Unfortunately `memcpy' takes a signed counter, but _that_
+ * size of numbers are almost too big! Or isn't it?
+ */
+#ifdef MEMCPY_LONG_COUNTER
+/* extern char *memcpy(); */
+#define digits_cpy(dst, src, count) memcpy((char *)(dst), (char *)(src), \
+ (count) * sizeof(DIGIT))
+#else
+static void
+digits_cpy(DIGIT *dst, DIGIT *src, ulong count)
+{
+ while (count-- > 0)
+ {
+ *dst++ = *src++;
+ }
+}
+#endif
+
+static DIGIT *
+copy_digits(DIGIT *src, ulong cp_count, ulong alloclen)
+{
+ DIGIT *dst;
+
+ if (big_errno != BIG_OK)
+ {
+ return NULL;
+ }
+ if ((dst = allocate_digits(alloclen)) == NULL)
+ {
+ return NULL;
+ }
+ digits_cpy(dst, src, cp_count);
+ return dst;
+}
+
+static void
+add_digit(bignum * a, DIGIT d)
+{
+ DIGIT2 res = d;
+ DIGIT *last_digit, *digit_ptr = a->dp, *digvect;
+
+ last_digit = digit_ptr + a->dgs_used;
+ while (digit_ptr < last_digit)
+ {
+ res = *digit_ptr + res;
+ *digit_ptr = DIGIT_PART(res);
+ res = SHIFT_DIGIT_DOWN(res);
+ digit_ptr++;
+ if (res == 0)
+ {
+ break;
+ }
+ }
+ if (res != 0)
+ {
+ if (a->dgs_used < a->dgs_alloc)
+ {
+ *digit_ptr = DIGIT_PART(res);
+ }
+ else
+ {
+ if ((digvect = copy_digits(a->dp, a->dgs_used,
+ a->dgs_used + 4)) == NULL)
+ {
+ return; /* big_errno will be set to last error */
+ }
+ digvect[a->dgs_used] = DIGIT_PART(res);
+ free_digits(a->dp, a->dgs_alloc);
+ a->dgs_alloc = a->dgs_used + 4;
+ a->dp = digvect;
+ }
+ a->dgs_used++;
+ }
+}
+
+static DIGIT
+vect_div_digit(DIGIT *digvect, ulong *len, DIGIT d)
+{
+ DIGIT *digit_ptr = digvect + *len - 1, newval;
+ DIGIT2 rest = 0;
+
+ if (d == 0)
+ {
+ big_errno = BIG_DIV_ZERO;
+ return -1;
+ }
+ if (d == 1)
+ {
+ return 0;
+ }
+ while (digit_ptr >= digvect)
+ {
+ rest = (DIGIT2)SHIFT_DIGIT_UP(rest);
+ newval = DIGIT_PART((*digit_ptr + rest) / d);
+ rest = (*digit_ptr + rest) % d;
+ *digit_ptr = newval;
+ digit_ptr--;
+ }
+ if (*len > 1)
+ {
+ if (digvect[*len - 1] == 0)
+ {
+ *len -= 1;
+ }
+ }
+ return DIGIT_PART(rest);
+}
+
+static DIGIT
+udiv_digit(bignum *a, DIGIT d)
+{
+ DIGIT res;
+
+ res = vect_div_digit(a->dp, &a->dgs_used, d);
+ if (zerop(a))
+ {
+ a->sign = BIG_SIGN_0;
+ }
+ return res;
+}
+
+static DIGIT
+vect_mul_digit(DIGIT *digvect, ulong len, DIGIT x)
+{
+ DIGIT *digit_ptr = digvect + len;
+ DIGIT2 res = 0;
+
+ while (digvect < digit_ptr)
+ {
+ res += *digvect * (DIGIT2)x;
+ *digvect = DIGIT_PART(res);
+ res = SHIFT_DIGIT_DOWN(res);
+ digvect++;
+ }
+ return DIGIT_PART(res);
+}
+
+static void
+umul_digit(bignum *a, DIGIT x)
+{
+ DIGIT ovfl, *digvect;
+
+ ovfl = vect_mul_digit(a->dp, a->dgs_used, x);
+ if (ovfl != 0)
+ {
+ if (a->dgs_used < a->dgs_alloc)
+ {
+ a->dp[a->dgs_used] = ovfl;
+ }
+ else
+ {
+ digvect = copy_digits(a->dp,
+ a->dgs_used,
+ a->dgs_used + 4);
+ digvect[a->dgs_used] = ovfl;
+ free_digits(a->dp, a->dgs_alloc);
+ a->dgs_alloc = a->dgs_used + 4;
+ a->dp = digvect;
+ }
+ a->dgs_used++;
+ }
+}
+
+static int
+ucompare_digits(bignum *a, bignum *b)
+{
+ DIGIT *a_ptr, *b_ptr;
+
+ if (a->dgs_used == b->dgs_used)
+ {
+ a_ptr = a->dp + a->dgs_used - 1;
+ b_ptr = b->dp + b->dgs_used - 1;
+ while ((*a_ptr == *b_ptr) && (a_ptr >= a->dp))
+ {
+ a_ptr--;
+ b_ptr--;
+ }
+ if (a_ptr < a->dp)
+ {
+ return 0;
+ }
+ else
+ {
+ return (*a_ptr > *b_ptr) ? 1 : -1;
+ }
+ }
+ return (a->dgs_used > b->dgs_used) ? 1 : -1;
+}
+
+static void
+uadd_digits(bignum *a, bignum *b, bignum *c)
+{
+ DIGIT *dp_x, *dp_y, *dp_z, *res_dp, *end_x, *end_y;
+ ulong len_x, len_y;
+ DIGIT2 res = 0;
+
+ if (a->dgs_used > b->dgs_used)
+ {
+ dp_x = a->dp;
+ len_x = a->dgs_used;
+ dp_y = b->dp;
+ len_y = b->dgs_used;
+ }
+ else
+ {
+ dp_x = b->dp;
+ len_x = b->dgs_used;
+ dp_y = a->dp;
+ len_y = a->dgs_used;
+ }
+ end_x = dp_x + len_x;
+ end_y = dp_y + len_y;
+ if (c->dgs_alloc >= len_x)
+ {
+ dp_z = c->dp;
+ }
+ else
+ {
+ if (newsize(&tmp_add.dp, &tmp_add.dgs_alloc,
+ len_x, len_x + 4) != BIG_OK)
+ {
+ return;
+ }
+ dp_z = tmp_add.dp;
+ }
+ res_dp = dp_z;
+ while (dp_y < end_y)
+ {
+ res += ((DIGIT2)*dp_x++) + *dp_y++;
+ *res_dp++ = DIGIT_PART(res);
+ res = SHIFT_DIGIT_DOWN(res);
+ }
+ while (dp_x < end_x)
+ {
+ res += *dp_x++;
+ *res_dp++ = DIGIT_PART(res);
+ res = SHIFT_DIGIT_DOWN(res);
+ }
+ if (res != 0)
+ {
+ *res_dp++ = DIGIT_PART(res);
+ }
+
+ if (dp_z != c->dp)
+ {
+ tmp_digits = c->dp;
+ c->dp = tmp_add.dp;
+ tmp_add.dp = tmp_digits;
+
+ tmp_ulong = c->dgs_alloc;
+ c->dgs_alloc = tmp_add.dgs_alloc;
+ tmp_add.dgs_alloc = tmp_ulong;
+ }
+ c->dgs_used = res_dp - c->dp;
+}
+
+static void
+usub_digits(bignum *a, bignum *b, bignum *c)
+{
+ DIGIT *dp_x, *dp_y, *dp_z, *res_dp, *end_x, *end_y;
+ ulong len_x, len_y;
+ DIGIT2 res = 0;
+
+ dp_x = a->dp;
+ len_x = a->dgs_used;
+ dp_y = b->dp;
+ len_y = b->dgs_used;
+
+ end_x = dp_x + len_x;
+ end_y = dp_y + len_y;
+ if (c->dgs_alloc >= len_x)
+ {
+ dp_z = c->dp;
+ }
+ else
+ {
+ if (newsize(&tmp_add.dp, &tmp_add.dgs_alloc,
+ len_x, len_x + 2) != BIG_OK)
+ {
+ return;
+ }
+ dp_z = tmp_add.dp;
+ }
+ res_dp = dp_z;
+ while (dp_y < end_y)
+ {
+ res = ((DIGIT2)*dp_x++) - *dp_y++ - RESULT_MINUSP(res);
+ *res_dp++ = DIGIT_PART(res);
+ }
+ while (dp_x < end_x)
+ {
+ res = *dp_x++ - RESULT_MINUSP(res);
+ *res_dp++ = DIGIT_PART(res);
+ }
+#ifdef BIG_CHECK_LIMITS
+ if (RESULT_MINUSP(res) != 0)
+ {
+ big_errno = BIG_ALGERR;
+ return;
+ }
+#endif
+ while ((*--res_dp == 0) && (res_dp > dp_z))
+ {
+ /* Move pointer down until we reach a non-zero */
+ }
+ if (dp_z != c->dp)
+ {
+ tmp_digits = c->dp;
+ c->dp = tmp_add.dp;
+ tmp_add.dp = tmp_digits;
+
+ tmp_ulong = tmp_add.dgs_alloc;
+ tmp_add.dgs_alloc = c->dgs_alloc;
+ c->dgs_alloc = tmp_ulong;
+ }
+ c->dgs_used = res_dp - dp_z + 1;
+}
+
+/*
+ * This (pseudo) random number generator is not very good. It has a long
+ * period [ 2 ^ (DIGIT_BITS * 2) (?)] before it starts with the same sequence
+ * again, but the lower bits are "less random" than they should be. I've
+ * solved it by using word of double length, and returning the upper bits.
+ * Please mail me if you know how to make it into a "more random" generator.
+ * One important thing though: it will have to reasonably fast.
+ * The good thing with this one is that it is very portable, but that doesn't
+ * help much when you want _good_ random numbers.
+ * Henrik.Johansson@Nexus.Comm.SE
+ */
+#ifdef UNUSED_CODE
+static DIGIT
+rand(void)
+{
+ static DIGIT2 x1 = 33, x2 = 45; /* Just give them two starting values */
+
+ if (x2 = BIG_RAND_A2 * x2 + BIG_RAND_C2, x2 == 45)
+ {
+ x1 = BIG_RAND_A1 * x1 + BIG_RAND_C1;
+ }
+ return SHIFT_DIGIT_DOWN(x1 + x2); /* Skip least significant bits */
+}
+/* UNUSED_CODE */
+#endif
+
+/* ----------------------------------------------------------------------
+ * All external functions comes here.
+ */
+
+bigerr_t
+big_init_pkg()
+{
+ strcpy (big_base_digits, _(big_base_digits1)); /* known to fit */
+ init_digit_blocks();
+ big_create(&tmp_string);
+ big_create(&tmp_add);
+ big_create(&tmp_mul);
+ big_create(&tmp_q);
+ big_create(&tmp_r);
+ big_create(&tmp_rand);
+ big_create(&big_one);
+ big_set_long((long)1, &big_one);
+ length_last_string = 10;
+ if ((last_string = calloc(1,length_last_string)) == NULL)
+ {
+ big_errno = BIG_MEMERR;
+ }
+ return big_errno;
+}
+
+void
+big_release_pkg()
+{
+ big_destroy(&tmp_string);
+ big_destroy(&tmp_add);
+ big_destroy(&tmp_mul);
+ big_destroy(&tmp_q);
+ big_destroy(&tmp_r);
+ big_destroy(&tmp_round);
+ big_destroy(&big_one);
+ if (last_string != NULL)
+ free(last_string);
+#ifdef COUNT_ALLOC
+ printf("Allocated digits: %lu\n", dgs_alloc);
+ printf("Freed digits: %lu\n", digits_freed);
+#endif
+}
+
+bigerr_t
+big_create(a)
+bignum *a;
+{
+ /* Make sure that big_create alway returns a NULL bignum
+ * that can safely be destroyed.
+ */
+ if (a != NULL)
+ {
+ a->dp = NULL;
+ }
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+ if (a == NULL)
+ {
+ big_errno = BIG_ARGERR;
+ return big_errno;
+ }
+
+ a->sign = BIG_SIGN_0;
+ a->dgs_used = 1;
+ if ((a->dp = allocate_digits((long)sizeof(long))) == NULL)
+ {
+ return big_errno;
+ }
+ a->dgs_alloc = sizeof(long);
+ *a->dp = 0;
+ return big_errno;
+}
+
+void
+big_destroy(a)
+bignum *a;
+{
+ /* Mar 4, 2000 R. Wichmann: check for a == NULL */
+ /* free_digits() checks for a->dp == NULL */
+ if (a != NULL)
+ free_digits(a->dp, a->dgs_alloc);
+}
+
+ulong
+big_bitcount(a)
+bignum *a;
+{
+ int bits = 0;
+ DIGIT high_digit;
+
+ if (big_errno != BIG_OK)
+ {
+ return 0;
+ }
+ high_digit = a->dp[a->dgs_used - 1];
+ while (high_digit != 0)
+ {
+ bits++;
+ high_digit >>= 1;
+ }
+ return DIGIT_BITS * (a->dgs_used - 1) + bits;
+}
+
+bigerr_t
+big_set_big(a, b)
+bignum *a;
+bignum *b;
+{
+ if ((big_errno != BIG_OK) || (a == b))
+ {
+ return big_errno;
+ }
+ if (newsize(&b->dp, &b->dgs_alloc, a->dgs_used, a->dgs_used) != BIG_OK)
+ {
+ return big_errno;
+ }
+ b->dgs_used = a->dgs_used;
+ b->sign = a->sign;
+ digits_cpy(b->dp, a->dp, a->dgs_used);
+ return big_errno;
+}
+
+
+void
+big_set_ulong(n, a)
+ulong n;
+bignum *a;
+{
+ unsigned int i;
+
+ if (big_errno != BIG_OK)
+ {
+ return;
+ }
+ if (n == 0)
+ {
+ *a->dp = 0;
+ a->dgs_used = 1;
+ a->sign = BIG_SIGN_0;
+ }
+ else
+ {
+ a->dgs_used = 0;
+ for (i = 0; i < sizeof(long) / sizeof(DIGIT); i++)
+ {
+ if (n == 0)
+ {
+ break;
+ }
+ a->dgs_used++;
+ a->dp[i] = DIGIT_PART(n);
+ n = SHIFT_DIGIT_DOWN(n);
+ }
+ a->sign = BIG_SIGN_PLUS;
+ }
+ print_digits("set_(u)long: a = ", a);
+}
+
+void
+big_set_long(n, a)
+long n;
+bignum *a;
+{
+ ulong m;
+
+ m = (n < 0) ? - n : n;
+ big_set_ulong(m, a);
+ if (!(n >= 0))
+ {
+ a->sign = BIG_SIGN_MINUS;
+ }
+}
+
+
+bigerr_t
+big_set_string(numstr, base, a)
+char *numstr;
+int base;
+bignum *a;
+{
+ char *src, *maxdigit, *chrptr;
+ DIGIT dig_base, dig_sum, last_base;
+ int cnt, maxcnt;
+
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+
+ big_end_string = numstr;
+ if ((base < 2) || (base > 36) || (numstr == NULL) || (a == NULL))
+ {
+ big_errno = BIG_ARGERR;
+ return big_errno;
+ }
+
+ src = numstr;
+
+ maxdigit = big_base_digits + (base << 1);
+
+ maxcnt = big_block[base].digCnt;
+ dig_base = big_block[base].dig_base;
+ a->dgs_used = 1;
+ *a->dp = 0;
+ a->sign = BIG_SIGN_PLUS; /* Assume it will be positive */
+ while (strchr(" \t\n\r", *src) != NULL) /* Skip whitespaces */
+ {
+ src++;
+ }
+ if ((*src == '-') || (*src == '+')) /* First non-white is a sign? */
+ {
+ a->sign = (*src == '-') ? BIG_SIGN_MINUS : BIG_SIGN_PLUS;
+ src++;
+ }
+ chrptr = strchr(big_base_digits, *src);
+ if ((chrptr == NULL) || (chrptr >= maxdigit)) /* Next chr not a digit? */
+ {
+ big_end_string = src;
+ big_errno = BIG_ARGERR;
+ return big_errno;
+ }
+ while (*src == '0') /* Next chr a '0'? */
+ {
+ src++; /* Read past all '0'es */
+ }
+ chrptr = strchr(big_base_digits, *src);
+ if ((chrptr == NULL) || (chrptr >= maxdigit)) /* Next char not a digit */
+ {
+ big_end_string = src;
+ a->sign = BIG_SIGN_0; /* It was just a plain 0 */
+ return big_errno;
+ }
+ dig_sum = 0;
+ cnt = 0;
+ while ((chrptr = strchr(big_base_digits, *src)),
+ (chrptr != NULL) && (chrptr < maxdigit))
+ {
+ dig_sum = dig_sum * base + ((chrptr - big_base_digits) >> 1);
+ if (++cnt >= maxcnt)
+ {
+ umul_digit(a, dig_base);
+ add_digit(a, dig_sum);
+ dig_sum = 0;
+ cnt = 0;
+ }
+ src++;
+ }
+ if (cnt > 0)
+ {
+ last_base = base;
+ while (--cnt > 0)
+ {
+ last_base *= base;
+ }
+ umul_digit(a, last_base);
+ add_digit(a, dig_sum);
+ }
+ big_end_string = src;
+ return big_errno;
+}
+
+
+int
+big_ulong(a, n)
+bignum *a;
+ulong *n;
+{
+ ulong old_n;
+ DIGIT *dp;
+
+ if (big_errno != BIG_OK)
+ {
+ return FALSE;
+ }
+ if (a->dgs_used > sizeof(ulong) / sizeof(DIGIT))
+ {
+ return FALSE;
+ }
+ dp = a->dp + a->dgs_used - 1;
+ old_n = *n = *dp--;
+ while ((dp >= a->dp) && (old_n < *n))
+ {
+ old_n = *n;
+ *n = SHIFT_DIGIT_UP(*n) + *dp--;
+ }
+ if (old_n >= *n)
+ {
+ return FALSE;
+ }
+ return FALSE;
+}
+
+int
+big_long(a, n)
+bignum *a;
+long *n;
+{
+ long old_n;
+ DIGIT *dp;
+
+ if (a->dgs_used > sizeof(ulong) / sizeof(DIGIT))
+ {
+ return FALSE;
+ }
+ dp = a->dp + a->dgs_used - 1;
+ old_n = *n = *dp--;
+ while ((dp >= a->dp) && (old_n <= *n))
+ {
+ old_n = *n;
+ *n = SHIFT_DIGIT_UP(*n) + *dp--;
+ }
+ if (old_n >= *n)
+ {
+ return FALSE;
+ }
+ if (a->sign == BIG_SIGN_MINUS)
+ {
+ *n = -*n;
+ }
+ return FALSE;
+}
+
+
+char *
+big_string(a, base)
+bignum *a;
+int base;
+{
+ ulong bit_length, str_length;
+ char *dst;
+ DIGIT dig_base, rem;
+ int cnt, maxcnt;
+
+ if (big_errno != BIG_OK)
+ {
+ return _(error_string);
+ }
+ big_set_big(a, &tmp_string);
+ /* Need more room than minimum here... */
+ bit_length = tmp_string.dgs_used * DIGIT_BITS;
+ /* bit_length = big_bitcount(&tmp_string); */
+ str_length = (ulong)(bit_length / log2tbl[base] + 4);
+ if (str_length > length_last_string)
+ {
+ if (last_string != NULL)
+ free(last_string);
+ if ((last_string = calloc(1,str_length)) == NULL)
+ {
+ big_errno = BIG_MEMERR;
+ return NULL;
+ }
+ length_last_string = str_length;
+ }
+
+ dst = last_string + length_last_string - 1;
+ *dst-- = '\0';
+ maxcnt = big_block[base].digCnt;
+ dig_base = big_block[base].dig_base;
+ while (tmp_string.dgs_used > 1)
+ {
+ rem = udiv_digit(&tmp_string, dig_base);
+ for (cnt = 0; cnt < maxcnt; cnt++)
+ {
+ *dst-- = big_base_digits[(rem % base) << 1];
+ rem /= base;
+ }
+ }
+ rem = *tmp_string.dp;
+ do
+ {
+ *dst-- = big_base_digits[(rem % base) << 1];
+ rem /= base;
+ } while (rem != 0);
+
+ if (a->sign == BIG_SIGN_MINUS)
+ {
+ *dst = '-';
+ }
+ else
+ {
+ dst++;
+ }
+ return dst;
+}
+
+bigerr_t
+big_negate(a, b)
+bignum *a;
+bignum *b;
+{
+ big_set_big(a, b);
+ b->sign = NEGATE_SIGN(a->sign);
+ return big_errno;
+}
+
+int
+big_sign(a)
+bignum *a;
+{
+ return a->sign;
+}
+
+bigerr_t
+big_abs(a, b)
+bignum *a;
+bignum *b;
+{
+ big_set_big(a, b);
+ if (a->sign == BIG_SIGN_MINUS)
+ {
+ b->sign = NEGATE_SIGN(a->sign);
+ }
+ return big_errno;
+}
+
+int
+big_compare(a, b)
+bignum *a;
+bignum *b;
+{
+ if (a->sign == b->sign)
+ {
+ if (a->sign == 0)
+ {
+ return 0;
+ }
+ return
+ (a->sign == BIG_SIGN_MINUS)
+ ? -ucompare_digits(a, b)
+ : ucompare_digits(a, b);
+ }
+ return b->sign - a->sign;
+}
+
+int
+big_lessp(a, b)
+bignum *a;
+bignum *b;
+{
+ return big_compare(a, b) < 0;
+}
+
+int
+big_leqp(a, b)
+bignum *a;
+bignum *b;
+{
+ return !(big_compare(a, b) > 0);
+}
+
+int
+big_equalp(a, b)
+bignum *a;
+bignum *b;
+{
+ return big_compare(a, b) == 0;
+}
+
+int
+big_geqp(a, b)
+bignum *a;
+bignum *b;
+{
+ return !(big_compare(a, b) < 0);
+}
+
+int
+big_greaterp(a, b)
+bignum *a;
+bignum *b;
+{
+ return big_compare(a, b) > 0;
+}
+
+int
+big_zerop(a)
+bignum *a;
+{
+ return a->sign == BIG_SIGN_0;
+}
+
+int
+big_evenp(a)
+bignum *a;
+{
+ return ((*a->dp & 0x01) == 0);
+}
+
+int
+big_oddp(a)
+bignum *a;
+{
+ return ((*a->dp & 0x01) == 1);
+}
+
+bigerr_t
+big_add(a, b, c)
+bignum *a;
+bignum *b;
+bignum *c;
+{
+ int cmp;
+
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+ print_digits("add:\ta = ", a);
+ print_digits("\tb = ", b);
+ if (a->sign == b->sign)
+ {
+ uadd_digits(a, b, c);
+ c->sign = a->sign;
+ }
+ else
+ {
+ cmp = ucompare_digits(a, b);
+ if (cmp < 0)
+ {
+ usub_digits(b, a, c);
+ if (zerop(c))
+ {
+ c->sign = BIG_SIGN_0;
+ }
+ else
+ {
+ c->sign = b->sign;
+ }
+ }
+ else if (cmp > 0)
+ {
+ usub_digits(a, b, c);
+ if (zerop(c))
+ {
+ c->sign = BIG_SIGN_0;
+ }
+ else
+ {
+ c->sign = a->sign;
+ }
+ }
+ else
+ {
+ c->dgs_used = 1;
+ *c->dp = 0;
+ c->sign = BIG_SIGN_0;
+ }
+ }
+ print_digits("\tc = ", c);
+ return big_errno;
+}
+
+bigerr_t
+big_sub(a, b, c)
+bignum *a;
+bignum *b;
+bignum *c;
+{
+ int cmp;
+
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+ print_digits("sub:\ta = ", a);
+ print_digits("\tb = ", b);
+ if (a->sign == BIG_SIGN_0)
+ {
+ big_set_big(b, c);
+ big_negate(c, c);
+ print_digits("\tc = ", c);
+ return big_errno;
+ }
+ if (b->sign == BIG_SIGN_0)
+ {
+ big_set_big(a, c);
+ print_digits("\tc = ", c);
+ return big_errno;
+ }
+
+ cmp = ucompare_digits(a, b);
+ if (cmp <= 0)
+ {
+ if (a->sign != b->sign)
+ {
+ uadd_digits(a, b, c);
+ c->sign = a->sign;
+ }
+ else
+ {
+ usub_digits(b, a, c);
+ c->sign = (zerop(c) ? BIG_SIGN_0 : NEGATE_SIGN(a->sign));
+ }
+ }
+ else if (cmp > 0)
+ {
+ if (a->sign != b->sign)
+ {
+ uadd_digits(a, b, c);
+ c->sign = a->sign;
+ }
+ else
+ {
+ usub_digits(a, b, c);
+ c->sign = (zerop(c) ? BIG_SIGN_0 : b->sign);
+ }
+ }
+ else
+ {
+ c->dgs_used = 1;
+ *c->dp = 0;
+ c->sign = BIG_SIGN_0;
+ }
+ print_digits("\tc = ", c);
+ return big_errno;
+}
+
+bigerr_t
+big_mul(a, b, c)
+bignum *a;
+bignum *b;
+bignum *c;
+{
+ DIGIT *dp_x, *dp_xstart, *dp_xend;
+ DIGIT *dp_y, *dp_ystart, *dp_yend;
+ DIGIT *dp_z, *dp_zstart, *dp_zend, *dp_zsumstart;
+ ulong len_x, len_y /* , len_z */;
+ DIGIT2 res;
+ DIGIT tmp_res; /* Without use of this, gcc (v 1.39) generates */
+ /* erroneous code on a sun386 machine */
+ /* Should be removed with #ifdef's, when */
+ /* not on a sun386, but... */
+
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+ print_digits("mul:\ta = ", a);
+ print_digits("\tb = ", b);
+
+ if (zerop(a) || zerop(b))
+ {
+ c->sign = BIG_SIGN_0;
+ c->dgs_used = 1;
+ *c->dp = 0;
+ print_digits("(a=0 || b=0)c = ", c);
+ return big_errno;
+ }
+ if (uonep(a))
+ {
+ big_set_big(b, c);
+ c->sign = (a->sign == b->sign) ? BIG_SIGN_PLUS : BIG_SIGN_MINUS;
+ print_digits("(abs(a)=1)c = ", c);
+ return big_errno;
+ }
+ if (uonep(b))
+ {
+ big_set_big(a, c);
+ c->sign = (a->sign == b->sign) ? BIG_SIGN_PLUS : BIG_SIGN_MINUS;
+ print_digits("(abs(b)=1)c = ", c);
+ return big_errno;
+ }
+
+ if (a->dgs_used < b->dgs_used)
+ {
+ dp_xstart = a->dp;
+ len_x = a->dgs_used;
+ dp_ystart = b->dp;
+ len_y = b->dgs_used;
+ }
+ else
+ {
+ dp_xstart = b->dp;
+ len_x = b->dgs_used;
+ dp_ystart = a->dp;
+ len_y = a->dgs_used;
+ }
+ if ((c == a) || (c == b))
+ {
+ if (newsize(&tmp_mul.dp, &tmp_mul.dgs_alloc,
+ len_x + len_y, len_x + len_y + 2) != BIG_OK)
+ {
+ return big_errno;
+ }
+ dp_zsumstart = tmp_mul.dp;
+ /* len_z = tmp_mul.dgs_alloc; */
+ }
+ else
+ {
+ if (newsize(&c->dp, &c->dgs_alloc,
+ len_x + len_y, len_x + len_y + 2) != BIG_OK)
+ {
+ return big_errno;
+ }
+ dp_zsumstart = c->dp;
+ /* len_z = c->dgs_alloc; */
+ }
+
+ dp_xend = dp_xstart + len_x;
+ dp_yend = dp_ystart + len_y;
+ dp_zend = dp_zsumstart + len_y;
+
+ for (dp_z = dp_zsumstart; dp_z < dp_zend; dp_z++)
+ {
+ *dp_z = 0; /* Zero out rightmost digits */
+ }
+
+ dp_zstart = dp_zsumstart;
+
+ for (dp_x = dp_xstart; dp_x < dp_xend; dp_x++)
+ {
+ dp_z = dp_zstart;
+ tmp_res = 0;
+ for (dp_y = dp_ystart; dp_y < dp_yend; dp_y++)
+ {
+ res = (DIGIT2)(*dp_x) * (*dp_y) + (*dp_z) + tmp_res;
+ *dp_z++ = DIGIT_PART(res);
+ tmp_res = SHIFT_DIGIT_DOWN(res);
+ }
+ *dp_z = tmp_res;
+ dp_zstart++;
+ }
+ if (dp_zsumstart != c->dp)
+ {
+ tmp_digits = c->dp;
+ c->dp = tmp_mul.dp;
+ tmp_mul.dp = tmp_digits;
+
+ tmp_ulong = c->dgs_alloc;
+ c->dgs_alloc = tmp_mul.dgs_alloc;
+ tmp_mul.dgs_alloc = tmp_ulong;
+ }
+ if (*dp_z == 0)
+ {
+ dp_z--;
+ }
+ c->dgs_used = dp_z - dp_zsumstart + 1;
+ c->sign = a->sign * b->sign;
+ print_digits("\tc = ", c);
+ return big_errno;
+}
+
+bigerr_t
+big_trunc(a, b, q, r)
+bignum *a;
+bignum *b;
+bignum *q;
+bignum *r;
+{
+ DIGIT *v_end, *q_end, *r_end, *src, *dst;
+ DIGIT norm, qhat, t1, t2, t3, v1, v2, u1, u2, u3;
+ DIGIT2 temp, res, carry;
+ long a_l, b_l, q_l, r_l;
+#if 0
+ ulong i;
+#endif
+ ulong j, m, n;
+ int cmp, q_eq_a, q_eq_b, r_eq_a, r_eq_b;
+
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+ print_digits("div:\ta = ", a);
+ print_digits("\tb = ", b);
+ if (zerop(b))
+ {
+ big_errno = BIG_DIV_ZERO;
+ return big_errno;
+ }
+
+ if (q == r)
+ {
+ big_errno = BIG_ARGERR;
+ return big_errno;
+ }
+
+ if (b->dgs_used == 1)
+ {
+ big_set_big(a, q);
+ q->sign = ((a->sign == b->sign) ? BIG_SIGN_PLUS : BIG_SIGN_MINUS);
+ *r->dp = udiv_digit(q, *b->dp);
+ r->dgs_used = 1;
+ r->sign = (zerop(r) ? BIG_SIGN_0 : a->sign);
+ print_digits("\t3:q = ", q);
+ print_digits("\t r = ", r);
+ return big_errno;
+ }
+
+ if (big_long(a, &a_l)) /* Pretend it is a signed value */
+ {
+ big_long(b, &b_l); /* |a| < |b| so this will succeed */
+ q_l = a_l / b_l; /* Compute with unsigned operators */
+ r_l = a_l % b_l;
+ big_set_long((long)q_l, q);
+ big_set_long((long)r_l, r);
+ print_digits("\t4:q = ", q);
+ print_digits("\t r = ", r);
+ return big_errno;
+ }
+
+ cmp = ucompare_digits(a, b); /* Unsigned compare, that is... */
+ if (cmp < 0)
+ {
+ big_set_big(a, r); /* r = a (don't care about big_errno here) */
+ q->sign = BIG_SIGN_0; /* q = 0 */
+ *q->dp = 0;
+ q->dgs_used = 1;
+ print_digits("\t1:q = ", q);
+ print_digits("\t r = ", r);
+ return big_errno;
+ }
+ else
+ if (cmp == 0)
+ {
+ q->sign = ((a->sign == b->sign) ? BIG_SIGN_PLUS : BIG_SIGN_MINUS);
+ *q->dp = 1; /* q = 1 */
+ q->dgs_used = 1;
+ r->sign = BIG_SIGN_0; /* r = 0 */
+ *r->dp = 0;
+ r->dgs_used = 1;
+ print_digits("\t2:q = ", q);
+ print_digits("\t r = ", r);
+ return big_errno;
+ }
+
+ q_eq_a = (q == a);
+ q_eq_b = (q == b);
+ if (q_eq_a || q_eq_b)
+ {
+ q = &tmp_q;
+ }
+
+ r_eq_a = (r == a);
+ r_eq_b = (r == b);
+ if (r_eq_a || r_eq_b)
+ {
+ r = &tmp_r;
+ }
+
+ if (newsize(&r->dp, &r->dgs_alloc, /* At least one more dig in r */
+ a->dgs_used + 1, a->dgs_used + 2) != BIG_OK)
+ {
+ return big_errno;
+ }
+ big_set_big(a, r);
+ r->dp[a->dgs_used] = 0; /* In case no overflow in mult. */
+
+ n = b->dgs_used;
+ v_end = b->dp + n - 1;
+ norm = DIGIT_PART((DIGIT_BASE / ((DIGIT2)*v_end + 1)));
+ if (norm != 1)
+ {
+ umul_digit(r, norm);
+ umul_digit(b, norm);
+ print_digits("r = ", r);
+ print_digits("b = ", b);
+ }
+ m = a->dgs_used + 1 - b->dgs_used;
+ r_end = r->dp + a->dgs_used;
+
+ if (newsize(&q->dp, &q->dgs_alloc, m, m + 2) != BIG_OK)
+ {
+ return big_errno;
+ }
+ q_end = q->dp + m - 1;
+
+ v1 = *v_end;
+ v2 = *(v_end - 1);
+
+ for (j = 0; j < m; j++) /* m steps through division */
+ {
+ u1 = *r_end; /* routine */
+ u2 = *(r_end - 1);
+ u3 = *(r_end - 2);
+ qhat = ((u1 == v1) ?
+ MAX_DIGIT :
+ DIGIT_PART(((DIGIT2)u1 * DIGIT_BASE + u2) / v1));
+ while (1)
+ {
+ t3 = DIGIT_PART(temp = (DIGIT2)qhat * v2);
+ t2 = DIGIT_PART(temp = SHIFT_DIGIT_DOWN(temp) + v1 * (DIGIT2)qhat);
+ t1 = DIGIT_PART(SHIFT_DIGIT_DOWN(temp));
+#if 0
+ printf("t1 = %lu, ", (ulong)t1);
+ printf("t2 = %lu, ", (ulong)t2);
+ printf("t3 = %lu\n", (ulong)t3);
+#endif
+ if (t1 < u1) break;
+ if (t1 > u1) {--qhat; continue; }
+ if (t2 < u2) break;
+ if (t2 > u2) { --qhat; continue; }
+ if (t3 <= u3) break;
+ qhat--;
+ }
+
+ /* This is a tricky one - multiply and subtract simultaneously */
+ carry = 1;
+ res = 0;
+ src = b->dp;
+ dst = r->dp + m - j - 1;
+ while (src <= v_end)
+ {
+ res = (DIGIT2)qhat * *(src++) + SHIFT_DIGIT_DOWN(res);
+ carry += (DIGIT2)(*dst) + MAX_DIGIT - DIGIT_PART(res);
+ *(dst++) = DIGIT_PART(carry);
+ carry = DIGIT_PART(SHIFT_DIGIT_DOWN(carry));
+ }
+ carry += (DIGIT2)(*dst) + MAX_DIGIT - SHIFT_DIGIT_DOWN(res);
+ *dst = DIGIT_PART(carry);
+ carry = DIGIT_PART(SHIFT_DIGIT_DOWN(carry));
+
+ if (carry == 0)
+ {
+ qhat--;
+ src = b->dp;
+ dst = r->dp + m - j - 1;
+ while (dst <= r_end)
+ {
+ carry = (DIGIT2)(*dst) + *src++ + SHIFT_DIGIT_DOWN(carry);
+ *dst++ = DIGIT_PART(carry);
+ }
+ *dst = 0;
+ }
+ *(q_end - j) = DIGIT_PART(qhat);
+ r_end--;
+ }
+ r->sign = a->sign;
+#if 0
+ i = r->dgs_used;
+#endif
+ while ((*r_end == 0) && (r_end > r->dp))
+ {
+ r_end--;
+ }
+ if (r_end == r->dp)
+ {
+ r->dgs_used = 1;
+ r->sign = BIG_SIGN_0;
+ }
+ else
+ {
+ r->dgs_used = r_end - r->dp + 1;
+ r->sign = a->sign;
+ }
+ if (norm != 1)
+ {
+ udiv_digit(b, norm);
+ udiv_digit(r, norm);
+ }
+ while ((*q_end == 0) && (q_end > q->dp)) /* This is not needed!(?) */
+ {
+ q_end--;
+ }
+ /* was ifdef'd out already in original */
+#if 0
+ i = m - 1;
+ while ((i > 0) && (q->dp[i--] == 0))
+ {
+ /* Loop through all zeroes */
+ }
+#endif
+ q->dgs_used = q_end - q->dp + 1;
+ q->sign = ((a->sign == b->sign) ? BIG_SIGN_PLUS : BIG_SIGN_MINUS);
+
+ if (q_eq_a)
+ {
+ big_set_big(q, a);
+ }
+ else
+ if (q_eq_b)
+ {
+ big_set_big(q, b);
+ }
+
+ if (r_eq_b)
+ {
+ big_set_big(r, b);
+ }
+ else
+ if (r_eq_a)
+ {
+ big_set_big(r, a);
+ }
+
+ print_digits("\t5:q = ", q);
+ print_digits("\t r = ", r);
+ return big_errno;
+}
+
+bigerr_t
+big_floor(a, b, q, r)
+bignum *a;
+bignum *b;
+bignum *q;
+bignum *r;
+{
+ int b_eq_qr, sign_eq;
+
+ if ( ( b_eq_qr = ((b == q) || (b == r)) ) )
+ {
+ big_set_big(b, &tmp_mul);
+ }
+ sign_eq = a->sign == b->sign;
+ big_trunc(a, b, q, r);
+ if (sign_eq)
+ {
+ return big_errno;
+ }
+ if (!zerop(r))
+ {
+ if (b_eq_qr)
+ {
+ big_add(r, &tmp_mul, r);
+ }
+ else
+ {
+ big_add(r, b, r);
+ }
+ print_digits("big_one = ", &big_one);
+ big_sub(q, &big_one, q);
+ }
+ return big_errno;
+}
+
+bigerr_t
+big_ceil(a, b, q, r)
+bignum *a;
+bignum *b;
+bignum *q;
+bignum *r;
+{
+ int b_eq_qr, sign_diff;
+
+ if ( ( b_eq_qr = ((b == q) || (b == r)) ) )
+ {
+ big_set_big(b, &tmp_mul);
+ }
+ sign_diff = a->sign != b->sign;
+ big_trunc(a, b, q, r);
+ if (sign_diff)
+ {
+ return big_errno;
+ }
+ if (!zerop(r))
+ {
+ if (b_eq_qr)
+ {
+ big_sub(r, &tmp_mul, r);
+ }
+ else
+ {
+ big_sub(r, b, r);
+ }
+ big_add(q, &big_one, q);
+ }
+ return big_errno;
+}
+
+#ifdef UNUSED_CODE
+/* This one doesn't work to 100%. I was a little braindamaged when I wrote
+ * this, but I'll eventually fix it. Zzzzzzz.
+ */
+bigerr_t
+big_round(a, b, q, r)
+bignum *a;
+bignum *b;
+bignum *q;
+bignum *r;
+{
+ int b_eq_qr, b_neg_p, a_sgn_neq_b_sgn;
+
+ if ( ( b_eq_qr = ((b == q) || (b == r)) ) )
+ {
+ big_set_big(b, &tmp_round);
+ }
+ b_neg_p = b->sign == BIG_SIGN_MINUS;
+ a_sgn_neq_b_sgn = a->sign != b->sign;
+ big_trunc(a, b, q, r);
+
+ big_set_big(r, &tmp_add);
+ umul_digit(&tmp_add, 2);
+ if (ucompare_digits(&tmp_add, b) > 0) /* |2 * r| > |b| */
+ {
+ if (q->sign == BIG_SIGN_0)
+ {
+ if (a_sgn_neq_b_sgn)
+ {
+ big_sub(q, &big_one, q);
+ }
+ else
+ {
+ big_add(q, &big_one, q);
+ }
+ }
+ else
+ {
+ if (q->sign == BIG_SIGN_MINUS)
+ {
+ big_sub(q, &big_one, q);
+ }
+ else
+ {
+ big_add(q, &big_one, q);
+ }
+ }
+ if (b_eq_qr)
+ {
+ if (q->sign == BIG_SIGN_PLUS)
+ {
+ big_sub(r, &tmp_round, r);
+ }
+ else
+ {
+ big_add(r, &tmp_round, r);
+ }
+ }
+ else
+ {
+ if (q->sign == BIG_SIGN_PLUS)
+ {
+ big_sub(r, b, r);
+ }
+ else
+ {
+ big_add(r, b, r);
+ }
+ }
+ }
+ return big_errno;
+}
+
+bigerr_t
+big_random(a, b)
+bignum *a;
+bignum *b;
+{
+ unsigned long i;
+ int a_sgn = a->sign;
+
+ if (big_errno != BIG_OK)
+ {
+ return big_errno;
+ }
+ if (zerop(a)) /* a = 0 -> big_random => 0 (special case) */
+ {
+ *b->dp = 0;
+ b->dgs_used = 1;
+ b->sign = a_sgn;
+ return big_errno;
+ }
+ if (newsize(&tmp_rand.dp, &tmp_rand.dgs_alloc,
+ a->dgs_used + 1, a->dgs_used + 1) != BIG_OK)
+ {
+ return big_errno;
+ }
+ for (i = 0; i <= a->dgs_used; i++)
+ {
+ tmp_rand.dp[i] = rand();
+ }
+ while (tmp_rand.dp[a->dgs_used] == 0) /* Make sure high digit is non-0 */
+ {
+ tmp_rand.dp[a->dgs_used] = rand();
+ }
+ tmp_rand.dgs_used = a->dgs_used + 1;
+ tmp_rand.sign = BIG_SIGN_PLUS;
+ a->sign = BIG_SIGN_PLUS;
+ big_trunc(&tmp_rand, a, &tmp_q, b); /* Dangerous to use tmp_q here... */
+ a->sign = a_sgn;
+ b->sign = zerop(&tmp_rand) ? BIG_SIGN_0 : a_sgn;
+ return big_errno;
+}
+
+/* UNUSED_CODE */
+#endif
+
+/* ----------------------------------------------------------------------
+ * External functions that do not need to know anything about the internal
+ * representation of a bignum.
+ */
+
+#ifdef UNUSED_CODE
+
+int
+big_expt(a, z, x)
+bignum *a;
+unsigned long z;
+bignum *x;
+{
+ bignum b;
+
+ big_create(&b);
+ big_set_big(a, &b);
+ big_set_long((long)1, x);
+
+ while ((z != 0) && (big_errno == BIG_OK))
+ {
+ while ((z & 0x01) == 0)
+ {
+ z >>= 1;
+ big_mul(&b, &b, &b);
+ }
+ z -= 1;
+ big_mul(x, &b, x);
+ }
+
+ big_destroy(&b);
+ return big_errno;
+}
+
+/* UNUSED_CODE */
+#endif
+
+int
+big_exptmod(a_in, z_in, n, x)
+bignum *a_in;
+bignum *z_in;
+bignum *n;
+bignum *x;
+{
+ bignum a, z, b0, b1, b2, dummy;
+
+ big_create(&a);
+ big_create(&z);
+ big_create(&b0);
+ big_create(&b1);
+ big_create(&b2);
+ big_create(&dummy);
+
+ big_set_big(a_in, &a);
+ big_set_big(z_in, &z);
+ big_set_long((long)1, x);
+ big_set_long((long)0, &b0);
+ big_set_long((long)1, &b1);
+ big_set_long((long)2, &b2);
+
+ /* No foolproof testing on big_errno - it really ought to be done */
+ while ((big_compare(&z, &b0) != 0) && (big_errno == BIG_OK))
+ {
+ while (big_evenp(&z) && (big_errno == BIG_OK))
+ {
+ big_trunc(&z, &b2, &z, &dummy);
+ big_mul(&a, &a, &a);
+ big_trunc(&a, n, &dummy, &a);
+ }
+ big_sub(&z, &b1, &z);
+ big_mul(x, &a, x);
+ big_trunc(x, n, &dummy, x);
+ }
+
+ big_destroy(&dummy);
+ big_destroy(&b2);
+ big_destroy(&b1);
+ big_destroy(&b0);
+ big_destroy(&z);
+ big_destroy(&a);
+
+ return big_errno;
+}
+
+#ifdef UNUSED_CODE
+
+int
+big_gcd(a, b, g)
+bignum *a;
+bignum *b;
+bignum *g;
+{
+ bignum a1, b1, tmp;
+
+ if (big_zerop(b))
+ {
+ big_abs(a, g);
+ return big_errno;
+ }
+
+ big_create(&a1);
+ big_create(&b1);
+ big_create(&tmp);
+
+ big_abs(a, &a1);
+ big_abs(b, &b1);
+
+ while (!big_zerop(&b1) && (big_errno == BIG_OK))
+ {
+ big_floor(&a1, &b1, &tmp, &a1);
+ if (big_zerop(&a1))
+ {
+ break;
+ }
+ big_floor(&b1, &a1, &tmp, &b1);
+ }
+
+ if (big_zerop(&a1))
+ {
+ big_set_big(&b1, g);
+ }
+ else
+ {
+ big_set_big(&a1, g);
+ }
+
+ big_destroy(&tmp);
+ big_destroy(&b1);
+ big_destroy(&a1);
+
+ return big_errno;
+}
+/* UNUSED_CODE */
+#endif
+
+/* #if (defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER)) */
+#endif
+
diff --git a/src/cutest_sh_hash.c b/src/cutest_sh_hash.c
new file mode 100644
index 0000000..b0b9477
--- /dev/null
+++ b/src/cutest_sh_hash.c
@@ -0,0 +1,121 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include "CuTest.h"
+
+extern char * quote_string (const char * str, size_t len);
+extern char * unquote_string (const char * str, size_t len);
+
+void Test_quote_string_ok (CuTest *tc) {
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ char * ret = 0;
+
+ char inp1[] = "foo\nba=r\ntest";
+ char out1[] = "foo=0Aba=3Dr=0Atest";
+
+ char inp2[] = "\n=foo\nba=r\ntest=\n";
+ char out2[] = "=0A=3Dfoo=0Aba=3Dr=0Atest=3D=0A";
+
+ ret = quote_string(inp1, strlen(inp1));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, out1, ret);
+
+ ret = quote_string(inp2,strlen(inp2));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, out2, ret);
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+
+void Test_unquote_string_ok (CuTest *tc) {
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ char * ret = 0;
+
+ char out1[] = "foo\nba=r\ntes[t";
+ char inp1[] = "foo=0Aba=3Dr=0Ates=5Bt";
+
+ char out2[] = "\n=foo\nba=r\ntest=\n";
+ char inp2[] = "=0A=3Dfoo=0Aba=3Dr=0Atest=3D=0A";
+
+ char out3[] = ""; /* encoded '\0' at start */
+ char inp3[] = "=00=3Dfoo=0Aba=3Dr=0Atest=3D=0A";
+
+ ret = unquote_string(inp1, strlen(inp1));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, out1, ret);
+
+ ret = unquote_string(inp2, strlen(inp2));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, out2, ret);
+
+ ret = unquote_string(inp3, strlen(inp3));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, out3, ret);
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+
+
+void Test_csv_escape_ok (CuTest *tc) {
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+ extern char * csv_escape(const char * str);
+
+ char test0[80];
+ char expec[80];
+ char *ret;
+
+ strcpy(test0, "foobar");
+ strcpy(expec, "\"foobar\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "\"foobar\"");
+ strcpy(expec, "\"\"\"foobar\"\"\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "foo,bar");
+ strcpy(expec, "\"foo,bar\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "foob,\"a\"r");
+ strcpy(expec, "\"foob,\"\"a\"\"r\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "\",\"foobar\",\"");
+ strcpy(expec, "\"\"\",\"\"foobar\"\",\"\"\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "");
+ strcpy(expec, "");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "a");
+ strcpy(expec, "\"a\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+ strcpy(test0, "foo\"bar");
+ strcpy(expec, "\"foo\"\"bar\"");
+ ret = csv_escape(test0);
+ CuAssertStrEquals(tc, expec, ret);
+
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+
+
+
diff --git a/src/cutest_sh_tiger0.c b/src/cutest_sh_tiger0.c
new file mode 100644
index 0000000..b712203
--- /dev/null
+++ b/src/cutest_sh_tiger0.c
@@ -0,0 +1,460 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "CuTest.h"
+
+#include "sh_tiger.h"
+#include "sh_checksum.h"
+
+#if defined(HAVE_PTHREAD) && defined(SH_STEALTH)
+extern void sh_g_init(void);
+#endif
+
+
+static void init(void) {
+
+ extern unsigned char TcpFlag[8][PW_LEN+1];
+ extern UINT32 ErrFlag[2];
+ unsigned char * dez = NULL;
+ int i;
+
+#if defined(HAVE_PTHREAD) && defined(SH_STEALTH)
+ sh_g_init();
+#endif
+ skey = (sh_key_t *) malloc (sizeof(sh_key_t));
+ if (skey != NULL)
+ {
+ skey->mlock_failed = S_FALSE;
+ skey->rngI = BAD;
+ /* properly initialized later
+ */
+ skey->rng0[0] = 0x03; skey->rng0[1] = 0x09; skey->rng0[2] = 0x17;
+ skey->rng1[0] = 0x03; skey->rng1[1] = 0x09; skey->rng1[2] = 0x17;
+ skey->rng2[0] = 0x03; skey->rng2[1] = 0x09; skey->rng2[2] = 0x17;
+
+ for (i = 0; i < KEY_BYT; ++i)
+ skey->poolv[i] = '\0';
+
+ skey->poolc = 0;
+
+ skey->ErrFlag[0] = ErrFlag[0];
+ ErrFlag[0] = 0;
+ skey->ErrFlag[1] = ErrFlag[1];
+ ErrFlag[1] = 0;
+
+ dez = &(TcpFlag[POS_TF-1][0]);
+ for (i = 0; i < PW_LEN; ++i)
+ {
+ skey->pw[i] = (char) (*dez);
+ (*dez) = '\0';
+ ++dez;
+ }
+
+ skey->sh_sockpass[0] = '\0';
+ skey->sigkey_old[0] = '\0';
+ skey->sigkey_new[0] = '\0';
+ skey->mailkey_old[0] = '\0';
+ skey->mailkey_new[0] = '\0';
+ skey->crypt[0] = '\0';
+ skey->session[0] = '\0';
+ skey->vernam[0] = '\0';
+ }
+ else
+ {
+ perror(_("sh_init"));
+ _exit (EXIT_FAILURE);
+ }
+
+}
+
+void Test_tiger(CuTest *tc) {
+
+ char * input;
+ char * actual;
+ char * expected;
+ char hashbuf[KEYBUF_SIZE];
+
+#if defined(HAVE_PTHREAD) && defined(SH_STEALTH)
+ sh_g_init();
+#endif
+
+ input = "";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "24F0130C63AC933216166E76B1BB925FF373DE2D49584E7A";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "abc";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "F258C1E88414AB2A527AB541FFC5B8BF935F7B951C132951";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "Tiger";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "9F00F599072300DD276ABB38C8EB6DEC37790C116F9D2BDF";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "87FB2A9083851CF7470D2CF810E6DF9EB586445034A5A386";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "467DB80863EBCE488DF1CD1261655DE957896565975F9197";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "0C410A042968868A1671DA5A3FD29A725EC1E457D3CDB303";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "EBF591D5AFA655CE7F22894FF87F54AC89C811B6B0DA3193";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "3D9AEB03D1BD1A6357B2774DFD6D5B24DD68151D503974FC";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+ actual = sh_tiger_hash(input, TIGER_DATA, strlen(input), hashbuf, sizeof(hashbuf));
+ expected = "00B83EB4E53440C576AC6AAEE0A7485825FD15E70A59FFE4";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_tiger_file(CuTest *tc) {
+
+ SL_TICKET rval_open;
+ FILE * fp;
+ int result;
+ char * actual;
+ char * expected;
+ char hashbuf[KEYBUF_SIZE];
+ char hexdigest[SHA256_DIGEST_STRING_LENGTH];
+ UINT64 length;
+
+ init();
+
+ fp = fopen("cutest_foo", "w");
+ CuAssertPtrNotNull(tc, fp);
+
+ result = fprintf(fp, "%s\n",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789");
+ CuAssertTrue(tc, result >= 0);
+
+ result = fclose(fp);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("TIGER192");
+ CuAssertTrue(tc, result == 0);
+
+ /* same result as GnuPG 1.0.6 (gpg --load-extension tiger --print-md TIGER192)
+ */
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "0E9321614C966A33608C2A15F156E0435CACFD1213B9F095";
+ CuAssertStrEquals(tc, expected, actual);
+
+ rval_open = sl_open_fastread (__FILE__, __LINE__, "cutest_foo", SL_YESPRIV);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "0E9321614C966A33608C2A15F156E0435CACFD1213B9F095";
+ CuAssertStrEquals(tc, expected, actual);
+
+ result = sl_close(rval_open);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("MD5");
+ CuAssertTrue(tc, result == 0);
+
+ rval_open = sl_open_fastread (__FILE__, __LINE__, "cutest_foo", SL_YESPRIV);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ /* same result as GNU md5sum
+ */
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "AEEC4DDA496BCFBA691F4E8863BA84C00000000000000000";
+ CuAssertStrEquals(tc, expected, actual);
+
+ result = sl_close(rval_open);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("SHA1");
+ CuAssertTrue(tc, result == 0);
+
+ rval_open = sl_open_fastread (__FILE__, __LINE__, "cutest_foo", SL_YESPRIV);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ /* same result as gpg --print-md SHA1
+ */
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "2FE65D1D995B8F8BC8B13F798C07E7E935A787ED00000000";
+ CuAssertStrEquals(tc, expected, actual);
+
+ result = sl_close(rval_open);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("SHA256");
+ CuAssertTrue(tc, result == 0);
+
+ rval_open = sl_open_fastread (__FILE__, __LINE__, "cutest_foo", SL_YESPRIV);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ /* same result as gpg --print-md SHA256
+ */
+ length = TIGER_NOLIM;
+ {
+ char * tmp = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ actual = SHA256_Base2Hex(tmp, hexdigest);
+ }
+ expected = "235790848f95e96b2c627f1bf58a2b8c05c535ada8c0a3326aac34ce1391ad40";
+ CuAssertStrEquals(tc, expected, actual);
+
+ result = sl_close(rval_open);
+ CuAssertTrue(tc, result == 0);
+
+ result = remove("cutest_foo");
+ CuAssertTrue(tc, result == 0);
+
+ /* --------------------------------------------------- */
+
+ fp = fopen("cutest_foo", "w");
+ CuAssertPtrNotNull(tc, fp);
+
+ result = fprintf(fp, "\n");
+ CuAssertTrue(tc, result >= 0);
+
+ result = fclose(fp);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("TIGER192");
+ CuAssertTrue(tc, result == 0);
+
+ /* same result as GnuPG 1.0.6 (gpg --load-extension tiger --print-md TIGER192)
+ */
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "F987845A0EA784367BF9E4DB09014995810F27C99C891734";
+ CuAssertStrEquals(tc, expected, actual);
+
+ result = remove("cutest_foo");
+ CuAssertTrue(tc, result == 0);
+
+ /* --------------------------------------------------- */
+
+ fp = fopen("cutest_foo", "w");
+ CuAssertPtrNotNull(tc, fp);
+
+ result = fprintf(fp, "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.\n");
+ CuAssertTrue(tc, result >= 0);
+
+ result = fclose(fp);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("TIGER192");
+ CuAssertTrue(tc, result == 0);
+
+ /* same result as GnuPG 1.0.6 (gpg --load-extension tiger --print-md TIGER192)
+ */
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "75B98A7AE257A230189828A40792E30B4038D286479CC7B8";
+ CuAssertStrEquals(tc, expected, actual);
+
+ result = remove("cutest_foo");
+ CuAssertTrue(tc, result == 0);
+
+}
+
+/* test checksum of file upto some given length
+ */
+void Test_tiger_file_with_length(CuTest *tc) {
+
+ SL_TICKET rval_open;
+ FILE * fp;
+ int result;
+ char * actual;
+ char * expected;
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 length;
+
+ char * teststring = "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.\n";
+ size_t testlen = strlen(teststring);
+
+ init();
+
+ fp = fopen("cutest_foo", "w");
+ CuAssertPtrNotNull(tc, fp);
+
+ result = fprintf(fp, "%s", teststring);
+ CuAssertTrue(tc, result >= 0);
+ result = fprintf(fp, "%s", teststring);
+ CuAssertTrue(tc, result >= 0);
+
+ result = fclose(fp);
+ CuAssertTrue(tc, result == 0);
+
+ result = sh_tiger_hashtype("TIGER192");
+ CuAssertTrue(tc, result == 0);
+
+ /* same as GnuPG 1.0.6 (gpg --load-extension tiger --print-md TIGER192)
+ */
+ length = 0;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "24F0130C63AC933216166E76B1BB925FF373DE2D49584E7A";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 0 == length);
+
+ length = testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "75B98A7AE257A230189828A40792E30B4038D286479CC7B8";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, testlen == length);
+
+ length = 2*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "B5B4FB97B01ADB58794D87A6A01B2368852FA764BD93AB90";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 2*testlen == length);
+
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "B5B4FB97B01ADB58794D87A6A01B2368852FA764BD93AB90";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 2*testlen == length);
+
+ fp = fopen("cutest_foo", "a");
+ CuAssertPtrNotNull(tc, fp);
+ result = fprintf(fp, "%s", teststring);
+ CuAssertTrue(tc, result >= 0);
+ result = fclose(fp);
+ CuAssertTrue(tc, result == 0);
+
+ length = testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "75B98A7AE257A230189828A40792E30B4038D286479CC7B8";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, testlen == length);
+
+ length = 2*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "B5B4FB97B01ADB58794D87A6A01B2368852FA764BD93AB90";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 2*testlen == length);
+
+ length = 3*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "D0EE1A9956CAB22D84B51A5E0C093B724828C6A1F9CBDB7F";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 3*testlen == length);
+
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "D0EE1A9956CAB22D84B51A5E0C093B724828C6A1F9CBDB7F";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 3*testlen == length);
+
+ length = 5;
+ actual = sh_tiger_generic_hash("cutest_foo", TIGER_FILE, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "9F00F599072300DD276ABB38C8EB6DEC37790C116F9D2BDF";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 5 == length);
+
+ /* same results as GNU md5sum */
+
+ result = sh_tiger_hashtype("MD5");
+ CuAssertTrue(tc, result == 0);
+
+ rval_open = sl_open_fastread (__FILE__, __LINE__, "cutest_foo", SL_YESPRIV);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "11E7E7EA486136273606BEE57C71F34B0000000000000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, testlen == length);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = 2*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "D49DAD474095D467E2E5EFCB2DC23A770000000000000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 2*testlen == length);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = 3*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "00A1F1C5EDDCCFC430D3862FDA94593E0000000000000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 3*testlen == length);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "00A1F1C5EDDCCFC430D3862FDA94593E0000000000000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 3*testlen == length);
+
+ /* same result as gpg --print-md SHA1
+ */
+
+ result = sh_tiger_hashtype("SHA1");
+ CuAssertTrue(tc, result == 0);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "F37DB4344CCD140EE315179E9A27512FB4704F0F00000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, testlen == length);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = 2*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "D2AD5FC366452D81400BAC31F96269DEEF314BC200000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 2*testlen == length);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = 3*testlen;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "FAA937EF3389C7E786EB0F1006D049D7AEA7B7B600000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 3*testlen == length);
+
+ result = sl_rewind(rval_open);
+ CuAssertTrue(tc, rval_open >= 0);
+
+ length = TIGER_NOLIM;
+ actual = sh_tiger_generic_hash("cutest_foo", rval_open, &length, 0, hashbuf, sizeof(hashbuf));
+ expected = "FAA937EF3389C7E786EB0F1006D049D7AEA7B7B600000000";
+ CuAssertStrEquals(tc, expected, actual);
+ CuAssertTrue(tc, 3*testlen == length);
+
+ result = sl_close(rval_open);
+ CuAssertTrue(tc, result == 0);
+
+ result = remove("cutest_foo");
+ CuAssertTrue(tc, result == 0);
+}
diff --git a/src/cutest_sh_tools.c b/src/cutest_sh_tools.c
new file mode 100644
index 0000000..6f9fcfe
--- /dev/null
+++ b/src/cutest_sh_tools.c
@@ -0,0 +1,138 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include "CuTest.h"
+#include "samhain.h"
+#include "sh_tools.h"
+#include "sh_ipvx.h"
+
+void Test_sh_tools_safe_name_01(CuTest *tc) {
+ /* xml specific */
+ char* input = strdup("hello<wo>rld\"foo&");
+ char* actual = sh_tools_safe_name(input, 1);
+#ifdef SH_USE_XML
+ char* expected = "hello=3cwo=3erld=22foo=26";
+#else
+ char* expected = "hello<wo>rld\"foo&";
+#endif
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_sh_tools_safe_name_02(CuTest *tc) {
+ /* html entities */
+ char* input = strdup("hello&amp;&quot;&gt;&lt;");
+ char* actual = sh_tools_safe_name(input, 0);
+ char* expected = "hello=26=22=3e=3c";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_sh_tools_safe_name_03(CuTest *tc) {
+ char* input = strdup("\\\'hello\\");
+ char* actual = sh_tools_safe_name(input, 0);
+ char* expected = "=27hello";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = strdup("hello \"world\\\"");
+ actual = sh_tools_safe_name(input, 0);
+ expected = "hello \"world=22";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = strdup("hello\\\\");
+ actual = sh_tools_safe_name(input, 0);
+ expected = "hello=5c";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = strdup("hello\\n");
+ actual = sh_tools_safe_name(input, 0);
+ expected = "hello=0a";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_sh_tools_safe_name_04(CuTest *tc) {
+ /* invalid and valid octal code */
+ char* input = strdup("hello\\\n");
+ char* actual = sh_tools_safe_name(input, 0);
+ char* expected = "hello";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = strdup("hello\\100");
+ actual = sh_tools_safe_name(input, 0);
+ expected = "hello=40";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = strdup("h\\\"ello\\100a");
+ actual = sh_tools_safe_name(input, 0);
+ expected = "h=22ello=40a";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_sh_tools_safe_name_05(CuTest *tc) {
+ /* encoding of '=' */
+ char* input = strdup("he=llo=\"foo\"");
+ char* actual = sh_tools_safe_name(input, 0);
+ char* expected = "he=3dllo=\"foo\"";
+ CuAssertStrEquals(tc, expected, actual);
+
+ input = strdup("he=llo=<foo>");
+ actual = sh_tools_safe_name(input, 0);
+ expected = "he=3dllo=<foo>";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_sh_tools_safe_name_06(CuTest *tc) {
+ /* line break removal */
+ char* input = strdup("hello\nworld");
+ char* actual = sh_tools_safe_name(input, 0);
+ char* expected = "hello world";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_sh_tools_safe_name_07(CuTest *tc) {
+ /* non-printable chars */
+ char* input = strdup("hello world");
+ char* actual;
+ char* expected;
+
+ input[0] = 0x01;
+ input[5] = 0xFF;
+ input[10] = 0xF0;
+
+ actual = sh_tools_safe_name(input, 0);
+ expected = "=01ello=ffworl=f0";
+ CuAssertStrEquals(tc, expected, actual);
+}
+
+void Test_is_numeric_01(CuTest *tc) {
+ char* input = strdup("hello world");
+
+ CuAssertTrue(tc, !sh_ipvx_is_numeric(input));
+
+ input = strdup("127.0.0.1");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("127.0.0.de");
+ CuAssertTrue(tc, !sh_ipvx_is_numeric(input));
+ input = strdup("127");
+ CuAssertTrue(tc, !sh_ipvx_is_numeric(input));
+#if defined(USE_IPVX)
+ input = strdup("::1");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("2002:c0a8:101::42");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("2003:dead:beef:4dad:23:46:bb:101");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("::192:168:0:1::");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("1:1:192:168:0:1:1:1");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("1:1:192:168:0:1:1:1:0");
+ CuAssertTrue(tc, !sh_ipvx_is_numeric(input));
+ input = strdup("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("2001:db8:85a3:0:0:8a2e:370:7334");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+ input = strdup("2001:db8:85a3::8a2e:370:7334");
+ CuAssertTrue(tc, sh_ipvx_is_numeric(input));
+#endif
+}
+
diff --git a/src/cutest_sh_unix.c b/src/cutest_sh_unix.c
new file mode 100644
index 0000000..57fb7e6
--- /dev/null
+++ b/src/cutest_sh_unix.c
@@ -0,0 +1,199 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include "CuTest.h"
+#include "samhain.h"
+#include "sh_unix.h"
+
+int malloc_count = 0;
+
+void Test_dnmalloc (CuTest *tc) {
+
+ const int nalloc = 64 /* original dnmalloc 1.0-beta5 fails for >= 45 */;
+ int j, i;
+ int sum;
+#ifndef USE_SYSTEM_MALLOC
+ int i_malloc = malloc_count;
+#endif
+
+ char * buf;
+ char * area[256];
+
+ /* test reuse of last freed chunk */
+ buf = malloc(1024);
+ CuAssertPtrNotNull(tc, buf);
+ free(buf);
+ area[0] = malloc(1024);
+ CuAssertTrue(tc, buf == area[0]);
+ free(area[0]);
+
+ /* test realloc */
+ buf = malloc(16);
+ CuAssertPtrNotNull(tc, buf);
+ strcpy(buf, "testing realloc");
+ buf = realloc(buf, 32);
+ strcat(buf, "testing realloc");
+ CuAssertStrEquals(tc, "testing realloctesting realloc", buf);
+
+#ifndef USE_SYSTEM_MALLOC
+ i_malloc = malloc_count;
+#endif
+
+ for (j = 0; j < 64; ++j)
+ {
+ buf = malloc((j+1) * 1024);
+ CuAssertPtrNotNull(tc, buf);
+#ifndef USE_SYSTEM_MALLOC
+#ifndef __clang__
+ CuAssertIntEquals (tc, malloc_count, (i_malloc + 1));
+#endif
+#endif
+ free(buf);
+#ifndef USE_SYSTEM_MALLOC
+ CuAssertIntEquals (tc, malloc_count, i_malloc);
+#endif
+ }
+
+ /* test realloc */
+ buf = malloc(16);
+ CuAssertPtrNotNull(tc, buf);
+ strcpy(buf, "testing realloc");
+ buf = realloc(buf, 32);
+ strcat(buf, "testing realloc");
+ CuAssertStrEquals(tc, "testing realloctesting realloc", buf);
+
+#ifndef USE_SYSTEM_MALLOC
+ i_malloc = malloc_count;
+#endif
+
+ for (j = 0; j < 64; ++j)
+ {
+ buf = calloc(1, (j+1) * 1024);
+ CuAssertPtrNotNull(tc, buf);
+#ifndef USE_SYSTEM_MALLOC
+ CuAssertIntEquals (tc, malloc_count, (i_malloc + 1));
+#endif
+ sum = 0;
+ for (i = 0; i < ((j+1) * 1024); ++i)
+ sum += buf[i];
+ CuAssertIntEquals (tc, 0, sum);
+ free(buf);
+#ifndef USE_SYSTEM_MALLOC
+ CuAssertIntEquals (tc, malloc_count, i_malloc);
+#endif
+ }
+
+ /* test realloc */
+ buf = malloc(16);
+ CuAssertPtrNotNull(tc, buf);
+ strcpy(buf, "testing realloc");
+ buf = realloc(buf, 32);
+ strcat(buf, "testing realloc");
+ CuAssertStrEquals(tc, "testing realloctesting realloc", buf);
+
+ for (j = 0; j < nalloc; ++j)
+ {
+ area[j] = malloc((j+1) * 1024);
+ CuAssertPtrNotNull(tc, area[j]);
+#ifndef USE_SYSTEM_MALLOC
+ /* CuAssertIntEquals (tc, malloc_count, (i_malloc + (j+1))); */
+#endif
+ memset(area[j], (unsigned char) ('a'+1), (j+1) * 1024);
+ }
+
+#ifndef USE_SYSTEM_MALLOC
+ i_malloc = malloc_count;
+#endif
+
+ for (j = 0; j < nalloc; ++j)
+ {
+ sum = 0;
+ for (i = 0; i < ((j+1) * 1024); ++i)
+ sum += area[j][i];
+ CuAssertIntEquals (tc, sum, ((j+1) * 1024 * ((unsigned char) ('a'+1))));
+ free(area[j]);
+#ifndef USE_SYSTEM_MALLOC
+ CuAssertIntEquals (tc, malloc_count, i_malloc - (j+1));
+#endif
+ }
+
+ /* test realloc */
+ buf = malloc(16);
+ CuAssertPtrNotNull(tc, buf);
+ strcpy(buf, "testing realloc");
+ buf = realloc(buf, 32);
+ strcat(buf, "testing realloc");
+ CuAssertStrEquals(tc, "testing realloctesting realloc", buf);
+
+
+ for (j = 0; j < 32; ++j)
+ {
+#ifndef USE_SYSTEM_MALLOC
+ i_malloc = malloc_count;
+#endif
+ buf = malloc((j+1) * 1024 * 1024);
+ CuAssertPtrNotNull(tc, buf);
+ for (i = 0; i < 32; ++i)
+ {
+ area[i] = malloc((i+1) * 1024);
+ CuAssertPtrNotNull(tc, area[i]);
+ }
+ free(buf);
+ for (i = 0; i < 32; ++i)
+ {
+ free(area[i]);
+ }
+#ifndef USE_SYSTEM_MALLOC
+ CuAssertIntEquals (tc, malloc_count, i_malloc);
+#endif
+ }
+
+ /* test realloc */
+ buf = malloc(16);
+ CuAssertPtrNotNull(tc, buf);
+ strcpy(buf, "testing realloc");
+ buf = realloc(buf, 32);
+ strcat(buf, "testing realloc");
+ CuAssertStrEquals(tc, "testing realloctesting realloc", buf);
+}
+
+
+void Test_sh_unix_lookup_page (CuTest *tc) {
+
+ long pagesize = sh_unix_pagesize();
+
+ unsigned long base;
+ int num_pages;
+
+ CuAssert (tc, "pagesize > 0", (pagesize > 0));
+
+ /* base = sh_unix_lookup_page(in_addr, len, *num_pages); */
+
+ base = sh_unix_lookup_page(0, pagesize, &num_pages);
+ CuAssert (tc, "base == 0", (base == 0));
+ CuAssertIntEquals (tc, num_pages, 1);
+
+ base = sh_unix_lookup_page(0, pagesize+1, &num_pages);
+ CuAssert (tc, "base == 0", (base == 0));
+ CuAssertIntEquals (tc, num_pages, 2);
+
+ base = sh_unix_lookup_page((void*)pagesize, pagesize, &num_pages);
+ CuAssert (tc, "base == 0", (base == (unsigned int)pagesize));
+ CuAssertIntEquals (tc, num_pages, 1);
+
+ base = sh_unix_lookup_page((void*)pagesize, pagesize+1, &num_pages);
+ CuAssert (tc, "base == 0", (base == (unsigned int)pagesize));
+ CuAssertIntEquals (tc, num_pages, 2);
+
+ base = sh_unix_lookup_page((void*)(pagesize-1), pagesize+1, &num_pages);
+ CuAssert (tc, "base == 0", (base == 0));
+ CuAssertIntEquals (tc, num_pages, 2);
+
+ base = sh_unix_lookup_page((void*)(pagesize-1), pagesize+2, &num_pages);
+ CuAssert (tc, "base == 0", (base == 0));
+ CuAssertIntEquals (tc, num_pages, 3);
+
+}
+
+
diff --git a/src/cutest_sh_utils.c b/src/cutest_sh_utils.c
new file mode 100644
index 0000000..99fbfce
--- /dev/null
+++ b/src/cutest_sh_utils.c
@@ -0,0 +1,532 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include "CuTest.h"
+#include "samhain.h"
+#include "sh_utils.h"
+
+void Test_sl_strlcpy (CuTest *tc) {
+ int ret;
+ char out[] = "aaaaaa";
+ char in[] = "bbb";
+
+ ret = sl_strlcpy (NULL, NULL, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcpy (NULL, in, 0);
+ CuAssertIntEquals(tc, ret, SL_ENULL);
+
+ ret = sl_strlcpy (out, NULL, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcpy (out, in, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcpy (out, NULL, 7);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+ CuAssertStrEquals(tc, "", out);
+
+ out[0] = 'a';
+ ret = sl_strlcpy (out, in, 4);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+ CuAssertStrEquals(tc, "bbb", out);
+ CuAssertStrEquals(tc, "aa", &out[4]);
+
+ return;
+}
+
+void Test_sl_strlcat (CuTest *tc) {
+ int ret;
+ char out[16] = "aaaaaa";
+ char in[16] = "bbb";
+
+ ret = sl_strlcat (NULL, NULL, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcat (NULL, in, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcat (out, NULL, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcat (out, in, 0);
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+
+ ret = sl_strlcat (out, NULL, sizeof(out));
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+ CuAssertStrEquals(tc, "aaaaaa", out);
+
+ ret = sl_strlcat (out, in, 7);
+ CuAssertIntEquals(tc, ret, SL_ETRUNC);
+ CuAssertStrEquals(tc, "aaaaaa", out);
+
+ ret = sl_strlcat (out, in, 8);
+ CuAssertIntEquals(tc, ret, SL_ETRUNC);
+ CuAssertStrEquals(tc, "aaaaaab", out);
+
+ ret = sl_strlcat (out, in, sizeof(out));
+ CuAssertIntEquals(tc, ret, SL_ENONE);
+ CuAssertStrEquals(tc, "aaaaaabbbb", out);
+
+ CuAssertStrEquals(tc, "bbb", in);
+
+ return;
+}
+
+void Test_sh_util_acl_compact (CuTest *tc) {
+ char * ret = 0;
+ char inp1[] = "user::r--\nuser:lisa:rwx\t\t#effective: r--\ngroup::r--\ngroup:toolies:rw- #effective: r--\nmask::r--\nother::r--\n";
+ char inp2[] = "use\n\nuser:lisa:rwx\t\t#effective: r--\ngroup::r--\ngroup:toolies:rw- #effective: r--\nmask::r--\nother::r--\n";
+ char inp3[] = "user:\177\145\177\122:r--\nuser:lisa:rwx\t\t#effective: r--\ngroup::r--\ngroup:toolies:rw- #effective: r--\nmask::r--\nother::r--\n";
+
+ ret = sh_util_acl_compact (inp1, strlen(inp1));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, "u::r--,u:lisa:rwx,g::r--,g:toolies:rw-,m::r--,o::r--",
+ ret);
+
+ ret = sh_util_acl_compact (inp2, strlen(inp2));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, "use,u:lisa:rwx,g::r--,g:toolies:rw-,m::r--,o::r--",
+ ret);
+
+ ret = sh_util_acl_compact (inp3, strlen(inp3));
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, "u:eR:r--,u:lisa:rwx,g::r--,g:toolies:rw-,m::r--,o::r--",
+ ret);
+
+ return;
+}
+
+void Test_sh_util_strdup_ok (CuTest *tc) {
+ char * ret = 0;
+ char inp[] = "foobar";
+
+ ret = sh_util_strdup(inp);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssert(tc, "expected inp != ret, but inp == ret", (inp != ret));
+ CuAssertStrEquals(tc, "foobar", ret);
+ return;
+}
+
+void Test_sh_util_strconcat_ok (CuTest *tc) {
+ char * ret = 0;
+
+ ret = sh_util_strconcat("foo", NULL);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, "foo", ret);
+
+ ret = sh_util_strconcat("foo", "bar", NULL);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, "foobar", ret);
+
+ ret = sh_util_strconcat("/", "foo", "/", "bar", NULL);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, "/foo/bar", ret);
+
+ return;
+}
+
+void Test_sh_util_base64_enc_ok (CuTest *tc) {
+ unsigned char out[64];
+ unsigned char ou2[64];
+ int ret;
+ unsigned char inp0[64] = "";
+ unsigned char inp1[64] = "A";
+ unsigned char inp2[64] = "AB";
+ unsigned char inp3[64] = "ABC";
+ unsigned char inp4[64] = "ABCD";
+
+ ret = sh_util_base64_enc (out, inp0, strlen((char*)inp0));
+ CuAssertIntEquals(tc, 0, ret);
+ CuAssertStrEquals(tc, "", (char*)out);
+ ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+ CuAssertIntEquals(tc, ret, 0);
+ CuAssertStrEquals(tc, (char*)inp0, (char*)ou2);
+
+ ret = sh_util_base64_enc (out, inp1, strlen((char*)inp1));
+ CuAssertIntEquals(tc, ret, 4);
+ CuAssertStrEquals(tc, "QQ??", (char*)out);
+ ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+ CuAssertStrEquals(tc, (char*)inp1, (char*)ou2);
+ CuAssertIntEquals(tc, 1, ret);
+
+ ret = sh_util_base64_enc (out, inp2, strlen((char*)inp2));
+ CuAssertIntEquals(tc, ret, 4);
+ CuAssertStrEquals(tc, "QUI?", (char*)out);
+ ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+ CuAssertStrEquals(tc, (char*)inp2, (char*)ou2);
+ CuAssertIntEquals(tc, 2, ret);
+
+ ret = sh_util_base64_enc (out, inp3, strlen((char*)inp3));
+ CuAssertIntEquals(tc, ret, 4);
+ CuAssertStrEquals(tc, "QUJD", (char*)out);
+ ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+ CuAssertStrEquals(tc, (char*)inp3, (char*)ou2);
+ CuAssertIntEquals(tc, 3, ret);
+
+ ret = sh_util_base64_enc (out, inp4, strlen((char*)inp4));
+ CuAssertIntEquals(tc, ret, 8);
+ CuAssertStrEquals(tc, "QUJDRA??", (char*)out);
+ ret = sh_util_base64_dec (ou2, out, strlen((char*)out));
+ CuAssertStrEquals(tc, (char*)inp4, (char*)ou2);
+ CuAssertIntEquals(tc, 4, ret);
+
+
+ return;
+}
+
+void Test_sh_util_dirname_ok (CuTest *tc) {
+ char * ret = 0;
+
+ char input0[] = "/foo/bar";
+ char res0[] = "/foo";
+
+ char input1[] = "/foo/bar/";
+ char res1[] = "/foo";
+
+ char input2[] = "/foo";
+ char res2[] = "/";
+
+ char input3[] = "/";
+ char res3[] = "/";
+
+ char input4[] = "///foo//bar";
+ char res4[] = "///foo";
+
+ char input5[] = "//foo///bar///";
+ char res5[] = "//foo";
+
+ char input6[] = "///";
+ char res6[] = "///";
+
+ char input7[] = "//f///b///";
+ char res7[] = "//f";
+
+ char input8[] = "/f/b/";
+ char res8[] = "/f";
+
+ char input9[] = "/e/b";
+ char res9[] = "/e";
+
+ ret = sh_util_dirname(input0);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res0, ret);
+
+ ret = sh_util_dirname(input1);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res1, ret);
+
+ ret = sh_util_dirname(input2);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res2, ret);
+
+ ret = sh_util_dirname(input3);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res3, ret);
+
+ ret = sh_util_dirname(input4);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res4, ret);
+
+ ret = sh_util_dirname(input5);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res5, ret);
+
+ ret = sh_util_dirname(input6);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res6, ret);
+
+ ret = sh_util_dirname(input7);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res7, ret);
+
+ ret = sh_util_dirname(input8);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res8, ret);
+
+ ret = sh_util_dirname(input9);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res9, ret);
+ return;
+}
+
+void Test_sh_util_basename_ok (CuTest *tc) {
+ char * ret = 0;
+
+ char input0[] = "/foo/bar";
+ char res0[] = "bar";
+
+ char input1[] = "/foo/";
+ char res1[] = "foo";
+
+ char input2[] = "/foo";
+ char res2[] = "foo";
+
+ char input3[] = "/";
+ char res3[] = "/";
+
+ char input4[] = "/foo/bar/";
+ char res4[] = "bar";
+
+ char input5[] = "/foo///bar///";
+ char res5[] = "bar";
+
+ char input6[] = "//foo";
+ char res6[] = "foo";
+
+ ret = sh_util_basename(input0);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res0, ret);
+
+ ret = sh_util_basename(input1);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res1, ret);
+
+ ret = sh_util_basename(input2);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res2, ret);
+
+ ret = sh_util_basename(input3);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res3, ret);
+
+ ret = sh_util_basename(input4);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res4, ret);
+
+ ret = sh_util_basename(input5);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res5, ret);
+
+ ret = sh_util_basename(input6);
+ CuAssertPtrNotNull(tc, ret);
+ CuAssertStrEquals(tc, res6, ret);
+
+ return;
+}
+
+void Test_sh_util_utf8_ok (CuTest *tc) {
+ int ret = 0;
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ unsigned char seq[16];
+ unsigned char input[16] = "foobar";
+
+ seq[0] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xd7; seq[1] = 0x90; seq[2] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xed; seq[1] = 0x9f; seq[2] = 0xbf; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xee; seq[1] = 0x80; seq[2] = 0x80; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xef; seq[1] = 0xbf; seq[2] = 0xbd; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xf4; seq[1] = 0x8f; seq[2] = 0xbf; seq[3] = 0xbf; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xf4; seq[1] = 0x90; seq[2] = 0x80; seq[3] = 0x80; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ seq[0] = 0xd7; seq[1] = 0x90; seq[2] = 0xd7; seq[3] = 0x90; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+
+ /* cont. char */
+
+ seq[0] = 0x80; seq[1] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xbf; seq[1] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ /* overlong */
+
+ seq[0] = 0xc0; seq[1] = 0xaf; seq[2] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xe0; seq[1] = 0x8f; seq[2] = 0xaf; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xf0; seq[1] = 0x80; seq[2] = 0x80; seq[3] = 0xaf; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ /* overlong */
+
+ seq[0] = 0xc1; seq[1] = 0xbf; seq[2] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xe0; seq[1] = 0x9f; seq[2] = 0xbf; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xf0; seq[1] = 0x8f; seq[2] = 0xbf; seq[3] = 0xbf; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ /* overlong */
+
+ seq[0] = 0xc0; seq[1] = 0x80; seq[2] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xe0; seq[1] = 0x80; seq[2] = 0x80; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xf0; seq[1] = 0x80; seq[2] = 0x80; seq[3] = 0x80; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ /* cont missing */
+
+ seq[0] = 0xd7; seq[1] = 0x20; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xee; seq[1] = 0x80; seq[2] = 0x20; seq[3] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ seq[0] = 0xf4; seq[1] = 0x8f; seq[2] = 0xbf; seq[3] = 0x20; seq[4] = 0x00;
+ ret = sh_util_valid_utf8(seq);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+
+ /* switch on utf8 checking for sh_util_obscurename() */
+
+ ret = sh_util_obscure_utf8("Y");
+ CuAssertIntEquals(tc, ret, 0);
+
+ ret = sh_util_obscure_ok ("0x01,0x02,0x03");
+ CuAssertIntEquals(tc, ret, 0);
+
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = '\t';
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, -1);
+
+ input[0] = 0x01;
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = 0x02;
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = 0x03;
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = 0x04;
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, -1);
+
+ input[0] = 'f';
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[5] = ' ';
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_FALSE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, -1);
+
+ input[5] = 'r'; input[3] = ' ';
+ ret = sh_util_valid_utf8 (input);
+ CuAssertIntEquals(tc, ret, S_TRUE);
+ ret = sh_util_obscurename (0, (char *)input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+
+#else
+ CuAssertIntEquals(tc, ret, 0);
+#endif
+}
+
+void Test_sh_util_obscure_ok (CuTest *tc) {
+
+ int ret = 0;
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ char input[16] = "foobar";
+
+ /* switch off utf8 checking for sh_util_obscurename() */
+
+ ret = sh_util_obscure_utf8("N");
+ CuAssertIntEquals(tc, ret, 0);
+
+ ret = sh_util_obscure_ok ("0xA1,0xA2,0xA3");
+ CuAssertIntEquals(tc, ret, 0);
+
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = '\t';
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, -1);
+
+ input[0] = 0xA1;
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = 0xA2;
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = 0xA3;
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[0] = 0xA4;
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, -1);
+
+ input[0] = 'f';
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+
+ input[5] = ' ';
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, -1);
+
+ input[5] = 'r'; input[3] = ' ';
+ ret = sh_util_obscurename (0, input, S_FALSE /* no log message */);
+ CuAssertIntEquals(tc, ret, 0);
+#else
+ CuAssertIntEquals(tc, ret, 0);
+#endif
+}
+
diff --git a/src/cutest_slib.c b/src/cutest_slib.c
new file mode 100644
index 0000000..1e0e6c4
--- /dev/null
+++ b/src/cutest_slib.c
@@ -0,0 +1,114 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include "CuTest.h"
+#include "samhain.h"
+
+void Test_sl_stale (CuTest *tc) {
+
+ extern int get_the_fd (SL_TICKET ticket);
+
+ int fd1, fd2, ret, line, val;
+ SL_TICKET tfd1, tfd2;
+ char * err1;
+ char err2[128];
+
+ line = __LINE__; tfd1 = sl_open_read(__FILE__, __LINE__, "/etc/group", SL_NOPRIV);
+ CuAssertTrue(tc, tfd1 > 0);
+
+ fd1 = get_the_fd(tfd1);
+ CuAssertTrue(tc, fd1 >= 0);
+
+ ret = close(fd1);
+ CuAssertTrue(tc, ret == 0);
+
+ tfd2 = sl_open_read(__FILE__, __LINE__, "/etc/group", SL_NOPRIV);
+ CuAssertTrue(tc, tfd2 > 0);
+ CuAssertTrue(tc, tfd2 != tfd1);
+
+ fd2 = get_the_fd(tfd2);
+ CuAssertIntEquals(tc, fd1, fd2);
+
+ err1 = sl_check_stale();
+ CuAssertTrue(tc, err1 != NULL);
+
+ sl_snprintf(err2, sizeof(err2),
+ "stale handle, %s, %d", __FILE__, line);
+ val = strcmp(err1, err2);
+ CuAssertIntEquals(tc, 0, val);
+}
+
+void Test_sl_snprintf (CuTest *tc) {
+
+ int ret = 0;
+ char input[16];
+
+ memset (&input, 'X', 16);
+ ret = sl_snprintf(input, 10, "%s\n", "01234567890123456789");
+ CuAssertIntEquals(tc, ret, 0);
+ CuAssertTrue(tc, input[9] == '\0');
+ CuAssertTrue(tc, input[10] == 'X');
+
+ memset (&input, 'X', 16);
+ ret = sl_snprintf(input, 4, "%d\n", "012345");
+ CuAssertIntEquals(tc, ret, 0);
+ CuAssertTrue(tc, input[3] == '\0');
+ CuAssertTrue(tc, input[4] == 'X');
+}
+
+void Test_sl_strcasecmp (CuTest *tc) {
+ char one[64], two[64];
+ int res;
+
+ strcpy(one, "foo");
+ strcpy(two, "foo");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, 0, res);
+
+ strcpy(one, "fo");
+ strcpy(two, "foo");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, -1, res);
+
+ strcpy(one, "foo");
+ strcpy(two, "fo");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, 1, res);
+
+ strcpy(one, "1234");
+ strcpy(two, "2345");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, -1, res);
+
+ strcpy(one, "234");
+ strcpy(two, "123");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, 1, res);
+
+ strcpy(one, "");
+ strcpy(two, "123");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, -1, res);
+
+ strcpy(one, "234");
+ strcpy(two, "");
+ res = sl_strcasecmp(one, two);
+ CuAssertIntEquals(tc, 1, res);
+
+ strcpy(one, "");
+ strcpy(two, "");
+ res = sl_strcasecmp(one, two);
+ CuAssertTrue(tc, res == 0);
+
+#ifndef SL_FAIL_ON_ERROR
+ res = sl_strcasecmp(NULL, two);
+ CuAssertIntEquals(tc, -1, res);
+
+ res = sl_strcasecmp(one, NULL);
+ CuAssertIntEquals(tc, 1, res);
+
+ res = sl_strcasecmp(NULL, NULL);
+ CuAssertTrue(tc, res != 0);
+#endif
+}
diff --git a/src/cutest_zAVLTree.c b/src/cutest_zAVLTree.c
new file mode 100644
index 0000000..1201ac9
--- /dev/null
+++ b/src/cutest_zAVLTree.c
@@ -0,0 +1,522 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include "CuTest.h"
+#include "zAVLTree.h"
+
+struct ztest {
+ char name[32];
+ int iname;
+};
+
+static zAVLTree * ztest_tree = NULL;
+
+static zAVLKey ztest_key (void const * arg)
+{
+ const struct ztest * sa = (const struct ztest *) arg;
+ return (zAVLKey) sa->name;
+}
+
+static zAVLKey ztest_intkey(void const *item)
+{
+ return (&((const struct ztest *)item)->iname);
+}
+
+
+static void free_node (void * inptr)
+{
+ struct ztest * ptr = (struct ztest *) inptr;
+ ptr->name[0] = '\0';
+ ptr->iname = 0;
+}
+
+void Test_zAVLTree(CuTest *tc) {
+ zAVLCursor cursor;
+
+ int result;
+ int counter = 0;
+
+ char * str;
+
+ struct ztest z1 = { "abc" , 1 };
+ struct ztest z2 = { "aac" , 2 };
+ struct ztest z3 = { "aaa1" , 3 };
+ struct ztest z4 = { "aaa3" , 4 };
+ struct ztest z5 = { "aaa2" , 5 };
+ struct ztest z6 = { "aaa6" , 6 };
+ struct ztest z7 = { "aaa5" , 7 };
+ struct ztest z8 = { "aaa4" , 8 };
+
+ struct ztest iz1 = { "aaa1" , 8 };
+ struct ztest iz2 = { "aaa2" , 7 };
+ struct ztest iz3 = { "aaa3" , 1 };
+ struct ztest iz4 = { "aaa4" , 3 };
+ struct ztest iz5 = { "aaa5" , 2 };
+ struct ztest iz6 = { "aaa5" , 6 };
+ struct ztest iz7 = { "aaa7" , 5 };
+ struct ztest iz8 = { "aaa8" , 4 };
+
+ struct ztest * ptr;
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertTrue(tc, NULL == ptr);
+
+ ztest_tree = zAVLAllocTree (ztest_key, zAVL_KEY_STRING);
+ CuAssertPtrNotNull(tc, ztest_tree);
+
+ do {
+
+ ++counter;
+
+ result = zAVLInsert(ztest_tree, &z1);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z2);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z3);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z4);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z5);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z6);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z7);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z8);
+ CuAssertTrue(tc, 0 == result);
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertStrEquals(tc, ptr->name, z3.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z5.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z4.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z8.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z7.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z6.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z2.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z1.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLInsert(ztest_tree, &z8);
+ CuAssertTrue(tc, 0 != result);
+ result = zAVLInsert(ztest_tree, &z7);
+ CuAssertTrue(tc, 0 != result);
+ result = zAVLInsert(ztest_tree, &z6);
+ CuAssertTrue(tc, 0 != result);
+ result = zAVLInsert(ztest_tree, &z5);
+ CuAssertTrue(tc, 0 != result);
+
+ ptr = zAVLSearch(ztest_tree, z1.name);
+ CuAssertStrEquals(tc, ptr->name, z1.name);
+ ptr = zAVLSearch(ztest_tree, z2.name);
+ CuAssertStrEquals(tc, ptr->name, z2.name);
+ ptr = zAVLSearch(ztest_tree, z3.name);
+ CuAssertStrEquals(tc, ptr->name, z3.name);
+ ptr = zAVLSearch(ztest_tree, z4.name);
+ CuAssertStrEquals(tc, ptr->name, z4.name);
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertStrEquals(tc, ptr->name, z3.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z5.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z4.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z8.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z7.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z6.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z2.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z1.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertTrue(tc, NULL == ptr);
+
+
+ ptr = zAVLSearch(ztest_tree, z5.name);
+ CuAssertStrEquals(tc, ptr->name, z5.name);
+ ptr = zAVLSearch(ztest_tree, z6.name);
+ CuAssertStrEquals(tc, ptr->name, z6.name);
+ ptr = zAVLSearch(ztest_tree, z7.name);
+ CuAssertStrEquals(tc, ptr->name, z7.name);
+ ptr = zAVLSearch(ztest_tree, z8.name);
+ CuAssertStrEquals(tc, ptr->name, z8.name);
+ ptr = zAVLSearch(ztest_tree, "foobar");
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z8.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z8.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z3.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z3.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z1.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z1.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLInsert(ztest_tree, &z1);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z8);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z3);
+ CuAssertTrue(tc, 0 == result);
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertStrEquals(tc, ptr->name, z3.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z5.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z4.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z8.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z7.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z6.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z2.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, z1.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z1.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z1.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z2.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z2.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z3.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z3.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z4.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z4.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z5.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z5.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z6.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z6.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z7.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z7.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, z8.name);
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, z8.name);
+ CuAssertTrue(tc, NULL == ptr);
+
+} while (counter < 100);
+
+ result = zAVLInsert(ztest_tree, &z1);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z2);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z3);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z4);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z5);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z6);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z7);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &z8);
+ CuAssertTrue(tc, 0 == result);
+
+ zAVLFreeTree (ztest_tree, free_node);
+ CuAssertTrue (tc, z1.name[0] == '\0');
+ CuAssertTrue (tc, z2.name[0] == '\0');
+ CuAssertTrue (tc, z3.name[0] == '\0');
+ CuAssertTrue (tc, z4.name[0] == '\0');
+ CuAssertTrue (tc, z5.name[0] == '\0');
+ CuAssertTrue (tc, z6.name[0] == '\0');
+ CuAssertTrue (tc, z7.name[0] == '\0');
+ CuAssertTrue (tc, z8.name[0] == '\0');
+
+
+ /* Numeric key here */
+
+ counter = 0;
+ ztest_tree = NULL;
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertTrue(tc, NULL == ptr);
+
+ ztest_tree = zAVLAllocTree (ztest_intkey, zAVL_KEY_INT);
+ CuAssertPtrNotNull(tc, ztest_tree);
+
+ do {
+
+ ++counter;
+
+ result = zAVLInsert(ztest_tree, &iz1);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz2);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz3);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz4);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz5);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz6);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz7);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz8);
+ CuAssertTrue(tc, 0 == result);
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertStrEquals(tc, ptr->name, iz3.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz5.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz4.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz8.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz7.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz6.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz2.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz1.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLInsert(ztest_tree, &iz8);
+ CuAssertTrue(tc, 0 != result);
+ result = zAVLInsert(ztest_tree, &iz7);
+ CuAssertTrue(tc, 0 != result);
+ result = zAVLInsert(ztest_tree, &iz6);
+ CuAssertTrue(tc, 0 != result);
+ result = zAVLInsert(ztest_tree, &iz5);
+ CuAssertTrue(tc, 0 != result);
+
+ ptr = zAVLSearch(ztest_tree, &(iz1.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz1.iname);
+ ptr = zAVLSearch(ztest_tree, &(iz2.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz2.iname);
+ ptr = zAVLSearch(ztest_tree, &(iz3.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz3.iname);
+ ptr = zAVLSearch(ztest_tree, &(iz6.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz6.iname);
+ ptr = zAVLSearch(ztest_tree, &(iz4.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz4.iname);
+
+ ptr = zAVLSearch(ztest_tree, &(iz2.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz2.iname);
+ ptr = zAVLSearch(ztest_tree, &(iz3.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz3.iname);
+ ptr = zAVLSearch(ztest_tree, &(iz7.iname));
+ CuAssertIntEquals(tc, ptr->iname, iz7.iname);
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertStrEquals(tc, ptr->name, iz3.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz5.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz4.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz8.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz7.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz6.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz2.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz1.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertTrue(tc, NULL == ptr);
+
+
+ ptr = zAVLSearch(ztest_tree, &(iz5.iname));
+ CuAssertStrEquals(tc, ptr->name, iz5.name);
+ ptr = zAVLSearch(ztest_tree, &(iz6.iname));
+ CuAssertStrEquals(tc, ptr->name, iz6.name);
+ ptr = zAVLSearch(ztest_tree, &(iz7.iname));
+ CuAssertStrEquals(tc, ptr->name, iz7.name);
+ ptr = zAVLSearch(ztest_tree, &(iz8.iname));
+ CuAssertStrEquals(tc, ptr->name, iz8.name);
+ ptr = zAVLSearch(ztest_tree, &(z1.iname)); /* been set to 0 */
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz8.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz8.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz3.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz3.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz1.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz1.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLInsert(ztest_tree, &iz1);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz8);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz3);
+ CuAssertTrue(tc, 0 == result);
+
+ ptr = zAVLFirst(&cursor, ztest_tree);
+ CuAssertIntEquals(tc, ptr->iname, iz3.iname);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz5.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz4.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertIntEquals(tc, ptr->iname, iz8.iname);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz7.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz6.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertIntEquals(tc, ptr->iname, iz2.iname);
+ ptr = zAVLNext(&cursor);
+ CuAssertStrEquals(tc, ptr->name, iz1.name);
+ ptr = zAVLNext(&cursor);
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz1.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz1.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz2.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz2.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz3.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz3.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz4.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz4.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz5.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz5.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz6.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz6.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz7.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz7.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+ result = zAVLDelete(ztest_tree, &(iz8.iname));
+ CuAssertTrue(tc, 0 == result);
+ ptr = zAVLSearch(ztest_tree, &(iz8.iname));
+ CuAssertTrue(tc, NULL == ptr);
+
+} while (counter < 100);
+
+ result = zAVLInsert(ztest_tree, &iz1);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz2);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz3);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz4);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz5);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz6);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz7);
+ CuAssertTrue(tc, 0 == result);
+ result = zAVLInsert(ztest_tree, &iz8);
+ CuAssertTrue(tc, 0 == result);
+
+ zAVLFreeTree (ztest_tree, free_node);
+ CuAssertTrue (tc, iz1.iname == 0);
+ CuAssertTrue (tc, iz2.iname == 0);
+ CuAssertTrue (tc, iz3.iname == 0);
+ CuAssertTrue (tc, iz4.iname == 0);
+ CuAssertTrue (tc, iz5.iname == 0);
+ CuAssertTrue (tc, iz6.iname == 0);
+ CuAssertTrue (tc, iz7.iname == 0);
+ CuAssertTrue (tc, iz8.iname == 0);
+
+ ztest_tree = NULL;
+ str = strdup("foo");
+ result = zAVL_string_set(&ztest_tree, str);
+ CuAssertTrue(tc, 0 == result);
+ CuAssertPtrNotNull(tc, ztest_tree);
+ CuAssertStrEquals(tc, "foo", zAVL_string_get(ztest_tree, "foo"));
+
+ str = strdup("bar");
+ result = zAVL_string_set(&ztest_tree, str);
+ CuAssertTrue(tc, 0 == result);
+ CuAssertStrEquals(tc, "foo", zAVL_string_get(ztest_tree, "foo"));
+ CuAssertStrEquals(tc, "bar", zAVL_string_get(ztest_tree, "bar"));
+
+ str = strdup("balloon");
+ result = zAVL_string_set(&ztest_tree, str);
+ CuAssertTrue(tc, 0 == result);
+ CuAssertStrEquals(tc, "foo", zAVL_string_get(ztest_tree, "foo"));
+ CuAssertStrEquals(tc, "bar", zAVL_string_get(ztest_tree, "bar"));
+ CuAssertStrEquals(tc, "balloon", zAVL_string_get(ztest_tree, "balloon"));
+
+ str = zAVL_string_get(ztest_tree, "foobar");
+ CuAssertTrue(tc, str == NULL);
+ str = zAVL_string_get(ztest_tree, "");
+ CuAssertTrue(tc, str == NULL);
+ str = zAVL_string_get(ztest_tree, NULL);
+ CuAssertTrue(tc, str == NULL);
+
+ zAVL_string_reset(ztest_tree);
+ str = zAVL_string_get(ztest_tree, "foo");
+ CuAssertTrue(tc, str == NULL);
+ str = zAVL_string_get(ztest_tree, "bar");
+ CuAssertTrue(tc, str == NULL);
+ str = zAVL_string_get(ztest_tree, "balloon");
+ CuAssertTrue(tc, str == NULL);
+
+}
diff --git a/src/depend-gen.c b/src/depend-gen.c
new file mode 100644
index 0000000..586feee
--- /dev/null
+++ b/src/depend-gen.c
@@ -0,0 +1,417 @@
+#include <stdio.h>
+#include <string.h>
+
+/* copyright (c) 2002 Rainer Wichmann
+ * License: GNU Public License (GPL) version 2 or later
+ */
+
+/* gcc -O2 -Wall -o depend depend.c
+ */
+
+/*
+
+# redo if sources change
+#
+depend.dep: depend.c $(SOURCES)
+ $(CC) -o depend depend.c
+ for ff in $(SOURCES); do; \
+ depend -o depend.dep $ff; \
+ done
+ nsum=`sum depend.dep`; \
+ osum=`cat depend.sum`; \
+ if test "x$$osum" != "x$$nsum"; then \
+ echo $$nsum > depend.sum
+ fi
+
+# only updated if depencies change
+#
+depend.sum: depend.dep
+
+Makefile.in: depend.sum
+ for ff in $(SOURCES); do; \
+ depend -o Makefile.in $ff; \
+ done
+
+Makefile: Makefile.in
+
+*/
+
+unsigned int lzo_adler32(unsigned int adler,
+ const char *buf, unsigned int len);
+
+
+int main (int argc, char * argv[])
+{
+ FILE * fout = NULL;
+ FILE * ftmp = NULL;
+ FILE * fin = NULL;
+
+ int filep = 1;
+
+ char name[1024];
+ char base[1024];
+ char tmpname[1024];
+ char line[1024];
+ char buffer[2048];
+ char incdir[1024];
+ int inclen = 0;
+ int count = 2047;
+ int len = 0;
+
+ unsigned int adler;
+
+ char * p;
+ char * q;
+
+ incdir[0] = '\0';
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "depend-gen: Missing argument\n");
+ return 1;
+ }
+
+ if (argv[1][0] == '-' && argv[1][1] == 'h')
+ {
+ printf("Usage: depend-gen [-i includedir] -(o|t) outfile infile\n");
+ printf(" -o replaces, -t truncates\n");
+ return 0;
+ }
+
+ if (argv[1][0] == '-' && argv[1][1] == 'i')
+ {
+ if (argc < 3)
+ {
+ fprintf(stderr, "depend-gen: -i: Missing argument (includedir)\n");
+ return 1;
+ }
+ strncpy(incdir, argv[2], 1023);
+ incdir[1023] = '\0';
+ inclen = strlen(incdir);
+ argc -= 2; ++argv; ++argv;
+ }
+
+ if (argv[1][0] == '-' &&
+ (argv[1][1] == 'o' || argv[1][1] == 't' || argv[1][1] == 'c'))
+ {
+ if (argc < 3)
+ {
+ fprintf(stderr, "depend-gen: -%c: Missing argument\n", argv[1][1]);
+ return 1;
+ }
+ if (argv[1][1] == 'o' || argv[1][1] == 'c')
+ fout = fopen(argv[2], "r+");
+ else
+ fout = fopen(argv[2], "w+");
+
+ if (!fout)
+ {
+ perror("depend-gen: fopen");
+ fprintf(stderr, "depend-gen [%d]: -%c %s: Could not open file\n",
+ __LINE__, argv[1][1], argv[2]);
+ return 1;
+ }
+ filep += 2;
+
+ if (argv[1][1] == 'c')
+ {
+ adler = lzo_adler32(0, NULL, 0);
+ while (NULL != fgets(line, 1023, fout))
+ {
+ adler = lzo_adler32(adler, line, strlen(line));
+ }
+ printf("%u\n", adler);
+ return 0;
+ }
+
+ if (argv[1][1] == 't')
+ ftmp = fout;
+ else
+ {
+ tmpname[0] = '\0';
+ if (strlen(argv[filep]) > 1029)
+ {
+ fprintf(stderr, "depend-gen: -%c %s: filename too long\n",
+ argv[1][1], argv[2]);
+ return 1;
+ }
+
+
+ strncat(tmpname, argv[filep], 1029);
+ strncat(tmpname, ".tmp", 1023);
+ ftmp = fopen(tmpname, "w");
+ if (!ftmp)
+ {
+ perror("depend-gen: fopen");
+ fprintf(stderr, "depend-gen [%d]: -%c %s: Could not open file\n",
+ __LINE__, argv[1][1], tmpname);
+ return 1;
+ }
+ }
+
+ }
+ else
+ {
+ fprintf(stderr, "depend-gen: no output file given (-(o|t) outfile)\n");
+ return 1;
+ }
+
+
+ if (argc < (filep+1))
+ {
+ fprintf(stderr, "depend-gen: missing argument (infile)\n");
+ return 1;
+ }
+ fin = fopen(argv[filep], "r");
+ if (!fin)
+ {
+ perror("depend-gen: fopen");
+ fprintf(stderr, "depend-gen [%d]: -%c %s: Could not open file\n",
+ __LINE__, argv[1][1], argv[filep]);
+ return 1;
+ }
+
+ /* fast forward to dependencies start
+ */
+ do
+ {
+ if (NULL == fgets(line, 1023, fout))
+ break;
+ if (0 == strncmp(line, "# DO NOT DELETE THIS LINE", 25))
+ break;
+ fprintf(ftmp, "%s", line);
+ }
+ while (1 == 1);
+
+ if (argv[1][1] == 'o')
+ {
+ fprintf(ftmp, "# DO NOT DELETE THIS LINE\n");
+ }
+
+ strncpy(name, argv[filep], 1023);
+ p = name;
+ while (*p != '\0') ++p;
+ if (name[0] != '\0') --p;
+ if (*p == 'c') *p = 'o';
+
+ p = strrchr(name, '/');
+ if (p)
+ {
+ ++p;
+ len = strlen(p);
+ }
+
+ /* skip other dependencies
+ */
+ do
+ {
+ if (NULL == fgets(line, 1023, fout))
+ break;
+ if (p && 0 == strncmp(line, p, len))
+ break;
+ fprintf(ftmp, "%s", line);
+ }
+ while (1 == 1);
+
+ buffer[0] = '\0';
+
+ while (NULL != fgets(line, 1023, fin))
+ {
+ p = line;
+ while (*p != '\0' && (*p == ' ' || *p == '\t'))
+ ++p;
+ if (0 == strncmp(p, "#include", 8))
+ p += 8;
+ else
+ continue;
+ while (*p != '\0' && (*p == ' ' || *p == '\t'))
+ ++p;
+ if (*p != '"')
+ continue;
+ else
+ {
+ ++p;
+ q = p;
+ ++q;
+ while (*q != '\0' && *q != '"')
+ ++q;
+ if (*q != '"')
+ continue;
+ *q = '\0';
+
+ /**************************************************
+ *
+ * EXCEPTIONS
+ *
+ **************************************************/
+ if (0 == strcmp(p, "sh_gpg_chksum.h") ||
+ 0 == strcmp(p, "sh_gpg_fp.h"))
+ {
+ /* fprintf(stderr, "Excluding %s\n", p); */
+ continue;
+ }
+
+ len = strlen(p);
+ if (len > count)
+ {
+ /* graceful failure */
+ fprintf(fout, "# OVERFLOW: incomplete dependencies\n");
+ break;
+ }
+ if (incdir[0] != '\0')
+ {
+ if (0 == strcmp(p, "config.h") ||
+ 0 == strcmp(p, "config_xor.h") ||
+ 0 == strcmp(p, "internal.h") ||
+ 0 == strcmp(p, "sh_ks.h") ||
+ 0 == strcmp(p, "sh_ks_xor.h") ||
+ 0 == strcmp(p, "sh_MK.h")); /* do nothing */
+ else
+ {
+ strncat(buffer, incdir, count);
+ count -= inclen;
+ }
+ }
+ strncat(buffer, p, count);
+ count -= len;
+ strncat(buffer, " ", count);
+ --count;
+ }
+ }
+
+ /* write the dependencies found
+ */
+ p = strrchr(argv[filep], '/');
+ if (p)
+ {
+ ++p;
+ strncpy(name, p, 1023);
+ }
+ else
+ strncpy(name, argv[filep], 1023);
+ name[1023] = '\0';
+
+ strcpy(base, "$(srcsrc)/");
+ strcat(base, name);
+
+ p = name;
+ while (*p != '\0') ++p;
+ if (name[0] != '\0') --p;
+ if (*p == 'c')
+ {
+ *p = 'o';
+ fprintf(ftmp, "%s: %s Makefile %s\n", name, base /* argv[filep] */,
+ buffer);
+ }
+ else
+ {
+ fprintf(ftmp, "%s: Makefile %s\n", argv[filep], buffer);
+ }
+
+ /* more dependencies
+ */
+ do
+ {
+ if (NULL == fgets(line, 1023, fout))
+ break;
+ fprintf(ftmp, "%s", line);
+ }
+ while (1 == 1);
+
+ if (ftmp != NULL)
+ {
+ fclose(ftmp);
+ }
+ if (fout != NULL)
+ {
+ fclose(fout);
+ }
+ if (fin != NULL)
+ {
+ fclose(fin);
+ }
+
+ if (argv[1][1] == 'o')
+ {
+ if (0 != rename (tmpname, argv[2]))
+ {
+ perror("depend-gen: rename");
+ fprintf(stderr, "depend-gen: could not rename %s --> %s\n",
+ tmpname, argv[2]);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* from the LZO real-time data compression library
+
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+
+ The LZO library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus.oberhumer@jk.uni-linz.ac.at>
+ http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+*/
+/*
+ * NOTE:
+ * the full LZO package can be found at
+ * http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ */
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+unsigned int lzo_adler32(unsigned int adler, const char *buf, unsigned int len)
+{
+ unsigned int s1 = adler & 0xffff;
+ unsigned int s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == NULL)
+ return 1;
+
+ while (len > 0)
+ {
+ k = len < LZO_NMAX ? (int) len : LZO_NMAX;
+ len -= k;
+ if (k >= 16) do
+ {
+ LZO_DO16(buf,0);
+ buf += 16;
+ k -= 16;
+ } while (k >= 16);
+ if (k != 0) do
+ {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k > 0);
+ s1 %= LZO_BASE;
+ s2 %= LZO_BASE;
+ }
+ return (s2 << 16) | s1;
+}
diff --git a/src/dnmalloc.c b/src/dnmalloc.c
new file mode 100644
index 0000000..4ab3b9a
--- /dev/null
+++ b/src/dnmalloc.c
@@ -0,0 +1,5619 @@
+/* DistriNet malloc (dnmalloc): a more secure memory allocator.
+ Copyright (C) 2005, Yves Younan, Wouter Joosen, Frank Piessens
+ and Rainer Wichmann
+
+ The authors can be contacted by:
+ Email: dnmalloc@fort-knox.org
+ Address:
+#if defined(WITH_TPT)
+ Yves Younan
+ Celestijnenlaan 200A
+ B-3001 Heverlee
+ Belgium
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+/* Current version: dnmalloc 1.0 */
+/* Includes arc4random from OpenBSD, which is under the BDS license */
+
+/* Versions:
+ 0.1-0.5:
+ Proof of concept implementation by Hans Van den Eynden and Yves Younan
+ 0.6-0.7:
+ Bug fixes by Yves Younan
+ 0.8-1.0.beta4:
+ Reimplementation from scratch by Yves Younan
+ 1.0.beta4:
+ Public release
+ 1.0.beta5:
+ Prev_chunkinfo speeded up, was really slow because of the way we did lookups
+ A freechunkinfo region is now freed when it is completely empty and
+ not the current one
+
+ 1.0 (Rainer Wichmann [support at la dash samhna dot org]):
+ ---------------------
+
+ Compiler warnings fixed
+ Define REALLOC_ZERO_BYTES_FREES because it's what GNU libc does
+ (and what the standard says)
+ Removed unused code
+ Fix assert(aligned_OK(chunk(newp)));
+ -> assert(aligned_OK(chunk(oldp)));
+ Fix statistics in sYSMALLOc
+ Fix overwrite of av->top in sYSMALLOc
+ Provide own assert(), glibc assert() doesn't work (calls malloc)
+ Fix bug in mEMALIGn(), put remainder in hashtable before calling fREe
+ Remove cfree, independent_cmalloc, independent_comalloc (untested
+ public functions not covered by any standard)
+ Provide posix_memalign (that one is in the standard)
+ Move the malloc_state struct to mmapped memory protected by guard pages
+ Add arc4random function to initialize random canary on startup
+ Implement random canary at end of (re|m)alloced/memaligned buffer,
+ check at free/realloc
+ Remove code conditional on !HAVE_MMAP, since mmap is required anyway.
+ Use standard HAVE_foo macros (as generated by autoconf) instead of LACKS_foo
+
+ Profiling: Reorder branches in hashtable_add, next_chunkinfo,
+ prev_chunkinfo, hashtable_insert, mALLOc, fREe, request2size,
+ checked_request2size (gcc predicts if{} branch to be taken).
+ Use UNLIKELY macro (gcc __builtin_expect()) where branch
+ reordering would make the code awkward.
+
+ Portability: Hashtable always covers full 32bit address space to
+ avoid assumptions about memory layout.
+ Portability: Try hard to enforce mapping of mmapped memory into
+ 32bit address space, even on 64bit systems.
+ Portability: Provide a dnmalloc_pthread_init() function, since
+ pthread locking on HP-UX only works if initialized
+ after the application has entered main().
+ Portability: On *BSD, pthread_mutex_lock is unusable since it
+ calls malloc, use spinlocks instead.
+ Portability: Dynamically detect whether the heap is within
+ 32bit address range (e.g. on Linux x86_64, it isn't).
+ Don't use sbrk() if the heap is mapped to an address
+ outside the 32bit range, since this doesn't work with
+ the hashtable. New macro morecore32bit.
+
+ Success on: HP-UX 11.11/pthread, Linux/pthread (32/64 bit),
+ FreeBSD/pthread, and Solaris 10 i386/pthread.
+ Fail on: OpenBSD/pthread (in _thread_machdep_save_float_state),
+ might be related to OpenBSD pthread internals (??).
+ Non-treaded version (#undef USE_MALLOC_LOCK)
+ works on OpenBSD.
+
+ further to 1.0:
+ Valgrind client requests inserted (#define USE_VALGRIND)
+ Fix: malloc_consolidate (nextchunk->fd, nextchunk->bck may be NULL)
+ Portability: minsize = 32 bit on 64bit architecture
+ Minor cleanups
+ Fix: eliminate prototypes for memset, memcpy (they're in string.h)
+ Fix: one more malloc_consolidate segfault
+
+ There may be some bugs left in this version. please use with caution.
+*/
+
+
+
+/* Please read the following papers for documentation:
+
+ Yves Younan, Wouter Joosen, and Frank Piessens, A Methodology for Designing
+ Countermeasures against Current and Future Code Injection Attacks,
+ Proceedings of the Third IEEE International Information Assurance
+ Workshop 2005 (IWIA2005), College Park, Maryland, U.S.A., March 2005,
+ IEEE, IEEE Press.
+ http://www.fort-knox.org/younany_countermeasures.pdf
+
+ Yves Younan, Wouter Joosen and Frank Piessens and Hans Van den
+ Eynden. Security of Memory Allocators for C and C++. Technical Report
+ CW419, Departement Computerwetenschappen, Katholieke Universiteit
+ Leuven, July 2005. http://www.fort-knox.org/CW419.pdf
+
+ */
+
+/* Compile:
+ gcc -fPIC -rdynamic -c -Wall dnmalloc-portable.c
+ "Link":
+ Dynamic:
+ gcc -shared -Wl,-soname,libdnmalloc.so.0 -o libdnmalloc.so.0.0 dnmalloc-portable.o -lc
+ Static:
+ ar -rv libdnmalloc.a dnmalloc-portable.o
+
+*/
+
+/*
+ dnmalloc is based on dlmalloc 2.7.2 (by Doug Lea (dl@cs.oswego.edu))
+ dlmalloc was released as public domain and contained the following license:
+
+ "This is a version (aka dlmalloc) of malloc/free/realloc written by
+ Doug Lea and released to the public domain. Use, modify, and
+ redistribute this code without permission or acknowledgement in any
+ way you wish. Send questions, comments, complaints, performance
+ data, etc to dl@cs.oswego.edu
+
+ * VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+ Check before installing!"
+
+*/
+
+/* The following preprocessor macros are tested,
+ * and hence should have #define directives:
+ *
+ * HAVE_CONFIG_H Define to #include "config.h" (autoconf-generated)
+ *
+ * HAVE_UNISTD_H Define to #include <unistd.h>
+ *
+ * HAVE_SYS_UIO_H Define to #include <sys/uio.h> (for writev)
+ * HAVE_WRITEV Define if the 'writev' function is available
+ *
+ * HAVE_SYS_PARAM_H Define to #include <sys/param.h> (for pagesize)
+ *
+ * HAVE_MALLOC_H Define to #include <malloc.h> (for struct mallinfo)
+ *
+ * HAVE_FCNTL_H Define to #include <fcntl.h>
+ *
+ * HAVE_SYS_MMAN_H Define to #include <sys/mman.h>
+ * HAVE_MMAP Define if the 'mmap' function is available.
+ *
+ * HAVE_SCHED_H Define to #include <sched.h>
+ * HAVE_SCHED_YIELD Define id the 'sched_yield' function is available
+ */
+
+
+/*
+ __STD_C should be nonzero if using ANSI-standard C compiler, a C++
+ compiler, or a C compiler sufficiently close to ANSI to get away
+ with it.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef USE_VALGRIND
+#include <valgrind/memcheck.h>
+#else
+#define VALGRIND_FREELIKE_BLOCK(a,b) ((void)0)
+#define VALGRIND_MALLOCLIKE_BLOCK(a,b,c,d) ((void)0)
+#define VALGRIND_CREATE_MEMPOOL(a,b,c) ((void)0)
+#define VALGRIND_MEMPOOL_ALLOC(a,b,c) ((void)0)
+#define VALGRIND_MEMPOOL_FREE(a,b) ((void)0)
+#define VALGRIND_DESTROY_MEMPOOL(a) ((void)0)
+#define VALGRIND_MAKE_MEM_DEFINED(a,b) ((void)0)
+#define VALGRIND_MAKE_MEM_UNDEFINED(a,b) ((void)0)
+#define VALGRIND_MAKE_MEM_NOACCESS(a,b) ((void)0)
+#endif
+
+#if defined (__GNUC__) && __GNUC__ > 2
+# define LIKELY(expression) (__builtin_expect(!!(expression), 1))
+# define UNLIKELY(expression) (__builtin_expect(!!(expression), 0))
+# define __attribute_malloc__ __attribute__ ((__malloc__))
+#else
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+# define __attribute_malloc__ /* Ignore */
+#endif
+
+/*
+ Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+ large blocks. This is currently only possible on Linux with
+ kernel versions newer than 1.3.77.
+*/
+
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#define _GNU_SOURCE 1
+#else
+#define HAVE_MREMAP 0
+#endif
+#endif /* HAVE_MREMAP */
+
+
+
+#ifndef __STD_C
+#if defined(__STDC__) || defined(_cplusplus)
+#define __STD_C 1
+#else
+#define __STD_C 0
+#endif
+#endif /*__STD_C*/
+
+
+/*
+ Void_t* is the pointer type that malloc should say it returns
+*/
+
+#ifndef Void_t
+#if (__STD_C || defined(WIN32))
+#define Void_t void
+#else
+#define Void_t char
+#endif
+#endif /*Void_t*/
+
+#if __STD_C
+#include <stddef.h> /* for size_t */
+#else
+#include <sys/types.h>
+#endif
+
+#if !defined(USE_SYSTEM_MALLOC)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* define HAVE_UNISTD_H if your system has a <unistd.h>. */
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <stdio.h> /* needed for malloc_stats */
+#include <errno.h> /* needed for optional MALLOC_FAILURE_ACTION */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/resource.h>
+
+extern int errno;
+
+ /* 0: lazy,
+ * 1: medium (assertions compiled in),
+ * 2: high (guard pages at end of hash table and ciregions)
+ * 3: paranoid (guards at end of each allocated chunk, check at free)
+ */
+#ifndef PARANOIA
+#define PARANOIA 9
+#endif
+
+ /* Using assert() with multithreading will cause the code
+ * to deadlock since glibc __assert_fail will call malloc().
+ * We need our very own assert().
+ */
+typedef void assert_handler_tp(const char * error, const char *file, int line);
+
+#if PARANOIA > 0
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+static void default_assert_handler(const char *error,
+ const char *file, int line)
+{
+#ifdef HAVE_WRITEV
+ struct iovec iov[5];
+ char * i1 = "assertion failed (";
+ char * i3 = "): ";
+ char * i5 = "\n";
+ int res = 0;
+ char ifile[128];
+ char ierr[128];
+
+ strncpy(ifile, file, sizeof(ifile)); ifile[sizeof(ifile)-1] = '\0';
+ strncpy(ierr, error, sizeof(ierr)); ierr[sizeof(ierr)-1] = '\0';
+
+ iov[0].iov_base = i1; iov[0].iov_len = strlen(i1);
+ iov[1].iov_base = ifile; iov[1].iov_len = strlen(ifile);
+ iov[2].iov_base = i3; iov[2].iov_len = strlen(i3);
+ iov[3].iov_base = ierr; iov[3].iov_len = strlen(ierr);
+ iov[4].iov_base = i5; iov[4].iov_len = strlen(i5);
+ do {
+ res = writev(STDERR_FILENO, iov, 5);
+ } while (res < 0 && errno == EINTR);
+#else
+ fputs("assertion failed (", stderr);
+ fputs(file, stderr);
+ fputs("): ", stderr);
+ fputs(error, stderr);
+ fputc('\n', stderr);
+#endif
+ (void) line;
+ abort();
+}
+static assert_handler_tp *assert_handler = default_assert_handler;
+
+
+#define assert(x) \
+ do { \
+ if (UNLIKELY(!(x))) { \
+ assert_handler(#x, __FILE__, __LINE__); \
+ } \
+ } while (0)
+
+#else
+
+static assert_handler_tp *assert_handler = NULL;
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+#define assert(x) ((void)0)
+
+#endif
+
+assert_handler_tp *dnmalloc_set_handler(assert_handler_tp *new)
+{
+ assert_handler_tp *old = assert_handler;
+ assert_handler = new;
+ return old;
+}
+
+
+#include <stdarg.h>
+
+ /* define for debugging */
+ /* #define DNMALLOC_DEBUG */
+
+ /* Do some extra checks? if not, covered by assrt()s */
+ /* #define DNMALLOC_CHECKS */
+
+ /*
+ The unsigned integer type used for comparing any two chunk sizes.
+ This should be at least as wide as size_t, but should not be signed.
+ */
+
+#ifndef CHUNK_SIZE_T
+#define CHUNK_SIZE_T unsigned long
+#endif
+
+/*
+ The unsigned integer type used to hold addresses when they are are
+ manipulated as integers. Except that it is not defined on all
+ systems, intptr_t would suffice.
+*/
+#ifndef PTR_UINT
+#define PTR_UINT unsigned long
+#endif
+
+
+/*
+ INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+ of chunk sizes.
+
+ The default version is the same as size_t.
+
+ While not strictly necessary, it is best to define this as an
+ unsigned type, even if size_t is a signed type. This may avoid some
+ artificial size limitations on some systems.
+
+ On a 64-bit machine, you may be able to reduce malloc overhead by
+ defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the
+ expense of not being able to handle more than 2^32 of malloced
+ space. If this limitation is acceptable, you are encouraged to set
+ this unless you are on a platform requiring 16byte alignments. In
+ this case the alignment requirements turn out to negate any
+ potential advantages of decreasing size_t word size.
+
+ Implementors: Beware of the possible combinations of:
+ - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits,
+ and might be the same width as int or as long
+ - size_t might have different width and signedness as INTERNAL_SIZE_T
+ - int and long might be 32 or 64 bits, and might be the same width
+ To deal with this, most comparisons and difference computations
+ among INTERNAL_SIZE_Ts should cast them to CHUNK_SIZE_T, being
+ aware of the fact that casting an unsigned int to a wider long does
+ not sign-extend. (This also makes checking for negative numbers
+ awkward.) Some of these casts result in harmless compiler warnings
+ on some systems.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/* The corresponding word size */
+#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
+
+
+
+/*
+ MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.
+ It must be a power of two at least 2 * SIZE_SZ, even on machines
+ for which smaller alignments would suffice. It may be defined as
+ larger than this though. Note however that code and data structures
+ are optimized for the case of 8-byte alignment.
+*/
+
+
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT (2 * SIZE_SZ)
+#endif
+
+/* The corresponding bit mask value */
+#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
+
+
+
+/*
+ REALLOC_ZERO_BYTES_FREES should be set if a call to
+ realloc with zero bytes should be the same as a call to free.
+ Some people think it should. Otherwise, since this malloc
+ returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+#define REALLOC_ZERO_BYTES_FREES
+
+/*
+ TRIM_FASTBINS controls whether free() of a very small chunk can
+ immediately lead to trimming. Setting to true (1) can reduce memory
+ footprint, but will almost always slow down programs that use a lot
+ of small chunks.
+
+ Define this only if you are willing to give up some speed to more
+ aggressively reduce system-level memory footprint when releasing
+ memory in programs that use many small chunks. You can get
+ essentially the same effect by setting MXFAST to 0, but this can
+ lead to even greater slowdowns in programs using many small chunks.
+ TRIM_FASTBINS is an in-between compile-time option, that disables
+ only those chunks bordering topmost memory from being placed in
+ fastbins.
+*/
+
+#ifndef TRIM_FASTBINS
+#define TRIM_FASTBINS 0
+#endif
+
+
+/*
+ USE_DL_PREFIX will prefix all public routines with the string 'dl'.
+ This is necessary when you only want to use this malloc in one part
+ of a program, using your regular system malloc elsewhere.
+*/
+
+/* #define USE_DL_PREFIX */
+
+
+/*
+ USE_MALLOC_LOCK causes wrapper functions to surround each
+ callable routine with pthread mutex lock/unlock.
+
+ USE_MALLOC_LOCK forces USE_PUBLIC_MALLOC_WRAPPERS to be defined
+*/
+
+/* #define USE_MALLOC_LOCK */
+
+
+/*
+ If USE_PUBLIC_MALLOC_WRAPPERS is defined, every public routine is
+ actually a wrapper function that first calls MALLOC_PREACTION, then
+ calls the internal routine, and follows it with
+ MALLOC_POSTACTION. This is needed for locking, but you can also use
+ this, without USE_MALLOC_LOCK, for purposes of interception,
+ instrumentation, etc. It is a sad fact that using wrappers often
+ noticeably degrades performance of malloc-intensive programs.
+*/
+
+
+#ifdef USE_MALLOC_LOCK
+#define USE_PUBLIC_MALLOC_WRAPPERS
+#else
+/* #define USE_PUBLIC_MALLOC_WRAPPERS */
+#endif
+
+
+/*
+ Two-phase name translation.
+ All of the actual routines are given mangled names.
+ When wrappers are used, they become the public callable versions.
+ When DL_PREFIX is used, the callable names are prefixed.
+*/
+
+#ifndef USE_PUBLIC_MALLOC_WRAPPERS
+#define cALLOc public_cALLOc
+#define fREe public_fREe
+#define mALLOc public_mALLOc
+#define mEMALIGn public_mEMALIGn
+#define posix_mEMALIGn public_posix_mEMALIGn
+#define rEALLOc public_rEALLOc
+#define vALLOc public_vALLOc
+#define pVALLOc public_pVALLOc
+#define mALLINFo public_mALLINFo
+#define mALLOPt public_mALLOPt
+#define mTRIm public_mTRIm
+#define mSTATs public_mSTATs
+#define mUSABLe public_mUSABLe
+#endif
+
+#ifdef USE_DL_PREFIX
+#define public_cALLOc dlcalloc
+#define public_fREe dlfree
+#define public_mALLOc dlmalloc
+#define public_mEMALIGn dlmemalign
+#define public_posix_mEMALIGn dlposix_memalign
+#define public_rEALLOc dlrealloc
+#define public_vALLOc dlvalloc
+#define public_pVALLOc dlpvalloc
+#define public_mALLINFo dlmallinfo
+#define public_mALLOPt dlmallopt
+#define public_mTRIm dlmalloc_trim
+#define public_mSTATs dlmalloc_stats
+#define public_mUSABLe dlmalloc_usable_size
+#else /* USE_DL_PREFIX */
+#define public_cALLOc calloc
+#define public_fREe free
+#define public_mALLOc malloc
+#define public_mEMALIGn memalign
+#define public_posix_mEMALIGn posix_memalign
+#define public_rEALLOc realloc
+#define public_vALLOc valloc
+#define public_pVALLOc pvalloc
+#define public_mALLINFo mallinfo
+#define public_mALLOPt mallopt
+#define public_mTRIm malloc_trim
+#define public_mSTATs malloc_stats
+#define public_mUSABLe malloc_usable_size
+#endif /* USE_DL_PREFIX */
+
+
+/*
+ HAVE_MEMCPY should be defined if you are not otherwise using
+ ANSI STD C, but still have memcpy and memset in your C library
+ and want to use them in calloc and realloc. Otherwise simple
+ macro versions are defined below.
+
+ USE_MEMCPY should be defined as 1 if you actually want to
+ have memset and memcpy called. People report that the macro
+ versions are faster than libc versions on some systems.
+
+ Even if USE_MEMCPY is set to 1, loops to copy/clear small chunks
+ (of <= 36 bytes) are manually unrolled in realloc and calloc.
+*/
+
+#ifndef HAVE_MEMCPY
+#define HAVE_MEMCPY
+#endif
+
+#ifndef USE_MEMCPY
+#ifdef HAVE_MEMCPY
+#define USE_MEMCPY 1
+#else
+#define USE_MEMCPY 0
+#endif
+#endif
+
+
+#if (__STD_C || defined(HAVE_MEMCPY))
+
+#ifdef WIN32
+ /* On Win32 memset and memcpy are already declared in windows.h */
+#else
+#if __STD_C
+ /* Defined in string.h */
+#else
+Void_t* memset();
+Void_t* memcpy();
+#endif
+#endif
+#endif
+
+/*
+ MALLOC_FAILURE_ACTION is the action to take before "return 0" when
+ malloc fails to be able to return memory, either because memory is
+ exhausted or because of illegal arguments.
+
+ By default, sets errno if running on STD_C platform, else does nothing.
+*/
+
+#ifndef MALLOC_FAILURE_ACTION
+#if __STD_C
+#define MALLOC_FAILURE_ACTION \
+ errno = ENOMEM;
+
+#else
+#define MALLOC_FAILURE_ACTION
+#endif
+#endif
+
+/*
+ MORECORE-related declarations. By default, rely on sbrk
+*/
+
+
+#if !defined(HAVE_UNISTD_H)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+#if __STD_C
+extern Void_t* sbrk(ptrdiff_t);
+#else
+extern Void_t* sbrk();
+#endif
+#endif
+#endif
+
+/*
+ MORECORE_FAILURE is the value returned upon failure of MORECORE
+ as well as mmap. Since it cannot be an otherwise valid memory address,
+ and must reflect values of standard sys calls, you probably ought not
+ try to redefine it.
+*/
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE ((void*)(-1UL))
+#endif
+
+/*
+ MORECORE is the name of the routine to call to obtain more memory
+ from the system. See below for general guidance on writing
+ alternative MORECORE functions, as well as a version for WIN32 and a
+ sample version for pre-OSX macos.
+*/
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+
+/*
+ If MORECORE_CONTIGUOUS is true, take advantage of fact that
+ consecutive calls to MORECORE with positive arguments always return
+ contiguous increasing addresses. This is true of unix sbrk. Even
+ if not defined, when regions happen to be contiguous, malloc will
+ permit allocations spanning regions obtained from different
+ calls. But defining this when applicable enables some stronger
+ consistency checks and space efficiencies.
+*/
+
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif
+
+/*
+ Define MORECORE_CANNOT_TRIM if your version of MORECORE
+ cannot release space back to the system when given negative
+ arguments. This is generally necessary only if you are using
+ a hand-crafted MORECORE function that cannot handle negative arguments.
+*/
+
+/* #define MORECORE_CANNOT_TRIM */
+
+
+/*
+ This malloc requires mmap for heap management data. It is an error
+ if mmap is not available.
+
+ Additionally, mmap will be used to satisfy large requests.
+*/
+
+#ifndef HAVE_MMAP
+# error HAVE_MMAP not defined, has your operating system mmap?
+#endif
+
+/*
+ Standard unix mmap using /dev/zero clears memory so calloc doesn't
+ need to.
+*/
+
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif
+
+
+/*
+ MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if
+ sbrk fails, and mmap is used as a backup (which is done only if
+ HAVE_MMAP). The value must be a multiple of page size. This
+ backup strategy generally applies only when systems have "holes" in
+ address space, so sbrk cannot perform contiguous expansion, but
+ there is still space available on system. On systems for which
+ this is known to be useful (i.e. most linux kernels), this occurs
+ only when programs allocate huge amounts of memory. Between this,
+ and the fact that mmap regions tend to be limited, the size should
+ be large, to avoid too many mmap calls and thus avoid running out
+ of kernel resources.
+*/
+
+#ifndef MMAP_AS_MORECORE_SIZE
+#define MMAP_AS_MORECORE_SIZE (1024 * 1024)
+#endif
+
+
+/*
+ The system page size. To the extent possible, this malloc manages
+ memory from the system in page-size units. Note that this value is
+ cached during initialization into a field of malloc_state. So even
+ if malloc_getpagesize is a function, it is only called once.
+
+ The following mechanics for getpagesize were adapted from bsd/gnu
+ getpagesize.h. If none of the system-probes here apply, a value of
+ 4096 is used, which should be OK: If they don't apply, then using
+ the actual value probably doesn't impact performance.
+*/
+
+
+#ifndef malloc_getpagesize
+
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32 /* use supplied emulation of getpagesize */
+# define malloc_getpagesize getpagesize()
+# else
+# if defined(HAVE_SYS_PARAM_H)
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else /* just guess */
+# define malloc_getpagesize (4096)
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/*
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing usage properties and
+ statistics. It should work on any SVID/XPG compliant system that has
+ a /usr/include/malloc.h defining struct mallinfo. (If you'd like to
+ install such a thing yourself, cut out the preliminary declarations
+ as described above and below and save them in a malloc.h file. But
+ there's no compelling reason to bother to do this.)
+
+ The main declaration needed is the mallinfo struct that is returned
+ (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
+ bunch of fields that are not even meaningful in this version of
+ malloc. These fields are are instead filled by mallinfo() with
+ other numbers that might be of interest.
+
+ HAVE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else an SVID2/XPG2 compliant
+ version is declared below. These must be precisely the same for
+ mallinfo() to work. The original SVID version of this struct,
+ defined on most systems with mallinfo, declares all fields as
+ ints. But some others define as unsigned long. If your system
+ defines the fields using a type of different width than listed here,
+ you must #include your system version and #define
+ HAVE_MALLOC_H.
+*/
+
+/* #define HAVE_MALLOC_H */
+
+/* On *BSD, malloc.h is deprecated, and on some *BSD including
+ * it may actually raise an error.
+ */
+#if defined(HAVE_MALLOC_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
+#include <malloc.h>
+#else
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo {
+ int arena; /* non-mmapped space allocated from system */
+ int ordblks; /* number of free chunks */
+ int smblks; /* number of fastbin blocks */
+ int hblks; /* number of mmapped regions */
+ int hblkhd; /* space in mmapped regions */
+ int usmblks; /* maximum total allocated space */
+ int fsmblks; /* space available in freed fastbin blocks */
+ int uordblks; /* total allocated space */
+ int fordblks; /* total free space */
+ int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/*
+ SVID/XPG defines four standard parameter numbers for mallopt,
+ normally defined in malloc.h. Only one of these (M_MXFAST) is used
+ in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt described below.
+*/
+#endif
+
+
+/* ---------- description of public routines ------------ */
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or null
+ if no space is available. Additionally, on failure, errno is
+ set to ENOMEM on ANSI C systems.
+
+ If n is zero, malloc returns a minumum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
+ systems.) On most systems, size_t is an unsigned type, so calls
+ with negative arguments are interpreted as requests for huge amounts
+ of space, which will often fail. The maximum supported value of n
+ differs across systems, but is in all cases less than the maximum
+ representable value of a size_t.
+*/
+#if __STD_C
+Void_t* public_mALLOc(size_t) __attribute_malloc__;
+#else
+Void_t* public_mALLOc();
+#endif
+
+/*
+ free(Void_t* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. It can have arbitrary (i.e., bad!)
+ effects if p has already been freed.
+
+ Unless disabled (using mallopt), freeing very large spaces will
+ when possible, automatically trigger operations that give
+ back unused memory to the system, thus reducing program footprint.
+*/
+#if __STD_C
+void public_fREe(Void_t*);
+#else
+void public_fREe();
+#endif
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+#if __STD_C
+Void_t* public_cALLOc(size_t, size_t) __attribute_malloc__;
+#else
+Void_t* public_cALLOc();
+#endif
+
+/*
+ realloc(Void_t* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p when possible, otherwise it employs the
+ equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. Unless the #define
+ REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
+ zero (re)allocates a minimum-sized chunk.
+
+ Large chunks that were internally obtained via mmap will always
+ be reallocated using malloc-copy-free sequences unless
+ the system supports MREMAP (currently only linux).
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+#if __STD_C
+Void_t* public_rEALLOc(Void_t*, size_t) __attribute_malloc__;
+#else
+Void_t* public_rEALLOc();
+#endif
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+#if __STD_C
+Void_t* public_mEMALIGn(size_t, size_t) __attribute_malloc__;
+#else
+Void_t* public_mEMALIGn();
+#endif
+
+/*
+ posix_memalign(void** memptr, size_t alignment, size_t n);
+ Sets *memptr to the address of a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument. Returns 0 on success, otherwise
+ an error (EINVAL for incorrect alignment, ENOMEM for out of memory).
+
+ The alignment must be a power of two, and a multiple of sizeof(void *).
+*/
+#if __STD_C
+int public_posix_mEMALIGn(Void_t**, size_t, size_t);
+#else
+int public_posix_mEMALIGn();
+#endif
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+#if __STD_C
+Void_t* public_vALLOc(size_t) __attribute_malloc__;
+#else
+Void_t* public_vALLOc();
+#endif
+
+
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. Only one of these (M_MXFAST) is used
+ in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+ so setting them has no effect. But this malloc also supports four
+ other options in mallopt. See below for details. Briefly, supported
+ parameters are as follows (listed defaults are for "typical"
+ configurations).
+
+ Symbol param # default allowed param values
+ M_MXFAST 1 64 0-80 (0 disables fastbins)
+ M_TRIM_THRESHOLD -1 256*1024 any (-1U disables trimming)
+ M_TOP_PAD -2 0 any
+ M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
+ M_MMAP_MAX -4 65536 any (0 disables use of mmap)
+*/
+#if __STD_C
+int public_mALLOPt(int, int);
+#else
+int public_mALLOPt();
+#endif
+
+
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: the number of fastbin blocks (i.e., small chunks that
+ have been freed but not use resused or consolidated)
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: total bytes held in fastbin blocks
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+#if __STD_C
+struct mallinfo public_mALLINFo(void);
+#else
+struct mallinfo public_mALLINFo();
+#endif
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+#if __STD_C
+Void_t* public_pVALLOc(size_t) __attribute_malloc__;
+#else
+Void_t* public_pVALLOc();
+#endif
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative
+ arguments to sbrk) if there is unused memory at the `high' end of
+ the malloc pool. You can call this after freeing large blocks of
+ memory to potentially reduce the system-level memory requirements
+ of a program. However, it cannot guarantee to reduce memory. Under
+ some allocation patterns, some large free blocks of memory will be
+ locked between two used chunks, so they cannot be given back to
+ the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero,
+ only the minimum amount of memory to maintain internal data
+ structures will be left (one page or less). Non-zero arguments
+ can be supplied to maintain enough trailing space to service
+ future expected allocations without having to re-obtain memory
+ from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+ On systems that do not support "negative sbrks", it will always
+ rreturn 0.
+*/
+#if __STD_C
+int public_mTRIm(size_t);
+#else
+int public_mTRIm();
+#endif
+
+/*
+ malloc_usable_size(Void_t* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+
+*/
+#if __STD_C
+size_t public_mUSABLe(Void_t*);
+#else
+size_t public_mUSABLe();
+#endif
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+
+*/
+#if __STD_C
+void public_mSTATs();
+#else
+void public_mSTATs();
+#endif
+
+/* mallopt tuning options */
+
+/*
+ M_MXFAST is the maximum request size used for "fastbins", special bins
+ that hold returned chunks without consolidating their spaces. This
+ enables future requests for chunks of the same size to be handled
+ very quickly, but can increase fragmentation, and thus increase the
+ overall memory footprint of a program.
+
+ This malloc manages fastbins very conservatively yet still
+ efficiently, so fragmentation is rarely a problem for values less
+ than or equal to the default. The maximum supported value of MXFAST
+ is 80. You wouldn't want it any higher than this anyway. Fastbins
+ are designed especially for use with many small structs, objects or
+ strings -- the default handles structs/objects/arrays with sizes up
+ to 16 4byte fields, or small strings representing words, tokens,
+ etc. Using fastbins for larger objects normally worsens
+ fragmentation without improving speed.
+
+ M_MXFAST is set in REQUEST size units. It is internally used in
+ chunksize units, which adds padding and alignment. You can reduce
+ M_MXFAST to 0 to disable all use of fastbins. This causes the malloc
+ algorithm to be a closer approximation of fifo-best-fit in all cases,
+ not just for larger requests, but will generally cause it to be
+ slower.
+*/
+
+
+/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */
+#ifndef M_MXFAST
+#define M_MXFAST 1
+#endif
+
+#ifndef DEFAULT_MXFAST
+#define DEFAULT_MXFAST 64
+#endif
+
+
+/*
+ M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+ to keep before releasing via malloc_trim in free().
+
+ Automatic trimming is mainly useful in long-lived programs.
+ Because trimming via sbrk can be slow on some systems, and can
+ sometimes be wasteful (in cases where programs immediately
+ afterward allocate more large chunks) the value should be high
+ enough so that your overall system performance would improve by
+ releasing this much memory.
+
+ The trim threshold and the mmap control parameters (see below)
+ can be traded off with one another. Trimming and mmapping are
+ two different ways of releasing unused memory back to the
+ system. Between these two, it is often possible to keep
+ system-level demands of a long-lived program down to a bare
+ minimum. For example, in one test suite of sessions measuring
+ the XF86 X server on Linux, using a trim threshold of 128K and a
+ mmap threshold of 192K led to near-minimal long term resource
+ consumption.
+
+ If you are using this malloc in a long-lived program, it should
+ pay to experiment with these values. As a rough guide, you
+ might set to a value close to the average size of a process
+ (program) running on your system. Releasing this much memory
+ would allow such a process to run in memory. Generally, it's
+ worth it to tune for trimming rather tham memory mapping when a
+ program undergoes phases where several large chunks are
+ allocated and released in ways that can reuse each other's
+ storage, perhaps mixed with phases where there are no such
+ chunks at all. And in well-behaved long-lived programs,
+ controlling release of large blocks via trimming versus mapping
+ is usually faster.
+
+ However, in most programs, these parameters serve mainly as
+ protection against the system-level effects of carrying around
+ massive amounts of unneeded memory. Since frequent calls to
+ sbrk, mmap, and munmap otherwise degrade performance, the default
+ parameters are set to relatively high values that serve only as
+ safeguards.
+
+ The trim value must be greater than page size to have any useful
+ effect. To disable trimming completely, you can set to
+ (unsigned long)(-1)
+
+ Trim settings interact with fastbin (MXFAST) settings: Unless
+ TRIM_FASTBINS is defined, automatic trimming never takes place upon
+ freeing a chunk with size less than or equal to MXFAST. Trimming is
+ instead delayed until subsequent freeing of larger chunks. However,
+ you can still force an attempted trim by calling malloc_trim.
+
+ Also, trimming is not generally possible in cases where
+ the main arena is obtained via mmap.
+
+ Note that the trick some people use of mallocing a huge space and
+ then freeing it at program startup, in an attempt to reserve system
+ memory, doesn't have the intended effect under automatic trimming,
+ since that memory will immediately be returned to the system.
+*/
+
+#define M_TRIM_THRESHOLD -1
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (256 * 1024)
+#endif
+
+/*
+ M_TOP_PAD is the amount of extra `padding' space to allocate or
+ retain whenever sbrk is called. It is used in two ways internally:
+
+ * When sbrk is called to extend the top of the arena to satisfy
+ a new malloc request, this much padding is added to the sbrk
+ request.
+
+ * When malloc_trim is called automatically from free(),
+ it is used as the `pad' argument.
+
+ In both cases, the actual amount of padding is rounded
+ so that the end of the arena is always a system page boundary.
+
+ The main reason for using padding is to avoid calling sbrk so
+ often. Having even a small pad greatly reduces the likelihood
+ that nearly every malloc request during program start-up (or
+ after trimming) will invoke sbrk, which needlessly wastes
+ time.
+
+ Automatic rounding-up to page-size units is normally sufficient
+ to avoid measurable overhead, so the default is 0. However, in
+ systems where sbrk is relatively slow, it can pay to increase
+ this value, at the expense of carrying around more memory than
+ the program needs.
+*/
+
+#define M_TOP_PAD -2
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD (0)
+#endif
+
+/*
+ M_MMAP_THRESHOLD is the request size threshold for using mmap()
+ to service a request. Requests of at least this size that cannot
+ be allocated using already-existing space will be serviced via mmap.
+ (If enough normal freed space already exists it is used instead.)
+
+ Using mmap segregates relatively large chunks of memory so that
+ they can be individually obtained and released from the host
+ system. A request serviced through mmap is never reused by any
+ other request (at least not directly; the system may just so
+ happen to remap successive requests to the same locations).
+
+ Segregating space in this way has the benefits that:
+
+ 1. Mmapped space can ALWAYS be individually released back
+ to the system, which helps keep the system level memory
+ demands of a long-lived program low.
+ 2. Mapped memory can never become `locked' between
+ other chunks, as can happen with normally allocated chunks, which
+ means that even trimming via malloc_trim would not release them.
+ 3. On some systems with "holes" in address spaces, mmap can obtain
+ memory that sbrk cannot.
+
+ However, it has the disadvantages that:
+
+ 1. The space cannot be reclaimed, consolidated, and then
+ used to service later requests, as happens with normal chunks.
+ 2. It can lead to more wastage because of mmap page alignment
+ requirements
+ 3. It causes malloc performance to be more dependent on host
+ system memory management support routines which may vary in
+ implementation quality and may impose arbitrary
+ limitations. Generally, servicing a request via normal
+ malloc steps is faster than going through a system's mmap.
+
+ The advantages of mmap nearly always outweigh disadvantages for
+ "large" chunks, but the value of "large" varies across systems. The
+ default is an empirically derived value that works well in most
+ systems.
+*/
+
+#define M_MMAP_THRESHOLD -3
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD (256 * 1024)
+#endif
+
+/*
+ M_MMAP_MAX is the maximum number of requests to simultaneously
+ service using mmap. This parameter exists because
+. Some systems have a limited number of internal tables for
+ use by mmap, and using more than a few of them may degrade
+ performance.
+
+ The default is set to a value that serves only as a safeguard.
+ Setting to 0 disables use of mmap for servicing large requests. If
+ HAVE_MMAP is not set, the default value is 0, and attempts to set it
+ to non-zero values in mallopt will fail.
+*/
+
+#define M_MMAP_MAX -4
+
+#ifndef DEFAULT_MMAP_MAX
+#define DEFAULT_MMAP_MAX (65536)
+#endif
+
+#ifdef __cplusplus
+}; /* end of extern "C" */
+#endif
+
+/*
+ ========================================================================
+ To make a fully customizable malloc.h header file, cut everything
+ above this line, put into file malloc.h, edit to suit, and #include it
+ on the next line, as well as in programs that use this malloc.
+ ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/* --------------------- public wrappers ---------------------- */
+
+#ifdef USE_PUBLIC_MALLOC_WRAPPERS
+
+/* DL_STATIC used to make functions (deep down) consistent
+ * with prototypes (otherwise the prototypes are static
+ * with USE_PUBLIC_MALLOC_WRAPPERS, but the functions aren't).
+ * The gcc compiler doesn't care, but the HP-UX compiler does.
+ */
+#define DL_STATIC static
+
+/* Declare all routines as internal */
+#if __STD_C
+static Void_t* mALLOc(size_t) __attribute_malloc__;
+static void fREe(Void_t*);
+static Void_t* rEALLOc(Void_t*, size_t) __attribute_malloc__;
+static Void_t* mEMALIGn(size_t, size_t) __attribute_malloc__;
+static int posix_mEMALIGn(Void_t**, size_t, size_t);
+static Void_t* vALLOc(size_t) __attribute_malloc__;
+static Void_t* pVALLOc(size_t) __attribute_malloc__;
+static Void_t* cALLOc(size_t, size_t) __attribute_malloc__;
+static int mTRIm(size_t);
+static size_t mUSABLe(Void_t*);
+static void mSTATs();
+static int mALLOPt(int, int);
+static struct mallinfo mALLINFo(void);
+#else
+static Void_t* mALLOc();
+static void fREe();
+static Void_t* rEALLOc();
+static Void_t* mEMALIGn();
+static int posix_mEMALIGn();
+static Void_t* vALLOc();
+static Void_t* pVALLOc();
+static Void_t* cALLOc();
+static int mTRIm();
+static size_t mUSABLe();
+static void mSTATs();
+static int mALLOPt();
+static struct mallinfo mALLINFo();
+#endif
+
+/*
+ MALLOC_PREACTION and MALLOC_POSTACTION should be
+ defined to return 0 on success, and nonzero on failure.
+ The return value of MALLOC_POSTACTION is currently ignored
+ in wrapper functions since there is no reasonable default
+ action to take on failure.
+*/
+
+
+#ifdef USE_MALLOC_LOCK
+
+# ifdef WIN32
+
+static int mALLOC_MUTEx;
+#define MALLOC_PREACTION slwait(&mALLOC_MUTEx)
+#define MALLOC_POSTACTION slrelease(&mALLOC_MUTEx)
+int dnmalloc_pthread_init(void) { return 0; }
+
+# elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+
+# if defined(__NetBSD__)
+#include <reentrant.h>
+extern int __isthreaded;
+static mutex_t thread_lock = MUTEX_INITIALIZER;
+#define _MALLOC_LOCK() if (__isthreaded) mutex_lock(&thread_lock)
+#define _MALLOC_UNLOCK() if (__isthreaded) mutex_unlock(&thread_lock)
+void _malloc_prefork(void) { _MALLOC_LOCK(); }
+void _malloc_postfork(void) { _MALLOC_UNLOCK(); }
+# endif
+
+# if defined(__OpenBSD__)
+extern int __isthreaded;
+void _thread_malloc_lock(void);
+void _thread_malloc_unlock(void);
+#define _MALLOC_LOCK() if (__isthreaded) _thread_malloc_lock()
+#define _MALLOC_UNLOCK() if (__isthreaded) _thread_malloc_unlock()
+# endif
+
+# if defined(__FreeBSD__)
+extern int __isthreaded;
+struct _spinlock {
+ volatile long access_lock;
+ volatile long lock_owner;
+ volatile char *fname;
+ volatile int lineno;
+};
+typedef struct _spinlock spinlock_t;
+#define _SPINLOCK_INITIALIZER { 0, 0, 0, 0 }
+void _spinlock(spinlock_t *);
+void _spinunlock(spinlock_t *);
+/* # include "/usr/src/lib/libc/include/spinlock.h" */
+static spinlock_t thread_lock = _SPINLOCK_INITIALIZER;
+spinlock_t *__malloc_lock = &thread_lock;
+#define _MALLOC_LOCK() if (__isthreaded) _spinlock(&thread_lock)
+#define _MALLOC_UNLOCK() if (__isthreaded) _spinunlock(&thread_lock)
+# endif
+
+/* Common for all three *BSD
+ */
+static int malloc_active = 0;
+static int dnmalloc_mutex_lock()
+{
+ _MALLOC_LOCK();
+ if (!malloc_active)
+ {
+ ++malloc_active;
+ return 0;
+ }
+ assert(malloc_active == 0);
+ _MALLOC_UNLOCK();
+ errno = EDEADLK;
+ return 1;
+}
+static int dnmalloc_mutex_unlock()
+{
+ --malloc_active;
+ _MALLOC_UNLOCK();
+ return 0;
+}
+#define MALLOC_PREACTION dnmalloc_mutex_lock()
+#define MALLOC_POSTACTION dnmalloc_mutex_unlock()
+int dnmalloc_pthread_init(void) { return 0; }
+
+# else
+
+/* Wrapping malloc with pthread_mutex_lock/pthread_mutex_unlock
+ *
+ * Works fine on linux (no malloc in pthread_mutex_lock)
+ * Works with on HP-UX if initialized after entering main()
+ */
+#include <pthread.h>
+static int malloc_active = 0;
+void dnmalloc_fork_prepare(void);
+void dnmalloc_fork_parent(void);
+void dnmalloc_fork_child(void);
+
+#if !defined(__linux__)
+
+static pthread_mutex_t mALLOC_MUTEx;
+pthread_once_t dnmalloc_once_control = PTHREAD_ONCE_INIT;
+static int dnmalloc_use_mutex = 0;
+static void dnmalloc_pthread_init_int(void)
+{
+ pthread_mutexattr_t mta;
+ pthread_mutexattr_init(&mta);
+ pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&(mALLOC_MUTEx), &mta);
+ pthread_mutexattr_destroy(&mta);
+ pthread_atfork(dnmalloc_fork_prepare,
+ dnmalloc_fork_parent,
+ dnmalloc_fork_child);
+ dnmalloc_use_mutex = 1;
+}
+int dnmalloc_pthread_init(void)
+{
+ return pthread_once(&dnmalloc_once_control, dnmalloc_pthread_init_int);
+}
+
+#else
+
+static pthread_mutex_t mALLOC_MUTEx = PTHREAD_MUTEX_INITIALIZER;
+static int dnmalloc_use_mutex = 1;
+int dnmalloc_pthread_init(void) {
+ return pthread_atfork(dnmalloc_fork_prepare,
+ dnmalloc_fork_parent,
+ dnmalloc_fork_child);
+}
+#endif /* !defined(__linux__) */
+
+void dnmalloc_fork_prepare(void) {
+ if (dnmalloc_use_mutex)
+ pthread_mutex_lock(&mALLOC_MUTEx);
+}
+void dnmalloc_fork_parent(void) {
+ if (dnmalloc_use_mutex)
+ pthread_mutex_unlock(&mALLOC_MUTEx);
+}
+void dnmalloc_fork_child(void) {
+ int rc = 0;
+#ifdef __GLIBC__
+ if (dnmalloc_use_mutex)
+ {
+ pthread_mutex_unlock (&mALLOC_MUTEx);
+ pthread_mutex_destroy(&mALLOC_MUTEx);
+ rc = pthread_mutex_init(&mALLOC_MUTEx, NULL);
+ }
+#else
+ if (dnmalloc_use_mutex)
+ rc = pthread_mutex_unlock(&mALLOC_MUTEx);
+#endif
+ if (rc != 0)
+ {
+ fputs("fork_child failed", stderr);
+ _exit(EXIT_FAILURE);
+ }
+}
+static int dnmalloc_mutex_lock(pthread_mutex_t *mutex)
+{
+ if (dnmalloc_use_mutex)
+ {
+ int rc = pthread_mutex_lock(mutex);
+ if (rc == 0)
+ {
+ if (!malloc_active)
+ {
+ ++malloc_active;
+ return 0;
+ }
+ assert(malloc_active == 0);
+ (void) pthread_mutex_unlock(mutex);
+ errno = EDEADLK;
+ return 1;
+ }
+ return rc;
+ }
+ return 0;
+}
+static int dnmalloc_mutex_unlock(pthread_mutex_t *mutex)
+{
+ if (dnmalloc_use_mutex)
+ {
+ --malloc_active;
+ return pthread_mutex_unlock(mutex);
+ }
+ return 0;
+}
+# define MALLOC_PREACTION dnmalloc_mutex_lock(&mALLOC_MUTEx)
+# define MALLOC_POSTACTION dnmalloc_mutex_unlock(&mALLOC_MUTEx)
+
+# endif
+
+#else
+
+/* Substitute anything you like for these */
+
+# define MALLOC_PREACTION (0)
+# define MALLOC_POSTACTION (0)
+int dnmalloc_pthread_init(void) { return 0; }
+
+#endif /* USE_MALLOC_LOCK */
+
+Void_t* public_mALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION == 0) {
+ m = mALLOc(bytes);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return 0;
+}
+
+void public_fREe(Void_t* m) {
+ if (MALLOC_PREACTION == 0) {
+ fREe(m);
+ (void) MALLOC_POSTACTION;
+ }
+}
+
+Void_t* public_rEALLOc(Void_t* m, size_t bytes) {
+ if (MALLOC_PREACTION == 0) {
+ m = rEALLOc(m, bytes);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return 0;
+}
+
+Void_t* public_mEMALIGn(size_t alignment, size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION == 0) {
+ m = mEMALIGn(alignment, bytes);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return 0;
+}
+
+int public_posix_mEMALIGn(Void_t**memptr, size_t alignment, size_t bytes) {
+ int m, ret;
+ if ((ret = MALLOC_PREACTION) == 0) {
+ m = posix_mEMALIGn(memptr, alignment, bytes);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return ret;
+}
+
+Void_t* public_vALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION == 0) {
+ m = vALLOc(bytes);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return 0;
+}
+
+Void_t* public_pVALLOc(size_t bytes) {
+ Void_t* m;
+ if (MALLOC_PREACTION == 0) {
+ m = pVALLOc(bytes);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return 0;
+}
+
+Void_t* public_cALLOc(size_t n, size_t elem_size) {
+ Void_t* m;
+ if (MALLOC_PREACTION == 0) {
+ m = cALLOc(n, elem_size);
+ (void) MALLOC_POSTACTION;
+ return m;
+ }
+ return 0;
+}
+
+int public_mTRIm(size_t s) {
+ int result;
+ if (MALLOC_PREACTION == 0) {
+ result = mTRIm(s);
+ (void) MALLOC_POSTACTION;
+ return result;
+ }
+ return 0;
+}
+
+size_t public_mUSABLe(Void_t* m) {
+ size_t result;
+ if (MALLOC_PREACTION == 0) {
+ result = mUSABLe(m);
+ (void) MALLOC_POSTACTION;
+ return result;
+ }
+ return 0;
+}
+
+void public_mSTATs() {
+ if (MALLOC_PREACTION == 0) {
+ mSTATs();
+ (void) MALLOC_POSTACTION;
+ }
+}
+
+struct mallinfo public_mALLINFo() {
+ struct mallinfo m;
+ if (MALLOC_PREACTION == 0) {
+ m = mALLINFo();
+ (void) MALLOC_POSTACTION;
+ return m;
+ } else {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ return nm;
+ }
+}
+
+int public_mALLOPt(int p, int v) {
+ int result;
+ if (MALLOC_PREACTION == 0) {
+ result = mALLOPt(p, v);
+ (void) MALLOC_POSTACTION;
+ return result;
+ }
+ return 0;
+}
+
+#else
+
+int dnmalloc_pthread_init(void) { return 0; }
+#define DL_STATIC
+
+#endif /* USE_PUBLIC_MALLOC_WRAPPERS */
+
+
+
+/* ------------- Optional versions of memcopy ---------------- */
+
+
+#if USE_MEMCPY
+
+/*
+ Note: memcpy is ONLY invoked with non-overlapping regions,
+ so the (usually slower) memmove is not needed.
+*/
+
+#define MALLOC_COPY(dest, src, nbytes) memcpy(dest, src, nbytes)
+#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes)
+
+#else /* !USE_MEMCPY */
+
+/* Use Duff's device for good zeroing/copying performance. */
+
+#define MALLOC_ZERO(charp, nbytes) \
+do { \
+ INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
+ CHUNK_SIZE_T mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \
+ long mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mzp++ = 0; \
+ case 7: *mzp++ = 0; \
+ case 6: *mzp++ = 0; \
+ case 5: *mzp++ = 0; \
+ case 4: *mzp++ = 0; \
+ case 3: *mzp++ = 0; \
+ case 2: *mzp++ = 0; \
+ case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#define MALLOC_COPY(dest,src,nbytes) \
+do { \
+ INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
+ INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
+ CHUNK_SIZE_T mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T); \
+ long mcn; \
+ if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
+ switch (mctmp) { \
+ case 0: for(;;) { *mcdst++ = *mcsrc++; \
+ case 7: *mcdst++ = *mcsrc++; \
+ case 6: *mcdst++ = *mcsrc++; \
+ case 5: *mcdst++ = *mcsrc++; \
+ case 4: *mcdst++ = *mcsrc++; \
+ case 3: *mcdst++ = *mcsrc++; \
+ case 2: *mcdst++ = *mcsrc++; \
+ case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
+ } \
+} while(0)
+
+#endif
+
+/* ------------------ MMAP support ------------------ */
+
+
+#if defined(HAVE_FCNTL_H)
+#include <fcntl.h>
+#endif
+
+#if defined(HAVE_SYS_MMAN_H)
+#include <sys/mman.h>
+#endif
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/*
+ Nearly all versions of mmap support MAP_ANONYMOUS,
+ so the following is unlikely to be needed, but is
+ supplied just in case.
+*/
+
+#ifndef MAP_ANONYMOUS
+
+/* rw 19.05.2008 changed to avoid cached file descriptor, untested
+ */
+void * anon_mmap (void *addr, size_t length, int prot, int flags)
+{
+ void * retval = NULL;
+ int dev_zero_fd = -1; /* File descriptor for /dev/zero. */
+
+ dev_zero_fd = open("/dev/zero", O_RDWR);
+ if (dev_zero_fd >= 0)
+ {
+ retval = mmap((addr), (size), (prot), (flags), dev_zero_fd, 0);
+ /* closing the file descriptor does not unmap the region */
+ close(dev_zero_fd);
+ }
+ return retval;
+}
+
+#define MMAP(addr, size, prot, flags) \
+ (anon_mmap((addr), (size), (prot), (flags)))
+
+
+#else /* have MAP_ANONYMOUS */
+
+#if !defined(MAP_32BIT) && defined(MAP_ADDR32)
+#define MAP_32BIT MAP_ADDR32
+#endif
+
+#if defined(MAP_32BIT)
+#define MMAP(addr, size, prot, flags) \
+ (mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS|MAP_32BIT, -1, 0))
+#elif defined(__sun)
+/*
+ * Hint an address within 32bit address space
+ */
+#define MMAP(addr, size, prot, flags) \
+ (mmap((void*)0xC0000000, (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0))
+#else
+/* *BSD */
+#define MMAP(addr, size, prot, flags) \
+ (mmap((void*)0x80000000, (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0))
+#endif
+
+#endif /* have MAP_ANONYMOUS */
+
+
+/*
+ ----------------------- Chunk representations -----------------------
+*/
+
+typedef void * mchunkptr;
+
+struct chunkinfo {
+ INTERNAL_SIZE_T prev_size; /* Size of previous in bytes */
+ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
+ INTERNAL_SIZE_T req; /* Original request size, for guard. */
+ struct chunkinfo* hash_next; /* contains a pointer to the next chunk
+ in the linked list if the hash
+ value is the same as the chunk */
+ struct chunkinfo* fd; /* double links -- used only if free. */
+ struct chunkinfo* bk;
+ mchunkptr chunk;
+};
+
+typedef struct chunkinfo* chunkinfoptr;
+
+struct cireginfo {
+ unsigned long position;
+ unsigned long *freebitmap;
+ struct cireginfo* next;
+ struct chunkinfo *freelist;
+ struct chunkinfo *begin;
+ unsigned long freecounter;
+};
+
+/*
+ ---------- Size and alignment checks and conversions ----------
+*/
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk(p) (p->chunk)
+
+
+#define chunk2mem(p) (chunk(p))
+#define mem2chunk(mem) (hashtable_lookup(mem))
+
+/* The smallest possible chunk */
+/* #define MIN_CHUNK_SIZE 16 */
+#if (SIZEOF_UNSIGNED_LONG == 8) || defined(__arch64__) || defined(__ia64__) || defined(__x86_64__) || defined(__LP64__) || defined(__64BIT__) || defined(_LP64) || defined(_M_IA64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64))
+# define MIN_CHUNK_SIZE 32
+#else
+# define MIN_CHUNK_SIZE 16
+#endif
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+
+#define MINSIZE \
+ (CHUNK_SIZE_T)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m) (((PTR_UINT)((m)) & (MALLOC_ALIGN_MASK)) == 0)
+
+#define GUARD_SIZE 4
+
+/*
+ Check if a request is so large that it would wrap around zero when
+ padded and aligned. To simplify some other code, the bound is made
+ low enough so that adding MINSIZE will also not wrap around zero.
+
+ Make it 4*MINSIZE.
+*/
+
+#define REQUEST_OUT_OF_RANGE(req) \
+ ((CHUNK_SIZE_T)(req) >= \
+ (CHUNK_SIZE_T)(INTERNAL_SIZE_T)(-4 * MINSIZE))
+
+/* pad request bytes into a usable size -- internal version */
+
+#define request2size(req) \
+ (((req) + GUARD_SIZE + MALLOC_ALIGN_MASK >= MINSIZE) ? \
+ ((req) + GUARD_SIZE + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK :\
+ MINSIZE)
+
+/* Same, except also perform argument check */
+
+#define checked_request2size(req, sz) \
+ if (!REQUEST_OUT_OF_RANGE(req)) { \
+ (sz) = request2size(req); \
+ assert((sz-req) >= GUARD_SIZE); \
+ } else { \
+ MALLOC_FAILURE_ACTION; \
+ return 0; \
+ }
+
+#if PARANOIA > 2
+static char * guard_set_p;
+static char * guard_set_q;
+
+#define guard_set(guard, P, request, sz) \
+ assert((sz-request) >= GUARD_SIZE); \
+ guard_set_p = (char*)(chunk(P)); \
+ guard_set_p += request; \
+ VALGRIND_MAKE_MEM_UNDEFINED(guard_set_p,GUARD_SIZE); \
+ guard_set_q = (char*)(guard); \
+ *guard_set_p = *guard_set_q; ++guard_set_p; ++guard_set_q; \
+ *guard_set_p = *guard_set_q; ++guard_set_p; ++guard_set_q; \
+ *guard_set_p = *guard_set_q; ++guard_set_p; ++guard_set_q; \
+ *guard_set_p = *guard_set_q; \
+ VALGRIND_MAKE_MEM_NOACCESS((((char*)chunk(P))+request),GUARD_SIZE); \
+ (P)->req = request
+
+#define guard_check(guard, P) \
+ VALGRIND_MAKE_MEM_DEFINED((((char *)chunk(P))+(P)->req), GUARD_SIZE); \
+ assert(0 == memcmp((((char *)chunk(P))+(P)->req),(void*)(guard),GUARD_SIZE));\
+ VALGRIND_MAKE_MEM_NOACCESS((((char *)chunk(P))+(P)->req), GUARD_SIZE);
+
+#else
+#define guard_set(guard, P, request, sz) ((void)0)
+#define guard_check(guard, P) ((void)0)
+#endif /* PARANOIA > 2 */
+
+/* dnmalloc forward declarations */
+static char * dnmalloc_arc4random(void);
+static void dnmalloc_init (void);
+static void malloc_mmap_state(void);
+static void cireg_extend (void);
+static chunkinfoptr cireg_getfree (void);
+static void hashtable_add (chunkinfoptr ci);
+static void hashtable_insert (chunkinfoptr ci_orig, chunkinfoptr ci_insert);
+static void hashtable_remove (mchunkptr p);
+static void hashtable_skiprm (chunkinfoptr ci_orig, chunkinfoptr ci_todelete);
+static chunkinfoptr hashtable_lookup (mchunkptr p);
+static chunkinfoptr next_chunkinfo (chunkinfoptr ci);
+static chunkinfoptr prev_chunkinfo (chunkinfoptr ci);
+
+
+
+/*
+ --------------- Physical chunk operations ---------------
+*/
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+#define PREV_INUSE 0x1
+
+/* extract inuse bit of previous chunk */
+#define prev_inuse(p) ((p)->size & PREV_INUSE)
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+#define IS_MMAPPED 0x2
+
+/* check for mmap()'ed chunk */
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+
+/* size field is or'ed when the chunk is in use */
+#define INUSE 0x4
+
+/* extract inuse bit of chunk */
+#define inuse(p) ((p)->size & INUSE)
+
+/*
+ Bits to mask off when extracting size
+
+ Note: IS_MMAPPED is intentionally not masked off from size field in
+ macros for which mmapped chunks should never be seen. This should
+ cause helpful core dumps to occur if it is tried by accident by
+ people extending or adapting this malloc.
+*/
+#define SIZE_BITS (PREV_INUSE|IS_MMAPPED|INUSE)
+
+/* Bits to mask off when extracting size of chunks for macros which do not use mmap */
+#define SIZE_NOMMAP (PREV_INUSE|INUSE)
+
+/* Get size, ignoring use bits */
+#define chunksize(p) ((p)->size & ~(SIZE_BITS))
+
+/* Ptr to chunkinfo of next physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & SIZE_NOMMAP) ))
+
+/* Treat space at ptr + offset as a chunk */
+#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+
+/* set/clear chunk as being inuse without otherwise disturbing */
+#define set_inuse(p) ((p)->size |= INUSE)
+
+#define clear_inuse(p) ((p)->size &= ~(INUSE))
+
+#define set_previnuse(p) ((p)->size |= PREV_INUSE)
+
+#define clear_previnuse(p) ((p)->size &= ~(PREV_INUSE))
+
+static void set_previnuse_next (chunkinfoptr p)
+{
+ chunkinfoptr q;
+ q = next_chunkinfo (p);
+ if (q)
+ set_previnuse (q);
+}
+
+#define set_all_inuse(p) \
+set_inuse(p); \
+set_previnuse_next(p);
+
+
+/* Set size at head, without disturbing its use bit */
+#define set_head_size(p, s) ((p)->size = (((p)->size & SIZE_NOMMAP) | (s)))
+
+/* Set size/use field */
+#define set_head(p, s) ((p)->size = (s))
+
+/*
+ Bins
+
+ An array of bin headers for free chunks. Each bin is doubly
+ linked. The bins are approximately proportionally (log) spaced.
+ There are a lot of these bins (128). This may look excessive, but
+ works very well in practice. Most bins hold sizes that are
+ unusual as malloc request sizes, but are more usual for fragments
+ and consolidated sets of chunks, which is what these bins hold, so
+ they can be found quickly. All procedures maintain the invariant
+ that no consolidated chunk physically borders another one, so each
+ chunk in a list is known to be preceeded and followed by either
+ inuse chunks or the ends of memory.
+
+ Chunks in bins are kept in size order, with ties going to the
+ approximately least recently used chunk. Ordering isn't needed
+ for the small bins, which all contain the same-sized chunks, but
+ facilitates best-fit allocation for larger chunks. These lists
+ are just sequential. Keeping them in order almost never requires
+ enough traversal to warrant using fancier ordered data
+ structures.
+
+ Chunks of the same size are linked with the most
+ recently freed at the front, and allocations are taken from the
+ back. This results in LRU (FIFO) allocation order, which tends
+ to give each chunk an equal opportunity to be consolidated with
+ adjacent freed chunks, resulting in larger free chunks and less
+ fragmentation.
+
+ To simplify use in double-linked lists, each bin header acts
+ as a malloc_chunk. This avoids special-casing for headers.
+ But to conserve space and improve locality, we allocate
+ only the fd/bk pointers of bins, and then use repositioning tricks
+ to treat these as the fields of a malloc_chunk*.
+*/
+
+typedef struct chunkinfo* mbinptr;
+
+/* addressing -- note that bin_at(0) does not exist */
+#define bin_at(m, i) (&(m)->bins[i])
+
+/* analog of ++bin */
+#define next_bin(b) (b+1)
+
+/* Reminders about list directionality within bins */
+#define first(b) ((b)->fd)
+#define last(b) ((b)->bk)
+
+/* Take a chunk off a bin list */
+#define unlink(P, BK, FD) { \
+ FD = P->fd; \
+ BK = P->bk; \
+ FD->bk = BK; \
+ BK->fd = FD; \
+}
+
+/*
+ Indexing
+
+ Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+ 8 bytes apart. Larger bins are approximately logarithmically spaced:
+
+ 64 bins of size 8
+ 32 bins of size 64
+ 16 bins of size 512
+ 8 bins of size 4096
+ 4 bins of size 32768
+ 2 bins of size 262144
+ 1 bin of size what's left
+
+ The bins top out around 1MB because we expect to service large
+ requests via mmap.
+*/
+
+#define NBINS 96
+#define NSMALLBINS 32
+#define SMALLBIN_WIDTH 8
+#define MIN_LARGE_SIZE 256
+
+#define in_smallbin_range(sz) \
+ ((CHUNK_SIZE_T)(sz) < (CHUNK_SIZE_T)MIN_LARGE_SIZE)
+
+#define smallbin_index(sz) (((unsigned)(sz)) >> 3)
+
+/*
+ Compute index for size. We expect this to be inlined when
+ compiled with optimization, else not, which works out well.
+*/
+static int largebin_index(size_t sz) {
+
+ unsigned long xx = sz >> SMALLBIN_WIDTH;
+
+ if (xx < 0x10000)
+ {
+ unsigned int m; /* bit position of highest set bit of m */
+
+ /* On intel, use BSRL instruction to find highest bit */
+#if defined(__GNUC__) && defined(i386) && !defined(USE_UNO)
+
+ unsigned int x = (unsigned int) xx;
+
+ __asm__("bsrl %1,%0\n\t"
+ : "=r" (m)
+ : "rm" (x));
+
+#elif defined(__GNUC__) && defined(x86_64) && !defined(USE_UNO)
+
+ __asm__("bsrq %1,%0\n\t"
+ : "=r" (m)
+ : "rm" (xx));
+
+#else
+
+ /* Taken from Bit Twiddling Hacks
+ * http://graphics.stanford.edu/~seander/bithacks.html
+ * public domain
+ */
+ unsigned int v = (unsigned int) xx;
+ register unsigned int shift;
+
+ m = (v > 0xFFFF) << 4; v >>= m;
+ shift = (v > 0xFF ) << 3; v >>= shift; m |= shift;
+ shift = (v > 0xF ) << 2; v >>= shift; m |= shift;
+ shift = (v > 0x3 ) << 1; v >>= shift; m |= shift;
+ m |= (v >> 1);
+
+#endif
+
+ /* Use next 2 bits to create finer-granularity bins */
+ return NSMALLBINS + (m << 2) + ((sz >> (m + 6)) & 3);
+ }
+ else
+ {
+ return NBINS-1;
+ }
+}
+
+#define bin_index(sz) \
+ ((in_smallbin_range(sz)) ? smallbin_index(sz) : largebin_index(sz))
+
+/*
+ FIRST_SORTED_BIN_SIZE is the chunk size corresponding to the
+ first bin that is maintained in sorted order. This must
+ be the smallest size corresponding to a given bin.
+
+ Normally, this should be MIN_LARGE_SIZE. But you can weaken
+ best fit guarantees to sometimes speed up malloc by increasing value.
+ Doing this means that malloc may choose a chunk that is
+ non-best-fitting by up to the width of the bin.
+
+ Some useful cutoff values:
+ 512 - all bins sorted
+ 2560 - leaves bins <= 64 bytes wide unsorted
+ 12288 - leaves bins <= 512 bytes wide unsorted
+ 65536 - leaves bins <= 4096 bytes wide unsorted
+ 262144 - leaves bins <= 32768 bytes wide unsorted
+ -1 - no bins sorted (not recommended!)
+*/
+
+/* #define FIRST_SORTED_BIN_SIZE 65536 */
+
+#define FIRST_SORTED_BIN_SIZE MIN_LARGE_SIZE
+
+
+/*
+ Unsorted chunks
+
+ All remainders from chunk splits, as well as all returned chunks,
+ are first placed in the "unsorted" bin. They are then placed
+ in regular bins after malloc gives them ONE chance to be used before
+ binning. So, basically, the unsorted_chunks list acts as a queue,
+ with chunks being placed on it in free (and malloc_consolidate),
+ and taken off (to be either used or placed in bins) in malloc.
+*/
+
+/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
+#define unsorted_chunks(M) (bin_at(M, 1))
+
+/*
+ Top
+
+ The top-most available chunk (i.e., the one bordering the end of
+ available memory) is treated specially. It is never included in
+ any bin, is used only if no other chunk is available, and is
+ released back to the system if it is very large (see
+ M_TRIM_THRESHOLD). Because top initially
+ points to its own bin with initial zero size, thus forcing
+ extension on the first malloc request, we avoid having any special
+ code in malloc to check whether it even exists yet. But we still
+ need to do so when getting memory from system, so we make
+ initial_top treat the bin as a legal but unusable chunk during the
+ interval between initialization and the first call to
+ sYSMALLOc. (This is somewhat delicate, since it relies on
+ the 2 preceding words to be zero during this interval as well.)
+*/
+
+/* Conveniently, the unsorted bin can be used as dummy top on first call */
+#define initial_top(M) (unsorted_chunks(M))
+
+/*
+ Binmap
+
+ To help compensate for the large number of bins, a one-level index
+ structure is used for bin-by-bin searching. `binmap' is a
+ bitvector recording whether bins are definitely empty so they can
+ be skipped over during during traversals. The bits are NOT always
+ cleared as soon as bins are empty, but instead only
+ when they are noticed to be empty during traversal in malloc.
+*/
+
+/* Conservatively use 32 bits per map word, even if on 64bit system */
+#define BINMAPSHIFT 5
+#define BITSPERMAP (1U << BINMAPSHIFT)
+#define BINMAPSIZE (NBINS / BITSPERMAP)
+
+#define idx2block(i) ((i) >> BINMAPSHIFT)
+#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1))))
+
+#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i))
+#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i)))
+#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i))
+
+/*
+ Fastbins
+
+ An array of lists holding recently freed small chunks. Fastbins
+ are not doubly linked. It is faster to single-link them, and
+ since chunks are never removed from the middles of these lists,
+ double linking is not necessary. Also, unlike regular bins, they
+ are not even processed in FIFO order (they use faster LIFO) since
+ ordering doesn't much matter in the transient contexts in which
+ fastbins are normally used.
+
+ Chunks in fastbins keep their inuse bit set, so they cannot
+ be consolidated with other free chunks. malloc_consolidate
+ releases all chunks in fastbins and consolidates them with
+ other free chunks.
+*/
+
+typedef struct chunkinfo* mfastbinptr;
+
+/* offset 2 to use otherwise unindexable first 2 bins */
+#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2)
+
+/* The maximum fastbin request size we support */
+#define MAX_FAST_SIZE 80
+
+#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1)
+
+/*
+ FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free()
+ that triggers automatic consolidation of possibly-surrounding
+ fastbin chunks. This is a heuristic, so the exact value should not
+ matter too much. It is defined at half the default trim threshold as a
+ compromise heuristic to only attempt consolidation if it is likely
+ to lead to trimming. However, it is not dynamically tunable, since
+ consolidation reduces fragmentation surrounding loarge chunks even
+ if trimming is not used.
+*/
+
+#define FASTBIN_CONSOLIDATION_THRESHOLD \
+ ((unsigned long)(DEFAULT_TRIM_THRESHOLD) >> 1)
+
+/*
+ Since the lowest 2 bits in max_fast don't matter in size comparisons,
+ they are used as flags.
+*/
+
+/*
+ ANYCHUNKS_BIT held in max_fast indicates that there may be any
+ freed chunks at all. It is set true when entering a chunk into any
+ bin.
+*/
+
+#define ANYCHUNKS_BIT (1U)
+
+#define have_anychunks(M) (((M)->max_fast & ANYCHUNKS_BIT))
+#define set_anychunks(M) ((M)->max_fast |= ANYCHUNKS_BIT)
+#define clear_anychunks(M) ((M)->max_fast &= ~ANYCHUNKS_BIT)
+
+/*
+ FASTCHUNKS_BIT held in max_fast indicates that there are probably
+ some fastbin chunks. It is set true on entering a chunk into any
+ fastbin, and cleared only in malloc_consolidate.
+*/
+
+#define FASTCHUNKS_BIT (2U)
+
+#define have_fastchunks(M) (((M)->max_fast & FASTCHUNKS_BIT))
+#define set_fastchunks(M) ((M)->max_fast |= (FASTCHUNKS_BIT|ANYCHUNKS_BIT))
+#define clear_fastchunks(M) ((M)->max_fast &= ~(FASTCHUNKS_BIT))
+
+/*
+ Set value of max_fast.
+ Use impossibly small value if 0.
+*/
+
+#define set_max_fast(M, s) \
+ (M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \
+ ((M)->max_fast & (FASTCHUNKS_BIT|ANYCHUNKS_BIT))
+
+#define get_max_fast(M) \
+ ((M)->max_fast & ~(FASTCHUNKS_BIT | ANYCHUNKS_BIT))
+
+
+/*
+ morecore_properties is a status word holding dynamically discovered
+ or controlled properties of the morecore function
+*/
+
+#define MORECORE_CONTIGUOUS_BIT (1U)
+
+#define contiguous(M) \
+ (((M)->morecore_properties & MORECORE_CONTIGUOUS_BIT))
+#define noncontiguous(M) \
+ (((M)->morecore_properties & MORECORE_CONTIGUOUS_BIT) == 0)
+#define set_contiguous(M) \
+ ((M)->morecore_properties |= MORECORE_CONTIGUOUS_BIT)
+#define set_noncontiguous(M) \
+ ((M)->morecore_properties &= ~MORECORE_CONTIGUOUS_BIT)
+
+#define MORECORE_32BIT_BIT (2U)
+
+#define morecore32bit(M) \
+ (((M)->morecore_properties & MORECORE_32BIT_BIT))
+#define nonmorecore32bit(M) \
+ (((M)->morecore_properties & MORECORE_32BIT_BIT) == 0)
+#define set_morecore32bit(M) \
+ ((M)->morecore_properties |= MORECORE_32BIT_BIT)
+#define set_nonmorecore32bit(M) \
+ ((M)->morecore_properties &= ~MORECORE_32BIT_BIT)
+
+
+
+/* ----------------- dnmalloc -------------------- */
+
+/* size of pages */
+#define PGSIZE malloc_getpagesize
+/* pointer size */
+#define PTRSIZE sizeof(long)
+
+
+
+/* TODO: mmapped chunks are always multiples of pagesize -> we're wasting
+ address space: the hashtable has granularity of 16*8, set it to something
+ closer to pagesize for mmapped chunks (current waste: 32 positions/mmapped
+ page)
+*/
+
+/* The maximum heap size that dnmalloc can operate with
+ * represented in hex to avoid annoying gcc warning
+ *
+ * Avoid integer overflow, cover complete 32bit address
+ * space for portability. With deferred allocation, the
+ * hashtable size is a non-issue.
+ */
+#define HEAPMAXSIZE_HALF 0x80000000UL
+
+/* How many elements are stored in the linked list */
+#define LINKEDLSTELS 8
+
+/* Minimum size of a chunk */
+
+#if (SIZEOF_UNSIGNED_LONG == 8) || defined(__arch64__) || defined(__ia64__) || defined(__x86_64__) || defined(__LP64__) || defined(__64BIT__) || defined(_LP64) || defined(_M_IA64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64))
+# define MINCHUNKSIZE 32
+#else
+# define MINCHUNKSIZE 16
+#endif
+
+
+/* The amount of hashtable entries for each page:
+Pagesize divded by the numer of elements in the linkedlists
+divided by the minimum chunk size
+*/
+#define CHUNKINFOPAGE (PGSIZE / LINKEDLSTELS / MINCHUNKSIZE)
+
+/* The amount of hashtable entries needed to manage the memory:
+Maximum heap size divided by page size multiplied by the amount
+of chunk info's per page
+*/
+#define AMOUNTHASH ((HEAPMAXSIZE_HALF / PGSIZE) * CHUNKINFOPAGE * 2)
+
+/* Initial size of the map for the hashtable
+Amount of entries muliplied by pointer size
+*/
+#define HASHTABLESIZE (AMOUNTHASH * PTRSIZE)
+
+/* Amount of free chunks that the system should allocate at the start */
+#define NUMBER_FREE_CHUNKS 32768
+
+/* Initial size of the chunk info region,
+also used when growing the region */
+#define CIREGSIZE (NUMBER_FREE_CHUNKS * sizeof(struct chunkinfo))
+
+/* Start address of the heap */
+char *startheap;
+
+/* pointer to the hashtable: struct chunkinfo **hashtable -> *hashtable[] */
+chunkinfoptr *hashtable;
+
+/* Current chunkinfo region */
+struct cireginfo *currciinfo = 0;
+struct cireginfo *firstciinfo = 0;
+
+unsigned long totalcictr = 0;
+
+
+/* Initialize the area for chunkinfos and the hashtable and protect
+ * it with non-writable pages
+ */
+static void
+dnmalloc_init ()
+{
+ void *hashtb;
+ int mprot;
+ int flags = MAP_PRIVATE;
+
+ /* Allocate the malloc_state struct */
+ malloc_mmap_state();
+
+ /* Use MAP_NORESERVE if available (Solaris, HP-UX; most other
+ * systems use defered allocation anyway.
+ */
+#ifdef MAP_NORESERVE
+ flags |= MAP_NORESERVE;
+#endif
+
+ /* Always start at 0, hashtable covers whole 32bit address space
+ */
+#define STARTHEAP_IS_ZERO
+ startheap = 0;
+
+ /* Map space for the hashtable */
+#if PARANOIA > 1
+ hashtb = MMAP(0, HASHTABLESIZE+(2*PGSIZE), PROT_READ|PROT_WRITE, flags);
+#else
+ hashtb = MMAP(0, HASHTABLESIZE+PGSIZE, PROT_READ|PROT_WRITE, flags);
+#endif
+
+#ifdef NDEBUG
+ if (hashtb == MAP_FAILED) {
+ fprintf (stderr, "Couldn't mmap hashtable: %s\n", strerror (errno));
+ abort ();
+ }
+#else
+ assert(hashtb != MAP_FAILED);
+#endif
+
+ /* Protect the hashtable with non-writable pages */
+ mprot = mprotect(hashtb, (size_t) PGSIZE, PROT_NONE);
+#ifdef NDEBUG
+ if (mprot == -1) {
+ fprintf (stderr, "Couldn't mprotect first non-rw page for hashtable: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(mprot != -1);
+#endif
+
+ /* HP-UX: Cannot do arithmetic with pointers to objects of unknown size. */
+ hashtable = (chunkinfoptr *) (((char*)hashtb) + PGSIZE);
+
+ /* Protect the hashtable with non-writable pages */
+#if PARANOIA > 1
+ mprot = mprotect((void*)((char*)hashtb+HASHTABLESIZE+PGSIZE), (size_t) PGSIZE, PROT_NONE);
+#ifdef NDEBUG
+ if (mprot == -1) {
+ fprintf (stderr, "Couldn't mprotect last non-rw page for hashtable: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(mprot != -1);
+#endif
+#endif
+}
+
+
+
+/* Extend the region for chunk infos by mapping more memory before the region */
+static void
+cireg_extend ()
+{
+ void *newcireg;
+ int mprot;
+ struct cireginfo *tempciinfo = 0;
+
+#if PARANOIA > 1
+ newcireg = MMAP(0, CIREGSIZE+(2*PGSIZE), PROT_READ|PROT_WRITE, MAP_PRIVATE);
+#else
+ newcireg = MMAP(0, CIREGSIZE+PGSIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE);
+#endif
+
+#ifdef NDEBUG
+ if (newcireg == MAP_FAILED)
+ {
+ fprintf (stderr, "Couldn't extend chunkinfo region: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(newcireg != MAP_FAILED);
+#endif
+ mprot = mprotect(newcireg, PGSIZE, PROT_NONE);
+#ifdef NDEBUG
+ if (mprot == -1) {
+ fprintf (stderr, "Couldn't mprotect first non-rw page for extended region: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(mprot != -1);
+#endif
+ newcireg = ((char*)newcireg)+PGSIZE;
+
+#if PARANOIA > 1
+ mprot = mprotect((void*)((char*)newcireg+CIREGSIZE), (size_t) PGSIZE, PROT_NONE);
+#ifdef NDEBUG
+ if (mprot == -1) {
+ fprintf (stderr, "Couldn't mprotect last non-rw page for extended region: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(mprot != -1);
+#endif
+#endif
+
+ tempciinfo = currciinfo;
+ currciinfo = (struct cireginfo *) newcireg;
+ if (tempciinfo)
+ tempciinfo->next = currciinfo;
+ currciinfo->position = 1;
+ currciinfo->freecounter = NUMBER_FREE_CHUNKS;
+ if (!firstciinfo)
+ firstciinfo = currciinfo;
+ totalcictr++;
+ VALGRIND_CREATE_MEMPOOL(newcireg, 0, 0);
+}
+
+
+/* Get a free chunkinfo */
+static chunkinfoptr
+cireg_getfree ()
+{
+ chunkinfoptr freeci;
+ chunkinfoptr freelst = 0;
+ struct cireginfo *newciinfo = firstciinfo;
+
+ if (newciinfo) {
+ freelst = newciinfo->freelist;
+
+ if (!freelst && newciinfo->next) {
+ do {
+ newciinfo = newciinfo->next;
+ freelst = newciinfo->freelist;
+ } while (!freelst && newciinfo->next);
+ }
+ }
+
+ /* Check if there are any free chunkinfos on the list of free chunkinfos */
+ if (freelst)
+ {
+ freeci = freelst;
+ newciinfo->freecounter--;
+ newciinfo->freelist = freelst->fd;
+
+ VALGRIND_MEMPOOL_ALLOC((char*)currciinfo, (char*)freeci,
+ sizeof(struct chunkinfo));
+
+ freeci->prev_size = 0;
+ freeci->size = 0;
+ freeci->req = 0;
+ freeci->hash_next = NULL;
+ freeci->fd = NULL;
+ freeci->bk = NULL;
+ freeci->chunk = NULL;
+ return (freeci);
+ }
+ else
+ {
+ /* No free chunkinfos, check if chunkinfo region still has place
+ * for a chunkinfo. If not, extend the region.
+ */
+ if (UNLIKELY(!currciinfo || currciinfo->position == NUMBER_FREE_CHUNKS))
+ cireg_extend ();
+ /* Get a chunkinfo from the chunkinfo region */
+ freeci = (chunkinfoptr) currciinfo + currciinfo->position;
+ currciinfo->freecounter--;
+ currciinfo->position++;
+
+ VALGRIND_MEMPOOL_ALLOC((char*)currciinfo, (char*)freeci,
+ sizeof(struct chunkinfo));
+
+ return (freeci);
+ }
+}
+
+static void freeciregion(struct cireginfo *freeme) {
+ /* free the chunkinfo region */
+ struct cireginfo *newciinfo = firstciinfo;
+ struct cireginfo *prevciinfo = firstciinfo;
+ void *unmapme;
+
+ while (newciinfo && newciinfo != freeme) {
+ prevciinfo = newciinfo;
+ newciinfo = newciinfo->next;
+ }
+ assert(freeme == newciinfo); /* rw */
+ assert(newciinfo != NULL); /* rw */
+ if (newciinfo)
+ prevciinfo->next = newciinfo->next;
+ unmapme = (void *) ((char*)freeme - PGSIZE);
+ VALGRIND_DESTROY_MEMPOOL((char*)freeme);
+#if PARANOIA > 1
+ munmap(unmapme, CIREGSIZE+(2*PGSIZE));
+#else
+ munmap(unmapme, CIREGSIZE+PGSIZE);
+#endif
+}
+
+
+static void freecilst_add(chunkinfoptr p) {
+
+ struct cireginfo *newciinfo;
+
+ newciinfo = currciinfo;
+ if (((chunkinfoptr) newciinfo < p) && (p < (chunkinfoptr) (newciinfo+NUMBER_FREE_CHUNKS))) {
+ p->fd = newciinfo->freelist;
+ newciinfo->freelist = p;
+ newciinfo->freecounter++;
+ VALGRIND_MEMPOOL_FREE((char*)newciinfo, (char*)p);
+ VALGRIND_MAKE_MEM_DEFINED(p,sizeof(struct chunkinfo));
+ VALGRIND_MAKE_MEM_NOACCESS(p->size, sizeof(INTERNAL_SIZE_T));
+ VALGRIND_MAKE_MEM_NOACCESS(p->req, sizeof(INTERNAL_SIZE_T));
+ VALGRIND_MAKE_MEM_NOACCESS(p->bk, sizeof(struct chunkinfo*));
+ VALGRIND_MAKE_MEM_NOACCESS(p->chunk, sizeof(mchunkptr));
+ } else {
+ newciinfo = firstciinfo;
+ if (newciinfo) {
+ do {
+ if (((chunkinfoptr) newciinfo < p) && (p < (chunkinfoptr) (newciinfo+NUMBER_FREE_CHUNKS))) {
+ p->fd = newciinfo->freelist;
+ newciinfo->freelist = p;
+ newciinfo->freecounter++;
+ VALGRIND_MEMPOOL_FREE((char*)newciinfo, (char*)p);
+ VALGRIND_MAKE_MEM_DEFINED(p,sizeof(struct chunkinfo));
+ VALGRIND_MAKE_MEM_NOACCESS(p->size, sizeof(INTERNAL_SIZE_T));
+ VALGRIND_MAKE_MEM_NOACCESS(p->req, sizeof(INTERNAL_SIZE_T));
+ VALGRIND_MAKE_MEM_NOACCESS(p->bk, sizeof(struct chunkinfo*));
+ VALGRIND_MAKE_MEM_NOACCESS(p->chunk, sizeof(mchunkptr));
+ if (UNLIKELY(newciinfo->freecounter == NUMBER_FREE_CHUNKS))
+ freeciregion(newciinfo);
+ break;
+ }
+ newciinfo = newciinfo->next;
+ } while (newciinfo);
+ }
+ }
+}
+
+/* Calculate the hash table entry for a chunk */
+#ifdef STARTHEAP_IS_ZERO
+#define hash(p) (((unsigned long) p) >> 7)
+#else
+#define hash(p) (((unsigned long) p - (unsigned long) startheap) >> 7)
+#endif
+
+static void
+hashtable_add (chunkinfoptr ci)
+{
+ chunkinfoptr temp, next;
+ unsigned long hashval;
+ mchunkptr cic = chunk (ci);
+
+ hashval = hash (cic);
+
+ if (hashval < AMOUNTHASH) {
+
+ temp = hashtable[hashval];
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "hashtable_add: %p, %lu\n", chunk(ci), hashval);
+#endif
+
+ /* If no pointer to a chunk info list is stored at this location
+ * in the hashtable or if the chunk's address is smaller than the
+ * one present, add the chunk to the front of the linked list
+ */
+ if (temp == 0 || chunk (temp) > cic)
+ {
+ ci->hash_next = temp;
+ hashtable[hashval] = ci;
+ if (!temp) /* more likely case */
+ goto out;
+ temp->prev_size = chunksize(ci);
+ return;
+ }
+ else
+ {
+ /* We must place the chunk in the linked list for this hashentry
+ * Loop to end of list or to a position where temp's chunk's address
+ * is larger than the new chunkinfo's chunk's address
+ */
+ if (!temp->hash_next || (chunk (temp->hash_next) > cic))
+ {
+ ci->hash_next = temp->hash_next;
+ temp->hash_next = ci;
+ }
+ else
+ {
+ while ((temp->hash_next != 0) && (chunk (temp->hash_next) < cic))
+ {
+ temp = temp->hash_next;
+ }
+ /* Place in linked list if not already there */
+ if (!temp->hash_next || !(chunk (temp->hash_next) == cic))
+ {
+ ci->hash_next = temp->hash_next;
+ temp->hash_next = ci;
+ }
+ }
+ }
+ }
+ else {
+#ifdef DNMALLOC_CHECKS
+ if (hashval >= AMOUNTHASH) {
+ fprintf(stderr, "Dnmalloc error: trying to write outside of the bounds of the hashtable, this is definitely a bug, please email dnmalloc@fort-knox.org (hashval: %lu, AMOUNTHASH: %lu, HEAPMAXSIZE_HALF %lu PGSIZE %ld CHUNKINFOPAGE %ld chunk: %p, chunkinfo: %p, startheap: %p).\n", hashval, AMOUNTHASH, HEAPMAXSIZE_HALF, PGSIZE, CHUNKINFOPAGE, chunk(ci), ci, startheap);
+ abort();
+ }
+#else
+ assert(hashval < AMOUNTHASH);
+#endif
+ }
+
+ out:
+ next = next_chunkinfo(ci);
+ if (!next)
+ return;
+ next->prev_size = chunksize(ci);
+}
+
+static void
+hashtable_insert (chunkinfoptr ci_orig, chunkinfoptr ci_insert)
+{
+ chunkinfoptr next;
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "hashtable_ins: %p, %lu\n", chunk(ci_insert),
+ (unsigned long)hash(chunk(ci_insert));
+#endif
+
+ if (hash(chunk(ci_orig)) != hash(chunk(ci_insert))) {
+ hashtable_add(ci_insert);
+ }
+ else {
+
+ ci_insert->hash_next = ci_orig->hash_next;
+ ci_orig->hash_next = ci_insert;
+
+ /* added for prevsize */
+ if (!(ci_insert->hash_next))
+ next = next_chunkinfo(ci_insert);
+ else
+ next = ci_insert->hash_next;
+
+ if (!next)
+ {
+ ci_insert->prev_size = chunksize(ci_orig);
+ }
+ else
+ {
+ next->prev_size = chunksize(ci_insert);
+ ci_insert->prev_size = chunksize(ci_orig);
+ }
+ }
+}
+
+static void
+hashtable_remove (mchunkptr p)
+{
+ chunkinfoptr prevtemp, temp;
+ unsigned long hashval;
+
+ hashval = hash (p);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "hashtable_rem: %p, %lu\n", p, hashval);
+#endif
+ assert(hashval < AMOUNTHASH); /* rw */
+ prevtemp = temp = hashtable[hashval];
+ if (chunk (temp) == p) {
+ hashtable[hashval] = temp->hash_next;
+ }
+ else
+ {
+ if (temp && chunk (temp) != p) {
+ do
+ {
+ prevtemp = temp;
+ temp = temp->hash_next;
+ } while (temp && chunk (temp) != p);
+ }
+#ifdef DNMALLOC_CHECKS
+ if (!temp) {
+ fprintf (stderr,
+ "Dnmalloc error (hash_rm): could not find a chunkinfo for the chunk %p in the hashtable at entry %lu\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n",
+ p, hashval);
+ abort();
+ }
+#else
+ assert(temp != NULL);
+#endif
+ if (temp) prevtemp->hash_next = temp->hash_next;
+ }
+}
+
+/* mmapped chunks are multiples of pagesize, no hash_nexts,
+ * just remove from the hashtable
+ */
+#define hashtable_remove_mmapped(p) hashtable[hash(p)] = 0;
+
+static void
+hashtable_skiprm (chunkinfoptr ci_orig, chunkinfoptr ci_todelete)
+{
+ unsigned long hashval;
+ chunkinfoptr next;
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "hashtable_skiprm: %p, %lu\n", chunk(ci_todelete), hash(chunk(ci_todelete)));
+#endif
+
+ if (ci_orig->hash_next != ci_todelete) {
+ hashval = hash(chunk(ci_todelete));
+ assert(hashval < AMOUNTHASH); /* rw */
+#ifdef DNMALLOC_CHECKS
+ if (hashtable[hashval] != ci_todelete ) {
+ fprintf(stderr, "Dnmalloc error: trying to delete wrong value (hash: %lu): ci_todelete: %p (%p), hashtable[hashval]: %p (%p)\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n", hashval, ci_todelete, chunk(ci_todelete), hashtable[hashval], chunk(hashtable[hashval]));
+ }
+#else
+ assert(hashtable[hashval] == ci_todelete);
+#endif
+ hashtable[hashval] = ci_todelete->hash_next;
+ }
+
+ else {
+ ci_orig->hash_next = ci_todelete->hash_next;
+ if (!ci_orig->hash_next) {
+ next = next_chunkinfo(ci_orig);
+ } else {
+ next = ci_orig->hash_next;
+ }
+ if (next)
+ next->prev_size = chunksize(ci_orig);
+
+ }
+}
+
+
+static chunkinfoptr
+hashtable_lookup (mchunkptr p)
+{
+ chunkinfoptr ci;
+ unsigned long hashval;
+
+ /* if we were called wrongly
+ * if ((char *) p < startheap) return 0;
+ */
+ if ((char *) p >= startheap)
+ {
+ hashval = hash (p);
+ assert(hashval < AMOUNTHASH); /* rw */
+ ci = hashtable[hashval];
+ if (ci && chunk (ci) == p)
+ return ci;
+
+ if (ci) {
+ do {
+ ci = ci->hash_next;
+ } while (ci && chunk (ci) != p);
+ }
+#ifdef DNMALLOC_CHECKS
+ /* This should never occur but if it does, we'd like to know */
+ if (!ci) {
+ fprintf (stderr,
+ "Dnmalloc error: could not find a chunkinfo for the chunk %p in the hashtable at entry %lu\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n",
+ p, hashval);
+ abort();
+ }
+#else
+ assert(ci != NULL);
+#endif
+ return ci;
+ }
+ return 0;
+}
+
+
+
+/*
+ ----------- Internal state representation and initialization -----------
+*/
+
+struct malloc_state {
+
+ /* The maximum chunk size to be eligible for fastbin */
+ INTERNAL_SIZE_T max_fast; /* low 2 bits used as flags */
+
+ /* Fastbins */
+ mfastbinptr fastbins[NFASTBINS];
+
+ /* Base of the topmost chunk -- not otherwise kept in a bin */
+ chunkinfoptr top;
+
+ /* The remainder from the most recent split of a small request */
+ chunkinfoptr last_remainder;
+
+ /* Normal bins */
+ struct chunkinfo bins[NBINS];
+
+ /* Bitmap of bins. Trailing zero map handles cases of largest binned size */
+ unsigned int binmap[BINMAPSIZE+1];
+
+ /* Tunable parameters */
+ CHUNK_SIZE_T trim_threshold;
+ INTERNAL_SIZE_T top_pad;
+ INTERNAL_SIZE_T mmap_threshold;
+
+ /* Memory map support */
+ int n_mmaps;
+ int n_mmaps_max;
+ int max_n_mmaps;
+
+ /* Cache malloc_getpagesize */
+ unsigned int pagesize;
+
+ /* Canary */
+ char guard_stored[GUARD_SIZE];
+
+ /* Track properties of MORECORE */
+ unsigned int morecore_properties;
+
+ /* Statistics */
+ INTERNAL_SIZE_T mmapped_mem;
+ INTERNAL_SIZE_T sbrked_mem;
+ INTERNAL_SIZE_T max_sbrked_mem;
+ INTERNAL_SIZE_T max_mmapped_mem;
+ INTERNAL_SIZE_T max_total_mem;
+};
+
+typedef struct malloc_state *mstate;
+
+/*
+ There is exactly one instance of this struct in this malloc.
+ If you are adapting this malloc in a way that does NOT use a static
+ malloc_state, you MUST explicitly zero-fill it before using. This
+ malloc relies on the property that malloc_state is initialized to
+ all zeroes (as is true of C statics).
+*/
+
+static struct malloc_state * av_ = NULL; /* never directly referenced */
+
+/*
+ All uses of av_ are via get_malloc_state().
+ At most one "call" to get_malloc_state is made per invocation of
+ the public versions of malloc and free, but other routines
+ that in turn invoke malloc and/or free may call more then once.
+ Also, it is called in check* routines if DEBUG is set.
+*/
+
+#define get_malloc_state() (av_)
+
+/*
+ Initialize a malloc_state struct.
+
+ This is called only from within malloc_consolidate, which needs
+ be called in the same contexts anyway. It is never called directly
+ outside of malloc_consolidate because some optimizing compilers try
+ to inline it at all call points, which turns out not to be an
+ optimization at all. (Inlining it in malloc_consolidate is fine though.)
+*/
+
+#if __STD_C
+static void malloc_mmap_state(void)
+#else
+static void malloc_mmap_state()
+#endif
+{
+ int mprot;
+ unsigned long pagesize = malloc_getpagesize;
+ size_t size = (sizeof(struct malloc_state) + pagesize - 1) & ~(pagesize - 1);
+
+ void * foo = MMAP(0, size+(2*pagesize), PROT_READ|PROT_WRITE, MAP_PRIVATE);
+
+
+#ifdef NDEBUG
+ if (foo == MAP_FAILED) {
+ fprintf (stderr, "Couldn't mmap struct malloc_state: %s\n", strerror (errno));
+ abort ();
+ }
+#else
+ assert(foo != MAP_FAILED);
+#endif
+
+ mprot = mprotect(foo, pagesize, PROT_NONE);
+#ifdef NDEBUG
+ if (mprot == -1) {
+ fprintf (stderr, "Couldn't mprotect first non-rw page for struct malloc_state: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(mprot != -1);
+#endif
+
+ av_ = (struct malloc_state *) ((char*)foo + pagesize);
+
+ MALLOC_ZERO(av_, sizeof(struct malloc_state));
+
+ mprot = mprotect((void*)((char*)foo + size + pagesize), (size_t) pagesize, PROT_NONE);
+#ifdef NDEBUG
+ if (mprot == -1) {
+ fprintf (stderr,
+ "Couldn't mprotect last non-rw page for struct malloc_state: %s\n",
+ strerror (errno));
+ abort ();
+ }
+#else
+ assert(mprot != -1);
+#endif
+}
+
+#if __STD_C
+static void malloc_init_state(mstate av)
+#else
+static void malloc_init_state(av) mstate av;
+#endif
+{
+ int i;
+ mbinptr bin;
+
+ void * morecore_test = MORECORE(0);
+ unsigned long hashval;
+
+ /* Test morecore function
+ */
+ set_morecore32bit(av);
+
+ if (morecore_test == MORECORE_FAILURE)
+ {
+ set_nonmorecore32bit(av);
+ }
+ else
+ {
+ /* On 64bit systems, the heap may be located above the
+ * 32bit address space. Since mmap() probably still can be
+ * convinced to map within 32bit, we don't use sbrk().
+ */
+ hashval = hash (morecore_test);
+ if (hashval >= AMOUNTHASH)
+ {
+ set_nonmorecore32bit(av);
+ }
+ }
+
+
+ /* Establish circular links for normal bins */
+ for (i = 1; i < NBINS; ++i) {
+ bin = bin_at(av,i);
+ bin->fd = bin->bk = bin;
+ }
+
+ av->top_pad = DEFAULT_TOP_PAD;
+ av->n_mmaps_max = DEFAULT_MMAP_MAX;
+ av->mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+ av->trim_threshold = DEFAULT_TRIM_THRESHOLD;
+
+#if MORECORE_CONTIGUOUS
+ set_contiguous(av);
+#else
+ set_noncontiguous(av);
+#endif
+
+ set_max_fast(av, DEFAULT_MXFAST);
+
+ av->top = cireg_getfree ();
+ av->top->chunk = (mchunkptr) startheap;
+ av->top->size = 0;
+ set_previnuse(av->top);
+ clear_inuse(av->top);
+ hashtable[0] = av->top;
+ av->pagesize = malloc_getpagesize;
+
+ memcpy(av->guard_stored, dnmalloc_arc4random(), GUARD_SIZE);
+
+}
+
+/*
+ Other internal utilities operating on mstates
+*/
+
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T, mstate);
+static int sYSTRIm(size_t, mstate);
+static void malloc_consolidate(mstate);
+#else
+static Void_t* sYSMALLOc();
+static int sYSTRIm();
+static void malloc_consolidate();
+#endif
+
+/* dnmalloc functions */
+/* needs mstate so moved here */
+
+static chunkinfoptr
+next_chunkinfo (chunkinfoptr ci)
+{
+ mchunkptr nextp;
+ unsigned long hashval;
+ chunkinfoptr cinfonextp;
+ mstate av = get_malloc_state();
+
+ /* ci is not the last element in the linked list, just
+ return the next chunkinfo from the list
+ */
+ if (!ci->hash_next)
+ {
+ /* ci is the last element, find the next chunkinfo by
+ * looking up the chunkinfo for the chunk that is after p's chunk
+ */
+ nextp = (mchunkptr) (((char *) (ci->chunk)) + chunksize (ci));
+
+ if (!(nextp == av->top->chunk))
+ {
+ hashval = hash (nextp);
+ /* assert(hashval < AMOUNTHASH); *//* major bottleneck */
+ cinfonextp = hashtable[hashval];
+ if (cinfonextp && chunk (cinfonextp) == nextp)
+ return cinfonextp;
+
+#ifdef DNMALLOC_CHECKS_EXTRA
+ /* This seems bogus; a chunkinfo may legally have no nextp if
+ * it's the last one allocated (?)
+ */
+ else {
+ if (cinfonextp)
+ fprintf (stderr,
+ "Dnmalloc error: could not find a next chunkinfo for the chunk %p in the hashtable at entry %lu, cinfonextp: %p, chunk(cinfonextp): %p, nextp: %p\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n",
+ chunk(ci), hashval, cinfonextp, chunk(cinfonextp), nextp);
+ else
+ fprintf (stderr,
+ "Dnmalloc error: could not find a next chunkinfo for the chunk %p in the hashtable at entry %lu, cinfonextp: %s, chunk(cinfonextp): %s, nextp: %p\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n",
+ chunk(ci), hashval, "null", "null", nextp);
+ }
+#endif
+
+ return NULL;
+ }
+ else
+ {
+ return av->top;
+ }
+
+ }
+ else
+ {
+ return (ci->hash_next);
+ }
+}
+
+static int is_next_chunk(chunkinfoptr oldp, chunkinfoptr newp) {
+ mchunkptr nextp;
+ if (oldp->hash_next == newp)
+ return 1;
+ nextp = (mchunkptr) (((char *) (oldp->chunk)) + chunksize (oldp));
+ if (nextp == chunk(newp))
+ return 1;
+ return 0;
+}
+
+
+
+/* Get the chunkinfo of the physically previous chunk */
+/* Since we disposed of prev_size, we need this function to find the previous */
+
+static chunkinfoptr
+prev_chunkinfo (chunkinfoptr ci)
+{
+ unsigned int i;
+ chunkinfoptr prev;
+ mchunkptr prevchunk = 0;
+ /* chunkinfoptr temp; */
+
+ /* Get the hashtable location of the chunkinfo */
+ i = hash (chunk (ci));
+ assert(i < AMOUNTHASH); /* rw */
+
+ /* Get the first element of the linked list of chunkinfo's that contains p */
+ prev = hashtable[i];
+
+ if (ci == prev) {
+ prevchunk = (mchunkptr) (((char *) (ci->chunk)) - (ci->prev_size));
+ i = hash(prevchunk);
+ assert(i < AMOUNTHASH); /* rw */
+ /* Loop over the linked list until we reach the last element */
+ for (prev = hashtable[i]; prev->hash_next != 0; prev = prev->hash_next) ;
+ } else {
+ /* p is not the first element in the linked list, we can just
+ loop over the list and return the previous
+ */
+ for (prev = hashtable[i]; prev->hash_next != ci; prev = prev->hash_next);
+ }
+
+ return prev;
+}
+
+
+/*
+ Debugging support
+ Dnmalloc broke dlmallocs debugging functions, should fix them some
+ time in the future, for now leave them undefined.
+*/
+
+#define check_chunk(P)
+#define check_free_chunk(P)
+#define check_inuse_chunk(P)
+#define check_remalloced_chunk(P,N)
+#define check_malloced_chunk(P,N)
+#define check_malloc_state()
+
+
+/* ----------- Routines dealing with system allocation -------------- */
+
+/*
+ sysmalloc handles malloc cases requiring more memory from the system.
+ On entry, it is assumed that av->top does not have enough
+ space to service request for nb bytes, thus requiring that av->top
+ be extended or replaced.
+*/
+
+#if __STD_C
+static Void_t* sYSMALLOc(INTERNAL_SIZE_T nb, mstate av)
+#else
+static Void_t* sYSMALLOc(nb, av) INTERNAL_SIZE_T nb; mstate av;
+#endif
+{
+ chunkinfoptr old_top; /* incoming value of av->top */
+ INTERNAL_SIZE_T old_size; /* its size */
+ char* old_end; /* its end address */
+
+ long size; /* arg to first MORECORE or mmap call */
+ char* brk; /* return value from MORECORE */
+
+ long correction; /* arg to 2nd MORECORE call */
+ char* snd_brk; /* 2nd return val */
+
+ INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */
+ INTERNAL_SIZE_T end_misalign; /* partial page left at end of new space */
+ char* aligned_brk; /* aligned offset into brk */
+
+ chunkinfoptr p; /* the allocated/returned chunk */
+ chunkinfoptr remainder; /* remainder from allocation */
+ chunkinfoptr fencepost; /* fencepost */
+ CHUNK_SIZE_T remainder_size; /* its size */
+
+ CHUNK_SIZE_T sum; /* for updating stats */
+
+ size_t pagemask = av->pagesize - 1;
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Enter sysmalloc\n");
+#endif
+ /*
+ If there is space available in fastbins, consolidate and retry
+ malloc from scratch rather than getting memory from system. This
+ can occur only if nb is in smallbin range so we didn't consolidate
+ upon entry to malloc. It is much easier to handle this case here
+ than in malloc proper.
+ */
+
+
+ if (have_fastchunks(av)) {
+ Void_t * retval;
+ assert(in_smallbin_range(nb));
+ malloc_consolidate(av);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Return sysmalloc have_fastchunks\n");
+#endif
+ retval = mALLOc(nb - MALLOC_ALIGN_MASK);
+ VALGRIND_FREELIKE_BLOCK(retval, 0);
+ return retval;
+ }
+
+
+ /*
+ If have mmap, and the request size meets the mmap threshold, and
+ the system supports mmap, and there are few enough currently
+ allocated mmapped regions, try to directly map this request
+ rather than expanding top.
+ */
+
+ if (UNLIKELY((CHUNK_SIZE_T)(nb) >= (CHUNK_SIZE_T)(av->mmap_threshold) &&
+ (av->n_mmaps < av->n_mmaps_max))) {
+
+ char* mm; /* return value from mmap call*/
+
+ /*
+ Round up size to nearest page. For mmapped chunks, the overhead
+ is one SIZE_SZ unit larger than for normal chunks, because there
+ is no following chunk whose prev_size field could be used.
+ */
+ size = (nb + MALLOC_ALIGN_MASK + pagemask) & ~pagemask;
+
+ /* Don't try if size wraps around 0 */
+ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) {
+
+
+ mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+
+ if (mm != (char*)(MORECORE_FAILURE)) {
+
+ VALGRIND_MAKE_MEM_NOACCESS(mm,size);
+
+ /*
+ The offset to the start of the mmapped region is stored
+ in the prev_size field of the chunk. This allows us to adjust
+ returned start address to meet alignment requirements here
+ and in memalign(), and still be able to compute proper
+ address argument for later munmap in free() and realloc().
+ */
+
+ front_misalign = (INTERNAL_SIZE_T) mm & MALLOC_ALIGN_MASK;
+ p = cireg_getfree();
+
+ if (front_misalign > 0) {
+ correction = MALLOC_ALIGNMENT - front_misalign;
+ p->chunk = (mchunkptr)(mm + correction);
+ p->hash_next = (chunkinfoptr) correction;
+ set_head(p, (size - correction) |INUSE|IS_MMAPPED);
+ }
+ else {
+ p->chunk = (mchunkptr)mm;
+ p->hash_next = 0;
+ set_head(p, size|INUSE|IS_MMAPPED);
+ }
+ hashtable_add(p);
+ /* update statistics */
+
+ if (++av->n_mmaps > av->max_n_mmaps)
+ av->max_n_mmaps = av->n_mmaps;
+
+ sum = av->mmapped_mem += size;
+ if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem))
+ av->max_mmapped_mem = sum;
+ sum += av->sbrked_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ check_chunk(p);
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Return mmapped (%lu, total %lu)\n",
+ size, (unsigned long)/* size_t */av->max_total_mem );
+#endif
+ return chunk(p);
+ }
+ }
+ }
+
+ /* Record incoming configuration of top */
+
+ old_top = av->top;
+ old_size = chunksize(old_top);
+ old_end = (char*)(chunk_at_offset(chunk(old_top), old_size));
+
+ brk = snd_brk = (char*)(MORECORE_FAILURE);
+
+ /*
+ If not the first time through, we require old_size to be
+ at least MINSIZE and to have prev_inuse set.
+ */
+
+ /* assert((old_top == initial_top(av) && old_size == 0) ||
+ ((CHUNK_SIZE_T) (old_size) >= MINSIZE &&
+ prev_inuse(old_top))); */
+
+ /* Precondition: not enough current space to satisfy nb request */
+ assert((CHUNK_SIZE_T)(old_size) < (CHUNK_SIZE_T)(nb + MINSIZE));
+
+ /* Precondition: all fastbins are consolidated */
+ assert(!have_fastchunks(av));
+
+ /* Request enough space for nb + pad + overhead */
+ size = nb + av->top_pad + MINSIZE;
+
+ /*
+ If contiguous, we can subtract out existing space that we hope to
+ combine with new space. We add it back later only if
+ we don't actually get contiguous space.
+ */
+ if (contiguous(av))
+ size -= old_size;
+
+ /*
+ Round to a multiple of page size.
+ If MORECORE is not contiguous, this ensures that we only call it
+ with whole-page arguments. And if MORECORE is contiguous and
+ this is not first time through, this preserves page-alignment of
+ previous calls. Otherwise, we correct to page-align below.
+ */
+
+ size = (size + pagemask) & ~pagemask;
+
+ /*
+ Don't try to call MORECORE if argument is so big as to appear
+ negative. Note that since mmap takes size_t arg, it may succeed
+ below even if we cannot call MORECORE.
+ */
+ if (size > 0 && morecore32bit(av))
+ brk = (char*)(MORECORE(size));
+
+ /*
+ If have mmap, try using it as a backup when MORECORE fails or
+ cannot be used. This is worth doing on systems that have "holes" in
+ address space, so sbrk cannot extend to give contiguous space, but
+ space is available elsewhere. Note that we ignore mmap max count
+ and threshold limits, since the space will not be used as a
+ segregated mmap region.
+ */
+ if (brk != (char*)(MORECORE_FAILURE)) {
+ av->sbrked_mem += size;
+ VALGRIND_MAKE_MEM_NOACCESS(brk,size);
+ }
+
+ else {
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Morecore failure in sysmalloc\n");
+#endif
+
+ /* Cannot merge with old top, so add its size back in */
+ if (contiguous(av))
+ size = (size + old_size + pagemask) & ~pagemask;
+
+ /* If we are relying on mmap as backup, then use larger units */
+ if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(MMAP_AS_MORECORE_SIZE))
+ size = MMAP_AS_MORECORE_SIZE;
+
+ /* Don't try if size wraps around 0 */
+ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb)) {
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Try mmap in sysmalloc\n");
+#endif
+ brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE));
+
+ if (brk != (char*)(MORECORE_FAILURE)) {
+
+ VALGRIND_MAKE_MEM_NOACCESS(brk,size);
+
+ av->mmapped_mem += size;
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Mmapped successfully in sysmalloc %p\n", brk);
+#endif
+
+ /* We do not need, and cannot use, another sbrk call to find end */
+ snd_brk = brk + size;
+
+ /*
+ Record that we no longer have a contiguous sbrk region.
+ After the first time mmap is used as backup, we do not
+ ever rely on contiguous space since this could incorrectly
+ bridge regions.
+ */
+ set_noncontiguous(av);
+ }
+ }
+ }
+
+ if (brk != (char*)(MORECORE_FAILURE)) {
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Success path %lu allocated, sbrked %lu\n",
+ size, (unsigned long)av->sbrked_mem);
+#endif
+ /* av->sbrked_mem += size; moved up */
+
+ /*
+ If MORECORE extends previous space, we can likewise extend top size.
+ */
+
+ if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) {
+ set_head(old_top, (size + old_size) | PREV_INUSE);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Previous space extended\n");
+#endif
+ }
+
+ /*
+ Otherwise, make adjustments:
+
+ * If the first time through or noncontiguous, we need to call sbrk
+ just to find out where the end of memory lies.
+
+ * We need to ensure that all returned chunks from malloc will meet
+ MALLOC_ALIGNMENT
+
+ * If there was an intervening foreign sbrk, we need to adjust sbrk
+ request size to account for fact that we will not be able to
+ combine new space with existing space in old_top.
+
+ * Almost all systems internally allocate whole pages at a time, in
+ which case we might as well use the whole last page of request.
+ So we allocate enough more memory to hit a page boundary now,
+ which in turn causes future contiguous calls to page-align.
+ */
+
+ else {
+ /* front_misalign = 0; *//*superfluous */
+ /* end_misalign = 0; *//*superfluous */
+ correction = 0;
+ aligned_brk = brk;
+
+ /*
+ If MORECORE returns an address lower than we have seen before,
+ we know it isn't really contiguous. This and some subsequent
+ checks help cope with non-conforming MORECORE functions and
+ the presence of "foreign" calls to MORECORE from outside of
+ malloc or by other threads. We cannot guarantee to detect
+ these in all cases, but cope with the ones we do detect.
+ */
+ if (contiguous(av) && old_size != 0 && brk < old_end) {
+ set_noncontiguous(av);
+ }
+
+ /* handle contiguous cases */
+ if (contiguous(av)) {
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Handle contiguous cases\n");
+#endif
+ /*
+ We can tolerate forward non-contiguities here (usually due
+ to foreign calls) but treat them as part of our space for
+ stats reporting.
+ */
+ if (old_size != 0)
+ av->sbrked_mem += brk - old_end;
+
+ /* Guarantee alignment of first new chunk made from this space */
+
+ front_misalign = (INTERNAL_SIZE_T) brk & MALLOC_ALIGN_MASK;
+ if (front_misalign > 0) {
+
+ /*
+ Skip over some bytes to arrive at an aligned position.
+ We don't need to specially mark these wasted front bytes.
+ They will never be accessed anyway because
+ prev_inuse of av->top (and any chunk created from its start)
+ is always true after initialization.
+ */
+
+ correction = MALLOC_ALIGNMENT - front_misalign;
+ aligned_brk += correction;
+ }
+
+ /*
+ If this isn't adjacent to existing space, then we will not
+ be able to merge with old_top space, so must add to 2nd request.
+ */
+
+ correction += old_size;
+
+ /* Extend the end address to hit a page boundary */
+ end_misalign = (INTERNAL_SIZE_T)(brk + size + correction);
+ correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign;
+
+ assert(correction >= 0);
+ snd_brk = (char*)(MORECORE(correction));
+
+ if (snd_brk == (char*)(MORECORE_FAILURE)) {
+ /*
+ If can't allocate correction, try to at least find out current
+ brk. It might be enough to proceed without failing.
+ */
+ correction = 0;
+ snd_brk = (char*)(MORECORE(0));
+ }
+ else if (snd_brk < brk) {
+ /*
+ If the second call gives noncontiguous space even though
+ it says it won't, the only course of action is to ignore
+ results of second call, and conservatively estimate where
+ the first call left us. Also set noncontiguous, so this
+ won't happen again, leaving at most one hole.
+
+ Note that this check is intrinsically incomplete. Because
+ MORECORE is allowed to give more space than we ask for,
+ there is no reliable way to detect a noncontiguity
+ producing a forward gap for the second call.
+ */
+ snd_brk = brk + size;
+ correction = 0;
+ set_noncontiguous(av);
+ }
+ else {
+ VALGRIND_MAKE_MEM_NOACCESS(snd_brk,correction);
+ }
+
+ }
+
+ /* handle non-contiguous cases */
+ else {
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Handle non-contiguous cases\n");
+#endif
+
+ /* MORECORE/mmap must correctly align */
+ assert(aligned_OK(brk));
+
+ /* Find out current end of memory */
+ if (snd_brk == (char*)(MORECORE_FAILURE)) {
+ snd_brk = (char*)(MORECORE(0));
+ av->sbrked_mem += snd_brk - brk - size;
+ }
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Sbrked now %lu\n", (unsigned long)av->sbrked_mem);
+#endif
+ }
+
+ /* Adjust top based on results of second sbrk.
+ *
+ * If mmap() has been used as backup for failed morecore(),
+ * we end up in this branch as well.
+ */
+ if (snd_brk != (char*)(MORECORE_FAILURE)) {
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Adjust top, correction %lu\n", correction);
+#endif
+ /* hashtable_remove(chunk(av->top)); *//* rw 19.05.2008 removed */
+ av->top = cireg_getfree();
+ av->top->chunk = (mchunkptr)aligned_brk;
+ set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Adjust top, top %p size %lu\n",
+ av->top, (unsigned long)chunksize(av->top));
+#endif
+ hashtable_add(av->top);
+ av->sbrked_mem += correction;
+
+ /*
+ If not the first time through, we either have a
+ gap due to foreign sbrk or a non-contiguous region. Insert a
+ double fencepost at old_top to prevent consolidation with space
+ we don't own. These fenceposts are artificial chunks that are
+ marked as inuse. Original dlmalloc had two of these but too
+ small to use. To ensure that the linked lists contain a maximum
+ of 8 elements we only use 1. Inuse is determined by the
+ current rather than the next chunk anyway.
+ */
+
+ if (old_size != 0) {
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Shrink old_top to insert fenceposts\n");
+#endif
+ /*
+ Shrink old_top to insert fenceposts, keeping size a
+ multiple of MALLOC_ALIGNMENT. We know there is at least
+ enough space in old_top to do this.
+ */
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Adjust top, old_top %p old_size before %lu\n",
+ old_top, (unsigned long)old_size);
+#endif
+ old_size = (old_size - 4*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+ set_head(old_top, old_size | PREV_INUSE);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Adjust top, old_size after %lu\n",
+ (unsigned long)old_size);
+#endif
+
+ /*
+ Note that the following assignments completely overwrite
+ old_top when old_size was previously MINSIZE. This is
+ intentional. We need the fencepost, even if old_top otherwise gets
+ lost.
+ */
+ /* dnmalloc, we need the fencepost to be 16 bytes, however since
+ it's marked inuse it will never be coalesced
+ */
+ fencepost = cireg_getfree();
+ fencepost->chunk = (mchunkptr) chunk_at_offset(chunk(old_top),
+ old_size);
+ fencepost->size = 16|INUSE|PREV_INUSE;
+ hashtable_add(fencepost);
+ /*
+ If possible, release the rest, suppressing trimming.
+ */
+ if (old_size >= MINSIZE) {
+ INTERNAL_SIZE_T tt = av->trim_threshold;
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Release\n");
+#endif
+ av->trim_threshold = (INTERNAL_SIZE_T)(-1);
+ set_head(old_top, old_size | PREV_INUSE | INUSE);
+ guard_set(av->guard_stored, old_top, 0, old_size);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(old_top), old_size, 0, 0);
+ fREe(chunk(old_top));
+ av->trim_threshold = tt;
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Release done\n");
+#endif
+ }
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Adjust top, size %lu\n",
+ (unsigned long)chunksize(av->top));
+#endif
+
+ } /* fenceposts */
+ } /* adjust top */
+ } /* not extended previous region */
+
+ /* Update statistics */
+ sum = av->sbrked_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_sbrked_mem))
+ av->max_sbrked_mem = sum;
+
+ sum += av->mmapped_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ check_malloc_state();
+
+ /* finally, do the allocation */
+
+ p = av->top;
+ size = chunksize(p);
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Size: %lu nb+MINSIZE: %lu\n",
+ (CHUNK_SIZE_T)(size), (CHUNK_SIZE_T)(nb + MINSIZE));
+#endif
+
+ /* check that one of the above allocation paths succeeded */
+ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ remainder_size = size - nb;
+ remainder = cireg_getfree();
+ remainder->chunk = chunk_at_offset(chunk(p), nb);
+ av->top = remainder;
+ set_head(p, nb | PREV_INUSE | INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ hashtable_insert (p, av->top);
+ check_malloced_chunk(p, nb);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Return any (total %lu)\n",
+ (unsigned long)/* size_t */av->max_total_mem );
+#endif
+ return chunk(p);
+ }
+
+ }
+
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Return failed (total %lu)\n",
+ (unsigned long)/* size_t */av->max_total_mem );
+#endif
+
+ /* catch all failure paths */
+ MALLOC_FAILURE_ACTION;
+ return 0;
+}
+
+
+
+
+/*
+ sYSTRIm is an inverse of sorts to sYSMALLOc. It gives memory back
+ to the system (via negative arguments to sbrk) if there is unused
+ memory at the `high' end of the malloc pool. It is called
+ automatically by free() when top space exceeds the trim
+ threshold. It is also called by the public malloc_trim routine. It
+ returns 1 if it actually released any memory, else 0.
+*/
+
+#if __STD_C
+static int sYSTRIm(size_t pad, mstate av)
+#else
+static int sYSTRIm(pad, av) size_t pad; mstate av;
+#endif
+{
+ long top_size; /* Amount of top-most memory */
+ long extra; /* Amount to release */
+ long released; /* Amount actually released */
+ char* current_brk; /* address returned by pre-check sbrk call */
+ char* new_brk; /* address returned by post-check sbrk call */
+ size_t pagesz;
+
+ pagesz = av->pagesize;
+ top_size = chunksize(av->top);
+
+ /* Release in pagesize units, keeping at least one page */
+ extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
+
+ if (extra > 0) {
+
+ /*
+ Only proceed if end of memory is where we last set it.
+ This avoids problems if there were foreign sbrk calls.
+ */
+ current_brk = (char*)(MORECORE(0));
+ if (current_brk == (char*)(av->top) + top_size) {
+
+ /*
+ Attempt to release memory. We ignore MORECORE return value,
+ and instead call again to find out where new end of memory is.
+ This avoids problems if first call releases less than we asked,
+ of if failure somehow altered brk value. (We could still
+ encounter problems if it altered brk in some very bad way,
+ but the only thing we can do is adjust anyway, which will cause
+ some downstream failure.)
+ */
+
+ MORECORE(-extra);
+ new_brk = (char*)(MORECORE(0));
+
+ if (new_brk != (char*)MORECORE_FAILURE) {
+ released = (long)(current_brk - new_brk);
+
+ if (released != 0) {
+ /* Success. Adjust top. */
+ av->sbrked_mem -= released;
+ set_head(av->top, (top_size - released) | PREV_INUSE);
+ check_malloc_state();
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ ------------------------------ malloc ------------------------------
+*/
+
+
+#if __STD_C
+DL_STATIC Void_t* mALLOc(size_t bytes)
+#else
+DL_STATIC Void_t* mALLOc(bytes) size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T nb; /* normalized request size */
+ unsigned int idx; /* associated bin index */
+ mbinptr bin; /* associated bin */
+ mfastbinptr* fb; /* associated fastbin */
+
+ chunkinfoptr victim; /* inspected/selected chunk */
+ INTERNAL_SIZE_T size; /* its size */
+ int victim_index; /* its bin index */
+
+ chunkinfoptr remainder; /* remainder from a split */
+ CHUNK_SIZE_T remainder_size; /* its size */
+
+ unsigned int block; /* bit map traverser */
+ unsigned int bit; /* bit map traverser */
+ unsigned int map; /* current word of binmap */
+
+ chunkinfoptr fwd; /* misc temp for linking */
+ chunkinfoptr bck; /* misc temp for linking */
+
+ Void_t* retval;
+
+ /* chunkinfoptr next; */
+
+
+ /*
+ Convert request size to internal form by adding SIZE_SZ bytes
+ overhead plus possibly more to obtain necessary alignment and/or
+ to obtain a size of at least MINSIZE, the smallest allocatable
+ size. Also, checked_request2size traps (returning 0) request sizes
+ that are so large that they wrap around zero when padded and
+ aligned.
+ */
+#if defined(SH_CUTEST)
+ extern int malloc_count;
+ ++malloc_count;
+#endif
+
+ checked_request2size(bytes, nb);
+
+ /*
+ Bypass search if no frees yet
+ */
+ if (av && have_anychunks(av)) {
+ goto av_initialized;
+ }
+ else {
+ if (!av || av->max_fast == 0) { /* initialization check */
+ malloc_consolidate(av);
+ av = get_malloc_state();
+ }
+ goto use_top;
+ }
+
+ av_initialized:
+
+ /*
+ If the size qualifies as a fastbin, first check corresponding bin.
+ */
+ if ((CHUNK_SIZE_T)(nb) <= (CHUNK_SIZE_T)(av->max_fast)) {
+ fb = &(av->fastbins[(fastbin_index(nb))]);
+ if ( (victim = *fb) != 0) {
+ *fb = victim->fd;
+ check_remalloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+ }
+
+ /*
+ If a small request, check regular bin. Since these "smallbins"
+ hold one size each, no searching within bins is necessary.
+ (For a large request, we need to wait until unsorted chunks are
+ processed to find best fit. But for small ones, fits are exact
+ anyway, so we can check now, which is faster.)
+ */
+
+ if (in_smallbin_range(nb)) {
+ idx = smallbin_index(nb);
+ bin = bin_at(av,idx);
+
+ if ((victim = last(bin)) != bin) {
+ bck = victim->bk;
+ bin->bk = bck;
+ bck->fd = bin;
+
+ set_all_inuse(victim);
+
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+ }
+
+ /*
+ If this is a large request, consolidate fastbins before continuing.
+ While it might look excessive to kill all fastbins before
+ even seeing if there is space available, this avoids
+ fragmentation problems normally associated with fastbins.
+ Also, in practice, programs tend to have runs of either small or
+ large requests, but less often mixtures, so consolidation is not
+ invoked all that often in most programs. And the programs that
+ it is called frequently in otherwise tend to fragment.
+ */
+
+ else {
+ idx = largebin_index(nb);
+ if (have_fastchunks(av))
+ malloc_consolidate(av);
+ }
+
+ /*
+ Process recently freed or remaindered chunks, taking one only if
+ it is exact fit, or, if this a small request, the chunk is remainder from
+ the most recent non-exact fit. Place other traversed chunks in
+ bins. Note that this step is the only place in any routine where
+ chunks are placed in bins.
+ */
+
+ while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {
+ bck = victim->bk;
+ size = chunksize(victim);
+
+ /*
+ If a small request, try to use last remainder if it is the
+ only chunk in unsorted bin. This helps promote locality for
+ runs of consecutive small requests. This is the only
+ exception to best-fit, and applies only when there is
+ no exact fit for a small chunk.
+ */
+
+ if (UNLIKELY(in_smallbin_range(nb) &&
+ bck == unsorted_chunks(av) &&
+ victim == av->last_remainder &&
+ (CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE))) {
+
+ /* split and reattach remainder */
+ remainder_size = size - nb;
+ remainder = cireg_getfree();
+ remainder->chunk = chunk_at_offset(chunk(victim), nb);
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ av->last_remainder = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+
+ set_head(victim, nb | PREV_INUSE|INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ hashtable_insert(victim, remainder);
+
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+
+ /* remove from unsorted list */
+ unsorted_chunks(av)->bk = bck;
+ bck->fd = unsorted_chunks(av);
+
+ /* Take now instead of binning if exact fit */
+
+ if (UNLIKELY(size == nb)) {
+ set_all_inuse(victim)
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+
+ /* place chunk in bin */
+
+ if (in_smallbin_range(size)) {
+
+ victim_index = smallbin_index(size);
+ bck = bin_at(av, victim_index);
+ fwd = bck->fd;
+ }
+ else {
+ victim_index = largebin_index(size);
+ bck = bin_at(av, victim_index);
+ fwd = bck->fd;
+
+ if (UNLIKELY(fwd != bck)) {
+ /* if smaller than smallest, place first */
+ if ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(bck->bk->size)) {
+ fwd = bck;
+ bck = bck->bk;
+ }
+ else if ((CHUNK_SIZE_T)(size) >=
+ (CHUNK_SIZE_T)(FIRST_SORTED_BIN_SIZE)) {
+
+ /* maintain large bins in sorted order */
+ size |= PREV_INUSE|INUSE; /* Or with inuse bits to speed comparisons */
+ while ((CHUNK_SIZE_T)(size) < (CHUNK_SIZE_T)(fwd->size))
+ fwd = fwd->fd;
+ bck = fwd->bk;
+ }
+ }
+ }
+
+ mark_bin(av, victim_index);
+ victim->bk = bck;
+ victim->fd = fwd;
+ fwd->bk = victim;
+ bck->fd = victim;
+ }
+
+ /*
+ If a large request, scan through the chunks of current bin to
+ find one that fits. (This will be the smallest that fits unless
+ FIRST_SORTED_BIN_SIZE has been changed from default.) This is
+ the only step where an unbounded number of chunks might be
+ scanned without doing anything useful with them. However the
+ lists tend to be short.
+ */
+
+ if (!in_smallbin_range(nb)) {
+ bin = bin_at(av, idx);
+
+ victim = last(bin);
+
+ if (UNLIKELY(victim != bin)) {
+
+ do {
+ size = chunksize(victim);
+
+ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb)) {
+ remainder_size = size - nb;
+ unlink(victim, bck, fwd);
+
+ /* Split */
+ if (remainder_size >= MINSIZE) {
+ remainder = cireg_getfree();
+ remainder->chunk = chunk_at_offset(chunk(victim), nb);
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+ set_head(victim, nb | PREV_INUSE | INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ hashtable_insert(victim, remainder);
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+ /* Exhaust */
+ else {
+ set_all_inuse(victim);
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+ }
+ victim = victim->bk;
+ } while(victim != bin);
+ }
+ }
+
+ /*
+ Search for a chunk by scanning bins, starting with next largest
+ bin. This search is strictly by best-fit; i.e., the smallest
+ (with ties going to approximately the least recently used) chunk
+ that fits is selected.
+
+ The bitmap avoids needing to check that most blocks are nonempty.
+ */
+
+
+ ++idx;
+ bin = bin_at(av,idx);
+ block = idx2block(idx);
+ map = av->binmap[block];
+ bit = idx2bit(idx);
+
+ for (;;) {
+
+ /* Skip rest of block if there are no more set bits in this block. */
+ if (bit > map || bit == 0) {
+ do {
+ if (++block >= BINMAPSIZE) /* out of bins */
+ goto use_top;
+ } while ( (map = av->binmap[block]) == 0);
+
+ bin = bin_at(av, (block << BINMAPSHIFT));
+ bit = 1;
+ }
+
+ /* Advance to bin with set bit. There must be one. */
+ while ((bit & map) == 0) {
+ bin = next_bin(bin);
+ bit <<= 1;
+ assert(bit != 0);
+ }
+
+ /* Inspect the bin. It is likely to be non-empty */
+ victim = last(bin);
+
+ /* If a false alarm (empty bin), clear the bit. */
+ if (victim == bin) {
+ av->binmap[block] = map &= ~bit; /* Write through */
+ bin = next_bin(bin);
+ bit <<= 1;
+ }
+
+ else {
+ size = chunksize(victim);
+
+ /* We know the first chunk in this bin is big enough to use. */
+ assert((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb));
+
+ remainder_size = size - nb;
+
+ /* unlink */
+ bck = victim->bk;
+ bin->bk = bck;
+ bck->fd = bin;
+
+ /* Split */
+ if (remainder_size >= MINSIZE) {
+ remainder = cireg_getfree();
+ remainder->chunk = chunk_at_offset(chunk(victim), nb);
+
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
+ /* advertise as last remainder */
+ if (in_smallbin_range(nb))
+ av->last_remainder = remainder;
+
+ set_head(victim, nb | PREV_INUSE | INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ hashtable_insert(victim, remainder);
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+ /* Exhaust */
+ else {
+ set_all_inuse(victim);
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+
+ }
+ }
+
+ use_top:
+
+
+ /*
+ If large enough, split off the chunk bordering the end of memory
+ (held in av->top). Note that this is in accord with the best-fit
+ search rule. In effect, av->top is treated as larger (and thus
+ less well fitting) than any other available chunk since it can
+ be extended to be as large as necessary (up to system
+ limitations).
+
+ We require that av->top always exists (i.e., has size >=
+ MINSIZE) after initialization, so if it would otherwise be
+ exhuasted by current request, it is replenished. (The main
+ reason for ensuring it exists is that we may need MINSIZE space
+ to put in fenceposts in sysmalloc.)
+ */
+
+ victim = av->top;
+ size = chunksize(victim);
+
+ if ((CHUNK_SIZE_T)(size) >= (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ remainder = cireg_getfree();
+ remainder_size = size - nb;
+ remainder->chunk = chunk_at_offset(chunk(victim), nb);
+ av->top = remainder;
+ set_head(victim, nb | PREV_INUSE | INUSE);
+ set_head(remainder, remainder_size | PREV_INUSE);
+ hashtable_insert(victim, remainder);
+ check_malloced_chunk(victim, nb);
+ guard_set(av->guard_stored, victim, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(victim), bytes, 0, 0);
+ return chunk(victim);
+ }
+
+ /*
+ If no space in top, relay to handle system-dependent cases
+ */
+ retval = sYSMALLOc(nb, av);
+ if (retval) {
+#if PARANOIA > 2
+ victim = mem2chunk(retval); /* is used in guard_set macro */
+#endif
+ guard_set(av->guard_stored, victim, bytes, nb);
+ }
+ VALGRIND_MALLOCLIKE_BLOCK(retval, bytes, 0, 0);
+ return retval;
+}
+
+/*
+ ------------------------------ free ------------------------------
+*/
+
+#if __STD_C
+DL_STATIC void fREe(Void_t* mem)
+#else
+DL_STATIC void fREe(mem) Void_t* mem;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ chunkinfoptr p; /* chunk corresponding to mem */
+ INTERNAL_SIZE_T size; /* its size */
+ mfastbinptr* fb; /* associated fastbin */
+ chunkinfoptr prevchunk; /* previous physical chunk */
+ chunkinfoptr nextchunk; /* next contiguous chunk */
+ INTERNAL_SIZE_T nextsize; /* its size */
+ INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
+ chunkinfoptr bck; /* misc temp for linking */
+ chunkinfoptr fwd; /* misc temp for linking */
+ chunkinfoptr next;
+#if defined(SH_CUTEST)
+ extern int malloc_count;
+ --malloc_count;
+#endif
+
+ /* free(0) has no effect */
+ if (mem != 0) {
+ p = hashtable_lookup(mem);
+ /* check that memory is managed by us
+ * and is inuse
+ */
+ if (UNLIKELY(!p || !inuse(p)))
+ {
+#ifdef DNMALLOC_CHECKS
+ if (p) {
+ fprintf(stderr, "Attempt to free memory not in use\n");
+ abort();
+ } else {
+ fprintf(stderr, "Attempt to free memory not allocated\n");
+ abort();
+ }
+#endif
+ assert(p && inuse(p));
+ return;
+ }
+
+ VALGRIND_FREELIKE_BLOCK(mem, 0);
+
+ guard_check(av->guard_stored, p);
+
+ size = chunksize(p);
+
+ check_inuse_chunk(p);
+
+ /*
+ If eligible, place chunk on a fastbin so it can be found
+ and used quickly in malloc.
+ */
+
+ if ((CHUNK_SIZE_T)(size) <= (CHUNK_SIZE_T)(av->max_fast)
+
+#if TRIM_FASTBINS
+ /*
+ If TRIM_FASTBINS set, don't place chunks
+ bordering top into fastbins
+ */
+ && (chunk_at_offset(chunk(p), size) != av->top)
+#endif
+ ) {
+
+ set_fastchunks(av);
+ fb = &(av->fastbins[fastbin_index(size)]);
+ p->fd = *fb;
+ *fb = p;
+ }
+
+ /*
+ Consolidate other non-mmapped chunks as they arrive.
+ */
+
+ else if (!chunk_is_mmapped(p)) {
+ set_anychunks(av);
+
+ nextchunk = next_chunkinfo(p);
+ if (nextchunk)
+ nextsize = chunksize(nextchunk);
+ else
+ nextsize = 0;/* gcc doesn't notice that it's only used if (nextchunk)*/
+
+ /* consolidate backward */
+ if (UNLIKELY(!prev_inuse(p))) {
+ prevchunk = prev_chunkinfo(p);
+ prevsize = chunksize(prevchunk);
+#ifdef DNMALLOC_CHECKS
+ if (inuse(prevchunk)) {
+ fprintf(stderr, "Dnmalloc error: trying to unlink an inuse chunk: %p (chunk: %p)\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n", prevchunk, chunk(prevchunk));
+ abort();
+ }
+#else
+ assert(!inuse(prevchunk));
+#endif
+ size += prevsize;
+ unlink(prevchunk, bck, fwd);
+ set_head(p, size | PREV_INUSE);
+ hashtable_skiprm(prevchunk,p);
+ /* This chunk no longer exists in any form: release the chunkinfoptr
+ */
+ freecilst_add(p);
+ p = prevchunk;
+ }
+
+ if (nextchunk) {
+ if (nextchunk != av->top) {
+ /* get and clear inuse bit */
+ clear_previnuse(nextchunk);
+
+ /* consolidate forward */
+ if (!inuse(nextchunk)) {
+ /* if mmap is used instead of sbrk, we may have a
+ * chunk with !nextchunk->fd && !nextchunk->bk
+ */
+ if (nextchunk->fd && nextchunk->fd)
+ {
+ unlink(nextchunk, bck, fwd);
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ hashtable_skiprm(p, nextchunk);
+ freecilst_add (nextchunk);
+ }
+ }
+
+ set_head(p, size | PREV_INUSE);
+ next = next_chunkinfo(p);
+ if (next)
+ next->prev_size = size;
+
+ /*
+ Place the chunk in unsorted chunk list. Chunks are
+ not placed into regular bins until after they have
+ been given one chance to be used in malloc.
+ */
+
+ bck = unsorted_chunks(av);
+ fwd = bck->fd;
+ p->bk = bck;
+ p->fd = fwd;
+ bck->fd = p;
+ fwd->bk = p;
+
+ nextchunk = next_chunkinfo(p);
+ if (nextchunk)
+ nextchunk->prev_size = chunksize(p);
+
+ check_free_chunk(p);
+ }
+
+ /*
+ If the chunk borders the current high end of memory,
+ consolidate into top
+ */
+
+ else {
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ hashtable_remove(chunk(av->top));
+ freecilst_add(av->top);
+ av->top = p;
+ check_chunk(p);
+ }
+ } /* if (nextchunk) */
+
+ /*
+ If freeing a large space, consolidate possibly-surrounding
+ chunks. Then, if the total unused topmost memory exceeds trim
+ threshold, ask malloc_trim to reduce top.
+
+ Unless max_fast is 0, we don't know if there are fastbins
+ bordering top, so we cannot tell for sure whether threshold
+ has been reached unless fastbins are consolidated. But we
+ don't want to consolidate on each free. As a compromise,
+ consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
+ is reached.
+ */
+
+ if (UNLIKELY((CHUNK_SIZE_T)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD)) {
+ if (have_fastchunks(av))
+ malloc_consolidate(av);
+
+#ifndef MORECORE_CANNOT_TRIM
+ if ((CHUNK_SIZE_T)(chunksize(av->top)) >=
+ (CHUNK_SIZE_T)(av->trim_threshold))
+ {
+ if (morecore32bit(av))
+ {
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Calling systrim from free()\n");
+#endif
+ sYSTRIm(av->top_pad, av);
+#ifdef DNMALLOC_DEBUG
+ fprintf(stderr, "Systrim done\n");
+#endif
+ }
+ }
+#endif
+ }
+
+ }
+ /*
+ If the chunk was allocated via mmap, release via munmap()
+ Note that if HAVE_MMAP is false but chunk_is_mmapped is
+ true, then user must have overwritten memory. There's nothing
+ we can do to catch this error unless DEBUG is set, in which case
+ check_inuse_chunk (above) will have triggered error.
+ */
+
+ else {
+#if PARANOIA > 0
+ int ret;
+#endif
+ INTERNAL_SIZE_T offset = (INTERNAL_SIZE_T) p->hash_next;
+ av->n_mmaps--;
+ av->mmapped_mem -= (size + offset);
+#if PARANOIA > 0
+ ret = munmap((char*) chunk(p) - offset, size + offset);
+#else
+ munmap((char*) chunk(p) - offset, size + offset);
+#endif
+ hashtable_remove_mmapped(chunk(p));
+ freecilst_add(p);
+ /* munmap returns non-zero on failure */
+ assert(ret == 0);
+ }
+ }
+}
+
+/*
+ ------------------------- malloc_consolidate -------------------------
+
+ malloc_consolidate is a specialized version of free() that tears
+ down chunks held in fastbins. Free itself cannot be used for this
+ purpose since, among other things, it might place chunks back onto
+ fastbins. So, instead, we need to use a minor variant of the same
+ code.
+
+ Also, because this routine needs to be called the first time through
+ malloc anyway, it turns out to be the perfect place to trigger
+ initialization code.
+*/
+
+#if __STD_C
+static void malloc_consolidate(mstate av)
+#else
+static void malloc_consolidate(av) mstate av;
+#endif
+{
+ mfastbinptr* fb; /* current fastbin being consolidated */
+ mfastbinptr* maxfb; /* last fastbin (for loop control) */
+ chunkinfoptr p; /* current chunk being consolidated */
+ chunkinfoptr nextp; /* next chunk to consolidate */
+ chunkinfoptr prevp;
+ chunkinfoptr unsorted_bin; /* bin header */
+ chunkinfoptr first_unsorted; /* chunk to link to */
+
+ /* These have same use as in free() */
+ chunkinfoptr nextchunk;
+ INTERNAL_SIZE_T size;
+ INTERNAL_SIZE_T nextsize;
+ INTERNAL_SIZE_T prevsize;
+ chunkinfoptr bck;
+ chunkinfoptr fwd;
+ chunkinfoptr next;
+
+ /*
+ If max_fast is 0, we know that av hasn't
+ yet been initialized, in which case do so below
+ */
+ if (av && av->max_fast != 0) {
+
+ clear_fastchunks(av);
+
+ unsorted_bin = unsorted_chunks(av);
+
+ /*
+ Remove each chunk from fast bin and consolidate it, placing it
+ then in unsorted bin. Among other reasons for doing this,
+ placing in unsorted bin avoids needing to calculate actual bins
+ until malloc is sure that chunks aren't immediately going to be
+ reused anyway.
+ */
+
+ maxfb = &(av->fastbins[fastbin_index(av->max_fast)]);
+ fb = &(av->fastbins[0]);
+ do {
+ if ( UNLIKELY((p = *fb) != 0)) {
+ *fb = 0;
+ do {
+ check_inuse_chunk(p);
+ nextp = p->fd;
+
+ /*
+ * Slightly streamlined version of consolidation code in free()
+ */
+
+ size = chunksize(p);
+ nextchunk = next_chunkinfo(p);
+
+ /* gcc doesn't notice that it's only used if (nextchunk) */
+ if (nextchunk)
+ nextsize = chunksize(nextchunk);
+ else
+ nextsize = 0;
+
+ if (!prev_inuse(p)) {
+ prevp = prev_chunkinfo(p);
+ prevsize = chunksize(prevp);
+ size += prevsize;
+#ifdef DNMALLOC_CHECKS
+ if (inuse(prevp)) {
+ fprintf(stderr, "Dnmalloc error: trying to unlink an inuse chunk (2): %p (chunk: %p)\n This is definitely a bug, please report it to dnmalloc@fort-knox.org.\n", prevp, chunk(prevp));
+ abort();
+ }
+#else
+ assert(!inuse(prevp));
+#endif
+ unlink(prevp, bck, fwd);
+ set_head(p, size | PREV_INUSE);
+ hashtable_skiprm(prevp,p);
+ freecilst_add(p);
+ p=prevp;
+ }
+
+ if (nextchunk) {
+ if (nextchunk != av->top) {
+
+ clear_previnuse(nextchunk);
+
+ /* if mmap is used instead of sbrk, we may have a
+ * chunk with !nextchunk->fd && !nextchunk->bk
+ */
+ if (!inuse(nextchunk)) {
+ if( nextchunk->fd && nextchunk->bk) {
+ size += nextsize;
+ unlink(nextchunk, bck, fwd);
+ set_head(p, size | PREV_INUSE);
+ hashtable_skiprm(p,nextchunk);
+ freecilst_add(nextchunk);
+ }
+ }
+
+ first_unsorted = unsorted_bin->fd;
+ unsorted_bin->fd = p;
+ first_unsorted->bk = p;
+
+ set_head(p, size | PREV_INUSE);
+ p->bk = unsorted_bin;
+ p->fd = first_unsorted;
+ next = next_chunkinfo(p);
+ if (next)
+ next->prev_size = size;
+
+
+ }
+
+ else if (nextchunk == av->top) {
+ size += nextsize;
+ set_head(p, size | PREV_INUSE);
+ hashtable_remove(chunk(av->top));
+ freecilst_add(av->top);
+ av->top = p;
+ }
+ } /* if (nextchunk) */
+
+ } while ( (p = nextp) != 0);
+
+ }
+ } while (fb++ != maxfb);
+ }
+ else {
+ /* Initialize dnmalloc */
+ dnmalloc_init();
+ malloc_init_state(get_malloc_state());
+ check_malloc_state();
+ }
+}
+
+/*
+ ------------------------------ realloc ------------------------------
+*/
+
+
+#if __STD_C
+DL_STATIC Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
+#else
+DL_STATIC Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+
+ INTERNAL_SIZE_T nb; /* padded request size */
+
+ chunkinfoptr oldp; /* chunk corresponding to oldmem */
+ INTERNAL_SIZE_T oldsize; /* its size */
+
+ chunkinfoptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ Void_t* newmem; /* corresponding user mem */
+
+ chunkinfoptr next; /* next contiguous chunk after oldp */
+
+ chunkinfoptr remainder; /* extra space at end of newp */
+ CHUNK_SIZE_T remainder_size; /* its size */
+
+ chunkinfoptr bck; /* misc temp for linking */
+ chunkinfoptr fwd; /* misc temp for linking */
+
+ CHUNK_SIZE_T copysize; /* bytes to copy */
+ unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */
+ INTERNAL_SIZE_T* s; /* copy source */
+ INTERNAL_SIZE_T* d; /* copy destination */
+
+
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (UNLIKELY(bytes == 0)) {
+ fREe(oldmem);
+ return 0;
+ }
+#endif
+
+ if (UNLIKELY(!av || av->max_fast == 0)) {
+ malloc_consolidate(av);
+ av = get_malloc_state();
+ }
+
+ /* realloc of null is supposed to be same as malloc */
+ if (UNLIKELY(oldmem == 0))
+ return mALLOc(bytes);
+
+ checked_request2size(bytes, nb);
+
+ oldp = hashtable_lookup(oldmem);
+
+ if (UNLIKELY(!oldp || !inuse(oldp))){
+ /* attempt to either realloc memory not managed by us
+ * or memory that is not in use
+ */
+#ifdef DNMALLOC_CHECKS
+ if (oldp) {
+ fprintf(stderr, "Attempt to free memory not in use\n");
+ abort();
+ } else {
+ fprintf(stderr, "Attempt to free memory not allocated\n");
+ abort();
+ }
+#endif
+ assert(oldp && inuse(oldp));
+ return 0;
+ }
+
+ VALGRIND_FREELIKE_BLOCK(oldmem, 0);
+ guard_check(av->guard_stored, oldp);
+
+ oldsize = chunksize(oldp);
+
+ check_inuse_chunk(oldp);
+
+ if (!chunk_is_mmapped(oldp)) {
+
+ if (UNLIKELY((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb))) {
+ /* already big enough; split below */
+ newp = oldp;
+ newsize = oldsize;
+ }
+
+ else {
+ next = next_chunkinfo(oldp);
+ if (next)
+ next->prev_size = oldsize;
+ /* Try to expand forward into top */
+ if (next && next == av->top &&
+ (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >=
+ (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ set_head_size(oldp, nb);
+ hashtable_remove(chunk(av->top));
+ av->top->chunk = chunk_at_offset(chunk(oldp), nb);
+ set_head(av->top, (newsize - nb) | PREV_INUSE);
+ /* av->top->chunk has been moved move in hashtable */
+ hashtable_insert(oldp, av->top);
+ guard_set(av->guard_stored, oldp, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(oldp), bytes, 0, 0);
+ return chunk(oldp);
+ }
+
+ /* Try to expand forward into next chunk; split off remainder below */
+ else if (next && next != av->top &&
+ !inuse(next) &&
+ (CHUNK_SIZE_T)(newsize = oldsize + chunksize(next)) >=
+ (CHUNK_SIZE_T)(nb)) {
+ newp = oldp;
+ unlink(next, bck, fwd);
+ hashtable_remove(chunk(next));
+ freecilst_add(next);
+ next = next_chunkinfo(oldp);
+ if (next)
+ next->prev_size = newsize;
+ }
+
+ /* allocate, copy, free */
+ else {
+
+ newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+ if (newmem == 0)
+ return 0; /* propagate failure */
+
+ newp = hashtable_lookup(newmem);
+ newsize = chunksize(newp);
+
+
+ /* next = next_chunkinfo(oldp); *//* 'next' never used rw 19.05.2008 */
+ /*
+ Avoid copy if newp is next chunk after oldp.
+ */
+ if (UNLIKELY(is_next_chunk(oldp, newp))) {
+ newsize += oldsize;
+ set_head_size(oldp, newsize);
+ hashtable_skiprm(oldp, newp);
+ freecilst_add(newp);
+ newp = oldp;
+ }
+ else {
+ /*
+ Unroll copy of <= 40 bytes (80 if 8byte sizes)
+ We know that contents have an even number of
+ INTERNAL_SIZE_T-sized words; minimally 4 (2 on amd64).
+ */
+
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(oldp), chunksize(oldp), 0, 0);
+
+ copysize = oldsize;
+ s = (INTERNAL_SIZE_T*)(oldmem);
+ d = (INTERNAL_SIZE_T*)(newmem);
+ ncopies = copysize / sizeof(INTERNAL_SIZE_T);
+ assert(ncopies >= 2);
+
+ if (ncopies > 10)
+ MALLOC_COPY(d, s, copysize);
+
+ else {
+ *(d+0) = *(s+0);
+ *(d+1) = *(s+1);
+ if (ncopies > 2) {
+ *(d+2) = *(s+2);
+ *(d+3) = *(s+3);
+ if (ncopies > 4) {
+ *(d+4) = *(s+4);
+ *(d+5) = *(s+5);
+ if (ncopies > 6) {
+ *(d+6) = *(s+6);
+ *(d+7) = *(s+7);
+ if (ncopies > 8) {
+ *(d+8) = *(s+8);
+ *(d+9) = *(s+9);
+ }
+ }
+ }
+ }
+ }
+
+ fREe(oldmem);
+ check_inuse_chunk(newp);
+ guard_set(av->guard_stored, newp, bytes, nb);
+ return chunk(newp);
+ }
+ }
+ }
+
+ /* If possible, free extra space in old or extended chunk */
+
+ assert((CHUNK_SIZE_T)(newsize) >= (CHUNK_SIZE_T)(nb));
+
+ remainder_size = newsize - nb;
+
+ if (remainder_size >= MINSIZE) { /* split remainder */
+ remainder = cireg_getfree();
+ remainder->chunk = chunk_at_offset(chunk(newp), nb);
+ set_head_size(newp, nb);
+ set_head(remainder, remainder_size | PREV_INUSE | INUSE);
+ remainder->prev_size = nb;
+ hashtable_insert(newp, remainder);
+ /* Mark remainder as inuse so free() won't complain */
+ set_all_inuse(remainder);
+ guard_set(av->guard_stored, remainder, 0, remainder_size);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(remainder), remainder_size, 0, 0);
+ fREe(chunk(remainder));
+ }
+ else { /* not enough extra to split off */
+ set_head_size(newp, newsize);
+ set_all_inuse(newp);
+ }
+
+ check_inuse_chunk(newp);
+ guard_set(av->guard_stored, newp, bytes, nb);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(newp), bytes, 0, 0);
+ return chunk(newp);
+ }
+
+ /*
+ Handle mmap cases
+ */
+
+ else {
+
+#if HAVE_MREMAP
+ INTERNAL_SIZE_T offset = (INTERNAL_SIZE_T) oldp->hash_next;
+ size_t pagemask = av->pagesize - 1;
+ char *cp;
+ CHUNK_SIZE_T sum;
+
+
+ /* Note the extra SIZE_SZ overhead */
+ /* newsize = (nb + offset + SIZE_SZ + pagemask) & ~pagemask; */
+ newsize = (nb + offset + pagemask) & ~pagemask;
+
+ /* don't need to remap if still within same page */
+ if (oldsize == newsize - offset)
+ {
+ guard_set(av->guard_stored, oldp, bytes, nb);
+ VALGRIND_FREELIKE_BLOCK(oldmem, 0);
+ VALGRIND_MALLOCLIKE_BLOCK(oldmem, bytes, 0, 0);
+ return oldmem;
+ }
+
+ cp = (char*)mremap((char*)chunk(oldp) - offset, oldsize + offset, newsize, 1);
+
+ if (cp != (char*)MORECORE_FAILURE) {
+
+ hashtable_remove_mmapped(chunk(oldp));
+
+ oldp->chunk = (mchunkptr)(cp + offset);
+ set_head(oldp, (newsize - offset)|IS_MMAPPED|INUSE);
+
+ hashtable_add(oldp);
+
+ assert(aligned_OK(chunk(oldp))); /* rw fix: newp -> oldp */
+ assert(( ((INTERNAL_SIZE_T) oldp->hash_next) == offset));
+
+ /* update statistics */
+ sum = av->mmapped_mem += newsize - oldsize;
+ if (sum > (CHUNK_SIZE_T)(av->max_mmapped_mem))
+ av->max_mmapped_mem = sum;
+ sum += av->sbrked_mem;
+ if (sum > (CHUNK_SIZE_T)(av->max_total_mem))
+ av->max_total_mem = sum;
+
+ guard_set(av->guard_stored, oldp, bytes, nb);
+ VALGRIND_FREELIKE_BLOCK(oldmem, 0);
+ VALGRIND_MALLOCLIKE_BLOCK(chunk(oldp), bytes, 0, 0);
+ return chunk(oldp);
+ }
+#endif /* have MREMAP */
+
+ /* Note the extra SIZE_SZ overhead. */
+ if ((CHUNK_SIZE_T)(oldsize) >= (CHUNK_SIZE_T)(nb + SIZE_SZ))
+ newmem = oldmem; /* do nothing */
+ else {
+ /* Must alloc, copy, free. */
+ newmem = mALLOc(nb - MALLOC_ALIGN_MASK);
+ if (newmem != 0) {
+ MALLOC_COPY(newmem, oldmem, oldsize);
+ fREe(oldmem);
+ }
+ }
+ VALGRIND_MALLOCLIKE_BLOCK(newmem, bytes, 0, 0);
+ guard_set(av->guard_stored, mem2chunk(newmem), bytes, nb);
+ return newmem;
+ }
+}
+
+/*
+ ---------------------------posix_memalign ----------------------------
+*/
+
+#if __STD_C
+DL_STATIC int posix_mEMALIGn(Void_t** memptr, size_t alignment, size_t bytes)
+#else
+DL_STATIC int posix_mEMALIGn(memptr, alignment, bytes) Void_t** memptr; size_t alignment; size_t bytes;
+#endif
+{
+ mstate av;
+
+ if (alignment % sizeof(void *) != 0)
+ return EINVAL;
+ if ((alignment & (alignment - 1)) != 0)
+ return EINVAL;
+
+ av = get_malloc_state();
+ if (!av || av->max_fast == 0) malloc_consolidate(av);
+ *memptr = mEMALIGn(alignment, bytes);
+
+ return (*memptr != NULL ? 0 : ENOMEM);
+}
+
+/*
+ ------------------------------ memalign ------------------------------
+*/
+
+#if __STD_C
+DL_STATIC Void_t* mEMALIGn(size_t alignment, size_t bytes)
+#else
+DL_STATIC Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+ INTERNAL_SIZE_T nb; /* padded request size */
+ char* m; /* memory returned by malloc call */
+ chunkinfoptr p; /* corresponding chunk */
+ char* brk; /* alignment point within p */
+ chunkinfoptr newp; /* chunk to return */
+ INTERNAL_SIZE_T newsize; /* its size */
+ INTERNAL_SIZE_T leadsize; /* leading space before alignment point */
+ chunkinfoptr remainder; /* spare room at end to split off */
+ CHUNK_SIZE_T remainder_size; /* its size */
+ INTERNAL_SIZE_T size;
+#if PARANOIA > 2
+ mstate av;
+#endif
+
+ /* If need less alignment than we give anyway, just relay to malloc */
+
+ if (UNLIKELY(alignment <= MALLOC_ALIGNMENT)) return mALLOc(bytes);
+
+ /* Otherwise, ensure that it is at least a minimum chunk size */
+
+ if (alignment < MINSIZE) alignment = MINSIZE;
+
+ /* Make sure alignment is power of 2 (in case MINSIZE is not). */
+ if (UNLIKELY((alignment & (alignment - 1)) != 0)) {
+ size_t a = MALLOC_ALIGNMENT * 2;
+ while ((CHUNK_SIZE_T)a < (CHUNK_SIZE_T)alignment) a <<= 1;
+ alignment = a;
+ }
+
+ checked_request2size(bytes, nb);
+
+ /*
+ Strategy: find a spot within that chunk that meets the alignment
+ request, and then possibly free the leading and trailing space.
+ */
+
+
+ /* Call malloc with worst case padding to hit alignment. */
+
+ m = (char*)(mALLOc(nb + alignment + MINSIZE));
+
+ if (m == 0) return 0; /* propagate failure */
+
+#if PARANOIA > 2
+ av = get_malloc_state();
+#endif
+
+ p = hashtable_lookup((mchunkptr) m);
+
+ if ((((PTR_UINT)(m)) % alignment) != 0) { /* misaligned */
+
+ /*
+ Find an aligned spot inside chunk. Since we need to give back
+ leading space in a chunk of at least MINSIZE, if the first
+ calculation places us at a spot with less than MINSIZE leader,
+ we can move to the next aligned spot -- we've allocated enough
+ total room so that this is always possible.
+ */
+
+ brk = (char*) ((PTR_UINT)(((PTR_UINT)(m + alignment - 1)) &
+ -((signed long) alignment)));
+ if ((CHUNK_SIZE_T)(brk - (char*)(chunk(p))) < MINSIZE)
+ brk += alignment;
+
+ newp = cireg_getfree();
+ newp->chunk = (mchunkptr)brk;
+ leadsize = brk - (char*)(chunk(p));
+ newsize = chunksize(p) - leadsize;
+
+ /* For mmapped chunks, just adjust offset */
+ if (UNLIKELY(chunk_is_mmapped(p))) {
+ newp->hash_next = (chunkinfoptr) (((INTERNAL_SIZE_T) p->hash_next) + leadsize);
+ set_head(newp, newsize|IS_MMAPPED|INUSE);
+ hashtable_remove_mmapped(chunk(p));
+ freecilst_add(p);
+ hashtable_add(newp);
+ guard_set(av->guard_stored, newp, bytes, nb);
+ return chunk(newp);
+ }
+
+ /* Otherwise, give back leader, use the rest */
+ set_head(newp, newsize | PREV_INUSE | INUSE);
+ set_head_size(p, leadsize);
+ set_all_inuse(newp);
+ hashtable_add(newp); /* 20.05.2008 rw */
+ guard_set(av->guard_stored, p, 0, leadsize);
+ fREe(chunk(p));
+ p = newp;
+
+ assert (newsize >= nb &&
+ (((PTR_UINT)(chunk(p))) % alignment) == 0);
+ }
+
+ /* Also give back spare room at the end */
+ if (!chunk_is_mmapped(p)) {
+ size = chunksize(p);
+ if ((CHUNK_SIZE_T)(size) > (CHUNK_SIZE_T)(nb + MINSIZE)) {
+ remainder = cireg_getfree();
+ remainder_size = size - nb;
+ remainder->chunk = chunk_at_offset(chunk(p), nb);
+ set_head(remainder, remainder_size | PREV_INUSE | INUSE);
+ set_head_size(p, nb);
+ hashtable_add(remainder); /* 20.05.2008 rw */
+ guard_set(av->guard_stored, remainder, 0, remainder_size);
+ fREe(chunk(remainder));
+ }
+ }
+
+ check_inuse_chunk(p);
+ guard_set(av->guard_stored, p, bytes, nb);
+ return chunk(p);
+}
+
+/*
+ ------------------------------ calloc ------------------------------
+*/
+
+#if __STD_C
+DL_STATIC Void_t* cALLOc(size_t n_elements, size_t elem_size)
+#else
+DL_STATIC Void_t* cALLOc(n_elements, elem_size) size_t n_elements; size_t elem_size;
+#endif
+{
+ chunkinfoptr p;
+ CHUNK_SIZE_T clearsize;
+ CHUNK_SIZE_T nclears;
+ INTERNAL_SIZE_T* d;
+ Void_t* mem;
+
+
+ mem = mALLOc(n_elements * elem_size);
+
+ if (mem != 0) {
+ p = hashtable_lookup(mem);
+
+ if (!chunk_is_mmapped(p))
+ {
+ /*
+ Unroll clear of <= 40 bytes (80 if 8byte sizes)
+ We know that contents have an even number of
+ INTERNAL_SIZE_T-sized words; minimally 4 (2 on amd64).
+ */
+
+ d = (INTERNAL_SIZE_T*)mem;
+ clearsize = chunksize(p);
+ nclears = clearsize / sizeof(INTERNAL_SIZE_T);
+ assert(nclears >= 2);
+
+ if (nclears > 10) {
+ MALLOC_ZERO(d, clearsize);
+ }
+
+ else {
+ *(d+0) = 0;
+ *(d+1) = 0;
+ if (nclears > 2) {
+ *(d+2) = 0;
+ *(d+3) = 0;
+ if (nclears > 4) {
+ *(d+4) = 0;
+ *(d+5) = 0;
+ if (nclears > 6) {
+ *(d+6) = 0;
+ *(d+7) = 0;
+ if (nclears > 8) {
+ *(d+8) = 0;
+ *(d+9) = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+#if ! MMAP_CLEARS
+ else
+ {
+ d = (INTERNAL_SIZE_T*)mem;
+ clearsize = chunksize(p);
+ MALLOC_ZERO(d, clearsize);
+ }
+#endif
+ /* Set guard again, since we just cleared it
+ */
+ guard_set(get_malloc_state()->guard_stored, p, (n_elements * elem_size), p->size);
+ }
+
+ return mem;
+}
+
+/*
+ ------------------------------ valloc ------------------------------
+*/
+
+#if __STD_C
+DL_STATIC Void_t* vALLOc(size_t bytes)
+#else
+DL_STATIC Void_t* vALLOc(bytes) size_t bytes;
+#endif
+{
+ /* Ensure initialization */
+ mstate av = get_malloc_state();
+ if (!av || av->max_fast == 0) {
+ malloc_consolidate(av);
+ av = get_malloc_state();
+ }
+ return mEMALIGn(av->pagesize, bytes);
+}
+
+/*
+ ------------------------------ pvalloc ------------------------------
+*/
+
+
+#if __STD_C
+DL_STATIC Void_t* pVALLOc(size_t bytes)
+#else
+DL_STATIC Void_t* pVALLOc(bytes) size_t bytes;
+#endif
+{
+ mstate av = get_malloc_state();
+ size_t pagesz;
+
+ /* Ensure initialization */
+ if (!av || av->max_fast == 0) {
+ malloc_consolidate(av);
+ av = get_malloc_state();
+ }
+ pagesz = av->pagesize;
+ return mEMALIGn(pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
+}
+
+
+/*
+ ------------------------------ malloc_trim ------------------------------
+*/
+
+#if __STD_C
+DL_STATIC int mTRIm(size_t pad)
+#else
+DL_STATIC int mTRIm(pad) size_t pad;
+#endif
+{
+ mstate av = get_malloc_state();
+ /* Ensure initialization/consolidation */
+ malloc_consolidate(av);
+ av = get_malloc_state();
+#ifndef MORECORE_CANNOT_TRIM
+ if (morecore32bit(av))
+ return sYSTRIm(pad, av);
+ else
+ return 0;
+#else
+ return 0;
+#endif
+}
+
+
+
+/*
+ ------------------------- malloc_usable_size -------------------------
+*/
+
+#if __STD_C
+DL_STATIC size_t mUSABLe(Void_t* mem)
+#else
+DL_STATIC size_t mUSABLe(mem) Void_t* mem;
+#endif
+{
+ chunkinfoptr p;
+ if (mem != 0) {
+ p = hashtable_lookup(mem);
+ if (p && inuse(p)) return chunksize(p);
+ }
+ return 0;
+}
+
+/*
+ ------------------------------ mallinfo ------------------------------
+*/
+
+DL_STATIC struct mallinfo mALLINFo()
+{
+ mstate av = get_malloc_state();
+ struct mallinfo mi;
+ unsigned int i;
+ mbinptr b;
+ chunkinfoptr p;
+ INTERNAL_SIZE_T avail;
+ INTERNAL_SIZE_T fastavail;
+ int nblocks;
+ int nfastblocks;
+
+ /* Ensure initialization */
+ if (!av || av->top == 0) {
+ malloc_consolidate(av);
+ av = get_malloc_state();
+ }
+ check_malloc_state();
+
+ /* Account for top */
+ avail = chunksize(av->top);
+ nblocks = 1; /* top always exists */
+
+ /* traverse fastbins */
+ nfastblocks = 0;
+ fastavail = 0;
+
+ for (i = 0; i < NFASTBINS; ++i) {
+ for (p = av->fastbins[i]; p != 0; p = p->fd) {
+ ++nfastblocks;
+ fastavail += chunksize(p);
+ }
+ }
+
+ avail += fastavail;
+
+ /* traverse regular bins */
+ for (i = 1; i < NBINS; ++i) {
+ b = bin_at(av, i);
+ for (p = last(b); p != b; p = p->bk) {
+ ++nblocks;
+ avail += chunksize(p);
+ }
+ }
+
+ mi.smblks = nfastblocks;
+ mi.ordblks = nblocks;
+ mi.fordblks = avail;
+ mi.uordblks = av->sbrked_mem - avail;
+ mi.arena = av->sbrked_mem;
+ mi.hblks = av->n_mmaps;
+ mi.hblkhd = av->mmapped_mem;
+ mi.fsmblks = fastavail;
+ mi.keepcost = chunksize(av->top);
+ mi.usmblks = av->max_total_mem;
+ return mi;
+}
+
+/*
+ ------------------------------ malloc_stats ------------------------------
+*/
+
+DL_STATIC void mSTATs()
+{
+ struct mallinfo mi = mALLINFo();
+
+ fprintf(stderr, "hashtable = %10lu MB\n",
+ (CHUNK_SIZE_T)(HASHTABLESIZE / (1024*1024)));
+ fprintf(stderr, "max system bytes = %10lu\n",
+ (CHUNK_SIZE_T)(mi.usmblks));
+ fprintf(stderr, "system bytes = %10lu (%10lu sbrked, %10lu mmaped)\n",
+ (CHUNK_SIZE_T)(mi.arena + mi.hblkhd),
+ (CHUNK_SIZE_T)(mi.arena),
+ (CHUNK_SIZE_T)(mi.hblkhd));
+ fprintf(stderr, "in use bytes = %10lu\n",
+ (CHUNK_SIZE_T)(mi.uordblks + mi.hblkhd));
+
+}
+
+
+/*
+ ------------------------------ mallopt ------------------------------
+*/
+
+#if __STD_C
+DL_STATIC int mALLOPt(int param_number, int value)
+#else
+DL_STATIC int mALLOPt(param_number, value) int param_number; int value;
+#endif
+{
+ mstate av = get_malloc_state();
+ /* Ensure initialization/consolidation */
+ malloc_consolidate(av);
+ av = get_malloc_state();
+
+ switch(param_number) {
+ case M_MXFAST:
+ if (value >= 0 && value <= MAX_FAST_SIZE) {
+ set_max_fast(av, value);
+ return 1;
+ }
+ else
+ return 0;
+
+ case M_TRIM_THRESHOLD:
+ av->trim_threshold = value;
+ return 1;
+
+ case M_TOP_PAD:
+ av->top_pad = value;
+ return 1;
+
+ case M_MMAP_THRESHOLD:
+ av->mmap_threshold = value;
+ return 1;
+
+ case M_MMAP_MAX:
+ if (value != 0)
+ return 0;
+ av->n_mmaps_max = value;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+/* $OpenBSD: arc4random.c,v 1.19 2008/06/04 00:50:23 djm Exp $ */
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * Here the stream cipher has been modified always to include the time
+ * when initializing the state. That makes it impossible to
+ * regenerate the same random sequence twice, so this can't be used
+ * for encryption, but will generate good random numbers.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+/* Moved u_int8_t -> unsigned char (portability)
+ * Eliminated unneeded functions, added read from /dev/urandom taken from:
+ $MirOS: contrib/code/Snippets/arc4random.c,v 1.3 2008-03-04 22:53:14 tg Exp $
+ * Modified by Robert Connolly from OpenBSD lib/libc/crypt/arc4random.c v1.11.
+ * This is arc4random(3) using urandom.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+struct arc4_stream {
+ unsigned char i;
+ unsigned char j;
+ unsigned char s[256];
+};
+
+static int rs_initialized;
+static struct arc4_stream rs;
+static pid_t arc4_stir_pid;
+static int arc4_count;
+
+static unsigned char arc4_getbyte(void);
+
+static void
+arc4_init(void)
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+static inline void
+arc4_addrandom(unsigned char *dat, int datlen)
+{
+ int n;
+ unsigned char si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + dat[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+ rs.j = rs.i;
+}
+
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+#endif
+
+static void
+arc4_stir(void)
+{
+ int i;
+ struct {
+ struct timeval tv1;
+ struct timeval tv2;
+ u_int rnd[(128 - 2*sizeof(struct timeval)) / sizeof(u_int)];
+ } rdat;
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+ ssize_t sz = 0;
+ int fd;
+#endif
+
+ gettimeofday(&rdat.tv1, NULL);
+
+
+ if (!rs_initialized) {
+ arc4_init();
+ rs_initialized = 1;
+ }
+
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+
+#ifdef HAVE_SCHED_YIELD
+ /* Yield the processor to introduce some random delay. */
+ (void) sched_yield();
+#endif
+
+ /*
+ * Pthread problem in multithreaded code on *BSD.
+ */
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd != -1) {
+ sz = (size_t)read(fd, rdat.rnd, sizeof (rdat.rnd));
+ /*
+ * gcc complains if we ignore the return value of read(), and
+ * the llvm/clang analyzer complains if we don't use it...
+ */
+ if (sz > (-256)) /* always true */
+ close(fd);
+ }
+ /*
+ if (sz > sizeof (rdat.rnd))
+ sz = 0;
+ */
+ #endif
+
+ arc4_stir_pid = getpid();
+ gettimeofday(&rdat.tv2, NULL);
+
+ arc4_addrandom((void *)&rdat, sizeof(rdat));
+
+ /*
+ * Discard early keystream, as per recommendations in:
+ * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+ */
+ for (i = 0; i < 256; i++)
+ (void)arc4_getbyte();
+ arc4_count = 1600000;
+}
+
+static unsigned char
+arc4_getbyte(void)
+{
+ unsigned char si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+
+ /* Changed to return char* */
+static char *
+dnmalloc_arc4random(void)
+{
+ static char val[4];
+
+ /* We only call this once, hence no need for locking. */
+
+ /* _ARC4_LOCK(); */
+ arc4_count -= 4;
+ if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid())
+ arc4_stir();
+
+ val[0] = (char) arc4_getbyte();
+ val[1] = (char) arc4_getbyte();
+ val[2] = (char) arc4_getbyte();
+ val[3] = (char) arc4_getbyte();
+
+ arc4_stir();
+ /* _ARC4_UNLOCK(); */
+ return val;
+}
+
+#else
+int dnmalloc_pthread_init() { return 0; }
+#endif /* ! USE_SYSTEM_MALLOC */
diff --git a/src/encode.c b/src/encode.c
new file mode 100644
index 0000000..dadd0ba
--- /dev/null
+++ b/src/encode.c
@@ -0,0 +1,200 @@
+
+/* #include "config.h" */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argv, char * argc[])
+{
+ int xor_base = -1;
+
+ FILE * inf;
+ FILE * ouf;
+ char a, b;
+ int i, j;
+ char outfile[1024];
+ int inbracket = 0, quoted = 0;
+ unsigned long count;
+
+
+ /* char command[1024]; */
+
+ if ( argv < 3)
+ {
+ fprintf(stderr,"\nUsage: encode <XOR_VAL> "\
+ "<file>\n\n");
+ fprintf(stderr," This program will:\n");
+ fprintf(stderr," - take as input a source code file <file>,\n");
+ fprintf(stderr," - search for literal strings inclosed by _(), "\
+ "like '_(string)',\n");
+ fprintf(stderr," - replace _(string) by "\
+ "_(string XOR <XOR_VAL>),\n");
+ fprintf(stderr,
+ " - and output the result to './x_<file>'.\n\n");
+ fprintf(stderr," _() is supposed to be defined as a macro in "\
+ "the code, that\n");
+ fprintf(stderr," will allow the program to decode the xor'ed string "\
+ "at runtime.\n");
+ fprintf(stderr," The effect is that the compiled executable does "\
+ "not contain literal\n");
+ fprintf(stderr," strings that may trivially be found with the Unix "\
+ "'strings' command,\n");
+ fprintf(stderr," and thus reveal the nature of "\
+ "the program.\n");
+
+ return -1;
+ }
+
+ --argv; ++argc;
+
+ xor_base = atoi(argc[0]);
+
+ if (xor_base < 0 || (xor_base > 0 && xor_base < 128) || xor_base > 255)
+ {
+ fprintf(stderr, "\nERROR: encode: XOR_VAL=%d is out of "\
+ "range (0, 128..255)\n",
+ xor_base);
+ fprintf(stderr, "** please follow these steps to fix the problem:\n\n");
+ fprintf(stderr, " make clean\n");
+ fprintf(stderr, " ./configure [more options] "\
+ "--with-stealth=XOR_VAL (range 0, 128..255)\n");
+ fprintf(stderr, " make\n\n");
+ return -1;
+ }
+
+ /* fprintf(stderr, "<XOR_CODE> %d\n", xor_base); */
+
+ --argv; ++argc;
+
+ /* fprintf(stderr, "File: %d\n", argv); */
+
+ while (argv > 0)
+ {
+ inf = fopen(argc[0], "r");
+ if (inf == NULL)
+ {
+ fprintf(stderr, "Error opening %s\n", argc[0]);
+ return -1;
+ }
+ /* outfile name
+ */
+ i = 0; j = 0;
+ while (argc[0][i] != '\0')
+ {
+ if (argc[0][i] == '/') j = i+1;
+ ++i;
+ }
+ i = 0;
+ outfile[0] = 'x';
+ outfile[1] = '_';
+ outfile[2] = '\0';
+ while (argc[0][j+i] != '\0')
+ {
+ outfile[i+2] = argc[0][j+i];
+ ++i;
+ }
+ outfile[i+2] = '\0';
+ ouf = fopen(outfile, "w");
+ if (ouf == NULL)
+ {
+ fprintf(stderr, "Error opening %s\n", outfile);
+ return -1;
+ }
+
+ /* fprintf(stderr, "File: %s\n", argc[0]); */
+ count = 0;
+
+ while (fread(&a, 1, 1, inf) != 0)
+ {
+ count++;
+
+ if (a == '"' && quoted == 0)
+ {
+ quoted = 1;
+ fwrite(&a, 1, 1, ouf);
+ continue;
+ }
+
+ if (a == '"' && quoted == 1)
+ {
+ quoted = 0;
+ fwrite(&a, 1, 1, ouf);
+ continue;
+ }
+
+ if (a == '\n' && quoted == 1)
+ {
+ quoted = 0;
+ fwrite(&a, 1, 1, ouf);
+ continue;
+ }
+
+ /* macro start ?
+ */
+ if (a == '_' && inbracket == 0 && quoted == 0)
+ {
+ fwrite(&a, 1, 1, ouf);
+ b = '\0';
+ fread(&b, 1, 1, inf);
+ count++;
+ fwrite(&b, 1, 1, ouf);
+ if (b == '(') inbracket = 1;
+ continue;
+ }
+
+ /* macro end
+ */
+ if (a == ')' && quoted == 0 && inbracket == 1)
+ {
+ inbracket = 0;
+ /* fprintf(stdout, "\n"); */
+ fwrite(&a, 1, 1, ouf);
+ continue;
+ }
+
+ /* in a bracket
+ */
+ if (inbracket == 1 && quoted == 1)
+ {
+ /* fprintf(stdout, "%c", a); */
+ if (a == '\\')
+ {
+ fread(&b, 1, 1, inf);
+
+ /* escape sequences
+ */
+ if (b == 't' || b == 'n' || b == 'r' || b == '"')
+ {
+ fwrite(&a, 1, 1, ouf);
+ fwrite(&b, 1, 1, ouf);
+ }
+
+ else
+ {
+ a ^= (char) xor_base;
+ b ^= (char) xor_base;
+ }
+ }
+ else
+ {
+ a ^= (char) xor_base;
+ fwrite(&a, 1, 1, ouf);
+ }
+ continue;
+ }
+
+ fwrite(&a, 1, 1, ouf);
+ }
+
+ /* fprintf(stderr, "Bytes read: %ld\n", count); */
+ /* sprintf(command, "mv tempfile %s", argc[0]); */
+ /* system(command); */
+
+ fclose(ouf);
+ fclose(inf);
+ --argv; ++argc;
+ }
+ return 0;
+}
+
diff --git a/src/exepack.c b/src/exepack.c
new file mode 100644
index 0000000..219abb4
--- /dev/null
+++ b/src/exepack.c
@@ -0,0 +1,350 @@
+#include "config.h"
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+extern char **environ;
+
+
+#include "minilzo.h"
+
+/* integer data type that is _exactly_ 32 bit
+ */
+#if defined(HAVE_INT_32)
+#define UINT32 unsigned int
+#elif defined(HAVE_LONG_32)
+#define UINT32 unsigned long
+#elif defined(HAVE_SHORT_32)
+#define UINT32 unsigned short
+#endif
+
+
+#include "exepack.data"
+
+
+static UINT32 cstate[3], astate[3];
+
+/* interval [0, 4294967296]
+ */
+static UINT32 taus_get_long (UINT32 * state)
+{
+#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
+
+ state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
+ state[1] = TAUSWORTHE (state[1], 2, 25, 4294967288UL, 4);
+ state[2] = TAUSWORTHE (state[2], 3, 11, 4294967280UL, 17);
+
+ return (state[0] ^ state[1] ^ state[2]);
+}
+
+void taus_set_from_state (UINT32 * state, UINT32 * state0)
+{
+ state[0] = state0[0] | (UINT32) 0x03;
+ state[1] = state0[1] | (UINT32) 0x09;
+ state[2] = state0[2] | (UINT32) 0x17;
+
+ /* 'warm up'
+ */
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+
+ return;
+}
+
+void set2 (char * pos, char c1, char c2)
+{
+ pos[0] = c1;
+ pos[1] = c2;
+ return;
+}
+
+void set4 (char * pos, char c1, char c2, char c3, char c4)
+{
+ pos[0] = c1;
+ pos[1] = c2;
+ pos[2] = c3;
+ pos[3] = c4;
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ int file;
+ long result;
+
+ unsigned long i = argc; /* dummy use of argc to fix compiler warning */
+ unsigned long len = 0;
+
+ struct stat sbuf;
+ struct stat fbuf;
+
+ /* For compression.
+ */
+ lzo_byte * inbuf;
+ lzo_byte * outbuf;
+ int r;
+ lzo_uint in_len;
+ lzo_uint out_len;
+
+
+ char * p;
+
+ char fname[128];
+#if defined (__linux__)
+ char pname[128];
+#endif
+
+ UINT32 pid;
+
+ /* no SUID
+ */
+ if (getuid() != geteuid())
+ {
+ setuid(getuid());
+ }
+
+ /* reset umask
+ */
+ umask(0);
+
+
+ astate[0] = programkey_0[0];
+ astate[1] = programkey_0[1];
+ astate[2] = programkey_0[2];
+
+ taus_set_from_state (cstate, astate);
+
+ out_len = (unsigned long) programlen_compressed_0;
+ len = (unsigned long) programlen_0;
+ in_len = len;
+
+ outbuf = program_0;
+
+ /* Decode.
+ */
+ for (i = 0; i < out_len; ++i)
+ {
+ outbuf[i] ^= (taus_get_long (cstate) & 0xff);
+ }
+
+
+ inbuf = (lzo_byte *) malloc (sizeof(lzo_byte) * len);
+
+
+ /*
+ * Step 1: initialize the LZO library
+ */
+ if (lzo_init() != LZO_E_OK)
+ {
+ return 1;
+ }
+
+ /*
+ * Step 2: decompress again, now going from `out' to `in'
+ */
+ r = lzo1x_decompress_safe (outbuf, out_len, inbuf, &in_len, NULL);
+
+ if (r == LZO_E_OK && in_len == len)
+ {
+ /*
+ printf("decompressed %lu bytes back into %lu bytes\n",
+ (long) out_len, (long) in_len);
+ */
+ ;
+ }
+ else
+ {
+ /*
+ printf("internal error - decompression failed: %d\n",
+ r);
+ */
+ return 2;
+ }
+
+ /*
+ * Step 3: choose a filename
+ */
+
+ nameIt:
+
+ p = fname;
+
+ /* --- use /tmp if the sticky bit is set ---
+ */
+#if defined(S_ISVTX)
+
+ set4 (p, '/', 't', 'm', 'p');
+ p += 4;
+ *p = '\0';
+
+ if ( 0 != stat(fname, &sbuf))
+ {
+ if ( (sbuf.st_mode & S_ISVTX) != S_ISVTX)
+ {
+ p = fname;
+ set4 (p, '/', 'u', 's', 'r');
+ p += 4;
+ set4 (p, '/', 'b', 'i', 'n');
+ p += 4;
+ }
+ }
+
+#else
+
+ set4 (p, '/', 'u', 's', 'r');
+ p += 4;
+ set4 (p, '/', 'b', 'i', 'n');
+ p += 4;
+
+#endif
+
+ set4 (p, '/', 't', 'm', 'p');
+
+ p += 4;
+
+ cstate[0] ^= (UINT32) getpid ();
+ cstate[1] ^= (UINT32) time (NULL);
+ cstate[0] |= (UINT32) 0x03;
+ cstate[1] |= (UINT32) 0x09;
+
+ pid = (UINT32) (taus_get_long (cstate) ^ taus_get_long (cstate));
+
+ for (i = 0; i < 4; ++i)
+ {
+ *p = 'a' + (pid % 26);
+ pid /= 26;
+ ++p;
+ }
+
+ pid = (UINT32) (taus_get_long (cstate) ^ taus_get_long (cstate));
+
+ for (i = 0; i < 4; ++i)
+ {
+ *p = 'a' + (pid % 26);
+ pid /= 26;
+ ++p;
+ }
+
+ pid = (UINT32) (taus_get_long (cstate) ^ taus_get_long (cstate));
+
+ for (i = 0; i < 3; ++i)
+ {
+ *p = 'a' + (pid % 26);
+ pid /= 26;
+ ++p;
+ }
+ *p = '\0';
+
+ if ( (-1) != stat(fname, &sbuf) || errno != ENOENT)
+ {
+ /* because cstate[2] is not initialized, the next name will
+ * be different
+ */
+ goto nameIt;
+ }
+
+ if ((file = open (fname, O_CREAT|O_EXCL|O_WRONLY, 0700)) < 0)
+ {
+ return (4);
+ }
+
+ result = (long) write(file, inbuf, in_len);
+ if (result < 0 || in_len != (lzo_uint) result)
+ {
+ return (5);
+ }
+
+#if defined(__linux__)
+
+ if ( 0 != fstat(file, &sbuf))
+ {
+ return (6);
+ }
+
+ /* Must reopen for read only.
+ */
+ close(file);
+ file = open (fname, O_RDONLY, 0);
+
+ if ( 0 != fstat(file, &fbuf))
+ {
+ return (7);
+ }
+
+ /* check mode, inode, owner, and device, to make sure it is the same file
+ */
+ if (sbuf.st_mode != fbuf.st_mode ||
+ sbuf.st_ino != fbuf.st_ino ||
+ sbuf.st_uid != fbuf.st_uid ||
+ sbuf.st_gid != fbuf.st_gid ||
+ sbuf.st_dev != fbuf.st_dev )
+ {
+ close ( file );
+ return ( 8 );
+ }
+
+ p = pname;
+ set4(p, '/', 'p', 'r', 'o');
+ p += 4;
+
+ set2(p, 'c', '/');
+ p += 2;
+
+ set4(p, 's', 'e', 'l', 'f');
+ p += 4;
+
+ set4(p, '/', 'f', 'd', '/');
+ p += 4;
+
+ sprintf(p, "%d", file);
+
+
+ if (0 == access(pname, R_OK|X_OK))
+ {
+ unlink (fname);
+ fcntl (file, F_SETFD, FD_CLOEXEC);
+ execve (pname, argv, environ);
+ return (9);
+ }
+#endif
+
+ /* /proc not working, or not linux
+ */
+ close (file);
+
+ if ( (i = fork()) != 0)
+ {
+ wait (NULL);
+ execve (fname, argv, environ);
+ unlink (fname);
+ return (10);
+ }
+ else if (i == 0)
+ {
+ if (0 == fork())
+ {
+ sleep (3);
+ unlink (fname);
+ }
+ return (0);
+ }
+
+ /* only reached in case of error
+ */
+ unlink (fname);
+ return (-1);
+}
+
diff --git a/src/exepack_fill.c b/src/exepack_fill.c
new file mode 100644
index 0000000..1668479
--- /dev/null
+++ b/src/exepack_fill.c
@@ -0,0 +1,384 @@
+/* +++Date last modified: 05-Jul-1997 */
+
+/*
+** Case-sensitive Boyer-Moore-Horspool pattern match
+**
+** public domain by Raymond Gardner 7/92
+**
+** limitation: pattern length + string length must be less than 32767
+**
+** 10/21/93 rdg Fixed bug found by Jeff Dunlop
+**
+** limitation lifted Rainer Wichmann 07/2000
+*/
+#include "config.h"
+
+#ifdef HAVE_BROKEN_INCLUDES
+#define _ANSI_C_SOURCE
+#define _POSIX_SOURCE
+#endif
+
+#include <limits.h> /* rdg 10/93 */
+#include <stddef.h>
+#include <string.h>
+
+typedef unsigned char uchar;
+
+#define LARGE 2147483647 /* rw 7/2000 */
+
+static long patlen; /* rw 7/2000 */
+static long skip[UCHAR_MAX+1]; /* rw 7/2000 */ /* rdg 10/93 */
+static long skip2; /* rw 7/2000 */
+static uchar *pat; /* rw 7/2000 */
+
+void bmh_init(const char *pattern)
+{
+ long i, lastpatchar;
+
+ pat = (uchar *)pattern;
+ patlen = strlen(pattern);
+ for (i = 0; i <= UCHAR_MAX; ++i) /* rdg 10/93 */
+ skip[i] = patlen;
+ for (i = 0; i < patlen; ++i)
+ skip[pat[i]] = patlen - i - 1;
+ lastpatchar = pat[patlen - 1];
+ skip[lastpatchar] = LARGE;
+ skip2 = patlen; /* Horspool's fixed second shift */
+ for (i = 0; i < patlen - 1; ++i)
+ {
+ if (pat[i] == lastpatchar)
+ skip2 = patlen - i - 1;
+ }
+}
+
+char * bmh_search(const char * string, const long stringlen)
+{
+ long i, j; /* rw 7/2000 */
+ char *s;
+
+ i = patlen - 1 - stringlen;
+ if (i >= 0)
+ return NULL;
+ string += stringlen;
+ for ( ;; )
+ {
+ while ( (i += skip[((uchar *)string)[i]]) < 0 )
+ ; /* mighty fast inner loop */
+ if (i < (LARGE - stringlen))
+ return NULL;
+ i -= LARGE;
+ j = patlen - 1;
+ s = (char *)string + (i - j);
+ while (--j >= 0 && s[j] == pat[j])
+ ;
+ if ( j < 0 ) /* rdg 10/93 */
+ return s; /* rdg 10/93 */
+ if ( (i += skip2) >= 0 ) /* rdg 10/93 */
+ return NULL; /* rdg 10/93 */
+ }
+}
+
+/* Everything below: Copyright 2000, Rainer Wichmann */
+
+char * my_locate (const char * pattern, const char * data, const long datalen)
+{
+ bmh_init (pattern);
+ return (bmh_search (data, datalen) );
+}
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+
+#include "config.h"
+
+#include "minilzo.h"
+
+/* integer data type that is _exactly_ 32 bit
+ */
+#if defined(HAVE_INT_32)
+#define UINT32 unsigned int
+#elif defined(HAVE_LONG_32)
+#define UINT32 unsigned long
+#elif defined(HAVE_SHORT_32)
+#define UINT32 unsigned short
+#endif
+
+static UINT32 cstate[3], astate[3];
+
+static UINT32 taus_get_long (UINT32 * state)
+{
+#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
+
+ state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
+ state[1] = TAUSWORTHE (state[1], 2, 25, 4294967288UL, 4);
+ state[2] = TAUSWORTHE (state[2], 3, 11, 4294967280UL, 17);
+
+ return (state[0] ^ state[1] ^ state[2]);
+}
+
+void taus_set_from_state (UINT32 * state, UINT32 * state0)
+{
+ state[0] = state0[0] | (UINT32) 0x03;
+ state[1] = state0[1] | (UINT32) 0x09;
+ state[2] = state0[2] | (UINT32) 0x17;
+
+ /* 'warm up'
+ */
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+
+ return;
+}
+
+int replaceData (char * data, long len, char * in, char * out, long size)
+{
+ char * pos;
+ int i;
+
+ pos = my_locate (in, data, len);
+ if (pos == NULL)
+ return (-1);
+
+ for (i = 0; i < size; ++i)
+ {
+ pos[i] = out[i];
+ }
+
+ return 0;
+}
+
+/* Work-memory needed for compression. Allocate memory in units
+ * of `long' (instead of `char') to make sure it is properly aligned.
+ */
+#define HEAP_ALLOC(var,size) long __LZO_MMODEL var [ ((size) + (sizeof(long) - 1)) / sizeof(long) ]
+
+static HEAP_ALLOC(wrkmem, LZO1X_1_MEM_COMPRESS);
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int main(int argc, char * argv[])
+{
+ FILE * fd;
+ unsigned long clen;
+ char * data;
+ struct stat sbuf;
+
+ char * ptest;
+
+ unsigned long i;
+
+ int status;
+
+ unsigned long len = 0;
+ unsigned long have = 0;
+
+ /* For compression.
+ */
+ lzo_byte * inbuf;
+ lzo_byte * outbuf;
+ int r;
+ lzo_uint in_len;
+ lzo_uint out_len;
+
+ UINT32 len_raw;
+ UINT32 len_cmp;
+
+
+ astate[0] = EXEPACK_STATE_0;
+ astate[1] = EXEPACK_STATE_1;
+ astate[2] = EXEPACK_STATE_2;
+
+
+ if (argc < 4)
+ {
+ fprintf(stderr,
+ "Usage: exepack_fill <container_file> <infile> <outfile>\n");
+ exit (EXIT_FAILURE);
+ }
+
+ if (0 != stat (argv[1], &sbuf))
+ {
+ fprintf(stderr, "exepack_fill: could not access file %s\n", argv[1]);
+ return (-1);
+ }
+ clen = sbuf.st_size;
+
+
+ data = (char *) malloc (clen * sizeof(char));
+ if (data == NULL)
+ return (-1);
+
+ fd = fopen (argv[1], "r");
+ if (fd == NULL)
+ return (-1);
+
+ if (clen != fread (data, 1, clen, fd))
+ return (-1);
+ fclose (fd);
+
+
+ /*******************
+ *
+ * THE DATA
+ *
+ *******************/
+
+
+
+ if (stat (argv[2], &sbuf) < 0)
+ {
+ perror ("exepack_fill");
+ exit (EXIT_FAILURE);
+ }
+
+ len = (unsigned long) sbuf.st_size;
+
+ /* Because the input block may be incompressible,
+ * we must provide a little more output space in case that compression
+ * is not possible.
+ */
+ inbuf = (lzo_byte *) malloc (sizeof(lzo_byte) * len);
+ outbuf = (lzo_byte *) malloc (sizeof(lzo_byte) * (len + len / 64 + 16 + 3));
+ in_len = len;
+
+ if (NULL == inbuf || NULL == outbuf)
+ {
+ fprintf(stderr, "exepack_fill: Out of memory.");
+ exit (EXIT_FAILURE);
+ }
+
+ if (NULL == (fd = fopen(argv[2], "r")))
+ {
+ perror ("exepack_fill");
+ exit (EXIT_FAILURE);
+ }
+
+ have = fread (inbuf, 1, len, fd);
+ fclose (fd);
+
+ if (have != len)
+ {
+ fprintf (stderr, "exepack_mkdata: Error reading %s", argv[2]);
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * Step 1: initialize the LZO library
+ */
+ if (lzo_init() != LZO_E_OK)
+ {
+ fprintf(stderr, "exepack_fill: lzo_init() failed\n");
+ return 3;
+ }
+
+ /*
+ * Step 3: compress from `in' to `out' with LZO1X-1
+ */
+ r = lzo1x_1_compress(inbuf, in_len, outbuf, &out_len, wrkmem);
+
+ if (r == LZO_E_OK)
+ printf("exepack_fill: compressed %lu bytes into %lu bytes\n",
+ (long) in_len, (long) out_len);
+ else
+ {
+ /* this should NEVER happen */
+ printf("exepack_fill: internal error - compression failed: %d\n", r);
+ return 2;
+ }
+
+ /* check for an incompressible block
+ */
+ if (out_len >= in_len)
+ {
+ printf("exepack_fill: Incompressible data.\n");
+ }
+
+ taus_set_from_state (cstate, astate);
+ for (i = 0; i < out_len; ++i)
+ {
+ outbuf[i] ^= (taus_get_long (cstate) & 0xff);
+ }
+
+ len_raw = in_len;
+ len_cmp = out_len;
+
+ if ( (unsigned long) len_cmp > (unsigned long) clen)
+ {
+ printf("exepack_fill: Compressed length (%ld) exceeds container length (%ld).\n", (long) len_cmp, (long) clen);
+ return (8);
+ }
+
+
+ /***********
+ *
+ * Fill program
+ *
+ **********/
+
+ status = replaceData (data, clen, "LLLL", (char *) &len_raw, sizeof(UINT32));
+ if (status < 0)
+ {
+ printf("exepack_fill: Could not write raw lenght %d.\n", len_raw);
+ return (8);
+ }
+ status = replaceData (data, clen, "CCCC", (char *) &len_cmp, sizeof(UINT32));
+ if (status < 0)
+ {
+ printf("exepack_fill: Could not write compressed lenght %d.\n",
+ len_cmp);
+ return (8);
+ }
+ status = replaceData (data, clen, "CONTAINER", (char *) outbuf, out_len);
+ if (status < 0)
+ {
+ printf("exepack_fill: Could not write program data.\n");
+ return (8);
+ }
+
+ /***********
+ *
+ * Write program
+ *
+ **********/
+
+ if ( NULL == (fd = fopen(argv[3], "w" )))
+ {
+ perror ("exepack_fill");
+ exit (EXIT_FAILURE);
+ }
+
+ fwrite (data, 1, clen, fd);
+
+ fclose (fd);
+
+ ptest = my_locate("LLLL", data, clen);
+ if (ptest != NULL)
+ {
+ printf("exepack_fill: ERROR: program length not updated.\n");
+ return (8);
+ }
+ ptest = my_locate("CCCC", data, clen);
+ if (ptest != NULL)
+ {
+ printf("exepack_fill: ERROR: compressed program length not updated.\n");
+ return (8);
+ }
+ ptest = my_locate("CONTAINER", data, clen);
+ if (ptest != NULL)
+ {
+ printf("exepack_fill: ERROR: program data not updated.\n");
+ return (8);
+ }
+
+ return 0;
+}
+
diff --git a/src/exepack_mkdata.c b/src/exepack_mkdata.c
new file mode 100644
index 0000000..e939ca8
--- /dev/null
+++ b/src/exepack_mkdata.c
@@ -0,0 +1,248 @@
+#include "config.h"
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+
+#include "minilzo.h"
+
+/* integer data type that is _exactly_ 32 bit
+ */
+#if defined(HAVE_INT_32)
+#define UINT32 unsigned int
+#elif defined(HAVE_LONG_32)
+#define UINT32 unsigned long
+#elif defined(HAVE_SHORT_32)
+#define UINT32 unsigned short
+#endif
+
+#if 0
+static UINT32 cstate[3], astate[3];
+
+/* interval [0, 4294967296]
+ */
+static UINT32 taus_get_long (UINT32 * state)
+{
+#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
+
+ state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
+ state[1] = TAUSWORTHE (state[1], 2, 25, 4294967288UL, 4);
+ state[2] = TAUSWORTHE (state[2], 3, 11, 4294967280UL, 17);
+
+ return (state[0] ^ state[1] ^ state[2]);
+}
+
+void taus_set_from_state (UINT32 * state, UINT32 * state0)
+{
+ state[0] = state0[0] | (UINT32) 0x03;
+ state[1] = state0[1] | (UINT32) 0x09;
+ state[2] = state0[2] | (UINT32) 0x17;
+
+ /* 'warm up'
+ */
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+ taus_get_long (state);
+
+ return;
+}
+#endif
+
+
+/* Work-memory needed for compression. Allocate memory in units
+ * of `long' (instead of `char') to make sure it is properly aligned.
+ */
+#define HEAP_ALLOC(var,size) \
+ long __LZO_MMODEL var [ ((size) + (sizeof(long) - 1)) / sizeof(long) ]
+
+static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS);
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+
+ FILE * fd;
+ FILE * fd_out;
+
+ struct stat sbuf;
+
+ int num = -1;
+
+ unsigned long i;
+ unsigned long len = 0;
+ unsigned long have = 0;
+
+ /* For compression.
+ */
+ lzo_byte * inbuf;
+ lzo_byte * outbuf;
+ int r;
+ lzo_uint in_len;
+ lzo_uint out_len;
+
+
+#if 0
+ astate[0] = EXEPACK_STATE_0;
+ astate[1] = EXEPACK_STATE_1;
+ astate[2] = EXEPACK_STATE_2;
+#endif
+
+ if (argc < 4 || (num = atoi(argv[3])) < 0)
+ {
+ fprintf(stderr,
+ "Usage: exepack_mkdata <infile> <outfile> <num> [ARGS]\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* the include file
+ */
+ if (NULL == (fd_out = fopen(argv[2], "w")) )
+ {
+ fprintf(stderr, "exepack_mkdata: Error opening %s for write.\n",
+ argv[2]);
+ exit (EXIT_FAILURE);
+ }
+
+
+ /* write data
+ */
+ fprintf (fd_out, "UINT32 programkey_%d[3] = { 0x%x, 0x%x, 0x%x };\n",
+ num, EXEPACK_STATE_0, EXEPACK_STATE_1, EXEPACK_STATE_2);
+
+ if (num == 0)
+ {
+ fprintf (fd_out, "UINT32 programlen_%d = %ld;\n\n",
+ num, 0x4C4C4C4CL);
+ fprintf (fd_out, "UINT32 programlen_compressed_%d = %ld;\n\n",
+ num, 0x43434343L);
+ }
+ else
+ {
+ fprintf (fd_out, "UINT32 programlen_%d = %ld;\n\n",
+ num, 0x4D4D4D4DL);
+ fprintf (fd_out, "UINT32 programlen_compressed_%d = %ld;\n\n",
+ num, 0x44444444L);
+ }
+
+
+ if (stat (argv[1], &sbuf) < 0)
+ {
+ perror ("exepack_mkdata");
+ exit (EXIT_FAILURE);
+ }
+
+ len = (unsigned long) sbuf.st_size;
+
+ /* Because the input block may be incompressible,
+ * we must provide a little more output space in case that compression
+ * is not possible.
+ */
+ inbuf = (lzo_byte *) malloc (sizeof(lzo_byte) * len);
+ outbuf = (lzo_byte *) malloc (sizeof(lzo_byte) * (len + len / 64 + 16 + 3));
+ in_len = len;
+
+ if (NULL == inbuf || NULL == outbuf)
+ {
+ fprintf(stderr, "exepack_mkdata: Out of memory.");
+ exit (EXIT_FAILURE);
+ }
+
+ if (NULL == (fd = fopen(argv[1], "r")))
+ {
+ perror ("exepack_mkdata");
+ exit (EXIT_FAILURE);
+ }
+
+ have = fread (inbuf, 1, len, fd);
+ fclose (fd);
+
+ if (have != len)
+ {
+ fprintf (stderr, "exepack_mkdata: Error reading %s", argv[1]);
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * Step 1: initialize the LZO library
+ */
+ if (lzo_init() != LZO_E_OK)
+ {
+ fprintf(stderr, "exepack_mkdata: lzo_init() failed\n");
+ return 3;
+ }
+
+ /*
+ * Step 3: compress from `in' to `out' with LZO1X-1
+ */
+ r = lzo1x_1_compress(inbuf, in_len, outbuf, &out_len, wrkmem);
+
+ if (r == LZO_E_OK)
+ printf("exepack_mkdata: compressed %lu bytes into %lu bytes\n",
+ (long) in_len, (long) out_len);
+ else
+ {
+ /* this should NEVER happen */
+ printf("exepack_mkdata: internal error - compression failed: %d\n", r);
+ return 2;
+ }
+
+ /* check for an incompressible block
+ */
+ if (out_len >= in_len)
+ {
+ printf("exepack_mkdata: Incompressible data.\n");
+ }
+
+ fprintf (fd_out, "lzo_byte program_%d[] = {\n", num);
+
+ fprintf (fd_out, "0x43, 0x4F, 0x4E, 0x54, 0x41, 0x49, 0x4E, 0x45, 0x52,\n");
+
+ /*
+ taus_set_from_state (cstate, astate);
+ for (i = 0; i < out_len; ++i)
+ {
+ outbuf[i] =^ (taus_get_long (cstate) & 0xff);
+ }
+ */
+
+
+ for (i = 1; i <= out_len; ++i)
+ {
+ fprintf(fd_out, "0x00,");
+ if (0 == (i % 20))
+ fprintf(fd_out, "\n");
+ }
+
+ fprintf(fd_out, "\n");
+
+ for (i = 1; i <= 256; ++i)
+ {
+ fprintf(fd_out, "0x00,");
+ if (0 == (i % 20))
+ fprintf(fd_out, "\n");
+ }
+
+ fprintf (fd_out, "0x00 };\n\n");
+
+
+ fclose (fd_out);
+
+ if (argc > 4)
+ {
+ fprintf (fd_out, "char * const programargv_%d[]={\n", num);
+
+ for(len = 4; len < (unsigned int) argc; len++)
+ fprintf(fd_out, "\"%s\",", argv[len-4]);
+
+ fprintf(fd_out, "NULL };\n\n");
+ }
+
+ return 0;
+}
diff --git a/src/kern_head.h.tmp b/src/kern_head.h.tmp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/kern_head.h.tmp
diff --git a/src/make-tests.sh b/src/make-tests.sh
new file mode 100755
index 0000000..b6cf814
--- /dev/null
+++ b/src/make-tests.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+# Auto generate single AllTests file for CuTest.
+# Searches through all *.c files in the current directory.
+# Prints to stdout.
+# Author: Asim Jalis
+# Date: 01/08/2003
+
+# Modified to return non-zero if any test has failed
+# Rainer Wichmann, 29. Jan 2006
+# ...and to print to stderr if any test has failed
+# Rainer Wichmann, 31. Jan 2006
+
+if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi
+
+echo '
+
+/* This is auto-generated code. Edit at your own peril. */
+
+#include "config.h"
+#include <stdio.h>
+#include "CuTest.h"
+'
+
+cat $FILES | grep '^void Test' |
+ sed -e 's/(.*$//' \
+ -e 's/$/(CuTest*);/' \
+ -e 's/^/extern /'
+
+echo \
+'
+
+int RunAllTests(void)
+{
+ CuString *output = CuStringNew();
+ CuSuite* suite = CuSuiteNew();
+
+'
+cat $FILES | grep '^void Test' |
+ sed -e 's/^void //' \
+ -e 's/(.*$//' \
+ -e 's/^/ SUITE_ADD_TEST(suite, /' \
+ -e 's/$/);/'
+
+echo \
+'
+ CuSuiteRun(suite);
+ CuSuiteSummary(suite, output);
+ CuSuiteDetails(suite, output);
+ if (suite->failCount > 0)
+ fprintf(stderr, "%s%c", output->buffer, 0x0A);
+ else
+ fprintf(stdout, "%s%c", output->buffer, 0x0A);
+ return suite->failCount;
+}
+
+int main(void)
+{
+#if !defined(USE_SYSTEM_MALLOC)
+ typedef void assert_handler_tp(const char * error, const char *file, int line);
+ extern assert_handler_tp *dnmalloc_set_handler(assert_handler_tp *new);
+ extern void safe_fatal (const char * details, const char *f, int l);
+#endif
+#if !defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)
+ extern int dnmalloc_pthread_init(void);
+ dnmalloc_pthread_init();
+#endif
+#if !defined(USE_SYSTEM_MALLOC)
+ (void) dnmalloc_set_handler(safe_fatal);
+#endif
+ int retval;
+ retval = RunAllTests();
+ return (retval == 0) ? 0 : 1;
+}
+'
diff --git a/src/minilzo.c b/src/minilzo.c
new file mode 100644
index 0000000..323155b
--- /dev/null
+++ b/src/minilzo.c
@@ -0,0 +1,2853 @@
+/* minilzo.c -- mini subset of the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+
+ The LZO library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus.oberhumer@jk.uni-linz.ac.at>
+ http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ */
+
+/*
+ * NOTE:
+ * the full LZO package can be found at
+ * http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html
+ */
+
+#define _ANSI_C_SOURCE
+#define _POSIX_SOURCE
+
+
+
+#define __LZO_IN_MINILZO
+
+#ifdef MINILZO_HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "minilzo.h"
+
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x1060)
+# error "version mismatch in miniLZO source files"
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+# define LZO_HAVE_CONFIG_H
+#endif
+
+#if !defined(LZO_NO_SYS_TYPES_H)
+# include <sys/types.h>
+#endif
+#include <stdio.h>
+
+#ifndef __LZO_CONF_H
+#define __LZO_CONF_H
+
+#if !defined(__LZO_IN_MINILZO)
+# ifndef __LZOCONF_H
+# include <lzoconf.h>
+# endif
+#endif
+
+#if !defined(LZO_HAVE_CONFIG_H)
+# include <stddef.h>
+# include <string.h>
+# if !defined(NO_STDLIB_H)
+# include <stdlib.h>
+# endif
+# define HAVE_MEMCMP
+# define HAVE_MEMCPY
+# define HAVE_MEMMOVE
+# define HAVE_MEMSET
+#else
+# include <sys/types.h>
+# if defined(STDC_HEADERS)
+# include <string.h>
+# include <stdlib.h>
+# endif
+# if defined(HAVE_STDDEF_H)
+# include <stddef.h>
+# endif
+# if defined(HAVE_MEMORY_H)
+# include <memory.h>
+# endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+# define HAVE_MALLOC_H
+# define HAVE_HALLOC
+#endif
+
+#undef NDEBUG
+#if !defined(LZO_DEBUG)
+# define NDEBUG
+#endif
+#if defined(LZO_DEBUG) || !defined(NDEBUG)
+# if !defined(NO_STDIO_H)
+# include <stdio.h>
+# endif
+#endif
+#include <assert.h>
+
+#if defined(__BOUNDS_CHECKING_ON)
+# include <unchecked.h>
+#else
+# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt
+# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr)
+#endif
+
+#if !defined(LZO_UNUSED)
+# define LZO_UNUSED(parm) (parm = parm)
+#endif
+
+#if !defined(__inline__) && !defined(__GNUC__)
+# if defined(__cplusplus)
+# define __inline__ inline
+# else
+# define __inline__
+# endif
+#endif
+
+#if defined(NO_MEMCMP)
+# undef HAVE_MEMCMP
+#endif
+
+#if !defined(HAVE_MEMCMP)
+# undef memcmp
+# define memcmp lzo_memcmp
+#endif
+#if !defined(HAVE_MEMCPY)
+# undef memcpy
+# define memcpy lzo_memcpy
+#endif
+#if !defined(HAVE_MEMMOVE)
+# undef memmove
+# define memmove lzo_memmove
+#endif
+#if !defined(HAVE_MEMSET)
+# undef memset
+# define memset lzo_memset
+#endif
+
+#if 1
+# define LZO_BYTE(x) ((unsigned char) (x))
+#else
+# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff))
+#endif
+#if 0
+# define LZO_USHORT(x) ((unsigned short) (x))
+#else
+# define LZO_USHORT(x) ((unsigned short) ((x) & 0xffff))
+#endif
+
+#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
+
+#define lzo_sizeof(type) ((lzo_uint) (sizeof(type)))
+
+#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array))))
+
+#define LZO_SIZE(bits) (1u << (bits))
+#define LZO_MASK(bits) (LZO_SIZE(bits) - 1)
+
+#define LZO_LSIZE(bits) (1ul << (bits))
+#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1)
+
+#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits))
+#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1)
+
+#define LZO_STYPE_MAX(b) (((1l << (8*(b)-2)) - 1l) + (1l << (8*(b)-2)))
+#define LZO_UTYPE_MAX(b) (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
+
+#if !defined(SIZEOF_UNSIGNED)
+# if (UINT_MAX == 0xffff)
+# define SIZEOF_UNSIGNED 2
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define SIZEOF_UNSIGNED 4
+# elif (UINT_MAX >= LZO_0xffffffffL)
+# define SIZEOF_UNSIGNED 8
+# else
+# error SIZEOF_UNSIGNED
+# endif
+#endif
+
+#if !defined(SIZEOF_UNSIGNED_LONG)
+# if (ULONG_MAX == LZO_0xffffffffL)
+# define SIZEOF_UNSIGNED_LONG 4
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+# define SIZEOF_UNSIGNED_LONG 8
+# else
+# error SIZEOF_UNSIGNED_LONG
+# endif
+#endif
+
+#if !defined(SIZEOF_SIZE_T)
+# define SIZEOF_SIZE_T SIZEOF_UNSIGNED
+#endif
+#if !defined(SIZE_T_MAX)
+# define SIZE_T_MAX LZO_UTYPE_MAX(SIZEOF_SIZE_T)
+#endif
+
+#if 1 && defined(__LZO_i386) && (UINT_MAX == LZO_0xffffffffL)
+# if !defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX == 0xffff)
+# define LZO_UNALIGNED_OK_2
+# endif
+# if !defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX == LZO_0xffffffffL)
+# define LZO_UNALIGNED_OK_4
+# endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) || defined(LZO_UNALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK)
+# define LZO_UNALIGNED_OK
+# endif
+#endif
+
+#if defined(__LZO_NO_UNALIGNED)
+# undef LZO_UNALIGNED_OK
+# undef LZO_UNALIGNED_OK_2
+# undef LZO_UNALIGNED_OK_4
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX != 0xffff)
+# error "LZO_UNALIGNED_OK_2 must not be defined on this system"
+#endif
+#if defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+# error "LZO_UNALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#if defined(__LZO_NO_ALIGNED)
+# undef LZO_ALIGNED_OK_4
+#endif
+
+#if defined(LZO_ALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL)
+# error "LZO_ALIGNED_OK_4 must not be defined on this system"
+#endif
+
+#define LZO_LITTLE_ENDIAN 1234
+#define LZO_BIG_ENDIAN 4321
+#define LZO_PDP_ENDIAN 3412
+
+#if !defined(LZO_BYTE_ORDER)
+# if defined(MFX_BYTE_ORDER)
+# define LZO_BYTE_ORDER MFX_BYTE_ORDER
+# elif defined(__LZO_i386)
+# define LZO_BYTE_ORDER LZO_LITTLE_ENDIAN
+# elif defined(BYTE_ORDER)
+# define LZO_BYTE_ORDER BYTE_ORDER
+# elif defined(__BYTE_ORDER)
+# define LZO_BYTE_ORDER __BYTE_ORDER
+# endif
+#endif
+
+#if defined(LZO_BYTE_ORDER)
+# if (LZO_BYTE_ORDER != LZO_LITTLE_ENDIAN) && \
+ (LZO_BYTE_ORDER != LZO_BIG_ENDIAN)
+# error "invalid LZO_BYTE_ORDER"
+# endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK) && !defined(LZO_BYTE_ORDER)
+# error "LZO_BYTE_ORDER is not defined"
+#endif
+
+#define LZO_OPTIMIZE_GNUC_i386_IS_BUGGY
+
+#if defined(NDEBUG) && !defined(LZO_DEBUG) && !defined(__BOUNDS_CHECKING_ON)
+# if defined(__GNUC__) && defined(__i386__)
+# if !defined(LZO_OPTIMIZE_GNUC_i386_IS_BUGGY)
+# define LZO_OPTIMIZE_GNUC_i386
+# endif
+# endif
+#endif
+
+__LZO_EXTERN_C int __lzo_init_done;
+__LZO_EXTERN_C const lzo_byte __lzo_copyright[];
+LZO_EXTERN(const lzo_byte *) lzo_copyright(void);
+__LZO_EXTERN_C const lzo_uint32 _lzo_crc32_table[256];
+
+#define _LZO_STRINGIZE(x) #x
+#define _LZO_MEXPAND(x) _LZO_STRINGIZE(x)
+
+#define _LZO_CONCAT2(a,b) a ## b
+#define _LZO_CONCAT3(a,b,c) a ## b ## c
+#define _LZO_CONCAT4(a,b,c,d) a ## b ## c ## d
+#define _LZO_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
+
+#define _LZO_ECONCAT2(a,b) _LZO_CONCAT2(a,b)
+#define _LZO_ECONCAT3(a,b,c) _LZO_CONCAT3(a,b,c)
+#define _LZO_ECONCAT4(a,b,c,d) _LZO_CONCAT4(a,b,c,d)
+#define _LZO_ECONCAT5(a,b,c,d,e) _LZO_CONCAT5(a,b,c,d,e)
+
+#if 0
+
+#define __LZO_IS_COMPRESS_QUERY(i,il,o,ol,w) ((lzo_voidp)(o) == (w))
+#define __LZO_QUERY_COMPRESS(i,il,o,ol,w,n,s) \
+ (*ol = (n)*(s), LZO_E_OK)
+
+#define __LZO_IS_DECOMPRESS_QUERY(i,il,o,ol,w) ((lzo_voidp)(o) == (w))
+#define __LZO_QUERY_DECOMPRESS(i,il,o,ol,w,n,s) \
+ (*ol = (n)*(s), LZO_E_OK)
+
+#define __LZO_IS_OPTIMIZE_QUERY(i,il,o,ol,w) ((lzo_voidp)(o) == (w))
+#define __LZO_QUERY_OPTIMIZE(i,il,o,ol,w,n,s) \
+ (*ol = (n)*(s), LZO_E_OK)
+
+#endif
+
+#ifndef __LZO_PTR_H
+#define __LZO_PTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+# include <dos.h>
+# if 1 && defined(__WATCOMC__)
+# include <i86.h>
+ __LZO_EXTERN_C unsigned char _HShift;
+# define __LZO_HShift _HShift
+# elif 1 && defined(_MSC_VER)
+ __LZO_EXTERN_C unsigned short __near _AHSHIFT;
+# define __LZO_HShift ((unsigned) &_AHSHIFT)
+# elif defined(__LZO_WIN16)
+# define __LZO_HShift 3
+# else
+# define __LZO_HShift 12
+# endif
+# if !defined(_FP_SEG) && defined(FP_SEG)
+# define _FP_SEG FP_SEG
+# endif
+# if !defined(_FP_OFF) && defined(FP_OFF)
+# define _FP_OFF FP_OFF
+# endif
+#endif
+
+#if (UINT_MAX >= LZO_0xffffffffL)
+ typedef ptrdiff_t lzo_ptrdiff_t;
+#else
+ typedef long lzo_ptrdiff_t;
+#endif
+
+#if !defined(__LZO_HAVE_PTR_T)
+# if defined(lzo_ptr_t)
+# define __LZO_HAVE_PTR_T
+# endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+# if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_LONG)
+# if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_LONG)
+ typedef unsigned long lzo_ptr_t;
+ typedef long lzo_sptr_t;
+# define __LZO_HAVE_PTR_T
+# endif
+# endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+# if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED)
+# if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED)
+ typedef unsigned int lzo_ptr_t;
+ typedef int lzo_sptr_t;
+# define __LZO_HAVE_PTR_T
+# endif
+# endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+# if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_SHORT)
+# if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_SHORT)
+ typedef unsigned short lzo_ptr_t;
+ typedef short lzo_sptr_t;
+# define __LZO_HAVE_PTR_T
+# endif
+# endif
+#endif
+#if !defined(__LZO_HAVE_PTR_T)
+# if defined(LZO_HAVE_CONFIG_H) || defined(SIZEOF_CHAR_P)
+# error "no suitable type for lzo_ptr_t"
+# else
+ typedef unsigned long lzo_ptr_t;
+ typedef long lzo_sptr_t;
+# define __LZO_HAVE_PTR_T
+# endif
+#endif
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+#define PTR(a) ((lzo_bytep) (a))
+#define PTR_ALIGNED_4(a) ((_FP_OFF(a) & 3) == 0)
+#define PTR_ALIGNED2_4(a,b) (((_FP_OFF(a) | _FP_OFF(b)) & 3) == 0)
+#else
+#define PTR(a) ((lzo_ptr_t) (a))
+#define PTR_LINEAR(a) PTR(a)
+#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0)
+#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0)
+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
+#endif
+
+#define PTR_LT(a,b) (PTR(a) < PTR(b))
+#define PTR_GE(a,b) (PTR(a) >= PTR(b))
+#define PTR_DIFF(a,b) ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
+
+LZO_EXTERN(lzo_ptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr);
+
+typedef union
+{
+ char a_char;
+ unsigned char a_uchar;
+ short a_short;
+ unsigned short a_ushort;
+ int a_int;
+ unsigned int a_uint;
+ long a_long;
+ unsigned long a_ulong;
+ lzo_int a_lzo_int;
+ lzo_uint a_lzo_uint;
+ lzo_int32 a_lzo_int32;
+ lzo_uint32 a_lzo_uint32;
+ ptrdiff_t a_ptrdiff_t;
+ lzo_ptrdiff_t a_lzo_ptrdiff_t;
+ lzo_ptr_t a_lzo_ptr_t;
+ char * a_charp;
+ lzo_bytep a_lzo_bytep;
+ lzo_bytepp a_lzo_bytepp;
+}
+lzo_align_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#define LZO_DETERMINISTIC
+
+#define LZO_DICT_USE_PTR
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16) || defined(__LZO_STRICT_16BIT)
+# undef LZO_DICT_USE_PTR
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+# define lzo_dict_t const lzo_bytep
+# define lzo_dict_p lzo_dict_t __LZO_MMODEL *
+#else
+# define lzo_dict_t lzo_uint
+# define lzo_dict_p lzo_dict_t __LZO_MMODEL *
+#endif
+
+#if !defined(lzo_moff_t)
+#define lzo_moff_t lzo_uint
+#endif
+
+#endif
+
+LZO_PUBLIC(lzo_ptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr)
+{
+ lzo_ptr_t p;
+
+#if defined(__LZO_DOS16) || defined(__LZO_WIN16)
+ p = (((lzo_ptr_t)(_FP_SEG(ptr))) << (16 - __LZO_HShift)) + (_FP_OFF(ptr));
+#else
+ p = PTR_LINEAR(ptr);
+#endif
+
+ return p;
+}
+
+LZO_PUBLIC(unsigned)
+__lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+{
+ lzo_ptr_t p, s, n;
+
+ assert(size > 0);
+
+ p = __lzo_ptr_linear(ptr);
+ s = (lzo_ptr_t) (size - 1);
+#if 0
+ assert((size & (size - 1)) == 0);
+ n = ((p + s) & ~s) - p;
+#else
+ n = (((p + s) / size) * size) - p;
+#endif
+
+ assert((long)n >= 0);
+ assert(n <= s);
+
+ return (unsigned)n;
+}
+
+#ifndef __LZO_UTIL_H
+#define __LZO_UTIL_H
+
+#ifndef __LZO_CONF_H
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if 1 && defined(HAVE_MEMCPY)
+#if !defined(__LZO_DOS16) && !defined(__LZO_WIN16)
+
+#define MEMCPY8_DS(dest,src,len) \
+ memcpy(dest,src,len); \
+ dest += len; \
+ src += len
+
+#endif
+#endif
+
+#if 0 && !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+ { do { \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ len -= 8; \
+ } while (len > 0); }
+
+#endif
+
+#if !defined(MEMCPY8_DS)
+
+#define MEMCPY8_DS(dest,src,len) \
+ { register lzo_uint __l = (len) / 8; \
+ do { \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ *dest++ = *src++; \
+ } while (--__l > 0); }
+
+#endif
+
+#define MEMCPY_DS(dest,src,len) \
+ do *dest++ = *src++; \
+ while (--len > 0)
+
+#define MEMMOVE_DS(dest,src,len) \
+ do *dest++ = *src++; \
+ while (--len > 0)
+
+#if 0 && defined(LZO_OPTIMIZE_GNUC_i386)
+
+#define BZERO8_PTR(s,l,n) \
+__asm__ __volatile__( \
+ "movl %0,%%eax \n" \
+ "movl %1,%%edi \n" \
+ "movl %2,%%ecx \n" \
+ "cld \n" \
+ "rep \n" \
+ "stosl %%eax,(%%edi) \n" \
+ : \
+ :"g" (0),"g" (s),"g" (n) \
+ :"eax","edi","ecx", "memory", "cc" \
+)
+
+#elif (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
+
+#if 1
+#define BZERO8_PTR(s,l,n) memset((s),0,(lzo_uint)(l)*(n))
+#else
+#define BZERO8_PTR(s,l,n) memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+#endif
+
+#else
+
+#define BZERO8_PTR(s,l,n) \
+ lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+
+#endif
+
+#if 0
+#if defined(__GNUC__) && defined(__i386__)
+
+unsigned char lzo_rotr8(unsigned char value, int shift);
+extern __inline__ unsigned char lzo_rotr8(unsigned char value, int shift)
+{
+ unsigned char result;
+
+ __asm__ __volatile__ ("movb %b1, %b0; rorb %b2, %b0"
+ : "=a"(result) : "g"(value), "c"(shift));
+ return result;
+}
+
+unsigned short lzo_rotr16(unsigned short value, int shift);
+extern __inline__ unsigned short lzo_rotr16(unsigned short value, int shift)
+{
+ unsigned short result;
+
+ __asm__ __volatile__ ("movw %b1, %b0; rorw %b2, %b0"
+ : "=a"(result) : "g"(value), "c"(shift));
+ return result;
+}
+
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+LZO_PUBLIC(lzo_bool)
+lzo_assert(int expr)
+{
+ return (expr) ? 1 : 0;
+}
+
+/* If you use the LZO library in a product, you *must* keep this
+ * copyright string in the executable of your product.
+ */
+
+const lzo_byte __lzo_copyright[] =
+#if !defined(__LZO_IN_MINLZO)
+ LZO_VERSION_STRING;
+#else
+ "\n\n\n"
+ "LZO real-time data compression library.\n"
+ "Copyright (C) 1996, 1997, 1998, 1999 Markus Franz Xaver Johannes Oberhumer\n"
+ "<markus.oberhumer@jk.uni-linz.ac.at>\n"
+ "http://wildsau.idv.uni-linz.ac.at/mfx/lzo.html\n"
+ "\n"
+ "LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE "\n"
+ "LZO build date: " __DATE__ " " __TIME__ "\n\n"
+ "LZO special compilation options:\n"
+#ifdef __cplusplus
+ " __cplusplus\n"
+#endif
+#if defined(__PIC__)
+ " __PIC__\n"
+#elif defined(__pic__)
+ " __pic__\n"
+#endif
+#if (UINT_MAX < LZO_0xffffffffL)
+ " 16BIT\n"
+#endif
+#if defined(__LZO_STRICT_16BIT)
+ " __LZO_STRICT_16BIT\n"
+#endif
+#if (UINT_MAX > LZO_0xffffffffL)
+ " UINT_MAX=" _LZO_MEXPAND(UINT_MAX) "\n"
+#endif
+#if (ULONG_MAX > LZO_0xffffffffL)
+ " ULONG_MAX=" _LZO_MEXPAND(ULONG_MAX) "\n"
+#endif
+#if defined(LZO_BYTE_ORDER)
+ " LZO_BYTE_ORDER=" _LZO_MEXPAND(LZO_BYTE_ORDER) "\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_2)
+ " LZO_UNALIGNED_OK_2\n"
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+ " LZO_UNALIGNED_OK_4\n"
+#endif
+#if defined(LZO_ALIGNED_OK_4)
+ " LZO_ALIGNED_OK_4\n"
+#endif
+#if defined(LZO_DICT_USE_PTR)
+ " LZO_DICT_USE_PTR\n"
+#endif
+#if defined(__LZO_QUERY_COMPRESS)
+ " __LZO_QUERY_COMPRESS\n"
+#endif
+#if defined(__LZO_QUERY_DECOMPRESS)
+ " __LZO_QUERY_DECOMPRESS\n"
+#endif
+#if defined(__LZO_IN_MINILZO)
+ " __LZO_IN_MINILZO\n"
+#endif
+ "\n\n"
+ "$Id: LZO " LZO_VERSION_STRING " built " __DATE__ " " __TIME__
+#if defined(__GNUC__) && defined(__VERSION__)
+ " by gcc " __VERSION__
+#elif defined(__BORLANDC__)
+ " by Borland C " _LZO_MEXPAND(__BORLANDC__)
+#elif defined(_MSC_VER)
+ " by Microsoft C " _LZO_MEXPAND(_MSC_VER)
+#elif defined(__PUREC__)
+ " by Pure C " _LZO_MEXPAND(__PUREC__)
+#elif defined(__SC__)
+ " by Symantec C " _LZO_MEXPAND(__SC__)
+#elif defined(__TURBOC__)
+ " by Turbo C " _LZO_MEXPAND(__TURBOC__)
+#elif defined(__WATCOMC__)
+ " by Watcom C " _LZO_MEXPAND(__WATCOMC__)
+#endif
+ " $\n"
+ "$Copyright: LZO (C) 1996, 1997, 1998, 1999 Markus Franz Xaver Johannes Oberhumer $\n";
+#endif
+
+LZO_PUBLIC(const lzo_byte *)
+lzo_copyright(void)
+{
+ return __lzo_copyright;
+}
+
+LZO_PUBLIC(unsigned)
+lzo_version(void)
+{
+ return LZO_VERSION;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_string(void)
+{
+ return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_date(void)
+{
+ return LZO_VERSION_DATE;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_string(void)
+{
+ return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_date(void)
+{
+ return LZO_VERSION_DATE;
+}
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+LZO_PUBLIC(lzo_uint32)
+lzo_adler32(lzo_uint32 adler, const lzo_byte *buf, lzo_uint len)
+{
+ lzo_uint32 s1 = adler & 0xffff;
+ lzo_uint32 s2 = (adler >> 16) & 0xffff;
+ int k;
+
+ if (buf == NULL)
+ return 1;
+
+ while (len > 0)
+ {
+ k = len < LZO_NMAX ? (int) len : LZO_NMAX;
+ len -= k;
+ if (k >= 16) do
+ {
+ LZO_DO16(buf,0);
+ buf += 16;
+ k -= 16;
+ } while (k >= 16);
+ if (k != 0) do
+ {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k > 0);
+ s1 %= LZO_BASE;
+ s2 %= LZO_BASE;
+ }
+ return (s2 << 16) | s1;
+}
+
+LZO_PUBLIC(int)
+lzo_memcmp(const lzo_voidp s1, const lzo_voidp s2, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMCMP)
+ return memcmp(s1,s2,len);
+#else
+ const lzo_byte *p1 = (const lzo_byte *) s1;
+ const lzo_byte *p2 = (const lzo_byte *) s2;
+ int d;
+
+ if (len > 0) do
+ {
+ d = *p1 - *p2;
+ if (d != 0)
+ return d;
+ p1++;
+ p2++;
+ }
+ while (--len > 0);
+ return 0;
+#endif
+}
+
+LZO_PUBLIC(lzo_voidp)
+lzo_memcpy(lzo_voidp dest, const lzo_voidp src, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMCPY)
+ return memcpy(dest,src,len);
+#else
+ lzo_byte *p1 = (lzo_byte *) dest;
+ const lzo_byte *p2 = (const lzo_byte *) src;
+
+ if (len <= 0 || p1 == p2)
+ return dest;
+ do
+ *p1++ = *p2++;
+ while (--len > 0);
+ return dest;
+#endif
+}
+
+LZO_PUBLIC(lzo_voidp)
+lzo_memmove(lzo_voidp dest, const lzo_voidp src, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMMOVE)
+ return memmove(dest,src,len);
+#else
+ lzo_byte *p1 = (lzo_byte *) dest;
+ const lzo_byte *p2 = (const lzo_byte *) src;
+
+ if (len <= 0 || p1 == p2)
+ return dest;
+
+ if (p1 < p2)
+ {
+ do
+ *p1++ = *p2++;
+ while (--len > 0);
+ }
+ else
+ {
+ p1 += len;
+ p2 += len;
+ do
+ *--p1 = *--p2;
+ while (--len > 0);
+ }
+ return dest;
+#endif
+}
+
+LZO_PUBLIC(lzo_voidp)
+lzo_memset(lzo_voidp s, int c, lzo_uint len)
+{
+#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET)
+ return memset(s,c,len);
+#else
+ lzo_byte *p = (lzo_byte *) s;
+
+ if (len > 0) do
+ *p++ = LZO_BYTE(c);
+ while (--len > 0);
+ return s;
+#endif
+}
+
+#include <stdio.h>
+
+#if 0
+# define IS_SIGNED(type) (((type) (1ul << (8 * sizeof(type) - 1))) < 0)
+# define IS_UNSIGNED(type) (((type) (1ul << (8 * sizeof(type) - 1))) > 0)
+#else
+# define IS_SIGNED(type) (((type) (-1)) < ((type) 0))
+# define IS_UNSIGNED(type) (((type) (-1)) > ((type) 0))
+#endif
+
+static lzo_bool schedule_insns_bug(void);
+static lzo_bool strength_reduce_bug(int *);
+
+#if 0 || defined(LZO_DEBUG)
+static lzo_bool __lzo_assert_fail(const char *s, unsigned line)
+{
+#if defined(__palmos__)
+ printf("LZO assertion failed in line %u: '%s'\n",line,s);
+#else
+ fprintf(stderr,"LZO assertion failed in line %u: '%s'\n",line,s);
+#endif
+ return 0;
+}
+# define __lzo_assert(x) ((x) ? 1 : __lzo_assert_fail(#x,__LINE__))
+#else
+# define __lzo_assert(x) ((x) ? 1 : 0)
+#endif
+
+static lzo_bool basic_integral_check(void)
+{
+ lzo_bool r = 1;
+ lzo_bool sanity;
+
+ r &= __lzo_assert(CHAR_BIT == 8);
+ r &= __lzo_assert(sizeof(char) == 1);
+ r &= __lzo_assert(sizeof(short) >= 2);
+ r &= __lzo_assert(sizeof(long) >= 4);
+ r &= __lzo_assert(sizeof(int) >= sizeof(short));
+ r &= __lzo_assert(sizeof(long) >= sizeof(int));
+
+ r &= __lzo_assert(sizeof(lzo_uint32) >= 4);
+ r &= __lzo_assert(sizeof(lzo_uint32) >= sizeof(unsigned));
+#if defined(__LZO_STRICT_16BIT)
+ r &= __lzo_assert(sizeof(lzo_uint) == 2);
+#else
+ r &= __lzo_assert(sizeof(lzo_uint) >= 4);
+ r &= __lzo_assert(sizeof(lzo_uint) >= sizeof(unsigned));
+#endif
+
+#if defined(SIZEOF_UNSIGNED)
+ r &= __lzo_assert(SIZEOF_UNSIGNED == sizeof(unsigned));
+#endif
+#if defined(SIZEOF_UNSIGNED_LONG)
+ r &= __lzo_assert(SIZEOF_UNSIGNED_LONG == sizeof(unsigned long));
+#endif
+#if defined(SIZEOF_UNSIGNED_SHORT)
+ r &= __lzo_assert(SIZEOF_UNSIGNED_SHORT == sizeof(unsigned short));
+#endif
+#if !defined(__LZO_IN_MINILZO)
+#if defined(SIZEOF_SIZE_T)
+ r &= __lzo_assert(SIZEOF_SIZE_T == sizeof(size_t));
+#endif
+#endif
+
+ sanity = IS_UNSIGNED(unsigned short) && IS_UNSIGNED(unsigned) &&
+ IS_UNSIGNED(unsigned long) &&
+ IS_SIGNED(short) && IS_SIGNED(int) && IS_SIGNED(long);
+ if (sanity)
+ {
+ r &= __lzo_assert(IS_UNSIGNED(lzo_uint32));
+ r &= __lzo_assert(IS_UNSIGNED(lzo_uint));
+ r &= __lzo_assert(IS_SIGNED(lzo_int32));
+ r &= __lzo_assert(IS_SIGNED(lzo_int));
+
+ r &= __lzo_assert(INT_MAX == LZO_STYPE_MAX(sizeof(int)));
+ r &= __lzo_assert(UINT_MAX == LZO_UTYPE_MAX(sizeof(unsigned)));
+ r &= __lzo_assert(LONG_MAX == LZO_STYPE_MAX(sizeof(long)));
+ r &= __lzo_assert(ULONG_MAX == LZO_UTYPE_MAX(sizeof(unsigned long)));
+ r &= __lzo_assert(SHRT_MAX == LZO_STYPE_MAX(sizeof(short)));
+ r &= __lzo_assert(USHRT_MAX == LZO_UTYPE_MAX(sizeof(unsigned short)));
+ r &= __lzo_assert(LZO_UINT32_MAX == LZO_UTYPE_MAX(sizeof(lzo_uint32)));
+ r &= __lzo_assert(LZO_UINT_MAX == LZO_UTYPE_MAX(sizeof(lzo_uint)));
+#if !defined(__LZO_IN_MINILZO)
+ r &= __lzo_assert(SIZE_T_MAX == LZO_UTYPE_MAX(sizeof(size_t)));
+#endif
+ }
+
+#if 0
+ r &= __lzo_assert(LZO_BYTE(257) == 1);
+ r &= __lzo_assert(LZO_USHORT(65537L) == 1);
+#endif
+
+ return r;
+}
+
+static lzo_bool basic_ptr_check(void)
+{
+ lzo_bool r = 1;
+ lzo_bool sanity;
+
+ r &= __lzo_assert(sizeof(char *) >= sizeof(int));
+ r &= __lzo_assert(sizeof(lzo_byte *) >= sizeof(char *));
+
+ r &= __lzo_assert(sizeof(lzo_voidp) == sizeof(lzo_byte *));
+ r &= __lzo_assert(sizeof(lzo_voidp) == sizeof(lzo_voidpp));
+ r &= __lzo_assert(sizeof(lzo_voidp) == sizeof(lzo_bytepp));
+ r &= __lzo_assert(sizeof(lzo_voidp) >= sizeof(lzo_uint));
+
+ r &= __lzo_assert(sizeof(lzo_ptr_t) == sizeof(lzo_voidp));
+ r &= __lzo_assert(sizeof(lzo_ptr_t) >= sizeof(lzo_uint));
+
+ r &= __lzo_assert(sizeof(lzo_ptrdiff_t) >= 4);
+ r &= __lzo_assert(sizeof(lzo_ptrdiff_t) >= sizeof(ptrdiff_t));
+
+#if defined(SIZEOF_CHAR_P)
+ r &= __lzo_assert(SIZEOF_CHAR_P == sizeof(char *));
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+ r &= __lzo_assert(SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t));
+#endif
+
+ sanity = IS_UNSIGNED(unsigned short) && IS_UNSIGNED(unsigned) &&
+ IS_UNSIGNED(unsigned long) &&
+ IS_SIGNED(short) && IS_SIGNED(int) && IS_SIGNED(long);
+ if (sanity)
+ {
+ r &= __lzo_assert(IS_UNSIGNED(lzo_ptr_t));
+ r &= __lzo_assert(IS_UNSIGNED(lzo_moff_t));
+ r &= __lzo_assert(IS_SIGNED(lzo_ptrdiff_t));
+ r &= __lzo_assert(IS_SIGNED(lzo_sptr_t));
+ }
+
+ return r;
+}
+
+static lzo_bool ptr_check(void)
+{
+ lzo_bool r = 1;
+ int i;
+ char _wrkmem[10 * sizeof(lzo_byte *) + sizeof(lzo_align_t)];
+ lzo_byte *wrkmem;
+ const lzo_bytepp dict;
+ unsigned char x[4 * sizeof(lzo_align_t)];
+ long d;
+ lzo_align_t a;
+
+ for (i = 0; i < (int) sizeof(x); i++)
+ x[i] = LZO_BYTE(i);
+
+ wrkmem = (lzo_byte *) LZO_PTR_ALIGN_UP(_wrkmem,sizeof(lzo_align_t));
+ dict = (const lzo_bytepp) wrkmem;
+
+ d = (long) ((const lzo_bytep) dict - (const lzo_bytep) _wrkmem);
+ r &= __lzo_assert(d >= 0);
+ r &= __lzo_assert(d < (long) sizeof(lzo_align_t));
+
+ memset(&a,0xff,sizeof(a));
+ r &= __lzo_assert(a.a_ushort == USHRT_MAX);
+ r &= __lzo_assert(a.a_uint == UINT_MAX);
+ r &= __lzo_assert(a.a_ulong == ULONG_MAX);
+ r &= __lzo_assert(a.a_lzo_uint == LZO_UINT_MAX);
+
+ if (r == 1)
+ {
+ for (i = 0; i < 8; i++)
+ r &= __lzo_assert((const lzo_voidp) (&dict[i]) == (const lzo_voidp) (&wrkmem[i * sizeof(lzo_byte *)]));
+ }
+
+ memset(&a,0,sizeof(a));
+ r &= __lzo_assert(a.a_charp == NULL);
+ r &= __lzo_assert(a.a_lzo_bytep == NULL);
+ r &= __lzo_assert(NULL == 0);
+ if (r == 1)
+ {
+ for (i = 0; i < 10; i++)
+ dict[i] = wrkmem;
+ BZERO8_PTR(dict+1,sizeof(dict[0]),8);
+ r &= __lzo_assert(dict[0] == wrkmem);
+ for (i = 1; i < 9; i++)
+ r &= __lzo_assert(dict[i] == NULL);
+ r &= __lzo_assert(dict[9] == wrkmem);
+ }
+
+ if (r == 1)
+ {
+ unsigned k = 1;
+ const unsigned n = (unsigned) sizeof(lzo_uint32);
+ lzo_byte *p0;
+ lzo_byte *p1;
+
+ k += __lzo_align_gap(&x[k],n);
+ p0 = (lzo_bytep) &x[k];
+#if defined(PTR_LINEAR)
+ r &= __lzo_assert((PTR_LINEAR(p0) & (n-1)) == 0);
+#else
+ r &= __lzo_assert(n == 4);
+ r &= __lzo_assert(PTR_ALIGNED_4(p0));
+#endif
+
+ r &= __lzo_assert(k >= 1);
+ p1 = (lzo_bytep) &x[1];
+ r &= __lzo_assert(PTR_GE(p0,p1));
+
+ r &= __lzo_assert(k < 1+n);
+ p1 = (lzo_bytep) &x[1+n];
+ r &= __lzo_assert(PTR_LT(p0,p1));
+
+ if (r == 1)
+ {
+ lzo_uint32 v0 = * (lzo_uint32 *) &x[k];
+ lzo_uint32 v1 = * (lzo_uint32 *) &x[k+n];
+
+ r &= __lzo_assert(v0 > 0);
+ r &= __lzo_assert(v1 > 0);
+ }
+ }
+
+ return r;
+}
+
+LZO_PUBLIC(int)
+_lzo_config_check(void)
+{
+ lzo_bool r = 1;
+ int i;
+ union {
+ lzo_uint32 a;
+ unsigned short b;
+ lzo_uint32 aa[4];
+ unsigned char x[4*sizeof(lzo_align_t)];
+ } u;
+
+#if 0
+ r &= __lzo_assert((const void *)&u == (const void *)&u.a);
+ r &= __lzo_assert((const void *)&u == (const void *)&u.b);
+ r &= __lzo_assert((const void *)&u == (const void *)&u.x[0]);
+ r &= __lzo_assert((const void *)&u == (const void *)&u.aa[0]);
+#endif
+
+ r &= basic_integral_check();
+ r &= basic_ptr_check();
+ if (r != 1)
+ return LZO_E_ERROR;
+
+ for (i = 0; i < (int) sizeof(u.x); i++)
+ u.x[i] = LZO_BYTE(i);
+
+#if 0
+ r &= __lzo_assert( (int) (unsigned char) ((char) -1) == 255);
+#endif
+
+#if defined(LZO_BYTE_ORDER)
+ if (r == 1)
+ {
+# if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ lzo_uint32 a = (lzo_uint32) (u.a & LZO_0xffffffffL);
+ unsigned short b = (unsigned short) (u.b & 0xffff);
+ r &= __lzo_assert(a == 0x03020100L);
+ r &= __lzo_assert(b == 0x0100);
+# elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+ lzo_uint32 a = u.a >> (8 * sizeof(u.a) - 32);
+ unsigned short b = u.b >> (8 * sizeof(u.b) - 16);
+ r &= __lzo_assert(a == 0x00010203L);
+ r &= __lzo_assert(b == 0x0001);
+# else
+# error invalid LZO_BYTE_ORDER
+# endif
+ }
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2)
+ r &= __lzo_assert(sizeof(short) == 2);
+ if (r == 1)
+ {
+ unsigned short b[4];
+
+ for (i = 0; i < 4; i++)
+ b[i] = * (const unsigned short *) &u.x[i];
+
+# if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ r &= __lzo_assert(b[0] == 0x0100);
+ r &= __lzo_assert(b[1] == 0x0201);
+ r &= __lzo_assert(b[2] == 0x0302);
+ r &= __lzo_assert(b[3] == 0x0403);
+# elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+ r &= __lzo_assert(b[0] == 0x0001);
+ r &= __lzo_assert(b[1] == 0x0102);
+ r &= __lzo_assert(b[2] == 0x0203);
+ r &= __lzo_assert(b[3] == 0x0304);
+# endif
+ }
+#endif
+
+#if defined(LZO_UNALIGNED_OK_4)
+ r &= __lzo_assert(sizeof(lzo_uint32) == 4);
+ if (r == 1)
+ {
+ lzo_uint32 a[4];
+
+ for (i = 0; i < 4; i++)
+ a[i] = * (const lzo_uint32 *) &u.x[i];
+
+# if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ r &= __lzo_assert(a[0] == 0x03020100L);
+ r &= __lzo_assert(a[1] == 0x04030201L);
+ r &= __lzo_assert(a[2] == 0x05040302L);
+ r &= __lzo_assert(a[3] == 0x06050403L);
+# elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN)
+ r &= __lzo_assert(a[0] == 0x00010203L);
+ r &= __lzo_assert(a[1] == 0x01020304L);
+ r &= __lzo_assert(a[2] == 0x02030405L);
+ r &= __lzo_assert(a[3] == 0x03040506L);
+# endif
+ }
+#endif
+
+#if defined(LZO_ALIGNED_OK_4)
+ r &= __lzo_assert(sizeof(lzo_uint32) == 4);
+#endif
+
+ r &= __lzo_assert(lzo_sizeof_dict_t == sizeof(lzo_dict_t));
+
+#if defined(__LZO_IN_MINLZO)
+ if (r == 1)
+ {
+ lzo_uint32 adler;
+ adler = lzo_adler32(0, NULL, 0);
+ adler = lzo_adler32(adler, lzo_copyright(), 200);
+ r &= __lzo_assert(adler == 0x7ea34377L);
+ }
+#endif
+
+ if (r == 1)
+ {
+ r &= __lzo_assert(!schedule_insns_bug());
+ }
+
+ if (r == 1)
+ {
+ static int x[3];
+ static unsigned xn = 3;
+ register unsigned j;
+
+ for (j = 0; j < xn; j++)
+ x[j] = (int)j - 3;
+ r &= __lzo_assert(!strength_reduce_bug(x));
+ }
+
+ if (r == 1)
+ {
+ r &= ptr_check();
+ }
+
+ return r == 1 ? LZO_E_OK : LZO_E_ERROR;
+}
+
+static lzo_bool schedule_insns_bug(void)
+{
+#if defined(__BOUNDS_CHECKING_ON) || defined(__CHECKER__)
+ return 0;
+#else
+ const int clone[] = {1, 2, 0};
+ const int *q;
+ q = clone;
+ return (*q) ? 0 : 1;
+#endif
+}
+
+static lzo_bool strength_reduce_bug(int *x)
+{
+ return x[0] != -3 || x[1] != -2 || x[2] != -1;
+}
+
+int __lzo_init_done = 0;
+
+LZO_PUBLIC(int)
+__lzo_init2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+ int s6, int s7, int s8, int s9)
+{
+ int r;
+
+ __lzo_init_done = 1;
+
+ if (v == 0)
+ return LZO_E_ERROR;
+
+ r = (s1 == -1 || s1 == (int) sizeof(short)) &&
+ (s2 == -1 || s2 == (int) sizeof(int)) &&
+ (s3 == -1 || s3 == (int) sizeof(long)) &&
+ (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) &&
+ (s5 == -1 || s5 == (int) sizeof(lzo_uint)) &&
+ (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) &&
+ (s7 == -1 || s7 == (int) sizeof(char *)) &&
+ (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) &&
+ (s9 == -1 || s9 == (int) sizeof(lzo_compress_t));
+ if (!r)
+ return LZO_E_ERROR;
+
+ r = _lzo_config_check();
+ if (r != LZO_E_OK)
+ return r;
+
+ return r;
+}
+
+#if !defined(__LZO_IN_MINILZO)
+
+LZO_EXTERN(int)
+__lzo_init(unsigned v,int s1,int s2,int s3,int s4,int s5,int s6,int s7);
+
+LZO_PUBLIC(int)
+__lzo_init(unsigned v,int s1,int s2,int s3,int s4,int s5,int s6,int s7)
+{
+ if (v == 0 || v > 0x1010)
+ return LZO_E_ERROR;
+ return __lzo_init2(v,s1,s2,s3,s4,s5,-1,-1,s6,s7);
+}
+
+#endif
+
+#define do_compress _lzo1x_1_do_compress
+
+#define LZO_NEED_DICT_H
+#define D_BITS 14
+#define D_INDEX1(d,p) d = DM((0x21*DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#ifndef __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H
+
+#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
+# define LZO1X
+#endif
+
+#if !defined(__LZO_IN_MINILZO)
+#include <lzo1x.h>
+#endif
+
+#define LZO_EOF_CODE
+#undef LZO_DETERMINISTIC
+
+#define M1_MAX_OFFSET 0x0400
+#ifndef M2_MAX_OFFSET
+#define M2_MAX_OFFSET 0x0800
+#endif
+#define M3_MAX_OFFSET 0x4000
+#define M4_MAX_OFFSET 0xbfff
+
+#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
+
+#define M1_MIN_LEN 2
+#define M1_MAX_LEN 2
+#define M2_MIN_LEN 3
+#ifndef M2_MAX_LEN
+#define M2_MAX_LEN 8
+#endif
+#define M3_MIN_LEN 3
+#define M3_MAX_LEN 33
+#define M4_MIN_LEN 3
+#define M4_MAX_LEN 9
+
+#define M1_MARKER 0
+#define M2_MARKER 64
+#define M3_MARKER 32
+#define M4_MARKER 16
+
+#ifndef MIN_LOOKAHEAD
+#define MIN_LOOKAHEAD (M2_MAX_LEN + 1)
+#endif
+
+#if defined(LZO_NEED_DICT_H)
+
+#ifndef LZO_HASH
+#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B
+#endif
+#define DL_MIN_LEN M2_MIN_LEN
+
+#ifndef __LZO_DICT_H
+#define __LZO_DICT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(D_BITS) && defined(DBITS)
+# define D_BITS DBITS
+#endif
+#if !defined(D_BITS)
+# error D_BITS is not defined
+#endif
+#if (D_BITS < 16)
+# define D_SIZE LZO_SIZE(D_BITS)
+# define D_MASK LZO_MASK(D_BITS)
+#else
+# define D_SIZE LZO_USIZE(D_BITS)
+# define D_MASK LZO_UMASK(D_BITS)
+#endif
+#define D_HIGH ((D_MASK >> 1) + 1)
+
+#if !defined(DD_BITS)
+# define DD_BITS 0
+#endif
+#define DD_SIZE LZO_SIZE(DD_BITS)
+#define DD_MASK LZO_MASK(DD_BITS)
+
+#if !defined(DL_BITS)
+# define DL_BITS (D_BITS - DD_BITS)
+#endif
+#if (DL_BITS < 16)
+# define DL_SIZE LZO_SIZE(DL_BITS)
+# define DL_MASK LZO_MASK(DL_BITS)
+#else
+# define DL_SIZE LZO_USIZE(DL_BITS)
+# define DL_MASK LZO_UMASK(DL_BITS)
+#endif
+
+#if (D_BITS != DL_BITS + DD_BITS)
+# error D_BITS does not match
+#endif
+#if (D_BITS < 8 || D_BITS > 18)
+# error invalid D_BITS
+#endif
+#if (DL_BITS < 8 || DL_BITS > 20)
+# error invalid DL_BITS
+#endif
+#if (DD_BITS < 0 || DD_BITS > 6)
+# error invalid DD_BITS
+#endif
+
+#if !defined(DL_MIN_LEN)
+# define DL_MIN_LEN 3
+#endif
+#if !defined(DL_SHIFT)
+# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
+#endif
+
+#define LZO_HASH_GZIP 1
+#define LZO_HASH_GZIP_INCREMENTAL 2
+#define LZO_HASH_LZO_INCREMENTAL_A 3
+#define LZO_HASH_LZO_INCREMENTAL_B 4
+
+#if !defined(LZO_HASH)
+# error choose a hashing strategy
+#endif
+
+#if (DL_MIN_LEN == 3)
+# define _DV2_A(p,shift1,shift2) \
+ (((( (lzo_uint32)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
+# define _DV2_B(p,shift1,shift2) \
+ (((( (lzo_uint32)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
+# define _DV3_B(p,shift1,shift2,shift3) \
+ ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
+#elif (DL_MIN_LEN == 2)
+# define _DV2_A(p,shift1,shift2) \
+ (( (lzo_uint32)(p[0]) << shift1) ^ p[1])
+# define _DV2_B(p,shift1,shift2) \
+ (( (lzo_uint32)(p[1]) << shift1) ^ p[2])
+#else
+# error invalid DL_MIN_LEN
+#endif
+#define _DV_A(p,shift) _DV2_A(p,shift,shift)
+#define _DV_B(p,shift) _DV2_B(p,shift,shift)
+#define DA2(p,s1,s2) \
+ (((((lzo_uint32)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
+#define DS2(p,s1,s2) \
+ (((((lzo_uint32)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
+#define DX2(p,s1,s2) \
+ (((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v) DMS(v,0)
+
+#if (LZO_HASH == LZO_HASH_GZIP)
+# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT))
+
+#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
+# define __LZO_HASH_INCREMENTAL
+# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT)
+# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2])
+# define _DINDEX(dv,p) (dv)
+# define DVAL_LOOKAHEAD DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
+# define __LZO_HASH_INCREMENTAL
+# define DVAL_FIRST(dv,p) dv = _DV_A((p),5)
+# define DVAL_NEXT(dv,p) \
+ dv ^= (lzo_uint32)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
+# define _DINDEX(dv,p) ((0x9f5f * (dv)) >> 5)
+# define DVAL_LOOKAHEAD DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
+# define __LZO_HASH_INCREMENTAL
+# define DVAL_FIRST(dv,p) dv = _DV_B((p),5)
+# define DVAL_NEXT(dv,p) \
+ dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint32)(p[2]) << (2*5)))
+# define _DINDEX(dv,p) ((0x9f5f * (dv)) >> 5)
+# define DVAL_LOOKAHEAD DL_MIN_LEN
+
+#else
+# error choose a hashing strategy
+#endif
+
+#ifndef DINDEX
+#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
+#endif
+#if !defined(DINDEX1) && defined(D_INDEX1)
+#define DINDEX1 D_INDEX1
+#endif
+#if !defined(DINDEX2) && defined(D_INDEX2)
+#define DINDEX2 D_INDEX2
+#endif
+
+#if !defined(__LZO_HASH_INCREMENTAL)
+# define DVAL_FIRST(dv,p) ((void) 0)
+# define DVAL_NEXT(dv,p) ((void) 0)
+# define DVAL_LOOKAHEAD 0
+#endif
+
+#if !defined(DVAL_ASSERT)
+#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+static void DVAL_ASSERT(lzo_uint32 dv, const lzo_byte *p)
+{
+ lzo_uint32 df;
+ DVAL_FIRST(df,(p));
+ assert(DINDEX(dv,p) == DINDEX(df,p));
+}
+#else
+# define DVAL_ASSERT(dv,p) ((void) 0)
+#endif
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+# define DENTRY(p,in) (p)
+# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
+#else
+# define DENTRY(p,in) ((lzo_uint) ((p)-(in)))
+# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex]
+#endif
+
+#if (DD_BITS == 0)
+
+# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in)
+# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in)
+# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in)
+
+#else
+
+# define UPDATE_D(dict,drun,dv,p,in) \
+ dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+# define UPDATE_I(dict,drun,index,p,in) \
+ dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+# define UPDATE_P(ptr,drun,p,in) \
+ (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
+
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+ (m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+ (BOUNDS_CHECKING_OFF_IN_EXPR( \
+ (PTR_LT(m_pos,in) || \
+ (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
+ m_off > max_offset) ))
+
+#else
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+ (m_off == 0 || \
+ ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+ (m_pos = (ip) - (m_off), 0) )
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+ ((lzo_moff_t) ((ip)-(in)) <= m_off || \
+ ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \
+ (m_pos = (ip) - (m_off), 0) )
+
+#endif
+
+#if defined(LZO_DETERMINISTIC)
+# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET
+#else
+# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
+#endif
+
+#define DO_COMPRESS lzo1x_1_compress
+
+static
+lzo_uint do_compress ( const lzo_byte *in , lzo_uint in_len,
+ lzo_byte *out, lzo_uint *out_len,
+ lzo_voidp wrkmem )
+{
+#if 0 && defined(__GNUC__) && defined(__i386__)
+ register const lzo_byte *ip __asm__("%esi");
+#else
+ register const lzo_byte *ip;
+#endif
+ lzo_byte *op;
+ const lzo_byte * const in_end = in + in_len;
+ const lzo_byte * const ip_end = in + in_len - M2_MAX_LEN - 5;
+ const lzo_byte *ii;
+ lzo_dict_p const dict = (lzo_dict_p) wrkmem;
+
+ op = out;
+ ip = in;
+ ii = ip;
+
+ ip += 4;
+ for (;;)
+ {
+#if 0 && defined(__GNUC__) && defined(__i386__)
+ register const lzo_byte *m_pos __asm__("%edi");
+#else
+ register const lzo_byte *m_pos;
+#endif
+ lzo_moff_t m_off;
+ lzo_uint m_len;
+ lzo_uint dindex;
+
+ DINDEX1(dindex,ip);
+ GINDEX(m_pos,m_off,dict,dindex,in);
+ if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+ goto literal;
+#if 1
+ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+ goto try_match;
+ DINDEX2(dindex,ip);
+#endif
+ GINDEX(m_pos,m_off,dict,dindex,in);
+ if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+ goto literal;
+ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+ goto try_match;
+ goto literal;
+
+try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+ if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+ if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+ {
+ }
+ else
+ {
+ if (m_pos[2] == ip[2])
+ {
+#if 0
+ if (m_off <= M2_MAX_OFFSET)
+ goto match;
+ if (lit <= 3)
+ goto match;
+ if (lit == 3)
+ {
+ assert(op - 2 > out); op[-2] |= LZO_BYTE(3);
+ *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
+ goto code_match;
+ }
+ if (m_pos[3] == ip[3])
+#endif
+ goto match;
+ }
+ else
+ {
+#if 0
+#if 0
+ if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+#else
+ if (m_off <= M1_MAX_OFFSET && lit == 3)
+#endif
+ {
+ register lzo_uint t;
+
+ t = lit;
+ assert(op - 2 > out); op[-2] |= LZO_BYTE(t);
+ do *op++ = *ii++; while (--t > 0);
+ assert(ii == ip);
+ m_off -= 1;
+ *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2));
+ *op++ = LZO_BYTE(m_off >> 2);
+ ip += 2;
+ goto match_done;
+ }
+#endif
+ }
+ }
+
+literal:
+ UPDATE_I(dict,0,dindex,ip,in);
+ ++ip;
+ if (ip >= ip_end)
+ break;
+ continue;
+
+match:
+ UPDATE_I(dict,0,dindex,ip,in);
+ if (ip - ii > 0)
+ {
+ register lzo_uint t = ip - ii;
+
+ if (t <= 3)
+ {
+ assert(op - 2 > out);
+ op[-2] |= LZO_BYTE(t);
+ }
+ else if (t <= 18)
+ *op++ = LZO_BYTE(t - 3);
+ else
+ {
+ register lzo_uint tt = t - 18;
+
+ *op++ = 0;
+ while (tt > 255)
+ {
+ tt -= 255;
+ *op++ = 0;
+ }
+ assert(tt > 0);
+ *op++ = LZO_BYTE(tt);
+ }
+ do *op++ = *ii++; while (--t > 0);
+ }
+
+ assert(ii == ip);
+ ip += 3;
+ if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
+ m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
+#ifdef LZO1Y
+ || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
+ || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+ )
+ {
+ --ip;
+ m_len = ip - ii;
+ assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
+
+ if (m_off <= M2_MAX_OFFSET)
+ {
+ m_off -= 1;
+#if defined(LZO1X)
+ *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+ *op++ = LZO_BYTE(m_off >> 3);
+#elif defined(LZO1Y)
+ *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
+ *op++ = LZO_BYTE(m_off >> 2);
+#endif
+ }
+ else if (m_off <= M3_MAX_OFFSET)
+ {
+ m_off -= 1;
+ *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+ goto m3_m4_offset;
+ }
+ else
+#if defined(LZO1X)
+ {
+ m_off -= 0x4000;
+ assert(m_off > 0); assert(m_off <= 0x7fff);
+ *op++ = LZO_BYTE(M4_MARKER |
+ ((m_off & 0x4000) >> 11) | (m_len - 2));
+ goto m3_m4_offset;
+ }
+#elif defined(LZO1Y)
+ goto m4_match;
+#endif
+ }
+ else
+ {
+ {
+ const lzo_byte *end = in_end;
+ const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
+ while (ip < end && *m == *ip)
+ m++, ip++;
+ m_len = (ip - ii);
+ }
+ assert(m_len > M2_MAX_LEN);
+
+ if (m_off <= M3_MAX_OFFSET)
+ {
+ m_off -= 1;
+ if (m_len <= 33)
+ *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+ else
+ {
+ m_len -= 33;
+ *op++ = M3_MARKER | 0;
+ goto m3_m4_len;
+ }
+ }
+ else
+ {
+#if defined(LZO1Y)
+m4_match:
+#endif
+ m_off -= 0x4000;
+ assert(m_off > 0); assert(m_off <= 0x7fff);
+ if (m_len <= M4_MAX_LEN)
+ *op++ = LZO_BYTE(M4_MARKER |
+ ((m_off & 0x4000) >> 11) | (m_len - 2));
+ else
+ {
+ m_len -= M4_MAX_LEN;
+ *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
+m3_m4_len:
+ while (m_len > 255)
+ {
+ m_len -= 255;
+ *op++ = 0;
+ }
+ assert(m_len > 0);
+ *op++ = LZO_BYTE(m_len);
+ }
+ }
+
+m3_m4_offset:
+ *op++ = LZO_BYTE((m_off & 63) << 2);
+ *op++ = LZO_BYTE(m_off >> 6);
+ }
+
+#if 0
+match_done:
+#endif
+ ii = ip;
+ if (ip >= ip_end)
+ break;
+ }
+
+ *out_len = op - out;
+ return (lzo_uint) (in_end - ii);
+}
+
+LZO_PUBLIC(int)
+DO_COMPRESS ( const lzo_byte *in , lzo_uint in_len,
+ lzo_byte *out, lzo_uint *out_len,
+ lzo_voidp wrkmem )
+{
+ lzo_byte *op = out;
+ lzo_uint t;
+
+#if defined(__LZO_QUERY_COMPRESS)
+ if (__LZO_IS_COMPRESS_QUERY(in,in_len,out,out_len,wrkmem))
+ return __LZO_QUERY_COMPRESS(in,in_len,out,out_len,wrkmem,D_SIZE,lzo_sizeof(lzo_dict_t));
+#endif
+
+ if (in_len <= M2_MAX_LEN + 5)
+ t = in_len;
+ else
+ {
+ t = do_compress(in,in_len,op,out_len,wrkmem);
+ op += *out_len;
+ }
+
+ if (t > 0)
+ {
+ const lzo_byte *ii = in + in_len - t;
+
+ if (op == out && t <= 238)
+ *op++ = LZO_BYTE(17 + t);
+ else if (t <= 3)
+ op[-2] |= LZO_BYTE(t);
+ else if (t <= 18)
+ *op++ = LZO_BYTE(t - 3);
+ else
+ {
+ lzo_uint tt = t - 18;
+
+ *op++ = 0;
+ while (tt > 255)
+ {
+ tt -= 255;
+ *op++ = 0;
+ }
+ assert(tt > 0);
+ *op++ = LZO_BYTE(tt);
+ }
+ do *op++ = *ii++; while (--t > 0);
+ }
+
+ *op++ = M4_MARKER | 1;
+ *op++ = 0;
+ *op++ = 0;
+
+ *out_len = op - out;
+ return LZO_E_OK;
+}
+
+#undef do_compress
+#undef DO_COMPRESS
+#undef LZO_HASH
+
+#undef LZO_TEST_DECOMPRESS_OVERRUN
+#undef LZO_TEST_DECOMPRESS_OVERRUN_INPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT
+#undef LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS lzo1x_decompress
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+# define LZO_TEST_DECOMPRESS_OVERRUN_INPUT 2
+# endif
+# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+# define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT 2
+# endif
+# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+# define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+# endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+# define TEST_IP (ip < ip_end)
+# endif
+# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+# define NEED_IP(x) \
+ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+# define TEST_OP (op <= op_end)
+# endif
+# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+# undef TEST_OP
+# define NEED_OP(x) \
+ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+# define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun
+#else
+# define TEST_LOOKBEHIND(m_pos,op) ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+# define TEST_IP (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+# define HAVE_TEST_IP
+#else
+# define TEST_IP 1
+#endif
+#if defined(TEST_OP)
+# define HAVE_TEST_OP
+#else
+# define TEST_OP 1
+#endif
+
+#if defined(NEED_IP)
+# define HAVE_NEED_IP
+#else
+# define NEED_IP(x) ((void) 0)
+#endif
+#if defined(NEED_OP)
+# define HAVE_NEED_OP
+#else
+# define NEED_OP(x) ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+# define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+# define HAVE_ANY_OP
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS ( const lzo_byte *in , lzo_uint in_len,
+ lzo_byte *out, lzo_uint *out_len,
+ lzo_voidp wrkmem )
+#endif
+{
+ register lzo_byte *op;
+ register const lzo_byte *ip;
+ register lzo_uint t;
+#if defined(COPY_DICT)
+ lzo_uint m_off;
+ const lzo_byte *dict_end;
+#else
+ register const lzo_byte *m_pos;
+#endif
+
+ const lzo_byte * const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+ lzo_byte * const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+ lzo_uint last_m_off = 0;
+#endif
+
+ LZO_UNUSED(wrkmem);
+
+#if defined(__LZO_QUERY_DECOMPRESS)
+ if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem))
+ return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0);
+#endif
+
+#if defined(COPY_DICT)
+ if (dict)
+ {
+ if (dict_len > M4_MAX_OFFSET)
+ {
+ dict += dict_len - M4_MAX_OFFSET;
+ dict_len = M4_MAX_OFFSET;
+ }
+ dict_end = dict + dict_len;
+ }
+ else
+ {
+ dict_len = 0;
+ dict_end = NULL;
+ }
+#endif
+
+ *out_len = 0;
+
+ op = out;
+ ip = in;
+
+ if (*ip > 17)
+ {
+ t = *ip++ - 17;
+ if (t < 4)
+ goto match_next;
+ assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+ do *op++ = *ip++; while (--t > 0);
+ goto first_literal_run;
+ }
+
+ while (TEST_IP && TEST_OP)
+ {
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 15 + *ip++;
+ }
+ assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (PTR_ALIGNED2_4(op,ip))
+ {
+#endif
+ * (lzo_uint32p) op = * (const lzo_uint32p) ip;
+ op += 4; ip += 4;
+ if (--t > 0)
+ {
+ if (t >= 4)
+ {
+ do {
+ * (lzo_uint32p) op = * (const lzo_uint32p) ip;
+ op += 4; ip += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *ip++; while (--t > 0);
+ }
+ else
+ do *op++ = *ip++; while (--t > 0);
+ }
+#if !defined(LZO_UNALIGNED_OK_4)
+ }
+ else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+ {
+ *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+ do *op++ = *ip++; while (--t > 0);
+ }
+#endif
+
+first_literal_run:
+
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(3);
+ t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - (1 + M2_MAX_OFFSET);
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LOOKBEHIND(m_pos,out); NEED_OP(3);
+ *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+
+ while (TEST_IP && TEST_OP)
+ {
+match:
+ if (t >= 64)
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+ m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ m_off = t & 0x1f;
+ if (m_off >= 0x1c)
+ m_off = last_m_off;
+ else
+ {
+ m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+ }
+ t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 7;
+ m_pos -= *ip++ << 3;
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 3;
+ m_pos -= *ip++ << 2;
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ {
+ lzo_uint off = t & 0x1f;
+ m_pos = op;
+ if (off >= 0x1c)
+ {
+ assert(last_m_off > 0);
+ m_pos -= last_m_off;
+ }
+ else
+ {
+ off = 1 + (off << 6) + (*ip++ >> 2);
+ m_pos -= off;
+ last_m_off = off;
+ }
+ }
+ t = (t >> 5) - 1;
+#endif
+ TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+ goto copy_match;
+#endif
+ }
+ else if (t >= 32)
+ {
+ t &= 31;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 31 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+ {
+ lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ m_pos = op - off;
+ last_m_off = off;
+ }
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ m_pos = op - 1;
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos = op - 1;
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+ ip += 2;
+ }
+ else if (t >= 16)
+ {
+#if defined(COPY_DICT)
+ m_off = (t & 8) << 11;
+#else
+ m_pos = op;
+ m_pos -= (t & 8) << 11;
+#endif
+ t &= 7;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 7 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+ m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_off == 0)
+ goto eof_found;
+ m_off += 0x4000;
+#if defined(LZO1Z)
+ last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+ m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_pos == op)
+ goto eof_found;
+ m_pos -= 0x4000;
+#if defined(LZO1Z)
+ last_m_off = op - m_pos;
+#endif
+#endif
+ }
+ else
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(2);
+ t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = 1 + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - 1;
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LOOKBEHIND(m_pos,out); NEED_OP(2);
+ *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+ }
+
+#if defined(COPY_DICT)
+
+ NEED_OP(t+3-1);
+ t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+ TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+ {
+ assert((op - m_pos) >= 4);
+#else
+ if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+ {
+#endif
+ * (lzo_uint32p) op = * (const lzo_uint32p) m_pos;
+ op += 4; m_pos += 4; t -= 4 - (3 - 1);
+ do {
+ * (lzo_uint32p) op = * (const lzo_uint32p) m_pos;
+ op += 4; m_pos += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+ }
+ else
+#endif
+ {
+copy_match:
+ *op++ = *m_pos++; *op++ = *m_pos++;
+ do *op++ = *m_pos++; while (--t > 0);
+ }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+ t = ip[-1] & 3;
+#else
+ t = ip[-2] & 3;
+#endif
+ if (t == 0)
+ break;
+
+match_next:
+ assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+ do *op++ = *ip++; while (--t > 0);
+ t = *ip++;
+ }
+ }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+ *out_len = op - out;
+ return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+ assert(t == 1);
+ *out_len = op - out;
+ return (ip == ip_end ? LZO_E_OK :
+ (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+ *out_len = op - out;
+ return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+ *out_len = op - out;
+ return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+ *out_len = op - out;
+ return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#define LZO_TEST_DECOMPRESS_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS lzo1x_decompress_safe
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN)
+# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+# define LZO_TEST_DECOMPRESS_OVERRUN_INPUT 2
+# endif
+# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+# define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT 2
+# endif
+# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+# define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND
+# endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LOOKBEHIND
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1)
+# define TEST_IP (ip < ip_end)
+# endif
+# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2)
+# define NEED_IP(x, y) \
+ if ( ((y > 0) && (x > (LZO_UINT_MAX - y))) || ((lzo_uint)(ip_end - ip) < (lzo_uint)((x)+(y))) ) goto input_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1)
+# define TEST_OP (op <= op_end)
+# endif
+# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2)
+# undef TEST_OP
+# define NEED_OP(x,y) \
+ if ( ((y > 0) && (x > (LZO_UINT_MAX - y))) || ((lzo_uint)(op_end - op) < (lzo_uint)((x)+(y))) ) goto output_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+# define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun
+#else
+# define TEST_LOOKBEHIND(m_pos,op) ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+# define TEST_IP (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+# define HAVE_TEST_IP
+#else
+# define TEST_IP 1
+#endif
+#if defined(TEST_OP)
+# define HAVE_TEST_OP
+#else
+# define TEST_OP 1
+#endif
+
+#if defined(NEED_IP)
+# define HAVE_NEED_IP
+#else
+ /* # define NEED_IP(x) ((void) 0) */
+#error "no need_ip"
+#endif
+#if defined(NEED_OP)
+# define HAVE_NEED_OP
+#else
+ /* # define NEED_OP(x) ((void) 0) */
+#error "no need_op"
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+# define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+# define HAVE_ANY_OP
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS ( const lzo_byte *in , lzo_uint in_len,
+ lzo_byte *out, lzo_uint *out_len,
+ lzo_voidp wrkmem )
+#endif
+{
+ register lzo_byte *op;
+ register const lzo_byte *ip;
+ register lzo_uint t;
+#if defined(COPY_DICT)
+ lzo_uint m_off;
+ const lzo_byte *dict_end;
+#else
+ register const lzo_byte *m_pos;
+#endif
+
+ const lzo_byte * const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+ lzo_byte * const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+ lzo_uint last_m_off = 0;
+#endif
+
+ LZO_UNUSED(wrkmem);
+
+#if defined(__LZO_QUERY_DECOMPRESS)
+ if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem))
+ return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0);
+#endif
+
+#if defined(COPY_DICT)
+ if (dict)
+ {
+ if (dict_len > M4_MAX_OFFSET)
+ {
+ dict += dict_len - M4_MAX_OFFSET;
+ dict_len = M4_MAX_OFFSET;
+ }
+ dict_end = dict + dict_len;
+ }
+ else
+ {
+ dict_len = 0;
+ dict_end = NULL;
+ }
+#endif
+
+ *out_len = 0;
+
+ op = out;
+ ip = in;
+
+ if (*ip > 17)
+ {
+ t = *ip++ - 17;
+ if (t < 4)
+ goto match_next;
+ assert(t > 0); NEED_OP(t, 0); NEED_IP(t, 1);
+ do *op++ = *ip++; while (--t > 0);
+ goto first_literal_run;
+ }
+
+ while (TEST_IP && TEST_OP)
+ {
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+ if (t == 0)
+ {
+ NEED_IP(1, 0);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1, 0);
+ }
+ t += 15 + *ip++;
+ }
+ assert(t > 0); NEED_OP(t,3); NEED_IP(t,4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (PTR_ALIGNED2_4(op,ip))
+ {
+#endif
+ * (lzo_uint32p) op = * (const lzo_uint32p) ip;
+ op += 4; ip += 4;
+ if (--t > 0)
+ {
+ if (t >= 4)
+ {
+ do {
+ * (lzo_uint32p) op = * (const lzo_uint32p) ip;
+ op += 4; ip += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *ip++; while (--t > 0);
+ }
+ else
+ do *op++ = *ip++; while (--t > 0);
+ }
+#if !defined(LZO_UNALIGNED_OK_4)
+ }
+ else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+ {
+ *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+ do *op++ = *ip++; while (--t > 0);
+ }
+#endif
+
+first_literal_run:
+
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(3);
+ t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - (1 + M2_MAX_OFFSET);
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LOOKBEHIND(m_pos,out); NEED_OP(3,0);
+ *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+
+ while (TEST_IP && TEST_OP)
+ {
+match:
+ if (t >= 64)
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+ m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ m_off = t & 0x1f;
+ if (m_off >= 0x1c)
+ m_off = last_m_off;
+ else
+ {
+ m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+ }
+ t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 7;
+ m_pos -= *ip++ << 3;
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 3;
+ m_pos -= *ip++ << 2;
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ {
+ lzo_uint off = t & 0x1f;
+ m_pos = op;
+ if (off >= 0x1c)
+ {
+ assert(last_m_off > 0);
+ m_pos -= last_m_off;
+ }
+ else
+ {
+ off = 1 + (off << 6) + (*ip++ >> 2);
+ m_pos -= off;
+ last_m_off = off;
+ }
+ }
+ t = (t >> 5) - 1;
+#endif
+ TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t,(3-1));
+ goto copy_match;
+#endif
+ }
+ else if (t >= 32)
+ {
+ t &= 31;
+ if (t == 0)
+ {
+ NEED_IP(1,0);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1,0);
+ }
+ t += 31 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+ {
+ lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ m_pos = op - off;
+ last_m_off = off;
+ }
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ m_pos = op - 1;
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos = op - 1;
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+ ip += 2;
+ }
+ else if (t >= 16)
+ {
+#if defined(COPY_DICT)
+ m_off = (t & 8) << 11;
+#else
+ m_pos = op;
+ m_pos -= (t & 8) << 11;
+#endif
+ t &= 7;
+ if (t == 0)
+ {
+ NEED_IP(1,0);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1,0);
+ }
+ t += 7 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+ m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_off == 0)
+ goto eof_found;
+ m_off += 0x4000;
+#if defined(LZO1Z)
+ last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+ m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN)
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_pos == op)
+ goto eof_found;
+ m_pos -= 0x4000;
+#if defined(LZO1Z)
+ last_m_off = op - m_pos;
+#endif
+#endif
+ }
+ else
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(2,0);
+ t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = 1 + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - 1;
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LOOKBEHIND(m_pos,out); NEED_OP(2,0);
+ *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+ }
+
+#if defined(COPY_DICT)
+
+ NEED_OP(t,(3-1));
+ t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+ TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t,(3-1));
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+ {
+ assert((op - m_pos) >= 4);
+#else
+ if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+ {
+#endif
+ * (lzo_uint32p) op = * (const lzo_uint32p) m_pos;
+ op += 4; m_pos += 4; t -= 4 - (3 - 1);
+ do {
+ * (lzo_uint32p) op = * (const lzo_uint32p) m_pos;
+ op += 4; m_pos += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+ }
+ else
+#endif
+ {
+copy_match:
+ *op++ = *m_pos++; *op++ = *m_pos++;
+ do *op++ = *m_pos++; while (--t > 0);
+ }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+ t = ip[-1] & 3;
+#else
+ t = ip[-2] & 3;
+#endif
+ if (t == 0)
+ break;
+
+match_next:
+ assert(t > 0); NEED_OP(t,0); NEED_IP(t,1);
+ do *op++ = *ip++; while (--t > 0);
+ t = *ip++;
+ }
+ }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+ *out_len = op - out;
+ return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+ assert(t == 1);
+ *out_len = op - out;
+ return (ip == ip_end ? LZO_E_OK :
+ (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+ *out_len = op - out;
+ return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+ *out_len = op - out;
+ return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+ *out_len = op - out;
+ return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+/***** End of minilzo.c *****/
+
diff --git a/src/mkhdr.c b/src/mkhdr.c
new file mode 100644
index 0000000..f281d64
--- /dev/null
+++ b/src/mkhdr.c
@@ -0,0 +1,222 @@
+#include "config.h"
+
+#ifdef HAVE_BROKEN_INCLUDES
+#define _ANSI_C_SOURCE
+#define _POSIX_SOURCE
+#endif
+
+#include <stdio.h>
+
+extern void exit(int status);
+extern int fclose(FILE *stream);
+
+#ifndef TRUE
+#define TRUE (1 == 1)
+#endif
+
+#ifndef FALSE
+#define FALSE (1 != 1)
+#endif
+
+struct description_int
+{
+ int int_size;
+ char int_name[20];
+};
+struct description_int int_descrs[] =
+{
+#ifdef LONGLONG
+ { sizeof(unsigned long long), "unsigned long long" },
+#endif
+ { sizeof(unsigned long), "unsigned long" },
+ { sizeof(unsigned int), "unsigned int" },
+ { sizeof(unsigned short), "unsigned short" },
+ { sizeof(unsigned char), "unsigned char" }
+};
+int size_count = sizeof(int_descrs) / sizeof(struct description_int);
+
+struct trnc_data
+{
+ long a, b, q, r;
+};
+struct trnc_data trunc_tbl[] =
+{
+ { 13, 4, 3, 1 },
+ { 13, -4, -3, 1 },
+ { -13, 4, -3, -1 },
+ { -13, -4, 3, -1 },
+ { 15, 4, 3, 3 },
+ { 15, -4, -3, 3 },
+ { -15, 4, -3, -3 },
+ { -15, -4, 3, -3 }
+};
+int size_trunc_tbl = sizeof(trunc_tbl) / sizeof(struct trnc_data);
+
+struct rand_data
+{
+ unsigned long dig_size, a1, c1, a2, c2;
+};
+struct rand_data rand_tbl[] =
+{
+ { 8, 197, 11, 37, 37 },
+ { 16, 805, 345, 925, 767 },
+ { 18, 13405, 4801, 20325, 19777 },
+ { 32, 13405, 4801, 20325, 19777 }
+};
+int size_rand_tbl = sizeof(rand_tbl) / sizeof(struct rand_data);
+
+int digit_bits;
+
+int
+div_trunc_p(void)
+{
+ int i;
+
+ for (i = 0; i < size_trunc_tbl; i++)
+ {
+ if (trunc_tbl[i].a / trunc_tbl[i].b != trunc_tbl[i].q)
+ {
+ printf("%ld / %ld = %ld, should have been %ld\n",
+ trunc_tbl[i].a,
+ trunc_tbl[i].b,
+ trunc_tbl[i].a / trunc_tbl[i].b,
+ trunc_tbl[i].q);
+ printf("when division truncates towards zero.\n");
+ return FALSE;
+ }
+ if (trunc_tbl[i].a % trunc_tbl[i].b != trunc_tbl[i].r)
+ {
+ printf("%ld %% %ld = %ld, should have been %ld\n",
+ trunc_tbl[i].a,
+ trunc_tbl[i].b,
+ trunc_tbl[i].a % trunc_tbl[i].b,
+ trunc_tbl[i].r);
+ printf("when division truncates towards zero.\n");
+ printf("Here a != q*b + r. Very strange!\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+int
+charsize(void)
+{
+ int i = 0;
+ unsigned char ch = 1;
+ unsigned char oldch = 0;
+
+ while (ch > oldch)
+ {
+ oldch = ch;
+ ch <<= 1;
+ i++;
+ }
+ return i;
+}
+
+void
+RandDefsOut(FILE *fpOut, int dig_size)
+{
+ int i = 0;
+
+ while ((i < size_rand_tbl) && (dig_size != (int)rand_tbl[i].dig_size))
+ {
+ i++;
+ }
+ if (i == size_rand_tbl)
+ {
+ if (dig_size < (int) rand_tbl[0].dig_size)
+ {
+ printf("Digit size %d too small.\n", dig_size);
+ exit(10);
+ }
+ while ((int) rand_tbl[--i].dig_size > dig_size)
+ {
+ /* Count down `i' */
+ }
+ }
+ fprintf(fpOut, "\n#define BIG_RAND_A1 %ld\n", rand_tbl[i].a1);
+ fprintf(fpOut, "#define BIG_RAND_C1 %ld\n", rand_tbl[i].c1);
+ fprintf(fpOut, "#define BIG_RAND_A2 %ld\n", rand_tbl[i].a2);
+ fprintf(fpOut, "#define BIG_RAND_C2 %ld\n", rand_tbl[i].c2);
+}
+
+int
+main(void)
+{
+ int i, j = 0, ints_found = FALSE, char_bits;
+ FILE *fpOut;
+
+ if (!div_trunc_p())
+ {
+ printf("Can't do division on this machine!\n");
+ exit(10);
+ }
+
+ if ((fpOut = fopen("internal.h", "w")) == NULL)
+ {
+ printf("Could not create \"internal.h\".\n");
+ exit(10);
+ }
+
+ fprintf(fpOut, "#ifndef _BIGNUM_INTERNAL_H_\n");
+ fprintf(fpOut, "#define _BIGNUM_INTERNAL_H_\n\n");
+
+ char_bits = charsize();
+
+ for (i = 0; (i < size_count - 1) && !ints_found; i++)
+ {
+ for (j = i + 1; (j < size_count) && !ints_found; j++)
+ {
+ if (int_descrs[i].int_size >= 2 * int_descrs[j].int_size)
+ {
+ fprintf(fpOut,
+ "#define BIGNUM_DIGIT %s\n",
+ int_descrs[j].int_name);
+ fprintf(fpOut,
+ "#define BIGNUM_TWO_DIGITS %s\n\n",
+ int_descrs[i].int_name);
+ ints_found = TRUE;
+ }
+ }
+ }
+
+ if (!ints_found)
+ {
+ fprintf(stderr, "Strange, no integer type was two times bigger ");
+ fprintf(stderr, "than another integer type.\n");
+ fprintf(stderr, "Can't create header file.\nExiting.\n");
+ exit(10);
+ }
+
+ if (i > 0) i--;
+ if (j > 0) j--;
+
+ digit_bits = char_bits * int_descrs[j].int_size;
+ fprintf(fpOut, "#define BIG_CHARBITS %d\n", char_bits);
+ fprintf(fpOut, "#define BIGNUM_DIGIT_BITS %d\n", digit_bits);
+ fprintf(fpOut, "#define BIGNUM_TWO_DIGITS_BITS %d\n\n",
+ char_bits * int_descrs[i].int_size);
+
+ fprintf(fpOut, "struct big_struct\n{\n int sign;\n");
+ fprintf(fpOut, " unsigned long dgs_alloc;\n");
+ fprintf(fpOut, " unsigned long dgs_used;\n");
+ fprintf(fpOut, " BIGNUM_DIGIT *dp;\n};\n");
+
+ RandDefsOut(fpOut, char_bits * int_descrs[j].int_size);
+
+ if (sizeof(long) == sizeof(int))
+ {
+ fprintf(fpOut, "\n#define MEMCPY_LONG_COUNTER\n");
+ }
+
+#ifdef BIG_SHORT_NAMES
+ fprintf(fpOut, "\n#define BIG_SHORT_NAMES\n");
+#endif
+
+ fprintf(fpOut, "\n#endif\n");
+ fclose(fpOut);
+ exit(0);
+ return 0; /* Keep gcc from complaining */
+}
diff --git a/src/rijndael-alg-fst.c b/src/rijndael-alg-fst.c
new file mode 100644
index 0000000..d584de2
--- /dev/null
+++ b/src/rijndael-alg-fst.c
@@ -0,0 +1,1235 @@
+/* $NetBSD: rijndael-alg-fst.c,v 1.7 2005/12/11 12:20:52 christos Exp $ */
+/* $KAME: rijndael-alg-fst.c,v 1.10 2003/07/15 10:47:16 itojun Exp $ */
+/**
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config_xor.h"
+
+#include <sys/types.h>
+#include <string.h>
+
+#ifdef SH_ENCRYPT
+
+typedef unsigned char u8;
+#if defined(HAVE_INT_32)
+typedef unsigned int u32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long u32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short u32;
+#else
+#error "No 32 bit integer type found"
+#endif
+
+#include "rijndael-alg-fst.h"
+
+#define FULL_UNROLL 1
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+ 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+ 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+ 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+ 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+ 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+ 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+ 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+ 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+ 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+ 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+ 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+ 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+ 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+ 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+ 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+ 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+ 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+ 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+ 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+ 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+ 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+ 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+ 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+ 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+ 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+ 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+ 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+ 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+ 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+ 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+ 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+ 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+ 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+ 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+ 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+ 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+ 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+ 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+ 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+ 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+ 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+ 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+ 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+ 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+ 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+ 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+ 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+ 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+ 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+ 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+ 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+ 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+ 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+ 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+ 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+ 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+ 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+ 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+ 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+ 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+ 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+ 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+ 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+ 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+ 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+ 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+ 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+ 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+ 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+ 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+ 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+ 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+ 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+ 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+ 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+ 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+ 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+ 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+ 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+ 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+ 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+ 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+ 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+ 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+ 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+ 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+ 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+ 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+ 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+ 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+ 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+ 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+ 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+ 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+ 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+ 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+ 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+ 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+ 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+ 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+ 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+ 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+ 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+ 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+ 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+ 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+ 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+ 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+ 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+ 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+ 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+ 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+ 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+ 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+ 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+ 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+ 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+ 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+ 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+ 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+ 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+ 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+ 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+ 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+ 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+ 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+ 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+ 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+ 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+ 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+ 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+ 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+ 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+ 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+ 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+ 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+ 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+ 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+ 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+ 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+ 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+ 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+ 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+ 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+ 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+ 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+ 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+ 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+ 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+ 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+ 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+ 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+ 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+ 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+ 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+ 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+ 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+ 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+ 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+ 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+ 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+ 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+ 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+ 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+ 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+ 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+ 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+ 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+ 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+ 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+ 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+ 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+ 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+ 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+ 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+ 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+ 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+ 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+ 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+ 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+ 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+ 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+ 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+ 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+ 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+ 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+ 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+ 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+ 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+ 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+ 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+ 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+ 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+ 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+ 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+ 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+ 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+ 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+ 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+ 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+ 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+ 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+ 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+ 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+ 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+ 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+ 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+ 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+ 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+ 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+ 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+ 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+ 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+ 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+ 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+ 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+ 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+ 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+ 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+ 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+ 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+ 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+ 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+ 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+ 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+ 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+ 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+ 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+ 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+ 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+ 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+ 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+ 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+ 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+ 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+ 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+ 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+ 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+ 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+ 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+ 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+ 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+ 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+ 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+ 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+ 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+ 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+ 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+ 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+ 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+ 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+ 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+ 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+ 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+ 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+ 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+ 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+ 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+ 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+ 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+ 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+ 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+ 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+ 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+ 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+ 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+ 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+ 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+ 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+ 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+ 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+ 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+ 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+ 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+ 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+ 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+ 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+ 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+ 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+ 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+ 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+ 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+ 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+ 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+ 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+ 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+ 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+ 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+ 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+ 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+ 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+ 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+ 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+ 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+ 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+ 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+ 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+ 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+ 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+ 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+ 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+ 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+ 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+ 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+ 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+ 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+ 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+ 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+ 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+ 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+ 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+ 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+ 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+ 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+ 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+ 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+ 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+ 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+ 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+ 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+ 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+ 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+ 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+ 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+ 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+ 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+ 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+ 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+ 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+ 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+ 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+ 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+ 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+ 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+ 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+ 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+ 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+ 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+ 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+ 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+ 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+ 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+ 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+ 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+ 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+ 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+ 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+ 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+ 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+ 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+ 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+ 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+ 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+ 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+ 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+ 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+ 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+ 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+ 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+ 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+ 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+ 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+ 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+ 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+ 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+ 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+ 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+ 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+ 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+ 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+ 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+ 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+ 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+ 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+ 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+ 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+ 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+ 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+ 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+ 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+ 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+ 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+ 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+ 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+ 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+ 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+ 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+ 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+ 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+ 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+ 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+ 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+ 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+ 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+ 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+ 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+ 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+ 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+ 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+ 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+ 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+ 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+ 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+ 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+ 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+ 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+ 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+ 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+ 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+ 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+ 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+ 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+ 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+ 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+ 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+ 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+ 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+ 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+ 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+ 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+ 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+ 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+ 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+ 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+ 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+ 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+ 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+ 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+ 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+ 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+ 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+ 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+ 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+ 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+ 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+ 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+ 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+ 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+ 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+ 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+ 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+ 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+ 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+ 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+ 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+ 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+ 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+ 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+ 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+ 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+ 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+ 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+ 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+ 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+ 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+ 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+ 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+ 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+ 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+ 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+ 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+ 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+ 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+ 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+ 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+ 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+ 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+ 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+ 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+ 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+ 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+ 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+ 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+ 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+ 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+ 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+ 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+ 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+ 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+ 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+ 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+ 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+ 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+ 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+ 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+ 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+ 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+ 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+ 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+ 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+ 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+ 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+ 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+ 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+ 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+ 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+ 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+ 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+ 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+ 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+ 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+ 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+ 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+ 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+ 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+ 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+ 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+ 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+ 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+ 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+ 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+ 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+ 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+ 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+ 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+ 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+ 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+ 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+ 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+ 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+ 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+ 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+ 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+ 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+ 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+ 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+ 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+ 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+ 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+ 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+ 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+ 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+ 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+ 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+ 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+ 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+ 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+ 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+ 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+ 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+ 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+ 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+ 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+ 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+ 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+ 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+ 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+ 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+ 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+ 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+ 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+ 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+ 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+ 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+ 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+ 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+ 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+ 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+ 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+ 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+ 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+ 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+ 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+ 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+ 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+ 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+ 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+ 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+ 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+ 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+ 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+ 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+ 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+ 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+ 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+ 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+ 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+ 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+ 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+ 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+ 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+ 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+ 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+ 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+ 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+ 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+ 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+ 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+ 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+ 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+ 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+ 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+ 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+ 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+ 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+ 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+ 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+ 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+ 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+ 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+ 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+ 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+ 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+ 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+ 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+ 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+ 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+ 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+ 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+ 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+ 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+ 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+ 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+ 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+ 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+ 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+ 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+ 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+ 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+ 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+ 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+ 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+ 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+ 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+ 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+ 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+ 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+ 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+ 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+ 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+ 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+ 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+ 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+ 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+ 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+ 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+ 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+ 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+ 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+ 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+
+#ifdef _MSC_VER
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int i = 0;
+ u32 temp;
+
+ rk[0] = GETU32(cipherKey );
+ rk[1] = GETU32(cipherKey + 4);
+ rk[2] = GETU32(cipherKey + 8);
+ rk[3] = GETU32(cipherKey + 12);
+ if (keyBits == 128) {
+ for (;;) {
+ temp = rk[3];
+ rk[4] = rk[0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[5] = rk[1] ^ rk[4];
+ rk[6] = rk[2] ^ rk[5];
+ rk[7] = rk[3] ^ rk[6];
+ if (++i == 10) {
+ return 10;
+ }
+ rk += 4;
+ }
+ }
+ rk[4] = GETU32(cipherKey + 16);
+ rk[5] = GETU32(cipherKey + 20);
+ if (keyBits == 192) {
+ for (;;) {
+ temp = rk[ 5];
+ rk[ 6] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 7] = rk[ 1] ^ rk[ 6];
+ rk[ 8] = rk[ 2] ^ rk[ 7];
+ rk[ 9] = rk[ 3] ^ rk[ 8];
+ if (++i == 8) {
+ return 12;
+ }
+ rk[10] = rk[ 4] ^ rk[ 9];
+ rk[11] = rk[ 5] ^ rk[10];
+ rk += 6;
+ }
+ }
+ rk[6] = GETU32(cipherKey + 24);
+ rk[7] = GETU32(cipherKey + 28);
+ if (keyBits == 256) {
+ for (;;) {
+ temp = rk[ 7];
+ rk[ 8] = rk[ 0] ^
+ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp ) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp >> 24) ] & 0x000000ff) ^
+ rcon[i];
+ rk[ 9] = rk[ 1] ^ rk[ 8];
+ rk[10] = rk[ 2] ^ rk[ 9];
+ rk[11] = rk[ 3] ^ rk[10];
+ if (++i == 7) {
+ return 14;
+ }
+ temp = rk[11];
+ rk[12] = rk[ 4] ^
+ (Te4[(temp >> 24) ] & 0xff000000) ^
+ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(temp ) & 0xff] & 0x000000ff);
+ rk[13] = rk[ 5] ^ rk[12];
+ rk[14] = rk[ 6] ^ rk[13];
+ rk[15] = rk[ 7] ^ rk[14];
+
+ rk += 8;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+ int Nr, i, j;
+ u32 temp;
+
+ /* expand the cipher key: */
+ Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+ /* invert the order of the round keys: */
+ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+ temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
+ temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+ temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+ temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+ }
+ /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+ for (i = 1; i < Nr; i++) {
+ rk += 4;
+ rk[0] =
+ Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[0] ) & 0xff] & 0xff];
+ rk[1] =
+ Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[1] ) & 0xff] & 0xff];
+ rk[2] =
+ Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[2] ) & 0xff] & 0xff];
+ rk[3] =
+ Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
+ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+ Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ }
+ return Nr;
+}
+
+void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(pt ) ^ rk[0];
+ s1 = GETU32(pt + 4) ^ rk[1];
+ s2 = GETU32(pt + 8) ^ rk[2];
+ s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+ s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+ s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+ s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Te0[(s0 >> 24) ] ^
+ Te1[(s1 >> 16) & 0xff] ^
+ Te2[(s2 >> 8) & 0xff] ^
+ Te3[(s3 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Te0[(s1 >> 24) ] ^
+ Te1[(s2 >> 16) & 0xff] ^
+ Te2[(s3 >> 8) & 0xff] ^
+ Te3[(s0 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Te0[(s2 >> 24) ] ^
+ Te1[(s3 >> 16) & 0xff] ^
+ Te2[(s0 >> 8) & 0xff] ^
+ Te3[(s1 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Te0[(s3 >> 24) ] ^
+ Te1[(s0 >> 16) & 0xff] ^
+ Te2[(s1 >> 8) & 0xff] ^
+ Te3[(s2 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Te0[(t0 >> 24) ] ^
+ Te1[(t1 >> 16) & 0xff] ^
+ Te2[(t2 >> 8) & 0xff] ^
+ Te3[(t3 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Te0[(t1 >> 24) ] ^
+ Te1[(t2 >> 16) & 0xff] ^
+ Te2[(t3 >> 8) & 0xff] ^
+ Te3[(t0 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Te0[(t2 >> 24) ] ^
+ Te1[(t3 >> 16) & 0xff] ^
+ Te2[(t0 >> 8) & 0xff] ^
+ Te3[(t1 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Te0[(t3 >> 24) ] ^
+ Te1[(t0 >> 16) & 0xff] ^
+ Te2[(t1 >> 8) & 0xff] ^
+ Te3[(t2 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Te4[(t0 >> 24) ] & 0xff000000) ^
+ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(ct , s0);
+ s1 =
+ (Te4[(t1 >> 24) ] & 0xff000000) ^
+ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(ct + 4, s1);
+ s2 =
+ (Te4[(t2 >> 24) ] & 0xff000000) ^
+ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(ct + 8, s2);
+ s3 =
+ (Te4[(t3 >> 24) ] & 0xff000000) ^
+ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Te4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(ct + 12, s3);
+}
+
+void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
+ u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+ int r;
+#endif /* ?FULL_UNROLL */
+
+ /*
+ * map byte array block to cipher state
+ * and add initial round key:
+ */
+ s0 = GETU32(ct ) ^ rk[0];
+ s1 = GETU32(ct + 4) ^ rk[1];
+ s2 = GETU32(ct + 8) ^ rk[2];
+ s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+ /* round 1: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+ /* round 2: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+ /* round 3: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+ /* round 4: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+ /* round 5: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+ /* round 6: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+ /* round 7: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+ /* round 8: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+ /* round 9: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+ if (Nr > 10) {
+ /* round 10: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+ /* round 11: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+ if (Nr > 12) {
+ /* round 12: */
+ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+ s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+ s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+ s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+ /* round 13: */
+ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+ t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+ t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+ t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+ }
+ }
+ rk += Nr << 2;
+#else /* !FULL_UNROLL */
+ /*
+ * Nr - 1 full rounds:
+ */
+ r = Nr >> 1;
+ for (;;) {
+ t0 =
+ Td0[(s0 >> 24) ] ^
+ Td1[(s3 >> 16) & 0xff] ^
+ Td2[(s2 >> 8) & 0xff] ^
+ Td3[(s1 ) & 0xff] ^
+ rk[4];
+ t1 =
+ Td0[(s1 >> 24) ] ^
+ Td1[(s0 >> 16) & 0xff] ^
+ Td2[(s3 >> 8) & 0xff] ^
+ Td3[(s2 ) & 0xff] ^
+ rk[5];
+ t2 =
+ Td0[(s2 >> 24) ] ^
+ Td1[(s1 >> 16) & 0xff] ^
+ Td2[(s0 >> 8) & 0xff] ^
+ Td3[(s3 ) & 0xff] ^
+ rk[6];
+ t3 =
+ Td0[(s3 >> 24) ] ^
+ Td1[(s2 >> 16) & 0xff] ^
+ Td2[(s1 >> 8) & 0xff] ^
+ Td3[(s0 ) & 0xff] ^
+ rk[7];
+
+ rk += 8;
+ if (--r == 0) {
+ break;
+ }
+
+ s0 =
+ Td0[(t0 >> 24) ] ^
+ Td1[(t3 >> 16) & 0xff] ^
+ Td2[(t2 >> 8) & 0xff] ^
+ Td3[(t1 ) & 0xff] ^
+ rk[0];
+ s1 =
+ Td0[(t1 >> 24) ] ^
+ Td1[(t0 >> 16) & 0xff] ^
+ Td2[(t3 >> 8) & 0xff] ^
+ Td3[(t2 ) & 0xff] ^
+ rk[1];
+ s2 =
+ Td0[(t2 >> 24) ] ^
+ Td1[(t1 >> 16) & 0xff] ^
+ Td2[(t0 >> 8) & 0xff] ^
+ Td3[(t3 ) & 0xff] ^
+ rk[2];
+ s3 =
+ Td0[(t3 >> 24) ] ^
+ Td1[(t2 >> 16) & 0xff] ^
+ Td2[(t1 >> 8) & 0xff] ^
+ Td3[(t0 ) & 0xff] ^
+ rk[3];
+ }
+#endif /* ?FULL_UNROLL */
+ /*
+ * apply last round and
+ * map cipher state to byte array block:
+ */
+ s0 =
+ (Td4[(t0 >> 24) ] & 0xff000000) ^
+ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t1 ) & 0xff] & 0x000000ff) ^
+ rk[0];
+ PUTU32(pt , s0);
+ s1 =
+ (Td4[(t1 >> 24) ] & 0xff000000) ^
+ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t2 ) & 0xff] & 0x000000ff) ^
+ rk[1];
+ PUTU32(pt + 4, s1);
+ s2 =
+ (Td4[(t2 >> 24) ] & 0xff000000) ^
+ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t3 ) & 0xff] & 0x000000ff) ^
+ rk[2];
+ PUTU32(pt + 8, s2);
+ s3 =
+ (Td4[(t3 >> 24) ] & 0xff000000) ^
+ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
+ (Td4[(t0 ) & 0xff] & 0x000000ff) ^
+ rk[3];
+ PUTU32(pt + 12, s3);
+}
+
+#endif
diff --git a/src/rijndael-api-fst.c b/src/rijndael-api-fst.c
new file mode 100644
index 0000000..4464c9b
--- /dev/null
+++ b/src/rijndael-api-fst.c
@@ -0,0 +1,407 @@
+/* $NetBSD: rijndael-api-fst.c,v 1.24 2011/05/14 16:46:55 jmmv Exp $ */
+
+/**
+ * rijndael-api-fst.c
+ *
+ * @version 2.9 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Acknowledgements:
+ *
+ * We are deeply indebted to the following people for their bug reports,
+ * fixes, and improvement suggestions to this implementation. Though we
+ * tried to list all contributions, we apologise in advance for any
+ * missing reference.
+ *
+ * Andrew Bales <Andrew.Bales@Honeywell.com>
+ * Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
+ * John Skodon <skodonj@webquill.com>
+ */
+#include "config_xor.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifdef SH_ENCRYPT
+
+#include "rijndael-api-fst.h"
+
+static void xor16(u8 *d, const u8 *a, const u8* b)
+{
+ size_t i;
+
+ for (i = 0; i < 4; i++) {
+ *d++ = *a++ ^ *b++;
+ *d++ = *a++ ^ *b++;
+ *d++ = *a++ ^ *b++;
+ *d++ = *a++ ^ *b++;
+ }
+}
+
+int
+rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen,
+ const char *keyMaterial)
+{
+ u8 cipherKey[RIJNDAEL_MAXKB];
+ int i;
+
+ if (key == NULL) {
+ return BAD_KEY_INSTANCE;
+ }
+
+ if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
+ key->direction = direction;
+ } else {
+ return BAD_KEY_DIR;
+ }
+
+ if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) {
+ key->keyLen = keyLen;
+ } else {
+ return BAD_KEY_MAT;
+ }
+
+ if (keyMaterial != NULL) {
+ char temp[RIJNDAEL_MAX_KEY_SIZE];
+ for (i = 0; i < key->keyLen/8; i++) {
+ int t, j;
+
+ t = *keyMaterial++;
+ if ((t >= '0') && (t <= '9')) j = (t - '0') << 4;
+ else if ((t >= 'a') && (t <= 'f')) j = (t - 'a' + 10) << 4;
+ else if ((t >= 'A') && (t <= 'F')) j = (t - 'A' + 10) << 4;
+ else return BAD_KEY_MAT;
+
+ t = *keyMaterial++;
+ if ((t >= '0') && (t <= '9')) j ^= (t - '0');
+ else if ((t >= 'a') && (t <= 'f')) j ^= (t - 'a' + 10);
+ else if ((t >= 'A') && (t <= 'F')) j ^= (t - 'A' + 10);
+ else return BAD_KEY_MAT;
+
+ temp[i] = (u8)j;
+ }
+
+ /* memcpy(key->keyMaterial, keyMaterial, keyLen/8); */
+ memcpy(key->keyMaterial, temp, keyLen/8);
+ }
+
+ /* initialize key schedule: */
+ memcpy(cipherKey, key->keyMaterial, keyLen/8);
+ if (direction == DIR_ENCRYPT) {
+ key->Nr = rijndaelKeySetupEnc(key->rk, cipherKey, keyLen);
+ } else {
+ key->Nr = rijndaelKeySetupDec(key->rk, cipherKey, keyLen);
+ }
+ rijndaelKeySetupEnc(key->ek, cipherKey, keyLen);
+ return TRUE;
+}
+
+int
+rijndael_cipherInit(cipherInstance *cipher, BYTE mode, const char *IV)
+{
+ if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
+ cipher->mode = mode;
+ } else {
+ return BAD_CIPHER_MODE;
+ }
+ if (IV != NULL) {
+ memcpy(cipher->IV, IV, RIJNDAEL_MAX_IV_SIZE);
+ } else {
+ memset(cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE);
+ }
+ return TRUE;
+}
+
+int
+rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
+ const BYTE *input, int inputLen, BYTE *outBuffer)
+{
+ int i, k, t, numBlocks;
+ u8 block[16], *iv;
+
+ if (cipher == NULL ||
+ key == NULL ||
+ key->direction == DIR_DECRYPT) {
+ return BAD_CIPHER_STATE;
+ }
+ if (input == NULL || inputLen <= 0) {
+ return 0; /* nothing to do */
+ }
+
+ numBlocks = inputLen/128;
+
+ switch (cipher->mode) {
+ case MODE_ECB:
+ for (i = numBlocks; i > 0; i--) {
+ rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+
+ case MODE_CBC:
+ iv = (u8 *)cipher->IV;
+ for (i = numBlocks; i > 0; i--) {
+ xor16(block, input, iv);
+ rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
+ iv = outBuffer;
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+
+ case MODE_CFB1:
+ iv = (u8 *)cipher->IV;
+ for (i = numBlocks; i > 0; i--) {
+ memcpy(outBuffer, input, 16);
+ for (k = 0; k < 128; k++) {
+ rijndaelEncrypt(key->ek, key->Nr, iv, block);
+ outBuffer[k >> 3] ^=
+ (block[0] & 0x80U) >> (k & 7);
+ for (t = 0; t < 15; t++) {
+ iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
+ }
+ iv[15] = (iv[15] << 1) |
+ ((outBuffer[k >> 3] >> (7 - (k & 7))) & 1);
+ }
+ outBuffer += 16;
+ input += 16;
+ }
+ break;
+
+ default:
+ return BAD_CIPHER_STATE;
+ }
+
+ return 128 * numBlocks;
+}
+
+/**
+ * Encrypt data partitioned in octets, using RFC 2040-like padding.
+ *
+ * @param input data to be encrypted (octet sequence)
+ * @param inputOctets input length in octets (not bits)
+ * @param outBuffer encrypted output data
+ *
+ * @return length in octets (not bits) of the encrypted output buffer.
+ */
+int
+rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
+ const BYTE *input, int inputOctets, BYTE *outBuffer)
+{
+ int i, numBlocks, padLen;
+ u8 block[16], *iv;
+
+ if (cipher == NULL ||
+ key == NULL ||
+ key->direction == DIR_DECRYPT) {
+ return BAD_CIPHER_STATE;
+ }
+ if (input == NULL || inputOctets <= 0) {
+ return 0; /* nothing to do */
+ }
+
+ numBlocks = inputOctets / 16;
+
+ switch (cipher->mode) {
+ case MODE_ECB:
+ for (i = numBlocks; i > 0; i--) {
+ rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ padLen = 16 - (inputOctets - 16*numBlocks);
+ memcpy(block, input, 16 - padLen);
+ memset(block + 16 - padLen, padLen, padLen);
+ rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
+ break;
+
+ case MODE_CBC:
+ iv = (u8 *)cipher->IV;
+ for (i = numBlocks; i > 0; i--) {
+ xor16(block, input, iv);
+ rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
+ iv = outBuffer;
+ input += 16;
+ outBuffer += 16;
+ }
+ padLen = 16 - (inputOctets - 16*numBlocks);
+ for (i = 0; i < 16 - padLen; i++) {
+ block[i] = input[i] ^ iv[i];
+ }
+ for (i = 16 - padLen; i < 16; i++) {
+ block[i] = (BYTE)padLen ^ iv[i];
+ }
+ rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
+ break;
+
+ default:
+ return BAD_CIPHER_STATE;
+ }
+
+ return 16 * (numBlocks + 1);
+}
+
+int
+rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
+ const BYTE *input, int inputLen, BYTE *outBuffer)
+{
+ int i, k, t, numBlocks;
+ u8 block[16], *iv;
+
+ if (cipher == NULL ||
+ key == NULL ||
+ (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
+ return BAD_CIPHER_STATE;
+ }
+ if (input == NULL || inputLen <= 0) {
+ return 0; /* nothing to do */
+ }
+
+ numBlocks = inputLen/128;
+
+ switch (cipher->mode) {
+ case MODE_ECB:
+ for (i = numBlocks; i > 0; i--) {
+ rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+
+ case MODE_CBC:
+ iv = (u8 *)cipher->IV;
+ for (i = numBlocks; i > 0; i--) {
+ rijndaelDecrypt(key->rk, key->Nr, input, block);
+ xor16(block, block, iv);
+ if (numBlocks > 1)
+ memcpy(cipher->IV, input, 16);
+ memcpy(outBuffer, block, 16);
+ input += 16;
+ outBuffer += 16;
+ }
+ break;
+
+ case MODE_CFB1:
+ iv = (u8 *)cipher->IV;
+ for (i = numBlocks; i > 0; i--) {
+ memcpy(outBuffer, input, 16);
+ for (k = 0; k < 128; k++) {
+ rijndaelEncrypt(key->ek, key->Nr, iv, block);
+ for (t = 0; t < 15; t++) {
+ iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
+ }
+ iv[15] = (iv[15] << 1) |
+ ((input[k >> 3] >> (7 - (k & 7))) & 1);
+ outBuffer[k >> 3] ^= (block[0] & 0x80U) >>
+ (k & 7);
+ }
+ outBuffer += 16;
+ input += 16;
+ }
+ break;
+
+ default:
+ return BAD_CIPHER_STATE;
+ }
+
+ return 128 * numBlocks;
+}
+
+int
+rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
+ const BYTE *input, int inputOctets, BYTE *outBuffer)
+{
+ int i, numBlocks, padLen;
+ u8 block[16], *iv;
+
+ if (cipher == NULL ||
+ key == NULL ||
+ key->direction == DIR_ENCRYPT) {
+ return BAD_CIPHER_STATE;
+ }
+ if (input == NULL || inputOctets <= 0) {
+ return 0; /* nothing to do */
+ }
+ if (inputOctets % 16 != 0) {
+ return BAD_DATA;
+ }
+
+ numBlocks = inputOctets/16;
+
+ switch (cipher->mode) {
+ case MODE_ECB:
+ /* all blocks but last */
+ for (i = numBlocks - 1; i > 0; i--) {
+ rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
+ input += 16;
+ outBuffer += 16;
+ }
+ /* last block */
+ rijndaelDecrypt(key->rk, key->Nr, input, block);
+ padLen = block[15];
+ if (padLen >= 16) {
+ return BAD_DATA;
+ }
+ for (i = 16 - padLen; i < 16; i++) {
+ if (block[i] != padLen) {
+ return BAD_DATA;
+ }
+ }
+ memcpy(outBuffer, block, 16 - padLen);
+ break;
+
+ case MODE_CBC:
+ iv = (u8 *)cipher->IV;
+ /* all blocks but last */
+ for (i = numBlocks - 1; i > 0; i--) {
+ rijndaelDecrypt(key->rk, key->Nr, input, block);
+ xor16(block, block, iv);
+ memcpy(cipher->IV, input, 16);
+ memcpy(outBuffer, block, 16);
+ input += 16;
+ outBuffer += 16;
+ }
+ /* last block */
+ rijndaelDecrypt(key->rk, key->Nr, input, block);
+ xor16(block, block, iv);
+ padLen = block[15];
+ if (padLen <= 0 || padLen > 16) {
+ return BAD_DATA;
+ }
+ for (i = 16 - padLen; i < 16; i++) {
+ if (block[i] != padLen) {
+ return BAD_DATA;
+ }
+ }
+ memcpy(outBuffer, block, 16 - padLen);
+ break;
+
+ default:
+ return BAD_CIPHER_STATE;
+ }
+
+ return 16 * numBlocks - padLen;
+}
+
+#endif
diff --git a/src/samhain.c b/src/samhain.c
new file mode 100644
index 0000000..43503cd
--- /dev/null
+++ b/src/samhain.c
@@ -0,0 +1,2354 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/* samhainctl */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <errno.h>
+
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_SETPRIORITY
+#include <sys/resource.h>
+#endif
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+/* for FLT_EPSILON
+ */
+#include <float.h>
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_error.h"
+#include "sh_unix.h"
+#include "sh_files.h"
+#include "sh_getopt.h"
+#include "sh_readconf.h"
+#include "sh_hash.h"
+#include "sh_dbIO.h"
+#include "sh_restrict.h"
+
+#include "sh_nmail.h"
+
+#include "sh_tiger.h"
+#include "sh_gpg.h"
+#include "sh_mem.h"
+#include "sh_xfer.h"
+#include "sh_tools.h"
+#include "sh_hash.h"
+#if defined(WITH_EXTERNAL)
+#include "sh_extern.h"
+#endif
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+#include "sh_modules.h"
+#include "sh_ignore.h"
+#include "sh_prelink.h"
+#include "sh_sem.h"
+#endif
+
+#undef FIL__
+#define FIL__ _("samhain.c")
+
+
+/**************************************************
+ *
+ * Needed to compile the key into the code.
+ *
+ **************************************************/
+
+extern UINT32 ErrFlag[2];
+#include "sh_MK.h"
+
+/**************************************************
+ *
+ * Variables for signal handling.
+ *
+ **************************************************/
+
+volatile int sig_raised;
+volatile int sig_urgent;
+volatile int sig_debug_switch; /* SIGUSR1 */
+volatile int sig_suspend_switch; /* SIGUSR2 */
+volatile int sh_global_suspend_flag;
+volatile int sig_fresh_trail; /* SIGIOT */
+volatile int sh_thread_pause_flag = S_FALSE;
+volatile int sig_config_read_again; /* SIGHUP */
+volatile int sig_terminate; /* SIGQUIT */
+volatile int sig_termfast; /* SIGTERM */
+volatile int sig_force_check; /* SIGTTOU */
+volatile int sig_force_silent; /* SIGTSTP */
+volatile int sh_global_check_silent;
+volatile int sh_load_delta_flag;
+long int eintr__result;
+char sh_sig_msg[SH_MINIBUF];
+
+
+#ifdef SH_STEALTH
+/**************************************************
+ *
+ * The following set of functions is required for
+ * the 'stealth' mode.
+ *
+ **************************************************/
+
+#ifndef SH_MAX_GLOBS
+#define SH_MAX_GLOBS 16
+#endif
+
+#ifndef GLOB_LEN
+#define GLOB_LEN 511
+#endif
+
+#ifdef HAVE_PTHREAD
+struct gt {
+ size_t g_count;
+ char * g_glob;
+};
+
+pthread_key_t g_key;
+
+int sh_g_thread()
+{
+ struct gt * ptr = calloc(1,sizeof(struct gt));
+ if (!ptr)
+ return -1;
+ ptr->g_count = 0;
+ ptr->g_glob = calloc(1, SH_MAX_GLOBS * (GLOB_LEN+1));
+ if (!(ptr->g_glob))
+ {
+ free(ptr);
+ return -1;
+ }
+ return pthread_setspecific(g_key, ptr);
+}
+
+void sh_g_destroy(void * data)
+{
+ struct gt * ptr = (struct gt *) data;
+ free(ptr->g_glob);
+ free(ptr);
+ return;
+}
+
+void sh_g_init(void)
+{
+#if !defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)
+ extern int dnmalloc_pthread_init(void);
+ dnmalloc_pthread_init();
+#endif
+
+ if (0 != pthread_key_create(&g_key, sh_g_destroy))
+ {
+ perror("1");
+ exit(EXIT_FAILURE);
+ }
+
+ if (0 != sh_g_thread())
+ {
+ perror("2");
+ exit(EXIT_FAILURE);
+ }
+ return;
+}
+#define SH_G_INIT sh_g_init()
+#else
+#define SH_G_INIT ((void)0)
+#endif
+
+char * globber(const char * str)
+{
+ size_t i;
+ size_t j;
+
+#ifndef HAVE_PTHREAD
+ static size_t count = 0;
+ static char glob[SH_MAX_GLOBS * (GLOB_LEN+1)];
+#else
+ struct gt * ptr = pthread_getspecific(g_key);
+ size_t count;
+ char * glob;
+
+ if (ptr) {
+ count = ptr->g_count;
+ glob = ptr->g_glob;
+ } else {
+ return NULL;
+ }
+#endif
+
+ if (str != NULL)
+ j = strlen(str);
+ else
+ return NULL;
+
+ ASSERT((j <= GLOB_LEN), _("j <= GLOB_LEN"))
+
+ if (j > GLOB_LEN)
+ j = GLOB_LEN;
+
+ /* Overwrap the buffer.
+ */
+ if ( (count + j) >= (SH_MAX_GLOBS * (GLOB_LEN+1)))
+ {
+ count = 0;
+ }
+
+ for (i = 0; i < j; ++i)
+ {
+ if (str[i] != '\n' && str[i] != '\t' && str[i] != '\r' && str[i] != '"')
+ glob[count + i] = str[i] ^ XOR_CODE;
+ else
+ glob[count + i] = str[i];
+ }
+ glob[count + j] = '\0';
+
+ i = count;
+#ifdef HAVE_PTHREAD
+ ptr->g_count = count + j + 1;
+#else
+ count = count + j + 1;
+#endif
+ return &glob[i];
+}
+
+void sh_do_encode (char * str, int len)
+{
+ register int i;
+
+ /* this is a symmetric operation
+ */
+ for (i = 0; i < len; ++i)
+ {
+ str[i] = str[i] ^ XOR_CODE;
+ }
+ return;
+}
+
+#else
+/* not stealth */
+#define SH_G_INIT ((void)0)
+#endif
+
+/**************************************************
+ *
+ * Global variables.
+ *
+ **************************************************/
+
+sh_struct sh;
+/*@null@*/ sh_key_t * skey = NULL;
+
+extern unsigned char TcpFlag[8][PW_LEN+1];
+
+/**************************************************
+ *
+ * Initializing.
+ *
+ **************************************************/
+
+static int is_samhainctl_init = S_FALSE;
+
+static
+void sh_init (void)
+{
+ unsigned char * dez = NULL;
+ int i;
+#if defined(SH_WITH_MAIL)
+ char * p;
+ char q[SH_PATHBUF];
+#endif
+
+ SL_ENTER(_("sh_init"));
+
+#ifdef MKA_09
+ ErrFlag[0] |= (1 << 8);
+#endif
+#ifdef MKA_10
+ ErrFlag[0] |= (1 << 9);
+#endif
+#ifdef MKA_11
+ ErrFlag[0] |= (1 << 10);
+#endif
+#ifdef MKA_12
+ ErrFlag[0] |= (1 << 11);
+#endif
+
+ sh.delayload = 0;
+
+#ifdef MKA_13
+ ErrFlag[0] |= (1 << 12);
+#endif
+#ifdef MKA_14
+ ErrFlag[0] |= (1 << 13);
+#endif
+#ifdef MKA_15
+ ErrFlag[0] |= (1 << 14);
+#endif
+#ifdef MKA_16
+ ErrFlag[0] |= (1 << 15);
+#endif
+
+ /* Signal handling.
+ */
+ sig_raised = 0;
+ sig_config_read_again = 0; /* SIGHUP */
+ sig_debug_switch = 0; /* SIGUSR1 */
+ sig_suspend_switch = 0; /* SIGUSR2 */
+ sh_global_suspend_flag = 0; /* SIGUSR2 */
+ sig_fresh_trail = 0; /* SIGIOT */
+ sig_terminate = 0; /* SIGQUIT */
+ sig_termfast = 0; /* SIGTERM */
+ sig_force_check = 0; /* SIGTTOU */
+ sig_force_silent = 0; /* SIGTSTP */
+ sh_global_check_silent = 0;
+ sh_load_delta_flag = 0;
+ strcpy ( sh_sig_msg, _("None"));
+
+#ifdef MKB_01
+ ErrFlag[1] |= (1 << 0);
+#endif
+#ifdef MKB_02
+ ErrFlag[1] |= (1 << 1);
+#endif
+#ifdef MKB_03
+ ErrFlag[1] |= (1 << 2);
+#endif
+#ifdef MKB_04
+ ErrFlag[1] |= (1 << 3);
+#endif
+#ifdef MKB_05
+ ErrFlag[1] |= (1 << 4);
+#endif
+#ifdef MKB_06
+ ErrFlag[1] |= (1 << 5);
+#endif
+#ifdef MKB_07
+ ErrFlag[1] |= (1 << 6);
+#endif
+#ifdef MKB_08
+ ErrFlag[1] |= (1 << 7);
+#endif
+
+#if defined(SH_WITH_SERVER) && !defined(SH_WITH_CLIENT)
+ strncpy(sh.prg_name, _("Yule"), 8);
+ sh.prg_name[4] = '\0';
+#else
+ strncpy(sh.prg_name, _("Samhain"), 8);
+ sh.prg_name[7] = '\0';
+#endif
+
+ sh.pid = (UINT64) getpid();
+
+ sh.outpath = NULL;
+
+ /* The flags.
+ */
+ if (is_samhainctl_init == S_FALSE)
+ sh.flag.checkSum = SH_CHECK_NONE;
+ sh.flag.update = S_FALSE;
+ sh.flag.opts = S_FALSE;
+ sh.flag.started = S_FALSE;
+ if (is_samhainctl_init == S_FALSE)
+ sh.flag.isdaemon = S_FALSE;
+ sh.flag.isserver = S_FALSE;
+ sh.flag.islocked = S_FALSE;
+ sh.flag.smsg = S_FALSE;
+ sh.flag.log_start = S_TRUE;
+ sh.flag.reportonce = S_TRUE;
+ sh.flag.fulldetail = S_FALSE;
+ sh.flag.audit = S_FALSE;
+ sh.flag.nice = 0;
+ sh.flag.aud_mask = 0xFFFFFFFFUL;
+ sh.flag.client_severity = S_FALSE;
+ sh.flag.client_class = S_FALSE;
+ sh.flag.hidefile = S_FALSE;
+ sh.flag.loop = S_FALSE;
+ sh.flag.inotify = 0;
+
+#ifdef MKB_09
+ ErrFlag[1] |= (1 << 8);
+#endif
+#ifdef MKB_10
+ ErrFlag[1] |= (1 << 9);
+#endif
+#ifdef MKB_11
+ ErrFlag[1] |= (1 << 10);
+#endif
+#ifdef MKB_12
+ ErrFlag[1] |= (1 << 11);
+#endif
+#ifdef MKB_13
+ ErrFlag[1] |= (1 << 12);
+#endif
+#ifdef MKB_14
+ ErrFlag[1] |= (1 << 13);
+#endif
+#ifdef MKB_15
+ ErrFlag[1] |= (1 << 14);
+#endif
+#ifdef MKB_16
+ ErrFlag[1] |= (1 << 15);
+#endif
+
+ /* The stats.
+ */
+ sh.statistics.bytes_speed = 0;
+ sh.statistics.bytes_hashed = 0;
+ sh.statistics.files_report = 0;
+ sh.statistics.files_error = 0;
+ sh.statistics.files_nodir = 0;
+
+ sh.statistics.mail_success = 0;
+ sh.statistics.mail_failed = 0;
+ sh.statistics.time_start = time(NULL);
+ sh.statistics.time_check = (time_t) 0;
+
+#ifdef MKC_01
+ ErrFlag[0] |= (1 << 16);
+#endif
+#ifdef MKC_02
+ ErrFlag[0] |= (1 << 17);
+#endif
+#ifdef MKC_03
+ ErrFlag[0] |= (1 << 18);
+#endif
+#ifdef MKC_04
+ ErrFlag[0] |= (1 << 19);
+#endif
+#ifdef MKC_05
+ ErrFlag[0] |= (1 << 20);
+#endif
+#ifdef MKC_06
+ ErrFlag[0] |= (1 << 21);
+#endif
+#ifdef MKC_07
+ ErrFlag[0] |= (1 << 22);
+#endif
+#ifdef MKC_08
+ ErrFlag[0] |= (1 << 23);
+#endif
+
+
+ /* The local host.
+ */
+ (void) sl_strlcpy (sh.host.name, _("localhost"), SH_MINIBUF);
+ sh.host.system[0] = '\0'; /* flawfinder: ignore *//* ff bug */
+ sh.host.release[0] = '\0';
+ sh.host.machine[0] = '\0';
+
+#ifdef MKC_09
+ ErrFlag[0] |= (1 << 24);
+#endif
+#ifdef MKC_10
+ ErrFlag[0] |= (1 << 25);
+#endif
+#ifdef MKC_11
+ ErrFlag[0] |= (1 << 26);
+#endif
+#ifdef MKC_12
+ ErrFlag[0] |= (1 << 27);
+#endif
+#ifdef MKC_13
+ ErrFlag[0] |= (1 << 28);
+#endif
+#ifdef MKC_14
+ ErrFlag[0] |= (1 << 29);
+#endif
+#ifdef MKC_15
+ ErrFlag[0] |= (1 << 30);
+#endif
+#ifdef MKC_16
+ ErrFlag[0] |= (1UL << 31);
+#endif
+
+ /* The paths.
+ */
+ (void) sl_strlcpy (sh.conf.path, DEFAULT_CONFIGFILE, SH_PATHBUF);
+ sh.conf.hash[0] = '\0';
+ (void) sl_strlcpy (sh.data.path, DEFAULT_DATA_FILE, SH_PATHBUF);
+ sh.data.hash[0] = '\0';
+ sh.exec.path[0] = '\0';
+ sh.exec.hash[0] = '\0';
+
+#ifdef MKD_01
+ ErrFlag[1] |= (1 << 16);
+#endif
+#ifdef MKD_02
+ ErrFlag[1] |= (1 << 17);
+#endif
+#ifdef MKD_03
+ ErrFlag[1] |= (1 << 18);
+#endif
+#ifdef MKD_04
+ ErrFlag[1] |= (1 << 19);
+#endif
+#ifdef MKD_05
+ ErrFlag[1] |= (1 << 20);
+#endif
+#ifdef MKD_06
+ ErrFlag[1] |= (1 << 21);
+#endif
+#ifdef MKD_07
+ ErrFlag[1] |= (1 << 22);
+#endif
+#ifdef MKD_08
+ ErrFlag[1] |= (1 << 23);
+#endif
+
+ /* The addresses.
+ */
+#if defined(SH_WITH_MAIL)
+ if (0 != strcmp (DEFAULT_MAILADDRESS, _("NULL")))
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+ (void) sl_strncpy(q, DEFAULT_MAILADDRESS, SH_PATHBUF);
+ p = strtok_r (q, ", \t", &saveptr);
+ if (p)
+ {
+ (void) sh_nmail_add_compiled_recipient (p);
+ while (NULL != (p = strtok_r (NULL, ", \t", &saveptr)))
+ (void) sh_nmail_add_compiled_recipient (p);
+ }
+#else
+ (void) sl_strncpy(q, DEFAULT_MAILADDRESS, SH_PATHBUF);
+ p = strtok (q, ", \t");
+ if (p)
+ {
+ (void) sh_nmail_add_compiled_recipient (p);
+ while (NULL != (p = strtok (NULL, ", \t")))
+ (void) sh_nmail_add_compiled_recipient (p);
+ }
+#endif
+ }
+#endif
+
+ if (0 == strcmp (ALT_TIMESERVER, _("NULL")))
+ sh.srvtime.alt[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvtime.alt, ALT_TIMESERVER, SH_PATHBUF);
+ if (0 == strcmp (DEFAULT_TIMESERVER, _("NULL")))
+ sh.srvtime.name[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvtime.name, DEFAULT_TIMESERVER, SH_PATHBUF);
+
+
+ if (0 == strcmp (ALT_LOGSERVER, _("NULL")))
+ sh.srvexport.alt[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvexport.alt, ALT_LOGSERVER, SH_PATHBUF);
+ if (0 == strcmp (DEFAULT_LOGSERVER, _("NULL")))
+ sh.srvexport.name[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvexport.name, DEFAULT_LOGSERVER, SH_PATHBUF);
+
+
+ if (0 == strcmp (DEFAULT_ERRLOCK, _("NULL")))
+ sh.srvlog.alt[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvlog.alt, DEFAULT_ERRLOCK, SH_PATHBUF);
+ if (0 == strcmp (DEFAULT_ERRFILE, _("NULL")))
+ sh.srvlog.name[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvlog.name, DEFAULT_ERRFILE, SH_PATHBUF);
+
+ if (0 == strcmp (ALT_CONSOLE, _("NULL")))
+ sh.srvcons.alt[0] = '\0';
+ else
+ (void) sl_strlcpy (sh.srvcons.alt, ALT_CONSOLE, SH_PATHBUF);
+#ifndef DEFAULT_CONSOLE
+ (void) sl_strlcpy (sh.srvcons.name, _("/dev/console"), SH_PATHBUF);
+#else
+ if (0 == strcmp (DEFAULT_CONSOLE, _("NULL")))
+ (void) sl_strlcpy (sh.srvcons.name, _("/dev/console"), SH_PATHBUF);
+ else
+ (void) sl_strlcpy (sh.srvcons.name, DEFAULT_CONSOLE, SH_PATHBUF);
+#endif
+
+#ifdef MKD_09
+ ErrFlag[1] |= (1 << 24);
+#endif
+#ifdef MKD_10
+ ErrFlag[1] |= (1 << 25);
+#endif
+#ifdef MKD_11
+ ErrFlag[1] |= (1 << 26);
+#endif
+#ifdef MKD_12
+ ErrFlag[1] |= (1 << 27);
+#endif
+#ifdef MKD_13
+ ErrFlag[1] |= (1 << 28);
+#endif
+#ifdef MKD_14
+ ErrFlag[1] |= (1 << 29);
+#endif
+#ifdef MKD_15
+ ErrFlag[1] |= (1 << 30);
+#endif
+#ifdef MKD_16
+ ErrFlag[1] |= (1UL << 31);
+#endif
+
+
+ /* The timers.
+ */
+ sh.fileCheck.alarm_last = 0;
+ sh.fileCheck.alarm_interval = 600; /* ten minutes */
+
+ sh.mailTime.alarm_last = 0;
+ sh.mailTime.alarm_interval = 86400;
+
+ sh.mailNum.alarm_last = 0;
+ sh.mailNum.alarm_interval = 10;
+
+ sh.looptime = 60;
+
+#ifdef SCREW_IT_UP
+ sh.sigtrap_max_duration = 500000; /* 500ms */
+#endif
+
+ /* The struct to hold privileged information.
+ */
+ skey = calloc(1,sizeof(sh_key_t));
+ if (skey != NULL)
+ {
+
+ skey->mlock_failed = S_FALSE;
+ skey->rngI = BAD;
+ /* properly initialized later
+ */
+ skey->rng0[0] = 0x03; skey->rng0[1] = 0x09; skey->rng0[2] = 0x17;
+ skey->rng1[0] = 0x03; skey->rng1[1] = 0x09; skey->rng1[2] = 0x17;
+ skey->rng2[0] = 0x03; skey->rng2[1] = 0x09; skey->rng2[2] = 0x17;
+
+ for (i = 0; i < KEY_BYT; ++i)
+ skey->poolv[i] = '\0';
+
+ skey->poolc = 0;
+
+ skey->ErrFlag[0] = ErrFlag[0];
+ ErrFlag[0] = 0;
+ skey->ErrFlag[1] = ErrFlag[1];
+ ErrFlag[1] = 0;
+
+ dez = &(TcpFlag[POS_TF-1][0]);
+ for (i = 0; i < PW_LEN; ++i)
+ {
+ skey->pw[i] = (char) (*dez);
+ (*dez) = '\0';
+ ++dez;
+ }
+
+ skey->sh_sockpass[0] = '\0';
+ skey->sigkey_old[0] = '\0';
+ skey->sigkey_new[0] = '\0';
+ skey->mailkey_old[0] = '\0';
+ skey->mailkey_new[0] = '\0';
+ skey->crypt[0] = '\0'; /* flawfinder: ignore *//* ff bug */
+ skey->session[0] = '\0';
+ skey->vernam[0] = '\0';
+ }
+ else
+ {
+ perror(_("sh_init"));
+ _exit (EXIT_FAILURE);
+ }
+
+ sh_unix_memlock();
+ SL_RET0(_("sh_init"));
+}
+
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#if defined(SH_USE_XML)
+extern int sh_log_file (char * message, char * inet_peer);
+#endif
+
+/*******************************************************
+ *
+ * Exit Handler
+ *
+ *******************************************************/
+static void exit_handler(void)
+{
+ /* --- Clean up modules, if any. ---
+ */
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ int modnum;
+#endif
+#if defined(SH_WITH_SERVER)
+ extern int sh_socket_remove (void);
+ extern int sh_html_zero();
+#endif
+
+#if defined(SH_WITH_SERVER)
+ sh_socket_remove ();
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ if (modList[modnum].initval == SH_MOD_ACTIVE)
+ (void) modList[modnum].mod_cleanup();
+ }
+#ifdef HAVE_PTHREAD
+ sh_pthread_cancel_all();
+#endif
+#endif
+
+ /* --- Push out all pending messages. ---
+ */
+#if defined(SH_WITH_MAIL)
+ if (sh.mailNum.alarm_last > 0)
+ {
+ (void) sh_nmail_flush ();
+ }
+#endif
+
+ /* --- Write the server stat. ---
+ */
+#if defined(SH_WITH_SERVER)
+ /* zero out the status file at exit, such that the status
+ * of client becomes unknown in the beltane interface
+ */
+ sh_html_zero();
+#endif
+
+ /* --- Clean up memory to check for problems. ---
+ */
+#ifdef MEM_DEBUG
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ sh_files_deldirstack ();
+ sh_files_delfilestack ();
+ sh_files_delglobstack ();
+ sh_hash_hashdelete();
+ sh_files_hle_reg (NULL);
+ /*
+ * Only flush on exit if running as deamon.
+ * Otherwise we couldn't run another instance
+ * while the deamon is running (would leave the
+ * deamon with flushed ruleset).
+ */
+ if (sh.flag.isdaemon == S_TRUE)
+ {
+ sh_audit_delete_all ();
+ }
+#endif
+#if defined(SH_WITH_SERVER)
+ sh_xfer_free_all ();
+#endif
+#if defined(SH_WITH_MAIL)
+ sh_nmail_free();
+#endif
+ delete_cache();
+ sh_userid_destroy ();
+ sh_mem_stat();
+#endif
+
+#ifdef MEM_DEBUG
+ sh_unix_count_mlock();
+#endif
+
+ /* --- Checksum of executable. ---
+ */
+ {
+ volatile int sig_store = sig_termfast;
+
+ sig_termfast = 0;
+ (void) sh_unix_self_check();
+ sig_termfast = sig_store;
+ }
+
+
+ /* --- Exit Message. ---
+ */
+ if (sh.flag.exit == EXIT_FAILURE && !strcmp(sh_sig_msg, _("None")))
+ sl_strlcpy(sh_sig_msg, _("exit_failure"), SH_MINIBUF);
+ if (sh.flag.exit == EXIT_SUCCESS && !strcmp(sh_sig_msg, _("None")))
+ sl_strlcpy(sh_sig_msg, _("exit_success"), SH_MINIBUF);
+ sh_error_handle ((-1), FIL__, __LINE__, sh.flag.exit, MSG_EXIT_NORMAL,
+ sh.prg_name, sh_sig_msg);
+#ifdef SH_USE_XML
+ (void) sh_log_file (NULL, NULL);
+#endif
+
+
+ /* --- Restrict error logging to stderr. ---
+ */
+ close_ipc ();
+ sh_error_only_stderr (S_TRUE);
+
+ /* --- Remove lock, delete critical information. ---
+ */
+ (void) sh_unix_rm_lock_file (sh.srvlog.name);
+ if (sh.flag.isdaemon == S_TRUE)
+ (void) sh_unix_rm_pid_file ();
+ if (skey != NULL)
+ memset (skey, (int) '\0', sizeof(sh_key_t));
+
+ /* --- Exit. ---
+ */
+ SL_RET0(_("exit_handler"));
+}
+
+/***********************************************************
+ *
+ */
+#ifndef SIGHUP
+#define SIGHUP 1
+#endif
+#ifndef SIGTERM
+#define SIGTERM 15
+#endif
+#ifndef SIGKILL
+#define SIGKILL 9
+#endif
+
+#if defined(__linux__) || defined(sun) || defined(__sun) || defined(__sun__)
+#include <dirent.h>
+static pid_t * procdirSamhain (void)
+{
+ pid_t * pidlist;
+ struct dirent * d;
+ DIR * dp;
+ long ino;
+ struct stat buf;
+ int i;
+ pid_t pid, mypid = getpid();
+ char * tail;
+ char exef[128];
+
+ if (0 != stat(SH_INSTALL_PATH, &buf))
+ {
+ return NULL;
+ }
+
+ ino = (long) buf.st_ino;
+
+ if (NULL == (dp = opendir(_("/proc"))))
+ {
+ return NULL;
+ }
+
+ SH_MUTEX_LOCK(mutex_readdir);
+
+ pidlist = calloc(1, sizeof(pid_t) * 65535);
+ if (!pidlist)
+ goto unlock_and_out;
+
+ for (i = 0; i < 65535; ++i) pidlist[i] = 0;
+
+ i = 0;
+ while (NULL != (d = readdir(dp)) && i < 65535)
+ {
+ if (0 != strcmp(d->d_name, ".") && 0 != strcmp(d->d_name, ".."))
+ {
+ errno = 0;
+ pid = (pid_t) strtol (d->d_name, &tail, 0);
+ if (*tail != '\0' || errno != 0)
+ continue;
+ if (pid == mypid)
+ continue;
+#if defined(__linux__)
+ sprintf(exef, _("/proc/%d/exe"), (int) pid); /* known to fit */
+#else
+ sprintf(exef, _("/proc/%d/object/a.out"), /* known to fit */
+ (int) pid);
+#endif
+ if (0 == stat(exef, &buf) && ino == (long) buf.st_ino)
+ { pidlist[i] = (pid_t) pid; ++i; }
+ }
+ }
+
+ unlock_and_out:
+ ;
+ SH_MUTEX_UNLOCK(mutex_readdir);
+
+ closedir(dp);
+ return pidlist;
+}
+#else
+static pid_t * procdirSamhain (void)
+{
+ return NULL;
+}
+#endif
+
+static int killprocSamhain (pid_t pid)
+{
+ int i;
+
+ /* fprintf(stderr, "Killing %d\n", pid); */
+ if (pid > 0 && 0 == kill (pid, SIGTERM))
+ {
+ for (i = 0; i < 16; ++i)
+ {
+ (void) retry_msleep(1, 0);
+ if (0 != kill (pid, 0) && errno == ESRCH)
+ return (0);
+ }
+
+ (void) kill (pid, SIGKILL);
+ return (0);
+ }
+ if (pid > 0)
+ {
+ if (errno == ESRCH)
+ return 7;
+ if (errno == EPERM)
+ return 4;
+ return 1;
+ }
+ else
+ return (7);
+}
+
+static pid_t pidofSamhain (int flag)
+{
+ FILE * fp;
+ char line[256];
+ char * tail;
+ char * p;
+ pid_t pid;
+ long inpid;
+ struct stat buf;
+
+ fp = fopen (DEFAULT_ERRLOCK, "r");
+
+ if (!fp)
+ { if (errno != ENOENT) perror(_("fopen")); return 0; }
+ if (NULL == fgets(line, sizeof(line), fp))
+ { perror(_("fgets")); (void) sl_fclose(FIL__, __LINE__, fp); return 0; }
+ (void) sl_fclose(FIL__, __LINE__, fp);
+ p = line;
+ while (*p == ' ' || *p == '\f' || *p == '\n' ||
+ *p == '\r' || *p == '\t' || *p == '\v')
+ ++p;
+ errno = 0;
+ inpid = strtol (p, &tail, 0);
+ if (p == tail || errno != 0)
+ { perror(_("strtol")); return 0; }
+
+ pid = (pid_t) inpid;
+ if (inpid != (long) pid)
+ { perror(_("strtol")); return 0; }
+
+ /* remove stale pid file
+ */
+ if (flag == 1 && pid > 0 && 0 != kill(pid, 0) && errno == ESRCH)
+ {
+ if /*@-unrecog@*/ (0 == lstat (DEFAULT_ERRLOCK, &buf))/*@+unrecog@*/
+ {
+ if /*@-usedef@*/(S_ISREG(buf.st_mode))/*@+usedef@*/
+ {
+ (void) unlink(DEFAULT_ERRLOCK);
+ }
+ }
+ else
+ {
+ perror(_("lstat")); return 0;
+ }
+ pid = 0;
+ }
+ return pid;
+}
+
+/* 1: start 2:stop 3:reload 4:status
+ */
+/*@-exitarg@*/
+static int samhainctl(int ctl, int * argc, char * argv[])
+{
+ char * fullpath;
+ pid_t pid;
+ int status;
+ int res;
+ pid_t respid;
+ int times;
+ char * argp[32];
+ pid_t * pidlist;
+ int i;
+#ifdef WCONTINUED
+ int wflags = WNOHANG|WUNTRACED|WCONTINUED;
+#else
+ int wflags = WNOHANG|WUNTRACED;
+#endif
+
+ fullpath = strdup (SH_INSTALL_PATH);
+ if (fullpath == NULL)
+ { perror(_("strdup")); exit (1); }
+
+ argp[0] = strdup (SH_INSTALL_PATH);
+ if (argp[0] == NULL)
+ { perror(_("strdup")); exit (1); }
+
+ for (times = 1; times < 32; ++times) argp[times] = NULL;
+
+ res = (*argc > 32) ? 32 : *argc;
+
+ for (times = 2; times < res; ++times)
+ {
+ argp[times-1] = strdup (argv[times]);
+ if (argp[times-1] == NULL)
+ { perror(_("strdup")); exit (1); }
+ }
+
+ if (ctl == 1)
+ {
+ pid = pidofSamhain(1);
+
+ if (pid != 0 && 0 == kill (pid, 0)) /* already started */
+ exit (0);
+
+ pid = fork();
+ switch (pid) {
+ case ((pid_t) -1):
+ perror(_("fork"));
+ exit (1);
+ case 0:
+ if (0 != sl_close_fd (FIL__, __LINE__, 0))
+ {
+ _exit(4);
+ }
+ (void) execv(fullpath, argp); /* flawfinder: ignore *//* wtf? */
+ if (errno == EPERM)
+ _exit(4);
+ else if (errno == ENOENT)
+ _exit(5);
+ _exit (1);
+ default:
+ times = 0;
+ while (times < 300) {
+ respid = waitpid(pid, &status, wflags);
+ if ((pid_t)-1 == respid)
+ {
+ perror(_("waitpid"));
+ exit (1);
+ }
+ else if (pid == respid)
+ {
+#ifndef USE_UNO
+ if (0 != WIFEXITED(status))
+ {
+ res = WEXITSTATUS(status);
+ exit (res == 0 ? 0 : res );
+ }
+ else
+ exit (1);
+#else
+ exit (1);
+#endif
+ }
+ ++times;
+ (void) retry_msleep(1, 0);
+ }
+ exit (0); /* assume that it runs ok */
+ }
+ }
+
+ pid = pidofSamhain(0);
+
+ if (ctl == 2) /* stop */
+ {
+ pidlist = procdirSamhain ();
+ if (pid == 0 && NULL == pidlist) /* pid file not found */
+ {
+ free(fullpath);
+ return (0);
+ }
+
+ status = 0;
+ if (pid != 0)
+ status = killprocSamhain(pid);
+ if (pidlist != NULL)
+ {
+ i = 0;
+ while (i < 65535 && pidlist[i] != 0)
+ {
+ if (pidlist[i] != pid)
+ status = killprocSamhain(pidlist[i]);
+ ++i;
+ }
+ }
+ free(fullpath);
+ if (status == 7)
+ return 0;
+ else
+ return status;
+ }
+
+ if (ctl == 3) /* reload */
+ {
+ if (pid == 0)
+ exit (7);
+ if (0 == kill (pid, SIGHUP))
+ exit (0);
+ else
+ {
+ if (errno == EPERM)
+ exit (4);
+ if (errno == ESRCH)
+ exit (7);
+ exit (1);
+ }
+ }
+
+ if (ctl == 4) /* status */
+ {
+ if (pid == 0)
+ exit (3);
+ if (0 == kill (pid, 0))
+ exit (0);
+ else
+ {
+ if (errno == EPERM)
+ exit (4);
+ if (errno == ESRCH)
+ exit (1);
+ }
+ }
+ free(fullpath); /* silence smatch false positive */
+ exit (1); /* no exit handler installed yet */
+ /*@notreached@*/
+ return (0);
+}
+/*@+exitarg@*/
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+#include "sh_schedule.h"
+static sh_schedule_t * FileSchedOne = NULL;
+static sh_schedule_t * FileSchedTwo = NULL;
+
+/* free a linked list of schedules
+ */
+static sh_schedule_t * free_sched (sh_schedule_t * isched)
+{
+ sh_schedule_t * current = isched;
+ sh_schedule_t * next = NULL;
+
+ while (current != NULL)
+ {
+ next = current->next;
+ SH_FREE(current);
+ current = next;
+ }
+ return NULL;
+}
+
+/* Add a new schedule to the linked list of schedules
+ */
+static sh_schedule_t * sh_set_schedule_int (const char * str,
+ sh_schedule_t * FileSchedIn,
+ /*@out@*/ int * status)
+{
+ sh_schedule_t * FileSched;
+
+ SL_ENTER(_("sh_set_schedule_int"));
+
+ if (0 == sl_strncmp(str, _("NULL"), 4))
+ {
+ (void) free_sched(FileSchedIn);
+ FileSchedIn = NULL;
+ *status = 0;
+ SL_RETURN(NULL, _("sh_set_schedule_int"));
+ }
+
+ FileSched = SH_ALLOC(sizeof(sh_schedule_t));
+ *status = create_sched(str, FileSched);
+ if (*status != 0)
+ {
+ SH_FREE(FileSched);
+ FileSched = NULL;
+ SL_RETURN(FileSchedIn , _("sh_set_schedule_int"));
+ }
+ else {
+ FileSched->next = FileSchedIn;
+ }
+ SL_RETURN(FileSched , _("sh_set_schedule_int"));
+}
+
+/* Add a new schedule to the linked list FileSchedOne
+ */
+int sh_set_schedule_one (const char * str)
+{
+ int status;
+ FileSchedOne = sh_set_schedule_int (str, FileSchedOne, &status);
+ return status;
+}
+
+/* Add a new schedule to the linked list FileSchedTwo
+ */
+int sh_set_schedule_two (const char * str)
+{
+ int status;
+ FileSchedTwo = sh_set_schedule_int (str, FileSchedTwo, &status);
+ return status;
+}
+
+static int sh_flag_silent = S_FALSE;
+
+int sh_set_silent_full (const char * str)
+{
+ int status = sh_util_flagval(str, &sh_flag_silent);
+ return status;
+}
+
+
+void do_reconf()
+{
+ int status, modnum;
+
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_RECONF);
+
+ sh_thread_pause_flag = S_TRUE;
+
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ if (0 != (SH_MODFL_NEEDPAUSED & modList[modnum].flags) &&
+ modList[modnum].initval == SH_MOD_THREAD)
+ {
+ int count = 50;
+ while (count && 0 == (SH_MODFL_ISPAUSED & modList[modnum].flags))
+ retry_msleep(0, 100), --count;
+ }
+ }
+
+#if defined(WITH_EXTERNAL)
+ /* delete list of external tasks
+ */
+ (void) sh_ext_cleanup();
+#endif
+#if defined(SH_WITH_MAIL)
+ sh_nmail_free();
+#endif
+
+ /* delete the file list, make all database
+ * entries visible (allignore = FALSE)
+ */
+ (void) sh_files_deldirstack ();
+ (void) sh_files_delfilestack ();
+ (void) sh_files_delglobstack ();
+ (void) sh_ignore_clean ();
+ (void) hash_full_tree ();
+ sh_audit_delete_all ();
+
+
+#if defined(SH_WITH_CLIENT)
+ reset_count_dev_server();
+#endif
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ sh_restrict_purge ();
+
+
+ FileSchedOne = free_sched(FileSchedOne);
+ FileSchedTwo = free_sched(FileSchedTwo);
+
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ /* sh_thread_pause_flag is true, and we block in lock
+ * until check has returned, so we are sure check will
+ * not run until sh_thread_pause_flag is set to false
+ */
+ /* if (modList[modnum].initval >= SH_MOD_ACTIVE) */
+ (void) modList[modnum].mod_reconf();
+ }
+#endif
+
+ reset_count_dev_console();
+ reset_count_dev_time();
+
+ (void) sh_unix_maskreset();
+
+#ifdef RELOAD_DATABASE
+ sh_hash_hashdelete();
+
+ if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
+ {
+ char hashbuf[KEYBUF_SIZE];
+ (void) sl_strlcpy(sh.data.hash,
+ sh_tiger_hash (file_path('D', 'R'),
+ TIGER_FILE, TIGER_NOLIM,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+#endif
+ (void) sl_trust_purge_user();
+ (void) sh_files_hle_reg (NULL);
+ (void) sh_prelink_run (NULL, NULL, 0, 0);
+
+ /* --------------------------
+ * --- READ CONFIGURATION ---
+ * --------------------------
+ */
+ (void) sh_readconf_read ();
+ sig_config_read_again = 0;
+ (void) sh_files_setrec();
+ (void) sh_files_test_setup();
+ sh_audit_commit ();
+
+ if (0 != sh.flag.nice)
+ {
+#ifdef HAVE_SETPRIORITY
+ setpriority(PRIO_PROCESS, 0, sh.flag.nice);
+#else
+ nice(sh.flag.nice);
+#endif
+ }
+
+ if (sh.flag.checkSum == SH_CHECK_INIT)
+ {
+ sh.flag.isdaemon = S_FALSE;
+ sh.flag.loop = S_FALSE;
+ }
+
+
+ /* --- Initialize modules. ---
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Initialize modules.>\n")));
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ status = modList[modnum].mod_init(&(modList[modnum]));
+
+ if (status < 0)
+ {
+ if (status == (-1)) {
+ sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__,
+ status, MSG_MOD_FAIL,
+ _(modList[modnum].name),
+ status+SH_MOD_OFFSET);
+ } else {
+ sh_error_handle ((-1), FIL__, __LINE__,
+ status, MSG_MOD_FAIL,
+ _(modList[modnum].name),
+ status+SH_MOD_OFFSET);
+ }
+ modList[modnum].initval = SH_MOD_FAILED;
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MOD_OK,
+ _(modList[modnum].name));
+ modList[modnum].initval = status;
+ }
+ }
+
+ /* module is properly set up now
+ */
+ sh_thread_pause_flag = S_FALSE;
+
+ return;
+}
+
+static void check_signals (volatile int *flag_check_1,
+ volatile int * flag_check_2)
+{
+ if (sig_raised > 0)
+ {
+
+ TPT((0, FIL__, __LINE__, _("msg=<Process a signal.>\n")))
+
+ if (sig_termfast == 1) /* SIGTERM */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ --sig_raised; --sig_urgent;
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ }
+
+ if (sig_force_check == 1) /* SIGTTOU / SIGTSTP */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Check run triggered.>\n")));
+ *flag_check_1 = 1; *flag_check_2 = 1;
+ sig_force_check = 0; --sig_raised;
+ if (sig_force_silent)
+ {
+ sig_force_silent = 0;
+ sh_global_check_silent = (sh_flag_silent == S_FALSE) ? SH_SILENT_STD : SH_SILENT_FULL;
+ }
+ sh_sem_trylock();
+ }
+
+ if (sig_config_read_again == 1 && /* SIGHUP */
+ sh_global_suspend_flag == 0)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Re-read configuration.>\n")));
+ do_reconf();
+ --sig_raised;
+ }
+
+ if (sig_fresh_trail == 1) /* SIGIOT */
+ {
+ if (sh_global_suspend_flag == 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+
+ /* Logfile access
+ */
+#ifdef SH_USE_XML
+ (void) sh_log_file (NULL, NULL);
+#endif
+ TPT((0, FIL__, __LINE__, _("msg=<Logfile stop/restart.>\n")));
+ sh_error_only_stderr (S_TRUE);
+ (void) sh_unix_rm_lock_file(sh.srvlog.name);
+ (void) retry_msleep(3, 0);
+ sh.flag.log_start = S_TRUE;
+ sh_error_only_stderr (S_FALSE);
+ sh_thread_pause_flag = S_FALSE;
+ sig_fresh_trail = 0;
+ --sig_raised;
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+
+ if (sig_terminate == 1) /* SIGQUIT */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ strncpy (sh_sig_msg, _("Quit"), 20);
+ --sig_raised;
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ }
+
+ if (sig_debug_switch == 1) /* SIGUSR1 */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Debug switch.>\n")));
+ sh_error_dbg_switch();
+ sig_debug_switch = 0;
+ --sig_raised;
+ }
+
+ if (sig_suspend_switch > 0) /* SIGUSR2 */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Suspend switch.>\n")));
+ if (sh_global_suspend_flag != 1) {
+ SH_MUTEX_LOCK_UNSAFE(mutex_thread_nolog);
+ sh_global_suspend_flag = 1;
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_SUSPEND,
+ sh.prg_name);
+ } else {
+ sh_global_suspend_flag = 0;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_thread_nolog);
+ }
+ --sig_suspend_switch;
+ --sig_raised; --sig_urgent;
+ }
+
+ if (sh_load_delta_flag > 0 &&
+ sh_global_suspend_flag == 0) /* DELTA Command */
+ {
+ if (0 == sh_dbIO_load_delta())
+ {
+ --sh_load_delta_flag; --sig_raised;
+ }
+ }
+
+ sig_raised = (sig_raised < 0) ? 0 : sig_raised;
+ sig_urgent = (sig_urgent < 0) ? 0 : sig_urgent;
+ TPT((0, FIL__, __LINE__, _("msg=<End signal processing.>\n")));
+ }
+ return;
+}
+
+void check_for_delta_db()
+{
+ /* Need to contact the server.
+ */
+ if (sh_global_check_silent < SH_SILENT_FULL)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_CHECK_2);
+
+ if (sig_raised > 0 && sh_load_delta_flag > 0) /* DELTA Command */
+ {
+ /* There was a DELTA Command
+ */
+ if (0 == sh_dbIO_load_delta())
+ {
+ --sh_load_delta_flag; --sig_raised;
+ }
+ }
+ return;
+}
+
+#endif
+
+/*******************************************************
+ *
+ * Main program
+ *
+ *******************************************************/
+#if !defined(SH_CUTEST)
+int main(int argc, char * argv[])
+#else
+int undef_main(int argc, char * argv[])
+#endif
+{
+#if defined(INET_SYSLOG)
+ extern int sh_xfer_create_syslog_socket (int flag);
+#endif
+#if defined(SH_WITH_SERVER)
+ extern int sh_create_tcp_socket(void);
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ int modnum;
+ time_t runtim;
+ float st_1, st_2;
+ int status;
+ volatile long cct = 0; /* main loop iterations */
+
+ volatile int flag_check_1 = 0;
+ volatile int flag_check_2 = 0;
+
+ int check_done = 0;
+#endif
+
+ volatile time_t told;
+ volatile time_t tcurrent;
+ size_t tzlen;
+ char * tzptr;
+ int res;
+
+#if defined (SH_STEALTH_NOCL)
+ char command_line[256];
+ int my_argc = 0;
+ char * my_argv[32];
+#endif
+
+#if !defined(USE_SYSTEM_MALLOC)
+ typedef void assert_handler_tp(const char * error, const char *file, int line);
+ extern assert_handler_tp *dnmalloc_set_handler(assert_handler_tp *new);
+ (void) dnmalloc_set_handler(safe_fatal);
+#endif
+
+ SH_G_INIT; /* Must precede any use of _() */
+
+ SL_ENTER(_("main"));
+
+ /* --- Close all but first three file descriptors. ---
+ */
+ sh_unix_closeall(3, -1, S_FALSE); /* at program start */
+
+
+ if (argc >= 2 && 0 != getuid() &&
+ (0 == strcmp(argv[1], _("start")) ||
+ 0 == strcmp(argv[1], _("stop")) ||
+ 0 == strcmp(argv[1], _("reload")) ||
+ 0 == strcmp(argv[1], _("force-reload")) ||
+ 0 == strcmp(argv[1], _("status")) ||
+ 0 == strcmp(argv[1], _("restart"))))
+ {
+ return 4;
+ }
+
+ if (argc >= 2 && 0 == getuid())
+ {
+ /* return codes:
+ * 0 Success
+ * 1 Can not send signal / start program
+ * 2 Pid file does not exist
+ */
+ if (0 == strcmp(argv[1], _("start")))
+ {
+ (void) samhainctl (1, &argc, argv); /* does not return */
+ }
+ else if (0 == strcmp(argv[1], _("stop")))
+ return (samhainctl (2, &argc, argv));
+ else if (0 == strcmp(argv[1], _("reload")))
+ (void) samhainctl (3, &argc, argv); /* does not return */
+ else if (0 == strcmp(argv[1], _("force-reload")))
+ (void) samhainctl (3, &argc, argv); /* does not return */
+ else if (0 == strcmp(argv[1], _("status")))
+ (void) samhainctl (4, &argc, argv); /* does not return */
+ else if (0 == strcmp(argv[1], _("restart")))
+ {
+ res = samhainctl (2, &argc, argv);
+ if (res == 0 || res == 7)
+ {
+ (void) samhainctl (1, &argc, argv); /* does not return */
+ }
+ else
+ return (res);
+ }
+ }
+
+ /* if fd 0 is closed, presume that we want to be daemon and
+ * run in check mode
+ */
+ if ((-1) == retry_fcntl(FIL__, __LINE__, 0, F_GETFL, 0) &&
+ errno == EBADF)
+ {
+ sh.flag.opts = S_TRUE;
+ (void) sh_unix_setdeamon(NULL);
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ sh.flag.checkSum = SH_CHECK_CHECK;
+ /* (void) sh_util_setchecksum(_("check")); */
+#endif
+ is_samhainctl_init = S_TRUE;
+ sh.flag.opts = S_FALSE;
+ }
+
+
+ /* --- Install the exit handler. ---
+ */
+ (void) atexit(exit_handler);
+
+ /* --- Zero the mailer key, and fill it. ---
+ */
+ memset (ErrFlag, 0, 2*sizeof(UINT32));
+
+#ifdef MKA_01
+ ErrFlag[0] |= (1 << 0);
+#endif
+#ifdef MKA_02
+ ErrFlag[0] |= (1 << 1);
+#endif
+#ifdef MKA_03
+ ErrFlag[0] |= (1 << 2);
+#endif
+#ifdef MKA_04
+ ErrFlag[0] |= (1 << 3);
+#endif
+#ifdef MKA_05
+ ErrFlag[0] |= (1 << 4);
+#endif
+#ifdef MKA_06
+ ErrFlag[0] |= (1 << 5);
+#endif
+#ifdef MKA_07
+ ErrFlag[0] |= (1 << 6);
+#endif
+#ifdef MKA_08
+ ErrFlag[0] |= (1 << 7);
+#endif
+
+#if defined(SCREW_IT_UP)
+ BREAKEXIT(sh_sigtrap_prepare);
+ (void) sh_sigtrap_prepare();
+#endif
+
+ /* Save the timezone.
+ */
+ if (NULL != (tzptr = getenv("TZ"))) /* flawfinder: ignore */
+ {
+ tzlen = strlen(tzptr);
+ if (tzlen < 1024)
+ {
+ sh.timezone = calloc(1, tzlen + 1);
+ if (sh.timezone != NULL)
+ (void) sl_strlcpy (sh.timezone, tzptr, tzlen + 1);
+ }
+ else
+ sh.timezone = NULL;
+ }
+ else
+ sh.timezone = NULL;
+
+
+ /* -------- INIT --------
+ */
+ sh_unix_ign_sigpipe();
+
+ /* Restrict error logging to stderr.
+ */
+ sh_error_only_stderr (S_TRUE);
+
+ /* Check that first three descriptors are open.
+ */
+ if ( retry_fcntl(FIL__, __LINE__, 0, F_GETFL, 0) == (-1))
+ (void) aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 0);
+ if ( retry_fcntl(FIL__, __LINE__, 1, F_GETFL, 0) == (-1))
+ (void) aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 1);
+ if ( retry_fcntl(FIL__, __LINE__, 2, F_GETFL, 0) == (-1))
+ (void) aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 2);
+
+ /* --- Set default values. ---
+ */
+ BREAKEXIT(sh_init);
+ sh_init (); /* we are still privileged here, so we can mlock skey */
+#if (defined (SH_WITH_SERVER) && !defined (SH_WITH_CLIENT))
+ sh.flag.isserver = S_TRUE;
+#endif
+
+ /* --- First check for an attached debugger (after setting
+ sh.sigtrap_max_duration which has to be done before). ---
+ */
+ BREAKEXIT(sh_derr);
+ (void) sh_derr();
+
+ /* --- Get local hostname. ---
+ */
+ BREAKEXIT(sh_unix_localhost);
+ sh_unix_localhost();
+
+ /* --- Read the command line. ---
+ */
+ sh.flag.opts = S_TRUE;
+
+#if !defined(SH_STEALTH_NOCL)
+ sh_argc_store = argc;
+ sh_argv_store = argv;
+ (void) sh_getopt_get (argc, argv);
+#else
+ if (argc > 1 && argv[1] != NULL &&
+ strlen(argv[1]) > 0 && strlen(NOCL_CODE) > 0)
+ {
+ if ( 0 == strcmp(argv[1], NOCL_CODE) )
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+#endif
+ my_argv[0] = argv[0]; ++my_argc;
+ command_line[0] = '\0';
+ if (NULL != fgets (command_line, sizeof(command_line), stdin))
+ command_line[sizeof(command_line)-1] = '\0';
+
+ do {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ my_argv[my_argc] =
+ strtok_r( (my_argc == 1) ? command_line : NULL, " \n", &saveptr);
+#else
+ my_argv[my_argc] =
+ strtok( (my_argc == 1) ? command_line : NULL, " \n");
+#endif
+ if (my_argv[my_argc] != NULL) {
+ ++my_argc;
+ } else {
+ break;
+ }
+ } while (my_argc < 32);
+
+ sh_argc_store = my_argc;
+ sh_argv_store = my_argv;
+
+ (void) sh_getopt_get (my_argc, my_argv);
+ }
+ else
+ {
+ /* discard command line */
+ /* _exit(EXIT_FAILURE) */ ;
+ }
+ }
+#endif
+ sh.flag.opts = S_FALSE;
+
+
+ /* --- Get user info. ---
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Get user name.>\n")))
+ if (0 != sh_unix_getUser ())
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+
+ /* *****************************
+ *
+ * Read the configuration file.
+ *
+ * *****************************/
+
+ TPT((0, FIL__, __LINE__, _("msg=<Read the configuration file.>\n")))
+ BREAKEXIT(sh_readconf_read);
+ (void) sh_readconf_read ();
+
+ sh_calls_enable_sub();
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (sh.flag.checkSum == SH_CHECK_NONE)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("No action specified: init, update, or check"),
+ _("main"));
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+#endif
+
+ /* do not append to database if run SUID
+ */
+ if ((sh.flag.checkSum == SH_CHECK_INIT) && (0 != sl_is_suid()))
+ {
+ (void) dlog(1, FIL__, __LINE__,
+ _("Cannot initialize database when running with SUID credentials.\nYou need to run this with the user ID %d.\nYour current user ID is %d."),
+ (int) geteuid(), (int) sh.real.uid);
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_ACCESS,
+ (long) sh.real.uid, sh.data.path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* avoid daemon mode for initialization
+ */
+ if (sh.flag.checkSum == SH_CHECK_INIT)
+ {
+ sh.flag.isdaemon = S_FALSE;
+ sh.flag.loop = S_FALSE;
+ }
+
+ /* --- load database; checksum of database
+ */
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (0 == sh.delayload)
+ sh_hash_init_and_checksum();
+#endif
+
+ /* --- initialize signal handling etc.; fork daemon
+ */
+ if (sh_unix_init(sh.flag.isdaemon) == -1)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (sh.delayload)
+ {
+ sleep(sh.delayload);
+ sh_hash_init_and_checksum();
+ }
+#endif
+
+ /* --- drop privileges eventually ---
+ */
+#if defined(SH_WITH_SERVER)
+ sh_create_tcp_socket ();
+#if defined(INET_SYSLOG)
+ sh_xfer_create_syslog_socket (S_TRUE);
+#endif
+ SL_REQUIRE(sl_policy_get_real(DEFAULT_IDENT) == SL_ENONE,
+ _("sl_policy_get_real(DEFAULT_IDENT) == SL_ENONE"));
+#else
+ SL_REQUIRE(sl_policy_get_user(DEFAULT_IDENT) == SL_ENONE,
+ _("sl_policy_get_user(DEFAULT_IDENT) == SL_ENONE"));
+#endif
+
+ /* --- Get user info (again). ---
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Get user name.>\n")))
+ if (0 != sh_unix_getUser ())
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* --- now check whether we really wanted it; if not, close ---
+ */
+#if defined(INET_SYSLOG) && defined(SH_WITH_SERVER)
+ sh_xfer_create_syslog_socket (S_FALSE);
+#endif
+
+
+ /* --- Enable full error logging ---
+ */
+ sh_error_only_stderr (S_FALSE);
+
+ sh.flag.started = S_TRUE;
+
+ /****************************************************
+ *
+ * SERVER
+ *
+ ****************************************************/
+
+#if defined(SH_WITH_SERVER) && !defined(SH_WITH_CLIENT)
+
+#if (defined(WITH_GPG) || defined(WITH_PGP))
+ /* log startup */
+ sh_gpg_log_startup ();
+#else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_1H,
+ sh.prg_name, (long) sh.real.uid,
+ (sh.flag.hidefile == S_TRUE) ?
+ _("(hidden)") : file_path('C','R'),
+ sh.conf.hash);
+#endif
+
+#else
+
+ /****************************************************
+ *
+ * CLIENT/STANDALONE
+ *
+ ****************************************************/
+
+ BREAKEXIT(sh_error_handle);
+
+ if (sh.flag.checkSum == SH_CHECK_CHECK)
+ {
+#if (defined(WITH_GPG) || defined(WITH_PGP))
+ /* log startup */
+ sh_gpg_log_startup ();
+#else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_2H,
+ sh.prg_name, (long) sh.real.uid,
+ (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('C', 'R'), sh.conf.hash,
+ (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('D', 'R'), sh.data.hash);
+#endif
+ }
+ else
+ {
+#if (defined(WITH_GPG) || defined(WITH_PGP))
+ /* log startup */
+ sh_gpg_log_startup ();
+#else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_1H,
+ sh.prg_name, (long) sh.real.uid,
+ (sh.flag.hidefile == S_TRUE) ? _("(hidden)") : file_path('C', 'R'), sh.conf.hash);
+#endif
+ }
+#endif
+
+
+ if ((skey == NULL) || (skey->mlock_failed == S_TRUE))
+ sh_error_handle ((-1), FIL__, __LINE__, EPERM, MSG_MLOCK);
+
+ /* timer
+ */
+ tcurrent = time (NULL);
+ told = tcurrent;
+ sh.mailTime.alarm_last = told;
+
+
+ /****************************************************
+ *
+ * SERVER
+ *
+ ****************************************************/
+
+#if defined(SH_WITH_SERVER)
+ TPT((0, FIL__, __LINE__, _("msg=<Start server.>\n")))
+
+#if defined (SH_WITH_CLIENT)
+ if (sh.flag.isserver == S_TRUE)
+ {
+ sh_xfer_start_server();
+ TPT((0, FIL__, __LINE__, _("msg=<End server.>\n")))
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ }
+#else
+ sh_xfer_start_server();
+ TPT((0, FIL__, __LINE__, _("msg=<End server.>\n")))
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+#endif
+
+#endif
+
+ /****************************************************
+ *
+ * CLIENT/STANDALONE
+ *
+ ****************************************************/
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+
+ /* --- Initialize modules. ---
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Initialize modules.>\n")))
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ status = modList[modnum].mod_init(&(modList[modnum]));
+ if ( status < 0 )
+ {
+ if (status == (-1)) {
+ sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, status,
+ MSG_MOD_FAIL,
+ _(modList[modnum].name),
+ status+SH_MOD_OFFSET);
+ } else {
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_MOD_FAIL,
+ _(modList[modnum].name),
+ status+SH_MOD_OFFSET);
+ }
+ modList[modnum].initval = SH_MOD_FAILED;
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MOD_OK,
+ _(modList[modnum].name));
+ modList[modnum].initval = status;
+ }
+ }
+
+ /* -------- TEST SETUP ---------
+ */
+ (void) sh_files_setrec();
+ (void) sh_files_test_setup();
+ sh_audit_commit ();
+
+ /* -------- NICE LEVEL ---------
+ */
+ if (0 != sh.flag.nice)
+ {
+#ifdef HAVE_SETPRIORITY
+ /*@-unrecog@*/
+ (void) setpriority(PRIO_PROCESS, 0, sh.flag.nice);
+ /*@+unrecog@*/
+#else
+ (void) nice(sh.flag.nice);
+#endif
+ }
+
+ /* -------- CREATE SEMAPHORE ---------
+ */
+ sh_sem_open();
+
+ /* -------- MAIN LOOP ---------
+ */
+ sh.statistics.bytes_speed = 0;
+ sh.statistics.bytes_hashed = 0;
+ sh.statistics.files_report = 0;
+ sh.statistics.files_error = 0;
+ sh.statistics.files_nodir = 0;
+
+ while (1 == 1)
+ {
+ ++cct;
+
+ BREAKEXIT(sh_error_handle);
+
+ TPT((0, FIL__, __LINE__, _("msg=<Start main loop.>, iter=<%ld>\n"), cct))
+
+ tcurrent = time (NULL);
+
+ do {
+ check_signals(&flag_check_1, &flag_check_2);
+ if (sh_global_suspend_flag == 1)
+ (void) retry_msleep (1, 0);
+ } while (sh_global_suspend_flag == 1);
+
+ /* see whether its time to check files
+ */
+ if (sh.flag.checkSum == SH_CHECK_INIT ||
+ (sh.flag.inotify & SH_INOTIFY_DOSCAN) != 0 ||
+ (sh.flag.checkSum == SH_CHECK_CHECK &&
+ (sh.flag.isdaemon == S_FALSE && sh.flag.loop == S_FALSE)))
+ {
+ flag_check_1 = 1;
+ if (FileSchedTwo != NULL)
+ flag_check_2 = 1;
+ }
+ else if (sh.flag.checkSum == SH_CHECK_CHECK ||
+ (sh.flag.update == S_TRUE &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE)))
+ {
+ if (FileSchedOne == NULL)
+ {
+ /* use interval if we have no schedule
+ */
+ if (tcurrent - sh.fileCheck.alarm_last >=
+ sh.fileCheck.alarm_interval)
+ flag_check_1 = 1;
+ }
+ else
+ {
+ flag_check_1 = test_sched(FileSchedOne);
+ if (FileSchedTwo != NULL)
+ flag_check_2 = test_sched(FileSchedTwo);
+ if (flag_check_2 == 1)
+ flag_check_1 = 1;
+ }
+ }
+
+ check_done = 0;
+
+ if (sh.flag.checkSum != SH_CHECK_NONE &&
+ (flag_check_1 == 1 || flag_check_2 == 1))
+ {
+ sh_sem_trylock();
+
+ /* Starting a check now, so make sure to fetch delta DB
+ * if there is one to download.
+ */
+ check_for_delta_db();
+
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN; );
+ /* Refresh list files matching glob patterns.
+ */
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ sh_files_check_globPatterns();
+
+ /*
+ * check directories and files
+ * ORDER IS IMPORTANT -- DIRZ FIRST
+ */
+ sh.statistics.bytes_hashed = 0;
+ sh.statistics.time_start = time (NULL);
+ sh.statistics.dirs_checked = 0;
+ sh.statistics.files_checked = 0;
+ sh.statistics.files_report = 0;
+ sh.statistics.files_error = 0;
+ sh.statistics.files_nodir = 0;
+
+ TPT((0, FIL__, __LINE__, _("msg=<Check directories.>\n")))
+ BREAKEXIT(sh_dirs_chk);
+ if (flag_check_1 == 1)
+ {
+ (void) sh_dirs_chk (1);
+#ifndef SH_PROFILE
+ (void) retry_aud_chdir (FIL__, __LINE__, "/");
+#endif
+ }
+ if (flag_check_2 == 1)
+ {
+ (void) sh_dirs_chk (2);
+#ifndef SH_PROFILE
+ (void) retry_aud_chdir (FIL__, __LINE__, "/");
+#endif
+ }
+ TPT((0, FIL__, __LINE__, _("msg=<Check files.>\n")))
+ BREAKEXIT(sh_files_chk);
+ if (flag_check_1 == 1)
+ (void) sh_files_chk ();
+
+ if (sig_urgent > 0) { sh_sem_unlock(sh.statistics.files_report); sh_global_check_silent = 0; continue; }
+ /*
+ * check for files not visited
+ */
+ if (flag_check_2 == 1 || FileSchedTwo == NULL)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Check for missing files.>\n")))
+ sh_hash_unvisited (ShDFLevel[SH_ERR_T_FILE]);
+ }
+
+ if (sig_urgent > 0) { sh_sem_unlock(sh.statistics.files_report); sh_global_check_silent = 0; continue; }
+
+ /* reset
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Reset status.>\n")))
+ sh_dirs_reset ();
+
+ if (sig_urgent > 0) { sh_sem_unlock(sh.statistics.files_report); sh_global_check_silent = 0; continue; }
+
+ sh_files_reset ();
+ check_done = 1;
+
+ flag_check_1 = 0;
+ flag_check_2 = 0;
+ sh_sem_unlock(sh.statistics.files_report);
+
+ SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN; );
+ SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_DOSCAN; );
+
+ (void) sh_prelink_run (NULL, NULL, 0, 0);
+
+ if (sig_urgent > 0) { sh_global_check_silent = 0; continue; }
+
+ runtim = time(NULL) - sh.statistics.time_start;
+ sh.statistics.time_check = runtim;
+
+ if ((sh.statistics.dirs_checked == 0) &&
+ (sh.statistics.files_checked == 0) &&
+ (sh_global_check_silent < SH_SILENT_FULL))
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_CHECK_0);
+
+ else
+ {
+ st_1 = (float) sh.statistics.bytes_hashed;
+ st_2 = (float) runtim;
+
+
+ if (st_1 > FLT_EPSILON && st_2 > FLT_EPSILON)
+ st_1 = st_1/st_2;
+ else if (st_1 > FLT_EPSILON)
+ st_1 = (float) (st_1 * 1.0);
+ else
+ st_1 = 0.0;
+
+ sh.statistics.bytes_speed = (unsigned long) st_1;
+
+ if (sh_global_check_silent < SH_SILENT_FULL)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_CHECK_1,
+ (long) runtim,
+ 0.001 * st_1);
+
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ sh_efile_report();
+ }
+
+ if (0 == sh_global_check_silent)
+ sh.fileCheck.alarm_last = time (NULL);
+
+ sh_global_check_silent = 0;
+
+ if (sig_urgent > 0) continue;
+
+ /*
+ * flush mail queue
+ */
+#if defined(SH_WITH_MAIL)
+ TPT((0, FIL__, __LINE__, _("msg=<Flush mail queue.>\n")))
+ (void) sh_nmail_flush ();
+#endif
+ }
+
+ if (sig_urgent > 0) continue;
+
+ /* execute modules
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Execute modules.>\n")))
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ if (modList[modnum].initval == SH_MOD_ACTIVE &&
+ 0 != modList[modnum].mod_timer(tcurrent))
+ if (0 != (status = modList[modnum].mod_check()))
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_MOD_EXEC,
+ _(modList[modnum].name), (long) (status+SH_MOD_OFFSET));
+ }
+
+ /* 27.05.2002 avoid empty database
+ * 22.10.2002 moved here b/o suid check initialization
+ */
+ if (sh.flag.checkSum == SH_CHECK_INIT)
+ sh_dbIO_data_write (NULL, NULL);
+
+ /* write out database
+ */
+ if (sh.flag.checkSum == SH_CHECK_CHECK &&
+ sh.flag.update == S_TRUE &&
+ check_done == 1)
+ sh_dbIO_writeout_update ();
+
+ /* no-op unless MEM_LOG is defined in sh_mem.c
+ */
+#ifdef MEM_DEBUG
+ sh_mem_dump ();
+#endif
+
+ {
+ char * stale;
+
+ stale = sl_check_stale();
+ if (stale)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ stale, _("sl_check_stale"));
+ }
+
+ stale = sl_check_badfd();
+ if (stale)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ stale, _("sl_check_stale"));
+ }
+ }
+
+ /* no loop if not daemon
+ */
+ if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE) break;
+ if (sig_urgent > 0) continue;
+
+ /* see whether its time to send mail
+ */
+#if defined(SH_WITH_MAIL)
+ if (tcurrent - sh.mailTime.alarm_last >= sh.mailTime.alarm_interval)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Flush mail queue.>\n")))
+ (void) sh_nmail_flush ();
+ sh.mailTime.alarm_last = time (NULL);
+ }
+#endif
+ if (sig_urgent > 0) continue;
+
+ /* log the timestamp
+ */
+ if ((int)(tcurrent - told) >= sh.looptime )
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Log the timestamp.>\n")))
+ told = tcurrent;
+#ifdef MEM_DEBUG
+ sh_mem_check();
+ sh_unix_count_mlock();
+#else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_STAMP);
+#endif
+ }
+
+ /* seed / re-seed the PRNG if required
+ */
+ (void) taus_seed();
+
+ if (sig_urgent > 0) continue;
+
+ /* reset cache
+ */
+ sh_userid_destroy();
+
+ /* go to sleep
+ */
+ (void) retry_msleep (1, 0);
+
+ BREAKEXIT(sh_derr);
+ (void) sh_derr();
+ }
+
+ /* ------ END -----------
+ */
+
+
+
+ /*
+ * cleanup
+ */
+ TPT((0, FIL__, __LINE__, _("msg=<Cleanup.>\n")));
+ sh_hash_hashdelete();
+
+#if defined(SH_WITH_MAIL)
+ if (sh.mailNum.alarm_last > 0)
+ (void)sh_nmail_flush ();
+#endif
+
+ /* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ SL_RETURN(0, _("main"));
+}
diff --git a/src/samhain_setpwd.c b/src/samhain_setpwd.c
new file mode 100644
index 0000000..e8de644
--- /dev/null
+++ b/src/samhain_setpwd.c
@@ -0,0 +1,515 @@
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+
+#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
+#include <sched.h>
+#endif
+
+#if defined(HAVE_INT_32)
+typedef unsigned int UINT32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long UINT32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short UINT32;
+#endif
+
+#define TAUS_MAX 4294967295UL
+
+static UINT32 taus_state[3];
+
+static UINT32 taus_get ()
+{
+
+#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
+ taus_state[0] = TAUSWORTHE (taus_state[0], 13, 19, 4294967294UL, 12);
+ taus_state[1] = TAUSWORTHE (taus_state[1], 2, 25, 4294967288UL, 4);
+ taus_state[2] = TAUSWORTHE (taus_state[2], 3, 11, 4294967280UL, 17);
+ return (taus_state[0] ^ taus_state[1] ^ taus_state[2]);
+}
+
+static void taus_seed ()
+{
+ unsigned char buf[12];
+ unsigned char buf2[12];
+ unsigned char buf3[12];
+ ssize_t count;
+ size_t nbytes = sizeof(buf);
+ size_t where = 0;
+
+ struct timeval t1, t2;
+ UINT32 delta, k[3];
+ int i, j;
+
+ int fd = open ("/dev/urandom", O_RDONLY);
+
+ if (fd == -1)
+ {
+ gettimeofday(&t1, NULL);
+ delta = t1.tv_usec;
+ memcpy(&buf[0], &delta, 4);
+ gettimeofday(&t1, NULL);
+ delta = t1.tv_usec;
+ memcpy(&buf[4], &delta, 4);
+ gettimeofday(&t1, NULL);
+ delta = t1.tv_usec;
+ memcpy(&buf[8], &delta, 4);
+ goto second;
+ }
+
+ do {
+ count = read(fd, &buf[where], nbytes);
+ if (count == -1 && errno == EINTR)
+ continue;
+ where += count;
+ nbytes -= count;
+ } while (nbytes);
+
+ close(fd);
+
+ second:
+ for (i = 0; i < 12; ++i)
+ {
+ gettimeofday(&t1, NULL);
+ if (0 == fork())
+ _exit(EXIT_SUCCESS);
+ wait(NULL);
+ gettimeofday(&t2, NULL);
+ delta = t2.tv_usec - t1.tv_usec;
+ buf2[i] = (unsigned char) delta;
+ }
+
+ for (i = 0; i < 12; ++i)
+ {
+ gettimeofday(&t1, NULL);
+ for (j = 0; j < 32768; ++j)
+ {
+ if (0 == kill (j,0))
+ k[i % 3] ^= j;
+ }
+ gettimeofday(&t2, NULL);
+ delta = t2.tv_usec - t1.tv_usec;
+ buf3[i] ^= (unsigned char) delta;
+ }
+
+ memcpy(&taus_state[0], &buf3[0], 4);
+ memcpy(&taus_state[1], &buf3[4], 4);
+ memcpy(&taus_state[2], &buf3[8], 4);
+
+ taus_state[0] ^= k[0];
+ taus_state[1] ^= k[1];
+ taus_state[2] ^= k[2];
+
+ memcpy(&k[0], &buf2[0], 4);
+ memcpy(&k[1], &buf2[4], 4);
+ memcpy(&k[2], &buf2[8], 4);
+
+ taus_state[0] ^= k[0];
+ taus_state[1] ^= k[1];
+ taus_state[2] ^= k[2];
+
+ memcpy(&k[0], &buf[0], 4);
+ memcpy(&k[1], &buf[4], 4);
+ memcpy(&k[2], &buf[8], 4);
+
+ taus_state[0] ^= k[0];
+ taus_state[1] ^= k[1];
+ taus_state[2] ^= k[2];
+
+ taus_state[0] |= (UINT32) 0x03;
+ taus_state[1] |= (UINT32) 0x09;
+ taus_state[2] |= (UINT32) 0x17;
+}
+
+#ifdef SH_STEALTH
+char * globber(const char * string);
+#define _(string) globber(string)
+#define N_(string) string
+#else
+#define _(string) string
+#define N_(string) string
+#endif
+
+#ifdef SH_STEALTH
+#ifndef SH_MAX_GLOBS
+#define SH_MAX_GLOBS 32
+#endif
+char * globber(const char * str)
+{
+ register int i, j;
+ static int count = -1;
+ static char glob[SH_MAX_GLOBS][128];
+
+ ++count; if (count > (SH_MAX_GLOBS-1) ) count = 0;
+ j = strlen(str);
+ if (j > 127) j = 127;
+
+ for (i = 0; i < j; ++i)
+ {
+ if (str[i] != '\n' && str[i] != '\t')
+ glob[count][i] = str[i] ^ XOR_CODE;
+ else
+ glob[count][i] = str[i];
+ }
+ glob[count][j] = '\0';
+ return glob[count];
+}
+#endif
+
+/* This is a very inefficient algorithm, but there is really no
+ * need for anything more elaborated here. Can handle NULL's in haystack
+ * (not in needle), which strstr() apparently cannot.
+ */
+char * my_strstr (char * haystack, char * needle, int haystack_size)
+{
+ register int i = 0, j = 0;
+ register int siz;
+ register char * ptr = haystack;
+ register int len;
+
+ siz = strlen(needle);
+ len = haystack_size - siz;
+
+ while (j < len)
+ {
+ i = 0;
+ while (i < siz)
+ {
+ if (needle[i] != ptr[i]) break;
+ if (i == (siz-1))
+ return ptr;
+ ++i;
+ }
+ ++ptr; ++j;
+ }
+ return NULL;
+}
+
+/* fread() does not return the number of chars read, thus we need to
+ * read only a small number of bytes, in order not to expand the binary
+ * too much with the last fwrite(). Too lazy to fix this now.
+ */
+#define GRAB_SIZE 1024
+
+int readhexchar ( char c )
+{
+ if ( c >= '0' && c <= '9' )
+ return c - '0';
+ else if ( c >= 'a' && c <= 'f' )
+ return c - 'a' + 10;
+ else if ( c >= 'A' && c <= 'F' )
+ return c - 'A' + 10;
+ else return -1;
+}
+
+int main (int argc, char * argv[])
+{
+ /* the default password
+ */
+ unsigned char TcpFlag[9] = { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7 };
+ unsigned char BadFlag[9] = { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF };
+
+ char * found_it;
+ int i;
+ int suc = 0;
+ int badcnt = 0;
+
+ char * newn;
+ size_t nlen;
+ int oldf;
+ int newf;
+ int ret;
+
+ unsigned long bytecount;
+
+ char in[9];
+ int j, k;
+ char ccd;
+ char * str;
+
+ char * buf = (char *) malloc(GRAB_SIZE);
+ size_t dat;
+ char * newpwd = (char *) malloc(5 * 8 + 2);
+ char * oldpwd = (char *) malloc(5 * 8 + 2);
+
+ memset (newpwd, '\0', 5 * 8 + 2);
+ memset (oldpwd, '\0', 5 * 8 + 2);
+
+
+ if (argc < 4)
+ {
+ fprintf (stderr, "%s", _("\nUsage: samhain_setpwd <filename> <suffix> "\
+ "<new_password>\n\n"));
+ fprintf (stderr, "%s", _(" This program is a utility that will:\n"));
+ fprintf (stderr, "%s", _(" - search in the binary executable "\
+ "<filename> for samhain's\n"));
+ fprintf (stderr, "%s", _(" compiled-in default password,\n"));
+ fprintf (stderr, "%s", _(" - change it to <new_password>,\n"));
+ fprintf (stderr, "%s", _(" - and output the modified binary to "\
+ "<filename>.<suffix>\n\n"));
+ fprintf (stderr, "%s", _(" To allow for non-printable chars, "\
+ "<new_password> must be\n"));
+ fprintf (stderr, "%s", _(" a 16-digit hexadecimal "\
+ "number (only 0-9,A-F allowed in input),\n"));
+ fprintf (stderr, "%s", _(" thus corresponding"\
+ " to an 8-byte password.\n\n"));
+ fprintf (stderr, "%s", _(" Example: 'samhain_setpwd samhain new "\
+ "4142434445464748'\n"));
+ fprintf (stderr, "%s", _(" takes the file 'samhain', sets the "\
+ "password to 'ABCDEFGH'\n"));
+ fprintf (stderr, "%s", _(" ('A' = 41 hex, 'B' = 42 hex, ...) "\
+ "and outputs the result\n"));
+ fprintf (stderr, "%s", _(" to 'samhain.new'.\n"));
+ return EXIT_FAILURE;
+ }
+
+ if (strlen(argv[3]) != 16)
+ {
+ fprintf (stdout,
+ _("ERROR <new_password> |%s| has not exactly 16 chars\n"),
+ argv[3]);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+
+
+ str = &argv[3][0];
+ i = 0;
+ while (i < 16)
+ {
+ k = i/2; j = 0;
+ if (2*k == i) in[k] = 0;
+ while (j < 16)
+ {
+ if (-1 != readhexchar(str[i]))
+ {
+ in[k] += readhexchar(str[i]) * (i == 2*k ? 16 : 1);
+ break;
+ }
+ ++j;
+ if (j == 16)
+ {
+ fprintf(stdout, _("ERROR Invalid char %c\n"), str[i]);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+ }
+ ++i;
+ }
+ in[8] = '\0';
+
+ /* ---- initialize -----
+ */
+ (void) umask (0);
+
+ taus_seed();
+
+ bytecount = 0;
+
+
+ /* ---- open files -----
+ */
+
+ oldf = open(argv[1], O_RDONLY);
+
+ nlen = strlen(argv[1])+strlen(argv[2])+2;
+ newn = (char *) malloc (nlen);
+ strncpy(newn, argv[1], nlen); newn[nlen-1] = '\0';
+ strncat(newn, ".", nlen); newn[nlen-1] = '\0';
+ strncat(newn, argv[2], nlen); newn[nlen-1] = '\0';
+ newf = open(newn, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
+
+ if (oldf < 0)
+ {
+ fprintf(stdout, _("ERROR Cannot open input file %s.\n"), argv[1]);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+ if (newf < 0)
+ {
+ fprintf(stdout, _("ERROR Cannot open output file %s.\n"), newn);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+
+ /* ---- scan file -----
+ */
+
+
+ while (1)
+ {
+ dat = read (oldf, buf, GRAB_SIZE);
+ if (dat == 0)
+ break;
+
+ bytecount += dat;
+
+ while ( (found_it = my_strstr(buf, (char *) TcpFlag, GRAB_SIZE)) != NULL)
+ {
+ suc = 1;
+ fprintf (stdout, "%s", _("INFO old password found\n"));
+ fflush(stdout);
+ for (i = 0; i < 8; ++i)
+ {
+ sprintf(&oldpwd[i*2], _("%02x"),
+ (unsigned char) *found_it);
+ sprintf(&newpwd[i*2], _("%02x"),
+ (unsigned char) in[i]);
+ *found_it = in[i];
+ ++found_it;
+ }
+ fprintf (stdout, _("INFO replaced: %s by: %s\n"),
+ oldpwd, newpwd);
+ fflush(stdout);
+ }
+
+ while ( (found_it = my_strstr(buf, (char *) BadFlag, GRAB_SIZE)) != NULL)
+ {
+ badcnt++;
+ /* fprintf (stderr, _("INFO old filler found\n")); */
+ for (i = 0; i < 8; ++i)
+ {
+ sprintf(&oldpwd[i*2], _("%02x"),
+ (unsigned char) *found_it);
+
+ ccd = (unsigned char) (256.0 * (taus_get()/(TAUS_MAX+1.0)));
+ sprintf(&newpwd[i*2], _("%02x"),
+ (unsigned char) ccd);
+ *found_it = ccd;
+
+ ++found_it;
+ }
+ /* fprintf (stderr, _("INFO replaced: %s by: %s\n"),
+ oldpwd, newpwd);
+ */
+ }
+
+
+ ret = write (newf, buf, dat);
+ if (dat > 0 && ret < 0)
+ {
+ fprintf(stdout, _("ERROR Cannot write to output file %s.\n"), newn);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (suc == 1 && badcnt == 7)
+ {
+ fprintf (stdout, "%s", _("INFO finished\n"));
+ close (newf);
+ close (oldf);
+ fflush(stdout);
+ return (0);
+ }
+
+ lseek (oldf, 0, SEEK_SET);
+ lseek (newf, 0, SEEK_SET);
+
+ fprintf (stdout, "%s", _("INFO Not found in first pass.\n"));
+ fprintf (stdout, "%s", _("INFO Second pass ..\n"));
+
+ /* offset the start point
+ */
+
+ dat = read (oldf, buf, (GRAB_SIZE / 2));
+ ret = write (newf, buf, dat);
+ if (dat > 0 && ret < 0)
+ {
+ fprintf(stdout, _("ERROR Cannot write to output file %s.\n"), newn);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+
+ bytecount = 0;
+ suc = 0;
+ badcnt = 0;
+
+ while (1)
+ {
+ dat = read (oldf, buf, GRAB_SIZE);
+ if (dat == 0)
+ break;
+
+ bytecount += dat;
+
+ while ( (found_it = my_strstr(buf, (char *) TcpFlag, GRAB_SIZE)) != NULL)
+ {
+ suc = 1;
+ fprintf (stdout, "%s", _("INFO old password found\n"));
+ for (i = 0; i < 8; ++i)
+ {
+ sprintf(&oldpwd[i*2], _("%02x"),
+ (unsigned char) *found_it);
+ sprintf(&newpwd[i*2], _("%02x"),
+ (unsigned char) in[i]);
+ *found_it = in[i];
+ ++found_it;
+ }
+ fprintf (stdout, _("INFO Replaced: %s by: %s\n"),
+ oldpwd, newpwd);
+ }
+
+ while ( (found_it = my_strstr(buf, (char *) BadFlag, GRAB_SIZE)) != NULL)
+ {
+ badcnt++;
+ /* fprintf (stderr, _("INFO old filler found\n")); */
+ for (i = 0; i < 8; ++i)
+ {
+ sprintf(&oldpwd[i*2], _("%02x"),
+ (unsigned char) *found_it);
+
+ ccd = (unsigned char) (256.0 * taus_get()/(TAUS_MAX+1.0));
+ sprintf(&newpwd[i*2], _("%02x"),
+ (unsigned char) ccd);
+ *found_it = ccd;
+
+ ++found_it;
+ }
+ /* fprintf (stderr, _("INFO Replaced: %s by: %s\n"),
+ oldpwd, newpwd);*/
+ }
+
+ ret = write (newf, buf, dat);
+ if (dat > 0 && ret < 0)
+ {
+ fprintf(stdout, _("ERROR Cannot write to output file %s.\n"), newn);
+ fflush(stdout);
+ return EXIT_FAILURE;
+ }
+ }
+
+ close (newf);
+ close (oldf);
+
+ if (suc == 1 && badcnt == 7)
+ {
+ fprintf (stdout, "%s", _("INFO finished\n"));
+ fflush(stdout);
+ return 0;
+ }
+
+ if (suc == 0 || badcnt < 7)
+ {
+ fprintf (stdout, "%s", _("ERROR incomplete replacement\n"));
+ }
+ else
+ {
+ fprintf (stdout, "%s", _("ERROR bad replacement\n"));
+ }
+ fflush(stdout);
+ return EXIT_FAILURE;
+}
diff --git a/src/samhain_stealth.c b/src/samhain_stealth.c
new file mode 100644
index 0000000..15fc8f3
--- /dev/null
+++ b/src/samhain_stealth.c
@@ -0,0 +1,464 @@
+#include "config_xor.h"
+
+#ifdef HAVE_BROKEN_INCLUDES
+#define _ANSI_C_SOURCE
+#define _POSIX_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+#ifndef SH_BUFSIZE
+#define SH_BUFSIZE 1024
+#endif
+
+#ifdef SH_STEALTH
+char * globber(const char * string);
+#define _(string) globber(string)
+#define N_(string) string
+#else
+#define _(string) string
+#define N_(string) string
+#endif
+
+#ifdef SH_STEALTH
+
+#ifndef SH_MAX_GLOBS
+#define SH_MAX_GLOBS 32
+#endif
+
+#ifndef GLOB_LEN
+#define GLOB_LEN 511
+#endif
+
+char * globber(const char * str)
+{
+ register int i, j;
+ static int count = -1;
+ static char glob[SH_MAX_GLOBS][GLOB_LEN+1];
+
+ ++count; if (count > (SH_MAX_GLOBS-1) ) count = 0;
+ j = strlen(str);
+ if (j > GLOB_LEN) j = GLOB_LEN;
+
+ for (i = 0; i < j; ++i)
+ {
+ if (str[i] != '\n' && str[i] != '\t')
+ glob[count][i] = str[i] ^ XOR_CODE;
+ else
+ glob[count][i] = str[i];
+ }
+ glob[count][j] = '\0';
+ return glob[count];
+}
+#endif
+
+static unsigned long off_data;
+
+char sh_util_charhex( int c )
+{
+ if ( c >= 0 && c <= 9 )
+ return '0' + c;
+ else if ( c >= 10 && c <= 15 )
+ return 'a' + (c - 10);
+ else
+ {
+ fprintf(stderr, _("Out of range: %d\n"), c);
+ return 'X';
+ }
+}
+
+int sh_util_hexchar( char c )
+{
+ if ( c >= '0' && c <= '9' )
+ return c - '0';
+ else if ( c >= 'a' && c <= 'f' )
+ return c - 'a' + 10;
+ else if ( c >= 'A' && c <= 'F' )
+ return c - 'A' + 10;
+ else return -1;
+}
+
+/* --------- third step -----------
+ *
+ * get data from a block of hex data
+ */
+int hideout_hex_block(int fd, unsigned char * str, int len)
+{
+ register int i, j, k;
+ unsigned char c, e;
+ register int num;
+ unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+ unsigned long here = 0;
+ unsigned long retval = 0;
+
+ i = 0;
+ while (i < len)
+ {
+ for (j = 0; j < 8; ++j)
+ {
+
+ /* get a low byte, modify, read back */
+ for (k = 0; k < 2; ++k)
+ {
+ c = ' ';
+ do {
+ do {
+ num = read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num == 0) return -1;
+ ++here;
+ } while (c == '\n' || c == '\t' || c == '\r' ||
+ c == ' ');
+ }
+
+
+ /* e is the value of the low byte
+ */
+ e = (unsigned char) sh_util_hexchar( c );
+ if ((e & mask[7]) != 0) /* bit is set */
+ str[i] |= mask[j];
+ else /* bit is not set */
+ str[i] &= ~mask[j];
+
+ }
+ if (str[i] == '\n') break;
+ ++i;
+ }
+ str[i+1] = '\0';
+ retval += here;
+ return retval;
+}
+
+/* --------- second step -----------
+ *
+ * hide data in a block of hex data
+ */
+int hidein_hex_block(int fd, char * str, int len)
+{
+ register int i, j, k;
+ unsigned char c, d, e;
+ register int num;
+ unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+ unsigned long here = 0;
+ unsigned long retval = 0;
+
+ for (i = 0; i < len; ++i)
+ {
+ d = str[i];
+ for (j = 0; j < 8; ++j)
+ {
+
+ /* get a low byte, modify, read back */
+ for (k = 0; k < 2; ++k)
+ {
+ c = ' ';
+ do {
+ do {
+ num = read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num == 0) return -1;
+ ++here;
+ } while (c == '\n' || c == '\t' || c == '\r' ||
+ c == ' ');
+ }
+
+ /* e is the value of the low byte
+ */
+ e = (unsigned char) sh_util_hexchar( c );
+ if ((d & mask[j]) != 0) /* bit is set */
+ e |= mask[7];
+ else /* bit is not set */
+ e &= ~mask[7];
+
+ e = sh_util_charhex ( e );
+ lseek(fd, -1, SEEK_CUR);
+ do {
+ num = write(fd, &e, 1);
+ } while (num == 0 && errno == EINTR);
+ }
+ }
+ retval += here;
+ return retval;
+}
+
+/* --------- first step -----------
+ *
+ * find first block of hex data
+ */
+unsigned long first_hex_block(int fd, unsigned long * max)
+{
+ int i;
+ register int num = 1;
+ char c;
+ int nothex = 0;
+ unsigned long retval = 0;
+ int this_line = 0;
+ char theline[SH_BUFSIZE];
+
+ *max = 0;
+
+ while (1)
+ {
+ theline[0] = '\0';
+ this_line = 0;
+ c = '\0';
+ while (c != '\n' && num > 0)
+ {
+ do {
+ num = read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0) theline[this_line] = c;
+ else return 0;
+ this_line += num;
+ }
+ theline[this_line] = '\0';
+
+ /* not only 'newline' */
+ if (this_line > 60)
+ {
+ nothex = 0;
+ i = 0;
+ while (nothex == 0 && i < (this_line-1))
+ {
+ if (! isxdigit((int)theline[i])) nothex = 1;
+ ++i;
+ }
+ if (nothex == 1) retval += this_line;
+ }
+ else
+ {
+ nothex = 1;
+ retval += this_line;
+ }
+
+ if (nothex == 0)
+ {
+ *max = 0;
+ do {
+ do {
+ num = read (fd, theline, SH_BUFSIZE);
+ } while (num == 0 && errno == EINTR);
+ for (i = 0; i < num; ++i)
+ {
+ c = theline[i];
+ if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
+ ;
+ else if (!isxdigit((int)c))
+ break;
+ else
+ *max += 1;
+ }
+ } while (num > 0);
+
+ *max /= 16;
+ return retval;
+ }
+
+ }
+ /* return 0; *//* unreachable */
+}
+
+static void usage ()
+{
+ fprintf(stdout, "%s", _("\nUsage: samhain_stealth -i|s|g|o <where> "\
+ "[what]\n\n"));
+
+ fprintf(stdout, "%s", _(" -i info on PS image 'where'\n"));
+ fprintf(stdout, "%s", _(" (how much bytes can be hidden in it).\n"));
+ fprintf(stdout, "%s", _(" -s hide file 'what' in PS image 'where'\n"));
+ fprintf(stdout, "%s", _(" -g get hidden data from PS image 'where'\n"));
+ fprintf(stdout, "%s", _(" (output to stdout)\n"));
+ fprintf(stdout, "%s", _(" -o size of file 'where' = offset to "\
+ "end-of-file\n"));
+ fprintf(stdout, "%s", _(" (same as wc -c).\n\n"));
+ fprintf(stdout, "%s", _(" Example: let bar.ps be the ps file, and"\
+ "foo the config file\n"));
+ fprintf(stdout, "%s", _(" 1) extract with: samhain_stealth "\
+ "-g bar.ps >foo\n"));
+ fprintf(stdout, "%s", _(" 2) hide with: samhain_stealth "\
+ "-s bar.ps foo\n\n"));
+
+ fprintf(stdout, "%s", _(" This program hides a file in an UNCOMPRESSED "\
+ "postscript\n"));
+ fprintf(stdout, "%s", _(" image. To generate such an image, you may " \
+ "use e.g.:\n"));
+ fprintf(stdout, "%s", _(" 'convert +compress foo.jpg bar.ps'.\n"));
+ fprintf(stdout, "%s", _(" 'gimp' apparently saves postscript "\
+ "uncompressed by default\n"));
+ fprintf(stdout, "%s", _(" (V 1.06 of the postscript plugin).\n"));
+ fprintf(stdout, "%s", _(" 'xv' seems to save with run-length "\
+ "compression, which is unsuitable.\n"));
+ fprintf(stdout, "%s", _(" The program does not check the "\
+ "compression type of the PS file.\n"));
+ fprintf(stdout, "%s", _(" Just have a look at the result to check.\n"));
+ return;
+}
+
+int main (int argc, char * argv[])
+{
+ int fd;
+ int add_off;
+ unsigned long max;
+ char buf[1024];
+ FILE * infil;
+ int pgp_flag = 0;
+
+ if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'h')
+ {
+ usage();
+ return (0);
+ }
+ if (argc == 2 && 0 == strcmp(argv[1], _("--help")))
+ {
+ usage();
+ return (0);
+ }
+
+ if (argc < 3 || argv[1][0] != '-' ||
+ (argv[1][1] != 'o' && argv[1][1] != 'i' &&
+ argv[1][1] != 's' && argv[1][1] != 'g'))
+ {
+ usage ();
+ return (1);
+ }
+
+
+
+ /* offset to end
+ */
+ if (argv[1][1] == 'o')
+ {
+ fd = open(argv[2], O_RDONLY);
+ if (fd == -1)
+ {
+ fprintf(stderr, _("Error: could not open() %s for reading\n"),
+ argv[2]);
+ return (1);
+ }
+
+ off_data = lseek (fd, 0, SEEK_END);
+ fprintf(stdout, _("%ld %s\n"),
+ off_data, argv[2]);
+ close (fd);
+ return (0);
+ }
+
+ fd = open(argv[2], O_RDWR);
+ if (fd == -1)
+ {
+ fprintf(stderr, _("Error: could not open() %s for read/write\n"),
+ argv[2]);
+ return (1);
+ }
+
+ /* find the first block of hex data
+ */
+ if (argv[1][1] == 'i')
+ {
+ off_data = first_hex_block(fd, &max);
+ fprintf(stdout, _("IMA START AT: %ld MAX. CAPACITY: %ld Bytes\n"),
+ off_data, max);
+ if (max > 0)
+ return (0);
+ else
+ {
+ fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
+ return (1);
+ }
+ }
+
+ /* seek to the first block of fresh hex data and hide data
+ */
+ if (argv[1][1] == 's')
+ {
+ infil = fopen(argv[3], "r");
+ if (infil == NULL)
+ {
+ fprintf(stderr, _("Error: could not open() %s\n"), argv[3]);
+ return (8);
+ }
+ off_data = first_hex_block(fd, &max);
+ fprintf(stdout, _("IMA START AT: %ld MAX. CAPACITY: %ld Bytes\n"),
+ off_data, max);
+ if (max == 0)
+ {
+ fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
+ return (1);
+ }
+
+ fprintf(stdout, _(" .. hide %s in %s .. \n"), argv[3], argv[2]);
+ while (fgets(buf, sizeof(buf), infil))
+ {
+ lseek(fd, off_data, SEEK_SET);
+ add_off = hidein_hex_block(fd, buf, strlen(buf));
+ if (add_off == -1)
+ {
+ fprintf(stderr, _("Error: %s has insufficient capacity\n"),
+ argv[2]);
+ return (1);
+ }
+ off_data += add_off;
+ }
+ fclose(infil);
+ /*
+ * make sure there is a terminator
+ */
+ lseek(fd, off_data, SEEK_SET);
+ add_off = hidein_hex_block(fd, _("\n[EOF]\n"), 7);
+ if (add_off == -1)
+ {
+ fprintf(stderr, _("Error: %s has insufficient capacity\n"),
+ argv[2]);
+ return (1);
+ }
+ fprintf(stdout, "%s", _(" .. finished\n"));
+ return (0);
+ }
+
+ if (argv[1][1] == 'g')
+ {
+ off_data = first_hex_block(fd, &max);
+ if (max == 0)
+ {
+ fprintf(stderr, _("Error: %s is probably not an uncompressed postscript image\n"), argv[2]);
+ return (1);
+ }
+ lseek(fd, off_data, SEEK_SET);
+
+ while (1 == 1)
+ {
+ add_off = hideout_hex_block(fd, (unsigned char *) buf, 1023);
+ if (add_off == -1)
+ {
+ fprintf(stderr, _("Error: premature end of data in %s\n"),
+ argv[2]);
+ return (1);
+ }
+ if (0 == strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n")))
+ pgp_flag = 1;
+ fprintf(stdout, "%s", buf);
+ if (0 == strncmp(buf, _("[EOF]"), 5) && pgp_flag == 0)
+ break;
+ if (0 == strcmp(buf, _("-----END PGP SIGNATURE-----\n")) &&
+ pgp_flag == 1)
+ break;
+
+ off_data += add_off;
+ lseek(fd, off_data, SEEK_SET);
+ }
+ return (0);
+ }
+
+ fprintf(stderr, _("Invalid mode of operation: %s"), argv[1]);
+ return (1);
+}
+
diff --git a/src/sh_audit.c b/src/sh_audit.c
new file mode 100644
index 0000000..52d0c70
--- /dev/null
+++ b/src/sh_audit.c
@@ -0,0 +1,570 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2010 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "samhain.h"
+#include "sh_error.h"
+
+#undef FIL__
+#define FIL__ _("sh_audit.c")
+
+#if !defined(SH_COMPILE_STATIC) && defined(__linux__) && defined(HAVE_AUPARSE_H) && defined(HAVE_AUPARSE_LIB)
+#include <auparse.h>
+
+#include "sh_extern.h"
+#include "sh_utils.h"
+
+
+#define REC_SIZE_SYSCALL 32
+#define REC_SIZE_EXE 64
+#define REC_SIZE_SUCCESS 32
+
+struct recordState {
+ char syscall[REC_SIZE_SYSCALL];
+ char exe[REC_SIZE_EXE];
+ char success[REC_SIZE_SUCCESS];
+ unsigned int auid;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int euid;
+ unsigned int egid;
+ unsigned int fsuid;
+ unsigned int fsgid;
+ time_t time;
+ unsigned int milli;
+};
+
+static int listRecords (auparse_state_t * au, struct recordState * state)
+{
+ if (auparse_first_record(au) != 1)
+ return -1;
+
+ state->time = auparse_get_time(au);
+ state->milli = auparse_get_milli(au);
+
+ if (auparse_find_field(au, _("syscall")))
+ sl_strlcpy(state->syscall, auparse_interpret_field(au), REC_SIZE_SYSCALL);
+
+ if (auparse_find_field(au, _("success")))
+ strncpy(state->success, auparse_interpret_field(au), REC_SIZE_SUCCESS);
+
+ if (auparse_find_field(au, "uid"))
+ state->uid = auparse_get_field_int(au);
+ if (auparse_find_field(au, "gid"))
+ state->gid = auparse_get_field_int(au);
+
+ if (auparse_find_field(au, _("euid")))
+ state->euid = auparse_get_field_int(au);
+ if (auparse_find_field(au, _("fsuid")))
+ state->fsuid = auparse_get_field_int(au);
+
+ auparse_first_field(au);
+
+ if (auparse_find_field(au, _("auid")))
+ state->auid = auparse_get_field_int(au);
+
+ auparse_first_field(au);
+
+ if (auparse_find_field(au, _("egid")))
+ state->egid = auparse_get_field_int(au);
+ if (auparse_find_field(au, _("fsgid")))
+ state->fsgid = auparse_get_field_int(au);
+
+ auparse_first_field(au);
+
+ if (auparse_find_field(au, "exe"))
+ sl_strlcpy(state->exe, auparse_interpret_field(au), REC_SIZE_EXE);
+
+ return 0;
+}
+
+static char * doAuparse (const char * file, time_t time, int tol, char * result, size_t rsize, int redo_flag)
+{
+ struct recordState state;
+ struct recordState stateFetched;
+ unsigned int found_flag = 0;
+
+ auparse_state_t * au = auparse_init(AUSOURCE_LOGS, NULL);
+
+ if (!au)
+ {
+ char ebuf[SH_ERRBUF_SIZE];
+ int errnum = errno;
+
+ sl_snprintf(ebuf, sizeof(ebuf), _("Error in auparse_init() - %s\n"),
+ strerror(errnum));
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ ebuf,
+ _("doAuparse") );
+ return NULL;
+ }
+
+ if (ausearch_add_interpreted_item(au, _("name"), "=", file,
+ AUSEARCH_RULE_CLEAR) != 0)
+ {
+ goto err;
+ }
+
+ if (time != 0)
+ {
+ ausearch_add_timestamp_item(au, ">=", time-tol, 0, AUSEARCH_RULE_AND);
+ ausearch_add_timestamp_item(au, "<=", time+tol, 0, AUSEARCH_RULE_AND);
+ }
+
+ if (ausearch_set_stop(au, AUSEARCH_STOP_RECORD) != 0)
+ {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Error in ausearch_set_stop\n"),
+ _("doAuparse") );
+ goto err;
+ }
+
+ memset(&state, '\0', sizeof(state));
+
+ while (ausearch_next_event(au) == 1)
+ {
+ memset(&stateFetched, '\0', sizeof(state));
+ listRecords(au, &stateFetched);
+ if (0 == strcmp(stateFetched.success, "yes"))
+ {
+ memcpy(&state, &stateFetched, sizeof(state));
+ ++found_flag;
+ }
+ auparse_next_event(au);
+ }
+
+ if (found_flag == 0 && redo_flag == S_FALSE)
+ {
+ size_t len = strlen(file);
+ char * path = SH_ALLOC(len + 2);
+ char * altres;
+
+ sl_strlcpy(path, file, len+2);
+ path[len] = '/'; path[len+1] = '\0';
+ auparse_destroy(au);
+
+ altres = doAuparse(path, time, tol, result, rsize, S_TRUE);
+
+ SH_FREE(path);
+ return altres;
+ }
+
+ if (0 == strcmp(state.success, "yes"))
+ {
+ char * tmp_exe = sh_util_safe_name(state.exe);
+ sl_snprintf(result, rsize,
+ _("time=%lu.%u, syscall=%s, auid=%u, uid=%u, gid=%u, euid=%u, egid=%u, fsuid=%u, fsgid=%u, exe=%s"),
+ (unsigned long) state.time, state.milli,
+ state.syscall,
+ state.auid, state.uid, state.gid, state.euid, state.egid,
+ state.fsuid, state.fsgid, tmp_exe);
+ SH_FREE(tmp_exe);
+ auparse_destroy(au);
+ return result;
+ }
+
+ err:
+ auparse_destroy(au);
+ return NULL;
+}
+
+static int sh_audit_checkdaemon();
+static int actl_pnum = -1;
+static char * actl_paths[4] =
+ {
+ N_("/sbin/auditctl"),
+ N_("/usr/sbin/auditctl"),
+ N_("/bin/auditctl"),
+ N_("/usr/bin/auditctl")
+ };
+
+
+/* Public function to fetch an audit record for path 'file', time 'time'
+ * The 'result' array should be sized ~256 char.
+ */
+char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, char * result, size_t rsize)
+{
+ char * res = NULL;
+
+ if (sh_audit_checkdaemon() >= 0)
+ {
+ time_t new;
+
+ if (mtime >= ctime) { new = mtime; }
+ else { new = ctime; }
+
+ res = doAuparse (file, new, 1, result, rsize, S_FALSE);
+
+ if (!res)
+ {
+ res = doAuparse (file, new, 3, result, rsize, S_FALSE);
+ }
+
+ }
+ return res;
+}
+
+void sh_audit_delete_all ()
+{
+ int p = sh_audit_checkdaemon();
+
+ if (p >= 0)
+ {
+ char ctl[64];
+
+ sl_snprintf(ctl, sizeof(ctl), _("%s -D -k samhain"),
+ _(actl_paths[p]));
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ 0, MSG_E_SUBGEN,
+ _("Deleting audit daemon rules with key samhain"),
+ _("sh_audit_delete_all") );
+
+ sl_strlcpy(ctl, _(actl_paths[p]), sizeof(ctl));
+ sh_ext_system(ctl, ctl, "-D", "-k", _("samhain"), NULL);
+ }
+ return;
+}
+
+static int sh_audit_isdir(const char * file)
+{
+ struct stat buf;
+
+ if ( (0 == lstat (file, &buf)) && S_ISDIR(buf.st_mode))
+ return S_TRUE;
+ return S_FALSE;
+}
+
+static void sh_audit_mark_int (const char * file)
+{
+ static int flushRules = 0;
+
+ int p = sh_audit_checkdaemon();
+
+ /* Flush all rules at startup.
+ */
+ if (flushRules == 0)
+ {
+ sh_audit_delete_all ();
+ flushRules = 1;
+ }
+
+ if (p >= 0)
+ {
+ size_t len = strlen(file) + 64;
+ char * command = SH_ALLOC(len);
+ char * safe;
+ char ctl[64];
+ char a1[32];
+ char a2[32];
+ char a3[32];
+
+ sl_snprintf(command, len, _("%s -w %s -p wa -k samhain"),
+ _(actl_paths[p]),
+ file);
+
+ safe = sh_util_safe_name_keepspace(command);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ 0, MSG_E_SUBGEN,
+ safe,
+ _("sh_audit_mark") );
+
+ SH_FREE(safe);
+
+ sl_strlcpy(ctl, _(actl_paths[p]), sizeof(ctl));
+ sl_strlcpy(command, file, len);
+
+ sl_strlcpy(a3, _("samhain"), sizeof(a3));
+ sh_ext_system(ctl, ctl, "-w", command, "-p", "wa", "-k", a3, NULL);
+
+ /* Placing a watch on a directory will not place a watch on the
+ * directory inode, so we do this explicitely.
+ */
+ if (S_TRUE == sh_audit_isdir(file))
+ {
+ safe = sh_util_safe_name(file);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ 0, MSG_E_SUBGPATH,
+ _("Add path watch for directory"),
+ _("sh_audit_mark_int"), safe );
+ SH_FREE(safe);
+ sl_strlcpy(command, _("path="), len);
+ sl_strlcat(command, file, len);
+ sl_strlcpy(a1, _("always,exit"), sizeof(a1));
+ sl_strlcpy(a2, _("perm=wa"), sizeof(a2));
+ sh_ext_system(ctl, ctl, "-a", a1, "-F", command, "-F", a2, "-k", a3, NULL);
+ }
+ SH_FREE(command);
+ }
+ return;
+}
+
+struct aud_list {
+ char * file;
+ struct aud_list * next;
+};
+
+struct aud_list * mark_these = NULL;
+
+static void add_this (char * file)
+{
+ struct aud_list * this = SH_ALLOC(sizeof(struct aud_list));
+ size_t len = strlen(file);
+
+ this->file = sh_util_strdup(file);
+ if ((len > 1) && (file[len-1] == '/'))
+ this->file[len-1] = '\0';
+
+ this->next = mark_these;
+ mark_these = this;
+ return;
+}
+
+/* Check whether it is already covered by a higher directory
+ */
+static int test_exchange (struct aud_list * this, char * file)
+{
+ size_t len0 = sl_strlen(this->file);
+ size_t len1 = sl_strlen(file);
+ int ret = -1;
+
+ if (len0 == len1)
+ {
+ return strcmp(this->file, file);
+ }
+ else
+ {
+ char * s0 = SH_ALLOC(len0 + 2);
+ char * s1 = SH_ALLOC(len1 + 2);
+
+ sl_strlcpy(s0, this->file, len0 + 2);
+ sl_strlcpy(s1, file, len1 + 2);
+
+ if (s0 < s1)
+ {
+ sl_strlcat(s0, "/", len0 + 2);
+ ret = strncmp(s0, s1, len0 + 1);
+ }
+ else
+ {
+ sl_strlcat(s1, "/", len1 + 2);
+ if (0 == strncmp(s0, s1, len1 + 1))
+ {
+ size_t len = strlen(file);
+ SH_FREE(this->file);
+ this->file = sh_util_strdup(file);
+ if ((len > 1) && (file[len-1] == '/'))
+ this->file[len-1] = '\0';
+ ret = 0;
+ }
+ }
+ SH_FREE(s0);
+ SH_FREE(s1);
+ }
+
+ return ret;
+}
+
+/* Place a path on the list of of paths to be watched
+ */
+void sh_audit_mark (char * file)
+{
+ struct aud_list * this = mark_these;
+
+ if (!mark_these) {
+ add_this (file);
+ return;
+ }
+
+ while (this)
+ {
+ /* Check whether it is already covered by a higher
+ * directory
+ */
+ if (0 == test_exchange(this, file))
+ return;
+ this = this->next;
+ }
+
+ add_this (file);
+ return;
+}
+
+void sh_audit_commit ()
+{
+ struct aud_list * next;
+ struct aud_list * this = mark_these;
+
+ mark_these = NULL;
+
+ while (this)
+ {
+ sh_audit_mark_int (this->file);
+ next = this->next;
+ SH_FREE(this->file);
+ SH_FREE(this);
+ this = next;
+ }
+
+}
+
+static int sh_audit_checkdaemon()
+{
+ int i;
+ static int flag = 0;
+ char command[64];
+ char * p;
+
+ if (flag != 0)
+ return -1;
+
+ if (actl_pnum >= 0)
+ return actl_pnum;
+
+ for (i = 0; i < 4; ++i)
+ {
+ if (0 == access(_(actl_paths[i]), F_OK))/* flawfinder: ignore */
+ {
+ if (0 == access(_(actl_paths[i]), X_OK))/* flawfinder: ignore */
+ {
+ actl_pnum = i;
+ break;
+ }
+ else
+ {
+ char ebuf[SH_ERRBUF_SIZE];
+ int errnum = errno;
+
+ sl_snprintf(ebuf, sizeof(ebuf),
+ _("Cannot execute auditctl - %s\n"),
+ strerror(errnum));
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ errnum, MSG_E_SUBGEN,
+ ebuf,
+ _("sh_audit_checkdaemon") );
+ flag = 1;
+ actl_pnum = -1;
+ return -1;
+ }
+ }
+ }
+
+ if (actl_pnum == -1 && flag == 0)
+ {
+ char ebuf[SH_ERRBUF_SIZE];
+ int errnum = errno;
+
+ sl_snprintf(ebuf, sizeof(ebuf),
+ _("Cannot find auditctl - %s\n"),
+ strerror(errnum));
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ errnum, MSG_E_SUBGEN,
+ ebuf,
+ _("sh_audit_checkdaemon") );
+ flag = 1;
+ actl_pnum = -1;
+ return -1;
+ }
+
+ /* We found an executable auditctl */
+
+ sl_snprintf(command, sizeof(command), _("%s -s"), _(actl_paths[actl_pnum]));
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ 0, MSG_E_SUBGEN,
+ command,
+ _("sh_audit_checkdaemon") );
+ p = sh_ext_popen_str (command);
+
+ if (p)
+ {
+ int retval = -1;
+ if (strstr(p, _(" pid=0 ")))
+ {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ 0, MSG_E_SUBGEN,
+ _("Audit daemon for Linux kernel audit system is not running"),
+ _("sh_audit_checkdaemon") );
+ flag = 1;
+ actl_pnum = -1;
+ }
+ else
+ {
+ retval = actl_pnum;
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ retval, MSG_E_SUBGEN,
+ _("Audit daemon is running"),
+ _("sh_audit_checkdaemon") );
+ }
+ SH_FREE(p);
+ return retval;
+ }
+
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ errno, MSG_E_SUBGEN,
+ _("No output from auditctl -s"),
+ _("sh_audit_checkdaemon") );
+ flag = 1;
+ actl_pnum = -1;
+ return -1;
+}
+
+/* HAVE_AUPARSE_H */
+#else
+char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, char * result, size_t rsize)
+{
+ (void) file;
+ (void) mtime;
+ (void) ctime;
+ (void) result;
+ (void) rsize;
+
+ return 0;
+}
+void sh_audit_mark (const char * file)
+{
+ (void) file;
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Setting audit watch not supported"),
+ _("sh_audit_mark"));
+ return;
+}
+void sh_audit_delete_all ()
+{
+ return;
+}
+void sh_audit_commit ()
+{
+ return;
+}
+#endif
+
+/* client || standalone */
+#endif
+
diff --git a/src/sh_calls.c b/src/sh_calls.c
new file mode 100644
index 0000000..2269836
--- /dev/null
+++ b/src/sh_calls.c
@@ -0,0 +1,964 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#ifdef HOST_IS_HPUX
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#ifndef S_SPLINT_S
+#include <arpa/inet.h>
+#else
+#define AF_INET 2
+#endif
+
+#include <time.h>
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_calls.h"
+#include "sh_ipvx.h"
+#include "sh_sub.h"
+#include "sh_utils.h"
+
+#undef FIL__
+#define FIL__ _("sh_calls.c")
+
+extern int flag_err_debug;
+
+char aud_err_message[64];
+
+typedef struct cht_struct
+{
+ const char * str;
+ unsigned long val;
+} cht_type;
+
+static cht_type aud_tab[] =
+{
+ { N_("execve"), AUD_EXEC },
+ { N_("utime"), AUD_UTIME },
+ { N_("unlink"), AUD_UNLINK },
+ { N_("dup"), AUD_DUP },
+ { N_("chdir"), AUD_CHDIR },
+ { N_("open"), AUD_OPEN },
+ { N_("kill"), AUD_KILL },
+ { N_("exit"), AUD_EXIT },
+ { N_("fork"), AUD_FORK },
+ { N_("setuid"), AUD_SETUID },
+ { N_("setgid"), AUD_SETGID },
+ { N_("pipe"), AUD_PIPE },
+ { NULL, 0 }
+};
+
+/* Set aud functions
+ */
+int sh_aud_set_functions(const char * str_s)
+{
+ int i = 0;
+
+ SL_ENTER(_("sh_aud_set_functions"));
+
+ if (str_s == NULL)
+ return -1;
+
+ while (aud_tab[i].str != NULL)
+ {
+ if (NULL != sl_strstr (str_s, _(aud_tab[i].str)))
+ {
+ sh.flag.audit = 1;
+ sh.flag.aud_mask |= aud_tab[i].val;
+ }
+ ++i;
+ }
+
+ SL_RETURN(0,_("sh_aud_set_functions"));
+}
+
+
+
+
+/* Need to catch EINTR for these functions.
+ */
+long int retry_sigaction(const char * file, int line,
+ int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_sigaction"));
+
+ do {
+ val_retry = sigaction(signum, act, oldact);
+ } while (val_retry < 0 && errno == EINTR);
+
+ error = errno;
+ if (val_retry < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_SIGACT,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) signum );
+ }
+ errno = error;
+ SL_RETURN(val_retry, _("retry_sigaction"));
+}
+
+static struct sh_sockaddr bind_addr;
+static int use_bind_addr = 0;
+
+int sh_calls_set_bind_addr (const char * str)
+{
+ static int reject = 0;
+
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ if (0 == sh_ipvx_aton(str, &bind_addr))
+ return -1;
+
+ use_bind_addr = 1;
+ return 0;
+}
+
+
+long int retry_connect(const char * file, int line, int sockfd,
+ struct sockaddr *serv_addr, int addrlen)
+{
+ int error;
+ int err_bind = 0;
+ long int val_retry = 0;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("retry_connect"));
+
+ errno = 0;
+
+ if (use_bind_addr)
+ {
+ int slen = SH_SS_LEN(bind_addr);
+ struct sockaddr *b_addr = sh_ipvx_sockaddr_cast(&bind_addr);
+
+ if (bind_addr.ss_family == AF_INET)
+ b_addr->sa_family = AF_INET;
+#if defined(USE_IPVX)
+ else
+ b_addr->sa_family = AF_INET6;
+#endif
+ val_retry = bind(sockfd, b_addr, slen);
+ }
+
+ if (val_retry == 0)
+ {
+ do {
+ val_retry = connect(sockfd, serv_addr, addrlen);
+ } while (val_retry < 0 && (errno == EINTR || errno == EINPROGRESS));
+ }
+ else
+ {
+ err_bind = 1;
+ }
+
+ error = errno;
+ if (val_retry != 0) {
+ long eport = 0;
+ char eaddr[SH_IP_BUF];
+ char emesg[SH_BUFSIZE];
+ struct sockaddr *err_addr = serv_addr;
+ struct sh_sockaddr ss;
+
+ if (err_bind)
+ err_addr = sh_ipvx_sockaddr_cast(&bind_addr);
+
+ sh_ipvx_save(&ss, err_addr->sa_family, err_addr);
+ sh_ipvx_ntoa(eaddr, sizeof(eaddr), &ss);
+
+ if (err_addr->sa_family == AF_INET)
+ eport = (long) ntohs(((struct sockaddr_in *)serv_addr)->sin_port);
+#if defined(USE_IPVX)
+ else
+ eport = (long) ntohs(((struct sockaddr_in6 *)serv_addr)->sin6_port);
+#endif
+
+ sl_strlcpy(emesg, sh_error_message(error, errbuf, sizeof(errbuf)), sizeof(emesg));
+ sl_strlcat(emesg,
+ (err_addr->sa_family == AF_INET) ? _(", AF_INET") : _(", AF_INET6"),
+ sizeof(emesg));
+
+ sl_strlcat(emesg,
+ (err_bind) ? _(", bind") : _(", connect"),
+ sizeof(emesg));
+
+ sh_error_handle ((-1), file, line, error, MSG_ERR_CONNECT,
+ emesg,
+ (long) sockfd, eport, eaddr);
+ }
+ errno = error;
+ SL_RETURN(val_retry, _("retry_connect"));
+}
+
+long int retry_accept(const char * file, int line, int fd,
+ struct sh_sockaddr *serv_addr, int * addrlen)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+ struct sockaddr_storage ss;
+
+ ACCEPT_TYPE_ARG3 my_addrlen = sizeof(ss);
+
+ errno = 0;
+
+ SL_ENTER(_("retry_accept"));
+
+ do {
+ val_retry = accept(fd, (struct sockaddr *)&ss, &my_addrlen);
+ } while (val_retry < 0 && errno == EINTR);
+
+ error = errno;
+ if (val_retry < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_ACCEPT,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) fd );
+ }
+ errno = error;
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char ipbuf[SH_IP_BUF];
+ char buf[SH_BUFSIZE];
+#if defined(USE_IPVX)
+ sl_strlcpy(errbuf, _("Address family: "), sizeof(errbuf));
+ sl_strlcat(errbuf,
+ (ss.ss_family == AF_INET6) ? _("AF_INET6") : _("AF_INET"),
+ sizeof(errbuf));
+ getnameinfo((struct sockaddr *)&ss, my_addrlen,
+ ipbuf, sizeof(ipbuf), NULL, 0, NI_NUMERICHOST);
+#else
+ struct sockaddr_in sa;
+ char * p;
+ memcpy(&(sa), (struct sockaddr_in*)&ss, sizeof(struct sockaddr_in));
+ p = inet_ntoa(sa.sin_addr);
+ sl_strlcpy(ipbuf, p, sizeof(ipbuf));
+ sl_strlcpy(errbuf, _("Address family: AF_INET"), sizeof(errbuf));
+#endif
+ sl_strlcpy(buf, _("Address: "), sizeof(buf));
+ sl_strlcat(buf, ipbuf, sizeof(buf));
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf, _("retry_accept"));
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ buf, _("retry_accept"));
+ }
+
+ sh_ipvx_save(serv_addr, ss.ss_family, (struct sockaddr *) &ss);
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char ipbuf[SH_IP_BUF];
+ char ipbuf2[SH_IP_BUF];
+ char buf[SH_BUFSIZE];
+#if defined(USE_IPVX)
+ int len = (serv_addr->ss_family == AF_INET) ?
+ sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6);
+ getnameinfo(sh_ipvx_sockaddr_cast(serv_addr), len,
+ ipbuf2, sizeof(ipbuf2), NULL, 0, NI_NUMERICHOST);
+#else
+ char * p = inet_ntoa((serv_addr->sin).sin_addr);
+ sl_strlcpy(ipbuf2, p, sizeof(ipbuf2));
+#endif
+ sh_ipvx_ntoa (ipbuf, sizeof(ipbuf), serv_addr);
+ sl_snprintf(buf, sizeof(buf), _("Address: %s / %s"),
+ ipbuf, ipbuf2);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ buf, _("retry_accept"));
+ }
+
+ *addrlen = (int) my_addrlen;
+ SL_RETURN(val_retry, _("retry_accept"));
+}
+
+static int sh_enable_use_sub = 0;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__)
+static int sh_use_sub = 0;
+#else
+static int sh_use_sub = 1;
+#endif
+#else
+static int sh_use_sub = 0;
+#endif
+
+void sh_calls_enable_sub()
+{
+ sh_enable_use_sub = 1;
+ return;
+}
+
+int sh_calls_set_sub (const char * str)
+{
+ int ret = sh_util_flagval(str, &sh_use_sub);
+
+ if ((ret == 0) && (!sh_use_sub))
+ {
+ sh_kill_sub();
+ }
+ return ret;
+}
+
+long int retry_lstat_ns(const char * file, int line,
+ const char *file_name, struct stat *buf)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("retry_lstat_ns"));
+
+ do {
+ val_retry = /*@-unrecog@*/lstat (file_name, buf)/*@+unrecog@*/;
+ } while (val_retry < 0 && errno == EINTR);
+
+ error = errno;
+ if (val_retry < 0) {
+ (void) sh_error_message(error, aud_err_message, 64);
+ sh_error_handle ((-1), file, line, error, MSG_ERR_LSTAT,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ file_name );
+ }
+ errno = error;
+
+ SL_RETURN(val_retry, _("retry_lstat_ns"));
+}
+
+long int retry_lstat(const char * file, int line,
+ const char *file_name, struct stat *buf)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("retry_lstat"));
+
+ if (sh_use_sub && sh_enable_use_sub)
+ {
+ val_retry = sh_sub_lstat (file_name, buf);
+ }
+ else
+ {
+ do {
+ val_retry = /*@-unrecog@*/lstat (file_name, buf)/*@+unrecog@*/;
+ } while (val_retry < 0 && errno == EINTR);
+ }
+
+ error = errno;
+ if (val_retry < 0) {
+ (void) sh_error_message(error, aud_err_message, 64);
+ sh_error_handle ((-1), file, line, error, MSG_ERR_LSTAT,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ file_name );
+ }
+ errno = error;
+
+ SL_RETURN(val_retry, _("retry_lstat"));
+}
+
+long int retry_stat(const char * file, int line,
+ const char *file_name, struct stat *buf)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("retry_stat"));
+
+ if (sh_use_sub && sh_enable_use_sub)
+ {
+ val_retry = sh_sub_stat (file_name, buf);
+ }
+ else
+ {
+ do {
+ val_retry = stat (file_name, buf);
+ } while (val_retry < 0 && errno == EINTR);
+ }
+
+ error = errno;
+ if (val_retry < 0) {
+ (void) sh_error_message(error, aud_err_message, 64);
+ sh_error_handle ((-1), file, line, error, MSG_ERR_STAT,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ file_name );
+ }
+ errno = error;
+
+ SL_RETURN(val_retry, _("retry_stat"));
+}
+
+long int retry_fstat(const char * file, int line, int filed, struct stat *buf)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("retry_fstat"));
+
+ do {
+ val_retry = fstat (filed, buf);
+ } while (val_retry < 0 && errno == EINTR);
+ error = errno;
+ if (val_retry < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_FSTAT,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) filed );
+ }
+ errno = error;
+ SL_RETURN(val_retry, _("retry_fstat"));
+}
+
+long int retry_fcntl(const char * file, int line, int fd, int cmd, long arg)
+{
+ int error;
+ long int val_retry = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_fcntl"));
+
+ if (cmd == F_GETFD || cmd == F_GETFL)
+ {
+ do {
+ val_retry = fcntl(fd, cmd);
+ } while (val_retry < 0 && errno == EINTR);
+ }
+ else
+ {
+ do {
+ val_retry = fcntl(fd, cmd, arg);
+ } while (val_retry < 0 && errno == EINTR);
+ }
+ error = errno;
+ if (val_retry < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_FCNTL,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) fd, (long) cmd, arg );
+ }
+ errno = error;
+ SL_RETURN(val_retry, _("retry_fcntl"));
+}
+
+long int retry_msleep (int sec, int millisec)
+{
+ int result = 0;
+#if defined(HAVE_NANOSLEEP)
+ struct timespec req, rem;
+#endif
+
+ errno = 0;
+ if (millisec > 999) millisec = 999;
+ if (millisec < 0) millisec = 0;
+ if (sec < 0) sec = 0;
+
+#if defined(HAVE_NANOSLEEP)
+ /*@-usedef@*/
+ req.tv_sec = sec; rem.tv_sec = 0;
+ req.tv_nsec = millisec * 1000000; rem.tv_nsec = 0;
+ /*@+usedef@*/
+ do {
+ result = /*@-unrecog@*/nanosleep(&req, &rem)/*@+unrecog@*/;
+
+ req.tv_sec = rem.tv_sec; rem.tv_sec = 0;
+ req.tv_nsec = rem.tv_nsec; rem.tv_nsec = 0;
+
+ } while ((result == -1) && (errno == EINTR));
+#else
+ if (sec > 0)
+ sleep (sec); /* nanosleep not available */
+ else {
+#ifdef HAVE_USLEEP
+ if (millisec > 0)
+ usleep(1000 * millisec);
+#else
+ if (millisec > 0)
+ sleep (1);
+#endif
+ }
+#endif
+ return result;
+}
+
+/***************************************************
+ *
+ * Audit these functions.
+ *
+ ***************************************************/
+
+long int retry_aud_execve (const char * file, int line,
+ const char *dateiname, char * argv[],
+ char * envp[])
+{
+ uid_t a = geteuid();
+ gid_t b = getegid();
+ int i;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("retry_aud_execve"));
+
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_EXEC) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_EXEC,
+ dateiname, (long) a, (long) b );
+ do {
+ i = execve(dateiname, argv, envp);
+ } while (i < 0 && errno == EINTR);
+
+ error = errno;
+ if (i < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_EXEC,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ dateiname, (long) a, (long) b );
+ }
+ errno = error;
+ SL_RETURN(i, _("retry_aud_execve"));
+}
+
+
+long int retry_aud_utime (const char * file, int line,
+ char * path, struct utimbuf *buf)
+{
+ long int val_return;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_aud_utime"));
+
+ do {
+ val_return = utime (path, buf);
+ } while (val_return < 0 && errno == EINTR);
+
+ error = errno;
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_UTIME) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_UTIME,
+ path,
+ (unsigned long) buf->actime,
+ (unsigned long) buf->modtime);
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_UTIME,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ path,
+ (unsigned long) buf->actime,
+ (unsigned long) buf->modtime);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("retry_aud_utime"));
+}
+
+long int retry_aud_unlink (const char * file, int line,
+ char * path)
+{
+ long int val_return;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_aud_unlink"));
+
+ do {
+ val_return = unlink (path);
+ } while (val_return < 0 && errno == EINTR);
+
+ error = errno;
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_UNLINK) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_UNLINK,
+ path);
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_UNLINK,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ path);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("retry_aud_unlink"));
+}
+
+long int retry_aud_dup2 (const char * file, int line,
+ int fd, int fd2)
+{
+ long int val_return;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_aud_dup2"));
+
+ do {
+ val_return = dup2 (fd, fd2);
+ } while (val_return < 0 && errno == EINTR);
+
+ error = errno;
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_DUP) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_DUP,
+ (long) fd, val_return);
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_DUP,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) fd, val_return);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("retry_aud_dup2"));
+}
+
+long int retry_aud_dup (const char * file, int line,
+ int fd)
+{
+ long int val_return;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_aud_dup"));
+
+ do {
+ val_return = dup (fd);
+ } while (val_return < 0 && errno == EINTR);
+ error = errno;
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_DUP) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_DUP,
+ (long) fd, val_return);
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_DUP,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) fd, val_return);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("retry_aud_dup"));
+}
+
+
+
+long int retry_aud_chdir (const char * file, int line,
+ const char *path)
+{
+ long int val_return;
+ int error = 0;
+ char errbuf[SH_ERRBUF_SIZE];
+ errno = 0;
+
+ SL_ENTER(_("retry_aud_chdir"));
+
+ do {
+ val_return = chdir (path);
+ } while (val_return < 0 && errno == EINTR);
+
+ error = errno;
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_CHDIR) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_CHDIR,
+ path);
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_CHDIR,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ path);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("retry_aud_chdir"));
+}
+
+
+long int aud_open_noatime (const char * file, int line, int privs,
+ const char *pathname, int flags, mode_t mode,
+ int * o_noatime)
+{
+ long int val_return;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("aud_open"));
+
+#ifdef USE_SUID
+ if (0 == strcmp(pathname, "/usr/bin/sudo"))
+ {
+ uid_t ruid; uid_t euid; uid_t suid;
+ getresuid(&ruid, &euid, &suid);
+ }
+ if (privs == SL_YESPRIV)
+ sl_set_suid();
+#else
+ /*@-noeffect@*/
+ (void) privs; /* fix compiler warning */
+ /*@+noeffect@*/
+#endif
+
+ val_return = open (pathname, *o_noatime|flags, mode);
+
+#ifdef USE_SUID
+ if (privs == SL_YESPRIV)
+ sl_unset_suid();
+#endif
+
+ if ((val_return < 0) && (*o_noatime != 0))
+ {
+ val_return = open (pathname, flags, mode);
+ if (val_return >= 0)
+ *o_noatime = 0;
+ }
+ error = errno;
+
+ if (val_return < 0)
+ {
+ (void) sh_error_message(error, aud_err_message, 64);
+ }
+
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_OPEN) != 0)
+ {
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_OPEN,
+ pathname, (long) flags, (long) mode, val_return);
+ }
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_OPEN,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ pathname, (long) flags, (long) mode, val_return);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("aud_open"));
+}
+
+long int aud_open (const char * file, int line, int privs,
+ const char *pathname, int flags, mode_t mode)
+{
+ long int val_return;
+ int error;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("aud_open"));
+
+#ifdef USE_SUID
+ if (privs == SL_YESPRIV)
+ sl_set_suid();
+#else
+ /*@-noeffect@*/
+ (void) privs; /* fix compiler warning */
+ /*@+noeffect@*/
+#endif
+
+ val_return = open (pathname, flags, mode);
+
+#ifdef USE_SUID
+ if (privs == SL_YESPRIV)
+ sl_unset_suid();
+#endif
+
+ error = errno;
+
+ if (val_return < 0)
+ {
+ (void) sh_error_message(error, aud_err_message, 64);
+ }
+
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_OPEN) != 0)
+ {
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_OPEN,
+ pathname, (long) flags, (long) mode, val_return);
+ }
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_OPEN,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ pathname, (long) flags, (long) mode, val_return);
+ }
+ errno = error;
+ SL_RETURN(val_return, _("aud_open"));
+}
+
+long int aud_kill (const char * file, int line, pid_t pid, int sig)
+{
+ int myerror;
+ long int val_return = kill (pid, sig);
+ char errbuf[SH_ERRBUF_SIZE];
+ myerror = errno;
+
+ SL_ENTER(_("aud_kill"));
+
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_KILL) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_KILL,
+ (long) pid, (long) sig);
+ if (val_return < 0) {
+ sh_error_handle ((-1), file, line, myerror, MSG_ERR_KILL,
+ sh_error_message(myerror, errbuf, sizeof(errbuf)),
+ (long) pid, (long) sig);
+ }
+ errno = myerror;
+ SL_RETURN(val_return, _("aud_kill"));
+}
+
+/*@noreturn@*/
+void aud_exit (const char * file, int line, int exitval)
+{
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_EXIT) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_EXIT,
+ (long) exitval);
+
+ SL_ENTER(_("aud_exit"));
+
+ sh.flag.exit = exitval;
+ exit(exitval);
+}
+
+/*@noreturn@*/
+void aud__exit (const char * file, int line, int exitval)
+{
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_EXIT) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_EXIT,
+ (long) exitval);
+
+ SL_ENTER(_("aud__exit"));
+
+ sh.flag.exit = exitval;
+ _exit(exitval);
+}
+
+pid_t aud_fork (const char * file, int line)
+{
+ int error;
+ pid_t i = fork();
+ char errbuf[SH_ERRBUF_SIZE];
+
+ error = errno;
+ SL_ENTER(_("aud_fork"));
+
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_FORK) != 0 && (i > 0))
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_FORK,
+ (long) i);
+ if (i == (pid_t) -1) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_FORK,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) i);
+ }
+ errno = error;
+ SL_RETURN(i, _("aud_fork"));
+}
+
+int aud_setuid (const char * file, int line, uid_t uid)
+{
+ int error = 0;
+ int i = 0;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("aud_setuid"));
+
+ if (uid != (uid_t) 0) {
+ i = setuid(uid);
+ error = errno;
+ }
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_SETUID) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_SETUID,
+ (long) uid);
+ if (uid == (uid_t) 0) {
+ i = setuid(uid);
+ error = errno;
+ }
+ if (i < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_SETUID,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) uid);
+ }
+ errno = error;
+ SL_RETURN(i, _("aud_setuid"));
+}
+
+int aud_setgid (const char * file, int line, gid_t gid)
+{
+ int error = 0;
+ int i = 0;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("aud_setgid"));
+
+ if (gid != (gid_t) 0) {
+ i = setgid(gid);
+ error = errno;
+ }
+
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_SETGID) != 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_SETGID,
+ (long) gid);
+ if (gid == (gid_t) 0) {
+ i = setgid(gid);
+ error = errno;
+ }
+ if (i < 0) {
+ sh_error_handle ((-1), file, line, error, MSG_ERR_SETGID,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) gid);
+ }
+ errno = error;
+ SL_RETURN(i, _("aud_setgid"));
+}
+
+int aud_pipe (const char * file, int line, int * modus)
+{
+ int error;
+ int i = pipe (modus);
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("aud_pipe"));
+
+ error = errno;
+ if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_PIPE) != 0)
+ {
+ if (i < 0)
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_PIPE,
+ (long) 0, (long) 0);
+ else
+ sh_error_handle ((-1), file, line, 0, MSG_AUD_PIPE,
+ (long) modus[0], (long) modus[1]);
+ }
+ if (i < 0) {
+ if (i < 0)
+ sh_error_handle ((-1), file, line, error, MSG_ERR_PIPE,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) 0, (long) 0);
+ else
+ sh_error_handle ((-1), file, line, error, MSG_ERR_PIPE,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ (long) modus[0], (long) modus[1]);
+ }
+ SL_RETURN(i, _("aud_pipe"));
+}
diff --git a/src/sh_cat.c b/src/sh_cat.c
new file mode 100644
index 0000000..dfffae1
--- /dev/null
+++ b/src/sh_cat.c
@@ -0,0 +1,702 @@
+#include "config_xor.h"
+
+#include "samhain.h"
+#include "sh_error.h"
+
+#include "sh_cat.h"
+
+/*@-nullassign@*/
+
+const char * class_cat[] = {
+ N_("AUD"), /* 0 */
+ N_("PANIC"), /* 1 */
+ N_("RUN_OLD"), /* 2 */
+ N_("FIL_OLD"), /* 3 */
+ N_("TCP"), /* 4 */
+ N_("ERR"), /* 5 */
+ N_("STAMP"), /* 6 */
+ N_("ENET"), /* 7 */
+ N_("EINPUT"), /* 8 */
+
+ /* new simplified classes */
+ N_("EVENT"), /* 9 */
+ N_("START"), /* 10 */
+ N_("LOGKEY"), /* 11 */
+ N_("OTHER"), /* 12 */
+ /* end simplified classes */
+
+ N_("RUN"), /* 13 */
+ N_("FIL"), /* 14 */
+ N_("ERROR"), /* 15 */
+ NULL
+};
+
+
+#ifdef SH_USE_XML
+
+cat_entry msg_cat[] = {
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ { MSG_FI_CSUM, SH_ERR_ALL, FIL, N_("msg=\"Checksum\" chk=\"%s\" path=\"%s\"")},
+ { MSG_FI_DSUM, SH_ERR_INFO, FIL, N_("msg=\"d: %3ld, -: %3ld, l: %3ld, |: %3ld, s: %3ld, c: %3ld, b: %3ld\"")},
+ { MSG_FI_CHK, SH_ERR_INFO, FIL, N_("msg=\"Checking %16s\" path=\"%s\"")},
+#endif
+
+ { MSG_EXIT_ABORTS, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC %s\" program=\"%s\" subroutine=\"%s\"")},
+ { MSG_START_SRV, SH_ERR_STAMP, START, N_("msg=\"Server up, simultaneous connections: %d\" socket_id=\"%d\"")},
+
+ { MSG_EXIT_ABORT1, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC Error initializing the application\" program=\"%s\"")},
+ { MSG_EXIT_NORMAL, SH_ERR_FATAL, START, N_("msg=\"EXIT\" program=\"%s\" status=\"%s\"")},
+ { MSG_START_KEY_MAIL, SH_ERR_FATAL, LOGKEY, N_("msg=\"LOGKEY\" program=\"%s\" hash=\"%s\"\r\n-----BEGIN LOGKEY-----\r\n%s%s")},
+ { MSG_START_KEY, SH_ERR_FATAL, LOGKEY, N_("msg=\"LOGKEY\" program=\"%s\" hash=\"%s\"")},
+ { MSG_START_0H, SH_ERR_FATAL, START, N_("msg=\"START\" program=\"%s\" userid=\"%ld\"")},
+ { MSG_START_1H, SH_ERR_FATAL, START, N_("msg=\"START\" program=\"%s\" userid=\"%ld\" path=\"%s\" hash=\"%s\"")},
+ { MSG_START_2H, SH_ERR_FATAL, START, N_("msg=\"START\" program=\"%s\" userid=\"%ld\" path=\"%s\" hash=\"%s\" path_data=\"%s\" hash_data=\"%s\"")},
+ { MSG_START_GH, SH_ERR_FATAL, START, N_("msg=\"START\" program=\"%s\" userid=\"%ld\" path=\"%s\" key_uid=\"%s\" key_id=\"%s\"")},
+ { MSG_START_GH2, SH_ERR_FATAL, START, N_("msg=\"EXIT\" program=\"%s\" userid=\"%ld\" path=\"%s\" key_uid=\"%s\" key_id=\"%s\" path_data=\"%s\" key_uid_data=\"%s\" key_id_data=\"%s\"")},
+ { MSG_SUSPEND, SH_ERR_STAMP, START, N_("msg=\"SUSPEND\" program=\"%s\"")},
+
+
+ { MSG_MLOCK, SH_ERR_WARN, RUN, N_("msg=\"Using insecure memory\"")},
+ { MSG_W_SIG, SH_ERR_WARN, RUN, N_("interface=\"sigaction\" msg=\"%s\" sig=\"%ld\"")},
+ { MSG_W_CHDIR, SH_ERR_ERR, RUN, N_("interface=\"chdir\" msg=\"%s\" path=\"%s\"")},
+
+ { MSG_MOD_FAIL, SH_ERR_WARN, RUN, N_("msg=\"Module not initialized\" module=\"%s\" return_code=\"%ld\"")},
+ { MSG_MOD_OK, SH_ERR_INFO, RUN, N_("msg=\"Module initialized\" module=\"%s\"")},
+ { MSG_MOD_EXEC, SH_ERR_ERR, RUN, N_("msg=\"Module execution error\" module=\"%s\" return_code=\"%ld\"")},
+
+ { MSG_RECONF, SH_ERR_SEVERE, START, N_("msg=\"Runtime configuration reloaded\"")},
+
+ { MSG_CHECK_0, SH_ERR_WARN, RUN, N_("msg=\"No files or directories defined for checking\"")},
+ { MSG_CHECK_1, SH_ERR_STAMP, STAMP, N_("msg=\"File check completed.\" time=\"%ld\" kBps=\"%f\"")},
+ { MSG_CHECK_2, SH_ERR_STAMP, STAMP, N_("msg=\"File check starting.\"")},
+ { MSG_STAMP, SH_ERR_STAMP, STAMP, N_("msg=\"---- TIMESTAMP ----\"")},
+
+ { MSG_D_START, SH_ERR_INFO, RUN, N_("msg=\"Downloading configuration file\"")},
+ { MSG_D_DSTART, SH_ERR_INFO, RUN, N_("msg=\"Downloading database file\"")},
+ { MSG_D_FAIL, SH_ERR_INFO, RUN, N_("msg=\"No file from server, trying local file\"")},
+ { MSG_D_DELTAOK, SH_ERR_SEVERE, RUN, N_("msg=\"Delta database downloaded\", path=\"%s\"")},
+ { MSG_D_DELTAFAIL, SH_ERR_SEVERE, RUN, N_("msg=\"Delta database download failed\", path=\"%s\"")},
+
+
+#ifndef HAVE_URANDOM
+ { MSG_ENSTART, SH_ERR_ALL, RUN, N_("msg=\"Found entropy source\" path=\"%s\"")},
+ { MSG_ENEXEC, SH_ERR_ALL, RUN, N_("msg=\"Execute entropy source\" path=\"%s\" rd_file_id=\"%ld\"")},
+ { MSG_ENFAIL, SH_ERR_ALL, RUN, N_("msg=\"Could not execute entropy source\" path=\"%s\"")},
+ { MSG_ENTOUT, SH_ERR_ALL, RUN, N_("msg=\"Timeout in entropy collector\" time=\"%ld\"")},
+ { MSG_ENCLOS, SH_ERR_ALL, RUN, N_("msg=\"End of data, closing entropy source\" rd_file_id=\"%ld\"")},
+ { MSG_ENCLOS1, SH_ERR_ALL, RUN, N_("msg=\"Close entropy source\" rd_file_id=\"%ld\"")},
+ { MSG_ENREAD, SH_ERR_ALL, RUN, N_("msg=\"Data from entropy source\" rd_file_id=\"%ld\" bytes=\"%ld\"")},
+#endif
+
+#ifdef SH_USE_SUIDCHK
+ { MSG_SUID_POLICY, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [SuidCheck] %s\" path=\"%s\" %s") },
+ { MSG_SUID_FOUND, SH_ERR_INFO, RUN, N_("msg=\"Found suid/sgid file\" path=\"%s\"") },
+ { MSG_SUID_SUMMARY,SH_ERR_INFO, RUN, N_("msg=\"Checked for SUID programs: %ld files, %ld seconds\"") },
+ { MSG_SUID_QREPORT,SH_ERR_SEVERE, EVENT, N_("msg=\"Quarantine report: %s\" path=\"%s\"") },
+ { MSG_SUID_ERROR, SH_ERR_SEVERE, EVENT, N_("msg=\"Quarantine error: %s\"") },
+#endif
+
+#ifdef SH_USE_UTMP
+ { MSG_UT_CHECK, SH_ERR_INFO, RUN, N_("msg=\"Checking logins\"")},
+ { MSG_UT_LG1X, SH_ERR_INFO, EVENT, N_("msg=\"Login\" userid=\"%s\" tty=\"%s\" host=\"%s\" ip=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG1A, SH_ERR_INFO, EVENT, N_("msg=\"Login\" userid=\"%s\" tty=\"%s\" host=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG1B, SH_ERR_INFO, EVENT, N_("msg=\"Login\" userid=\"%s\" tty=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG2X, SH_ERR_INFO, EVENT, N_("msg=\"Multiple login\" userid=\"%s\" tty=\"%s\" host=\"%s\" ip=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG2A, SH_ERR_INFO, EVENT, N_("msg=\"Multiple login\" userid=\"%s\" tty=\"%s\" host=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG2B, SH_ERR_INFO, EVENT, N_("msg=\"Multiple login\" userid=\"%s\" tty=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG3X, SH_ERR_INFO, EVENT, N_("msg=\"Logout\" userid=\"%s\" tty=\"%s\" host=\"%s\" ip=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG3A, SH_ERR_INFO, EVENT, N_("msg=\"Logout\" userid=\"%s\" tty=\"%s\" host=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG3B, SH_ERR_INFO, EVENT, N_("msg=\"Logout\" userid=\"%s\" tty=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_LG3C, SH_ERR_INFO, EVENT, N_("msg=\"Logout\" tty=\"%s\" time=\"%s\" status=\"%d\"")},
+ { MSG_UT_ROT, SH_ERR_WARN, RUN, N_("msg=\"Logfile size decreased\" path=\"%s\"")},
+
+ { MSG_UT_BAD, SH_ERR_SEVERE, EVENT, N_("msg=\"Login at disallowed time\" userid=\"%s\" host=\"%s\" time=\"%s\"")},
+ { MSG_UT_FIRST, SH_ERR_SEVERE, EVENT, N_("msg=\"First login from this host\" userid=\"%s\" host=\"%s\" time=\"%s\"")},
+ { MSG_UT_OUTLIER, SH_ERR_SEVERE, EVENT, N_("msg=\"Login time outlier\" userid=\"%s\" host=\"%s\" time=\"%s\"")},
+
+#endif
+
+#ifdef SH_USE_PROCESSCHECK
+ { MSG_PCK_CHECK, SH_ERR_INFO, RUN, N_("msg=\"Checking processes in pid interval [%ld,%ld]\"")},
+ { MSG_PCK_OK, SH_ERR_ALL, RUN, N_("msg=\"PID %ld found with tests %s\"")},
+ { MSG_PCK_P_HIDDEN,SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Process] Hidden pid: %ld tests: %s\" path=\"%s\" userid=\"%s\"")},
+ { MSG_PCK_HIDDEN, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Process] Hidden pid: %ld tests: %s\"")},
+ { MSG_PCK_FAKE, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Process] Fake pid: %ld tests: %s\"")},
+ { MSG_PCK_MISS, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Process] Missing: %s\"")},
+#endif
+
+#ifdef SH_USE_PORTCHECK
+ { MSG_PORT_MISS, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [ServiceMissing] %s\"")},
+ { MSG_PORT_NEW, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [ServiceNew] %s\" path=\"%s\" pid=\"%lu\" userid=\"%s\"")},
+ { MSG_PORT_RESTART,SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [ServiceRestarted] %s\" path=\"%s\" pid=\"%lu\" userid=\"%s\"")},
+ { MSG_PORT_NEWPORT,SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [ServicePortSwitch] %s\" path=\"%s\" pid=\"%lu\" userid=\"%s\"")},
+#endif
+
+#ifdef SH_USE_MOUNTS
+ { MSG_MNT_CHECK, SH_ERR_INFO, RUN, N_("msg=\"Checking mounts\"")},
+ { MSG_MNT_MEMLIST, SH_ERR_ERR, RUN, N_("msg=\"Cannot read mount list from memory\"")},
+ { MSG_MNT_MNTMISS, SH_ERR_WARN, EVENT, N_("msg=\"POLICY [Mounts] Mount missing\" path=\"%s\"")},
+ { MSG_MNT_OPTMISS, SH_ERR_WARN, EVENT, N_("msg=\"POLICY [Mounts] Mount option missing\" path=\"%s\" option=\"%s\"")},
+#endif
+
+#ifdef SH_USE_USERFILES
+ { MSG_USERFILES_SUMMARY,SH_ERR_INFO, RUN, N_("msg=\"Checked for users files\"") },
+#endif
+
+#ifdef USE_LOGFILE_MONITOR
+ { MSG_LOGMON_CHKS, SH_ERR_INFO, RUN, N_("msg=\"Checking logfile %s\"") },
+ { MSG_LOGMON_CHKE, SH_ERR_INFO, RUN, N_("msg=\"Finished logfile %s, %lu new records processed\"") },
+ { MSG_LOGMON_MISS, SH_ERR_ERR, RUN, N_("msg=\"Missing logfile %s\"") },
+ { MSG_LOGMON_EOPEN,SH_ERR_ERR, RUN, N_("msg=\"Cannot open logfile %s\"") },
+ { MSG_LOGMON_EREAD,SH_ERR_ERR, RUN, N_("msg=\"Error while reading logfile %s\"") },
+ { MSG_LOGMON_REP, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Logfile] %s\" time=\"%s\" host=\"%s\" path=\"%s\"") },
+ { MSG_LOGMON_SUM, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Logfile] %s\" host=\"%s\" path=\"%s\"") },
+ { MSG_LOGMON_COR, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Logfile] Correlation event %s occured %d time(s)\"") },
+ { MSG_LOGMON_MARK, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Logfile] Event %s missing for %lu seconds\"") },
+ { MSG_LOGMON_BURST, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [Logfile] Repeated %d times: %s\" host=\"%s\"") },
+#endif
+
+#ifdef USE_REGISTRY_CHECK
+ { MSG_REG_MISS, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [RegistryKeyMissing] %s\" path=\"%s\" %s")},
+ { MSG_REG_NEW, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [RegistryKeyNew] %s\" path=\"%s\" %s")},
+ { MSG_REG_CHANGE, SH_ERR_SEVERE, EVENT, N_("msg=\"POLICY [RegistryKeyChanged] %s\" path=\"%s\" %s")},
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+ { MSG_FI_TOOLATE, SH_ERR_ERR, FIL, N_("msg=\"Large lstat/open overhead: %ld sec\" path=\"%s\"")},
+
+#if 0
+ { MSG_FI_CSUM, SH_ERR_ALL, FIL, N_("msg=\"Checksum\" chk=\"%s\" path=\"%s\"")},
+ { MSG_FI_DSUM, SH_ERR_INFO, FIL, N_("msg=\"d: %3ld, -: %3ld, l: %3ld, |: %3ld, s: %3ld, c: %3ld, b: %3ld\"")},
+ { MSG_FI_CHK, SH_ERR_INFO, FIL, N_("msg=\"Checking %16s\" path=\"%s\"")},
+#endif
+
+ { MSG_FI_NULL, SH_ERR_ERR, FIL, N_("msg=\"Path is NULL\"")},
+ { MSG_FI_FAIL, SH_ERR_ERR, FIL, N_("msg=\"Check failed\" path=\"%s\"")},
+ { MSG_FI_GLOB, SH_ERR_ERR, FIL, N_("interface=\"glob\" msg=\"%s\" path=\"%s\"")},
+ { MSG_FI_COLL, SH_ERR_WARN, FIL, N_("msg=\"Writeable file with timestamps of parent directory fixed\" dir=\"%s\" path=\"%s\"")},
+ { MSG_FI_DOUBLE, SH_ERR_WARN, FIL, N_("msg=\"File or directory appears twice in configuration\" path=\"%s\"")},
+ { MSG_FI_2LONG, SH_ERR_ERR, FIL, N_("msg=\"Filename too long\" path=\"%s\"")},
+ { MSG_FI_2LONG2, SH_ERR_ERR, FIL, N_("msg=\"Filename too long\" path=\"%s/%s\"")},
+ { MSG_FI_NOPATH, SH_ERR_ERR, FIL, N_("msg=\"Filename not an absolute path\" path=\"%s\"")},
+ { MSG_FI_DLNK, SH_ERR_INFO, FIL, N_("msg=\"Dangling link\" path=\"%s\" linked_path=\"%s\"")},
+ { MSG_FI_RDLNK, SH_ERR_ERR, FIL, N_("interface=\"readlink\" msg=\"%s\" path=\"%s\"")},
+ { MSG_FI_NOGRP, SH_ERR_ERR, FIL, N_("interface=\"getgrgid\" msg=\"No such group\" group=\"%ld\" path=\"%s\"")},
+ { MSG_FI_NOUSR, SH_ERR_ERR, FIL, N_("interface=\"getpwuid\" msg=\"No such user\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_FI_STAT, SH_ERR_ERR, FIL, N_("interface=\"%s\" msg=\"%s\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_FI_OBSC, SH_ERR_ERR, FIL, N_("msg=\"Weird filename\" path=\"%s\"")},
+ { MSG_FI_OBSC2, SH_ERR_ERR, FIL, N_("msg=\"Weird filename\" path=\"%s/%s\"")},
+ { MSG_FI_LIST, SH_ERR_ALL, FIL, N_("msg=\"%10s %2d %8s %8s %14ld %21s %s\"")},
+ { MSG_FI_LLNK, SH_ERR_ALL, FIL, N_("msg=\" >>> %10s %s\"")},
+ { MSG_FI_MISS, SH_ERR_ERR, EVENT, N_("msg=\"POLICY MISSING\" path=\"%s\"")},
+ { MSG_FI_MISS2, SH_ERR_ERR, EVENT, N_("msg=\"POLICY MISSING\" path=\"%s\" %s")},
+ { MSG_FI_ADD, SH_ERR_ERR, EVENT, N_("msg=\"POLICY ADDED\" path=\"%s\"")},
+ { MSG_FI_ADD2, SH_ERR_ERR, EVENT, N_("msg=\"POLICY ADDED\" path=\"%s\" %s")},
+ { MSG_FI_CHAN, SH_ERR_ERR, EVENT, N_("msg=\"POLICY %s %s\" path=\"%s\" %s")},
+ { MSG_FI_NODIR, SH_ERR_ERR, EVENT, N_("msg=\"POLICY NODIRECTORY\" path=\"%s\"")},
+ { MSG_FI_DBEX, SH_ERR_WARN, FIL, N_("msg=\"Signature database exists\" path=\"%s\"")},
+#endif
+
+ { MSG_TCP_NETRP, SH_ERR_ERR, TCP, N_("msg=\"Connection error: %s\" port=\"%ld\" subroutine=\"%s\"")},
+
+#ifndef SH_STANDALONE
+
+#ifdef INET_SYSLOG
+ { MSG_INET_SYSLOG, SH_ERR_INET, TCP, N_("ip=\"%s\" facility=\"%s\" priority=\"%s\" syslog_msg=\"%s\"")},
+ { MSG_ERR_SYSLOG, SH_ERR_ERR, TCP, N_("msg=\"syslog socket: %s\" ip=\"%s\"")},
+#endif
+ { MSG_TCP_MISMATCH,SH_ERR_ERR, TCP, N_("msg=\"Protocol mismatch\"")},
+ { MSG_TCP_MISENC, SH_ERR_ERR, TCP, N_("msg=\"Encryption mismatch in %s: server: %s client: %s\"")},
+ { MSG_TCP_NONAME, SH_ERR_ERR, TCP, N_("msg=\"No server name known\"")},
+ { MSG_TCP_UNEXP, SH_ERR_ERR, TCP, N_("msg=\"Unexpected reply\"")},
+ { MSG_TCP_EFIL, SH_ERR_ERR, TCP, N_("msg=\"Could not open temporary file\"")},
+ { MSG_TCP_NOCONF, SH_ERR_ERR, TCP, N_("msg=\"Message delivery not confirmed\"")},
+ { MSG_TCP_NOAUTH, SH_ERR_ERR, TCP, N_("msg=\"Session key negotiation failed\"")},
+ { MSG_TCP_CONF, SH_ERR_ALL, TCP, N_("msg=\"Message delivery confirmed\"")},
+ { MSG_TCP_AUTH, SH_ERR_INFO, TCP, N_("msg=\"Session key negotiated\"")},
+ { MSG_TCP_FOK, SH_ERR_INFO, TCP, N_("msg=\"File download completed\"")},
+ { MSG_TCP_FBAD, SH_ERR_ERR, TCP, N_("msg=\"File download failed\"")},
+ { MSG_TCP_ECONN, SH_ERR_ERR, TCP, N_("msg=\"Connection error: %s\"")},
+ { MSG_TCP_EZERO, SH_ERR_ERR, TCP, N_("msg=\"Illegal zero reply\"")},
+ { MSG_TCP_EBGN, SH_ERR_ERR, TCP, N_("msg=\"Error in big integer library\"")},
+
+ { MSG_TCP_CREG, SH_ERR_ALL, TCP, N_("msg=\"Registered %s, salt %s, verifier %s\"")},
+ { MSG_TCP_FAUTH, SH_ERR_INFO, TCP, N_("msg=\"Force authentication\" host=\"%s\"")},
+
+ { MSG_TCP_RESCLT, SH_ERR_SEVERE, TCP, N_("msg=\"Cannot resolve client name\" host=\"%s\"")},
+ { MSG_TCP_RESPEER, SH_ERR_SEVERE, TCP, N_("msg=\"Cannot resolve socket peer IP for client\" host=\"%s\" peer=\"%s\"")},
+ { MSG_TCP_LOOKERS, SH_ERR_SEVERE, TCP, N_("msg=\"Reverse lookup of socket peer failed\" host=\"%s\" peer=\"%s\" obj=\"%s\"")},
+ { MSG_TCP_LOOKUP, SH_ERR_SEVERE, TCP, N_("msg=\"No socket peer alias matches client name\" host=\"%s\" peer=\"%s\"")},
+
+ { MSG_TCP_TIMOUT, SH_ERR_SEVERE, TCP, N_("msg=\"Connection timeout\" host=\"%s\"")},
+ { MSG_TCP_TIMEXC, SH_ERR_SEVERE, TCP, N_("msg=\"Time limit exceeded\" host=\"%s\"")},
+ { MSG_TCP_NOCLT, SH_ERR_SEVERE, TCP, N_("msg=\"Hostname is NULL\"")},
+ { MSG_TCP_BADCONN, SH_ERR_SEVERE, TCP, N_("msg=\"Invalid connection attempt: %s\" host=\"%s\"")},
+ { MSG_TCP_FFILE , SH_ERR_SEVERE, TCP, N_("msg=\"Unknown file request\" host=\"%s\" path=\"%s\"")},
+ { MSG_TCP_NFILE , SH_ERR_SEVERE, TCP, N_("msg=\"Requested file not found\" host=\"%s\" path=\"%s\"")},
+ { MSG_TCP_FINV , SH_ERR_SEVERE, TCP, N_("msg=\"Invalid request (%d) in pass %d\" host=\"%s\" request=\"%c%03o%c%03o%c%03o%c%03o\"")},
+ { MSG_TCP_OKFILE, SH_ERR_INFO, TCP, N_("msg=\"File transfer completed\" host=\"%s\"")},
+ { MSG_TCP_OKMSG, SH_ERR_ALL, TCP, N_("msg=\"Message transfer completed\" host=\"%s\"")},
+ { MSG_TCP_MSG, SH_ERR_INET, TCP, N_("remote_host=\"%s\" > %s </log>")},
+ { MSG_TCP_NEW, SH_ERR_NOTICE, TCP, N_("msg=\"NEW CLIENT\" host=\"%s\"")},
+ { MSG_TCP_ILL, SH_ERR_SEVERE, TCP, N_("msg=\"Restart without prior exit\" host=\"%s\"")},
+ { MSG_TCP_SYNC, SH_ERR_SEVERE, TCP, N_("msg=\"Out of sync\" host=\"%s\"")},
+ { MSG_TCP_RESET, SH_ERR_NOTICE, TCP, N_("msg=\"Connection reset by peer\" host=\"%s\"")},
+ { MSG_TCP_CNEW, SH_ERR_INFO, TCP, N_("msg=\"New connection\" socket_id=\"%d\"")},
+ { MSG_E_HTML, SH_ERR_ERR, ERR, N_("msg=\"Error writing HTML status\"")},
+#endif
+
+
+ { MSG_E_AUTH, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC - File modified\" path=\"%s\"")},
+ { MSG_ACCESS, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC - Access violation\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_TRUST, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC - Untrusted path\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_NOACCESS, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC - File not accessible\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_P_NODATA, SH_ERR_FATAL, PANIC, N_("msg=\"PANIC - No data in file\" path=\"%s\"")},
+
+
+#ifndef MEM_DEBUG
+ { MSG_E_MNULL, SH_ERR_ERR, ERR, N_("msg=\"Dereferenced NULL pointer\"")},
+ { MSG_E_MMEM, SH_ERR_ERR, ERR, N_("msg=\"Out of memory\"")},
+#else
+ { MSG_MSTAMP, SH_ERR_STAMP, STAMP, N_("msg=\"Memory used: max.=%lu, current=%lu\"")},
+ { MSG_MSTAMP2, SH_ERR_STAMP, STAMP, N_("msg=\"Blocks: %d allocated, %d freed, %d maximum\"")},
+ { MSG_E_MNULL, SH_ERR_ERR, ERR, N_("msg=\"Dereferenced NULL pointer allocated in %s, line %d\" source_file=\"%s\" source_line=\"%d\"")},
+ { MSG_E_MMEM, SH_ERR_ERR, ERR, N_("msg=\"Out of memory\" source_file=\"%s\" source_line=\"%d\"")},
+ { MSG_E_MREC, SH_ERR_ERR, ERR, N_("msg=\"Free() on unrecorded block\" source_file=\"%s\" source_line=\"%d\"")},
+ { MSG_E_MOVER, SH_ERR_ERR, ERR, N_("msg=\"Memory overrun on block allocated in %s, line %d\" source_file=\"%s\" source_line=\"%d\"")},
+ { MSG_E_MUNDER, SH_ERR_ERR, ERR, N_("msg=\"Memory underrun on block allocated in %s, line %d\" source_file=\"%s\" source_line=\"%d\"")},
+ { MSG_E_NOTFREE, SH_ERR_ERR, ERR, N_("msg=\"Block not deallocated\" size=\"%14ld\" source_file=\"%19s\" source_line=\"%d\"")},
+#endif
+
+ { MSG_E_TRUST, SH_ERR_ERR, ERR, N_("msg=\"Untrusted path\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_E_HASH, SH_ERR_ERR, ERR, N_("msg=\"Incorrect checksum\" path=\"%s\"")},
+ { MSG_E_ACCESS, SH_ERR_ERR, ERR, N_("msg=\"File not accessible\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_E_READ, SH_ERR_ERR, ERR, N_("msg=\"Not accessible or not a regular file (%s / %s)\" path=\"%s\"")},
+ { MSG_E_NOTREG, SH_ERR_ERR, ERR, N_("msg=\"Not a regular file\" path=\"%s\"")},
+ { MSG_E_TIMEOUT, SH_ERR_ERR, ERR, N_("msg=\"Timeout (%d sec) while checksumming file\" path=\"%s\"")},
+ { MSG_NODEV, SH_ERR_ERR, ERR, N_("msg=\"Device not available or timeout during read attempt\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_LOCKED, SH_ERR_ERR, ERR, N_("msg=\"File lock error\" userid=\"%ld\" path=\"%s\" obj=\"%s\"")},
+ { MSG_PIDFILE, SH_ERR_ERR, ERR, N_("msg=\"Could not write PID file\" userid=\"%ld\" path=\"%s\"")},
+ { MSG_NOEXEC, SH_ERR_ERR, ERR, N_("msg=\"Could not execute file\" userid=\"%ld\" path=\"%s\"")},
+
+ { MSG_ES_ENT, SH_ERR_ERR, ERR, N_("msg=\"No entropy collected\" subroutine=\"%s\"")},
+ { MSG_ES_KEY1, SH_ERR_ERR, ERR, N_("msg=\"Insecure key generation\" subroutine=\"%s\"")},
+ { MSG_ES_KEY2, SH_ERR_ERR, ERR, N_("msg=\"Error copying key\" subroutine=\"%s\"")},
+ { MSG_E_GPG, SH_ERR_ERR, ERR, N_("msg=\"Compiled-in gpg checksum does not match: need %s got %s\"")},
+ { MSG_E_GPG_FP, SH_ERR_ERR, ERR, N_("msg=\"Compiled-in fingerprint modified: one %s two %s\"")},
+ { MSG_E_GPG_CHK, SH_ERR_ERR, ERR, N_("msg=\"Compiled-in checksum modified: one %s two %s\"")},
+ { MSG_E_SUBGEN, SH_ERR_ERR, ERR, N_("msg=\"%s\" subroutine=\"%s\"")},
+ { MSG_E_SUBGPATH, SH_ERR_ERR, ERR, N_("msg=\"%s\" subroutine=\"%s\" path=\"%s\"")},
+ { MSG_E_UNLNK, SH_ERR_ERR, FIL, N_("interface=\"unlink\" msg=\"%s\" path=\"%s\"")},
+ { MSG_E_REGEX, SH_ERR_ERR, ERR, N_("interface=\"regcomp\" msg=\"%s\" obj=\"%s\"")},
+ { MSG_E_OPENDIR, SH_ERR_ERR, FIL, N_("interface=\"opendir\" msg=\"%s\" path=\"%s\"")},
+ { MSG_E_TRUST1, SH_ERR_ERR, ERR, N_("msg=\"%s\" subroutine=\"trustfile\" path=\"%s\"")},
+ { MSG_E_TRUST2, SH_ERR_ERR, ERR, N_("msg=\"%s\" subroutine=\"trustfile\" path=\"%s\" obj=\"%s\"")},
+ { MSG_E_PWNULL, SH_ERR_ERR, ERR, N_("msg=\"Empty password file entry: %s\" subroutine=\"%s\" userid=\"%ld\" obj=\"%s\"")},
+ { MSG_E_PWLONG, SH_ERR_ERR, ERR, N_("msg=\"Password file entry too long\" subroutine=\"%s\" userid=\"%ld\" obj=\"%s\"")},
+ { MSG_E_GRNULL, SH_ERR_ERR, ERR, N_("msg=\"Empty groups file entry: %s\" subroutine=\"%s\" group=\"%ld\" obj=\"%s\"")},
+
+ { MSG_E_NET, SH_ERR_ERR, ENET, N_("msg=\"%s\" subroutine=\"%s\" service=\"%s\" host=\"%s\"")},
+ { MSG_E_NETST, SH_ERR_ERR, ENET, N_("msg=\"Invalid connection state\" expect=\"%4s\" received=\"%4s\"")},
+ { MSG_E_NETST1, SH_ERR_ERR, ENET, N_("msg=\"Invalid connection state\" expect=\"%4s\" received=\"%4s\" host=\"%s\"")},
+ { MSG_E_NLOST, SH_ERR_ERR, ENET, N_("msg=\"Connection failure\" service=\"%s\" host=\"%s\"")},
+ { MSG_E_NEST, SH_ERR_ERR, ENET, N_("msg=\"Connection reestablished\" service=\"%s\" host=\"%s\"")},
+
+ { MSG_EINVALHEAD, SH_ERR_WARN, EINPUT,N_("msg=\"Unrecognized section heading in line %ld of configuration file\"")},
+ { MSG_EINVALCONF, SH_ERR_WARN, EINPUT,N_("msg=\"Invalid line %ld in configuration file: incorrect format, unrecognized option, or missing section header\"")},
+ { MSG_EINVALS, SH_ERR_WARN, EINPUT,N_("msg=\"Invalid input\" option=\"%s\" obj=\"%s\"")},
+ { MSG_EINVALL, SH_ERR_WARN, EINPUT,N_("msg=\"Invalid input\" option=\"%s\" obj=\"%ld\"")},
+ { MSG_EINVALD, SH_ERR_WARN, EINPUT,N_("msg=\"Configuration file: unmatched @end\" option=\"%s\" obj=\"%ld\"")},
+ { MSG_EINVALDD, SH_ERR_WARN, EINPUT,N_("msg=\"Configuration file: missing @end\" option=\"%s\" obj=\"%ld\"")},
+
+ { MSG_SRV_FAIL, SH_ERR_ERR, ERR, N_("msg=\"Service failure\" service=\"%s\" obj=\"%s\"")},
+ { MSG_QUEUE_FULL, SH_ERR_ERR, ERR, N_("msg=\"Queue full, messages may get lost\" service=\"%s\"")},
+
+ { MSG_AUD_OPEN, SH_ERR_NOTICE, AUD, N_("interface=\"open\" path=\"%s\" oflag=\"%ld\" mode=\"%ld\" return_id=\"%ld\"")},
+ { MSG_AUD_DUP, SH_ERR_NOTICE, AUD, N_("interface=\"dup\" file_id=\"%ld\" return_id=\"%ld\"")},
+ { MSG_AUD_PIPE, SH_ERR_NOTICE, AUD, N_("interface=\"pipe\" rd_file_id=\"%ld\" wr_file_id=\"%ld\"")},
+ { MSG_AUD_FORK, SH_ERR_NOTICE, AUD, N_("interface=\"fork\" return_id=\"%ld\"")},
+ { MSG_AUD_EXIT, SH_ERR_NOTICE, AUD, N_("interface=\"exit\" exit_code=\"%ld\"")},
+ { MSG_AUD_SETUID, SH_ERR_NOTICE, AUD, N_("interface=\"setuid\" uid=\"%ld\"")},
+ { MSG_AUD_SETGID, SH_ERR_NOTICE, AUD, N_("interface=\"setgid\" gid=\"%ld\"")},
+ { MSG_AUD_UTIME, SH_ERR_NOTICE, AUD, N_("interface=\"utime\" path=\"%s\" atime=\"%ld\" mtime=\"%ld\"")},
+ { MSG_AUD_EXEC, SH_ERR_NOTICE, AUD, N_("interface=\"exec\" path=\"%s\" uid=\"%ld\" gid=\"%ld\"")},
+ { MSG_AUD_CHDIR, SH_ERR_NOTICE, AUD, N_("interface=\"chdir\" path=\"%s\"")},
+ { MSG_AUD_UNLINK, SH_ERR_NOTICE, AUD, N_("interface=\"unlink\" path=\"%s\"")},
+ { MSG_AUD_KILL, SH_ERR_NOTICE, AUD, N_("interface=\"kill\" pid=\"%ld\" sig=\"%ld\"")},
+
+ { MSG_ERR_OPEN, SH_ERR_ALL, ERR, N_("interface=\"open\" msg=\"%s\" path=\"%s\" oflag=\"%ld\" mode=\"%ld\" return_id=\"%ld\"")},
+ { MSG_ERR_DUP, SH_ERR_ALL, ERR, N_("interface=\"dup\" msg=\"%s\" file_id=\"%ld\" return_id=\"%ld\"")},
+ { MSG_ERR_PIPE, SH_ERR_ALL, ERR, N_("interface=\"pipe\" msg=\"%s\" rd_file_id=\"%ld\" wr_file_id=\"%ld\"")},
+ { MSG_ERR_FORK, SH_ERR_ALL, ERR, N_("interface=\"fork\" msg=\"%s\" return_id=\"%ld\"")},
+ { MSG_ERR_SETUID, SH_ERR_ALL, ERR, N_("interface=\"setuid\" msg=\"%s\" uid=\"%ld\"")},
+ { MSG_ERR_SETGID, SH_ERR_ALL, ERR, N_("interface=\"setgid\" msg=\"%s\" gid=\"%ld\"")},
+ { MSG_ERR_UTIME, SH_ERR_ALL, ERR, N_("interface=\"utime\" msg=\"%s\" path=\"%s\" atime=\"%ld\" mtime=\"%ld\"")},
+ { MSG_ERR_EXEC, SH_ERR_ALL, ERR, N_("interface=\"exec\" msg=\"%s\" path=\"%s\" uid=\"%ld\" gid=\"%ld\"")},
+ { MSG_ERR_CHDIR, SH_ERR_ALL, ERR, N_("interface=\"chdir\" msg=\"%s\" path=\"%s\"")},
+ { MSG_ERR_UNLINK, SH_ERR_ALL, ERR, N_("interface=\"unlink\" msg=\"%s\" path=\"%s\"")},
+ { MSG_ERR_KILL, SH_ERR_ALL, ERR, N_("interface=\"kill\" msg=\"%s\" pid=\"%ld\" sig=\"%ld\"")},
+
+ { MSG_ERR_SIGACT, SH_ERR_ALL, ERR, N_("interface=\"sigaction\" msg=\"%s\" sig=\"%ld\"")},
+ { MSG_ERR_CONNECT, SH_ERR_ALL, ERR, N_("interface=\"connect\" msg=\"%s\" socket_id=\"%ld\" port=\"%ld\" host=\"%s\"")},
+ { MSG_ERR_ACCEPT, SH_ERR_ALL, ERR, N_("interface=\"accept\" msg=\"%s\" socket_id=\"%ld\"")},
+ { MSG_ERR_LSTAT, SH_ERR_ALL, ERR, N_("interface=\"lstat\" msg=\"%s\" path=\"%s\"")},
+ { MSG_ERR_STAT, SH_ERR_ALL, ERR, N_("interface=\"stat\" msg=\"%s\" path=\"%s\"")},
+ { MSG_ERR_FSTAT, SH_ERR_ALL, ERR, N_("interface=\"fstat\" msg=\"%s\" file_id=\"%ld\"")},
+ { MSG_ERR_FCNTL, SH_ERR_ALL, ERR, N_("interface=\"fcntl\" msg=\"%s\" file_id=\"%ld\" cmd=\"%ld\" arg=\"%ld\"")},
+
+ { 0, 0, 0, NULL}
+};
+
+
+
+/********************************************************************
+ *
+ *
+ * NO XML
+ *
+ *
+ ********************************************************************/
+
+
+
+
+
+/* #ifdef (SH_USE_XML) */
+#else
+
+cat_entry msg_cat[] = {
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ { MSG_FI_CSUM, SH_ERR_ALL, FIL, N_("msg=<Checksum>, chk=<%s>, path=<%s>")},
+ { MSG_FI_DSUM, SH_ERR_INFO, FIL, N_("msg=<d: %3ld, -: %3ld, l: %3ld, |: %3ld, s: %3ld, c: %3ld, b: %3ld>")},
+ { MSG_FI_CHK, SH_ERR_INFO, FIL, N_("msg=<Checking %16s>, path=<%s>")},
+#endif
+
+ { MSG_EXIT_ABORTS, SH_ERR_FATAL, PANIC, N_("msg=<PANIC %s>, program=<%s>, subroutine=<%s>")},
+ { MSG_START_SRV, SH_ERR_STAMP, START, N_("msg=<Server up, simultaneous connections: %d>, socket_id=<%d>")},
+
+ { MSG_EXIT_ABORT1, SH_ERR_FATAL, PANIC, N_("msg=<PANIC Error initializing the application>, program=<%s>")},
+ { MSG_EXIT_NORMAL, SH_ERR_FATAL, START, N_("msg=<EXIT>, program=<%s>, status=<%s>")},
+ { MSG_START_KEY_MAIL, SH_ERR_FATAL, LOGKEY, N_("msg=<LOGKEY>, program=<%s>, hash=<%s>\r\n-----BEGIN LOGKEY-----\r\n%s%s")},
+ { MSG_START_KEY, SH_ERR_FATAL, LOGKEY, N_("msg=<LOGKEY>, program=<%s>, hash=<%s>")},
+ { MSG_START_0H, SH_ERR_FATAL, START, N_("msg=<START>, program=<%s>, userid=<%ld>")},
+ { MSG_START_1H, SH_ERR_FATAL, START, N_("msg=<START>, program=<%s>, userid=<%ld>, path=<%s>, hash=<%s>")},
+ { MSG_START_2H, SH_ERR_FATAL, START, N_("msg=<START>, program=<%s>, userid=<%ld>, path=<%s>, hash=<%s>, path=<%s>, hash=<%s>")},
+ { MSG_START_GH, SH_ERR_FATAL, START, N_("msg=<START>, program=<%s>, userid=<%ld>, path=<%s>, key_uid=<%s>, key_id=<%s>")},
+ { MSG_START_GH2, SH_ERR_FATAL, START, N_("msg=<EXIT>, program=<%s>, userid=<%ld>, path=<%s>, key_uid=<%s>, key_id=<%s>, path=<%s>, key_uid=<%s>, key_id=<%s>")},
+ { MSG_SUSPEND, SH_ERR_STAMP, START, N_("msg=<SUSPEND> program=<%s>")},
+
+
+ { MSG_MLOCK, SH_ERR_WARN, RUN, N_("msg=<Using insecure memory>")},
+ { MSG_W_SIG, SH_ERR_WARN, RUN, N_("msg=<%s>, interface=<sigaction>, signal=<%ld>")},
+ { MSG_W_CHDIR, SH_ERR_ERR, RUN, N_("msg=<%s>, interface=<chdir>, path=<%s>")},
+
+ { MSG_MOD_FAIL, SH_ERR_WARN, RUN, N_("msg=<Module not initialized>, module=<%s>, return_code=<%ld>")},
+ { MSG_MOD_OK, SH_ERR_INFO, RUN, N_("msg=<Module initialized>, module=<%s>")},
+ { MSG_MOD_EXEC, SH_ERR_ERR, RUN, N_("msg=<Module execution error>, module=<%s>, return_code=<%ld>")},
+
+ { MSG_RECONF, SH_ERR_SEVERE, START, N_("msg=<Runtime configuration reloaded>")},
+ { MSG_CHECK_0, SH_ERR_WARN, RUN, N_("msg=<No files or directories defined for checking>")},
+ { MSG_CHECK_1, SH_ERR_STAMP, STAMP, N_("msg=<File check completed.>, time=<%ld>, kBps=<%f>")},
+ { MSG_CHECK_2, SH_ERR_STAMP, STAMP, N_("msg=<File check starting.>")},
+ { MSG_STAMP, SH_ERR_STAMP, STAMP, N_("msg=<---- TIMESTAMP ---->")},
+
+ { MSG_D_START, SH_ERR_INFO, RUN, N_("msg=<Downloading configuration file>")},
+ { MSG_D_DSTART, SH_ERR_INFO, RUN, N_("msg=<Downloading database file>")},
+ { MSG_D_FAIL, SH_ERR_INFO, RUN, N_("msg=<No file from server, trying local file>")},
+ { MSG_D_DELTAOK, SH_ERR_SEVERE, RUN, N_("msg=<Delta database downloaded>, path=<%s>")},
+ { MSG_D_DELTAFAIL, SH_ERR_SEVERE, RUN, N_("msg=<Delta database download failed>, path=<%s>")},
+
+
+#ifndef HAVE_URANDOM
+ { MSG_ENSTART, SH_ERR_ALL, RUN, N_("msg=<Found entropy source>, path=<%s>")},
+ { MSG_ENEXEC, SH_ERR_ALL, RUN, N_("msg=<Execute entropy source>, path=<%s>, rd_file_id=<%ld>")},
+ { MSG_ENFAIL, SH_ERR_ALL, RUN, N_("msg=<Could not execute entropy source>, path=<%s>")},
+ { MSG_ENTOUT, SH_ERR_ALL, RUN, N_("msg=<Timeout in entropy collector>, time=<%ld>")},
+ { MSG_ENCLOS, SH_ERR_ALL, RUN, N_("msg=<End of data, closing entropy source>, rd_file_id=<%ld>")},
+ { MSG_ENCLOS1, SH_ERR_ALL, RUN, N_("msg=<Close entropy source>, rd_file_id=<%ld>")},
+ { MSG_ENREAD, SH_ERR_ALL, RUN, N_("msg=<Data from entropy source>, rd_file_id=<%ld>, bytes=<%ld>")},
+#endif
+
+#ifdef SH_USE_SUIDCHK
+ { MSG_SUID_POLICY, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [SuidCheck] %s>, path=<%s>, %s") },
+ { MSG_SUID_FOUND, SH_ERR_INFO, RUN, N_("msg=<Found suid/sgid file> path=<%s>") },
+ { MSG_SUID_SUMMARY,SH_ERR_INFO, RUN, N_("msg=<Checked for SUID programs: %ld files, %ld seconds>") },
+ { MSG_SUID_QREPORT,SH_ERR_SEVERE, EVENT, N_("msg=<Quarantine report: %s>, path=<%s>") },
+ { MSG_SUID_ERROR, SH_ERR_SEVERE, EVENT, N_("msg=<Quarantine error: %s>") },
+#endif
+
+#ifdef SH_USE_KERN
+ { MSG_KERN_POLICY, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Kernel] BSD syscall table: new: %#lx old: %#lx>, syscall=<%03d %s>") },
+ { MSG_KERN_POL_CO, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Kernel] BSD syscall code: new: %#x,%#x old: %#x,%#x>, syscall=<%03d %s>") },
+
+ { MSG_KERN_SYSCALL,SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Kernel] SYSCALL modified> syscall=<%03d %s>, %s") },
+ { MSG_KERN_PROC, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Kernel] PROC modified proc filesystem: %s>") },
+ { MSG_KERN_IDT, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Kernel] IDT interrupt %03d: new: 0x%-8.8lx %-9s %3d %c old: 0x%-8.8lx %-9s %3d %c>, %s") },
+ { MSG_KERN_GATE, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Kernel SYS_GATE code: new: %#x,%#x old: %#x,%#x> syscall=<%03d %s>, %s") },
+
+#endif
+
+#ifdef SH_USE_UTMP
+ { MSG_UT_CHECK, SH_ERR_INFO, RUN, N_("msg=<Checking logins>")},
+
+ { MSG_UT_LG1X, SH_ERR_INFO, EVENT, N_("msg=<Login>, name=<%s>, tty=<%s>, host=<%s>, ip=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG1A, SH_ERR_INFO, EVENT, N_("msg=<Login>, name=<%s>, tty=<%s>, host=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG1B, SH_ERR_INFO, EVENT, N_("msg=<Login>, name=<%s>, tty=<%s>, time=<%s>, status=<%d>")},
+
+ { MSG_UT_LG2X, SH_ERR_INFO, EVENT, N_("msg=<Multiple login>, name=<%s>, tty=<%s>, host=<%s>, ip=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG2A, SH_ERR_INFO, EVENT, N_("msg=<Multiple login>, name=<%s>, tty=<%s>, host=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG2B, SH_ERR_INFO, EVENT, N_("msg=<Multiple login>, name=<%s>, tty=<%s>, time=<%s>, status=<%d>")},
+
+ { MSG_UT_LG3X, SH_ERR_INFO, EVENT, N_("msg=<Logout>, name=<%s>, tty=<%s>, host=<%s>, ip=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG3A, SH_ERR_INFO, EVENT, N_("msg=<Logout>, name=<%s>, tty=<%s>, host=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG3B, SH_ERR_INFO, EVENT, N_("msg=<Logout>, name=<%s>, tty=<%s>, time=<%s>, status=<%d>")},
+ { MSG_UT_LG3C, SH_ERR_INFO, EVENT, N_("msg=<Logout>, tty=<%s>, time=<%s>")},
+ { MSG_UT_ROT, SH_ERR_WARN, RUN, N_("msg=<Logfile size decreased>, path=<%s>")},
+
+ { MSG_UT_BAD, SH_ERR_SEVERE, EVENT, N_("msg=<Login at disallowed time> userid=<%s> host=<%s> time=<%s>")},
+ { MSG_UT_FIRST, SH_ERR_SEVERE, EVENT, N_("msg=<First login from this host> userid=<%s> host=<%s> time=<%s>")},
+ { MSG_UT_OUTLIER, SH_ERR_SEVERE, EVENT, N_("msg=<Login time outlier> userid=<%s> host=<%s> time=<%s>")},
+#endif
+
+#ifdef SH_USE_PROCESSCHECK
+ { MSG_PCK_CHECK, SH_ERR_INFO, RUN, N_("msg=<Checking processes in pid interval [%ld,%ld]>")},
+ { MSG_PCK_OK, SH_ERR_ALL, RUN, N_("msg=<PID %ld found with tests %s>")},
+ { MSG_PCK_P_HIDDEN,SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Process] Hidden pid: %ld tests: %s> path=<%s> userid=<%s>")},
+ { MSG_PCK_HIDDEN, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Process] Hidden pid: %ld tests: %s>")},
+ { MSG_PCK_FAKE, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Process] Fake pid: %ld tests: %s>")},
+ { MSG_PCK_MISS, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Process] Missing: %s>")},
+#endif
+
+#ifdef SH_USE_PORTCHECK
+ { MSG_PORT_MISS, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [ServiceMissing] %s>")},
+ { MSG_PORT_NEW, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [ServiceNew] %s> path=<%s> pid=<%lu> userid=<%s>")},
+ { MSG_PORT_RESTART,SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [ServiceRestarted] %s> path=<%s> pid=<%lu> userid=<%s>")},
+ { MSG_PORT_NEWPORT,SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [ServicePortSwitch] %s> path=<%s> pid=<%lu> userid=<%s>")},
+#endif
+
+#ifdef SH_USE_MOUNTS
+ { MSG_MNT_CHECK, SH_ERR_INFO, RUN, N_("msg=<Checking mounts>")},
+ { MSG_MNT_MEMLIST, SH_ERR_ERR, RUN, N_("msg=<Cannot read mount list from memory>")},
+ { MSG_MNT_MNTMISS, SH_ERR_WARN, EVENT, N_("msg=<POLICY [Mounts] Mount missing>, path=<%s>")},
+ { MSG_MNT_OPTMISS, SH_ERR_WARN, EVENT, N_("msg=<POLICY [Mounts] Mount option missing>, path=<%s>, option=<%s>")},
+#endif
+
+#ifdef SH_USE_USERFILES
+ { MSG_USERFILES_SUMMARY,SH_ERR_INFO, RUN, N_("msg=<Checked for users files>") },
+#endif
+
+#ifdef USE_LOGFILE_MONITOR
+ { MSG_LOGMON_CHKS, SH_ERR_INFO, RUN, N_("msg=<Checking logfile %s>") },
+ { MSG_LOGMON_CHKE, SH_ERR_INFO, RUN, N_("msg=<Finished logfile %s, %lu new records processed>") },
+ { MSG_LOGMON_MISS, SH_ERR_ERR, RUN, N_("msg=<Missing logfile %s>") },
+ { MSG_LOGMON_EOPEN,SH_ERR_ERR, RUN, N_("msg=<Cannot open logfile %s>") },
+ { MSG_LOGMON_EREAD,SH_ERR_ERR, RUN, N_("msg=<Error while reading logfile %s>") },
+ { MSG_LOGMON_REP, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Logfile] %s> time=<%s>, host=<%s>, path=<%s>") },
+ { MSG_LOGMON_SUM, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Logfile] %s> host=<%s> path=<%s>") },
+ { MSG_LOGMON_COR, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Logfile] Correlation event %s occured %d time(s)>") },
+ { MSG_LOGMON_MARK, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Logfile] Event %s missing for %lu seconds>") },
+ { MSG_LOGMON_BURST, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [Logfile] Repeated %d times: %s>, host=<%s> ") },
+#endif
+
+#ifdef USE_REGISTRY_CHECK
+ { MSG_REG_MISS, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [RegistryKeyMissing] %s>, path=<%s>, %s")},
+ { MSG_REG_NEW, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [RegistryKeyNew] %s>, path=<%s>, %s")},
+ { MSG_REG_CHANGE, SH_ERR_SEVERE, EVENT, N_("msg=<POLICY [RegistryKeyChanged] %s>, path=<%s>, %s")},
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+ { MSG_FI_TOOLATE, SH_ERR_ERR, FIL, N_("msg=<Large lstat/open overhead (%ld sec)>, path=<%s>")},
+
+#if 0
+ { MSG_FI_CSUM, SH_ERR_ALL, FIL, N_("msg=<Checksum>, chk=<%s>, path=<%s>")},
+ { MSG_FI_DSUM, SH_ERR_INFO, FIL, N_("msg=<d: %3ld, -: %3ld, l: %3ld, |: %3ld, s: %3ld, c: %3ld, b: %3ld>")},
+ { MSG_FI_CHK, SH_ERR_INFO, FIL, N_("msg=<Checking %16s>, path=<%s>")},
+#endif
+
+ { MSG_FI_NULL, SH_ERR_ERR, FIL, N_("msg=<Path is NULL>")},
+ { MSG_FI_FAIL, SH_ERR_ERR, FIL, N_("msg=<Check failed>, path=<%s>")},
+ { MSG_FI_GLOB, SH_ERR_ERR, FIL, N_("msg=<%s>, interface=<glob>, path=<%s>")},
+ { MSG_FI_COLL, SH_ERR_WARN, FIL, N_("msg=<Writeable file with timestamps of parent directory fixed>, dir=<%s>, path=<%s>")},
+ { MSG_FI_DOUBLE, SH_ERR_WARN, FIL, N_("msg=<File or directory appears twice in configuration>, path=<%s>")},
+ { MSG_FI_2LONG, SH_ERR_ERR, FIL, N_("msg=<Filename too long>, path=<%s>")},
+ { MSG_FI_2LONG2, SH_ERR_ERR, FIL, N_("msg=<Filename too long>, path=<%s/%s>")},
+ { MSG_FI_NOPATH, SH_ERR_ERR, FIL, N_("msg=<Filename not an absolute path>, path=<%s>")},
+ { MSG_FI_DLNK, SH_ERR_INFO, FIL, N_("msg=<Dangling link>, path=<%s>, linked_path=<%s>")},
+ { MSG_FI_RDLNK, SH_ERR_ERR, FIL, N_("msg=<%s>, interface=<readlink>, path=<%s>")},
+ { MSG_FI_NOGRP, SH_ERR_ERR, FIL, N_("msg=<No such group>, interface=<getgrgid>, group=<%ld>, path=<%s>")},
+ { MSG_FI_NOUSR, SH_ERR_ERR, FIL, N_("msg=<No such user>, interface=<getpwuid>, userid=<%ld>, path=<%s>")},
+ { MSG_FI_STAT, SH_ERR_ERR, FIL, N_("interface=<%s>, msg=<%s>, userid=<%ld>, path=<%s>")},
+ { MSG_FI_OBSC, SH_ERR_ERR, FIL, N_("msg=<Weird filename>, path=<%s>")},
+ { MSG_FI_OBSC2, SH_ERR_ERR, FIL, N_("msg=<Weird filename>, path=<%s/%s>")},
+ { MSG_FI_LIST, SH_ERR_ALL, FIL, N_("msg=<%10s %2d %8s %8s %14ld %21s %s>")},
+ { MSG_FI_LLNK, SH_ERR_ALL, FIL, N_("msg=< >>> %10s %s>")},
+ { MSG_FI_MISS, SH_ERR_ERR, EVENT, N_("msg=<POLICY MISSING>, path=<%s>")},
+ { MSG_FI_MISS2, SH_ERR_ERR, EVENT, N_("msg=<POLICY MISSING>, path=<%s>, %s")},
+ { MSG_FI_ADD, SH_ERR_ERR, EVENT, N_("msg=<POLICY ADDED>, path=<%s>")},
+ { MSG_FI_ADD2, SH_ERR_ERR, EVENT, N_("msg=<POLICY ADDED>, path=<%s>, %s")},
+ { MSG_FI_CHAN, SH_ERR_ERR, EVENT, N_("msg=<POLICY %s %s>, path=<%s>, %s")},
+ { MSG_FI_NODIR, SH_ERR_ERR, EVENT, N_("msg=<POLICY NODIRECTORY>, path=<%s>")},
+ { MSG_FI_DBEX, SH_ERR_WARN, FIL, N_("msg=<Signature database exists>, path=<%s>")},
+#endif
+
+ { MSG_TCP_NETRP, SH_ERR_ERR, TCP, N_("msg=<Connection error: %s>, port=<%ld>, subroutine=<%s>")},
+
+#ifndef SH_STANDALONE
+#ifdef INET_SYSLOG
+ { MSG_INET_SYSLOG, SH_ERR_INET, TCP, N_("ip=<%s> facility=<%s> priority=<%s> syslog_msg=<%s>")},
+ { MSG_ERR_SYSLOG, SH_ERR_ERR, TCP, N_("msg=<syslog socket: %s>, ip=<%s>")},
+#endif
+ { MSG_TCP_MISMATCH,SH_ERR_ERR, TCP, N_("msg=<Protocol mismatch>")},
+ { MSG_TCP_MISENC, SH_ERR_ERR, TCP, N_("msg=<Encryption mismatch in %s: server: %s client: %s>")},
+ { MSG_TCP_NONAME, SH_ERR_ERR, TCP, N_("msg=<No server name known>")},
+ { MSG_TCP_UNEXP, SH_ERR_ERR, TCP, N_("msg=<Unexpected reply>")},
+ { MSG_TCP_EFIL, SH_ERR_ERR, TCP, N_("msg=<Could not open temporary file>")},
+ { MSG_TCP_NOCONF, SH_ERR_ERR, TCP, N_("msg=<Message delivery not confirmed>")},
+ { MSG_TCP_NOAUTH, SH_ERR_ERR, TCP, N_("msg=<Session key negotiation failed>")},
+ { MSG_TCP_CONF, SH_ERR_ALL, TCP, N_("msg=<Message delivery confirmed>")},
+ { MSG_TCP_AUTH, SH_ERR_INFO, TCP, N_("msg=<Session key negotiated>")},
+ { MSG_TCP_FOK, SH_ERR_INFO, TCP, N_("msg=<File download completed>")},
+ { MSG_TCP_FBAD, SH_ERR_ERR, TCP, N_("msg=<File download failed>")},
+ { MSG_TCP_ECONN, SH_ERR_ERR, TCP, N_("msg=<Connection error: %s>")},
+ { MSG_TCP_EZERO, SH_ERR_ERR, TCP, N_("msg=<Illegal zero reply>")},
+ { MSG_TCP_EBGN, SH_ERR_ERR, TCP, N_("msg=<Error in big integer library>")},
+
+ { MSG_TCP_CREG, SH_ERR_ALL, TCP, N_("msg=<Registered %s, salt %s, verifier %s>")},
+ { MSG_TCP_FAUTH, SH_ERR_INFO, TCP, N_("msg=<Force authentication>, client=<%s>")},
+
+ { MSG_TCP_RESCLT, SH_ERR_SEVERE, TCP, N_("msg=<Cannot resolve client name> host=<%s>")},
+ { MSG_TCP_RESPEER, SH_ERR_SEVERE, TCP, N_("msg=<Cannot resolve socket peer IP for client> host=<%s> peer=<%s>")},
+ { MSG_TCP_LOOKERS, SH_ERR_SEVERE, TCP, N_("msg=<Reverse lookup of socket peer failed> host=<%s> peer=<%s> obj=<%s>")},
+ { MSG_TCP_LOOKUP, SH_ERR_SEVERE, TCP, N_("msg=<No socket peer alias matches client name> host=<%s> peer=<%s>")},
+
+ { MSG_TCP_TIMOUT, SH_ERR_SEVERE, TCP, N_("msg=<Connection timeout>, client=<%s>")},
+ { MSG_TCP_TIMEXC, SH_ERR_SEVERE, TCP, N_("msg=<Time limit exceeded>, client=<%s>")},
+ { MSG_TCP_NOCLT, SH_ERR_SEVERE, TCP, N_("msg=<Hostname is NULL>")},
+ { MSG_TCP_BADCONN, SH_ERR_SEVERE, TCP, N_("msg=<Invalid connection attempt: %s>, client=<%s>")},
+ { MSG_TCP_FFILE , SH_ERR_SEVERE, TCP, N_("msg=<Unknown file request>, client=<%s>, path=<%s>")},
+ { MSG_TCP_NFILE , SH_ERR_SEVERE, TCP, N_("msg=<Requested file not found>, client=<%s>, path=<%s>")},
+ { MSG_TCP_FINV , SH_ERR_SEVERE, TCP, N_("msg=<Invalid request (%d) in pass %d>, client=<%s>, request=<%c%03o%c%03o%c%03o%c%03o>")},
+ { MSG_TCP_OKFILE, SH_ERR_INFO, TCP, N_("msg=<File transfer completed>, client=<%s>")},
+ { MSG_TCP_OKMSG, SH_ERR_ALL, TCP, N_("msg=<Message transfer completed>, client=<%s>")},
+ { MSG_TCP_MSG, SH_ERR_INET, TCP, N_("client=<%s>, msg=<%s>")},
+ { MSG_TCP_NEW, SH_ERR_NOTICE, TCP, N_("msg=<NEW CLIENT>, client=<%s>")},
+ { MSG_TCP_ILL, SH_ERR_SEVERE, TCP, N_("msg=<Restart without prior exit>, client=<%s>")},
+ { MSG_TCP_SYNC, SH_ERR_SEVERE, TCP, N_("msg=<Out of sync>, client=<%s>")},
+ { MSG_TCP_RESET, SH_ERR_NOTICE, TCP, N_("msg=<Connection reset by peer>, client=<%s>")},
+ { MSG_TCP_CNEW, SH_ERR_INFO, TCP, N_("msg=<New connection>, socket_id=<%d>")},
+ { MSG_E_HTML, SH_ERR_ERR, ERR, N_("msg=<Error writing HTML status>")},
+#endif
+
+
+ { MSG_E_AUTH, SH_ERR_FATAL, PANIC, N_("msg=<PANIC - File modified>, path=<%s>")},
+ { MSG_ACCESS, SH_ERR_FATAL, PANIC, N_("msg=<PANIC - Access violation>, userid=<%ld>, path=<%s>")},
+ { MSG_TRUST, SH_ERR_FATAL, PANIC, N_("msg=<PANIC - Untrusted path>, userid=<%ld>, path=<%s>")},
+ { MSG_NOACCESS, SH_ERR_FATAL, PANIC, N_("msg=<PANIC - File not accessible>, userid=<%ld>, path=<%s>")},
+ { MSG_P_NODATA, SH_ERR_FATAL, PANIC, N_("msg=<PANIC - No data in file>, path=<%s>")},
+
+
+#ifndef MEM_DEBUG
+ { MSG_E_MNULL, SH_ERR_ERR, ERR, N_("msg=<Dereferenced NULL pointer>")},
+ { MSG_E_MMEM, SH_ERR_ERR, ERR, N_("msg=<Out of memory>")},
+#else
+ { MSG_MSTAMP, SH_ERR_STAMP, STAMP, N_("msg=<Memory used: max.=%lu, current=%lu>")},
+ { MSG_MSTAMP2, SH_ERR_STAMP, STAMP, N_("msg=<Blocks: %d allocated, %d freed, %d maximum>")},
+ { MSG_E_MNULL, SH_ERR_ERR, ERR, N_("msg=<Dereferenced NULL pointer>, source_file=<%s>, source_line=<%d>")},
+ { MSG_E_MMEM, SH_ERR_ERR, ERR, N_("msg=<Out of memory>, source_file=<%s>, source_line=<%d>")},
+ { MSG_E_MREC, SH_ERR_ERR, ERR, N_("msg=<Free() on unrecorded block>, source_file=<%s>, source_line=<%d>")},
+ { MSG_E_MOVER, SH_ERR_ERR, ERR, N_("msg=<Memory overrun on block allocated in %s, line %d>, source_file=<%s>, source_line=<%d>")},
+ { MSG_E_MUNDER, SH_ERR_ERR, ERR, N_("msg=<Memory underrun on block allocated in %s, line %d>, source_file=<%s>, source_line=<%d>")},
+ { MSG_E_NOTFREE, SH_ERR_ERR, ERR, N_("msg=<Not deallocated: size %14ld>, source_file=<%19s>, source_line=<%d>")},
+#endif
+
+ { MSG_E_TRUST, SH_ERR_ERR, ERR, N_("msg=<Untrusted path>, userid=<%ld>, path=<%s>")},
+ { MSG_E_HASH, SH_ERR_ERR, ERR, N_("msg=<Incorrect checksum>, path=<%s>")},
+ { MSG_E_ACCESS, SH_ERR_ERR, ERR, N_("msg=<File not accessible>, userid=<%ld>, path=<%s>")},
+ { MSG_E_READ, SH_ERR_ERR, ERR, N_("msg=<Not accessible or not a regular file (%s / %s)>, path=<%s>")},
+ { MSG_E_NOTREG, SH_ERR_ERR, ERR, N_("msg=<Not a regular file>, path=<%s>")},
+ { MSG_E_TIMEOUT, SH_ERR_ERR, ERR, N_("msg=<Timeout (%d sec) while checksumming file>, path=<%s>")},
+ { MSG_NODEV, SH_ERR_ERR, ERR, N_("msg=<Device not available or timeout during read attempt>, userid=<%ld>, path=<%s>")},
+ { MSG_LOCKED, SH_ERR_ERR, ERR, N_("msg=<File lock error>, userid=<%ld>, path=<%s>, obj=<%s>")},
+ { MSG_PIDFILE, SH_ERR_ERR, ERR, N_("msg=<Could not write PID file>, userid=<%ld>, path=<%s>")},
+ { MSG_NOEXEC, SH_ERR_ERR, ERR, N_("msg=<Could not execute file>, userid=<%ld>, path=<%s>")},
+
+ { MSG_ES_ENT, SH_ERR_ERR, ERR, N_("msg=<No entropy collected>, subroutine=<%s>")},
+ { MSG_ES_KEY1, SH_ERR_ERR, ERR, N_("msg=<Insecure key generation>, subroutine=<%s>")},
+ { MSG_ES_KEY2, SH_ERR_ERR, ERR, N_("msg=<Error copying key>, subroutine=<%s>")},
+ { MSG_E_GPG, SH_ERR_ERR, ERR, N_("msg=<Compiled-in gpg checksum does not match: need %s got %s>")},
+ { MSG_E_GPG_FP, SH_ERR_ERR, ERR, N_("msg=<Compiled-in fingerprint modified: one %s two %s>")},
+ { MSG_E_GPG_CHK, SH_ERR_ERR, ERR, N_("msg=<Compiled-in checksum modified: one %s two %s>")},
+ { MSG_E_SUBGEN, SH_ERR_ERR, ERR, N_("msg=<%s>, subroutine=<%s>")},
+ { MSG_E_SUBGPATH, SH_ERR_ERR, ERR, N_("msg=<%s>, subroutine=<%s>, path=<%s>")},
+ { MSG_E_UNLNK, SH_ERR_ERR, FIL, N_("msg=<%s>, interface=<unlink>, path=<%s>")},
+ { MSG_E_REGEX, SH_ERR_ERR, ERR, N_("msg=<%s>, interface=<regcomp>, regexp=<%s>")},
+ { MSG_E_OPENDIR, SH_ERR_ERR, FIL, N_("msg=<%s>, interface=<opendir>, path=<%s>")},
+ { MSG_E_TRUST1, SH_ERR_ERR, ERR, N_("msg=<%s>, subroutine=<trustfile>, path=<%s>")},
+ { MSG_E_TRUST2, SH_ERR_ERR, ERR, N_("msg=<%s>, subroutine=<trustfile>, path=<%s>, obj=<%s>")},
+ { MSG_E_PWNULL, SH_ERR_ERR, ERR, N_("msg=<Empty password file entry: %s>, subroutine=<%s>, userid=<%ld>, obj=<%s>")},
+ { MSG_E_PWLONG, SH_ERR_ERR, ERR, N_("msg=<Password file entry too long>, subroutine=<%s>, userid=<%ld>, obj=<%s>")},
+ { MSG_E_GRNULL, SH_ERR_ERR, ERR, N_("msg=<Empty groups file entry: %s>, subroutine=<%s>, group=<%ld>, obj=<%s>")},
+
+ { MSG_E_NET, SH_ERR_ERR, ENET, N_("msg=<%s>, subroutine=<%s>, service=<%s>, host=<%s>")},
+ { MSG_E_NETST, SH_ERR_ERR, ENET, N_("msg=<Invalid connection state>, expect=<%4s>, received=<%4s>")},
+ { MSG_E_NETST1, SH_ERR_ERR, ENET, N_("msg=<Invalid connection state>, expect=<%4s>, received=<%4s>, host=<%s>")},
+ { MSG_E_NLOST, SH_ERR_ERR, ENET, N_("msg=<Connection failure>, service=<%s>, obj=<%s>")},
+ { MSG_E_NEST, SH_ERR_ERR, ENET, N_("msg=<Connection reestablished>, service=<%s>, obj=<%s>")},
+
+ { MSG_EINVALHEAD, SH_ERR_WARN, EINPUT,N_("msg=<Unrecognized section heading in line %ld of configuration file>")},
+ { MSG_EINVALCONF, SH_ERR_WARN, EINPUT,N_("msg=<Invalid line %ld in configuration file: incorrect format, unrecognized option, or missing section header>")},
+ { MSG_EINVALS, SH_ERR_WARN, EINPUT,N_("msg=<Invalid input>, option=<%s>, obj=<%s>")},
+ { MSG_EINVALL, SH_ERR_WARN, EINPUT,N_("msg=<Invalid input>, option=<%s>, obj=<%ld>")},
+ { MSG_EINVALD, SH_ERR_WARN, EINPUT,N_("msg=<Configuration file: Unmatched @end>, option=<%s>, obj=<%ld>")},
+ { MSG_EINVALDD, SH_ERR_WARN, EINPUT,N_("msg=<Configuration file: Missing @end>, option=<%s>, obj=<%ld>")},
+
+ { MSG_SRV_FAIL, SH_ERR_ERR, ERR, N_("msg=<Service failure>, service=<%s>, obj=<%s>")},
+ { MSG_QUEUE_FULL, SH_ERR_ERR, ERR, N_("msg=<Queue full, messages may get lost> service=<%s>")},
+
+ { MSG_AUD_OPEN, SH_ERR_NOTICE, AUD, N_("interface=<open>, pathname=<%s>, oflag=<%ld>, mode=<%ld>, return_id=<%ld>")},
+ { MSG_AUD_DUP, SH_ERR_NOTICE, AUD, N_("interface=<dup>, file_id=<%ld>, return_id=<%ld>")},
+ { MSG_AUD_PIPE, SH_ERR_NOTICE, AUD, N_("interface=<pipe>, rd_file_id=<%ld>, wr_file_id=<%ld>")},
+ { MSG_AUD_FORK, SH_ERR_NOTICE, AUD, N_("interface=<fork>, return_id=<%ld>")},
+ { MSG_AUD_EXIT, SH_ERR_NOTICE, AUD, N_("interface=<exit>, exit_code=<%ld>")},
+ { MSG_AUD_SETUID, SH_ERR_NOTICE, AUD, N_("interface=<setuid>, uid=<%ld>")},
+ { MSG_AUD_SETGID, SH_ERR_NOTICE, AUD, N_("interface=<setgid>, gid=<%ld>")},
+ { MSG_AUD_UTIME, SH_ERR_NOTICE, AUD, N_("interface=<utime>, pathname=<%s>, atime=<%ld>, mtime=<%ld>")},
+ { MSG_AUD_EXEC, SH_ERR_NOTICE, AUD, N_("interface=<exec>, pathname=<%s>, uid=<%ld>, gid=<%ld>")},
+ { MSG_AUD_CHDIR, SH_ERR_NOTICE, AUD, N_("interface=<chdir>, pathname=<%s>")},
+ { MSG_AUD_UNLINK, SH_ERR_NOTICE, AUD, N_("interface=<unlink>, pathname=<%s>")},
+ { MSG_AUD_KILL, SH_ERR_NOTICE, AUD, N_("interface=<kill>, pid=<%ld>, sig=<%ld>")},
+
+ { MSG_ERR_OPEN, SH_ERR_ALL, ERR, N_("interface=<open>, msg=<%s>, path=<%s>, oflag=<%ld>, mode=<%ld>, return_id=<%ld>")},
+ { MSG_ERR_DUP, SH_ERR_ALL, ERR, N_("interface=<dup>, msg=<%s>, file_id=<%ld>, return_id=<%ld>")},
+ { MSG_ERR_PIPE, SH_ERR_ALL, ERR, N_("interface=<pipe>, msg=<%s>, rd_file_id=<%ld>, wr_file_id=<%ld>")},
+ { MSG_ERR_FORK, SH_ERR_ALL, ERR, N_("interface=<fork>, msg=<%s>, return_id=<%ld>")},
+ { MSG_ERR_SETUID, SH_ERR_ALL, ERR, N_("interface=<setuid>, msg=<%s>, uid=<%ld>")},
+ { MSG_ERR_SETGID, SH_ERR_ALL, ERR, N_("interface=<setgid>, msg=<%s>, gid=<%ld>")},
+ { MSG_ERR_UTIME, SH_ERR_ALL, ERR, N_("interface=<utime>, msg=<%s>, path=<%s>, atime=<%ld>, mtime=<%ld>")},
+ { MSG_ERR_EXEC, SH_ERR_ALL, ERR, N_("interface=<exec>, msg=<%s>, path=<%s>, uid=<%ld>, gid=<%ld>")},
+ { MSG_ERR_CHDIR, SH_ERR_ALL, ERR, N_("interface=<chdir>, msg=<%s>, path=<%s>")},
+ { MSG_ERR_UNLINK, SH_ERR_ALL, ERR, N_("interface=<unlink>, msg=<%s>, path=<%s>")},
+ { MSG_ERR_KILL, SH_ERR_ALL, ERR, N_("interface=<kill>, msg=<%s>, pid=<%ld>, sig=<%ld>")},
+
+ { MSG_ERR_SIGACT, SH_ERR_ALL, ERR, N_("interface=<sigaction>, msg=<%s>, sig=<%ld>")},
+ { MSG_ERR_CONNECT, SH_ERR_ALL, ERR, N_("interface=<connect>, msg=<%s>, socket_id=<%ld>, port=<%ld>, host=<%s>")},
+ { MSG_ERR_ACCEPT, SH_ERR_ALL, ERR, N_("interface=<accept>, msg=<%s>, socket_id=<%ld>")},
+ { MSG_ERR_LSTAT, SH_ERR_ALL, ERR, N_("interface=<lstat>, msg=<%s>, path=<%s>")},
+ { MSG_ERR_STAT, SH_ERR_ALL, ERR, N_("interface=<stat>, msg=<%s>, path=<%s>")},
+ { MSG_ERR_FSTAT, SH_ERR_ALL, ERR, N_("interface=<fstat>, msg=<%s>, file_id=<%ld>")},
+ { MSG_ERR_FCNTL, SH_ERR_ALL, ERR, N_("interface=<fcntl>, msg=<%s>, file_id=<%ld>, cmd=<%ld>, arg=<%ld>")},
+
+ { 0, 0, 0, NULL}
+};
+
+/* #ifdef (SH_USE_XML) */
+#endif
+
+
+
+
+
diff --git a/src/sh_checksum.c b/src/sh_checksum.c
new file mode 100644
index 0000000..0587edc
--- /dev/null
+++ b/src/sh_checksum.c
@@ -0,0 +1,638 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2013 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+#include "samhain.h"
+#include "sh_checksum.h"
+#include <string.h>
+
+#undef FIL__
+#define FIL__ _("sh_checksum.c")
+
+/*
+ * sha2.c
+ *
+ * Version 1.0.0beta1
+ *
+ * Written by Aaron D. Gifford <me@aarongifford.com>
+ *
+ * Copyright 2000 Aaron D. Gifford. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* Modified for use in samhain by R. Wichmann */
+
+#if WORDS_BIGENDIAN
+#define SHA2_BIG_ENDIAN 4321
+#define SHA2_BYTE_ORDER SHA2_BIG_ENDIAN
+#else
+#define SHA2_LITTLE_ENDIAN 1234
+#define SHA2_BYTE_ORDER SHA2_LITTLE_ENDIAN
+#endif
+
+#if SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN
+#define REVERSE32(w,x) { \
+ sha2_word32 tmp = (w); \
+ tmp = (tmp >> 16) | (tmp << 16); \
+ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
+}
+#define REVERSE64(w,x) { \
+ sha2_word64 tmp = (w); \
+ tmp = (tmp >> 32) | (tmp << 32); \
+ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
+ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
+ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
+ ((tmp & 0x0000ffff0000ffffULL) << 16); \
+}
+#endif
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) { \
+ (w)[0] += (sha2_word64)(n); \
+ if ((w)[0] < (n)) { \
+ (w)[1]++; \
+ } \
+}
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ * NOTE: The naming of R and S appears backwards here (R is a SHIFT and
+ * S is a ROTATION) because the SHA-256/384/512 description document
+ * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ * same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x) ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
+#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
+
+/*** INTERNAL FUNCTION PROTOTYPES *************************************/
+/* NOTE: These should not be accessed directly from outside this
+ * library -- they are intended for private internal visibility/use
+ * only.
+ */
+void SHA256_Transform(SHA256_CTX*, const sha2_word32*);
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-256: */
+static const sha2_word32 K256[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-256: */
+static const sha2_word32 sha256_initial_hash_value[8] = {
+ 0x6a09e667UL,
+ 0xbb67ae85UL,
+ 0x3c6ef372UL,
+ 0xa54ff53aUL,
+ 0x510e527fUL,
+ 0x9b05688cUL,
+ 0x1f83d9abUL,
+ 0x5be0cd19UL
+};
+
+/*
+ * Constant used by SHA256/384/512_End() functions for converting the
+ * digest to a readable hexadecimal character string:
+ */
+static const char *sha2_hex_digits = "0123456789abcdef";
+
+/*** SHA-256: *********************************************************/
+void SHA256_Init(SHA256_CTX* context) {
+ if (context == (SHA256_CTX*)0) {
+ return;
+ }
+ memcpy(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH);
+ /* bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); */
+ memset(context->buffer, 0, SHA256_BLOCK_LENGTH);
+ /* bzero(context->buffer, SHA256_BLOCK_LENGTH); */
+
+ context->bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#if SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ REVERSE32(*data++, W256[j]); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + W256[j]; \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#else /* SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \
+ K256[j] + (W256[j] = *data++); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+#endif /* SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN */
+
+#define ROUND256(a,b,c,d,e,f,g,h) \
+ s0 = W256[(j+1)&0x0f]; \
+ s0 = sigma0_256(s0); \
+ s1 = W256[(j+14)&0x0f]; \
+ s1 = sigma1_256(s1); \
+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \
+ (d) += T1; \
+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \
+ j++
+
+void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+ sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word32 T1, *W256;
+ int j;
+
+ W256 = (sha2_word32*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+ /* Rounds 0 to 15 (unrolled): */
+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+ } while (j < 16);
+
+ /* Now for the remaining rounds to 64: */
+ do {
+ ROUND256(a,b,c,d,e,f,g,h);
+ ROUND256(h,a,b,c,d,e,f,g);
+ ROUND256(g,h,a,b,c,d,e,f);
+ ROUND256(f,g,h,a,b,c,d,e);
+ ROUND256(e,f,g,h,a,b,c,d);
+ ROUND256(d,e,f,g,h,a,b,c);
+ ROUND256(c,d,e,f,g,h,a,b);
+ ROUND256(b,c,d,e,f,g,h,a);
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) {
+ sha2_word32 a, b, c, d, e, f, g, h, s0, s1;
+ sha2_word32 T1, T2, *W256;
+ int j;
+
+ W256 = (sha2_word32*)context->buffer;
+
+ /* Initialize registers with the prev. intermediate value */
+ a = context->state[0];
+ b = context->state[1];
+ c = context->state[2];
+ d = context->state[3];
+ e = context->state[4];
+ f = context->state[5];
+ g = context->state[6];
+ h = context->state[7];
+
+ j = 0;
+ do {
+#if SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN
+ /* Copy data while converting to host byte order */
+ REVERSE32(*data++,W256[j]);
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+#else /* SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN */
+ /* Apply the SHA-256 compression function to update a..h with copy */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++);
+#endif /* SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN */
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 16);
+
+ do {
+ /* Part of the message block expansion: */
+ s0 = W256[(j+1)&0x0f];
+ s0 = sigma0_256(s0);
+ s1 = W256[(j+14)&0x0f];
+ s1 = sigma1_256(s1);
+
+ /* Apply the SHA-256 compression function to update a..h */
+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] +
+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+ T2 = Sigma0_256(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+
+ j++;
+ } while (j < 64);
+
+ /* Compute the current intermediate hash value */
+ context->state[0] += a;
+ context->state[1] += b;
+ context->state[2] += c;
+ context->state[3] += d;
+ context->state[4] += e;
+ context->state[5] += f;
+ context->state[6] += g;
+ context->state[7] += h;
+
+ /* Clean up */
+ a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) {
+ unsigned int freespace, usedspace;
+
+ if (len == 0) {
+ /* Calling with no data is valid - we do nothing */
+ return;
+ }
+
+ usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+
+ if (usedspace > 0) {
+ /* Calculate how much free space is available in the buffer */
+ freespace = SHA256_BLOCK_LENGTH - usedspace;
+
+ if (len >= freespace) {
+ /* Fill the buffer completely and process it */
+ memcpy(&context->buffer[usedspace], data, freespace);
+ /* bcopy(data, &context->buffer[usedspace], freespace); */
+ context->bitcount += freespace << 3;
+ len -= freespace;
+ data += freespace;
+ SHA256_Transform(context, (sha2_word32*)context->buffer);
+ } else {
+ /* The buffer is not yet full */
+ memcpy(&context->buffer[usedspace], data, len);
+ /* bcopy(data, &context->buffer[usedspace], len); */
+ context->bitcount += len << 3;
+
+ /* Clean up: */
+ usedspace = freespace = 0;
+ return;
+ }
+ }
+ while (len >= SHA256_BLOCK_LENGTH) {
+ /* Process as many complete blocks as we can */
+ SHA256_Transform(context, (const sha2_word32*)data);
+ context->bitcount += SHA256_BLOCK_LENGTH << 3;
+ len -= SHA256_BLOCK_LENGTH;
+ data += SHA256_BLOCK_LENGTH;
+ }
+ if (len > 0) {
+ /* There's left-overs, so save 'em */
+ memcpy(context->buffer, data, len);
+ /* bcopy(data, context->buffer, len); */
+ context->bitcount += len << 3;
+ }
+ /* Clean up: */
+ usedspace = freespace = 0;
+}
+
+void SHA256_Final(sha2_byte digest[], SHA256_CTX* context)
+{
+ sha2_word32 *d = (sha2_word32*)digest;
+ unsigned int usedspace;
+ union {
+ sha2_word64 bitcount;
+ sha2_byte buffer[sizeof(sha2_word64)];
+ } sha2_union;
+
+ /* If no digest buffer is passed, we don't bother doing this: */
+ if (digest != (sha2_byte*)0) {
+
+ usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+
+#if SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN
+ /* Convert FROM host byte order */
+ REVERSE64(context->bitcount,context->bitcount);
+#endif
+ if (usedspace > 0) {
+ /* Begin padding with a 1 bit: */
+ context->buffer[usedspace++] = 0x80;
+
+ if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
+ /* Set-up for the last transform: */
+ memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace);
+ } else {
+ if (usedspace < SHA256_BLOCK_LENGTH) {
+ memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace);
+ }
+ /* Do second-to-last transform: */
+ SHA256_Transform(context, (sha2_word32*)context->buffer);
+
+ /* And set-up for the last transform: */
+ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
+ }
+ } else {
+ /* Set-up for the last transform: */
+ memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
+
+ /* Begin padding with a 1 bit: */
+ *context->buffer = 0x80;
+ }
+
+ /* Set the bit count (with fix for gcc type-punning warning): */
+ sha2_union.bitcount = context->bitcount;
+ memcpy (&context->buffer[SHA256_SHORT_BLOCK_LENGTH], sha2_union.buffer, sizeof(sha2_word64));
+ /* *(sha2_word64*) &context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; */
+
+ /* Final transform: */
+ SHA256_Transform(context, (sha2_word32*)context->buffer);
+
+#if SHA2_BYTE_ORDER == SHA2_LITTLE_ENDIAN
+ {
+ /* Convert TO host byte order */
+ int j;
+ for (j = 0; j < 8; j++) {
+ REVERSE32(context->state[j],context->state[j]);
+ *d++ = context->state[j];
+ }
+ }
+#else
+ memset(d, context->state, SHA256_DIGEST_LENGTH);
+ /* bcopy(context->state, d, SHA256_DIGEST_LENGTH); */
+#endif
+ }
+
+ /* Clean up state data: */
+ memset(context, 0, sizeof(SHA256_CTX));
+ usedspace = 0;
+}
+
+#include "sh_utils.h"
+
+/* If buffer is of length KEYBUF_SIZE, the digest will fit */
+char *SHA256_End(SHA256_CTX* context, char buffer[])
+{
+ sha2_byte digest[SHA256_DIGEST_LENGTH];
+
+ if (buffer != (char*)0) {
+ SHA256_Final(digest, context);
+ sh_util_base64_enc ((unsigned char *)buffer, digest, SHA256_DIGEST_LENGTH);
+ } else {
+ memset(context, 0, sizeof(SHA256_CTX));
+ }
+ memset(digest, 0, SHA256_DIGEST_LENGTH);
+ return buffer;
+}
+
+char* SHA256_Data(const sha2_byte* data, size_t len, char digest[KEYBUF_SIZE])
+{
+ SHA256_CTX context;
+
+ SHA256_Init(&context);
+ SHA256_Update(&context, data, len);
+ return SHA256_End(&context, digest);
+}
+
+char* SHA256_Base2Hex(char * b64digest, char * hexdigest)
+{
+ int i;
+ sha2_byte data[512];
+ sha2_byte *d;
+ size_t len;
+ char * buffer;
+
+ len = strlen(b64digest);
+ sh_util_base64_dec ((unsigned char*) data, (unsigned char *)b64digest, len);
+ d = data;
+
+ buffer = hexdigest;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+
+ return hexdigest;
+}
+
+char * SHA256_ReplaceBaseByHex(const char * str, char * before, char after)
+{
+ char keybuf[KEYBUF_SIZE];
+ char * s = strstr(str, before);
+
+ if (s)
+ {
+ char * p;
+
+ s += strlen(before);
+ memcpy(keybuf, s, sizeof(keybuf));
+ keybuf[sizeof(keybuf)-1] = '\0';
+ p = strchr(keybuf, after);
+
+ if (p)
+ {
+ char hexbuf[SHA256_DIGEST_STRING_LENGTH];
+ char * ret = SH_ALLOC(strlen(str) + 1 + sizeof(keybuf));
+ char * r = ret;
+
+ *p = '\0';
+ SHA256_Base2Hex(keybuf, hexbuf);
+
+ memcpy(ret, str, (s - str));
+ r += (int)(s - str); *r = '\0';
+ strcpy(r, hexbuf); /* flawfinder: ignore */
+ r += strlen(hexbuf);
+ p = strchr(s, after);
+ strcpy(r, p); /* flawfinder: ignore */
+
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+
+#ifdef SH_CUTEST
+#include <stdlib.h>
+#include "CuTest.h"
+
+void Test_sha256 (CuTest *tc) {
+
+ char hexdigest[SHA256_DIGEST_STRING_LENGTH];
+ char b64digest[KEYBUF_SIZE];
+ char * b64;
+ char * buffer;
+ size_t len;
+ sha2_byte data[512];
+ sha2_byte *d;
+ int i;
+
+ data[0] = '\0'; len = 0;
+ b64 = SHA256_Data(data, len, b64digest);
+ CuAssertPtrNotNull(tc, b64);
+
+ len = strlen((char*)b64);
+ sh_util_base64_dec (data, (unsigned char*)b64, len);
+ d = data;
+ buffer = hexdigest;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ CuAssertStrEquals(tc, hexdigest, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+
+ memset(hexdigest, 0, sizeof(hexdigest));
+ buffer = SHA256_Base2Hex(b64digest, hexdigest);
+ CuAssertPtrNotNull(tc, buffer);
+ CuAssertStrEquals(tc, hexdigest, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+ CuAssertStrEquals(tc, buffer, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
+
+ strcpy((char*)data, "The quick brown fox jumps over the lazy dog"); len = strlen((char*)data);
+ b64 = SHA256_Data(data, len, b64digest);
+ CuAssertPtrNotNull(tc, b64);
+
+ len = strlen((char*)b64);
+ sh_util_base64_dec (data, (unsigned char*)b64, len);
+ d = data;
+ buffer = hexdigest;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ CuAssertStrEquals(tc, hexdigest, "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592");
+
+ strcpy((char*)data, "The quick brown fox jumps over the lazy dog."); len = strlen((char*)data);
+ b64 = SHA256_Data(data, len, b64digest);
+ CuAssertPtrNotNull(tc, b64);
+
+ len = strlen((char*)b64);
+ sh_util_base64_dec (data, (unsigned char*)b64, len);
+ d = data;
+ buffer = hexdigest;
+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) {
+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4];
+ *buffer++ = sha2_hex_digits[*d & 0x0f];
+ d++;
+ }
+ *buffer = (char)0;
+ CuAssertStrEquals(tc, hexdigest, "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c");
+
+}
+
+#endif
diff --git a/src/sh_database.c b/src/sh_database.c
new file mode 100644
index 0000000..fdeed45
--- /dev/null
+++ b/src/sh_database.c
@@ -0,0 +1,1853 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2001 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#ifdef WITH_DATABASE
+
+/* define this if you want to debug the Oracle database support */
+/* #define DB_DEBUG */
+
+#define SH_REAL_SET
+
+#include "samhain.h"
+
+#include "sh_cat.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+
+#undef FIL__
+#define FIL__ _("sh_database.c")
+
+typedef struct my_attr_
+{
+ char * attr;
+ char * attr_o;
+ int inHash;
+ int val;
+ int size;
+ int alen;
+ size_t off;
+} my_attr;
+
+typedef struct dbins_ {
+ struct dbins_ * next;
+ char host[64];
+ char time[20];
+ char msg[1024];
+ char sev[8];
+ char path[MAX_PATH_STORE+1];
+ char user[9];
+ char group[9];
+ char program[8];
+ char subroutine[16];
+ char status[12];
+ char hash[50];
+ char path_data[1024];
+ char hash_data[50];
+ char key_uid[64];
+ char key_uid_data[64];
+ char key_id[16];
+ char module[8];
+ char syscall[16];
+ char ip[SH_IP_BUF];
+ char tty[16];
+ char peer[64];
+ char fromhost[64];
+ char obj[1024];
+ char interface[64];
+ char ltime[64];
+ char dir[MAX_PATH_STORE+1];
+ char linked_path[MAX_PATH_STORE+1];
+ char service[64];
+ char facility[32];
+ char priority[32];
+ char syslog_msg[1024];
+
+ char mode_old[16];
+ char mode_new[16];
+ char attr_old[16];
+ char attr_new[16];
+ char device_old[16];
+ char device_new[16];
+ char owner_old[9];
+ char owner_new[9];
+ char group_old[9];
+ char group_new[9];
+ char ctime_old[20];
+ char ctime_new[20];
+ char atime_old[20];
+ char atime_new[20];
+ char mtime_old[20];
+ char mtime_new[20];
+ char chksum_old[50];
+ char chksum_new[50];
+ char link_old[MAX_PATH_STORE+1];
+ char link_new[MAX_PATH_STORE+1];
+ char acl_old[1024];
+ char acl_new[1024];
+
+ unsigned long ulong_data[20];
+
+ /*
+ long size_old;
+ long size_new;
+ long hardlinks_old;
+ long hardlinks_new;
+ long inode_old;
+ long inode_new;
+ */
+
+} dbins;
+
+static my_attr * attr_tab_srch = NULL;
+static int attr_tab_srch_siz = 0;
+
+static my_attr attr_tab[] = {
+ { NULL, N_("sev"), 0, 1, 8, 0, offsetof(struct dbins_, sev) },
+ { NULL, N_("tstamp"), 0, 2, 16, 0, offsetof(struct dbins_, time) },
+ { NULL, N_("remote_host"), 0, 3, 64, 0, offsetof(struct dbins_, host) },
+ { NULL, N_("msg"), 0, 4, 1024, 0, offsetof(struct dbins_, msg) },
+
+ { NULL, N_("path"), 0, 5,MAX_PATH_STORE+1, 0, offsetof(struct dbins_, path) },
+ /* username -> userid; replace (long) 'userid' - below - by 'dummy' */
+ { NULL, N_("userid"), 0, 6, 9, 0, offsetof(struct dbins_, user) },
+ { NULL, N_("group"), 0, 7, 9, 0, offsetof(struct dbins_, group) },
+ { NULL, N_("program"), 0, 8, 8, 0, offsetof(struct dbins_, program) },
+ { NULL, N_("subroutine"), 0, 9, 16, 0, offsetof(struct dbins_, subroutine)},
+ { NULL, N_("status"), 0, 10, 12, 0, offsetof(struct dbins_, status) },
+ { NULL, N_("hash"), 0, 11, 50, 0, offsetof(struct dbins_, hash) },
+ { NULL, N_("path_data"), 0, 12, 1024, 0, offsetof(struct dbins_, path_data) },
+ { NULL, N_("hash_data"), 0, 13, 50, 0, offsetof(struct dbins_, hash_data) },
+ { NULL, N_("key_uid"), 0, 14, 64, 0, offsetof(struct dbins_, key_uid) },
+ { NULL, N_("key_uid_data"),0, 15, 64, 0, offsetof(struct dbins_, key_uid_data)},
+ { NULL, N_("key_id"), 0, 16, 16, 0, offsetof(struct dbins_, key_id) },
+ { NULL, N_("module"), 0, 17, 8, 0, offsetof(struct dbins_, module) },
+ { NULL, N_("syscall"), 0, 19, 16, 0, offsetof(struct dbins_, syscall) },
+ { NULL, N_("ip"), 0, 20,SH_IP_BUF, 0, offsetof(struct dbins_, ip) },
+ { NULL, N_("tty"), 0, 21, 16, 0, offsetof(struct dbins_, tty) },
+ { NULL, N_("peer"), 0, 22, 64, 0, offsetof(struct dbins_, peer) },
+ { NULL, N_("obj"), 0, 23, 1024, 0, offsetof(struct dbins_, obj) },
+ { NULL, N_("interface"), 0, 24, 64, 0, offsetof(struct dbins_, interface)},
+ { NULL, N_("time"), 0, 25, 64, 0, offsetof(struct dbins_, ltime) },
+ { NULL, N_("dir"), 0, 26, MAX_PATH_STORE+1, 0, offsetof(struct dbins_, dir) },
+ { NULL, N_("linked_path"), 0, 27, MAX_PATH_STORE+1, 0, offsetof(struct dbins_, linked_path)},
+ { NULL, N_("service"), 0, 29, 64, 0, offsetof(struct dbins_, service)},
+ { NULL, N_("facility"), 0, 30, 32, 0, offsetof(struct dbins_, facility) },
+ { NULL, N_("priority"), 0, 31, 32, 0, offsetof(struct dbins_, priority) },
+ { NULL, N_("syslog_msg"), 0, 32, 1024, 0, offsetof(struct dbins_, syslog_msg) },
+
+ { NULL, N_("mode_old"), 0, 33, 16, 0, offsetof(struct dbins_, mode_old) },
+ { NULL, N_("mode_new"), 0, 34, 16, 0, offsetof(struct dbins_, mode_new) },
+ { NULL, N_("device_old"), 0, 35, 16, 0, offsetof(struct dbins_, device_old)},
+ { NULL, N_("device_new"), 0, 36, 16, 0, offsetof(struct dbins_, device_new)},
+ { NULL, N_("owner_old"), 0, 37, 9, 0, offsetof(struct dbins_, owner_old)},
+ { NULL, N_("owner_new"), 0, 38, 9, 0, offsetof(struct dbins_, owner_new)},
+ { NULL, N_("group_old"), 0, 39, 9, 0, offsetof(struct dbins_, group_old)},
+ { NULL, N_("group_new"), 0, 40, 9, 0, offsetof(struct dbins_, group_new)},
+ { NULL, N_("ctime_old"), 0, 41, 20, 0, offsetof(struct dbins_, ctime_old)},
+ { NULL, N_("ctime_new"), 0, 42, 20, 0, offsetof(struct dbins_, ctime_new)},
+ { NULL, N_("atime_old"), 0, 43, 20, 0, offsetof(struct dbins_, atime_old)},
+ { NULL, N_("atime_new"), 0, 44, 20, 0, offsetof(struct dbins_, atime_new)},
+ { NULL, N_("mtime_old"), 0, 45, 20, 0, offsetof(struct dbins_, mtime_old)},
+ { NULL, N_("mtime_new"), 0, 46, 20, 0, offsetof(struct dbins_, mtime_new)},
+ { NULL, N_("chksum_old"), 0, 47, 50, 0, offsetof(struct dbins_, chksum_old)},
+ { NULL, N_("chksum_new"), 0, 48, 50, 0, offsetof(struct dbins_, chksum_new)},
+ { NULL, N_("link_old"), 0, 49, MAX_PATH_STORE+1, 0, offsetof(struct dbins_, link_old)},
+ { NULL, N_("link_new"), 0, 50, MAX_PATH_STORE+1, 0, offsetof(struct dbins_, link_new)},
+
+ /* These go into dbins.ulong_data[n - START_SEC_LONGS] */
+ { NULL, N_("size_old"), 0, 51, 0, 0, 0 },
+ { NULL, N_("size_new"), 0, 52, 0, 0, 0 },
+ { NULL, N_("hardlinks_old"),0, 53, 0, 0, 0 },
+ { NULL, N_("hardlinks_new"),0, 54, 0, 0, 0 },
+ { NULL, N_("inode_old"), 0, 55, 0, 0, 0 },
+ { NULL, N_("inode_new"), 0, 56, 0, 0, 0 },
+
+ { NULL, N_("imode_old"), 0, 57, 0, 0, 0 },
+ { NULL, N_("imode_new"), 0, 58, 0, 0, 0 },
+ { NULL, N_("iattr_old"), 0, 59, 0, 0, 0 },
+ { NULL, N_("iattr_new"), 0, 60, 0, 0, 0 },
+ { NULL, N_("idevice_old"), 0, 61, 0, 0, 0 },
+ { NULL, N_("idevice_new"), 0, 62, 0, 0, 0 },
+ { NULL, N_("iowner_old"), 0, 63, 0, 0, 0 },
+ { NULL, N_("iowner_new"), 0, 64, 0, 0, 0 },
+ { NULL, N_("igroup_old"), 0, 65, 0, 0, 0 },
+ { NULL, N_("igroup_new"), 0, 66, 0, 0, 0 },
+
+ { NULL, N_("port"), 0, 67, 0, 0, 0 },
+ { NULL, N_("return_code"), 0, 68, 0, 0, 0 },
+
+ { NULL, N_("checkflags_old"), 0, 69, 0, 0, 0 },
+ { NULL, N_("checkflags_new"), 0, 70, 0, 0, 0 },
+
+ /* END_SEC_LONGS */
+
+ { NULL, N_("host"), 0, 71, 64, 0, offsetof(struct dbins_, fromhost)},
+ { NULL, N_("attr_old"), 0, 72, 16, 0, offsetof(struct dbins_, attr_old)},
+ { NULL, N_("attr_new"), 0, 73, 16, 0, offsetof(struct dbins_, attr_new)},
+ { NULL, N_("acl_old"), 0, 74, 1024, 0, offsetof(struct dbins_, acl_old)},
+ { NULL, N_("acl_new"), 0, 75, 1024, 0, offsetof(struct dbins_, acl_new)},
+
+ { NULL, NULL, 0, 0, 0, 0, 0 }
+};
+
+#define SH_SLOT_CHECKFLAGS 69
+
+/* need special attention b/o reserved SQL words */
+#define SH_SLOT_HOST 71
+#define SH_SLOT_GROUP 7
+
+/* these go into dbins.ulong_data[n-START_SEC_LONGS */
+#define START_SEC_LONGS 51
+#define END_SEC_LONGS 70
+
+#if defined(HAVE_INT_32)
+typedef unsigned int uint32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long uint32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short uint32;
+#else
+#error No 32 byte type found !
+#endif
+
+typedef unsigned char uint8;
+
+typedef struct md5_ctx
+{
+ uint32 A;
+ uint32 B;
+ uint32 C;
+ uint32 D;
+
+ uint32 total[2];
+ uint32 buflen;
+ char buffer[128];
+} md5Param;
+
+
+typedef unsigned char sh_byte;
+
+
+extern int md5Reset(register md5Param* p);
+extern int md5Update(md5Param* p, const sh_byte* data, int size);
+extern int md5Digest(md5Param* p, uint32* data);
+
+static char db_name[64] = "";
+static char db_table[64] = "";
+static char db_host[64] = "";
+static char db_user[64] = "";
+static char db_password[64] = "";
+
+static int sh_persistent_dbconn = S_TRUE;
+
+int sh_database_use_persistent (const char * str)
+{
+ return sh_util_flagval (str, &sh_persistent_dbconn);
+}
+
+static int insert_value (char * ptr, const char * str)
+{
+ if (!ptr || !str)
+ return -1;
+ if (strlen(str) > 63)
+ return -1;
+ (void) sl_strlcpy(ptr, str, 64);
+ return 0;
+}
+
+static void init_db_entry (dbins * ptr)
+{
+ memset (ptr, (int) '\0', sizeof(dbins));
+ ptr->next = NULL;
+ return;
+}
+
+
+int sh_database_set_database (const char * str)
+{
+ return insert_value (db_name, str);
+}
+int sh_database_set_table (const char * str)
+{
+ return insert_value (db_table, str);
+}
+int sh_database_set_host (const char * str)
+{
+ return insert_value (db_host, str);
+}
+int sh_database_set_user (const char * str)
+{
+ return insert_value (db_user, str);
+}
+int sh_database_set_password (const char * str)
+{
+ return insert_value (db_password, str);
+}
+
+/******************************************************************
+ *
+ * Oracle and unixODBC stuff, only Oracle tested untested
+ *
+ * Based on the code in the snort output plugin (spo_database.c).
+ * Copyright/license statement in spo_database.c:
+ *
+ * Portions Copyright (C) 2000,2001,2002 Carnegie Mellon University
+ * Copyright (C) 2001 Jed Pickel <jed@pickel.net>
+ * Portions Copyright (C) 2001 Andrew R. Baker <andrewb@farm9.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ******************************************************************/
+#ifdef WITH_ODBC
+
+#include <sql.h>
+#include <sqlext.h>
+#include <sqltypes.h>
+
+static SQLHENV u_handle;
+static SQLHDBC u_connection;
+static SQLHSTMT u_statement;
+static SQLINTEGER u_col;
+static SQLINTEGER u_rows;
+
+void sh_database_reset()
+{
+ return;
+}
+
+static
+int sh_database_query (char * query, /*@out@*/ long * id)
+{
+ static int fatal_error = 0;
+ int result = 0;
+ char row_query[128];
+ long result_call;
+
+ SL_ENTER(_("sh_database_query"));
+
+ *id = 0;
+
+ if (fatal_error == 1)
+ {
+ SL_RETURN((-1), _("sh_database_query"));
+ }
+
+ /* Connect
+ */
+ if (db_name[0] == '\0')
+ sl_strlcpy(db_name, _("samhain"), 64);
+
+ if (db_user[0] == '\0')
+ sl_strlcpy(db_user, _("samhain"), 64);
+
+ result_call = SQLAllocEnv(&u_handle);
+ if ((result_call != SQL_SUCCESS) && (result_call != SQL_SUCCESS_WITH_INFO))
+ {
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, result_call,
+ MSG_E_SUBGEN,
+ _("Error in SQLAllocEnv when connecting to ODBC data source"),
+ _("sh_database_query"));
+ fatal_error = 1;
+ SL_RETURN((-1), _("sh_database_query"));
+ }
+ result_call = SQLAllocConnect(u_handle, &u_connection);
+ if ((result_call != SQL_SUCCESS) && (result_call != SQL_SUCCESS_WITH_INFO))
+ {
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, result_call,
+ MSG_E_SUBGEN,
+ _("Error in SQLAllocEnv when connecting to ODBC data source"),
+ _("sh_database_query"));
+ fatal_error = 1;
+ SL_RETURN((-1), _("sh_database_query"));
+ }
+ result_call = SQLConnect(u_connection, db_name, SQL_NTS,
+ db_user, SQL_NTS, db_password, SQL_NTS);
+ if ((result_call != SQL_SUCCESS) && (result_call != SQL_SUCCESS_WITH_INFO))
+ {
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, result_call,
+ MSG_E_SUBGEN,
+ _("Error in SQLAllocEnv when connecting to ODBC data source"),
+ _("sh_database_query"));
+ fatal_error = 1;
+ SL_RETURN((-1), _("sh_database_query"));
+ }
+
+ /* Insert
+ */
+ result_call = SQLAllocStmt(u_connection, &u_statement);
+ if ((result_call == SQL_SUCCESS) || (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result_call = SQLPrepare(u_statement, query, SQL_NTS);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result_call = SQLExecute(u_statement);
+ if((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result = 1;
+ }
+ }
+ }
+
+ if (result == 0)
+ {
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Error inserting into ODBC data source"),
+ _("sh_database_query"));
+ goto odbc_disconnect;
+ }
+
+ /* Select
+ */
+ result = 0;
+
+ sl_strlcpy (row_query, _("SELECT MAX(log_index) FROM "), 128);
+ sl_strlcat (row_query, db_table, 128);
+
+ result_call = SQLAllocStmt(u_connection, &u_statement);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result_call = SQLPrepare(u_statement, row_query, SQL_NTS);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result_call = SQLExecute(u_statement);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result_call = SQLRowCount(u_statement, &u_rows);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ if((u_rows) && (u_rows == 1))
+ {
+ result_call = SQLFetch(u_statement);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ result_call = SQLGetData(u_statement, 1,
+ SQL_INTEGER, &u_col,
+ sizeof(u_col), NULL);
+ if ((result_call == SQL_SUCCESS) ||
+ (result_call == SQL_SUCCESS_WITH_INFO))
+ {
+ *id = (long int) u_col;
+ result = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (result == 0)
+ {
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Error selecting MAX(log_index) from ODBC data source"),
+ _("sh_database_query"));
+ }
+
+ odbc_disconnect:
+ SQLFreeHandle(SQL_HANDLE_STMT, u_statement);
+ SQLDisconnect(u_connection);
+ SQLFreeHandle(SQL_HANDLE_DBC, u_connection);
+ SQLFreeHandle(SQL_HANDLE_ENV, u_handle);
+
+ SL_RETURN(((result == 0) ? -1 : 0), _("sh_database_query"));
+
+}
+
+/* #ifdef WITH_ODBC */
+#endif
+
+#ifdef WITH_ORACLE
+
+#include <oci.h>
+
+static OCIDefine * o_define;
+static OCIEnv * o_environment;
+static OCISvcCtx * o_servicecontext;
+static OCIError * o_error = NULL;
+static OCIStmt * o_statement;
+static OCIBind * o_bind = (OCIBind *) 0;
+static text o_errormsg[512];
+static sb4 o_errorcode;
+
+static int connected = 0;
+
+void sh_database_reset()
+{
+ if (connected == 1)
+ {
+ OCILogoff(o_servicecontext, o_error);
+ OCIHandleFree((dvoid *) o_statement, OCI_HTYPE_STMT);
+ OCIHandleFree((dvoid *) o_servicecontext, OCI_HTYPE_SVCCTX);
+ OCIHandleFree((dvoid *) o_error, OCI_HTYPE_ERROR);
+ o_error = NULL;
+ }
+ connected = 0;
+ return;
+}
+
+static char * sh_stripnl (char * str)
+{
+ size_t len = sl_strlen(str);
+ if (len > 0)
+ {
+ if (str[len-1] == '\n')
+ str[len-1] = '\0';
+ }
+ return str;
+}
+
+static
+int sh_database_query (char * query, /*@out@*/ long * id)
+{
+ static int bad_init = 0;
+ int result = 0;
+ char row_query[128];
+ int retry = 0;
+ static SH_TIMEOUT sh_timer = { 0, 3600, S_TRUE };
+
+
+ SL_ENTER(_("sh_database_query"));
+
+ *id = 0;
+
+ if (bad_init == 1) {
+ SL_RETURN(-1, _("sh_database_query"));
+ }
+ else if (connected == 1) {
+ goto oracle_connected;
+ }
+
+ /*
+ * Connect
+ */
+#define PRINT_ORACLE_ERR(func_name) \
+ do { \
+ OCIErrorGet(o_error, 1, NULL, &o_errorcode, \
+ o_errormsg, sizeof(o_errormsg), \
+ OCI_HTYPE_ERROR); \
+ sh_stripnl (o_errormsg); \
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN, \
+ o_errormsg, _("sh_database_query")); \
+ sl_snprintf(row_query, 127, \
+ _("%s: Connection to database '%s' failed"), \
+ func_name, db_name); \
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN, \
+ row_query, _("sh_database_query")); \
+ bad_init = 1; \
+ SL_RETURN(-1, _("sh_database_query")); \
+ } while (1 == 0)
+
+ oracle_doconnect:
+
+ if (!getenv("ORACLE_HOME")) /* flawfinder: ignore */
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("ORACLE_HOME environment variable not set"),
+ _("sh_database_query"));
+ }
+ if (db_name[0] == '\0')
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("database name not set, using default 'samhain'"),
+ _("sh_database_query"));
+ sl_strlcpy(db_name, _("samhain"), 64);
+ }
+ if (db_user[0] == '\0')
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("database user not set, using default 'samhain'"),
+ _("sh_database_query"));
+ sl_strlcpy(db_user, _("samhain"), 64);
+ }
+ if (db_password[0] == '\0')
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("database password not set, cannot proceed"),
+ _("sh_database_query"));
+ bad_init = 1;
+ SL_RETURN(-1, _("sh_database_query"));
+ }
+
+
+#ifdef DB_DEBUG
+ sl_snprintf(row_query, 127,
+ _("Conncting to oracle database '%s'"),
+ db_name);
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ row_query,
+ _("sh_database_query"));
+#endif
+
+ /* a) Oracle says use OCIEnvCreate instead of OCIInitialize/OCIEnvcreate
+ * b) why two times OCIEnvInit() ???
+ */
+ if (OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL))
+ PRINT_ORACLE_ERR("OCIInitialize");
+
+ if (OCIEnvInit(&o_environment, OCI_DEFAULT, 0, NULL))
+ PRINT_ORACLE_ERR("OCIEnvInit");
+
+ if (OCIEnvInit(&o_environment, OCI_DEFAULT, 0, NULL))
+ PRINT_ORACLE_ERR("OCIEnvInit (2)");
+
+ /* allocate and initialize the error handle
+ */
+ if (OCIHandleAlloc(o_environment, (dvoid **)&o_error,
+ OCI_HTYPE_ERROR, (size_t) 0, NULL))
+ PRINT_ORACLE_ERR("OCIHandleAlloc");
+
+ /* logon and allocate the service context handle
+ */
+ if (OCILogon(o_environment, o_error, &o_servicecontext,
+ (OraText*) db_user, sl_strlen(db_user),
+ (OraText*) db_password, sl_strlen(db_password),
+ (OraText*) db_name, sl_strlen(db_name)))
+ {
+
+ connected = 0;
+
+ sh_timer.flag_ok = S_FALSE;
+
+ if (S_TRUE == sh_util_timeout_check(&sh_timer))
+ {
+ OCIErrorGet(o_error, 1, NULL, &o_errorcode,
+ o_errormsg, sizeof(o_errormsg), OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("check database is listed in tnsnames.ora"),
+ _("sh_database_query"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("check tnsnames.ora readable"),
+ _("sh_database_query"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("check database accessible with sqlplus"),
+ _("sh_database_query"));
+ sl_snprintf(row_query, 127,
+ _("OCILogon: Connection to database '%s' failed"),
+ db_name);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ row_query, _("sh_database_query"));
+
+ goto err_out;
+ }
+ else
+ {
+ SL_RETURN(0, _("sh_database_query"));
+ }
+ }
+
+ if (OCIHandleAlloc(o_environment, (dvoid **)&o_statement,
+ OCI_HTYPE_STMT, 0, NULL))
+ PRINT_ORACLE_ERR("OCIHandleAlloc (2)");
+
+ /* Flag connection status
+ */
+ connected = 1;
+
+ oracle_connected:
+
+ /* Get row index
+ */
+ sl_strlcpy (row_query, _("SELECT log_log_index_seq.NEXTVAL FROM dual"), 128);
+
+#ifdef DB_DEBUG
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ row_query,
+ _("sh_database_query"));
+#endif
+
+ if (OCIStmtPrepare(o_statement, o_error,
+ (OraText*) row_query, sl_strlen(row_query),
+ OCI_NTV_SYNTAX, OCI_DEFAULT))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+
+ if (OCIStmtExecute(o_servicecontext, o_statement, o_error,
+ 0, 0, NULL, NULL, OCI_DEFAULT))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+
+ if (OCIDefineByPos (o_statement, &o_define, o_error, 1,
+ &result, sizeof(result),
+ SQLT_INT, 0, 0, 0, OCI_DEFAULT))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+ if (OCIStmtFetch (o_statement, o_error, 1, OCI_FETCH_NEXT, OCI_DEFAULT))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+
+#ifdef DB_DEBUG
+ sl_snprintf(row_query, 127, _("Returned value: %d"), result);
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ row_query,
+ _("sh_database_query"));
+#endif
+
+ *id = result;
+
+ /* do the insert
+ */
+#ifdef DB_DEBUG
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ query,
+ _("sh_database_query"));
+#endif
+
+ if (OCIStmtPrepare(o_statement, o_error,
+ (OraText*) query, sl_strlen(query),
+ OCI_NTV_SYNTAX, OCI_DEFAULT))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+
+ if (OCIBindByPos(o_statement, &o_bind, o_error, 1,
+ (dvoid *) &result, (sword) sizeof(result), SQLT_INT,
+ (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+
+ if (OCIStmtExecute(o_servicecontext,
+ o_statement, o_error, 1, 0,
+ NULL, NULL, OCI_COMMIT_ON_SUCCESS))
+ {
+ OCIErrorGet(o_error, 1, NULL,
+ &o_errorcode, o_errormsg, sizeof(o_errormsg),
+ OCI_HTYPE_ERROR);
+ sh_stripnl (o_errormsg);
+ sh_error_handle((-1), FIL__, __LINE__, (long) o_errorcode, MSG_E_SUBGEN,
+ o_errormsg,
+ _("sh_database_query"));
+ if (retry == 0 &&
+ (3114 == o_errorcode || 0 == strncmp(o_errormsg, _("ORA-03114"), 9)))
+ {
+ ++retry; sh_database_reset(); goto oracle_doconnect;
+ }
+ goto err_out;
+ }
+
+#ifdef DB_DEBUG
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("No error on insert"),
+ _("sh_database_query"));
+#endif
+
+ if (sh_persistent_dbconn == S_FALSE)
+ {
+ OCILogoff(o_servicecontext, o_error);
+ OCIHandleFree((dvoid *) o_statement, OCI_HTYPE_STMT);
+ OCIHandleFree((dvoid *) o_servicecontext, OCI_HTYPE_SVCCTX);
+ OCIHandleFree((dvoid *) o_error, OCI_HTYPE_ERROR);
+ o_error = NULL;
+ connected = 0;
+ }
+ SL_RETURN(0, _("sh_database_query"));
+
+ err_out:
+ /*
+ * Error
+ */
+ sh_database_reset();
+
+ SL_RETURN(-1, _("sh_database_query"));
+}
+
+/* #ifdef WITH_ORACLE */
+#endif
+
+#ifdef WITH_POSTGRES
+/******************************************************************
+ *
+ * Postgresql stuff, tested
+ *
+ ******************************************************************/
+
+#if defined(HAVE_PGSQL_LIBPQ_FE_H)
+#include <pgsql/libpq-fe.h>
+#elif defined(HAVE_POSTGRESQL_LIBPQ_FE_H)
+#include <postgresql/libpq-fe.h>
+#else
+#if !defined(USE_UNO)
+#include <libpq-fe.h>
+#else
+#include <postgresql/libpq-fe.h>
+#endif
+#endif
+
+static int connection_status = S_FALSE;
+
+void sh_database_reset()
+{
+ connection_status = S_FALSE;
+ return;
+}
+
+static
+int sh_database_query (char * query, /*@out@*/ long * id)
+{
+ char conninfo[256];
+ char * p;
+ static PGconn * conn = NULL;
+ PGresult * res;
+ unsigned int i;
+ const char * params[1];
+ char id_param[32];
+ static SH_TIMEOUT sh_timer = { 0, 3600, S_TRUE };
+
+ SL_ENTER(_("sh_database_query"));
+
+ *id = 0;
+
+ p = &conninfo[0];
+
+ if (db_host[0] == '\0')
+ sl_strlcpy(db_host, _("localhost"), 64);
+ if (db_name[0] == '\0')
+ sl_strlcpy(db_name, _("samhain"), 64);
+ if (db_user[0] == '\0')
+ sl_strlcpy(db_user, _("samhain"), 64);
+
+ if (db_host[0] != '\0' && NULL != strchr(db_host, '.'))
+ {
+ sl_snprintf(p, 255, "hostaddr=%s ", db_host);
+ p = &conninfo[strlen(conninfo)];
+ }
+ if (db_name[0] != '\0')
+ {
+ sl_snprintf(p, 255 - strlen(conninfo), "dbname=%s ", db_name);
+ p = &conninfo[strlen(conninfo)];
+ }
+
+ if (db_user[0] != '\0')
+ {
+ sl_snprintf(p, 255 - strlen(conninfo), "user=%s ", db_user);
+ p = &conninfo[strlen(conninfo)];
+ }
+
+ if (db_password[0] != '\0')
+ {
+ sl_snprintf(p, 255 - strlen(conninfo), "password=%s ", db_password);
+ }
+
+ if (connection_status == S_FALSE)
+ {
+ if (conn)
+ PQfinish(conn);
+ conn = NULL;
+ conn = PQconnectdb(conninfo);
+ }
+ else
+ {
+ if (PQstatus(conn) == CONNECTION_BAD)
+ PQreset(conn);
+ }
+
+ if ((conn == NULL) || (PQstatus(conn) == CONNECTION_BAD))
+ {
+ connection_status = S_FALSE;
+
+ sh_timer.flag_ok = S_FALSE;
+ if (S_TRUE == sh_util_timeout_check(&sh_timer))
+ {
+ goto err_out;
+ }
+ else
+ {
+ if (conn)
+ PQfinish(conn);
+ conn = NULL;
+ SL_RETURN(0, _("sh_database_query"));
+ }
+ }
+ connection_status = S_TRUE;
+
+
+ /* get the unique row index
+ */
+ res = PQexec(conn, _("SELECT NEXTVAL('log_log_index_seq')"));
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ PQclear(res);
+ goto err_out;
+ }
+
+ *id = atoi (PQgetvalue(res, 0, 0));
+ PQclear(res);
+
+ sl_snprintf(id_param, 32, "%ld", *id);
+ params[0] = id_param;
+
+ /* do the insert
+ */
+ res = PQexecParams(conn, query, 1, NULL, params, NULL, NULL, 1);
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ PQclear(res);
+ goto err_out;
+ }
+ PQclear(res);
+
+ if (S_FALSE == sh_persistent_dbconn)
+ {
+ if (conn)
+ PQfinish(conn);
+ conn = NULL;
+ connection_status = S_FALSE;
+ }
+ SL_RETURN(0, _("sh_database_query"));
+
+
+ err_out:
+ if (conn)
+ {
+ p = PQerrorMessage(conn);
+ for (i = 0; i < sl_strlen(p); ++i)
+ if (p[i] == '\n') p[i] = ' ';
+ }
+ else
+ {
+ p = NULL;
+ }
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ (p == NULL ? _("(null)") : p),
+ _("sh_database_query"));
+ if (conn)
+ PQfinish(conn);
+ conn = NULL;
+ connection_status = S_FALSE;
+ SL_RETURN(-1, _("sh_database_query"));
+}
+#endif
+
+
+#ifdef WITH_MYSQL
+
+#ifdef HAVE_MYSQL_MYSQL_H
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+extern int flag_err_debug;
+
+static int connection_status = S_FALSE;
+
+void sh_database_reset(void)
+{
+ connection_status = S_FALSE;
+ return;
+}
+
+static
+int sh_database_query (char * query, /*@out@*/ long * id)
+{
+ int status = 0;
+ const char * p;
+ static MYSQL * db_conn = NULL;
+ static SH_TIMEOUT sh_timer = { 0, 3600, S_TRUE };
+
+ SL_ENTER(_("sh_database_query"));
+
+ *id = 0;
+
+ if (query == NULL)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("NULL query"),
+ _("sh_database_query"));
+ SL_RETURN(0, _("sh_database_query"));
+ }
+
+ if (db_host[0] == '\0')
+ (void) sl_strlcpy(db_host, _("localhost"), 64);
+ if (db_name[0] == '\0')
+ (void) sl_strlcpy(db_name, _("samhain"), 64);
+ if (db_user[0] == '\0')
+ (void) sl_strlcpy(db_user, _("samhain"), 64);
+
+ if ((db_conn == NULL) || (connection_status == S_FALSE))
+ {
+ if (db_conn)
+ {
+ mysql_close(db_conn);
+ db_conn = NULL;
+ }
+ connection_status = S_FALSE;
+
+ db_conn = mysql_init(NULL);
+ if (NULL == db_conn)
+ {
+ p = NULL; status = 0;
+ sh_timer.flag_ok = S_FALSE;
+ if (S_TRUE == sh_util_timeout_check(&sh_timer))
+ {
+ goto alt_out;
+ }
+ else
+ {
+ SL_RETURN(0, _("sh_database_query"));
+ }
+ }
+
+ /* Read in defaults from /etc/my.cnf and associated files,
+ * suggested by arjones at simultan dyndns org
+ * see: - http://dev.mysql.com/doc/refman/5.0/en/option-files.html
+ * for the my.cnf format,
+ * - http://dev.mysql.com/doc/refman/5.0/en/mysql-options.html
+ * for possible options
+ * We don't check the return value because it's useless (failure due
+ * to lack of access permission is not reported).
+ */
+#if !defined(__x86_64__)
+ /*
+ * libmysql segfaults on x86-64 if this is used
+ */
+ mysql_options(db_conn, MYSQL_READ_DEFAULT_GROUP, _("samhain"));
+#endif
+
+ status = 0;
+
+ if (NULL == mysql_real_connect(db_conn,
+ db_host[0] == '\0' ? NULL : db_host,
+ db_user[0] == '\0' ? NULL : db_user,
+ db_password[0] == '\0' ? NULL : db_password,
+ db_name[0] == '\0' ? NULL : db_name,
+ 0, NULL, 0))
+ {
+ sh_timer.flag_ok = S_FALSE;
+ if (S_TRUE == sh_util_timeout_check(&sh_timer))
+ {
+ goto err_out;
+ }
+ else
+ {
+ SL_RETURN(0, _("sh_database_query"));
+ }
+ }
+ connection_status = S_TRUE;
+ }
+ else
+ {
+ if (0 != mysql_ping(db_conn))
+ {
+ connection_status = S_FALSE;
+ sh_timer.flag_ok = S_FALSE;
+ if (S_TRUE == sh_util_timeout_check(&sh_timer))
+ {
+ goto err_out;
+ }
+ else
+ {
+ SL_RETURN(0, _("sh_database_query"));
+ }
+ }
+ }
+
+ if (0 != mysql_query(db_conn, query))
+ {
+ goto err_out;
+ }
+
+ if (flag_err_debug == S_TRUE)
+ {
+ p = mysql_info (db_conn);
+ if (p != NULL)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ p,
+ _("sh_database_query"));
+ }
+ }
+
+ *id = (long) mysql_insert_id(db_conn);
+ if (S_FALSE == sh_persistent_dbconn)
+ {
+ if (db_conn)
+ mysql_close(db_conn);
+ db_conn = NULL;
+ connection_status = S_FALSE;
+ }
+ SL_RETURN(0, _("sh_database_query"));
+
+ err_out:
+
+ if (db_conn)
+ {
+ p = mysql_error (db_conn);
+ status = (int) mysql_errno (db_conn);
+ }
+ else
+ {
+ p = NULL; p = 0;
+ }
+
+ alt_out:
+
+ *id = 0;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ (p == NULL ? _("(null)") : p),
+ _("sh_database_query"));
+ if (db_conn)
+ mysql_close(db_conn);
+ db_conn = NULL;
+ connection_status = S_FALSE;
+ SL_RETURN(status, _("sh_database_query"));
+}
+#endif
+
+static
+char * null_or_val (char * end, char * val, int * size, int flag)
+{
+ long len;
+
+ if (!((end == NULL) || (val == NULL) || (size == NULL)))
+ {
+ if (val[0] != '\0')
+ {
+ if (*size > 1)
+ {
+ *end = ','; ++end; (*size) -= 1;
+ if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
+ *end = '\0';
+ }
+ len = (long) strlen(val);
+ if ((long) *size > (len+1))
+ {
+ (void) sl_strlcat(end, val, (size_t) *size);
+ end += len; (*size) -= len;
+ if (flag == 1) { *end = '\''; ++end; (*size) -= 1; }
+ *end = '\0';
+ }
+ }
+ }
+
+ return end;
+}
+
+#define SH_QUERY_MAX SH_MSG_BUF
+/* define SH_QUERY_MAX 16383 */
+
+static
+long sh_database_entry (dbins * db_entry, long id)
+{
+ /* This does not need to be re-entrant
+ */
+ char * query;
+ static char columns[1024];
+ char * values;
+
+ long the_id;
+ int size;
+ char * end;
+ int c_size;
+ char * c_end;
+ char * p;
+ int i;
+ char num[64];
+
+ md5Param crc;
+ unsigned char md5buffer[16];
+ char md5out[33];
+ int cnt;
+
+ size_t len_val;
+ size_t len_col;
+
+ SL_ENTER(_("sh_database_entry"));
+
+ query = SH_ALLOC(SH_QUERY_MAX+1);
+ values = SH_ALLOC(SH_QUERY_MAX+1);
+
+ (void) md5Reset(&crc);
+
+ if (db_entry->host[0] == '\0')
+ {
+ if (sh.host.name[0] == '\0')
+ (void) strcpy (db_entry->host, _("localhost")); /* known to fit */
+ else
+ (void) sl_strlcpy (db_entry->host, sh.host.name, 64);
+ }
+
+ /*@-bufferoverflowhigh@*/
+ if (id >= 0)
+ sprintf(num, "%ld", id); /* known to fit */
+ /*@+bufferoverflowhigh@*/
+
+#if defined(WITH_ORACLE)
+ /* Oracle needs some help for the time format (fix by Michael Somers)
+ */
+ (void)
+ sl_snprintf (values, SH_QUERY_MAX,
+ _("(:1,%s,%c%s%c,to_date(%c%s%c,'YYYY-MM-DD HH24:MI:SS'),%c%s%c,%c%s%c"),
+ id >= 0 ? num : _("NULL"),
+ '\'', db_entry->host,'\'',
+ '\'', db_entry->time,'\'',
+ '\'', db_entry->sev, '\'',
+ '\'',
+ (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
+ '\'');
+ (void) sl_snprintf (columns, 1023,
+ _("(log_index,log_ref,log_host,log_time,log_sev,log_msg"));
+#elif defined(WITH_POSTGRES)
+ /* Prepare query for PQexecParams
+ */
+ (void)
+ sl_snprintf (values, SH_QUERY_MAX,
+ _("($1,%s,%c%s%c,%c%s%c,%c%s%c,%c%s%c"),
+ id >= 0 ? num : _("NULL"),
+ '\'', db_entry->host,'\'',
+ '\'', db_entry->time,'\'',
+ '\'', db_entry->sev, '\'',
+ '\'',
+ (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
+ '\'');
+ (void) sl_snprintf (columns, 1023,
+ _("(log_index,log_ref,log_host,log_time,log_sev,log_msg"));
+#else
+ (void)
+ sl_snprintf (values, SH_QUERY_MAX, _("(%s,%c%s%c,%c%s%c,%c%s%c,%c%s%c"),
+ id >= 0 ? num : _("NULL"),
+ '\'', db_entry->host,'\'',
+ '\'', db_entry->time,'\'',
+ '\'', db_entry->sev, '\'',
+ '\'',
+ (db_entry->msg[0] == '\0' ? _("NULL") : db_entry->msg),
+ '\'');
+ (void) sl_snprintf (columns, 1023,
+ _("(log_ref,log_host,log_time,log_sev,log_msg"));
+#endif
+
+
+ /*@-type@*//* byte* versus char[..] */
+ if (attr_tab[0].inHash == 1)
+ (void) md5Update(&crc, (sh_byte*) db_entry->sev,
+ (int) strlen(db_entry->sev));
+ if (attr_tab[1].inHash == 1)
+ (void) md5Update(&crc, (sh_byte*) db_entry->time,
+ (int) strlen(db_entry->time));
+ if (attr_tab[2].inHash == 1)
+ (void) md5Update(&crc, (sh_byte*) db_entry->host,
+ (int) strlen(db_entry->host));
+ if (attr_tab[3].inHash == 1 && db_entry->msg[0] != '\0')
+ (void) md5Update(&crc, (sh_byte*) db_entry->msg,
+ (int) strlen(db_entry->sev));
+ /*@+type@*/
+
+ len_val = strlen(values);
+ size = (int) (SH_QUERY_MAX - len_val);
+ end = values + len_val;
+
+ len_col = strlen(columns);
+ c_size = 1023 - (int) len_col; /* sizeof(colums) == 1024 */
+ c_end = columns + len_col;
+
+ i = 4;
+
+ while (attr_tab[i].attr != NULL)
+ {
+ if (SH_SLOT_CHECKFLAGS == attr_tab[i].val) {
+ if (db_entry->ulong_data[attr_tab[i].val-START_SEC_LONGS] == 0 &&
+ db_entry->ulong_data[attr_tab[i+1].val-START_SEC_LONGS] == 0)
+ { i+= 2; continue; }
+ }
+
+ if (attr_tab[i].size != 0)
+ {
+ if (attr_tab[i].val > 40 && attr_tab[i].val < 47)
+ {
+ /* remove the 'T' between date and time
+ */
+ p = (char *)(db_entry)+attr_tab[i].off;
+ p = strchr(p, 'T');
+ if (p) *p = ' ';
+ }
+ p = end;
+ end = null_or_val(end,((char *)(db_entry)+attr_tab[i].off),&size,1);
+ if (p != end)
+ {
+ if ((attr_tab[i].val != SH_SLOT_HOST) &&
+ (attr_tab[i].val != SH_SLOT_GROUP))
+ {
+ c_end = null_or_val (c_end, attr_tab[i].attr, &c_size,0);
+ }
+ else
+ {
+ /*
+ * 'host' is a reserved word in SQL
+ */
+ if (attr_tab[i].val == SH_SLOT_HOST)
+ c_end = null_or_val (c_end, _("fromhost"), &c_size,0);
+ /*
+ * 'group' is a reserved word in SQL
+ */
+ else /* if (attr_tab[i].val == SH_SLOT_GROUP) */
+ c_end = null_or_val (c_end, _("grp"), &c_size,0);
+ }
+ }
+ /*@-type@*//* byte* versus char[..] */
+ if (attr_tab[i].inHash == 1 &&
+ ((char *)(db_entry)+attr_tab[i].off) != '\0')
+ {
+ (void)md5Update(&crc,
+ (sh_byte*) ((char *)(db_entry)+attr_tab[i].off),
+ (int)strlen((char *)(db_entry)+attr_tab[i].off));
+ }
+ /*@+type@*/
+ }
+ else if (attr_tab[i].val >= START_SEC_LONGS &&
+ attr_tab[i].val <= END_SEC_LONGS)
+ {
+ (void)
+ sl_snprintf(end, (size_t)(size-1), _(",\'%lu\'"),
+ db_entry->ulong_data[attr_tab[i].val-START_SEC_LONGS]);
+ while (*end != '\0') { ++end; --size; }
+ (void) sl_snprintf(c_end, (size_t)(c_size-1),
+ _(",%s"), attr_tab[i].attr);
+ while (*c_end != '\0') { ++c_end; --c_size; }
+ if (attr_tab[i].inHash == 1)
+ {
+ /*@-type@*//* byte* versus char[..] */
+ (void)
+ md5Update(&crc,
+ (sh_byte *) db_entry->ulong_data[attr_tab[i].val-START_SEC_LONGS],
+ sizeof(long));
+ /*@+type@*/
+ }
+ }
+
+ ++i;
+ }
+
+ (void) md5Digest(&crc, (uint32 *) md5buffer);
+ /*@-bufferoverflowhigh -usedef@*/
+ for (cnt = 0; cnt < 16; ++cnt)
+ sprintf (&md5out[cnt*2], _("%02X"), /* known to fit */
+ (unsigned int) md5buffer[cnt]);
+ /*@+bufferoverflowhigh +usedef@*/
+ md5out[32] = '\0';
+
+ (void) sl_snprintf(end, (size_t) (size-1), _(",%c%s%c"), '\'', md5out, '\'');
+ while (*end != '\0') { ++end; --size; }
+ (void) sl_snprintf(c_end, (size_t) (c_size-1),_(",log_hash"));
+ while (*c_end != '\0') { ++c_end; --c_size; }
+
+
+ if (size > 1) { *end = ')'; ++end; *end = '\0'; }
+ if (c_size > 1) { *c_end = ')'; ++c_end; *c_end = '\0'; }
+
+ if (db_table[0] == '\0')
+ (void) sl_strlcpy(db_table, _("log"), 64);
+
+ (void) sl_snprintf (query, SH_QUERY_MAX,
+ _("INSERT INTO %s %s VALUES %s"),
+ db_table, columns, values);
+
+ sh_database_query (query, &the_id);
+
+ /*@-usedef@*//* no, 'values' is allocated here */
+ SH_FREE(values);
+ /*@+usedef@*/
+ SH_FREE(query);
+
+ SL_RETURN(the_id, _("sh_database_entry"));
+}
+
+static int sh_database_comp_attr (const void *m1, const void *m2)
+{
+ const my_attr *mi1 = (const my_attr *) m1;
+ const my_attr *mi2 = (const my_attr *) m2;
+ return strcmp(mi1->attr, mi2->attr);
+}
+
+
+static void init_attr_table(void)
+{
+ static int first = S_TRUE;
+ int i, j;
+
+#ifdef SH_STEALTH
+ int k;
+
+ if (first == S_FALSE)
+ return;
+
+ i = 0;
+ while (attr_tab[i].attr_o != NULL)
+ {
+ j = strlen(attr_tab[i].attr_o);
+ attr_tab[i].attr = calloc(1, j+1); /* only once */
+ if (NULL == attr_tab[i].attr)
+ return;
+ for (k = 0; k < j; ++k)
+ attr_tab[i].attr[k] = attr_tab[i].attr_o[k] ^ XOR_CODE;
+ attr_tab[i].attr[j] = '\0';
+ attr_tab[i].alen = strlen(attr_tab[i].attr_o);
+ ++i;
+ }
+ first = S_FALSE;
+
+#else
+
+ if (first == S_FALSE)
+ return;
+
+ i = 0;
+ while (attr_tab[i].attr_o != NULL)
+ {
+ attr_tab[i].attr = attr_tab[i].attr_o;
+ attr_tab[i].alen = strlen(attr_tab[i].attr_o);
+ ++i;
+ }
+ first = S_FALSE;
+
+#endif
+
+ /* create a sorted table for binary search
+ */
+ attr_tab_srch = SH_ALLOC(i * sizeof(my_attr));
+ for (j=0; j<i; ++j)
+ memcpy(&attr_tab_srch[j], &attr_tab[j], sizeof(my_attr));
+ qsort(attr_tab_srch, i, sizeof(my_attr), sh_database_comp_attr);
+ attr_tab_srch_siz = i;
+
+ return;
+}
+
+int sh_database_add_to_hash (const char * str)
+{
+ int i;
+
+ if (!str)
+ return -1;
+ init_attr_table();
+ if (0 == strcmp(str, _("log_msg"))) { attr_tab[3].inHash = 1; return 0;}
+ if (0 == strcmp(str, _("log_sev"))) { attr_tab[0].inHash = 1; return 0;}
+ if (0 == strcmp(str, _("log_time"))) { attr_tab[1].inHash = 1; return 0;}
+ if (0 == strcmp(str, _("log_host"))) { attr_tab[2].inHash = 1; return 0;}
+ i = 4;
+ while (attr_tab[i].attr != NULL)
+ {
+ if (0 == strcmp(str, attr_tab[i].attr))
+ { attr_tab[i].inHash = 1; return 0; }
+ ++i;
+ }
+ return -1;
+}
+
+static int is_escaped(char * p_in) {
+
+ int escp = 0;
+ int retv = S_TRUE;
+ unsigned char * p = (unsigned char *) p_in;
+
+ if (*p != '\0')
+ {
+ do
+ {
+ if (*p <= 126 && *p >= 32)
+ {
+ if (escp == 0)
+ {
+ if (!((*p == '\'') || (*p == '\"') || (*p == '\\')))
+ /* do nothing */;
+ else if (*p == '\\')
+ {
+#ifndef WITH_MYSQL
+ if (p[1] == '\'')
+ {
+ *p = '\'';
+ }
+#endif
+ escp = 1;
+ }
+ else
+ retv = S_FALSE; /* (*p == '\'' || *p == '\"') */
+ }
+ else /* escp == 1 */
+ {
+ escp = 0;
+ }
+ }
+ else /* *p > 126 || *p < 32 */
+ {
+ retv = S_FALSE;
+ }
+
+ ++p;
+
+ }
+ while (*p != '\0');
+ }
+
+ if (escp == 0)
+ return retv;
+ else
+ return S_FALSE;
+}
+
+/* this is not a real XML parser, but it copes with the XML format of
+ * the log messages provided by sh_error_handle()
+ */
+static
+char * sh_database_parse (char * message, dbins * db_entry)
+{
+ static int first = S_TRUE;
+ char * p;
+ char * q;
+ char * z;
+ dbins * new;
+ int i;
+ size_t j;
+ my_attr * res;
+ my_attr key;
+ char key_str[64];
+
+ SL_ENTER(_("sh_database_parse"));
+
+ if (!message || *message == '\0')
+ SL_RETURN (NULL, _("sh_database_parse"));
+
+ if (first == S_TRUE)
+ {
+ init_attr_table();
+ first = S_FALSE;
+ }
+
+ p = strchr (message, '<');
+ if (!p)
+ SL_RETURN (NULL, _("sh_database_parse"));
+
+ while ((*p != '\0') && (*p != '>'))
+ {
+ if (p[0] == 'l' && p[1] == 'o' && p[2] == 'g' &&
+ (p[3] == ' ' || p[3] == '>'))
+ {
+ p = &p[4];
+ goto parse;
+ }
+ else if (p[0] == '/' && p[1] == '>')
+ SL_RETURN (&p[2], _("sh_database_parse"));
+ else if (p[0] == '/' && p[1] == 'l' && p[2] == 'o' &&
+ p[3] == 'g' && p[4] == '>')
+ SL_RETURN (&p[5], _("sh_database_parse"));
+ ++p;
+ }
+ SL_RETURN(NULL, _("sh_database_parse"));
+
+ parse:
+
+ while (*p == ' ' || *p == '>')
+ ++p;
+
+ if (*p == '\0')
+ SL_RETURN(NULL, _("sh_database_parse"));
+
+ if (*p != '<' && *p != '/')
+ goto par2;
+
+ if (p[0] == '<' && p[1] == 'l' &&
+ p[2] == 'o' && p[3] == 'g')
+ {
+ /*
+ * recursive call
+ */
+ new = SH_ALLOC(sizeof(dbins));
+ init_db_entry(new);
+ db_entry->next = new;
+ p = sh_database_parse (p, new);
+ }
+
+ if (p[0] == '/' && p[1] == '>')
+ SL_RETURN (&p[1], _("sh_database_parse"));
+
+ if (p[0] == '<' && p[1] == '/' && p[2] == 'l' &&
+ p[3] == 'o' && p[4] == 'g' && p[5] == '>')
+ SL_RETURN (&p[5], _("sh_database_parse"));
+
+ par2:
+
+ /* non-whitespace
+ */
+ for (i=0; i < 64; ++i)
+ {
+ if (p[i] != '=')
+ {
+ key_str[i] = p[i];
+ }
+ else
+ {
+ key_str[i] = '\0';
+ break;
+ }
+ }
+ key_str[63] = '\0';
+ key.attr = &key_str[0];
+
+ res = bsearch(&key, attr_tab_srch, attr_tab_srch_siz,
+ sizeof(my_attr), sh_database_comp_attr);
+
+ if (res != NULL)
+ {
+ j = res->alen; /* strlen(attr_tab[i].attr); */
+ if (p[j] == '=' && p[j+1] == '"')
+ {
+ q = strchr(&p[j+2], '"');
+ if (q)
+ {
+ *q = '\0';
+
+ if (S_TRUE == is_escaped(&p[j+2])) {
+
+ if (res->val == 1)
+ (void) sl_strlcpy(db_entry->sev, &p[j+2],
+ (size_t)res->size);
+ else if (res->val == 2)
+ {
+ z = strchr(&p[j+2], 'T');
+ if (z) *z = ' ';
+ (void) sl_strlcpy(db_entry->time, &p[j+2], 20);
+ }
+ else if (res->val == 3)
+ (void) sl_strlcpy(db_entry->host, &p[j+2],
+ (size_t) res->size);
+ else if (res->val == 4)
+ (void) sl_strlcpy(db_entry->msg, &p[j+2],
+ (size_t) res->size);
+ else if (res->size != 0)
+ {
+ (void) sl_strlcpy( (((char *)(db_entry))+ res->off),
+ &p[j+2],
+ (size_t) res->size);
+ }
+ else if (res->val >= START_SEC_LONGS && res->val <= END_SEC_LONGS)
+ {
+ db_entry->ulong_data[res->val-START_SEC_LONGS]
+ = strtoul(&p[j+2], (char **) NULL, 0);
+ }
+
+ *q = '"';
+ p = q;
+ ++p;
+
+ goto parse;
+ }
+ else { /* S_FALSE == is_escaped(&p[j+2]) */
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Message not properly escaped"),
+ _("sh_database_parse"));
+ SL_RETURN(NULL, _("sh_database_parse"));
+ }
+ }
+ else /* q == NULL */
+ {
+ SL_RETURN(NULL, _("sh_database_parse"));
+ }
+ }
+ }
+
+ /* unknown attribute, skip
+ */
+ while ((p != NULL) && (*p != '\0') && (*p != ' '))
+ ++p;
+
+ goto parse;
+}
+
+static int enter_wrapper = 1;
+
+int set_enter_wrapper (const char * str)
+{
+ return sh_util_flagval(str, &enter_wrapper);
+}
+
+/* recursively enter linked list of messages into database, last first
+ * - last is client (if this is a client message received by client)
+ */
+long sh_database_insert_rec (dbins * curr, int depth, char * host)
+{
+ unsigned long id = 0;
+
+ SL_ENTER(_("sh_database_insert_rec"));
+
+ if (curr->next)
+ {
+ /*
+ prev = curr->next;
+ sl_strlcpy(prev->host, curr->host, 64);
+ id = sh_database_insert_rec (curr->next, (depth + 1));
+ */
+ ++depth;
+ id = sh_database_insert_rec (curr->next, depth, curr->host);
+ }
+
+ if (host)
+ sl_strlcpy(curr->host, host, 64);
+
+ if (id != 0) /* this is a server wrapper */
+ {
+ if (enter_wrapper != 0)
+ {
+ id = sh_database_entry (curr, id);
+ }
+ }
+ else
+ {
+ /*
+ * id = -1 is the client message; log_ref will be NULL
+ */
+ if (depth > 0) /* this is a client message */
+ id = sh_database_entry (curr, -1);
+ else /* this is a generic server message */
+ id = sh_database_entry (curr, 0);
+ }
+
+ SH_FREE(curr);
+
+ SL_RETURN(id, _("sh_database_insert_rec"));
+}
+
+int sh_database_insert (char * message)
+{
+ dbins * db_entry;
+
+ SL_ENTER(_("sh_database_insert"));
+
+ db_entry = SH_ALLOC(sizeof(dbins));
+ init_db_entry(db_entry);
+
+ /* recursively parse the message into a linked list
+ */
+ (void) sh_database_parse (message, db_entry);
+
+ /* recursively enter the linked list into the database
+ */
+ (void) sh_database_insert_rec (db_entry, 0, NULL);
+
+ SL_RETURN(0, _("sh_database_insert"));
+}
+
+#endif
diff --git a/src/sh_dbCheck.c b/src/sh_dbCheck.c
new file mode 100644
index 0000000..4d135a9
--- /dev/null
+++ b/src/sh_dbCheck.c
@@ -0,0 +1,122 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+
+#include "samhain.h"
+#include "sh_unix.h"
+#include "sh_utils.h"
+#include "sh_hash.h"
+#include "sh_files.h"
+#include "sh_tiger.h"
+
+#include "sh_dbIO.h"
+#include "sh_dbIO_int.h"
+#include "sh_pthread.h"
+
+#undef FIL__
+#define FIL__ _("sh_dbCheck.c")
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+static void file_verify(sh_file_t * p)
+{
+ int reported = 0;
+ unsigned long check_flags;
+ char * dir_name;
+ char * file_name;
+
+ if (p->next != NULL)
+ file_verify(p->next);
+ if (p->fullpath == NULL || p->fullpath[0] != '/')
+ return;
+
+ check_flags = p->theFile.checkflags;
+
+ if (!MODI_INITIALIZED(check_flags)) {
+ MODI_SET(check_flags, MODI_INIT|MASK_READONLY_);
+ sh_tiger_get_mask_hashtype(&check_flags);
+ }
+
+ dir_name = sh_util_dirname(p->fullpath);
+ file_name = sh_util_basename(p->fullpath);
+
+ if (SH_FILE_UNKNOWN == sh_files_filecheck (SH_LEVEL_READONLY, check_flags,
+ dir_name, file_name,
+ &reported, 0))
+ ++sh.statistics.files_report;
+
+ SH_FREE(dir_name);
+ SH_FREE(file_name);
+ return;
+}
+
+static void dbCheck_setup()
+{
+ sh_hash_set_initialized();
+ sh.flag.isdaemon = S_FALSE;
+ sh.flag.loop = S_FALSE;
+ sh.flag.update = S_FALSE;
+ sh.flag.checkSum = SH_CHECK_CHECK;
+
+ sh.statistics.files_report = 0;
+ ShDFLevel[SH_ERR_T_FILE] = SH_ERR_SEVERE;
+ ShDFLevel[SH_ERR_T_RO] = SH_ERR_SEVERE;
+ ShDFLevel[SH_ERR_T_NAME] = SH_ERR_SEVERE;
+
+ return;
+}
+#include <stddef.h>
+int sh_dbCheck_verify (const char * db_file)
+{
+ unsigned int i;
+ sh_file_t ** mtab = get_default_data_table();
+
+ sh_error_only_stderr (S_TRUE);
+ sh_error_setprint(_("none"));
+
+ /* for sh.effective.home in open_tmp() */
+ sh_unix_getUser ();
+
+ if (sh_dbIO_load_db_file(mtab, db_file) < 0)
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+
+ dbCheck_setup();
+
+ /* Don't lock because:
+ * (a) we are single-treaded, thus it's not required
+ * (b) it will lead to deadlocking
+ */
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ if (mtab[i] != NULL)
+ file_verify(mtab[i]);
+ }
+
+ sh_hash_unvisited (SH_ERR_INFO);
+
+ if (0 != sh.statistics.files_report)
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ return 0;
+}
+
+#endif
diff --git a/src/sh_dbCreate.c b/src/sh_dbCreate.c
new file mode 100644
index 0000000..08e6968
--- /dev/null
+++ b/src/sh_dbCreate.c
@@ -0,0 +1,227 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_hash.h"
+#include "sh_files.h"
+
+#include "sh_dbIO.h"
+#include "sh_dbIO_int.h"
+#include "sh_pthread.h"
+#include "sh_guid.h"
+
+#undef FIL__
+#define FIL__ _("sh_dbCreate.c")
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+static int dbCreate_writeout()
+{
+ char uuid[SH_UUID_BUF];
+ char * path;
+ int retval;
+
+ if (sh.outpath == NULL || sh.outpath[0] == '\0')
+ {
+ sh_uuid_generate_random(uuid, sizeof(uuid));
+ path = sh_util_strconcat(_("file."), sh.host.name, ".", uuid, NULL);
+ }
+ else
+ path = sh_util_strdup(sh.outpath);
+
+ retval = sh_dbIO_writeout_to_path(path);
+ SH_FREE(path);
+ return retval;
+}
+
+static void dbCreate_run_filecheck(unsigned long add_mask, char * str)
+{
+ int status;
+
+ int reported = 0;
+ unsigned long check_flags = (MASK_READONLY_ | MODI_INIT | add_mask);
+ char * dir_name = sh_util_dirname(str);
+ char * file_name = sh_util_basename(str);
+
+ status = sh_files_filecheck (SH_LEVEL_READONLY, check_flags,
+ dir_name, file_name, &reported, 0);
+
+ if (status == SH_FILE_UNKNOWN)
+ {
+ sh_hash_insert_null(str);
+ }
+
+ return;
+}
+
+static int dbCreate_filecheck(char * str)
+{
+ unsigned long add_mask = 0;
+
+ if (*str == '+')
+ {
+ add_mask = MODI_TXT;
+ ++str; while (isspace((int)*str)) ++str;
+ }
+ if (*str != '/')
+ {
+ char * tmp = sh_util_safe_name (str);
+ sh_error_handle((-1), FIL__, __LINE__, EINVAL, MSG_E_SUBGPATH,
+ _("Not an absolute path"),
+ _("dbCreate_filecheck"), tmp);
+ SH_FREE(tmp);
+ return -1;
+ }
+ dbCreate_run_filecheck(add_mask, str);
+ return 0;
+}
+
+char * rtrim(char * str)
+{
+ size_t len;
+
+ if (!str)
+ return str;
+
+ len = strlen(str);
+ while (len > 0)
+ {
+ --len;
+ if (str[len] == '\n' || str[len] == '\r')
+ str[len] = '\0';
+ else
+ break;
+ }
+
+ return str;
+}
+
+static int dbCreate_loop(FILE * fd)
+{
+ int status, retval = 0;
+ size_t linesize = MAX_PATH_STORE+2;
+ char * line = SH_ALLOC(linesize);
+
+ do {
+ status = sh_dbIO_getline(fd, line, linesize);
+
+ if (status > 0)
+ {
+ char * str = rtrim(line);
+ while (isspace((int)*str)) ++str;
+ if (*str != '#')
+ {
+ int fstatus = -1;
+ size_t len = 0;
+ char * p = sh_files_parse_input(str, &len);
+
+ if (p)
+ {
+ fstatus = dbCreate_filecheck(p);
+ SH_FREE(p);
+ }
+ if (fstatus != 0)
+ retval = -1;
+ }
+ }
+ } while (status != -1);
+
+ SH_FREE(line);
+ return retval;
+}
+
+static FILE * dbCreate_open (const char * path)
+{
+ FILE * fd = fopen(path, "r");
+ if (!fd)
+ {
+ int error = errno;
+ char * tmp = sh_util_safe_name (path);
+ sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_SUBGPATH,
+ _("Cannot open file for read"),
+ _("dbCreate_open"), tmp);
+ SH_FREE(tmp);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ return fd;
+}
+
+static void dbCreate_setup()
+{
+ sh_hash_set_initialized();
+ sh.flag.isdaemon = S_FALSE;
+ sh.flag.loop = S_FALSE;
+ sh.flag.update = S_FALSE;
+ sh.flag.checkSum = SH_CHECK_CHECK;
+
+ sh.statistics.files_report = 0;
+ ShDFLevel[SH_ERR_T_FILE] = SH_ERR_SEVERE;
+ ShDFLevel[SH_ERR_T_RO] = SH_ERR_SEVERE;
+ ShDFLevel[SH_ERR_T_NAME] = SH_ERR_SEVERE;
+
+ sh_error_only_stderr (S_TRUE);
+ sh_error_setprint(_("none"));
+
+ return;
+}
+
+
+int sh_dbCreate (const char * path)
+{
+ FILE * fd;
+
+ /* Initialize application status
+ */
+ dbCreate_setup();
+
+ /* Open file list
+ */
+ fd = dbCreate_open(path);
+
+ /* Load the database
+ */
+ sh_hash_init_and_checksum();
+
+ /* Loop over file list to check files.
+ */
+ dbCreate_loop(fd);
+
+ /* Close file list
+ */
+ fclose(fd);
+
+ /* Write out database
+ */
+ if (0 != dbCreate_writeout())
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+
+ /* Exit on success.
+ */
+ aud_exit(FIL__, __LINE__, EXIT_SUCCESS);
+ return 0;
+}
+
+#endif
diff --git a/src/sh_dbIO.c b/src/sh_dbIO.c
new file mode 100644
index 0000000..0ac9194
--- /dev/null
+++ b/src/sh_dbIO.c
@@ -0,0 +1,1807 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_dbIO_int.h"
+#include "sh_hash.h"
+#include "sh_dbIO.h"
+#include "sh_gpg.h"
+#include "sh_tiger.h"
+#include "sh_xfer.h"
+#include "sh_pthread.h"
+#include "sh_socket.h"
+#include "sh_files.h"
+
+#undef FIL__
+#define FIL__ _("sh_dbIO.c")
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+/* external prototypes */
+
+extern int get_the_fd (SL_TICKET ticket);
+
+SH_MUTEX_EXTERN(mutex_hash);
+
+/******************************************************************
+ *
+ * Get a single line
+ *
+ ******************************************************************/
+static FILE * sh_fin_fd = NULL;
+
+int sh_dbIO_getline (FILE * fd, char * line, const size_t sizeofline)
+{
+ size_t n = 0;
+
+ SL_REQUIRE(sizeofline >= SH_MINIBUF, _("sizeofline >= SH_MINIBUF"));
+
+ if (NULL != fgets(line, sizeofline, fd))
+ {
+ n = strlen(line);
+ if (n > 0 && line[n-1] == '\n') {
+ n--; line[n] = '\0';
+ }
+ }
+ else {
+ line[0] = '\0';
+ return -1;
+ }
+
+ return n;
+}
+
+/******************************************************************
+ *
+ * Fast forward to start of data
+ *
+ ******************************************************************/
+
+static void reopen_fin_fd(SL_TICKET fd)
+{
+ if (sh_fin_fd != NULL)
+ {
+ sl_fclose (FIL__, __LINE__, sh_fin_fd);
+ sh_fin_fd = NULL;
+ }
+
+ sh_fin_fd = fdopen(dup(get_the_fd(fd)), "rb");
+ return;
+}
+
+
+static int seek_sof(FILE * fd, char * line, int size, const char * file)
+{
+ long i;
+
+ while (1)
+ {
+ i = sh_dbIO_getline (fd, line, size);
+ if (i < 0 )
+ {
+ SH_FREE(line);
+ dlog(1, FIL__, __LINE__,
+ _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
+ (NULL == file) ? _("(null)") : file);
+
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
+ ( (NULL == file) ? _("(null)") : file)
+ );
+ return -1;
+ }
+
+#if defined(SH_STEALTH)
+ if (0 == sl_strncmp (line, N_("[SOF]"), 5))
+#else
+ if (0 == sl_strncmp (line, _("[SOF]"), 5))
+#endif
+ break;
+ }
+ fflush(fd);
+ return 0;
+}
+
+static int sh_dbIO_setdataent (SL_TICKET fd, char * line, int size,
+ const char * file)
+{
+ int retval;
+
+ SL_ENTER(_("sh_dbIO_setdataent"));
+
+ sl_rewind (fd);
+ reopen_fin_fd(fd);
+
+ if (!sh_fin_fd)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The file signature database: %s is not readable.\n"),
+ (NULL == file) ? _("(null)") : file);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
+ ( (NULL == file) ? _("(null)") : file)
+ );
+ SL_RETURN( -1, _("sh_dbIO_setdataent"));
+ }
+
+ retval = seek_sof(sh_fin_fd, line, size, file);
+ SL_RETURN( retval, _("sh_dbIO_setdataent"));
+}
+
+static int sh_dbIO_setdataent_old (SL_TICKET fd, char * line, int size,
+ const char * file)
+{
+ FILE * fdp;
+
+ SL_ENTER(_("sh_dbIO_setdataent_old"));
+
+ sl_rewind (fd);
+ fdp = sl_stream(fd, "r+");
+ if (0 != seek_sof(fdp, line, size, file))
+ SL_RETURN( SL_EREAD, _("sh_dbIO_setdataent_old"));
+
+ lseek(fileno(fdp), ftello(fdp), SEEK_SET);
+
+ if (0 != ftruncate(fileno(fdp), ftello(fdp)))
+ {
+ char ebuf[SH_ERRBUF_SIZE];
+ int errnum = errno;
+ sh_error_message(errnum, ebuf, sizeof(ebuf));
+ sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ ebuf, _("sh_dbIO_setdataent_old") );
+ SL_RETURN( SL_EWRITE, _("sh_dbIO_setdataent_old"));
+ }
+ SL_RETURN( 0, _("sh_dbIO_setdataent_old"));
+}
+
+/******************************************************************
+ *
+ * IO helper functions
+ *
+ ******************************************************************/
+
+
+static UINT32 * swap_32 (UINT32 * iptr)
+{
+#ifdef WORDS_BIGENDIAN
+ unsigned char swap;
+ unsigned char * ii = (unsigned char *) iptr;
+ swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
+ swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
+ return iptr;
+#else
+ return iptr;
+#endif
+}
+
+static UINT64 * swap_64 (UINT64 * iptr)
+{
+#ifdef WORDS_BIGENDIAN
+#ifdef UINT64_IS_32
+ swap_32 ((UINT32*) iptr);
+#else
+ unsigned char swap;
+ unsigned char * ii = (unsigned char *) iptr;
+ swap = ii[0]; ii[0] = ii[7]; ii[7] = swap;
+ swap = ii[1]; ii[1] = ii[6]; ii[6] = swap;
+ swap = ii[2]; ii[2] = ii[5]; ii[5] = swap;
+ swap = ii[3]; ii[3] = ii[4]; ii[4] = swap;
+#endif
+ return iptr;
+#else
+ return iptr;
+#endif
+}
+
+static unsigned short * swap_short (unsigned short * iptr)
+{
+#ifdef WORDS_BIGENDIAN
+ if (sizeof(short) == 4)
+ swap_32 ((UINT32*) iptr);
+ else
+ {
+ /* alignment problem */
+ unsigned char swap;
+ static unsigned short ooop;
+ unsigned char * ii;
+ ooop = *iptr;
+ ii = (unsigned char *) &ooop;
+ swap = ii[0]; ii[0] = ii[1]; ii[1] = swap;
+ return &ooop;
+ }
+ return iptr;
+#else
+ return iptr;
+#endif
+}
+
+static void swap_data(sh_filestore_t * ft)
+{
+ swap_32(&(ft->mode));
+ swap_32(&(ft->linkmode));
+ swap_64(&(ft->dev));
+ swap_64(&(ft->rdev));
+ swap_32(&(ft->hardlinks));
+ swap_32(&(ft->ino));
+ swap_64(&(ft->size));
+ swap_64(&(ft->atime));
+ swap_64(&(ft->mtime));
+ swap_64(&(ft->ctime));
+ swap_32(&(ft->owner));
+ swap_32(&(ft->group));
+ swap_32(&(ft->checkflags));
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ swap_32(&(ft->attributes));
+#endif
+ ft->mark = *(swap_short(&(ft->mark)));
+ return;
+}
+
+#define QUOTE_CHAR '='
+
+char * unquote_string (const char * str, size_t len)
+{
+ int i = 0, t1, t2;
+ char * tmp = NULL;
+ size_t l2, j, k = 0;
+
+ SL_ENTER(_("unquote_string"));
+
+ if (str != NULL)
+ {
+ l2 = len - 2;
+ tmp = SH_ALLOC(len + 1);
+
+ for (j = 0; j <= len; ++j)
+ {
+ if (str[j] != QUOTE_CHAR)
+ {
+ tmp[k] = str[j];
+ }
+ else if (str[j] == QUOTE_CHAR && j < l2)
+ {
+ t1 = sh_util_hexchar(str[j+1]);
+ t2 = sh_util_hexchar(str[j+2]);
+ if ((t1|t2) >= 0)
+ {
+ i = 16 * t1 + t2;
+ tmp[k] = i;
+ j += 2;
+ }
+ else
+ {
+ tmp[k] = str[j];
+ }
+ }
+ else
+ tmp[k] = str[j];
+ ++k;
+ }
+ }
+ SL_RETURN(tmp, _("unquote_string"));
+}
+
+static char * int2hex (unsigned char i, char * i2h)
+{
+ static char hexchars[] = "0123456789ABCDEF";
+
+ i2h[0] = hexchars[(((i) & 0xF0) >> 4)]; /* high */
+ i2h[1] = hexchars[((i) & 0x0F)]; /* low */
+
+ return i2h;
+}
+
+char * quote_string (const char * str, size_t len)
+{
+ char * tmp;
+ char * tmp2;
+ size_t l2, j, i = 0, k = 0;
+ char i2h[2];
+
+ SL_ENTER(_("quote_string"));
+
+ if (str == NULL)
+ {
+ SL_RETURN(NULL, _("quote_string"));
+ }
+
+ for (j = 0; j < len; ++j)
+ if (str[j] == '\n' || str[j] == QUOTE_CHAR) ++i;
+
+ l2 = len + 1;
+ if (sl_ok_muls(3, i) && sl_ok_adds(l2, (3*i)))
+ {
+ tmp = SH_ALLOC(len + 1 + 3*i);
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("integer overflow"),
+ _("quote_string"));
+ SL_RETURN(NULL, _("quote_string"));
+ }
+
+ for (j = 0; j <= len; ++j)
+ {
+ if (str[j] == '\n')
+ {
+ tmp2 = int2hex((unsigned char) '\n', i2h);
+ tmp[k] = QUOTE_CHAR; ++k;
+ tmp[k] = tmp2[0]; ++k;
+ tmp[k] = tmp2[1];
+ }
+ else if (str[j] == QUOTE_CHAR)
+ {
+ tmp2 = int2hex((unsigned char) QUOTE_CHAR, i2h);
+ tmp[k] = QUOTE_CHAR; ++k;
+ tmp[k] = tmp2[0]; ++k;
+ tmp[k] = tmp2[1];
+ }
+ else
+ {
+ tmp[k] = str[j];
+ }
+ ++k;
+ }
+ SL_RETURN(tmp, _("quote_string"));
+}
+
+static char * unquote_path(char * line, long i)
+{
+ char * tmp = unquote_string (line, i);
+ size_t len = sl_strlen(tmp)+1;
+ char * path = SH_ALLOC(len);
+
+ (void) sl_strlcpy (path, tmp, len);
+ if (tmp)
+ SH_FREE(tmp);
+ if (len > 1) {
+ if (path[len-2] == '\n')
+ path[len-2] = '\0';
+ }
+ return path;
+}
+
+/******************************************************************
+ *
+ * Read next record and return it
+ *
+ ******************************************************************/
+
+static void corrupt_record(char * file, int line, const char * filepath)
+{
+ dlog(1, file, line,
+ _("There is a corrupt record in the file signature database: %s\n"),
+ (NULL == filepath)? _("(null)") : filepath);
+ sh_error_handle ((-1), file, line, 0, MSG_E_SUBGPATH,
+ _("Corrupt record in file signature database"),
+ _("sh_dbIO_getdataent"),
+ ( (NULL == filepath) ? _("(null)") : filepath) );
+ return;
+}
+
+static void wrong_version(char * file, int line, const char * filepath)
+{
+ dlog(1, file, line,
+ _("There is a record with a bad version number in the file signature database: %s\n"),
+ (NULL == filepath) ? _("(null)") : filepath);
+ sh_error_handle((-1), file, line, 0, MSG_E_SUBGPATH,
+ _("Record with bad version number in file signature database"),
+ _("sh_dbIO_getdataent"),
+ (NULL == filepath) ? _("(null)") : filepath);
+ return;
+}
+
+static void hexdump(unsigned char * data, size_t size)
+{
+ unsigned int count =0;
+ char ith[3];
+
+ do {
+ int2hex(data[count], ith); ith[2] = '\0';
+ printf("%2s", ith);
+ ++count;
+ if (count % 40 == 0) putc('\n', stdout);
+ } while (count < size);
+}
+
+static size_t dbIO_fread_struct (sh_filestore_t * ptr, FILE *stream,
+ const char * path, int * errflag)
+{
+ sh_filestore_old_t old_struct;
+ fpos_t position;
+ static int oldflag = -1;
+
+ start:
+ if (oldflag != -1) /* 'initialized' case first */
+ {
+ if (oldflag == 0)
+ return fread (ptr, sizeof(sh_filestore_t), 1, stream);
+
+ else
+ {
+ unsigned short mark;
+ if (1 != fread (&old_struct, sizeof(old_struct), 1, stream))
+ return 0;
+
+ /* set mark to current version */
+ mark = old_struct.mark;
+ mark = *(swap_short(&(mark)));
+ if ((mark & ~REC_FLAGS_MASK) != OLD_REC_MAGIC)
+ {
+ sh_filestore_old_t try_struct;
+ char try[5];
+
+ if (1 == 0)
+ hexdump((unsigned char *)&old_struct, sizeof(old_struct));
+ memset(&try_struct, '\0', sizeof(try_struct));
+ if (!memcmp(&old_struct, &try_struct, sizeof(try_struct)))
+ return 0; /* NULL read */
+ if (1 != fread (try, sizeof(try), 1, stream))
+ return 0;
+ if (feof(stream))
+ return 0;
+
+ wrong_version(FIL__, __LINE__, path);
+ *errflag = -1;
+ return 0;
+ }
+ if ((mark & REC_FLAGS_ATTR) != 0)
+ mark = REC_MAGIC|REC_FLAGS_ATTR;
+ else
+ mark = REC_MAGIC;
+ mark = *(swap_short(&(mark)));
+ old_struct.mark = mark;
+
+ /* copy into current struct version */
+ memcpy(ptr, &old_struct, sizeof(old_struct));
+ ptr->checkflags = 0;
+ return 1;
+ }
+ }
+ else /* not initialized yet, test DB version */
+ {
+ if (0 == fgetpos(stream, &position))
+ {
+ unsigned short mark;
+
+ if (1 != fread (&old_struct, sizeof(old_struct), 1, stream))
+ return 0;
+
+ mark = old_struct.mark;
+ mark = *(swap_short(&(mark)));
+ if ((mark & ~REC_FLAGS_MASK) == REC_MAGIC)
+ oldflag = 0;
+ else if ((mark & ~REC_FLAGS_MASK) == OLD_REC_MAGIC)
+ oldflag = 1;
+ else
+ {
+ wrong_version(FIL__, __LINE__, path);
+ *errflag = -1;
+ return 0;
+ }
+
+ /* return to previous position and read data */
+ if (0 != fsetpos(stream, &position))
+ return 0;
+ goto start;
+ }
+ return 0;
+ }
+}
+
+int sig_end_detected (void * ft)
+{
+ char * str = (char *) ft;
+ char cmp[SH_MINIBUF];
+
+ sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp));
+
+ if ( 0 == memcmp(str, cmp, strlen(cmp)) )
+ return S_TRUE;
+ return S_FALSE;
+}
+
+static sh_file_t * sh_dbIO_getdataent (char * line, int size,
+ const char * filepath, int * errflag)
+{
+ sh_file_t * p;
+ sh_filestore_t ft;
+ long i;
+ char * fullpath;
+ char * linkpath;
+ char * attr_string = NULL;
+
+ SL_ENTER(_("sh_dbIO_getdataent"));
+
+ *errflag = 0;
+
+ p = SH_ALLOC(sizeof(sh_file_t));
+
+ /* Read next record -- Part One
+ */
+ if (1 != dbIO_fread_struct (&ft, sh_fin_fd, filepath, errflag))
+ {
+ SH_FREE(p);
+ SL_RETURN( NULL, _("sh_dbIO_getdataent"));
+ }
+
+ ft.mark = *(swap_short(&(ft.mark)));
+
+ if ((ft.mark & ~REC_FLAGS_MASK) != REC_MAGIC)
+ {
+ if (sig_end_detected(&ft))
+ {
+ SH_FREE(p);
+ SL_RETURN( NULL, _("sh_dbIO_getdataent"));
+ }
+ SH_FREE(p);
+ wrong_version(FIL__, __LINE__, filepath);
+ *errflag = -1;
+ SL_RETURN( NULL, _("sh_dbIO_getdataent"));
+ }
+
+ ft.mark = *(swap_short(&(ft.mark)));
+ swap_data(&ft);
+
+ /* Read next record -- Part Two -- Fullpath
+ */
+ i = sh_dbIO_getline (sh_fin_fd, line, size);
+
+ if (i <= 0 )
+ {
+ SH_FREE(p);
+ corrupt_record(FIL__, __LINE__, filepath);
+ *errflag = -1;
+ SL_RETURN( NULL, _("sh_dbIO_getdataent"));
+ }
+
+ fullpath = unquote_path(line, i);
+
+ /* Read next record -- Part Three -- Linkpath
+ */
+ i = sh_dbIO_getline (sh_fin_fd, line, size);
+
+ if (i <= 0 )
+ {
+ SH_FREE(fullpath); SH_FREE(p);
+ corrupt_record(FIL__, __LINE__, filepath);
+ *errflag = -1;
+ SL_RETURN( NULL, _("sh_dbIO_getdataent"));
+ }
+
+ linkpath = unquote_path(line, i);
+
+ /* Read next record -- Part Four -- attr_string
+ */
+ if ((ft.mark & REC_FLAGS_ATTR) != 0)
+ {
+ i = sh_dbIO_getline (sh_fin_fd, line, size);
+ if (i <= 0 )
+ {
+ SH_FREE(fullpath); SH_FREE(linkpath); SH_FREE(p);
+ corrupt_record(FIL__, __LINE__, filepath);
+ *errflag = -1;
+ SL_RETURN( NULL, _("sh_dbIO_getdataent"));
+ }
+
+ attr_string = unquote_path(line, i);
+ }
+
+ /* Read next record -- Part Four -- Decode
+ */
+#if defined(SH_STEALTH)
+ sh_do_decode(fullpath, sl_strlen(fullpath));
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sh_do_decode(ft.c_attributes, sl_strlen(ft.c_attributes));
+#endif
+ sh_do_decode(ft.c_mode, sl_strlen(ft.c_mode));
+ sh_do_decode(ft.c_owner, sl_strlen(ft.c_owner));
+ sh_do_decode(ft.c_group, sl_strlen(ft.c_group));
+ sh_do_decode(ft.checksum, sl_strlen(ft.checksum));
+ /*
+ * TXT entries are c_mode[0] != 'l' and do not get decoded
+ */
+ if (ft.c_mode[0] == 'l' && linkpath[0] != '-')
+ {
+ sh_do_decode(linkpath, sl_strlen(linkpath));
+ }
+ if ((ft.mark & REC_FLAGS_ATTR) != 0)
+ {
+ sh_do_decode(attr_string, sl_strlen(attr_string));
+ }
+#endif
+
+ memcpy( &(*p).theFile, &ft, sizeof(sh_filestore_t) );
+
+ /* init fflags, such that suid files in
+ * database are recognized as such
+ */
+ {
+ mode_t mode = (mode_t) ft.mode;
+
+ if (S_ISREG(mode) &&
+ (0 !=(S_ISUID & mode) ||
+#if defined(HOST_IS_LINUX)
+ (0 !=(S_ISGID & mode) &&
+ 0 !=(S_IXGRP & mode))
+#else
+ 0 !=(S_ISGID & mode)
+#endif
+ )
+ )
+ p->fflags = SH_FFLAG_SUIDCHK;
+
+ else
+ p->fflags = 0;
+ }
+
+ p->modi_mask = ft.checkflags;
+ if (MODI_ISSET(ft.checkflags, MODI_ALLIGNORE))
+ SET_SH_FFLAG_ALLIGNORE(p->fflags);
+ p->fullpath = fullpath;
+ p->linkpath = linkpath;
+ p->attr_string = attr_string;
+
+ /* set to an invalid value
+ */
+ ft.mark = (REC_MAGIC + 5);
+
+ SL_REQUIRE((*errflag == 0), _("errflag not set correctly"));
+ SL_RETURN( p, _("sh_dbIO_getdataent"));
+}
+
+/******************************************************************
+ *
+ * Data loading routines
+ *
+ ******************************************************************/
+static SL_TICKET load_data_from_server(const char * uuid)
+{
+ SL_TICKET fd = -1;
+
+#if defined(SH_WITH_CLIENT)
+ char hashbuf[KEYBUF_SIZE];
+
+ /* Data file from Server
+ */
+ if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
+ return -1;
+
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART);
+ fd = sh_xfer_request_file((!uuid) ? _("DATA") : uuid);
+
+ if (SL_ISERROR(fd))
+ {
+ if (!uuid)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FBAD);
+ dlog(1, FIL__, __LINE__,
+ _("Could not retrieve the file signature database from the server(errnum = %ld).\nPossible reasons include:\n - the server is not running,\n - session key negotiation failed (see the manual for proper setup), or\n - the server cannot access the file.\n"), fd);
+ }
+ else
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_TCP_FBAD);
+ return fd;
+ }
+ sl_rewind (fd);
+
+ if (!uuid)
+ {
+ sl_strlcpy (sh.data.hash,
+ sh_tiger_hash (file_path('D', 'R'),
+ fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ sl_rewind (fd);
+ }
+#else
+ (void) uuid;
+#endif
+ return fd;
+}
+
+static SL_TICKET load_data_from_disk(const char * filepath)
+{
+ char hashbuf[KEYBUF_SIZE];
+ SL_TICKET fd = -1;
+
+ /* Local data file
+ */
+ if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, filepath, SL_YESPRIV)) )
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s>\n"), filepath));
+ dlog(1, FIL__, __LINE__,
+ _("Could not open the local file signature database for reading because\nof the following error: %s (errnum = %ld)\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"),
+ sl_get_errmsg(), fd, (int) sl_ret_euid());
+ sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ return -1;
+ }
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Opened database: %s>\n"),
+ filepath));
+
+ if (sh.data.hash[0] == '\0')
+ {
+ char hashbuf[KEYBUF_SIZE];
+ sl_strlcpy(sh.data.hash,
+ sh_tiger_hash (filepath, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+ else
+ {
+ if (0 != sl_strncmp(sh.data.hash,
+ sh_tiger_hash (filepath, fd, TIGER_NOLIM,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN)
+ && sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The checksum of the file signature database has changed since startup: %s -> %s\n"),
+ sh.data.hash, sh_tiger_hash (filepath, fd, TIGER_NOLIM,
+ hashbuf, sizeof(hashbuf)));
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH,
+ ( (NULL == filepath) ? _("(null)") :
+ filepath )
+ );
+ }
+ }
+ sl_rewind (fd);
+ return fd;
+}
+
+static SL_TICKET verify_data (SL_TICKET fd)
+{
+#if defined(WITH_GPG) || defined(WITH_PGP)
+ SL_TICKET fdTmp;
+
+ /* extract the data and copy to temporary file
+ */
+ fdTmp = sh_gpg_extract_signed(fd);
+
+ if (sig_termfast == 1) /* SIGTERM */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ --sig_raised; --sig_urgent;
+ return -1;
+ }
+
+ sl_close(fd);
+ fd = fdTmp;
+
+ /* Validate signature of open file.
+ */
+ if (0 != sh_gpg_check_sign (fd, SIG_DATA))
+ {
+ sl_close(fd);
+ return -1;
+ }
+ sl_rewind (fd);
+#endif
+
+ return fd;
+}
+
+static int read_data(SL_TICKET fd, sh_file_t * tab[TABSIZE],
+ const char * filepath)
+{
+ sh_file_t * p;
+ int count = 0;
+ int errflag = 0;
+ char * line = SH_ALLOC(MAX_PATH_STORE+2);
+
+ /* fast forward to start of data
+ */
+ if (0 != sh_dbIO_setdataent(fd, line, MAX_PATH_STORE+1, filepath))
+ return -1;
+
+ while (1)
+ {
+ if (sig_termfast == 1) /* SIGTERM */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ --sig_raised; --sig_urgent;
+ SH_FREE(line);
+ return -1;
+ }
+
+ p = sh_dbIO_getdataent (line, MAX_PATH_STORE+1, filepath, &errflag);
+ if (p != NULL)
+ {
+ if (!sh_hash_is_null_record(&(p->theFile)))
+ hashinsert (tab, p);
+ else
+ sh_hash_remove_unconditional (p->fullpath);
+ ++count;
+ }
+ else
+ break;
+ }
+
+ if (line != NULL)
+ SH_FREE(line);
+
+ /* Always keep db in memory, so we have no open file
+ */
+ sl_close (fd);
+
+ sl_fclose (FIL__, __LINE__, sh_fin_fd);
+ sh_fin_fd = NULL;
+
+ return errflag;
+}
+
+
+static int sh_dbIO_load_db_int(sh_file_t * tab[TABSIZE],
+ const char * filepath, const char * uuid)
+{
+#define FGETS_BUF 16384
+
+ SL_TICKET fd = -1;
+
+ if (uuid)
+ {
+ fd = load_data_from_server(uuid);
+ if (SL_ISERROR(fd))
+ return -1;
+ }
+ else if (!filepath)
+ {
+ char * dbpath = file_path('D', 'R');
+
+ fd = load_data_from_server(NULL);
+
+ if (SL_ISERROR(fd))
+ {
+ if (*dbpath == '/')
+ fd = load_data_from_disk(dbpath);
+ }
+ }
+ else
+ {
+ fd = load_data_from_disk(filepath);
+ }
+
+ if (SL_ISERROR(fd))
+ return -1;
+
+ if (sig_termfast == 1) /* SIGTERM */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ --sig_raised; --sig_urgent;
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ }
+
+ fd = verify_data(fd);
+ if (SL_ISERROR(fd))
+ return -1;
+
+ if (!uuid) { int i; for (i = 0; i < TABSIZE; ++i) tab[i] = NULL; }
+
+ return read_data (fd, tab, filepath);
+}
+
+
+int sh_dbIO_load_db(sh_file_t * tab[TABSIZE])
+{
+ return sh_dbIO_load_db_int(tab, NULL, NULL);
+}
+int sh_dbIO_load_db_file(sh_file_t * tab[TABSIZE], const char * filepath)
+{
+ return sh_dbIO_load_db_int(tab, filepath, NULL);
+}
+
+int sh_dbIO_load_delta()
+{
+ int status = 0;
+#if defined(SH_WITH_CLIENT)
+ sh_file_t ** mtab = get_default_data_table();
+ int errflag = 0;
+ unsigned int count;
+ time_t last;
+
+ if ( sh.flag.checkSum != SH_CHECK_INIT )
+ {
+ if (sh_hash_get_initialized() != 0)
+ {
+ char * uuid = sh_socket_get_uuid(&errflag, &count, &last);
+
+ if (!uuid)
+ return errflag;
+
+ if (count > 0)
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, count, MSG_E_SUBGEN,
+ _("Retrying download of delta DB"),
+ _("sh_dbIO_load_delta"));
+
+ status = sh_dbIO_load_db_int(mtab, NULL, uuid);
+ if (status < 0)
+ {
+ /* Return status < 0 indicates that max_try is exceeded
+ */
+ if (sh_socket_return_uuid(uuid, count, last) < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_D_DELTAFAIL, uuid);
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_D_DELTAOK, uuid);
+ }
+ SH_FREE(uuid);
+ }
+ else
+ {
+ /* not initialized yet */
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("Download of delta DB skipped, not initialized yet"),
+ _("sh_dbIO_load_delta"));
+ return -1;
+ }
+ }
+#endif
+ return status;
+}
+
+/******************************************************************
+ *
+ * Writing out a file to the database.
+ *
+ ******************************************************************/
+static int pushdata_isfirst = 1;
+static SL_TICKET pushdata_fd = -1;
+
+static int pushdata_stdout = S_FALSE;
+
+static char * sh_db_version_string = NULL;
+
+int sh_dbIO_writeout_stdout (const char * str)
+{
+ if (!str)
+ { pushdata_stdout = S_TRUE; return 0; }
+ return -1;
+}
+
+int sh_dbIO_version_string(const char * str)
+{
+ if (str)
+ {
+ if (sh_db_version_string != NULL) {
+ SH_FREE(sh_db_version_string);
+ }
+ if (0 == sl_strncmp(str, _("NULL"), 4))
+ {
+ sh_db_version_string = NULL;
+ return 0;
+ }
+ sh_db_version_string = sh_util_strdup(str);
+ return 0;
+ }
+ return -1;
+}
+
+void do_writeout_checks(const char * outpath)
+{
+ if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("You cannot write the database to stdout when you use update rather than init.\n"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
+ _("Writing database to stdout with update"),
+ sh.prg_name,
+ _("sh_dbIO_data_write_int"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ if ((pushdata_stdout == S_TRUE) && (sl_is_suid()))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("You cannot write the database to stdout when running with suid privileges.\n"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
+ _("Writing database to stdout when suid"),
+ sh.prg_name,
+ _("sh_dbIO_data_write_int"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+
+ if ( (pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE) &&
+ ( (NULL == outpath) || (0 == sl_strcmp(outpath, _("REQ_FROM_SERVER"))) ) )
+ {
+ dlog(1, FIL__, __LINE__,
+ _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
+ _("No local path for database specified"),
+ sh.prg_name,
+ _("sh_dbIO_data_write_int"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE))
+ {
+ /* Warn that file already exists; file_path != NULL here because
+ * checked above
+ */
+ struct stat sbuf;
+
+ if (0 == retry_lstat(FIL__, __LINE__, outpath, &sbuf))
+ {
+ if (sh.flag.update == S_FALSE)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX,
+ file_path('D', 'W'));
+ }
+ }
+ }
+
+ return;
+}
+
+static SL_TICKET open_writeout_data_truncate(const char * path)
+{
+ int status;
+ SL_TICKET fd;
+
+ if ( SL_ISERROR(fd = sl_open_rdwr_trunc(FIL__, __LINE__, path, SL_YESPRIV)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
+ geteuid(), path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ if (SL_ISERROR(status = sl_lock (fd)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
+ _("Failed to lock baseline database"), _("sh_dbIO_data_write_int"),
+ path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ return fd;
+}
+
+static SL_TICKET open_writeout_data(const char * path)
+{
+ int status;
+ SL_TICKET fd;
+
+ if ( SL_ISERROR(fd = sl_open_rdwr(FIL__, __LINE__, path, SL_YESPRIV)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
+ geteuid(), path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ if (SL_ISERROR(status = sl_lock (fd)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
+ _("Failed to lock baseline database"), _("sh_dbIO_data_write_int"),
+ path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ return fd;
+}
+
+static void seek_writeout_data(SL_TICKET fd, const char * path)
+{
+ int status;
+
+ if ( SL_ISERROR(status = sl_forward(fd)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
+ _("Failed to seek to end of baseline database"),
+ _("seek_writeout_data"),
+ path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ return;
+}
+
+static int seek_writeout_data_old(SL_TICKET fd, const char * path)
+{
+ char * line = SH_ALLOC(MAX_PATH_STORE+1);
+
+ if (SL_ISERROR(sh_dbIO_setdataent_old (fd, line, MAX_PATH_STORE, path)))
+ {
+ SH_FREE(line);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Failed to seek to end of baseline database"),
+ _("seek_writeout_data_old"),
+ path);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ SH_FREE(line);
+ return 0;
+}
+
+char * prep_path(char * path, int flag)
+{
+ size_t old_len = sl_strlen(path);
+ char * tmp;
+ size_t tmp_len;
+ size_t path_len;
+ char * outpath = NULL;
+#if !defined(SH_STEALTH)
+ (void) flag;
+#endif
+
+#if defined(SH_STEALTH)
+ if (flag == S_TRUE)
+ sh_do_encode(path, old_len);
+#endif
+ tmp = quote_string(path, old_len);
+ tmp_len = sl_strlen(tmp);
+#if defined(SH_STEALTH)
+ if (flag == S_TRUE)
+ sh_do_decode(path, old_len);
+#endif
+
+ if (tmp && tmp_len <= MAX_PATH_STORE)
+ {
+ outpath = sh_util_strdup(path);
+ }
+ else
+ {
+ char hashbuf[KEYBUF_SIZE];
+
+ outpath = sh_util_strdup(sh_tiger_hash (path,
+ TIGER_DATA, old_len,
+ hashbuf, sizeof(hashbuf)));
+ }
+ if (tmp)
+ SH_FREE(tmp);
+
+ path_len = sl_strlen(outpath);
+#if defined(SH_STEALTH)
+ if (flag == S_TRUE)
+ sh_do_encode(outpath, path_len);
+#endif
+
+ tmp = quote_string(outpath, path_len);
+ if (tmp) {
+ SH_FREE(outpath);
+ outpath = tmp;
+ }
+ return outpath;
+}
+
+static char * prep_attr(char * attr_str)
+{
+ char * tmp;
+ char * outstr = NULL;
+ size_t old_len = sl_strlen(attr_str);
+
+#if defined(SH_STEALTH)
+ sh_do_encode(attr_str, old_len);
+#endif
+
+ tmp = quote_string(attr_str, old_len);
+ if (tmp)
+ {
+ outstr = tmp;
+ }
+
+#if defined(SH_STEALTH)
+ sh_do_decode(attr_str, old_len);
+#endif
+ return outstr;
+}
+
+static void prep_encode(sh_filestore_t * p)
+{
+#if defined(SH_STEALTH)
+ sh_do_encode(p->c_mode, sl_strlen(p->c_mode));
+ sh_do_encode(p->c_owner, sl_strlen(p->c_owner));
+ sh_do_encode(p->c_group, sl_strlen(p->c_group));
+ sh_do_encode(p->checksum, sl_strlen(p->checksum));
+ sh_do_encode(p->c_attributes, sl_strlen(p->c_attributes));
+#else
+ (void) p;
+#endif
+ return;
+}
+
+static void prep_struct(sh_filestore_t * p, file_type * buf, char * fileHash)
+{
+#if !defined(__linux__) && !defined(HAVE_STAT_FLAGS)
+ int i;
+#endif
+ p->mark = REC_MAGIC;
+ sl_strlcpy(p->c_mode, buf->c_mode, CMODE_SIZE);
+ sl_strlcpy(p->c_group, buf->c_group, GROUP_MAX+1);
+ sl_strlcpy(p->c_owner, buf->c_owner, USER_MAX+1);
+ if (fileHash) {
+ sl_strlcpy(p->checksum, fileHash, KEY_LEN+1);
+ }
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_strlcpy(p->c_attributes, buf->c_attributes, ATTRBUF_SIZE);
+#else
+ for (i = 0; i < ATTRBUF_USED; ++i) p->c_attributes[i] = '-';
+ p->c_attributes[ATTRBUF_USED] = '\0';
+#endif
+
+ prep_encode(p);
+
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ p->attributes = (UINT32) buf->attributes;
+#else
+ p->attributes = 0;
+#endif
+ p->linkmode = (UINT32) buf->linkmode;
+ p->hardlinks = (UINT32) buf->hardlinks;
+ p->dev = (UINT64) buf->dev;
+ p->rdev = (UINT64) buf->rdev;
+ p->mode = (UINT32) buf->mode;
+ p->ino = (UINT32) buf->ino;
+ p->size = (UINT64) buf->size;
+ p->mtime = (UINT64) buf->mtime;
+ p->atime = (UINT64) buf->atime;
+ p->ctime = (UINT64) buf->ctime;
+ p->owner = (UINT32) buf->owner;
+ p->group = (UINT32) buf->group;
+
+ p->checkflags = (UINT32) buf->check_flags;
+
+ return;
+}
+
+
+static void write_start_header(SL_TICKET fd)
+{
+ char timestring[81];
+
+ if (pushdata_stdout == S_FALSE)
+ {
+ sl_write (fd, _("\n#Host "), 7);
+ sl_write (fd, sh.host.name,
+ sl_strlen(sh.host.name));
+ sl_write (fd, _(" Version "), 9);
+ sl_write (fd, sh_db_version_string,
+ sl_strlen(sh_db_version_string));
+ sl_write (fd, _(" Date "), 6);
+ (void) sh_unix_time(0, timestring, sizeof(timestring));
+ sl_write (fd, timestring, strlen(timestring));
+ sl_write (fd, "\n", 1);
+ }
+ else
+ {
+ printf ("%s",_("\n#Host "));
+ printf ("%s", sh.host.name);
+ printf ("%s",_(" Version "));
+ printf ("%s", sh_db_version_string);
+ printf ("%s",_(" Date "));
+ (void) sh_unix_time(0, timestring, sizeof(timestring));
+ printf ("%s\n", timestring);
+ }
+}
+
+static void write_start_marker(SL_TICKET fd)
+{
+ if (sh_db_version_string != NULL)
+ {
+ write_start_header(fd);
+ }
+
+ if (pushdata_stdout == S_FALSE)
+ {
+#if defined(SH_STEALTH)
+ sl_write (fd, "\n", 1);
+ sl_write_line (fd, N_("[SOF]"), 5);
+#else
+ sl_write_line (fd, _("\n[SOF]"), 6);
+#endif
+ }
+ else
+ {
+#if defined(SH_STEALTH)
+ puts (N_("[SOF]"));
+#else
+ puts (_("\n[SOF]"));
+#endif
+ }
+}
+
+static void write_record(SL_TICKET fd, sh_filestore_t * p,
+ char * fullpath, char * linkpath, char * attr_string)
+{
+ static char ll[2] = { '-', '\0' };
+ char * lpath;
+
+ if (!linkpath || 0 == sl_strlen(linkpath))
+ lpath = ll;
+ else
+ lpath = linkpath;
+
+ if (pushdata_stdout == S_FALSE)
+ {
+ if (SL_ENONE != sl_write (fd, p, sizeof(sh_filestore_t)))
+ {
+ char * tmp = sh_util_safe_name(fullpath);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Failed to write record to baseline database"),
+ _("write_record"),
+ tmp);
+ SH_FREE(tmp);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE );
+ }
+ if (SL_ENONE != sl_write_line_fast (fd, fullpath, sl_strlen(fullpath)))
+ {
+ char * tmp = sh_util_safe_name(fullpath);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Failed to write path to baseline database"),
+ _("write_record"),
+ tmp);
+ SH_FREE(tmp);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE );
+ }
+ if (SL_ENONE != sl_write_line_fast (fd, lpath, sl_strlen(lpath)))
+ {
+ char * tmp = sh_util_safe_name(fullpath);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Failed to write lpath to baseline database"),
+ _("write_record"),
+ tmp);
+ SH_FREE(tmp);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE );
+ }
+ if (attr_string)
+ sl_write_line_fast (fd, attr_string, sl_strlen(attr_string));
+ }
+ else
+ {
+ if (fwrite (p, sizeof(sh_filestore_t), 1, stdout))
+ {
+ puts (fullpath);
+ puts (lpath);
+ if (attr_string)
+ puts (attr_string);
+ }
+ else
+ {
+ perror(_("Error writing database"));
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ }
+
+ SH_FREE(fullpath);
+ if (linkpath)
+ SH_FREE(linkpath);
+ if (attr_string)
+ SH_FREE(attr_string);
+
+ return;
+}
+
+static void sh_dbIO_data_write_int (file_type * buf, char * fileHash,
+ const char * outpath, int truncate)
+{
+ static long p_count = 0;
+ sh_filestore_t p;
+ char * fullpath = NULL;
+ char * linkpath = NULL;
+ char * attr_string = NULL;
+
+ SL_ENTER(_("sh_dbIO_data_write_int"));
+
+ do_writeout_checks(outpath);
+
+ if (sh.flag.update == S_FALSE)
+ {
+ if (pushdata_stdout == S_FALSE && pushdata_fd == -1)
+ {
+ if (truncate == S_TRUE)
+ pushdata_fd = open_writeout_data_truncate(outpath);
+ else
+ {
+ pushdata_fd = open_writeout_data(outpath);
+ seek_writeout_data(pushdata_fd, outpath);
+ }
+ }
+ }
+ else /* update == TRUE */
+ {
+ if (pushdata_isfirst == 1)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Update.>\n")));
+ pushdata_fd = open_writeout_data(outpath);
+ seek_writeout_data_old(pushdata_fd, outpath);
+ }
+ }
+
+ if (!buf) {
+ memset(&p, '\0', sizeof(sh_filestore_t));
+ }
+
+ if (buf != NULL)
+ {
+ fullpath = prep_path(buf->fullpath, S_TRUE);
+ }
+
+ /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
+ */
+ if (buf != NULL /* && buf->c_mode[0] == 'l' */ && buf->link_path != NULL)
+ {
+ if (buf->c_mode[0] == 'l')
+ linkpath = prep_path(buf->link_path, S_TRUE);
+ else
+ linkpath = prep_path(buf->link_path, S_FALSE);
+ }
+
+ if (buf != NULL && buf->attr_string != NULL)
+ {
+ attr_string = prep_attr(buf->attr_string);
+ }
+
+ if (buf != NULL)
+ {
+ prep_struct(&p, buf, fileHash);
+ if (attr_string)
+ p.mark |= REC_FLAGS_ATTR;
+ swap_data(&p);
+ }
+
+ /* write the start marker
+ */
+ if (pushdata_isfirst == 1)
+ {
+ if (sh.flag.update == S_FALSE)
+ write_start_marker(pushdata_fd);
+ pushdata_isfirst = 0;
+ }
+
+ if (buf && fullpath)
+ {
+ write_record(pushdata_fd, &p, fullpath, linkpath, attr_string);
+ ++p_count;
+ }
+
+ if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
+ {
+ if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL))
+ {
+ sl_close (pushdata_fd);
+ pushdata_fd = -1;
+ }
+ }
+
+ SL_RET0(_("sh_dbIO_data_write_int"));
+}
+
+SH_MUTEX_STATIC(mutex_writeout,PTHREAD_MUTEX_INITIALIZER);
+
+void sh_dbIO_data_write (file_type * buf, char * fileHash)
+{
+ SH_MUTEX_LOCK(mutex_writeout);
+ sh_dbIO_data_write_int (buf, fileHash, file_path('D', 'W'), S_FALSE);
+ SH_MUTEX_UNLOCK(mutex_writeout);
+ return;
+}
+
+
+static int dbIO_writeout(sh_file_t * mtab[TABSIZE], const char * outpath, int truncate)
+{
+ sh_file_t * p;
+ int i;
+ file_type * f;
+ char fileHash[KEY_LEN + 1];
+
+ SL_ENTER(_("dbIO_writeout"));
+
+ SH_MUTEX_LOCK(mutex_writeout);
+ if (!SL_ISERROR(pushdata_fd))
+ {
+ sl_close(pushdata_fd);
+ pushdata_fd = -1;
+ }
+ pushdata_isfirst = 1;
+
+
+ SH_MUTEX_LOCK(mutex_hash);
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ for (p = mtab[i]; p; p = p->next)
+ {
+ f = sh_hash_create_ft (p, fileHash);
+ sh_dbIO_data_write_int (f, fileHash, outpath, (i == 0) ? truncate : S_FALSE);
+ if (f->attr_string) SH_FREE(f->attr_string);
+ if (f->link_path) SH_FREE(f->link_path);
+ SH_FREE(f);
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ if (!SL_ISERROR(pushdata_fd))
+ {
+ sl_close(pushdata_fd);
+ pushdata_fd = -1;
+ }
+ pushdata_isfirst = 1;
+ SH_MUTEX_UNLOCK(mutex_writeout);
+
+ SL_RETURN (0, _("dbIO_writeout"));
+}
+
+int sh_dbIO_writeout_update()
+{
+ sh_file_t ** mtab = get_default_data_table();
+
+ if (S_TRUE == file_is_remote())
+ {
+ sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN,
+ _("Baseline database is remote"), _("sh_dbIO_writeout"));
+ SL_RETURN (1, _("sh_dbIO_writeout_update"));
+ }
+
+ return dbIO_writeout(mtab, file_path('D', 'W'), S_FALSE);
+}
+
+int sh_dbIO_writeout_to_path(const char * path)
+{
+ sh_file_t ** mtab = get_default_data_table();
+ return dbIO_writeout(mtab, path, S_TRUE);
+}
+
+static void dbIO_write_record(sh_file_t * record, SL_TICKET fd)
+{
+ sh_filestore_t * p = &(record->theFile);
+ char * fullpath = NULL;
+ char * linkpath = NULL;
+ char * attr_string = NULL;
+
+ fullpath = prep_path(record->fullpath, S_TRUE);
+
+ /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
+ */
+ if (record->linkpath != NULL && 0 != strcmp("-", record->linkpath))
+ {
+ if (p->c_mode[0] == 'l')
+ linkpath = prep_path(record->linkpath, S_TRUE);
+ else
+ linkpath = prep_path(record->linkpath, S_FALSE);
+ }
+
+ if (record->attr_string != NULL)
+ attr_string = prep_attr(record->attr_string);
+
+ prep_encode(p);
+ swap_data(p);
+
+ write_record(fd, p, fullpath, linkpath, attr_string);
+ return;
+}
+
+static void dbIO_write_entry(sh_file_t * p)
+{
+ static int is_first = 1;
+
+ if (is_first)
+ {
+ pushdata_isfirst = 1;
+ if (!sh.outpath || sh.outpath[0] == '\0')
+ pushdata_stdout = S_TRUE;
+ else
+ pushdata_fd = open_writeout_data_truncate(sh.outpath);
+ write_start_marker(pushdata_fd);
+ pushdata_isfirst = 0;
+ is_first = 0;
+ }
+
+ dbIO_write_record(p, pushdata_fd);
+
+}
+
+
+/******************************************************************
+ *
+ * Listing the database.
+ *
+ ******************************************************************/
+
+static int ListBinary = S_FALSE;
+static char * ListFilter = NULL;
+
+int sh_dbIO_list_binary (const char * c)
+{
+ (void) c;
+ ListBinary = S_TRUE;
+ return 0;
+}
+int sh_dbIO_list_filter (const char * c)
+{
+ ListFilter = sh_util_strdup(c);
+ return 0;
+}
+
+#include "zAVLTree.h"
+
+static zAVLTree * filter_list = NULL;
+extern char * rtrim (char * str);
+
+#include <ctype.h>
+static void read_filter()
+{
+ int i, n = 0;
+ size_t len;
+ char * key;
+ char * str;
+ char * line = SH_ALLOC(SH_MAXBUF);
+ FILE * fd = fopen(ListFilter, "r");
+
+ if (!fd)
+ {
+ perror(_("read_filter: fopen:"));
+ _exit(EXIT_FAILURE);
+ }
+ do {
+ i = sh_dbIO_getline (fd, line, SH_MAXBUF);
+ str = rtrim(line);
+ while (isspace((int)*str)) ++str;
+
+ key = sh_files_parse_input(str, &len);
+
+ if (key && *key == '/')
+ {
+ zAVL_string_set(&filter_list, key);
+ ++n;
+ }
+ } while (i >= 0);
+
+ fclose(fd);
+ SH_FREE(line);
+
+ if (n == 0)
+ {
+ fprintf(stderr, _("read_filter: empty file <%s>\n"), ListFilter);
+ _exit (EXIT_FAILURE);
+ }
+ return;
+}
+
+static int check_filter(char * path)
+{
+ if (NULL == zAVL_string_get(filter_list, path))
+ return S_FALSE;
+ return S_TRUE;
+}
+
+int sh_dbIO_list_db (const char * db_file)
+{
+ sh_file_t * p;
+ SL_TICKET fd;
+ char * line;
+ int errflag = 0;
+ int flag = 0;
+ char * ListFile = get_list_file();
+
+ if (!db_file)
+ {
+ fputs(_("ERROR: no database file given\n"), stderr);
+ _exit(EXIT_FAILURE);
+ return -1;
+ }
+ if (sl_is_suid())
+ {
+ fputs(_("ERROR: insufficient privilege\n"), stderr);
+ _exit (EXIT_FAILURE);
+ return -1; /* for Mac OSX compiler */
+ }
+ if (0 == strcmp(db_file, _("default")))
+ db_file = file_path('D', 'W');
+ if (!db_file)
+ {
+ fputs(_("ERROR: no filename\n"), stderr);
+ _exit(EXIT_FAILURE);
+ return -1;
+ }
+
+ if (ListFilter)
+ read_filter();
+
+ line = SH_ALLOC(MAX_PATH_STORE+2);
+
+ if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, db_file, SL_YESPRIV)))
+ {
+ fprintf(stderr, _("ERROR: can't open %s for read (errnum = %ld)\n"),
+ db_file, fd);
+ _exit(EXIT_FAILURE);
+ return -1;
+ }
+
+ /* fast forward to start of data
+ */
+ if (0 != sh_dbIO_setdataent(fd, line, MAX_PATH_STORE+1, db_file))
+ {
+ fprintf(stderr, _("ERROR: can't find start marker in %s\n"),
+ db_file);
+ _exit(EXIT_FAILURE);
+ return -1;
+ }
+
+ while (1)
+ {
+ p = sh_dbIO_getdataent (line, MAX_PATH_STORE+1, db_file, &errflag);
+ if ((p != NULL) && (p->fullpath[0] == '/'))
+ {
+ if (!ListFile)
+ {
+ flag = 1;
+ if (ListFilter && S_FALSE == check_filter(p->fullpath))
+ continue;
+ if (ListBinary)
+ dbIO_write_entry (p);
+ else
+ sh_hash_list_db_entry (p);
+ }
+ else
+ {
+ if (0 != sl_strcmp(ListFile, p->fullpath))
+ {
+ continue;
+ }
+ flag = 1;
+ if ('l' != p->theFile.c_mode[0])
+ {
+ if (sh_hash_printcontent(p->linkpath) < 0)
+ {
+ fputs(_("Error listing file content\n"), stderr);
+ _exit(EXIT_FAILURE);
+ return -1;
+ }
+ }
+ else
+ {
+ fputs(_("File is a link\n"), stderr);
+ _exit(EXIT_FAILURE);
+ return -1;
+ }
+ break;
+ }
+ }
+ else if (p == NULL)
+ {
+ break;
+ }
+ }
+
+ if (line != NULL)
+ SH_FREE(line);
+ sl_close (fd);
+
+ fflush(NULL);
+
+ if (flag == 0)
+ {
+ fputs(_("File not found.\n"), stderr);
+ _exit(EXIT_FAILURE);
+ }
+ else if (errflag < 0)
+ {
+ fputs(_("Error while reading file.\n"), stderr);
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ return 0;
+}
+
+/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
+#endif
diff --git a/src/sh_entropy.c b/src/sh_entropy.c
new file mode 100644
index 0000000..bf2a3ee
--- /dev/null
+++ b/src/sh_entropy.c
@@ -0,0 +1,1055 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/types.h>
+
+
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_tiger.h"
+#include "sh_calls.h"
+
+#undef FIL__
+#define FIL__ _("sh_entropy.c")
+
+#if defined (HAVE_EGD_RANDOM)
+/* rndegd.c - interface to the EGD
+ * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ */
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+static int
+do_write( int fd, void *buf, size_t nbytes )
+{
+ size_t nleft = nbytes;
+ int nwritten;
+
+ while( nleft > 0 ) {
+ nwritten = write( fd, buf, nleft);
+ if( nwritten < 0 ) {
+ if( errno == EINTR )
+ continue;
+ return -1;
+ }
+ nleft -= nwritten;
+ buf = (char*)buf + nwritten;
+ }
+ return 0;
+}
+
+static int
+do_read( int fd, void *buf, int nbytes )
+{
+ int n, nread = 0;
+
+ if (nbytes < 0)
+ return 0;
+
+ do {
+ do {
+ n = read(fd, (char*)buf + nread, nbytes );
+ } while( n == -1 && errno == EINTR );
+ if( n == -1 )
+ return -1;
+ nread += n;
+ } while( nread < nbytes );
+ return nbytes;
+}
+
+
+int sh_entropy(int getbytes, char * nbuf)
+{
+ int fd = -1;
+ int n;
+ byte buffer[256+2];
+ int nbytes;
+ int do_restart = 0;
+ int myerror = 0;
+ int length;
+ char * p = nbuf;
+ int i;
+
+ SL_ENTER(_("sh_entropy"));
+
+ if( getbytes <= 0)
+ SL_RETURN( -1, _("sh_entropy"));
+ if (getbytes > KEY_BYT)
+ getbytes = KEY_BYT;
+ length = getbytes;
+
+ restart:
+ if( do_restart ) {
+ if( fd != -1 ) {
+ sl_close_fd(FIL__, __LINE__, fd );
+ fd = -1;
+ }
+ }
+ if( fd == -1 ) {
+ const char *bname = NULL;
+ char *name;
+ struct sockaddr_un addr;
+ int addr_len;
+ int retval;
+
+#ifdef EGD_SOCKET_NAME
+ bname = EGD_SOCKET_NAME;
+#endif
+ if ( !bname || !*bname )
+ bname = _("=entropy");
+
+ if ( *bname == '=' && bname[1] )
+ name = sh_util_strconcat ( DEFAULT_DATAROOT, "/", bname+1 , NULL );
+ else
+ name = sh_util_strconcat ( bname , NULL );
+
+ if ( strlen(name)+1 >= sizeof(addr.sun_path) )
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, ENAMETOOLONG, MSG_E_SUBGEN,
+ _("EGD socketname is too long"),
+ _("sh_entropy") );
+ SH_FREE(name);
+ SL_RETURN( -1, _("sh_entropy") );
+ }
+
+ memset( &addr, 0, sizeof(addr) );
+ addr.sun_family = AF_UNIX;
+ sl_strlcpy( addr.sun_path, name, sizeof(addr.sun_path) );
+ addr_len = offsetof( struct sockaddr_un, sun_path )
+ + strlen( addr.sun_path );
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if( fd == -1 )
+ {
+ myerror = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
+ _("cannot create unix domain socket"),
+ _("sh_entropy") );
+ SH_FREE(name);
+ SL_RETURN( -1, _("sh_entropy") );
+ }
+ do {
+ retval = connect(fd, (struct sockaddr *) &sinr, sizeof(sinr));
+ } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
+ if( retval == -1 )
+ {
+ myerror = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
+ _("cannot connect to unix domain socket"),
+ _("sh_entropy") );
+ SH_FREE(name);
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_RETURN( -1, _("sh_entropy") );
+ }
+ SH_FREE(name);
+ }
+ do_restart = 0;
+
+ nbytes = length < 255? length : 255;
+ /* first time we do it with a non blocking request */
+ buffer[0] = 1; /* non blocking */
+ buffer[1] = nbytes;
+ if( do_write( fd, buffer, 2 ) == -1 )
+ {
+ myerror = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
+ _("cannot write to EGD"),
+ _("sh_entropy") );
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_RETURN( -1, _("sh_entropy") );
+ }
+ n = do_read( fd, buffer, 1 );
+ if( n == -1 ) {
+ myerror = errno;
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror, MSG_E_SUBGEN,
+ _("read error on EGD"),
+ _("sh_entropy") );
+ do_restart = 1;
+ goto restart;
+ }
+ n = buffer[0];
+ if( n ) {
+ n = do_read( fd, buffer, n );
+ if( n == -1 ) {
+ myerror = errno;
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror,MSG_E_SUBGEN,
+ _("read error on EGD"),
+ _("sh_entropy") );
+ do_restart = 1;
+ goto restart;
+ }
+ for (i = 0; i < n; ++i)
+ {
+ if (getbytes >= 0)
+ { *p = buffer[i]; ++p; --getbytes; }
+ }
+ length -= n;
+ }
+
+ while( length ) {
+ nbytes = length < 255? length : 255;
+
+ buffer[0] = 2; /* blocking */
+ buffer[1] = nbytes;
+ if( do_write( fd, buffer, 2 ) == -1 )
+ {
+ myerror = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, myerror, MSG_E_SUBGEN,
+ _("cannot write to EGD"),
+ _("sh_entropy") );
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_RETURN( -1, _("sh_entropy") );
+ }
+ n = do_read( fd, buffer, nbytes );
+ if( n == -1 ) {
+ myerror = errno;
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, myerror,MSG_E_SUBGEN,
+ _("read error on EGD"),
+ _("sh_entropy") );
+ do_restart = 1;
+ goto restart;
+ }
+ for (i = 0; i < n; ++i)
+ {
+ if (getbytes >= 0)
+ { *p = buffer[i]; ++p; --getbytes; }
+ }
+ length -= n;
+ }
+ memset(buffer, 0, sizeof(buffer) );
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_RETURN( 0, _("sh_entropy") ); /* success */
+}
+
+/* HAVE_EGD_RANDOM */
+#endif
+
+#if defined (HAVE_URANDOM)
+
+#include "sh_pthread.h"
+
+int read_mbytes(int timeout_val, const char * path, char * nbuf, int nbytes)
+{
+ int m_count;
+ int fd2;
+
+ SL_ENTER(_("read_mbytes"));
+
+ if ((fd2 = aud_open (FIL__, __LINE__, SL_NOPRIV, path, O_RDONLY, 0)) >= 0)
+ {
+ /* Test whether file is a character device, and is
+ * readable.
+ */
+ if (0 == sh_unix_device_readable(fd2))
+ {
+ m_count = sl_read_timeout_fd(fd2, nbuf, nbytes,
+ timeout_val, S_FALSE);
+ if (m_count < 0)
+ m_count = 0;
+ }
+ else
+ m_count = 0;
+ }
+ else
+ m_count = 0;
+
+ sl_close_fd(FIL__, __LINE__, fd2);
+
+ TPT((0, FIL__, __LINE__, _("msg=<read_mbytes: OK>\n")));
+ SL_RETURN(m_count, _("read_mbytes"));
+}
+
+/* Read nbytes bytes from /dev/random, mix them with
+ * previous reads using a hash function, and give out
+ * nbytes bytes from the result.
+ */
+int sh_entropy(int nbytes, char * nbuf)
+{
+ int i, m_count = 0;
+ char * keybuf;
+ UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
+ char addbuf[2 * KEY_BYT];
+
+ SL_ENTER(_("sh_entropy"));
+
+ ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
+
+ if (nbytes > KEY_BYT)
+ nbytes = KEY_BYT;
+
+ memset(nbuf, '\0', nbytes);
+
+#ifdef NAME_OF_DEV_URANDOM
+ m_count = read_mbytes ( 10, NAME_OF_DEV_URANDOM, nbuf, nbytes);
+#else
+ m_count = read_mbytes (300, NAME_OF_DEV_RANDOM, nbuf, nbytes);
+#endif
+
+ if (m_count == 0)
+ {
+#ifdef NAME_OF_DEV_URANDOM
+ sh_error_handle (SH_ERR_NOTICE, FIL__, __LINE__, EIO, MSG_NODEV,
+ (long) sh.real.uid, NAME_OF_DEV_URANDOM);
+#else
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_NODEV,
+ (long) sh.real.uid, NAME_OF_DEV_RANDOM);
+#endif
+ }
+
+#ifdef NAME_OF_DEV_RANDOM
+ if (m_count < nbytes)
+ {
+ i = read_mbytes(300, NAME_OF_DEV_RANDOM, &nbuf[m_count], nbytes-m_count);
+ if (i == 0)
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_NODEV,
+ (long) sh.real.uid, NAME_OF_DEV_RANDOM);
+ else
+ m_count += i;
+ }
+#endif
+
+
+ if (m_count > 0)
+ {
+ /* -- Add previous entropy into the new pool. --
+ */
+ memset(addbuf, '\0', sizeof(addbuf));
+ for (i = 0; i < m_count; ++i)
+ addbuf[i] = nbuf[i];
+ for (i = 0; i < KEY_BYT; ++i)
+ addbuf[i+KEY_BYT] = skey->poolv[i];
+ keybuf = (char *) sh_tiger_hash_uint32 (addbuf,
+ TIGER_DATA, 2 * KEY_BYT,
+ kbuf, KEY_BYT/sizeof(UINT32));
+ memset(addbuf, '\0', sizeof(addbuf));
+
+ /* -- Give out nbytes bytes from the new pool. --
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ for (i = 0; i < KEY_BYT; ++i)
+ {
+ skey->poolv[i] = keybuf[i];
+ if (i < nbytes)
+ nbuf[i] = keybuf[i];
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ memset (keybuf, '\0', KEY_BYT);
+ memset (kbuf, '\0', sizeof(kbuf));
+
+ SL_RETURN(0, _("sh_entropy"));
+ }
+ else
+ {
+ SL_RETURN((-1), _("sh_entropy"));
+ }
+}
+
+/* HAVE_URANDOM */
+#endif
+
+#ifdef HAVE_UNIX_RANDOM
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+#include "sh_static.h"
+#include "sh_pthread.h"
+
+static
+char * com_path[] = {
+ N_("/usr/bin/xpg4/"),
+ N_("/usr/ucb/"),
+ N_("/bin/"),
+ N_("/sbin/"),
+ N_("/usr/bin/"),
+ N_("/usr/sbin/"),
+ N_("/usr/local/bin/"),
+ N_("/opt/local/bin/"),
+ NULL
+};
+
+
+typedef struct {
+ char * command;
+ char * arg;
+ int pipeFD;
+ pid_t pid;
+ int isset;
+ FILE * pipe;
+} sourcetable_t;
+
+static
+sourcetable_t source_template[] = {
+ { N_("w"),
+ N_("w"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("netstat"),
+ N_("netstat -n"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("ps"),
+ N_("ps -ef"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("arp"),
+ N_("arp -a"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("free"),
+ N_("free"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("uptime"),
+ N_("uptime"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("procinfo"),
+ N_("procinfo -a"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("vmstat"),
+ N_("vmstat"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { N_("w"), /* Play it again, Sam. */
+ N_("w"),
+ 0,
+ 0,
+ 0,
+ NULL },
+ { NULL,
+ NULL,
+ 0,
+ 0,
+ 0,
+ NULL }
+};
+
+
+static FILE * sh_popen (sourcetable_t *source, char * command)
+{
+ int i;
+ int pipedes[2];
+ FILE *outf = NULL;
+ char * arg[4];
+ char * envp[2];
+ size_t len;
+ char arg0[80];
+ char arg1[80];
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+ struct passwd * tempres;
+#else
+ struct passwd * tempres;
+#endif
+
+ SL_ENTER(_("sh_popen"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ tempres = sh_getpwnam(DEFAULT_IDENT);
+#endif
+
+ strncpy (arg0, _("/bin/sh"), sizeof(arg0));
+ arg[0] = arg0;
+ strncpy (arg1, _("-c"), sizeof(arg1));
+ arg[1] = arg1;
+ arg[2] = command;
+ arg[3] = NULL;
+
+ if (sh.timezone != NULL)
+ {
+ len = sl_strlen(sh.timezone) + 4;
+ envp[0] = calloc(1, len); /* free() ok */
+ if (envp[0] != NULL)
+ sl_snprintf (envp[0], len, "TZ=%s", sh.timezone);
+ else
+ envp[0] = NULL;
+ envp[1] = NULL;
+ }
+ else
+ {
+ envp[0] = NULL;
+ }
+
+
+ /* Create the pipe
+ */
+ if (aud_pipe(FIL__, __LINE__, pipedes) < 0) {
+ if (envp[0] != NULL) free(envp[0]);
+ SL_RETURN(NULL, _("sh_popen"));
+ }
+
+ fflush (NULL);
+
+ source->pid = aud_fork(FIL__, __LINE__);
+
+ /* Failure
+ */
+ if (source->pid == (pid_t) - 1) {
+ sl_close_fd(FIL__, __LINE__, pipedes[0]);
+ sl_close_fd(FIL__, __LINE__, pipedes[1]);
+ if (envp[0] != NULL) free(envp[0]);
+ SL_RETURN(NULL, _("sh_popen"));
+ }
+
+ if (source->pid == (pid_t) 0)
+ {
+ int val_return;
+
+ /* child - make read side of the pipe stdout
+ */
+ do {
+ val_return = dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO);
+ } while (val_return < 0 && errno == EINTR);
+
+ if (val_return < 0)
+ _exit(EXIT_FAILURE);
+
+ /* close the pipe descriptors
+ */
+ sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
+ sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+
+ /* don't leak file descriptors
+ */
+ sh_unix_closeall (3, -1, S_TRUE); /* in child process */
+
+ /* zero priv info
+ */
+ memset(skey, 0, sizeof(sh_key_t));
+
+ /* drop root privileges
+ */
+ i = 0;
+ if (0 == geteuid())
+ {
+
+ if (NULL != tempres) {
+ i = setgid(tempres->pw_gid);
+
+ /*** locks up in dnmalloc ***/
+ /*
+ * if (i == 0)
+ * i = sh_unix_initgroups(DEFAULT_IDENT ,tempres->pw_gid);
+ */
+
+ if (i == 0)
+ i = setuid(tempres->pw_uid);
+ /* make sure we cannot get root again
+ */
+ if ((tempres->pw_uid != 0) &&
+ (setuid(0) >= 0))
+ i = -1;
+ } else {
+ i = -1;
+ }
+ }
+
+ /* some problem ...
+ */
+ if (i == -1) {
+ _exit(EXIT_FAILURE);
+ }
+
+ /* cppcheck-suppress leakNoVarFunctionCall */
+ if (NULL != freopen (_("/dev/null"), "r+", stderr))
+ {
+
+ /* exec the program */
+ do {
+ val_return = execve (_("/bin/sh"), arg, envp);
+ } while (val_return < 0 && errno == EINTR);
+ }
+
+ /* failed
+ */
+ _exit(EXIT_FAILURE);
+ }
+
+ /* parent
+ */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+
+ if (envp[0] != NULL)
+ free(envp[0]);
+
+ sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+ retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
+
+ outf = fdopen (pipedes[STDIN_FILENO], "r");
+
+ if (outf == NULL)
+ {
+ aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
+ sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+ waitpid (source->pid, NULL, 0);
+ source->pid = 0;
+ SL_RETURN(NULL, _("sh_popen"));
+ }
+
+ SL_RETURN(outf, _("sh_popen"));
+}
+
+
+static int sh_pclose (sourcetable_t *source)
+{
+ int status = 0;
+ int retval;
+ char msg[128];
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_pclose"));
+
+ retval = sl_fclose(FIL__, __LINE__, source->pipe);
+ if (retval)
+ {
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
+ MSG_E_SUBGEN,
+ sh_error_message(retval, errbuf, sizeof(errbuf)),
+ _("sh_pclose"));
+ SL_RETURN((-1), _("sh_pclose"));
+ }
+
+ retval = waitpid(source->pid, &status, 0);
+ if (retval != source->pid)
+ {
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
+ MSG_E_SUBGEN,
+ sh_error_message(retval, errbuf, sizeof(errbuf)),
+ _("sh_pclose"));
+
+ status = -1;
+ }
+#if !defined(USE_UNO)
+ else if (WIFSIGNALED(status))
+ {
+ sl_snprintf(msg, sizeof(msg), _("Subprocess terminated by signal %d"),
+ WTERMSIG(status));
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, retval,
+ MSG_E_SUBGEN,
+ msg,
+ _("sh_pclose"));
+ status = -1;
+ }
+#endif
+
+ source->pipe = NULL;
+ source->pid = 0;
+ SL_RETURN(status, _("sh_pclose"));
+}
+
+#define BUF_ENT 32766
+
+/* Poll the system for randomness, mix results with
+ * previous reads using a hash function, and give out
+ * nbytes bytes from the result.
+ */
+int sh_entropy(int nbytes, char * nbuf)
+{
+ int caperr;
+ char combuf[80];
+ char * buffer;
+ int i, j, icount;
+ int bufcount = 0;
+ int count;
+
+ char * keybuf;
+ UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
+ char addbuf[2 * KEY_BYT];
+
+ struct timeval tv;
+ fd_set fds;
+ unsigned long select_now = 0;
+ int maxFD = 0;
+ int imax, selcount;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ sourcetable_t *source = NULL;
+
+ SL_ENTER(_("sh_entropy"));
+
+ ASSERT((nbytes <= KEY_BYT), _("nbytes <= KEY_BYT"))
+
+ if (nbytes > KEY_BYT)
+ nbytes = KEY_BYT;
+
+
+ /* --- If there is entropy in the pool, return it. ---
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ if (skey->poolc >= nbytes)
+ {
+ j = KEY_BYT - skey->poolc;
+ for (i = 0; i < nbytes; ++i)
+ {
+ nbuf[i] = skey->poolv[i+j];
+ --skey->poolc;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */
+ SL_RETURN(0, _("sh_entropy"));
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+
+
+ FD_ZERO(&fds);
+
+ i = 0; icount = 0;
+ buffer = SH_ALLOC(BUF_ENT+2);
+
+ if (0 != (caperr = sl_get_cap_sub()))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_get_cap_sub"));
+ }
+
+ while (source_template[i].command != NULL) {
+ ++i;
+ }
+ source = SH_ALLOC(i * sizeof(sourcetable_t));
+ for (j = 0; j < i;++j)
+ memcpy(&source[j], &source_template[j], sizeof(sourcetable_t));
+ i = 0;
+
+ while (source_template[i].command != NULL) {
+
+ j = 0;
+ while (com_path[j] != NULL)
+ {
+ sl_strlcpy(combuf, _(com_path[j]), 80);
+ sl_strlcat(combuf, _(source[i].command), 80);
+
+ /* flawfinder: ignore */
+ if ( access (combuf, X_OK) == 0)
+ {
+ sl_strlcpy(combuf, _(com_path[j]), 80);
+ sl_strlcat(combuf, _(source[i].arg), 80);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENSTART,
+ combuf);
+ break;
+ }
+ ++j;
+ }
+
+ /* Not found, try next command.
+ */
+ if (com_path[j] == NULL)
+ {
+ ++i;
+ continue;
+ }
+
+ /* Source exists
+ */
+ source[i].pipe = sh_popen ( &source[i], combuf );
+ if (NULL != source[i].pipe)
+ {
+ source[i].pipeFD = fileno ( source[i].pipe );
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENEXEC,
+ combuf, (long) source[i].pipeFD);
+
+ maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
+ retry_fcntl( FIL__, __LINE__, source[i].pipeFD, F_SETFL, O_NONBLOCK);
+ FD_SET( source[i].pipeFD, &fds );
+ source[i].isset = 1;
+ ++icount;
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENFAIL,
+ combuf);
+ }
+
+ ++i;
+ }
+
+ imax = i;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ bufcount = 0;
+
+ while ( (icount > 0) && (bufcount < BUF_ENT) ) {
+
+ if ( (selcount = select (maxFD+1, &fds, NULL, NULL, &tv)) == -1)
+ break;
+
+ /* reset timeout for select()
+ */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ /* timeout - let's not hang on forever
+ */
+ if (selcount == 0)
+ {
+ ++select_now;
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENTOUT,
+ (unsigned long) select_now);
+ if ( select_now > 9 )
+ break;
+ }
+
+ for (i = 0; i < imax; ++i) {
+
+ if ( FD_ISSET (source[i].pipeFD, &fds) ) {
+ count = fread (&buffer[bufcount],
+ 1,
+ BUF_ENT-bufcount,
+ source[i].pipe );
+ if (count == 0)
+ {
+ if (0 != feof(source[i].pipe))
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS,
+ (long) source[i].pipeFD);
+ else
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_ENCLOS1,
+ (long) source[i].pipeFD);
+ source[i].isset = 0;
+ sh_pclose ( &source[i] );
+ --icount;
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENREAD,
+ (long) source[i].pipeFD, (long) count);
+ }
+ bufcount += count;
+
+ }
+ }
+
+ maxFD = 0;
+ FD_ZERO(&fds);
+
+ for (i = 0; i < imax; ++i)
+ {
+ if (source[i].isset == 1)
+ {
+ FD_SET( source[i].pipeFD, &fds );
+ maxFD = (source[i].pipeFD > maxFD) ? source[i].pipeFD : maxFD;
+ }
+ }
+ }
+
+ for (i = 0; i < imax; ++i)
+ {
+ if (source[i].isset == 1)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_ENCLOS1,
+ (long) source[i].pipeFD);
+ sh_pclose ( &source[i] );
+ }
+ }
+ buffer[bufcount] = '\0';
+
+ SH_FREE(source);
+
+ if (0 != (caperr = sl_drop_cap_sub()))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_drop_cap_sub"));
+ }
+
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ unsigned short tseed[3];
+
+ gettimeofday(&tv, 0);
+ tseed[0] = tv.tv_sec & 0xFFFF;
+ tseed[1] = tv.tv_usec & 0xFFFF;
+ tseed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
+ keybuf = (char *) sh_tiger_hash_uint32 ((char *) tseed,
+ TIGER_DATA, sizeof(tseed),
+ kbuf, KEY_BYT/sizeof(UINT32));
+ memset(addbuf, '\0', sizeof(addbuf));
+ for (i = 0; i < KEY_BYT; ++i)
+ {
+ addbuf[i] = keybuf[i];
+ addbuf[i+KEY_BYT] = skey->poolv[i];
+ }
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ for (i = 0; i < KEY_BYT; ++i)
+ skey->poolv[i] ^= keybuf[i];
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+#endif
+
+ if (bufcount > 0)
+ {
+ keybuf = (char *) sh_tiger_hash_uint32 (buffer,
+ TIGER_DATA, sl_strlen(buffer),
+ kbuf, KEY_BYT/sizeof(UINT32));
+
+ /* add previous entropy into the new pool
+ */
+ memset(addbuf, '\0', sizeof(addbuf));
+ for (i = 0; i < KEY_BYT; ++i)
+ {
+ addbuf[i] = keybuf[i];
+ addbuf[i+KEY_BYT] = skey->poolv[i];
+ }
+ keybuf = (char *) sh_tiger_hash_uint32 (addbuf,
+ TIGER_DATA, sizeof(addbuf),
+ kbuf, KEY_BYT/sizeof(UINT32));
+ memset(addbuf, '\0', sizeof(addbuf));
+
+ /* store in system pool
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ for (i = 0; i < KEY_BYT; ++i)
+ skey->poolv[i] = keybuf[i];
+ skey->poolc = KEY_BYT;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ memset (buffer, '\0', BUF_ENT+2);
+ memset (keybuf, '\0', KEY_BYT);
+ SH_FREE(buffer);
+ }
+ else
+ {
+ SH_FREE(buffer);
+ SL_RETURN((-1), _("sh_entropy"));
+ }
+
+ /* give out nbytes Bytes from the entropy pool
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ for (i = 0; i < nbytes; ++i)
+ {
+ nbuf[i] = skey->poolv[i];
+ --skey->poolc;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+
+ SL_RETURN(0, _("sh_entropy"));
+}
+
+/* HAVE_UNIX_RANDOM */
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_entropy (CuTest *tc)
+{
+ char bufx[9 * sizeof(UINT32) + 1];
+ char bufy[9 * sizeof(UINT32) + 1];
+ int status;
+ int count;
+
+ for (count = 0; count < 20; ++count)
+ {
+ memset(skey->poolv, '\0', KEY_BYT);
+ skey->poolc = 0;
+
+ status = sh_entropy (24, bufx);
+ CuAssertTrue(tc, 0 == status);
+
+ memset(skey->poolv, '\0', KEY_BYT);
+ skey->poolc = 0;
+
+ status = sh_entropy (24, bufy);
+ CuAssertTrue(tc, 0 == status);
+
+ CuAssertTrue(tc, 0 != memcmp(bufx, bufy, 24));
+ }
+}
+#endif
+
+
+
+
+
+
+
+
diff --git a/src/sh_err_console.c b/src/sh_err_console.c
new file mode 100644
index 0000000..c3a8269
--- /dev/null
+++ b/src/sh_err_console.c
@@ -0,0 +1,378 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_sem.h"
+
+#undef FIL__
+#define FIL__ _("sh_err_console.c")
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+extern int OnlyStderr;
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+#if defined(WITH_MESSAGE_QUEUE)
+
+#if defined(HAVE_SYS_MSG_H)
+
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#if !defined(EIDRM)
+#define EIDRM (EINVAL)
+#endif
+
+struct sh_msgbuf {
+ long mtype;
+ char mtext[1]; /* <-- sizeof(mtext) will be 1+MY_MAX_MSG */
+};
+
+static int msgq_enabled = S_FALSE;
+
+/* The identifier of the message queue
+ */
+static int msgid = -1;
+
+/* Open the SysV message queue, creating it when neccesary
+ */
+static int open_queue(void)
+{
+ key_t key;
+#if defined(WITH_TPT)
+ char errbuf[SH_ERRBUF_SIZE];
+#endif
+
+ SL_ENTER(_("open_queue"));
+
+ /* get key
+ */
+ key = ftok (DEFAULT_DATAROOT, '#');
+
+ if (key == (key_t) -1)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ftok: %s> errno=<%d>\n"),
+ sh_error_message(errno, errbuf, sizeof(errbuf)), errno));
+ SL_RETURN(-1, _("open_queue"));
+ }
+
+ /* get message identifier
+ */
+ msgid = msgget (key, IPC_CREAT|MESSAGE_QUEUE_MODE);
+
+ if (msgid < 0)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<msgget: %s> errno=<%d>\n"),
+ sh_error_message(errno, errbuf, sizeof(errbuf)), errno));
+ SL_RETURN(-1, _("open_queue"));
+ }
+
+ SL_RETURN(0, _("open_queue"));
+}
+
+/* Close the SysV message queue and/or semaphore
+ */
+void close_ipc (void)
+{
+ if (msgid != (-1))
+ (void) msgctl (msgid, IPC_RMID, NULL);
+ sh_sem_close();
+ return;
+}
+
+/* Enable the message queue
+ */
+int enable_msgq(const char * foo)
+{
+ int i;
+
+ SL_ENTER(_("enable_msgq"));
+ i = sh_util_flagval(foo, &msgq_enabled);
+ SL_RETURN(i, _("enable_msgq"));
+}
+
+#define MY_MAX_MSG 1022
+
+static void remove_message()
+{
+ int rc;
+ struct {
+ long mtype; /* Message type. */
+ char mtext[128]; /* Message text. */
+ } recv_msg;
+
+ recv_msg.mtype = 1;
+ do {
+ rc = msgrcv(msgid, &recv_msg, sizeof(recv_msg.mtext), 1,
+ MSG_NOERROR|IPC_NOWAIT);
+ } while (rc < 0 && errno == EINTR);
+
+ memset(&recv_msg, '\0', sizeof(recv_msg));
+ return;
+}
+
+static int push_message_queue (const char * msg)
+{
+ struct sh_msgbuf* recv_msg = NULL;
+ int rc = -1;
+ static int status = -1;
+ int count = 0;
+#if defined(WITH_TPT)
+ char errbuf[SH_ERRBUF_SIZE];
+#endif
+
+ SL_ENTER(_("push_message_queue"));
+
+ if (msgq_enabled == -1)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<msg_queue not enabled>\n")));
+ SL_RETURN(0, _("push_message_queue"));
+ }
+
+ if (status < 0)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<msg_queue not open>\n")));
+ status = open_queue();
+ }
+
+ if (status < 0)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<open_queue() failed>\n")));
+ SL_RETURN(-1, _("push_message_queue"));
+ }
+
+ /* struct msgbuf {
+ * long mtype;
+ * char mtext[1]; <-- sizeof(mtext) will be 1+MY_MAX_MSG
+ * } */
+
+ recv_msg = (struct sh_msgbuf*) SH_ALLOC(sizeof(struct sh_msgbuf)+MY_MAX_MSG);
+ recv_msg->mtype = 1;
+ sl_strlcpy (recv_msg->mtext, msg, MY_MAX_MSG+1);
+
+ count = 0;
+
+ send_it:
+
+ if (count > 1)
+ {
+ memset(recv_msg, '\0', MY_MAX_MSG+1);
+ SH_FREE(recv_msg);
+ SL_RETURN(-1, _("push_message_queue"));
+ }
+
+ do { errno = 0;
+ rc = msgsnd(msgid, recv_msg, strlen(recv_msg->mtext)+1, IPC_NOWAIT);
+
+ if (rc == -1 && errno == EAGAIN)
+ remove_message();
+ } while (rc < 0 && (errno == EINTR && errno == EAGAIN));
+
+ if (rc == -1 && errno != EAGAIN)
+ {
+ /* EIDRM is not in OpenBSD */
+ if (errno == EINVAL || errno == EIDRM) {
+ TPT(( 0, FIL__, __LINE__, _("msg=<msg_queue not open>\n")));
+ status = open_queue();
+ if (status == 0) {
+ ++count;
+ goto send_it; }
+ } else {
+ TPT(( 0, FIL__, __LINE__, _("msg=<msgsnd: %s> errno=<%d>\n"),
+ sh_error_message(errno, errbuf, sizeof(errbuf)), errno));
+ memset(recv_msg, '\0', MY_MAX_MSG+1);
+ SH_FREE(recv_msg);
+ SL_RETURN(-1, _("push_message_queue"));
+ }
+ }
+
+ memset(recv_msg, '\0', MY_MAX_MSG+1);
+ SH_FREE(recv_msg);
+
+ SL_RETURN(0, _("push_message_queue"));
+}
+/* if defined(HAVE_SYS_MSG_H) */
+#else
+
+#error **********************************************
+#error
+#error The sys/msg.h header was not found,
+#error cannot compile with --enable-message-queue
+#error
+#error **********************************************
+
+#endif
+
+#else /* no message queue */
+
+void close_ipc() { sh_sem_close(); return; }
+
+#endif
+
+static int count_dev_console = 0;
+
+void reset_count_dev_console(void)
+{
+ count_dev_console = 0;
+ return;
+}
+
+/* ---- Set the console device. ----
+ */
+int sh_log_set_console (const char * address)
+{
+ SL_ENTER(_("sh_log_set_console"));
+ if (address != NULL && count_dev_console < 2
+ && sl_strlen(address) < SH_PATHBUF)
+ {
+ if (count_dev_console == 0)
+ (void) sl_strlcpy (sh.srvcons.name, address, SH_PATHBUF);
+ else
+ (void) sl_strlcpy (sh.srvcons.alt, address, SH_PATHBUF);
+
+ ++count_dev_console;
+ SL_RETURN(0, _("sh_log_set_console"));
+ }
+ SL_RETURN((-1), _("sh_log_set_console"));
+}
+
+#if defined(WITH_TRACE) || defined(WITH_TPT)
+char * sh_log_console_name (void)
+{
+ if (sh.srvcons.name[0] == '\0' ||
+ 0 == strcmp(sh.srvcons.name, _("NULL")))
+ return (_("/dev/console"));
+ return sh.srvcons.name;
+}
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+/* ---- Print out a message. ----
+ */
+int sh_log_console (const /*@null@*/char *errmsg)
+{
+ static int service_failure[2] = { 0, 0};
+ int fd[2] = { -1, -1};
+ int cc;
+ size_t len;
+ int ccMax = 1;
+ int retval = -1;
+ /* static int logkey_seen = 0; */
+ int error;
+ static int blockMe = 0;
+ int val_return;
+
+ SL_ENTER(_("sh_log_console"));
+
+ if (errmsg == NULL || blockMe == 1)
+ {
+ SL_RETURN(0, _("sh_log_console"));
+ }
+ else
+ blockMe = 1;
+
+
+#ifdef WITH_MESSAGE_QUEUE
+ if (0 != push_message_queue (errmsg))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<push_message_queue() failed>\n")));
+ }
+#endif
+
+ if (sh.flag.isdaemon == S_FALSE || OnlyStderr == S_TRUE)
+ {
+ len = strlen(errmsg);
+ do {
+ val_return = write(STDERR_FILENO, errmsg, len);
+ } while (val_return < 0 && errno == EINTR);
+ do {
+ val_return = write(STDERR_FILENO, "\n", 1);
+ } while (val_return < 0 && errno == EINTR);
+ /*
+ * fprintf (stderr, "%s\n", errmsg);
+ */
+ blockMe = 0;
+ SL_RETURN(0, _("sh_log_console"));
+ }
+
+ /* --- daemon && initialized ---
+ */
+ if ( OnlyStderr == S_FALSE )
+ {
+ fd[0] = open ( sh.srvcons.name, O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK);
+
+ if (sh.srvcons.alt[0] != '\0')
+ {
+ fd[1] = open (sh.srvcons.alt, O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK);
+ ccMax = 2;
+ }
+
+ for (cc = 0; cc < ccMax; ++cc)
+ {
+
+ if (fd[cc] < 0 && service_failure[cc] == 0)
+ {
+ error = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, error, MSG_SRV_FAIL,
+ _("console"),
+ (cc == 0) ? sh.srvcons.name : sh.srvcons.alt);
+ service_failure[cc] = 1;
+ }
+
+ if (fd[cc] >= 0)
+ {
+ do {
+ val_return = write(fd[cc], errmsg, strlen(errmsg));
+ } while (val_return < 0 && errno == EINTR);
+ do {
+ val_return = write(fd[cc], "\r\n", 2);
+ } while (val_return < 0 && errno == EINTR);
+ (void) sl_close_fd(FIL__, __LINE__, fd[cc]);
+ service_failure[cc] = 0;
+ }
+ }
+ }
+ else
+ retval = 0;
+
+ blockMe = 0;
+ SL_RETURN(retval, _("sh_log_console"));
+}
+
+
diff --git a/src/sh_err_log.c b/src/sh_err_log.c
new file mode 100644
index 0000000..da6ed06
--- /dev/null
+++ b/src/sh_err_log.c
@@ -0,0 +1,1332 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_tiger.h"
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+
+#undef FIL__
+#define FIL__ _("sh_err_log.c")
+
+#undef FIX_XML
+#define FIX_XML 1
+
+#define MYSIGLEN (2*KEY_LEN + 32)
+
+typedef struct _sh_log_buf {
+ char signature[KEY_LEN+1];
+ char timestamp[KEY_LEN+1];
+#ifdef SH_USE_XML
+ char sig[MYSIGLEN];
+#endif
+ char * msg;
+} sh_sh_log_buf;
+
+extern struct _errFlags errFlags;
+
+#define CHK_KEY 0
+#define CHK_FIL 1
+#define CHK_NON 2
+
+static int get_key_from_file(char * path, char * keyid, char * key)
+{
+ SL_TICKET fd;
+ char * buf;
+ char * bufc;
+
+ if (path[strlen(path)-1] == '\n')
+ path[strlen(path)-1] = '\0';
+
+ /* open the file, then check it
+ */
+ if ( SL_ISERROR(fd = sl_open_read (FIL__, __LINE__, path, SL_NOPRIV)))
+ {
+ fprintf(stderr, _("Could not open file <%s>\n"), path);
+ _exit (EXIT_FAILURE);
+ }
+
+ buf = SH_ALLOC( (size_t)(SH_BUFSIZE+1));
+ bufc = SH_ALLOC( (size_t)(SH_MAXBUF+1));
+
+ while (1 == 1)
+ {
+ buf[0] = '\0';
+ bufc[0] = '\0';
+
+ /* find start of next key
+ */
+ while (0 != sl_strncmp(buf, _("-----BEGIN LOGKEY-----"),
+ sizeof("-----BEGIN LOGKEY-----")-1))
+ {
+ (void) sh_unix_getline (fd, buf, SH_BUFSIZE);
+ if (buf[0] == '\0')
+ {
+ /* End of file reached, return.
+ */
+ (void) fflush(stdout);
+ (void) sl_close(fd);
+ return -1;
+ }
+ }
+
+ /* read key
+ */
+ (void) sh_unix_getline (fd, buf, SH_BUFSIZE);
+
+ if (0 == sl_strncmp(keyid, &buf[KEY_LEN], strlen(keyid)))
+ {
+ (void) sl_strlcpy(key, buf, KEY_LEN+1);
+ (void) sl_close(fd);
+ return 0;
+ }
+ }
+
+ /*@notreached@*/
+}
+
+static int just_list = S_FALSE;
+
+int sh_error_logverify_mod (const char * s)
+{
+ just_list = S_TRUE;
+ if (s) /* compiler warning (unused var) fix */
+ return 0;
+ else
+ return 0;
+}
+
+int sh_error_logverify (const char * s)
+{
+ SL_TICKET fd;
+ int len;
+ int status;
+ int count = 0;
+ int start = -1;
+ char * buf;
+ char * bufc;
+#ifdef SH_USE_XML
+ char * ptr;
+ int fixed_xml = S_TRUE;
+ char c_start;
+#endif
+ char signature[64];
+ char key[KEY_LEN+2];
+ char path[KEY_LEN+1];
+ char timestamp[64];
+ char c_cont;
+ int chk_mode = CHK_KEY;
+ char hashbuf[KEYBUF_SIZE];
+
+ sh_error_logoff();
+
+ if (s == NULL || sl_strlen(s) >= PATH_MAX)
+ {
+ fprintf(stderr, _("FAIL: msg=\"Invalid input\", path=\"%s\"\n"), s);
+ _exit (EXIT_FAILURE);
+ }
+
+ /* Open the file, then check it.
+ */
+ if (0 != sl_is_suid())
+ {
+ fprintf(stderr, _("Cannot open file %s in suid mode\n"), s);
+ _exit (EXIT_FAILURE);
+ }
+
+ if ( SL_ISERROR(fd = sl_open_read (FIL__, __LINE__, s, SL_NOPRIV)) )
+ {
+ fprintf(stderr,
+ _("FAIL: msg=\"File not accessible\", error=\"%ld\", path=\"%s\"\n"), fd, s);
+ _exit (EXIT_FAILURE);
+ }
+
+ /* Find space value.
+ */
+ c_cont = ' ';
+#ifdef SH_STEALTH
+ c_cont ^= XOR_CODE;
+#endif
+
+#ifdef SH_USE_XML
+ c_start = '<';
+#ifdef SH_STEALTH
+ c_start ^= XOR_CODE;
+#endif
+#endif
+
+ buf = (char *) SH_ALLOC( 2*SH_MSG_BUF+1 );
+ bufc = (char *) SH_ALLOC( 2*SH_MSG_BUF+1 );
+
+ while (1 == 1)
+ {
+ /* get the log message
+ */
+ if (sh_unix_getline (fd, buf, (2*SH_MSG_BUF)) < 0)
+ break;
+
+ len = (int) sl_strlen(buf);
+
+#ifdef SH_USE_XML
+#ifdef SH_STEALTH
+ if (0 == sl_strncmp (buf, N_("<trail>"), 7))
+#else
+ if (0 == sl_strncmp (buf, _("<trail>"), 7))
+#endif
+#else
+#ifdef SH_STEALTH
+ if (0 == sl_strncmp (buf, N_("[SOF]"), 5))
+#else
+ if (0 == sl_strncmp (buf, _("[SOF]"), 5))
+#endif
+#endif
+ {
+ if (just_list == S_TRUE)
+ {
+#ifdef SH_STEALTH
+ sh_do_decode (buf, sl_strlen(buf));
+#endif
+ fprintf (stdout, _("%s\n"), buf);
+ }
+
+ /* Found start of audit trail, read first line.
+ */
+ start = 1;
+ do {
+ if ( sh_unix_getline (fd, buf, (2*SH_MSG_BUF)) < 0)
+ break;
+ } while (buf[0] == '\0' || buf[0] == '\n');
+ len = (int) sl_strlen(buf);
+
+ if (just_list == S_TRUE)
+ {
+#ifdef SH_STEALTH
+ if (buf[0] != '\n')
+ sh_do_decode (buf, sl_strlen(buf));
+#endif
+ fprintf (stdout, _("%s\n"), buf);
+ start = 0;
+ }
+
+ ++count;
+ }
+ else if (buf[0] == '\n'
+#ifdef SH_USE_XML
+ ||
+#ifdef SH_STEALTH
+ 0 == sl_strncmp(buf, N_("</trail>"), 7)
+#else
+ 0 == sl_strncmp(buf, _("</trail>"), 7)
+#endif
+#endif
+ )
+ {
+ if (just_list == S_TRUE)
+ {
+#ifdef SH_STEALTH
+ if (buf[0] != '\n')
+ sh_do_decode (buf, sl_strlen(buf));
+#endif
+ fprintf (stdout, _("%s\n"), buf);
+ }
+
+ /* A newline.
+ */
+ ++count;
+ continue;
+ }
+ else if (start == 0)
+ {
+ /* We are inside an audit trail.
+ */
+ ++count;
+ if (just_list == S_TRUE)
+ {
+#ifdef SH_STEALTH
+ sh_do_decode (buf, sl_strlen(buf));
+#endif
+ fprintf (stdout, _("%s\n"), buf);
+ continue;
+ }
+ }
+ else
+ {
+ /* No start-of-file found yet.
+ */
+ continue;
+ }
+
+ if (just_list == S_TRUE)
+ continue;
+
+ /* Check for a continuation line.
+ */
+ while (1 == 1)
+ {
+ do {
+ if ( sh_unix_getline (fd, bufc, (2*SH_MSG_BUF)) < 0)
+ break;
+ } while (bufc[0] == '\0' || bufc[0] == '\n');
+ ++count;
+ if (bufc[0] == c_cont)
+ {
+ /* A continuation line. Add the newline.
+ */
+ (void) sl_strlcat(buf, "\n", 2*SH_MSG_BUF+1);
+ ++len;
+ (void) sl_strlcat(buf, bufc, 2*SH_MSG_BUF+1);
+ len += (int) sl_strlen(bufc);
+ }
+ else
+ {
+ /* No continuation line. Use it as signature.
+ * A48014C05604EF7C9472330E85453E704024943E556163C2
+ */
+#ifdef SH_USE_XML
+#ifdef SH_STEALTH
+ if (bufc[0] == c_start) /* FIX XML */
+#else
+ if (bufc[0] == c_start)
+#endif
+ {
+ (void) sl_strlcpy(signature, &bufc[5], KEY_LEN+1);
+ fixed_xml = S_TRUE;
+ }
+ else
+ {
+ (void) sl_strlcpy(signature, &bufc[4], KEY_LEN+1);
+ fixed_xml = S_FALSE;
+ }
+ if (sl_strlen(bufc) > (KEY_LEN+18))
+ {
+#ifdef SH_STEALTH
+ if (bufc[0] == c_start) /* FIX XML */
+#else
+ if (bufc[0] == c_start)
+#endif
+ (void) sl_strlcpy(timestamp, &bufc[KEY_LEN+5], 64);
+ else
+ (void) sl_strlcpy(timestamp, &bufc[KEY_LEN+4], 64);
+#ifdef SH_STEALTH
+ ptr = strchr(timestamp, c_start);
+#else
+ ptr = strchr(timestamp, c_start);
+#endif
+ if (ptr) *ptr = '\0';
+ }
+ break;
+#else
+ sl_strlcpy(signature, bufc, KEY_LEN+1);
+ if (sl_strlen(bufc) > KEY_LEN)
+ sl_strlcpy(timestamp, &bufc[KEY_LEN], 64);
+ break;
+#endif
+ }
+ }
+
+ /* Get starting key from command line.
+ */
+ if (start == 1)
+ {
+
+ /* Get the timestamp.
+ */
+
+#ifdef SH_STEALTH
+ sh_do_decode (timestamp, sl_strlen(timestamp));
+#endif
+ key[0] = '\0';
+
+ findKey:
+
+ if (chk_mode != CHK_FIL)
+ {
+ /* Ask for the key.
+ */
+ chk_mode = CHK_KEY;
+ fprintf(stdout, _("\nNew audit trail (%s), enter key|keyfile: "),
+ /*@-usedef@*/timestamp/*@+usedef@*/);
+ key[0] = '\0';
+
+ while (strlen(key) < KEY_LEN )
+ {
+ if (key[0] != '\n' && key[0] != '\0')
+ fprintf(stdout, "%s",_("New audit trail, enter key: "));
+ else if (key[0] == '\n')
+ {
+ (void) sl_strlcpy(key,
+ sh_tiger_hash(NULL, TIGER_DATA, 0,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ chk_mode = CHK_NON;
+ break;
+ }
+ (void) fflush(stdout);
+ key[0] = '\0';
+ if (NULL != fgets(key, sizeof(key), stdin))
+ {
+ if (key[0] != '\n')
+ {
+ if (key[strlen(key) - 1] == '\n')
+ key[strlen(key) - 1] = '\0';
+ }
+ if (key[0] == '/')
+ {
+ chk_mode = CHK_FIL;
+ (void) sl_strlcpy(path, key, KEY_LEN+1);
+ break;
+ }
+ }
+ }
+ }
+ /* we now have either a key (chk_mode == CHK_NON|CHK_KEY)
+ * or a file (chk_mode == CHK_FIL)
+ */
+ if (chk_mode == CHK_FIL)
+ {
+ fprintf(stdout, _("\nAudit trail (%s), searching file %s\n"),
+ /*@-usedef@*/timestamp, path/*@+usedef@*/);
+ if (-1 == get_key_from_file(path, timestamp, key))
+ {
+ chk_mode = CHK_KEY;
+ fprintf(stdout, "%s",_("Key not found in file\n"));
+ goto findKey;
+ }
+ }
+
+
+ sh_util_encode(key, buf, 1, 'B');
+ start = 0;
+ }
+ else
+ {
+ /* Iterate the key.
+ */
+ (void) sl_strlcpy (key,
+ sh_tiger_hash (key, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+
+ (void) sl_strlcat ( buf, key, 2*SH_MSG_BUF + 1);
+
+#ifdef SH_STEALTH
+ sh_do_decode (signature, sl_strlen(signature));
+#endif
+
+ status = sl_strncmp (signature,
+ sh_tiger_hash (buf, TIGER_DATA,
+ (unsigned long) sl_strlen(buf),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN);
+
+ buf[len] = '\0'; /* do not print out the key */
+#ifdef SH_STEALTH
+ sh_do_decode (buf, sl_strlen(buf));
+#endif
+
+ if (status != 0)
+ {
+#ifdef SH_USE_XML
+ if (chk_mode == CHK_NON)
+ {
+ if (fixed_xml == S_FALSE)
+ fprintf (stdout, _("XFAIL: line=%05d %s/log>\n"),
+ count-1, buf);
+ else
+ fprintf (stdout, _("XFAIL: line=%05d %s</log>\n"),
+ count-1, buf);
+ }
+ else
+ {
+ if (fixed_xml == S_FALSE)
+ fprintf (stdout, _("FAIL: line=%05d %s/log>\n"),
+ count-1, buf);
+ else
+ fprintf (stdout, _("FAIL: line=%05d %s</log>\n"),
+ count-1, buf);
+ }
+#else
+ if (chk_mode == CHK_NON)
+ fprintf (stdout, _("XFAIL: line=%5d %s\n"), count-1, buf);
+ else
+ fprintf (stdout, _("FAIL: line=%5d %s\n"), count-1, buf);
+#endif
+ }
+ else
+ {
+#ifdef SH_USE_XML
+ if (fixed_xml == S_FALSE)
+ fprintf (stdout, _("PASS: line=%05d %s/log>\n"), count-1, buf);
+ else
+ fprintf (stdout, _("PASS: line=%05d %s</log>\n"), count-1, buf);
+#else
+ fprintf (stdout, _("PASS: line=%5d %s\n"), count-1, buf);
+#endif
+ }
+ }
+
+ /* Cleanup and exit.
+ */
+ (void) sl_close (fd);
+ SH_FREE (buf);
+ SH_FREE (bufc);
+ (void) fflush (stdout);
+ _exit (EXIT_SUCCESS);
+
+ /* Make compilers happy.
+ */
+ /*@notreached@*/
+ return 0;
+}
+
+/********************************************************************
+ *
+ * Runtime code
+ *
+ ********************************************************************/
+static
+int sh_log_open (char * inet_peer,
+ char * logfile, int * service_failure, SL_TICKET * fildesc)
+{
+ SL_TICKET fd = -1;
+ long int status;
+ char * tmp = NULL;
+ uid_t uid;
+ size_t len;
+ char * lockfile = NULL;
+
+ SL_ENTER(_("sh_log_open"));
+
+ /* open/create the file, then check it
+ */
+
+ if ( 0 != (status = tf_trust_check (logfile, SL_YESPRIV))
+ && (*service_failure) == 0)
+ {
+ tmp = sh_util_safe_name (logfile);
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_TRUST,
+ (long) sh.effective.uid, tmp);
+ }
+
+ if (status == 0)
+ {
+ fd = sl_open_write (FIL__, __LINE__, logfile, SL_YESPRIV);
+ if (SL_ISERROR(fd))
+ {
+ tmp = sh_util_safe_name (logfile);
+ (void) sl_get_euid(&uid);
+ if ((*service_failure) == 0)
+ sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
+ (long) uid, tmp);
+ status = -1;
+ }
+ }
+
+
+ if (status == 0 && inet_peer == NULL )
+ {
+ status = sh_unix_write_lock_file(logfile);
+ if (status < 0)
+ {
+ tmp = sh_util_safe_name (logfile);
+ len = sl_strlen(tmp);
+ if (sl_ok_adds (6, len))
+ len += 6;
+ lockfile = SH_ALLOC(len);
+ (void) sl_strlcpy(lockfile, tmp, len);
+ (void) sl_strlcat(lockfile, _(".lock"), len);
+ (void) sl_get_euid(&uid);
+ if ((*service_failure) == 0)
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_LOCKED,
+ (long) uid, tmp, lockfile);
+ status = -1;
+ SH_FREE(lockfile);
+ (void) sl_close(fd);
+ }
+ }
+
+ if (status == 0)
+ {
+ status = sl_forward(fd);
+ if (SL_ISERROR(status))
+ {
+ tmp = sh_util_safe_name (logfile);
+ (void) sl_get_euid(&uid);
+ if ((*service_failure) == 0)
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_ACCESS,
+ (long) uid, tmp);
+ status = -1;
+ (void) sl_close(fd);
+ }
+ }
+
+ if (status < 0)
+ {
+ if ((*service_failure) == 0) {
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_SRV_FAIL,
+ _("logfile"), tmp);
+ (*service_failure) = 1;
+ }
+ if (tmp)
+ SH_FREE(tmp);
+ SL_RETURN(-1, _("sh_log_open"));
+ }
+
+ *fildesc = fd;
+ *service_failure = 0;
+ SL_RETURN(0, _("sh_log_open"));
+}
+
+typedef struct lfstc {
+ char * logfile;
+ int service_failure;
+ int log_start;
+ char sigkey_old[KEY_LEN+1];
+ char sigkey_new[KEY_LEN+1];
+ char crypto[KEY_LEN+1];
+ struct lfstc * next;
+} open_logfile;
+
+static open_logfile * logfile_list = NULL;
+
+static int flag_sep_log = S_FALSE;
+
+#ifdef SH_WITH_SERVER
+int set_flag_sep_log (const char * str)
+{
+ return sh_util_flagval(str, &flag_sep_log);
+}
+#endif
+
+/*
+ * --- Log error message to log file. ---
+ */
+int sh_log_file (/*@null@*/char *errmsg, /*@null@*/char * inet_peer)
+{
+ int store1;
+ int store2;
+ int store3;
+ int store4;
+ int store5;
+ int store6;
+ int store7;
+ int store8;
+
+ SL_TICKET fd = -1;
+ size_t status;
+ struct _sh_log_buf log_msg;
+
+ char logfile[SH_PATHBUF+SH_MINIBUF+2];
+ open_logfile * current = logfile_list;
+ open_logfile * next = NULL;
+ char * sigkey_new;
+ char * sigkey_old;
+ char * crypto;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_log_file"));
+
+ if (errFlags.HaveLog == BAD) /* paranoia */
+ SL_RETURN((-1), _("sh_log_file"));
+
+#ifdef SH_USE_XML
+ if (NULL == errmsg)
+ {
+ while (current != NULL)
+ {
+ /* don't write second EOF mark
+ */
+ if (current->log_start != S_TRUE && sh.flag.islocked == GOOD)
+ {
+ /* Don't use inet_peer == NULL, userwise a lock file will
+ * be created.
+ */
+ (void) sh_log_open ("\0",
+ current->logfile,
+ &(current->service_failure), &fd);
+
+#ifdef SH_STEALTH
+ (void) sl_write_line (fd, N_("</trail>"), 7);
+ (void) sl_write (fd, "\n", 1);
+ (void) sl_sync(fd);
+#else
+ (void) sl_write_line (fd, _("</trail>\n"), 8);
+ (void) sl_sync(fd);
+#endif
+ (void) sl_close(fd);
+ /* sh_unix_rm_lock_file (current->logfile); */
+ }
+ next = current->next;
+ SH_FREE(current->logfile);
+ SH_FREE(current);
+ current = next;
+ }
+ logfile_list = NULL;
+ SL_RETURN( 0, _("sh_log_file"));
+ }
+#else
+ if (NULL == errmsg)
+ {
+ while (current != NULL)
+ {
+ /* sh_unix_rm_lock_file (current->logfile); */
+ next = current->next;
+ SH_FREE(current->logfile);
+ SH_FREE(current);
+ current = next;
+ }
+ logfile_list = NULL;
+ SL_RETURN( 0, _("sh_log_file"));
+ }
+#endif
+
+ (void) sl_strlcpy (logfile, sh.srvlog.name, sizeof(logfile));
+ if (inet_peer != NULL && flag_sep_log == S_TRUE)
+ {
+ (void) sl_strlcat (logfile, ".", sizeof(logfile));
+ (void) sl_strlcat (logfile, inet_peer, sizeof(logfile));
+ }
+
+ if (sh.flag.log_start == S_TRUE)
+ {
+ while (current != NULL)
+ {
+ current->log_start = S_TRUE;
+ current = current->next;
+ }
+ sh.flag.log_start = S_FALSE;
+ current = logfile_list;
+ }
+
+ while (current != NULL)
+ {
+ if (strcmp(logfile, current->logfile) == 0)
+ break;
+ current = current->next;
+ }
+
+ if (current == NULL)
+ {
+ current = SH_ALLOC(sizeof(open_logfile));
+ current->logfile = SH_ALLOC(strlen(logfile) + 1);
+ (void) sl_strlcpy(current->logfile, logfile, strlen(logfile) + 1);
+ current->service_failure = 0;
+ current->log_start = S_TRUE;
+ memset(current->sigkey_old, (int)'\0', KEY_LEN+1);
+ memset(current->sigkey_new, (int)'\0', KEY_LEN+1);
+ memset(current->crypto, (int)'\0', KEY_LEN+1);
+ current->next = logfile_list;
+ logfile_list = current;
+ }
+
+ if (0 != sh_log_open (inet_peer, current->logfile,
+ &(current->service_failure), &fd))
+ {
+ SL_RETURN ((-1), _("sh_log_file"));
+ }
+
+
+ /* --- Allocate storage and mlock it. ---
+ */
+
+ status = sl_strlen (errmsg);
+ if (!sl_ok_adds(status, (2*KEY_LEN)) || !sl_ok_adds((2*KEY_LEN + status),32))
+ {
+ sl_close(fd);
+ SL_RETURN ((-1), _("sh_log_file"));
+ }
+
+ log_msg.msg = (char *) SH_ALLOC ((size_t) (2*KEY_LEN + status + 32));
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ if (skey->mlock_failed == S_FALSE)
+ {
+ if ( (-1) == sh_unix_mlock( FIL__, __LINE__, log_msg.msg,
+ (size_t)(2*KEY_LEN + status + 32) ) )
+ {
+ skey->mlock_failed = S_TRUE;
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ sh_error_handle ((-1), FIL__, __LINE__, EPERM, MSG_MLOCK);
+#endif
+ }
+ }
+#else
+ if (skey->mlock_failed == S_FALSE)
+ {
+ skey->mlock_failed = S_TRUE;
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ sh_error_handle ((-1), FIL__, __LINE__, EPERM, MSG_MLOCK);
+#endif
+ }
+#endif
+
+ /* --- Write the start marker. ---
+ */
+
+ if (current->log_start == S_TRUE)
+ {
+#ifdef SH_USE_XML
+#ifdef SH_STEALTH
+ (void) sl_write (fd, "\n", 1);
+ (void) sl_write_line (fd, N_("<trail>"), 7);
+ (void) sl_sync(fd);
+#else
+ (void) sl_write_line (fd, _("\n<trail>"), 8);
+ (void) sl_sync(fd);
+#endif
+#else
+#ifdef SH_STEALTH
+ (void) sl_write (fd, "\n", 1);
+ (void) sl_write_line (fd, N_("[SOF]"), 5);
+ (void) sl_sync(fd);
+#else
+ (void) sl_write_line (fd, _("\n[SOF]"), 6);
+ (void) sl_sync(fd);
+#endif
+#endif
+ }
+
+ /* reserve KEY_LEN chars at end for key
+ */
+ (void) sl_strlcpy (log_msg.msg, errmsg, (size_t) status+1 );
+
+
+#ifdef SH_USE_XML
+ /* cut the trailing "/>"
+ */
+ if (log_msg.msg[status-2] == '/')
+ {
+#ifdef FIX_XML
+ log_msg.msg[status-2] = ' '; /* ' ' FIX XML */
+ log_msg.msg[status-1] = '>'; /* '>' FIX XML */
+#else
+ log_msg.msg[status-2] = '>'; /* ' ' FIX XML */
+ log_msg.msg[status-1] = '<'; /* '>' FIX XML */
+#endif
+ log_msg.msg[status] = '\0';
+ }
+ else if (status >= 6 && log_msg.msg[status-5] == '/' &&
+ log_msg.msg[status-6] == '<')
+ {
+#ifdef FIX_XML
+ log_msg.msg[status-6] = '\0';
+ status -= 6;
+#else
+ log_msg.msg[status-5] = '\0';
+ status -= 5;
+#endif
+ }
+#endif
+
+
+#ifdef SH_STEALTH
+ sh_do_encode (log_msg.msg, status);
+#endif
+
+ if (flag_sep_log == S_TRUE && inet_peer != NULL)
+ {
+ sigkey_old = current->sigkey_old;
+ sigkey_new = current->sigkey_new;
+ crypto = current->crypto;
+ }
+ else
+ {
+ sigkey_old = skey->sigkey_old;
+ sigkey_new = skey->sigkey_new;
+ crypto = skey->crypt; /* flawfinder: ignore */
+ }
+
+ /* write the signature
+ */
+ if (current->log_start == S_TRUE)
+ {
+ if (sh.real.user[0] == '\0')
+ (void) sh_unix_getUser();
+
+ /* Initialize the key.
+ */
+ (void) sh_util_keyinit(sigkey_old, KEY_LEN+1);
+
+ /* Hash the key to make sure it has the correct format.
+ */
+ (void) sl_strlcpy(sigkey_new,
+ sh_tiger_hash (sigkey_old, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ /* Copy it to 'crypt' for encryption.
+ */
+ (void) sl_strlcpy(crypto, sigkey_new, KEY_LEN+1);
+
+ /* Use message and compiled-in key to encrypt.
+ */
+ BREAKEXIT(sh_util_encode);
+ sh_util_encode(crypto, log_msg.msg, 0, 'B');
+
+ /* Send out the key.
+ */
+ (void) sh_unix_time(0, log_msg.timestamp, KEY_LEN+1);
+
+ store1 = errFlags.loglevel;
+ store2 = errFlags.sysloglevel;
+ store3 = errFlags.printlevel;
+ store4 = errFlags.exportlevel;
+ store5 = errFlags.maillevel;
+ store6 = errFlags.externallevel;
+ store7 = errFlags.databaselevel;
+ store8 = errFlags.preludelevel;
+
+ /* mail the key
+ */
+ errFlags.loglevel = SH_ERR_NOT;
+ errFlags.sysloglevel = SH_ERR_NOT;
+ errFlags.printlevel = SH_ERR_NOT;
+ errFlags.exportlevel = SH_ERR_NOT;
+ errFlags.externallevel = SH_ERR_NOT;
+ errFlags.databaselevel = SH_ERR_NOT;
+ errFlags.preludelevel = SH_ERR_NOT;
+
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_KEY_MAIL,
+ sh.prg_name, crypto,
+ crypto, log_msg.timestamp);
+
+ /* send to other allowed channels
+ */
+ errFlags.maillevel = SH_ERR_NOT;
+ /* errFlags.printlevel = store3; */
+ errFlags.exportlevel = store4;
+ errFlags.externallevel = store6;
+ errFlags.databaselevel = store7;
+ errFlags.preludelevel = store8;
+
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_KEY,
+ sh.prg_name, crypto);
+
+ /* Cleanup.
+ */
+ errFlags.loglevel = store1;
+ errFlags.sysloglevel = store2;
+ errFlags.printlevel = store3;
+ errFlags.exportlevel = store4;
+ errFlags.maillevel = store5;
+ errFlags.externallevel = store6;
+ errFlags.databaselevel = store7;
+
+
+ memset (crypto, (int) '\0', KEY_LEN);
+ sh.flag.log_start = S_FALSE;
+ current->log_start = S_FALSE;
+ }
+ else
+ {
+ log_msg.timestamp[0] = '\0';
+ (void) sl_strlcpy (sigkey_new,
+ sh_tiger_hash (sigkey_old, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+
+ /* --- Sign the message with the signature key. ---
+ */
+ sh_tiger_hash (log_msg.msg, TIGER_DATA,
+ (unsigned long)(status + KEY_LEN),
+ (char *) hashbuf, (size_t) sizeof(hashbuf));
+
+ (void) sl_strlcat (log_msg.msg, sigkey_new, (size_t)(status + KEY_LEN + 2));
+ (void) sl_strlcpy (log_msg.signature,
+ sh_tiger_hash (log_msg.msg, (TigerType) TIGER_DATA,
+ (unsigned long)(status + KEY_LEN),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ (void) sl_strlcpy (sigkey_old, sigkey_new, KEY_LEN+1);
+
+ /*@-usedef@*/
+#ifdef SH_USE_XML
+ if (log_msg.timestamp[0] != '\0')
+ sl_snprintf(log_msg.sig, sizeof(log_msg.sig),
+#ifdef FIX_XML
+ _("\n<sig>%s%s</sig></log>\n"), /* <sig> FIX XML */
+#else
+ _("\nsig>%s%s</sig></log>\n"), /* <sig> FIX XML */
+#endif
+ log_msg.signature, log_msg.timestamp);
+ else
+ sl_snprintf(log_msg.sig, sizeof(log_msg.sig),
+#ifdef FIX_XML
+ _("\n<sig>%s</sig></log>\n"), /* <sig> FIX XML */
+#else
+ _("\nsig>%s</sig></log>\n"), /* <sig> FIX XML */
+#endif
+ log_msg.signature);
+ /*@+usedef@*/
+
+#ifdef SH_STEALTH
+ /* don't encode the line breaks (0 + last char)
+ */
+ sh_do_encode (&log_msg.sig[1], (sl_strlen(log_msg.sig)-2) );
+#endif
+#else
+#ifdef SH_STEALTH
+ sh_do_encode (log_msg.signature, KEY_LEN);
+ sh_do_encode (log_msg.timestamp, sl_strlen(log_msg.timestamp));
+#endif
+#endif
+
+#ifdef SH_USE_XML
+ log_msg.msg[status] = '\0';
+ (void) sl_strlcat (log_msg.msg, log_msg.sig,
+ (size_t)(status + 2*KEY_LEN + 32));
+#ifdef SH_STEALTH
+ if (NULL != sl_strstr(log_msg.msg, N_("EXIT")) &&
+ NULL == sl_strstr(log_msg.msg, N_("remote_host")))
+ {
+ (void) sl_strlcat (log_msg.msg, N_("</trail>"),
+ (size_t)(status + 2*KEY_LEN + 32));
+#else
+ if (NULL != sl_strstr(log_msg.msg, _("msg=\"EXIT\"")) &&
+ NULL == sl_strstr(log_msg.msg, _("remote_host")))
+ {
+ (void) sl_strlcat (log_msg.msg, _("</trail>"),
+ (size_t)(status + 2*KEY_LEN + 32));
+#endif
+
+ (void) sl_strlcat (log_msg.msg, _("\n"),
+ (size_t)(status + 2*KEY_LEN + 32));
+ current->log_start = S_TRUE;
+ }
+#else
+ log_msg.msg[status] = '\0';
+ (void) sl_strlcat (log_msg.msg, "\n",
+ (size_t)(status + KEY_LEN + 2));
+ (void) sl_strlcat (log_msg.msg, log_msg.signature,
+ (size_t)(status + KEY_LEN + 2));
+ if (log_msg.timestamp[0] != '\0')
+ (void) sl_strlcat (log_msg.msg, log_msg.timestamp,
+ (size_t)(status + 2*KEY_LEN + 2));
+ (void) sl_strlcat (log_msg.msg, "\n",
+ (size_t)(status + 2*KEY_LEN + 3));
+#endif
+
+ /* --- Write out the record. ---
+ */
+ (void) sl_write (fd, log_msg.msg, (long) strlen(log_msg.msg));
+ (void) sl_sync (fd);
+ (void) sl_close (fd);
+
+ /* --- Clean up and free record. ---
+ */
+ memset (log_msg.msg, (int)'\0', (size_t)(status + 2*KEY_LEN + 32));
+ memset (log_msg.signature, (int)'\0', KEY_LEN);
+ (void) sh_unix_munlock (log_msg.msg,
+ (size_t)(status + 2*KEY_LEN + 32));
+ SH_FREE(log_msg.msg);
+
+ SL_RETURN (0, _("sh_log_file"));
+}
+
+/* >>>>>>>>>>>>>>>>>>>>>>>>>>>> efile <<<<<<<<<<<<<<<<<< */
+
+static char * gEfile = NULL;
+static int gFail = 0;
+static long gGid = 0;
+
+int sh_efile_group(const char * str)
+{
+ int fail;
+ long gid = sh_group_to_gid(str, &fail);
+
+ if (fail < 0)
+ {
+ return -1;
+ }
+ gGid = gid;
+ return 0;
+}
+
+
+int sh_efile_path(const char * str)
+{
+ if (!str || !strcmp(str, _("none")))
+ {
+ if (gEfile)
+ SH_FREE(gEfile);
+ gEfile = NULL;
+ }
+ else if (str[0] != '/')
+ {
+ return -1;
+ }
+ else
+ {
+ if (gEfile)
+ SH_FREE(gEfile);
+ gEfile = sh_util_strdup(str);
+ }
+ gFail = 0;
+ return 0;
+}
+
+/* write lock for filename
+ */
+static int sh_efile_lock (char * filename, int flag)
+{
+ extern int get_the_fd (SL_TICKET ticket);
+ size_t len;
+ int res = -1;
+ char myPid[64];
+ SL_TICKET fd;
+ char * lockfile;
+ int status;
+
+ sprintf (myPid, "%ld\n", (long) sh.pid); /* known to fit */
+
+ if (filename == NULL)
+ return res;
+
+ len = sl_strlen(filename);
+ if (sl_ok_adds(len, 6))
+ len += 6;
+ lockfile = SH_ALLOC(len);
+ sl_strlcpy(lockfile, filename, len);
+ sl_strlcat(lockfile, _(".lock"), len);
+
+ if ( 0 != (status = tf_trust_check (lockfile, SL_YESPRIV))
+ && gFail == 0)
+ {
+ char * tmp = sh_util_safe_name (lockfile);
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_TRUST,
+ (long) sh.effective.uid, tmp);
+ ++gFail;
+ SH_FREE(tmp);
+ }
+
+ if (status == 0)
+ {
+ if (flag == 0)
+ {
+ /* --- Delete the lock file. ---
+ */
+ res = retry_aud_unlink (FIL__, __LINE__, lockfile);
+ }
+ else
+ {
+ unsigned int count = 0;
+
+ /* fails if file exists
+ */
+ do {
+ fd = sl_open_safe_rdwr (FIL__, __LINE__,
+ lockfile, SL_YESPRIV);
+ if (SL_ISERROR(fd))
+ {
+ retry_msleep(0, 100);
+ ++count;
+ }
+
+ } while (SL_ISERROR(fd) && count < 3);
+
+ if (!SL_ISERROR(fd))
+ {
+ int filed;
+
+ res = sl_write (fd, myPid, sl_strlen(myPid));
+ filed = get_the_fd(fd);
+ fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ sl_close (fd);
+ }
+ else
+ {
+ static int nFail = 0;
+
+ if (nFail == 0)
+ {
+ char errmsg[1024];
+ char * tmp = sh_util_safe_name (lockfile);
+
+ sl_snprintf(errmsg, sizeof(errmsg),
+ _("Error creating lockfile %s"),
+ tmp);
+
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ 0, MSG_E_SUBGEN,
+ errmsg, _("sh_efile_lock"));
+ ++nFail;
+ SH_FREE(tmp);
+ }
+ }
+ }
+ }
+
+ SH_FREE(lockfile);
+ return res;
+}
+
+static size_t gSave[6] = { 0 };
+
+static void sh_efile_clear()
+{
+ int i;
+
+ for (i = 0; i < 6; ++i)
+ gSave[i] = 0;
+ return;
+}
+
+static void sh_efile_load(size_t * tmp)
+{
+ int i;
+
+ if (S_TRUE == sl_ok_adds (gSave[0], sh.statistics.bytes_hashed))
+ gSave[0] += sh.statistics.bytes_hashed;
+ if (S_TRUE == sl_ok_adds (gSave[1], sh.statistics.dirs_checked))
+ gSave[1] += sh.statistics.dirs_checked;
+ if (S_TRUE == sl_ok_adds (gSave[2], sh.statistics.files_checked))
+ gSave[2] += sh.statistics.files_checked;
+ if (S_TRUE == sl_ok_adds (gSave[3], sh.statistics.files_report))
+ gSave[3] += sh.statistics.files_report;
+ if (S_TRUE == sl_ok_adds (gSave[4], sh.statistics.files_error))
+ gSave[4] += sh.statistics.files_error;
+ if (S_TRUE == sl_ok_adds (gSave[5], sh.statistics.files_nodir))
+ gSave[5] += sh.statistics.files_nodir;
+
+ for (i = 0; i < 6; ++i)
+ tmp[i] = gSave[i];
+ return;
+}
+
+void sh_efile_report()
+{
+ extern int get_the_fd (SL_TICKET ticket);
+ SL_TICKET fd;
+ char *efile;
+ int status = -1;
+
+ if (gEfile)
+ {
+ size_t tmp[6];
+
+ sh_efile_load(tmp);
+
+ efile = sh_util_strdup(gEfile);
+
+ if (sh_efile_lock (efile, 1) < 0)
+ goto end;
+
+ if ( 0 != (status = tf_trust_check (efile, SL_YESPRIV))
+ && gFail == 0)
+ {
+ char * tmp = sh_util_safe_name (efile);
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_TRUST,
+ (long) sh.effective.uid, tmp);
+ ++gFail;
+ SH_FREE(tmp);
+ }
+
+ if (status == 0)
+ {
+ fd = sl_open_write (FIL__, __LINE__, efile, SL_YESPRIV);
+
+ if (!SL_ISERROR(fd))
+ {
+ char report[511];
+ char tstamp[TIM_MAX];
+
+ time_t now = time(NULL);
+ int filed = get_the_fd(fd);
+
+ (void) sh_unix_time (now, tstamp, sizeof(tstamp));
+#ifdef HAVE_LONG_LONG
+ sl_snprintf(report, sizeof(report),
+ _("%s %lld %ld %ld %ld %ld %ld %ld\n"),
+ tstamp,
+ (long long) now,
+ (long) tmp[0], (long) tmp[1], (long) tmp[2],
+ (long) tmp[3], (long) tmp[4], (long) tmp[5]);
+#else
+ sl_snprintf(report, sizeof(report),
+ _("%s %ld %ld %ld %ld %ld %ld %ld\n"),
+ tstamp,
+ (long) now,
+ (long) tmp[0], (long) tmp[1], (long) tmp[2],
+ (long) tmp[3], (long) tmp[4], (long) tmp[5]);
+#endif
+
+ status = sl_forward(fd);
+ if (!SL_ISERROR(status))
+ status = sl_write (fd, report, strlen(report));
+ (void) sl_sync(fd);
+
+ /* make group writeable, such that nagios can truncate */
+ fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
+ status = fchown (filed, -1, gGid);
+ if (status < 0)
+ {
+ int errnum = errno;
+ static int nFail = 0;
+ if (nFail == 0)
+ {
+ char errmsg[1024];
+ char buf[256];
+ char * tmp = sh_util_safe_name (efile);
+
+ sl_snprintf(errmsg, sizeof(errmsg),
+ _("Error changing group of %s to %ld: %s"),
+ tmp, gGid,
+ sh_error_message (errnum, buf, sizeof(buf)));
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ errnum, MSG_E_SUBGEN,
+ errmsg, _("sh_efile_report"));
+ ++nFail;
+ SH_FREE(tmp);
+ }
+ }
+
+ (void) sl_close(fd);
+ }
+ else
+ {
+ status = -1;
+ }
+ }
+
+ (void) sh_efile_lock (efile, 0);
+ end:
+ SH_FREE(efile);
+
+ if (!SL_ISERROR(status))
+ {
+ sh_efile_clear();
+ }
+ }
+ return;
+}
diff --git a/src/sh_err_syslog.c b/src/sh_err_syslog.c
new file mode 100644
index 0000000..e46187b
--- /dev/null
+++ b/src/sh_err_syslog.c
@@ -0,0 +1,240 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <syslog.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "samhain.h"
+#include "sh_error.h"
+
+#undef FIL__
+#define FIL__ _("sh_err_syslog.c")
+
+typedef struct log_fac_struct {
+ const char * name;
+ int facility;
+} logfct;
+
+static logfct fct_tab[] = {
+#ifdef LOG_AUTH
+ { N_("LOG_AUTH"), LOG_AUTH },
+#endif
+#ifdef LOG_AUTHPRIV
+ { N_("LOG_AUTHPRIV"), LOG_AUTHPRIV },
+#endif
+#ifdef LOG_CRON
+ { N_("LOG_CRON"), LOG_CRON },
+#endif
+#ifdef LOG_DAEMON
+ { N_("LOG_DAEMON"), LOG_DAEMON },
+#endif
+#ifdef LOG_FTP
+ { N_("LOG_FTP"), LOG_FTP },
+#endif
+#ifdef LOG_KERN
+ { N_("LOG_KERN"), LOG_KERN },
+#endif
+#ifdef LOG_LOCAL0
+ { N_("LOG_LOCAL0"), LOG_LOCAL0 },
+#endif
+#ifdef LOG_LOCAL1
+ { N_("LOG_LOCAL1"), LOG_LOCAL1 },
+#endif
+#ifdef LOG_LOCAL2
+ { N_("LOG_LOCAL2"), LOG_LOCAL2 },
+#endif
+#ifdef LOG_LOCAL3
+ { N_("LOG_LOCAL3"), LOG_LOCAL3 },
+#endif
+#ifdef LOG_LOCAL4
+ { N_("LOG_LOCAL4"), LOG_LOCAL4 },
+#endif
+#ifdef LOG_LOCAL5
+ { N_("LOG_LOCAL5"), LOG_LOCAL5 },
+#endif
+#ifdef LOG_LOCAL6
+ { N_("LOG_LOCAL6"), LOG_LOCAL6 },
+#endif
+#ifdef LOG_LOCAL7
+ { N_("LOG_LOCAL7"), LOG_LOCAL7 },
+#endif
+#ifdef LOG_LPR
+ { N_("LOG_LPR"), LOG_LPR },
+#endif
+#ifdef LOG_MAIL
+ { N_("LOG_MAIL"), LOG_MAIL },
+#endif
+#ifdef LOG_NEWS
+ { N_("LOG_NEWS"), LOG_NEWS },
+#endif
+#ifdef LOG_SYSLOG
+ { N_("LOG_SYSLOG"), LOG_SYSLOG },
+#endif
+#ifdef LOG_USER
+ { N_("LOG_USER"), LOG_USER },
+#endif
+#ifdef LOG_UUCP
+ { N_("LOG_UUCP"), LOG_UUCP },
+#endif
+ { NULL, -1 }
+};
+
+#ifdef LOG_AUTHPRIV
+static int my_syslog_facility = LOG_AUTHPRIV;
+#else
+/*@-unrecog@*/
+static int my_syslog_facility = LOG_AUTH;
+/*@+unrecog@*/
+#endif
+
+
+/* set syslog facility
+ */
+int sh_log_set_facility (const char * c)
+{
+ int loop = 0;
+ SL_ENTER(_("sh_log_set_facility"));
+
+ if (c == NULL)
+ SL_RETURN(-1, _("sh_log_set_facility"));
+
+ while (fct_tab[loop].name != NULL)
+ {
+ if (0 == strcmp ( _(fct_tab[loop].name), c))
+ {
+ my_syslog_facility = fct_tab[loop].facility;
+ SL_RETURN(0, _("sh_log_set_facility"));
+ }
+ ++loop;
+ }
+
+ SL_RETURN(-1, _("sh_log_set_facility"));
+}
+
+static int sh_stamp_priority = LOG_ERR;
+
+/* set priority for heartbeat messages
+ */
+int sh_log_set_stamp_priority (const char * c)
+{
+ int retval = 0;
+
+ if (0 == strcmp(c, _("LOG_DEBUG"))) { sh_stamp_priority = LOG_DEBUG; }
+ else if (0 == strcmp(c, _("LOG_INFO"))) { sh_stamp_priority = LOG_INFO; }
+ else if (0 == strcmp(c, _("LOG_NOTICE"))) { sh_stamp_priority = LOG_NOTICE;}
+ else if (0 == strcmp(c, _("LOG_WARNING"))) { sh_stamp_priority = LOG_WARNING;}
+ else if (0 == strcmp(c, _("LOG_ERR"))) { sh_stamp_priority = LOG_ERR; }
+ else if (0 == strcmp(c, _("LOG_CRIT"))) { sh_stamp_priority = LOG_CRIT; }
+ else if (0 == strcmp(c, _("LOG_ALERT"))) { sh_stamp_priority = LOG_ALERT; }
+#ifdef LOG_EMERG
+ else if (0 == strcmp(c, _("LOG_EMERG"))) { sh_stamp_priority = LOG_EMERG; }
+#endif
+ else { retval = -1; }
+
+ return retval;
+}
+
+/* syslog error message
+ */
+int sh_log_syslog (int severity, /*@null@*/char *errmsg)
+{
+ int priority;
+ size_t len;
+ size_t i;
+ char store;
+ char * p;
+
+ static int init = 0;
+
+ SL_ENTER(_("sh_log_syslog"));
+
+ ASSERT_RET((errmsg != NULL), _("errmsg != NULL"), 0);
+
+ /*@-unrecog@*/
+ if (severity == SH_ERR_ALL) priority = LOG_DEBUG;
+ else if (severity == SH_ERR_INFO) priority = LOG_INFO;
+ else if (severity == SH_ERR_NOTICE) priority = LOG_NOTICE;
+ else if (severity == SH_ERR_WARN) priority = LOG_WARNING;
+ else if (severity == SH_ERR_STAMP) priority = sh_stamp_priority;
+ else if (severity == SH_ERR_ERR) priority = LOG_ERR;
+ else if (severity == SH_ERR_SEVERE) priority = LOG_CRIT;
+ else if (severity == SH_ERR_FATAL) priority = LOG_ALERT;
+ else priority = LOG_DEBUG;
+ /*@+unrecog@*/
+
+#ifndef LOG_PID
+#define LOG_PID 0
+#endif
+
+ if (init == 0)
+ {
+ /*@-unrecog@*/
+ openlog (sh.prg_name, LOG_PID, my_syslog_facility);
+ /*@+unrecog@*/
+ init = 1;
+ }
+
+ /* --- Limit the message size. ---
+ */
+ len = sl_strlen(errmsg);
+ if (len < 960)
+ {
+ /*@-unrecog@*/
+ syslog (priority, "%s", errmsg);
+ /*@+unrecog@*/
+ }
+ else
+ {
+ i = 960;
+ p = errmsg;
+
+ while (i < len)
+ {
+ store = errmsg[i];
+ errmsg[i] = '\0';
+ /*@-unrecog@*/
+ syslog (priority, "%s", p);
+ /*@+unrecog@*/
+ errmsg[i] = store;
+ p = &errmsg[i];
+ i += 960;
+ }
+ if (i != len)
+ {
+ /*@-unrecog@*/
+ syslog (priority, "%s", p);
+ /*@+unrecog@*/
+ }
+ }
+
+ /* Solaris does not recover if a closeall() closes the
+ * syslog file descriptor, so close it here.
+ */
+ /*@-unrecog@*/
+ closelog();
+ /*@+unrecog@*/
+ init = 0;
+ SL_RETURN(0, _("sh_log_syslog"));
+}
+
+
+
diff --git a/src/sh_error.c b/src/sh_error.c
new file mode 100644
index 0000000..5ec934b
--- /dev/null
+++ b/src/sh_error.c
@@ -0,0 +1,1813 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+/* Required on Linux to get the correct strerror_r function. Also
+ * for recursive mutexes (_XOPEN_SOURCE >= 500). Gives funny error
+ * on Solaris 10/gcc ('c99' compiler required - huh? Isn't gcc
+ * good enough?).
+ */
+#if !defined(__sun__) && !defined(__sun)
+#define _XOPEN_SOURCE 600
+#undef _GNU_SOURCE
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+
+/* Required on FreeBSD
+ */
+#include <sys/types.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+
+
+#include "samhain.h"
+
+#include "sh_cat.h"
+#include "sh_database.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_tiger.h"
+#include "sh_nmail.h"
+#include "sh_xfer.h"
+#include "sh_prelude.h"
+#include "sh_pthread.h"
+
+#if defined(WITH_DATABASE)
+#include "sh_tools.h"
+#endif
+
+#if defined(WITH_EXTERNAL)
+#include "sh_extern.h"
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_error.c")
+/*@-noret -compmempass@*/
+extern int clt_class;
+
+int flag_err_debug = S_FALSE;
+int flag_err_info = S_FALSE;
+
+int ShDFLevel[SH_ERR_T_END];
+
+typedef struct _log_t {
+ char file[SH_PATHBUF];
+ char format[SH_PATHBUF];
+ /*@null@*/char * msg;
+ size_t msg_len;
+ int severity;
+ int class;
+ int pid;
+ long status;
+ long line;
+ char timestamp[TIM_MAX];
+} sh_log_t;
+
+
+struct _errFlags errFlags;
+
+static int sh_error_init (void);
+
+inline
+static const char * get_format(unsigned long msg_id, int * priority,
+ unsigned int * class);
+
+static int sh_error_string (struct _log_t * lmsg, va_list vl);
+
+extern int sh_log_console (/*@null@*/const char *message);
+extern int sh_log_syslog (int severity, /*@null@*/char *message);
+extern int sh_log_file (/*@null@*/char *message,
+ /*@null@*/char * inet_peer);
+/* convert a string to a numeric priority
+ */
+int sh_error_convert_level (const char * str_s);
+
+static int IsInitialized = BAD;
+
+/* --- Only log to stderr. ---
+ */
+int OnlyStderr = S_TRUE;
+
+/* --- Enable facilities not safe for closeall(). ---
+ */
+int enableUnsafe = S_FALSE;
+
+/*********************************************
+ * utility functions for verifying entries
+ *********************************************/
+
+int sh_error_verify (const char * s)
+{
+ char * foo;
+ char hashbuf[KEYBUF_SIZE];
+
+ if (s[0] == '/')
+ {
+ foo = sh_tiger_hash_gpg (s, TIGER_FILE, TIGER_NOLIM);
+ fprintf (stdout, _("%s\n"), foo);
+ SH_FREE(foo);
+ }
+ else
+ {
+ fprintf (stdout, _("string=<%s>, hash=<%s>\n"),
+ s, sh_tiger_hash (s, TIGER_DATA,
+ (unsigned long) sl_strlen(s),
+ hashbuf, sizeof(hashbuf))
+ );
+ }
+ (void) fflush(stdout);
+ _exit (EXIT_SUCCESS);
+ /*@i@*/return 0;
+}
+
+
+
+/*********************************************
+ * end utility functions
+ *********************************************/
+
+void sh_error_only_stderr (int flag)
+{
+ OnlyStderr = flag;
+ return;
+}
+
+void sh_error_enable_unsafe (int flag)
+{
+ enableUnsafe = flag;
+ return;
+}
+
+static int dbg_store = 0;
+static int dbg_flag = 0;
+
+static
+void compute_flag_err_debug(void)
+{
+ if ((errFlags.loglevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.printlevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.maillevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.exportlevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.sysloglevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.externallevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.databaselevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else if ((errFlags.preludelevel & SH_ERR_ALL) != 0)
+ flag_err_debug = S_TRUE;
+ else
+ flag_err_debug = S_FALSE;
+ return;
+}
+
+static
+void compute_flag_err_info(void)
+{
+ if ((errFlags.loglevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.printlevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.maillevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.exportlevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.sysloglevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.externallevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.databaselevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else if ((errFlags.preludelevel & SH_ERR_INFO) != 0)
+ flag_err_info = S_TRUE;
+ else
+ flag_err_info = S_FALSE;
+ return;
+}
+
+void sh_error_dbg_switch(void)
+{
+ if (dbg_flag == 0)
+ {
+ dbg_store = errFlags.printlevel;
+ errFlags.printlevel = (SH_ERR_ALL | SH_ERR_INFO | SH_ERR_NOTICE |
+ SH_ERR_WARN | SH_ERR_STAMP | SH_ERR_ERR |
+ SH_ERR_SEVERE | SH_ERR_FATAL);
+ dbg_flag = 1;
+ flag_err_debug = S_TRUE;
+ }
+ else {
+ errFlags.printlevel = dbg_store;
+ dbg_store = 0;
+ dbg_flag = 0;
+ compute_flag_err_debug();
+ }
+ return;
+}
+
+static int sh_error_set_classmask (const char * str, int * facility_mask)
+{
+ char * p;
+ int num = 0;
+ unsigned int i;
+ size_t len;
+ char * c;
+
+ SL_ENTER(_("sh_error_set_classmask"));
+
+ if (str == NULL)
+ SL_RETURN( -1, _("sh_error_set_classmask"));
+
+ if (IsInitialized == BAD)
+ (void) sh_error_init();
+
+ if (str[0] == (char) 34)
+ ++str;
+ len = strlen(str);
+
+ c = SH_ALLOC(len+1);
+ sl_strlcpy(c, str, len+1);
+
+ if (c[len-1] == (char) 34)
+ c[len-1] = '\0';
+
+ *facility_mask = 0;
+
+ do {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+ if (num == 0) {
+ p = strtok_r (c, " ,\t", &saveptr);
+ ++num;
+ } else {
+ p = strtok_r (NULL, " ,\t", &saveptr);
+ }
+#else
+ if (num == 0) {
+ p = strtok (c, " ,\t");
+ ++num;
+ } else {
+ p = strtok (NULL, " ,\t");
+ }
+#endif
+
+ if (p == NULL)
+ break;
+
+ for (i = 0; i < SH_CLA_MAX; ++i)
+ {
+ if (i < SH_CLA_RAW_MAX) {
+ if (0 == strcmp(p, _(class_cat[i])))
+ *facility_mask |= (1 << i);
+ } else {
+ if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 0])))
+ *facility_mask |= OTHER_CLA;
+ if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 1])))
+ *facility_mask |= RUN_NEW;
+ if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 2])))
+ *facility_mask |= FIL_NEW;
+ if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 3])))
+ *facility_mask |= ERROR_CLA;
+ }
+ }
+
+ } while (p);
+
+ SH_FREE(c);
+ SL_RETURN( 0, _("sh_error_set_classmask"));
+}
+
+int sh_error_log_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.log_class)));
+}
+int sh_error_mail_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.mail_class)));
+}
+int sh_error_print_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.print_class)));
+}
+int sh_error_export_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.export_class)));
+}
+int sh_error_syslog_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.syslog_class)));
+}
+int sh_error_external_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.external_class)));
+}
+int sh_error_database_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.database_class)));
+}
+int sh_error_prelude_mask (const char * c)
+{
+ return (sh_error_set_classmask(c, &(errFlags.prelude_class)));
+}
+
+
+
+char * sh_error_message (int tellme, char * str, size_t len)
+{
+
+#if defined(HAVE_STRERROR_R)
+ if (len > 0) str[0] = '\0';
+ strerror_r(tellme, str, len);
+ return str;
+#elif defined(HAVE_STRERROR)
+ sl_strlcpy(str, strerror(tellme), len);
+ return str;
+#else
+
+ char *p = NULL;
+#ifdef EACCES
+ if (tellme == EACCES) p = _("Permission denied.");
+#endif
+#ifdef EAGAIN
+ if (tellme == EAGAIN) p = _("Try again.");
+#endif
+#ifdef EBADF
+ if (tellme == EBADF) p = _("File descriptor in bad state.");
+#endif
+#ifdef EEXIST
+ if (tellme == EEXIST) p = _("File exists.");
+#endif
+#ifdef EFAULT
+ if (tellme == EFAULT) p = _("Bad address.");
+#endif
+#ifdef EINVAL
+ if (tellme == EINVAL) p = _("Invalid argument.");
+#endif
+#ifdef EISDIR
+ if (tellme == EISDIR) p = _("Is a directory.");
+#endif
+#ifdef EINTR
+ if (tellme == EINTR) p = _("System call was interrupted.");
+#endif
+#ifdef EIO
+ if (tellme == EIO) p = _("Low-level I/O error.");
+#endif
+#ifdef ELOOP
+ if (tellme == ELOOP) p = _("Too many symbolic links encountered.");
+#endif
+#ifdef EMFILE
+ if (tellme == EMFILE) p = _("Too many open files.");
+#endif
+#ifdef EMLINK
+ if (tellme == EMLINK) p = _("Too many links.");
+#endif
+#ifdef ENAMETOOLONG
+ if (tellme == ENAMETOOLONG)
+ p = _("File name too long.");
+#endif
+#ifdef ENFILE
+ if (tellme == ENFILE) p = _("File table overflow.");
+#endif
+#ifdef ENOENT
+ if (tellme == ENOENT) p = _("File does not exist.");
+#endif
+#ifdef ENOMEM
+ if (tellme == ENOMEM) p = _("Out of memory.");
+#endif
+#ifdef ENOSPC
+ if (tellme == ENOSPC) p = _("No space on device.");
+#endif
+#ifdef ENOTDIR
+ if (tellme == ENOTDIR) p = _("Not a directory.");
+#endif
+#ifdef ENOTSOCK
+ if (tellme == ENOTSOCK) p = _("Not a socket.");
+#endif
+#ifdef EOPNOTSUPP
+ if (tellme == EOPNOTSUPP) p = _("Socket is not of type SOCK_STREAM.");
+#endif
+#ifdef EPERM
+ if (tellme == EPERM) p = _("Permission denied.");
+#endif
+#ifdef EPIPE
+ if (tellme == EPIPE) p = _("No read on pipe.");
+#endif
+#ifdef EROFS
+ if (tellme == EROFS) p = _("Read-only file system.");
+#endif
+#ifdef ETXTBSY
+ if (tellme == ETXTBSY) p = _("Text file busy.");
+#endif
+#ifdef EWOULDBLOCK
+ if (tellme == EWOULDBLOCK)
+ p = _("No connections on non-blocking socket.");
+#endif
+#ifdef EXDEV
+ if (tellme == EXDEV) p = _("Not on same file system.");
+#endif
+ if (!p) p = _("Unknown error");
+ sl_strlcpy(str, p, len);
+ return str;
+#endif /* ifndef HAVE_STRERROR */
+}
+
+
+/* switch off file log
+ */
+void sh_error_logoff()
+{
+ errFlags.HaveLog = BAD;
+ return;
+}
+
+/* switch on file log
+ */
+void sh_error_logrestore()
+{
+ errFlags.HaveLog = GOOD;
+ return;
+}
+
+/* --- Relate priority levels to literals. ---
+ */
+typedef struct eef
+{
+ const char * str;
+ int val;
+} eef_struc;
+
+static eef_struc eef_tab[] =
+{
+ { N_("none"), SH_ERR_NOT },
+ { N_("debug"), SH_ERR_ALL },
+ { N_("info"), SH_ERR_INFO },
+ { N_("notice"), SH_ERR_NOTICE },
+ { N_("warn"), SH_ERR_WARN },
+ { N_("mark"), SH_ERR_STAMP },
+ { N_("err"), SH_ERR_ERR },
+ { N_("crit"), SH_ERR_SEVERE },
+ { N_("alert"), SH_ERR_FATAL },
+#if defined(SH_WITH_SERVER)
+#define SH_EEF_MAX 10
+ { N_("inet"), SH_ERR_INET },
+#else
+#define SH_EEF_MAX 9
+#endif
+};
+
+int sh_error_convert_level (const char * str_s)
+{
+ int i;
+ int level = (-1);
+
+ SL_ENTER(_("sh_error_convert_level"));
+
+ if (str_s == NULL)
+ SL_RETURN( -1, _("sh_error_convert_level"));
+
+ for (i = 0; i < SH_EEF_MAX; ++i)
+ {
+ if (0 == sl_strncmp(str_s, _(eef_tab[i].str),
+ sl_strlen(eef_tab[i].str)))
+ {
+ level = eef_tab[i].val;
+ break;
+ }
+ }
+
+ SL_RETURN( level, _("sh_error_convert_level"));
+}
+
+
+/* --- Set severity levels. ---
+ */
+int sh_error_set_iv (int iv, const char * str_s)
+{
+ int level = (-1);
+
+ SL_ENTER(_("sh_error_set_iv"));
+
+ if (IsInitialized == BAD)
+ (void) sh_error_init();
+
+ level = sh_error_convert_level (str_s);
+
+ if (level == (-1))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("severity"),
+ str_s != NULL ? str_s : _("(NULL)"));
+ SL_RETURN (-1, _("sh_error_set_iv"));
+ }
+
+ if (iv > SH_ERR_T_START && iv < SH_ERR_T_END)
+ {
+ ShDFLevel[iv] = level;
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALL,
+ _("severity"), (long) iv);
+ SL_RETURN (-1, _("sh_error_set_iv"));
+ }
+ SL_RETURN (0, _("sh_error_set_iv"));
+}
+
+int sh_error_set_level(const char * str_in, int * facility)
+{
+ register int i, j, f = BAD;
+
+ int old_facility;
+ const char * str_s = str_in;
+
+ SL_ENTER(_("sh_error_set_level"));
+
+ if (IsInitialized == BAD)
+ (void) sh_error_init();
+
+ old_facility = *facility;
+ *facility = 0;
+
+ checkstr:
+
+ if (str_s != NULL)
+ {
+ if (0 == sl_strncmp(str_s, _(eef_tab[0].str), sl_strlen(eef_tab[0].str)))
+ {
+ *facility |= eef_tab[0].val; /* This is 'none' */
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ *facility &= ~eef_tab[i].val;
+ f = GOOD;
+ }
+ else if (str_s[0] == '*') /* all */
+ {
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ *facility |= eef_tab[i].val;
+ f = GOOD;
+ }
+ else if (str_s[0] == '=')
+ {
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ if (0 == sl_strncmp(&str_s[1], _(eef_tab[i].str),
+ sl_strlen(eef_tab[i].str)))
+ {
+ *facility |= eef_tab[i].val;
+ f = GOOD;
+ }
+ }
+ else if (str_s[0] == '!')
+ {
+ if (str_s[1] == '*' ||
+ 0 == sl_strncmp(&str_s[1], _(eef_tab[1].str),
+ sl_strlen(eef_tab[1].str)))
+ {
+ *facility |= eef_tab[0].val; /* This is 'none' */
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ *facility &= ~eef_tab[i].val;
+ f = GOOD;
+ }
+ else if (str_s[1] == '=')
+ {
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ {
+ if (0 == sl_strncmp(&str_s[2], _(eef_tab[i].str),
+ sl_strlen(eef_tab[i].str)))
+ {
+ *facility &= ~eef_tab[i].val;
+ f = GOOD;
+ }
+ }
+ }
+ else
+ {
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ {
+ if (0 == sl_strncmp(&str_s[1], _(eef_tab[i].str),
+ sl_strlen(eef_tab[i].str)))
+ {
+ for (j = i; j < SH_EEF_MAX; ++j)
+ {
+ *facility &= ~eef_tab[j].val;
+ }
+ f = GOOD;
+ }
+ }
+ }
+ }
+ else /* plain severity name */
+ {
+ for (i = 1; i < SH_EEF_MAX; ++i)
+ {
+ if (0 == sl_strncmp(str_s, _(eef_tab[i].str),
+ sl_strlen(eef_tab[i].str)))
+ {
+ for (j = i; j < SH_EEF_MAX; ++j)
+ {
+ *facility |= eef_tab[j].val;
+ }
+ f = GOOD;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!str_s)
+ {
+ SL_RETURN ((-1), _("sh_error_set_level"));
+ }
+ /* skip to end of string
+ */
+ while (*str_s != '\0' && *str_s != ';' && *str_s != ',' &&
+ *str_s != ' ' && *str_s != '\t')
+ ++str_s;
+
+ /* skip seperator
+ */
+ while ((*str_s != '\0') &&
+ (*str_s == ';' || *str_s == ',' || *str_s == ' ' || *str_s == '\t'))
+ ++str_s;
+
+ if (*str_s != '\0')
+ {
+ f = BAD;
+ goto checkstr;
+ }
+
+ if (f == BAD)
+ {
+ *facility = old_facility;
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("priority"), str_in);
+ SL_RETURN (-1, _("sh_error_set_level"));
+ }
+ compute_flag_err_debug();
+ compute_flag_err_info();
+ SL_RETURN (0, _("sh_error_set_level"));
+}
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+/* set severity for TCP export
+ */
+int sh_error_setexport(const char * str_s)
+{
+ static int reject = 0;
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return (sh_error_set_level(str_s, &errFlags.exportlevel));
+}
+#endif
+
+/* set severity for printing
+ */
+extern void dlog_set_active(int flag);
+
+int sh_error_setprint(const char * str_s)
+{
+ static int reject = 0;
+ int retval;
+
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ retval = sh_error_set_level(str_s, &errFlags.printlevel);
+
+ if (0 != (errFlags.printlevel & SH_ERR_INFO))
+ dlog_set_active(1);
+ if (0 != (errFlags.printlevel & SH_ERR_ALL))
+ dlog_set_active(2);
+ return retval;
+}
+
+
+/* set level for error logging
+ */
+int sh_error_setlog(const char * str_s)
+{
+ static int reject = 0;
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return ( sh_error_set_level(str_s, &errFlags.loglevel) );
+}
+
+
+/* set severity for syslog
+ */
+int sh_error_set_syslog (const char * str_s)
+{
+ static int reject = 0;
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return (sh_error_set_level(str_s, &errFlags.sysloglevel));
+}
+
+#if defined(WITH_EXTERNAL)
+/* set severity for external
+ */
+int sh_error_set_external (const char * str_s)
+{
+ static int reject = 0;
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return (sh_error_set_level(str_s, &errFlags.externallevel));
+}
+#endif
+
+#if defined(WITH_DATABASE)
+/* set severity for database
+ */
+int sh_error_set_database (const char * str_s)
+{
+ static int reject = 0;
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return (sh_error_set_level(str_s, &errFlags.databaselevel));
+}
+#endif
+
+#if defined(HAVE_LIBPRELUDE)
+/* set severity for prelude
+ */
+int sh_error_set_prelude (const char * str_s)
+{
+ static int reject = 0;
+
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return sh_error_set_level(str_s, &errFlags.preludelevel);
+}
+#endif
+
+/* init or re-init log facilities that need it
+ */
+void sh_error_fixup(void)
+{
+#if defined(HAVE_LIBPRELUDE)
+ if ((errFlags.preludelevel & SH_ERR_NOT) == 0)
+ sh_prelude_init();
+ else
+ sh_prelude_stop();
+#endif
+#ifdef WITH_DATABASE
+ sh_database_reset();
+#endif
+ return;
+}
+
+/* to be called from sh_prelude_reset
+ */
+void sh_error_init_prelude(void)
+{
+#if defined(HAVE_LIBPRELUDE)
+ if ((errFlags.preludelevel & SH_ERR_NOT) == 0)
+ sh_prelude_init();
+ else
+ sh_prelude_stop();
+#endif
+ return;
+}
+
+
+/* set severity for mailing
+ */
+int sh_error_setseverity (const char * str_s)
+{
+ static int reject = 0;
+ if (reject == 1)
+ return (0);
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ return (sh_error_set_level(str_s, &errFlags.maillevel));
+}
+
+#ifdef SH_WITH_SERVER
+static char inet_peer[SH_MINIBUF] = { '\0' };
+#ifdef HAVE_LIBPRELUDE
+static char inet_peer_ip[SH_IP_BUF] = { '\0' };
+
+void sh_error_set_peer_ip(const char * str)
+{
+ if (str == NULL)
+ inet_peer_ip[0] = '\0';
+ else
+ sl_strlcpy(inet_peer_ip, str, sizeof(inet_peer_ip));
+}
+#endif
+
+void sh_error_set_peer(const char * str)
+{
+ if (str == NULL)
+ inet_peer[0] = '\0';
+ else
+ sl_strlcpy(inet_peer, str, sizeof(inet_peer));
+}
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+#include "sh_checksum.h"
+static char * sh_error_replace(const char * msg)
+{
+ char * ret = NULL;
+
+ if (sh_tiger_get_hashtype () == SH_SHA256)
+ {
+ char * store = NULL;
+
+#ifdef SH_USE_XML
+ char c_end = '"';
+ char * str = _("chksum_old=\"");
+ char * str2 = _("chksum_new=\"");
+#else
+ char c_end = '>';
+ char * str = _("chksum_old=<");
+ char * str2 = _("chksum_new=<");
+#endif
+
+ ret = SHA256_ReplaceBaseByHex(msg, str, c_end);
+
+ if (ret) {
+ store = ret;
+ ret = SHA256_ReplaceBaseByHex(ret, str2, c_end);
+ if (ret)
+ SH_FREE(store);
+ else
+ ret = store;
+ } else {
+ ret = SHA256_ReplaceBaseByHex(msg, str2, c_end);
+ }
+ }
+ return ret;
+}
+static void sh_replace_free(char * msg)
+{
+ if (msg)
+ SH_FREE(msg);
+ return;
+}
+#else
+static char * sh_error_replace(const char * msg) { (void) msg; return NULL; }
+static void sh_replace_free(char * msg) { (void) msg; return; }
+#endif
+
+/**********************************************************
+ **********************************************************
+ *
+ * -------- MAIN ERROR HANDLING FUNCTION -----------------
+ *
+ *
+ * this function should be called to report an error
+ *
+ **********************************************************
+ **********************************************************/
+
+SH_MUTEX_RECURSIVE(mutex_err_handle);
+
+void sh_error_handle (int sev1, const char * file, long line,
+ long status, unsigned long msg_id, ...)
+{
+ va_list vl; /* argument list */
+ struct _log_t * lmsg;
+
+ int severity;
+ unsigned int class;
+ const char * fmt;
+ volatile int sev = sev1; /* Avoids the 'clobbered by longjmp' warning. */
+
+ int flag_inet;
+
+#ifdef SH_WITH_SERVER
+ int class_inet = clt_class; /* initialize from global */
+ char local_inet_peer[SH_MINIBUF];
+#ifdef HAVE_LIBPRELUDE
+ char local_inet_peer_ip[SH_IP_BUF];
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+ char * ex_msg;
+#endif
+#if defined(WITH_DATABASE)
+ char * escape_msg;
+#endif
+
+ char * hexmsg = NULL;
+
+ static int own_block = 0;
+
+ /*
+ * Block a facility for errors generated
+ * within that facility.
+ */
+ static int print_block = 0;
+#if defined(SH_WITH_MAIL)
+ static int mail_block = 0;
+#endif
+ static int syslog_block = 0;
+ static int log_block = 0;
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+ static int export_block = 0;
+#endif
+#if defined(WITH_EXTERNAL)
+ static int external_block = 0;
+#endif
+#if defined(WITH_DATABASE)
+ static int database_block = 0;
+#endif
+#ifdef HAVE_LIBPRELUDE
+ static int prelude_block = 0;
+#endif
+
+ SL_ENTER(_("sh_error_handle"));
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_err_handle);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_err_handle);
+
+#ifdef SH_WITH_SERVER
+ /* copy the global string into a local array
+ */
+ if ((msg_id == MSG_TCP_MSG) && (inet_peer[0] != '\0'))
+ {
+ sl_strlcpy(local_inet_peer, inet_peer, sizeof(local_inet_peer));
+ sh_error_set_peer(NULL);
+ }
+ else
+ local_inet_peer[0] = '\0';
+
+#ifdef HAVE_LIBPRELUDE
+ if ((msg_id == MSG_TCP_MSG) && (inet_peer_ip[0] != '\0'))
+ {
+ sl_strlcpy(local_inet_peer_ip, inet_peer_ip, sizeof(local_inet_peer_ip));
+ sh_error_set_peer_ip(NULL);
+ }
+ else
+ local_inet_peer_ip[0] = '\0';
+#endif
+
+ clt_class = (-1); /* reset global */
+#endif
+
+
+ if (own_block == 1)
+ {
+ goto exit_here;
+ }
+
+ /* --- Initialize to default values. ---
+ */
+ if (IsInitialized == BAD)
+ (void) sh_error_init();
+
+ /* Returns pointer to (constant|thread-specific) static memory
+ */
+ fmt = /*@i@*/get_format (msg_id, &severity, &class);
+
+#ifdef SH_WITH_SERVER
+ if (class_inet != (-1))
+ class = (unsigned int) class_inet;
+#endif
+
+ /* --- Consistency check. ---
+ */
+ ASSERT((fmt != NULL), _("fmt != NULL"))
+ if (fmt == NULL)
+ {
+ fprintf(stderr,
+ _("ERROR: msg=<NULL format>, file=<%s>, line=<%ld>\n"),
+ file, line);
+ goto exit_here;
+ }
+
+ /* --- Override the catalogue severity. ---
+ */
+ if (sev != (-1))
+ severity = sev;
+
+ /* --- Some statistics. ---
+ */
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if ( ((1 << class) & ERROR_CLA) &&
+ (severity & (SH_ERR_ERR|SH_ERR_SEVERE|SH_ERR_FATAL)))
+ {
+ ++sh.statistics.files_error;
+ }
+#endif
+
+ /* these are messages from remote sources
+ */
+ if ((severity & SH_ERR_INET) != 0)
+ {
+ flag_inet = S_TRUE;
+ }
+ else
+ {
+ flag_inet = S_FALSE;
+ }
+
+ /* --- Messages not wanted for logging. ---
+ */
+ if ( ( (errFlags.printlevel & severity ) == 0 ||
+ (errFlags.print_class & (1 << class)) == 0 ) &&
+ ( (errFlags.loglevel & severity ) == 0 ||
+ (errFlags.log_class & (1 << class)) == 0 ) &&
+ ( (errFlags.sysloglevel & severity ) == 0 ||
+ (errFlags.syslog_class & (1 << class)) == 0 ) &&
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_CLIENT)
+ ( (errFlags.exportlevel & severity ) == 0 ||
+ (errFlags.export_class & (1 << class)) == 0 ) &&
+#endif
+#ifdef WITH_EXTERNAL
+ ( (errFlags.externallevel & severity ) == 0 ||
+ (errFlags.external_class & (1 << class)) == 0 ) &&
+#endif
+#ifdef HAVE_LIBPRELUDE
+ ( (errFlags.preludelevel & severity ) == 0 ||
+ (errFlags.prelude_class & (1 << class)) == 0 ) &&
+#endif
+#ifdef WITH_DATABASE
+ ( (errFlags.databaselevel & severity ) == 0 ||
+ (errFlags.database_class & (1 << class)) == 0 ) &&
+#endif
+ ( (errFlags.maillevel & severity ) == 0 ||
+ (errFlags.mail_class & (1 << class)) == 0 )
+#ifdef SH_WITH_SERVER
+ && (flag_inet == S_FALSE) /* still log messages from remote sources */
+#endif
+ )
+ {
+ goto exit_here;
+ }
+
+ if ((severity & SH_ERR_NOT) != 0)
+ {
+ goto exit_here;
+ }
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ if ((sh_global_check_silent > SH_SILENT_STD) &&
+ (((1 << FIL) & (1 << class)) != 0))
+ {
+ goto exit_here;
+ }
+#endif
+
+ /* Allocate space for the message.
+ */
+ own_block = 1;
+ lmsg = (struct _log_t *) SH_ALLOC(sizeof(struct _log_t));
+ MLOCK( (char *) lmsg, sizeof(struct _log_t));
+ /*@i@*/lmsg->msg = NULL;
+
+ /*@i@*/(void) sl_strlcpy(lmsg->format, fmt, SH_PATHBUF);
+ (void) sl_strlcpy(lmsg->file, file, SH_PATHBUF);
+ lmsg->severity = severity;
+ lmsg->class = (int) class;
+ lmsg->line = line;
+ lmsg->status = status;
+
+ /* Format the log message with timestamp etc.
+ * Allocate lmsg->msg
+ */
+ va_start (vl, msg_id);
+ (void) sh_error_string (lmsg, vl);
+ va_end (vl);
+ own_block = 0;
+
+ hexmsg = sh_error_replace(lmsg->msg);
+
+ /* Log to stderr.
+ */
+ if ( ((errFlags.printlevel & severity) != 0 &&
+ (errFlags.print_class & (1 << class)) != 0 &&
+ (errFlags.printlevel & SH_ERR_NOT) == 0)
+#ifdef SH_WITH_SERVER
+ || (flag_inet == S_TRUE)
+#endif
+ )
+ {
+ if (print_block == 0 && (errFlags.printlevel & SH_ERR_NOT) == 0)
+ {
+ /* no truncation
+ */
+ print_block = 1;
+ TPT(( 0, FIL__, __LINE__, lmsg->msg));
+ /*
+ * Reports first error after failure. Always tries.
+ */
+ (void) sh_log_console (hexmsg ? hexmsg : lmsg->msg);
+ print_block = 0;
+ }
+ }
+
+
+ /* Full logging enabled.
+ */
+ if (OnlyStderr == S_FALSE) /* full error logging enabled */
+ {
+
+ /* Log to syslog.
+ */
+ if ( (errFlags.sysloglevel & severity) != 0 &&
+ (errFlags.syslog_class & (1 << class)) != 0 &&
+#ifndef INET_SYSLOG
+ (flag_inet != S_TRUE) && /* !inet->syslog */
+#endif
+ (errFlags.sysloglevel & SH_ERR_NOT) == 0 )
+ {
+ /* will truncate to 1023 bytes
+ */
+ if (syslog_block == 0)
+ {
+ syslog_block = 1;
+ /*
+ * Ignores errors. Always tries.
+ */
+ (void) sh_log_syslog (lmsg->severity, hexmsg ? hexmsg : lmsg->msg);
+ syslog_block = 0;
+ }
+ }
+
+#if defined(WITH_EXTERNAL)
+ /*
+ * -- external facility
+ */
+ if ((errFlags.externallevel & severity) != 0 &&
+ (errFlags.external_class & (1 << class)) != 0 &&
+ (errFlags.externallevel & SH_ERR_NOT) == 0 &&
+ class != AUD)
+ {
+ if (external_block == 0)
+ {
+ /* no truncation
+ */
+ external_block = 1;
+ /*
+ * Reports first error after failure. Always tries.
+ */
+ (void) sh_ext_execute ('l', 'o', 'g', hexmsg ? hexmsg : lmsg->msg, 0);
+ external_block = 0;
+ }
+ }
+#endif
+
+#if defined(WITH_DATABASE)
+ /*
+ * -- database facility
+ */
+ if ((errFlags.databaselevel & severity) != 0 &&
+ (errFlags.database_class & (1 << class)) != 0 &&
+ (errFlags.databaselevel & SH_ERR_NOT) == 0 &&
+ class != AUD)
+ {
+ if (database_block == 0 && enableUnsafe == S_TRUE)
+ {
+ /* truncates; query_max is 16k
+ */
+ database_block = 1;
+#ifndef SH_STANDALONE
+ if (msg_id == MSG_TCP_MSG
+#ifdef INET_SYSLOG
+ || msg_id == MSG_INET_SYSLOG
+#endif
+ )
+ {
+ /* do not escape twice
+ */
+ /*
+ * Reports failure every 60 min. Always tries.
+ */
+ (void) sh_database_insert (lmsg->msg);
+ }
+ else
+#endif
+ {
+ escape_msg = sh_tools_safe_name(lmsg->msg, 0);
+ /*
+ * Reports failure every 60 min. Always tries.
+ */
+ (void) sh_database_insert (escape_msg);
+ SH_FREE(escape_msg);
+ }
+ database_block = 0;
+ }
+ }
+#endif
+
+ /****************************************************
+ * Optionally include client code for TCP forwarding
+ * to log server
+ ****************************************************/
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+ /* Export by TCP.
+ */
+
+ if ( ((errFlags.exportlevel & severity ) != 0 &&
+ (errFlags.export_class & (1 << class)) != 0 &&
+ (errFlags.exportlevel & SH_ERR_NOT) == 0 &&
+ class != AUD )
+#ifdef SH_WITH_SERVER
+ /* always log inet to export */
+ || (flag_inet == S_TRUE && sh.srvexport.name[0] != '\0')
+#endif
+ /* sh.flag.isserver != GOOD && */
+ /* (flag_inet == S_FALSE) */ /* don't log inet to export */
+ )
+ {
+ if (export_block == 0)
+ {
+ int retval;
+ size_t ex_len;
+
+ /* will truncate to 65280 bytes
+ */
+ export_block = 1;
+ /* ex_len = 64 + sl_strlen(lmsg->msg) + 1; */
+ ex_len = sl_strlen(lmsg->msg);
+ if (sl_ok_adds(ex_len, 65))
+ ex_len = 64 + ex_len + 1;
+ ex_msg = SH_ALLOC (ex_len);
+
+ sl_snprintf(ex_msg, ex_len, _("%d?%u?%s"),
+ severity, class, lmsg->msg);
+ retval = sh_xfer_report (ex_msg);
+ SH_FREE(ex_msg);
+ export_block = 0;
+ if (retval == -2)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_QUEUE_FULL,
+ _("log server"));
+ }
+ }
+ }
+#endif
+
+
+ /* Log to mail.
+ */
+#if defined(SH_WITH_MAIL)
+ if ((errFlags.maillevel & severity ) != 0 &&
+ (errFlags.mail_class & (1 << class)) != 0 &&
+ (errFlags.maillevel & SH_ERR_NOT) == 0 &&
+ class != AUD &&
+ (flag_inet == S_FALSE) ) /* don't log inet to email */
+ {
+ if (mail_block == 0)
+ {
+ int retval;
+
+ /* will truncate to 998 bytes
+ */
+ mail_block = 1;
+
+ BREAKEXIT(sh_nmail_msg);
+ if ( (severity & SH_ERR_FATAL) == 0)
+ retval = sh_nmail_pushstack (severity, hexmsg ? hexmsg : lmsg->msg, NULL);
+ else
+ retval = sh_nmail_msg (severity, hexmsg ? hexmsg : lmsg->msg, NULL);
+
+ mail_block = 0;
+ if (retval == -2)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_QUEUE_FULL,
+ _("email"));
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_LIBPRELUDE
+ if (((errFlags.preludelevel & severity ) != 0 &&
+ (errFlags.prelude_class & (1 << class)) != 0 &&
+ (errFlags.preludelevel & SH_ERR_NOT) == 0 &&
+ (class != AUD))
+#ifdef SH_WITH_SERVER
+ || (flag_inet == S_TRUE)
+#endif
+ )
+ {
+ if (prelude_block == 0 && enableUnsafe == S_TRUE)
+ {
+ /* will truncate to 998 bytes
+ */
+ prelude_block = 1;
+
+ BREAKEXIT(sh_prelude_alert);
+ /*
+ * Reports first error after failure. Always tries.
+ */
+#if defined(HAVE_LIBPRELUDE) && defined(SH_WITH_SERVER)
+ (void) sh_prelude_alert (severity, (int) class,
+ hexmsg ? hexmsg : lmsg->msg, lmsg->status, msg_id,
+ local_inet_peer_ip);
+#else
+ (void) sh_prelude_alert (severity, (int) class,
+ hexmsg ? hexmsg : lmsg->msg, lmsg->status, msg_id,
+ NULL);
+#endif
+ prelude_block = 0;
+ }
+ }
+#endif
+
+ /* Log to logfile
+ */
+
+ if ( ( ( (errFlags.loglevel & severity) != 0 &&
+ (errFlags.log_class & (1 << class)) != 0 &&
+ (errFlags.loglevel & SH_ERR_NOT) == 0 )
+#ifdef SH_WITH_SERVER
+ || (flag_inet == S_TRUE)
+#endif
+ ) &&
+ class != AUD &&
+ (errFlags.HaveLog != BAD) && /* temporary switched off */
+ (severity & SH_ERR_NOT) == 0 /* paranoia */
+ )
+ {
+ if (log_block == 0)
+ {
+ /* no truncation
+ */
+ log_block = 1;
+ BREAKEXIT(sh_log_file);
+#ifdef SH_WITH_SERVER
+ if (0 != sl_ret_euid())
+ {
+ /*
+ * Reports first error after failure. Always tries.
+ */
+ if (local_inet_peer[0] == '\0')
+ (void) sh_log_file (lmsg->msg, NULL);
+ else
+ (void) sh_log_file (lmsg->msg, local_inet_peer);
+ }
+#else
+ (void) sh_log_file (hexmsg ? hexmsg : lmsg->msg, NULL);
+#endif
+ /* sh_log_file (lmsg->msg); */
+ log_block = 0;
+ }
+ }
+
+ }
+
+ /* Cleanup.
+ */
+ own_block = 1;
+
+ if (lmsg->msg)
+ SH_FREE( lmsg->msg );
+ sh_replace_free(hexmsg);
+
+ memset ( lmsg, (int) '\0', sizeof(struct _log_t) );
+ MUNLOCK( (char *) lmsg, sizeof(struct _log_t) );
+ SH_FREE( lmsg );
+ own_block = 0;
+
+ exit_here:
+ ; /* label at end of compound statement */
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_err_handle);
+
+ /*@i@*/SL_RET0(_("sh_error_handle"));
+/*@i@*/}
+
+#if defined(SH_WITH_MAIL)
+void sh_error_mail (const char * alias, int sev,
+ const char * file, long line,
+ long status, unsigned long msg_id, ...)
+{
+ va_list vl; /* argument list */
+ struct _log_t * lmsg;
+
+ int severity;
+ unsigned int class;
+ const char * fmt;
+ int retval;
+
+ SL_ENTER(_("sh_error_mail"));
+
+ /* Returns pointer to (constant|thread-specific) static memory
+ */
+ fmt = /*@i@*/get_format (msg_id, &severity, &class);
+
+ if (!fmt)
+ {
+ SL_RET0(_("sh_error_mail"));
+ }
+
+ /* --- Override the catalogue severity. ---
+ */
+ if (sev != (-1))
+ severity = sev;
+
+ /* --- Build the message. ---
+ */
+ lmsg = (struct _log_t *) SH_ALLOC(sizeof(struct _log_t));
+ MLOCK( (char *) lmsg, sizeof(struct _log_t));
+ /*@i@*/lmsg->msg = NULL;
+
+ /*@i@*/(void) sl_strlcpy(lmsg->format, fmt, SH_PATHBUF);
+ (void) sl_strlcpy(lmsg->file, file, SH_PATHBUF);
+ lmsg->severity = severity;
+ lmsg->class = (int) class;
+ lmsg->line = line;
+ lmsg->status = status;
+
+ /* Format the log message with timestamp etc.
+ * Allocate lmsg->msg
+ */
+ va_start (vl, msg_id);
+ (void) sh_error_string (lmsg, vl);
+ va_end (vl);
+
+ if ( (severity & SH_ERR_FATAL) == 0)
+ retval = sh_nmail_pushstack (severity, lmsg->msg, alias);
+ else
+ retval = sh_nmail_msg (severity, lmsg->msg, alias);
+
+ if (retval == -2)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_QUEUE_FULL,
+ _("email"));
+ }
+ SL_RET0(_("sh_error_mail"));
+}
+#else
+void sh_error_mail (const char * alias, int sev,
+ const char * file, long line,
+ long status, unsigned long msg_id, ...)
+{
+ (void) alias;
+ (void) sev;
+ (void) file;
+ (void) line;
+ (void) status;
+ (void) msg_id;
+
+ return;
+}
+/* defined(SH_WITH_MAIL) */
+#endif
+
+/* -------------------------
+ *
+ * private functions below
+ *
+ * -------------------------
+ */
+
+
+/* --- Get the format from the message catalog. ---
+ */
+/*@owned@*/ /*@null@*/inline
+static const char * get_format(unsigned long msg_id, /*@out@*/ int * priority,
+ /*@out@*/unsigned int * class)
+{
+ int i = 0;
+
+ SL_ENTER(_("get_format"));
+ while (1 == 1)
+ {
+ if ( msg_cat[i].format == NULL )
+ break;
+
+ if ( (unsigned long) msg_cat[i].id == msg_id)
+ {
+ *priority = (int) msg_cat[i].priority;
+ *class = (unsigned int) msg_cat[i].class;
+ SL_RETURN (((const char *) _(msg_cat[i].format)), _("get_format"));
+ }
+ ++i;
+ }
+ *priority = SH_ERR_ERR;
+ *class = ERR;
+ SL_RETURN (NULL, _("get_format"));
+}
+
+/*@null@*//*@only@*/static char * ehead_format = NULL;
+
+/* allocate space for user-defined message header
+ */
+int sh_error_ehead (/*@null@*/const char * str_s)
+{
+ size_t size;
+ const char * s;
+
+ SL_ENTER(_("sh_error_ehead"));
+
+ if (str_s == NULL)
+ {
+ SL_RETURN (-1, _("sh_error_ehead"));
+ }
+
+ /* ascii 34 ist t\"ttelchen
+ */
+ /*@i@*/ if (str_s[0] == 34) s = &str_s[1];
+ else s = str_s;
+
+ size = /*@i@*/strlen(s);
+ if (/*@i@*/s[size-1] == (char) 34) --size; /* truncate */
+
+ if (ehead_format != NULL)
+ SH_FREE(ehead_format);
+
+ /*@i@*/ehead_format = SH_ALLOC(size+1);
+ /*@i@*/ (void) sl_strlcpy(ehead_format, s, size+1);
+
+ SL_RETURN( 0, _("sh_error_ehead"));
+}
+
+#if !defined(VA_COPY)
+#if defined(__GNUC__) && defined(__PPC__) && (defined(_CALL_SYSV) || defined(_WIN32))
+#define VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
+#elif defined(VA_COPY_AS_ARRAY)
+#define VA_COPY(ap1, ap2) memmove ((ap1), (ap2), sizeof (va_list))
+#else /* va_list is a pointer */
+#define VA_COPY(ap1, ap2) ((ap1) = (ap2))
+#endif
+#endif
+
+
+/* print an error into string
+ */
+static int sh_error_string (struct _log_t * lmsg, va_list vl)
+{
+ size_t len;
+ int required;
+ unsigned long line;
+ char sev[16] = "";
+ char cla[16] = "";
+ char tst[64] = "";
+ char *p;
+ va_list vl2;
+
+ st_format rep_ehead_tab[] = {
+ { 'S', S_FMT_STRING, 0, 0, NULL}, /* severity */
+ { 'T', S_FMT_STRING, 0, 0, NULL}, /* timestamp */
+ { 'F', S_FMT_STRING, 0, 0, NULL}, /* file */
+ { 'L', S_FMT_ULONG, 0, 0, NULL}, /* line */
+ { 'C', S_FMT_STRING, 0, 0, NULL}, /* class */
+ { 'E', S_FMT_LONG, 0, 0, NULL}, /* status */
+ {'\0', S_FMT_ULONG, 0, 0, NULL},
+ };
+
+ SL_ENTER(_("sh_error_string"));
+
+ if (ehead_format == NULL)
+ {
+ ehead_format = SH_ALLOC(64);
+#ifdef SH_USE_XML
+ if ((errFlags.printlevel & SH_ERR_ALL) == 0)
+ (void) sl_strlcpy(ehead_format,
+ _("<log sev=\"%S\" tstamp=\"%T\" "), 64);
+ else
+ (void) sl_strlcpy(ehead_format,
+ _("<log sev=\"%S\" tstamp=\"%T\" p.f=\"%F\" p.l=\"%L\" p.s=\"%E\" "), 64);
+#else
+ if ((errFlags.printlevel & SH_ERR_ALL) == 0)
+ (void) sl_strlcpy(ehead_format, _("%S %T "), 64);
+ else
+ (void) sl_strlcpy(ehead_format, _("%S %T (%F, %L, %E) "), 64);
+#endif
+ }
+
+ /* header of error message
+ */
+#ifdef SH_USE_XML
+ if ( (lmsg->severity & SH_ERR_INET) != 0)
+ (void) sl_strlcpy (sev, _("RCVT"), 11);
+ else if ( (lmsg->severity & SH_ERR_ALL) != 0)
+ (void) sl_strlcpy (sev, _("DEBG"), 11);
+ else if ( (lmsg->severity & SH_ERR_INFO) != 0)
+ (void) sl_strlcpy (sev, _("INFO"), 11);
+ else if ( (lmsg->severity & SH_ERR_NOTICE) != 0)
+ (void) sl_strlcpy (sev, _("NOTE"), 11);
+ else if ( (lmsg->severity & SH_ERR_WARN) != 0)
+ (void) sl_strlcpy (sev, _("WARN"), 11);
+ else if ( (lmsg->severity & SH_ERR_STAMP) != 0)
+ (void) sl_strlcpy (sev, _("MARK"), 11);
+ else if ( (lmsg->severity & SH_ERR_ERR) != 0)
+ (void) sl_strlcpy (sev, _("ERRO"), 11);
+ else if ( (lmsg->severity & SH_ERR_SEVERE) != 0)
+ (void) sl_strlcpy (sev, _("CRIT"), 11);
+ else if ( (lmsg->severity & SH_ERR_FATAL) != 0)
+ (void) sl_strlcpy (sev, _("ALRT"), 11);
+ else {
+ (void) sl_strlcpy (sev, _("????"), 11);
+#else
+#if defined(INET_SYSLOG)
+ if ( (lmsg->severity & SH_ERR_INET) != 0)
+ (void) sl_strlcpy (sev, _("<NET> : "), 11);
+#else
+ if ( (lmsg->severity & SH_ERR_INET) != 0)
+ (void) sl_strlcpy (sev, _("<TCP> : "), 11);
+#endif
+ else if ( (lmsg->severity & SH_ERR_ALL) != 0)
+ (void) sl_strlcpy (sev, _("DEBUG : "), 11);
+ else if ( (lmsg->severity & SH_ERR_INFO) != 0)
+ (void) sl_strlcpy (sev, _("INFO : "), 11);
+ else if ( (lmsg->severity & SH_ERR_NOTICE) != 0)
+ (void) sl_strlcpy (sev, _("NOTICE : "), 11);
+ else if ( (lmsg->severity & SH_ERR_WARN) != 0)
+ (void) sl_strlcpy (sev, _("WARN : "), 11);
+ else if ( (lmsg->severity & SH_ERR_STAMP) != 0)
+ (void) sl_strlcpy (sev, _("MARK : "), 11);
+ else if ( (lmsg->severity & SH_ERR_ERR) != 0)
+ (void) sl_strlcpy (sev, _("ERROR : "), 11);
+ else if ( (lmsg->severity & SH_ERR_SEVERE) != 0)
+ (void) sl_strlcpy (sev, _("CRIT : "), 11);
+ else if ( (lmsg->severity & SH_ERR_FATAL) != 0)
+ (void) sl_strlcpy (sev, _("ALERT : "), 11);
+ else {
+ (void) sl_strlcpy (sev, _("??? : "), 11);
+#endif
+ }
+
+ (void) sh_unix_time (0, tst, 64);
+ line = (unsigned long) lmsg->line;
+ (void) sl_strlcpy (cla, _(class_cat[lmsg->class]), 11);
+
+ /*@i@*/rep_ehead_tab[0].data_str = sev;
+ /*@i@*/rep_ehead_tab[1].data_str = tst;
+ /*@i@*/rep_ehead_tab[2].data_str = lmsg->file;
+ /*@i@*/rep_ehead_tab[3].data_ulong = line;
+ /*@i@*/rep_ehead_tab[4].data_str = cla;
+ /*@i@*/rep_ehead_tab[5].data_long = lmsg->status;
+
+ p = /*@i@*/sh_util_formatted(ehead_format, rep_ehead_tab);
+
+ /* --- copy the header to lmsg->msg ---
+ */
+ /*@i@*/lmsg->msg = SH_ALLOC(SH_BUFSIZE);
+ lmsg->msg_len = SH_BUFSIZE;
+
+ if (p)
+ {
+ (void) sl_strlcpy (lmsg->msg, p, SH_BUFSIZE);
+ SH_FREE(p);
+ }
+ else
+ {
+ lmsg->msg[0] = '\0';
+ }
+
+
+ /* --- copy message to lmsg->msg ---
+ */
+ if ( NULL == strchr(lmsg->format, '%') )
+ {
+ (void) sl_strlcat (lmsg->msg, lmsg->format, (size_t) lmsg->msg_len);
+ }
+ else
+ {
+ /* use VA_COPY */
+ /*@i@*/VA_COPY(vl2, vl);
+ len = sl_strlen(lmsg->msg);
+ /*@i@*/required = sl_vsnprintf(&(lmsg->msg[len]),
+ (lmsg->msg_len - len), lmsg->format, vl);
+
+ if ((required >= 0) &&
+ sl_ok_adds(required, len) &&
+ sl_ok_adds((required+len), 4) &&
+ ((required + len) > (lmsg->msg_len - 4)) )
+ {
+ /*@i@*/p = SH_ALLOC(required + len + 4);
+ (void) sl_strlcpy (p, lmsg->msg, required + len + 1);
+ SH_FREE(lmsg->msg);
+ lmsg->msg = p;
+ lmsg->msg_len = required + len + 4;
+ (void) sl_vsnprintf(&(lmsg->msg[len]),
+ (required + 1), lmsg->format, vl2);
+ }
+ va_end(vl2);
+ }
+
+#ifdef SH_USE_XML
+ /* closing tag
+ */
+ if (lmsg->msg[sl_strlen(lmsg->msg)-1] != '>')
+ (void) sl_strlcat (lmsg->msg, _(" />"), lmsg->msg_len);
+#endif
+
+ SL_RETURN(0, _("sh_error_string"));
+}
+
+
+
+
+/* --- Initialize. ---
+ */
+static int sh_error_init ()
+{
+ register int j;
+
+ SL_ENTER(_("sh_error_init"));
+
+ errFlags.debug = 0;
+ errFlags.HaveLog = GOOD;
+ errFlags.sysloglevel = SH_ERR_NOT;
+#if defined(SH_STEALTH)
+ errFlags.loglevel = SH_ERR_NOT;
+#else
+ errFlags.loglevel = (SH_ERR_STAMP | SH_ERR_ERR | SH_ERR_SEVERE |
+ SH_ERR_FATAL);
+#endif
+ errFlags.externallevel = SH_ERR_NOT;
+ errFlags.databaselevel = SH_ERR_NOT;
+ errFlags.preludelevel = SH_ERR_NOT;
+ errFlags.maillevel = SH_ERR_FATAL;
+#if defined(SH_STEALTH)
+ errFlags.printlevel = SH_ERR_NOT;
+#else
+ errFlags.printlevel = (SH_ERR_INFO | SH_ERR_NOTICE | SH_ERR_WARN |
+ SH_ERR_STAMP | SH_ERR_ERR | SH_ERR_SEVERE |
+ SH_ERR_FATAL);
+ flag_err_info = S_TRUE;
+#endif
+
+#if defined(SH_WITH_SERVER)
+ errFlags.exportlevel = SH_ERR_NOT;
+#else
+ errFlags.exportlevel = (SH_ERR_STAMP | SH_ERR_ERR | SH_ERR_SEVERE |
+ SH_ERR_FATAL);
+#endif
+
+ errFlags.log_class = 0xFFFF;
+ errFlags.print_class = 0xFFFF;
+ errFlags.mail_class = 0xFFFF;
+ errFlags.export_class = 0xFFFF;
+ errFlags.syslog_class = 0xFFFF;
+ errFlags.external_class = 0xFFFF;
+ errFlags.database_class = 0xFFFF;
+ errFlags.prelude_class = 0xFFFF;
+
+
+ for (j = 0; j < SH_ERR_T_END; ++j)
+ ShDFLevel[j] = SH_ERR_SEVERE;
+
+ IsInitialized = GOOD;
+ SL_RETURN (0, _("sh_error_init"));
+}
diff --git a/src/sh_extern.c b/src/sh_extern.c
new file mode 100644
index 0000000..c048873
--- /dev/null
+++ b/src/sh_extern.c
@@ -0,0 +1,1703 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2000,2004 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config_xor.h"
+
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.'
+ * for debugging
+ */
+#if 0
+#define PDGBFILE "/pdbg."
+#endif
+
+
+#if defined(PDGBFILE)
+static FILE * pdbg = NULL;
+static FILE * pdbgc = NULL;
+#define PDBG_OPEN if (pdbg == NULL) pdbg = fopen(PDGBFILE"main", "a")
+#define PDBG_CLOSE sl_fclose (FIL__, __LINE__, pdbg); pdbg = NULL
+#define PDBG(arg) fprintf(pdbg, "PDBG: step %d\n", arg); fflush(pdbg)
+#define PDBG_D(arg) fprintf(pdbg, "PDBG: %d\n", arg); fflush(pdbg)
+#define PDBG_S(arg) fprintf(pdbg, "PDBG: %s\n", arg); fflush(pdbg)
+
+#define PDBGC_OPEN if (pdbgc == NULL) pdbgc = fopen(PDGBFILE"child", "a")
+#define PDBGC_CLOSE sl_fclose (FIL__, __LINE__, pdbgc); pdbgc = NULL
+#define PDBGC(arg) fprintf(pdbgc, "PDBGC: step %d\n", arg); fflush(pdbgc)
+#define PDBGC_D(arg) fprintf(pdbgc, "PDBGC: %d\n", arg); fflush(pdbgc)
+#define PDBGC_S(arg) fprintf(pdbgc, "PDBGC: %s\n", arg); fflush(pdbgc)
+#else
+#define PDBG_OPEN
+#define PDBG_CLOSE
+#define PDBG(arg)
+#define PDBG_D(arg)
+#define PDBG_S(arg)
+#define PDBGC_OPEN
+#define PDBGC_CLOSE
+#define PDBGC(arg)
+#define PDBGC_D(arg)
+#define PDBGC_S(arg)
+#endif
+
+
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_tiger.h"
+#include "sh_extern.h"
+#include "sh_calls.h"
+#include "sh_filter.h"
+#define SH_NEED_PWD_GRP 1
+#include "sh_static.h"
+
+
+#undef FIL__
+#define FIL__ _("sh_extern.c")
+
+extern int get_the_fd (SL_TICKET ticket);
+
+/*
+ * -- generic safe popen
+ */
+
+int sh_ext_popen (sh_tas_t * task)
+{
+ long status = 0;
+ int flags;
+ char * tmp;
+ char * tmp2;
+ int errnum;
+ int pipedes[2];
+ FILE * outf = NULL;
+ char * envp[1];
+ char * argp[2];
+
+ char * errfile;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ static int some_error = 0;
+
+#if defined (__linux__)
+ SL_TICKET fd = -1;
+ char pname[128];
+ int pfd = -1;
+#endif
+
+ SL_ENTER(_("sh_ext_popen"));
+
+ /* Linux, HP-UX and FreeBSD will happily accept envp = argp = NULL
+ * (newer Linuxes (gcc 4.4.4) warn on argp == NULL, but accept it,
+ * as reported by T. Luettgert)
+ * Solaris (and probably some other Unices)
+ * needs a valid *envp[] with envp[0] = NULL;
+ * and similarly for argp
+ * OpenBSD finally needs non-null argp[0] ...
+ */
+ argp[0] = task->command;
+ argp[1] = NULL;
+ envp[0] = NULL;
+
+ /*
+ * -- check whether path is trustworthy
+ */
+ status = sl_trustfile(task->command, NULL, NULL);
+#if 0
+ if ((uid_t) -1 != task->trusted_users[0])
+ {
+ status = sl_trustfile(task->command, task->trusted_users, NULL);
+ }
+#endif
+
+ PDBG_OPEN;
+ PDBG_D( (int) status);
+
+ if ( SL_ENONE != status)
+ {
+ PDBG_S("SL_ENONE != status");
+ if (some_error == 0)
+ {
+ tmp = sh_util_safe_name (task->command);
+ errfile = sl_trust_errfile();
+ if (errfile[0] != '\0')
+ {
+ tmp2 = sh_util_safe_name (sl_trust_errfile());
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_TRUST2,
+ sl_error_string((int)status), tmp, tmp2);
+ SH_FREE(tmp2);
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_TRUST1,
+ sl_error_string((int)status), tmp);
+ }
+ SH_FREE(tmp);
+ }
+ some_error = 1;
+ SL_RETURN ((-1), _("sh_ext_popen"));
+ }
+
+ PDBG(1);
+
+ /*
+ * -- check whether the checksum is correct; with linux emulate fdexec
+ */
+#if ( !defined(__linux__) || ( defined(__linux__) && defined(HAVE_PTHREAD)) ) && !defined(SL_DEBUG)
+ if (task->checksum[0] != '\0')
+ {
+ char hashbuf[KEYBUF_SIZE];
+ PDBG_S("checksum test");
+ if (0 != sl_strcmp(task->checksum,
+ sh_tiger_hash (task->command, TIGER_FILE, TIGER_NOLIM,
+ hashbuf, sizeof(hashbuf))
+ )
+ )
+ {
+ PDBG_S("checksum mismatch");
+ if (some_error == 0)
+ {
+ tmp = sh_util_safe_name (task->command);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_HASH, tmp);
+ SH_FREE(tmp);
+ }
+ some_error = 1;
+ SL_RETURN ((-1), _("sh_ext_popen"));
+ }
+ }
+#endif
+
+ some_error = 0;
+
+ PDBG(2);
+
+ /*
+ * -- Create the pipe
+ */
+ if (aud_pipe(FIL__, __LINE__, pipedes) < 0)
+ {
+ PDBG_S("pipe() failure");
+ errnum = errno;
+ sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ sh_error_message(errnum, errbuf, sizeof(errbuf)), _("pipe"));
+ SL_RETURN ((-1), _("sh_ext_popen"));
+ }
+
+ PDBG(3);
+
+ /*
+ * -- Flush streams and fork
+ */
+ fflush (NULL);
+
+ task->pid = aud_fork(FIL__, __LINE__);
+
+ if (task->pid == (pid_t) - 1)
+ {
+ PDBG_S("fork() failure");
+ /*@-usedef@*/
+ (void) sl_close_fd(FIL__, __LINE__, pipedes[0]);
+ (void) sl_close_fd(FIL__, __LINE__, pipedes[1]);
+ /*@+usedef@*/
+ errnum = errno;
+ sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ sh_error_message(errnum, errbuf, sizeof(errbuf)), _("fork"));
+ SL_RETURN ((-1), _("sh_ext_popen"));
+ }
+
+ PDBG(4);
+
+ if (task->pid == (pid_t) 0)
+ {
+ /*
+ * -- fork again, if requested
+ */
+ if (S_TRUE == task->fork_twice)
+ {
+ task->pid = fork();
+
+ if (task->pid == (pid_t) - 1)
+ {
+ _exit (EXIT_FAILURE);
+ }
+ }
+
+ if (task->pid == (pid_t) 0)
+ {
+ int val_return;
+
+ PDBGC_OPEN;
+ PDBGC(1);
+
+ /*
+ * -- grandchild - make write side of the pipe stdin
+ */
+ if (task->rw == 'w')
+ {
+ do {
+ val_return = dup2 (pipedes[STDIN_FILENO], STDIN_FILENO);
+ } while (val_return < 0 && errno == EINTR);
+
+ if (val_return < 0)
+ _exit(EXIT_FAILURE);
+ }
+ else
+ {
+ do {
+ val_return = dup2 (pipedes[STDOUT_FILENO], STDOUT_FILENO);
+ } while (val_return < 0 && errno == EINTR);
+
+ if (val_return < 0)
+ _exit(EXIT_FAILURE);
+ }
+ PDBGC(2);
+
+
+ /* close the pipe descriptors
+ */
+ (void) sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
+ (void) sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+
+ /* don't leak file descriptors
+ */
+#if !defined(PDGBFILE)
+ sh_unix_closeall (3, task->com_fd, S_TRUE); /* in child process */
+#endif
+
+ /* drop root privileges, if possible && requested
+ */
+ if (task->privileged == 0 && 0 == getuid())
+ {
+ PDBGC_S("privileged");
+
+ /* zero priv info
+ */
+ memset(skey, 0, sizeof(sh_key_t));
+
+ if (setgid((gid_t) task->run_user_gid) != 0)
+ _exit(EXIT_FAILURE);
+ if (setuid((uid_t) task->run_user_uid) != 0)
+ _exit(EXIT_FAILURE);
+
+ /* make sure we cannot get root again
+ */
+ if (setuid(0) >= 0)
+ _exit(EXIT_FAILURE);
+ }
+
+ PDBGC(3);
+ (void) fflush(NULL);
+
+ if (task->rw == 'w')
+ {
+ PDBGC_S("w");
+ (void) fcntl (STDOUT_FILENO, F_SETFD, FD_CLOEXEC);
+ (void) fcntl (STDERR_FILENO, F_SETFD, FD_CLOEXEC);
+ /*
+ freopen(_("/dev/null"), "r+", stderr);
+ freopen(_("/dev/null"), "r+", stdout);
+ */
+ }
+ else
+ {
+ PDBGC_S("r");
+ do {
+ val_return = dup2 (STDOUT_FILENO, STDERR_FILENO);
+ } while (val_return < 0 && errno == EINTR);
+
+ (void) fcntl (STDIN_FILENO, F_SETFD, FD_CLOEXEC);
+ /*
+ freopen(_("/dev/null"), "r+", stdin);
+ */
+ }
+
+ PDBGC(4);
+
+
+#if defined(__linux__)
+ /*
+ * -- emulate an fdexec with checksum testing
+ */
+
+#if !defined(HAVE_PTHREAD)
+ if (task->checksum[0] != '\0')
+#endif
+ {
+ PDBGC_S("fexecve");
+ if (task->com_fd != (-1))
+ {
+ do {
+ val_return = dup (task->com_fd);
+ } while (val_return < 0 && errno == EINTR);
+ pfd = val_return;
+ if (pfd < 0)
+ {
+ PDBGC_S("fexecve: dup failed");
+ _exit(EXIT_FAILURE);
+ }
+ }
+#if !defined(HAVE_PTHREAD)
+ else
+ {
+ char hashbuf[KEYBUF_SIZE];
+
+ fd =
+ sl_open_read(FIL__, __LINE__, task->command,
+ task->privileged==0 ? SL_NOPRIV : SL_YESPRIV);
+
+ if (0 != sl_strcmp(task->checksum,
+ sh_tiger_hash (task->command,
+ fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf))))
+ {
+ PDBGC_S("fexecve: checksum mismatch");
+ sl_close(fd);
+ _exit(EXIT_FAILURE);
+ }
+
+ pfd = get_the_fd(fd);
+
+ do {
+ val_return = dup (pfd);
+ } while (val_return < 0 && errno == EINTR);
+ pfd = val_return;
+
+ sl_close(fd);
+ fd = -1;
+
+ if (pfd < 0)
+ {
+ PDBGC_S("fexecve: dup (2) failed");
+ _exit(EXIT_FAILURE);
+ }
+ }
+#endif
+
+ PDBGC(5);
+ /* Cannot use sprintf because of deadlock in malloc/free */
+ {
+ static char digit[] = "0123456789";
+ char str0[128];
+ char str1[128];
+ int ival = pfd;
+ unsigned int n = 0;
+ unsigned int m = 0;
+
+ if (ival < 0) ival = -ival;
+ do {
+ str0[n] = digit[ival % 10];
+ ++n;
+ ival /= 10;
+ } while (ival);
+
+ if (pfd < 0)
+ {
+ str0[n] = '-';
+ ++n;
+ }
+ str0[n] = '\0';
+ str1[n] = '\0';
+ while (n > 0)
+ {
+ str1[m] = str0[n-1];
+ ++m; --n;
+ }
+ sl_strlcpy(pname, _("/proc/self/fd/"), sizeof(pname));
+ sl_strlcat(pname, str1, sizeof(pname));
+ }
+ if (access(pname, R_OK|X_OK) == 0) /* flawfinder: ignore */
+ {
+ PDBGC(6);
+ PDBGC_CLOSE;
+ fcntl (pfd, F_SETFD, FD_CLOEXEC);
+ do {
+ val_return = execve (pname,
+ (task->argc == 0) ? argp : task->argv,
+ (task->envc == 0) ? NULL : task->envv
+ );
+ } while (val_return < 0 && errno == EINTR);
+
+ errnum = errno;
+ PDBGC_OPEN;
+ PDBGC_S(strerror(errnum));
+ PDBGC_S(task->command);
+ PDBGC_S("fexecve: failed");
+ PDBGC_CLOSE;
+ /* failed
+ */
+ _exit((errnum == 0) ? (EXIT_SUCCESS) : (EXIT_FAILURE));
+ }
+ PDBGC_S("fexecve: not working");
+ /*
+ * procfs not working, go ahead; checksum is tested already
+ */
+ if (fd != -1)
+ sl_close(fd);
+ else if (pfd != -1)
+ sl_close_fd(FIL__, __LINE__, pfd);
+ }
+#endif
+
+ PDBGC_S(" -- non fexecve --");
+ /*
+ * -- execute path if executable
+ */
+ if (0 == access(task->command, R_OK|X_OK)) /* flawfinder: ignore */
+ {
+ PDBGC(5);
+ PDBGC_CLOSE;
+ do {
+ val_return = execve (task->command,
+ (task->argc == 0) ? argp : task->argv,
+ (task->envc == 0) ? envp : task->envv
+ );
+ } while (val_return < 0 && errno == EINTR);
+ }
+ errnum = errno;
+ PDBGC_OPEN;
+ PDBGC_S(strerror(errnum));
+ PDBGC_S(task->command);
+ PDBGC_S("execve: failed");
+ PDBGC_CLOSE;
+ /* failed
+ */
+ _exit((errnum == 0) ? (EXIT_SUCCESS) : (EXIT_FAILURE));
+ }
+ /*
+ * if we have forked twice, this is parent::detached_subprocess
+ */
+ if (S_TRUE == task->fork_twice)
+ {
+ _exit (0);
+ }
+ }
+
+
+ /*
+ * -- parent; task->pid is child pid; exit status is status of
+ * grandchild if exited
+ */
+ if (S_TRUE == task->fork_twice)
+ {
+ (void) waitpid (task->pid, NULL, 0);
+ }
+
+ PDBG(5);
+ /* open an output stream on top of the write side of the pipe
+ */
+ if (task->rw == 'w')
+ {
+ PDBG_S("is w");
+ (void) sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
+ (void) retry_fcntl (FIL__, __LINE__, pipedes[STDOUT_FILENO],
+ F_SETFD, FD_CLOEXEC);
+ outf = fdopen (pipedes[STDOUT_FILENO], "w");
+ }
+ else
+ {
+ PDBG_S("is r");
+ (void) sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+ (void) retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO],
+ F_SETFD, FD_CLOEXEC);
+ outf = fdopen (pipedes[STDIN_FILENO], "r");
+ }
+
+ if (outf == NULL)
+ {
+ errnum = errno;
+ PDBG_S("outf == NULL");
+ tmp = sh_util_safe_name (task->command);
+
+ if (task->privileged == 0 && 0 == getuid())
+ sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_NOEXEC,
+ (UID_CAST) task->run_user_uid, tmp);
+ else
+ sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_NOEXEC,
+ (UID_CAST) getuid(), tmp);
+
+ SH_FREE(tmp);
+
+ (void) aud_kill (FIL__, __LINE__, task->pid, SIGKILL);
+ (void) sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+ (void) sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
+ (void) waitpid (task->pid, NULL, 0);
+ task->pid = 0;
+
+ SL_RETURN ((-1), _("sh_ext_popen"));
+ }
+
+ if (task->rw == 'w')
+ task->pipeFD = pipedes[STDOUT_FILENO];
+ else
+ task->pipeFD = pipedes[STDIN_FILENO];
+
+ PDBG_D(task->pipeFD);
+
+ task->pipeTI = sl_make_ticket(FIL__, __LINE__, task->pipeFD, _("pipe"), outf);
+
+ flags = (int) retry_fcntl (FIL__, __LINE__, task->pipeFD, F_GETFL, 0);
+ if (flags != (-1))
+ (void) retry_fcntl (FIL__, __LINE__, task->pipeFD,
+ F_SETFL, flags|O_NONBLOCK);
+ task->pipe = outf;
+
+ PDBG_S("return from popen");
+ PDBG_CLOSE;
+
+ SL_RETURN (0, _("sh_ext_popen"));
+}
+
+/*
+ * -- close the pipe
+ */
+extern int flag_err_debug;
+
+int sh_ext_pclose (sh_tas_t * task)
+{
+ int status = 0;
+ int retry = 0;
+ pid_t retval;
+ char infomsg[256];
+
+#ifdef WCONTINUED
+ int wflags = WNOHANG|WUNTRACED|WCONTINUED;
+#else
+ int wflags = WNOHANG|WUNTRACED;
+#endif
+
+ SL_ENTER(_("sh_ext_pclose"));
+
+ PDBG_OPEN;
+ PDBG_S(" -> pclose");
+ (void) fflush(task->pipe);
+ if (!SL_ISERROR(task->pipeTI))
+ (void) sl_close(task->pipeTI);
+
+ task->pipe = NULL;
+ task->pipeFD = (-1);
+ task->pipeTI = SL_ETICKET;
+
+ if (S_FALSE == task->fork_twice)
+ {
+ infomsg[0] = '\0';
+
+ nochmal:
+ retval = waitpid(task->pid, &(task->exit_status), wflags);
+ /*@-bufferoverflowhigh@*/
+ if (task->pid == retval)
+ {
+#ifndef USE_UNO
+ if (WIFEXITED(task->exit_status) != 0)
+ {
+ task->exit_status = WEXITSTATUS(task->exit_status);
+ if ((flag_err_debug == S_TRUE) || (task->exit_status != 0))
+ sl_snprintf(infomsg, sizeof(infomsg),
+ _("Subprocess exited normally with status %d"),
+ task->exit_status);
+ }
+ else if (WIFSIGNALED(task->exit_status) != 0)
+ {
+ sl_snprintf(infomsg, sizeof(infomsg),
+ _("Subprocess terminated by signal %d"),
+ WTERMSIG(task->exit_status));
+ task->exit_status = EXIT_FAILURE;
+ }
+ else if (WIFSTOPPED(task->exit_status) != 0)
+ {
+ sl_snprintf(infomsg, sizeof(infomsg),
+ _("Subprocess stopped by signal %d, killing"),
+ WSTOPSIG(task->exit_status));
+ task->exit_status = EXIT_FAILURE;
+ (void) aud_kill (FIL__, __LINE__, task->pid, 9);
+ (void) retry_msleep (0, 30);
+ (void) waitpid (task->pid, NULL, wflags);
+ }
+ else
+ {
+ sl_snprintf(infomsg, sizeof(infomsg),
+ _("Subprocess exit status unknown"));
+ task->exit_status = EXIT_FAILURE;
+ }
+#else
+ task->exit_status = EXIT_FAILURE;
+#endif
+ }
+ else if (0 == retval)
+ {
+ if (retry < 3)
+ {
+ ++retry;
+ (void) retry_msleep(0, (retry * 30));
+ goto nochmal;
+ }
+ (void) aud_kill (FIL__, __LINE__, task->pid, 9);
+ sl_snprintf(infomsg, sizeof(infomsg),
+ _("Subprocess not yet exited, killing"));
+ task->exit_status = EXIT_FAILURE;
+ (void) waitpid (task->pid, NULL, 0);
+ }
+ else
+ {
+ sl_snprintf(infomsg, sizeof(infomsg),
+ _("Waitpid returned error %d\n"), errno);
+ task->exit_status = EXIT_FAILURE;
+ }
+ /*@+bufferoverflowhigh@*/
+ status = task->exit_status;
+ if (flag_err_debug == S_TRUE)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, task->exit_status,
+ MSG_E_SUBGEN, infomsg, _("sh_ext_pclose"));
+ }
+ else if (status != 0)
+ {
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, task->exit_status,
+ MSG_E_SUBGEN, infomsg, _("sh_ext_pclose"));
+ }
+ }
+
+ task->pid = 0;
+ task->exit_status = 0;
+ PDBG_S(" <--");
+ PDBG_CLOSE;
+ SL_RETURN (status, _("sh_ext_pclose"));
+}
+
+void sh_ext_tas_init (sh_tas_t * tas)
+{
+ int i;
+
+ tas->command = NULL;
+ tas->argc = 0;
+ tas->envc = 0;
+ tas->checksum[0] = '\0';
+ tas->pipeFD = (-1);
+ tas->pipeTI = SL_ETICKET;
+ tas->pid = (pid_t) -1;
+ tas->privileged = 1;
+ tas->pipe = NULL;
+ tas->rw = 'w';
+ tas->exit_status = 0;
+ tas->fork_twice = S_TRUE;
+
+ for (i = 0; i < 32; ++i)
+ {
+ tas->argv[i] = NULL;
+ tas->envv[i] = NULL;
+#if 0
+ tas->trusted_users[i] = (uid_t) -1;
+#endif
+ }
+
+ tas->run_user_uid = (uid_t) getuid();
+ tas->run_user_gid = (gid_t) getgid();
+
+ tas->com_fd = -1;
+ tas->com_ti = -1;
+ return;
+}
+
+
+int sh_ext_tas_add_envv(sh_tas_t * tas, const char * key, const char * val)
+{
+ size_t sk = 0, sv = 0;
+ int si;
+
+ SL_ENTER(_("sh_ext_tas_add_envv"));
+
+ if (tas == NULL || (key == NULL && val == NULL) ||
+ tas->envc >= 30)
+ {
+ SL_RETURN (-1, _("sh_ext_tas_add_envv"));
+ }
+ if (key != NULL)
+ sk = strlen(key) + 1;
+ if (val != NULL)
+ sv = strlen(val) + 1;
+
+ if (!sl_ok_adds(sk, sv))
+ {
+ SL_RETURN (-1, _("sh_ext_tas_add_envv"));
+ }
+ si = tas->envc;
+ tas->envv[si] = SH_ALLOC(sk + sv);
+
+ if (key != NULL)
+ {
+ (void) sl_strlcpy(tas->envv[si], key, sk+sv);
+ (void) sl_strlcat(tas->envv[si], "=", sk+sv);
+ if (val != NULL)
+ (void) sl_strlcat(tas->envv[si], val, sk+sv);
+ }
+ else
+ (void) sl_strlcpy(tas->envv[si], val, sv);
+
+ ++(tas->envc);
+ SL_RETURN ((tas->envc), _("sh_ext_tas_add_envv"));
+}
+
+int sh_ext_tas_rm_argv(sh_tas_t * tas)
+{
+ int last;
+
+ SL_ENTER(_("sh_ext_tas_rm_argv"));
+ if (tas == NULL || tas->argc == 0)
+ {
+ SL_RETURN (-1, _("sh_ext_tas_rm_argv"));
+ }
+
+ last = (tas->argc - 1);
+ --(tas->argc);
+ SH_FREE(tas->argv[last]);
+ tas->argv[last] = NULL;
+ SL_RETURN ((tas->argc), _("sh_ext_tas_rm_argv"));
+}
+
+int sh_ext_tas_add_argv(sh_tas_t * tas, const char * val)
+{
+ size_t sv = 0;
+ int si;
+
+ SL_ENTER(_("sh_ext_tas_add_argv"));
+
+ if (tas == NULL || val == NULL ||
+ tas->argc >= 30)
+ {
+ SL_RETURN (-1, _("sh_ext_tas_add_argv"));
+ }
+
+ if (val != NULL)
+ sv = strlen(val) + 1;
+
+ si = tas->argc;
+ tas->argv[si] = SH_ALLOC(sv);
+
+ (void) sl_strlcpy(tas->argv[si], val, sv);
+
+ ++(tas->argc);
+ SL_RETURN ((tas->argc), _("sh_ext_tas_add_argv"));
+}
+
+void sh_ext_tas_command(sh_tas_t * tas, const char * command)
+{
+ size_t len = sl_strlen(command);
+ tas->command = SH_ALLOC(len+1);
+ (void) sl_strlcpy(tas->command, command, len+1);
+ return;
+}
+
+void sh_ext_tas_free(sh_tas_t * tas)
+{
+ int i;
+ if (NULL != tas->command) SH_FREE(tas->command);
+
+ for (i = 0; i < 32; ++i)
+ {
+ if (NULL != tas->argv[i]) SH_FREE(tas->argv[i]);
+ if (NULL != tas->envv[i]) SH_FREE(tas->envv[i]);
+ }
+
+ if (tas->com_ti != (-1))
+ {
+ (void) sl_close(tas->com_ti);
+ tas->com_ti = -1;
+ tas->com_fd = -1;
+ }
+
+ return;
+}
+
+static void task_init (sh_tas_t * task)
+{
+ sh_ext_tas_init(task);
+
+ (void) sh_ext_tas_add_envv (task, _("SHELL"),
+ _("/bin/sh"));
+ (void) sh_ext_tas_add_envv (task, _("PATH"),
+ _("/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb"));
+ (void) sh_ext_tas_add_envv (task, _("IFS"), " \n\t");
+
+ if (sh.timezone != NULL)
+ {
+ (void) sh_ext_tas_add_envv(task, "TZ", sh.timezone);
+ }
+ return;
+}
+
+int sh_ext_popen_init (sh_tas_t * task, const char * command, char * argv0, ...)
+{
+ va_list vl;
+ int status;
+
+ task_init (task);
+
+ if (!argv0)
+ {
+ sh_ext_tas_command(task, _("/bin/sh"));
+
+ (void) sh_ext_tas_add_argv(task, _("/bin/sh"));
+ (void) sh_ext_tas_add_argv(task, _("-c"));
+ (void) sh_ext_tas_add_argv(task, command);
+ }
+ else
+ {
+ char * s;
+
+ sh_ext_tas_command(task, command);
+
+ (void) sh_ext_tas_add_argv(task, argv0);
+
+ va_start (vl, argv0);
+ s = va_arg (vl, char * );
+ while (s != NULL)
+ {
+ (void) sh_ext_tas_add_argv(task, s);
+ s = va_arg (vl, char * );
+ }
+ va_end (vl);
+
+ }
+ task->rw = 'r';
+ task->fork_twice = S_FALSE;
+
+ status = sh_ext_popen(task);
+
+ return status;
+}
+
+/* Execute a system command */
+
+int sh_ext_system (char * command, char * argv0, ...)
+{
+ sh_tas_t task;
+ int status;
+ va_list vl;
+ char * s;
+
+ SL_ENTER(_("sh_ext_system"));
+
+ task_init (&task);
+
+ sh_ext_tas_command(&task, command);
+
+ (void) sh_ext_tas_add_argv(&task, argv0);
+
+ va_start (vl, argv0);
+ s = va_arg (vl, char * );
+ while (s != NULL)
+ {
+ (void) sh_ext_tas_add_argv(&task, s);
+ s = va_arg (vl, char * );
+ }
+ va_end (vl);
+
+ task.rw = 'r';
+ task.fork_twice = S_FALSE;
+
+ status = sh_ext_popen(&task);
+
+ if (status != 0)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Could not execute command"), _("sh_ext_system"));
+ SL_RETURN ((-1), _("sh_ext_system"));
+ }
+
+ /* close pipe and return exit status
+ */
+ (void) sh_ext_pclose(&task);
+ sh_ext_tas_free (&task);
+ SL_RETURN ((status), _("sh_ext_system"));
+}
+
+/* Execute command, return first line of output
+ * ifconfig | grep -1 lo | tail -n 1 | sed s/.*inet addr:\([0-9.]*\)\(.*\)/\1/
+ */
+char * sh_ext_popen_str (const char * command)
+{
+ sh_tas_t task;
+ struct sigaction new_act;
+ struct sigaction old_act;
+ char * out = NULL;
+ int status;
+
+ SL_ENTER(_("sh_ext_popen_str"));
+
+ status = sh_ext_popen_init (&task, command, NULL, NULL);
+
+ if (status != 0)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Could not open pipe"), _("sh_ext_popen_str"));
+ SL_RETURN ((NULL), _("sh_ext_popen_str"));
+ }
+
+ /* ignore SIGPIPE (instead get EPIPE if connection is closed)
+ */
+ new_act.sa_handler = SIG_IGN;
+ new_act.sa_flags = 0;
+ sigemptyset( &new_act.sa_mask );
+
+ (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
+
+ /* read from the open pipe
+ */
+ if (task.pipe != NULL)
+ {
+ int try = 1200; /* 1000 * 0.1 = 120 sec */
+ sh_string * s = sh_string_new(0);
+ do {
+ sh_string_read(s, task.pipe, 0);
+ if (sh_string_len(s) == 0)
+ {
+ --try; retry_msleep(0, 100);
+ }
+ } while (sh_string_len(s) == 0 && try != 0);
+
+ if (sh_string_len(s) == 0)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("No output from command"), _("sh_ext_popen_str"));
+ }
+
+ out = sh_util_strdup(sh_string_str(s));
+ sh_string_destroy(&s);
+ }
+
+ /* restore old signal handler
+ */
+ (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
+
+ /* close pipe and return exit status
+ */
+ (void) sh_ext_pclose(&task);
+ sh_ext_tas_free (&task);
+ SL_RETURN ((out), _("sh_ext_popen_str"));
+}
+
+
+
+
+/* --------------- EXTERN STUFF ------------------- */
+
+#if defined(WITH_EXTERNAL)
+
+typedef struct _sh_com_t
+{
+ char type[4];
+
+ sh_filter_type * filter;
+
+ time_t deadtime;
+ time_t last_run;
+
+ sh_tas_t tas;
+
+ struct _sh_com_t * next;
+
+} sh_com_t;
+
+
+static
+void set3 (char * pos, char c1, char c2, char c3)
+{
+ pos[0] = c1;
+ pos[1] = c2;
+ pos[2] = c3;
+ pos[3] = '\0';
+ return;
+}
+
+
+
+/* initialize the external command structure
+ */
+static
+sh_com_t * command_init(void)
+{
+ uid_t ff_euid;
+ sh_com_t * ext_com = NULL;
+
+ SL_ENTER(_("command_init"));
+
+ ext_com = (sh_com_t *) SH_ALLOC(sizeof(sh_com_t));
+
+ if (!ext_com)
+ {
+ SL_RETURN( NULL, _("command_init"));
+ }
+
+ sh_ext_tas_init (&(ext_com->tas));
+
+ (void) sl_get_euid(&ff_euid);
+#if 0
+ ext_com->tas.trusted_users[0] = (uid_t) 0;
+ ext_com->tas.trusted_users[1] = (uid_t) (ff_euid);
+#endif
+
+ /* ------------------------------------------------- */
+
+ set3(ext_com->type, 'l', 'o', 'g');
+ ext_com->filter = NULL;
+ ext_com->deadtime = 0;
+ ext_com->last_run = 0;
+
+ ext_com->next = NULL;
+
+ SL_RETURN( ext_com, _("command_init"));
+}
+
+/* the list of external commands
+ */
+static sh_com_t * ext_coms = NULL;
+
+/* if -1, allocation of last command has failed,
+ * thus don't fill in options
+ */
+static int ext_failed = -1;
+
+static
+int sh_ext_add_envv(const char * key, const char * val)
+{
+ int retval;
+
+ SL_ENTER(_("sh_ext_add_envv"));
+
+ if (ext_coms == NULL || ext_failed == (-1) ||
+ (key == NULL && val == NULL) ||
+ ext_coms->tas.envc >= 30)
+ {
+ SL_RETURN (-1, _("sh_ext_add_envv"));
+ }
+
+ retval = sh_ext_tas_add_envv(&(ext_coms->tas), key, val);
+
+ if (retval >= 0)
+ retval = 0;
+
+ SL_RETURN (retval, _("sh_ext_add_envv"));
+}
+
+
+
+static
+int sh_ext_init(const char * command)
+{
+ sh_com_t * retval;
+ size_t size;
+
+ SL_ENTER(_("sh_ext_init"));
+
+ if (command == NULL)
+ {
+ SL_RETURN (-1, _("sh_ext_init"));
+ }
+ size = strlen(command);
+ if (command[0] != '/' || size < 2)
+ {
+ SL_RETURN (-1, _("sh_ext_init"));
+ }
+
+ if (NULL == (retval = command_init()))
+ {
+ SL_RETURN (-1, _("sh_ext_init"));
+ }
+
+ sh_ext_tas_command(&(retval->tas), command);
+
+ if (sh.timezone != NULL)
+ {
+ (void) sh_ext_add_envv( "TZ", sh.timezone);
+ }
+
+ retval->next = ext_coms;
+ ext_coms = retval;
+ SL_RETURN (0, _("sh_ext_init"));
+}
+
+static
+int sh_ext_uid (const char * user, /*@out@*/uid_t * uid, /*@out@*/gid_t * gid)
+{
+ struct passwd * tempres;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
+#endif
+
+ SL_ENTER(_("sh_ext_uid"));
+
+ *uid = (uid_t)-1; *gid = (gid_t)-1;
+
+ if (user == NULL)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN (-1, _("sh_ext_uid"));
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ sh_getpwnam_r(user, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ tempres = sh_getpwnam(user);
+#endif
+
+ if (NULL != tempres)
+ {
+ *uid = tempres->pw_uid;
+ *gid = tempres->pw_gid;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN (0, _("sh_ext_uid"));
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN (-1, _("sh_ext_uid"));
+}
+
+
+static
+int sh_ext_add (const char * argstring, int * ntok, char * stok[])
+{
+ int i = 0;
+ size_t s;
+ char * p;
+ char * new;
+ size_t len;
+
+ SL_ENTER(_("sh_ext_add"));
+
+ if (NULL == argstring)
+ {
+ SL_RETURN((-1), _("sh_ext_add"));
+ }
+
+ len = strlen(argstring) + 1;
+ new = SH_ALLOC(len);
+ sl_strlcpy(new, argstring, len);
+
+ do
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+ if (i == 0)
+ p = strtok_r (new, ", \t", &saveptr);
+ else
+ p = strtok_r (NULL, ", \t", &saveptr);
+#else
+ if (i == 0)
+ p = strtok (new, ", \t");
+ else
+ p = strtok (NULL, ", \t");
+#endif
+
+ if (p == NULL)
+ break;
+
+ s = strlen(p) + 1;
+ if (stok[i] != NULL)
+ SH_FREE(stok[i]);
+ stok[i] = SH_ALLOC(s);
+ (void) sl_strlcpy(stok[i], p, s);
+
+ ++i;
+ if (i == 30)
+ break;
+ }
+ while (p != NULL);
+
+ *ntok = i;
+ SH_FREE(new);
+
+ SL_RETURN (0, _("sh_ext_add"));
+}
+
+/*********************************************************
+ *
+ * Public functions
+ *
+ *
+ *********************************************************/
+
+/*
+ * -- start a new external command, and add it to the list
+ */
+int sh_ext_setcommand(const char * cmd)
+{
+ int i;
+
+ SL_ENTER(_("sh_ext_setcommand"));
+ if ( (i = sh_ext_init(cmd)) < 0)
+ ext_failed = -1;
+ else
+ ext_failed = 0;
+ SL_RETURN( i, _("sh_ext_setcommand"));
+}
+
+
+/*
+ * -- clean up the command list
+ */
+int sh_ext_cleanup(void)
+{
+ sh_com_t * retval;
+
+ SL_ENTER(_("sh_ext_cleanup"));
+
+ while (ext_coms != NULL)
+ {
+ retval = ext_coms;
+ ext_coms = retval->next;
+
+ sh_ext_tas_free (&(retval->tas));
+
+ if (retval->filter)
+ sh_filter_free (retval->filter);
+
+ SH_FREE(retval);
+
+ }
+
+ SL_RETURN (0, _("sh_ext_cleanup"));
+}
+
+/*
+ * -- explicitely close a command
+ */
+int sh_ext_close_command (const char * str)
+{
+ (void) str;
+ if (ext_coms == NULL || ext_failed == (-1))
+ return (-1);
+ ext_failed = (-1);
+ return 0;
+}
+
+/*
+ * -- add keywords to the OR filter
+ */
+int sh_ext_add_or (const char * str)
+{
+ if (ext_coms == NULL || ext_failed == (-1))
+ return (-1);
+ if (ext_coms->filter == NULL)
+ ext_coms->filter = sh_filter_alloc();
+ return (sh_filter_add(str, ext_coms->filter, SH_FILT_OR));
+}
+
+/*
+ * -- add keywords to the AND filter
+ */
+int sh_ext_add_and (const char * str)
+{
+ if (ext_coms == NULL || ext_failed == (-1))
+ return (-1);
+ if (ext_coms->filter == NULL)
+ ext_coms->filter = sh_filter_alloc();
+ return (sh_filter_add(str, ext_coms->filter, SH_FILT_AND));
+}
+
+/*
+ * -- add keywords to the NOT filter
+ */
+int sh_ext_add_not (const char * str)
+{
+ if (ext_coms == NULL || ext_failed == (-1))
+ return (-1);
+ if (ext_coms->filter == NULL)
+ ext_coms->filter = sh_filter_alloc();
+ return (sh_filter_add(str, ext_coms->filter, SH_FILT_NOT));
+}
+
+/*
+ * -- add keywords to the CL argument list
+ */
+int sh_ext_add_argv (const char * str)
+{
+ if (ext_coms == NULL || ext_failed == (-1))
+ return (-1);
+ return (sh_ext_add (str, &(ext_coms->tas.argc), ext_coms->tas.argv));
+}
+
+/*
+ * -- add a path to the environment
+ */
+int sh_ext_add_default (const char * dummy)
+{
+ char * p = NULL;
+ int i;
+ char dir[SH_PATHBUF];
+
+ SL_ENTER(_("sh_ext_add_default"));
+ if (dummy[0] == 'n' || dummy[0] == 'N' ||
+ dummy[0] == 'f' || dummy[0] == 'F' || dummy[0] == '0')
+ {
+ SL_RETURN(0, _("sh_ext_add_default"));
+ }
+ p = sh_unix_getUIDdir (SH_ERR_ERR, (uid_t) ext_coms->tas.run_user_uid,
+ dir, sizeof(dir));
+ if (p)
+ (void) sh_ext_add_envv (_("HOME"), p);
+ (void) sh_ext_add_envv (_("SHELL"), _("/bin/sh"));
+ (void) sh_ext_add_envv (_("PATH"), _("/sbin:/bin:/usr/sbin:/usr/bin"));
+ (void) sh_ext_add_envv (_("IFS"), " \n\t");
+ i = (p == NULL ? (-1) : 0);
+ SL_RETURN(i, _("sh_ext_add_default"));
+}
+
+/*
+ * -- add an environment variable
+ */
+int sh_ext_add_environ (const char * str)
+{
+ int i;
+
+ SL_ENTER(_("sh_ext_add_environ"));
+ i = sh_ext_add_envv (NULL, str);
+ SL_RETURN(i, _("sh_ext_add_environ"));
+}
+
+/*
+ * -- set deadtime
+ */
+int sh_ext_deadtime (const char * str)
+{
+ long deadtime = 0;
+ char * tail = NULL;
+
+ SL_ENTER(_("sh_ext_deadtime"));
+
+ if (ext_coms == NULL || ext_failed == (-1) || str == NULL)
+ {
+ SL_RETURN (-1, _("sh_ext_deadtime"));
+ }
+ deadtime = strtol(str, &tail, 10);
+ if (tail == str || deadtime < 0 || deadtime == LONG_MAX)
+ {
+ SL_RETURN (-1, _("sh_ext_deadtime"));
+ }
+
+ ext_coms->deadtime = (time_t) deadtime;
+ SL_RETURN (0, _("sh_ext_deadtime"));
+}
+
+/*
+ * -- define type
+ */
+int sh_ext_type (const char * str)
+{
+ SL_ENTER(_("sh_ext_type"));
+
+ if (ext_coms == NULL || ext_failed == (-1) || str == NULL)
+ {
+ SL_RETURN((-1), _("sh_ext_type"));
+ }
+
+ if (strlen(str) != 3)
+ {
+ SL_RETURN((-1), _("sh_ext_type"));
+ }
+
+ set3(ext_coms->type, str[0], str[1], str[2]);
+
+ if (str[0] == 'l' && str[1] == 'o' && str[2] == 'g')
+ ext_coms->tas.rw = 'w';
+ else if (str[0] == 's' && str[1] == 'r' && str[2] == 'v')
+ ext_coms->tas.rw = 'w';
+ else if (str[0] == 'm' && str[1] == 'o' && str[2] == 'n')
+ ext_coms->tas.rw = 'r';
+ else
+ {
+ SL_RETURN((-1), _("sh_ext_type"));
+ }
+
+ SL_RETURN(0, _("sh_ext_type"));
+}
+
+
+
+/*
+ * -- define checksum
+ */
+int sh_ext_checksum (const char * str)
+{
+ SL_ENTER(_("sh_ext_checksum"));
+ if (ext_coms == NULL || ext_failed == (-1) || str == NULL)
+ {
+ SL_RETURN((-1), _("sh_ext_checksum"));
+ }
+
+ if (sl_strlen(str) != KEY_LEN)
+ {
+ SL_RETURN((-1), _("sh_ext_checksum"));
+ }
+
+ (void) sl_strlcpy (ext_coms->tas.checksum, str, KEY_LEN+1);
+
+ SL_RETURN((0), _("sh_ext_checksum"));
+}
+
+/*
+ * -- choose privileges
+ */
+int sh_ext_priv (const char * c)
+{
+
+ uid_t me_uid;
+ gid_t me_gid;
+
+ SL_ENTER(_("sh_ext_priv"));
+ if (0 == sh_ext_uid (c, &me_uid, &me_gid))
+ {
+ ext_coms->tas.run_user_uid = me_uid;
+ ext_coms->tas.run_user_gid = me_gid;
+ if (me_uid != (uid_t) 0)
+ ext_coms->tas.privileged = 0;
+ SL_RETURN((0), _("sh_ext_priv"));
+ }
+
+ SL_RETURN (-1, _("sh_ext_priv"));
+}
+
+
+
+
+/*
+ * -- check filters
+ */
+static int sh_ext_filter (char * message, sh_com_t * task)
+{
+ time_t now_time;
+
+ SL_ENTER(_("sh_ext_filter"));
+
+ if (task->filter)
+ {
+ if (0 != sh_filter_filter (message, task->filter))
+ {
+ SL_RETURN ((-1), _("sh_ext_filter"));
+ }
+ }
+
+ /* Filter passed, check deadtime */
+
+ if (task->deadtime != (time_t) 0)
+ {
+ now_time = time (NULL);
+
+ if (task->last_run == (time_t) 0)
+ {
+ task->last_run = now_time;
+ }
+ else if ((time_t)(now_time-task->last_run) < task->deadtime)
+ {
+ SL_RETURN ((-1), _("sh_ext_filter"));
+ }
+ else
+ {
+ task->last_run = now_time;
+ }
+ }
+
+ SL_RETURN ((0), _("sh_ext_filter"));
+}
+
+
+
+/*
+ * -- execute external script/program
+ */
+int sh_ext_execute (char t1, char t2, char t3, /*@null@*/char * message,
+ size_t msg_siz)
+{
+ int caperr;
+ sh_com_t * listval = ext_coms;
+ int status = 0;
+ char * tmp;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ static int some_error = 0;
+
+ struct sigaction new_act;
+ struct sigaction old_act;
+
+ SL_ENTER(_("sh_ext_execute"));
+
+ PDBG_OPEN;
+
+ if (listval == NULL || message == NULL)
+ {
+ SL_RETURN ((-1), _("sh_ext_execute"));
+ }
+
+ PDBG(-1);
+
+ if (msg_siz == 0)
+ msg_siz = sl_strlen(message);
+
+
+ /* ignore SIGPIPE (instead get EPIPE if connection is closed)
+ */
+ new_act.sa_handler = SIG_IGN;
+ (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
+
+ while (listval != NULL)
+ {
+ PDBG_OPEN;
+ PDBG(-2);
+ if (t1 == listval->type[0] &&
+ t2 == listval->type[1] &&
+ t3 == listval->type[2] &&
+ 0 == sh_ext_filter (message, listval))
+ {
+ PDBG(-3);
+
+ if (0 != (caperr = sl_get_cap_sub()))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_get_cap_sub"));
+ }
+ if (0 == sh_ext_popen (&(listval->tas)))
+ {
+ PDBG_OPEN;
+ PDBG(-4);
+ if (NULL != listval->tas.pipe && listval->tas.rw == 'w')
+ {
+ PDBG(-5);
+ if (message != NULL)
+ {
+ PDBG(-6);
+ status = (int) write (listval->tas.pipeFD,
+ message, msg_siz);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "\n", 1);
+ }
+ PDBG_D(status);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "[", 1);
+ PDBG_D(status);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "E", 1);
+ PDBG_D(status);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "O", 1);
+ PDBG_D(status);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "F", 1);
+ PDBG_D(status);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "]", 1);
+ PDBG_D(status);
+ if (status >= 0)
+ status = (int) write (listval->tas.pipeFD, "\n", 1);
+ PDBG_D(status);
+ if (status >= 0)
+ {
+ some_error = 0;
+ }
+ if ((status < 0) && (some_error == 0))
+ {
+ some_error = 1;
+ PDBG_S("some error");
+ PDBG_D(status);
+ tmp = sh_util_safe_name (listval->tas.command);
+
+ if (tmp)
+ {
+ if (listval->tas.privileged == 0 &&
+ (0 == getuid() || 0 != sl_is_suid()) )
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_NOEXEC,
+ (UID_CAST) listval->tas.run_user_uid,
+ tmp);
+ else
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_NOEXEC,
+ (UID_CAST) getuid(), tmp);
+
+ SH_FREE(tmp);
+ }
+
+ }
+ PDBG(-7);
+ (void) fflush(listval->tas.pipe);
+ }
+ PDBG(-8);
+ (void) sh_ext_pclose(&(listval->tas));
+ }
+ else
+ {
+ PDBG_OPEN;
+ PDBG_S("0 != sh_ext_popen()");
+ }
+ if (0 != (caperr = sl_drop_cap_sub()))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_drop_cap_sub"));
+ }
+
+ }
+ listval = listval->next;
+ }
+ PDBG_OPEN;
+ PDBG_S("no more commands");
+
+ /* restore old signal handler
+ */
+ (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &old_act, NULL);
+ PDBG_S("return");
+ PDBG_CLOSE;
+
+ SL_RETURN ((0), _("sh_ext_execute"));
+}
+
+
+/* #if defined(WITH_EXTERNAL) */
+#endif
diff --git a/src/sh_fInotify.c b/src/sh_fInotify.c
new file mode 100644
index 0000000..67162e7
--- /dev/null
+++ b/src/sh_fInotify.c
@@ -0,0 +1,725 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2011 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/***************************************************************************
+ *
+ * This file provides a module for samhain to use inotify for file checking.
+ *
+ */
+
+#include "config_xor.h"
+
+#if (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_modules.h"
+#include "sh_pthread.h"
+#include "sh_inotify.h"
+#include "sh_unix.h"
+#include "sh_hash.h"
+#include "sh_dbIO.h"
+#include "sh_files.h"
+#include "sh_ignore.h"
+
+#define FIL__ _("sh_fInotify.c")
+
+sh_watches sh_file_watches = SH_INOTIFY_INITIALIZER;
+
+#if defined(HAVE_SYS_INOTIFY_H)
+
+static sh_watches sh_file_missing = SH_INOTIFY_INITIALIZER;
+
+#include <sys/inotify.h>
+
+/* --- Configuration ------- */
+
+static int ShfInotifyActive = S_FALSE;
+static int ShfInotifyClose = S_FALSE; /* for reconf, mark instance for closing */
+
+static unsigned long ShfInotifyWatches = 0;
+
+static int sh_fInotify_active(const char *s)
+{
+ int value;
+
+ SL_ENTER(_("sh_fInotify_active"));
+ value = sh_util_flagval(s, &ShfInotifyActive);
+ if (value == 0 && ShfInotifyActive != S_FALSE)
+ {
+ sh.flag.inotify |= SH_INOTIFY_USE;
+ sh.flag.inotify |= SH_INOTIFY_DOSCAN;
+ sh.flag.inotify |= SH_INOTIFY_NEEDINIT;
+ }
+ if (value == 0 && ShfInotifyActive == S_FALSE)
+ {
+ sh.flag.inotify = 0;
+ }
+ SL_RETURN((value), _("sh_fInotify_active"));
+}
+
+static int sh_fInotify_watches(const char *s)
+{
+ int retval = -1;
+ char * foo;
+ unsigned long value;
+
+ SL_ENTER(_("sh_fInotify_watches"));
+
+ value = strtoul(s, &foo, 0);
+ if (*foo == '\0')
+ {
+ ShfInotifyWatches = (value > 2147483647) ? 2147483647 /* MAX_INT_32 */: value;
+ retval = 0;
+ }
+ SL_RETURN((retval), _("sh_fInotify_watches"));
+}
+
+
+sh_rconf sh_fInotify_table[] = {
+ {
+ N_("inotifyactive"),
+ sh_fInotify_active,
+ },
+ {
+ N_("inotifywatches"),
+ sh_fInotify_watches,
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/* --- End Configuration --- */
+
+static int sh_fInotify_init_internal(void);
+static int sh_fInotify_process(struct inotify_event * event);
+static int sh_fInotify_report(struct inotify_event * event, char * filename,
+ int class, unsigned long check_flags, int ftype, int rdepth);
+
+int sh_fInotify_init(struct mod_type * arg)
+{
+#ifndef HAVE_PTHREAD
+ (void) arg;
+ return SH_MOD_FAILED;
+#else
+
+ if (ShfInotifyActive == S_FALSE)
+ return SH_MOD_FAILED;
+
+ if (sh.flag.checkSum == SH_CHECK_INIT)
+ return SH_MOD_FAILED;
+
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ /* Init from main thread */
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN; );
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
+
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ {
+ return SH_MOD_THREAD;
+ }
+ else
+ {
+ sh.flag.inotify = 0;
+ return SH_MOD_FAILED;
+ }
+ }
+ else if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon != S_TRUE && sh.flag.loop != S_TRUE))
+ {
+ sh.flag.inotify = 0;
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ /* Reconfigure from main thread */
+
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN; );
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
+ return SH_MOD_THREAD;
+ }
+
+ /* Within thread, init */
+ return sh_fInotify_init_internal();
+#endif
+}
+
+int sh_fInotify_run()
+{
+ ssize_t len = -1;
+ char * buffer;
+ static int count = 0;
+ static int count2 = 0;
+
+ if (ShfInotifyActive == S_FALSE)
+ {
+ return SH_MOD_FAILED;
+ }
+
+ if (ShfInotifyClose == S_TRUE)
+ {
+ ShfInotifyClose = S_FALSE;
+ sh_inotify_close();
+ }
+
+ if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
+ (sh.flag.inotify & SH_INOTIFY_NEEDINIT))
+ {
+ if (0 != sh_fInotify_init_internal())
+ {
+ return SH_MOD_FAILED;
+ }
+ }
+
+ buffer = SH_ALLOC(16384);
+
+ /* Blocking read from inotify file descriptor.
+ */
+ len = sh_inotify_read_timeout(buffer, 16384, 1);
+
+ if (len > 0)
+ {
+ struct inotify_event *event;
+ int i = 0;
+
+ while (i < len)
+ {
+ event = (struct inotify_event *) &(buffer[i]);
+
+ sh_fInotify_process(event);
+
+ i += sizeof (struct inotify_event) + event->len;
+ }
+
+ if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
+ (sh.flag.inotify & SH_INOTIFY_NEEDINIT))
+ {
+ if (0 != sh_fInotify_init_internal())
+ {
+ SH_FREE(buffer);
+ return SH_MOD_FAILED;
+ }
+ }
+ }
+
+ /* Re-scan 'dormant' list of sh_file_missing.
+ */
+ sh_inotify_recheck_watches (&sh_file_watches, &sh_file_missing);
+
+ ++count;
+ ++count2;
+
+ if (count >= 10)
+ {
+ count = 0; /* Re-expand glob patterns to discover added files. */
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN; );
+ sh_files_check_globFilePatterns();
+ SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN; );
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
+ }
+
+ if (count2 >= 300)
+ {
+ count2 = 0; /* Update baseline database. */
+ if (sh.flag.checkSum == SH_CHECK_CHECK && sh.flag.update == S_TRUE)
+ sh_dbIO_writeout_update ();
+ }
+
+ SH_FREE(buffer);
+ return 0;
+}
+
+/* We block in the read() call on the inotify descriptor,
+ * so we always run.
+ */
+int sh_fInotify_timer(time_t tcurrent)
+{
+ (void) tcurrent;
+ return 1;
+}
+
+int sh_fInotify_cleanup()
+{
+ sh_inotify_purge_dormant(&sh_file_watches);
+ sh_inotify_remove(&sh_file_watches);
+ sh_inotify_init(&sh_file_watches);
+ return 0;
+}
+
+/* This runs in the main thread, so it won't close
+ * the (threadspecific) inotify instance.
+ */
+int sh_fInotify_reconf()
+{
+ sh.flag.inotify = 0;
+
+ ShfInotifyWatches = 0;
+ ShfInotifyActive = 0;
+
+ ShfInotifyClose = S_TRUE;
+
+ return sh_fInotify_cleanup();
+}
+
+#define PROC_WATCHES_MAX _("/proc/sys/fs/inotify/max_user_watches")
+
+static void sh_fInotify_set_nwatches()
+{
+ static int fails = 0;
+
+ if (ShfInotifyWatches == 0 || fails == 1)
+ return;
+
+ if (0 == access(PROC_WATCHES_MAX, R_OK|W_OK)) /* flawfinder: ignore */
+ {
+ FILE * fd;
+
+ if (NULL != (fd = fopen(PROC_WATCHES_MAX, "r+")))
+ {
+ char str[128];
+ char * ret;
+ char * ptr;
+ unsigned long wn;
+
+ str[0] = '\0';
+ ret = fgets(str, 128, fd);
+ if (ret && *str != '\0')
+ {
+ wn = strtoul(str, &ptr, 0);
+ if (*ptr == '\0' || *ptr == '\n')
+ {
+ if (wn < ShfInotifyWatches)
+ {
+ sl_snprintf(str, sizeof(str), "%lu\n", ShfInotifyWatches);
+ (void) fseek(fd, 0L, SEEK_SET);
+ fputs(str, fd);
+ }
+ sl_fclose(FIL__, __LINE__, fd);
+ return;
+ }
+ }
+ sl_fclose(FIL__, __LINE__, fd);
+ }
+ }
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Cannot set max_user_watches"),
+ _("sh_fInotify_set_nwatches"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ fails = 1;
+ return;
+}
+
+/* The watch fd is thread specific. To have it in the fInotify thread,
+ * the main thread writes a list of files/dirs to watch, and here we
+ * now pop files from the list to add watches for them.
+ */
+static int sh_fInotify_init_internal()
+{
+ char * filename;
+ int class;
+ int type;
+ int rdepth;
+ unsigned long check_flags;
+ int retval;
+ int errnum;
+
+ if (ShfInotifyActive == S_FALSE)
+ return SH_MOD_FAILED;
+
+ /* Wait until file scan is finished.
+ */
+ while((sh.flag.inotify & SH_INOTIFY_DOSCAN) != 0)
+ {
+ retry_msleep(1,0);
+
+ if (ShfInotifyActive == S_FALSE)
+ return SH_MOD_FAILED;
+ }
+
+ sh_fInotify_set_nwatches();
+
+ while (NULL != (filename = sh_inotify_pop_dormant(&sh_file_watches,
+ &class, &check_flags,
+ &type, &rdepth)))
+ {
+ retval = sh_inotify_add_watch(filename, &sh_file_watches, &errnum,
+ class, check_flags, type, rdepth);
+
+ if (retval < 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ sh_error_message(errnum, errbuf, sizeof(errbuf));
+
+ if ((errnum == ENOENT) || (errnum == EEXIST))
+ {
+ /* (1) Did it exist at init ?
+ */
+ if (sh_hash_have_it (filename) >= 0)
+ {
+ /* (2) Do we want to report on it ?
+ */
+ if (S_FALSE == sh_ignore_chk_del(filename))
+ {
+ char * epath = sh_util_safe_name (filename);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle( SH_ERR_ALL /* debug */,
+ FIL__, __LINE__, errnum, MSG_E_SUBGPATH,
+ errbuf, _("sh_fInotify_init_internal"), epath);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(epath);
+ }
+ }
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ errbuf, _("sh_fInotify_init_internal"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ SH_FREE(filename);
+ }
+
+ /* Need this because mod_check() may run after
+ * DOSCAN is finished, hence wouldn't call init().
+ */
+ SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_NEEDINIT; );
+
+ return 0;
+}
+
+static void sh_fInotify_logmask(struct inotify_event * event)
+{
+ char dbgbuf[256];
+
+ sl_strlcpy (dbgbuf, "inotify mask: ", sizeof(dbgbuf));
+
+ if (event->mask & IN_ACCESS) sl_strlcat(dbgbuf, "IN_ACCESS ", sizeof(dbgbuf));
+ if (event->mask & IN_ATTRIB) sl_strlcat(dbgbuf, "IN_ATTRIB ", sizeof(dbgbuf));
+ if (event->mask & IN_CLOSE_WRITE) sl_strlcat(dbgbuf, "IN_CLOSE_WRITE ", sizeof(dbgbuf));
+ if (event->mask & IN_CLOSE_NOWRITE) sl_strlcat(dbgbuf, "IN_CLOSE_NOWRITE ", sizeof(dbgbuf));
+ if (event->mask & IN_CREATE) sl_strlcat(dbgbuf, "IN_CREATE ", sizeof(dbgbuf));
+ if (event->mask & IN_DELETE) sl_strlcat(dbgbuf, "IN_DELETE ", sizeof(dbgbuf));
+ if (event->mask & IN_DELETE_SELF) sl_strlcat(dbgbuf, "IN_DELETE_SELF ", sizeof(dbgbuf));
+ if (event->mask & IN_MODIFY) sl_strlcat(dbgbuf, "IN_MODIFY ", sizeof(dbgbuf));
+ if (event->mask & IN_MOVE_SELF) sl_strlcat(dbgbuf, "IN_MOVE_SELF ", sizeof(dbgbuf));
+ if (event->mask & IN_MOVED_FROM) sl_strlcat(dbgbuf, "IN_MOVED_FROM ", sizeof(dbgbuf));
+ if (event->mask & IN_MOVED_TO) sl_strlcat(dbgbuf, "IN_MOVED_TO ", sizeof(dbgbuf));
+ if (event->mask & IN_OPEN) sl_strlcat(dbgbuf, "IN_OPEN ", sizeof(dbgbuf));
+ if (event->mask & IN_IGNORED) sl_strlcat(dbgbuf, "IN_IGNORED ", sizeof(dbgbuf));
+ if (event->mask & IN_ISDIR) sl_strlcat(dbgbuf, "IN_ISDIR ", sizeof(dbgbuf));
+ if (event->mask & IN_Q_OVERFLOW) sl_strlcat(dbgbuf, "IN_Q_OVERFLOW ", sizeof(dbgbuf));
+ if (event->mask & IN_UNMOUNT) sl_strlcat(dbgbuf, "IN_UNMOUNT ", sizeof(dbgbuf));
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ dbgbuf, _("sh_fInotify_process"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+}
+
+static int sh_fInotify_process(struct inotify_event * event)
+{
+ int class;
+ int ftype;
+ int rdepth;
+ unsigned long check_flags;
+ char * filename;
+ extern int flag_err_debug;
+
+ if (flag_err_debug == S_TRUE)
+ {
+ sh_fInotify_logmask(event);
+ }
+
+ if (event->wd >= 0)
+ {
+ filename = sh_inotify_search_item(&sh_file_watches, event->wd,
+ &class, &check_flags, &ftype, &rdepth);
+
+ if (filename)
+ {
+ sh_fInotify_report(event, filename, class, check_flags, ftype, rdepth);
+ SH_FREE(filename);
+ }
+ else if (sh.flag.inotify & SH_INOTIFY_NEEDINIT)
+ {
+ return 1;
+ }
+ else if ((event->mask & IN_UNMOUNT) == 0 && (event->mask & IN_IGNORED) == 0)
+ {
+ /* Remove watch ? Seems reasonable. */
+ sh_inotify_rm_watch(NULL, NULL, event->wd);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, event->wd, MSG_E_SUBGEN,
+ _("Watch removed: file path unknown"),
+ _("sh_fInotify_process"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ else if ((event->mask & IN_Q_OVERFLOW) != 0)
+ {
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN; );
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, event->wd, MSG_E_SUBGEN,
+ _("Inotify queue overflow"),
+ _("sh_fInotify_process"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return 1;
+ }
+
+ return 0;
+}
+
+void sh_fInotify_report_add(char * path, int class, unsigned long check_flags)
+{
+ if (S_FALSE == sh_ignore_chk_new(path))
+ {
+ int reported = 0;
+
+ sh_files_clear_file_reported(path);
+
+ sh_files_search_file(path, &class, &check_flags, &reported);
+
+ sh_files_filecheck (class, check_flags, path, NULL,
+ &reported, 0);
+ if (SH_FFLAG_REPORTED_SET(reported))
+ sh_files_set_file_reported(path);
+ }
+ return;
+}
+
+
+static void sh_fInotify_report_miss(char * name, int level)
+{
+ char * tmp = sh_util_safe_name (name);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ if (!sh_global_check_silent)
+ sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_MISS, tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ ++sh.statistics.files_report;
+ SH_FREE(tmp);
+ return;
+}
+
+static int sh_fInotify_report_change (struct inotify_event * event,
+ char * path, char * filename,
+ int class, unsigned long check_flags, int ftype)
+{
+ int reported;
+ int ret;
+
+
+ if (S_FALSE == sh_ignore_chk_mod(path))
+ {
+ ret = sh_files_search_file(path, &class, &check_flags, &reported);
+
+ if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
+ {
+ ; /* do nothing, watch was for directory monitored as file only */
+ }
+ else
+ {
+ sh_files_filecheck (class, check_flags, filename,
+ (event->len > 0) ? event->name : NULL,
+ &reported, 0);
+ }
+ }
+ return 0;
+}
+
+
+static int sh_fInotify_report_missing (struct inotify_event * event,
+ char * path,
+ int class, unsigned long check_flags, int ftype)
+{
+ int reported;
+ int isdir = (event->mask & IN_ISDIR);
+ int level = (class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[class] :
+ ShDFLevel[(isdir == 0) ? SH_ERR_T_FILE : SH_ERR_T_DIR];
+
+ if (S_FALSE == sh_ignore_chk_del(path))
+ {
+ if (0 != hashreport_missing(path, level))
+ {
+ int ret = sh_files_search_file(path, &class, &check_flags, &reported);
+
+ if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
+ {
+ ; /* do nothing, watch was for directory monitored as file only */
+ }
+ else
+ {
+ /* Removal of a directory triggers:
+ * (1) IN_DELETE IN_ISDIR
+ * (2) IN_DELETE_SELF
+ */
+ if ((event->mask & IN_DELETE_SELF) == 0)
+ sh_fInotify_report_miss(path, level);
+ }
+ }
+ }
+
+ sh_hash_set_missing(path);
+
+ if (sh.flag.reportonce == S_TRUE)
+ sh_files_set_file_reported(path);
+
+ /* Move to 'dormant' list, if not file within directory.
+ */
+ if (event->len == 0)
+ sh_inotify_rm_watch(&sh_file_watches, &sh_file_missing, event->wd);
+
+ return 0;
+}
+
+static int sh_fInotify_report_added (struct inotify_event * event,
+ char * path, char * filename,
+ int class, unsigned long check_flags,
+ int ftype, int rdepth)
+{
+ if (S_FALSE == sh_ignore_chk_new(path))
+ {
+ int reported;
+ int ret;
+ int retD = 0;
+ int rdepthD = rdepth;
+
+ sh_files_clear_file_reported(path);
+
+ ret = sh_files_search_file(path, &class, &check_flags, &reported);
+
+ if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
+ {
+ ; /* do nothing, watch was for directory monitored as file only */
+ }
+ else
+ {
+ int classD = class;
+ int reportedD = reported;
+ unsigned long check_flagsD = check_flags;
+
+ if (event->mask & IN_ISDIR)
+ {
+ retD = sh_files_search_dir(path, &classD, &check_flagsD,
+ &reportedD, &rdepthD);
+
+ if (retD != 0)
+ {
+ if (ret == 0) /* because checked as file below */
+ {
+ class = classD;
+ check_flags = check_flagsD;
+ }
+ }
+ rdepthD -= 1; if (rdepthD < -1) rdepthD = -1;
+ }
+
+ sh_files_filecheck (class, check_flags, filename,
+ (event->len > 0) ? event->name : NULL,
+ &reported, 0);
+
+ if (event->mask & IN_ISDIR)
+ {
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN; );
+ /* Here we use classD because we check as directory now */
+ sh_files_checkdir (classD, check_flagsD, rdepthD,
+ path, (event->len > 0) ? event->name : NULL);
+ SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN; );
+ SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
+ sh_dirs_reset ();
+ sh_files_reset ();
+ }
+ }
+
+ if (SH_FFLAG_REPORTED_SET(reported))
+ sh_files_set_file_reported(path);
+
+ if ((ret != 0) || (event->mask & IN_ISDIR))
+ {
+ int inotify_type = SH_INOTIFY_FILE;
+
+ if ((event->mask & IN_ISDIR) && (rdepthD >= 0))
+ inotify_type = SH_INOTIFY_DIR;
+
+ sh_inotify_add_watch(path, &sh_file_watches, &ret,
+ class, check_flags,
+ inotify_type,
+ rdepthD);
+ }
+ }
+ return 0;
+}
+
+static int sh_fInotify_report(struct inotify_event * event, char * filename,
+ int class, unsigned long check_flags, int ftype, int rdepth)
+{
+ char * fullpath = NULL;
+ char * path;
+
+ if (event->len > 0)
+ {
+ fullpath = sh_util_strconcat(filename, "/", event->name, NULL);
+ path = fullpath;
+ }
+ else
+ {
+ path = filename;
+ }
+
+ if ( (event->mask & (IN_ATTRIB|IN_MODIFY)) != 0)
+ {
+ sh_fInotify_report_change (event, path, filename,
+ class, check_flags, ftype);
+ }
+ else if ((event->mask & (IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF|IN_MOVED_FROM)) != 0)
+ {
+ sh_fInotify_report_missing (event, path,
+ class, check_flags, ftype);
+ }
+ else if((event->mask & (IN_CREATE|IN_MOVED_TO)) != 0)
+ {
+ sh_fInotify_report_added (event, path, filename,
+ class, check_flags,
+ ftype, rdepth);
+ }
+
+ if (fullpath)
+ SH_FREE(fullpath);
+
+ return 0;
+}
+
+
+#endif
+
+#endif
diff --git a/src/sh_fifo.c b/src/sh_fifo.c
new file mode 100644
index 0000000..45f87b0
--- /dev/null
+++ b/src/sh_fifo.c
@@ -0,0 +1,441 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#undef FIL__
+#define FIL__ _("sh.fifo.c")
+
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_unix.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+#include "sh_fifo.h"
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#define SH_FIFO_TAGGED 1
+#define SH_FIFO_M_FAIL 2
+#define SH_FIFO_MARKED 4
+
+/* Prepare an email message and return it. Iterate over list on stack and
+ * check for each if it is valid for recipient 'tag'. If yes, add to the
+ * returned string.
+ * okNull == False means that item->s_xtra must be defined
+ */
+sh_string * tag_list (SH_FIFO * fifo, char * tag,
+ int(*valid)(int, const char*, const char*, const void*),
+ const void * info, int okNull)
+{
+ struct dlist * item;
+ sh_string * result = NULL;
+
+ if (fifo && fifo->fifo_cts > 0)
+ {
+ item = fifo->head_ptr;
+
+ while (item)
+ {
+ /* Same recipient, or no recipient ( := all )
+ */
+ if ( (tag && item->s_xtra && 0 == strcmp(item->s_xtra, tag)) ||
+ ((okNull == S_TRUE) && !(item->s_xtra)) )
+ {
+ if (valid == NULL)
+ {
+ item->transact |= SH_FIFO_TAGGED;
+ }
+ else
+ {
+ /* level, message, recipient, list */
+ if (!valid(item->i_xtra, item->data, tag, info))
+ goto skipped;
+ item->transact |= SH_FIFO_TAGGED;
+ }
+ if (!result)
+ {
+ result = sh_string_new_from_lchar(item->data, strlen(item->data));
+ }
+ else
+ {
+ result = sh_string_cat_lchar(result, "\r\n", 2);
+ result = sh_string_add_from_char(result, item->data);
+ }
+ }
+ skipped:
+ item = item->next;
+ }
+ }
+ return result;
+}
+
+void rollback_list (SH_FIFO * fifo)
+{
+ struct dlist * item;
+
+ if (fifo && fifo->fifo_cts > 0)
+ {
+ item = fifo->head_ptr;
+
+ while (item && 0 != (item->transact & SH_FIFO_TAGGED))
+ {
+ item->transact |= SH_FIFO_M_FAIL;
+ item = item->next;
+ }
+ }
+}
+
+void mark_list (SH_FIFO * fifo)
+{
+ struct dlist * item;
+
+ if (fifo && fifo->fifo_cts > 0)
+ {
+ item = fifo->head_ptr;
+
+ while (item && 0 != (item->transact & SH_FIFO_TAGGED))
+ {
+ item->transact |= SH_FIFO_MARKED;
+ item = item->next;
+ }
+ }
+}
+
+void reset_list (SH_FIFO * fifo)
+{
+ struct dlist * item;
+
+ if (fifo && fifo->fifo_cts > 0)
+ {
+ item = fifo->head_ptr;
+
+ while (item)
+ {
+ item->transact = 0;
+ item = item->next;
+ }
+ }
+}
+
+int commit_list (SH_FIFO * fifo)
+{
+ struct dlist * item;
+ struct dlist * getit;
+ int retval = 0;
+
+ if (fifo && fifo->fifo_cts > 0)
+ {
+ item = fifo->head_ptr;
+
+ while (item)
+ {
+ getit = NULL;
+
+ if ( 0 != (item->transact & SH_FIFO_MARKED) && /* sent */
+ 0 == (item->transact & SH_FIFO_M_FAIL) ) /* no recipient fail */
+ {
+ if (item == fifo->head_ptr)
+ fifo->head_ptr = item->next;
+ if (item == fifo->tail_ptr)
+ fifo->tail_ptr = item->prev;
+ if (item->prev)
+ item->prev->next = item->next;
+ if (item->next)
+ item->next->prev = item->prev;
+ --(fifo->fifo_cts);
+ getit = item;
+ }
+ item = item->next;
+
+ /* Delete it
+ */
+ if (getit)
+ {
+ size_t len = sl_strlen(getit->data);
+ memset(getit->data, 0, len);
+ if (NULL != sl_strstr (getit->data, _("LOGKEY")))
+ MUNLOCK(getit->data, (len+1));
+ if (getit->s_xtra)
+ SH_FREE(getit->s_xtra);
+ SH_FREE(getit->data);
+ SH_FREE(getit);
+ ++retval;
+ }
+ }
+ }
+ return retval;
+}
+
+/* push an item on the head of the list
+ */
+int push_list (SH_FIFO * fifo, const char * indat, int in_i, const char * in_str)
+{
+ struct dlist * item;
+ size_t len;
+
+ SL_ENTER(_("push_list"));
+
+ if (indat == NULL || fifo == NULL)
+ {
+ SL_RETURN((-1), _("push_list"));
+ }
+
+ if (fifo->fifo_cts > SH_FIFO_MAX)
+ {
+ SL_RETURN((-1), _("push_list"));
+ }
+
+ len = sl_strlen(indat);
+
+ if (len == 0)
+ {
+ SL_RETURN((-1), _("push_list"));
+ }
+ item = SH_ALLOC(sizeof(struct dlist));
+ item->data = SH_ALLOC(len+1);
+
+ if (NULL != sl_strstr (indat, _("LOGKEY")))
+ MLOCK(item->data, (len+1));
+
+ sl_strlcpy (item->data, indat, len+1);
+ item->data[len] = '\0';
+
+ item->i_xtra = in_i;
+ if (in_str)
+ item->s_xtra = sh_util_strdup(in_str);
+ else
+ item->s_xtra = NULL;
+ item->transact = 0;
+
+ if (fifo->tail_ptr == NULL)
+ {
+ fifo->tail_ptr = item;
+ item->prev = NULL;
+ }
+ else
+ {
+ fifo->head_ptr->prev = item;
+ item->prev = NULL;
+ }
+
+ item->next = fifo->head_ptr;
+ fifo->head_ptr = item;
+
+ ++(fifo->fifo_cts);
+
+ SL_RETURN((fifo->fifo_cts), _("push_list"));
+}
+
+/* push an item on the tail of the list
+ */
+int push_tail_list (SH_FIFO * fifo, const char * indat, int in_i, const char * in_str)
+{
+ struct dlist * item;
+ size_t len;
+
+ SL_ENTER(_("push_tail_list"));
+
+ if (indat == NULL || fifo == NULL)
+ {
+ SL_RETURN((-1), _("push_tail_list"));
+ }
+
+ if (fifo->fifo_cts > SH_FIFO_MAX)
+ {
+ SL_RETURN((-1), _("push_tail_list"));
+ }
+
+ len = sl_strlen(indat);
+ if (len == 0)
+ {
+ SL_RETURN((-1), _("push_list"));
+ }
+
+ item = SH_ALLOC(sizeof(struct dlist));
+ item->data = SH_ALLOC(len+1);
+
+ if (NULL != sl_strstr (indat, _("LOGKEY")))
+ MLOCK(item->data, (len+1));
+
+ sl_strlcpy (item->data, indat, len+1);
+ item->data[len] = '\0';
+
+ item->i_xtra = in_i;
+ if (in_str)
+ item->s_xtra = sh_util_strdup(in_str);
+ else
+ item->s_xtra = NULL;
+ item->transact = 0;
+
+ if (fifo->head_ptr == NULL)
+ {
+ item->next = NULL;
+ fifo->head_ptr = item;
+ }
+ else
+ {
+ item->next = NULL;
+ fifo->tail_ptr->next = item;
+ }
+
+ item->prev = fifo->tail_ptr;
+ fifo->tail_ptr = item;
+
+ ++(fifo->fifo_cts);
+
+ SL_RETURN((fifo->fifo_cts), _("push_tail_list"));
+}
+
+/* pop an item from the tail of the list
+ */
+/*@null@*/ char * pop_list (SH_FIFO * fifo)
+{
+ size_t len;
+ struct dlist * getit;
+ char * retval;
+
+ SL_ENTER(_("pop_list"));
+
+ if (fifo == NULL || fifo->tail_ptr == NULL)
+ {
+ SL_RETURN (NULL, _("pop_list"));
+ }
+
+ getit = fifo->tail_ptr;
+
+ if (getit->prev == NULL) /* last element */
+ {
+ fifo->tail_ptr = NULL;
+ fifo->head_ptr = NULL;
+ }
+ else
+ {
+ fifo->tail_ptr = getit->prev;
+ fifo->tail_ptr->next = getit->next;
+ }
+
+ len = sl_strlen(getit->data);
+ retval = SH_ALLOC(len+1);
+ sl_strlcpy (retval, getit->data, len+1);
+
+ memset(getit->data, 0, len);
+
+ if (NULL != sl_strstr (retval, _("LOGKEY")))
+ MUNLOCK(getit->data, (len+1));
+
+ if (getit->s_xtra)
+ SH_FREE(getit->s_xtra);
+ SH_FREE(getit->data);
+ SH_FREE(getit);
+
+ --(fifo->fifo_cts);
+
+ SL_RETURN (retval, _("pop_list"));
+}
+
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_fifo (CuTest *tc) {
+
+ SH_FIFO ff;
+ int ret;
+ char * p;
+
+ fifo_init(&ff);
+
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrEquals(tc, NULL, p);
+
+ /* first sequence */
+ ret = sh_fifo_push(&ff, "one");
+ CuAssertIntEquals(tc,1,ret);
+ ret = sh_fifo_push(&ff, "two");
+ CuAssertIntEquals(tc,2,ret);
+ ret = sh_fifo_push(&ff, "three");
+ CuAssertIntEquals(tc,3,ret);
+
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"one", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"two", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"three", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrEquals(tc, NULL, p);
+
+ /* second sequence */
+ ret = sh_fifo_push(&ff, "one");
+ CuAssertIntEquals(tc,1,ret);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"one", p);
+ ret = sh_fifo_push_tail(&ff, "one");
+ CuAssertIntEquals(tc,1,ret);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"one", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrEquals(tc, NULL, p);
+
+ /* third sequence */
+ ret = sh_fifo_push(&ff, "one");
+ CuAssertIntEquals(tc,1,ret);
+ ret = sh_fifo_push(&ff, "two");
+ CuAssertIntEquals(tc,2,ret);
+ ret = sh_fifo_push(&ff, "three");
+ CuAssertIntEquals(tc,3,ret);
+
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"one", p);
+ ret = sh_fifo_push_tail(&ff, p);
+ CuAssertIntEquals(tc,3,ret);
+
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"one", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"two", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc,"three", p);
+ p = sh_fifo_pop(&ff);
+ CuAssertPtrEquals(tc, NULL, p);
+}
+
+#endif
+
+
+
+
diff --git a/src/sh_files.c b/src/sh_files.c
new file mode 100644
index 0000000..c32c4bc
--- /dev/null
+++ b/src/sh_files.c
@@ -0,0 +1,3359 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include <errno.h>
+
+/* Must be before <utime.h> on FreeBSD
+ */
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#if !defined(O_NOATIME)
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
+#define O_NOATIME 01000000
+#endif
+#endif
+
+#include <utime.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
+#define NEED_ADD_DIRENT
+
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+
+#include "samhain.h"
+
+#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
+
+#include "sh_pthread.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_files.h"
+#include "sh_tiger.h"
+#include "sh_hash.h"
+#include "sh_ignore.h"
+#include "sh_inotify.h"
+#include "zAVLTree.h"
+#include "sh_dbIO.h"
+
+#undef FIL__
+#define FIL__ _("sh_files.c")
+
+extern sh_watches sh_file_watches;
+
+static char * sh_files_C_dequote (char * s, size_t * length)
+{
+ size_t i, len = *length;
+ int flag = 0;
+ char *p, *q, *po, *pend;
+
+ /* search for backslash
+ */
+ for (i = 0; i < len; ++i)
+ {
+ if (s[i] == '\\')
+ {
+ flag = 1;
+ break;
+ }
+ }
+
+ if (flag == 0 || *s == '\0')
+ return s;
+
+ po = SH_ALLOC(len+1); *po = '\0'; p = po; pend = &po[len];
+
+ q = s;
+
+ do
+ {
+ if (*q == '\\')
+ {
+ ++q;
+
+ if (*q == '\0')
+ { *p = *q; flag = 0; break; }
+ else if (*q == 'a')
+ { *p = '\a'; ++p; ++q; }
+ else if (*q == 'b')
+ { *p = '\b'; ++p; ++q; }
+ else if (*q == 'f')
+ { *p = '\f'; ++p; ++q; }
+ else if (*q == 'n')
+ { *p = '\n'; ++p; ++q; }
+ else if (*q == 'r')
+ { *p = '\r'; ++p; ++q; }
+ else if (*q == 't')
+ { *p = '\t'; ++p; ++q; }
+ else if (*q == 'v')
+ { *p = '\v'; ++p; ++q; }
+ else if (*q == '\\')
+ { *p = '\\'; ++p; ++q; }
+ else if (*q == '\'')
+ { *p = '\''; ++p; ++q; }
+ else if (*q == '"')
+ { *p = '"'; ++p; ++q; }
+ else if (*q == 'x')
+ {
+ if (isxdigit((int) q[1]) && isxdigit((int) q[2]))
+ {
+ /* hexadecimal value following */
+ unsigned char cc = (16 * sh_util_hexchar(q[1]))
+ + sh_util_hexchar(q[2]);
+ *p = (char) cc;
+ ++p; q += 3;
+ }
+ else
+ {
+ *p = '\0'; flag = 0; break;
+ }
+ }
+ else if (isdigit((int)*q))
+ {
+ if (isdigit((int) q[1]) && q[1] < '8' &&
+ isdigit((int) q[2]) && q[2] < '8')
+ {
+ /* octal value following */
+ char tmp[4]; unsigned char cc;
+ tmp[0] = *q; ++q; tmp[1] = *q; ++q; tmp[2] = *q; ++q;
+ tmp[3] = '\0';
+ cc = strtol(tmp, NULL, 8);
+ *p = (char) cc; ++p;
+ }
+ else
+ {
+ *p = '\0'; flag = 0; break;
+ }
+ }
+ else
+ {
+ /* invalid escape sequence */
+ *p = '\0'; flag = 0; break;
+ }
+ }
+ else
+ {
+ *p = *q;
+ ++p; ++q;
+ }
+ } while (*q && p <= pend);
+
+ SL_REQUIRE (p <= pend, _("p <= pend"));
+
+ if (flag)
+ {
+ *p = '\0';
+ *length = strlen(po);
+ }
+ else
+ {
+ SH_FREE(po);
+ po = NULL;
+ *length = 0;
+ }
+
+ SL_REQUIRE (*length <= len, _("*length <= len"));
+
+ SH_FREE(s);
+ return po;
+}
+
+char * sh_files_parse_input(const char * str_s, size_t * len)
+{
+ char * p;
+
+ if (!str_s || *str_s == '\0')
+ return NULL;
+
+ *len = sl_strlen(str_s);
+
+ if ( (str_s[0] == '"' && str_s[*len-1] == '"' ) ||
+ (str_s[0] == '\'' && str_s[*len-1] == '\'') )
+ {
+ if (*len < 3)
+ return NULL;
+ --(*len);
+ p = sh_util_strdup_l(&str_s[1], *len);
+ p[*len-1] = '\0';
+ --(*len);
+ }
+ else
+ {
+ p = sh_util_strdup_l(str_s, *len);
+ }
+
+ p = sh_files_C_dequote(p, len);
+
+ return p;
+}
+
+
+extern int flag_err_debug;
+extern int flag_err_info;
+
+int sh_files_reportonce(const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_files_reportonce"));
+ i = sh_util_flagval(c, &(sh.flag.reportonce));
+
+ SL_RETURN(i, _("sh_files_reportonce"));
+}
+
+int sh_files_fulldetail(const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_files_fulldetail"));
+ i = sh_util_flagval(c, &(sh.flag.fulldetail));
+
+ SL_RETURN((i), _("sh_files_fulldetail"));
+}
+
+
+typedef struct dir_struct {
+ long NumRegular;
+ long NumDirs;
+ long NumSymlinks;
+ long NumFifos;
+ long NumSockets;
+ long NumCDev;
+ long NumBDev;
+ long NumDoor;
+ long NumPort;
+ long NumAll;
+ long TotalBytes;
+ char DirPath[PATH_MAX];
+} dir_type;
+
+typedef struct dirstack_entry {
+ char * name;
+ int class;
+ unsigned long check_flags;
+ int rdepth;
+ short checked;
+ short childs_checked;
+ short is_reported;
+ /* struct dirstack_entry * next; */
+} dirstack_t;
+
+
+/* the destructor
+ */
+void free_dirstack (void * inptr)
+{
+ dirstack_t * here;
+
+ SL_ENTER(_("free_dirstack"));
+ if (inptr == NULL)
+ SL_RET0(_("free_dirstack"));
+ else
+ here = (dirstack_t *) inptr;
+
+ if (here->name != NULL)
+ SH_FREE(here->name);
+ SH_FREE(here);
+ SL_RET0(_("free_dirstack"));
+}
+
+/* Function to return the key for indexing
+ * the argument
+ */
+zAVLKey zdirstack_key (void const * arg)
+{
+ const dirstack_t * sa = (const dirstack_t *) arg;
+ return (zAVLKey) sa->name;
+}
+
+#define SH_LIST_FILE 0
+#define SH_LIST_DIR1 1
+#define SH_LIST_DIR2 2
+
+
+static int which_dirList = SH_LIST_DIR1;
+
+static zAVLTree * zdirListOne = NULL;
+static zAVLTree * zdirListTwo = NULL;
+static zAVLTree * zfileList = NULL;
+
+SH_MUTEX_STATIC(mutex_zfiles, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_STATIC(mutex_zglob, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_RECURSIVE(mutex_zdirs);
+
+static int sh_files_fullpath (const char * testdir,
+ const char * d_name,
+ char * statpath);
+static int sh_files_pushdir (int class, const char * str_s);
+static int sh_files_pushfile (int class, const char * str_s);
+
+static long MaxRecursionLevel = 0;
+
+/* set default recursion level
+ */
+int sh_files_setrecursion (const char * flag_s)
+{
+ long flag = 0;
+ static int reject = 0;
+
+ SL_ENTER( _("sh_files_setrecursion"));
+
+ if (reject == 1)
+ SL_RETURN((-1), _("sh_files_setrecursion"));
+
+ if (sh.flag.opts == S_TRUE)
+ reject = 1;
+
+ if (flag_s != NULL)
+ flag = (int)(atof(flag_s));
+
+ if (flag >= 0 && flag <= 99)
+ MaxRecursionLevel = flag;
+ else
+ SL_RETURN((-1), _("sh_files_setrecursion"));
+
+ SL_RETURN((0), _("sh_files_setrecursion"));
+}
+
+static int handle_filecheck_ret(dirstack_t * ptr, char * tmp_in, int status)
+{
+ int fcount = 0;
+ char * tmp;
+
+ if (!tmp_in)
+ tmp = sh_util_safe_name (ptr->name);
+ else
+ tmp = tmp_in;
+
+ if (status == SH_FILE_UNKNOWN && (!SH_FFLAG_REPORTED_SET(ptr->is_reported)))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"),
+ tmp, status));
+
+ if ( sh.flag.checkSum == SH_CHECK_INIT ||
+ sh_hash_have_it (ptr->name) >= 0)
+ {
+ if (S_FALSE == sh_ignore_chk_del(ptr->name))
+ {
+ if (0 != hashreport_missing(ptr->name,
+ (ptr->class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_FILE])) {
+ if (tmp == NULL)
+ tmp = sh_util_safe_name (ptr->name);
+ if (!sh_global_check_silent)
+ sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_FILE],
+ FIL__, __LINE__, 0, MSG_FI_MISS,
+ tmp);
+ ++sh.statistics.files_report;
+ }
+ }
+ }
+ else /* not there at init, and still missing */
+ {
+ if (tmp == NULL)
+ tmp = sh_util_safe_name (ptr->name);
+ sh_error_handle (SH_ERR_NOTICE,
+ FIL__, __LINE__, 0,
+ MSG_FI_FAIL,
+ tmp);
+ }
+
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ sh_hash_set_missing(ptr->name);
+
+ if (sh.flag.reportonce == S_TRUE)
+ SET_SH_FFLAG_REPORTED(ptr->is_reported);
+ }
+ else
+ {
+ /* exists (status >= 0), but was missing (reported == TRUE)
+ */
+ if (status != SH_FILE_UNKNOWN && SH_FFLAG_REPORTED_SET(ptr->is_reported))
+ {
+ CLEAR_SH_FFLAG_REPORTED(ptr->is_reported);
+ sh_hash_clear_flag(ptr->name, SH_FFLAG_ENOENT);
+ }
+
+ /* Catchall
+ */
+ else if (status == SH_FILE_UNKNOWN)
+ {
+ /* Thu Mar 7 15:09:40 CET 2002 Make sure missing file
+ * is reported if ptr->reported == S_TRUE because the
+ * file has been added.
+ */
+ if (sh_hash_have_it (ptr->name) >= 0 &&
+ !SH_FFLAG_REPORTED_SET(ptr->is_reported))
+ {
+ if (S_FALSE == sh_ignore_chk_del(ptr->name))
+ {
+ if (0 != hashreport_missing(ptr->name,
+ (ptr->class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_FILE])) {
+ if (tmp == NULL)
+ tmp = sh_util_safe_name (ptr->name);
+ if (!sh_global_check_silent)
+ sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE)?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_FILE],
+ FIL__, __LINE__, 0, MSG_FI_MISS,
+ tmp);
+ ++sh.statistics.files_report;
+ }
+ }
+
+ /* delete from database
+ */
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ sh_hash_set_missing(ptr->name);
+ }
+ else
+ {
+ if (tmp == NULL)
+ tmp = sh_util_safe_name (ptr->name);
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
+ MSG_FI_FAIL,
+ tmp);
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ sh_hash_set_visited_true(ptr->name);
+ }
+ }
+
+ ++fcount;
+ }
+ if (!tmp_in)
+ SH_FREE(tmp);
+
+ return fcount;
+}
+
+
+unsigned long sh_files_chk ()
+{
+ zAVLCursor cursor;
+ ShFileType status;
+ unsigned long fcount = 0;
+
+ char * tmp = NULL;
+
+ dirstack_t * ptr;
+ char * dir;
+ char * file;
+ int tmp_reported;
+
+ SL_ENTER(_("sh_files_chk"));
+
+ for (ptr = (dirstack_t *) zAVLFirst(&cursor, zfileList); ptr;
+ ptr = (dirstack_t *) zAVLNext(&cursor))
+ {
+
+ if (sig_urgent > 0) {
+ SL_RETURN(fcount, _("sh_files_chk"));
+ }
+
+ if (ptr->checked == S_FALSE)
+ {
+ dir = sh_util_dirname (ptr->name);
+ file = sh_util_basename (ptr->name);
+#if defined(WITH_TPT)
+ tmp = sh_util_safe_name (ptr->name);
+#endif
+
+
+ if (flag_err_info == S_TRUE)
+ {
+ char pstr[32];
+#if !defined(WITH_TPT)
+ tmp = sh_util_safe_name (ptr->name);
+#endif
+ sl_strlcpy(pstr, sh_hash_getpolicy(ptr->class), sizeof(pstr));
+ sh_error_handle ((-1), FIL__, __LINE__, 0,
+ MSG_FI_CHK, pstr, tmp);
+ }
+
+ if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
+ {
+ sh_inotify_add_watch_later(ptr->name, &sh_file_watches, NULL,
+ ptr->class, ptr->check_flags,
+ SH_INOTIFY_FILE, 0);
+ }
+
+ BREAKEXIT(sh_files_filecheck);
+ tmp_reported = ptr->is_reported; /* fix aliasing warning */
+ status = sh_files_filecheck (ptr->class, ptr->check_flags, dir, file,
+ &tmp_reported, 0);
+ ptr->is_reported = tmp_reported;
+
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<filecheck complete: %s> status=<%d> reported=<%d>\n"),
+ tmp, status, ptr->is_reported));
+
+ fcount += handle_filecheck_ret(ptr, tmp, status);
+
+ if (tmp != NULL)
+ {
+ SH_FREE(tmp);
+ tmp = NULL;
+ }
+ if (file)
+ SH_FREE(file);
+ if (dir)
+ SH_FREE(dir);
+
+ ptr->checked = S_TRUE;
+ }
+ }
+
+ SL_RETURN(fcount, _("sh_files_chk"));
+}
+
+static zAVLTree * fileTree = NULL;
+static zAVLTree * dirTree = NULL;
+
+static void clear_lists()
+{
+ if (fileTree) {
+ zAVL_string_reset(fileTree);
+ fileTree = NULL;
+ }
+ if (dirTree) {
+ zAVL_string_reset(dirTree);
+ dirTree = NULL;
+ }
+ return;
+}
+
+static void add_to_filelist(zAVLTree * tree)
+{
+ dirstack_t * ptr;
+ zAVLCursor avlcursor;
+
+ SL_ENTER(_("add_to_filelist"));
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor))
+ zAVL_string_set (&fileTree, ptr->name);
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+ SL_RET0(_("add_to_filelist"));
+}
+static void add_to_dirlist(zAVLTree * tree)
+{
+ dirstack_t * ptr;
+ zAVLCursor avlcursor;
+
+ SL_ENTER(_("add_to_dirlist"));
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor))
+ zAVL_string_set (&dirTree, ptr->name);
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+ SL_RET0(_("add_to_dirlist"));
+}
+char * sh_files_findfile(const char * path)
+{
+ return zAVL_string_get (fileTree, path);
+}
+
+void * sh_dummy_621_candidate;
+
+static char * intern_find_morespecific_dir(zAVLTree * tree,
+ const char * path, size_t * len)
+{
+ dirstack_t * ptr;
+ zAVLCursor avlcursor;
+ size_t l_path = strlen(path);
+ size_t l_name;
+ char * candidate = NULL;
+ size_t l_candidate = 0;
+
+ if (NULL == tree)
+ return NULL;
+
+ sh_dummy_621_candidate = (void *) &candidate;
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor))
+ {
+ l_name = strlen(ptr->name);
+ if (l_name <= l_path)
+ {
+ if (0 == strncmp(ptr->name, path, l_name))
+ {
+ if ((l_name == l_path) || (path[l_name] == '/'))
+ {
+ if (!candidate || (l_candidate < l_name))
+ {
+ candidate = ptr->name;
+ l_candidate = l_name;
+ *len = l_candidate;
+ }
+ }
+ }
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+ return candidate;
+}
+char * sh_files_find_mostspecific_dir(const char * path)
+{
+ size_t l_one = 0;
+ size_t l_two = 0;
+ char * one;
+ char * two;
+
+ one = intern_find_morespecific_dir(zdirListOne, path, &l_one);
+ two = intern_find_morespecific_dir(zdirListTwo, path, &l_two);
+
+ if (l_one > l_two) return one;
+ else return two;
+}
+
+int sh_files_delfilestack ()
+{
+ SL_ENTER(_("sh_files_delfilestack"));
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ zAVLFreeTree (zfileList, free_dirstack);
+ zfileList = NULL;
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+
+ SL_RETURN(0, _("sh_files_delfilestack"));
+}
+
+int sh_files_setrec_int (zAVLTree * tree)
+{
+ dirstack_t * ptr;
+ zAVLCursor avlcursor;
+
+ SL_ENTER(_("sh_files_setrec"));
+ if (tree != NULL) {
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, tree); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor))
+ {
+ if (ptr->rdepth < (-1) || ptr->rdepth > 99)
+ {
+ ptr->rdepth = MaxRecursionLevel;
+ }
+
+ if ( (ptr->rdepth == (-1)) &&
+ (ptr->class == SH_LEVEL_ALLIGNORE) &&
+ (sh.flag.checkSum != SH_CHECK_INIT))
+ hash_remove_tree (ptr->name);
+ }
+ }
+ SL_RETURN(0, _("sh_files_setrec"));
+}
+
+int sh_files_setrec ()
+{
+ volatile int ret;
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ clear_lists();
+ add_to_dirlist(zdirListOne);
+ add_to_dirlist(zdirListTwo);
+ add_to_filelist(zfileList);
+ sh_files_setrec_int(zdirListOne);
+ ret = sh_files_setrec_int(zdirListTwo);
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ return ret;
+}
+
+zAVLTree * sh_files_deldirstack_int (zAVLTree * ptr)
+{
+ SL_ENTER(_("sh_files_deldirstack"));
+
+ zAVLFreeTree (ptr, free_dirstack);
+
+ SL_RETURN(NULL, _("sh_files_deldirstack"));
+}
+
+int sh_files_deldirstack ()
+{
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ zdirListOne = sh_files_deldirstack_int(zdirListOne);
+ zdirListTwo = sh_files_deldirstack_int(zdirListTwo);
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+ return 0;
+}
+
+void sh_files_reset()
+{
+ dirstack_t * ptr;
+ zAVLCursor avlcursor;
+
+ SL_ENTER(_("sh_files_reset"));
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, zfileList); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor))
+ ptr->checked = 0;
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+ SL_RET0(_("sh_files_reset"));
+}
+
+void sh_dirs_reset()
+{
+ dirstack_t * ptr;
+ zAVLCursor avlcursor1;
+ zAVLCursor avlcursor2;
+
+ SL_ENTER(_("sh_dirs_reset"));
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor1, zdirListOne); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor1))
+ ptr->checked = 0;
+
+ for (ptr = (dirstack_t *) zAVLFirst(&avlcursor2, zdirListTwo); ptr;
+ ptr = (dirstack_t *) zAVLNext(&avlcursor2))
+ ptr->checked = 0;
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ SL_RET0(_("sh_dirs_reset"));
+}
+
+
+int sh_files_pushfile_prelink (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_PRELINK, str_s));
+}
+
+int sh_files_pushfile_user0 (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_USER0, str_s));
+}
+
+int sh_files_pushfile_user1 (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_USER1, str_s));
+}
+
+int sh_files_pushfile_user2 (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_USER2, str_s));
+}
+
+int sh_files_pushfile_user3 (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_USER3, str_s));
+}
+
+int sh_files_pushfile_user4 (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_USER4, str_s));
+}
+
+
+int sh_files_pushfile_ro (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_READONLY, str_s));
+}
+
+int sh_files_pushfile_attr (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_ATTRIBUTES, str_s));
+}
+
+int sh_files_pushfile_log (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_LOGFILES, str_s));
+}
+
+int sh_files_pushfile_glog (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_LOGGROW, str_s));
+}
+
+int sh_files_pushfile_noig (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_NOIGNORE, str_s));
+}
+
+int sh_files_pushfile_allig (const char * str_s)
+{
+ return (sh_files_pushfile (SH_LEVEL_ALLIGNORE, str_s));
+}
+
+
+static void sh_files_set_mask (unsigned long * mask,
+ unsigned long val, int act)
+{
+ SL_ENTER(_("sh_files_set_mask"));
+
+ if (act == 0)
+ (*mask) = val;
+ else if (act > 0)
+ (*mask) |= val;
+ else
+ (*mask) &= ~val;
+
+ SL_RET0(_("sh_files_set_mask"));
+}
+
+/* set mask(class)
+ */
+static int sh_files_parse_mask (unsigned long * mask, const char * str)
+{
+ int l, i = 0, act = 0, k = 0;
+ char myword[64];
+
+ SL_ENTER(_("sh_files_parse_mask"));
+
+ myword[0] = '\0';
+
+ if (str == NULL)
+ {
+ SL_RETURN ( (-1), _("sh_files_parse_mask"));
+ }
+ else
+ l = sl_strlen(str);
+
+ while (i < l) {
+
+ if (str[i] == '\0')
+ break;
+
+ if (str[i] == ' ' || str[i] == '\t' || str[i] == ',')
+ {
+ ++i;
+ continue;
+ }
+
+ if (str[i] == '+')
+ {
+ act = +1; ++i;
+ myword[0] = '\0';
+ goto getword;
+ }
+ else if (str[i] == '-')
+ {
+ act = -1; ++i;
+ myword[0] = '\0';
+ goto getword;
+ }
+ else /* a word */
+ {
+ getword:
+ k = 0;
+ while (k < 63 && str[i] != ' ' && str[i] != '\t' && str[i] != ','
+ && str[i] != '+' && str[i] != '-' && str[i] != '\0') {
+ myword[k] = str[i];
+ ++i; ++k;
+ }
+ myword[k] = '\0';
+
+ if (sl_strlen(myword) == 0)
+ {
+ SL_RETURN ( (-1), _("sh_files_parse_mask"));
+ }
+
+/* checksum */
+ if (0 == strcmp(myword, _("CHK")))
+ sh_files_set_mask (mask, MODI_CHK, act);
+/* link */
+ else if (0 == strcmp(myword, _("LNK")))
+ sh_files_set_mask (mask, MODI_LNK, act);
+/* inode */
+ else if (0 == strcmp(myword, _("RDEV")))
+ sh_files_set_mask (mask, MODI_RDEV, act);
+/* inode */
+ else if (0 == strcmp(myword, _("INO")))
+ sh_files_set_mask (mask, MODI_INO, act);
+/* user */
+ else if (0 == strcmp(myword, _("USR")))
+ sh_files_set_mask (mask, MODI_USR, act);
+/* group */
+ else if (0 == strcmp(myword, _("GRP")))
+ sh_files_set_mask (mask, MODI_GRP, act);
+/* mtime */
+ else if (0 == strcmp(myword, _("MTM")))
+ sh_files_set_mask (mask, MODI_MTM, act);
+/* ctime */
+ else if (0 == strcmp(myword, _("CTM")))
+ sh_files_set_mask (mask, MODI_CTM, act);
+/* atime */
+ else if (0 == strcmp(myword, _("ATM")))
+ sh_files_set_mask (mask, MODI_ATM, act);
+/* size */
+ else if (0 == strcmp(myword, _("SIZ")))
+ sh_files_set_mask (mask, MODI_SIZ, act);
+/* file mode */
+ else if (0 == strcmp(myword, _("MOD")))
+ sh_files_set_mask (mask, MODI_MOD, act);
+/* hardlinks */
+ else if (0 == strcmp(myword, _("HLN")))
+ sh_files_set_mask (mask, MODI_HLN, act);
+/* size may grow */
+ else if (0 == strcmp(myword, _("SGROW")))
+ sh_files_set_mask (mask, MODI_SGROW, act);
+/* use prelink */
+ else if (0 == strcmp(myword, _("PRE")))
+ sh_files_set_mask (mask, MODI_PREL, act);
+/* get content */
+ else if (0 == strcmp(myword, _("TXT")))
+ sh_files_set_mask (mask, MODI_TXT, act);
+/* get audit report */
+ else if (0 == strcmp(myword, _("AUDIT")))
+ sh_files_set_mask (mask, MODI_AUDIT, act);
+ else
+ {
+ SL_RETURN ( (-1), _("sh_files_parse_mask"));
+ }
+ act = 0;
+ myword[0] = '\0';
+ }
+ }
+ SL_RETURN ( (0), _("sh_files_parse_mask"));
+}
+
+int sh_files_redef_prelink(const char * str)
+{
+ return (sh_files_parse_mask(&mask_PRELINK, str));
+}
+int sh_files_redef_user0(const char * str)
+{
+ return (sh_files_parse_mask(&mask_USER0, str));
+}
+int sh_files_redef_user1(const char * str)
+{
+ return (sh_files_parse_mask(&mask_USER1, str));
+}
+int sh_files_redef_user2(const char * str)
+{
+ return (sh_files_parse_mask(&mask_USER2, str));
+}
+int sh_files_redef_user3(const char * str)
+{
+ return (sh_files_parse_mask(&mask_USER3, str));
+}
+int sh_files_redef_user4(const char * str)
+{
+ return (sh_files_parse_mask(&mask_USER4, str));
+}
+int sh_files_redef_readonly(const char * str)
+{
+ return (sh_files_parse_mask(&mask_READONLY, str));
+}
+int sh_files_redef_loggrow(const char * str)
+{
+ return (sh_files_parse_mask(&mask_LOGGROW, str));
+}
+int sh_files_redef_logfiles(const char * str)
+{
+ return (sh_files_parse_mask(&mask_LOGFILES, str));
+}
+int sh_files_redef_attributes(const char * str)
+{
+ return (sh_files_parse_mask(&mask_ATTRIBUTES, str));
+}
+int sh_files_redef_noignore(const char * str)
+{
+ return (sh_files_parse_mask(&mask_NOIGNORE, str));
+}
+int sh_files_redef_allignore(const char * str)
+{
+ return (sh_files_parse_mask(&mask_ALLIGNORE, str));
+}
+
+unsigned long sh_files_maskof (int class)
+{
+ switch (class)
+ {
+ case SH_LEVEL_READONLY:
+ return (unsigned long) (mask_READONLY | MODI_INIT);
+ case SH_LEVEL_ATTRIBUTES:
+ return (unsigned long) (mask_ATTRIBUTES | MODI_INIT);
+ case SH_LEVEL_LOGFILES:
+ return (unsigned long) (mask_LOGFILES | MODI_INIT);
+ case SH_LEVEL_LOGGROW:
+ return (unsigned long) (mask_LOGGROW | MODI_INIT);
+ case SH_LEVEL_ALLIGNORE:
+ return (unsigned long) (mask_ALLIGNORE | MODI_INIT);
+ case SH_LEVEL_NOIGNORE:
+ return (unsigned long) (mask_NOIGNORE | MODI_INIT);
+ case SH_LEVEL_USER0:
+ return (unsigned long) (mask_USER0 | MODI_INIT);
+ case SH_LEVEL_USER1:
+ return (unsigned long) (mask_USER1 | MODI_INIT);
+ case SH_LEVEL_USER2:
+ return (unsigned long) (mask_USER2 | MODI_INIT);
+ case SH_LEVEL_USER3:
+ return (unsigned long) (mask_USER3 | MODI_INIT);
+ case SH_LEVEL_USER4:
+ return (unsigned long) (mask_USER4 | MODI_INIT);
+ case SH_LEVEL_PRELINK:
+ return (unsigned long) (mask_PRELINK | MODI_INIT);
+ default:
+ return (unsigned long) 0;
+ }
+}
+
+#ifdef HAVE_GLOB_H
+int sh_files_has_metachar (const char * str)
+{
+ SL_ENTER(_("sh_files_has_metachar"));
+ if (NULL != strchr(str, '*'))
+ SL_RETURN(1, _("sh_files_has_metachar"));
+ else if (NULL != strchr(str, '?'))
+ SL_RETURN(1, _("sh_files_has_metachar"));
+ else if (NULL != (strchr(str, '[')))
+ SL_RETURN(1, _("sh_files_has_metachar"));
+ else
+ SL_RETURN(0, _("sh_files_has_metachar"));
+}
+
+
+int sh_files_globerr (const char * epath, int errnum)
+{
+ char * p;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_files_globerr"));
+
+ if (errnum == ENOTDIR || errnum == ENOENT)
+ {
+ SL_RETURN(0, _("sh_files_globerr"));
+ }
+
+ p = sh_util_safe_name (epath);
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_FI_GLOB,
+ sh_error_message (errnum, errbuf, sizeof(errbuf)), p);
+ SH_FREE(p);
+
+ SL_RETURN(0, _("sh_files_globerr"));
+}
+
+/* #ifdef HAVE_GLOB_H
+ */
+#endif
+
+int sh_files_push_file_int (int class, const char * str_s, size_t len,
+ unsigned long check_flags)
+{
+ dirstack_t * new_item_ptr;
+ char * fileName;
+ int ret;
+ volatile int count = 0;
+
+ SL_ENTER(_("sh_files_push_file_int"));
+
+ fileName = SH_ALLOC(len+1);
+ sl_strlcpy(fileName, str_s, len+1);
+
+ new_item_ptr = (dirstack_t *) SH_ALLOC (sizeof(dirstack_t));
+
+ new_item_ptr->name = fileName;
+ new_item_ptr->class = class;
+ new_item_ptr->check_flags = check_flags;
+ new_item_ptr->rdepth = 0;
+ new_item_ptr->checked = S_FALSE;
+ new_item_ptr->is_reported = 0;
+ new_item_ptr->childs_checked = S_FALSE;
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ if (zfileList == NULL)
+ {
+ zfileList = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
+ if (zfileList == NULL)
+ {
+ (void) safe_logger (0, 0, NULL);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ }
+
+ ret = zAVLInsert (zfileList, new_item_ptr);
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+
+ if (-1 == ret)
+ {
+ (void) safe_logger (0, 0, NULL);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ else if (3 == ret)
+ {
+ if (sh.flag.started != S_TRUE)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
+ fileName);
+ SH_FREE(fileName);
+ SH_FREE(new_item_ptr);
+ new_item_ptr = NULL;
+ }
+ else
+ {
+ int reported;
+ unsigned long check_flags = sh_files_maskof(class);
+
+ if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
+ {
+ sh_files_filecheck (class, check_flags, str_s, NULL,
+ &reported, 0);
+ if (SH_FFLAG_REPORTED_SET(reported))
+ sh_files_set_file_reported(str_s);
+ sh_inotify_add_watch_later(str_s, &sh_file_watches, NULL,
+ class, check_flags,
+ SH_INOTIFY_FILE, 0);
+ }
+
+ if (MODI_AUDIT_ENABLED(check_flags))
+ {
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Setting audit watch"),
+ _("sh_files_push_file_int"), str_s);
+ sh_audit_mark(str_s);
+ }
+ ++count;
+ }
+ SL_RETURN(count, _("sh_files_push_file_int"));
+}
+
+int sh_files_push_dir_int (int class, char * tail, size_t len, int rdepth, unsigned long check_flags);
+
+#ifdef HAVE_GLOB_H
+
+typedef struct globstack_entry {
+ char * name;
+ char * type_name;
+ int class;
+ unsigned long check_flags;
+ int rdepth;
+ short type;
+ /* struct dirstack_entry * next; */
+} sh_globstack_t;
+
+static zAVLTree * zglobList = NULL;
+
+zAVLKey zglobstack_key (void const * arg)
+{
+ const sh_globstack_t * sa = (const sh_globstack_t *) arg;
+ return (zAVLKey) sa->type_name;
+}
+
+
+static int sh_files_pushglob (int class, int type, const char * p, int rdepth,
+ unsigned long check_flags_in, int flag)
+{
+ int globstatus = -1;
+ unsigned int gloop;
+ glob_t pglob;
+
+ volatile int count = 0;
+ volatile unsigned long check_flags = (flag == 0) ? sh_files_maskof(class) : check_flags_in;
+
+ SL_ENTER(_("sh_files_pushglob"));
+
+ pglob.gl_offs = 0;
+ globstatus = glob (p, 0, sh_files_globerr, &pglob);
+
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ sh_globstack_t * new_item_ptr;
+ char * fileName;
+ char * typeName;
+ int ret;
+
+ SH_MUTEX_TRYLOCK(mutex_zfiles);
+ fileName = sh_util_strdup (p);
+ typeName = sh_util_strconcat ((type == SH_LIST_FILE) ? "F" : "D", p, NULL);
+
+ new_item_ptr = (sh_globstack_t *) SH_ALLOC (sizeof(sh_globstack_t));
+
+ new_item_ptr->name = fileName;
+ new_item_ptr->type_name = typeName;
+ new_item_ptr->class = class;
+ new_item_ptr->check_flags = check_flags;
+ new_item_ptr->rdepth = rdepth;
+ new_item_ptr->type = type;
+
+ if (zglobList == NULL)
+ {
+ zglobList = zAVLAllocTree (zglobstack_key, zAVL_KEY_STRING);
+ if (zglobList == NULL)
+ {
+ (void) safe_logger (0, 0, NULL);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ }
+
+ ret = zAVLInsert (zglobList, new_item_ptr);
+
+ if (ret != 0) /* already in list */
+ {
+ SH_FREE(fileName);
+ SH_FREE(typeName);
+ SH_FREE(new_item_ptr);
+ }
+ SH_MUTEX_TRYLOCK_UNLOCK(mutex_zfiles);
+ }
+
+
+ if (globstatus == 0 && pglob.gl_pathc > 0)
+ {
+ for (gloop = 0; gloop < (unsigned int) pglob.gl_pathc; ++gloop)
+ {
+ if (type == SH_LIST_FILE)
+ {
+ count += sh_files_push_file_int (class, pglob.gl_pathv[gloop],
+ sl_strlen(pglob.gl_pathv[gloop]), check_flags);
+ }
+ else
+ {
+ which_dirList = type;
+
+ count += sh_files_push_dir_int (class, pglob.gl_pathv[gloop],
+ sl_strlen(pglob.gl_pathv[gloop]), rdepth, check_flags);
+ }
+ }
+ }
+ else
+ {
+ char * tmp = sh_util_safe_name (p);
+
+ if (pglob.gl_pathc == 0
+#ifdef GLOB_NOMATCH
+ || globstatus == GLOB_NOMATCH
+#endif
+ )
+ sh_error_handle ((sh.flag.started != S_TRUE) ? SH_ERR_ERR : SH_ERR_NOTICE,
+ FIL__, __LINE__,
+ globstatus, MSG_FI_GLOB,
+ _("No matches found"), tmp);
+#ifdef GLOB_NOSPACE
+ else if (globstatus == GLOB_NOSPACE)
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ globstatus, MSG_FI_GLOB,
+ _("Out of memory"), tmp);
+#endif
+#ifdef GLOB_ABORTED
+ else if (globstatus == GLOB_ABORTED)
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ globstatus, MSG_FI_GLOB,
+ _("Read error"), tmp);
+#endif
+ else
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
+ globstatus, MSG_FI_GLOB,
+ _("Unknown error"), tmp);
+
+ SH_FREE(tmp);
+
+ }
+
+ globfree(&pglob);
+ SL_RETURN(count, _("sh_files_pushglob"));
+ return count;
+}
+
+void sh_files_check_globFilePatterns()
+{
+ sh_globstack_t * testPattern;
+ zAVLCursor cursor;
+
+ SL_ENTER(_("sh_files_check_globPatterns"));
+
+ SH_MUTEX_LOCK(mutex_zglob);
+ for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList);
+ testPattern;
+ testPattern = (sh_globstack_t *) zAVLNext (&cursor))
+ {
+ if (testPattern->type == SH_LIST_FILE)
+ {
+ sh_files_pushglob(testPattern->class, testPattern->type,
+ testPattern->name, testPattern->rdepth,
+ testPattern->check_flags, 1);
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_zglob);
+ SL_RET0(_("sh_files_check_globPatterns"));
+}
+
+void sh_files_check_globPatterns()
+{
+ sh_globstack_t * testPattern;
+ zAVLCursor cursor;
+
+ SL_ENTER(_("sh_files_check_globPatterns"));
+
+ SH_MUTEX_LOCK(mutex_zglob);
+ for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList);
+ testPattern;
+ testPattern = (sh_globstack_t *) zAVLNext (&cursor))
+ {
+ sh_files_pushglob(testPattern->class, testPattern->type,
+ testPattern->name, testPattern->rdepth,
+ testPattern->check_flags, 1);
+ }
+ SH_MUTEX_UNLOCK(mutex_zglob);
+ SL_RET0(_("sh_files_check_globPatterns"));
+}
+
+/* the destructor
+ */
+void free_globstack (void * inptr)
+{
+ sh_globstack_t * here;
+
+ SL_ENTER(_("free_globstack"));
+ if (inptr == NULL)
+ SL_RET0(_("free_globstack"));
+ else
+ here = (sh_globstack_t *) inptr;
+
+ if (here->name != NULL)
+ SH_FREE(here->name);
+ if (here->type_name != NULL)
+ SH_FREE(here->type_name);
+ SH_FREE(here);
+ SL_RET0(_("free_globstack"));
+}
+
+int sh_files_delglobstack ()
+{
+ SL_ENTER(_("sh_files_delglobstack"));
+
+ SH_MUTEX_LOCK(mutex_zglob);
+ zAVLFreeTree (zglobList, free_globstack);
+ zglobList = NULL;
+ SH_MUTEX_UNLOCK(mutex_zglob);
+
+ SL_RETURN(0, _("sh_files_delglobstack"));
+}
+
+
+#else
+void sh_files_check_globPatterns()
+{
+ return;
+}
+int sh_files_delglobstack ()
+{
+ return 0;
+}
+#endif
+
+static int sh_files_pushfile (int class, const char * str_s)
+{
+ size_t len;
+ char * tmp;
+ char * p;
+
+ static int reject = 0;
+
+ SL_ENTER(_("sh_files_pushfile"));
+
+ if (reject == 1)
+ SL_RETURN((-1),_("sh_files_pushfile"));
+
+ /* if we push a filename from the command line, make sure it
+ * is the only one -- and will stay the only one
+ */
+ if (sh.flag.opts == S_TRUE)
+ {
+ sh_files_delfilestack ();
+ sh_files_deldirstack ();
+ sh_files_delglobstack ();
+ reject = 1;
+ }
+
+ p = sh_files_parse_input(str_s, &len);
+ if (!p || len == 0)
+ SL_RETURN((-1), _("sh_files_pushfile"));
+
+ if (len >= PATH_MAX)
+ {
+ /* Name too long
+ */
+ tmp = sh_util_safe_name (p);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
+ tmp);
+ SH_FREE(tmp);
+ SL_RETURN((-1),_("sh_files_pushfile"));
+ }
+ else if (p[0] != '/')
+ {
+ /* Not an absolute path
+ */
+ tmp = sh_util_safe_name (p);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
+ tmp);
+ SH_FREE(tmp);
+ SL_RETURN((-1),_("sh_files_pushfile"));
+ }
+ else
+ {
+ /* remove a terminating '/', take care of the
+ * special case of the root directory.
+ */
+ if (p[len-1] == '/' && len > 1)
+ {
+ p[len-1] = '\0';
+ --len;
+ }
+ }
+
+#ifdef HAVE_GLOB_H
+ if (0 == sh_files_has_metachar(p))
+ {
+ sh_files_push_file_int (class, p, len, sh_files_maskof(class));
+ }
+ else
+ {
+ sh_files_pushglob (class, SH_LIST_FILE, p, 0, 0, 0);
+ }
+
+#else
+ sh_files_push_file_int (class, p, len, sh_files_maskof(class));
+#endif
+
+ SH_FREE(p);
+ SL_RETURN((0),_("sh_files_pushfile"));
+}
+
+
+/* ------ directories ----- */
+
+int sh_files_is_allignore_int (char * str, zAVLTree * tree)
+{
+ dirstack_t * ptr;
+
+ SL_ENTER(_("sh_files_is_allignore"));
+
+ if (tree)
+ {
+ ptr = zAVLSearch(tree, str);
+ if (ptr)
+ {
+ if (ptr->class == SH_LEVEL_ALLIGNORE)
+ SL_RETURN( 1, _("sh_files_is_allignore"));
+ else
+ SL_RETURN( 0, _("sh_files_is_allignore"));
+ }
+ }
+ SL_RETURN( 0, _("sh_files_is_allignore"));
+}
+
+int sh_files_is_allignore (char * str)
+{
+ int retval = 0;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ retval = sh_files_is_allignore_int(str, zdirListOne);
+
+ if (NULL != zdirListTwo && retval == 0)
+ {
+ retval = sh_files_is_allignore_int(str, zdirListTwo);
+ }
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+ return retval;
+}
+
+void * sh_dummy_1493_ptr;
+
+unsigned long sh_dirs_chk (int which)
+{
+ zAVLTree * tree;
+ zAVLCursor cursor;
+ dirstack_t * ptr;
+ dirstack_t * dst_ptr;
+ int status;
+ int tmp_reported;
+ volatile int filetype = SH_FILE_UNKNOWN;
+ volatile unsigned long dcount = 0;
+ char * tmp;
+
+ SL_ENTER(_("sh_dirs_chk"));
+
+ sh_dummy_1493_ptr = (void *) &ptr;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ if (which == 1)
+ tree = zdirListOne;
+ else
+ tree = zdirListTwo;
+
+ for (ptr = (dirstack_t *) zAVLFirst(&cursor, tree); ptr;
+ ptr = (dirstack_t *) zAVLNext(&cursor))
+ {
+ if (sig_urgent > 0) {
+ goto out;
+ }
+
+ if (ptr->checked == S_FALSE)
+ {
+ SH_MUTEX_LOCK(mutex_zfiles);
+ /* 28 Aug 2001 check the top level directory
+ */
+ status = S_FALSE;
+ dst_ptr = zAVLSearch(zfileList, ptr->name);
+ if (dst_ptr)
+ {
+ if (dst_ptr->checked == S_FALSE)
+ {
+ BREAKEXIT(sh_files_filecheck);
+ tmp_reported = dst_ptr->is_reported;
+ filetype = sh_files_filecheck (dst_ptr->class, dst_ptr->check_flags,
+ ptr->name,
+ NULL, &tmp_reported, 0);
+ dst_ptr->is_reported = tmp_reported;
+ (void) handle_filecheck_ret(dst_ptr, NULL, filetype);
+
+ dst_ptr->checked = S_TRUE;
+ status = S_TRUE;
+ }
+ else
+ {
+ status = S_TRUE;
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+
+ if (status == S_FALSE)
+ {
+ tmp_reported = ptr->is_reported;
+ filetype = sh_files_filecheck (ptr->class, ptr->check_flags,
+ ptr->name, NULL, &tmp_reported, 0);
+ ptr->is_reported = tmp_reported;
+ (void) handle_filecheck_ret(ptr, NULL, filetype);
+ }
+
+ BREAKEXIT(sh_files_checkdir);
+ status = sh_files_checkdir (ptr->class, ptr->check_flags,
+ ptr->rdepth, ptr->name,
+ ptr->name);
+
+ if (status < 0 && (!SH_FFLAG_REPORTED_SET(ptr->is_reported)))
+ {
+ /* directory is missing
+ */
+ if (S_FALSE == sh_ignore_chk_del(ptr->name))
+ {
+ if (0 != hashreport_missing(ptr->name,
+ (ptr->class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_DIR])) {
+ tmp = sh_util_safe_name (ptr->name);
+ if (!sh_global_check_silent)
+ sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__,
+ 0, MSG_FI_MISS, tmp);
+ ++sh.statistics.files_report;
+ SH_FREE(tmp);
+ }
+ }
+ if (sh.flag.reportonce == S_TRUE)
+ SET_SH_FFLAG_REPORTED(ptr->is_reported);
+ }
+ else
+ {
+ /* exists (status >= 0), but was missing (reported == TRUE)
+ */
+ if (status >= 0 && SH_FFLAG_REPORTED_SET(ptr->is_reported))
+ {
+ CLEAR_SH_FFLAG_REPORTED(ptr->is_reported);
+ sh_hash_clear_flag(ptr->name, SH_FFLAG_ENOENT);
+#if 0
+ /* obsoleted (really?) by the mandatory sh_files_filecheck()
+ * above, which will catch missing directories anyway
+ */
+ tmp = sh_util_safe_name (ptr->name);
+ if (!sh_global_check_silent)
+ sh_error_handle ((ptr->class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[ptr->class] :
+ ShDFLevel[SH_ERR_T_DIR],
+ FIL__, __LINE__, 0, MSG_FI_ADD,
+ tmp);
+ ++sh.statistics.files_report;
+ SH_FREE(tmp);
+#endif
+ }
+ else if (status == SH_FILE_UNKNOWN)
+ {
+ /* catchall
+ */
+ tmp = sh_util_safe_name (ptr->name);
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0,
+ MSG_FI_FAIL,
+ tmp);
+ SH_FREE(tmp);
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ sh_hash_set_visited_true(ptr->name);
+ }
+
+ ++dcount;
+ }
+ ptr->checked = S_TRUE;
+ ptr->childs_checked = S_TRUE;
+ }
+
+ if (sig_urgent > 0) {
+ goto out;
+ }
+
+ }
+ out:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ SL_RETURN(dcount, _("sh_dirs_chk"));
+}
+
+int sh_files_pushdir_prelink (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_PRELINK, str_s));
+}
+
+int sh_files_pushdir_user0 (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_USER0, str_s));
+}
+
+int sh_files_pushdir_user1 (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_USER1, str_s));
+}
+
+int sh_files_pushdir_user2 (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_USER2, str_s));
+}
+
+int sh_files_pushdir_user3 (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_USER3, str_s));
+}
+
+int sh_files_pushdir_user4 (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_USER4, str_s));
+}
+
+int sh_files_pushdir_attr (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_ATTRIBUTES, str_s));
+}
+
+int sh_files_pushdir_ro (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_READONLY, str_s));
+}
+
+int sh_files_pushdir_log (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_LOGFILES, str_s));
+}
+
+int sh_files_pushdir_glog (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_LOGGROW, str_s));
+}
+
+int sh_files_pushdir_noig (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_NOIGNORE, str_s));
+}
+
+int sh_files_pushdir_allig (const char * str_s)
+{
+ return (sh_files_pushdir (SH_LEVEL_ALLIGNORE, str_s));
+}
+
+int set_dirList (int which)
+{
+ if (which == 2)
+ which_dirList = SH_LIST_DIR2;
+ else
+ which_dirList = SH_LIST_DIR1;
+ return 0;
+}
+
+int sh_files_push_dir_int (int class, char * tail, size_t len, int rdepth, unsigned long check_flags)
+{
+ zAVLTree * tree;
+ dirstack_t * new_item_ptr;
+ char * dirName;
+ int ret;
+
+ SL_ENTER(_("sh_files_push_dir_int"));
+
+ dirName = SH_ALLOC(len+1);
+ sl_strlcpy(dirName, tail, len+1);
+
+ new_item_ptr = (dirstack_t * ) SH_ALLOC (sizeof(dirstack_t));
+
+ new_item_ptr->name = dirName;
+ new_item_ptr->class = class;
+ new_item_ptr->check_flags = check_flags;
+ new_item_ptr->rdepth = rdepth;
+ new_item_ptr->checked = S_FALSE;
+ new_item_ptr->is_reported = 0;
+ new_item_ptr->childs_checked = S_FALSE;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ if (which_dirList == SH_LIST_DIR1)
+ {
+ tree = zdirListOne;
+ }
+ else
+ {
+ tree = zdirListTwo;
+ }
+
+ if (tree == NULL)
+ {
+ tree = zAVLAllocTree (zdirstack_key, zAVL_KEY_STRING);
+ if (tree == NULL)
+ {
+ (void) safe_logger (0, 0, NULL);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ if (which_dirList == SH_LIST_DIR1)
+ zdirListOne = tree;
+ else
+ zdirListTwo = tree;
+ }
+
+ ret = zAVLInsert (tree, new_item_ptr);
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ if (-1 == ret)
+ {
+ (void) safe_logger (0, 0, NULL);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ if (3 == ret)
+ {
+ if (sh.flag.started != S_TRUE)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
+ dirName);
+ SH_FREE(dirName);
+ SH_FREE(new_item_ptr);
+ new_item_ptr = NULL;
+ }
+ else
+ {
+ if (MODI_AUDIT_ENABLED(check_flags))
+ {
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Setting audit watch"),
+ _("sh_files_push_file_int"), tail);
+ sh_audit_mark(tail);
+ }
+ }
+ SL_RETURN(0, _("sh_files_push_dir_int"));
+}
+
+static int sh_files_pushdir (int class, const char * str_s)
+{
+ char * tmp;
+ size_t len;
+ int rdepth = 0;
+ char * tail = NULL;
+ char * p;
+
+ SL_ENTER(_("sh_files_pushdir"));
+
+ if (sh.flag.opts == S_TRUE) {
+ sh_files_delfilestack ();
+ sh_files_deldirstack ();
+ sh_files_delglobstack ();
+ }
+
+ p = sh_files_parse_input(str_s, &len);
+ if (!p || len == 0)
+ SL_RETURN((-1),_("sh_files_pushdir"));
+
+ if (p[0] != '/')
+ {
+ rdepth = strtol(p, &tail, 10);
+ if (tail == p)
+ {
+ SH_FREE(p);
+ SL_RETURN((-1), _("sh_files_pushdir"));
+ }
+ }
+ else
+ tail = p;
+
+
+ if (tail == p)
+ {
+ /* Setting to an invalid number will force MaxRecursionLevel,
+ * see sh_files_setrec_int()
+ */
+ rdepth = (-2);
+ }
+ else if ( (rdepth < (-1) || rdepth > 99) ||
+ ((rdepth == (-1)) && (class != SH_LEVEL_ALLIGNORE)) )
+ {
+ SH_FREE(p);
+ SL_RETURN((-1), _("sh_files_pushdir"));
+ }
+
+ len = sl_strlen(tail);
+
+ if (len >= PATH_MAX)
+ {
+ tmp = sh_util_safe_name (tail);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_2LONG,
+ tmp);
+ SH_FREE(tmp);
+ SH_FREE(p);
+ SL_RETURN((-1), _("sh_files_pushdir"));
+ }
+ else if (len < 1)
+ {
+ SH_FREE(p);
+ SL_RETURN((-1), _("sh_files_pushdir"));
+ }
+ else if (tail[0] != '/')
+ {
+ tmp = sh_util_safe_name (tail);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NOPATH,
+ tmp);
+ SH_FREE(tmp);
+ SH_FREE(p);
+ SL_RETURN((-1), _("sh_files_pushdir"));
+ }
+ else
+ {
+ if (tail[len-1] == '/' && len > 1)
+ {
+ tail[len-1] = '\0';
+ --len;
+ }
+ }
+
+#ifdef HAVE_GLOB_H
+ if (0 == sh_files_has_metachar(tail))
+ {
+ sh_files_push_dir_int (class, tail, len, rdepth, sh_files_maskof(class));
+ }
+ else
+ {
+ sh_files_pushglob (class, which_dirList, tail, rdepth, 0, 0);
+ }
+#else
+ sh_files_push_dir_int (class, tail, len, rdepth, sh_files_maskof(class));
+#endif
+
+ SH_FREE(p);
+ SL_RETURN((0), _("sh_files_pushdir"));
+}
+
+/**
+struct sh_dirent {
+ char * sh_d_name;
+ struct sh_dirent * next;
+};
+**/
+
+void kill_sh_dirlist (struct sh_dirent * dirlist)
+{
+ struct sh_dirent * this;
+
+ while (dirlist)
+ {
+ this = dirlist->next;
+ SH_FREE(dirlist->sh_d_name);
+ SH_FREE(dirlist);
+ dirlist = this;
+ }
+ return;
+}
+
+/* -- add an entry to a directory listing
+ */
+struct sh_dirent * addto_sh_dirlist (struct dirent * thisEntry,
+ struct sh_dirent * dirlist)
+{
+ struct sh_dirent * this;
+ size_t len;
+
+ if (thisEntry == NULL)
+ return dirlist;
+
+ len = sl_strlen(thisEntry->d_name);
+ if (len == 0)
+ return dirlist;
+ ++len;
+
+ this = SH_ALLOC(sizeof(struct sh_dirent));
+ if (!this)
+ return dirlist;
+
+ this->sh_d_name = SH_ALLOC(len);
+ sl_strlcpy(this->sh_d_name, thisEntry->d_name, len);
+
+ this->next = dirlist;
+ return this;
+}
+
+static int sh_check_hardlinks = S_TRUE;
+
+/* Simply sets our boolean as to whether this check is active
+ */
+int sh_files_check_hardlinks (const char * opt)
+{
+ int i;
+ SL_ENTER(_("sh_files_check_hardlinks"));
+ i = sh_util_flagval(opt, &sh_check_hardlinks);
+ SL_RETURN(i, _("sh_files_check_hardlinks"));
+}
+
+struct sh_hle_struct {
+ long offset;
+ char * path;
+ struct sh_hle_struct * next;
+};
+
+static struct sh_hle_struct * sh_hl_exc = NULL;
+
+int sh_files_hle_reg (const char * str)
+{
+ long offset;
+ size_t len;
+ char * path;
+
+ struct sh_hle_struct * tmp = sh_hl_exc;
+
+ SL_ENTER(_("sh_files_hle_reg"));
+
+ /* Free the linked list if called with NULL argument
+ */
+ if (str == NULL)
+ {
+ while (tmp)
+ {
+ sh_hl_exc = tmp->next;
+ SH_FREE(tmp->path);
+ SH_FREE(tmp);
+ tmp = sh_hl_exc;
+ }
+ sh_hl_exc = NULL;
+ SL_RETURN(0, _("sh_files_hle_reg"));
+ }
+
+ /* We expect 'offset:/path'
+ */
+ offset = strtol(str, &path, 0);
+ if ((path == NULL) || (*path == '\0') || (*path != ':') || (path[1] != '/'))
+ {
+ SL_RETURN(-1, _("sh_files_hle_reg"));
+ }
+ ++path;
+ len = 1 + sl_strlen(path);
+
+ tmp = SH_ALLOC(sizeof(struct sh_hle_struct));
+ tmp->path = SH_ALLOC(len);
+ sl_strlcpy (tmp->path, path, len);
+ tmp->offset = offset;
+ tmp->next = sh_hl_exc;
+ sh_hl_exc = tmp;
+
+ SL_RETURN(0, _("sh_files_hle_reg"));
+}
+
+#if !defined(HOST_IS_DARWIN)
+static int sh_files_hle_test (int offset, char * path)
+{
+ struct sh_hle_struct * tmp = sh_hl_exc;
+
+ SL_ENTER(_("sh_files_hle_reg"));
+
+ while(tmp)
+ {
+ if ((offset == tmp->offset) && (0 == strcmp(path, tmp->path)))
+ {
+ SL_RETURN(0, _("sh_files_hle_test"));
+ }
+ tmp = tmp->next;
+ }
+#ifdef HAVE_FNMATCH_H
+ if ( (offset == 1) && (0 == fnmatch(_("/run/user/*"), path, FNM_PATHNAME)) )
+ {
+ /* gvfs directory in /run/user/username/ */
+ SL_RETURN(0, _("sh_files_hle_test"));
+ }
+#endif
+
+ SL_RETURN(-1, _("sh_files_hle_test"));
+}
+#endif
+
+static void * sh_dummy_dirlist;
+static void * sh_dummy_tmpcat;
+
+/* -- Check a single directory and its content. Does not
+ * check the directory inode itself.
+ */
+int sh_files_checkdir (int iclass, unsigned long check_flags,
+ int idepth, char * iname,
+ char * relativeName)
+{
+ struct sh_dirent * dirlist;
+ struct sh_dirent * dirlist_orig;
+
+ DIR * thisDir = NULL;
+ struct dirent * thisEntry;
+ int status;
+ int dummy = S_FALSE;
+ dir_type * theDir;
+ ShFileType checkit;
+ static unsigned int state = 1;
+
+ file_type * theFile;
+ char * tmpname;
+ char * tmpcat;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ int rdepth = 0;
+ int class = 0;
+ volatile int rdepth_next;
+ volatile int class_next;
+ volatile int file_class_next;
+ volatile unsigned long check_flags_next;
+ volatile unsigned long file_check_flags_next;
+
+ volatile int checked_flag = S_FALSE;
+ volatile int cchecked_flag = S_FALSE;
+
+ dirstack_t * dst_ptr;
+ dirstack_t * tmp_ptr;
+
+ int hardlink_num = 0;
+#if !defined(HOST_IS_DARWIN)
+ size_t len;
+#endif
+
+ SL_ENTER(_("sh_files_checkdir"));
+
+ if (sig_urgent > 0) {
+ SL_RETURN((0), _("sh_files_checkdir"));
+ }
+
+ if (iname == NULL || idepth < (-1))
+ SL_RETURN((-1), _("sh_files_checkdir"));
+
+ if (idepth < 0)
+ {
+ /* hash_remove_tree (iname); */
+ SL_RETURN((0), _("sh_files_checkdir"));
+ }
+
+ rdepth = idepth;
+ class = iclass;
+
+ tmpname = sh_util_safe_name (iname);
+
+ /* ---- check for obscure name ----
+ */
+ if (iclass != SH_LEVEL_ALLIGNORE)
+ {
+ sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME], iname, S_TRUE);
+ }
+
+ if (flag_err_info == S_TRUE)
+ {
+ char pstr[32];
+
+ sl_strlcpy(pstr, sh_hash_getpolicy(iclass), sizeof(pstr));
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CHK, pstr, tmpname);
+ }
+
+ /* ---- check input ----
+ */
+ if ( sl_strlen(iname) >= PATH_MAX)
+ {
+ sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
+ MSG_FI_2LONG,
+ tmpname);
+ SH_FREE(tmpname);
+ SL_RETURN((-1), _("sh_files_checkdir"));
+ }
+
+ /* ---- check for absolute path ---- */
+ if ( iname[0] != '/')
+ {
+ sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
+ MSG_FI_NOPATH,
+ tmpname);
+ SH_FREE(tmpname);
+ SL_RETURN((-1), _("sh_files_checkdir"));
+ }
+
+ /* ---- stat the directory ----
+ */
+ theFile = SH_ALLOC(sizeof(file_type));
+ sl_strlcpy (theFile->fullpath, iname, PATH_MAX);
+ theFile->attr_string = NULL;
+ theFile->link_path = NULL;
+ theFile->check_flags = check_flags;
+
+ (void) relativeName;
+ status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_DIR],
+ iname,
+ theFile, NULL, iclass);
+
+ if ((sig_termfast == 1) || (sig_terminate == 1))
+ {
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+ SH_FREE(tmpname);
+ SL_RETURN((0), _("sh_files_checkdir"));
+ }
+
+ if (status == -1)
+ {
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+ SH_FREE(tmpname);
+ SL_RETURN((-1), _("sh_files_checkdir"));
+ }
+
+ if (theFile->c_mode[0] != 'd')
+ {
+ if (!sh_global_check_silent)
+ sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
+ MSG_FI_NODIR,
+ tmpname);
+ ++sh.statistics.files_nodir;
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+ SH_FREE(tmpname);
+ SL_RETURN((-1), _("sh_files_checkdir"));
+ }
+
+ if ((sh.flag.inotify & SH_INOTIFY_INSCAN) != 0)
+ {
+ sh_inotify_add_watch_later(iname, &sh_file_watches, &status,
+ iclass, check_flags, SH_INOTIFY_DIR, idepth);
+ }
+
+ hardlink_num = theFile->hardlinks;
+
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+
+ /* ---- open directory for reading ----
+ *
+ * opendir() will fail with ENOTDIR if the path has been changed
+ * to a non-directory in between lstat() and opendir().
+ */
+ thisDir = opendir (iname);
+
+ if (thisDir == NULL)
+ {
+ status = errno;
+ sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
+ MSG_E_OPENDIR,
+ sh_error_message (status, errbuf, sizeof(errbuf)), tmpname);
+ SH_FREE(tmpname);
+ SL_RETURN((-1), _("sh_files_checkdir"));
+ }
+
+ theDir = SH_ALLOC(sizeof(dir_type));
+
+ theDir->NumRegular = 0;
+ theDir->NumDirs = 0;
+ theDir->NumSymlinks = 0;
+ theDir->NumFifos = 0;
+ theDir->NumSockets = 0;
+ theDir->NumCDev = 0;
+ theDir->NumBDev = 0;
+ theDir->NumDoor = 0;
+ theDir->NumPort = 0;
+ theDir->NumAll = 0;
+ theDir->TotalBytes = 0;
+ sl_strlcpy (theDir->DirPath, iname, PATH_MAX);
+
+
+ sh_dummy_dirlist = (void *) &dirlist;
+ sh_dummy_tmpcat = (void *) &tmpcat;
+
+ /* ---- read ----
+ */
+ SH_MUTEX_LOCK(mutex_readdir);
+
+ dirlist = NULL;
+ dirlist_orig = NULL;
+
+ do {
+ thisEntry = readdir (thisDir);
+ if (thisEntry != NULL)
+ {
+ ++theDir->NumAll;
+ if (sl_strcmp (thisEntry->d_name, ".") == 0)
+ {
+ ++theDir->NumDirs;
+ continue;
+ }
+ if (sl_strcmp (thisEntry->d_name, "..") == 0)
+ {
+ ++theDir->NumDirs;
+ continue;
+ }
+ dirlist = addto_sh_dirlist (thisEntry, dirlist);
+ }
+ } while (thisEntry != NULL);
+
+ SH_MUTEX_UNLOCK(mutex_readdir);
+
+ closedir (thisDir);
+
+ ++sh.statistics.dirs_checked;
+
+ dirlist_orig = dirlist;
+
+ do {
+
+ /* If the directory is empty, dirlist = NULL
+ */
+ if (!dirlist)
+ break;
+
+ if (sig_termfast == 1)
+ {
+ SH_FREE(theDir);
+ SH_FREE(tmpname);
+ SL_RETURN((0), _("sh_files_checkdir"));
+ }
+
+ BREAKEXIT(sh_derr);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R)
+ if (0 == (rand_r(&state) % 5)) (void) sh_derr();
+#else
+ if (0 == state * (rand() % 5)) (void) sh_derr();
+#endif
+
+ /* ---- Check the file. ----
+ */
+ tmpcat = SH_ALLOC(PATH_MAX);
+ sl_strlcpy(tmpcat, iname, PATH_MAX);
+ if (sl_strlen(tmpcat) > 1 || tmpcat[0] != '/')
+ sl_strlcat(tmpcat, "/", PATH_MAX);
+ sl_strlcat(tmpcat, dirlist->sh_d_name, PATH_MAX);
+
+ rdepth_next = rdepth - 1;
+ class_next = class;
+ check_flags_next = check_flags;
+ file_class_next = class;
+ file_check_flags_next = check_flags;
+ checked_flag = -1;
+ cchecked_flag = -1;
+
+ /* Wed Aug 24 2005 compare against dirListOne, dirListTwo
+ * this fixes the problem that the directory special file
+ * is checked with the policy of the parent directory
+ */
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ dst_ptr = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
+
+ if (dst_ptr)
+ {
+ /* Tue Aug 6 22:13:27 CEST 2002 introduce file_class_next
+ * this fixes the problem that a policy for the directory
+ * inode erroneously becomes a policy for the directory itself.
+ */
+ file_class_next = dst_ptr->class;
+ file_check_flags_next = dst_ptr->check_flags;
+ checked_flag = dst_ptr->checked;
+ cchecked_flag = dst_ptr->childs_checked;
+ }
+
+ if (checked_flag == -1)
+ {
+ dst_ptr = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
+
+ if (dst_ptr)
+ {
+ /* Tue Aug 6 22:13:27 CEST 2002 introduce file_class_next
+ * this fixes the problem that a policy for the directory
+ * inode erroneously becomes a policy for the directory itself.
+ */
+ file_class_next = dst_ptr->class;
+ file_check_flags_next = dst_ptr->check_flags;
+ checked_flag = dst_ptr->checked;
+ cchecked_flag = dst_ptr->childs_checked;
+ }
+ }
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
+ dst_ptr = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
+
+ if (dst_ptr)
+ {
+ /* Tue Aug 6 22:13:27 CEST 2002 introduce file_class_next
+ * this fixes the problem that a policy for the directory
+ * inode erroneously becomes a policy for the directory itself.
+ */
+ file_class_next = dst_ptr->class;
+ file_check_flags_next = dst_ptr->check_flags;
+ checked_flag = dst_ptr->checked;
+ /* not set, hence always FALSE */
+ /* cchecked_flag = dst_ptr->childs_checked; */
+
+ if (checked_flag != S_TRUE)
+ {
+ /* -- need to check the file itself --
+ */
+ if (sh.flag.reportonce == S_TRUE)
+ dummy = dst_ptr->is_reported;
+ }
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
+
+ /* ---- Has been checked already. ----
+ */
+ if (checked_flag == S_TRUE && cchecked_flag == S_TRUE)
+ {
+ /* Mar 11 2004 get ftype for complete directory count
+ */
+ checkit = sh_unix_get_ftype(tmpcat);
+ if (checkit == SH_FILE_DIRECTORY)
+ {
+ ++theDir->NumDirs;
+ }
+ SH_FREE(tmpcat);
+ dirlist = dirlist->next;
+ continue;
+ }
+
+ /* --- May be true, false, or not found. ---
+ */
+ if (checked_flag == S_TRUE)
+ {
+ /* -- need only the file type --
+ */
+ checkit = sh_unix_get_ftype(tmpcat);
+ }
+ else
+ {
+ /* -- need to check the file itself --
+ */
+ /* -- moved up --
+ * if (dst_ptr && sh.flag.reportonce == S_TRUE)
+ * dummy = dst_ptr->is_reported;
+ */
+
+ checkit = sh_files_filecheck (file_class_next, file_check_flags_next,
+ iname,
+ dirlist->sh_d_name,
+ &dummy, 0);
+
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
+ dst_ptr = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
+
+ if (dst_ptr && checked_flag == S_FALSE)
+ dst_ptr->checked = S_TRUE;
+
+ /* Thu Mar 7 15:09:40 CET 2002 Propagate the 'reported' flag
+ */
+ if (dst_ptr && sh.flag.reportonce == S_TRUE)
+ dst_ptr->is_reported = dummy;
+
+ if (dst_ptr)
+ dst_ptr->childs_checked = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
+ }
+
+ if (checkit == SH_FILE_REGULAR)
+ ++theDir->NumRegular;
+
+ else if (checkit == SH_FILE_DIRECTORY)
+ {
+ ++theDir->NumDirs;
+
+ if (rdepth_next >= 0 && cchecked_flag != S_TRUE)
+ {
+ rdepth_next = rdepth - 1;
+
+ /* check whether the new directory is in the
+ * list with a recursion depth already defined
+ */
+ checked_flag = -1;
+ cchecked_flag = -1;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ tmp_ptr = (dirstack_t *) zAVLSearch(zdirListOne, tmpcat);
+
+ if (tmp_ptr)
+ {
+ TPT((0, FIL__, __LINE__,
+ _("msg=<%s -> recursion depth %d\n>"),
+ tmp_ptr->name, tmp_ptr->rdepth));
+ rdepth_next = tmp_ptr->rdepth;
+ class_next = tmp_ptr->class;
+ check_flags_next = tmp_ptr->check_flags;
+ /* 28. Aug 2001 reversed
+ */
+ cchecked_flag = tmp_ptr->childs_checked;
+ checked_flag = tmp_ptr->checked;
+ }
+
+ if (checked_flag == -1)
+ {
+ tmp_ptr = (dirstack_t *) zAVLSearch(zdirListTwo, tmpcat);
+
+ if (tmp_ptr)
+ {
+ TPT((0, FIL__, __LINE__,
+ _("msg=<%s -> recursion depth %d\n>"),
+ tmp_ptr->name, tmp_ptr->rdepth));
+ rdepth_next = tmp_ptr->rdepth;
+ class_next = tmp_ptr->class;
+ check_flags_next = tmp_ptr->check_flags;
+ /* 28. Aug 2001 reversed
+ */
+ cchecked_flag = tmp_ptr->childs_checked;
+ checked_flag = tmp_ptr->checked;
+ }
+ }
+
+ if (tmp_ptr && cchecked_flag == S_FALSE)
+ {
+ tmp_ptr->childs_checked = S_TRUE;
+ /*
+ * 04. Feb 2006 avoid double checking
+ */
+ tmp_ptr->checked = S_TRUE;
+ }
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ if (cchecked_flag == S_FALSE)
+ {
+ sh_files_checkdir (class_next, check_flags_next, rdepth_next,
+ tmpcat, dirlist->sh_d_name);
+ /*
+ tmp_ptr->childs_checked = S_TRUE;
+ tmp_ptr->checked = S_TRUE;
+ */
+ }
+ else if (checked_flag == -1)
+ sh_files_checkdir (class_next, check_flags_next, rdepth_next,
+ tmpcat, dirlist->sh_d_name);
+
+ }
+ }
+
+ else if (checkit == SH_FILE_SYMLINK) ++theDir->NumSymlinks;
+ else if (checkit == SH_FILE_FIFO) ++theDir->NumFifos;
+ else if (checkit == SH_FILE_SOCKET) ++theDir->NumSockets;
+ else if (checkit == SH_FILE_CDEV) ++theDir->NumCDev;
+ else if (checkit == SH_FILE_BDEV) ++theDir->NumBDev;
+ else if (checkit == SH_FILE_DOOR) ++theDir->NumDoor;
+ else if (checkit == SH_FILE_PORT) ++theDir->NumPort;
+
+ SH_FREE(tmpcat);
+
+ if ((sig_termfast == 1) || (sig_terminate == 1))
+ {
+ SH_FREE(theDir);
+ sh_dummy_dirlist = NULL;
+ SH_FREE(tmpname);
+ SL_RETURN((0), _("sh_files_checkdir"));
+ }
+
+ dirlist = dirlist->next;
+
+ /* -- moved up, only affects zfileList anyway
+ * if (dst_ptr)
+ * dst_ptr->childs_checked = S_TRUE;
+ */
+
+ } while (dirlist != NULL);
+
+ if (flag_err_info == S_TRUE)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DSUM,
+ theDir->NumDirs,
+ theDir->NumRegular,
+ theDir->NumSymlinks,
+ theDir->NumFifos,
+ theDir->NumSockets,
+ theDir->NumCDev,
+ theDir->NumBDev);
+ }
+
+ kill_sh_dirlist (dirlist_orig);
+
+#if !defined(HOST_IS_DARWIN)
+ /*
+ * Hardlink check; not done on MacOS X because of resource forks
+ */
+ if ((sh_check_hardlinks == S_TRUE) && (hardlink_num != theDir->NumDirs))
+ {
+ if (0 != sh_files_hle_test(hardlink_num-theDir->NumDirs, iname))
+ {
+ len = strlen(tmpname);
+ if (sl_ok_adds(len, 256))
+ len += 256;
+ tmpcat = SH_ALLOC(len);
+ sl_snprintf(tmpcat, len,
+ _("%s: subdirectory count (%d) != hardlinks (%d)"),
+ tmpname, theDir->NumDirs, hardlink_num);
+ sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, 0,
+ MSG_E_SUBGEN, tmpcat, _("sh_files_checkdir"));
+ SH_FREE(tmpcat);
+ }
+ }
+#endif
+
+ SH_FREE(tmpname);
+ SH_FREE(theDir);
+
+ sh_dummy_dirlist = NULL;
+
+ SL_RETURN((0), _("sh_files_checkdir"));
+}
+
+void sh_files_fixup_mask (int class, unsigned long * check_flags)
+{
+ if (class == SH_LEVEL_ALLIGNORE)
+ MODI_SET((*check_flags), MODI_ALLIGNORE);
+ sh_tiger_get_mask_hashtype(check_flags);
+ return;
+}
+
+int get_the_fd (SL_TICKET ticket);
+
+static int sh_use_rsrc = S_FALSE;
+
+int sh_files_use_rsrc(const char * str)
+{
+ return sh_util_flagval(str, &sh_use_rsrc);
+}
+
+static void * sh_dummy_fileName;
+static void * sh_dummy_tmpname;
+static void * sh_dummy_tmpdir;
+
+ShFileType sh_files_filecheck (int class, unsigned long check_flags,
+ const char * dirName,
+ const char * infileName,
+ int * reported,
+ int rsrcflag)
+{
+ /* 28 Aug 2001 allow NULL fileName
+ */
+ char * fullpath;
+ char fileHash[2*(KEY_LEN + 1)];
+ int status;
+ file_type * theFile;
+ char * tmpdir;
+ char * tmpname;
+ const char * fileName;
+#if !defined(O_NOATIME)
+ struct utimbuf utime_buf;
+#endif
+ static unsigned int state = 1;
+ char sc;
+
+ SL_ENTER(_("sh_files_filecheck"));
+
+ fullpath = SH_ALLOC(PATH_MAX);
+ theFile = SH_ALLOC(sizeof(file_type));
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_fileName = (void *) &fileName;
+ sh_dummy_tmpname = (void *) &tmpname;
+ sh_dummy_tmpdir = (void *) &tmpdir;
+
+ BREAKEXIT(sh_derr);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R)
+ if (0 == (rand_r(&state) % 2)) (void) sh_derr();
+#else
+ if (0 == state * (rand() % 2)) (void) sh_derr();
+#endif
+
+ if (dirName && infileName && (dirName[0] == '/') && (dirName[1] == '\0')
+ && (infileName[0] == '/') && (infileName[1] == '\0'))
+ {
+ fileName = NULL;
+ }
+ else
+ {
+ fileName = infileName;
+ }
+
+ /* fileName may be NULL if this is a directory
+ */
+ if (dirName == NULL /* || fileName == NULL */)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_NULL);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(fullpath);
+ SH_FREE(theFile);
+ SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
+ }
+
+ if ((fileName != NULL) && (class != SH_LEVEL_ALLIGNORE) &&
+ (0 != sh_util_obscurename (ShDFLevel[SH_ERR_T_NAME],
+ fileName, S_FALSE)))
+ {
+ if ((dirName != NULL) && (dirName[0] == '/') && (dirName[1] == '\0'))
+ {
+ tmpname = sh_util_safe_name (fileName);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
+ MSG_FI_OBSC2,
+ "", tmpname);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmpname);
+ }
+ else
+ {
+ tmpdir = sh_util_safe_name (dirName);
+ tmpname = sh_util_safe_name (fileName);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, 0,
+ MSG_FI_OBSC2,
+ tmpdir, tmpname);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmpname);
+ SH_FREE(tmpdir);
+ }
+ }
+
+ /* sh_files_fullpath accepts NULL fileName
+ */
+ if (0 != sh_files_fullpath (dirName, fileName, fullpath))
+ {
+ tmpdir = sh_util_safe_name (dirName);
+ tmpname = sh_util_safe_name (fileName);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, 0,
+ MSG_FI_2LONG2,
+ tmpdir, tmpname);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmpname);
+ SH_FREE(tmpdir);
+ SH_FREE(fullpath);
+ SH_FREE(theFile);
+ SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
+ }
+
+ /* stat the file and determine checksum (if a regular file)
+ */
+ sl_strlcpy (theFile->fullpath, fullpath, PATH_MAX);
+ theFile->check_flags = check_flags /* sh_files_maskof(class) */;
+ theFile->file_reported = (*reported);
+ theFile->attr_string = NULL;
+ theFile->link_path = NULL;
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<checking file: %s>\n"), fullpath));
+
+ status = sh_unix_getinfo ( (class == SH_LEVEL_ALLIGNORE) ?
+ ShDFLevel[class] : ShDFLevel[SH_ERR_T_FILE],
+ fileName,
+ theFile, fileHash, class);
+
+ if (status != 0)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<file: %s> status=<%d>\n"),
+ fullpath, status));
+ if (class == SH_LEVEL_ALLIGNORE && sh.flag.checkSum != SH_CHECK_INIT)
+ sh_hash_set_visited_true (fullpath);
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(fullpath);
+ SH_FREE(theFile);
+ SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
+ }
+
+ if (sig_termfast == 1) {
+ goto ret_point;
+ }
+
+ /* report
+ */
+ if ((flag_err_debug == S_TRUE) && (theFile->c_mode[0] == '-'))
+ {
+ tmpname = sh_util_safe_name (fullpath); /* fixed in 1.5.4 */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_CSUM,
+ fileHash, tmpname);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmpname);
+ }
+ ++sh.statistics.files_checked;
+
+ if ( sh.flag.checkSum == SH_CHECK_INIT)
+ {
+ if (class == SH_LEVEL_ALLIGNORE)
+ MODI_SET(theFile->check_flags, MODI_ALLIGNORE);
+ if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
+ MODI_SET(theFile->check_flags, MODI_NOCHECK);
+ sh_tiger_get_mask_hashtype(&(theFile->check_flags));
+ sh_dbIO_data_write (theFile, fileHash);
+ }
+ else if (sh.flag.checkSum == SH_CHECK_CHECK
+ /* && theFile.c_mode[0] == '-' */
+ /* && class != SH_LEVEL_ALLIGNORE */
+ )
+ {
+ if (sh.flag.update == S_TRUE)
+ {
+ if (class == SH_LEVEL_ALLIGNORE)
+ MODI_SET(theFile->check_flags, MODI_ALLIGNORE);
+ if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
+ MODI_SET(theFile->check_flags, MODI_NOCHECK);
+ sh_tiger_get_mask_hashtype(&(theFile->check_flags));
+ }
+ sh_hash_compdata (class, theFile, fileHash, NULL, -1);
+ }
+
+ (*reported) = theFile->file_reported;
+
+ /* reset the access time
+ */
+#if !defined(O_NOATIME)
+ if (class == SH_LEVEL_NOIGNORE && (theFile->check_flags & MODI_ATM) != 0)
+ {
+ utime_buf.actime = (time_t) theFile->atime;
+ utime_buf.modtime = (time_t) theFile->mtime;
+
+ retry_aud_utime (FIL__, __LINE__, fullpath, &utime_buf);
+ }
+#endif
+
+#if defined(HOST_IS_DARWIN)
+ /*
+ * Check for resource fork
+ */
+ if ( (sh_use_rsrc == S_TRUE) && (theFile->c_mode[0] != 'd') && (rsrcflag == 0) )
+ {
+ int dummy;
+ static int rsrc_init = 0;
+ static char rsrc[17];
+ char * testpath = SH_ALLOC(PATH_MAX);
+
+ if (rsrc_init == 0) {
+ sl_strlcpy(rsrc, _("..namedfork/rsrc"), 17);
+ rsrc_init = 1;
+ }
+ sl_strlcpy (testpath, fullpath, PATH_MAX);
+ sl_strlcat (testpath, "/", PATH_MAX);
+ sl_strlcat (testpath, rsrc, PATH_MAX);
+
+ if (sl_strlen(testpath) == (17 + sl_strlen(fullpath)))
+ {
+ if (S_TRUE == sh_unix_file_exists (testpath))
+ {
+ sh_files_filecheck (class, check_flags, fullpath, rsrc, &dummy, 1);
+ }
+ }
+ SH_FREE(testpath);
+ }
+#else
+ (void) rsrcflag; /* avoid compiler warning */
+#endif
+
+ ret_point:
+
+ sc = theFile->c_mode[0];
+
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(fullpath);
+ SH_FREE(theFile);
+
+ switch (sc)
+ {
+ case '-': SL_RETURN(SH_FILE_REGULAR, _("sh_files_filecheck"));
+ case 'l': SL_RETURN(SH_FILE_SYMLINK, _("sh_files_filecheck"));
+ case 'd': SL_RETURN(SH_FILE_DIRECTORY, _("sh_files_filecheck"));
+ case 'c': SL_RETURN(SH_FILE_CDEV, _("sh_files_filecheck"));
+ case 'b': SL_RETURN(SH_FILE_BDEV, _("sh_files_filecheck"));
+ case '|': SL_RETURN(SH_FILE_FIFO, _("sh_files_filecheck"));
+ case 'D': SL_RETURN(SH_FILE_DOOR, _("sh_files_filecheck"));
+ case 'P': SL_RETURN(SH_FILE_PORT, _("sh_files_filecheck"));
+ case 's': SL_RETURN(SH_FILE_SOCKET, _("sh_files_filecheck"));
+ default: SL_RETURN(SH_FILE_UNKNOWN, _("sh_files_filecheck"));
+ }
+
+ /* notreached */
+}
+
+/* concatenate statpath = testdir"/"d_name
+ */
+static int sh_files_fullpath (const char * testdir, const char * d_name,
+ char * statpath)
+{
+ int llen = 0;
+
+ SL_ENTER(_("sh_files_fullpath"));
+
+ if (testdir != NULL)
+ {
+ if ( (llen = sl_strlen(testdir)) > (PATH_MAX-2) )
+ SL_RETURN((-1),_("sh_files_fullpath"));
+ sl_strlcpy(statpath, testdir, PATH_MAX - 1);
+ }
+ if (d_name != NULL)
+ {
+ if (llen > 1 || statpath[0] != '/')
+ sl_strlcat(statpath, "/", PATH_MAX);
+ if ((sl_strlen(d_name) + sl_strlen(statpath)) >= PATH_MAX)
+ SL_RETURN((-1),_("sh_files_fullpath"));
+ sl_strlcat(statpath, d_name, PATH_MAX);
+ }
+ if (statpath == NULL)
+ SL_RETURN((-1),_("sh_files_fullpath"));
+ SL_RETURN((0),_("sh_files_fullpath"));
+}
+
+/* -----------------------------------
+ * Routines required for inotify
+ * -----------------------------------
+ */
+int sh_files_search_dir(char * name, int * class,
+ unsigned long *check_flags, int *reported,
+ int * rdepth)
+{
+ volatile int retval = 0;
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+ sh_globstack_t * testPattern;
+ zAVLCursor cursor;
+#endif
+ dirstack_t * item;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+
+ item = zAVLSearch(zdirListOne, name);
+
+ if (item)
+ {
+ *check_flags = item->check_flags;
+ *class = item->class;
+ *reported = item->is_reported;
+ *rdepth = item->rdepth;
+ item->checked = S_FALSE;
+ item->childs_checked = S_FALSE;
+ item->is_reported = S_FALSE;
+ retval = 1;
+ goto out;
+ }
+
+ item = zAVLSearch(zdirListTwo, name);
+
+ if (item)
+ {
+ *check_flags = item->check_flags;
+ *class = item->class;
+ *reported = item->is_reported;
+ *rdepth = item->rdepth;
+ item->checked = S_FALSE;
+ item->childs_checked = S_FALSE;
+ item->is_reported = S_FALSE;
+ retval = 1;
+ goto out;
+ }
+
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+ SH_MUTEX_LOCK(mutex_zglob);
+ for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList);
+ testPattern;
+ testPattern = (sh_globstack_t *) zAVLNext (&cursor))
+ {
+ if (testPattern->type == SH_LIST_DIR1 ||
+ testPattern->type == SH_LIST_DIR2)
+ {
+ if (0 == fnmatch(testPattern->name, name, FNM_PATHNAME|FNM_PERIOD))
+ {
+ *check_flags = testPattern->check_flags;
+ *class = testPattern->class;
+ *rdepth = testPattern->rdepth;
+ retval = 1;
+ break;
+ }
+
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_zglob);
+#endif
+ out:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+ return retval;
+}
+
+int sh_files_search_file(char * name, int * class,
+ unsigned long *check_flags, int *reported)
+{
+ volatile int retval = 0;
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+ sh_globstack_t * testPattern;
+ zAVLCursor cursor;
+#endif
+ dirstack_t * item;
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ item = zAVLSearch(zfileList, name);
+
+ if (item)
+ {
+ *check_flags = item->check_flags;
+ *class = item->class;
+ *reported = item->is_reported;
+ retval = 1;
+ }
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+ if (retval == 0)
+ {
+ SH_MUTEX_LOCK(mutex_zglob);
+ for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList);
+ testPattern;
+ testPattern = (sh_globstack_t *) zAVLNext (&cursor))
+ {
+ if (testPattern->type == SH_LIST_FILE)
+ {
+ if (0 == fnmatch(testPattern->name, name,
+ FNM_PATHNAME|FNM_PERIOD))
+ {
+ *check_flags = testPattern->check_flags;
+ *class = testPattern->class;
+ retval = 1;
+ break;
+ }
+
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_zglob);
+ }
+#endif
+
+ return retval;
+}
+
+void sh_files_set_file_reported(const char * name)
+{
+ dirstack_t * item;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
+ item = zAVLSearch(zfileList, name);
+
+ if (item)
+ {
+ if (sh.flag.reportonce == S_TRUE)
+ SET_SH_FFLAG_REPORTED(item->is_reported);
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
+ return;
+}
+
+void sh_files_clear_file_reported(const char * name)
+{
+ dirstack_t * item;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
+ item = zAVLSearch(zfileList, name);
+
+ if (item)
+ {
+ CLEAR_SH_FFLAG_REPORTED(item->is_reported);
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
+ return;
+}
+
+/* -----------------------------------
+ *
+ * The following two routines serve to
+ * verify that the user has selected
+ * a proper setup for file policies.
+ *
+ * -----------------------------------
+ */
+static int check_file(char * name)
+{
+ dirstack_t * pfilL;
+ zAVLCursor cursor;
+ volatile int retval = -1;
+
+ SL_ENTER(_("check_file"));
+
+ if (SH_FILE_DIRECTORY == sh_unix_get_ftype(name))
+ SL_RETURN(0, _("check_file"));
+
+ for (pfilL = (dirstack_t *) zAVLFirst (&cursor, zfileList); pfilL;
+ pfilL = (dirstack_t *) zAVLNext (&cursor))
+ {
+ if (0 == strcmp(name, pfilL->name) &&
+ (pfilL->check_flags & MODI_ATM) == 0 &&
+ (pfilL->check_flags & MODI_CTM) == 0 &&
+ (pfilL->check_flags & MODI_MTM) == 0)
+ {
+ retval = 0;
+ break;
+ }
+ }
+
+ SL_RETURN(retval, _("check_file"));
+}
+
+static void * sh_dummy_pdirL;
+
+int sh_files_test_setup_int (zAVLTree * tree)
+{
+ int dlen, flen;
+ zAVLCursor cursor1;
+ zAVLCursor cursor2;
+
+ dirstack_t * pdirL;
+ dirstack_t * pfilL;
+
+ SL_ENTER(_("sh_files_test_setup"));
+
+ sh_dummy_pdirL = (void *) &pdirL;
+
+ for (pdirL = (dirstack_t *) zAVLFirst (&cursor1, tree); pdirL;
+ pdirL = (dirstack_t *) zAVLNext (&cursor1))
+ {
+ dlen = strlen(pdirL->name);
+
+ SH_MUTEX_LOCK(mutex_zfiles);
+ for (pfilL = (dirstack_t *) zAVLFirst (&cursor2, zfileList); pfilL;
+ pfilL = (dirstack_t *) zAVLNext (&cursor2))
+ {
+ flen = strlen(pfilL->name);
+
+ /* check whether file is in tree of dir
+ */
+ if ((pfilL->class == SH_LEVEL_READONLY) ||
+ (pfilL->class == SH_LEVEL_NOIGNORE))
+ {
+ ; /* do nothing */
+ }
+ else
+ {
+ if ((flen > (dlen+1)) &&
+ (pfilL->name[dlen] == '/') &&
+ (NULL == strchr(&(pfilL->name[dlen+1]), '/')) && /*30-5-01*/
+ (0 == strncmp(pfilL->name, pdirL->name, dlen)))
+ {
+ if ((pdirL->check_flags & MODI_ATM) != 0 ||
+ (pdirL->check_flags & MODI_MTM) != 0 ||
+ (pdirL->check_flags & MODI_CTM) != 0)
+ {
+ if (check_file (pdirL->name) != 0)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_COLL,
+ pdirL->name, pfilL->name);
+ }
+ }
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_zfiles);
+ }
+
+ SL_RETURN((0), _("sh_files_test_setup"));
+}
+
+int sh_files_test_double (zAVLTree * firstList, zAVLTree * secondList)
+{
+ int retval = 0;
+ zAVLCursor cursor;
+ dirstack_t * first;
+
+ for (first = (dirstack_t *) zAVLFirst (&cursor, firstList); first;
+ first = (dirstack_t *) zAVLNext (&cursor))
+ {
+
+ if (NULL != zAVLSearch(secondList, first->name))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DOUBLE,
+ first->name);
+ retval = 1;
+ }
+ }
+ return retval;
+}
+
+extern void aud_exit (const char * file, int line, int fd);
+
+int sh_files_test_setup ()
+{
+ int retval;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_zdirs);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_zdirs);
+ /* Test for modifications allowed in ReadOnly directory
+ */
+ sh_files_test_setup_int (zdirListOne);
+ sh_files_test_setup_int (zdirListTwo);
+
+ /* Test for files/dirz defined twice
+ */
+ retval = sh_files_test_double (zdirListOne, zdirListTwo);
+ if (retval != 0)
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+
+ retval = sh_files_test_double (zdirListTwo, zdirListOne);
+ if (retval != 0)
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_zdirs);
+
+ return 0;
+}
+
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_file_lists (CuTest *tc)
+{
+#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
+
+ extern int hash_remove_tree_test(char * s, char * fullpath, size_t len_s);
+
+ char * test;
+ int ret;
+
+ sh_files_pushfile_ro("/usr/test");
+ sh_files_pushfile_ro("/usr/bin/test");
+ sh_files_pushfile_ro("/usr/bin/foo/test");
+
+ sh_files_pushdir_ro("/usr");
+ sh_files_pushdir_attr("/usr/bin");
+ sh_files_pushdir_ro("/usr/bin/foo");
+
+ add_to_dirlist(zdirListOne);
+ add_to_dirlist(zdirListTwo);
+ add_to_filelist(zfileList);
+
+ test = sh_files_findfile("/usr/tes");
+ CuAssertTrue(tc, test == NULL);
+ test = sh_files_findfile("/usr/test");
+ CuAssertPtrNotNull(tc, test);
+ test = sh_files_findfile("/usr/testi");
+ CuAssertTrue(tc, test == NULL);
+ test = sh_files_findfile("/test");
+ CuAssertTrue(tc, test == NULL);
+
+ test = sh_files_find_mostspecific_dir("/usr/bin/foo/test");
+ CuAssertStrEquals(tc, "/usr/bin/foo", test);
+ test = sh_files_find_mostspecific_dir("/usr/bin/test");
+ CuAssertStrEquals(tc, "/usr/bin", test);
+ test = sh_files_find_mostspecific_dir("/usr/test");
+ CuAssertStrEquals(tc, "/usr", test);
+ test = sh_files_find_mostspecific_dir("/test");
+ CuAssertTrue(tc, test == NULL);
+ test = sh_files_find_mostspecific_dir("/usr/foo/test");
+ CuAssertStrEquals(tc, "/usr", test);
+
+ test = sh_files_find_mostspecific_dir("/usr/bin");
+ CuAssertStrEquals(tc, "/usr/bin", test);
+
+ ret = hash_remove_tree_test("/usr", "/usr/test", strlen("/usr"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+ ret = hash_remove_tree_test("/usr", "/usr/testi", strlen("/usr"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+ ret = hash_remove_tree_test("/usr", "/usr/tes", strlen("/usr"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+
+ ret = hash_remove_tree_test("/usr/bin", "/usr/test", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+ ret = hash_remove_tree_test("/usr/bin", "/usr/testi", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+ ret = hash_remove_tree_test("/usr/bin", "/usr/tes", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+
+ ret = hash_remove_tree_test("/usr/bin", "/usr/bin/test", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+ ret = hash_remove_tree_test("/usr/bin", "/usr/bin/testi", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+ ret = hash_remove_tree_test("/usr/bin", "/usr/bin/tes", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+
+ ret = hash_remove_tree_test("/usr/bin", "/usr/bin", strlen("/usr/bin"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+ ret = hash_remove_tree_test("/usr", "/usr", strlen("/usr"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+ ret = hash_remove_tree_test("/usr", "/usrbin", strlen("/usr"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+ ret = hash_remove_tree_test("/", "/usrbin", strlen("/"));
+ CuAssertIntEquals(tc, S_TRUE, ret);
+ ret = hash_remove_tree_test("/", "/usr", strlen("/"));
+ CuAssertIntEquals(tc, S_FALSE, ret);
+
+#else
+ (void) tc; /* fix compiler warning */
+ return;
+#endif
+}
+
+void Test_file_dequote (CuTest *tc)
+{
+#if (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
+
+ char str1[] = "1234567890";
+ char str1a[] = "123456\\\"789\\r";
+ char str1b[] = "12345678\\r9";
+ char str1c[] = "12345678\\x0a_9";
+ char str1d[] = "12345678\\007_9";
+ char str1e[] = "123456789\\\\";
+
+ char str2[] = "1234567890\\xw";
+ char str3[] = "1234567890\\xw99";
+ char str4[] = "1234567890\\0ww";
+ char str5[] = "12345\\g67890";
+ char str6[] = "1234567890\\009a";
+
+ char *s, *p, *q;
+ size_t lo, lr;
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str1, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertTrue(tc, p == q);
+ CuAssertTrue(tc, lr == lo);
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str1a, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertTrue(tc, p != q);
+ CuAssertTrue(tc, 0 == strcmp(q, "123456\"789\r"));
+ CuAssertTrue(tc, lr == (lo-2));
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str1b, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertTrue(tc, p != q);
+ CuAssertTrue(tc, 0 == strcmp(q, "12345678\r9"));
+ CuAssertTrue(tc, lr == (lo-1));
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str1c, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertTrue(tc, p != q);
+ CuAssertTrue(tc, 0 == strcmp(q, "12345678\x0a_9"));
+ CuAssertTrue(tc, lr == (lo-3));
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str1d, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertTrue(tc, p != q);
+ CuAssertTrue(tc, 0 == strcmp(q, "12345678\007_9"));
+ CuAssertTrue(tc, lr == (lo-3));
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str1e, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertTrue(tc, p != q);
+ CuAssertTrue(tc, 0 == strcmp(q, "123456789\\"));
+ CuAssertTrue(tc, lr == (lo-1));
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str2, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertTrue(tc, q == NULL);
+ CuAssertTrue(tc, lr == 0);
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str3, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertTrue(tc, q == NULL);
+ CuAssertTrue(tc, lr == 0);
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str4, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertTrue(tc, q == NULL);
+ CuAssertTrue(tc, lr == 0);
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str5, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertTrue(tc, q == NULL);
+ CuAssertTrue(tc, lr == 0);
+
+ s = SH_ALLOC(64); sl_strlcpy(s, str6, 64); p = s; lo = strlen(s); lr = lo;
+ q = sh_files_C_dequote(s, &lr);
+ CuAssertTrue(tc, q == NULL);
+ CuAssertTrue(tc, lr == 0);
+
+ return;
+#else
+ (void) tc; /* fix compiler warning */
+ return;
+#endif
+}
+#endif
+
diff --git a/src/sh_filetype.c b/src/sh_filetype.c
new file mode 100644
index 0000000..9abac46
--- /dev/null
+++ b/src/sh_filetype.c
@@ -0,0 +1,606 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2011 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#ifndef NULL
+#if !defined(__cplusplus)
+#define NULL ((void*)0)
+#else
+#define NULL (0)
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error_min.h"
+#include "sh_utils.h"
+
+#define FIL__ _("sh_filetype.c")
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/* #define SH_FILE_MAIN 1 */
+#ifdef SH_FILE_MAIN
+#include <stdio.h>
+#define _(a) a
+#define N_(a) a
+#define sl_strlcpy strncpy
+#endif
+
+#define SH_FTYPE_MAX 32
+
+/* List of filetype description, in the format:
+ * offset : type(0=text, 1=binary) : length(if binary) : G1 : G2 : G3 : Name : Teststring
+ *
+ * This list is mostly taken from the 'filetype' library by Paul L Daniels.
+ *
+ * Copyright (c) 2003, PLD
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of the PLD nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+char * sh_ftype_list[] = {
+
+ N_("6:0:0:IMAGE:COMPRESSED:JPG:JFIF Jpeg:JFIF"),
+ N_("0:0:0:IMAGE:COMPRESSED:PNG:PNG:=89PNG=0d=0a=1a=0a"),
+ N_("0:0:0:IMAGE:COMPRESSED:JPG:JFIF Jpeg:=FF=D8=FF"),
+ N_("0:0:0:IMAGE:COMPRESSED:GIF:GIF:GIF97a"),
+ N_("0:0:0:IMAGE:COMPRESSED:GIF:GIF:GIF89a"),
+ N_("0:0:0:IMAGE:COMPRESSED:GIF:GIF:GIF87a"),
+ N_("0:1:4:IMAGE:COMPRESSED:TIFF:TIFF-LE:II=2A=00"),
+ N_("0:1:4:IMAGE:COMPRESSED:TIFF:TIFF-BE:MM=00=2A"),
+ N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX25:=0A=00"),
+ N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX28WP:=0A=02"),
+ N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX28NP:=0A=03"),
+ N_("0:1:2:IMAGE:COMPRESSED:PCX:PCX30:=0A=05"),
+ N_("0:0:0:IMAGE:RAW:BMP:Bitmap:BM"),
+ N_("0:0:0:IMAGE:RAW:XPM:XPM:/* XPM */"),
+ N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:DWT:AC=31=30=31"),
+ N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:DWF:(DWF V"),
+ N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:WMF:=D7=CD=C6=9A"),
+ N_("0:0:0:IMAGE:SPECIAL:AUTOCAD:DWG:AC10"),
+ N_("8:0:0:IMAGE:SPECIAL:COREL:CorelDraw:CDR"),
+ N_("0:0:0:IMAGE:SPECIAL:FITS:Fits file:SIMPLE=20=20="),
+ N_("1536:0:0:IMAGE:SPECIAL:VISIO:VisioDraw:Visio"),
+ N_("128:0:0:IMAGE:SPECIAL:DICM:DICOM medical:DICM"),
+ N_("0:0:0:IMAGE:SPECIAL:PHS:Photoshop:8BPS"),
+ N_("0:0:0:IMAGE:SPECIAL:XCF:Gimp XCF:gimp xcf"),
+ N_("0:0:0:MOVIE:COMPRESSED:RIFF:RIFF/AVI Movie:RIFF"),
+ N_("0:0:0:MOVIE:RAW:MOV:SGI Movie:MOVI:.mov SGI Movie"),
+ N_("0:1:4:MOVIE:COMPRESSED:MPG:Mpeg 2:=00=00=01=BA"),
+ N_("0:1:4:MOVIE:COMPRESSED:MPG:Mpeg 2:=00=00=01=B3"),
+ N_("4:0:0:MOVIE:COMPRESSED:QT:QuickTime:moov"),
+ N_("4:0:0:MOVIE:COMPRESSED:QT:QuickTime:mdat"),
+ N_("36:0:0:MOVIE:COMPRESSED:QT:QuickTime:moov"),
+ N_("36:0:0:MOVIE:COMPRESSED:QT:QuickTime:mdat"),
+ N_("68:0:0:MOVIE:COMPRESSED:QT:QuickTime:moov"),
+ N_("68:0:0:MOVIE:COMPRESSED:QT:QuickTime:mdat"),
+ N_("0:1:3:MOVIE:COMPRESSED:FLI:FLIC animation:=00=11=AF"),
+ N_("0:0:0:MOVIE:COMPRESSED:FLASH:Flash data:FWS"),
+ N_("0:0:0:MOVIE:COMPRESSED:FLASH:Flash data:CWS"),
+ N_("0:0:0:MOVIE:COMPRESSED:FLASH:Flash video:FLV"),
+ N_("0:0:0:MOVIE:COMPRESSED:WMV:WMV:=30=26=B2=75=8E=66=CF"),
+ N_("0:0:0:AUDIO:RAW:SND:Sun Audio:.snd"),
+ N_("0:0:0:AUDIO:RAW:EMOD:EMOD:Mod"),
+ N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (.M.K):.M.K"),
+ N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (M.K.):M.K."),
+ N_("1080:0:0:AUDIO:RAW:MOD:NoiseTracker:N.T."),
+ N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (M!K!):M!K!"),
+ N_("1080:0:0:AUDIO:RAW:MOD:SoundTracker (M&K!):M&K!"),
+ N_("8:0:0:AUDIO:RAW:WAVE:Wave:WAVE"),
+ N_("0:1:4:AUDIO:RAW:DEC:DEC-Audio:=00=64=73=2E"),
+ N_("0:0:0:AUDIO:STANDARD:MIDI:Midi:MThd"),
+ N_("0:0:0:AUDIO:COMPRESSED:REAL:RealMedia:.RMF"),
+ N_("0:0:0:AUDIO:COMPRESSED:OGG:Ogg Vorbis:OggS"),
+ N_("0:0:0:AUDIO:COMPRESSED:FLAC:Flac:fLaC"),
+ N_("0:1:5:AUDIO:COMPRESSED:MP3:MP3 Audio:=49=44=33=02=00"),
+ N_("0:1:5:AUDIO:COMPRESSED:MP3:MP3 Audio:=49=44=33=03=00"),
+ N_("0:1:5:AUDIO:COMPRESSED:MP3:MP3 Audio:=49=44=33=04=00"),
+ N_("0:1:2:AUDIO:COMPRESSED:MP3:MP3 Audio:=ff=fb"),
+ N_("0:1:2:AUDIO:COMPRESSED:MP3:MP3 Audio:=ff=fa"),
+ N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 0:-lh0-"),
+ N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 1:-lh1-"),
+ N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 4:-lz4-"),
+ N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha z5:-lz5-"),
+ N_("2:0:0:ARCHIVE:COMPRESSED:LHA:Lha 5:-lh5-"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:RAR:RarArchive:Rar!"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:ZIP:PkZip:PK=03=04"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:7Z:7-Zip:=37=7A=BC=AF=27=1C"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:COMPRESS:Compress:=1F=89"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:GZIP:Gzip:=1F=8B"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:BZIP2:Bzip2:BZh"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:ARJ:ARJ:=60=ea"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:ARJ:ARJ:=ea=60"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:HPAK:HPack:HPAK"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:JAM:Jam:=E9,=01JAM"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:SQUISH:Squish:SQSH"),
+ N_("0:1:8:ARCHIVE:COMPRESSED:CAB:MS Cabinet:MSCF=00=00=00=00"),
+ N_("20:0:0:ARCHIVE:COMPRESSED:ZOO:Zoo:=FD=C4=A7=DC"),
+ N_("0:0:0:ARCHIVE:COMPRESSED:XPK:Amiga XPK Archive:XPKF"),
+ N_("0:0:0:ARCHIVE:PACKAGE:RPM:RPM:=ED=AB=EE=DB"),
+ N_("0:0:0:ARCHIVE:PACKAGE:DEB:DEB:!<arch>=0A""debian"),
+ N_("0:0:0:ARCHIVE:UNIX:AR:AR:!<arch>"),
+ N_("0:0:0:ARCHIVE:UNIX:AR:AR:<ar>"),
+ N_("257:1:8:ARCHIVE:UNIX:TAR:TAR:ustar=20=20=00"),
+ N_("257:1:6:ARCHIVE:UNIX:TAR:TAR:ustar=00"),
+ N_("0:0:0:LIBRARY:JAVA:CLASS:Java:=CA=FE=BA=BE"),
+ N_("2108:0:0:DOCUMENT:OFFICE:WORD:Word v5:MSWordDoc"),
+ N_("2112:0:0:DOCUMENT:OFFICE:WORD:Word v5:MSWordDoc"),
+ N_("2080:0:0:DOCUMENT:OFFICE:EXCEL:Excel v4:Microsoft Excel"),
+ N_("2080:0:0:DOCUMENT:OFFICE:WORD:MS Word:Microsoft Word"),
+ N_("0:0:0:DOCUMENT:OFFICE:WORD:Word:=94=A6=2E"),
+ N_("512:1:19:DOCUMENT:OFFICE:WORD:Word:R=00o=00o=00t=00 =00""E=00n=00t=00r=00y"),
+ N_("0:1:9:DOCUMENT:OFFICE:ALL:MSOffice:=D0=CF=11=E0=A1=B1=1A=E1=00"),
+ N_("0:0:0:DOCUMENT:ADOBE:PDF:PortableDocument:%PDF-"),
+ N_("0:0:0:DOCUMENT:ADOBE:EPS:EncapsulatedPS:%!PS-ADOBE EPS"),
+ N_("0:0:0:DOCUMENT:STANDARD:RTF:RichText:{\\rtf"),
+ N_("6:1:4:DOCUMENT:STANDARD:RTF:RichText Compressed:=00=00LZ"),
+ N_("6:0:0:DOCUMENT:ID:VCARD:VCARD:vcard"),
+ N_("0:0:0:EXECUTABLE:DOS:EXE:DosExe:MZ"),
+ N_("0:0:0:EXECUTABLE:DOS:EXE:DosExe:LZ"),
+ N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 1:=E9"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#!/bin/sh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#! /bin/sh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#!/bin/bash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#! /bin/bash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#!/usr/bin/bash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Bourne:#! /usr/bin/bash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#!/usr/bin/csh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#! /usr/bin/csh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#!/bin/csh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Csh:#! /bin/csh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#! /usr/bin/ksh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#!/usr/bin/ksh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#! /bin/ksh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Korn:#!/bin/ksh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#!/usr/bin/tcsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#! /usr/bin/tcsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#!/bin/tcsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Tenex:#! /bin/tcsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#!/usr/bin/zsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#! /usr/bin/zsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#!/bin/zsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Zsh:#! /bin/zsh"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#!/usr/bin/ash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#! /usr/bin/ash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#!/bin/ash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:ash:#! /bin/ash"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/usr/bin/nawk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /usr/bin/nawk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/bin/nawk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /bin/nawk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/bin/gawk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /bin/gawk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#!/bin/awk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:awk:#! /bin/awk"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#!/usr/bin/perl"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#! /usr/bin/perl"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#!/bin/perl"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:perl:#! /bin/perl"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Shell script:#!/"),
+ N_("0:0:0:EXECUTABLE:UNIX:SHELL:Shell script:#! /"),
+ N_("0:0:0:EXECUTABLE:UNIX:ELF:Linux ELF32:=7f""ELF=01"),
+ N_("0:0:0:EXECUTABLE:UNIX:ELF:Linux ELF:=7f""ELF=02"),
+ N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 2:=8c"),
+ N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 3:=eb"),
+ N_("0:0:0:EXECUTABLE:DOS:COM:DosCom 4:=b8"),
+ N_("0:1:4:EXECUTABLE:AMIGAOS:EXECUTABLE:AmigaOS Executable:=00=00=03=F3"),
+ N_("0:1:20:DATABASE:ANY:ACCESS:MSAccess:=00=01=00=00Standard=20Jet=20""DB=00"),
+ N_("0:1:2:DATABASE:ANY:MYSQL:MySQL database:=fe=01"),
+ N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=03=00"),
+ N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=07=00"),
+ N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=05=00"),
+ N_("0:1:4:DATABASE:ANY:MYSQL:MySQL database:=fe=fe=06=00"),
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+};
+
+static unsigned int sh_ftype_def = 0;
+
+#define SH_FTYPE_ADD 16
+
+struct sh_ftype_rec {
+ size_t offset;
+ size_t length;
+ char pattern[SH_FTYPE_MAX];
+
+ char type[SH_FTYPE_MAX];
+};
+
+
+struct sh_ftype_rec ** sh_ftype_arr = NULL;
+static unsigned int sh_ftype_nn = 0;
+
+#if !defined(SH_FILE_MAIN)
+
+static unsigned int sh_ftype_usr = 0;
+
+extern char * unquote_string (const char * str, size_t len);
+
+int sh_restrict_add_ftype(const char * str)
+{
+ size_t len;
+ char * cond;
+
+ if (sh_ftype_def == 0)
+ {
+ while(sh_ftype_list[sh_ftype_def] != NULL) ++sh_ftype_def;
+ }
+
+ if (!str)
+ {
+ if (sh_ftype_usr > 0)
+ {
+ unsigned int i, j = sh_ftype_def;
+
+ for (i = 0; i < sh_ftype_usr; ++i)
+ {
+ SH_FREE(sh_ftype_list[j+i]);
+ sh_ftype_list[j+i] = NULL;
+ }
+ sh_ftype_usr = 0;
+ }
+
+ if (sh_ftype_arr)
+ {
+ unsigned int i = 0;
+
+ while(sh_ftype_arr[i] != NULL)
+ {
+ SH_FREE(sh_ftype_arr[i]);
+ ++i;
+ }
+ SH_FREE(sh_ftype_arr);
+ sh_ftype_arr = NULL;
+ }
+ }
+ else if (sh_ftype_usr < SH_FTYPE_ADD)
+ {
+ len = strlen(str);
+ cond = unquote_string(str, len);
+ sh_ftype_list[sh_ftype_def+sh_ftype_usr] = cond;
+ ++sh_ftype_usr;
+ }
+ else
+ {
+ return -1;
+ }
+ return 0;
+}
+
+
+#endif
+
+
+static int init_record(unsigned int n, char * define,
+ struct sh_ftype_rec * record)
+{
+ unsigned int offset, dtype, length, i = 0, xn = 0;
+ char type[SH_FTYPE_MAX];
+ char pattern[SH_FTYPE_MAX];
+
+ char * end;
+ char * start;
+
+ offset = strtoul(define, &end, 0);
+ if (*end != ':')
+ return -1;
+
+ start = end; ++start;
+ dtype = strtoul(start, &end, 0);
+ if (*end != ':')
+ return -1;
+
+ start = end; ++start;
+ length = strtoul(start, &end, 0);
+ if (*end != ':')
+ return -1;
+
+ start = end; ++start;
+
+ while (*start && (i < sizeof(type)))
+ {
+ type[i] = *start; ++start;
+ if (type[i] == ':')
+ ++xn;
+ if (xn == 3)
+ {
+ type[i] = '\0';
+ break;
+ }
+ ++i;
+ }
+ if (xn != 3)
+ return -1;
+
+ start = strchr(start, ':');
+
+ if (!start)
+ return -1;
+
+ ++start;
+
+ if (dtype == 0)
+ {
+ sl_strlcpy(pattern, start, sizeof(pattern));
+ length = strlen(pattern);
+ }
+ else if (length <= sizeof(pattern))
+ {
+ memcpy(pattern, start, length);
+ }
+ else
+ {
+ return -1;
+ }
+
+ for (i = 0; i < n; ++i)
+ {
+ if (sh_ftype_arr[i]->length <= length &&
+ sh_ftype_arr[i]->offset == offset)
+ {
+ if (0 == memcmp(sh_ftype_arr[i]->pattern, pattern,
+ sh_ftype_arr[i]->length))
+ {
+#ifdef SH_FILE_MAIN
+ fprintf(stderr,
+ "Pattern %d (%s / %s) override by earlier pattern %d (%s / %s)\n",
+ n, type, pattern,
+ i, sh_ftype_arr[i]->type, sh_ftype_arr[i]->pattern);
+#else
+ char errbuf[256];
+
+ sl_snprintf(errbuf, sizeof(errbuf),
+ _("Pattern %d (%s) override by earlier pattern %d (%s)"),
+ n, type,
+ i, sh_ftype_arr[i]->type);
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errbuf,
+ _("init_record"));
+#endif
+ }
+ }
+ }
+
+
+ record->offset = offset;
+ record->length = length;
+ memcpy(record->pattern, pattern, length);
+ sl_strlcpy(record->type, type, SH_FTYPE_MAX);
+
+ return 0;
+}
+
+static void file_arr_init()
+{
+ unsigned int i, nn = 0;
+
+ if (sh_ftype_def == 0)
+ {
+ while(sh_ftype_list[sh_ftype_def] != NULL) ++sh_ftype_def;
+ }
+
+ while (sh_ftype_list[nn] != NULL) ++nn;
+
+#ifdef SH_FILE_MAIN
+ printf("%d definitions found, defined = %d\n", nn, sh_ftype_def);
+#endif
+
+#ifdef SH_FILE_MAIN
+ sh_ftype_arr = calloc((nn+1), sizeof(struct sh_ftype_rec *));
+#else
+ sh_ftype_arr = SH_ALLOC((nn+1) * sizeof(struct sh_ftype_rec *));
+#endif
+
+ for(i = 0; i < nn; i++)
+ {
+#ifdef SH_FILE_MAIN
+ sh_ftype_arr[i] = calloc(1, sizeof(struct sh_ftype_rec));
+#else
+ sh_ftype_arr[i] = SH_ALLOC(sizeof(struct sh_ftype_rec));
+#endif
+
+ memset(sh_ftype_arr[i], 0, sizeof(struct sh_ftype_rec));
+ if (i < sh_ftype_def)
+ {
+ char * p = _(sh_ftype_list[i]);
+ size_t len = strlen(p);
+ char * cond = unquote_string(p, len);
+
+ init_record(i, cond, sh_ftype_arr[i]);
+ }
+ else
+ {
+ init_record(i, sh_ftype_list[i], sh_ftype_arr[i]);
+ }
+ }
+ sh_ftype_arr[nn] = NULL;
+ sh_ftype_nn = nn;
+
+ return;
+}
+
+static char * check_filetype(char * filetype,
+ const char * buffer, size_t buflen)
+{
+ unsigned int i;
+ const char * p;
+
+ if (!sh_ftype_arr)
+ {
+ file_arr_init();
+ }
+
+ for (i = 0; i < sh_ftype_nn; ++i)
+ {
+ if (sh_ftype_arr[i]->length > 0 &&
+ (sh_ftype_arr[i]->length + sh_ftype_arr[i]->offset) < buflen)
+ {
+ p = &buffer[sh_ftype_arr[i]->offset];
+
+ if (0 == memcmp(p, sh_ftype_arr[i]->pattern, sh_ftype_arr[i]->length))
+ {
+ sl_strlcpy(filetype, sh_ftype_arr[i]->type, SH_FTYPE_MAX);
+ return (filetype);
+ }
+ }
+ }
+
+ if (buflen > 0) {
+
+ int flag = 0;
+
+ p = buffer;
+ for (i = 0; i < buflen; ++i) {
+ if (*p == '\0')
+ {
+ sl_strlcpy(filetype, _("FILE:BINARY:UNKNOWN"), SH_FTYPE_MAX);
+ goto out;
+ }
+ else if (!isgraph((int)*p) && !isspace((int)*p))
+ {
+ flag = 1;
+ }
+ ++p;
+ }
+ if (flag == 0)
+ {
+ sl_strlcpy(filetype, _("FILE:TEXT:ASCII"), SH_FTYPE_MAX);
+ goto out;
+ }
+ }
+ sl_strlcpy(filetype, _("FILE:UNKNOWN:UNKNOWN"), SH_FTYPE_MAX);
+ out:
+ return filetype;
+}
+
+#if !defined(SH_FILE_MAIN)
+
+int matches_filetype(SL_TICKET ft, char * test_type)
+{
+ char buffer[3072];
+ char filetype[SH_FTYPE_MAX];
+ long len;
+
+ len = sl_read_timeout (ft, buffer, sizeof(buffer), 12, S_TRUE);
+
+ sl_rewind(ft);
+
+ if (len > 0)
+ {
+ check_filetype(filetype, buffer, len);
+ }
+ else
+ {
+ sl_strlcpy(filetype, _("FILE:UNKNOWN:UNKNOWN"), SH_FTYPE_MAX);
+ }
+
+ if (0 == strcmp(filetype, test_type))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+#else
+/* SH_FILE_MAIN */
+#include <unistd.h>
+
+int main (int argc, char * argv[])
+{
+ char buffer[3072];
+ char filetype[SH_FTYPE_MAX];
+ size_t len;
+
+ FILE * fh = fopen(argv[1], "r");
+
+ if (fh)
+ {
+ int fd = fileno(fh);
+
+ len = read(fd, buffer, 3072);
+
+ check_filetype(filetype, buffer, len);
+
+ fprintf(stdout, "%s: %s\n", argv[1], filetype);
+
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+#endif
+/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
diff --git a/src/sh_filter.c b/src/sh_filter.c
new file mode 100644
index 0000000..4cd9578
--- /dev/null
+++ b/src/sh_filter.c
@@ -0,0 +1,300 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2009 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include "config_xor.h"
+
+#include <string.h>
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_mem.h"
+#include "sh_filter.h"
+
+#undef FIL__
+#define FIL__ _("sh_filter.c")
+
+
+void sh_filter_free (sh_filter_type * filter)
+{
+ int i;
+
+ if (filter)
+ {
+ for (i = 0; i < filter->for_c; ++i) {
+#ifdef HAVE_REGEX_H
+ if (filter->for_v[i])
+ regfree(filter->for_v[i]);
+#else
+ if (filter->for_v[i])
+ SH_FREE(filter->for_v[i]);
+#endif
+ filter->for_v[i] = NULL;
+ }
+ filter->for_c = 0;
+
+ for (i = 0; i < filter->fand_c; ++i) {
+#ifdef HAVE_REGEX_H
+ if (filter->fand_v[i])
+ regfree(filter->fand_v[i]);
+#else
+ if (filter->fand_v[i])
+ SH_FREE(filter->fand_v[i]);
+#endif
+ filter->fand_v[i] = NULL;
+ }
+ filter->fand_c = 0;
+
+ for (i = 0; i < filter->fnot_c; ++i) {
+#ifdef HAVE_REGEX_H
+ if (filter->fnot_v[i])
+ regfree(filter->fnot_v[i]);
+#else
+ if (filter->fnot_v[i])
+ SH_FREE(filter->fnot_v[i]);
+#endif
+ filter->fnot_v[i] = NULL;
+ }
+ filter->fnot_c = 0;
+ }
+}
+
+
+int sh_filter_add (const char * str, sh_filter_type * filter, int type)
+{
+ int i = 0;
+ int flag = 0;
+ size_t s;
+
+ char * dupp;
+ char * p;
+ char * end;
+ int * ntok;
+ void ** stok;
+
+ SL_ENTER(_("sh_filter_filteradd"));
+
+ if (NULL == str || NULL == filter)
+ {
+ SL_RETURN((-1), _("sh_filter_filteradd"));
+ }
+
+ if (type == SH_FILT_OR) {
+ ntok = &(filter->for_c);
+ stok = filter->for_v;
+ }
+ else if (type == SH_FILT_AND) {
+ ntok = &(filter->fand_c);
+ stok = filter->fand_v;
+ }
+ else if (type == SH_FILT_NOT) {
+ ntok = &(filter->fnot_c);
+ stok = filter->fnot_v;
+ }
+ else {
+ SL_RETURN((-1), _("sh_filter_filteradd"));
+ }
+
+ i = *ntok;
+ if (i == SH_FILT_NUM) {
+ SL_RETURN((-1), _("sh_filter_filteradd"));
+ }
+
+ dupp = sh_util_strdup(str);
+ p = dupp;
+
+ do
+ {
+ while (*p == ',' || *p == ' ' || *p == '\t')
+ ++p;
+ if (*p == '\0')
+ break;
+
+ end = p; ++end;
+ if (*end == '\0')
+ break;
+
+ if (*p == '\'')
+ {
+ ++p; end = p; if (*end != '\'') ++end;
+ if (*p == '\0' || *end == '\0')
+ break;
+ while (*end != '\0' && *end != '\'')
+ ++end;
+ }
+ else if (*p == '"')
+ {
+ ++p; end = p; if (*end != '"') ++end;
+ if (*p == '\0' || *end == '\0')
+ break;
+ while (*end != '\0' && *end != '"')
+ ++end;
+ }
+ else
+ {
+ while (*end != '\0' && *end != ',' && *end != ' ' && *end != '\t')
+ ++end;
+ }
+ if (*end == '\0')
+ flag = 1;
+ else
+ *end = '\0';
+
+ s = strlen(p);
+ if (s > 0)
+ {
+ ++s;
+#ifdef HAVE_REGEX_H
+ if (stok[i] != NULL)
+ regfree((regex_t *) stok[i]);
+ {
+ int status;
+
+ stok[i] = SH_ALLOC(sizeof(regex_t));
+
+ status = regcomp((regex_t *) stok[i], p,
+ REG_NOSUB|REG_EXTENDED);
+ if (status != 0)
+ {
+ char * errbuf = SH_ALLOC(BUFSIZ);
+ (void) regerror(status, (regex_t *) stok[i],
+ errbuf, BUFSIZ);
+ errbuf[BUFSIZ-1] = '\0';
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX,
+ errbuf, p);
+ SH_FREE(errbuf);
+ }
+ }
+#else
+ if (stok[i] != NULL)
+ SH_FREE(stok[i]);
+
+ stok[i] = SH_ALLOC(s);
+ (void) sl_strlcpy((char *) stok[i], p, s);
+#endif
+ ++i;
+ }
+
+ p = end; ++p;
+
+ if (i == SH_FILT_NUM)
+ break;
+ }
+ while (p != NULL && *p != '\0' && flag == 0);
+
+ *ntok = i;
+ SH_FREE(dupp);
+
+ SL_RETURN (0, _("sh_filter_filteradd"));
+}
+
+#ifdef HAVE_REGEX_H
+static int sh_filter_cmp(const char * message, void * pattern)
+{
+ int result;
+
+ result = regexec((regex_t *)pattern, message, 0, NULL, 0);
+
+ if (result != 0)
+ return -1;
+
+ /* Successful match. */
+ return 0;
+}
+#else
+static int sh_filter_cmp(const char * message, void * pattern)
+{
+ if (NULL == sl_strstr(message, (char *)pattern))
+ return -1;
+
+ /* Successful match. */
+ return 0;
+}
+#endif
+
+/*
+ * -- Check filters. Returns 0 if message passes.
+ */
+int sh_filter_filter (const char * message, sh_filter_type * filter)
+{
+ int i;
+
+ SL_ENTER(_("sh_filter_filter"));
+
+ if (filter)
+ {
+
+ /* Presence of any of these keywords prevents execution.
+ */
+ if (filter->fnot_c > 0)
+ {
+ for (i = 0; i < filter->fnot_c; ++i)
+ {
+ if (0 == sh_filter_cmp(message, filter->fnot_v[i]))
+ {
+ SL_RETURN ((-1), _("sh_filter_filter"));
+ }
+ }
+ }
+
+ /* Presence of all of these keywords is required for execution.
+ */
+ if (filter->fand_c > 0)
+ {
+ for (i = 0; i < filter->fand_c; ++i)
+ {
+ if (0 != sh_filter_cmp(message, filter->fand_v[i]))
+ {
+ SL_RETURN ((-1), _("sh_filter_filter"));
+ }
+ }
+ }
+
+ /* Presence of at least one of these keywords is required for execution.
+ */
+ if (filter->for_c > 0)
+ {
+ for (i = 0; i < filter->for_c; ++i)
+ {
+ if (0 == sh_filter_cmp(message, filter->for_v[i]))
+ {
+ goto isok;
+ }
+ }
+ SL_RETURN ((-1), _("sh_filter_filter"));
+ }
+ }
+
+ isok:
+ SL_RETURN ((0), _("sh_filter_filter"));
+}
+
+sh_filter_type * sh_filter_alloc(void)
+{
+ sh_filter_type * filter = SH_ALLOC(sizeof(sh_filter_type));
+
+ memset(filter, '\0', sizeof(sh_filter_type));
+ filter->for_c = 0;
+ filter->fand_c = 0;
+ filter->fnot_c = 0;
+ return filter;
+}
diff --git a/src/sh_getopt.c b/src/sh_getopt.c
new file mode 100644
index 0000000..7969d4e
--- /dev/null
+++ b/src/sh_getopt.c
@@ -0,0 +1,990 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_getopt.h"
+#include "sh_unix.h"
+#include "sh_files.h"
+#include "sh_utils.h"
+#include "sh_mail.h"
+#include "sh_xfer.h"
+#include "sh_hash.h"
+#include "sh_dbIO.h"
+#include "sh_dbCheck.h"
+#include "sh_dbCreate.h"
+#include "sh_sem.h"
+
+#if defined(WITH_EXTERNAL)
+#include "sh_extern.h"
+#endif
+
+extern int sh_calls_set_bind_addr (const char *);
+
+#undef FIL__
+#define FIL__ _("sh_getopt.c")
+
+#define HAS_ARG_NO 0
+#define HAS_ARG_YES 1
+#define DROP_PRIV_NO 0
+#define DROP_PRIV_YES 1
+
+
+typedef struct options {
+ const char * longopt;
+ const char shortopt;
+ const char * usage;
+ int hasArg;
+ int (*func)(const char * opt);
+} opttable_t;
+
+/*@noreturn@*/
+static int sh_getopt_usage (const char * dummy);
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+static int sh_getopt_forever (const char * dummy);
+static int sh_getopt_outpath (const char * dummy);
+#endif
+static int sh_getopt_copyright (const char * dummy);
+static int sh_getopt_version (const char * dummy);
+
+static opttable_t op_table[] = {
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ { N_("set-checksum-test"),
+ 't',
+ N_("Set checksum testing to 'init', 'update', or 'check'"),
+ HAS_ARG_YES,
+ sh_util_setchecksum },
+ { N_("interactive"),
+ 'i',
+ N_("Run update in interactive mode"),
+ HAS_ARG_NO,
+ sh_util_set_interactive },
+ { N_("listfile"),
+ '-',
+ N_("Run update with listfile"),
+ HAS_ARG_YES,
+ sh_util_update_file },
+#endif
+#if defined(SH_WITH_SERVER) || defined(SH_WITH_CLIENT)
+ { N_("server-port"),
+ '-',
+ N_("Set the server port to connect to"),
+ HAS_ARG_YES,
+ sh_xfer_server_port },
+ { N_("server-host"),
+ '-',
+ N_("Set the server host to connect to"),
+ HAS_ARG_YES,
+ sh_xfer_set_logserver },
+#endif
+#ifdef SH_WITH_SERVER
+ { N_("server"),
+ 'S',
+ N_("Run as log server (obsolete)"),
+ HAS_ARG_NO,
+ sh_util_setserver },
+ { N_("qualified"),
+ 'q',
+ N_("Log fully qualified name of client host"),
+ HAS_ARG_NO,
+ sh_xfer_set_strip },
+ { N_("chroot"),
+ '-',
+ N_("Chroot to specified directory"),
+ HAS_ARG_YES,
+ sh_unix_set_chroot },
+#endif
+ { N_("daemon"),
+ 'D',
+ N_("Run as daemon"),
+ HAS_ARG_NO,
+ sh_unix_setdeamon },
+ { N_("foreground"),
+ '-',
+ N_("Stay in the foreground"),
+ HAS_ARG_NO,
+ sh_unix_setnodeamon },
+ { N_("bind-address"),
+ '-',
+ N_("Bind to this address (interface) for outgoing connections"),
+ HAS_ARG_YES,
+ sh_calls_set_bind_addr },
+#if defined(SH_WITH_SERVER) || defined(SH_WITH_CLIENT)
+ { N_("set-export-severity"),
+ 'e',
+ N_("Set severity threshold for export to remote log server"),
+ HAS_ARG_YES,
+ sh_error_setexport },
+#endif
+ { N_("set-syslog-severity"),
+ 's',
+ N_("Set severity threshold for syslog"),
+ HAS_ARG_YES,
+ sh_error_set_syslog },
+#ifdef WITH_EXTERNAL
+ { N_("set-extern-severity"),
+ 'x',
+ N_("Set severity threshold for logging by external program(s)"),
+ HAS_ARG_YES,
+ sh_error_set_external },
+#endif
+#ifdef HAVE_LIBPRELUDE
+ { N_("set-prelude-severity"),
+ '-',
+ N_("Set severity threshold for logging to prelude"),
+ HAS_ARG_YES,
+ sh_error_set_prelude },
+#endif
+#if defined(WITH_DATABASE)
+ { N_("set-database-severity"),
+ '-',
+ N_("Set severity threshold for logging to RDBMS"),
+ HAS_ARG_YES,
+ sh_error_set_database },
+#endif
+ { N_("set-log-severity"),
+ 'l',
+ N_("Set severity threshold for logfile"),
+ HAS_ARG_YES,
+ sh_error_setlog },
+#if defined(SH_WITH_MAIL)
+ { N_("set-mail-severity"),
+ 'm',
+ N_("Set severitythreshold for e-mail"),
+ HAS_ARG_YES,
+ sh_error_setseverity },
+#endif
+ { N_("set-print-severity"),
+ 'p',
+ N_("Set the severity threshold for terminal/console log"),
+ HAS_ARG_YES,
+ sh_error_setprint },
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ { N_("recursion"),
+ 'r',
+ N_("Set recursion level for directories"),
+ HAS_ARG_YES,
+ sh_files_setrecursion },
+#endif
+ { N_("verify-log"),
+ 'L',
+ N_("Verify the audit trail"),
+ HAS_ARG_YES,
+ sh_error_logverify },
+ { N_("just-list"),
+ 'j',
+ N_("Modify -L to just list the audit trail"),
+ HAS_ARG_NO,
+ sh_error_logverify_mod },
+#if defined(SH_WITH_MAIL)
+ { N_("verify-mail"),
+ 'M',
+ N_("Verify the mailbox"),
+ HAS_ARG_YES,
+ sh_mail_sigverify
+ },
+#endif
+ { N_("add-key"),
+ 'V',
+ N_("Add key for the mail/log signature"),
+ HAS_ARG_YES,
+ sh_util_set_newkey
+ },
+ { N_("hash-string"),
+ 'H',
+ N_("Print the hash of a string"),
+ HAS_ARG_YES,
+ sh_error_verify },
+#if defined (SH_WITH_SERVER)
+ { N_("password"),
+ 'P',
+ N_("Compute a client registry entry for password"),
+ HAS_ARG_YES,
+ sh_xfer_make_client },
+ { N_("gen-password"),
+ 'G',
+ N_("Generate a random password"),
+ HAS_ARG_NO,
+ sh_xfer_create_password },
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ { N_("forever"),
+ 'f',
+ N_("Loop forever, even if not daemon"),
+ HAS_ARG_NO,
+ sh_getopt_forever},
+ { N_("outfile"),
+ 'o',
+ N_("Pathname for output file"),
+ HAS_ARG_YES,
+ sh_getopt_outpath},
+ { N_("list-file"),
+ '-',
+ N_("Modify -d to show content of a single file"),
+ HAS_ARG_YES,
+ set_list_file},
+ { N_("list-filter"),
+ '-',
+ N_("Modify -d to filter by file list given in text file"),
+ HAS_ARG_YES,
+ sh_dbIO_list_filter},
+ { N_("full-detail"),
+ 'a',
+ N_("Modify -d to show full details"),
+ HAS_ARG_NO,
+ set_full_detail},
+ { N_("delimited"),
+ '-',
+ N_("Modify -d to show full details, comma delimited"),
+ HAS_ARG_NO,
+ set_list_delimited},
+ { N_("binary"),
+ '-',
+ N_("Modify -d to output in binary database format"),
+ HAS_ARG_NO,
+ sh_dbIO_list_binary},
+ { N_("list-database"),
+ 'd',
+ N_("List database content (like ls -l)"),
+ HAS_ARG_YES,
+ sh_dbIO_list_db},
+ { N_("init2stdout"),
+ '-',
+ N_("Write database to stdout on init"),
+ HAS_ARG_NO,
+ sh_dbIO_writeout_stdout},
+ { N_("verify-database"),
+ '-',
+ N_("Verify the given database"),
+ HAS_ARG_YES,
+ sh_dbCheck_verify},
+ { N_("create-database"),
+ '-',
+ N_("Create database from file list"),
+ HAS_ARG_YES,
+ sh_dbCreate},
+ { N_("wait-on-check"),
+ 'w',
+ N_("Timed wait for end of filecheck (0 for no timeout)"),
+ HAS_ARG_YES,
+ sh_sem_wait},
+#endif
+ { N_("trace-logfile"),
+ '-',
+ N_("Logfile for trace"),
+ HAS_ARG_YES,
+ sl_trace_file },
+ { N_("trace-enable"),
+ '-',
+ N_("Enable tracing"),
+ HAS_ARG_NO,
+ sl_trace_use },
+ { N_("copyright"),
+ 'c',
+ N_("Print copyright information"),
+ HAS_ARG_NO,
+ sh_getopt_copyright },
+ { N_("help"),
+ 'h',
+ N_("Print usage information"),
+ HAS_ARG_NO,
+ sh_getopt_usage },
+ { N_("version"),
+ 'v',
+ N_("Show version and compiled-in options"),
+ HAS_ARG_NO,
+ sh_getopt_version },
+#if defined(HAVE_LIBPRELUDE)
+ /* need to skip over these */
+ { N_("prelude"),
+ '-',
+ N_("Prelude generic options"),
+ HAS_ARG_NO,
+ NULL },
+ { N_("profile"),
+ '-',
+ N_("Profile to use for this analyzer"),
+ HAS_ARG_YES,
+ NULL },
+ { N_("heartbeat-interval"),
+ '-',
+ N_("Number of seconds between two heartbeats"),
+ HAS_ARG_YES,
+ NULL },
+ { N_("server-addr"),
+ '-',
+ N_("Address where this sensor should report to"),
+ HAS_ARG_YES,
+ NULL },
+ { N_("analyzer-name"),
+ '-',
+ N_("Name for this analyzer"),
+ HAS_ARG_YES,
+ NULL },
+#endif
+ /* last entry -- required !! -- */
+ { NULL,
+ '\0',
+ NULL,
+ HAS_ARG_NO,
+ NULL }
+};
+
+
+static void sh_getopt_print_log_facilities (void)
+{
+ int num = 0;
+
+ fputs (_("Compiled-in log facilities:\n"), stdout);
+
+#ifndef DEFAULT_CONSOLE
+ if (num > 0) fputc ('\n', stdout);
+ printf ("%s", _(" console (/dev/console)")); ++num;
+#else
+ if (num > 0) fputc ('\n', stdout);
+ if (0 == strcmp (DEFAULT_CONSOLE, _("NULL")))
+ { printf ("%s", _("console (/dev/console)")); ++num; }
+ else
+ { printf (_("console (%s)"), DEFAULT_CONSOLE); ++num; }
+#endif
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" syslog"), stdout); ++num;
+ if (num > 0) fputc ('\n', stdout);
+ printf (_(" logfile (%s)"), DEFAULT_ERRFILE); ++num;
+
+#if defined(WITH_EXTERNAL)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" external program"), stdout); ++num;
+#endif
+
+#if defined(WITH_MESSAGE_QUEUE)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" message queue"), stdout); ++num;
+#endif
+
+#if defined(WITH_DATABASE)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" database"), stdout); ++num;
+#ifdef WITH_ODBC
+ fputs (_(" (odbc)"), stdout);
+#endif
+#ifdef WITH_ORACLE
+ fputs (_(" (Oracle)"), stdout);
+#endif
+#ifdef WITH_POSTGRES
+ fputs (_(" (PostgreSQL)"), stdout);
+#endif
+#ifdef WITH_MYSQL
+ fputs (_(" (MySQL)"), stdout);
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" server"), stdout); ++num;
+#endif
+
+#if defined(SH_WITH_MAIL)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" email"), stdout); ++num;
+#endif
+
+#ifdef HAVE_LIBPRELUDE
+ if (num > 0) fputc ('\n', stdout); ++num;
+ fputs (_(" prelude (0.9.6+)"), stdout);
+#endif
+
+ if (num == 0)
+ fputs (_(" none"), stdout);
+ fputc ('\n', stdout);
+ return;
+}
+
+static void sh_getopt_print_options (void)
+{
+ int num = 0;
+
+
+#if defined(SH_STANDALONE)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_("Standalone executable"), stdout); ++num;
+#endif
+#if defined(SH_WITH_CLIENT)
+ if (num > 0) fputc ('\n', stdout);
+ printf (_("Client executable (port %d)"), SH_DEFAULT_PORT); ++num;
+#endif
+#if defined(SH_WITH_SERVER)
+ if (num > 0) fputc ('\n', stdout);
+ printf (_("Server executable (port %d, user %s)"),
+ SH_DEFAULT_PORT, DEFAULT_IDENT);
+ ++num;
+#endif
+#if defined(USE_IPVX)
+ fputs (_(", IPv6 supported"), stdout);
+#endif
+
+ fputs (_(", compiled-in options:"), stdout);
+
+#if defined(USE_SYSTEM_MALLOC)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" using system malloc"), stdout); ++num;
+#else
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" using dnmalloc"), stdout); ++num;
+#endif
+
+#if defined(HAVE_EGD_RANDOM)
+ if (num > 0) fputc ('\n', stdout);
+ printf (_(" using entropy gathering daemon (%s)"), EGD_SOCKET_NAME); ++num;
+#endif
+#if defined(HAVE_UNIX_RANDOM)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" using unix entropy gatherer"), stdout); ++num;
+#endif
+#if defined(HAVE_URANDOM)
+ if (num > 0) fputc ('\n', stdout);
+ printf (_(" using entropy device (%s)"), NAME_OF_DEV_RANDOM); ++num;
+#endif
+
+#ifdef WITH_GPG
+ if (num > 0) fputc ('\n', stdout);
+ printf (_(" GnuPG signatures (%s)"), DEFAULT_GPG_PATH); ++num;
+#ifdef HAVE_GPG_CHECKSUM
+ if (num > 0) fputc ('\n', stdout);
+ printf (_(" -- GnuPG checksum: %s"), GPG_HASH); ++num;
+#endif
+#ifdef USE_FINGERPRINT
+ if (num > 0) fputc ('\n', stdout);
+ printf (_(" -- Key fingerprint: %s"), SH_GPG_FP); ++num;
+#endif
+#endif
+
+#if defined(SH_EVAL_SHELL)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" shell expansion in configuration file supported"), stdout); ++num;
+#endif
+
+#if defined(SL_DEBUG)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" debug build (do not use for production)"), stdout); ++num;
+#endif
+#if defined(SCREW_IT_UP)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" anti-debugger"), stdout); ++num;
+#endif
+#if defined(SH_USE_XML)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" xml log format"), stdout); ++num;
+#endif
+#if defined(HAVE_NTIME)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" using time server"), stdout); ++num;
+#endif
+#if defined(HAVE_REGEX_H)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" posix regex support"), stdout); ++num;
+#endif
+
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+#if defined(HAVE_LIBZ)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" optionally store full text for files"), stdout); ++num;
+#endif
+#if !defined(SH_COMPILE_STATIC) && defined(__linux__) && defined(HAVE_AUPARSE_H) && defined(HAVE_AUPARSE_LIB)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" optionally report auditd record of changed file"), stdout); ++num;
+#endif
+#if defined(USE_XATTR)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" check SELinux attributes"), stdout); ++num;
+#endif
+#if defined(USE_ACL)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" check Posix ACLs"), stdout); ++num;
+#endif
+#if defined(RELOAD_DATABASE)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" fetch database on reload"), stdout); ++num;
+#endif
+#endif
+
+#if defined(SH_WITH_SERVER)
+
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" command socket authentication: use SetSocketPassword"), stdout);
+ ++num;
+#else
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" command socket authentication: use SetSocketAllowUID"), stdout);
+ ++num;
+#endif
+
+#if defined(SH_USE_LIBWRAP)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" support tcp wrapper"), stdout); ++num;
+#endif
+#if defined(INET_SYSLOG)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" support listening on 514/udp (syslog)"), stdout); ++num;
+#endif
+#endif
+
+ if (num == 0)
+ fputs (_(" none"), stdout);
+ fputc ('\n', stdout);
+ return;
+}
+
+static void sh_getopt_print_modules (void)
+{
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ int num = 0;
+
+ fputs (_("Compiled-in modules:\n"), stdout);
+#ifdef SH_USE_UTMP
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" login/logout"), stdout); ++num;
+#endif
+#ifdef SH_USE_MOUNTS
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" mount options"), stdout); ++num;
+#endif
+#ifdef SH_USE_USERFILES
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" userfiles"), stdout); ++num;
+#endif
+#ifdef SH_USE_KERN
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" kernel"), stdout); ++num;
+#endif
+#ifdef SH_USE_SUIDCHK
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" suid"), stdout); ++num;
+#endif
+#ifdef SH_USE_PROCESSCHECK
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" processes"), stdout); ++num;
+#endif
+#ifdef SH_USE_PORTCHECK
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" ports"), stdout); ++num;
+#endif
+#ifdef USE_LOGFILE_MONITOR
+ if (num > 0) fputc (',', stdout);
+ fputs (_(" logfile monitor"), stdout); ++num;
+#endif
+#if defined(USE_REGISTRY_CHECK)
+ if (num > 0) fputc ('\n', stdout);
+ fputs (_(" Windows registry"), stdout); ++num;
+#endif
+ if (num == 0)
+ fputs (_(" none"), stdout);
+ fputc ('\n', stdout);
+#endif
+ return;
+}
+
+static int sh_getopt_version (const char * dummy)
+{
+ (void) dummy;
+ fprintf (stdout,
+ _("This is samhain (%s), "\
+ "(c) 1999-2008 Rainer Wichmann (http://la-samhna.de).\n"),
+ VERSION);
+ fprintf (stdout, "%s",_("This software comes with ABSOLUTELY NO WARRANTY. "));
+ fprintf (stdout, "%s",_("Use at own risk.\n\n"));
+
+ sh_getopt_print_log_facilities ();
+ sh_getopt_print_modules ();
+ sh_getopt_print_options ();
+
+ _exit (EXIT_SUCCESS);
+ /*@notreached@*/
+ return 0; /* make compilers happy */
+}
+static int sh_getopt_copyright (const char * dummy)
+{
+ fprintf (stdout, "%s",
+ _("Copyright (C) 1999-2008 Rainer Wichmann"\
+ " (http://la-samhna.de).\n\n"));
+
+ fprintf (stdout, "%s",
+ _("This program is free software; "\
+ "you can redistribute it and/or modify\n"));
+ fprintf (stdout, "%s",_("it under the terms of the GNU General "\
+ "Public License as published by\n"));
+ fprintf (stdout, "%s",_("the Free Software Foundation; either version 2 "\
+ "of the License, or\n"));
+ fprintf (stdout, "%s",_("(at your option) any later version.\n\n"));
+
+ fprintf (stdout, "%s",_("This program is distributed in the hope "\
+ "that it will be useful,\n"));
+ fprintf (stdout, "%s",_("but WITHOUT ANY WARRANTY; "\
+ "without even the implied warranty of\n"));
+ fprintf (stdout, "%s",_("MERCHANTABILITY or FITNESS FOR A PARTICULAR "\
+ "PURPOSE. See the\n"));
+ fprintf (stdout, "%s",_("GNU General Public License for more details.\n\n"));
+
+ fprintf (stdout, "%s",_("You should have received a copy of the "\
+ "GNU General Public License\n"));
+ fprintf (stdout, "%s",_("along with this program; "\
+ "if not, write to the Free Software\n"));
+ fprintf (stdout, "%s",_("Foundation, Inc., 59 Temple Place - Suite 330, "\
+ "Boston, MA 02111-1307, USA.\n\n"));
+
+ fprintf (stdout, "%s",_("This product makes use of the reference "\
+ "implementation of the TIGER message\n"));
+ fprintf (stdout, "%s",_("digest algorithm. This code is copyright Eli Biham "\
+ "(biham@cs.technion.ac.il)\n"));
+ fprintf (stdout, "%s",_("and Ross Anderson (rja14@cl.cam.ac.uk). It can be used "\
+ "freely without any\n"));
+ fprintf (stdout, "%s",_("restrictions.\n"));
+#if defined(USE_SRP_PROTOCOL) && !defined(SH_STANDALONE)
+#if (!defined(HAVE_LIBGMP) || !defined(HAVE_GMP_H))
+ fprintf (stdout, "%s",_("This product makes use of the 'bignum' library by "\
+ "Henrik Johansson\n"));
+ fprintf (stdout, "%s",_("(Henrik.Johansson@Nexus.Comm.SE). If you are "\
+ "including this library in a\n"));
+ fprintf (stdout, "%s",_("commercial product, be sure to distribute ALL of"\
+ " it with the product.\n"));
+#endif
+ fprintf (stdout, "%s",_("This product uses the 'Secure Remote Password' "\
+ "cryptographic\n"));
+ fprintf (stdout, "%s",_("authentication system developed by Tom Wu "\
+ "(tjw@CS.Stanford.EDU).\n"));
+#endif
+ fprintf (stdout, "%s",_("\nPlease refer to the file COPYING in the source "\
+ "distribution for a"));
+ fprintf (stdout, "%s",_("\nfull list of incorporated code and associated "\
+ "licenses.\n"));
+
+ if (dummy)
+ _exit (EXIT_SUCCESS);
+ else
+ _exit (EXIT_SUCCESS);
+ /*@notreached@*/
+ return 0; /* make compilers happy */
+}
+
+/*@noreturn@*/
+static int sh_getopt_usage (const char * dummy)
+{
+ int i;
+ char fmt[64];
+
+ char opts[64];
+
+ for (i = 0; i < 64; ++i) /* splint does not grok char opts[64] = { '\0' }; */
+ opts[i] = '\0';
+
+ fprintf (stdout,
+ _("This is samhain (%s), "\
+ "(c) 1999-2006 Rainer Wichmann (http://la-samhna.de).\n"),
+ VERSION);
+ fprintf (stdout, "%s",_("This software comes with ABSOLUTELY NO WARRANTY. "));
+ fprintf (stdout, "%s",_("Use at own risk.\n"));
+
+ fprintf (stdout, "%s",_("Usage:\n\n"));
+
+ for (i = 0; op_table[i].longopt != NULL; ++i) {
+
+ if (i == 63)
+ break;
+
+ if (op_table[i].shortopt != '-' &&
+ strchr(opts, op_table[i].shortopt) != NULL)
+ fprintf (stdout, "%s",_("Short option char collision !\n"));
+ opts[i] = op_table[i].shortopt;
+
+
+ if (op_table[i].hasArg == HAS_ARG_NO) {
+ if (sl_strlen(op_table[i].longopt) < 10)
+ sl_strlcpy(fmt,_("%c%c%c --%-s,\t\t\t %s\n"), sizeof(fmt));
+ else if (sl_strlen(op_table[i].longopt) < 17)
+ sl_strlcpy(fmt, _("%c%c%c --%-s,\t\t %s\n"), sizeof(fmt));
+ else
+ sl_strlcpy(fmt, _("%c%c%c --%-s,\t %s\n"), sizeof(fmt));
+ /* flawfinder: ignore */
+ fprintf (stdout, fmt,
+ (op_table[i].shortopt == '-') ? ' ' : '-',
+ (op_table[i].shortopt == '-') ? ' ' : op_table[i].shortopt,
+ (op_table[i].shortopt == '-') ? ' ' : ',',
+ _(op_table[i].longopt),
+ _(op_table[i].usage));
+ } else {
+ if (sl_strlen(op_table[i].longopt) < 12)
+ sl_strlcpy(fmt, _("%c%c %s --%-s=<arg>,\t\t %s\n"), sizeof(fmt));
+ else
+ sl_strlcpy(fmt, _("%c%c %s --%-s=<arg>,\t %s\n"), sizeof(fmt));
+ /* flawfinder: ignore */
+ fprintf (stdout, fmt,
+ (op_table[i].shortopt == '-') ? ' ' : '-',
+ (op_table[i].shortopt == '-') ? ' ' : op_table[i].shortopt,
+ (op_table[i].shortopt == '-') ? _(" ") : _("<arg>,"),
+ _(op_table[i].longopt),
+ _(op_table[i].usage));
+ }
+ }
+
+ fprintf (stdout, "%s",
+ _("\nPlease report bugs to support@la-samhna.de.\n"));
+
+ (void) fflush(stdout);
+
+ if ( dummy != NULL)
+ {
+ if (sl_strcmp( dummy, _("fail")) == 0 )
+ _exit (EXIT_FAILURE);
+ }
+
+ _exit (EXIT_SUCCESS);
+ /*@notreached@*/
+ return 0; /* make compilers happy */
+}
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+static int sh_getopt_forever (const char * dummy)
+{
+ (void) dummy;
+ SL_ENTER(_("sh_getopt_forever"));
+ sh.flag.loop = S_TRUE;
+ SL_RETURN(0, _("sh_getopt_forever"));
+}
+
+static int sh_getopt_outpath (const char * str)
+{
+ if (str)
+ {
+ if (sh.outpath)
+ SH_FREE(sh.outpath);
+ sh.outpath = sh_util_strdup(str);
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+int sh_getopt_get (int argc, char * argv[])
+{
+ int count = 0;
+ size_t len = 0;
+ int foundit = 0;
+ int i;
+ size_t k;
+ char * theequal;
+
+ SL_ENTER(_("sh_getopt_get"));
+
+ /* -- Return if no args. --
+ */
+ if (argc < 2)
+ SL_RETURN(0, _("sh_getopt_get"));
+
+ while (argc > 1 && argv[1][0] == '-')
+ {
+
+ /* Initialize
+ */
+ foundit = 0;
+ len = sl_strlen (argv[1]);
+
+ /* a '-' with no argument: error
+ */
+ if (len == 1)
+ (void) sh_getopt_usage(_("fail"));
+
+ /* a '--' with no argument: stop argument processing
+ */
+ if (len == 2 && argv[1][1] == '-')
+ SL_RETURN( count, _("sh_getopt_get"));
+
+ /* a short option: process it
+ */
+ if (len >= 2 && argv[1][1] != '-')
+ {
+ for (k = 1; k < len; ++k)
+ {
+ for (i = 0; op_table[i].shortopt != '\0'; ++i)
+ {
+
+ if ( op_table[i].shortopt == argv[1][k] )
+ {
+ foundit = 1;
+ if ( op_table[i].hasArg == HAS_ARG_YES )
+ {
+ if (k != (len - 1))
+ {
+ /* not last option
+ */
+ fprintf (stderr, "%s",
+ _("Error: short option with argument is not last in option string\n"));
+ (void) sh_getopt_usage(_("fail"));
+ }
+ if (argc < 3)
+ {
+ /* argument required, but no avail
+ */
+ fprintf (stderr, "%s",
+ _("Error: missing argument\n"));
+ (void) sh_getopt_usage(_("fail"));
+ }
+ else
+ {
+ /* call function with argument */
+ --argc; ++argv;
+ if (NULL != op_table[i].func &&
+ 0 != (* op_table[i].func )(argv[1]))
+ fprintf (stderr,
+ _("Error processing option -%c\n"),
+ op_table[i].shortopt);
+ break;
+ }
+ }
+ else
+ {
+ if (NULL != op_table[i].func &&
+ 0 != (* op_table[i].func )(NULL))
+ fprintf (stderr,
+ _("Error processing option -%c\n"),
+ op_table[i].shortopt);
+ break;
+ }
+ }
+ }
+ }
+
+ /* 'break' should get here
+ */
+ if (foundit == 1)
+ {
+ --argc; ++argv;
+ continue;
+ }
+ else
+ {
+ /* unrecognized short option */
+ fprintf (stderr, "%s",_("Error: unrecognized short option\n"));
+ (void) sh_getopt_usage(_("fail"));
+ }
+ }
+
+ /* a long option: process it
+ */
+ if (len > 2)
+ {
+
+ for (i = 0; op_table[i].longopt != NULL; ++i)
+ {
+
+ if (sl_strncmp(_(op_table[i].longopt),
+ &argv[1][2],
+ sl_strlen(op_table[i].longopt)) == 0 )
+ {
+ foundit = 1;
+ if ( op_table[i].hasArg == HAS_ARG_YES )
+ {
+ theequal = strchr(argv[1], '=');
+ if (theequal == NULL)
+ {
+ if (argc < 3)
+ {
+ /* argument required, but no avail
+ */
+ fprintf (stderr, "%s",
+ _("Error: missing argument\n"));
+ (void) sh_getopt_usage(_("fail"));
+ }
+ else
+ {
+ /* call function with argument */
+ --argc; ++argv;
+ if (NULL != op_table[i].func &&
+ 0 != (* op_table[i].func )(argv[1]))
+ fprintf (stderr,
+ _("Error processing option -%s\n"),
+ op_table[i].longopt);
+ break;
+ }
+ }
+ else
+ {
+ if (sl_strlen (theequal) > 1)
+ {
+ ++theequal;
+ /* call function with argument */
+ if (NULL != op_table[i].func &&
+ 0 != (* op_table[i].func )(theequal))
+ fprintf (stderr,
+ _("Error processing option -%s\n"),
+ op_table[i].longopt);
+ break;
+ }
+ else
+ {
+ fprintf (stderr, "%s",
+ _("Error: invalid argument\n"));
+ /* argument required, but no avail */
+ (void) sh_getopt_usage(_("fail"));
+ }
+ }
+ }
+ else
+ {
+ if (NULL != op_table[i].func &&
+ 0 != (* op_table[i].func )(NULL))
+ fprintf (stderr,
+ _("Error processing option -%s\n"),
+ op_table[i].longopt);
+ break;
+ }
+ }
+ }
+
+ /* 'break' should get here */
+ if (foundit == 1)
+ {
+ ++count;
+ --argc;
+ ++argv;
+ continue;
+ }
+ else
+ {
+ /* unrecognized long option */
+ fprintf (stderr, "%s",_("Error: unrecognized long option\n"));
+ (void) sh_getopt_usage(_("fail"));
+ }
+ }
+ }
+
+ SL_RETURN( count, _("sh_getopt_get"));
+}
diff --git a/src/sh_gpg.c b/src/sh_gpg.c
new file mode 100644
index 0000000..e06d42c
--- /dev/null
+++ b/src/sh_gpg.c
@@ -0,0 +1,1035 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#if defined(WITH_GPG) || defined(WITH_PGP)
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#if defined(SH_WITH_SERVER)
+#include <pwd.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#include <string.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_error.h"
+#include "sh_tiger.h"
+#if defined(SH_WITH_SERVER)
+#define SH_NEED_PWD_GRP 1
+#include "sh_static.h"
+#endif
+#include "sh_gpg.h"
+
+static struct {
+ char conf_id[SH_MINIBUF+1];
+ char conf_fp[SH_MINIBUF+1];
+ char data_id[SH_MINIBUF+1];
+ char data_fp[SH_MINIBUF+1];
+} gp;
+
+typedef struct {
+ pid_t pid;
+ FILE * pipe;
+} sh_gpg_popen_t;
+
+#define SH_GPG_OK 0
+#define SH_GPG_BAD 1
+#define SH_GPG_BADSIGN 2
+
+/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.'
+ * for debugging
+ */
+#if 0
+#define PDGBFILE "/pdbg."
+#endif
+
+#if defined(PDGBFILE)
+FILE * pdbg;
+FILE * pdbgc;
+#define PDBG_OPEN pdbg = fopen(PDGBFILE"main", "a")
+#define PDBG_CLOSE sl_fclose (FIL__, __LINE__, pdbg)
+#define PDBG(arg) fprintf(pdbg, "PDBG: step %d\n", arg); fflush(pdbg)
+#define PDBG_D(arg) fprintf(pdbg, "PDBG: %d\n", arg); fflush(pdbg)
+#define PDBG_S(arg) fprintf(pdbg, "PDBG: %s\n", arg); fflush(pdbg)
+
+#define PDBGC_OPEN pdbgc = fopen(PDGBFILE"child", "a")
+#define PDBGC_CLOSE sl_fclose (FIL__, __LINE__, pdbgc)
+#define PDBGC(arg) fprintf(pdbgc, "PDBG: step %d\n", arg); fflush(pdbgc)
+#define PDBGC_D(arg) fprintf(pdbgc, "PDBG: %d\n", arg); fflush(pdbgc)
+#define PDBGC_S(arg) fprintf(pdbgc, "PDBG: %s\n", arg); fflush(pdbgc)
+#else
+#define PDBG_OPEN
+#define PDBG_CLOSE
+#define PDBG(arg)
+#define PDBG_D(arg)
+#define PDBG_S(arg)
+#define PDBGC_OPEN
+#define PDBGC_CLOSE
+#define PDBGC(arg)
+#define PDBGC_D(arg)
+#define PDBGC_S(arg)
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_gpg.c")
+
+#ifdef GPG_HASH
+
+static int sh_gpg_checksum (SL_TICKET checkfd, int flag)
+{
+ char * test_gpg;
+ char * test_ptr1 = NULL;
+ char * test_ptr2 = NULL;
+ char wstrip1[128];
+ char wstrip2[128];
+ int i, k;
+#include "sh_gpg_chksum.h"
+
+ SL_ENTER(_("sh_gpg_checksum"));
+
+ test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, checkfd, TIGER_NOLIM);
+
+ test_ptr1 = strchr(GPG_HASH, ':');
+ if (test_gpg != NULL)
+ test_ptr2 = strchr(test_gpg, ':');
+
+ if (test_ptr2 != NULL)
+ test_ptr2 += 2;
+ else
+ test_ptr2 = test_gpg;
+ if (test_ptr1 != NULL)
+ test_ptr1 += 2;
+ else
+ test_ptr1 = GPG_HASH;
+
+ /* Tue Jun 24 23:11:54 CEST 2003 (1.7.9) -- strip whitespace
+ */
+ k = 0;
+ for (i = 0; i < 127; ++i)
+ {
+ if (test_ptr1[i] == '\0')
+ break;
+ if (test_ptr1[i] != ' ')
+ {
+ wstrip1[k] = test_ptr1[i];
+ ++k;
+ }
+ }
+ wstrip1[k] = '\0';
+
+ for(i = 0; i < KEY_LEN; ++i)
+ {
+ if (gpgchk[i] != wstrip1[i])
+ {
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, MSG_E_GPG_CHK,
+ gpgchk, wstrip1);
+ break;
+ }
+ }
+
+ k = 0;
+ if (test_ptr2)
+ {
+ for (i = 0; i < 127; ++i)
+ {
+ if (test_ptr2[i] == '\0')
+ break;
+ if (test_ptr2[i] != ' ')
+ {
+ wstrip2[k] = test_ptr2[i];
+ ++k;
+ }
+ }
+ }
+ wstrip2[k] = '\0';
+
+ if (0 != sl_strncmp(wstrip1, wstrip2, 127))
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<pgp checksum: %s>\n"), test_gpg));
+ TPT(((0), FIL__, __LINE__, _("msg=<Compiled-in : %s>\n"), GPG_HASH));
+ TPT(((0), FIL__, __LINE__, _("msg=<wstrip1 : %s>\n"), wstrip1));
+ TPT(((0), FIL__, __LINE__, _("msg=<wstrip2 : %s>\n"), wstrip2));
+ if (flag == 1)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_GPG,
+ GPG_HASH, test_gpg);
+ dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the gpg binary\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), wstrip1, wstrip2);
+ SH_FREE(test_gpg);
+ SL_RETURN((-1), _("sh_gpg_checksum"));
+ }
+ SH_FREE(test_gpg);
+ SL_RETURN( (0), _("sh_gpg_checksum"));
+}
+#endif
+
+struct startup_info {
+ long line;
+ char * program;
+ long uid;
+ char * path;
+ char * key_uid;
+ char * key_id;
+};
+
+static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL };
+
+void sh_gpg_log_startup (void)
+{
+ if (startInfo.program != NULL)
+ {
+ sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH,
+ startInfo.program, startInfo.uid,
+ startInfo.path,
+ startInfo.key_uid, startInfo.key_id);
+ }
+ return;
+}
+
+static void sh_gpg_fill_startup (long line, char * program, long uid, char * path,
+ char * key_uid, char * key_id)
+{
+ startInfo.line = line;
+ startInfo.program = sh_util_strdup(program);
+ startInfo.uid = uid;
+ startInfo.path = sh_util_strdup(path);
+ startInfo.key_uid = sh_util_strdup(key_uid);
+ startInfo.key_id = sh_util_strdup(key_id);
+ return;
+}
+
+static FILE * sh_gpg_popen (sh_gpg_popen_t *source, int fd,
+ int mode, char * id, char * homedir)
+{
+ extern int flag_err_debug;
+ int pipedes[2];
+ FILE * outf = NULL;
+ char * envp[2];
+ size_t len;
+ char path[256];
+ char cc1[32];
+ char cc2[32];
+
+ char cc0[2] = "-";
+ char cc3[32];
+ char cc4[SH_PATHBUF+32];
+ char cc5[32];
+
+
+ char * arg[9];
+
+#if defined(HAVE_GPG_CHECKSUM)
+ SL_TICKET checkfd = -1;
+ int myrand;
+ int i;
+#if defined(__linux__)
+ int get_the_fd(SL_TICKET);
+ char pname[128];
+ int pfd;
+ int val_return;
+#endif
+#endif
+
+ SL_ENTER(_("sh_gpg_popen"));
+
+ /* -- GnuPG -- */
+ sl_strlcpy (path, DEFAULT_GPG_PATH, 256);
+ sl_strlcpy (cc1, _("--status-fd"), 32);
+ sl_strlcpy (cc2, _("--verify"), 32);
+ sl_strlcpy (cc3, _("--homedir"), 32);
+ /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */
+ sl_strlcpy (cc4, homedir, SH_PATHBUF+32);
+ sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
+ sl_strlcpy (cc5, _("--no-tty"), 32);
+
+ /* fprintf(stderr, "YULE: homedir=%s\n", homedir); */
+
+#if defined(SH_WITH_SERVER)
+ if (0 == sl_ret_euid()) /* privileges not dropped yet */
+ {
+ struct stat lbuf;
+ int status_stat = 0;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ struct passwd * tempres;
+ sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
+#endif
+
+ if (!tempres)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("User %s does not exist. Please add the user to your system.\n"),
+ DEFAULT_IDENT);
+ status_stat = -1;
+ }
+ if (!tempres->pw_dir || tempres->pw_dir[0] == '\0')
+ {
+ dlog(1, FIL__, __LINE__,
+ _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"),
+ DEFAULT_IDENT);
+ status_stat = -2;
+ }
+ if (status_stat == 0)
+ {
+ sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
+ sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
+ status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
+ if (status_stat == -1)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Gnupg directory %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg) there\nto verify the configuration file.\n"),
+ cc4, DEFAULT_IDENT);
+ status_stat = -3;
+ }
+ }
+ if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Gnupg directory %s\nis not owned by user %s.\n"),
+ cc4, DEFAULT_IDENT);
+ status_stat = -4;
+ }
+ if (status_stat == 0)
+ {
+ sl_strlcat (cc4, _("/pubring.gpg"), SH_PATHBUF+32);
+ status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf);
+ if (status_stat == -1)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Gnupg public keyring %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg) there\nto verify the configuration file.\n"),
+ cc4, DEFAULT_IDENT);
+ status_stat = -5;
+ }
+ }
+ if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Gnupg public keyring %s\nis not owned by user %s.\n"),
+ cc4, DEFAULT_IDENT);
+ status_stat = -6;
+ }
+ if (status_stat != 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32);
+ sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+#endif
+
+ arg[0] = path;
+ arg[1] = cc1;
+ arg[2] = "1";
+ arg[3] = cc2;
+ arg[4] = cc3;
+ arg[5] = cc4;
+ arg[6] = cc5;
+ arg[7] = cc0;
+ arg[8] = NULL;
+
+ /* catch 'unused parameter' compiler warning
+ */
+ (void) mode;
+ (void) id;
+
+ /* use homedir of effective user
+ */
+ len = sl_strlen(sh.effective.home) + 6;
+ envp[0] = calloc(1, len); /* free() ok */
+ if (envp[0] != NULL)
+ sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home);
+ envp[1] = NULL;
+
+ /* Create the pipe
+ */
+ if (aud_pipe(FIL__, __LINE__, pipedes) < 0)
+ {
+ if (envp[0] != NULL)
+ free(envp[0]);
+ SL_RETURN( (NULL), _("sh_gpg_popen"));
+ }
+
+ fflush (NULL);
+
+ source->pid = aud_fork(FIL__, __LINE__);
+
+ /* Failure
+ */
+ if (source->pid == (pid_t) - 1)
+ {
+ sl_close_fd(FIL__, __LINE__, pipedes[0]);
+ sl_close_fd(FIL__, __LINE__, pipedes[1]);
+ if (envp[0] != NULL)
+ free(envp[0]);
+ SL_RETURN( (NULL), _("sh_gpg_popen"));
+ }
+
+ if (source->pid == (pid_t) 0)
+ {
+
+ /* child - make read side of the pipe stdout
+ */
+ if (retry_aud_dup2(FIL__, __LINE__,
+ pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n")));
+ dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* close the pipe descriptors
+ */
+ sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]);
+ sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+
+ if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n")));
+ dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n"));
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* don't leak file descriptors
+ */
+ sh_unix_closeall (3, -1, S_TRUE); /* in child process */
+
+ if (flag_err_debug != S_TRUE)
+ {
+ if (NULL == freopen(_("/dev/null"), "r+", stderr))
+ {
+ dlog(1, FIL__, __LINE__, _("Internal error: freopen failed\n"));
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ }
+
+
+ /* We should become privileged if SUID,
+ * to be able to read the keyring.
+ * We have checked that gpg is OK,
+ * AND that only a trusted user could overwrite
+ * gpg.
+ */
+ memset (skey, '\0', sizeof(sh_key_t));
+ aud_setuid(FIL__, __LINE__, geteuid());
+
+ PDBGC_OPEN;
+ PDBGC_D((int)getuid());
+ PDBGC_D((int)geteuid());
+
+ {
+ int i = 0;
+ while (arg[i] != NULL)
+ {
+ PDBGC_S(arg[i]);
+ ++i;
+ }
+ }
+ PDBGC_CLOSE;
+
+ /* exec the program */
+
+#if defined(__linux__) && defined(HAVE_GPG_CHECKSUM)
+ /*
+ * -- emulate an fexecve with checksum testing
+ */
+ checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_NOPRIV);
+
+ if (0 != sh_gpg_checksum(checkfd, 0))
+ {
+ sl_close(checkfd);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ pfd = get_the_fd(checkfd);
+ do {
+ val_return = dup (pfd);
+ } while (val_return < 0 && errno == EINTR);
+ pfd = val_return;
+ sl_close(checkfd);
+ /* checkfd = -1; *//* never read */
+
+ sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd);
+ if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */
+
+ {
+ fcntl (pfd, F_SETFD, FD_CLOEXEC);
+ retry_aud_execve (FIL__, __LINE__, pname, arg, envp);
+
+ dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
+ pname);
+ /* failed
+ */
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* procfs not working, go ahead
+ */
+#endif
+
+#if defined(HAVE_GPG_CHECKSUM)
+ /* This is an incredibly ugly kludge to prevent an attacker
+ * from knowing when it is safe to slip in a fake executable
+ * between the integrity check and the execve
+ */
+ myrand = (int) taus_get ();
+
+ myrand = (myrand < 0) ? (-myrand) : myrand;
+ myrand = (myrand % 32) + 2;
+
+ for (i = 0; i < myrand; ++i)
+ {
+ checkfd = sl_open_fastread(FIL__, __LINE__,
+ DEFAULT_GPG_PATH, SL_NOPRIV);
+
+ if (0 != sh_gpg_checksum(checkfd, 0)) {
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ sl_close(checkfd);
+ }
+#endif
+
+ retry_aud_execve (FIL__, __LINE__, DEFAULT_GPG_PATH, arg, envp);
+ dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"),
+ DEFAULT_GPG_PATH);
+
+ /* failed
+ */
+ TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n")));
+ dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n"));
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* parent
+ */
+
+ if (envp[0] != NULL)
+ free(envp[0]);
+
+ sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+ retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
+ retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK);
+
+ outf = fdopen (pipedes[STDIN_FILENO], "r");
+
+ if (outf == NULL)
+ {
+ aud_kill (FIL__, __LINE__, source->pid, SIGKILL);
+ sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]);
+ waitpid (source->pid, NULL, 0);
+ source->pid = 0;
+ SL_RETURN( (NULL), _("sh_gpg_popen"));
+ }
+
+ SL_RETURN( (outf), _("sh_gpg_popen"));
+}
+
+
+static int sh_gpg_pclose (sh_gpg_popen_t *source)
+{
+ int status = 0;
+
+ SL_ENTER(_("sh_gpg_pclose"));
+
+ status = sl_fclose(FIL__, __LINE__, source->pipe);
+ if (status)
+ SL_RETURN( (-1), _("sh_gpg_pclose"));
+
+ if (waitpid(source->pid, NULL, 0) != source->pid)
+ status = -1;
+
+ source->pipe = NULL;
+ source->pid = 0;
+ SL_RETURN( (status), _("sh_gpg_pclose"));
+}
+
+static
+int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp,
+ char * homedir, int whichfile)
+{
+ struct stat buf;
+ char line[256];
+ sh_gpg_popen_t source;
+ int have_id = BAD, have_fp = BAD, status = 0;
+
+#ifdef HAVE_GPG_CHECKSUM
+ SL_TICKET checkfd;
+#endif
+
+ SL_ENTER(_("sh_gpg_check_file_sign"));
+
+ /* check whether GnuPG exists and has the correct checksum
+ */
+ TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n")));
+ TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_GPG_PATH));
+
+ if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_GPG_PATH, &buf))
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ status = errno;
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT,
+ sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_GPG_PATH);
+ SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
+ }
+
+ if (0 != tf_trust_check (DEFAULT_GPG_PATH, SL_YESPRIV))
+ SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
+
+#ifdef HAVE_GPG_CHECKSUM
+ checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_YESPRIV);
+
+ if (0 != sh_gpg_checksum(checkfd, 1))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Checksum mismatch"),
+ _("gpg_check_file_sign"));
+ sl_close(checkfd);
+ SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
+ }
+ sl_close(checkfd);
+#endif
+
+ TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n")));
+
+ fflush(NULL);
+
+ source.pipe = sh_gpg_popen ( &source, fd, 0, NULL, homedir );
+
+ if (NULL == source.pipe)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Could not open pipe"),
+ _("gpg_check_file_sign"));
+ SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign"));
+ }
+
+ TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n")));
+
+ xagain:
+
+ errno = 0;
+
+ while (NULL != fgets(line, sizeof(line), source.pipe))
+ {
+
+ TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line));
+ if (line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = ' ';
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ line,
+ _("gpg_check_file_sign"));
+
+ if (sl_strlen(line) < 18)
+ continue;
+
+ /* Sun May 27 18:40:05 CEST 2001
+ */
+ if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) ||
+ 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) ||
+ 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) ||
+ 0 == sl_strncmp(_("NODATA"), &line[9], 6) ||
+ 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6))
+ {
+ if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) {
+ dlog(1, FIL__, __LINE__,
+ _("%s file is signed, but the signature is invalid."),
+ ((whichfile == 1) ? _("Configuration") : _("Database")));
+ }
+ else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) {
+ dlog(1, FIL__, __LINE__,
+ _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
+ ((whichfile == 1) ? _("Configuration") : _("Database")),
+ homedir);
+ }
+ else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) {
+ dlog(1, FIL__, __LINE__,
+ _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."),
+ ((whichfile == 1) ? _("Configuration") : _("Database")),
+ homedir);
+ }
+ else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) {
+ dlog(1, FIL__, __LINE__,
+ _("%s file is signed, but the public key to verify the signature has expired."),
+ ((whichfile == 1) ? _("Configuration") : _("Database")));
+ }
+ else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) {
+ dlog(1, FIL__, __LINE__,
+ _("%s file is not signed."),
+ ((whichfile == 1) ? _("Configuration") : _("Database")));
+ }
+
+ have_fp = BAD; have_id = BAD;
+ break;
+ }
+ if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7))
+ {
+ sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1);
+ if (sign_id)
+ sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */
+ have_id = GOOD;
+ }
+ if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8))
+ {
+ strncpy (sign_fp, &line[18], 40);
+ sign_fp[40] = '\0';
+ have_fp = GOOD;
+ }
+ }
+
+ if (ferror(source.pipe) && errno == EAGAIN)
+ {
+ /* sleep 10 ms to avoid starving the gpg child writing to the pipe */
+ retry_msleep(0,10);
+ clearerr(source.pipe);
+ goto xagain;
+ }
+
+ sh_gpg_pclose (&source);
+
+ TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n")));
+
+ if (have_id == GOOD)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n")));
+ }
+ if (have_fp == GOOD)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n")));
+ }
+
+ if (have_id == GOOD && have_fp == GOOD)
+ SL_RETURN( SH_GPG_OK, _("sh_gpg_check_file_sign"));
+ else
+ {
+ if (have_id == BAD)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("No good signature"),
+ _("gpg_check_file_sign"));
+ else
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("No fingerprint for key"),
+ _("gpg_check_file_sign"));
+ SL_RETURN( SH_GPG_BADSIGN, _("sh_gpg_check_file_sign"));
+ }
+}
+
+int get_the_fd(SL_TICKET file_1);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \
+ defined(HAVE_GETPWNAM_R)
+#define USE_GETPWNAM_R 1
+#endif
+
+int sh_gpg_check_sign (long file, int what)
+{
+ int status = SH_GPG_BAD;
+ int fd = 0;
+
+ static int smsg = S_FALSE;
+ char * tmp;
+
+ char * sig_id;
+ char * sig_fp;
+
+ char * homedir = sh.effective.home;
+#if defined(SH_WITH_SERVER)
+ struct passwd * tempres;
+#if defined(USE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
+#endif
+#endif
+
+#ifdef USE_FINGERPRINT
+#include "sh_gpg_fp.h"
+#endif
+
+ SL_ENTER(_("sh_gpg_check_sign"));
+
+
+ if (what == SIG_CONF)
+ fd = get_the_fd(file);
+ if (what == SIG_DATA)
+ fd = get_the_fd(file);
+
+
+ if (fd < 0)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
+ dlog(1, FIL__, __LINE__,
+ _("This looks like an unexpected internal error.\n"));
+#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( (-1), _("sh_gpg_check_sign"));
+ }
+
+#if defined(SH_WITH_SERVER)
+#if defined(USE_GETPWNAM_R)
+ sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ tempres = sh_getpwnam(DEFAULT_IDENT);
+#endif
+ if ((tempres != NULL) && (0 == sl_ret_euid()))
+ {
+ /* privileges not dropped yet*/
+ homedir = tempres->pw_dir;
+ }
+#endif
+
+ if (what == SIG_CONF)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
+ status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, 1);
+ TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id));
+ TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp));
+ sig_id = gp.conf_id; sig_fp = gp.conf_fp;
+ }
+
+ if (what == SIG_DATA)
+ {
+ TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd));
+ status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, 2);
+ TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id));
+ TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp));
+ sig_id = gp.data_id; sig_fp = gp.data_fp;
+ }
+
+ if (SH_GPG_OK == status)
+ {
+#ifdef USE_FINGERPRINT
+ if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0))
+ {
+ int i;
+
+ for(i = 0; i < (int) sl_strlen(sig_fp); ++i) {
+ if (gpgfp[i] != sig_fp[i]) {
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
+ MSG_E_GPG_FP, gpgfp, sig_fp);
+ break; }
+ }
+
+ if (smsg == S_FALSE) {
+ tmp = sh_util_safe_name(sig_id);
+ sh_gpg_fill_startup (__LINE__, sh.prg_name, sh.real.uid,
+ (sh.flag.hidefile == S_TRUE) ?
+ _("(hidden)") : file_path('C', 'R'),
+ tmp,
+ sig_fp);
+ SH_FREE(tmp); }
+ smsg = S_TRUE;
+
+#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN(0, _("sh_gpg_check_sign"));
+ }
+ else
+ {
+ /* fp mismatch */
+ dlog(1, FIL__, __LINE__,
+ _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"),
+ sig_fp, SH_GPG_FP);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Fingerprint mismatch"), _("gpg_check_sign"));
+ status = SH_GPG_BADSIGN;
+ }
+#else /* ifdef USE_FINGERPRINT */
+ if (smsg == S_FALSE)
+ {
+ tmp = sh_util_safe_name(sig_id);
+ sh_gpg_fill_startup (__LINE__,
+ sh.prg_name, sh.real.uid,
+ (sh.flag.hidefile == S_TRUE) ?
+ _("(hidden)") : file_path('C', 'R'),
+ tmp, sig_fp);
+ SH_FREE(tmp);
+ }
+ smsg = S_TRUE;
+
+#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN(0, _("sh_gpg_check_sign"));
+#endif /* !ifdef USE_FINGERPRINT */
+ }
+
+ if (status != SH_GPG_OK)
+ {
+ uid_t e_uid = sl_ret_euid();
+ char * e_home = sh.effective.home;
+
+#if defined(SH_WITH_SERVER)
+#if defined(USE_GETPWNAM_R)
+ struct passwd e_pwd;
+ char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ struct passwd * e_tempres;
+ sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres);
+#else
+ struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT);
+#endif
+
+ if ((e_tempres != NULL) && (0 == sl_ret_euid()))
+ {
+ /* privileges not dropped yet */
+ e_uid = e_tempres->pw_uid;
+ e_home = e_tempres->pw_dir;
+ }
+#endif
+ dlog(1, FIL__, __LINE__,
+ _("The signature of the configuration file or the file signature database\ncould not be verified. Possible reasons are:\n - gpg binary (%s) not found\n - invalid signature\n - the signature key is not in the private keyring of UID %d,\n - there is no keyring in %s/.gnupg, or\n - the file is not signed - did you move /filename.asc to /filename ?\nTo create a signed file, use (remove old signatures before):\n gpg -a --clearsign --not-dash-escaped FILE\n mv FILE.asc FILE\n"),
+ DEFAULT_GPG_PATH,
+ (int) e_uid, e_home);
+
+#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R)
+ SH_FREE(e_buffer);
+#endif
+ }
+
+ TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status));
+
+ return (-1); /* make compiler happy */
+}
+
+#define FGETS_BUF 16384
+
+SL_TICKET sh_gpg_extract_signed(SL_TICKET fd)
+{
+ FILE * fin_cp = NULL;
+ char * buf = NULL;
+ int bufc;
+ int flag_pgp = S_FALSE;
+ int flag_nohead = S_FALSE;
+ SL_TICKET fdTmp = (-1);
+ SL_TICKET open_tmp (void);
+
+ /* extract the data and copy to temporary file
+ */
+ fdTmp = open_tmp();
+ if (SL_ISERROR(fdTmp))
+ {
+ dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n"));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Error opening temporary file."),
+ _("sh_gpg_extract_signed"));
+ return -1;
+ }
+
+ fin_cp = fdopen(dup(get_the_fd(fd)), "rb");
+ buf = SH_ALLOC(FGETS_BUF);
+
+ while (NULL != fgets(buf, FGETS_BUF, fin_cp))
+ {
+ bufc = 0;
+ while (bufc < FGETS_BUF) {
+ if (buf[bufc] == '\n') { ++bufc; break; }
+ ++bufc;
+ }
+
+ if (flag_pgp == S_FALSE &&
+ (0 == sl_strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n"))||
+ 0 == sl_strcmp(buf, _("-----BEGIN PGP MESSAGE-----\n")))
+ )
+ {
+ flag_pgp = S_TRUE;
+ sl_write(fdTmp, buf, bufc);
+ continue;
+ }
+
+ if (flag_pgp == S_TRUE && flag_nohead == S_FALSE)
+ {
+ if (buf[0] == '\n')
+ {
+ flag_nohead = S_TRUE;
+ sl_write(fdTmp, buf, 1);
+ continue;
+ }
+ else if (0 == sl_strncmp(buf, _("Hash:"), 5) ||
+ 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15))
+ {
+ sl_write(fdTmp, buf, bufc);
+ continue;
+ }
+ else
+ continue;
+ }
+
+ if (flag_pgp == S_TRUE && buf[0] == '\n')
+ {
+ sl_write(fdTmp, buf, 1);
+ }
+ else if (flag_pgp == S_TRUE)
+ {
+ /* sl_write_line(fdTmp, buf, bufc); */
+ sl_write(fdTmp, buf, bufc);
+ }
+
+ if (flag_pgp == S_TRUE &&
+ 0 == sl_strcmp(buf, _("-----END PGP SIGNATURE-----\n")))
+ break;
+ }
+ SH_FREE(buf);
+ sl_fclose(FIL__, __LINE__, fin_cp); /* fin_cp = fdopen(dup(), "rb"); */
+ sl_rewind (fdTmp);
+
+ return fdTmp;
+}
+
+/* #ifdef WITH_GPG */
+#endif
+
+
+
+
+
+
+
+
diff --git a/src/sh_guid.c b/src/sh_guid.c
new file mode 100644
index 0000000..34a77bc
--- /dev/null
+++ b/src/sh_guid.c
@@ -0,0 +1,376 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+#include "samhain.h"
+#include "sh_utils.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#define UUID_SIZE 36
+
+struct uuid {
+ UINT32 time_low;
+ UINT16 time_mid;
+ UINT16 time_hi_and_version;
+ UINT16 clock_seq;
+ UBYTE node[6];
+};
+
+typedef unsigned char uuid_t[16];
+
+
+static void uuid_pack(const struct uuid *uu, uuid_t ptr)
+{
+ UINT32 tmp;
+ unsigned char *out = ptr;
+
+ tmp = uu->time_low;
+ out[3] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[2] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[1] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[0] = (unsigned char) tmp;
+
+ tmp = uu->time_mid;
+ out[5] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[4] = (unsigned char) tmp;
+
+ tmp = uu->time_hi_and_version;
+ out[7] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[6] = (unsigned char) tmp;
+
+ tmp = uu->clock_seq;
+ out[9] = (unsigned char) tmp;
+ tmp >>= 8;
+ out[8] = (unsigned char) tmp;
+
+ memcpy(out+10, uu->node, 6);
+ return;
+}
+
+static void uuid_unpack(const uuid_t in, struct uuid *uu)
+{
+ const uint8_t *ptr = in;
+ uint32_t tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_low = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_mid = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->time_hi_and_version = tmp;
+
+ tmp = *ptr++;
+ tmp = (tmp << 8) | *ptr++;
+ uu->clock_seq = tmp;
+
+ memcpy(uu->node, ptr, 6);
+ return;
+}
+
+static void get_random_bytes(unsigned char * buf, size_t len)
+{
+ unsigned int j;
+
+ union {
+ UINT32 i;
+ char c[sizeof(UINT32)];
+ } u;
+
+ do {
+ u.i = taus_get();
+
+ for (j= 0; j < sizeof(UINT32); j++)
+ {
+ if (len) {
+ --len;
+ *buf = u.c[j];
+ ++buf;
+ }
+ }
+ } while (len);
+
+ return;
+}
+
+static void uuid_generate_random(uuid_t out)
+{
+ uuid_t buf;
+ struct uuid uu;
+
+ get_random_bytes(buf, sizeof(buf));
+ uuid_unpack(buf, &uu);
+
+ /* Version and variant
+ */
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+ uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
+ | 0x4000;
+ uuid_pack(&uu, out);
+ return;
+}
+
+static const char *fmt_lower = N_("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x");
+
+static void uuid_unparse(const uuid_t uu, char *out, size_t len)
+{
+ struct uuid uuid;
+ char fmt[80];
+
+
+ sl_strlcpy(fmt, _(fmt_lower), sizeof(fmt));
+
+ uuid_unpack(uu, &uuid);
+
+ sl_snprintf (out, len, fmt,
+ uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+ uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+ uuid.node[0], uuid.node[1], uuid.node[2],
+ uuid.node[3], uuid.node[4], uuid.node[5]);
+
+ return;
+}
+
+#if defined(__linux__)
+static char * uuid_generate_random_linux(char * out, size_t len)
+{
+ FILE * fd = fopen(_("/proc/sys/kernel/random/uuid"), "r");
+
+ if (fd)
+ {
+ if (NULL != fgets(out, len, fd))
+ {
+ size_t ll = strlen(out);
+ if (ll > 0 && out[ll-1] == '\n') {
+ --ll;
+ out[ll] = '\0';
+ }
+ }
+ fclose(fd);
+ }
+ return out;
+}
+#endif
+
+static char * uuid_generate_random_gen(char * out, size_t len)
+{
+ uuid_t u;
+
+ uuid_generate_random(u);
+ uuid_unparse(u, out, len);
+
+ return out;
+}
+
+char * sh_uuid_generate_random(char * out, size_t len)
+{
+ *out = '\0';
+
+#if defined(__linux__)
+ uuid_generate_random_linux(out, len);
+ if (UUID_SIZE == strlen(out))
+ return out;
+#endif
+
+ uuid_generate_random_gen(out, len);
+ return out;
+}
+
+#include <ctype.h>
+int sh_uuid_check(const char * in)
+{
+ int i;
+ const char *cp;
+
+ if (strlen(in) != UUID_SIZE)
+ return -1;
+ for (i=0, cp = in; i <= UUID_SIZE; i++,cp++) {
+ if ((i == 8) || (i == 13) || (i == 18) ||
+ (i == 23)) {
+ if (*cp == '-')
+ continue;
+ else
+ return -1;
+ }
+ if (i== UUID_SIZE)
+ if (*cp == 0)
+ continue;
+ if (!isxdigit(*cp))
+ return -1;
+ }
+ return 0;
+}
+
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+#include <stdlib.h>
+
+static int uuid_type(const uuid_t uu)
+{
+ struct uuid uuid;
+
+ uuid_unpack(uu, &uuid);
+ return ((uuid.time_hi_and_version >> 12) & 0xF);
+}
+
+#define UUID_VARIANT_NCS 0
+#define UUID_VARIANT_DCE 1
+#define UUID_VARIANT_MICROSOFT 2
+#define UUID_VARIANT_OTHER 3
+
+#define UUID_TYPE_DCE_TIME 1
+#define UUID_TYPE_DCE_RANDOM 4
+
+static int uuid_variant(const uuid_t uu)
+{
+ struct uuid uuid;
+ int var;
+
+ uuid_unpack(uu, &uuid);
+ var = uuid.clock_seq;
+
+ if ((var & 0x8000) == 0)
+ return UUID_VARIANT_NCS;
+ if ((var & 0x4000) == 0)
+ return UUID_VARIANT_DCE;
+ if ((var & 0x2000) == 0)
+ return UUID_VARIANT_MICROSOFT;
+ return UUID_VARIANT_OTHER;
+}
+
+static int uuid_parse(const char *in, uuid_t uu)
+{
+ struct uuid uuid;
+ int i;
+ const char *cp;
+ char buf[3];
+
+ if (sh_uuid_check(in) < 0)
+ return -1;
+
+ uuid.time_low = strtoul(in, NULL, 16);
+ uuid.time_mid = strtoul(in+9, NULL, 16);
+ uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
+ uuid.clock_seq = strtoul(in+19, NULL, 16);
+ cp = in+24;
+ buf[2] = 0;
+ for (i=0; i < 6; i++) {
+ buf[0] = *cp++;
+ buf[1] = *cp++;
+ uuid.node[i] = strtoul(buf, NULL, 16);
+ }
+
+ uuid_pack(&uuid, uu);
+ return 0;
+}
+
+void Test_uuid (CuTest *tc) {
+
+ char * p; int res;
+ char out[80];
+ size_t len = sizeof(out);
+ uuid_t uu;
+ int type, variant;
+
+ p = uuid_generate_random_gen(out, len);
+ CuAssertPtrNotNull(tc, p);
+ res = strlen(p);
+ CuAssertIntEquals(tc,UUID_SIZE,res);
+ res = uuid_parse(p, uu);
+ CuAssertIntEquals(tc,0,res);
+ type = uuid_type(uu);
+ CuAssertIntEquals(tc,UUID_TYPE_DCE_RANDOM,type);
+ variant = uuid_variant(uu);
+ CuAssertIntEquals(tc,UUID_VARIANT_DCE,variant);
+
+#if defined(__linux__)
+ p = uuid_generate_random_linux(out, len);
+ CuAssertPtrNotNull(tc, p);
+ res = strlen(p);
+ CuAssertIntEquals(tc,UUID_SIZE,res);
+ res = uuid_parse(p, uu);
+ CuAssertIntEquals(tc,0,res);
+ type = uuid_type(uu);
+ CuAssertIntEquals(tc,UUID_TYPE_DCE_RANDOM,type);
+ variant = uuid_variant(uu);
+ CuAssertIntEquals(tc,UUID_VARIANT_DCE,variant);
+#endif
+
+ p = sh_uuid_generate_random(out, len);
+ CuAssertPtrNotNull(tc, p);
+ res = strlen(p);
+ CuAssertIntEquals(tc,UUID_SIZE,res);
+ res = uuid_parse(p, uu);
+ CuAssertIntEquals(tc,0,res);
+ type = uuid_type(uu);
+ CuAssertIntEquals(tc,UUID_TYPE_DCE_RANDOM,type);
+ variant = uuid_variant(uu);
+ CuAssertIntEquals(tc,UUID_VARIANT_DCE,variant);
+
+}
+#endif
diff --git a/src/sh_hash.c b/src/sh_hash.c
new file mode 100644
index 0000000..345475d
--- /dev/null
+++ b/src/sh_hash.c
@@ -0,0 +1,3264 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000, 2001, 2002 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#else
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_dbIO_int.h"
+#include "sh_dbIO.h"
+#include "sh_hash.h"
+#include "sh_error.h"
+#include "sh_tiger.h"
+#include "sh_gpg.h"
+#include "sh_unix.h"
+#include "sh_files.h"
+#include "sh_ignore.h"
+#include "sh_pthread.h"
+
+#if defined(SH_WITH_CLIENT)
+#include "sh_xfer.h"
+#endif
+
+
+#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
+
+
+#undef FIL__
+#define FIL__ _("sh_hash.c")
+
+SH_MUTEX_INIT(mutex_hash,PTHREAD_MUTEX_INITIALIZER);
+
+static char * all_items (file_type * theFile, char * fileHash, int is_new);
+
+static const char *policy[] = {
+ N_("[]"),
+ N_("[ReadOnly]"),
+ N_("[LogFiles]"),
+ N_("[GrowingLogs]"),
+ N_("[IgnoreNone]"),
+ N_("[IgnoreAll]"),
+ N_("[Attributes]"),
+ N_("[User0]"),
+ N_("[User1]"),
+ N_("[User2]"),
+ N_("[User3]"),
+ N_("[User4]"),
+ N_("[Prelink]"),
+ NULL
+};
+
+static int report_checkflags = S_FALSE;
+int set_report_checkflags(const char * c)
+{
+ return sh_util_flagval(c, &report_checkflags);
+}
+int get_report_checkflags()
+{
+ return report_checkflags;
+}
+
+
+
+const char * sh_hash_getpolicy(int class)
+{
+ if (class > 0 && class < SH_ERR_T_DIR)
+ return _(policy[class]);
+ return _("[indef]");
+}
+
+/**********************************
+ *
+ * hash table functions
+ *
+ **********************************
+ */
+
+#include "sh_hash.h"
+
+
+/**************************************************************
+ *
+ * create a file_type from a sh_file_t
+ *
+ **************************************************************/
+file_type * sh_hash_create_ft (const sh_file_t * p, char * fileHash)
+{
+ file_type * theFile;
+
+ SL_ENTER(_("sh_hash_create_ft"));
+
+ theFile = SH_ALLOC(sizeof(file_type));
+
+ sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
+ theFile->mode = p->theFile.mode;
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, ATTRBUF_SIZE);
+ theFile->attributes = p->theFile.attributes;
+#endif
+
+ sl_strlcpy(theFile->fullpath, p->fullpath, PATH_MAX);
+ if (p->linkpath != NULL /* && theFile->c_mode[0] == 'l' */)
+ {
+ theFile->link_path = sh_util_strdup(p->linkpath);
+ }
+ else
+ {
+ theFile->link_path = NULL;
+ }
+ sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
+
+ theFile->mtime = p->theFile.mtime;
+ theFile->ctime = p->theFile.ctime;
+ theFile->atime = p->theFile.atime;
+
+ theFile->size = p->theFile.size;
+
+ sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
+ theFile->group = p->theFile.group;
+ sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
+ theFile->owner = p->theFile.owner;
+
+ theFile->ino = p->theFile.ino;
+ theFile->rdev = p->theFile.rdev;
+ theFile->dev = p->theFile.dev;
+ theFile->hardlinks = p->theFile.hardlinks;
+ theFile->check_flags = p->theFile.checkflags;
+
+ if (p->attr_string)
+ theFile->attr_string = sh_util_strdup(p->attr_string);
+ else
+ theFile->attr_string = NULL;
+
+ SL_RETURN((theFile), _("sh_hash_create_ft"));
+}
+
+struct two_sh_file_t {
+ sh_file_t * prev;
+ sh_file_t * this;
+};
+
+static sh_file_t * hashsearch (const char * s);
+static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index);
+
+
+/**************************************************************
+ *
+ * >>>> The internal database <<<
+ *
+ **************************************************************/
+
+static sh_file_t * tab[TABSIZE];
+
+sh_file_t ** get_default_data_table()
+{
+ return tab;
+}
+
+/**************************************************************
+ *
+ * compute hash function
+ *
+ **************************************************************/
+
+static int hashfunc(const char *s)
+{
+ unsigned int n = 0;
+
+ for ( ; *s; s++)
+ n = 31 * n + *s;
+
+ return n & (TABSIZE - 1); /* % TABSIZE */;
+}
+
+
+int hashreport_missing( char *fullpath, int level)
+{
+ sh_file_t * p;
+ char * tmp;
+ char fileHash[KEY_LEN + 1];
+ file_type * theFile;
+ char * str;
+ char hashbuf[KEYBUF_SIZE];
+ volatile int retval;
+
+ /* -------- find the entry for the file ---------------- */
+
+ SH_MUTEX_LOCK(mutex_hash);
+
+ retval = 0;
+
+ if (sl_strlen(fullpath) <= MAX_PATH_STORE)
+ p = hashsearch(fullpath);
+ else
+ p = hashsearch( sh_tiger_hash(fullpath,
+ TIGER_DATA,
+ sl_strlen(fullpath),
+ hashbuf, sizeof(hashbuf))
+ );
+ if (p == NULL)
+ {
+ retval = -1;
+ goto unlock_and_return;
+ }
+
+ theFile = sh_hash_create_ft (p, fileHash);
+ str = all_items(theFile, fileHash, 0);
+ tmp = sh_util_safe_name(fullpath);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ if (!sh_global_check_silent)
+ sh_error_handle (level, FIL__, __LINE__, 0,
+ MSG_FI_MISS2, tmp, str);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ ++sh.statistics.files_report;
+
+ SH_FREE(tmp);
+ SH_FREE(str);
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+
+ unlock_and_return:
+ ; /* 'label at end of compound statement */
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ /* remove here to avoid second message from hash_unvisited */
+ if (retval == 0)
+ sh_hash_remove (fullpath);
+
+ return retval;
+}
+
+
+/**************************************************************
+ *
+ * search for files not visited, and check whether they exist
+ *
+ **************************************************************/
+static sh_file_t * delete_db_entry(sh_file_t *p)
+{
+ if (p->fullpath)
+ {
+ SH_FREE(p->fullpath);
+ p->fullpath = NULL;
+ }
+ if (p->linkpath)
+ {
+ SH_FREE(p->linkpath);
+ p->linkpath = NULL;
+ }
+ if (p->attr_string)
+ {
+ SH_FREE(p->attr_string);
+ p->attr_string = NULL;
+ }
+ SH_FREE(p);
+ return NULL;
+}
+
+static void hash_unvisited (int j,
+ sh_file_t *prev, sh_file_t *p, ShErrLevel level)
+{
+ struct stat buf;
+ int i;
+ char * tmp;
+ char * ptr;
+ char fileHash[KEY_LEN + 1];
+ file_type * theFile;
+ char * str;
+
+ SL_ENTER(_("hash_unvisited"));
+
+ if (p->next != NULL)
+ hash_unvisited (j, p, p->next, level);
+
+ if (p->fullpath == NULL)
+ {
+ SL_RET0(_("hash_unvisited"));
+ }
+
+ /* Not a fully qualified path, i.e. some info stored by some module
+ */
+ if (p->fullpath[0] != '/')
+ {
+ SL_RET0(_("hash_unvisited"));
+ }
+
+ /* visited flag not set: not seen;
+ * checked flag set: not seen (i.e. missing), and already checked
+ * reported flag not set: not reported yet
+ * allignore flag not set: not under IgnoreAll
+ *
+ * Files/directories under IgnoreAll are noticed as missing already
+ * during the file check.
+ */
+ if (((!SH_FFLAG_VISITED_SET(p->fflags)) || SH_FFLAG_CHECKED_SET(p->fflags))
+ && (!SH_FFLAG_REPORTED_SET(p->fflags))
+ /* && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)) */)
+ {
+ i = retry_lstat(FIL__, __LINE__, p->fullpath, &buf);
+
+ /* if file does not exist
+ */
+ if (0 != i)
+ {
+ ptr = sh_util_dirname (p->fullpath);
+ if (ptr)
+ {
+ /* If any of the parent directories is under IgnoreAll
+ */
+ if ((0 != sh_files_is_allignore(ptr)) || SH_FFLAG_ALLIGNORE_SET(p->fflags))
+ level = ShDFLevel[SH_LEVEL_ALLIGNORE];
+ SH_FREE(ptr);
+ }
+
+ /* Only report if !SH_FFLAG_CHECKED_SET
+ */
+ if (!SH_FFLAG_CHECKED_SET(p->fflags))
+ {
+ if (S_FALSE == sh_ignore_chk_del(p->fullpath))
+ {
+ tmp = sh_util_safe_name(p->fullpath);
+
+ theFile = sh_hash_create_ft (p, fileHash);
+ str = all_items(theFile, fileHash, 0);
+ if (!sh_global_check_silent)
+ sh_error_handle (level, FIL__, __LINE__, 0,
+ MSG_FI_MISS2, tmp, str);
+ ++sh.statistics.files_report;
+ SH_FREE(str);
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+
+ SH_FREE(tmp);
+ }
+ }
+
+ /* We rewrite the db on update, thus we need to keep this
+ * if the user does not want to purge it from the db.
+ */
+
+ if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) ||
+ (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(p->fullpath)))
+ {
+ /* Remove the old entry
+ */
+ if (prev == p)
+ tab[j] = p->next;
+ else
+ prev->next = p->next;
+
+ delete_db_entry(p);
+
+ SL_RET0(_("hash_unvisited"));
+ }
+ }
+ }
+
+ else if (SH_FFLAG_VISITED_SET(p->fflags) && SH_FFLAG_REPORTED_SET(p->fflags)
+ && (!SH_FFLAG_ALLIGNORE_SET(p->fflags)))
+ {
+ if (S_FALSE == sh_ignore_chk_new(p->fullpath))
+ {
+ tmp = sh_util_safe_name(p->fullpath);
+
+ theFile = sh_hash_create_ft (p, fileHash);
+ str = all_items(theFile, fileHash, 0);
+ if (!sh_global_check_silent)
+ sh_error_handle (level, FIL__, __LINE__, 0,
+ MSG_FI_MISS2, tmp, str);
+ ++sh.statistics.files_report;
+ SH_FREE(str);
+ if (theFile->attr_string)
+ SH_FREE(theFile->attr_string);
+ SH_FREE(theFile);
+
+ SH_FREE(tmp);
+ }
+
+ CLEAR_SH_FFLAG_REPORTED(p->fflags);
+ }
+
+ if (sh.flag.reportonce == S_FALSE)
+ CLEAR_SH_FFLAG_REPORTED(p->fflags);
+
+ CLEAR_SH_FFLAG_VISITED(p->fflags);
+ CLEAR_SH_FFLAG_CHECKED(p->fflags);
+ SET_SH_FFLAG_ENOENT(p->fflags);
+
+ SL_RET0(_("hash_unvisited"));
+}
+
+
+
+/*********************************************************************
+ *
+ * Search for files in the database that have been deleted from disk.
+ *
+ *********************************************************************/
+void sh_hash_unvisited (ShErrLevel level)
+{
+ int i;
+
+ SL_ENTER(_("sh_hash_unvisited"));
+
+ SH_MUTEX_LOCK(mutex_hash);
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ if (tab[i] != NULL)
+ hash_unvisited (i, tab[i], tab[i], level);
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ SL_RET0(_("hash_unvisited"));
+}
+
+/*********************************************************************
+ *
+ * Remove a single file from the database.
+ *
+ *********************************************************************/
+void sh_hash_remove_unconditional (const char * path)
+{
+ struct two_sh_file_t entries;
+ int index;
+
+ SL_ENTER(_("sh_hash_remove_unconditional"));
+
+ SH_MUTEX_LOCK(mutex_hash);
+ if (0 == hashsearch_prev (path, &entries, &index))
+ {
+ sh_file_t * p = entries.this;
+
+ /* Remove the old entry
+ */
+ if (entries.prev == p)
+ tab[index] = p->next;
+ else
+ entries.prev->next = p->next;
+
+ delete_db_entry(p);
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ SL_RET0(_("sh_hash_remove_unconditional"));
+}
+
+void sh_hash_remove (const char * path)
+{
+ SL_ENTER(_("sh_hash_remove"));
+
+ if ((sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE) ||
+ (S_TRUE == sh.flag.update && S_TRUE == sh_util_ask_update(path)))
+ {
+ sh_hash_remove_unconditional (path);
+ }
+ SL_RET0(_("sh_hash_remove"));
+}
+
+
+/*********************************************************************
+ *
+ * Search for unvisited entries in the database, custom error handler.
+ *
+ *********************************************************************/
+void sh_hash_unvisited_custom (char prefix, void(*handler)(const char * key))
+{
+ int i;
+ sh_file_t *p = NULL;
+ sh_file_t *prev = NULL;
+ sh_file_t *next = NULL;
+
+ SL_ENTER(_("sh_hash_unvisited_custom"));
+
+ SH_MUTEX_LOCK(mutex_hash);
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ if (tab[i] != NULL)
+ {
+ p = tab[i]; prev = p;
+
+ do
+ {
+ next = p->next;
+
+ if (p->fullpath &&
+ prefix == p->fullpath[0])
+ {
+ if ((!SH_FFLAG_VISITED_SET(p->fflags))
+ && (!SH_FFLAG_REPORTED_SET(p->fflags)))
+ {
+ handler(p->fullpath);
+
+ if (!SH_FFLAG_CHECKED_SET(p->fflags))
+ {
+ /* delete */
+ if (tab[i] == p)
+ {
+ tab[i] = p->next;
+ prev = tab[i];
+ next = prev;
+ }
+ else
+ {
+ prev->next = p->next;
+ next = prev->next;
+ }
+
+ p = delete_db_entry(p);
+ }
+ }
+ if (p)
+ {
+ CLEAR_SH_FFLAG_VISITED(p->fflags);
+ CLEAR_SH_FFLAG_CHECKED(p->fflags);
+ }
+ }
+ if (p)
+ prev = p;
+ p = next;
+ }
+ while (p);
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ SL_RET0(_("hash_unvisited_custom"));
+}
+
+
+/**********************************************************************
+ *
+ * delete hash array
+ *
+ **********************************************************************/
+static void hash_kill (sh_file_t *p)
+{
+ SL_ENTER(_("hash_kill"));
+
+ if (p == NULL)
+ SL_RET0(_("hash_kill"));
+
+ if (p->next != NULL)
+ hash_kill (p->next);
+
+ if (p->fullpath)
+ {
+ SH_FREE(p->fullpath);
+ p->fullpath = NULL;
+ }
+ if (p->linkpath)
+ {
+ SH_FREE(p->linkpath);
+ p->linkpath = NULL;
+ }
+ if (p->attr_string)
+ {
+ SH_FREE(p->attr_string);
+ p->attr_string = NULL;
+ }
+ SH_FREE(p);
+ p = NULL;
+ SL_RET0(_("hash_kill"));
+}
+
+
+/***********************************************************************
+ *
+ * get info out of hash array
+ *
+ ***********************************************************************/
+static sh_file_t * hashsearch (const char * s)
+{
+ sh_file_t * p;
+
+ SL_ENTER(_("hashsearch"));
+
+ if (s)
+ {
+ for (p = tab[hashfunc(s)]; p; p = p->next)
+ if ((p->fullpath != NULL) && (0 == strcmp(s, p->fullpath)))
+ SL_RETURN( p, _("hashsearch"));
+ }
+ SL_RETURN( NULL, _("hashsearch"));
+}
+
+static int hashsearch_prev (const char * s, struct two_sh_file_t * a, int * index)
+{
+ sh_file_t * this;
+ sh_file_t * prev = NULL;
+
+ SL_ENTER(_("hashsearch_prev"));
+
+ if (s)
+ {
+ *index = hashfunc(s);
+ this = tab[*index];
+ prev = this;
+
+ if (this)
+ {
+ do {
+ if ((this->fullpath != NULL) && (0 == strcmp(s, this->fullpath)))
+ {
+ a->prev = prev;
+ a->this = this;
+ SL_RETURN( 0, _("hashsearch_prev"));
+ }
+ prev = this;
+ this = this->next;
+ } while(this);
+ }
+ }
+ SL_RETURN( -1, _("hashsearch"));
+}
+
+
+/***********************************************************************
+ *
+ * insert into hash array
+ *
+ ***********************************************************************/
+void hashinsert (sh_file_t * mtab[TABSIZE], sh_file_t * s)
+{
+ sh_file_t * p;
+ sh_file_t * q;
+ int key;
+
+ SL_ENTER(_("hashinsert"));
+
+ key = hashfunc(s->fullpath);
+
+ if (mtab[key] == NULL)
+ {
+ mtab[key] = s;
+ mtab[key]->next = NULL;
+ SL_RET0(_("hashinsert"));
+ }
+ else
+ {
+ p = mtab[key];
+ while (1)
+ {
+ if (p && p->fullpath && 0 == strcmp(s->fullpath, p->fullpath))
+ {
+ q = p->next;
+ SH_FREE(p->fullpath);
+ if(p->linkpath) SH_FREE(p->linkpath);
+ if(p->attr_string) SH_FREE(p->attr_string);
+ memcpy(p, s, sizeof(sh_file_t));
+ p->next = q;
+ SH_FREE(s); s = NULL;
+ SL_RET0(_("hashinsert"));
+ }
+ else if (p && p->next == NULL)
+ {
+ p->next = s;
+ p->next->next = NULL;
+ SL_RET0(_("hashinsert"));
+ }
+ if (p)
+ p = p->next;
+ else /* cannot really happen, but llvm/clang does not know */
+ break;
+ }
+ }
+ /* notreached */
+}
+
+
+
+/******************************************************************
+ *
+ * ------- Check functions -------
+ *
+ ******************************************************************/
+
+static int IsInit = 0;
+
+void sh_hash_set_initialized()
+{
+ IsInit = 1;
+ return;
+}
+
+int sh_hash_get_initialized()
+{
+ return IsInit;
+}
+
+
+/******************************************************************
+ *
+ * Initialize
+ *
+ ******************************************************************/
+void sh_hash_init ()
+{
+ volatile int retval = 0;
+ volatile int exitval = EXIT_SUCCESS;
+
+ SL_ENTER(_("sh_hash_init"));
+
+ if ( sh.flag.checkSum == SH_CHECK_INIT )
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Attempt to load the baseline database during initialisation. This is an internal error, please report it to the developer.\n"));
+ SH_ABORT;
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ SH_MUTEX_LOCK(mutex_hash);
+
+ if (IsInit == 1)
+ {
+ goto unlock_and_return;
+ }
+
+ /* Initialization completed.
+ */
+ retval = sh_dbIO_load_db(tab);
+
+ if (0 == retval)
+ IsInit = 1;
+ else
+ exitval = EXIT_FAILURE;
+
+ unlock_and_return:
+ ; /* 'label at end of compound statement */
+ SH_MUTEX_UNLOCK(mutex_hash);
+ if (retval == 0)
+ {
+ SL_RET0(_("sh_hash_init"));
+ }
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
+ aud_exit (FIL__, __LINE__, exitval);
+}
+
+void sh_hash_init_and_checksum()
+{
+ TPT((0, FIL__, __LINE__, _("msg=<Get checksum of the database.>\n")))
+ if (sh.flag.checkSum == SH_CHECK_CHECK)
+ {
+ if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
+ {
+ char hashbuf[KEYBUF_SIZE];
+ (void) sl_strlcpy(sh.data.hash,
+ sh_tiger_hash (file_path('D', 'R'),
+ TIGER_FILE, TIGER_NOLIM,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+
+ /* this eventually fetches the file from server to get checksum
+ */
+ sh_hash_init ();
+ }
+ return;
+}
+
+/*****************************************************************
+ *
+ * delete hash array
+ *
+ *****************************************************************/
+void sh_hash_hashdelete ()
+{
+ int i;
+
+ SL_ENTER(_("sh_hash_hashdelete"));
+
+ /* need deadlock detection here if called from exit handler
+ */
+ SH_MUTEX_TRYLOCK(mutex_hash);
+
+ if (IsInit == 0)
+ goto unlock_and_exit;
+
+ for (i = 0; i < TABSIZE; ++i)
+ if (tab[i] != NULL)
+ {
+ hash_kill (tab[i]);
+ tab[i] = NULL;
+ }
+ IsInit = 0;
+
+ unlock_and_exit:
+ ; /* 'label at end of compound statement */
+ SH_MUTEX_TRYLOCK_UNLOCK(mutex_hash);
+
+ SL_RET0(_("sh_hash_hashdelete"));
+}
+
+static int sh_loosedircheck = S_FALSE;
+
+int sh_hash_loosedircheck(const char * str)
+{
+ return sh_util_flagval(str, &sh_loosedircheck);
+}
+
+
+
+
+/*********************************************************************
+ *
+ * Check whether a file is present in the database.
+ *
+ *********************************************************************/
+static sh_file_t * sh_hash_have_it_int (const char * newname)
+{
+ sh_file_t * p;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_hash_have_it_int"));
+
+ if (newname == NULL)
+ SL_RETURN( (NULL), _("sh_hash_have_it_int"));
+
+ if (sl_strlen(newname) <= MAX_PATH_STORE)
+ p = hashsearch(newname);
+ else
+ p = hashsearch ( sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
+ hashbuf, sizeof(hashbuf)) );
+ if (p == NULL)
+ SL_RETURN( (NULL), _("sh_hash_have_it_int"));
+
+ SL_RETURN( (p), _("sh_hash_have_it_int"));
+}
+
+int sh_hash_have_it (const char * newname)
+{
+ sh_file_t * p;
+ int retval;
+
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK(mutex_hash);
+
+ retval = 0;
+
+ p = sh_hash_have_it_int (newname);
+
+ if (!p)
+ retval = (-1);
+ else if ((!SH_FFLAG_ALLIGNORE_SET(p->fflags)) &&
+ (p->modi_mask & MODI_CHK) != 0 &&
+ (p->modi_mask & MODI_MOD) != 0)
+ retval = 1;
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ return retval;
+}
+
+int sh_hash_get_it (const char * newname, file_type * tmpFile, char * fileHash)
+{
+ sh_file_t * p;
+ int retval;
+
+ if (IsInit != 1)
+ sh_hash_init();
+
+ tmpFile->link_path = NULL;
+ tmpFile->attr_string = NULL;
+
+ SH_MUTEX_LOCK(mutex_hash);
+
+ retval = (-1);
+
+ p = sh_hash_have_it_int (newname);
+ if (p)
+ {
+ sl_strlcpy(tmpFile->fullpath, p->fullpath, PATH_MAX);
+ if (p->linkpath)
+ tmpFile->link_path = sh_util_strdup (p->linkpath);
+ tmpFile->size = p->theFile.size;
+ tmpFile->mtime = p->theFile.mtime;
+ tmpFile->ctime = p->theFile.ctime;
+ tmpFile->atime = p->theFile.atime;
+
+ if (NULL != fileHash)
+ sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
+
+ tmpFile->attr_string = NULL;
+ retval = 0;
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+
+ return retval;
+}
+
+int sh_hash_getflags (char * filename)
+{
+ sh_file_t * p;
+ int retval = 0;
+
+ if ( sh.flag.checkSum != SH_CHECK_INIT )
+ {
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK(mutex_hash);
+ p = sh_hash_have_it_int (filename);
+ if (p)
+ retval = p->fflags;
+ else
+ retval = -1;
+ SH_MUTEX_UNLOCK(mutex_hash);
+ }
+ return retval;
+}
+
+int sh_hash_setflags (char * filename, int flags)
+{
+ sh_file_t * p;
+ int retval = 0;
+
+ if ( sh.flag.checkSum != SH_CHECK_INIT )
+ {
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK(mutex_hash);
+ p = sh_hash_have_it_int (filename);
+ if (p)
+ {
+ p->fflags = flags;
+ retval = 0;
+ }
+ else
+ retval = -1;
+ SH_MUTEX_UNLOCK(mutex_hash);
+ }
+ return retval;
+}
+
+/* needs lock to be threadsafe
+ */
+void sh_hash_set_flag (char * filename, int flag_to_set)
+{
+ sh_file_t * p;
+
+ if ( sh.flag.checkSum != SH_CHECK_INIT )
+ {
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK(mutex_hash);
+ p = sh_hash_have_it_int (filename);
+ if (p)
+ {
+ p->fflags |= flag_to_set;
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+ }
+ return;
+}
+
+/* needs lock to be threadsafe
+ */
+void sh_hash_clear_flag (char * filename, int flag_to_clear)
+{
+ sh_file_t * p;
+
+ if ( sh.flag.checkSum != SH_CHECK_INIT )
+ {
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK(mutex_hash);
+ p = sh_hash_have_it_int (filename);
+ if (p)
+ {
+ p->fflags &= ~flag_to_clear;
+ }
+ SH_MUTEX_UNLOCK(mutex_hash);
+ }
+ return;
+}
+
+
+/*****************************************************************
+ *
+ * Set a file's status to 'visited'. This is required for
+ * files that should be ignored, and may be present in the
+ * database, but not on disk.
+ *
+ *****************************************************************/
+static int sh_hash_set_visited_int (char * newname, int flag)
+{
+ sh_file_t * p;
+ char hashbuf[KEYBUF_SIZE];
+ int retval;
+
+ SL_ENTER(_("sh_hash_set_visited_int"));
+
+ if (newname == NULL)
+ SL_RETURN((-1), _("sh_hash_set_visited_int"));
+
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK(mutex_hash);
+
+ if (sl_strlen(newname) <= MAX_PATH_STORE)
+ p = hashsearch(newname);
+ else
+ p = hashsearch (sh_tiger_hash(newname, TIGER_DATA, sl_strlen(newname),
+ hashbuf, sizeof(hashbuf)));
+
+ if (p)
+ {
+ if (flag == SH_FFLAG_CHECKED)
+ {
+ CLEAR_SH_FFLAG_REPORTED(p->fflags);
+ CLEAR_SH_FFLAG_VISITED(p->fflags);
+ SET_SH_FFLAG_CHECKED(p->fflags);
+ }
+ else
+ {
+ SET_SH_FFLAG_VISITED(p->fflags);
+ CLEAR_SH_FFLAG_CHECKED(p->fflags);
+ if (flag == SH_FFLAG_REPORTED)
+ SET_SH_FFLAG_REPORTED(p->fflags);
+ else
+ CLEAR_SH_FFLAG_REPORTED(p->fflags);
+ }
+ retval = 0;
+ }
+ else
+ retval = -1;
+
+ SH_MUTEX_UNLOCK(mutex_hash);
+ SL_RETURN((retval), _("sh_hash_set_visited_int"));
+}
+
+
+/* cause the record to be deleted without a 'missing' message
+ */
+int sh_hash_set_missing (char * newname)
+{
+ int i;
+ SL_ENTER(_("sh_hash_set_missing"));
+
+ i = sh_hash_set_visited_int(newname, SH_FFLAG_CHECKED);
+
+ if (sh.flag.checkSum != SH_CHECK_INIT) {
+ sh_hash_remove(newname);
+ }
+
+ SL_RETURN(i, _("sh_hash_set_missing"));
+}
+
+/* mark the file as visited and reported
+ */
+int sh_hash_set_visited (char * newname)
+{
+ int i;
+ SL_ENTER(_("sh_hash_set_visited"));
+ i = sh_hash_set_visited_int(newname, SH_FFLAG_REPORTED);
+ SL_RETURN(i, _("sh_hash_set_visited"));
+}
+
+/* mark the file as visited and NOT reported
+ * used to avoid deletion of file from internal database
+ */
+int sh_hash_set_visited_true (char * newname)
+{
+ int i;
+ SL_ENTER(_("sh_hash_set_visited_true"));
+ i = sh_hash_set_visited_int(newname, 0);
+ SL_RETURN(i, _("sh_hash_set_visited_true"));
+}
+
+
+/******************************************************************
+ *
+ * Data entry for arbitrary data into database
+ *
+ ******************************************************************/
+
+void sh_hash_push2db (const char * key, struct store2db * save)
+{
+ int i = 0;
+ char * p;
+ char i2h[2];
+ file_type * tmpFile = SH_ALLOC(sizeof(file_type));
+
+ int size = save->size;
+ unsigned char * str = save->str;
+
+
+ tmpFile->attr_string = NULL;
+ tmpFile->link_path = NULL;
+
+ sl_strlcpy(tmpFile->fullpath, key, PATH_MAX);
+ tmpFile->size = save->val0;
+ tmpFile->mtime = save->val1;
+ tmpFile->ctime = save->val2;
+ tmpFile->atime = save->val3;
+
+ tmpFile->mode = 0;
+ tmpFile->owner = 0;
+ tmpFile->group = 0;
+ sl_strlcpy(tmpFile->c_owner, _("root"), 5);
+ sl_strlcpy(tmpFile->c_group, _("root"), 5);
+
+ tmpFile->check_flags = 0;
+
+ if ((str != NULL) && (size < (PATH_MAX/2)-1))
+ {
+ tmpFile->c_mode[0] = 'l';
+ tmpFile->c_mode[1] = 'r'; tmpFile->c_mode[2] = 'w';
+ tmpFile->c_mode[3] = 'x'; tmpFile->c_mode[4] = 'r';
+ tmpFile->c_mode[5] = 'w'; tmpFile->c_mode[6] = 'x';
+ tmpFile->c_mode[7] = 'r'; tmpFile->c_mode[8] = 'w';
+ tmpFile->c_mode[9] = 'x'; tmpFile->c_mode[10] = '\0';
+ tmpFile->link_path = SH_ALLOC((size * 2) + 2);
+ for (i = 0; i < size; ++i)
+ {
+ p = sh_util_charhex (str[i],i2h);
+ tmpFile->link_path[2*i] = p[0];
+ tmpFile->link_path[2*i+1] = p[1];
+ tmpFile->link_path[2*i+2] = '\0';
+ }
+ }
+ else
+ {
+ for (i = 0; i < 10; ++i)
+ tmpFile->c_mode[i] = '-';
+ tmpFile->c_mode[10] = '\0';
+ tmpFile->link_path = sh_util_strdup("-");
+ }
+
+ if (sh.flag.checkSum == SH_CHECK_INIT)
+ sh_dbIO_data_write (tmpFile,
+ (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
+ else
+ sh_hash_pushdata_memory (tmpFile,
+ (save->checksum[0] == '\0') ? SH_KEY_NULL : save->checksum);
+
+ if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
+ SH_FREE(tmpFile);
+ return;
+}
+
+extern int sh_util_hextobinary (char * binary, char * hex, int bytes);
+
+char * sh_hash_db2pop (const char * key, struct store2db * save)
+{
+ size_t len;
+ char * p;
+ int i;
+ char * retval = NULL;
+ char fileHash[KEY_LEN+1];
+ file_type * tmpFile = SH_ALLOC(sizeof(file_type));
+
+ save->size = 0;
+
+ if (0 == sh_hash_get_it (key, tmpFile, fileHash))
+ {
+ save->val0 = tmpFile->size;
+ save->val1 = tmpFile->mtime;
+ save->val2 = tmpFile->ctime;
+ save->val3 = tmpFile->atime;
+
+ sl_strlcpy(save->checksum, fileHash, KEY_LEN+1);
+
+ if (tmpFile->link_path && tmpFile->link_path[0] != '-')
+ {
+ len = strlen(tmpFile->link_path);
+
+ p = SH_ALLOC((len/2)+1);
+ i = sh_util_hextobinary (p, tmpFile->link_path, len);
+
+ if (i == 0)
+ {
+ save->size = (len/2);
+ p[save->size] = '\0';
+ retval = p;
+ }
+ else
+ {
+ SH_FREE(p);
+ save->size = 0;
+ }
+ }
+ else
+ {
+ save->size = 0;
+ }
+ }
+ else
+ {
+ save->size = -1;
+ save->val0 = 0;
+ save->val1 = 0;
+ save->val2 = 0;
+ save->val3 = 0;
+ }
+ if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
+ SH_FREE(tmpFile);
+ return retval;
+}
+
+
+
+
+/******************************************************************
+ *
+ * Data entry in hash table
+ *
+ ******************************************************************/
+sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash)
+{
+ sh_file_t * fp;
+ sh_filestore_t p;
+
+ size_t len;
+ char * fullpath;
+ char * linkpath;
+ char * attr_string = NULL;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_hash_push_int"));
+
+ fp = SH_ALLOC(sizeof(sh_file_t));
+
+ p.mark = REC_MAGIC;
+ if (buf->attr_string)
+ p.mark |= REC_FLAGS_ATTR;
+ sl_strlcpy(p.c_mode, buf->c_mode, 11);
+ sl_strlcpy(p.c_group, buf->c_group, GROUP_MAX+1);
+ sl_strlcpy(p.c_owner, buf->c_owner, USER_MAX+1);
+ sl_strlcpy(p.checksum, fileHash, KEY_LEN+1);
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_strlcpy(p.c_attributes, buf->c_attributes, 13);
+#endif
+
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ p.attributes = (UINT32) buf->attributes;
+#endif
+ p.linkmode = (UINT32) buf->linkmode;
+ p.hardlinks = (UINT32) buf->hardlinks;
+ p.dev = (UINT64) buf->dev;
+ p.rdev = (UINT64) buf->rdev;
+ p.mode = (UINT32) buf->mode;
+ p.ino = (UINT32) buf->ino;
+ p.size = (UINT64) buf->size;
+ p.mtime = (UINT64) buf->mtime;
+ p.atime = (UINT64) buf->atime;
+ p.ctime = (UINT64) buf->ctime;
+ p.owner = (UINT32) buf->owner;
+ p.group = (UINT32) buf->group;
+
+ p.checkflags = (UINT32) buf->check_flags;
+
+ memcpy( &(*fp).theFile, &p, sizeof(sh_filestore_t) );
+ fp->fflags = 0; /* init fflags */
+ fp->modi_mask = 0L;
+
+ if (buf->attr_string)
+ attr_string = sh_util_strdup(buf->attr_string);
+ fp->attr_string = attr_string;
+
+ len = sl_strlen(buf->fullpath);
+ if (len <= MAX_PATH_STORE)
+ {
+ fullpath = SH_ALLOC(len+1);
+ sl_strlcpy(fullpath, buf->fullpath, len+1);
+ }
+ else
+ {
+ fullpath = SH_ALLOC(KEY_LEN + 1);
+ sl_strlcpy(fullpath,
+ sh_tiger_hash (buf->fullpath, TIGER_DATA, len,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+ fp->fullpath = fullpath;
+
+ if (buf->link_path)
+ {
+ len = sl_strlen(buf->link_path);
+ if (len <= MAX_PATH_STORE)
+ {
+ linkpath = SH_ALLOC(len+1);
+ sl_strlcpy(linkpath, buf->link_path, len+1);
+ }
+ else
+ {
+ linkpath = SH_ALLOC(KEY_LEN + 1);
+ sl_strlcpy(linkpath,
+ sh_tiger_hash (buf->link_path, TIGER_DATA, len,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+ fp->linkpath = linkpath;
+ }
+ else
+ fp->linkpath = NULL;
+
+ SL_RETURN( fp, _("sh_hash_push_int"));
+}
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#else
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#endif
+
+#ifndef PRIu64
+#ifdef HAVE_LONG_32
+#define PRIu64 "llu"
+#else
+#define PRIu64 "lu"
+#endif
+#endif
+
+char * sh_hash_size_format()
+{
+ static char form_rval[81];
+
+ SL_ENTER(_("sh_hash_size_format"));
+
+
+#ifdef SH_USE_XML
+ sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
+ _("size_old=\"%"), PRIu64, _("\" size_new=\"%"), PRIu64, "\" ");
+#else
+ sl_snprintf(form_rval, 80, _("%s%s%s%s%s"),
+ _("size_old=<%"), PRIu64, _(">, size_new=<%"), PRIu64, ">, ");
+#endif
+
+ SL_RETURN( form_rval, _("sh_hash_size_format"));
+}
+
+
+#ifdef SH_USE_XML
+static char * all_items (file_type * theFile, char * fileHash, int is_new)
+{
+ char timstr1c[32];
+ char timstr1a[32];
+ char timstr1m[32];
+
+ char * tmp_lnk;
+ char * format;
+
+ char * tmp = SH_ALLOC(SH_MSG_BUF);
+ char * msg = SH_ALLOC(SH_MSG_BUF);
+
+ tmp[0] = '\0';
+ msg[0] = '\0';
+
+ if (report_checkflags != S_FALSE)
+ {
+ if (is_new)
+ format = _("checkflags_new=\"0%lo\" ");
+ else
+ format = _("checkflags_old=\"0%lo\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ (unsigned long) theFile->check_flags);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ if (is_new)
+ format = _("mode_new=\"%s\" attr_new=\"%s\" imode_new=\"%ld\" iattr_new=\"%ld\" ");
+ else
+ format = _("mode_old=\"%s\" attr_old=\"%s\" imode_old=\"%ld\" iattr_old=\"%ld\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_mode,
+ theFile->c_attributes,
+ (long) theFile->mode,
+ (long) theFile->attributes
+ );
+#else
+ if (is_new)
+ format = _("mode_new=\"%s\" imode_new=\"%ld\" ");
+ else
+ format = _("mode_old=\"%s\" imode_old=\"%ld\" ");
+
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_mode,
+ (long) theFile->mode
+ );
+#endif
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (is_new)
+ format = _("hardlinks_new=\"%lu\" ");
+ else
+ format = _("hardlinks_old=\"%lu\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ (unsigned long) theFile->hardlinks);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ format = _("idevice_new=\"%lu\" ");
+ else
+ format = _("idevice_old=\"%lu\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ format = _("inode_new=\"%lu\" ");
+ else
+ format = _("inode_old=\"%lu\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ /*
+ * also report device for prelude
+ */
+#if defined(HAVE_LIBPRELUDE)
+ if (is_new)
+ format = _("dev_new=\"%lu,%lu\" ");
+ else
+ format = _("dev_old=\"%lu,%lu\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ (unsigned long) major(theFile->dev),
+ (unsigned long) minor(theFile->dev));
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+#endif
+
+
+ if (is_new)
+ format = _("owner_new=\"%s\" iowner_new=\"%ld\" ");
+ else
+ format = _("owner_old=\"%s\" iowner_old=\"%ld\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_owner, (long) theFile->owner);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ format = _("group_new=\"%s\" igroup_new=\"%ld\" ");
+ else
+ format = _("group_old=\"%s\" igroup_old=\"%ld\" ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_group, (long) theFile->group);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
+ (UINT64) 0, (UINT64) theFile->size);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
+ (UINT64) theFile->size, (UINT64) 0);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=\"%s\" "), timstr1c);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" "), timstr1c);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=\"%s\" "), timstr1a);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" "), timstr1a);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=\"%s\" "), timstr1m);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" "), timstr1m);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=\"%s\" "), fileHash);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=\"%s\" "), fileHash);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (theFile->c_mode[0] == 'l' ||
+ (theFile->link_path != NULL && theFile->link_path[0] != '-'))
+ {
+ tmp_lnk = sh_util_safe_name(theFile->link_path);
+ if (tmp_lnk)
+ {
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("link_new=\"%s\" "), tmp_lnk);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" "), tmp_lnk);
+ SH_FREE(tmp_lnk);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+ }
+
+ if (theFile->attr_string)
+ {
+ tmp_lnk = sh_util_safe_name(theFile->attr_string);
+ if (tmp_lnk)
+ {
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("acl_new=\"%s\" "), tmp_lnk);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("acl_old=\"%s\" "), tmp_lnk);
+ SH_FREE(tmp_lnk);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+ }
+
+
+ SH_FREE(tmp);
+ return (msg);
+}
+#else
+static char * all_items (file_type * theFile, char * fileHash, int is_new)
+{
+ char timstr1c[32];
+ char timstr1a[32];
+ char timstr1m[32];
+
+ char * tmp_lnk;
+ char * format;
+
+ char * tmp = SH_ALLOC(SH_MSG_BUF);
+ char * msg = SH_ALLOC(SH_MSG_BUF);
+
+ tmp[0] = '\0';
+ msg[0] = '\0';
+
+ if (report_checkflags == S_TRUE)
+ {
+ if (is_new)
+ format = _("checkflags_new=<0%lo> ");
+ else
+ format = _("checkflags_old=<0%lo> ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ (unsigned long) theFile->check_flags);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+
+
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ if (is_new)
+ format = _("mode_new=<%s>, attr_new=<%s>, imode_new=<%ld>, iattr_new=<%ld>, ");
+ else
+ format = _("mode_old=<%s>, attr_old=<%s>, imode_old=<%ld>, iattr_old=<%ld>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_mode,
+ theFile->c_attributes,
+ (long) theFile->mode,
+ (long) theFile->attributes
+ );
+#else
+ if (is_new)
+ format = _("mode_new=<%s>, imode_new=<%ld>, ");
+ else
+ format = _("mode_old=<%s>, imode_old=<%ld>, ");
+
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_mode,
+ (long) theFile->mode
+ );
+#endif
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (is_new)
+ format = _("hardlinks_new=<%lu>, ");
+ else
+ format = _("hardlinks_old=<%lu>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ (unsigned long) theFile->hardlinks);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ format = _("idevice_new=<%lu>, ");
+ else
+ format = _("idevice_old=<%lu>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->rdev);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ format = _("inode_new=<%lu>, ");
+ else
+ format = _("inode_old=<%lu>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format, (unsigned long) theFile->ino);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ /*
+ * also report device for prelude
+ */
+#if defined(HAVE_LIBPRELUDE)
+ if (is_new)
+ format = _("dev_new=<%lu,%lu>, ");
+ else
+ format = _("dev_old=<%lu,%lu>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ (unsigned long) major(theFile->dev),
+ (unsigned long) minor(theFile->dev));
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+#endif
+
+ if (is_new)
+ format = _("owner_new=<%s>, iowner_new=<%ld>, ");
+ else
+ format = _("owner_old=<%s>, iowner_old=<%ld>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_owner, (long) theFile->owner);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ format = _("group_new=<%s>, igroup_new=<%ld>, ");
+ else
+ format = _("group_old=<%s>, igroup_old=<%ld>, ");
+ sl_snprintf(tmp, SH_MSG_BUF, format,
+ theFile->c_group, (long) theFile->group);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
+ (UINT64) 0, (UINT64) theFile->size);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
+ (UINT64) theFile->size, (UINT64) 0);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+
+ (void) sh_unix_gmttime (theFile->ctime, timstr1c, sizeof(timstr1c));
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("ctime_new=<%s>, "), timstr1c);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, "), timstr1c);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ (void) sh_unix_gmttime (theFile->atime, timstr1a, sizeof(timstr1a));
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("atime_new=<%s>, "), timstr1a);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, "), timstr1a);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ (void) sh_unix_gmttime (theFile->mtime, timstr1m, sizeof(timstr1m));
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("mtime_new=<%s>, "), timstr1m);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, "), timstr1m);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _("chksum_new=<%s>"), fileHash);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _("chksum_old=<%s>"), fileHash);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (theFile->c_mode[0] == 'l' ||
+ (theFile->link_path != NULL && theFile->link_path[0] != '-'))
+ {
+ tmp_lnk = sh_util_safe_name(theFile->link_path);
+ if (tmp_lnk)
+ {
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _(", link_new=<%s> "), tmp_lnk);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _(", link_old=<%s> "), tmp_lnk);
+ SH_FREE(tmp_lnk);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+ }
+
+ if (theFile->attr_string)
+ {
+ tmp_lnk = sh_util_safe_name(theFile->attr_string);
+ if (tmp_lnk)
+ {
+ if (is_new)
+ sl_snprintf(tmp, SH_MSG_BUF, _(", acl_new=<%s> "), tmp_lnk);
+ else
+ sl_snprintf(tmp, SH_MSG_BUF, _(", acl_old=<%s> "), tmp_lnk);
+ SH_FREE(tmp_lnk);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+ }
+
+ SH_FREE(tmp);
+ return (msg);
+}
+#endif
+
+void sh_hash_pushdata_memory (file_type * theFile, char * fileHash)
+{
+ sh_file_t * p;
+
+ SL_ENTER(_("sh_hash_pushdata_memory"));
+
+ p = sh_hash_push_int(theFile, fileHash);
+ if (p)
+ {
+ SH_MUTEX_LOCK(mutex_hash);
+ hashinsert (tab, p);
+ p->modi_mask = theFile->check_flags;
+ SH_MUTEX_UNLOCK(mutex_hash);
+ }
+
+ SL_RET0(_("sh_hash_pushdata_memory"));
+}
+
+int sh_hash_is_null_file(file_type * theFile)
+{
+ if (theFile->hardlinks == SH_DEADFILE && theFile->mode == 0 &&
+ theFile->ino == 0 && theFile->ctime == 0)
+ {
+ return S_TRUE;
+ }
+ return S_FALSE;
+}
+
+int sh_hash_is_null_record(sh_filestore_t * theFile)
+{
+ if (theFile->hardlinks == SH_DEADFILE && theFile->mode == 0 &&
+ theFile->ino == 0 && theFile->ctime == 0)
+ {
+ return S_TRUE;
+ }
+ return S_FALSE;
+}
+
+void sh_hash_insert_null(char * str)
+{
+ file_type theFile = { 0, 0, {'\0'}, 0, 0, 0, 0, 0,
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ 0, {'\0'},
+#endif
+ {'\0'}, 0, {'\0'}, 0, {'\0'},
+ 0, 0, 0, 0, 0, 0, 0, NULL, 0, {'\0'}, 0, NULL
+ }; /* clang compiler bails out on standard conforming init with just {0} */
+ char fileHash[KEY_LEN+1];
+ char hashbuf[KEYBUF_SIZE];
+
+ sl_strlcpy(fileHash, SH_KEY_NULL, sizeof(fileHash));
+ theFile.hardlinks = SH_DEADFILE;
+
+ if (sl_strlen(str) < PATH_MAX)
+ sl_strlcpy(theFile.fullpath, str, PATH_MAX);
+ else
+ sl_strlcpy(theFile.fullpath,
+ sh_tiger_hash(str, TIGER_DATA, sl_strlen(str),
+ hashbuf, sizeof(hashbuf)),
+ PATH_MAX);
+
+ sh_hash_pushdata_memory(&theFile, fileHash);
+ return;
+}
+
+static int handle_notfound(int log_severity, int class,
+ file_type * theFile, char * fileHash)
+{
+ sh_file_t * p;
+ int retval = 0;
+
+ if (S_FALSE == sh_ignore_chk_new(theFile->fullpath))
+ {
+ char * tmp = sh_util_safe_name(theFile->fullpath);
+ char * str;
+
+ sh_files_fixup_mask(class, &(theFile->check_flags));
+ str = all_items (theFile, fileHash, 1);
+
+ if (!sh_global_check_silent)
+ sh_error_handle (log_severity, FIL__, __LINE__, 0,
+ MSG_FI_ADD2,
+ tmp, str);
+ ++sh.statistics.files_report;
+ SH_FREE(str);
+ SH_FREE(tmp);
+ }
+
+ if (sh.flag.reportonce == S_TRUE)
+ SET_SH_FFLAG_REPORTED(theFile->file_reported);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ p = sh_hash_push_int(theFile, fileHash);
+ if (p)
+ {
+ hashinsert (tab, p);
+ p->modi_mask = theFile->check_flags;
+ p->theFile.checkflags = p->modi_mask;
+ }
+ }
+
+ else if (S_TRUE == sh.flag.update)
+ {
+ if (S_TRUE == sh_util_ask_update (theFile->fullpath))
+ {
+ p = sh_hash_push_int(theFile, fileHash);
+ if (p)
+ {
+ hashinsert (tab, p);
+ p->modi_mask = theFile->check_flags;
+ p->theFile.checkflags = p->modi_mask;
+ }
+ }
+ else
+ retval = 1;
+ }
+ return retval;
+}
+
+/*****************************************************************
+ *
+ * Compare a file with the database status.
+ *
+ *****************************************************************/
+int sh_hash_compdata (int class, file_type * theFile, char * fileHash,
+ char * policy_override, int severity_override)
+{
+ char * msg;
+ sh_file_t * p;
+ char * tmp;
+ char * tmp_path;
+ char * tmp_lnk;
+ char * tmp_lnk_old;
+
+ char timstr1c[32];
+ char timstr2c[32];
+ char timstr1a[32];
+ char timstr2a[32];
+ char timstr1m[32];
+ char timstr2m[32];
+ char linkHash[KEY_LEN+1];
+ char * linkComp;
+ int maxcomp;
+ volatile int checksum_flag = 0;
+
+ char change_code[16];
+ int i;
+
+ unsigned long modi_mask;
+
+ char log_policy[32];
+ volatile int log_severity;
+ char hashbuf[KEYBUF_SIZE];
+ struct {
+ unsigned long oldflags;
+ unsigned long newflags;
+ } cf_report;
+
+ int retval;
+
+ SL_ENTER(_("sh_hash_compdata"));
+
+ if (IsInit != 1) sh_hash_init();
+
+ if (severity_override < 0)
+ log_severity = ShDFLevel[class];
+ else
+ log_severity = severity_override;
+
+ if (policy_override != NULL)
+ sl_strlcpy (log_policy, policy_override, 32);
+
+ /* -------- find the entry for the file ---------------- */
+
+ SH_MUTEX_LOCK(mutex_hash);
+
+ modi_mask = 0;
+ retval = 0;
+
+ if (sl_strlen(theFile->fullpath) <= MAX_PATH_STORE)
+ p = hashsearch(theFile->fullpath);
+ else
+ p = hashsearch( sh_tiger_hash(theFile->fullpath,
+ TIGER_DATA,
+ sl_strlen(theFile->fullpath),
+ hashbuf, sizeof(hashbuf))
+ );
+
+
+ /* --------- Not found in database. ------------
+ */
+
+ if (p == NULL)
+ {
+ retval = handle_notfound(log_severity, class, theFile, fileHash);
+ goto unlock_and_return;
+ }
+
+ /* --------- Skip if we don't want to report changes. ------------
+ */
+
+ if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath))
+ {
+ MODI_SET(theFile->check_flags, MODI_NOCHECK);
+ p->modi_mask = theFile->check_flags;
+ p->theFile.checkflags = p->modi_mask;
+ goto unlock_and_return;
+ }
+
+ cf_report.oldflags = p->theFile.checkflags;
+ cf_report.newflags = theFile->check_flags;
+
+ p->modi_mask = theFile->check_flags;
+ p->theFile.checkflags = p->modi_mask;
+
+ /* initialize change_code */
+ for (i = 0; i < 15; ++i)
+ change_code[i] = '-';
+ change_code[15] = '\0';
+
+ TPT ((0, FIL__, __LINE__, _("file=<%s>, cs_old=<%s>, cs_new=<%s>\n"),
+ theFile->fullpath, fileHash, p->theFile.checksum));
+
+ if ( (fileHash != NULL) &&
+ (strncmp (fileHash, p->theFile.checksum, KEY_LEN) != 0) &&
+ (theFile->check_flags & MODI_CHK) != 0)
+ {
+ checksum_flag = 1;
+
+ if ((theFile->check_flags & MODI_SGROW) == 0)
+ {
+ modi_mask |= MODI_CHK;
+ change_code[0] = 'C';
+ TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
+ }
+ else
+ {
+ if (0 != strncmp (&fileHash[KEY_LEN + 1], p->theFile.checksum, KEY_LEN))
+ {
+ if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size,
+ (UINT64) p->theFile.ino, p->theFile.checksum,
+ p->theFile.checkflags))
+ {
+ modi_mask |= MODI_CHK;
+ change_code[0] = 'C';
+ TPT ((0, FIL__, __LINE__, _("mod=<checksum>")));
+ }
+ else
+ {
+ /* logfile has been rotated */
+ p->theFile.size = theFile->size;
+ p->theFile.ino = theFile->ino;
+ sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
+ }
+ }
+ else
+ {
+ p->theFile.size = theFile->size;
+ sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
+ }
+ }
+ }
+
+ if (p->theFile.c_mode[0] == 'l')
+ {
+ if (!(theFile->link_path) &&
+ (theFile->check_flags & MODI_LNK) != 0)
+ {
+ linkComp = NULL;
+ modi_mask |= MODI_LNK;
+ change_code[1] = 'L';
+ TPT ((0, FIL__, __LINE__, _("mod=<link>")));
+ }
+ else
+ {
+ if (sl_strlen(theFile->link_path) >= MAX_PATH_STORE)
+ {
+ sl_strlcpy(linkHash,
+ sh_tiger_hash(theFile->link_path,
+ TIGER_DATA,
+ sl_strlen(theFile->link_path),
+ hashbuf, sizeof(hashbuf)),
+ MAX_PATH_STORE+1);
+ linkComp = linkHash;
+ maxcomp = KEY_LEN;
+ }
+ else
+ {
+ linkComp = theFile->link_path;
+ maxcomp = MAX_PATH_STORE;
+ }
+
+ if ( sl_strncmp (linkComp, p->linkpath, maxcomp) != 0 &&
+ (theFile->check_flags & MODI_LNK) != 0)
+ {
+ modi_mask |= MODI_LNK;
+ change_code[1] = 'L';
+ TPT ((0, FIL__, __LINE__, _("mod=<link>")));
+ }
+ }
+ }
+
+ if (p->theFile.c_mode[0] == 'c' || p->theFile.c_mode[0] == 'b')
+ {
+ if ( ( major(theFile->rdev) != major((dev_t)p->theFile.rdev) ||
+ minor(theFile->rdev) != minor((dev_t)p->theFile.rdev) ) &&
+ (theFile->check_flags & MODI_RDEV) != 0)
+ {
+ modi_mask |= MODI_RDEV;
+ change_code[2] = 'D';
+ TPT ((0, FIL__, __LINE__, _("mod=<rdev>")));
+ }
+ }
+
+ /* cast to UINT32 in case ino_t is not 32bit
+ */
+ if ( (UINT32) theFile->ino != (UINT32) p->theFile.ino &&
+ (theFile->check_flags & MODI_INO) != 0)
+ {
+ if ((theFile->check_flags & MODI_SGROW) == 0)
+ {
+ modi_mask |= MODI_INO;
+ change_code[3] = 'I';
+ TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
+ }
+ else
+ {
+ /* growing log, checksum ok but inode changed
+ */
+ if (checksum_flag == 0)
+ {
+ if (S_FALSE == sh_check_rotated_log (theFile->fullpath, (UINT64) p->theFile.size,
+ (UINT64) p->theFile.ino, p->theFile.checksum,
+ p->theFile.checkflags))
+ {
+ modi_mask |= MODI_INO;
+ change_code[3] = 'I';
+ TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
+ }
+ else
+ {
+ /* logfile has been rotated */
+ p->theFile.size = theFile->size;
+ p->theFile.ino = theFile->ino;
+ sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
+ }
+ }
+ else
+ {
+ modi_mask |= MODI_INO;
+ change_code[3] = 'I';
+ TPT ((0, FIL__, __LINE__, _("mod=<inode>")));
+ }
+ }
+ }
+
+ if ( theFile->hardlinks != (nlink_t) p->theFile.hardlinks &&
+ (theFile->check_flags & MODI_HLN) != 0)
+ {
+ modi_mask |= MODI_HLN;
+ change_code[4] = 'H';
+ TPT ((0, FIL__, __LINE__, _("mod=<hardlink>")));
+ }
+
+
+ if ( ( (theFile->mode != p->theFile.mode)
+#if defined(USE_ACL) || defined(USE_XATTR)
+ || ( (sh_unix_check_selinux|sh_unix_check_acl) &&
+ (
+ (theFile->attr_string == NULL && p->attr_string != NULL) ||
+ (theFile->attr_string != NULL && p->attr_string == NULL) ||
+ (theFile->attr_string != NULL && 0 != strcmp(theFile->attr_string, p->attr_string))
+ )
+ )
+#endif
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ || (theFile->attributes != p->theFile.attributes)
+#endif
+ )
+ && (theFile->check_flags & MODI_MOD) != 0)
+ {
+ modi_mask |= MODI_MOD;
+ change_code[5] = 'M';
+ TPT ((0, FIL__, __LINE__, _("mod=<mode>")));
+ /*
+ * report link path if switch link/no link
+ */
+ if ((theFile->check_flags & MODI_LNK) != 0 &&
+ (theFile->c_mode[0] != p->theFile.c_mode[0]) &&
+ (theFile->c_mode[0] == 'l' || p->theFile.c_mode[0] == 'l'))
+ {
+ modi_mask |= MODI_LNK;
+ change_code[1] = 'L';
+ TPT ((0, FIL__, __LINE__, _("mod=<link>")));
+ }
+ }
+
+ if ( theFile->owner != (uid_t) p->theFile.owner &&
+ (theFile->check_flags & MODI_USR) != 0)
+ {
+ modi_mask |= MODI_USR;
+ change_code[6] = 'U';
+ TPT ((0, FIL__, __LINE__, _("mod=<user>")));
+ }
+
+ if ( theFile->group != (gid_t) p->theFile.group &&
+ (theFile->check_flags & MODI_GRP) != 0)
+ {
+ modi_mask |= MODI_GRP;
+ change_code[7] = 'G';
+ TPT ((0, FIL__, __LINE__, _("mod=<group>")));
+ }
+
+
+ if ( theFile->mtime != (time_t) p->theFile.mtime &&
+ (theFile->check_flags & MODI_MTM) != 0)
+ {
+ modi_mask |= MODI_MTM;
+ change_code[8] = 'T';
+ TPT ((0, FIL__, __LINE__, _("mod=<mtime>")));
+ }
+
+ if ( (theFile->check_flags & MODI_ATM) != 0 &&
+ theFile->atime != (time_t) p->theFile.atime)
+ {
+ modi_mask |= MODI_ATM;
+ change_code[8] = 'T';
+ TPT ((0, FIL__, __LINE__, _("mod=<atime>")));
+ }
+
+
+ /* Resetting the access time will set a new ctime. Thus, either we ignore
+ * the access time or the ctime for NOIGNORE
+ */
+ if ( theFile->ctime != (time_t) p->theFile.ctime &&
+ (theFile->check_flags & MODI_CTM) != 0)
+ {
+ modi_mask |= MODI_CTM;
+ change_code[8] = 'T';
+ TPT ((0, FIL__, __LINE__, _("mod=<ctime>")));
+ }
+
+ if ( theFile->size != (off_t) p->theFile.size &&
+ (theFile->check_flags & MODI_SIZ) != 0)
+ {
+ if ((theFile->check_flags & MODI_SGROW) == 0 ||
+ theFile->size < (off_t) p->theFile.size)
+ {
+ modi_mask |= MODI_SIZ;
+ change_code[9] = 'S';
+ TPT ((0, FIL__, __LINE__, _("mod=<size>")));
+ }
+ }
+ change_code[10] = '\0';
+
+ /* --- Directories special case ---
+ */
+ if (p->theFile.c_mode[0] == 'd' &&
+ 0 == (modi_mask & ~(MODI_SIZ|MODI_ATM|MODI_CTM|MODI_MTM)) &&
+ sh_loosedircheck == S_TRUE)
+ {
+ modi_mask = 0;
+ }
+
+ /* --- Report full details. ---
+ */
+ if (modi_mask != 0 && sh.flag.fulldetail == S_TRUE)
+ {
+ if ((theFile->check_flags & MODI_ATM) == 0)
+ modi_mask = MASK_READONLY_;
+ else
+ modi_mask = MASK_NOIGNORE_;
+ }
+
+ /* --- Report on modified files. ---
+ */
+ if (modi_mask != 0 && (!SH_FFLAG_REPORTED_SET(p->fflags)))
+ {
+ tmp = SH_ALLOC(SH_MSG_BUF);
+ msg = SH_ALLOC(SH_MSG_BUF);
+ msg[0] = '\0';
+
+ sh_files_fixup_mask(class, &(cf_report.newflags));
+
+ if ( (report_checkflags != S_FALSE) && (cf_report.oldflags != cf_report.newflags))
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("checkflags_old=\"0%lo\" checkflags_new=\"0%lo\" "),
+#else
+ _("checkflags_old=<0%lo>, checkflags_new=<0%lo>, "),
+#endif
+ cf_report.oldflags, cf_report.newflags);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+
+ if ( ((modi_mask & MODI_MOD) != 0)
+#if defined(HAVE_LIBPRELUDE)
+ || ((modi_mask & MODI_USR) != 0)
+ || ((modi_mask & MODI_GRP) != 0)
+#endif
+ )
+ {
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("mode_old=\"%s\" mode_new=\"%s\" attr_old=\"%s\" attr_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" iattr_old=\"%ld\" iattr_new=\"%ld\" "),
+#else
+ _("mode_old=<%s>, mode_new=<%s>, attr_old=<%s>, attr_new=<%s>, "),
+#endif
+ p->theFile.c_mode, theFile->c_mode,
+ p->theFile.c_attributes, theFile->c_attributes
+#ifdef SH_USE_XML
+ , (long) p->theFile.mode, (long) theFile->mode,
+ (long) p->theFile.attributes,
+ (long) theFile->attributes
+#endif
+ );
+#else
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF,
+ _("mode_old=\"%s\" mode_new=\"%s\" imode_old=\"%ld\" imode_new=\"%ld\" "),
+ p->theFile.c_mode, theFile->c_mode,
+ (long) p->theFile.mode, (long) theFile->mode);
+#else
+ sl_snprintf(tmp, SH_MSG_BUF, _("mode_old=<%s>, mode_new=<%s>, "),
+ p->theFile.c_mode, theFile->c_mode);
+#endif
+#endif
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+#if defined(USE_ACL) || defined(USE_XATTR)
+ if (theFile->attr_string != NULL || p->attr_string != NULL)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("acl_old=\"%s\" acl_new=\"%s\" "),
+#else
+ _("acl_old=<%s>, acl_new=<%s>, "),
+#endif
+ (p->attr_string) ? p->attr_string : _("none"),
+ (theFile->attr_string) ? theFile->attr_string : _("none"));
+
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+ }
+#endif
+
+ if ((modi_mask & MODI_MOD) != 0)
+ {
+ /*
+ * We postpone update if sh.flag.update == S_TRUE because
+ * in interactive mode the user may not accept the change.
+ */
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
+ p->theFile.mode = theFile->mode;
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_strlcpy(p->theFile.c_attributes,theFile->c_attributes,16);
+ p->theFile.attributes = theFile->attributes;
+#endif
+#if defined(USE_ACL) || defined(USE_XATTR)
+ if (p->attr_string == NULL && theFile->attr_string != NULL)
+ { p->attr_string = sh_util_strdup (theFile->attr_string); }
+ else if (p->attr_string != NULL && theFile->attr_string == NULL)
+ { SH_FREE(p->attr_string); p->attr_string = NULL; }
+ else if (theFile->attr_string != NULL && p->attr_string != NULL)
+ {
+ if (0 != strcmp(theFile->attr_string, p->attr_string))
+ {
+ SH_FREE(p->attr_string);
+ p->attr_string = sh_util_strdup (theFile->attr_string);
+ }
+ }
+#endif
+ }
+ }
+
+ }
+
+ if ((modi_mask & MODI_HLN) != 0)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("hardlinks_old=\"%lu\" hardlinks_new=\"%lu\" "),
+#else
+ _("hardlinks_old=<%lu>, hardlinks_new=<%lu>, "),
+#endif
+ (unsigned long) p->theFile.hardlinks,
+ (unsigned long) theFile->hardlinks);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.hardlinks = theFile->hardlinks;
+ }
+
+ if ((modi_mask & MODI_RDEV) != 0)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("device_old=\"%lu,%lu\" device_new=\"%lu,%lu\" idevice_old=\"%lu\" idevice_new=\"%lu\" "),
+#else
+ _("device_old=<%lu,%lu>, device_new=<%lu,%lu>, "),
+#endif
+ (unsigned long) major(p->theFile.rdev),
+ (unsigned long) minor(p->theFile.rdev),
+ (unsigned long) major(theFile->rdev),
+ (unsigned long) minor(theFile->rdev)
+#ifdef SH_USE_XML
+ , (unsigned long) p->theFile.rdev,
+ (unsigned long) theFile->rdev
+#endif
+ );
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.rdev = theFile->rdev;
+ }
+
+ if ((modi_mask & MODI_INO) != 0)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("inode_old=\"%lu\" inode_new=\"%lu\" "),
+#else
+ _("inode_old=<%lu>, inode_new=<%lu>, "),
+#endif
+ (unsigned long) p->theFile.ino,
+ (unsigned long) theFile->ino);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ p->theFile.ino = theFile->ino;
+ p->theFile.dev = theFile->dev;
+ }
+ }
+
+
+ /*
+ * also report device for prelude
+ */
+#if defined(HAVE_LIBPRELUDE)
+ if ((modi_mask & MODI_INO) != 0)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("dev_old=\"%lu,%lu\" dev_new=\"%lu,%lu\" "),
+#else
+ _("dev_old=<%lu,%lu>, dev_new=<%lu,%lu>, "),
+#endif
+ (unsigned long) major(p->theFile.dev),
+ (unsigned long) minor(p->theFile.dev),
+ (unsigned long) major(theFile->dev),
+ (unsigned long) minor(theFile->dev)
+ );
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.dev = theFile->dev;
+ }
+#endif
+
+ if ( ((modi_mask & MODI_USR) != 0)
+#if defined(HAVE_LIBPRELUDE)
+ || ((modi_mask & MODI_MOD) != 0)
+#endif
+ )
+ {
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF,
+ _("owner_old=\"%s\" owner_new=\"%s\" iowner_old=\"%ld\" iowner_new=\"%ld\" "),
+#else
+ sl_snprintf(tmp, SH_MSG_BUF,
+ _("owner_old=<%s>, owner_new=<%s>, iowner_old=<%ld>, iowner_new=<%ld>, "),
+#endif
+ p->theFile.c_owner, theFile->c_owner,
+ (long) p->theFile.owner, (long) theFile->owner
+ );
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if ((modi_mask & MODI_USR) != 0) {
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
+ p->theFile.owner = theFile->owner;
+ }
+ }
+ }
+
+ if ( ((modi_mask & MODI_GRP) != 0)
+#if defined(HAVE_LIBPRELUDE)
+ || ((modi_mask & MODI_MOD) != 0)
+#endif
+ )
+ {
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF,
+ _("group_old=\"%s\" group_new=\"%s\" igroup_old=\"%ld\" igroup_new=\"%ld\" "),
+ p->theFile.c_group, theFile->c_group,
+ (long) p->theFile.group, (long) theFile->group);
+#else
+ sl_snprintf(tmp, SH_MSG_BUF,
+ _("group_old=<%s>, group_new=<%s>, igroup_old=<%ld>, igroup_new=<%ld>, "),
+ p->theFile.c_group, theFile->c_group,
+ (long) p->theFile.group, (long) theFile->group);
+#endif
+
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if ((modi_mask & MODI_GRP) != 0) {
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
+ p->theFile.group = theFile->group;
+ }
+ }
+ }
+
+ if ((modi_mask & MODI_SIZ) != 0)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF, sh_hash_size_format(),
+ (UINT64) p->theFile.size,
+ (UINT64) theFile->size);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.size = theFile->size;
+ }
+
+ if ((modi_mask & MODI_CTM) != 0)
+ {
+ (void) sh_unix_gmttime (p->theFile.ctime, timstr1c, sizeof(timstr1c));
+ (void) sh_unix_gmttime (theFile->ctime, timstr2c, sizeof(timstr2c));
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=\"%s\" ctime_new=\"%s\" "),
+ timstr1c, timstr2c);
+#else
+ sl_snprintf(tmp, SH_MSG_BUF, _("ctime_old=<%s>, ctime_new=<%s>, "),
+ timstr1c, timstr2c);
+#endif
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.ctime = theFile->ctime;
+ }
+
+ if ((modi_mask & MODI_ATM) != 0)
+ {
+ (void) sh_unix_gmttime (p->theFile.atime, timstr1a, sizeof(timstr1a));
+ (void) sh_unix_gmttime (theFile->atime, timstr2a, sizeof(timstr2a));
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=\"%s\" atime_new=\"%s\" "),
+ timstr1a, timstr2a);
+#else
+ sl_snprintf(tmp, SH_MSG_BUF, _("atime_old=<%s>, atime_new=<%s>, "),
+ timstr1a, timstr2a);
+#endif
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.atime = theFile->atime;
+ }
+
+ if ((modi_mask & MODI_MTM) != 0)
+ {
+ (void) sh_unix_gmttime (p->theFile.mtime, timstr1m, sizeof(timstr1m));
+ (void) sh_unix_gmttime (theFile->mtime, timstr2m, sizeof(timstr2m));
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=\"%s\" mtime_new=\"%s\" "),
+ timstr1m, timstr2m);
+#else
+ sl_snprintf(tmp, SH_MSG_BUF, _("mtime_old=<%s>, mtime_new=<%s>, "),
+ timstr1m, timstr2m);
+#endif
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ p->theFile.mtime = theFile->mtime;
+ }
+
+
+ if ((modi_mask & MODI_CHK) != 0)
+ {
+ sl_snprintf(tmp, SH_MSG_BUF,
+#ifdef SH_USE_XML
+ _("chksum_old=\"%s\" chksum_new=\"%s\" "),
+#else
+ _("chksum_old=<%s>, chksum_new=<%s>, "),
+#endif
+ p->theFile.checksum, fileHash);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
+ if ((theFile->check_flags & MODI_SGROW) != 0)
+ p->theFile.size = theFile->size;
+ }
+
+
+ if (theFile->c_mode[0] != 'l' && theFile->link_path &&
+ strlen(theFile->link_path) > 2)
+ modi_mask |= MODI_LNK;
+ }
+
+
+ if ((modi_mask & MODI_LNK) != 0 /* && theFile->c_mode[0] == 'l' */)
+ {
+ if (theFile->link_path)
+ tmp_lnk = sh_util_safe_name(theFile->link_path);
+ else
+ tmp_lnk = sh_util_strdup("-");
+ if (p->linkpath)
+ tmp_lnk_old = sh_util_safe_name(p->linkpath);
+ else
+ tmp_lnk_old = sh_util_strdup("-");
+#ifdef SH_USE_XML
+ sl_snprintf(tmp, SH_MSG_BUF, _("link_old=\"%s\" link_new=\"%s\" "),
+ tmp_lnk_old, tmp_lnk);
+#else
+ sl_snprintf(tmp, SH_MSG_BUF, _("link_old=<%s>, link_new=<%s>, "),
+ tmp_lnk_old, tmp_lnk);
+#endif
+ SH_FREE(tmp_lnk);
+ SH_FREE(tmp_lnk_old);
+ sl_strlcat(msg, tmp, SH_MSG_BUF);
+
+ if (sh.flag.reportonce == S_TRUE && sh.flag.update == S_FALSE)
+ {
+ if (p->linkpath != NULL)
+ SH_FREE(p->linkpath);
+ if (!(theFile->link_path))
+ p->linkpath = sh_util_strdup("-");
+ else
+ p->linkpath = sh_util_strdup(theFile->link_path);
+ }
+ }
+
+ if (MODI_AUDIT_ENABLED(theFile->check_flags))
+ {
+ char result[256];
+
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__,
+ 0, MSG_E_SUBGPATH,
+ _("Fetching audit record"),
+ _("sh_hash"), theFile->fullpath );
+
+ if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, theFile->ctime, result, sizeof(result)))
+ {
+#ifdef SH_USE_XML
+ sl_strlcat(msg, _("obj=\""), SH_MSG_BUF);
+#else
+ sl_strlcat(msg, _("obj=<"), SH_MSG_BUF);
+#endif
+
+ sl_strlcat(msg, result, SH_MSG_BUF);
+
+#ifdef SH_USE_XML
+ sl_strlcat(msg, _("\" "), SH_MSG_BUF);
+#else
+ sl_strlcat(msg, _(">"), SH_MSG_BUF);
+#endif
+ }
+ }
+
+ /****************************************************
+ *
+ * REPORT on file change
+ *
+ ****************************************************/
+ tmp_path = sh_util_safe_name(theFile->fullpath);
+ if (!sh_global_check_silent)
+ sh_error_handle(log_severity, FIL__, __LINE__,
+ (long) modi_mask, MSG_FI_CHAN,
+ (policy_override == NULL) ? _(policy[class]):log_policy,
+ change_code, tmp_path, msg);
+ ++sh.statistics.files_report;
+
+ SH_FREE(tmp_path);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+
+ if (S_TRUE == sh.flag.update)
+ {
+ if (S_FALSE == sh_util_ask_update(theFile->fullpath))
+ {
+ /* user does not want to update, thus we replace
+ * with data from the baseline database
+ */
+ sl_strlcpy(theFile->c_mode, p->theFile.c_mode, 11);
+ theFile->mode = p->theFile.mode;
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_strlcpy(theFile->c_attributes, p->theFile.c_attributes, 16);
+ theFile->attributes = p->theFile.attributes;
+#endif
+#if defined(USE_ACL) || defined(USE_XATTR)
+ if (theFile->attr_string == NULL && p->attr_string != NULL)
+ { theFile->attr_string = sh_util_strdup (p->attr_string); }
+ else if (theFile->attr_string != NULL && p->attr_string == NULL)
+ { SH_FREE(theFile->attr_string); theFile->attr_string = NULL; }
+ else if (theFile->attr_string != NULL && p->attr_string != NULL)
+ {
+ if (0 != strcmp(theFile->attr_string, p->attr_string))
+ {
+ SH_FREE(theFile->attr_string);
+ theFile->attr_string = sh_util_strdup (p->attr_string);
+ }
+ }
+#endif
+
+ if (theFile->c_mode[0] == 'l') /* c_mode is already copied */
+ {
+ if (theFile->link_path)
+ SH_FREE(theFile->link_path);
+ if (p->linkpath)
+ theFile->link_path = sh_util_strdup(p->linkpath);
+ else
+ theFile->link_path = sh_util_strdup("-");
+ }
+ else
+ {
+ if (theFile->link_path)
+ SH_FREE(theFile->link_path);
+ if (p->linkpath)
+ theFile->link_path = sh_util_strdup(p->linkpath);
+ else
+ theFile->link_path = NULL;
+ }
+
+ sl_strlcpy(fileHash, p->theFile.checksum, KEY_LEN+1);
+
+ theFile->mtime = p->theFile.mtime;
+ theFile->ctime = p->theFile.ctime;
+ theFile->atime = p->theFile.atime;
+
+ theFile->size = p->theFile.size;
+
+ sl_strlcpy(theFile->c_group, p->theFile.c_group, GROUP_MAX+2);
+ theFile->group = p->theFile.group;
+ sl_strlcpy(theFile->c_owner, p->theFile.c_owner, USER_MAX+2);
+ theFile->owner = p->theFile.owner;
+
+ theFile->ino = p->theFile.ino;
+ theFile->rdev = p->theFile.rdev;
+ theFile->dev = p->theFile.dev;
+ theFile->hardlinks = p->theFile.hardlinks;
+
+ SET_SH_FFLAG_VISITED(p->fflags);
+ CLEAR_SH_FFLAG_CHECKED(p->fflags);
+ retval = 1;
+ goto unlock_and_return;
+ }
+ else /* if (sh.flag.reportonce == S_TRUE) */
+ {
+ /* we replace the data in the in-memory copy of the
+ * baseline database, because otherwise we would get
+ * another warning if the suidcheck runs
+ */
+ sl_strlcpy(p->theFile.c_mode, theFile->c_mode, 11);
+ p->theFile.mode = theFile->mode;
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+ sl_strlcpy(p->theFile.c_attributes, theFile->c_attributes, 16);
+ p->theFile.attributes = theFile->attributes;
+#endif
+#if defined(USE_ACL) || defined(USE_XATTR)
+ if (p->attr_string == NULL && theFile->attr_string != NULL)
+ { p->attr_string = sh_util_strdup (theFile->attr_string); }
+ else if (p->attr_string != NULL && theFile->attr_string == NULL)
+ { SH_FREE(p->attr_string); p->attr_string = NULL; }
+ else if (theFile->attr_string != NULL && p->attr_string != NULL)
+ {
+ if (0 != strcmp(theFile->attr_string, p->attr_string))
+ {
+ SH_FREE(p->attr_string);
+ p->attr_string = sh_util_strdup (theFile->attr_string);
+ }
+ }
+#endif
+
+ if (theFile->c_mode[0] == 'l' || theFile->link_path)
+ {
+ if (p->linkpath != NULL)
+ SH_FREE(p->linkpath);
+ p->linkpath = sh_util_strdup(theFile->link_path);
+ }
+ else
+ {
+ if (p->linkpath != NULL)
+ SH_FREE(p->linkpath);
+ p->linkpath = sh_util_strdup("-");
+ }
+
+ sl_strlcpy(p->theFile.checksum, fileHash, KEY_LEN+1);
+
+ p->theFile.mtime = theFile->mtime;
+ p->theFile.ctime = theFile->ctime;
+ p->theFile.atime = theFile->atime;
+
+ p->theFile.size = theFile->size;
+
+ sl_strlcpy(p->theFile.c_group, theFile->c_group, GROUP_MAX+2);
+ p->theFile.group = theFile->group;
+ sl_strlcpy(p->theFile.c_owner, theFile->c_owner, USER_MAX+2);
+ p->theFile.owner = theFile->owner;
+
+ p->theFile.ino = theFile->ino;
+ p->theFile.rdev = theFile->rdev;
+ p->theFile.dev = theFile->dev;
+ p->theFile.hardlinks = theFile->hardlinks;
+ }
+ }
+ }
+
+ SET_SH_FFLAG_VISITED(p->fflags);
+ CLEAR_SH_FFLAG_CHECKED(p->fflags);
+
+ unlock_and_return:
+ ; /* 'label at end of compound statement */
+ SH_MUTEX_UNLOCK(mutex_hash);
+ SL_RETURN(retval, _("sh_hash_compdata"));
+}
+
+int hash_full_tree ()
+{
+ sh_file_t * p;
+ int i;
+
+ SL_ENTER(_("hash_full_tree"));
+
+ if (IsInit != 1)
+ SL_RETURN(0, _("hash_full_tree"));
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_hash);
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ for (p = tab[i]; p; p = p->next)
+ CLEAR_SH_FFLAG_ALLIGNORE(p->fflags);
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
+ SL_RETURN (0, _("hash_full_tree"));
+}
+
+#if !defined(SH_CUTEST)
+static
+#endif
+int hash_remove_tree_test(char * s, char * fullpath, size_t len_s)
+{
+ size_t len_p;
+ char * test;
+
+ len_p = strlen(fullpath);
+
+ if (len_p >= len_s)
+ {
+ if (0 == strncmp(s, fullpath, len_s))
+ {
+ if (len_p > len_s)
+ {
+ /* continue if not inside directory;
+ * len_s > 1 because everything is inside '/'
+ */
+ if ((len_s > 1) && (fullpath[len_s] != '/'))
+ return S_FALSE;
+
+ test = sh_files_find_mostspecific_dir(fullpath);
+
+ if (test && 0 != strcmp(test, s)) {
+ /* There is a more specific directory, continue */
+ return S_FALSE;
+ }
+
+ if (NULL == sh_files_findfile(fullpath)) {
+ /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
+ return S_TRUE;
+ }
+ }
+ else /* len_p == len */
+ {
+ /* it is 's' itself, mark and continue
+ * unless there is a policy for the inode itself
+ */
+ if (NULL == sh_files_findfile(fullpath)) {
+ /* SET_SH_FFLAG_ALLIGNORE(p->fflags); */
+ return S_TRUE;
+ }
+ else {
+ return S_FALSE;
+ }
+ }
+
+ } /* if path is in tree */
+ } /* if path is possibly in tree */
+ return S_FALSE;
+}
+
+
+int hash_remove_tree (char * s)
+{
+ sh_file_t * p;
+ size_t len_s;
+ unsigned int i;
+
+ SL_ENTER(_("hash_remove_tree"));
+
+ if (!s || *s == '\0')
+ SL_RETURN ((-1), _("hash_remove_tree"));
+
+ len_s = sl_strlen(s);
+
+ if (IsInit != 1)
+ sh_hash_init();
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_hash);
+ for (i = 0; i < TABSIZE; ++i)
+ {
+ for (p = tab[i]; p; p = p->next)
+ {
+ if (p->fullpath)
+ {
+ /* if (0 == strncmp(s, p->fullpath, len_s)) *//* old */
+ if (S_TRUE == hash_remove_tree_test(s, p->fullpath, len_s)) {
+ SET_SH_FFLAG_ALLIGNORE(p->fflags);
+ MODI_SET(p->theFile.checkflags, MODI_ALLIGNORE);
+ }
+ } /* if path is not null */
+
+ }
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_hash);
+ SL_RETURN ((0), _("hash_remove_tree"));
+}
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+static int ListFullDetail = S_FALSE;
+static int ListWithDelimiter = S_FALSE;
+static char * ListFile = NULL;
+
+int set_list_file (const char * c)
+{
+ ListFile = sh_util_strdup(c);
+ return 0;
+}
+char * get_list_file()
+{
+ return ListFile;
+}
+
+int set_full_detail (const char * c)
+{
+ (void) c;
+ ListFullDetail = S_TRUE;
+ return 0;
+}
+
+int set_list_delimited (const char * c)
+{
+ (void) c;
+ ListFullDetail = S_TRUE;
+ ListWithDelimiter = S_TRUE;
+ return 0;
+}
+
+/* Always quote the string, except if it is empty. Quote quotes by
+ * doubling them.
+ */
+char * csv_escape(const char * str)
+{
+ const char * p = str;
+ const char * q;
+
+ size_t size = 0;
+ size_t flag_quote = 0;
+
+ char * new;
+ char * pnew;
+
+ if (p)
+ {
+
+ while (*p)
+ {
+ if (*p == '"')
+ ++flag_quote;
+
+ ++size; ++p;
+ }
+
+ if (sl_ok_adds(size, flag_quote))
+ size += flag_quote; /* double each quote */
+ else
+ return NULL;
+
+ if (sl_ok_adds(size, 3))
+ size += 3; /* two quotes and terminating null */
+ else
+ return NULL;
+
+ new = SH_ALLOC(size);
+
+ if (flag_quote != 0)
+ {
+ new[0] = '"';
+ pnew = &new[1];
+ q = str;
+ while (*q)
+ {
+ *pnew = *q;
+ if (*pnew == '"')
+ {
+ ++pnew; *pnew = '"';
+ }
+ ++pnew; ++q;
+ }
+ *pnew = '"'; ++pnew;
+ *pnew = '\0';
+ }
+ else
+ {
+ if (size > 3)
+ {
+ new[0] = '"';
+ sl_strlcpy (&new[1], str, size-1);
+ new[size-2] = '"';
+ new[size-1] = '\0';
+ }
+ else
+ {
+ new[0] = '\0';
+ }
+ }
+
+ return new;
+ }
+ return NULL;
+}
+
+int isHexKey(char * s)
+{
+ int i;
+
+ for (i = 0; i < KEY_LEN; ++i)
+ {
+ if (*s)
+ {
+ if ((*s >= '0' && *s <= '9') ||
+ (*s >= 'A' && *s <= 'F') ||
+ (*s >= 'a' && *s <= 'f'))
+ {
+ ++s;
+ continue;
+ }
+ }
+ return S_FALSE;
+ }
+ return S_TRUE;
+}
+
+#include "sh_checksum.h"
+
+static char * KEYBUFtolower (char * s, char * result)
+{
+ char * r = result;
+ if (s)
+ {
+ for (; *s; ++s)
+ {
+ *r = tolower((unsigned char) *s); ++r;
+ }
+ *r = '\0';
+ }
+ return result;
+}
+
+void sh_hash_list_db_entry_full_detail (sh_file_t * p)
+{
+ char * tmp;
+ char * esc;
+ char str[81];
+ char hexdigest[SHA256_DIGEST_STRING_LENGTH];
+ char keybuffer[KEYBUF_SIZE];
+
+ if (ListWithDelimiter == S_TRUE)
+ {
+ printf(_("%7ld, %7ld, %10s, %5d, %12s, %5d, %3d, %-8s, %5d, %-8s, %5d, "),
+ (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
+ p->theFile.c_mode, (int) p->theFile.mode,
+ p->theFile.c_attributes, (int) p->theFile.attributes,
+ (int) p->theFile.hardlinks,
+ p->theFile.c_owner, (int) p->theFile.owner,
+ p->theFile.c_group, (int) p->theFile.group);
+ }
+ else
+ {
+ printf(_("%7ld %7ld %10s %5d %12s %5d %3d %-8s %5d %-8s %5d "),
+ (unsigned long) p->theFile.ino, (unsigned long) p->theFile.dev,
+ p->theFile.c_mode, (int) p->theFile.mode,
+ p->theFile.c_attributes, (int) p->theFile.attributes,
+ (int) p->theFile.hardlinks,
+ p->theFile.c_owner, (int) p->theFile.owner,
+ p->theFile.c_group, (int) p->theFile.group);
+ }
+
+ if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
+ sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.rdev);
+ else
+ sl_snprintf(str, sizeof(str), "%"PRIu64, p->theFile.size);
+
+ printf( _(" %8s"), str);
+ if (ListWithDelimiter == S_TRUE)
+ putchar(',');
+
+ printf( _(" %s"), sh_unix_gmttime (p->theFile.ctime, str, sizeof(str)));
+ if (ListWithDelimiter == S_TRUE)
+ putchar(',');
+ printf( _(" %s"), sh_unix_gmttime (p->theFile.mtime, str, sizeof(str)));
+ if (ListWithDelimiter == S_TRUE)
+ putchar(',');
+ printf( _(" %s"), sh_unix_gmttime (p->theFile.atime, str, sizeof(str)));
+ if (ListWithDelimiter == S_TRUE)
+ putchar(',');
+
+ if (isHexKey(p->theFile.checksum))
+ printf( _(" %s"), KEYBUFtolower(p->theFile.checksum, keybuffer));
+ else
+ printf( _(" %s"), SHA256_Base2Hex(p->theFile.checksum, hexdigest));
+ if (ListWithDelimiter == S_TRUE)
+ putchar(',');
+
+ tmp = sh_util_safe_name(p->fullpath);
+ if (ListWithDelimiter != S_TRUE)
+ {
+ printf( _(" %s"), tmp);
+ }
+ else
+ {
+ esc = csv_escape(tmp);
+ printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
+ if (esc)
+ SH_FREE(esc);
+ }
+ SH_FREE(tmp);
+
+ if ('l' == p->theFile.c_mode[0])
+ {
+ tmp = sh_util_safe_name(p->linkpath);
+ if (ListWithDelimiter != S_TRUE)
+ {
+ printf(_(" -> %s"), tmp);
+ }
+ else
+ {
+ esc = csv_escape(tmp);
+ printf( _(" %s,"), (esc != NULL) ? esc : _("(null)"));
+ if (esc)
+ SH_FREE(esc);
+ }
+ SH_FREE(tmp);
+ }
+
+ if (p->attr_string)
+ {
+ tmp = sh_util_safe_name(p->attr_string);
+ if (ListWithDelimiter != S_TRUE)
+ {
+ printf(_(" %s"), tmp);
+ }
+ else
+ {
+ esc = csv_escape(tmp);
+ printf( _(" %s"), (esc != NULL) ? esc : _("(null)"));
+ if (esc)
+ SH_FREE(esc);
+ }
+ SH_FREE(tmp);
+ }
+ else
+ {
+ if (ListWithDelimiter == S_TRUE)
+ printf("%s",_(" no_attr"));
+ }
+ putchar('\n');
+
+ return;
+}
+
+void sh_hash_list_db_entry (sh_file_t * p)
+{
+ char nowtime[128];
+ char thetime[128];
+ char * tmp;
+ time_t now = time(NULL);
+ time_t then = (time_t) p->theFile.mtime;
+ struct tm * time_ptr;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
+ struct tm time_tm;
+#endif
+
+ if (ListFullDetail != S_FALSE)
+ {
+ sh_hash_list_db_entry_full_detail (p);
+ return;
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
+ time_ptr = gmtime_r(&then, &time_tm);
+ if (!time_ptr)
+ return;
+ strftime(thetime, 127, _("%b %d %Y"), time_ptr);
+ time_ptr = gmtime_r(&now, &time_tm);
+ if (!time_ptr)
+ return;
+ strftime(nowtime, 127, _("%b %d %Y"), time_ptr);
+ if (0 == strncmp(&nowtime[7], &thetime[7], 4))
+ {
+ time_ptr = gmtime_r(&then, &time_tm);
+ if (!time_ptr)
+ return;
+ strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
+ }
+#else
+ time_ptr = gmtime(&then);
+ if (!time_ptr)
+ return;
+ strftime(thetime, 127, _("%b %d %Y"), time_ptr);
+ time_ptr = gmtime(&now);
+ if (!time_ptr)
+ return;
+ strftime(nowtime, 127, _("%b %d %Y"), time_ptr);
+ if (0 == strncmp(&nowtime[7], &thetime[7], 4))
+ {
+ time_ptr = gmtime(&then);
+ if (!time_ptr)
+ return;
+ strftime(thetime, 127, _("%b %d %H:%M"), time_ptr);
+ }
+#endif
+
+ tmp = sh_util_safe_name(p->fullpath);
+ if ('c' == p->theFile.c_mode[0] || 'b' == p->theFile.c_mode[0])
+ printf(_("%10s %3d %-8s %-8s %3d,%4d %s %s"),
+ p->theFile.c_mode, (int) p->theFile.hardlinks,
+ p->theFile.c_owner, p->theFile.c_group,
+ (int) major((dev_t)p->theFile.rdev),
+ (int) minor((dev_t)p->theFile.rdev),
+ thetime,
+ tmp);
+ else
+ printf(_("%10s %3d %-8s %-8s %8ld %s %s"),
+ p->theFile.c_mode, (int) p->theFile.hardlinks,
+ p->theFile.c_owner, p->theFile.c_group, (long) p->theFile.size,
+ thetime,
+ tmp);
+ SH_FREE(tmp);
+
+ if ('l' == p->theFile.c_mode[0])
+ {
+ tmp = sh_util_safe_name(p->linkpath);
+ printf(_(" -> %s\n"), tmp);
+ SH_FREE(tmp);
+ }
+ else
+ printf("\n");
+
+ return;
+}
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+int sh_hash_printcontent(char * linkpath)
+{
+#ifdef HAVE_LIBZ
+ unsigned char * decoded;
+ unsigned char * decompressed = NULL;
+ size_t dlen;
+ unsigned long clen;
+ unsigned long clen_o;
+ int res;
+
+ if (linkpath && *linkpath != '-')
+ {
+ dlen = sh_util_base64_dec_alloc (&decoded,
+ (unsigned char *)linkpath,
+ strlen(linkpath));
+
+ clen = dlen * 2 + 1;
+
+ do {
+ if (decompressed)
+ SH_FREE(decompressed);
+ clen += dlen; clen_o = clen;
+ decompressed = SH_ALLOC(clen);
+ res = uncompress(decompressed, &clen, decoded, dlen);
+ if (res == Z_MEM_ERROR)
+ { fprintf(stderr, "%s",_("Error: Not enough memory\n")); return -1; }
+ if (res == Z_DATA_ERROR)
+ { fprintf(stderr, "%s",_("Error: Data corrupt or incomplete\n")); return -1; }
+ } while (res == Z_BUF_ERROR || clen == clen_o);
+
+ decompressed[clen] = '\0';
+ fputs( (char*) decompressed, stdout);
+ SH_FREE(decompressed);
+ return 0;
+ }
+#else
+ (void) linkpath;
+#endif
+ fprintf(stderr, "%s",_("Error: No data available\n"));
+ return -1;
+}
+
+/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
+#endif
diff --git a/src/sh_html.c b/src/sh_html.c
new file mode 100644
index 0000000..b9b4555
--- /dev/null
+++ b/src/sh_html.c
@@ -0,0 +1,558 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+#include <unistd.h>
+
+
+#ifdef SH_WITH_SERVER
+
+
+#include "samhain.h"
+#include "sh_xfer.h"
+#include "sh_error.h"
+#include "sh_unix.h"
+#include "sh_utils.h"
+#include "sh_html.h"
+
+#undef FIL__
+#define FIL__ _("sh_html.c")
+
+
+s_stat server_status;
+
+
+
+static
+char * replace_stat (char * line)
+{
+ st_format rep_serv_tab[] = {
+ { 'T', S_FMT_TIME, 0, 0, NULL},
+ { 'S', S_FMT_TIME, 0, 0, NULL},
+ { 'L', S_FMT_TIME, 0, 0, NULL},
+ { 'O', S_FMT_ULONG, 0, 0, NULL},
+ { 'A', S_FMT_ULONG, 0, 0, NULL},
+ { 'M', S_FMT_ULONG, 0, 0, NULL},
+ {'\0', S_FMT_ULONG, 0, 0, NULL},
+ };
+
+ rep_serv_tab[0].data_ulong = (unsigned long) time(NULL);
+ rep_serv_tab[1].data_ulong = server_status.start;
+ rep_serv_tab[2].data_ulong = server_status.last;
+ rep_serv_tab[3].data_ulong = server_status.conn_open;
+ rep_serv_tab[4].data_ulong = server_status.conn_total;
+ rep_serv_tab[5].data_ulong = server_status.conn_max;
+
+ return (sh_util_formatted(line, rep_serv_tab));
+}
+
+
+static
+int sh_html_head(SL_TICKET ticket)
+{
+ long status = SL_ENONE;
+ SL_TICKET fd = (-1);
+ char line[512];
+ char endhead[512];
+ char outline[1024];
+ char ts1[81];
+ char ts2[81];
+ time_t now;
+ struct tm * time_ptr;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ struct tm time_tm;
+#endif
+
+ char * formatted;
+ char * qstr;
+
+ char * p;
+
+ SL_ENTER(_("sh_html_head"));
+
+ p = sh_util_strconcat(DEFAULT_DATAROOT, _("/head.html"), NULL);
+
+ if (p)
+ {
+ fd = sl_open_read (FIL__, __LINE__, p, SL_YESPRIV);
+ SH_FREE(p);
+ }
+
+ if (!SL_ISERROR(fd))
+ {
+ while (!SL_ISERROR(status) && sh_unix_getline (fd, line, sizeof(line)) > 0)
+ {
+ formatted = replace_stat (line);
+ if (formatted)
+ {
+ status = sl_write_line (ticket, formatted, sl_strlen(formatted));
+ SH_FREE(formatted);
+ }
+ }
+ sl_close(fd);
+ }
+ else
+ {
+ qstr = sh_util_basename(DEFAULT_HTML_FILE);
+ if (qstr != NULL)
+ {
+ sl_snprintf(endhead, 511,
+ _("<meta http-equiv=%crefresh%c content=%c120; URL=./%s%c></HEAD><BODY>"),
+ 34, 34, 34, qstr, 34);
+ SH_FREE(qstr);
+ }
+ else
+ {
+ sl_snprintf(endhead, 511, _("</HEAD><BODY>"));
+ }
+
+ status =
+ sl_write_line (ticket,
+ _("<HTML><HEAD><TITLE>Report</TITLE>"),
+ sizeof("<HTML><HEAD><TITLE>Report</TITLE>")-1);
+ if (!SL_ISERROR(status))
+ status =
+ sl_write_line (ticket, endhead, strlen(endhead));
+ if (!SL_ISERROR(status))
+ status =
+ sl_write_line (ticket,
+ _("<H1>Samhain Server Report</H1>"),
+ sizeof("<H1>Samhain Server Report</H1>")-1);
+ if (!SL_ISERROR(status))
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&(server_status.start), &time_tm);
+#else
+ time_ptr = localtime (&(server_status.start));
+#endif
+ if (time_ptr != NULL)
+ strftime (ts1, 80, _("%d-%m-%Y %H:%M:%S"), time_ptr);
+ else
+ sl_strlcpy(ts1, _("01-01-1970 00:00:00"), sizeof(ts1));
+ now = time(NULL);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&now, &time_tm);
+#else
+ time_ptr = localtime (&now);
+#endif
+ if (time_ptr != NULL)
+ strftime (ts2, 80, _("%d-%m-%Y %H:%M:%S"), time_ptr);
+ else
+ sl_strlcpy(ts2, _("01-01-1970 00:00:00"), sizeof(ts2));
+
+ sl_snprintf(outline, 1023,
+ _("<p>Time:<BR>Now: %s<BR>Start: %s</p>"),
+ ts2, ts1);
+ status =
+ sl_write_line (ticket, outline, sl_strlen(outline));
+ }
+ if (!SL_ISERROR(status))
+ {
+ sl_snprintf(outline, 1023,
+ _("<p>Connections (max. %d simultaneous):"\
+ "<BR>Now: %d<BR>Total: %ld</p>"),
+ server_status.conn_max,
+ server_status.conn_open,
+ server_status.conn_total);
+ status =
+ sl_write_line (ticket, outline, sl_strlen(outline));
+ if (server_status.last > (time_t) 0)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&(server_status.last), &time_tm);
+#else
+ time_ptr = localtime (&(server_status.last));
+#endif
+ if (time_ptr != NULL)
+ strftime (ts1, 80, _("%d-%m-%Y %H:%M:%S"), time_ptr);
+ else
+ sl_strlcpy(ts1, _("01-01-1970 00:00:00"), sizeof(ts1));
+ sl_snprintf(outline, 1023,
+ _("<p>Last connection at %s</p>"),
+ ts1);
+ status =
+ sl_write_line (ticket, outline, sl_strlen(outline));
+ }
+ }
+ if (!SL_ISERROR(status))
+ status =
+ sl_write_line (ticket,
+ _("<center><table cellpadding=5 cellspacing=2 border=2>"),
+ sizeof("<center><table cellpadding=5 cellspacing=2 border=2>")-1);
+ }
+
+ if (SL_ISERROR(status))
+ SL_RETURN((-1), _("sh_html_head"));
+
+ SL_RETURN((0), _("sh_html_head"));
+}
+
+static
+int sh_html_foot(SL_TICKET ticket)
+{
+ long status = SL_ENONE;
+ SL_TICKET fd = (-1);
+ char line[512];
+ char * p;
+
+ SL_ENTER(_("sh_html_foot"));
+
+ p = sh_util_strconcat(DEFAULT_DATAROOT, _("/foot.html"), NULL);
+
+ if (p)
+ {
+ fd = sl_open_read (FIL__, __LINE__, p, SL_YESPRIV);
+ SH_FREE(p);
+ }
+
+ if (!SL_ISERROR(fd))
+ {
+ while (!SL_ISERROR(status) && sh_unix_getline (fd, line, sizeof(line)) > 0)
+ {
+ status = sl_write_line (ticket, line, sl_strlen(line));
+ }
+ sl_close(fd);
+ }
+ else
+ {
+ status = sl_write_line (ticket, _("</table></center></BODY></HTML>"),
+ sizeof("</table></center></BODY></HTML>")-1);
+ }
+ if (SL_ISERROR(status))
+ SL_RETURN((-1), _("sh_html_foot"));
+
+ SL_RETURN((0), _("sh_html_foot"));
+}
+
+
+static
+char * replace_tab (const char * line, char * host, char * status,
+ char * timestamp)
+{
+ st_format rep_serv_tab[] = {
+ { 'H', S_FMT_STRING, 0, 0, NULL},
+ { 'S', S_FMT_STRING, 0, 0, NULL},
+ { 'T', S_FMT_STRING, 0, 0, NULL},
+ {'\0', S_FMT_ULONG, 0, 0, NULL},
+ };
+ char * p;
+
+ SL_ENTER(_("replace_tab"));
+
+ rep_serv_tab[0].data_str = host;
+ rep_serv_tab[1].data_str = status;
+ rep_serv_tab[2].data_str = timestamp;
+
+ p = sh_util_formatted(line, rep_serv_tab);
+ SL_RETURN(p, _("replace_tab"));
+}
+
+static char * entry_orig = NULL;
+static size_t entry_size = 0;
+
+static
+int sh_html_get_entry (void)
+{
+ long retval = SL_ENONE;
+ SL_TICKET fd = (-1);
+ char line[512];
+ size_t line_size;
+ size_t add_size = 0;
+ char * p;
+
+ SL_ENTER(_("sh_html_get_entry"));
+
+ p = sh_util_strconcat(DEFAULT_DATAROOT, _("/entry.html"), NULL);
+
+ entry_size = 0;
+ if (entry_orig != NULL)
+ {
+ free (entry_orig);
+ entry_orig = NULL;
+ entry_size = 0;
+ }
+
+ if (p)
+ {
+ fd = sl_open_read (FIL__, __LINE__, p, SL_YESPRIV);
+ SH_FREE(p);
+ }
+ if (!SL_ISERROR(fd))
+ {
+ while (!SL_ISERROR(retval) && sh_unix_getline (fd, line, sizeof(line)) > 0)
+ {
+ line_size = sl_strlen(line);
+ add_size = 0;
+ if (entry_orig != NULL)
+ {
+ char * ptr = realloc(entry_orig, /* free() ok */
+ entry_size + line_size + 1);
+ if (ptr) {
+ entry_orig = ptr;
+ add_size = line_size;
+ } else {
+ { free(entry_orig); entry_orig = NULL; }
+ }
+ }
+ else
+ {
+ entry_orig = calloc(1, line_size + 1); /* free() ok */
+ if (entry_orig) { entry_orig[0] = '\0'; add_size = line_size; }
+ }
+ if (!entry_orig)
+ {
+ entry_size = 0;
+ /* add_size = 0; *//* never read */
+ SL_RETURN( 0, _("sh_html_get_entry"));
+ }
+
+ sl_strlcat(&entry_orig[entry_size], line, line_size + 1);
+ entry_size += add_size;
+ SH_VALIDATE_EQ(entry_orig[entry_size], '\0');
+ }
+ sl_close(fd);
+ }
+ SL_RETURN( entry_size, _("sh_html_get_entry"));
+}
+
+static
+int sh_html_entry (SL_TICKET ticket,
+ char * host, char * status, char * timestamp, int flag)
+{
+ char outline[1024];
+ long retval = SL_ENONE;
+
+ char * formatted;
+
+ SL_ENTER(_("sh_html_entry"));
+
+ if (entry_size > 0 && entry_orig != NULL)
+ {
+ formatted = replace_tab(entry_orig, host, status, timestamp);
+ if (formatted)
+ {
+ retval = sl_write_line (ticket, formatted, sl_strlen(formatted));
+ SH_FREE(formatted);
+ }
+ }
+ else
+ {
+ sl_snprintf(outline, 1023,
+ _("<tr><td>%s</td><td>%s</td><td>%s</td></tr>"),
+ host, status, timestamp);
+ retval = sl_write_line (ticket, outline, sl_strlen(outline));
+ }
+
+ /* write a status line
+ */
+ if ((flag == 1) && (!SL_ISERROR(retval)))
+ {
+ sl_snprintf(outline, 1023,
+ _("<!-- \n[STATUS:] %s %s %s\n -->"),
+ host, status, timestamp);
+ retval = sl_write_line (ticket, outline, sl_strlen(outline));
+ }
+
+ if (SL_ISERROR(retval))
+ SL_RETURN((-1), _("sh_html_entry"));
+
+ SL_RETURN((0), _("sh_html_entry"));
+}
+
+typedef struct _sort_arr {
+ char msg[TIM_MAX];
+ char tim[TIM_MAX];
+} sort_arr;
+
+static sort_arr sort_stat[CLT_MAX];
+
+static
+int comp_arr (const void * ao, const void * bo)
+{
+ const sort_arr * a;
+ const sort_arr * b;
+
+ if (ao == NULL && bo == NULL)
+ return 0;
+ else if (ao == NULL && bo != NULL)
+ return (-1);
+ else if (ao != NULL && bo == NULL)
+ return (1);
+
+ a = (const sort_arr *) ao;
+ b = (const sort_arr *) bo;
+
+ return ((-1) * sl_strcmp(a->tim, b->tim));
+}
+
+static
+int sh_html_print_one (SL_TICKET ticket, client_t * top)
+{
+ int status;
+ int clt_status;
+ unsigned int i, n;
+
+ SL_ENTER(_("sh_html_print_one"));
+
+ if (top == NULL)
+ SL_RETURN((0), _("sh_html_print_one"));
+
+ clt_status = top->status_now;
+ status = sh_html_entry (ticket,
+ top->hostname,
+ _(clt_stat[clt_status]),
+ top->timestamp[clt_status],
+ 1);
+
+ n = 0;
+
+ if (clt_status != CLT_INACTIVE)
+ {
+ for (i = 1; i < CLT_MAX; ++i)
+ {
+ if (top->status_arr[i] != CLT_INACTIVE)
+ {
+ clt_status = top->status_arr[i];
+ sl_strlcpy(sort_stat[n].msg, _(clt_stat[clt_status]), TIM_MAX);
+ sl_strlcpy(sort_stat[n].tim, top->timestamp[clt_status],TIM_MAX);
+ ++n;
+ }
+ }
+ }
+
+ if (n > 0)
+ {
+ qsort(&(sort_stat[0]), n, sizeof(sort_arr), comp_arr);
+
+ for (i = 1; i < n; ++i)
+ {
+ status = sh_html_entry (ticket,
+ " ",
+ sort_stat[i].msg,
+ sort_stat[i].tim,
+ 0);
+ }
+ }
+
+ if (SL_ISERROR(status))
+ SL_RETURN((-1), _("sh_html_print_one"));
+
+ SL_RETURN((0), _("sh_html_print_one"));
+}
+
+#include "zAVLTree.h"
+
+int sh_html_write(void * inptr)
+{
+ long fd;
+ zAVLCursor avlcursor;
+ client_t * item;
+ zAVLTree * top = (zAVLTree *) inptr;
+
+ SL_ENTER(_("sh_html_write"));
+
+ if (0 != (fd = tf_trust_check (DEFAULT_HTML_FILE, SL_YESPRIV)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_TRUST,
+ (long) sh.effective.uid,
+ DEFAULT_HTML_FILE);
+ SL_RETURN((-1), _("sh_html_write"));
+ }
+
+
+ fd = sl_open_write_trunc (FIL__, __LINE__, DEFAULT_HTML_FILE, SL_YESPRIV);
+
+ if (SL_ISERROR(fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
+ (long) sh.effective.uid,
+ DEFAULT_HTML_FILE);
+ SL_RETURN((-1), _("sh_html_write"));
+ }
+
+ sh_html_get_entry();
+
+ sh_html_head(fd);
+ for (item = (client_t *) zAVLFirst(&avlcursor, top); item;
+ item = (client_t *) zAVLNext(&avlcursor))
+ sh_html_print_one (fd, item);
+ sh_html_foot(fd);
+ sl_close(fd);
+
+ SL_RETURN((0), _("sh_html_write"));
+}
+
+int sh_html_zero()
+{
+ long fd;
+
+ SL_ENTER(_("sh_html_zero"));
+
+ if (0 != (fd = tf_trust_check (DEFAULT_HTML_FILE, SL_YESPRIV)))
+ {
+ SL_RETURN((-1), _("sh_html_zero"));
+ }
+
+ fd = sl_open_write_trunc (FIL__, __LINE__, DEFAULT_HTML_FILE, SL_YESPRIV);
+
+ if (SL_ISERROR(fd))
+ {
+ SL_RETURN((-1), _("sh_html_zero"));
+ }
+
+ sh_html_head(fd);
+ sh_html_foot(fd);
+
+ sl_close(fd);
+
+ SL_RETURN((0), _("sh_html_zero"));
+}
+
+/* SH_WITH_SERVER */
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/sh_ignore.c b/src/sh_ignore.c
new file mode 100644
index 0000000..407c426
--- /dev/null
+++ b/src/sh_ignore.c
@@ -0,0 +1,330 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2003 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#ifndef NULL
+#if !defined(__cplusplus)
+#define NULL ((void*)0)
+#else
+#define NULL (0)
+#endif
+#endif
+
+#ifdef HAVE_REGEX_H
+#include <sys/types.h>
+#include <regex.h>
+#endif
+
+#include <string.h>
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error.h"
+
+#define FIL__ _("sh_ignore.c")
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+struct sh_ignore_list {
+#ifdef HAVE_REGEX_H
+ regex_t preg;
+#else
+ char * path;
+#endif
+ struct sh_ignore_list * next;
+};
+
+
+static struct sh_ignore_list * sh_del_ign = NULL;
+static struct sh_ignore_list * sh_new_ign = NULL;
+static struct sh_ignore_list * sh_mod_ign = NULL;
+
+static struct sh_ignore_list * sh_ignore_add_int(struct sh_ignore_list * list,
+ const char * addpath)
+{
+ struct sh_ignore_list * new;
+ char * reg_expr;
+ size_t len;
+
+#ifdef HAVE_REGEX_H
+ int status = -1;
+ char * errbuf;
+#else
+ size_t size;
+#endif
+
+ SL_ENTER(_("sh_ignore_add"));
+
+ if ( (addpath == NULL) || (sl_ok_adds(2, strlen(addpath)) == S_FALSE) )
+ {
+ SL_RETURN(list, _("sh_ignore_add"));
+ }
+
+ new = SH_ALLOC(sizeof(struct sh_ignore_list));
+
+ len = 2 + strlen(addpath);
+ reg_expr = SH_ALLOC(len);
+ sl_strlcpy(reg_expr, "^", len);
+ sl_strlcat(reg_expr, addpath, len);
+
+#ifdef HAVE_REGEX_H
+ status = regcomp(&(new->preg), reg_expr, REG_NOSUB|REG_EXTENDED);
+ if (status != 0)
+ {
+ errbuf = SH_ALLOC(BUFSIZ+2);
+ (void) regerror(status, &(new->preg), errbuf, BUFSIZ);
+ errbuf[BUFSIZ] = '\0';
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX,
+ errbuf, reg_expr);
+ SH_FREE(errbuf);
+ SH_FREE(new);
+ SH_FREE(reg_expr);
+ SL_RETURN(list, _("sh_ignore_add"));
+ }
+#else
+ size = sl_strlen(addpath);
+ new->path = SH_ALLOC(size + 1);
+ sl_strlcpy(new->path, addpath, size+1);
+#endif
+
+ SH_FREE(reg_expr);
+ new->next = list;
+
+ SL_RETURN(new, _("sh_ignore_add"));
+}
+
+int sh_ignore_add_del (const char * addpath)
+{
+ if ((addpath == NULL) || (addpath[0] != '/'))
+ {
+ return -1;
+ }
+ sh_del_ign = sh_ignore_add_int (sh_del_ign, addpath);
+ return 0;
+}
+
+int sh_ignore_add_new (const char * addpath)
+{
+ if ((addpath == NULL) || (addpath[0] != '/'))
+ {
+ return -1;
+ }
+ sh_new_ign = sh_ignore_add_int (sh_new_ign, addpath);
+ return 0;
+}
+
+int sh_ignore_add_mod (const char * addpath)
+{
+ if ((addpath == NULL) || (addpath[0] != '/'))
+ {
+ return -1;
+ }
+ sh_mod_ign = sh_ignore_add_int (sh_mod_ign, addpath);
+ return 0;
+}
+
+static int sh_ignore_chk_int (struct sh_ignore_list * list,
+ const char * chkpath)
+{
+ struct sh_ignore_list * new = list;
+
+ SL_ENTER(_("sh_ignore_chk"));
+
+ if (chkpath == NULL)
+ {
+ SL_RETURN(S_FALSE, _("sh_ignore_add"));
+ }
+
+ while (new)
+ {
+#ifdef HAVE_REGEX_H
+ if (0 == regexec(&(new->preg), chkpath, 0, NULL, 0))
+ {
+ SL_RETURN(S_TRUE, _("sh_ignore_add"));
+ }
+#else
+ if (0 == sl_strcmp(new->path, chkpath))
+ {
+ SL_RETURN(S_TRUE, _("sh_ignore_add"));
+ }
+#endif
+ new = new->next;
+ }
+
+ SL_RETURN(S_FALSE, _("sh_ignore_add"));
+}
+
+int sh_ignore_chk_new (const char * chkpath)
+{
+ return (sh_ignore_chk_int(sh_new_ign, chkpath));
+}
+
+int sh_ignore_chk_del (const char * chkpath)
+{
+ return (sh_ignore_chk_int(sh_del_ign, chkpath));
+}
+
+int sh_ignore_chk_mod (const char * chkpath)
+{
+ return (sh_ignore_chk_int(sh_mod_ign, chkpath));
+}
+
+int sh_ignore_clean (void)
+{
+ struct sh_ignore_list * new;
+
+ new = sh_new_ign;
+
+ while (new)
+ {
+ sh_new_ign = new->next;
+#ifdef HAVE_REGEX_H
+ regfree (&(new->preg));
+#else
+ SH_FREE(new->path);
+#endif
+ SH_FREE(new);
+ new = sh_new_ign;
+ }
+
+ new = sh_del_ign;
+
+ while (new)
+ {
+ sh_del_ign = new->next;
+#ifdef HAVE_REGEX_H
+ regfree (&(new->preg));
+#else
+ SH_FREE(new->path);
+#endif
+ SH_FREE(new);
+ new = sh_del_ign;
+ }
+
+ new = sh_mod_ign;
+
+ while (new)
+ {
+ sh_mod_ign = new->next;
+#ifdef HAVE_REGEX_H
+ regfree (&(new->preg));
+#else
+ SH_FREE(new->path);
+#endif
+ SH_FREE(new);
+ new = sh_mod_ign;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_ignore_ok (CuTest *tc) {
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+ int ret;
+
+ CuAssertTrue(tc, NULL == sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_new_ign);
+ CuAssertTrue(tc, NULL == sh_mod_ign);
+
+ ret = sh_ignore_add_del ("/var/log/foo/.*");
+ CuAssertTrue(tc, 0 == ret);
+
+ CuAssertPtrNotNull(tc, sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_new_ign);
+ CuAssertTrue(tc, NULL == sh_mod_ign);
+
+ ret = sh_ignore_chk_del ("/var/log/foo/test");
+ CuAssertTrue(tc, S_TRUE == ret);
+
+ ret = sh_ignore_chk_del ("/var/log/footest");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ ret = sh_ignore_chk_del ("/my/var/log/footest");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ ret = sh_ignore_chk_del ("/my/var/log/foo/test");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ sh_ignore_clean();
+ CuAssertTrue(tc, NULL == sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_new_ign);
+ CuAssertTrue(tc, NULL == sh_mod_ign);
+
+ ret = sh_ignore_add_new ("/var/log/foo/.*");
+ CuAssertTrue(tc, 0 == ret);
+
+ CuAssertPtrNotNull(tc, sh_new_ign);
+ CuAssertTrue(tc, NULL == sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_mod_ign);
+
+ ret = sh_ignore_chk_new ("/var/log/foo/test");
+ CuAssertTrue(tc, S_TRUE == ret);
+
+ ret = sh_ignore_chk_new ("/var/log/footest");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ ret = sh_ignore_chk_new ("/my/var/log/footest");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ ret = sh_ignore_chk_new ("/my/var/log/foo/test");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ sh_ignore_clean();
+ CuAssertTrue(tc, NULL == sh_new_ign);
+ CuAssertTrue(tc, NULL == sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_mod_ign);
+
+ ret = sh_ignore_add_mod ("/var/log/foo/.*");
+ CuAssertTrue(tc, 0 == ret);
+
+ CuAssertPtrNotNull(tc, sh_mod_ign);
+ CuAssertTrue(tc, NULL == sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_new_ign);
+
+ ret = sh_ignore_chk_mod ("/var/log/foo/test");
+ CuAssertTrue(tc, S_TRUE == ret);
+
+ ret = sh_ignore_chk_mod ("/var/log/footest");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ ret = sh_ignore_chk_mod ("/my/var/log/footest");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ ret = sh_ignore_chk_mod ("/my/var/log/foo/test");
+ CuAssertTrue(tc, S_FALSE == ret);
+
+ sh_ignore_clean();
+ CuAssertTrue(tc, NULL == sh_new_ign);
+ CuAssertTrue(tc, NULL == sh_del_ign);
+ CuAssertTrue(tc, NULL == sh_mod_ign);
+
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+/* #ifdef SH_CUTEST */
+#endif
+
diff --git a/src/sh_inotify.c b/src/sh_inotify.c
new file mode 100644
index 0000000..5fc8dab
--- /dev/null
+++ b/src/sh_inotify.c
@@ -0,0 +1,1052 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2009 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#if defined(HAVE_SYS_INOTIFY_H)
+
+#if defined(GCC_VERSION_MAJOR) && !defined(__clang__)
+#if (GCC_VERSION_MAJOR > 4) || ((GCC_VERSION_MAJOR == 4) && (GCC_VERSION_MINOR > 8))
+#pragma GCC diagnostic ignored "-Wclobbered"
+#endif
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_inotify.c")
+
+/* printf */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_calls.h"
+#include "sh_inotify.h"
+#include "sh_mem.h"
+#include "sh_utils.h"
+#include "slib.h"
+
+/**************************************************
+ *
+ * Make the inotify fd thread-specific by
+ * encapsulating it in get/set functions:
+ * sh_get_inotify_fd() / sh_set_inotify_fd()
+ *
+ **************************************************/
+
+#if defined(HAVE_PTHREAD)
+
+SH_MUTEX_STATIC(mutex_list_dormant, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_STATIC(mutex_watches, PTHREAD_MUTEX_INITIALIZER);
+
+static pthread_key_t inotify_key;
+static pthread_once_t inotify_key_once = PTHREAD_ONCE_INIT;
+
+static void make_inotify_key()
+{
+ (void) pthread_key_create(&inotify_key, free);
+}
+
+static int sh_get_inotify_fd()
+{
+ void * ptr;
+ int * fp;
+
+ (void) pthread_once(&inotify_key_once, make_inotify_key);
+
+ if ((ptr = pthread_getspecific(inotify_key)) == NULL)
+ {
+ ptr = calloc(1,sizeof(int));
+ if (ptr)
+ {
+ fp = (int*) ptr;
+ *fp = -1;
+ (void) pthread_setspecific(inotify_key, ptr);
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ fp = (int*) ptr;
+ }
+ return *fp;
+}
+
+static void sh_set_inotify_fd(int fd)
+{
+ int * fp;
+
+ fp = (int*) pthread_getspecific(inotify_key);
+ if (fp)
+ *fp = fd;
+ return;
+}
+
+/* !defined(HAVE_PTHREAD) */
+#else
+
+static int sh_inotify_fd = -1;
+
+static inline int sh_get_inotify_fd()
+{
+ return sh_inotify_fd;
+}
+
+static inline void sh_set_inotify_fd(int fd)
+{
+ sh_inotify_fd = fd;
+}
+
+#endif
+
+/*--- nothing thread-related below this point --- */
+
+#include "zAVLTree.h"
+
+typedef struct
+{
+ int watch;
+ short flag;
+ short type;
+ int class;
+ int rdepth;
+ unsigned long check_flags;
+ char * file;
+} sh_watch;
+
+/**************************************************
+ *
+ * Get inotify fd, initialize inotify if necessary
+ *
+ **************************************************/
+#define SH_INOTIFY_FAILED -2
+
+static int sh_inotify_getfd()
+{
+ int ifd = sh_get_inotify_fd();
+
+ if (ifd >= 0)
+ {
+ return ifd;
+ }
+
+ else if (ifd == SH_INOTIFY_FAILED)
+ {
+ return -1;
+ }
+
+ else /* if (ifd == -1) */
+ {
+#if defined(HAVE_INOTIFY_INIT1)
+ ifd = inotify_init1(IN_CLOEXEC);
+#else
+ ifd = inotify_init();
+ if (ifd >= 0)
+ {
+ long sflags;
+
+ sflags = retry_fcntl(FIL__, __LINE__, ifd, F_GETFD, 0);
+ retry_fcntl(FIL__, __LINE__, ifd, F_SETFD, sflags|FD_CLOEXEC);
+ }
+#endif
+
+ if (ifd < 0)
+ {
+ sh_set_inotify_fd(SH_INOTIFY_FAILED);
+ return -1;
+ }
+
+ sh_set_inotify_fd(ifd);
+ return ifd;
+ }
+}
+
+/**************************************************
+ *
+ * Public function:
+ * int sh_inotify_wait_for_change(char * filename,
+ * int watch,
+ * int * errnum,
+ * int waitsec);
+ * Returns: watch, if nonnegative
+ * -1 on error or reopen required
+ * (check errnum != 0)
+ *
+ * Caller needs to keep track of watch descriptor
+ *
+ **************************************************/
+
+#define SH_INOTIFY_REOPEN 0
+#define SH_INOTIFY_MODIFY 1
+
+void sh_inotify_init(sh_watches * watches)
+{
+ SH_MUTEX_LOCK_UNSAFE(mutex_watches);
+ watches->list_of_watches = NULL;
+ watches->count = 0;
+ watches->max_count = 0;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_watches);
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_list_dormant);
+ watches->dormant_watches = NULL;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_list_dormant);
+
+ return;
+}
+
+ssize_t sh_inotify_read(char * buffer, size_t count)
+{
+ ssize_t len = -1;
+ int ifd = sh_inotify_getfd();
+
+ do {
+ len = read (ifd, buffer, count);
+ } while (len < 0 && (errno == EINTR || errno == EAGAIN));
+
+ return len;
+}
+
+ssize_t sh_inotify_read_timeout(char * buffer, size_t count, int timeout)
+{
+ ssize_t len;
+ int ifd = sh_inotify_getfd();
+
+ len = sl_read_timeout_fd (ifd, buffer, count, timeout, S_FALSE);
+
+ return len;
+}
+
+
+static void sh_inotify_free_watch(void * item)
+{
+ sh_watch * this = (sh_watch *) item;
+
+ if (this->file)
+ SH_FREE(this->file);
+ SH_FREE(this);
+ return;
+}
+
+static sh_watch * sh_inotify_create_watch(const char * file,
+ int nwatch, int flag)
+{
+ sh_watch * this = SH_ALLOC(sizeof(sh_watch));
+
+ this->file = sh_util_strdup_track(file, __FILE__, __LINE__);
+ this->watch = nwatch;
+ this->flag = flag;
+ return this;
+}
+
+/********** List Handling ******************/
+
+struct sh_inotify_litem
+{
+ sh_watch * watch;
+ struct sh_inotify_litem * next;
+};
+
+static void sh_inotify_listitem_destroy(struct sh_inotify_litem * this)
+{
+ if (this)
+ SH_FREE(this);
+ return;
+}
+
+/* No Mutex in the list cursor functions, must be in the caller
+ * function...
+ */
+typedef struct {
+ struct sh_inotify_litem *prenode;
+ struct sh_inotify_litem *curnode;
+} sh_inotify_listCursor;
+
+static sh_watch * sh_inotify_list_first(sh_inotify_listCursor * listcursor,
+ sh_watches * watches)
+{
+ listcursor->prenode = watches->dormant_watches;
+ listcursor->curnode = watches->dormant_watches;
+
+ if (listcursor->curnode)
+ return listcursor->curnode->watch;
+ return NULL;
+}
+
+static sh_watch * sh_inotify_list_next(sh_inotify_listCursor * listcursor,
+ sh_watches * watches)
+{
+ (void) watches;
+
+ listcursor->prenode = listcursor->curnode;
+
+ if (listcursor->curnode)
+ {
+ listcursor->curnode = listcursor->curnode->next;
+ if (listcursor->curnode)
+ return listcursor->curnode->watch;
+ else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static sh_watch * sh_inotify_list_del_cur(sh_inotify_listCursor * listcursor,
+ sh_watches * watches)
+{
+ sh_watch * ret = NULL;
+
+ if (listcursor->curnode)
+ {
+ struct sh_inotify_litem * this = listcursor->curnode;
+
+ if (listcursor->prenode == this)
+ {
+ watches->dormant_watches = this->next;
+
+ listcursor->prenode = watches->dormant_watches;
+ listcursor->curnode = watches->dormant_watches;
+ }
+ else
+ {
+ listcursor->prenode->next = this->next;
+ listcursor->curnode = this->next;
+ }
+ if (listcursor->curnode)
+ ret = listcursor->curnode->watch;
+ else
+ ret = NULL;
+ sh_inotify_listitem_destroy(this);
+ }
+ return ret;
+}
+
+static int sh_inotify_add_dormant(sh_watches * watches, sh_watch * item)
+{
+ struct sh_inotify_litem * this;
+
+ SH_MUTEX_LOCK(mutex_list_dormant);
+ this = SH_ALLOC(sizeof(struct sh_inotify_litem));
+
+ this->watch = item;
+ this->next = (struct sh_inotify_litem *) watches->dormant_watches;
+
+ watches->dormant_watches = this;
+ SH_MUTEX_UNLOCK(mutex_list_dormant);
+ return 0;
+}
+
+static void * sh_dummy_popret = NULL;
+
+char * sh_inotify_pop_dormant(sh_watches * watches,
+ int * class, unsigned long * check_flags,
+ int * type, int * rdepth)
+{
+ char * popret = NULL;
+ struct sh_inotify_litem * this;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_popret = (void *) &popret;
+
+ SH_MUTEX_LOCK(mutex_list_dormant);
+
+ this = (struct sh_inotify_litem *) watches->dormant_watches;
+
+ if (this)
+ {
+ *class = this->watch->class;
+ *type = this->watch->type;
+ *rdepth = this->watch->rdepth;
+ *check_flags = this->watch->check_flags;
+ popret = sh_util_strdup_track(this->watch->file, __FILE__, __LINE__);
+
+ watches->dormant_watches = this->next;
+
+ sh_inotify_free_watch(this->watch);
+ SH_FREE(this);
+ }
+ SH_MUTEX_UNLOCK(mutex_list_dormant);
+
+ sh_dummy_popret = NULL;
+ return popret;
+}
+
+void sh_inotify_purge_dormant(sh_watches * watches)
+{
+ struct sh_inotify_litem * this;
+
+ SH_MUTEX_LOCK(mutex_list_dormant);
+ this = (struct sh_inotify_litem *) watches->dormant_watches;
+
+ watches->dormant_watches = NULL;
+
+ while (this)
+ {
+ struct sh_inotify_litem * cur = this;
+
+ this = this->next;
+
+ sh_inotify_free_watch(cur->watch);
+ SH_FREE(cur);
+ }
+ SH_MUTEX_UNLOCK(mutex_list_dormant);
+ return;
+}
+
+/********** End List Handling **************/
+
+static zAVLKey sh_inotify_getkey(void const *item)
+{
+ return (&((const sh_watch *)item)->watch);
+}
+
+void sh_inotify_close()
+{
+ int ifd = sh_inotify_getfd();
+
+ if (ifd >= 0)
+ close(ifd);
+ sh_set_inotify_fd(-1);
+
+ return;
+}
+
+
+/* This function removes all watches from the list,
+ * and closes the inode file descriptor in this thread.
+ */
+void sh_inotify_remove(sh_watches * watches)
+{
+ zAVLTree * all_watches;
+
+ SH_MUTEX_LOCK(mutex_watches);
+ all_watches = (zAVLTree *)(watches->list_of_watches);
+
+ if (all_watches)
+ zAVLFreeTree(all_watches, sh_inotify_free_watch);
+
+ watches->list_of_watches = NULL;
+ watches->count = 0;
+ SH_MUTEX_UNLOCK(mutex_watches);
+
+ sh_inotify_close();
+ return;
+}
+
+static int index_watched_file(char * filename, sh_watches * watches)
+{
+ sh_watch * item;
+ zAVLCursor avlcursor;
+ zAVLTree * all_watches = (zAVLTree *)(watches->list_of_watches);
+
+ if (all_watches)
+ {
+ for (item = (sh_watch *) zAVLFirst(&avlcursor, all_watches); item;
+ item = (sh_watch *) zAVLNext(&avlcursor))
+ {
+ if (item->file)
+ {
+ if (0 == strcmp(filename, item->file))
+ return item->watch;
+ }
+ }
+ }
+ return -1;
+}
+
+#if !defined(IN_DONT_FOLLOW)
+#define IN_DONT_FOLLOW 0
+#endif
+
+#define SH_INOTIFY_FILEFLAGS \
+ (IN_ATTRIB|IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_DONT_FOLLOW)
+#define SH_INOTIFY_DIRFLAGS \
+ (SH_INOTIFY_FILEFLAGS|IN_DELETE|IN_CREATE|IN_MOVED_FROM|IN_MOVED_TO)
+
+#define SH_INOTIFY_FLAGS (SH_INOTIFY_FILEFLAGS|SH_INOTIFY_DIRFLAGS)
+
+
+/* Create an item and put it on the 'dormant' list for later watch creation
+ */
+int sh_inotify_add_watch_later(const char * filename, sh_watches * watches,
+ int * errnum,
+ int class, unsigned long check_flags, int type,
+ int rdepth)
+{
+ sh_watch * item;
+
+ item = sh_inotify_create_watch(filename, -1, /* flag */ 0);
+
+ item->class = class;
+ item->type = (short) type;
+ item->rdepth = (short) rdepth;
+ item->check_flags = check_flags;
+
+ sh_inotify_add_dormant(watches, item);
+ if (errnum)
+ *errnum = 0;
+
+ return 0;
+}
+
+int sh_inotify_rm_watch (sh_watches * watches, sh_watches * save, int wd)
+{
+ int ifd = sh_get_inotify_fd();
+
+ if (watches)
+ {
+ sh_watch * item;
+
+ SH_MUTEX_LOCK(mutex_watches);
+ item = zAVLSearch(watches->list_of_watches, &wd);
+
+ if (item)
+ {
+ zAVLDelete(watches->list_of_watches, &wd);
+ if (save) /* optionally save the item */
+ {
+ item->watch = -1;
+ sh_inotify_add_dormant(save, item);
+ }
+ else
+ {
+ sh_inotify_free_watch(item);
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_watches);
+ }
+ return inotify_rm_watch(ifd, wd);
+}
+
+#if (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
+static void * sh_dummy_litem;
+
+int sh_inotify_recheck_watches (sh_watches * watches, sh_watches * save)
+{
+ sh_watch * litem;
+ sh_inotify_listCursor listcursor;
+ int ifd = sh_get_inotify_fd();
+
+ extern void sh_fInotify_report_add(char * path,
+ int class, unsigned long check_flags);
+
+ sh_dummy_litem = (void*) &litem;
+
+ /* -- Check dormant watches for reopening.
+ */
+ SH_MUTEX_LOCK(mutex_list_dormant);
+
+ litem = sh_inotify_list_first(&listcursor, save);
+
+ while (litem)
+ {
+ have_next:
+
+ /* sh_inotify_list_del_cur may return NULL */
+ if (litem && litem->file && litem->watch == -1)
+ {
+ litem->watch = inotify_add_watch (ifd, litem->file,
+ SH_INOTIFY_FLAGS);
+
+ if (litem->watch >= 0)
+ {
+ SH_MUTEX_LOCK(mutex_watches);
+ if (watches->list_of_watches)
+ zAVLInsert(watches->list_of_watches, litem);
+ SH_MUTEX_UNLOCK(mutex_watches);
+
+ sh_fInotify_report_add(litem->file, litem->class, litem->check_flags);
+
+ litem = sh_inotify_list_del_cur(&listcursor, save);
+
+ goto have_next;
+ }
+ }
+ litem = sh_inotify_list_next(&listcursor, save);
+ }
+ SH_MUTEX_UNLOCK(mutex_list_dormant);
+ return 0;
+}
+#endif
+
+/* This function is idempotent; it will add the watch only once
+ */
+int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum,
+ int class, unsigned long check_flags, int type, int rdepth)
+{
+ volatile int retval = 0;
+
+ SH_MUTEX_LOCK(mutex_watches);
+
+ *errnum = 0;
+
+ if (filename)
+ {
+ int nwatch;
+ sh_watch * item;
+ int index = index_watched_file(filename, watches);
+
+ if (index < 0)
+ {
+ int ifd = sh_inotify_getfd();
+
+ /*************************************
+
+ if (watches->count == SH_INOTIFY_MAX)
+ {
+#ifdef EMFILE
+ *errnum = EMFILE;
+#else
+ *errnum = 24;
+#endif
+ return -1;
+ }
+ **************************************/
+
+ nwatch = inotify_add_watch (ifd, filename,
+ SH_INOTIFY_FLAGS);
+ if (nwatch < 0)
+ {
+ *errnum = errno;
+ retval = -1;
+ goto retpoint;
+ }
+
+ item = sh_inotify_create_watch(filename, nwatch, /* flag */ 0);
+
+ item->class = class;
+ item->type = type;
+ item->rdepth = rdepth;
+ item->check_flags = check_flags;
+
+ if (NULL == watches->list_of_watches)
+ watches->list_of_watches = zAVLAllocTree (sh_inotify_getkey,
+ zAVL_KEY_INT);
+
+ if (watches->list_of_watches)
+ {
+ *errnum = zAVLInsert((zAVLTree *)(watches->list_of_watches),
+ item);
+
+ if (*errnum != 0)
+ {
+ /* zAVLInsert returns -1 on malloc() error and 3 if
+ * the node already exists.
+ */
+ *errnum = (*errnum == -1) ? ENOMEM : EEXIST;
+ sh_inotify_free_watch(item);
+ retval = -1;
+ goto retpoint;
+ }
+ }
+ else
+ {
+ *errnum = ENOMEM;
+ sh_inotify_free_watch(item);
+ retval = -1;
+ goto retpoint;
+ }
+
+ ++(watches->count);
+ }
+ else if (type == SH_INOTIFY_DIR) /* watch exists */
+ {
+ /* This covers the case that a directory has been added,
+ * but is watched as file at first because it is also
+ * specified as file in the config.
+ */
+ item = zAVLSearch(watches->list_of_watches, &index);
+
+ if (item && item->type == SH_INOTIFY_FILE)
+ {
+ item->type = SH_INOTIFY_DIR;
+ }
+ }
+ }
+ retpoint:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_UNLOCK(mutex_watches);
+ return retval;
+}
+
+static void * sh_dummy_sret = NULL;
+
+char * sh_inotify_search_item(sh_watches * watches, int watch,
+ int * class, unsigned long * check_flags,
+ int * type, int * rdepth)
+{
+ sh_watch * item;
+ char * sret = NULL;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_sret = (void *) &sret;
+
+ SH_MUTEX_LOCK(mutex_watches);
+ item = zAVLSearch(watches->list_of_watches, &watch);
+
+ if (item)
+ {
+ *class = item->class;
+ *check_flags = item->check_flags;
+ *type = item->type;
+ *rdepth = item->rdepth;
+ sret = sh_util_strdup_track(item->file, __FILE__, __LINE__);
+ }
+ SH_MUTEX_UNLOCK(mutex_watches);
+ return sret;
+}
+
+static void * sh_dummy_litem = NULL;
+
+int sh_inotify_wait_for_change(char * filename, sh_watches * watches,
+ int * errnum, int waitsec)
+{
+ sh_watch * litem;
+ sh_watch * zitem;
+ int ifd = sh_inotify_getfd();
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_litem = (void*) &litem;
+
+ *errnum = 0;
+
+ start_it:
+
+ if (ifd >= 0)
+ {
+ volatile ssize_t i = 0;
+ ssize_t len = -1;
+ int flag = 0;
+ char buffer[1024];
+
+ sh_inotify_listCursor listcursor;
+
+ /* -- Add watch if required
+ */
+ if (filename)
+ {
+ if (sh_inotify_add_watch(filename, watches, errnum,
+ 0, 0, SH_INOTIFY_FILE, 0) < 0)
+ {
+ retry_msleep(waitsec, 0);
+ return -1;
+ }
+ }
+
+ /* -- Check dormant watches for reopening.
+ */
+ SH_MUTEX_LOCK(mutex_list_dormant);
+
+ for (litem = sh_inotify_list_first(&listcursor, watches); litem;
+ litem = sh_inotify_list_next(&listcursor, watches))
+ {
+ have_next:
+ /* sh_inotify_list_del_cur may return NULL */
+ if (litem && litem->file && litem->watch == -1)
+ {
+ litem->watch = inotify_add_watch (ifd, litem->file,
+ SH_INOTIFY_FLAGS);
+
+ if (litem->watch >= 0)
+ {
+ SH_MUTEX_LOCK(mutex_watches);
+ if (watches->list_of_watches)
+ zAVLInsert(watches->list_of_watches, litem);
+ SH_MUTEX_UNLOCK(mutex_watches);
+ litem = sh_inotify_list_del_cur(&listcursor, watches);
+ goto have_next;
+ }
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_list_dormant);
+
+
+ /* -- Blocking read on inotify file descriptor
+ */
+ len = sh_inotify_read(buffer, sizeof(buffer));
+
+ if (len > 0)
+ {
+ struct inotify_event *event;
+
+ i = 0;
+
+ while (i < len) {
+
+ event = (struct inotify_event *) &buffer[i];
+
+ SH_MUTEX_LOCK(mutex_watches);
+ zitem = zAVLSearch(watches->list_of_watches, &(event->wd));
+
+ if (zitem)
+ {
+ if (event->mask & IN_MODIFY)
+ {
+ zitem->flag |= SH_INOTIFY_MODIFY;
+ flag |= SH_INOTIFY_MODIFY;
+ }
+ else if (event->mask & IN_DELETE_SELF ||
+ event->mask & IN_UNMOUNT ||
+ event->mask & IN_MOVE_SELF )
+ {
+ zitem->flag |= SH_INOTIFY_REOPEN;
+ (void) inotify_rm_watch(ifd, zitem->watch);
+ zAVLDelete(watches->list_of_watches, zitem);
+ sh_inotify_add_dormant(watches, zitem);
+ zitem->watch = -1;
+ flag |= SH_INOTIFY_REOPEN;
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_watches);
+
+ i += sizeof (struct inotify_event) + event->len;
+ }
+ }
+ else if (len == -1)
+ {
+ *errnum = errno;
+ retry_msleep(waitsec, 0);
+
+ return -1;
+ }
+
+ if (flag & SH_INOTIFY_REOPEN)
+ {
+ if (flag & SH_INOTIFY_MODIFY)
+ return 0;
+ else
+ goto start_it;
+ }
+
+ return 0;
+ }
+
+ /* Inotify not working, sleep
+ */
+ retry_msleep(waitsec, 0);
+
+ *errnum = 0;
+ return -1;
+}
+
+
+/* !defined(HAVE_SYS_INOTIFY_H) */
+#else
+
+#include "sh_calls.h"
+#include "sh_inotify.h"
+
+void sh_inotify_remove(sh_watches * watches)
+{
+ (void) watches;
+ return;
+}
+
+int sh_inotify_wait_for_change(char * filename, sh_watches * watches,
+ int * errnum, int waitsec)
+{
+ (void) filename;
+ (void) watches;
+
+ /* Inotify not working, sleep for waitsec seconds
+ */
+ retry_msleep(waitsec, 0);
+
+ if (errnum)
+ *errnum = 0;
+ return -1;
+}
+
+int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum,
+ int class, unsigned long check_flags, int type, int rdepth)
+{
+ (void) filename;
+ (void) watches;
+ (void) class;
+ (void) check_flags;
+ (void) type;
+ (void) rdepth;
+
+ if (errnum)
+ *errnum = 0;
+ return 0;
+}
+
+int sh_inotify_add_watch_later(const char * filename, sh_watches * watches,
+ int * errnum,
+ int class, unsigned long check_flags, int type, int rdepth)
+{
+ (void) filename;
+ (void) watches;
+ (void) class;
+ (void) check_flags;
+ (void) type;
+ (void) rdepth;
+
+ if (errnum)
+ *errnum = 0;
+ return 0;
+}
+
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+void Test_inotify(CuTest *tc) {
+#if defined(HAVE_SYS_INOTIFY_H) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
+
+ int ret;
+ sh_watches twatch = SH_INOTIFY_INITIALIZER;
+ sh_watch * litem;
+ sh_inotify_listCursor listcursor;
+ char * p;
+ int class;
+ int type;
+ int rdepth;
+ unsigned long check_flags;
+ int nrun = 0;
+
+ sh_watch aw1 = { -1, 0, 0, 1, 99, 1, "a1" };
+ sh_watch aw2 = { -1, 0, 0, 2, 99, 1, "a2" };
+ sh_watch aw3 = { 2, 0, 0, 3, 99, 1, "a3" };
+ sh_watch aw4 = { -1, 0, 0, 4, 99, 1, "a4" };
+ sh_watch aw5 = { 5, 0, 0, 5, 99, 1, "a5" };
+
+ do {
+
+ int count = 0;
+
+ sh_watch * w1 = SH_ALLOC(sizeof(sh_watch));
+ sh_watch * w2 = SH_ALLOC(sizeof(sh_watch));
+ sh_watch * w3 = SH_ALLOC(sizeof(sh_watch));
+ sh_watch * w4 = SH_ALLOC(sizeof(sh_watch));
+ sh_watch * w5 = SH_ALLOC(sizeof(sh_watch));
+
+ memcpy(w1, &aw1, sizeof(sh_watch));
+ w1->file = sh_util_strdup(aw1.file);
+ memcpy(w2, &aw2, sizeof(sh_watch));
+ w2->file = sh_util_strdup(aw2.file);
+ memcpy(w3, &aw3, sizeof(sh_watch));
+ w3->file = sh_util_strdup(aw3.file);
+ memcpy(w4, &aw4, sizeof(sh_watch));
+ w4->file = sh_util_strdup(aw4.file);
+ memcpy(w5, &aw5, sizeof(sh_watch));
+ w5->file = sh_util_strdup(aw5.file);
+
+ ret = sh_inotify_add_dormant(&twatch, w1);
+ CuAssertIntEquals(tc, ret, 0);
+ ret = sh_inotify_add_dormant(&twatch, w2);
+ CuAssertIntEquals(tc, ret, 0);
+ ret = sh_inotify_add_dormant(&twatch, w3);
+ CuAssertIntEquals(tc, ret, 0);
+ ret = sh_inotify_add_dormant(&twatch, w4);
+ CuAssertIntEquals(tc, ret, 0);
+ ret = sh_inotify_add_dormant(&twatch, w5);
+ CuAssertIntEquals(tc, ret, 0);
+
+ /* -- Check dormant watches for reopening.
+ */
+ for (litem = sh_inotify_list_first(&listcursor, &twatch); litem;
+ litem = sh_inotify_list_next(&listcursor, &twatch))
+ {
+ have_next:
+
+ /* sh_inotify_list_del_cur may return NULL */
+ if (litem)
+ {
+ ++count;
+
+ if (litem->file && litem->watch == -1)
+ {
+
+ switch (litem->class)
+ {
+ case 1:
+ CuAssertStrEquals(tc, litem->file, "a1");
+ break;
+ case 2:
+ CuAssertStrEquals(tc, litem->file, "a2");
+ break;
+ case 3:
+ CuAssertStrEquals(tc, litem->file, "deadbeef");
+ break;
+ case 4:
+ CuAssertStrEquals(tc, litem->file, "a4");
+ break;
+ case 5:
+ CuAssertStrEquals(tc, litem->file, "deadbeef");
+ break;
+ default:
+ CuAssertStrEquals(tc, litem->file, "deadbeef");
+ }
+ litem = sh_inotify_list_del_cur(&listcursor, &twatch);
+ goto have_next;
+ }
+ switch (litem->class)
+ {
+ case 3:
+ CuAssertStrEquals(tc, litem->file, "a3");
+ break;
+ case 5:
+ CuAssertStrEquals(tc, litem->file, "a5");
+ break;
+ default:
+ CuAssertStrEquals(tc, litem->file, "foobar");
+ }
+ }
+ }
+
+ CuAssertIntEquals(tc, count, 5);
+
+ p = sh_inotify_pop_dormant(&twatch, &class, &check_flags, &type, &rdepth);
+ CuAssertStrEquals(tc, p, "a5");
+
+ p = sh_inotify_pop_dormant(&twatch, &class, &check_flags, &type, &rdepth);
+ CuAssertStrEquals(tc, p, "a3");
+ CuAssertIntEquals(tc, class, 3);
+
+ p = sh_inotify_pop_dormant(&twatch, &class, &check_flags, &type, &rdepth);
+ CuAssertTrue(tc, NULL == p);
+ CuAssertTrue(tc, NULL == twatch.dormant_watches);
+
+ ++nrun;
+
+ } while (nrun < 100);
+
+#else
+ (void) tc;
+#endif
+
+ return;
+}
+#endif
diff --git a/src/sh_ipvx.c b/src/sh_ipvx.c
new file mode 100644
index 0000000..84ceec9
--- /dev/null
+++ b/src/sh_ipvx.c
@@ -0,0 +1,591 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2010 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <ctype.h>
+
+#undef FIL__
+#define FIL__ _("sh_ipvx.c")
+
+#include "samhain.h"
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_ipvx.h"
+
+static int sh_ipvx_is_ipv4 (const char * addr)
+{
+ int j;
+ int count = 0;
+ int len = sl_strlen(addr);
+ unsigned int a, b, c, d;
+
+ if (len > 15) /* 3*4 + 3 dots */
+ return (1 == 0);
+
+ for (j = 0; j < len; ++j) {
+ if ( (addr[j] < '0' || addr[j] > '9') && addr[j] != '.')
+ return (1 == 0);
+ if (addr[j] == '.') ++count;
+ }
+
+ if (count != 3)
+ return (1 == 0);
+
+ if (sscanf(addr, "%3u.%3u.%3u.%3u", &a, &b, &c, &d) != 4)
+ return( 1 == 0 );
+
+ if ((a|b|c|d) > 255)
+ return( 1 == 0 );
+
+ return (1 == 1);
+}
+
+#if defined(USE_IPVX)
+static int sh_ipvx_is_ipv6 (const char * addr)
+{
+ int j, k = 0;
+ char c;
+ int len = sl_strlen(addr);
+
+ for (j = 0; j < len; ++j) {
+ c = addr[j];
+ if (( c < '0' || c > '9' ) &&
+ ( c < 'a' || c > 'f' ) &&
+ ( c < 'A' || c > 'F' ) &&
+ ( c != ':') && ( c != '.'))
+ return (1 == 0);
+ else if (c == ':')
+ ++k;
+ else if (c == '.' && k < 2)
+ return (1 == 0); /* ::ffff:ipv4 */
+ }
+ if (k < 2 || k > 7)
+ return (1 == 0);
+
+ return (1 == 1);
+}
+#endif
+
+
+int sh_ipvx_is_numeric (const char * addr)
+{
+#if defined(USE_IPVX)
+ if (!sh_ipvx_is_ipv4(addr))
+ return sh_ipvx_is_ipv6(addr);
+ else
+ return (1 == 1);
+#else
+ return sh_ipvx_is_ipv4(addr);
+#endif
+}
+
+int sh_ipvx_isany (struct sh_sockaddr * a)
+{
+#if defined(HOST_IS_CYGWIN)
+ /*
+ * Cygwin implementation gives 'missing braces around initializer'
+ * warning, thus replace it with correct version.
+ */
+#undef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
+#endif
+
+#if defined(USE_IPVX)
+ struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
+#endif
+
+ switch (a->ss_family)
+ {
+ case AF_INET:
+ if ((a->sin).sin_addr.s_addr == INADDR_ANY)
+ return 1;
+ break;
+#if defined(USE_IPVX)
+ case AF_INET6:
+ if (0 == memcmp(&((a->sin6).sin6_addr.s6_addr), &anyaddr, 16))
+ return 1;
+ break;
+#endif
+ }
+ return 0;
+}
+
+int sh_ipvx_cmp (struct sh_sockaddr * a, struct sh_sockaddr * b)
+{
+ if (a->ss_family != b->ss_family)
+ return 1;
+
+ switch (a->ss_family)
+ {
+ case AF_INET:
+ return memcmp(&((a->sin).sin_addr.s_addr), &((b->sin).sin_addr.s_addr), 4);
+ break;
+#if defined(USE_IPVX)
+ case AF_INET6:
+ return memcmp(&((a->sin6).sin6_addr.s6_addr), &((b->sin6).sin6_addr.s6_addr), 16);
+ break;
+#endif
+ }
+ return 1;
+}
+
+int sh_ipvx_ntoa (char * name, size_t name_size, struct sh_sockaddr * ss)
+{
+#if defined(USE_IPVX)
+ int len = (ss->ss_family == AF_INET) ?
+ sizeof(struct sockaddr_in) :
+ sizeof(struct sockaddr_in6);
+
+ int ret = getnameinfo(sh_ipvx_sockaddr_cast(ss), len,
+ name, name_size, NULL, 0, NI_NUMERICHOST);
+
+ if (ret != 0 && name_size > 0)
+ {
+ name[name_size-1] = '\0';
+
+ if (!sh_ipvx_is_numeric(name))
+ {
+ if (name_size > 7) {
+ name[0] = '0'; name[1] = '.'; name[2] = '0'; name[3] = '.';
+ name[4] = '0'; name[5] = '.'; name[6] = '0'; name[7] = '\0';
+ } else {
+ name[0] = '\0';
+ }
+ }
+ }
+ return ret;
+#else
+ char * p = inet_ntoa((ss->sin).sin_addr);
+ sl_strlcpy(name, p, name_size);
+ return 0;
+#endif
+}
+
+struct sockaddr * sh_ipvx_sockaddr_cast (struct sh_sockaddr * ss)
+{
+#if defined(USE_IPVX)
+ if (ss->ss_family == AF_INET6)
+ return (struct sockaddr *) &(ss->sin6);
+#endif
+ return (struct sockaddr *) &(ss->sin);
+}
+
+char * sh_ipvx_print_sockaddr (struct sockaddr * sa, int sa_family)
+{
+ struct sh_sockaddr ss;
+ static char ipbuf[SH_IP_BUF];
+
+ sh_ipvx_save(&ss, sa_family, sa);
+ sh_ipvx_ntoa (ipbuf, sizeof(ipbuf), &ss);
+ return ipbuf;
+}
+
+void sh_ipvx_save(struct sh_sockaddr * ss, int sa_family, struct sockaddr * sa)
+{
+ /* memset(ss, '\0', sizeof(struct sh_sockaddr)); */
+
+ switch (sa_family)
+ {
+ case AF_INET:
+ ss->ss_family = AF_INET;
+ memcpy(&(ss->sin), (struct sockaddr_in*) sa, sizeof(struct sockaddr_in));
+ break;
+#if defined(USE_IPVX)
+ case AF_INET6:
+ ss->ss_family = AF_INET6;
+ memcpy(&(ss->sin6), (struct sockaddr_in6*) sa, sizeof(struct sockaddr_in6));
+ break;
+#endif
+ default:
+ break;
+ }
+ return;
+}
+
+int sh_ipvx_set_port(struct sh_sockaddr * ss, int port)
+{
+#if defined(USE_IPVX)
+
+ switch (ss->ss_family)
+ {
+ case AF_INET:
+ (ss->sin).sin_family = AF_INET;
+ (ss->sin).sin_port = htons (port);
+ break;
+ case AF_INET6:
+ (ss->sin6).sin6_family = AF_INET6;
+ (ss->sin6).sin6_port = htons (port);
+ break;
+ }
+ return 0;
+#else
+ (ss->sin).sin_family = AF_INET;
+ (ss->sin).sin_port = htons (port);
+ return 0;
+#endif
+}
+
+int sh_ipvx_get_port(struct sockaddr * sa, int sa_family)
+{
+ int port = 0;
+#if defined(USE_IPVX)
+
+ switch (sa_family)
+ {
+ case AF_INET:
+ port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+ break;
+ case AF_INET6:
+ port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
+ break;
+ }
+#else
+ (void) sa_family;
+ port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+#endif
+ return port;
+}
+
+int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss)
+{
+#if defined(USE_IPVX)
+ int ret;
+ struct addrinfo hints;
+ struct addrinfo *res;
+
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+ ret = getaddrinfo(name, NULL, &hints, &res);
+
+ if (ret)
+ return 0;
+
+ memset(ss, '\0', sizeof(struct sh_sockaddr));
+ switch(res->ai_family)
+ {
+ case AF_INET:
+ memcpy(&(ss->sin), res->ai_addr, sizeof(struct sockaddr_in));
+ ss->ss_family = AF_INET;
+ break;
+ case AF_INET6:
+ memcpy(&(ss->sin6), res->ai_addr, sizeof(struct sockaddr_in6));
+ ss->ss_family = AF_INET6;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ return 1;
+#else
+ int ret = inet_aton(name, &((ss->sin).sin_addr));
+ ss->ss_family = AF_INET;
+ return ret;
+#endif
+}
+
+#if !defined(USE_IPVX)
+static const char * sh_ipvx_h_name (struct hostent * host_entry)
+{
+ char ** p;
+ if (strchr(host_entry->h_name, '.')) {
+ return host_entry->h_name;
+ } else {
+ for (p = host_entry->h_aliases; *p; ++p) {
+ if (strchr(*p, '.'))
+ return *p;
+ }
+ }
+ return host_entry->h_name;
+}
+#endif
+
+static char * sh_tolower (char * s)
+{
+ char * ret = s;
+ if (s)
+ {
+ for (; *s; ++s)
+ {
+ *s = tolower((unsigned char) *s);
+ }
+ }
+ return ret;
+}
+
+void * sh_dummy_341_out;
+
+char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen)
+{
+ volatile int flag = 0;
+ char *out = NULL;
+#if defined(USE_IPVX)
+ struct addrinfo hints;
+ struct addrinfo *res;
+ struct sockaddr *sa;
+ int salen;
+ int err;
+ struct sh_sockaddr ss;
+ const char * host;
+ char hostbuf[SH_BUFSIZE];
+
+ numeric[0] = '\0';
+
+ sh_dummy_341_out = (void *) &out;
+
+ if (sh_ipvx_is_numeric(hostname))
+ {
+ sh_ipvx_aton (hostname, &ss);
+ if (0 == getnameinfo(sh_ipvx_sockaddr_cast(&ss), SH_SS_LEN(ss),
+ hostbuf, sizeof(hostbuf), NULL, 0, NI_NAMEREQD))
+ host = hostbuf;
+ else
+ host = hostname;
+ }
+ else
+ {
+ host = hostname;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+#if defined(AI_CANONNAME)
+ hints.ai_flags = AI_CANONNAME;
+#endif
+
+ err = getaddrinfo(host, NULL, &hints, &res);
+ if (err == 0)
+ {
+#if defined(AI_CANONNAME)
+ if (res->ai_canonname && strlen(res->ai_canonname) > 0)
+ {
+ out = sh_util_strdup(res->ai_canonname);
+ sh_tolower (out);
+ if (strchr(out, '.'))
+ flag = 1;
+ }
+#endif
+
+ sa = res->ai_addr;
+ salen = res->ai_addrlen;
+ getnameinfo(sa, salen,
+ numeric, nlen, NULL, 0, NI_NUMERICHOST);
+
+ if (!flag)
+ out = SH_ALLOC(SH_PATHBUF);
+
+ while (res && !flag)
+ {
+ sa = res->ai_addr;
+ salen = res->ai_addrlen;
+
+ getnameinfo(sa, salen,
+ out, SH_PATHBUF, NULL, 0, 0);
+ sh_tolower (out);
+ if (strchr(out, '.'))
+ flag = 1;
+
+ res = res->ai_next;
+ }
+ }
+#else
+ struct hostent *he;
+ struct sh_sockaddr ss;
+ volatile int isNum = 0;
+ struct sockaddr_in *sin;
+
+ numeric[0] = '\0';
+
+ sh_dummy_341_out = (void *) &out;
+
+ if (sh_ipvx_is_numeric(hostname))
+ {
+ sh_ipvx_aton (hostname, &ss);
+ isNum = 1;
+ }
+
+
+ SH_MUTEX_LOCK(mutex_resolv);
+
+ if (isNum == 0)
+ {
+ he = sh_gethostbyname(hostname);
+ }
+ else
+ {
+ sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(&ss);
+ he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
+ }
+
+ if (he != NULL)
+ {
+ out = sh_util_strdup(sh_ipvx_h_name(he));
+ sh_tolower (out);
+ sl_strlcpy (numeric,
+ inet_ntoa (*(struct in_addr *) he->h_addr),
+ nlen);
+ flag = 1;
+ }
+ SH_MUTEX_UNLOCK(mutex_resolv);
+#endif
+
+ if (flag)
+ return out;
+
+ if (out)
+ SH_FREE(out);
+ if (numeric[0] == '\0')
+ sl_strlcpy (numeric, _("0.0.0.0"), nlen);
+ return NULL;
+}
+
+char * sh_ipvx_addrtoname(struct sh_sockaddr * ss)
+{
+#if defined(USE_IPVX)
+ char namebuf[SH_BUFSIZE];
+
+ if (getnameinfo(sh_ipvx_sockaddr_cast(ss), SH_SSP_LEN(ss),
+ namebuf, sizeof(namebuf), NULL, 0, NI_NAMEREQD) != 0)
+ {
+ return NULL;
+ }
+ return sh_util_strdup(namebuf);
+#else
+ struct sockaddr_in *sin;
+ struct hostent *he;
+
+ sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
+
+ he = sh_gethostbyaddr(&(sin->sin_addr), sizeof(sin->sin_addr), AF_INET);
+
+ if (he && he->h_name)
+ {
+ return sh_util_strdup(he->h_name);
+ }
+
+ return NULL;
+#endif
+}
+
+int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss)
+{
+#if defined(USE_IPVX)
+ struct addrinfo *res;
+ struct addrinfo hints;
+ char sport[32];
+ struct addrinfo *p;
+
+ sl_snprintf(sport, sizeof(sport), "%d", port);
+
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ if (getaddrinfo(peer, sport, &hints, &res) != 0)
+ {
+ return 0;
+ }
+
+ p = res;
+ while (p != NULL)
+ {
+ if (ss->ss_family == p->ai_family)
+ {
+ struct sh_sockaddr pp;
+
+ char dst1[SH_IP_BUF];
+ char dst2[SH_IP_BUF];
+
+ sh_ipvx_save(&pp, p->ai_family, p->ai_addr);
+
+ sh_ipvx_ntoa (dst1, sizeof(dst1), &pp);
+ sh_ipvx_ntoa (dst2, sizeof(dst2), ss);
+
+ if (0 == sl_strcmp(dst1, dst2))
+ {
+ return 1;
+ }
+ }
+ p = p->ai_next;
+ }
+ freeaddrinfo(res);
+#else
+ struct hostent * he;
+ char ** p;
+ struct sockaddr_in * sin = (struct sockaddr_in *) sh_ipvx_sockaddr_cast(ss);
+
+ (void) port;
+
+ he = sh_gethostbyname(peer);
+ if (he != NULL)
+ {
+ for (p = he->h_addr_list; *p; ++p)
+ {
+ if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) )
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+#ifdef SH_CUTEST
+#include <stdlib.h>
+#include "CuTest.h"
+
+void Test_ipvx (CuTest *tc) {
+
+ int result;
+
+ result = sh_ipvx_is_ipv4("123456789");
+ CuAssertTrue(tc, result == FALSE);
+
+ result = sh_ipvx_is_ipv4("123456789123...");
+ CuAssertTrue(tc, result == FALSE);
+
+ result = sh_ipvx_is_ipv4("123.456.789.123");
+ CuAssertTrue(tc, result == FALSE);
+
+ result = sh_ipvx_is_ipv4("123.156.189.254");
+ CuAssertTrue(tc, result == TRUE);
+
+ result = sh_ipvx_is_ipv4("255.255.255.255");
+ CuAssertTrue(tc, result == TRUE);
+
+ result = sh_ipvx_is_ipv4("0.0.0.0");
+ CuAssertTrue(tc, result == TRUE);
+
+ result = sh_ipvx_is_ipv4("0022.156.189.254");
+ CuAssertTrue(tc, result == FALSE);
+
+ result = sh_ipvx_is_ipv4("999999999.1.1.2");
+ CuAssertTrue(tc, result == FALSE);
+
+}
+#endif
+
diff --git a/src/sh_log_check.c b/src/sh_log_check.c
new file mode 100644
index 0000000..cc6fc4f
--- /dev/null
+++ b/src/sh_log_check.c
@@ -0,0 +1,1522 @@
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+#ifdef USE_LOGFILE_MONITOR
+
+#undef FIL__
+#define FIL__ _("sh_log_check.c")
+
+/* Debian/Ubuntu: libpcre3-dev */
+#ifdef HAVE_PCRE_PCRE_H
+#include <pcre/pcre.h>
+#else
+#include <pcre.h>
+#endif
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_string.h"
+#include "sh_log_check.h"
+#include "sh_log_evalrule.h"
+#include "sh_log_correlate.h"
+#include "sh_log_mark.h"
+#include "sh_log_repeat.h"
+#include "sh_extern.h"
+
+/* List of supported logfile types, format is
+ * {
+ * "TYPE_CODE",
+ * Reader_Callback_Function,
+ * Parser_Callback_function,
+ * Evaluate_Callback_Function
+ * }
+ * If Reader_Callback_Function is NULL, the default (line-oriented
+ * text file) reader is used.
+ */
+struct sh_logfile_type sh_logtypes_def[] = {
+ { "SYSLOG", NULL, sh_parse_syslog, NULL },
+ { "SAMBA", sh_read_samba, sh_parse_samba, NULL },
+ { "APACHE", NULL, sh_parse_apache, sh_eval_fileinfo_apache },
+#if defined(HAVE_SYS_ACCT_H)
+ { "PACCT", sh_read_pacct, sh_parse_pacct, NULL },
+#endif
+ { "SHELL", sh_read_shell, sh_parse_shell, NULL },
+};
+
+/* -------------------------- Internal Stuff -------------------------- */
+
+struct logfile_record {
+ dev_t device_id;
+ ino_t inode;
+ fpos_t offset;
+};
+
+static int do_checkpoint_cleanup = S_FALSE;
+
+static char * save_dir = NULL;
+
+static const char * get_save_dir(void)
+{
+ int retval;
+
+ if (!save_dir)
+ {
+ save_dir = sh_util_strdup(DEFAULT_DATAROOT);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ retval = tf_trust_check (save_dir, SL_YESPRIV);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ if (retval != 0)
+ {
+ return(NULL);
+ }
+ }
+ return save_dir;
+}
+
+static void clean_dir()
+{
+ DIR * dir;
+ struct dirent * entry;
+
+ const char * dirpath;
+
+ if (S_FALSE == do_checkpoint_cleanup)
+ return;
+
+ dirpath = get_save_dir();
+
+ if (dirpath)
+ {
+ dir = opendir(dirpath);
+ if (dir)
+ {
+ unsigned long a, b;
+ int retval;
+ char c;
+ size_t dlen = strlen(dirpath) + 1;
+ time_t now = time(NULL);
+
+ while (NULL != (entry = readdir(dir)))
+ {
+ retval = sscanf(entry->d_name, "%lu_%lu%c", &a, &b, &c);
+
+ if (2 == retval)
+ {
+ struct stat buf;
+ char * path;
+ size_t plen = strlen(entry->d_name) + 1;
+
+ if (S_TRUE == sl_ok_adds(plen, dlen))
+ {
+ plen += dlen;
+ path = SH_ALLOC(plen);
+ (void) sl_snprintf(path, plen, "%s/%s",
+ dirpath,entry->d_name);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &buf) &&
+ S_ISREG(buf.st_mode))
+ {
+ if (buf.st_mtime < now &&
+ (now - buf.st_mtime) > 2592000) /* 30 days */
+ {
+ if (0 == tf_trust_check (path, SL_YESPRIV))
+ {
+ unlink(path);
+ }
+ }
+ }
+ }
+ }
+ }
+ closedir(dir);
+ }
+ }
+}
+
+static char * build_path (struct sh_logfile * record)
+{
+ size_t plen;
+ char * path = NULL;
+ const char * dir = get_save_dir();
+
+ if (dir)
+ {
+ plen = strlen(dir);
+
+ if (S_TRUE == sl_ok_adds(plen, 130))
+ {
+ plen += 130; /* 64 + 64 + 2 */
+ path = SH_ALLOC(plen);
+ (void) sl_snprintf(path, plen, "%s/%lu_%lu", dir,
+ (unsigned long) record->device_id,
+ (unsigned long) record->inode);
+ }
+ }
+
+ return path;
+}
+
+static void save_pos (struct sh_logfile * record)
+{
+ char * path;
+ FILE * fd;
+ mode_t mask;
+ struct logfile_record save_rec;
+
+ path = build_path(record);
+
+ if (path)
+ {
+ if (0 != sh_unix_check_piddir (path))
+ {
+ SH_FREE(path);
+ return;
+ }
+
+ mask = umask(S_IWGRP | S_IWOTH);
+ fd = fopen(path, "wb");
+ (void) umask(mask);
+
+ if (fd)
+ {
+ save_rec.device_id = record->device_id;
+ save_rec.inode = record->inode;
+ memcpy(&(save_rec.offset), &(record->offset), sizeof(fpos_t));
+ if (1 != fwrite(&save_rec, sizeof(struct logfile_record), 1, fd))
+ {
+ (void) sl_fclose(FIL__, __LINE__, fd);
+ (void) remove(path);
+ }
+ else
+ {
+ (void) sl_fclose(FIL__, __LINE__, fd);
+ }
+ }
+ SH_FREE(path);
+ }
+ return;
+}
+
+static int read_pos (struct sh_logfile * record)
+{
+ int retval = 0;
+ char * path;
+ FILE * fd;
+ struct logfile_record save_rec;
+
+ path = build_path(record);
+
+ if (path)
+ {
+ fd = fopen(path, "rb");
+ if (fd)
+ {
+ if (1 == fread(&save_rec, sizeof(struct logfile_record), 1, fd))
+ {
+ if (save_rec.device_id == record->device_id &&
+ save_rec.inode == record->inode)
+ {
+ memcpy(&(record->offset),&(save_rec.offset),sizeof(fpos_t));
+ retval = 1;
+ }
+ }
+ (void) sl_fclose(FIL__, __LINE__, fd);
+ }
+ SH_FREE(path);
+ }
+ return retval;
+}
+
+/*@null@*/ static struct sh_logfile * sh_watched_logs = NULL;
+
+int sh_add_watch (const char * str)
+{
+ char * filename;
+
+ unsigned int i;
+ unsigned int defsize;
+ struct sh_logfile_type * log_type = NULL;
+ struct sh_logfile * thisfile;
+ struct stat buf;
+
+ unsigned int nfields = 3; /* logtype:path[:regex] */
+ size_t lengths[3];
+ char * new = sh_util_strdup(str);
+ char ** splits = split_array(new, &nfields, ':', lengths);
+
+ if (nfields < 2 || (lengths[0] == 0 || lengths[0] >= SH_MAX_LCODE_SIZE || lengths[1] == 0))
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Format error: "));
+ sh_string_add_from_char(msg, str);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_add_watch"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(new);
+ return -2;
+ }
+
+ defsize =
+ (unsigned int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type));
+
+ for (i = 0; i < defsize; ++i)
+ {
+ if (0 == strcmp(splits[0], sh_logtypes_def[i].code))
+ {
+ log_type = &(sh_logtypes_def[i]);
+ break;
+ }
+ }
+
+ if (log_type == NULL)
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Unsupported log type: "));
+ sh_string_add_from_char(msg, splits[0]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_add_watch"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(new);
+ return -3;
+ }
+
+ if (splits[1][0] != '/' && 0 != strcmp(splits[0], _("SHELL")))
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Logfile path not absolute: "));
+ sh_string_add_from_char(msg, splits[1]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_add_watch"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(new);
+ return -4;
+ }
+
+ filename = /*@i@*/sh_util_strdup(splits[1]);
+ thisfile = SH_ALLOC(sizeof(struct sh_logfile));
+
+ thisfile->filename = filename;
+ if (0 == strcmp(splits[0], _("SHELL")))
+ thisfile->flags = SH_LOGFILE_NOFILE;
+ else
+ thisfile->flags = SH_LOGFILE_REWIND;
+ thisfile->inode = 0;
+ thisfile->device_id = 0;
+ thisfile->fp = NULL;
+ if (log_type->get_record)
+ thisfile->get_record = log_type->get_record;
+ else
+ thisfile->get_record = sh_default_reader;
+ thisfile->parse_record = log_type->parse_record;
+
+ /* An optional regex for parsing the file. The result
+ * 'fileinfo' should contain info about host/time position.
+ */
+ if (log_type->eval_fileinfo)
+ {
+ if (nfields == 3 && lengths[2] > 0)
+ {
+ thisfile->fileinfo = log_type->eval_fileinfo(splits[2]);
+
+ if (thisfile->fileinfo == NULL)
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Logfile format description not recognized: "));
+ sh_string_add_from_char(msg, splits[2]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_add_watch"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(filename);
+ SH_FREE(thisfile);
+ SH_FREE(new);
+ return -1;
+ }
+ }
+ else
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Logfile format description missing: "));
+ sh_string_add_from_char(msg, splits[1]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_add_watch"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(filename);
+ SH_FREE(thisfile);
+ SH_FREE(new);
+ return -1;
+ }
+ }
+ else
+ {
+ thisfile->fileinfo = NULL;
+ }
+ thisfile->next = sh_watched_logs;
+
+ /* Try reading saved offset. On success clear rewind flag.
+ */
+ if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0)
+ {
+ if (0 == stat(thisfile->filename, &buf))
+ {
+ if (S_ISREG(buf.st_mode)
+#ifdef S_ISLNK
+ || S_ISLNK(buf.st_mode)
+#endif
+ )
+ {
+ thisfile->inode = buf.st_ino;
+ thisfile->device_id = buf.st_dev;
+
+ if (0 != read_pos(thisfile))
+ {
+ thisfile->flags &= ~SH_LOGFILE_REWIND;
+ }
+ }
+ else if (S_ISFIFO(buf.st_mode))
+ {
+ thisfile->inode = buf.st_ino;
+ thisfile->device_id = buf.st_dev;
+ thisfile->flags |= SH_LOGFILE_PIPE;
+ }
+ }
+ else
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Logfile is not a regular file, link, or named pipe: "));
+ sh_string_add_from_char(msg, splits[1]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_add_watch"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(filename);
+ SH_FREE(thisfile);
+ SH_FREE(new);
+ return -1;
+ }
+ }
+
+ sh_watched_logs = thisfile;
+
+ SH_FREE(new);
+ return 0;
+}
+
+void sh_dump_watches()
+{
+ struct sh_logfile * thisfile;
+
+ while (sh_watched_logs)
+ {
+ thisfile = sh_watched_logs;
+ sh_watched_logs = thisfile->next;
+
+ if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0 &&
+ (thisfile->flags & SH_LOGFILE_PIPE) == 0)
+ {
+ save_pos(thisfile);
+ }
+
+ if ((thisfile->flags & SH_LOGFILE_NOFILE) == 0)
+ {
+ if (thisfile->fp)
+ sl_fclose(FIL__, __LINE__, thisfile->fp);
+ }
+
+ if (thisfile->filename)
+ SH_FREE(thisfile->filename);
+ SH_FREE(thisfile);
+ }
+ return;
+}
+
+/* This variable is not used anywhere. It only exist
+ * to assign &new to them, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+void * sh_dummy_502_thisfile = NULL;
+
+void sh_check_watches()
+{
+ struct sh_logrecord * logrecord;
+ struct sh_logfile * thisfile = sh_watched_logs;
+ sh_string * record = sh_string_new(0);
+ char * tmp;
+
+ /* Take the address to keep gcc from putting them into registers.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_502_thisfile = (void*) &thisfile;
+
+ while (thisfile)
+ {
+ volatile size_t count = 0;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (thisfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKS,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ for (;;) {
+
+ record = thisfile->get_record(record, thisfile);
+
+ if (record)
+ {
+ logrecord = thisfile->parse_record(record, thisfile->fileinfo);
+ ++count;
+
+ if (logrecord)
+ {
+ logrecord->filename = thisfile->filename;
+
+ /* Don't report if 'init', just set file pointer
+ */
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ sh_eval_process_msg(logrecord);
+ }
+
+ if (logrecord->message)
+ sh_string_destroy(&(logrecord->message));
+ if (logrecord->host)
+ sh_string_destroy(&(logrecord->host));
+ if (logrecord->timestr)
+ sh_string_destroy(&(logrecord->timestr));
+ SH_FREE(logrecord);
+ }
+ }
+ else
+ {
+ record = sh_string_new(0);
+ break;
+ }
+ }
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (thisfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_CHKE,
+ tmp, (unsigned long)count);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ thisfile = thisfile->next;
+ }
+ sh_string_destroy(&record);
+ return;
+}
+
+/********************************************************
+ * Search rotated logfile
+ */
+extern char * sh_rotated_log_search(const char * path, struct stat * buf);
+
+
+/* Open file, position at stored offset
+ */
+int sh_open_for_reader (struct sh_logfile * logfile)
+{
+ struct stat buf;
+ sh_string * filename;
+
+ /* check whether file exists, get inode to check for
+ * logfile rotation
+ */
+ if (0 != retry_stat(FIL__, __LINE__, logfile->filename, &buf))
+ {
+ char * tmp;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (logfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_MISS,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ memset (&(logfile->offset), '\0', sizeof(fpos_t));
+ logfile->flags |= SH_LOGFILE_REWIND;
+ return 0;
+ }
+
+ filename = sh_string_new(0);
+ (void) sh_string_set_from_char (filename, logfile->filename);
+
+ /* detect and handle logfile rotation
+ */
+ if (logfile->inode != buf.st_ino &&
+ logfile->inode != 0 &&
+ !S_ISFIFO(buf.st_mode))
+ {
+ /* Case 1) We have dealt with the moved file already.
+ * Clear the moved flag, set the rewind flag,
+ * fix logfile->inode.
+ */
+ if ((logfile->flags & SH_LOGFILE_MOVED) != 0)
+ {
+ /* done with rotated file, start with current file
+ */
+ memset (&(logfile->offset), '\0', sizeof(fpos_t));
+ logfile->flags |= SH_LOGFILE_REWIND;
+ logfile->flags &= ~SH_LOGFILE_MOVED;
+ logfile->inode = buf.st_ino;
+ logfile->device_id = buf.st_dev;
+ }
+
+ /* Case 2) Searching for rotated file.
+ * If found: set the moved flag, fix path for fopen.
+ * If not found: set the rewind flag, fix logfile->inode.
+ */
+ else
+ {
+ char *oldfile = sh_rotated_log_search(logfile->filename, &buf);
+
+ if (NULL != oldfile)
+ {
+ (void) sh_string_set_from_char (filename, oldfile);
+ SH_FREE(oldfile);
+ logfile->flags |= SH_LOGFILE_MOVED;
+ }
+ else
+ {
+ memset (&(logfile->offset), '\0', sizeof(fpos_t));
+ logfile->flags |= SH_LOGFILE_REWIND;
+ logfile->inode = buf.st_ino;
+ logfile->device_id = buf.st_dev;
+ }
+ }
+ }
+
+ /* open file
+ */
+ if (!S_ISFIFO(buf.st_mode))
+ {
+ logfile->fp = fopen(filename->str, "r");
+ }
+ else
+ {
+ int fd_temp = open (filename->str, O_RDONLY|O_NONBLOCK);
+
+ if (fd_temp >= 0)
+ {
+ logfile->fp = fdopen(fd_temp, "r");
+ }
+ }
+
+ if (!logfile->fp)
+ {
+ char * tmp;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (logfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EOPEN,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ sh_string_destroy(&filename);
+ return 0;
+ }
+
+ sh_string_destroy(&filename);
+
+ if ((logfile->flags & SH_LOGFILE_PIPE) == 0)
+ {
+ if ((logfile->flags & SH_LOGFILE_REWIND) != 0)
+ {
+ rewind(logfile->fp);
+ fgetpos(logfile->fp, &(logfile->offset));
+ logfile->flags &= ~SH_LOGFILE_REWIND;
+ }
+ else
+ {
+ /* file too short
+ */
+ if (0 != fsetpos(logfile->fp, &(logfile->offset)))
+ {
+ rewind(logfile->fp);
+ fgetpos(logfile->fp, &(logfile->offset));
+ }
+ }
+ }
+
+ return 1;
+}
+
+/******************************************************
+ * Default reader for ascii text files
+ */
+sh_string * sh_default_reader (sh_string * s, struct sh_logfile * logfile)
+{
+ volatile int status;
+ char * tmp;
+
+ start_read:
+
+ if (logfile->fp)
+ {
+ /* Result cannot be larger than 8192, thus cast is ok
+ */
+ status = (int) sh_string_read(s, logfile->fp, 8192);
+ if (status <= 0)
+ {
+ fgetpos(logfile->fp, &(logfile->offset));
+ sl_fclose(FIL__, __LINE__, logfile->fp);
+ logfile->fp = NULL;
+ sh_string_destroy(&s);
+ if (status == 0 || (logfile->flags & SH_LOGFILE_PIPE) != 0)
+ {
+ return NULL;
+ }
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (logfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ return NULL;
+ }
+ return s;
+ }
+
+ if (0 != sh_open_for_reader(logfile))
+ goto start_read;
+
+ return NULL;
+}
+
+struct task_entry
+{
+ sh_tas_t task;
+ struct task_entry * next;
+};
+
+static struct task_entry * tasklist = NULL;
+
+static struct task_entry * task_find(FILE * fp)
+{
+ struct task_entry * entry = tasklist;
+ while (entry)
+ {
+ if (entry->task.pipe == fp)
+ return (entry);
+ entry = entry->next;
+ }
+ return NULL;
+}
+
+static void task_remove(struct task_entry * task)
+{
+ struct task_entry * entry = tasklist;
+ struct task_entry * prev = tasklist;
+
+ while (entry)
+ {
+ if (entry == task)
+ {
+ if (entry == tasklist)
+ {
+ tasklist = entry->next;
+ SH_FREE(entry);
+ return;
+ }
+ else
+ {
+ prev->next = entry->next;
+ SH_FREE(entry);
+ return;
+ }
+ }
+ prev = entry;
+ entry = entry->next;
+ }
+ return;
+}
+
+static void task_add(struct task_entry * entry)
+{
+ entry->next = tasklist;
+ tasklist = entry;
+ return;
+}
+
+sh_string * sh_command_reader (sh_string * s, struct sh_logfile * logfile)
+{
+ struct task_entry * entry;
+
+ volatile int status;
+ char * tmp;
+
+ start_read:
+
+ if (logfile->fp)
+ {
+ /* Result cannot be larger than 8192, thus cast is ok
+ */
+ status = (int) sh_string_read(s, logfile->fp, 8192);
+
+ if (status <= 0)
+ {
+ entry = task_find(logfile->fp);
+ sh_ext_pclose (&(entry->task));
+ task_remove(entry);
+
+ logfile->fp = NULL;
+ sh_string_destroy(&s);
+
+ if (status == 0)
+ {
+ return NULL;
+ }
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (logfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ return NULL;
+ }
+ return s;
+ }
+
+ entry = SH_ALLOC(sizeof(struct task_entry));
+
+ status = sh_ext_popen_init (&(entry->task), logfile->filename, logfile->filename, NULL);
+ if (0 == status)
+ {
+ task_add(entry);
+ logfile->fp = entry->task.pipe;
+ goto start_read;
+ }
+ else
+ {
+ SH_FREE(entry);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Could not open pipe"), _("sh_command reader"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ return NULL;
+}
+
+/******************************************************
+ * Reader for continued text files
+ */
+sh_string * sh_cont_reader (sh_string * s, struct sh_logfile * logfile, char*cont)
+{
+ int status;
+ char * tmp;
+ sh_string * str;
+ int remain = 8192;
+ int count = 0;
+
+ if (!sh_string_truncate(s, 0))
+ return NULL;
+
+ start_read:
+
+ if (logfile->fp)
+ {
+ str = sh_string_new(0);
+
+ /* Result cannot be larger than 8192, thus cast is ok
+ */
+ status = (int) sh_string_read(str, logfile->fp, 8192);
+
+ if (status > 0)
+ {
+
+ do {
+ s = sh_string_add (s, str);
+ count += status;
+ remain -= status;
+
+ if (remain <= 0)
+ {
+ return s;
+ }
+
+ status = (int) sh_string_read_cont(str, logfile->fp, count, cont);
+
+ if (status == 0)
+ {
+ return s;
+ }
+ }
+ while (status > 0);
+ }
+
+ if (status <= 0)
+ {
+ fgetpos(logfile->fp, &(logfile->offset));
+ sl_fclose(FIL__, __LINE__, logfile->fp);
+ logfile->fp = NULL;
+ sh_string_destroy(&s);
+ if (status == 0 || (logfile->flags & SH_LOGFILE_PIPE) != 0)
+ {
+ return NULL;
+ }
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (logfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_LOGMON_EREAD,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ return NULL;
+ }
+
+ return s;
+ }
+
+ if (0 != sh_open_for_reader(logfile))
+ goto start_read;
+
+ return NULL;
+}
+
+/******************************************************
+ * Reader for binary files
+ */
+sh_string * sh_binary_reader (void * s, size_t size,
+ struct sh_logfile * logfile)
+{
+ size_t status;
+
+ start_read:
+
+ if (logfile->fp)
+ {
+
+ status = fread(s, size, 1, logfile->fp);
+
+ if (status != 1)
+ {
+ memset(s, '\0', size);
+ if (ferror(logfile->fp) && (logfile->flags & SH_LOGFILE_PIPE) == 0)
+ {
+ char * tmp;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (logfile->filename);
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_LOGMON_EREAD,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ fgetpos(logfile->fp, &(logfile->offset));
+ sl_fclose(FIL__, __LINE__, logfile->fp);
+ logfile->fp = NULL;
+ return NULL;
+ }
+ return s;
+ }
+
+ if (0 != sh_open_for_reader(logfile))
+ goto start_read;
+
+ return NULL;
+}
+
+
+
+/**********************************************************
+ *
+ * Utilities
+ *
+ **********************************************************/
+
+/* Return current year, unless that would result
+ * in a date far in the future. If that happens,
+ * return last year.
+ */
+static int year_guess (struct tm * btime)
+{
+ int year;
+ struct tm ts;
+ time_t now = time(NULL);
+ time_t check;
+
+ memcpy(&ts, localtime(&now), sizeof(struct tm));
+ year = ts.tm_year;
+
+ /* Check result to detect year wrap
+ * (logfile entry from last year).
+ */
+ btime->tm_year = year;
+ check = mktime(btime);
+ if (check > (now + (86400*30)))
+ --year;
+
+ return year;
+}
+
+time_t conv_timestamp (struct tm * btime,
+ struct tm * old_tm, time_t * old_time)
+{
+ time_t timestamp;
+ long offtime;
+
+ /* timestamp - mktime is slooow, thus cache result
+ */
+ if (btime->tm_isdst == old_tm->tm_isdst &&
+ btime->tm_year == old_tm->tm_year &&
+ btime->tm_mon == old_tm->tm_mon &&
+ btime->tm_mday == old_tm->tm_mday)
+ {
+ offtime =
+ (btime->tm_hour - old_tm->tm_hour) * 3600 +
+ (btime->tm_min - old_tm->tm_min) * 60 +
+ (btime->tm_sec - old_tm->tm_sec);
+
+ *old_time += offtime;
+ memcpy(old_tm, btime, sizeof(struct tm));
+ timestamp = *old_time;
+ }
+ else
+ {
+ int year_btime = btime->tm_year;
+
+ if (btime->tm_year == 0)
+ btime->tm_year = year_guess(btime);
+ timestamp = mktime(btime);
+ btime->tm_year = year_btime;
+ *old_time = timestamp;
+ memcpy(old_tm, btime, sizeof(struct tm));
+ }
+ return timestamp;
+}
+
+/*********************************************************
+ *
+ * MODULE STUFF
+ *
+ *********************************************************/
+#include "sh_modules.h"
+
+SH_MUTEX_STATIC(mutex_logmon_check, PTHREAD_MUTEX_INITIALIZER);
+
+static int ShLogmonActive = S_FALSE;
+#define SH_LOGMON_INTERVAL 10
+static time_t sh_logmon_interval = SH_LOGMON_INTERVAL;
+
+int sh_log_check_init (struct mod_type * arg)
+{
+#if !defined(HAVE_PTHREAD)
+ (void) arg;
+#endif
+
+ if (ShLogmonActive == S_FALSE)
+ return SH_MOD_FAILED;
+#ifdef HAVE_PTHREAD
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ return SH_MOD_THREAD;
+ else
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ return SH_MOD_THREAD;
+ }
+#endif
+ if (sh_watched_logs != NULL)
+ return 0;
+
+ return -1;
+}
+
+int sh_log_check_timer(time_t tcurrent)
+{
+ static time_t lastcheck = 0;
+
+ SL_ENTER(_("sh_log_check_timer"));
+ if ((time_t) (tcurrent - lastcheck) >= sh_logmon_interval)
+ {
+ lastcheck = tcurrent;
+ SL_RETURN((-1), _("sh_log_check_timer"));
+ }
+ SL_RETURN(0, _("sh_log_check_timer"));
+}
+
+
+int sh_log_check_check(void)
+{
+ int status = 0;
+
+ SL_ENTER(_("sh_log_check_check"));
+
+ SH_MUTEX_LOCK(mutex_logmon_check);
+
+ status = 0;
+
+ if( ShLogmonActive != S_FALSE )
+ {
+ sh_check_watches();
+ sh_keep_match();
+ sh_log_mark_check();
+ clean_dir();
+ }
+ SH_MUTEX_UNLOCK(mutex_logmon_check);
+
+ SL_RETURN(status, _("sh_log_check_check"));
+}
+
+int sh_log_check_reconf(void)
+{
+ int status = 0;
+
+ SL_ENTER(_("sh_log_check_check"));
+
+ SH_MUTEX_LOCK(mutex_logmon_check);
+
+ ShLogmonActive = S_FALSE;
+ sh_logmon_interval = SH_LOGMON_INTERVAL;
+ sh_dump_watches();
+ sh_eval_cleanup();
+
+ SH_MUTEX_UNLOCK(mutex_logmon_check);
+
+ SL_RETURN(status, _("sh_log_check_check"));
+}
+
+int sh_log_check_cleanup(void)
+{
+ sh_log_mark_destroy();
+ return sh_log_check_reconf();
+}
+
+/********************* OPTIONS **********************/
+
+static int sh_logmon_set_active (const char *str);
+static int sh_logmon_set_clean (const char *str);
+static int sh_logmon_set_interval(const char *str);
+static int sh_logmon_add_watch (const char * str);
+static int sh_logmon_add_group (const char * str);
+static int sh_logmon_end_group (const char * str);
+static int sh_logmon_add_host (const char * str);
+static int sh_logmon_end_host (const char * str);
+static int sh_logmon_add_queue (const char * str);
+static int sh_logmon_add_rule (const char * str);
+extern int sh_set_hidepid(const char *s);
+static int sh_logmon_set_save_dir(const char *s);
+
+sh_rconf sh_log_check_table[] = {
+ {
+ N_("logmonactive"),
+ sh_logmon_set_active,
+ },
+ {
+ N_("logmoninterval"),
+ sh_logmon_set_interval,
+ },
+ {
+ N_("logmonclean"),
+ sh_logmon_set_clean,
+ },
+ {
+ N_("logmonwatch"),
+ sh_logmon_add_watch,
+ },
+ {
+ N_("logmonqueue"),
+ sh_logmon_add_queue,
+ },
+ {
+ N_("logmongroup"),
+ sh_logmon_add_group,
+ },
+ {
+ N_("logmonendgroup"),
+ sh_logmon_end_group,
+ },
+ {
+ N_("logmonhost"),
+ sh_logmon_add_host,
+ },
+ {
+ N_("logmonendhost"),
+ sh_logmon_end_host,
+ },
+ {
+ N_("logmonrule"),
+ sh_logmon_add_rule,
+ },
+ {
+ N_("logmonhidepid"),
+ sh_set_hidepid,
+ },
+ {
+ N_("logmonsavedir"),
+ sh_logmon_set_save_dir,
+ },
+ {
+ N_("logmonmarkseverity"),
+ sh_log_set_mark_severity,
+ },
+ {
+ N_("logmonburstthreshold"),
+ sh_repeat_set_trigger,
+ },
+ {
+ N_("logmonburstqueue"),
+ sh_repeat_set_queue,
+ },
+ {
+ N_("logmonburstcron"),
+ sh_repeat_set_cron,
+ },
+ {
+ N_("logmondeadtime"),
+ sh_keep_deadtime,
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/* Decide if we're active.
+ */
+static int sh_logmon_set_active(const char *str)
+{
+ int value;
+
+ SL_ENTER(_("sh_logmon_set_active"));
+
+ value = sh_util_flagval(str, &ShLogmonActive);
+
+ SL_RETURN((value), _("sh_logmon_set_active"));
+}
+
+/* Decide if we're active.
+ */
+static int sh_logmon_set_clean(const char *str)
+{
+ int value;
+
+ SL_ENTER(_("sh_logmon_set_active"));
+
+ value = sh_util_flagval(str, &do_checkpoint_cleanup);
+
+ SL_RETURN((value), _("sh_logmon_set_active"));
+}
+
+static int sh_logmon_set_save_dir(const char *str)
+{
+ int retval = -1;
+
+ SL_ENTER(_("sh_logmon_set_save_dir"));
+
+ if (str && str[0] == '/')
+ {
+ if (save_dir)
+ {
+ SH_FREE(save_dir);
+ save_dir = NULL;
+ }
+ save_dir = sh_util_strdup(str);
+ retval = 0;
+ }
+
+ SL_RETURN((retval), _("sh_logmon_set_save_dir"));
+}
+
+static int sh_logmon_set_interval (const char * c)
+{
+ int retval = 0;
+ long val;
+
+ SL_ENTER(_("sh_logmon_set_interval"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("log monitoring interval"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ retval = -1;
+ }
+ else
+ {
+ sh_logmon_interval = (time_t) val;
+ }
+ SL_RETURN(retval, _("sh_logmon_set_interval"));
+}
+
+/* Add a watch on a logfile.
+ * Format: TYPE : Filename [: File_Format]
+ */
+static int sh_logmon_add_watch (const char * str)
+{
+ return sh_add_watch(str);
+}
+
+/* Add a host.
+ * Format: Name_Regex
+ */
+static int sh_logmon_add_host (const char * str)
+{
+ return sh_eval_hadd(str);
+}
+
+/* End a host.
+ * Format: Name
+ */
+static int sh_logmon_end_host (const char * str)
+{
+ (void) str;
+ return sh_eval_hend(NULL);
+}
+
+/* Add a group of rules.
+ * Groups can be under hosts, but not vice versa.
+ * Format: Name : Prefix_Regex
+ */
+static int sh_logmon_add_group (const char * str)
+{
+ return sh_eval_gadd(str);
+}
+
+/* End a group of rules.
+ * Format: Name
+ */
+static int sh_logmon_end_group (const char * str)
+{
+ (void) str;
+ return sh_eval_gend(NULL);
+}
+
+/* Define a reporting queue.
+ * Format: Label : [Interval] : TYPE : Severity[:alias]
+ * TYPE must be 'report' or 'sum'
+ * Interval is ignored for TYPE='report'
+ */
+static int sh_logmon_add_queue (const char * str)
+{
+ return sh_eval_qadd(str);
+}
+
+/* Define a check rule.
+ * Format: [KEEP(seconds,label):]Queue_Label : Regex
+ * KEEP indicates that we keep the label, to perform
+ * correlation matching
+ */
+static int sh_logmon_add_rule (const char * str)
+{
+ return sh_eval_radd(str);
+}
+
+
+#if 0
+
+/* >>>>>>>>>>> MAIN <<<<<<<<<<<<<<<<<<< */
+
+int main (int argc, char * argv[])
+{
+ int status, i;
+ FILE * fp;
+ sh_string * s = NULL;
+ static char template[] = "/tmp/xtest.XXXXXX";
+
+ /* pacct */
+ status = sh_add_watch("PACCT:/var/log/account/pacct");
+ sh_check_watches();
+ sh_dump_watches();
+ exit(0);
+
+ /* apache log */
+ sh_eval_gadd("four_o_four:404");
+ sh_eval_qadd("test:1:sum:7");
+ sh_eval_radd("test:^(\\d+.\\d+.\\d+.\\d+).*");
+ sh_eval_gend(NULL);
+ sh_eval_radd("trash:.*");
+ status = sh_add_watch("APACHE:/var/log/apache2/access.log:combined");
+ sh_check_watches();
+ sh_dump_watches();
+ exit(0);
+
+ /* logfile */
+ sh_set_hidepid(1);
+ sh_eval_hadd("hslxmsrv1");
+ sh_eval_gadd("postfix:postfix");
+ sh_eval_qadd("test::report:7");
+ sh_eval_radd("test:postfix/smtpd: disconnect from localhost.*");
+ sh_eval_radd("trash:postfix/smtpd: disconnect.*");
+ sh_eval_hadd("hspc05");
+ sh_eval_gadd("cron:CRON");
+ sh_eval_qadd("test:1:sum:7");
+ sh_eval_radd("test:CRON: PAM adding faulty module: (/lib/security/.*.so)");
+ sh_eval_radd("trash:.*");
+ status = sh_add_watch("SYSLOG:/var/log/messages");
+ sh_check_watches();
+
+ sh_dump_watches();
+ exit(0);
+
+ printf("%d types\n",
+ (int) (sizeof(sh_logtypes_def)/sizeof(struct sh_logfile_type)));
+
+ /* test sh_add_watch
+ */
+ status = sh_add_watch("");
+ printf("%2d: zero length, expect -1\n", status);
+ status = sh_add_watch(NULL);
+ printf("%2d: NULL, expect -2\n", status);
+ status = sh_add_watch("0123456789012345:/var/log/messages");
+ printf("%2d: long, expect -2\n", status);
+ status = sh_add_watch("012345678901234:/var/log/messages");
+ printf("%2d: exact length, expect -3\n", status);
+ status = sh_add_watch("01234567890123:56789");
+ printf("%2d: short length, expect -3\n", status);
+ status = sh_add_watch("SYSLOG:var/log/messages");
+ printf("%2d: short badpath, expect -4\n", status);
+ status = sh_add_watch("SYSLOG:/var/log/messages");
+ /* status = sh_add_watch("SYSLOG:/var/log/dpkg.log.1"); */
+ printf("%2d: short path ok, expect 0\n", status);
+
+ /* test sh_string_read
+ */
+ s = sh_string_new();
+
+ status = /*@i@*/mkstemp(template);
+
+ if (status < 0) {
+ fprintf(stderr, "error in mkstemp!\n"); exit(EXIT_FAILURE); }
+
+ fp = fdopen(status, "r+");
+ if (!fp) {
+ fprintf(stderr, "error in fdopen!\n"); exit(EXIT_FAILURE); }
+
+ for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
+ for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
+ for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
+ for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
+ for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
+ for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+ for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+ for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+ for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+
+ rewind(fp);
+
+ for (i = 0; i < 9; ++i)
+ {
+ status = (int) sh_string_read(s, fp, 120);
+ printf("%d: status = %d, len = %d, size = %d\n",
+ i, status, (int)s->len, (int)s->siz);
+ if (status == -2)
+ (void) sh_string_read(s, fp, 240);
+ else
+ printf("%s\n", s->str);
+ }
+
+ rewind(fp);
+
+ (void) sh_string_truncate(s, 0);
+
+ for (i = 0; i < 9; ++i)
+ {
+ status = (int) sh_string_read(s, fp, 240);
+ printf("%d: status = %d, len = %d, size = %d\n",
+ i, status, (int)s->len, (int)s->siz);
+ if (status == -2)
+ (void) sh_string_read(s, fp, 240);
+ else
+ {
+ for (status = 0; status < (int)s->len; ++status)
+ {
+ if (s->str[status] != 'a')
+ {
+ break;
+ }
+ }
+ printf("%d %s\n", status, s->str);
+ }
+ }
+
+ sl_fclose(FIL__, __LINE__, fp); remove(template);
+
+
+
+ return 0;
+}
+#endif
+
+/* #ifdef USE_LOGFILE_MONITOR */
+#endif
+
diff --git a/src/sh_log_correlate.c b/src/sh_log_correlate.c
new file mode 100644
index 0000000..9598254
--- /dev/null
+++ b/src/sh_log_correlate.c
@@ -0,0 +1,349 @@
+#include "config_xor.h"
+
+#ifdef USE_LOGFILE_MONITOR
+
+#undef FIL__
+#define FIL__ _("sh_log_correlate.c")
+
+#include <string.h>
+#include <time.h>
+
+/* Debian/Ubuntu: libpcre3-dev */
+#ifdef HAVE_PCRE_PCRE_H
+#include <pcre/pcre.h>
+#else
+#include <pcre.h>
+#endif
+
+#ifndef PCRE_NO_AUTO_CAPTURE
+#define PCRE_NO_AUTO_CAPTURE 0
+#endif
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+#include "sh_log_check.h"
+#include "sh_log_evalrule.h"
+
+extern int flag_err_debug;
+
+/*--------------------------------------------------------------
+ *
+ * Event correlation
+ *
+ *--------------------------------------------------------------*/
+
+/* For each even to be correlated, we keep a label in a list. We
+ * then build a string from the (time-sorted) list of labels, and
+ * match this string against a regular expression.
+ */
+
+/* -- The list of labels kept in memory ----------------------- */
+
+struct sh_keep
+{
+ sh_string * label; /* label of keep rule */
+ unsigned long delay; /* valid delay */
+ time_t last; /* seen at */
+ struct sh_keep * next;
+};
+
+static struct sh_keep * keeplist = NULL;
+static struct sh_keep * keeplast = NULL;
+static unsigned long keepcount = 0;
+
+static void sh_keep_free(void * item)
+{
+ struct sh_keep * keep = (struct sh_keep *) item;
+
+ if (!keep)
+ return;
+ sh_string_destroy(&(keep->label));
+ SH_FREE(keep);
+}
+
+void sh_keep_destroy()
+{
+ struct sh_keep * keep;
+
+ while (keeplist)
+ {
+ keep = keeplist;
+ keeplist = keep->next;
+ sh_keep_free(keep);
+ --keepcount;
+ }
+ keeplist = NULL;
+ keeplast = NULL;
+ keepcount = 0;
+}
+
+int sh_keep_add(sh_string * label, unsigned long delay, time_t last)
+{
+ struct sh_keep * keep = SH_ALLOC(sizeof(struct sh_keep));
+
+ keep->label = sh_string_copy(label);
+ keep->delay = delay;
+ keep->last = last;
+ keep->next = NULL;
+
+ if (keeplast && keeplist)
+ {
+ keeplast->next = keep;
+ keeplast = keep;
+ }
+ else
+ {
+ keeplist = keep;
+ keeplast = keeplist;
+ }
+ ++keepcount;
+ return 0;
+}
+
+int sh_keep_comp(const void * a, const void * b)
+{
+ return ( (int)(((const struct sh_keep *)a)->last) -
+ (int)(((const struct sh_keep *)b)->last) );
+}
+
+/* -- Sort the kept labels and build a string ----------------- */
+
+static sh_string * sh_keep_eval()
+{
+ unsigned long count = 0;
+ sh_string * res = NULL;
+ time_t now = time(NULL);
+ struct sh_keep * keep = keeplist;
+ struct sh_keep * prev = keeplist;
+ struct sh_keep * arr;
+
+ if (keepcount > 0)
+ {
+ arr = SH_ALLOC (keepcount * sizeof(struct sh_keep));
+
+ while (count < keepcount && keep)
+ {
+ if ((now >= keep->last) &&
+ ((unsigned long)(now - keep->last) <= keep->delay))
+ {
+ memcpy(&(arr[count]), keep, sizeof(struct sh_keep));
+ ++count;
+ prev = keep;
+ keep = keep->next;
+ }
+ else /* Too old or in future, delete it */
+ {
+ if (keep != keeplist)
+ {
+ prev->next = keep->next;
+ sh_keep_free(keep);
+ keep = prev->next;
+ --keepcount;
+ }
+ else /* list head */
+ {
+ keeplist = keep->next;
+ prev = keeplist;
+ sh_keep_free(keep);
+ keep = keeplist;
+ --keepcount;
+ }
+ }
+ }
+
+ if (count > 0)
+ {
+ unsigned long i;
+ qsort(arr, count, sizeof(struct sh_keep), sh_keep_comp);
+ res = sh_string_copy(arr[0].label);
+ for (i = 1; i < count; ++i)
+ res = sh_string_add(res, arr[i].label);
+ }
+ SH_FREE(arr);
+ }
+
+ return res;
+}
+
+/* -- Match the string against correlation rules -------------- */
+
+struct sh_mkeep
+{
+ sh_string * label; /* label of match rule */
+ pcre * rule; /* compiled regex for rule */
+ time_t reported; /* last reported */
+ struct sh_qeval * queue; /* assigned queue */
+ struct sh_mkeep * next;
+};
+
+struct sh_mkeep * mkeep_list = NULL;
+unsigned long mkeep_deadtime = 60;
+
+int sh_keep_deadtime (const char * str)
+{
+ unsigned long value;
+ char * foo;
+
+ value = (size_t) strtoul(str, &foo, 0);
+
+ if (*foo == '\0') {
+ mkeep_deadtime = value;
+ return 0;
+ }
+ return -1;
+}
+
+int sh_keep_match_add(const char * str, const char * queue,
+ const char * pattern)
+{
+ unsigned int nfields = 1; /* seconds:label */
+ size_t lengths[1];
+ char * new = sh_util_strdup(str);
+ char ** splits = split_array_braced(new, _("CORRELATE"),
+ &nfields, lengths);
+
+ if (nfields == 1 && lengths[0] > 0)
+ {
+ struct sh_mkeep * mkeep = SH_ALLOC(sizeof(struct sh_mkeep));
+ const char * error;
+ int erroffset;
+ struct sh_qeval * rqueue = NULL;
+
+ mkeep->rule = pcre_compile(pattern, PCRE_NO_AUTO_CAPTURE,
+ &error, &erroffset, NULL);
+ if (!(mkeep->rule))
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Bad regex: "));
+ sh_string_add_from_char(msg, pattern);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_keep_match_add"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(splits);
+ SH_FREE(mkeep);
+ SH_FREE(new);
+ return -1;
+ }
+
+ if (0 != strcmp(queue, _("trash")))
+ {
+
+ rqueue = sh_log_find_queue(queue);
+ if (!rqueue)
+ {
+ pcre_free(mkeep->rule);
+ SH_FREE(splits);
+ SH_FREE(mkeep);
+ SH_FREE(new);
+ return -1;
+ }
+ }
+
+ mkeep->queue = rqueue;
+ mkeep->label = sh_string_new_from_lchar(splits[0], strlen(splits[0]));
+ mkeep->reported = 0;
+ mkeep->next = mkeep_list;
+ mkeep_list = mkeep;
+ }
+ SH_FREE(new);
+ return 0;
+}
+
+void sh_keep_match_del()
+{
+ struct sh_mkeep * mkeep = mkeep_list;
+ while (mkeep)
+ {
+ mkeep_list = mkeep->next;
+ sh_string_destroy(&(mkeep->label));
+ pcre_free(mkeep->rule);
+ mkeep = mkeep_list;
+ }
+ mkeep_list = NULL;
+}
+
+static struct sh_mkeep ** dummy_mkeep;
+
+void sh_keep_match()
+{
+ if (mkeep_list)
+ {
+ sh_string * res = sh_keep_eval();
+
+ if (res)
+ {
+ struct sh_mkeep * mkeep = mkeep_list;
+
+ dummy_mkeep = &mkeep;
+
+ while (mkeep)
+ {
+ /* Use pcre_dfa_exec() to obtain number of matches. Needs ovector
+ * array, otherwise number of matches is not returned.
+ */
+#if defined(HAVE_PCRE_DFA_EXEC)
+ int ovector[SH_MINIBUF];
+ int wspace[SH_MINIBUF];
+#endif
+
+#if defined(HAVE_PCRE_DFA_EXEC)
+ int val = pcre_dfa_exec(mkeep->rule, NULL,
+ sh_string_str(res),
+ (int)sh_string_len(res),
+ 0, /* start at offset 0 in the subject */
+ 0,
+ ovector, SH_MINIBUF,
+ wspace, SH_MINIBUF);
+#else
+ int val = pcre_exec(mkeep->rule, NULL,
+ sh_string_str(res),
+ (int)sh_string_len(res),
+ 0, /* start at offset 0 in the subject */
+ 0,
+ NULL, 0);
+ val = (val >= 0) ? 1 : val;
+#endif
+
+ if (val >= 0)
+ {
+ sh_string * alias;
+ time_t now = time(NULL);
+
+ if ((mkeep->reported < now) &&
+ (mkeep_deadtime < (unsigned int)(now - mkeep->reported)))
+ {
+ mkeep->reported = now;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (mkeep->queue->severity, FIL__, __LINE__, 0,
+ MSG_LOGMON_COR, sh_string_str(mkeep->label),
+ val);
+
+ alias = mkeep->queue->alias;
+ if (alias)
+ {
+ sh_error_mail (sh_string_str(alias),
+ mkeep->queue->severity, FIL__, __LINE__, 0,
+ MSG_LOGMON_COR, sh_string_str(mkeep->label),
+ val);
+ }
+
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ mkeep = mkeep->next;
+ }
+ sh_string_destroy(&res);
+ }
+ }
+ return;
+}
+
+#endif
diff --git a/src/sh_log_evalrule.c b/src/sh_log_evalrule.c
new file mode 100644
index 0000000..98a36d0
--- /dev/null
+++ b/src/sh_log_evalrule.c
@@ -0,0 +1,1266 @@
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#ifdef USE_LOGFILE_MONITOR
+
+#undef FIL__
+#define FIL__ _("sh_log_evalrule.c")
+
+/* Debian/Ubuntu: libpcre3-dev */
+#ifdef HAVE_PCRE_PCRE_H
+#include <pcre/pcre.h>
+#else
+#include <pcre.h>
+#endif
+
+#ifndef PCRE_NO_AUTO_CAPTURE
+#define PCRE_NO_AUTO_CAPTURE 0
+#endif
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+#include "sh_log_check.h"
+#include "sh_log_evalrule.h"
+#include "sh_log_correlate.h"
+#include "sh_log_mark.h"
+#include "sh_log_repeat.h"
+#include "zAVLTree.h"
+
+extern int flag_err_debug;
+
+/* #define DEBUG_EVALRULES */
+
+#ifdef DEBUG_EVALRULES
+static void DEBUG(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap); /* flawfinder: ignore *//* we control fmt string */
+ va_end(ap);
+ return;
+}
+#else
+static void DEBUG(const char *fmt, ...)
+{
+ (void) fmt;
+ return;
+}
+#endif
+
+struct sh_ceval /* Counter for summarizing */
+{
+ sh_string * hostname;
+ sh_string * counted_str;
+ sh_string * filename;
+ unsigned long count;
+ time_t start;
+ time_t interval;
+};
+
+void sh_ceval_free(void * item)
+{
+ struct sh_ceval * counter = (struct sh_ceval *) item;
+ if (!counter)
+ return;
+ sh_string_destroy(&(counter->hostname));
+ sh_string_destroy(&(counter->counted_str));
+ sh_string_destroy(&(counter->filename));
+ SH_FREE(counter);
+}
+
+enum {
+ RFL_ISRULE = 1 << 0,
+ RFL_ISGROUP = 1 << 1,
+ RFL_KEEP = 1 << 2,
+ RFL_MARK = 1 << 3
+};
+
+
+/*--------------------------------------------------------------
+ *
+ * Adding rules/groups/hosts
+ *
+ *--------------------------------------------------------------*/
+
+struct sh_geval /* Group of rules (may be a single rule) */
+{
+ sh_string * label; /* label for this group */
+ pcre * rule; /* compiled regex for rule */
+ pcre_extra * rule_extra;
+ int * ovector; /* captured substrings */
+ int ovecnum; /* how many captured */
+ int captures; /* (captures+1)*3 required */
+ int flags; /* bit flags */
+ unsigned long delay; /* delay for keep rules */
+ zAVLTree * counterlist; /* counters if EVAL_SUM */
+ struct sh_qeval * queue; /* queue for this rule */
+ struct sh_geval * nextrule; /* next rule in this group */
+ struct sh_geval * next; /* next group of rules */
+ struct sh_geval * gnext; /* grouplist next */
+};
+
+struct sh_heval /* host-specific rules */
+{
+ pcre * hostname; /* compiled regex for hostname */
+ pcre_extra * hostname_extra;
+ struct sh_geval * rulegroups; /* list of group of rules */
+ struct sh_heval * next;
+};
+
+static struct sh_heval * hostlist = NULL;
+static struct sh_qeval * queuelist = NULL;
+static struct sh_geval * grouplist = NULL;
+
+/* These flags are set if we are within
+ * the define of a host/rule group.
+ */
+static struct sh_heval * host_open = NULL;
+static struct sh_geval * group_open = NULL;
+
+int sh_eval_gend (const char * str)
+{
+ (void) str;
+ if (group_open) {
+ group_open = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+int sh_eval_gadd (const char * str)
+{
+ struct sh_geval * ng;
+ struct sh_geval * tmp;
+ pcre * group;
+ pcre_extra * group_extra;
+ const char * error;
+ int erroffset;
+ unsigned int nfields = 2;
+ size_t lengths[2];
+ char * new = sh_util_strdup(str);
+ char ** splits = split_array(new, &nfields, ':', lengths);
+
+ /* group is label:regex
+ */
+
+ if (group_open)
+ group_open = NULL;
+
+ if (nfields != 2)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ group = pcre_compile(splits[1], PCRE_NO_AUTO_CAPTURE,
+ &error, &erroffset, NULL);
+ if (!group)
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Bad regex: "));
+ sh_string_add_from_char(msg, splits[1]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_eval_gadd"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+ group_extra = NULL; /* pcre_study(group, 0, &error); */
+
+ ng = SH_ALLOC(sizeof(struct sh_geval));
+ memset(ng, '\0', sizeof(struct sh_geval));
+
+ ng->label = sh_string_new_from_lchar(splits[0], lengths[0]);
+ ng->flags = RFL_ISGROUP;
+
+ ng->rule = group;
+ ng->rule_extra = group_extra;
+ ng->ovector = NULL;
+ ng->ovecnum = 0;
+ ng->captures = 0;
+ ng->counterlist = NULL;
+ ng->queue = NULL;
+ ng->nextrule = NULL;
+ ng->next = NULL;
+ ng->gnext = NULL;
+
+ if (!host_open)
+ {
+ if (0 != sh_eval_hadd("^.*"))
+ {
+ pcre_free(group);
+ sh_string_destroy(&(ng->label));
+ SH_FREE(splits);
+ SH_FREE(new);
+ SH_FREE(ng);
+ return -1;
+ }
+ }
+
+ /*
+ * Insert at end, to keep user-defined order
+ */
+
+ if (host_open)
+ {
+ if (grouplist)
+ {
+ tmp = grouplist;
+ while (tmp->gnext != NULL) { tmp = tmp->gnext; }
+ tmp->gnext = ng;
+ } else {
+ grouplist = ng;
+ }
+
+
+ /*
+ * If there is an open host group, add it to its
+ * rulegroups
+ */
+
+ if (host_open->rulegroups)
+ {
+ tmp = host_open->rulegroups;
+ while (tmp->next != NULL) { tmp = tmp->next; }
+ tmp->next = ng;
+ } else {
+ host_open->rulegroups = ng;
+ }
+ }
+
+ group_open = ng;
+ SH_FREE(splits);
+ SH_FREE(new);
+ return 0;
+}
+
+int sh_eval_hend (const char * str)
+{
+ (void) str;
+ if (host_open) {
+ host_open = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+int sh_eval_hadd (const char * str)
+{
+ struct sh_heval * nh;
+ struct sh_heval * tmp;
+ pcre * host;
+ pcre_extra * host_extra;
+ const char * error;
+ int erroffset;
+
+ if (host_open)
+ host_open = NULL;
+
+ host = pcre_compile(str, PCRE_NO_AUTO_CAPTURE,
+ &error, &erroffset, NULL);
+ if (!host)
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Bad regex: "));
+ sh_string_add_from_char(msg, str);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_eval_hadd"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ return -1;
+ }
+ host_extra = NULL; /* pcre_study(host, 0, &error); */
+
+ nh = SH_ALLOC(sizeof(struct sh_heval));
+ memset(nh, '\0', sizeof(struct sh_heval));
+
+ nh->hostname = host;
+ nh->hostname_extra = host_extra;
+ nh->rulegroups = NULL;
+
+ /*
+ * Insert at end, to keep user-defined order
+ */
+ nh->next = NULL;
+ if (hostlist) {
+ tmp = hostlist;
+ while (tmp->next != NULL) { tmp = tmp->next; }
+ tmp->next = nh;
+ } else {
+ hostlist = nh;
+ }
+ host_open = nh;
+
+ return 0;
+}
+
+int sh_eval_qadd (const char * str)
+{
+ struct sh_qeval * nq;
+ int severity;
+ unsigned int nfields = 5; /* label:interval:(report|sum):severity[:alias] */
+ size_t lengths[5];
+ char * new = sh_util_strdup(str);
+ char ** splits = split_array(new, &nfields, ':', lengths);
+
+ if (nfields < 4)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ if (strcmp(splits[2], _("sum")) && strcmp(splits[2], _("report")))
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ if (!strcmp(splits[2], _("sum")) && atoi(splits[1]) < 0)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ if (!strcmp(splits[1], _("trash"))) /* predefined, reserved */
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ severity = sh_error_convert_level (splits[3]);
+ if (severity < 0)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ nq = SH_ALLOC(sizeof(struct sh_qeval));
+ memset(nq, '\0', sizeof(struct sh_qeval));
+
+ nq->label = sh_string_new_from_lchar(splits[0], lengths[0]);
+ nq->alias = NULL;
+
+ DEBUG("debug: splits[2] = %s, policy = %d\n",splits[2],nq->policy);
+ if (0 == strcmp(splits[2], _("report"))) {
+ nq->policy = EVAL_REPORT;
+ nq->interval = 0;
+ }
+ else {
+ nq->policy = EVAL_SUM;
+ nq->interval = (time_t) atoi(splits[1]);
+ }
+
+ nq->severity = severity;
+
+ if (nfields == 5)
+ {
+ nq->alias = sh_string_new_from_lchar(splits[4], lengths[4]);
+ }
+
+ nq->next = queuelist;
+ queuelist = nq;
+
+ SH_FREE(splits);
+ SH_FREE(new);
+ return 0;
+}
+
+struct sh_qeval * sh_log_find_queue(const char * str)
+{
+ struct sh_qeval * retval = queuelist;
+
+ if (!str)
+ return NULL;
+
+ while (retval)
+ {
+ if (0 == strcmp(str, sh_string_str(retval->label)))
+ break;
+ retval = retval->next;
+ }
+ return retval;
+}
+
+int sh_log_lookup_severity(const char * str)
+{
+ struct sh_qeval * queue;
+
+ if (str)
+ {
+ if (0 != strcmp(str, _("trash")))
+ {
+ queue = sh_log_find_queue(str);
+
+ if (queue)
+ return queue->severity;
+ }
+ }
+ return SH_ERR_SEVERE;
+}
+
+sh_string * sh_log_lookup_alias(const char * str)
+{
+ struct sh_qeval * queue;
+
+ if (str)
+ {
+ if (0 != strcmp(str, _("trash")))
+ {
+ queue = sh_log_find_queue(str);
+
+ if (queue)
+ return queue->alias;
+ }
+ }
+ return NULL;
+}
+
+
+static char * get_label_and_time(const char * inprefix, char * str,
+ unsigned long * seconds)
+{
+ char * res = NULL;
+ char * endptr = NULL;
+
+ unsigned int nfields = 2; /* seconds:label */
+ size_t lengths[2];
+ char * prefix = sh_util_strdup(inprefix);
+ char * new = sh_util_strdup(str);
+ char ** splits = split_array_braced(new, prefix, &nfields, lengths);
+
+ if (splits && nfields == 2 && lengths[0] > 0 && lengths[1] > 0)
+ {
+ *seconds = strtoul(splits[0], &endptr, 10);
+ if ((endptr == '\0' || endptr != splits[0]) && (*seconds != ULONG_MAX))
+ {
+ res = sh_util_strdup(splits[1]);
+ }
+ }
+ if (splits)
+ SH_FREE(splits);
+ SH_FREE(new);
+ SH_FREE(prefix);
+ return res;
+}
+
+struct sh_qeval ** sh_dummy_472_queue;
+char ** sh_dummy_473_dstr;
+
+int sh_eval_radd (const char * str)
+{
+ struct sh_geval * nr;
+ struct sh_geval * tmp;
+ struct sh_qeval * queue;
+ pcre * rule;
+ pcre_extra * rule_extra;
+ const char * error;
+ int erroffset;
+ int captures = 0;
+ unsigned int nfields = 2; /* queue:regex */
+ size_t lengths[3];
+ char * new = sh_util_strdup(str);
+ char ** splits;
+
+ int qpos = 0;
+ volatile int rpos = 1;
+ unsigned long dsec = 0;
+ char * dstr = NULL;
+ char * s = new;
+ volatile char pflag = '-';
+
+ while ( *s && isspace((int)*s) ) ++s;
+ if (0 == strncmp(s, _("KEEP"), 4) ||
+ 0 == strncmp(s, _("CORRELATE"), 9) ||
+ 0 == strncmp(s, _("MARK"), 4))
+ {
+ pflag = s[0];
+ nfields = 3;
+ }
+
+ splits = split_array(new, &nfields, ':', lengths);
+
+ sh_dummy_472_queue = &queue;
+ sh_dummy_473_dstr = &dstr;
+
+ queue = NULL;
+
+ if (nfields < 2 || nfields > 3)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+
+ if (nfields == 3)
+ {
+ if (pflag == 'K')
+ {
+ /* KEEP(nsec,label):queue:regex
+ */
+ dstr = get_label_and_time(_("KEEP"), splits[0], &dsec);
+ if (!dstr)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+ }
+ else if (pflag == 'C')
+ {
+ /* CORRELATE(description):queue:regex
+ */
+ int retval = sh_keep_match_add(splits[0], splits[1], splits[2]);
+ SH_FREE(splits);
+ SH_FREE(new);
+ return retval;
+ }
+ else if (pflag == 'M')
+ {
+ /* MARK(description, interval):queue:regex
+ */
+ int retval = -1;
+
+ dstr = get_label_and_time(_("MARK"), splits[0], &dsec);
+ if (dstr)
+ {
+ retval = sh_log_mark_add(dstr, dsec, splits[1]);
+ }
+ if (retval != 0)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return retval;
+ }
+ }
+ ++qpos; ++rpos;
+ }
+
+ if (0 != strcmp(splits[qpos], _("trash")))
+ {
+ queue = sh_log_find_queue(splits[qpos]);
+ if (!queue)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+ }
+
+ rule = pcre_compile(splits[rpos], 0,
+ &error, &erroffset, NULL);
+ if (!rule)
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Bad regex: "));
+ sh_string_add_from_char(msg, splits[rpos]);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_eval_radd"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+
+ SH_FREE(splits);
+ SH_FREE(new);
+ return -1;
+ }
+ rule_extra = NULL; /* pcre_study(rule, 0, &error); */
+ pcre_fullinfo(rule, rule_extra, PCRE_INFO_CAPTURECOUNT, &captures);
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ if (dstr)
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures, keep(%lu,%s)"),
+ splits[rpos], captures, dsec, dstr);
+ else
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures"),
+ splits[rpos], captures);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("sh_eval_radd"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+
+ DEBUG("adding rule: |%s| with %d captures\n", splits[rpos], captures);
+
+ SH_FREE(splits);
+ SH_FREE(new);
+
+ nr = SH_ALLOC(sizeof(struct sh_geval));
+ memset(nr, '\0', sizeof(struct sh_geval));
+
+ nr->label = NULL;
+ nr->flags = RFL_ISRULE;
+ nr->delay = 0;
+
+ nr->rule = rule;
+ nr->rule_extra = rule_extra;
+ nr->captures = captures;
+ nr->ovector = SH_ALLOC(sizeof(int) * (captures+1) * 3);
+ nr->ovecnum = 0;
+ nr->counterlist = NULL;
+ nr->queue = queue;
+ nr->nextrule = NULL;
+ nr->next = NULL;
+ nr->gnext = NULL;
+
+
+ if (pflag == 'K')
+ {
+ nr->label = sh_string_new_from_lchar(dstr, sl_strlen(dstr));
+ nr->flags |= RFL_KEEP;
+ nr->delay = dsec;
+ SH_FREE(dstr);
+ }
+ else if (pflag == 'M')
+ {
+ nr->label = sh_string_new_from_lchar(dstr, sl_strlen(dstr));
+ nr->flags |= RFL_MARK;
+ nr->delay = dsec;
+ SH_FREE(dstr);
+ }
+
+ /*
+ * If there is an open group, add it to its
+ * rules
+ */
+ if (group_open)
+ {
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Adding rule to group |%s|"),
+ sh_string_str(group_open->label));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("sh_eval_radd"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+
+ DEBUG("adding rule to group |%s|\n", sh_string_str(group_open->label));
+
+ if (group_open->nextrule)
+ {
+ tmp = group_open->nextrule;
+ while (tmp->nextrule != NULL) { tmp = tmp->nextrule; } /* next -> nextrule */
+ tmp->nextrule = nr; /* next -> nextrule */
+ } else {
+ group_open->nextrule = nr;
+ }
+ }
+
+ /*
+ * ..else, add it to the currently open host (open the
+ * default host, if there is no open one)
+ */
+ else
+ {
+ if (!host_open)
+ {
+ if (0 != sh_eval_hadd("^.*"))
+ {
+ if (nr->label)
+ sh_string_destroy(&(nr->label));
+ SH_FREE(nr->ovector);
+ SH_FREE(nr);
+ return -1;
+ }
+ }
+
+ if (host_open)
+ {
+ /*
+ * Add rule as member to grouplist, to facilitate cleanup
+ */
+
+ DEBUG("adding solitary rule to grouplist\n");
+
+ if (grouplist)
+ {
+ tmp = grouplist;
+ while (tmp->gnext != NULL) { tmp = tmp->gnext; }
+ tmp->gnext = nr;
+ } else {
+ grouplist = nr;
+ }
+
+
+ /*
+ * Add rule to host rulegroups
+ */
+ DEBUG("adding solitary rule to host rulegroups\n");
+
+ if (host_open->rulegroups)
+ {
+ /* Second, third, ... rule go to host_open->rulegroups->next,
+ * since test_grules() iterates over nextrules
+ */
+ tmp = host_open->rulegroups;
+ while (tmp->next != NULL) { tmp = tmp->next; }
+ tmp->next = nr;
+ }
+ else
+ {
+ /* First rule goes to host_open->rulegroups */
+ host_open->rulegroups = nr;
+ }
+ }
+ else
+ {
+ if (nr->label)
+ sh_string_destroy(&(nr->label));
+ SH_FREE(nr->ovector);
+ SH_FREE(nr);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void sh_eval_cleanup()
+{
+ struct sh_geval * gtmp;
+ struct sh_qeval * qtmp;
+ struct sh_heval * htmp;
+
+ while (grouplist)
+ {
+ gtmp = grouplist;
+ grouplist = gtmp->gnext;
+
+ if (gtmp->label) sh_string_destroy(&(gtmp->label));
+ if (gtmp->rule_extra) (*pcre_free)(gtmp->rule_extra);
+ if (gtmp->rule) (*pcre_free)(gtmp->rule);
+ if (gtmp->counterlist)
+ zAVLFreeTree(gtmp->counterlist, sh_ceval_free);
+ if (gtmp->ovector)
+ SH_FREE(gtmp->ovector);
+#if 0
+ while (gtmp->nextrule)
+ {
+ tmp = gtmp->nextrule;
+ gtmp->nextrule = tmp->nextrule;
+
+ if (tmp->rule_extra) (*pcre_free)(tmp->rule_extra);
+ if (tmp->rule) (*pcre_free)(tmp->rule);
+ if (tmp->counterlist)
+ zAVLFreeTree(tmp->counterlist, sh_ceval_free);
+ if (tmp->ovector)
+ SH_FREE(tmp->ovector);
+ SH_FREE(tmp);
+ }
+#endif
+ SH_FREE(gtmp);
+ }
+
+ qtmp = queuelist;
+ while (qtmp)
+ {
+ if (qtmp->label) sh_string_destroy(&(qtmp->label));
+ queuelist = qtmp->next;
+ SH_FREE(qtmp);
+ qtmp = queuelist;
+ }
+
+ htmp = hostlist;
+ while (htmp)
+ {
+ if (htmp->hostname_extra) (*pcre_free)(htmp->hostname_extra);
+ if (htmp->hostname) (*pcre_free)(htmp->hostname);
+ if (htmp->rulegroups) htmp->rulegroups = NULL;
+ hostlist = htmp->next;
+ htmp->next = NULL;
+ SH_FREE(htmp);
+ htmp = hostlist;
+ }
+
+ hostlist = NULL;
+ queuelist = NULL;
+ grouplist = NULL;
+
+ host_open = NULL;
+ group_open = NULL;
+
+ sh_keep_destroy();
+ sh_keep_match_del();
+
+ return;
+}
+
+/**********************************************************************
+ *
+ * Actual rule processing
+ *
+ **********************************************************************/
+
+/* Test a list of rules against msg; return matched rule, with ovector
+ * filled in
+ */
+struct sh_geval ** sh_dummy_828_rule;
+
+static struct sh_geval * test_rule (struct sh_geval * rule, sh_string *msg, time_t tstamp)
+{
+ int res;
+ volatile int count;
+ volatile time_t timestamp = tstamp;
+
+ sh_dummy_828_rule = &rule;
+
+ if (!rule)
+ DEBUG("debug: (NULL) rule\n");
+
+ if (rule && sh_string_len(msg) < (size_t)INT_MAX)
+ {
+ count = 1;
+ do {
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Check rule %d for |%s|"),
+ count, sh_string_str(msg));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("test_rule"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+
+ DEBUG("debug: check rule %d for <%s>\n", count, msg->str);
+ res = pcre_exec(rule->rule, rule->rule_extra,
+ sh_string_str(msg), (int)sh_string_len(msg), 0,
+ 0, rule->ovector, (3*(1+rule->captures)));
+ if (res >= 0)
+ {
+ rule->ovecnum = res;
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ if ( rule->flags & RFL_KEEP )
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d matches, result = %d (keep)"),
+ count, res);
+ else if ( rule->flags & RFL_MARK )
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d matches, result = %d (mark)"),
+ count, res);
+ else
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d matches, result = %d"),
+ count, res);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("test_rule"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+
+ if ( rule->flags & RFL_KEEP )
+ {
+ DEBUG("debug: rule %d matches (keep), timestamp = %lu\n", count, timestamp);
+ sh_keep_add(rule->label, rule->delay,
+ timestamp == 0 ? time(NULL) : timestamp);
+ }
+
+ else if ( rule->flags & RFL_MARK )
+ {
+ DEBUG("debug: rule %d matches (mark)\n", count);
+ sh_log_mark_update(rule->label,
+ timestamp == 0 ? time(NULL) : timestamp);
+ }
+
+ break; /* return the matching rule; ovector is filled in */
+ }
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Rule %d did not match"),
+ count);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("test_rule"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+ DEBUG("debug: rule %d did not match\n", count);
+
+ rule = rule->nextrule; ++count;
+ } while (rule);
+ }
+ if (!rule)
+ DEBUG("debug: no match found\n");
+ /* If there was no match, this is NULL */
+ sh_dummy_828_rule = NULL;
+ return rule;
+}
+
+/* Test a (struct sh_geval *), which may be single rule or a group of rules,
+ * against msg
+ */
+struct sh_geval ** sh_dummy_928_result;
+struct sh_geval ** sh_dummy_929_group;
+
+static struct sh_geval * test_grules (struct sh_heval * host,
+ sh_string * msg,
+ time_t timestamp)
+{
+ struct sh_geval * result = NULL;
+ struct sh_geval * group = host->rulegroups;
+
+ sh_dummy_928_result = &result;
+ sh_dummy_929_group = &group;
+
+ if (group && sh_string_len(msg) < (size_t)INT_MAX)
+ {
+ DEBUG("debug: if group\n");
+ do {
+ if( (group->label != NULL) && (0 != (group->flags & RFL_ISGROUP)))
+ {
+ /* this is a rule group */
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Checking group |%s| of rules against |%s|"),
+ sh_string_str(group->label), sh_string_str(msg));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("test_rule"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+
+ DEBUG("debug: if group->label %s\n", sh_string_str(group->label));
+ if (pcre_exec(group->rule, group->rule_extra,
+ sh_string_str(msg), (int) sh_string_len(msg),
+ 0, 0, NULL, 0) >= 0)
+ {
+ result = test_rule(group->nextrule, msg, timestamp);
+ if (result)
+ break;
+ }
+ }
+ else
+ {
+ /* If there is no group label, the 'group' is actually a solitary
+ * rule (not within any group).
+ */
+
+ if (flag_err_debug == S_TRUE)
+ {
+ char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
+ sl_snprintf(emsg, SH_ERRBUF_SIZE, _("Checking solitary rules"));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ emsg, _("test_rule"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(emsg);
+ }
+
+ DEBUG("debug: else (single rule)\n");
+ result = test_rule(group, msg, timestamp);
+ if (result)
+ break;
+ }
+ group = group->next; /* next group of rules */
+ } while (group);
+ }
+
+ sh_dummy_928_result = NULL;
+ sh_dummy_929_group = NULL;
+ return result;
+}
+
+/* Top-level find_rule() function
+ */
+static struct sh_geval * find_rule (sh_string *host,
+ sh_string *msg,
+ time_t timestamp)
+{
+ struct sh_geval * result = NULL;
+ struct sh_heval * hlist = hostlist;
+
+ if (hlist && sh_string_len(host) < (size_t)INT_MAX)
+ {
+ do {
+ if (pcre_exec(hlist->hostname, hlist->hostname_extra,
+ sh_string_str(host), (int) sh_string_len(host),
+ 0, 0, NULL, 0) >= 0)
+ {
+ /* matching host, check rules/groups of rules */
+ result = test_grules(hlist, msg, timestamp);
+ if (result)
+ break;
+ }
+ hlist = hlist->next;
+ } while (hlist);
+ }
+ return result;
+}
+
+/* copy the message and replace captured substrings with '___'
+ */
+static sh_string * replace_captures(const sh_string * message,
+ int * ovector, int ovecnum)
+{
+ sh_string * retval = sh_string_new_from_lchar(sh_string_str(message),
+ sh_string_len(message));
+
+ if (ovecnum > 1)
+ {
+ retval = sh_string_replace(retval, &(ovector[2]), (ovecnum-1), "___", 3);
+ }
+ return retval;
+}
+
+static void msg_report(int severity, const sh_string * alias,
+ struct sh_geval * rule, struct sh_logrecord * record)
+{
+ char * tmp;
+ char * msg;
+ sh_string * mmm = NULL;
+ char * ttt;
+
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ if (rule) {
+ mmm = replace_captures(record->message, rule->ovector,
+ rule->ovecnum);
+ rule->ovecnum = 0;
+ msg = sh_util_safe_name_keepspace (sh_string_str(mmm));
+ }
+ else {
+ msg = sh_util_safe_name_keepspace (sh_string_str(record->message));
+ }
+ tmp = sh_util_safe_name_keepspace (record->filename);
+ ttt = sh_util_safe_name_keepspace (sh_string_str(record->timestr));
+ sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_REP,
+ msg,
+ ttt,
+ sh_string_str(record->host),
+ tmp);
+ if (alias)
+ {
+ sh_error_mail (sh_string_str(alias),
+ severity, FIL__, __LINE__, 0, MSG_LOGMON_REP,
+ msg,
+ ttt,
+ sh_string_str(record->host),
+ tmp);
+ }
+ SH_FREE(ttt);
+ SH_FREE(msg);
+ SH_FREE(tmp);
+ if (mmm)
+ sh_string_destroy(&mmm);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+}
+
+static void sum_report(int severity, const sh_string * alias,
+ sh_string * host, sh_string * message, sh_string * path)
+{
+ char * tmp;
+ char * msg;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name_keepspace (sh_string_str(path));
+ msg = sh_util_safe_name_keepspace (sh_string_str(message));
+ sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_SUM,
+ msg,
+ sh_string_str(host),
+ tmp);
+ if (alias)
+ {
+ sh_error_mail (sh_string_str(alias),
+ severity, FIL__, __LINE__, 0, MSG_LOGMON_SUM,
+ msg,
+ sh_string_str(host),
+ tmp);
+ }
+ SH_FREE(msg);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+}
+
+static zAVLKey sh_eval_getkey(void const *item)
+{
+ return ((const struct sh_ceval *)item)->hostname->str;
+}
+
+/* Find the counter, or initialize one if there is none already
+ */
+static struct sh_ceval * find_counter(struct sh_geval * rule,
+ sh_string * host, time_t interval)
+{
+ struct sh_ceval * counter;
+
+ if (!(rule->counterlist))
+ {
+ DEBUG("debug: allocate new counterlist AVL tree\n");
+ rule->counterlist = zAVLAllocTree(sh_eval_getkey, zAVL_KEY_STRING);
+ }
+
+ counter = (struct sh_ceval *) zAVLSearch (rule->counterlist,
+ sh_string_str(host));
+
+ if (!counter)
+ {
+ DEBUG("debug: no counter found\n");
+
+ counter = SH_ALLOC(sizeof(struct sh_ceval));
+ memset(counter, '\0', sizeof(struct sh_ceval));
+
+ counter->hostname = sh_string_new_from_lchar(sh_string_str(host),
+ sh_string_len(host));
+ counter->counted_str = NULL;
+ counter->filename = NULL;
+ counter->count = 0;
+ counter->start = time(NULL);
+ counter->interval = interval;
+
+ zAVLInsert(rule->counterlist, counter);
+ }
+ return counter;
+
+}
+
+
+/* process the counter for a SUM rule
+ */
+static int process_counter(struct sh_ceval * counter,
+ struct sh_geval * rule,
+ struct sh_logrecord * record)
+{
+ int retval = -1;
+ time_t now;
+
+ if (!(counter->counted_str))
+ {
+ counter->counted_str = replace_captures(record->message, rule->ovector,
+ rule->ovecnum);
+ rule->ovecnum = 0;
+ counter->filename = sh_string_new_from_lchar(record->filename,
+ strlen(record->filename));
+ DEBUG("debug: counted_str after replace: %s\n",
+ sh_string_str(counter->counted_str));
+ }
+
+ ++(counter->count);
+ now = time(NULL); now -= counter->start;
+ DEBUG("debug: count %lu, interval %lu, time %lu\n",
+ counter->count, counter->interval, now);
+ if (now >= counter->interval)
+ {
+ DEBUG("debug: report count\n");
+ sum_report(rule->queue->severity, rule->queue->alias,
+ counter->hostname, counter->counted_str, counter->filename);
+ counter->start = time(NULL);
+ counter->count = 0;
+ }
+ return retval;
+}
+
+/* Process a rule
+ */
+static int process_rule(struct sh_geval * rule, struct sh_logrecord * record)
+{
+ int retval = -1;
+ struct sh_qeval * queue = rule->queue;
+
+ if (queue)
+ {
+ DEBUG("debug: queue policy = %d found\n", queue->policy);
+ if (queue->policy == EVAL_REPORT)
+ {
+ DEBUG("debug: EVAL_REPORT host: %s, message: %s\n",
+ sh_string_str(record->host),
+ sh_string_str(record->message));
+ msg_report(queue->severity, queue->alias, rule, record);
+ retval = 0;
+ }
+ else if (queue->policy == EVAL_SUM)
+ {
+
+ struct sh_ceval * counter =
+ find_counter(rule, record->host, queue->interval);
+ DEBUG("debug: EVAL_SUM host: %s, message: %s\n",
+ sh_string_str(record->host),
+ sh_string_str(record->message));
+ if (counter)
+ {
+ DEBUG("debug: counter found\n");
+ retval = process_counter(counter, rule, record);
+ }
+ }
+ }
+ else
+ {
+ DEBUG("debug: no queue found -- trash\n");
+ /* No queue means 'trash' */
+ retval = 0;
+ }
+ return retval;
+}
+
+#define DEFAULT_SEVERITY (-1)
+
+int sh_eval_process_msg(struct sh_logrecord * record)
+{
+ static unsigned long i = 0;
+ if (record)
+ {
+ struct sh_geval * rule = find_rule (record->host,
+ record->message,
+ record->timestamp);
+
+ if (rule)
+ {
+ DEBUG("debug: (%lu) rule found\n", i); ++i;
+ return process_rule(rule, record);
+ }
+ else
+ {
+ DEBUG("debug: (%lu) no rule found\n", i); ++i;
+ msg_report(DEFAULT_SEVERITY, NULL, NULL, record);
+ }
+
+ sh_repeat_message_check(record->host,
+ record->message,
+ record->timestamp);
+
+ return 0;
+ }
+ return -1;
+}
+
+#endif
diff --git a/src/sh_log_mark.c b/src/sh_log_mark.c
new file mode 100644
index 0000000..cf006ab
--- /dev/null
+++ b/src/sh_log_mark.c
@@ -0,0 +1,250 @@
+#include "config_xor.h"
+
+#ifdef USE_LOGFILE_MONITOR
+
+#include <string.h>
+#include <time.h>
+
+#undef FIL__
+#define FIL__ _("sh_log_mark.c")
+
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_mem.h"
+#include "sh_string.h"
+#include "sh_error_min.h"
+#include "sh_log_check.h"
+#include "sh_log_evalrule.h"
+#include "zAVLTree.h"
+
+/* #define DEBUG_MARK */
+
+#ifdef DEBUG_MARK
+static void DEBUG(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap); /* flawfinder: ignore *//* we control fmt string */
+ va_end(ap);
+ return;
+}
+#else
+static void DEBUG(const char *fmt, ...)
+{
+ (void) fmt;
+ return;
+}
+#endif
+
+static zAVLTree * marklist = NULL;
+
+struct sh_mark_event
+{
+ sh_string * label;
+ sh_string * queue_id;
+ time_t last_seen;
+ time_t interval;
+ time_t delay;
+ time_t last_reported;
+};
+
+static void sh_marklist_free(void * item)
+{
+ struct sh_mark_event * event = (struct sh_mark_event *) item;
+ if (!event)
+ return;
+ sh_string_destroy(&(event->label));
+ sh_string_destroy(&(event->queue_id));
+ SH_FREE(event);
+ return;
+}
+
+void sh_log_mark_destroy()
+{
+ zAVLFreeTree(marklist, sh_marklist_free);
+}
+
+static zAVLKey sh_log_mark_getkey(void const *item)
+{
+ return ((const struct sh_mark_event *)item)->label->str;
+}
+
+int sh_log_mark_add (const char * label, time_t interval, const char * qlabel)
+{
+ struct sh_mark_event * event;
+
+ if (!(marklist))
+ {
+ marklist = zAVLAllocTree(sh_log_mark_getkey, zAVL_KEY_STRING);
+ }
+
+ event = (struct sh_mark_event *) zAVLSearch(marklist, label);
+ if (event)
+ {
+ event->interval = interval;
+ sh_string_destroy(&(event->queue_id));
+ event->queue_id = sh_string_new_from_lchar(qlabel, strlen(qlabel));
+ return 0;
+ }
+
+ event = SH_ALLOC(sizeof(struct sh_mark_event));
+
+ event->last_seen = time(NULL);
+ event->interval = interval;
+ event->delay = 0;
+ event->last_reported = 0;
+ event->label = sh_string_new_from_lchar(label, strlen(label));
+ event->queue_id = sh_string_new_from_lchar(qlabel, strlen(qlabel));
+
+ if (0 != zAVLInsert(marklist, event))
+ {
+ sh_marklist_free(event);
+ return -1;
+ }
+ return 0;
+}
+
+void sh_log_mark_update (sh_string * label, time_t timestamp)
+{
+ struct sh_mark_event * event =
+ (struct sh_mark_event *) zAVLSearch (marklist, sh_string_str(label));
+
+ DEBUG("debug: running mark update for %s\n", sh_string_str(label));
+
+ if (event)
+ {
+ DEBUG("debug: updating, timestamp %lu, last_seen %lu, interval %d\n",
+ (unsigned long)timestamp, (unsigned long) event->last_seen,
+ (int)event->interval);
+
+ if ((timestamp > event->last_seen) &&
+ (event->interval < (timestamp - event->last_seen)) &&
+ (timestamp > event->last_reported) &&
+ (event->interval < (timestamp - event->last_reported)))
+ {
+ event->delay = timestamp - event->last_seen;
+ DEBUG("debug: updating delay to %d\n", (int) event->delay);
+ }
+ event->last_seen = timestamp;
+ }
+ return;
+}
+
+/* This should allow to get all overdue labels with a for loop like:
+ * for (label = sh_log_mark_first(); label; label = sh_log_mark_next()) {}
+ */
+
+static zAVLCursor mark_cursor;
+
+static struct sh_mark_event * sh_log_mark_cursor(time_t * delay, time_t now,
+ struct sh_mark_event * event)
+{
+ while (event)
+ {
+ DEBUG("debug: echeck, delay %d, now %lu, last_seen %lu, reported %lu\n",
+ (int) event->delay,
+ (unsigned long)now, (unsigned long) event->last_seen,
+ (unsigned long)event->last_reported);
+ if (event->delay > 0)
+ {
+ DEBUG("debug: event delay > 0, value %d\n", (int) event->delay);
+ *delay = event->delay;
+ event->delay = 0;
+ event->last_reported = time(NULL);
+ return event;
+ }
+ else if ((now > event->last_seen) &&
+ (now > event->last_reported) &&
+ (event->interval < (now - event->last_seen)) &&
+ (event->interval < (now - event->last_reported))
+ )
+ {
+ DEBUG("debug: event delay 0, now %lu, last_seen %lu, reported %lu\n",
+ (unsigned long)now, (unsigned long) event->last_seen,
+ (unsigned long)event->last_reported);
+ *delay = now - event->last_seen;
+ event->delay = 0;
+ /* Subtract 1 sec to prevent accumulation of the
+ * one second offset. */
+ event->last_reported = time(NULL) - 1;
+ return event;
+ }
+ event = (struct sh_mark_event *) zAVLNext(&mark_cursor);
+ }
+
+ return NULL;
+}
+
+struct sh_mark_event * sh_log_mark_first(time_t * delay, time_t now)
+{
+ struct sh_mark_event * event =
+ (struct sh_mark_event *) zAVLFirst(&mark_cursor, marklist);
+
+ return sh_log_mark_cursor (delay, now, event);
+}
+
+struct sh_mark_event * sh_log_mark_next(time_t * delay, time_t now)
+{
+ struct sh_mark_event * event =
+ (struct sh_mark_event *) zAVLNext(&mark_cursor);
+
+ return sh_log_mark_cursor (delay, now, event);
+}
+
+static int sh_mark_default_severity = SH_ERR_SEVERE;
+
+int sh_log_set_mark_severity (const char * str)
+{
+ int val = sh_error_convert_level(str);
+ if (val < 0)
+ return -1;
+ sh_mark_default_severity = val;
+ return 0;
+}
+
+static struct sh_mark_event ** dummy_event;
+
+void sh_log_mark_check()
+{
+ struct sh_mark_event * event;
+ time_t now = time(NULL);
+ time_t delay;
+
+ /* variable 'event' might be clobbered by 'longjmp' or 'vfork'
+ */
+ dummy_event = &event;
+
+ DEBUG("debug: running mark check\n");
+ for (event = sh_log_mark_first(&delay, now); event;
+ event = sh_log_mark_next (&delay, now))
+ {
+ int severity;
+ sh_string * alias;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+
+ severity = sh_log_lookup_severity(sh_string_str(event->queue_id));
+ if (severity < 0)
+ severity = sh_mark_default_severity;
+
+ DEBUG("debug: mark check: queue %s, severity %d\n",
+ sh_string_str(event->queue_id), severity);
+ sh_error_handle (severity,
+ FIL__, __LINE__, 0, MSG_LOGMON_MARK,
+ sh_string_str(event->label),
+ (unsigned long) delay);
+ alias = sh_log_lookup_alias(sh_string_str(event->queue_id));
+ if (alias)
+ {
+ sh_error_mail (sh_string_str(alias), severity,
+ FIL__, __LINE__, 0, MSG_LOGMON_MARK,
+ sh_string_str(event->label),
+ (unsigned long) delay);
+ }
+
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ return;
+}
+
+#endif
diff --git a/src/sh_log_parse_apache.c b/src/sh_log_parse_apache.c
new file mode 100644
index 0000000..06cdf4e
--- /dev/null
+++ b/src/sh_log_parse_apache.c
@@ -0,0 +1,446 @@
+/**************************************
+ **
+ ** PARSER RULES
+ **
+ ** (a) must set record->host
+ ** (eventually to dummy value)
+ **
+ ** (b) must set record->prefix
+ ** (itoa(status))
+ **
+ **
+ **************************************/
+
+/* for strptime */
+#define _XOPEN_SOURCE 500
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#ifdef USE_LOGFILE_MONITOR
+
+#undef FIL__
+#define FIL__ _("sh_log_parse_apache.c")
+
+/* Debian/Ubuntu: libpcre3-dev */
+#ifdef HAVE_PCRE_PCRE_H
+#include <pcre/pcre.h>
+#else
+#include <pcre.h>
+#endif
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_log_check.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+
+extern int flag_err_debug;
+
+struct sh_fileinfo_apache {
+ pcre * line_regex;
+ int * line_ovector; /* captured substrings */
+ int line_ovecnum; /* how many captured */
+
+ int pos_host;
+ int pos_status;
+ int pos_time;
+ char * format_time;
+};
+
+static const char lf_error0[] = N_("%error");
+static const char lf_common0[] = N_("%h %l %u %t \"%r\" %>s %b");
+static const char lf_combined0[] = N_("%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
+
+/* This variable is not used anywhere. It only exist
+ * to assign &new to them, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+void * sh_dummy_65_new = NULL;
+void * sh_dummy_66_fti = NULL;
+void * sh_dummy_67_ftr = NULL;
+
+void * sh_eval_fileinfo_apache(char * str)
+{
+ struct sh_fileinfo_apache * result = NULL;
+ unsigned int i, quotes;
+ unsigned int nfields = 64;
+ size_t lengths[64];
+ char * new = NULL;
+ char ** splits;
+ char * token;
+ sh_string * re_string;
+ char * p;
+ volatile int p_host = -1;
+ volatile int p_status = -1;
+ volatile int p_time = -1;
+ char * f_time = NULL;
+ const char * error;
+ int erroffset;
+
+ /* Take the address to keep gcc from putting them into registers.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_65_new = (void*) &new;
+ sh_dummy_66_fti = (void*) &f_time;
+ sh_dummy_67_ftr = (void*) &result;
+
+ if (0 == strncmp("common", str, 6))
+ {
+ new = sh_util_strdup(_(lf_common0));
+ }
+ else if (0 == strncmp("combined", str, 8))
+ {
+ new = sh_util_strdup(_(lf_combined0));
+ }
+ else if (0 == strncmp("error", str, 8))
+ {
+ new = sh_util_strdup(_(lf_error0));
+ }
+ else
+ {
+ new = sh_util_strdup(str);
+ }
+
+ if (flag_err_debug == S_TRUE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ new,
+ _("eval_fileinfo"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ splits = split_array_ws(new, &nfields, lengths);
+
+ if (nfields < 1)
+ {
+ SH_FREE(splits);
+ SH_FREE(new);
+ return NULL;
+ }
+
+ /* Build the regex string re_string
+ */
+ re_string = sh_string_new(0);
+ sh_string_add_from_char(re_string, "^");
+
+ for (i = 0; i < nfields; ++i)
+ {
+
+ if (i > 0)
+ sh_string_add_from_char(re_string, " ");
+
+ if (splits[i][0] != '"')
+ quotes = 0;
+ else
+ quotes = 1;
+
+ if (quotes && lengths[i] > 1 && splits[i][lengths[i]-1] == '"')
+ {
+ splits[i][lengths[i]-1] = '\0'; /* cut trailing quote */
+ token = &(splits[i][1]);
+ } else {
+ token = splits[i];
+ }
+
+ if(quotes)
+ {
+ if(strcmp(token, "%r") == 0 ||
+ strstr(token, _("{Referer}")) != NULL ||
+ strstr(token, _("{User-Agent}")) != NULL ||
+ strstr(token, _("{X-Forwarded-For}")) != NULL )
+ {
+ /*
+ p = "\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"";
+ sh_string_add_from_char(re_string, p);
+ */
+ sh_string_add_from_char(re_string, "\"([^");
+ sh_string_add_from_char(re_string, "\"\\\\");
+ sh_string_add_from_char(re_string, "]*");
+ sh_string_add_from_char(re_string, "(?:");
+ sh_string_add_from_char(re_string, "\\\\.");
+ sh_string_add_from_char(re_string, "[^\"");
+ sh_string_add_from_char(re_string, "\\\\]*");
+ sh_string_add_from_char(re_string, ")*)\"");
+ }
+ else
+ {
+ sh_string_add_from_char(re_string, "(");
+ sh_string_add_from_char(re_string, "\\S+");
+ sh_string_add_from_char(re_string, ")");
+ }
+ }
+ else if (token[0] == 'R' && token[1] == 'E' && token[2] == '{' && token[strlen(token)-1] == '}')
+ {
+ char * lb = strchr(token, '{');
+ char * rb = strrchr(token, '}');
+
+ if (lb && rb)
+ {
+ ++lb; *rb = '\0';
+ sh_string_add_from_char(re_string, lb);
+ }
+ }
+ else if (token[0] == '%' && token[strlen(token)-1] == 't')
+ {
+ char * lb = strchr(token, '{');
+ char * rb = strchr(token, '}');
+
+ sh_string_add_from_char(re_string, "\\[");
+ sh_string_add_from_char(re_string, "([^");
+ sh_string_add_from_char(re_string, "(\\]");
+ sh_string_add_from_char(re_string, "]+)");
+ sh_string_add_from_char(re_string, "\\]");
+
+ p_time = i+1;
+ if (lb && rb)
+ {
+ ++lb; *rb = '\0';
+ f_time = sh_util_strdup(lb);
+ }
+ else
+ {
+ f_time = sh_util_strdup(_("%d/%b/%Y:%T"));
+ }
+ }
+ else if (token[0] == '%' && token[1] == 'e' && 0 == strcmp(token, _("%error")))
+ {
+ sh_string_add_from_char(re_string, "\\[");
+ sh_string_add_from_char(re_string, "([^");
+ sh_string_add_from_char(re_string, "]");
+ sh_string_add_from_char(re_string, "]+)");
+ sh_string_add_from_char(re_string, "\\]");
+
+ p_time = i+1; f_time = sh_util_strdup(_("%a %b %d %T %Y")); ++i;
+ sh_string_add_from_char(re_string, " ");
+
+ sh_string_add_from_char(re_string, "\\[");
+ sh_string_add_from_char(re_string, "([^");
+ sh_string_add_from_char(re_string, "]");
+ sh_string_add_from_char(re_string, "]+)");
+ sh_string_add_from_char(re_string, "\\]");
+
+ p_status = i+1;
+ sh_string_add_from_char(re_string, " ");
+
+ p = "(.+)";
+ sh_string_add_from_char(re_string, p);
+
+ nfields = 3;
+
+ break;
+ }
+ else
+ {
+ sh_string_add_from_char(re_string, "(");
+ sh_string_add_from_char(re_string, "\\S+");
+ sh_string_add_from_char(re_string, ")");
+ if (token[0] == '%' && token[strlen(token)-1] == 's')
+ p_status = i+1;
+ else if (token[0] == '%' && token[strlen(token)-1] == 'v')
+ p_host = i+1;
+ }
+ }
+ sh_string_add_from_char(re_string, "$");
+
+ if (flag_err_debug == S_TRUE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(re_string),
+ _("eval_fileinfo"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ result = SH_ALLOC(sizeof(struct sh_fileinfo_apache));
+ result->line_regex = pcre_compile(sh_string_str(re_string), 0,
+ &error, &erroffset, NULL);
+ if (!(result->line_regex))
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Bad regex: "));
+ sh_string_add_from_char(msg, sh_string_str(re_string));
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("eval_fileinfo"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SH_FREE(result);
+ SH_FREE(splits);
+ SH_FREE(new);
+ sh_string_destroy(&msg);
+ sh_string_destroy(&re_string);
+
+ return NULL;
+ }
+ sh_string_destroy(&re_string);
+
+ result->line_ovector = SH_ALLOC(sizeof(int) * (nfields+1) * 3);
+ result->line_ovecnum = nfields;
+ result->pos_host = p_host;
+ result->pos_status = p_status;
+ result->pos_time = p_time;
+ result->format_time = f_time;
+
+ SH_FREE(splits);
+ SH_FREE(new);
+ return (void*)result;
+}
+
+struct sh_logrecord * sh_parse_apache (sh_string * logline, void * fileinfo)
+{
+ static struct tm old_tm;
+ static time_t old_time;
+
+ char tstr[128];
+ char sstr[128];
+ const char * hstr;
+ int res;
+ const char **hstr_addr = (const char **) &hstr;
+
+ struct sh_fileinfo_apache * info = (struct sh_fileinfo_apache *) fileinfo;
+
+ if (sh_string_len(logline) > 0 && flag_err_debug == S_TRUE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(logline),
+ _("sh_parse_apache"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (logline == NULL || info == NULL)
+ {
+ return NULL;
+ }
+
+ res = pcre_exec(info->line_regex, NULL,
+ sh_string_str(logline), (int)sh_string_len(logline), 0,
+ 0, info->line_ovector, (3*(1+info->line_ovecnum)));
+
+ if (res == (1+info->line_ovecnum))
+ {
+ struct sh_logrecord * record;
+ time_t timestamp = 0;
+
+ if (info->pos_time > 0)
+ {
+ res = pcre_copy_substring(sh_string_str(logline),
+ info->line_ovector, res,
+ info->pos_time, tstr, sizeof(tstr));
+ if (res <= 0)
+ goto corrupt;
+ }
+ else
+ {
+ res = 0;
+ timestamp = 0;
+ info->format_time = sh_util_strdup(_("%d/%b/%Y:%T"));
+ sl_strlcpy(tstr, _("01/Jan/1970:00:00:00"), sizeof(tstr));
+ }
+
+ if (res > 0)
+ {
+ struct tm btime;
+ char * ptr = NULL;
+
+ memset(&btime, '\0', sizeof(struct tm));
+ btime.tm_isdst = -1;
+
+ /* example: 01/Jun/2008:07:55:28 +0200 */
+
+ ptr = /*@i@*/strptime(tstr, info->format_time, &btime);
+
+ if (ptr)
+ {
+ timestamp = conv_timestamp(&btime, &old_tm, &old_time);
+ }
+ else
+ goto corrupt;
+ }
+
+ if (info->pos_status > 0)
+ {
+ res = pcre_copy_substring(sh_string_str(logline),
+ info->line_ovector, res,
+ info->pos_status, sstr, sizeof(sstr));
+ if (res <= 0)
+ goto corrupt;
+ }
+ else
+ {
+ sl_strlcpy(sstr, _("000"), sizeof(sstr));
+ }
+
+ if (info->pos_host > 0)
+ {
+ res = pcre_get_substring(sh_string_str(logline),
+ info->line_ovector, res,
+ info->pos_host, hstr_addr);
+ if (res <= 0)
+ goto corrupt;
+ }
+ else
+ {
+ hstr = NULL;
+ }
+
+ record = SH_ALLOC(sizeof(struct sh_logrecord));
+
+ record->timestamp = timestamp;
+ record->timestr = sh_string_new_from_lchar(tstr, strlen(tstr));
+
+ if (hstr)
+ record->host = sh_string_new_from_lchar(hstr, strlen(hstr));
+ else
+ record->host = sh_string_new_from_lchar(sh.host.name, strlen(sh.host.name));
+
+ record->message = sh_string_new_from_lchar(sh_string_str(logline),
+ sh_string_len(logline));
+ record->pid = PID_INVALID;
+
+ pcre_free_substring(hstr);
+ return record;
+ }
+ else
+ {
+ char msg[128];
+ sl_snprintf(msg, sizeof(msg), _("Incorrect number of captured subexpressions: %d vs %d"),
+ res, info->line_ovecnum);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ msg,
+ _("sh_parse_apache"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ /* Corrupted logline */
+ corrupt:
+
+ {
+ sh_string * msg = sh_string_new(0);
+ sh_string_add_from_char(msg, _("Corrupt logline: "));
+ sh_string_add_from_char(msg, sh_string_str(logline));
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(msg),
+ _("sh_parse_apache"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_string_destroy(&msg);
+ }
+ return NULL;
+}
+
+/* USE_LOGFILE_MONITOR */
+#endif
diff --git a/src/sh_log_parse_generic.c b/src/sh_log_parse_generic.c
new file mode 100644
index 0000000..85cae68
--- /dev/null
+++ b/src/sh_log_parse_generic.c
@@ -0,0 +1,119 @@
+/**************************************
+ **
+ ** PARSER RULES
+ **
+ ** (a) must set record->host
+ ** (eventually to dummy value)
+ **
+ ** (b) must set record->prefix
+ ** (itoa(status))
+ **
+ **
+ **************************************/
+
+#include "config_xor.h"
+
+#ifdef USE_LOGFILE_MONITOR
+
+#undef FIL__
+#define FIL__ _("sh_log_parse_apache.c")
+
+#include <string.h>
+#include <time.h>
+
+/* Debian/Ubuntu: libpcre3-dev */
+#ifdef HAVE_PCRE_PCRE_H
+#include <pcre/pcre.h>
+#else
+#include <pcre.h>
+#endif
+
+#include "samhain.h"
+#include "sh_log_check.h"
+#include "sh_string.h"
+
+struct sh_fileinfo_generic {
+ pcre * line_regex;
+ int * line_ovector; /* captured substrings */
+ int line_ovecnum; /* how many captured */
+
+ int pos_host;
+ int pos_status;
+ int pos_time;
+ char * format_time;
+};
+
+static void default_time (struct sh_logrecord * record)
+{
+ struct tm ts;
+ struct tm * ts_ptr;
+ char tmp[80];
+ size_t len;
+
+ record->timestamp = time(NULL);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ ts_ptr = localtime_r (&(record->timestamp), &ts);
+#else
+ ts_ptr = localtime(&(record->timestamp));
+ if (ts_ptr)
+ memcpy(&ts, ts_ptr, sizeof(struct tm));
+#endif
+ if (ts_ptr)
+ len = strftime(tmp, sizeof(tmp), _("%Y-%m-%dT%H:%M:%S"), &ts);
+ else
+ {
+ sl_strlcpy(tmp, _("1970-01-01T00:00:00"), sizeof(tmp));
+ len = strlen(tmp);
+ }
+ record->timestr = sh_string_new_from_lchar(tmp, len);
+
+ return;
+}
+
+static void default_host (struct sh_logrecord * record)
+{
+ record->host = sh_string_new_from_lchar(sh.host.name, strlen(sh.host.name));
+ return;
+}
+
+sh_string * sh_read_shell (sh_string * record, struct sh_logfile * logfile)
+{
+ return sh_command_reader (record, logfile);
+}
+
+struct sh_logrecord * sh_parse_shell (sh_string * logline, void * fileinfo)
+{
+ (void) fileinfo;
+
+ if (logline)
+ {
+ struct sh_logrecord * record = SH_ALLOC(sizeof(struct sh_logrecord));
+
+ default_time(record);
+ default_host(record);
+
+ record->message = sh_string_new_from_lchar(sh_string_str(logline),
+ sh_string_len(logline));
+ record->pid = PID_INVALID;
+ return record;
+ }
+ return NULL;
+}
+
+void * sh_eval_fileinfo_generic(char * str)
+{
+ (void) str;
+
+ return NULL;
+}
+
+struct sh_logrecord * sh_parse_generic (sh_string * logline, void * fileinfo)
+{
+ (void) logline;
+ (void) fileinfo;
+
+ return NULL;
+}
+
+#endif
diff --git a/src/sh_log_parse_pacct.c b/src/sh_log_parse_pacct.c
new file mode 100644
index 0000000..d6d12ac
--- /dev/null
+++ b/src/sh_log_parse_pacct.c
@@ -0,0 +1,354 @@
+/**************************************
+ **
+ ** PARSER RULES
+ **
+ ** (a) must set record->host
+ ** (eventually to dummy value)
+ **
+ ** (b) must set record->prefix
+ ** (command)
+ **
+ **
+ **************************************/
+
+/* Based on the GNU Accounting Utilities, which is distributed with the
+ * following copyright:
+ */
+
+/* Copyright (C) 1993, 1996, 1997, 2003, 2005 Free Software Foundation, Inc.
+ *
+ * This file is part of the GNU Accounting Utilities
+ *
+ * The GNU Accounting Utilities are free software; you can redistribute
+ * them and/or modify them under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either version
+ * 2, or (at your option) any later version.
+ *
+ * The GNU Accounting Utilities are distributed in the hope that they will
+ * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the GNU Accounting Utilities; see the file COPYING. If
+ * not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
+ * MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <dirent.h>
+
+#if defined(USE_LOGFILE_MONITOR) && defined(HAVE_SYS_ACCT_H)
+
+#include <sys/acct.h>
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_log_check.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+
+#undef FIL__
+#define FIL__ _("sh_log_parse_pacct.c")
+
+extern int flag_err_debug;
+
+#ifndef ACCT_COMM
+#define ACCT_COMM 16
+#endif
+#ifndef AHZ
+#define AHZ 100
+#endif
+
+#if defined(ACUTIME_COMPT) || defined(ACSTIME_COMPT) || defined(ACETIME_COMPT)
+static double comp_t_2_double (comp_t ct)
+{
+ unsigned long out = 0;
+
+ out = ct & 017777;
+ ct >>= 13;
+
+ while (ct) {
+ ct--;
+ out <<= 3;
+ }
+
+ return (double) out;
+}
+#endif
+
+#ifdef ACUTIME_COMPT
+# define ACUTIME_2_DOUBLE(x) (comp_t_2_double(x))
+#else
+# define ACUTIME_2_DOUBLE(x) ((double)(x))
+#endif
+
+#ifdef ACSTIME_COMPT
+# define ACSTIME_2_DOUBLE(x) (comp_t_2_double(x))
+#else
+# define ACSTIME_2_DOUBLE(x) ((double)(x))
+#endif
+
+#ifdef ACETIME_COMPT
+# define ACETIME_2_DOUBLE(x) (comp_t_2_double(x))
+#else
+# define ACETIME_2_DOUBLE(x) ((double)(x))
+#endif
+
+
+static void expand_flags(char flag, char * out)
+{
+ int i = 0;
+
+#define BIT(flg, ch) if (flag & flg) out[i] = ch; else out[i] = ' '; ++i
+
+ BIT(ASU, 'S');
+ BIT(AFORK, 'F');
+#ifdef ACOMPAT
+ BIT(ACOMPAT, 'C');
+#endif
+#ifdef ACORE
+ BIT(ACORE, 'D');
+#endif
+#ifdef AXSIG
+ BIT(AXSIG, 'X');
+#endif
+
+ out[i] = '\0';
+ return;
+}
+
+static char * uid_name (int uid)
+{
+ static int userid = 0;
+ static char user[16] = "";
+
+ if (uid == userid && user[0] != '\0')
+ {
+ return user;
+ }
+ else
+ {
+ struct passwd *thispw = getpwuid (uid);
+ if (thispw)
+ sl_strlcpy (user, thispw->pw_name, sizeof(user));
+ else
+ sl_snprintf(user, sizeof(user), "%d", uid);
+ user[sizeof(user)-1] = '\0';
+ userid = uid;
+ }
+ return user;
+}
+
+struct dev_struct {
+ char * device;
+ long dev_id;
+ struct dev_struct * next;
+};
+static struct dev_struct * devicelist = NULL;
+
+static void add_devices(const char * dir)
+{
+ DIR * mdir;
+ char dirl[256];
+
+ sl_strlcpy(dirl, dir, sizeof(dirl));
+ dirl[sizeof(dirl)-1] = '\0';
+
+ mdir = opendir(dir);
+
+ if (mdir)
+ {
+ char * path;
+ size_t len;
+ struct dirent * dent;
+ struct stat buf;
+
+ while (NULL != (dent = readdir(mdir)))
+ {
+ if (0 == strcmp(dent->d_name, "."))
+ continue;
+ if (0 == strcmp(dent->d_name, ".."))
+ continue;
+ len = strlen(dir) + strlen(dent->d_name) + 2;
+ path = SH_ALLOC(len);
+ snprintf(path, len, "%s/%s", dir, dent->d_name);
+ if (0 == lstat(path, &buf) && S_ISCHR(buf.st_mode))
+ {
+ struct dev_struct * dstruct;
+ dstruct = SH_ALLOC(sizeof(struct dev_struct));
+ /* eliminate leading '/dev/' */
+ memmove(path, &path[5], strlen(path)-4);
+ dstruct->device = path;
+ dstruct->dev_id = buf.st_rdev;
+ dstruct->next = devicelist;
+ devicelist = dstruct;
+ }
+ else
+ {
+ SH_FREE(path);
+ }
+ }
+ closedir(mdir);
+ }
+ return;
+}
+
+static char * dev_name(long tty)
+{
+ struct dev_struct * dstruct;
+
+ if (!devicelist)
+ {
+ add_devices("/dev");
+ add_devices("/dev/pts");
+ add_devices("/dev/pty");
+ add_devices("/dev/ptym");
+ }
+
+ dstruct = devicelist;
+ while (dstruct)
+ {
+ if (dstruct->dev_id == tty)
+ return dstruct->device;
+ dstruct = dstruct->next;
+ }
+ return "??";
+}
+
+#if defined(__linux__) && defined(HAVE_ACCT_V3)
+# define STRUCT_ACCT struct acct_v3
+#elif defined(__FreeBSD__) && defined(HAVE_ACCTV2)
+# define STRUCT_ACCT struct acctv2
+#else
+# define STRUCT_ACCT struct acct
+#endif
+
+/* This looks strange, but it's real ANSI C. */
+extern STRUCT_ACCT pacct_rd_never_used;
+#define COMM_LEN ((int) sizeof (pacct_rd_never_used.ac_comm))
+
+sh_string * sh_read_pacct (sh_string * record, struct sh_logfile * logfile)
+{
+ STRUCT_ACCT rec;
+
+ if (NULL != sh_binary_reader ((void*) &rec, sizeof(STRUCT_ACCT), logfile))
+ {
+ time_t btime = (time_t) rec.ac_btime;
+ double ut = ACUTIME_2_DOUBLE (rec.ac_utime);
+ double st = ACSTIME_2_DOUBLE (rec.ac_stime);
+ char fl[6];
+ char comm[COMM_LEN+1];
+ int i;
+ char out[64+COMM_LEN+1+5+8+8+32+4+19+7]; /* see printf format below */
+
+#if defined(ac_flagx)
+ expand_flags(rec.ac_flagx, fl);
+#else
+ expand_flags(rec.ac_flag, fl);
+#endif
+
+ /* ac_comm may not be null terminated
+ */
+ for (i = 0; i < COMM_LEN; i++)
+ {
+ if (rec.ac_comm[i] == '\0')
+ {
+ comm[i] = '\0';
+ break;
+ }
+ if (! isprint (rec.ac_comm[i]))
+ comm[i] = '?';
+ else
+ comm[i] = rec.ac_comm[i];
+ }
+ comm[COMM_LEN] = '\0';
+
+ sl_snprintf (out, sizeof(out),
+ "%ld:%-*.*s %5.5s %-8.8s %-8.8s %6.2f secs %-19.19s",
+ btime,
+ COMM_LEN, COMM_LEN, comm, fl,
+ uid_name(rec.ac_uid),
+ dev_name((long)rec.ac_tty),
+ ((ut + st) / (double) AHZ),
+ ctime (&btime));
+
+
+ sh_string_set_from_char(record, out);
+ return record;
+ }
+
+ if (record)
+ sh_string_destroy(&record);
+ return NULL;
+}
+
+void * sh_dummy_294_record = NULL;
+
+struct sh_logrecord * sh_parse_pacct (sh_string * logline, void * fileinfo)
+{
+ char * p;
+ char * endptr;
+ unsigned long ltime;
+ struct sh_logrecord * record = NULL;
+
+ (void) fileinfo;
+
+ sh_dummy_294_record = (void *) &record;
+
+ if (sh_string_len(logline) > 0 && flag_err_debug == S_TRUE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_string_str(logline),
+ _("sh_parse_pacct"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ p = strchr(sh_string_str(logline), ':');
+
+ if (!p || p == sh_string_str(logline))
+ return NULL;
+
+ ltime = strtoul(sh_string_str(logline), &endptr, 10);
+ if (p != endptr)
+ return NULL;
+
+ ++p; /* points to first char of pacct record */
+
+ if (*p != '\0')
+ {
+ size_t lengths[7];
+ unsigned int fields = 7;
+ char ** array;
+ sh_string * message = sh_string_new_from_lchar(p, strlen(p));
+ array = split_array_ws(p, &fields, lengths);
+
+ if (fields == 7)
+ {
+ record = SH_ALLOC(sizeof(struct sh_logrecord));
+
+ record->timestamp = ltime;
+ record->timestr = sh_string_new_from_lchar(array[6], lengths[6]);
+ record->message = message;
+ record->pid = 0;
+ record->host = sh_string_new_from_lchar(sh.host.name, strlen(sh.host.name));
+ }
+ else
+ {
+ sh_string_destroy(&message);
+ }
+ SH_FREE(array);
+ }
+ return record;
+}
+/* USE_LOGFILE_MONITOR */
+#endif
diff --git a/src/sh_log_parse_samba.c b/src/sh_log_parse_samba.c
new file mode 100644
index 0000000..820bbe3
--- /dev/null
+++ b/src/sh_log_parse_samba.c
@@ -0,0 +1,104 @@
+/**************************************
+ **
+ ** PARSER RULES
+ **
+ ** (a) must set record->host
+ ** (eventually to dummy value)
+ **
+ ** (b) must set record->prefix
+ ** (command)
+ **
+ **
+ **************************************/
+
+/* for strptime */
+#define _XOPEN_SOURCE
+
+#include "config_xor.h"
+#include <string.h>
+
+#if defined(HOST_IS_SOLARIS)
+/* For 'struct timeval' in <sys/time.h> */
+#define __EXTENSIONS__
+#endif
+
+#include <time.h>
+
+#if defined(USE_LOGFILE_MONITOR)
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_log_check.h"
+#include "sh_string.h"
+
+#undef FIL__
+#define FIL__ _("sh_log_parse_samba.c")
+
+
+sh_string * sh_read_samba (sh_string * record, struct sh_logfile * logfile)
+{
+ return sh_cont_reader (record, logfile, " \t");
+}
+
+struct sh_logrecord * sh_parse_samba (sh_string * logline, void * fileinfo)
+{
+ static struct tm old_tm;
+ static time_t old_time;
+
+ struct sh_logrecord * record = NULL;
+
+ static const char * format0_1 = N_("[%Y/%m/%d %T");
+ static char format_1[16];
+ static int format_init = 0;
+
+ (void) fileinfo;
+
+ if (!format_init)
+ {
+ sl_strlcpy(format_1, _(format0_1), sizeof(format_1));
+ format_init = 1;
+ }
+
+ if (logline && sh_string_len(logline) > 0)
+ {
+ size_t lengths[3];
+ unsigned int fields = 3;
+ char ** array;
+ char * p = strchr(sh_string_str(logline), ',');
+
+ *p = '\0'; ++p;
+ array = split_array_ws(p, &fields, lengths);
+
+ if (fields == 3)
+ {
+ struct tm btime;
+ char * ptr;
+
+ memset(&btime, '\0', sizeof(struct tm));
+ btime.tm_isdst = -1;
+
+ ptr = strptime(sh_string_str(logline), format_1, &btime);
+
+ if (ptr && *ptr == '\0') /* no error, whole string consumed */
+ {
+ record = SH_ALLOC(sizeof(struct sh_logrecord));
+
+ record->timestamp = conv_timestamp(&btime, &old_tm, &old_time);
+
+ p = sh_string_str(logline); ++p;
+
+ record->timestr = sh_string_new_from_lchar(p, strlen(p));
+
+ record->message = sh_string_new_from_lchar(array[2], lengths[2]);
+
+ record->pid = 0;
+ record->host = sh_string_new_from_lchar(sh.host.name,
+ strlen(sh.host.name));
+ }
+ }
+ SH_FREE(array);
+ }
+ return record;
+}
+
+#endif
diff --git a/src/sh_log_parse_syslog.c b/src/sh_log_parse_syslog.c
new file mode 100644
index 0000000..ae9f801
--- /dev/null
+++ b/src/sh_log_parse_syslog.c
@@ -0,0 +1,190 @@
+/**************************************
+ **
+ ** PARSER RULES
+ **
+ ** (a) must set record->host
+ ** (eventually to dummy value)
+ **
+ ** (b) must set record->prefix
+ ** (eventually to dummy value)
+ **
+ **
+ **************************************/
+
+/* for strptime */
+#define _XOPEN_SOURCE
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(HOST_IS_SOLARIS)
+/* For 'struct timeval' in <sys/time.h> */
+#define __EXTENSIONS__
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+
+#ifdef USE_LOGFILE_MONITOR
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_log_check.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+
+#undef FIL__
+#define FIL__ _("sh_log_parse_syslog.c")
+
+static int hidepid = 0;
+extern int flag_err_debug;
+
+int sh_get_hidepid()
+{
+ return hidepid;
+}
+
+int sh_set_hidepid(const char *s)
+{
+ return sh_util_flagval(s, &hidepid);
+}
+
+struct sh_logrecord * sh_parse_syslog (sh_string * logline, void * fileinfo)
+{
+ static const char * format0_1 = N_("%b %d %T");
+ static const char * format0_2 = N_("%Y-%m-%dT%T");
+
+ static char format_1[16];
+ static char format_2[16];
+ static int format_init = 0;
+
+ static struct tm old_tm;
+ static time_t old_time;
+
+ const unsigned int Tpos = 10;
+ volatile unsigned int tlen = 16;
+
+ (void) fileinfo;
+
+ if (!format_init)
+ {
+ sl_strlcpy(format_1, _(format0_1), sizeof(format_1));
+ sl_strlcpy(format_2, _(format0_2), sizeof(format_2));
+ format_init = 1;
+ }
+
+
+ if (flag_err_debug == S_TRUE && sh_string_len(logline) > 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ logline->str,
+ _("sh_parse_syslog"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (logline && sh_string_len(logline) > tlen)
+ {
+ struct tm btime;
+ char * ptr;
+ int flag;
+ size_t lengths[3];
+
+ memset(&btime, '\0', sizeof(struct tm));
+ btime.tm_isdst = -1;
+
+ /* This is RFC 3164.
+ */
+ if (logline->str[Tpos] != 'T')
+ {
+ logline->str[tlen-1] = '\0';
+ ptr = /*@i@*/strptime(logline->str, format_1, &btime);
+ }
+
+ /* RFC 3339 describes an alternative timestamp format.
+ * Unfortunately, POSIX strptime() does not support reading
+ * the TZ offset.
+ */
+ else
+ {
+ ptr = strptime(logline->str, format_2, &btime);
+ if (ptr)
+ {
+ tlen = 20;
+ if (*ptr && *ptr != ' ') {
+ do { ++ptr; ++tlen; } while (*ptr && *ptr != ' ');
+ if (*ptr == ' ') *ptr = '\0';
+ }
+ }
+ }
+
+ if (ptr && *ptr == '\0') /* no error, whole string consumed */
+ {
+ unsigned int fields = 3; /* host program(\[pid\])+: message */
+ char ** array = split_array_ws(&(logline->str[tlen]), &fields, lengths);
+
+ if (fields == 3)
+ {
+ struct sh_logrecord * record = SH_ALLOC(sizeof(struct sh_logrecord));
+
+ record->timestamp = conv_timestamp(&btime, &old_tm, &old_time);
+ record->timestr = sh_string_new_from_lchar(logline->str, (tlen-1));
+
+ /* host
+ */
+ record->host = sh_string_new_from_lchar(array[0], lengths[0]);
+
+ /* program and pid
+ */
+ if (NULL != (ptr = strchr(array[1], '[')))
+ {
+ *ptr = '\0';
+ ++ptr;
+ record->pid = (pid_t) atoi(ptr);
+
+ if (hidepid == 0 || !*ptr) {
+ --ptr;
+ *ptr = '[';
+ } else {
+ *ptr = '\0'; /* overwrite first digit */
+ --ptr;
+ *ptr = ':'; /* overwrite ex-':' */
+ lengths[1] = strlen(array[1]);
+ }
+ }
+ else
+ {
+ flag = 0;
+ ptr = array[1];
+ if (ptr[lengths[1]] == ':') {
+ ptr[lengths[1]] = '\0';
+ flag = 1;
+ }
+ record->pid = PID_INVALID;
+ if (flag == 1) {
+ ptr[lengths[1]] = ':';
+ }
+ }
+
+ /* message
+ */
+ record->message = sh_string_new_from_lchar3(array[1], lengths[1],
+ " ", 1,
+ array[2], lengths[2]);
+
+ SH_FREE(array);
+ return record;
+ }
+ SH_FREE(array);
+ }
+ }
+ /* corrupted logline
+ */
+ return NULL;
+}
+
+/* USE_LOGFILE_MONITOR */
+#endif
diff --git a/src/sh_log_repeat.c b/src/sh_log_repeat.c
new file mode 100644
index 0000000..9285c82
--- /dev/null
+++ b/src/sh_log_repeat.c
@@ -0,0 +1,566 @@
+#include "config_xor.h"
+
+#ifdef USE_LOGFILE_MONITOR
+
+#include <string.h>
+#include <ctype.h>
+
+#undef FIL__
+#define FIL__ _("sh_log_repeat.c")
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_string.h"
+#include "sh_log_check.h"
+#include "sh_log_evalrule.h"
+
+#define SH_NHIST 12
+#define SH_NFINT 5
+#define SH_NFIELDS 5*sizeof(SINT32) /* 16 */
+#define SH_NBLOCK 63
+
+typedef enum
+{
+ SH_GFLAG_EMAIL = 1 << 0,
+ SH_GFLAG_PATH = 1 << 1,
+ SH_GFLAG_IP = 1 << 2,
+ SH_GFLAG_FQDN = 1 << 3,
+ SH_GFLAG_NUM = 1 << 4,
+ SH_GFLAG_ELSE = 1 << 5,
+
+ SH_GFLAG_XNUM = 1 << 6,
+ SH_GFLAG_CHAR = 1 << 7,
+ SH_GFLAG_USC = 1 << 8
+} SH_GFlags;
+
+
+/* 64 bytes
+ */
+struct gestalt {
+ unsigned char hist[SH_NHIST]; /* time histogram 12 minutes */
+ union {
+ unsigned char flags[SH_NFIELDS]; /* flags indicating field type */
+ SINT32 flint[SH_NFINT];
+ } f;
+ UINT16 sum[SH_NFIELDS]; /* checksum of field */
+ UINT16 ltime; /* last time, in minutes */
+ UINT16 total; /* seen how often? */
+};
+
+static unsigned int nrec = 0; /* size of array */
+static unsigned int urec = 0; /* in use thereof */
+static struct gestalt * arec = NULL; /* array */
+
+static int repeat_count = 24; /* triggers report */
+static int clean_counter = 0; /* cleanup after N inserts */
+static int free_slots = 0; /* free slots available */
+
+#define SH_CLEANUP 256
+
+static struct gestalt * add_entry (unsigned char * flags, UINT16 * sum,
+ time_t ltime)
+{
+ struct gestalt * array = NULL;
+
+ start:
+ if (urec < nrec)
+ {
+ if (free_slots)
+ {
+ unsigned int i;
+ for (i = 0; i < urec; ++i)
+ {
+ if (arec[i].total == 0)
+ {
+ array = &arec[i];
+ --free_slots;
+ break;
+ }
+ }
+ }
+
+ if (!array)
+ {
+ array = &arec[urec];
+ ++urec;
+ }
+
+ memcpy(array->sum, sum, sizeof(UINT16) * SH_NFIELDS);
+ memcpy(array->f.flags, flags, sizeof(unsigned char) * SH_NFIELDS);
+ memset(array->hist, 0, sizeof(unsigned char) * SH_NHIST);
+
+ array->ltime = (UINT16)(ltime % 60);
+ array->hist[SH_NHIST-1] = 1;
+ array->total = 1;
+
+ ++clean_counter;
+ return array;
+ }
+
+ array = SH_ALLOC(sizeof(struct gestalt) * (nrec + SH_NBLOCK + 1));
+ memset(array, 0, sizeof(struct gestalt) * (nrec + SH_NBLOCK + 1));
+ memcpy(array, arec, sizeof(struct gestalt) * (nrec));
+
+ nrec += (SH_NBLOCK + 1);
+ goto start;
+}
+
+static UINT16 shift_history(unsigned char * hist, unsigned int shift,
+ UINT16 total)
+{
+ unsigned int i, j = 0;
+
+ if (shift >= SH_NHIST)
+ {
+ memset(hist, 0, sizeof(unsigned char) * SH_NHIST);
+ return 0;
+ }
+
+ for (i = shift; i < SH_NHIST; ++i)
+ {
+ if (j < shift)
+ total -= hist[j];
+ hist[j] = hist[i];
+ ++j;
+ }
+ for (i = (SH_NHIST-shift); i < SH_NHIST; ++i)
+ {
+ hist[i] = 0;
+ }
+ return total;
+}
+
+static void update_entry (struct gestalt * array, time_t ltime)
+{
+ UINT16 ntime = (UINT16)(ltime % 60);
+
+ if (array->ltime == ntime)
+ {
+ if (array->hist[SH_NHIST-1] < 255)
+ {
+ ++(array->hist[SH_NHIST-1]);
+ ++(array->total);
+ }
+ }
+ else if (array->ltime < ntime)
+ {
+ unsigned int shift = ntime - array->ltime;
+ array->total = shift_history(array->hist, shift, array->total);
+ array->hist[SH_NHIST-1] = 1;
+ array->ltime = ntime;
+ ++(array->total);
+ }
+}
+
+static struct gestalt * update_or_add (unsigned char * flags, UINT16 * sum,
+ time_t ltime)
+{
+ SINT32 flint[SH_NFINT];
+ start:
+
+ if (arec)
+ {
+ unsigned int i;
+ struct gestalt * array = arec;
+
+ memcpy(flint, flags, SH_NFIELDS);
+
+ for (i = 0; i < urec; ++i)
+ {
+ /* Check whether field types match. Integer
+ * comparison is much faster than memcmp() [tested].
+ */
+ if (flint[0] == array->f.flint[0] &&
+ flint[1] == array->f.flint[1] &&
+ flint[2] == array->f.flint[2] &&
+ flint[3] == array->f.flint[3] &&
+ flint[4] == array->f.flint[4])
+ {
+ unsigned int j;
+ int c1 = 0, c2 = 0;
+ UINT16 * asum = array->sum;
+
+ for (j = 0; j < SH_NFIELDS; ++j)
+ {
+ if (flags[j] == SH_GFLAG_ELSE)
+ {
+ ++c1;
+ if (asum[j] == sum[j])
+ ++c2;
+ }
+ }
+
+ if (c1 == c2)
+ {
+ /* Found a matching entry, update time histogram
+ */
+ update_entry (array, ltime);
+ return array;
+ }
+ }
+ ++array;
+ }
+
+ /* No match found, create a new entry
+ */
+ array = add_entry (flags, sum, ltime);
+ return array;
+ }
+
+ arec = SH_ALLOC(sizeof(struct gestalt) * SH_NBLOCK);
+ nrec = SH_NBLOCK;
+ urec = 0;
+
+ goto start;
+}
+
+/* --------------------------------------------------------------------
+ *
+ * crc16 checksum from the linux kernel.
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.
+ */
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
+UINT16 const crc16_table[256] = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+static inline UINT16 crc16_byte(UINT16 crc, const unsigned char data)
+{
+ return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+/**
+ * crc16 - compute the CRC-16 for the data buffer
+ * @crc: previous CRC value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
+ *
+ * Returns the updated CRC value.
+ */
+static inline UINT16 crc16(UINT16 crc, const unsigned char * buffer,
+ size_t len)
+{
+ while (len--)
+ crc = crc16_byte(crc, *buffer++);
+ return crc;
+}
+
+
+/* end crc16 code
+ *
+ * -------------------------------------------------------------------- */
+
+static void classify(char ** splits, size_t * lengths, unsigned int nfields,
+ unsigned char * flags, UINT16 * sums)
+{
+ unsigned int i;
+ unsigned int flag;
+
+ /* flags we don't want to see in XYZ
+ */
+ static int m_ip = SH_GFLAG_PATH|SH_GFLAG_EMAIL|SH_GFLAG_USC|SH_GFLAG_ELSE|SH_GFLAG_CHAR|SH_GFLAG_XNUM;
+ static int m_num = SH_GFLAG_PATH|SH_GFLAG_EMAIL|SH_GFLAG_USC|SH_GFLAG_ELSE|SH_GFLAG_CHAR;
+ static int m_fqdn = SH_GFLAG_PATH|SH_GFLAG_EMAIL|SH_GFLAG_USC|SH_GFLAG_ELSE;
+ static int m_email = SH_GFLAG_PATH;
+
+ nfields = (nfields > SH_NFIELDS) ? SH_NFIELDS : nfields;
+
+ for (i = 0; i < nfields; ++i)
+ {
+ char *p = splits[i];
+ unsigned int np = 0;
+ unsigned int fqdn = 0;
+
+ flag = 0;
+
+ while (*p)
+ {
+ if (isxdigit((unsigned int)*p))
+ {
+ if (isdigit((unsigned int)*p))
+ {
+ flag |= SH_GFLAG_NUM;
+ }
+ else
+ {
+ flag |= SH_GFLAG_XNUM;
+ }
+ }
+ else if (*p == '.')
+ {
+ flag |= SH_GFLAG_IP;
+ ++np;
+ }
+ else if (*p == '/')
+ {
+ flag |= SH_GFLAG_PATH;
+ }
+ else if (*p == '@')
+ {
+ flag |= SH_GFLAG_EMAIL;
+ }
+ else if (*p == '-')
+ {
+ flag |= SH_GFLAG_FQDN;
+ }
+ else if (*p == '_')
+ {
+ flag |= SH_GFLAG_USC;
+ }
+ else if (isalpha((unsigned int)*p))
+ {
+ if (flag & SH_GFLAG_IP)
+ ++fqdn;
+ flag |= SH_GFLAG_CHAR;
+ }
+ else if (!isascii((unsigned int)*p))
+ {
+ flags[i] = SH_GFLAG_ELSE;
+ break;
+ }
+ else
+ {
+ flag |= SH_GFLAG_ELSE;
+ }
+ ++p;
+ }
+
+ if (flags[i] == 0)
+ {
+ if (0 == (flag & m_ip) &&
+ 0 != (flag & SH_GFLAG_IP) &&
+ 0 != (flag & SH_GFLAG_NUM) &&
+ np > 2)
+ {
+ flags[i] = SH_GFLAG_IP;
+ }
+ else if (0 == (flag & m_num) &&
+ (0 != (flag & SH_GFLAG_NUM) || 0 != (flag & SH_GFLAG_XNUM)))
+ {
+ flags[i] = SH_GFLAG_NUM;
+ }
+ else if (0 == (flag & m_fqdn) &&
+ 0 != (flag & SH_GFLAG_IP) &&
+ 0 != (flag & SH_GFLAG_CHAR) &&
+ fqdn)
+ {
+ flags[i] = SH_GFLAG_FQDN;
+ }
+ else if ('/' == splits[i][0])
+ {
+ flags[i] = SH_GFLAG_PATH;
+ }
+ else if (0 == (flag & m_email) &&
+ 0 != (flag & SH_GFLAG_EMAIL) &&
+ 0 != (flag & SH_GFLAG_CHAR))
+ {
+ flags[i] = SH_GFLAG_EMAIL;
+ }
+ else
+ {
+ flags[i] = SH_GFLAG_ELSE;
+ }
+ }
+
+ /* CRC-16 checksum
+ */
+ sums[i] = crc16(0, (unsigned char *) splits[i], lengths[i]);
+ }
+
+ return;
+}
+
+static void cleanup_array (time_t ltime)
+{
+ UINT16 ntime = (UINT16)(ltime % 60);
+
+ if (ntime > 12) ntime -= 12;
+
+ if (arec && urec > 0)
+ {
+ struct gestalt * array;
+ unsigned int i, last, urec_orig = urec;
+
+ last = urec-1;
+ array = &arec[0];
+
+ for (i = 0; i < urec_orig; ++i)
+ {
+ if (array->ltime < ntime)
+ {
+ memset(array, 0, sizeof(struct gestalt));
+ if (i != last)
+ ++free_slots;
+ else
+ --urec;
+ }
+ }
+ ++array;
+ }
+ clean_counter = 0;
+ return;
+}
+
+/* ----------------------------------------------------------------------
+ *
+ * Public functions
+ */
+
+int sh_repeat_set_trigger (const char * str)
+{
+ unsigned long value;
+ char * foo;
+
+ value = (size_t) strtoul(str, &foo, 0);
+
+ if (*foo == '\0' && value < 65535) {
+ repeat_count = value;
+ return 0;
+ }
+ return -1;
+}
+
+static char * sh_repeat_queue = NULL;
+
+int sh_repeat_set_queue (const char * str)
+{
+ if (!str)
+ return -1;
+ if (sh_repeat_queue)
+ SH_FREE(sh_repeat_queue);
+ sh_repeat_queue = sh_util_strdup(str);
+ return 0;
+}
+
+static int sh_repeat_cron = S_FALSE;
+
+int sh_repeat_set_cron (const char * str)
+{
+ return sh_util_flagval(str, &sh_repeat_cron);
+}
+
+int sh_repeat_message_check (const sh_string * host,
+ const sh_string * msg,
+ time_t ltime)
+{
+ struct gestalt * array;
+
+ UINT16 sums[SH_NFIELDS] = { 0 };
+ unsigned char flags[SH_NFIELDS] = { 0 };
+
+ /* split message into SH_NFIELDS+1, discard last */
+
+ unsigned int nfields = SH_NFIELDS+1;
+ size_t lengths[SH_NFIELDS+1];
+ char * new;
+ char ** splits;
+
+ if (repeat_count == 0)
+ return 0;
+
+ if (sh_repeat_cron == S_FALSE)
+ {
+ char * s = sh_string_str(msg);
+
+ if (0 == strcmp(s, _("cron")) || 0 == strcmp(s, _("CRON")))
+ return 0;
+ }
+
+ new = sh_util_strdup_l(sh_string_str(msg), sh_string_len(msg));
+
+ splits = split_array_token (new, &nfields, lengths,
+ " :,()='[]<>\t\n");
+
+ /* classify fields */
+
+ classify (splits, lengths, nfields, flags, sums);
+
+ /* compare */
+
+ array = update_or_add (flags, sums, ltime);
+
+ /* report */
+
+ if (array->total > repeat_count)
+ {
+ volatile int repeat = array->total;
+ char * tmpmsg;
+ char * tmphost;
+ sh_string * alias;
+
+ /* issue report */
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmphost = sh_util_safe_name (sh_string_str(host));
+ tmpmsg = sh_util_safe_name_keepspace (sh_string_str(msg));
+ sh_error_handle (sh_log_lookup_severity(sh_repeat_queue),
+ FIL__, __LINE__, 0, MSG_LOGMON_BURST,
+ repeat, tmpmsg, tmphost);
+ alias = sh_log_lookup_alias(sh_repeat_queue);
+ if (alias)
+ {
+ sh_error_mail (sh_string_str(alias),
+ sh_log_lookup_severity(sh_repeat_queue),
+ FIL__, __LINE__, 0, MSG_LOGMON_BURST,
+ repeat, tmpmsg, tmphost);
+ }
+ SH_FREE(tmpmsg);
+ SH_FREE(tmphost);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ /* mark slot as free */
+
+ memset(array, 0, sizeof(struct gestalt));
+ if (array != &arec[urec-1])
+ ++free_slots;
+ else
+ urec -= 1;
+ }
+
+ SH_FREE(new);
+
+ /* run cleanup routine */
+
+ if (clean_counter >= SH_CLEANUP)
+ {
+ cleanup_array(ltime);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/src/sh_login_track.c b/src/sh_login_track.c
new file mode 100644
index 0000000..854df9e
--- /dev/null
+++ b/src/sh_login_track.c
@@ -0,0 +1,1422 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2010 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#undef FIL__
+#define FIL__ _("sh_login_track.c")
+
+#if defined(SH_USE_UTMP) && (defined(SH_WITH_CLIENT) || defined (SH_STANDALONE))
+
+#include <string.h>
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_string.h"
+#include "sh_tools.h"
+#include "sh_ipvx.h"
+#include "sh_error_min.h"
+
+#ifdef HAVE_UTMPX_H
+
+#include <utmpx.h>
+#define SH_UTMP_S utmpx
+#undef ut_name
+#define ut_name ut_user
+#ifdef HAVE_UTXTIME
+#undef ut_time
+#define ut_time ut_xtime
+#else
+#undef ut_time
+#define ut_time ut_tv.tv_sec
+#endif
+
+#else
+
+#include <utmp.h>
+#define SH_UTMP_S utmp
+
+#endif
+
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+
+#define SH_LTRACK_VERSION 1
+
+#define SH_LTRACK_USIZE 32
+#define SH_LTRACK_HSIZE 256
+/* One hour (15 deg) */
+#define SH_LTRACK_HTRES 24
+/* Ten minutes (2.5 deg) */
+#define SH_LTRACK_GTRES 144
+
+/* Avoid compiling against lmath by including result tables for sin, cos
+ */
+const double sintab_htres[SH_LTRACK_HTRES] = {
+ 0.13052619222005157340, 0.38268343236508978178, 0.60876142900872065589, 0.79335334029123516508, 0.92387953251128673848, 0.99144486137381038215,
+ 0.99144486137381038215, 0.92387953251128673848, 0.79335334029123516508, 0.60876142900872087793, 0.38268343236508989280, 0.13052619222005157340,
+-0.13052619222005132360, -0.38268343236508967076, -0.60876142900872065589, -0.79335334029123494304, -0.92387953251128651644, -0.99144486137381038215,
+-0.99144486137381049318, -0.92387953251128662746, -0.79335334029123516508, -0.60876142900872087793, -0.38268343236509039240, -0.13052619222005168442,
+};
+const double costab_htres[SH_LTRACK_HTRES] = {
+ 0.99144486137381038215, 0.92387953251128673848, 0.79335334029123516508, 0.60876142900872065589, 0.38268343236508983729, 0.13052619222005171218,
+-0.13052619222005160116, -0.38268343236508972627, -0.60876142900872065589, -0.79335334029123505406, -0.92387953251128673848, -0.99144486137381038215,
+-0.99144486137381049318, -0.92387953251128684951, -0.79335334029123516508, -0.60876142900872087793, -0.38268343236509033689, -0.13052619222005162891,
+ 0.13052619222005126809, 0.38268343236509000382, 0.60876142900872054486, 0.79335334029123494304, 0.92387953251128651644, 0.99144486137381038215,
+};
+const double sintab_gtres[SH_LTRACK_GTRES] = {
+ 0.02181488503456112046, 0.06540312923014306168, 0.10886687485196457070, 0.15212338618991669281, 0.19509032201612824808, 0.23768589232617309825,
+ 0.27982901403099208482, 0.32143946530316158672, 0.36243803828370163567, 0.40274668985873718352, 0.44228869021900124592, 0.48098876891938763256,
+ 0.51877325816052144436, 0.55557023301960217765, 0.59130964836358235193, 0.62592347218405908205, 0.65934581510006884386, 0.69151305578226940352,
+ 0.72236396205975550444, 0.75183980747897738439, 0.77988448309288171956, 0.80644460426748254545, 0.83146961230254523567, 0.85491187067294649449,
+ 0.87672675570750768781, 0.89687274153268836674, 0.91531147911944710227, 0.93200786928279844012, 0.94693012949510557696, 0.96004985438592871372,
+ 0.97134206981326143282, 0.98078528040323043058, 0.98836151046776066220, 0.99405633822231964647, 0.99785892323860347908, 0.99976202707990913243,
+ 0.99976202707990913243, 0.99785892323860347908, 0.99405633822231964647, 0.98836151046776066220, 0.98078528040323043058, 0.97134206981326143282,
+ 0.96004985438592871372, 0.94693012949510568799, 0.93200786928279855115, 0.91531147911944721329, 0.89687274153268836674, 0.87672675570750779883,
+ 0.85491187067294671653, 0.83146961230254545772, 0.80644460426748254545, 0.77988448309288183058, 0.75183980747897738439, 0.72236396205975561546,
+ 0.69151305578226951454, 0.65934581510006895488, 0.62592347218405919307, 0.59130964836358257397, 0.55557023301960217765, 0.51877325816052133334,
+ 0.48098876891938763256, 0.44228869021900130143, 0.40274668985873729454, 0.36243803828370174669, 0.32143946530316175325, 0.27982901403099230686,
+ 0.23768589232617337581, 0.19509032201612860891, 0.15212338618991663730, 0.10886687485196457070, 0.06540312923014311719, 0.02181488503456121761,
+-0.02181488503456097475, -0.06540312923014286739, -0.10886687485196432090, -0.15212338618991641526, -0.19509032201612835911, -0.23768589232617312601,
+-0.27982901403099202930, -0.32143946530316153121, -0.36243803828370152464, -0.40274668985873707250, -0.44228869021900107938, -0.48098876891938741052,
+-0.51877325816052122232, -0.55557023301960195560, -0.59130964836358235193, -0.62592347218405908205, -0.65934581510006884386, -0.69151305578226929249,
+-0.72236396205975550444, -0.75183980747897727337, -0.77988448309288194160, -0.80644460426748265647, -0.83146961230254523567, -0.85491187067294660551,
+-0.87672675570750768781, -0.89687274153268825572, -0.91531147911944710227, -0.93200786928279844012, -0.94693012949510557696, -0.96004985438592860270,
+-0.97134206981326132180, -0.98078528040323031956, -0.98836151046776066220, -0.99405633822231953545, -0.99785892323860347908, -0.99976202707990913243,
+-0.99976202707990913243, -0.99785892323860347908, -0.99405633822231964647, -0.98836151046776066220, -0.98078528040323043058, -0.97134206981326143282,
+-0.96004985438592871372, -0.94693012949510568799, -0.93200786928279855115, -0.91531147911944721329, -0.89687274153268847776, -0.87672675570750790985,
+-0.85491187067294682755, -0.83146961230254545772, -0.80644460426748287851, -0.77988448309288216365, -0.75183980747897782848, -0.72236396205975605955,
+-0.69151305578226918147, -0.65934581510006873284, -0.62592347218405897102, -0.59130964836358235193, -0.55557023301960217765, -0.51877325816052144436,
+-0.48098876891938774358, -0.44228869021900141245, -0.40274668985873740557, -0.36243803828370185771, -0.32143946530316186427, -0.27982901403099241788,
+-0.23768589232617348683, -0.19509032201612871993, -0.15212338618991719241, -0.10886687485196513969, -0.06540312923014367230, -0.02181488503456178660
+};
+const double costab_gtres[SH_LTRACK_GTRES] = {
+ 0.99976202707990913243, 0.99785892323860347908, 0.99405633822231964647, 0.98836151046776066220, 0.98078528040323043058, 0.97134206981326143282,
+ 0.96004985438592871372, 0.94693012949510568799, 0.93200786928279855115, 0.91531147911944721329, 0.89687274153268836674, 0.87672675570750768781,
+ 0.85491187067294660551, 0.83146961230254523567, 0.80644460426748265647, 0.77988448309288183058, 0.75183980747897738439, 0.72236396205975561546,
+ 0.69151305578226940352, 0.65934581510006884386, 0.62592347218405908205, 0.59130964836358235193, 0.55557023301960228867, 0.51877325816052155538,
+ 0.48098876891938774358, 0.44228869021900124592, 0.40274668985873723903, 0.36243803828370169118, 0.32143946530316169774, 0.27982901403099202930,
+ 0.23768589232617309825, 0.19509032201612833135, 0.15212338618991680383, 0.10886687485196473724, 0.06540312923014304780, 0.02181488503456115863,
+-0.02181488503456103373, -0.06540312923014292290, -0.10886687485196461234, -0.15212338618991669281, -0.19509032201612819257, -0.23768589232617298723,
+-0.27982901403099191828, -0.32143946530316158672, -0.36243803828370158016, -0.40274668985873712801, -0.44228869021900113490, -0.48098876891938746603,
+-0.51877325816052122232, -0.55557023301960195560, -0.59130964836358246295, -0.62592347218405908205, -0.65934581510006884386, -0.69151305578226929249,
+-0.72236396205975550444, -0.75183980747897727337, -0.77988448309288160853, -0.80644460426748243442, -0.83146961230254534669, -0.85491187067294660551,
+-0.87672675570750768781, -0.89687274153268825572, -0.91531147911944710227, -0.93200786928279844012, -0.94693012949510557696, -0.96004985438592860270,
+-0.97134206981326132180, -0.98078528040323043058, -0.98836151046776066220, -0.99405633822231964647, -0.99785892323860347908, -0.99976202707990913243,
+-0.99976202707990913243, -0.99785892323860347908, -0.99405633822231964647, -0.98836151046776077322, -0.98078528040323043058, -0.97134206981326143282,
+-0.96004985438592871372, -0.94693012949510568799, -0.93200786928279855115, -0.91531147911944721329, -0.89687274153268836674, -0.87672675570750779883,
+-0.85491187067294671653, -0.83146961230254545772, -0.80644460426748254545, -0.77988448309288183058, -0.75183980747897749541, -0.72236396205975561546,
+-0.69151305578226951454, -0.65934581510006906591, -0.62592347218405897102, -0.59130964836358224090, -0.55557023301960217765, -0.51877325816052144436,
+-0.48098876891938768807, -0.44228869021900135694, -0.40274668985873735005, -0.36243803828370180220, -0.32143946530316180876, -0.27982901403099236237,
+-0.23768589232617343132, -0.19509032201612866442, -0.15212338618991713690, -0.10886687485196507030, -0.06540312923014361679, -0.02181488503456172415,
+ 0.02181488503456135639, 0.06540312923014325597, 0.10886687485196470948, 0.15212338618991677608, 0.19509032201612830359, 0.23768589232617307050,
+ 0.27982901403099197379, 0.32143946530316147570, 0.36243803828370146913, 0.40274668985873701699, 0.44228869021900102387, 0.48098876891938735501,
+ 0.51877325816052111129, 0.55557023301960184458, 0.59130964836358201886, 0.62592347218405863796, 0.65934581510006839977, 0.69151305578226895943,
+ 0.72236396205975572649, 0.75183980747897749541, 0.77988448309288183058, 0.80644460426748254545, 0.83146961230254523567, 0.85491187067294660551,
+ 0.87672675570750768781, 0.89687274153268825572, 0.91531147911944710227, 0.93200786928279844012, 0.94693012949510557696, 0.96004985438592860270,
+ 0.97134206981326132180, 0.98078528040323031956, 0.98836151046776066220, 0.99405633822231953545, 0.99785892323860347908, 0.99976202707990913243
+};
+
+struct sh_track_entry_data {
+ UINT64 last_login;
+ UINT32 array[SH_LTRACK_HTRES]; /* 1 h resolution */
+ char hostname[SH_LTRACK_HSIZE];
+};
+
+struct sh_track_entry {
+ struct sh_track_entry_data data;
+ struct sh_track_entry * next;
+};
+
+struct sh_track_head {
+ UINT32 version;
+ UINT32 n_entries;
+ UINT64 last_login;
+ char hostname[SH_LTRACK_HSIZE];
+ UINT32 array[SH_LTRACK_GTRES]; /* 10 min resolution */
+};
+
+struct sh_track {
+ struct sh_track_head head;
+ struct sh_track_entry * list;
+};
+
+
+/* Returns zero/nonzero
+ */
+static int get_bool(char *bitarray, unsigned int index)
+{
+ int bool;
+
+ bitarray += index / 8; /* skip to char */
+ bool = (*bitarray & (1 << (index % 8)));
+
+ return bool;
+}
+
+static void set_bool(char *bitarray, unsigned int index, int bool)
+{
+ bitarray += index / 8; /* skip to char */
+ if (bool)
+ *bitarray |= 1 << (index % 8);
+ else
+ *bitarray &= ~(1 << (index % 8));
+ return;
+}
+
+
+static char * build_path (const char * user)
+{
+ char * ui;
+
+ if (0 != sh_util_base64_enc_alloc (&ui, user, sl_strlen(user)))
+ {
+ char * path = sh_util_strconcat(DEFAULT_DATAROOT, "/", ui, NULL);
+
+ SH_FREE(ui);
+ return path;
+ }
+ return NULL;
+}
+
+static void destroy_loaded(struct sh_track * urecord)
+{
+ if (urecord)
+ {
+ struct sh_track_entry * entry = urecord->list;
+ struct sh_track_entry * entry_old;
+
+ while(entry)
+ {
+ entry_old = entry;
+ entry = entry->next;
+ SH_FREE(entry_old);
+ }
+ SH_FREE(urecord);
+ }
+ return;
+}
+
+static struct sh_track * load_data_int (char * path)
+{
+ struct sh_track_head * uhead;
+ struct sh_track * urecord;
+
+ urecord = SH_ALLOC(sizeof(struct sh_track));
+ memset(urecord, '\0', sizeof(struct sh_track));
+
+ uhead = &(urecord->head);
+ uhead->version = SH_LTRACK_VERSION;
+
+ if (path)
+ {
+ FILE * fp = fopen(path, "rb");
+
+ if (fp)
+ {
+ size_t n;
+
+ n = fread(uhead, sizeof(struct sh_track_head), 1, fp);
+
+ if (n == 1)
+ {
+ struct sh_track_entry_data entry_data;
+ struct sh_track_entry * entry;
+
+ while (1 == fread(&entry_data, sizeof(entry_data), 1, fp))
+ {
+ entry = SH_ALLOC(sizeof(struct sh_track_entry));
+ memcpy(&(entry->data), &entry_data, sizeof(entry_data));
+ entry->next = urecord->list;
+ urecord->list = entry;
+ }
+ }
+ fclose(fp);
+ }
+ }
+
+ return urecord;
+}
+
+static struct sh_track * load_data (const char * user)
+{
+ char * path = build_path (user);
+ struct sh_track * res = load_data_int (path);
+
+ if (path)
+ SH_FREE(path);
+ return res;
+}
+
+static void save_data_int (struct sh_track * urecord, char * path)
+{
+ mode_t mask;
+ FILE * fp;
+
+ mask = umask(S_IWGRP | S_IWOTH);
+ fp = fopen(path, "wb");
+ (void) umask(mask);
+
+ if (fp)
+ {
+ size_t n;
+
+ n = fwrite(&(urecord->head), sizeof(struct sh_track_head), 1, fp);
+
+ if (n == 1)
+ {
+ struct sh_track_entry * entry = urecord->list;
+
+ while (entry && (n > 0))
+ {
+ n = fwrite(&(entry->data), sizeof(struct sh_track_entry_data),
+ 1, fp);
+ entry = entry->next;
+ }
+ }
+ fclose(fp);
+ }
+ return;
+}
+
+static void save_data (struct sh_track * urecord, const char * user)
+{
+ char * path = build_path (user);
+
+ if (path)
+ {
+ save_data_int (urecord, path);
+ SH_FREE(path);
+ }
+ return;
+}
+
+/**************
+ *
+ * Configurable
+ *
+ **************/
+
+enum significance { SIG00, SIG01, SIG05 };
+enum checklevel { CHECK_NONE, CHECK_HOST, CHECK_DOMAIN };
+enum days { WORKDAYS = 0, SATURDAY, SUNDAY };
+#define LTRACK_NDAYS 3
+
+static int sig_level = SIG00;
+static int check_level = CHECK_NONE;
+static int check_date = S_FALSE;
+
+/* We use a bit array of SH_LTRACK_GTRES bits for allowed times
+ * (10 min resolution)
+ */
+#define BITARRSIZ(a) ((a + 7) / 8)
+
+static int global_init = S_FALSE;
+static char global_dates[LTRACK_NDAYS][BITARRSIZ(SH_LTRACK_GTRES)];
+
+struct sh_track_dates {
+ char user[SH_LTRACK_USIZE];
+ char dates[LTRACK_NDAYS][BITARRSIZ(SH_LTRACK_GTRES)];
+ struct sh_track_dates * next;
+};
+struct sh_track_dates * user_dates = NULL;
+
+static int set_dates (char bitarray[][BITARRSIZ(SH_LTRACK_GTRES)],
+ unsigned int size, const char * defstr);
+
+void sh_login_reset (void)
+{
+ int i, j;
+ struct sh_track_dates *u_old, *u;
+
+ u = user_dates;
+ user_dates = NULL;
+
+ while(u)
+ {
+ u_old = u;
+ u = u->next;
+ SH_FREE(u_old);
+ }
+
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ {
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ {
+ set_bool(global_dates[j], i, 0);
+ }
+ }
+ global_init = S_FALSE;
+
+ sig_level = SIG00;
+ check_level = CHECK_NONE;
+ check_date = S_FALSE;
+
+ return;
+}
+
+int sh_login_set_def_allow(const char * c)
+{
+ int res = set_dates(global_dates, SH_LTRACK_GTRES, c);
+
+ if (res == 0)
+ {
+ check_date = S_TRUE;
+ global_init = S_TRUE;
+ }
+ return res;
+}
+
+static struct sh_track_dates * find_user(const char * user)
+{
+ struct sh_track_dates * u = user_dates;
+
+ while(u)
+ {
+ if (0 == strcmp(user, u->user))
+ {
+ return u;
+ }
+ u = u->next;
+ }
+ return NULL;
+}
+
+int sh_login_set_user_allow(const char * c)
+{
+ unsigned int i = 0;
+ const char *p = c;
+ char user[SH_LTRACK_USIZE];
+
+ struct sh_track_dates * u;
+
+ while (p && *p && *p != ':' && *p != ' ' && *p != '\t')
+ {
+ user[i] = *p; ++p; ++i;
+
+ if (i == SH_LTRACK_USIZE)
+ return -1;
+ }
+
+ while (p && *p && (*p == ' ' || *p == '\t')) ++p;
+
+ if (p && *p && (i < SH_LTRACK_USIZE) && (*p == ':'))
+ {
+ user[i] = '\0';
+
+ ++p; while (*p && (*p == ' ' || *p == '\t')) ++p;
+
+ if (*p)
+ {
+ int res;
+ int flag = 0;
+
+ u = find_user(user);
+
+ if (!u)
+ {
+ u = SH_ALLOC(sizeof(struct sh_track_dates));
+ memset(u, '\0', sizeof(struct sh_track_dates));
+ sl_strlcpy(u->user, user, SH_LTRACK_USIZE);
+ flag = 1;
+ }
+
+ res = set_dates(u->dates, SH_LTRACK_GTRES, p);
+ if (res != 0)
+ {
+ if (flag == 1)
+ SH_FREE(u);
+ return -1;
+ }
+
+ if (flag == 1)
+ {
+ u->next = user_dates;
+ user_dates = u;
+ }
+
+ check_date = S_TRUE;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int sh_login_set_siglevel(const char * c)
+{
+ int ret = sh_util_flagval(c, &sig_level);
+
+ if (ret == 0)
+ {
+ sig_level = (sig_level == S_FALSE) ? SIG00 : SIG01;
+ return 0;
+ }
+ else
+ {
+ if (0 == strcmp(c, _("paranoid")))
+ {
+ sig_level = SIG05;
+ return 0;
+ }
+ }
+ sig_level = SIG00;
+ return -1;
+}
+
+int sh_login_set_checklevel(const char * c)
+{
+ int ret = sh_util_flagval(c, &check_level);
+
+ if (ret == 0)
+ {
+ check_level = (check_level == S_FALSE) ? CHECK_NONE : CHECK_HOST;
+ return 0;
+ }
+ else
+ {
+ if (0 == strcmp(c, _("domain")))
+ {
+ check_level = CHECK_DOMAIN;
+ return 0;
+ }
+ }
+ check_level = CHECK_NONE;
+ return -1;
+}
+
+static int eval_range(char * bitarray, unsigned int size, char * def)
+{
+ unsigned int h1, m1, h2, m2;
+
+ int res = sscanf(def, "%d:%d - %d:%d", &h1, &m1, &h2, &m2);
+
+ if (res == 4)
+ {
+ unsigned int t1 = 3600*h1 + 60*m1;
+ unsigned int t2 = 3600*h2 + 60*m2;
+ int hres = (60*60*24)/size;
+ unsigned int i;
+
+ if (t1 > t2 || t1 > 86340 || t2 > 86340)
+ return -1;
+
+ t1 = t1 / hres;
+ t2 = t2 / hres;
+ t1 = (t1 < size) ? t1 : (size-1);
+ t2 = (t2 < size) ? t2 : (size-1);
+
+ for (i = t1; i <= t2; ++i)
+ {
+ set_bool(bitarray, i, 1);
+ }
+ return 0;
+ }
+ return -1;
+}
+
+static int set_ranges(char * bitarray, unsigned int size,
+ char ** splits, unsigned int nfields)
+{
+ unsigned int i;
+ int retval = 0;
+
+ for (i = 0; i < nfields; ++i)
+ {
+ char * range = &(splits[i][0]);
+
+ if (0 != eval_range(bitarray, size, range))
+ retval = -1;
+ }
+ return retval;
+}
+
+/* 'always', 'never', workdays(list of ranges), (sun|satur)day(list of ranges)
+ */
+static int set_dates (char bitarray[][BITARRSIZ(SH_LTRACK_GTRES)],
+ unsigned int size,
+ const char * defstr)
+{
+ unsigned int i, j;
+ int retval = -1;
+
+ if (0 == strcmp(_("always"), defstr))
+ {
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ for (i = 0; i < size; ++i)
+ set_bool(bitarray[j], i, 1);
+ retval = 0;
+ }
+ else if (0 == strcmp(_("never"), defstr))
+ {
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ for (i = 0; i < size; ++i)
+ set_bool(bitarray[j], i, 0);
+ retval = 0;
+ }
+ else
+ {
+ unsigned int nfields = 24; /* list of ranges */
+ size_t lengths[24];
+ char * new = NULL;
+ char ** splits = NULL;
+
+ if (0 == strncmp(_("workdays"), defstr, 7))
+ {
+ new = sh_util_strdup(defstr);
+ splits = split_array_braced(new, _("workdays"),
+ &nfields, lengths);
+ j = WORKDAYS;
+ }
+ else if (0 == strncmp(_("saturday"), defstr, 8))
+ {
+ new = sh_util_strdup(defstr);
+ splits = split_array_braced(new, _("saturday"),
+ &nfields, lengths);
+ j = SATURDAY;
+ }
+ else if (0 == strncmp(_("sunday"), defstr, 6))
+ {
+ new = sh_util_strdup(defstr);
+ splits = split_array_braced(new, _("sunday"),
+ &nfields, lengths);
+ j = SUNDAY;
+ }
+ else
+ {
+ return -1;
+ }
+
+ if (new && splits && nfields > 0)
+ {
+ retval = set_ranges(bitarray[j], size, splits, nfields);
+ }
+
+ if (new) SH_FREE(new);
+ }
+ return retval;
+}
+
+
+
+/**************
+ *
+ * Report
+ *
+ **************/
+
+void report_generic(char * file, int line,
+ const char * user, time_t time, const char * host, int what)
+{
+ char ttt[TIM_MAX];
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (time, ttt, TIM_MAX);
+ sh_error_handle ((-1), file, line, 0, what,
+ user, host, ttt);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return;
+}
+
+void report_bad_date(char * file, int line,
+ const char *user, time_t time, const char * host)
+{
+ report_generic(file, line, user, time, host, MSG_UT_BAD);
+}
+
+void report_first(char * file, int line,
+ const char *user, time_t time, const char * host)
+{
+ report_generic(file, line, user, time, host, MSG_UT_FIRST);
+}
+
+void report_outlier(char * file, int line,
+ const char *user, time_t time, const char * host)
+{
+ report_generic(file, line, user, time, host, MSG_UT_OUTLIER);
+}
+
+/**************
+ *
+ * Dates
+ *
+ **************/
+
+static int check_login_date(const char * user, unsigned int index, int wday)
+{
+ unsigned int i, j;
+ struct sh_track_dates * allowed = NULL;
+ int day;
+
+ /* Use an intermediate array 'char* b[m]' to cast 'char a[m][n]' to 'char** c' */
+ char * aux[LTRACK_NDAYS];
+ char **good = (char **) aux;
+
+ for (i = 0; i < LTRACK_NDAYS; ++i)
+ {
+ aux[i] = (char *) &global_dates[i][0];
+ /* + i * BITARRSIZ(SH_LTRACK_GTRES); */
+ }
+
+ if (wday > 0 && wday < 6)
+ day = WORKDAYS;
+ else if (wday == 6)
+ day = SATURDAY;
+ else
+ day = SUNDAY;
+
+ if (check_date != S_FALSE)
+ {
+ if (S_FALSE == global_init)
+ {
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ {
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ set_bool(global_dates[j], i, 1);
+ }
+ global_init = S_TRUE;
+ }
+
+ if (user) {
+ allowed = find_user(user);
+ }
+
+ if (allowed)
+ {
+ for (i = 0; i < LTRACK_NDAYS; ++i)
+ {
+ aux[i] = (char *)&(allowed->dates)[i][0];
+ /* + i*BITARRSIZ(SH_LTRACK_GTRES); */
+ }
+ }
+
+ if (0 == get_bool(good[day], index))
+ {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**************
+ *
+ * Statistics
+ *
+ **************/
+
+/* Compute sqrt(s) using the babylonian algorithm
+ * (to avoid linking with -lm).
+ */
+static double sh_sqrt(double s)
+{
+ double eps = 1.0e-6;
+ double x0 = 1.0;
+ double xs = s;
+
+ double diff = xs - x0;
+ diff = (diff > 0.0) ? diff : -diff;
+
+ while (diff > eps)
+ {
+ xs = x0;
+ x0 = 0.5 * (x0 + (s/x0));
+ diff = xs - x0;
+ diff = (diff > 0.0) ? diff : -diff;
+ }
+ return x0;
+}
+
+static double M_crit(int n, int flag)
+{
+#define SH_MCSIZE 10
+ const double M_05[SH_MCSIZE] = { 0.975, 0.918, 0.855, 0.794, 0.739, 0.690, 0.647, 0.577, 0.497, 0.406 };
+ const double M_01[SH_MCSIZE] = { 0.995, 0.970, 0.934, 0.891, 0.845, 0.799, 0.760, 0.688, 0.603, 0.498 };
+ const int M_nn[SH_MCSIZE] = { 4, 5, 6, 7, 8, 9, 10, 12, 15, 20 };
+
+ if (n > M_nn[SH_MCSIZE-1])
+ {
+ return ((flag == SIG05) ? M_05[SH_MCSIZE-1] : M_01[SH_MCSIZE-1]);
+ }
+ else
+ {
+ unsigned int i;
+
+ for (i = 1; i < SH_MCSIZE; ++i)
+ {
+ if (n < M_nn[i])
+ {
+ return ((flag == SIG05) ? M_05[i-1] : M_01[i-1]);
+ }
+ }
+ }
+
+ return ((flag == SIG05) ? M_05[SH_MCSIZE-1] : M_01[SH_MCSIZE-1]);
+}
+
+static int check_statistics (unsigned int index, UINT32 * array, unsigned int size,
+ const double * costab, const double * sintab)
+{
+ double C = 0.0;
+ double S = 0.0;
+ double R, Rk, M;
+
+ unsigned int i, n = 0;
+
+ if (sig_level != SIG00)
+ {
+ for (i = 0; i < size; ++i)
+ {
+ n += array[i];
+ C += (array[i] * costab[i]);
+ S += (array[i] * sintab[i]);
+ }
+
+ if (n > 2) /* current is at least 4th datapoint */
+ {
+ R = sh_sqrt(S*S + C*C);
+
+ C += array[index] * costab[index];
+ S += array[index] * sintab[index];
+ Rk = sh_sqrt(S*S + C*C);
+ ++n;
+
+ M = (Rk - R + 1.0)/((double)n - R);
+
+ if (M > M_crit(n, sig_level))
+ {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static char * stripped_hostname (const char * host)
+{
+ char *p, *q;
+
+ if (sh_ipvx_is_numeric(host))
+ {
+ p = sh_util_strdup(host);
+ q = strrchr(p, '.');
+ if (q)
+ {
+ *q = '\0';
+ q = strrchr(p, '.');
+ if (q)
+ {
+ *q = '\0';
+ }
+ }
+ }
+ else
+ {
+ q = strchr(host, '.');
+ if (q && *q)
+ {
+ ++q;
+ p = sh_util_strdup(q);
+ }
+ else
+ {
+ p = sh_util_strdup(host);
+ }
+ }
+ return p;
+}
+
+static unsigned int time_to_index(struct tm * tp, int nbin)
+{
+ int hres = (60*60*24)/nbin;
+ int index = tp->tm_hour * 3600 + tp->tm_min * 60 + tp->tm_sec;
+ index = index / hres;
+ index = (index < nbin) ? index : (nbin-1);
+
+ return index;
+}
+
+static struct sh_track_entry * check_host(struct sh_track_entry * list,
+ const char * user, time_t time, const char * host,
+ struct tm * tp)
+{
+ unsigned int index = time_to_index(tp, SH_LTRACK_HTRES);
+ struct sh_track_entry * entry = list;
+
+ char * p = NULL;
+ const char * q;
+
+ if (check_level == CHECK_DOMAIN)
+ {
+ p = stripped_hostname(host);
+ q = p;
+ }
+ else
+ {
+ q = host;
+ }
+
+ while (entry)
+ {
+ if (0 == strncmp(q, (entry->data).hostname, SH_LTRACK_HSIZE))
+ break;
+ entry = entry->next;
+ }
+
+ if (entry)
+ {
+ int isAlert;
+
+ (entry->data).last_login = time;
+
+ /* Check host statistics here
+ */
+ isAlert = check_statistics (index, (entry->data).array, SH_LTRACK_HTRES,
+ costab_htres, sintab_htres);
+
+ if (isAlert != 0)
+ {
+ report_outlier(FIL__, __LINE__, user, time, host);
+ }
+
+ /* Update array afterwards
+ */
+ (entry->data).array[index] += 1;
+ }
+ else
+ {
+ entry = SH_ALLOC(sizeof(struct sh_track_entry));
+ memset(entry, '\0', sizeof(struct sh_track_entry));
+ (entry->data).last_login = time;
+ (entry->data).array[index] = 1;
+ sl_strlcpy((entry->data).hostname, q, SH_LTRACK_HSIZE);
+
+ /* Report first login from this host
+ */
+ if (check_level != CHECK_NONE)
+ {
+ report_first (FIL__, __LINE__, user, time, host);
+ }
+
+ if (p)
+ SH_FREE(p);
+ return entry;
+ }
+
+ if (p)
+ SH_FREE(p);
+ return NULL;
+}
+
+/********************************************************
+ *
+ * Public Function
+ *
+ ********************************************************/
+
+void sh_ltrack_check(struct SH_UTMP_S * ut)
+{
+ int gres;
+ const char * user;
+ time_t time;
+#if defined(HAVE_UTHOST)
+ const char * host;
+#else
+ const char * host;
+#endif
+ struct sh_track * urecord;
+ time_t last_login;
+
+ /* Just return if we are not supposed to do anything
+ */
+ if (sig_level == SIG00 && check_level == CHECK_NONE && check_date == S_FALSE)
+ return;
+
+
+#if defined(HAVE_UTHOST)
+ host = ut->ut_host;
+#else
+ host = sh_util_strdup(_("unknown"));
+#endif
+ time = ut->ut_time;
+ user = ut->ut_name;
+
+ gres = (60*60*24)/SH_LTRACK_GTRES;
+
+ urecord = load_data(user);
+ last_login = (urecord->head).last_login;
+
+ if ( last_login < time &&
+ ( (time - last_login) >= gres ||
+ 0 != strcmp(host, (urecord->head).hostname)
+ )
+ )
+ {
+ struct tm ts;
+ unsigned int index;
+ int isAlert;
+ struct sh_track_entry * entry;
+
+ (urecord->head).last_login = time;
+ sl_strlcpy((urecord->head).hostname, host, SH_LTRACK_HSIZE);
+ (urecord->head).n_entries += 1;
+
+ memcpy(&ts, localtime(&time), sizeof(struct tm));
+ index = time_to_index(&ts, SH_LTRACK_GTRES);
+
+ /* Check global statistics here
+ */
+ isAlert = check_statistics (index, (urecord->head).array,
+ SH_LTRACK_GTRES,
+ costab_gtres, sintab_gtres);
+
+ if (isAlert != 0)
+ {
+ report_outlier(FIL__, __LINE__, user, time, host);
+ }
+
+
+ if (check_date != S_FALSE)
+ {
+ int isBad = check_login_date(user, index, ts.tm_wday);
+
+ if (isBad != 0)
+ {
+ report_bad_date(FIL__, __LINE__, user, time, host);
+ }
+ }
+
+ /* Update array afterwards
+ */
+ (urecord->head).array[index] += 1;
+
+ entry = check_host(urecord->list, user, time, host, &ts);
+ if (entry)
+ {
+ entry->next = urecord->list;
+ urecord->list = entry;
+ }
+
+ save_data(urecord, user);
+ }
+
+ destroy_loaded(urecord);
+
+#if !defined(HAVE_UTHOST)
+ SH_FREE(host);
+#endif
+ return;
+}
+
+#ifdef SH_CUTEST
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "CuTest.h"
+
+void Test_login (CuTest *tc) {
+ char bitarr[10] = { 0,0,0,0,0,0,0,0,0,128 };
+ unsigned int i;
+ int j, k;
+ char buf[1024];
+ char *p, *q;
+ size_t l1, l2;
+
+ /* Check bitarray */
+
+ for (i = 0; i < 72; ++i)
+ {
+ set_bool(bitarr, i, 1);
+ }
+ for (i = 72; i < 80; ++i)
+ {
+ set_bool(bitarr, i, 0);
+ }
+ for (i = 0; i < 80; ++i)
+ {
+ j = get_bool(bitarr, i);
+ if (i < 72)
+ CuAssertTrue(tc, j > 0);
+ else
+ CuAssertIntEquals(tc, 0, j);
+ }
+
+ /* check build_path */
+
+ j = sl_strlcpy(buf, DEFAULT_DATAROOT, sizeof(buf));
+ CuAssertIntEquals(tc, 0, j);
+
+ p = build_path("rainer");
+ q = sh_util_dirname(p);
+ j = strncmp(buf, q, strlen(buf));
+ l1 = strlen(buf); l2 = strlen(q);
+ CuAssertTrue(tc, l2 >= l1);
+ CuAssertIntEquals(tc, 0, j);
+
+ q = sh_util_basename(p);
+ CuAssertStrEquals(tc, q, "cmFpbmVy");
+
+ { /* Check load/save of user data */
+ struct sh_track urecord, *precord;
+ struct sh_track_entry uentry0, *pentry;
+ struct sh_track_entry uentry1;
+
+ urecord.head.version = 40;
+ urecord.head.n_entries = 41;
+ urecord.head.last_login = 42;
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ urecord.head.array[i] = 0;
+ urecord.head.array[30] = 30;
+
+ urecord.list = &uentry0;
+ uentry0.next = &uentry1;
+ uentry1.next = NULL;
+
+ uentry0.data.last_login = 52;
+ strcpy(uentry0.data.hostname, "host0");
+ for (i = 0; i < SH_LTRACK_HTRES; ++i)
+ uentry0.data.array[i] = 0;
+ uentry0.data.array[5] = 50;
+
+ uentry1.data.last_login = 62;
+ strcpy(uentry1.data.hostname, "host1");
+ for (i = 0; i < SH_LTRACK_HTRES; ++i)
+ uentry1.data.array[i] = 0;
+ uentry1.data.array[6] = 60;
+
+ snprintf(buf, sizeof(buf), "cutest_%06d", (int) getpid());
+
+ save_data_int(&urecord, buf);
+
+ precord = load_data_int(buf);
+
+ CuAssertIntEquals(tc, urecord.head.version, (precord->head).version);
+ CuAssertIntEquals(tc, urecord.head.n_entries, (precord->head).n_entries);
+ CuAssertIntEquals(tc, urecord.head.last_login, (precord->head).last_login);
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ CuAssertIntEquals(tc, urecord.head.array[i], (precord->head).array[i]);
+
+ CuAssertPtrNotNull(tc, precord->list);
+ pentry = precord->list;
+ CuAssertIntEquals(tc, uentry1.data.last_login, (pentry->data).last_login);
+ CuAssertStrEquals(tc, uentry1.data.hostname, (pentry->data).hostname);
+ for (i = 0; i < SH_LTRACK_HTRES; ++i)
+ CuAssertIntEquals(tc, uentry1.data.array[i], (pentry->data).array[i]);
+
+ CuAssertPtrNotNull(tc, pentry->next);
+ pentry = pentry->next;
+ CuAssertIntEquals(tc, uentry0.data.last_login, (pentry->data).last_login);
+ CuAssertStrEquals(tc, uentry0.data.hostname, (pentry->data).hostname);
+ for (i = 0; i < SH_LTRACK_HTRES; ++i)
+ CuAssertIntEquals(tc, uentry0.data.array[i], (pentry->data).array[i]);
+
+ CuAssertPtrEquals(tc, pentry->next, NULL);
+ destroy_loaded(precord);
+ unlink(buf);
+
+ precord = load_data_int("supacalifragilistic");
+ CuAssertPtrNotNull(tc, precord);
+ CuAssertPtrEquals(tc, precord->list, NULL);
+ CuAssertIntEquals(tc, SH_LTRACK_VERSION, (precord->head).version);
+ CuAssertIntEquals(tc, 0, (precord->head).n_entries);
+ CuAssertIntEquals(tc, 0, (precord->head).last_login);
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ CuAssertIntEquals(tc, 0, (precord->head).array[i]);
+ destroy_loaded(precord);
+
+ precord = load_data_int(NULL);
+ CuAssertPtrNotNull(tc, precord);
+ CuAssertPtrEquals(tc, precord->list, NULL);
+ CuAssertIntEquals(tc, SH_LTRACK_VERSION, (precord->head).version);
+ CuAssertIntEquals(tc, 0, (precord->head).n_entries);
+ CuAssertIntEquals(tc, 0, (precord->head).last_login);
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ CuAssertIntEquals(tc, 0, (precord->head).array[i]);
+ destroy_loaded(precord);
+ }
+
+ /* check configuration */
+
+ j = sh_login_set_siglevel("duh");
+ CuAssertIntEquals(tc, -1, j);
+ CuAssertIntEquals(tc, SIG00, sig_level);
+
+ j = sh_login_set_siglevel("yes");
+ CuAssertIntEquals(tc, 0, j);
+ CuAssertIntEquals(tc, SIG01, sig_level);
+ j = sh_login_set_siglevel("no");
+ CuAssertIntEquals(tc, 0, j);
+ CuAssertIntEquals(tc, SIG00, sig_level);
+ j = sh_login_set_siglevel("paranoid");
+ CuAssertIntEquals(tc, 0, j);
+ CuAssertIntEquals(tc, SIG05, sig_level);
+
+ j = sh_login_set_checklevel("duh");
+ CuAssertIntEquals(tc, -1, j);
+ CuAssertIntEquals(tc, CHECK_NONE, check_level);
+
+ j = sh_login_set_checklevel("yes");
+ CuAssertIntEquals(tc, 0, j);
+ CuAssertIntEquals(tc, CHECK_HOST, check_level);
+ j = sh_login_set_checklevel("no");
+ CuAssertIntEquals(tc, 0, j);
+ CuAssertIntEquals(tc, CHECK_NONE, check_level);
+ j = sh_login_set_checklevel("domain");
+ CuAssertIntEquals(tc, 0, j);
+ CuAssertIntEquals(tc, CHECK_DOMAIN, check_level);
+
+ j = sh_login_set_def_allow("always");
+ CuAssertIntEquals(tc, 0, j);
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ {
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ {
+ k = get_bool(global_dates[j], i);
+ CuAssertTrue(tc, k > 0);
+ }
+ }
+
+ j = sh_login_set_def_allow("never");
+ CuAssertIntEquals(tc, 0, j);
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ {
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ {
+ k = get_bool(global_dates[j], i);
+ CuAssertIntEquals(tc, 0, k);
+ }
+ }
+
+ j = sh_login_set_def_allow("workdays( 0:12-1:30, 07:30-18:29,23:30-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ {
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ {
+ k = get_bool(global_dates[j], i);
+ // fprintf(stderr, "%d: %d: %d\n", j, i, k);
+ if (j == WORKDAYS)
+ {
+ if ( (i>=1 && i<=9) || (i>=45 && i <=110) || (i>=141 && i<=143))
+ CuAssertTrue(tc, k > 0);
+ else
+ CuAssertIntEquals(tc, 0, k);
+ }
+ else
+ {
+ CuAssertIntEquals(tc, 0, k);
+ }
+ }
+ }
+
+ j = sh_login_set_user_allow("rainer :workdays( 0:12-1:30, 07:30-18:29,23:30-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ j = sh_login_set_user_allow("rainer :saturday( 0:0-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ j = sh_login_set_user_allow("rain : workdays(0:12-1:30, 07:30-18:29,23:30-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ j = sh_login_set_user_allow("cat: workdays( 0:12-1:30, 07:30-18:29,23:30-23:59 )");
+ CuAssertIntEquals(tc, 0, j);
+ j = sh_login_set_user_allow("cat: sunday(0:00-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+
+ {
+ int count = 0;
+ struct sh_track_dates * u = user_dates;
+
+ CuAssertPtrNotNull(tc, u);
+
+ do {
+
+ if (count == 0) {
+ CuAssertStrEquals(tc, u->user, "cat");
+ CuAssertPtrNotNull(tc, u->next);
+ }
+ else if (count == 1) {
+ CuAssertStrEquals(tc, u->user, "rain");
+ CuAssertPtrNotNull(tc, u->next);
+ }
+ else if (count == 2) {
+ CuAssertStrEquals(tc, u->user, "rainer");
+ CuAssertPtrEquals(tc, u->next, NULL);
+ }
+
+ for (j = 0; j < LTRACK_NDAYS; ++j)
+ {
+ for (i = 0; i < SH_LTRACK_GTRES; ++i)
+ {
+ k = get_bool(u->dates[j], i);
+ // fprintf(stderr, "%d: %d: %d\n", j, i, k);
+ if (j == WORKDAYS)
+ {
+ if ( (i>=1 && i<=9) || (i>=45 && i <=110) ||
+ (i>=141 && i<=143) )
+ {
+ CuAssertTrue(tc, k > 0);
+ }
+ else
+ {
+ CuAssertIntEquals(tc, 0, k);
+ }
+ }
+ else
+ {
+ if ((count == 0 && j == SUNDAY) ||
+ (count == 2 && j == SATURDAY))
+ CuAssertTrue(tc, k > 0);
+ else
+ CuAssertIntEquals(tc, 0, k);
+ }
+ }
+ }
+
+ if (u->next == NULL)
+ break;
+
+ u = u->next; ++count;
+
+ } while (1 == 1);
+ }
+
+ sh_login_reset();
+ CuAssertIntEquals(tc, SIG00, sig_level);
+ CuAssertIntEquals(tc, CHECK_NONE, check_level);
+
+ /* check dates */
+
+ j = sh_login_set_def_allow("workdays( 0:12-1:30, 07:30-18:29,23:30-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+
+ j = check_login_date("rainer", 0, 2);
+ CuAssertIntEquals(tc, -1, j);
+ j = check_login_date("rainer", 1, 2);
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("rainer",50, 3);
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("rainer",142, 5);
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("rainer", 1, 0);
+ CuAssertIntEquals(tc, -1, j);
+ j = check_login_date("rainer", 1, 6);
+ CuAssertIntEquals(tc, -1, j);
+ j = sh_login_set_user_allow("rainer :saturday( 0:0-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("rainer", 1, 6);
+ CuAssertIntEquals(tc, 0, j);
+ j = sh_login_set_user_allow("mouse :sunday( 0:0-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ j = sh_login_set_user_allow("cat :saturday(0:0-23:59)");
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("rainer", 1, 6);
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("mouse", 1, 6);
+ CuAssertIntEquals(tc, -1, j);
+ j = check_login_date("mouse", 1, 0);
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("cat", 1, 6);
+ CuAssertIntEquals(tc, 0, j);
+ j = check_login_date("dog", 1, 6);
+ CuAssertIntEquals(tc, -1, j);
+
+ sh_login_reset();
+
+ /* statistics, critical values */
+ {
+ double f;
+
+ f = M_crit(1, SIG05);
+ CuAssertTrue(tc, f > 0.974 && f < 0.976);
+ f = M_crit(13, SIG05);
+ CuAssertTrue(tc, f > 0.576 && f < 0.578);
+ f = M_crit(22, SIG05);
+ CuAssertTrue(tc, f > 0.405 && f < 0.407);
+ f = M_crit(10, SIG05);
+ CuAssertTrue(tc, f > 0.646 && f < 0.648);
+ f = M_crit(10, SIG01);
+ CuAssertTrue(tc, f > 0.759 && f < 0.761);
+ }
+
+ /* stripped hostname */
+ p = stripped_hostname("127.20.120.100");
+ CuAssertStrEquals(tc, "127.20", p);
+
+ p = stripped_hostname("foo.www.example.com");
+ CuAssertStrEquals(tc, p, "www.example.com");
+
+ p = stripped_hostname("www.example.com");
+ CuAssertStrEquals(tc, p, "example.com");
+
+ p = stripped_hostname("localhost");
+ CuAssertStrEquals(tc, p, "localhost");
+
+ {
+ struct tm tt;
+
+ tt.tm_hour = 0;
+ tt.tm_min = 30;
+ tt.tm_sec = 0;
+
+ for (i = 0; i < 24; ++i)
+ {
+ tt.tm_hour = i;
+ j = time_to_index(&tt, SH_LTRACK_HTRES);
+ CuAssertIntEquals(tc, j, i);
+ }
+
+ tt.tm_min = 10;
+
+ for (i = 0; i < 24; ++i)
+ {
+ tt.tm_hour = i;
+ j = time_to_index(&tt, SH_LTRACK_GTRES);
+ CuAssertIntEquals(tc, 1+i*6, j);
+ }
+ }
+}
+/* #ifdef SH_CUTEST */
+#endif
+
+#else
+
+#ifdef SH_CUTEST
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "CuTest.h"
+
+void Test_login (CuTest *tc) {
+ (void) tc;
+}
+
+/* #ifdef SH_CUTEST */
+#endif
+
+#endif
diff --git a/src/sh_mail.c b/src/sh_mail.c
new file mode 100644
index 0000000..4511e8f
--- /dev/null
+++ b/src/sh_mail.c
@@ -0,0 +1,2002 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#if defined(SH_WITH_MAIL)
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_unix.h"
+#include "sh_tiger.h"
+#include "sh_mail.h"
+#include "sh_utils.h"
+#include "sh_fifo.h"
+#include "sh_tools.h"
+#include "sh_pthread.h"
+#include "sh_filter.h"
+#include "sh_mail_int.h"
+#include "sh_nmail.h"
+#include "sh_ipvx.h"
+
+#undef FIL__
+#define FIL__ _("sh_mail.c")
+#undef GOOD
+#undef BAD
+
+static int failedMail = S_FALSE;
+
+static dnsrep * return_mx (char *domain);
+
+/*********************************************
+ * utility function for verifying mails
+ *********************************************/
+
+typedef struct mail_trail_struct {
+ char trail_id[2*SH_MINIBUF];
+ char trail_key[KEY_LEN+1];
+ struct mail_trail_struct * next;
+} mail_trail_type;
+
+static mail_trail_type * mail_trail = NULL;
+
+int sh_mail_sigverify (const char * s)
+{
+ SL_TICKET fd;
+ long i;
+ char * buf;
+ char * bufc;
+ char key[81];
+ char number[2*SH_MINIBUF];
+ char audit_id[2 * SH_MINIBUF];
+ long numsig;
+ char key2[KEY_LEN+1];
+
+ char * theSig;
+
+ mail_trail_type * mail_trail_ptr = NULL;
+
+ sh_error_logoff();
+
+ ASSERT((s != NULL && sl_strlen(s) < PATH_MAX),
+ _("(s != NULL && sl_strlen(s) < PATH_MAX)"));
+
+ if (s == NULL || sl_strlen(s) >= PATH_MAX)
+ _exit (EXIT_FAILURE);
+
+ /* open the file, then check it
+ */
+ if (0 != sl_is_suid())
+ {
+ fprintf(stderr, _("Cannot open file %s in suid mode\n"), s);
+ _exit (EXIT_FAILURE);
+ }
+ if ( SL_ISERROR(fd = sl_open_read (FIL__, __LINE__, s, SL_NOPRIV)))
+ {
+ fprintf(stderr, _("Could not open file %s\n"), s);
+ _exit (EXIT_FAILURE);
+ }
+
+ buf = SH_ALLOC( (size_t)(SH_MSG_BUF+SH_BUFSIZE+1));
+ bufc = SH_ALLOC( (size_t)(SH_MSG_BUF+SH_MAXBUF+1));
+
+ while (1 == 1)
+ {
+ buf[0] = '\0';
+ bufc[0] = '\0';
+
+ /* find start of next message
+ */
+ while (0 != sl_strncmp(buf, _("-----BEGIN MESSAGE-----"),
+ sizeof("-----BEGIN MESSAGE-----")-1))
+ {
+ (void) sh_unix_getline (fd, buf, SH_MSG_BUF+SH_BUFSIZE);
+ if (buf[0] == '\0')
+ {
+ /* End of mailbox reached, exit.
+ */
+ (void) fflush(stdout);
+ _exit (EXIT_SUCCESS);
+
+ /* Fix for AIX cc complaint.
+ */
+ /*@notreached@*/
+ return 0;
+ }
+ }
+
+ /* Read message, compress into bufc.
+ */
+ while (1 == 1)
+ {
+ (void) sh_unix_getline (fd, buf, SH_MSG_BUF+SH_BUFSIZE);
+ if (0 == sl_strncmp(buf, _("-----BEGIN SIGNATURE-----"),
+ sizeof("-----BEGIN SIGNATURE-----")-1))
+ break;
+ if (buf[0] == '\0')
+ _exit (EXIT_FAILURE);
+ (void) sh_util_compress(bufc, buf, SH_MSG_BUF+SH_MAXBUF-KEY_LEN);
+ }
+
+ /* get signature and number
+ */
+ (void) sh_unix_getline (fd, key, (int)sizeof(key));
+ key[KEY_LEN] = '\0';
+
+ (void) sh_unix_getline (fd, number, (int)sizeof(number));
+ number[(2*SH_MINIBUF) - 2] = '\0';
+ numsig = atol (number);
+ (void) sl_strlcpy (audit_id, &number[7], 2*SH_MINIBUF);
+
+ fprintf(stderr, _("Message %06ld Trail %s\n"),
+ numsig, /*@-usedef@*/ audit_id /*@+usedef@*/);
+
+ mail_trail_ptr = mail_trail;
+ while (mail_trail_ptr)
+ {
+ if (0 == sl_strcmp(mail_trail_ptr->trail_id, audit_id))
+ break;
+ mail_trail_ptr = mail_trail_ptr->next;
+ }
+
+ if (!mail_trail_ptr)
+ {
+ if (numsig > 0)
+ {
+ fprintf (stderr, "%s",_("ERROR (no key -- cannot check)\n"));
+ continue;
+ }
+ else
+ {
+ mail_trail_ptr = SH_ALLOC (sizeof(mail_trail_type));
+ mail_trail_ptr->next = mail_trail;
+ mail_trail = mail_trail_ptr;
+ (void) sl_strlcpy (mail_trail_ptr->trail_id,
+ audit_id, 2*SH_MINIBUF);
+ }
+ }
+ else if (numsig == 0)
+ {
+ fprintf (stderr, "%s",_("ERROR (repeated audit trail)\n"));
+ continue;
+ }
+
+
+ if (numsig == 0)
+ {
+ sh_util_encode(key, bufc, 1, 'A');
+ (void) sl_strlcpy (mail_trail_ptr->trail_key, key, KEY_LEN+1);
+ fprintf (stderr, "%s",_("(unchecked)\n"));
+ }
+ else
+ {
+ char sigbuf[KEYBUF_SIZE];
+
+ /* iterate key
+ */
+ (void) sl_strlcpy(key2, mail_trail_ptr->trail_key, KEY_LEN+1);
+ for (i = 0; i < numsig; ++i)
+ {
+ char hashbuf[KEYBUF_SIZE];
+ (void) sl_strlcpy (key2,
+ sh_tiger_hash (key2, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+
+ theSig = sh_util_siggen (key2, bufc, sl_strlen(bufc),
+ sigbuf, sizeof(sigbuf));
+
+ if (sl_strncmp (key,
+ theSig,
+ KEY_LEN) != 0)
+ {
+ fprintf (stderr, "%s",_("(FAILED)\n"));
+ }
+ else
+ {
+ fprintf (stderr, "%s",_("(passed)\n"));
+ }
+
+ }
+
+ } /* end scan mailbox */
+
+ /*@notreached@*/
+}
+
+int sh_mail_setNum (const char * str)
+{
+ int i = atoi (str);
+
+ SL_ENTER(_("sh_mail_setNum"));
+
+ if (i >= 0 && i < SH_FIFO_MAX)
+ sh.mailNum.alarm_interval = (time_t) i;
+ else
+ SL_RETURN ((-1), _("sh_mail_setNum"));
+ SL_RETURN( (0), _("sh_mail_setNum"));
+}
+
+
+int sh_mail_all_in_one = S_FALSE;
+
+int sh_mail_setFlag (const char * str)
+{
+ int i;
+ SL_ENTER(_("sh_mail_setFlag"));
+ i = sh_util_flagval(str, &sh_mail_all_in_one);
+ SL_RETURN(i, _("sh_mail_setFlag"));
+}
+
+static char * mail_subject = NULL;
+
+int set_mail_subject (const char * str)
+{
+ SL_ENTER(_("set_mail_subject"));
+ if (!str)
+ SL_RETURN( (-1), _("set_mail_subject"));
+
+ if (mail_subject != NULL)
+ SH_FREE(mail_subject);
+
+ if (0 == sl_strncmp(str, _("NULL"), 4))
+ {
+ mail_subject = NULL;
+ SL_RETURN( 0, _("set_mail_subject"));
+ }
+
+ mail_subject = sh_util_strdup(str);
+ SL_RETURN( (0), _("set_mail_subject"));
+}
+
+SH_MUTEX_INIT(mutex_fifo_mail, PTHREAD_MUTEX_INITIALIZER);
+
+SH_FIFO * fifo_mail = NULL;
+
+static
+void sh_mail_emptystack (void)
+{
+ char * msg;
+ size_t len;
+
+ SL_ENTER(_("sh_mail_emptystack"));
+
+ if (fifo_mail == NULL)
+ SL_RET0(_("sh_mail_emptystack"));
+
+ SH_MUTEX_LOCK(mutex_fifo_mail);
+ while (NULL != (msg = pop_list(fifo_mail)))
+ {
+ len = sl_strlen(msg);
+ memset(msg, 0, len);
+ SH_FREE(msg);
+ }
+ SH_MUTEX_UNLOCK(mutex_fifo_mail);
+
+ SL_RET0(_("sh_mail_emptystack"));
+}
+
+/* insert "\r\n" after each 998 char
+ */
+static char * split_string(const char * str);
+
+/* fixes warning: variable ‘p’ might be clobbered by ‘longjmp’ or ‘vfork’*/
+static char ** p_dummy;
+
+int sh_mail_pushstack (int severity, const char * msg, const char * alias)
+{
+ char * p;
+ volatile int retval = 0;
+ int status;
+
+ SL_ENTER(_("sh_mail_pushstack"));
+
+ if (msg == NULL || failedMail == S_TRUE /* || sh.srvmail.name[0] == '\0' */)
+ SL_RETURN((0), (_("sh_mail_pushstack")));
+
+ p = split_string(msg);
+ /* fixes "variable ‘p’ might be clobbered by ‘longjmp’ or ‘vfork’" */
+ p_dummy = &p;
+
+ SH_MUTEX_LOCK(mutex_fifo_mail);
+
+ if (fifo_mail == NULL)
+ {
+ fifo_mail = SH_ALLOC(sizeof(SH_FIFO));
+ fifo_init(fifo_mail);
+ }
+ status = push_list (fifo_mail, p, severity, alias);
+ SH_MUTEX_UNLOCK(mutex_fifo_mail);
+
+ if (status >= 0)
+ ++sh.mailNum.alarm_last;
+
+ SH_FREE(p);
+
+ if (sh.mailNum.alarm_last >= sh.mailNum.alarm_interval)
+ {
+ BREAKEXIT(sh_nmail_flush);
+ retval = sh_nmail_flush ();
+ }
+
+ if (status == SH_FIFO_MAX)
+ retval = -2;
+ SL_RETURN(retval, (_("sh_mail_pushstack")));
+}
+
+
+/* The mailer.
+ */
+static int sh_mail_end_conn (FILE * connfile, int fd);
+static FILE * sh_mail_start_conn (struct alias * address, int * fd, int * anum);
+
+static
+void sh_mail_get_subject(const char * message,
+ char * mheader, size_t len)
+{
+ st_format rep_serv_tab[] = {
+ { 'T', S_FMT_TIME, 0, 0, NULL},
+ { 'H', S_FMT_STRING, 0, 0, NULL},
+ { 'M', S_FMT_STRING, 0, 0, NULL},
+ { 'S', S_FMT_STRING, 0, 0, NULL},
+ {'\0', S_FMT_ULONG, 0, 0, NULL},
+ };
+
+ char * p;
+ char * mptr;
+ char sev[8];
+ char * msg;
+
+ SL_ENTER(_("sh_mail_get_subject"));
+
+ (void) sl_strlcpy(mheader, _("Subject: "), len);
+ if (NULL == strchr(mail_subject, '%'))
+ {
+ (void) sl_strlcat(mheader, mail_subject, len);
+ SL_RET0(_("sh_mail_get_subject"));
+ }
+
+
+ rep_serv_tab[0].data_ulong = (unsigned long) time(NULL);
+ rep_serv_tab[1].data_str = sh.host.name;
+
+ /* fast forward to the important part
+ */
+ msg = sh_util_strdup(message);
+
+ mptr = sl_strstr(msg, _("msg="));
+ if (mptr)
+ {
+ mptr += 4;
+ rep_serv_tab[2].data_str = mptr;
+ }
+ else
+ rep_serv_tab[2].data_str = msg;
+
+ mptr = sl_strstr(msg, _("sev="));
+ if (mptr)
+ {
+ mptr += 5;
+ sev[0] = *mptr; ++mptr;
+ sev[1] = *mptr; ++mptr;
+ sev[2] = *mptr; ++mptr;
+ sev[3] = *mptr; ++mptr;
+ sev[4] = '\0';
+ }
+ else
+ {
+ mptr = msg;
+ sev[0] = *mptr; ++mptr;
+ sev[1] = *mptr; ++mptr;
+ sev[2] = *mptr; ++mptr;
+ sev[3] = *mptr; ++mptr;
+ if (*mptr == ' ') {
+ sev[4] = '\0';
+ } else {
+ sev[4] = *mptr; ++mptr;
+ if (*mptr == ' ') {
+ sev[5] = '\0';
+ } else {
+ sev[5] = *mptr;
+ sev[6] = '\0';
+ }
+ }
+ }
+ rep_serv_tab[3].data_str = sev;
+
+
+ p = sh_util_formatted(mail_subject, rep_serv_tab);
+ (void) sl_strlcat(mheader, p, len);
+ SH_FREE(p);
+ SH_FREE(msg);
+ SL_RET0(_("sh_mail_get_subject"));
+}
+
+sh_string * sh_mail_signature_block (sh_string * sigMsg, char * recipient,
+ char * bufcompress)
+{
+ time_t id_audit;
+ char * theSig;
+ char ibuf[80];
+ unsigned int count;
+
+ /* ------ signature block ------------------------------------ */
+
+ sigMsg = sh_string_add_from_char(sigMsg,
+ _("-----BEGIN SIGNATURE-----\r\n"));
+
+ count = sh_nmail_get_mailkey (recipient, skey->mailkey_new, KEY_LEN+1,
+ &id_audit);
+
+ if (count != 0)
+ {
+ char sigbuf[KEYBUF_SIZE];
+
+ /* Sign the message with the signature key.
+ */
+ theSig = sh_util_siggen (skey->mailkey_new,
+ bufcompress, sl_strlen(bufcompress),
+ sigbuf, sizeof(sigbuf));
+ sigMsg = sh_string_add_from_char(sigMsg, theSig);
+ }
+ else
+ {
+ /* reveal first signature key
+ */
+ /* flawfinder: ignore */
+ (void) sl_strlcpy(skey->crypt, skey->mailkey_new, KEY_LEN+1);
+
+ BREAKEXIT(sh_util_encode);
+ /* flawfinder: ignore */
+ sh_util_encode(skey->crypt, bufcompress, 0, 'A');
+
+ /* flawfinder: ignore */
+ sigMsg = sh_string_add_from_char(sigMsg, skey->crypt);
+
+ /* flawfinder: ignore */
+ memset (skey->crypt, 0, KEY_LEN);
+ }
+
+ sigMsg = sh_string_add_from_char(sigMsg, "\r\n");
+
+ sl_snprintf(ibuf, sizeof(ibuf), _("%06u %010lu::%s\r\n"),
+ count, (unsigned long) id_audit, sh.host.name);
+
+ sigMsg = sh_string_add_from_char(sigMsg, ibuf);
+ sigMsg = sh_string_add_from_char(sigMsg, _("-----END MESSAGE-----"));
+
+ return sigMsg;
+}
+
+int sh_mail_msg (const char * message)
+{
+ char subject[32+32+SH_MINIBUF+2+3+SH_PATHBUF];
+ char mheader[32+32+SH_MINIBUF+2+3];
+
+ sh_string * mailMsg;
+ sh_string * compMsg;
+ int status = 0;
+ volatile int errcount;
+ size_t wrlen;
+ volatile int retval = -1;
+
+ char * bufcompress;
+ size_t compressed;
+
+ static int failcount = 0;
+ FILE * connfile = NULL;
+
+ static time_t fail_time = 0;
+ static time_t success_time = 0;
+
+ int ma_socket = -1;
+
+ int address_num = 0;
+ sh_string * theMsg = NULL;
+
+ /* #define SH_MAILBUF (256) */
+#define SH_MAILBUF 4096
+
+ char timebuf[81];
+
+ SL_ENTER(_("sh_mail_msg"));
+
+ /*
+ * Return if we cannot mail.
+ */
+ if (failedMail == S_TRUE)
+ SL_RETURN((-1), _("sh_mail_msg"));
+
+ /*
+ * Final failure, can't mail for SH_MAX_FAIL hours.
+ */
+ if ( (success_time > 0) && (fail_time > 0) &&
+ (time(NULL) - success_time) > 3600*SH_MAX_FAIL)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
+ _("mail"),
+ sh_string_str(all_recipients->recipient));
+ sh_mail_emptystack();
+ sh.mailNum.alarm_last = 0;
+ failedMail = S_TRUE;
+ SL_RETURN((-1), _("sh_mail_msg"));
+ }
+
+ /*
+ * Try at most every three seconds to mail if there was a failure.
+ */
+ if ((fail_time > 0) && (time(NULL) - fail_time) < 3/*600*/)
+ {
+ if (failcount > 3)
+ {
+ /* -- Save for later. Changed: done by caller. --
+ * sh_nmail_pushstack (severity, message, alias);
+ */
+ ++failcount;
+
+ SL_RETURN((-2), _("sh_mail_msg"));
+ }
+ else
+ {
+ (void) retry_msleep(2, 0);
+ ++failcount;
+ }
+ }
+
+ /* -- Reset time of last failure. --
+ */
+ fail_time = 0;
+
+
+ /* --------- Build complete message. ------------------------ */
+
+ /* Don't flush the queue here, because tag_list doesn't know
+ * how to filter messages. */
+
+ theMsg = sh_string_new_from_lchar(message, sl_strlen(message));
+ if (!theMsg)
+ {
+ SL_RETURN((-1), _("sh_mail_msg"));
+ }
+
+ /* ---------- Header ---------------------------------------- */
+
+ if (mail_subject == NULL)
+ {
+ (void) sl_strlcpy(mheader, _("Subject: "), sizeof(mheader)-5);
+ (void) sl_strlcat(mheader,
+ sh_unix_time (0, timebuf, sizeof(timebuf)),
+ sizeof(mheader)-5);
+ (void) sl_strlcat(mheader, " ", sizeof(mheader)-5);
+ (void) sl_strlcat(mheader, sh.host.name, sizeof(mheader)-5);
+ }
+ else
+ {
+
+ if (message)
+ {
+ sh_mail_get_subject(message, mheader, sizeof(mheader)-5);
+ }
+ else
+ {
+ (void) sl_strlcpy(mheader, _("Subject: "), sizeof(mheader)-5);
+ (void) sl_strlcat(mheader,
+ sh_unix_time (0, timebuf, sizeof(timebuf)),
+ sizeof(mheader)-5);
+ (void) sl_strlcat(mheader, " ", sizeof(mheader)-5);
+ (void) sl_strlcat(mheader, sh.host.name, sizeof(mheader)-5);
+ }
+ }
+
+ /* RFC 821: Header is terminated by an empty line
+ */
+ (void) sl_strlcat(mheader, "\015\012\015\012", sizeof(mheader));
+
+ /* ---------- Message --------------------------------------- */
+
+ (void) sl_strlcpy(subject, sh_unix_time (0, timebuf, sizeof(timebuf)),
+ sizeof(subject));
+ (void) sl_strlcat(subject, " ", sizeof(subject));
+ (void) sl_strlcat(subject, sh.host.name, sizeof(subject));
+ (void) sl_strlcat(subject, "\r\n", sizeof(subject));
+
+
+ mailMsg = sh_string_new (SH_MAILBUF);
+ compMsg = sh_string_new (SH_MAILBUF);
+
+ mailMsg = sh_string_add_from_char(mailMsg, mheader);
+ mailMsg = sh_string_add_from_char(mailMsg,
+ _("-----BEGIN MESSAGE-----\r\n"));
+
+ mailMsg = sh_string_add_from_char(mailMsg, subject);
+ mailMsg = sh_string_add (mailMsg, theMsg);
+ mailMsg = sh_string_add_from_char(mailMsg, "\r\n");
+
+ /* ---------- Compressed Message ---------------------------- */
+
+ compMsg = sh_string_add_from_char(compMsg, subject);
+ compMsg = sh_string_add (compMsg, theMsg);
+ compMsg = sh_string_add_from_char(compMsg, "\r\n");
+
+ bufcompress = SH_ALLOC(sh_string_len(compMsg) + KEY_LEN + 1);
+ bufcompress[0] = '\0';
+
+ compressed = sh_util_compress (bufcompress,
+ sh_string_str(compMsg),
+ sh_string_len(compMsg) + 1);
+
+ /* ---------- Connect ---------------------------------------- */
+
+ errcount = 0;
+
+ if (sh_mail_all_in_one == S_FALSE)
+ {
+ struct alias * address_list;
+
+ address_list = all_recipients;
+
+ while (address_list)
+ {
+ if (address_list->send_mail == 1)
+ {
+ connfile = sh_mail_start_conn (address_list,
+ &ma_socket, &address_num);
+
+ if (NULL != connfile)
+ {
+ wrlen = fwrite (sh_string_str(mailMsg), 1,
+ sh_string_len(mailMsg), connfile);
+ wrlen -= sh_string_len(mailMsg);
+
+ if (wrlen == 0)
+ {
+ sh_string * sigMsg = sh_string_new (0);
+
+ sigMsg = sh_mail_signature_block (sigMsg,
+ sh_string_str(address_list->recipient),
+ bufcompress);
+
+ wrlen = fwrite (sh_string_str(sigMsg), 1,
+ sh_string_len(sigMsg), connfile);
+ wrlen -= sh_string_len(sigMsg);
+
+ sh_string_destroy(&sigMsg);
+ }
+
+ if (wrlen == 0)
+ status = sh_mail_end_conn (connfile, ma_socket);
+ else
+ status = -1;
+ }
+ if (NULL == connfile || status != 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
+ _("mail"),
+ sh_string_str(address_list->recipient));
+ ++errcount;
+ ++sh.statistics.mail_failed;
+ }
+ else
+ {
+ ++sh.statistics.mail_success;
+ }
+
+ if (connfile != NULL)
+ {
+ (void) sl_fclose (FIL__, __LINE__, connfile);
+ connfile = NULL;
+ }
+ }
+ address_list = address_list->all_next;
+ }
+ }
+ else
+ {
+ connfile = sh_mail_start_conn (NULL, &ma_socket, &address_num);
+
+ if (NULL != connfile)
+ {
+ wrlen = fwrite (sh_string_str(mailMsg), 1,
+ sh_string_len(mailMsg), connfile);
+ wrlen -= sh_string_len(mailMsg);
+
+ if (wrlen == 0)
+ {
+ sh_string * sigMsg = sh_string_new (0);
+
+ sigMsg = sh_mail_signature_block (sigMsg,
+ NULL,
+ bufcompress);
+
+ wrlen = fwrite (sh_string_str(sigMsg), 1,
+ sh_string_len(sigMsg), connfile);
+ wrlen -= sh_string_len(sigMsg);
+
+ sh_string_destroy(&sigMsg);
+ }
+
+ if (wrlen == 0)
+ status = sh_mail_end_conn (connfile, ma_socket);
+ else
+ status = -1;
+ }
+
+ if (NULL == connfile || status != 0)
+ {
+ struct alias* ma_address = all_recipients;
+
+ while (ma_address)
+ {
+ if (ma_address->send_mail == 1)
+ break;
+ ma_address = ma_address->all_next;
+ }
+
+ if (ma_address)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
+ _("mail"),
+ sh_string_str(ma_address->recipient));
+ errcount = address_num;
+ ++sh.statistics.mail_failed;
+ }
+ else
+ {
+ ++sh.statistics.mail_success;
+ }
+
+ if (connfile != NULL)
+ {
+ (void) sl_fclose (FIL__, __LINE__, connfile);
+ connfile = NULL;
+ }
+ }
+
+ memset (bufcompress, 0, compressed);
+ SH_FREE(bufcompress);
+
+ memset (sh_string_str(mailMsg), 0, sh_string_len(mailMsg));
+ memset (sh_string_str(compMsg), 0, sh_string_len(compMsg));
+ memset (sh_string_str(theMsg), 0, sh_string_len(theMsg));
+
+ sh_string_destroy(&mailMsg);
+ sh_string_destroy(&compMsg);
+ sh_string_destroy(&theMsg);
+
+ /* --- Stay responsible for delivery in case of failure --- */
+
+ if (errcount == address_num)
+ {
+ rollback_list(fifo_mail);
+ retval = -3;
+ }
+ else
+ {
+ mark_list(fifo_mail);
+ }
+
+ if (errcount == address_num)
+ {
+ fail_time = time(NULL);
+ SL_RETURN((retval), _("sh_mail_msg"));
+ }
+
+ success_time = time(NULL);
+ failcount = 0;
+
+ SL_RETURN((0), _("sh_mail_msg"));
+}
+
+
+/*
+ *
+ * SMTP CODE BELOW
+ *
+ *
+ */
+
+#include <ctype.h>
+#ifdef HOST_IS_HPUX
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef S_SPLINT_S
+#include <arpa/inet.h>
+#else
+#define AF_INET 2
+#endif
+
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+
+/* missing on HP-UX 10.20 */
+#ifndef IPPORT_SMTP
+#define IPPORT_SMTP 25
+#endif
+
+static int sh_mail_wait(int code, int ma_socket);
+
+static char * relay_host = NULL;
+
+int sh_mail_set_relay (const char * str_s)
+{
+ SL_ENTER(_("sh_mail_set_relay"));
+
+ if (str_s == NULL)
+ SL_RETURN( -1, _("sh_mail_set_relay"));
+
+ if (relay_host != NULL)
+ {
+ SH_FREE (relay_host);
+ relay_host = NULL;
+ }
+
+ if (0 == sl_strncmp(str_s, _("NULL"), 4))
+ {
+ SL_RETURN( 0, _("sh_mail_set_relay"));
+ }
+
+ relay_host = sh_util_strdup(str_s);
+
+ SL_RETURN( 0, _("sh_mail_set_relay"));
+}
+
+static char * mail_sender = NULL;
+
+int sh_mail_set_sender (const char *str)
+{
+ if (mail_sender != NULL)
+ {
+ SH_FREE (mail_sender);
+ mail_sender = NULL;
+ }
+ if (str != NULL)
+ {
+ mail_sender = sh_util_strdup (str);
+ }
+ if (mail_sender == NULL)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+static int sh_mail_port = IPPORT_SMTP;
+
+int sh_mail_set_port (const char * str)
+{
+ int i = atoi (str);
+
+ SL_ENTER(_("sh_mail_set_port"));
+
+ if (i >= 0 && i < 65535)
+ {
+ sh_mail_port = i;
+ }
+ else
+ {
+ sh_mail_port = IPPORT_SMTP;
+ SL_RETURN ((-1), _("sh_mail_set_port"));
+ }
+
+ SL_RETURN( (0), _("sh_mail_set_port"));
+}
+
+/*************************
+ *
+ * start connection
+ * for details on SMTP, see RFC 821
+ *
+ * If ma_address == NULL, will send to all marked with
+ * send_mail=1 in recipient list, else to ma_address.
+ */
+
+static time_t time_wait = 300;
+static void report_smtp (char * reply);
+
+static FILE * sh_mail_start_conn (struct alias * ma_address,
+ int * ma_socket, int * anum)
+{
+ char * address;
+ int aFlag = 0;
+
+ int ecount;
+
+ char this_address[256];
+ char ma_machine[256];
+ char ma_user[256];
+ char error_msg[256];
+ char error_call[SH_MINIBUF];
+ int error_num = 0;
+ register int i, j, k;
+ FILE * connFile = NULL;
+ struct tm * my_tm;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ struct tm time_tm;
+#endif
+ time_t my_time;
+ char my_tbuf[128];
+
+ int fd;
+
+ dnsrep * answers;
+ mx * result;
+
+ SL_ENTER(_("sh_mail_start_conn"));
+
+ *ma_socket = -1;
+ time_wait = 300;
+
+ if (ma_address == NULL)
+ {
+ aFlag = 1;
+ ma_address = all_recipients;
+
+ while (ma_address)
+ {
+ if (ma_address->send_mail == 1)
+ break;
+ ma_address = ma_address->all_next;
+ }
+ }
+
+ if (!ma_address)
+ {
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+ address = sh_string_str(ma_address->recipient);
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<address %s>\n"),
+ address));
+
+ /* ------- split adress ------------------ */
+
+ if (strchr (address, '@') == NULL) {
+ (void) sl_strlcpy(ma_user, address, 256);
+ (void) sl_strlcpy(ma_machine, _("localhost"), 256);
+ } else {
+ i = 0;
+ while (i < 255 && address[i] != '@') {
+ ma_user[i] = address[i];
+ ++i;
+ }
+
+ /* adress[i] = '@'
+ */
+ ma_user[i] = '\0';
+ j = i + 1; k = i; i = 0;
+ while (i < 255 && address[i+j] != '\0') {
+ ma_machine[i] = address[i+j];
+ ++i;
+ }
+ ma_machine[i] = '\0';
+ if (address[k] != '@' || address[k+i+1] != '\0')
+ {
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+ }
+
+
+ if (relay_host != NULL)
+ {
+ (void) sl_strlcpy (ma_machine, relay_host, sizeof(ma_machine));
+ TPT((0, FIL__, __LINE__, _("msg=<user %s machine %s>\n"),
+ ma_user, ma_machine));
+ fd = connect_port (ma_machine, sh_mail_port,
+ error_call, &error_num, error_msg, 256);
+ }
+ else
+ {
+ answers = ma_address->mx_list;
+ if (!answers)
+ {
+ answers = return_mx (ma_machine);
+ ma_address->mx_list = answers;
+ }
+
+ if (answers)
+ {
+ result = answers->reply;
+ fd = -1;
+ for (i = 0; i < answers->count; ++i)
+ {
+ (void) sl_strlcpy(ma_machine, result[i].address,
+ sizeof(ma_machine));
+ TPT((0, FIL__, __LINE__,
+ _("msg=<user %s mx %s pref %d>\n"),
+ ma_user, ma_machine, result[i].pref));
+ fd = connect_port (ma_machine, sh_mail_port,
+ error_call, &error_num, error_msg, 256);
+ if (fd >= 0)
+ break;
+ }
+ }
+ else
+ {
+ (void) sl_strlcpy(error_call, _("return_mx"), SH_MINIBUF);
+ (void) sl_strlcpy(error_msg, _("The specified host is unknown: "),
+ 256);
+ (void) sl_strlcat(error_msg, ma_machine, 256);
+ fd = -1;
+ }
+ }
+
+
+ if (fd < 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, error_num,
+ MSG_E_NET, error_msg, error_call,
+ _("email"), ma_machine);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+ /* associate a FILE structure with it
+ */
+ connFile = fdopen (fd, "r+");
+ if (connFile == NULL)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<fdopen() failed>\n")));
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+
+ /* say HELO to the other socket
+ */
+ if (0 == sh_mail_wait (220, fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("Timeout on SMTP session init"),
+ _("sh_mail_start_conn"),
+ _("mail"), sh.host.name);
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout>\n")));
+ (void) sl_fclose(FIL__, __LINE__, connFile);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+ (void) fflush(connFile);
+
+ if (0 != sh_ipvx_is_numeric(sh.host.name))
+ {
+ sl_snprintf(error_msg, sizeof(error_msg), "HELO [%s]",
+ sh.host.name);
+ }
+ else
+ {
+ sl_snprintf(error_msg, sizeof(error_msg), "HELO %s",
+ sh.host.name);
+ }
+ report_smtp(error_msg);
+
+ if (0 != sh_ipvx_is_numeric(sh.host.name))
+ fprintf(connFile, _("HELO [%s]%c%c"), sh.host.name, 13, 10);
+ else
+ fprintf(connFile, _("HELO %s%c%c"), sh.host.name, 13, 10);
+
+ (void) fflush(connFile);
+
+ if (0 == sh_mail_wait(250, fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("HELO failed"), _("sh_mail_start_conn"),
+ _("mail"), sh.host.name);
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
+ (void) sl_fclose(FIL__, __LINE__, connFile);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+ /* tell them who we are
+ */
+ (void) sl_strlcpy (this_address,
+ mail_sender ? mail_sender : DEFAULT_SENDER, 256);
+ if (NULL == strchr(this_address, '@'))
+ {
+ (void) sl_strlcat (this_address, "@", 256);
+ if (0 != sh_ipvx_is_numeric(sh.host.name))
+ (void) sl_strlcat (this_address, _("example.com"), 256);
+ else
+ (void) sl_strlcat (this_address, sh.host.name, 256);
+ }
+
+ sl_snprintf(error_msg, sizeof(error_msg), "MAIL FROM:<%s>",
+ this_address);
+ report_smtp(error_msg);
+
+ (void) fflush(connFile);
+ /*@-usedef@*/
+ fprintf(connFile, _("MAIL FROM:<%s>%c%c"), this_address, 13, 10);
+ /*@+usedef@*/
+ (void) fflush(connFile);
+
+ if (0 == sh_mail_wait(250, fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("MAIL FROM failed"), _("sh_mail_start_conn"),
+ _("mail"), this_address);
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
+ (void) sl_fclose(FIL__, __LINE__, connFile);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+ /* tell them who to send mail to
+ */
+ if (aFlag == 0)
+ {
+ sl_snprintf(error_msg, sizeof(error_msg), "RCPT TO:<%s>",
+ address);
+ report_smtp(error_msg);
+
+ (void) fflush(connFile);
+ fprintf(connFile, _("RCPT TO:<%s>%c%c"), address, 13, 10);
+ (void) fflush(connFile);
+
+ if (0 == sh_mail_wait(250, fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("RCPT TO failed"), _("sh_mail_start_conn"),
+ _("mail"), address);
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
+ (void) sl_fclose(FIL__, __LINE__, connFile);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+ *anum = 1;
+ }
+ else
+ {
+ int address_num = 0;
+ ecount = 0;
+
+ ma_address = all_recipients;
+
+ while (ma_address)
+ {
+ if (ma_address->send_mail != 1)
+ {
+ ma_address = ma_address->next;
+ continue;
+ }
+
+ ++address_num;
+
+ sl_snprintf(error_msg, sizeof(error_msg), "RCPT TO:<%s>",
+ sh_string_str(ma_address->recipient));
+ report_smtp(error_msg);
+
+ (void) fflush(connFile);
+ fprintf(connFile, _("RCPT TO:<%s>%c%c"),
+ sh_string_str(ma_address->recipient), 13, 10);
+ (void) fflush(connFile);
+
+ if (0 == sh_mail_wait(250, fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("RCPT TO failed"), _("sh_mail_start_conn"),
+ _("mail"), sh_string_str(ma_address->recipient));
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
+ ++ecount;
+ }
+ ma_address = ma_address->next;
+ }
+
+ *anum += address_num;
+
+ if (ecount == address_num)
+ {
+ (void) sl_fclose(FIL__, __LINE__, connFile);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+ }
+
+ /* Send the message
+ */
+ report_smtp(_("DATA"));
+
+ (void) fflush(connFile);
+ fprintf(connFile, _("DATA%c%c"), 13, 10);
+ (void) fflush(connFile);
+
+ if (0 == sh_mail_wait(354, fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("DATA failed"), _("sh_mail_start_conn"),
+ _("mail"), address);
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
+ (void) sl_fclose(FIL__, __LINE__, connFile);
+ SL_RETURN( NULL, _("sh_mail_start_conn"));
+ }
+
+
+ my_time = time(NULL);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ my_tm = localtime_r(&my_time, &time_tm);
+#else
+ my_tm = localtime(&my_time);
+#endif
+
+ if (!my_tm)
+ {
+ sl_strlcpy(my_tbuf, _("Thu, 01 Jan 1970 00:00:00 +00:00"), sizeof(my_tbuf));
+ }
+ else
+ {
+#if defined(HAVE_STRFTIME_Z)
+ (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %z"), my_tm);
+#else
+ (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %Z"), my_tm);
+#endif
+ }
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<From: <%s>%c%cTo: <%s>%c%cDate: %s>%c%c"),
+ this_address, 13, 10, address, 13, 10, my_tbuf, 13, 10));
+
+ report_smtp(_("sending data.."));
+
+ (void) fflush(connFile);
+ fprintf(connFile,
+ _("From: <%s>%c%c"\
+ "To: <%s>%c%c"\
+ "Date: %s%c%c"),
+ this_address, 13, 10,
+ address, 13, 10,
+ my_tbuf, 13, 10);
+
+ *ma_socket = fd;
+ SL_RETURN( connFile, _("sh_mail_start_conn"));
+}
+
+/*************************
+ *
+ * end connection
+ *
+ */
+
+static int sh_mail_end_conn (FILE * connFile, int fd)
+{
+ SL_ENTER(_("sh_mail_end_conn"));
+
+ time_wait = 300;
+
+ report_smtp(_("."));
+
+ (void) fflush(connFile);
+ fprintf(connFile, _("%c%c.%c%c"), 13, 10, 13, 10);
+ (void) fflush(connFile);
+
+ if (0 != sh_mail_wait(250, fd))
+ {
+ (void) fflush(connFile);
+ fprintf(connFile, _("QUIT%c%c"), 13, 10);
+ (void) fflush(connFile);
+ TPT(( 0, FIL__, __LINE__, _("msg=<exit>\n")));
+
+ SL_RETURN (0, _("sh_mail_end_conn"));
+ }
+
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ _("QUIT failed"), _("sh_mail_end_conn"),
+ _("mail"), _("SMTP server"));
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<abnormal exit>\n")));
+
+ SL_RETURN ((-1), _("sh_mail_end_conn"));
+}
+
+
+
+/****************************
+ *
+ * Handle server replies
+ *
+ *
+ */
+extern int flag_err_debug;
+
+static void report_smtp (char * reply)
+{
+ char * tmp;
+
+ if (flag_err_debug == S_TRUE)
+ {
+ tmp = sh_util_safe_name_keepspace(reply);
+
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ tmp,
+ _("report_smtp") );
+ SH_FREE(tmp);
+ }
+ return;
+}
+
+
+static int sh_mail_wait(int code, int ma_socket)
+{
+ int rcode, g;
+
+ char c;
+
+ char errmsg[194];
+ char reply[128];
+ unsigned int ireply = 0;
+
+ enum {
+ WAIT_CODE_START,
+ WAIT_CODE,
+ WAIT_NL,
+ WAIT_NL_CONT
+ } state;
+
+ time_t waited_time;
+
+ SL_ENTER(_("mail_wait"));
+
+ waited_time = time(NULL);
+
+ /* timeout after 5 minutes
+ */
+
+ rcode = 0;
+ state = WAIT_CODE_START;
+ reply[0] = '\0';
+
+ while (sl_read_timeout_fd (ma_socket, &c, 1, time_wait, S_FALSE) > 0) {
+
+ if (ireply < (sizeof(reply) - 1))
+ {
+ if (c != '\n' && c != '\r')
+ {
+ reply[ireply] = c;
+ ++ireply;
+ reply[ireply] = '\0';
+ }
+ }
+
+ g = (int) c;
+
+ /*
+ if (g == EOF)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<mail_wait: EOF>\n")));
+ SL_RETURN( 0, _("mail_wait"));
+ }
+ */
+
+ switch(state) {
+
+ /* wait for start of a numerical code
+ */
+ case WAIT_CODE_START:
+ if (0 != isspace(g))
+ break; /* Skip white space */
+ if (0 == isdigit(g))
+ {
+ report_smtp(reply);
+ SL_RETURN( 0, _("mail_wait")); /* No leading number */
+ }
+ rcode = g-(int)'0'; /* convert to number */
+ state = WAIT_CODE;
+ break;
+
+ /* wait for completion of numerical code
+ */
+ case WAIT_CODE:
+ if (0 != isdigit(g)) {
+ rcode = rcode * 10 + (g-(int)'0'); /* next digit */
+ break;
+ }
+ /*@+charintliteral@*/
+ state = ((g == '-') ? WAIT_NL_CONT : WAIT_NL);
+ /*@-charintliteral@*/
+ break;
+
+ /* wait for newline, then return with status code
+ */
+ case WAIT_NL:
+ /*@+charintliteral@*/
+ if (g != '\n')
+ break;
+ /*@-charintliteral@*/
+
+ TPT((0, FIL__, __LINE__,
+ _("msg=<mail_wait: OK got %d (%d) need %d (%d)>\n"),
+ rcode, (int)(rcode/100), code, (int)(code/100) ));
+ g = ((int)(rcode/100) == (int)(code/100)) ? 1 : 0;
+ if (g != 1)
+ {
+ char * tmp = sh_util_safe_name_keepspace(reply);
+ sl_snprintf(errmsg, sizeof(errmsg),
+ _("Bad response (%s), expected %d"), tmp, code);
+ SH_FREE(tmp);
+
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
+ errmsg, _("sh_mail_wait"),
+ _("mail"), _("SMTP server"));
+ }
+ else
+ {
+ report_smtp(reply);
+ }
+ waited_time = time(NULL) - waited_time;
+ time_wait -= waited_time;
+ TPT((0, FIL__, __LINE__,
+ _("msg=<mail_wait: time_wait reduced to %d sec>\n"),
+ (int) time_wait));
+ SL_RETURN( (g), _("mail_wait")) ;
+
+ /* wait for continuation line
+ */
+ /*@fallthrough@*//* no, but splint doesn't understand */
+ case WAIT_NL_CONT:
+ /*@+charintliteral@*/
+ if (g == '\n')
+ state = WAIT_CODE_START; /* There is a continuation line */
+ /*@-charintliteral@*/
+ break;
+
+ default:
+
+ TPT((0, FIL__, __LINE__, _("msg=<mail_wait: bad>\n")));
+ report_smtp(reply);
+ SL_RETURN( 0, _("mail_wait"));
+
+ }
+ }
+
+ TPT((0, FIL__, __LINE__, _("msg=<mail_wait: failed>\n")));
+
+ /* Failed, EOF or error on socket */
+ report_smtp(reply);
+ SL_RETURN( 0, _("mail_wait"));
+}
+
+/* -- function to insert "\r\n" after each 998 chars --
+ */
+
+#define SPLIT_AT 998
+
+static char * split_string(const char * str)
+{
+ size_t size;
+ size_t blocks;
+ int count = 0;
+
+ char * p, * p0;
+ const char * q;
+
+ if (!str)
+ return NULL;
+
+ size = strlen(str) + 1;
+ blocks = 1 + (size / SPLIT_AT);
+
+ if (sl_ok_muls(2, blocks) && sl_ok_adds(size, (2*blocks)))
+ {
+ size = size + (2*blocks);
+ }
+ else
+ {
+ /* integer overflow, do not split */
+ p = sh_util_strdup(str);
+ return p;
+ }
+
+ p = SH_ALLOC(size);
+ memset(p, 0, size);
+
+ p0 = p;
+
+ q = str;
+ while (*q != '\0') {
+ *p = *q;
+ ++p;
+ ++q;
+ ++count;
+ if (0 == (count % SPLIT_AT)) {
+ count = 0;
+ *p = '\r';
+ ++p;
+ *p = '\n';
+ ++p;
+ }
+ }
+ /* fprintf(stderr, "used = %d\n", strlen(p0)); */
+
+ return p0;
+}
+
+
+
+/*****************************************************************
+ *
+ * MX Resolver Routines
+ *
+ *****************************************************************/
+
+#if defined(HAVE_ARPA_NAMESER_H)
+
+#include <netinet/in.h>
+#ifdef __APPLE__
+#define BIND_8_COMPAT 1
+#endif
+#ifndef S_SPLINT_S
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif
+#include <netdb.h>
+#include <sys/socket.h>
+#ifndef S_SPLINT_S
+#include <arpa/inet.h>
+#endif
+
+#include "sh_tools.h"
+
+#ifndef HFIXEDSZ
+#define HFIXEDSZ 12
+#endif
+#ifndef QFIXEDSZ
+#define QFIXEDSZ 4
+#endif
+
+/*@unused@*//* used in get_mx() which is not parsed by splint */
+static unsigned int get_short (unsigned char * loc)
+{
+ unsigned int retval = 0;
+ if (loc)
+ {
+ /* byte order: MSB first
+ */
+ /*@+charint@*/
+ retval = (((unsigned char) * loc) * 256) | ((unsigned char) * (loc + 1));
+ /*@-charint@*/
+ }
+ return (retval);
+}
+
+/* parser errors with splint */
+#ifndef S_SPLINT_S
+static dnsrep * get_mx (char *hostname)
+{
+ int ret, length, status;
+ mx * result;
+ size_t len;
+
+ typedef union
+ {
+ HEADER head;
+ unsigned char buffer[4096];
+ } querybuf;
+
+ querybuf * reply;
+ char expanded[1024];
+ unsigned char * comp_dn, * eom;
+ HEADER * header;
+ int type, rdlength, pref;
+ unsigned int count, theindex;
+ dnsrep * retval;
+
+ SL_ENTER(_("get_mx"));
+
+ if (0 != res_init ())
+ SL_RETURN (NULL, _("get_mx"));
+
+ reply = SH_ALLOC(sizeof(querybuf));
+
+ errno = 0;
+ length = res_query (hostname, C_IN, T_MX,
+ (unsigned char *) reply, 4095);
+
+ if (length < 1)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ /* error handling
+ */
+ if (length == -1)
+ {
+ if (errno == ECONNREFUSED)
+ status = ECONNREFUSED;
+ else
+ status = h_errno;
+
+#ifdef FIL__
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ (errno == ECONNREFUSED) ?
+ sh_error_message (status, errbuf, sizeof(errbuf)) :
+ sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
+ _("res_query"));
+#else
+ if (errno == ECONNREFUSED)
+ fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
+ else
+ fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
+#endif
+ }
+ SH_FREE(reply);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+
+ header = (HEADER *) reply;
+
+ /* start of data section
+ */
+ comp_dn = (unsigned char *) reply + HFIXEDSZ;
+
+ /* end-of-message
+ */
+ eom = (unsigned char *) reply + length;
+
+ /* HEADER NAME -- must be skipped or decompressed
+ * TYPE -- type of data we got back, 16 bit integer
+ * CLASS -- class we got back, also a 16 bit integer
+ * TTL -- 32 bit time-to-live. just skip this
+ * RDLENGTH -- length of the data to follow
+ * RDATA -- the data:
+ * PREF -- 16 bit preference
+ * MX -- name of mail exchanger, must be decompressed
+ */
+
+ /* Skip the query data.
+ * QDCOUNT is the number of entries (unsigned 16 bit int).
+ */
+ count = ntohs (header->qdcount);
+ for (theindex = 0; theindex < count; ++theindex)
+ {
+ ret = dn_skipname (comp_dn, eom);
+ comp_dn += ret + QFIXEDSZ;
+ if (ret < 1 || comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+ }
+
+ count = ntohs (header->ancount);
+ if (count < 1)
+ {
+ SH_FREE(reply);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ retval = SH_ALLOC (sizeof (dnsrep));
+ if (!retval)
+ {
+ SH_FREE(reply);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ retval->count = count;
+
+ /* allocate space for the results */
+
+ if (!sl_ok_muls(count, sizeof (mx)))
+ {
+ SH_FREE(reply);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ result = SH_ALLOC (count * sizeof (mx));
+
+ if (!result)
+ {
+ SH_FREE(reply);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+ retval->reply = result;
+
+ do
+ {
+ /* HEADER NAME
+ */
+ ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
+ (char *) expanded, 1023);
+ comp_dn += ret;
+ if (ret < 1 || comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ /* TYPE
+ */
+ type = get_short (comp_dn);
+ comp_dn += 2;
+ if (type != T_MX || comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+
+ /* CLASS (re-use 'type' var)
+ */
+ /* type = get_short (comp_dn); *//* don't care */
+ comp_dn += 2;
+ if (comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+
+ /* TTL
+ */
+ comp_dn += 4;
+ if (comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ /* RDLENGTH
+ */
+ rdlength = get_short (comp_dn);
+ comp_dn += 2;
+ if (rdlength < 1 || comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ /* RDATA
+ */
+ pref = get_short (comp_dn);
+ comp_dn += 2;
+ if (comp_dn >= eom)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+
+ ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
+ (char *) expanded, 1023);
+ comp_dn += ret;
+ if (ret < 1)
+ {
+ SH_FREE(reply);
+ SH_FREE (result);
+ SH_FREE (retval);
+ SL_RETURN (NULL, _("get_mx"));
+ }
+ count--;
+
+ /* fill in the struct
+ */
+ result[count].pref = pref;
+ len = strlen (expanded) + 1;
+ result[count].address = SH_ALLOC (len);
+ sl_strlcpy (result[count].address, expanded, len);
+ }
+ while (ret > 0 && comp_dn < eom && count);
+
+ SH_FREE(reply);
+ SL_RETURN (retval, _("get_mx"));
+}
+/* ifndef S_SPLINT_S */
+#endif
+
+/* #if defined(HAVE_ARPA_NAMESER_H) */
+#endif
+
+
+static int comp_mx_pref (const void * a, const void * b)
+{
+ const mx * ax = (const mx *) a;
+ const mx * bx = (const mx *) b;
+
+ if (ax->pref > bx->pref)
+ return 1;
+ else if (ax->pref < bx->pref)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * return_mx returns a list of valid mail exchangers for domain
+ */
+static dnsrep * return_mx (char *domain)
+{
+ dnsrep * answers = NULL;
+ mx * result;
+ dnsrep * retval;
+ char * address = NULL;
+ char errmsg[128];
+
+ SL_ENTER(_("return_mx"));
+
+#if defined(HAVE_ARPA_NAMESER_H)
+ if (domain != NULL)
+ answers = /*@-unrecog@*/get_mx (domain)/*@+unrecog@*/;
+#endif
+
+ if (answers != NULL && answers->count > 0)
+ {
+ qsort(answers->reply, (size_t) answers->count, sizeof(mx),
+ comp_mx_pref);
+ SL_RETURN (answers, _("return_mx"));
+ }
+ else
+ {
+ char numeric[SH_IP_BUF];
+
+ if (domain != NULL)
+ {
+#if defined(HAVE_ARPA_NAMESER_H)
+#ifdef FIL__
+ (void) sl_strlcpy (errmsg, _("No MX record for domain "), 127);
+ (void) sl_strlcat (errmsg, domain, 127);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errmsg,
+ _("get_mx"));
+#else
+ /* flawfinder: ignore *//* test code only */
+ strcpy (errmsg, /* known to fit */
+ _("No MX record for domain "));
+ strncat (errmsg, domain, 100);
+ errmsg[122] = '\0';
+ fprintf(stderr, "Warning: %s\n", errmsg);
+#endif
+#endif
+ }
+
+ retval = NULL;
+
+ if (domain != NULL)
+ address = sh_ipvx_canonical(domain, numeric, sizeof(numeric));
+
+ if (address)
+ {
+ result = SH_ALLOC (sizeof (mx));
+ retval = SH_ALLOC (sizeof (dnsrep));
+ retval->reply = result;
+ retval->count = 1;
+ result->pref = 0;
+
+ result->address = address;
+ }
+ else
+ {
+#ifdef FIL__
+ (void) sl_strlcpy (errmsg, _("Unknown host "), 127);
+ (void) sl_strlcat (errmsg, domain, 127);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errmsg,
+ _("return_mx"));
+#endif
+ SL_RETURN (NULL, _("return_mx"));
+ }
+
+ SL_RETURN (retval, _("return_mx"));
+ }
+}
+
+int free_mx (dnsrep * answers)
+{
+ mx * result;
+ int i;
+
+ SL_ENTER(_("free_mx"));
+ if (!answers)
+ SL_RETURN (0, _("return_mx"));
+
+ result = answers->reply;
+ for (i = 0; i < answers->count; ++i)
+ {
+ SH_FREE (result[i].address);
+ }
+ SH_FREE(result);
+ SH_FREE(answers);
+ SL_RETURN (0, _("return_mx"));
+}
+
+#ifdef TEST_ONLY
+int main(int argc, char * argv[])
+{
+ int i;
+ dnsrep * answers;
+ mx * result;
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "Usage: dns <hostname>\n");
+ return -1;
+ }
+ answers = return_mx(argv[1]);
+
+ if (!answers)
+ {
+ fprintf(stderr, "No answer\n");
+ return -1;
+ }
+
+ if (answers->count > 0)
+ {
+ result = answers->reply;
+ for (i = 0; i < answers->count; ++i)
+ {
+ fprintf(stderr, "Record %3d: [%3d] %s\n", i,
+ result[i].pref, result[i].address);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "No answer\n");
+ free_mx(answers);
+ return -1;
+ }
+ free_mx(answers);
+ return (0);
+}
+#endif
+
+
+
+/* if defined(SH_WITH_MAIL) */
+#endif
+
+
+
diff --git a/src/sh_mem.c b/src/sh_mem.c
new file mode 100644
index 0000000..453640f
--- /dev/null
+++ b/src/sh_mem.c
@@ -0,0 +1,479 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#define SH_REAL_SET
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_mem.h"
+#include "sh_pthread.h"
+
+extern int safe_logger (int thesignal, int method, char * details);
+
+#undef FIL__
+#define FIL__ _("sh_mem.c")
+
+#ifdef MEM_DEBUG
+
+#define CHECKBYTE 0x7F
+
+/* Memory alignment; should be 16 bytes on 64 bit machines.
+ * -> 32 bytes overhead/allocation
+ */
+#define SH_MEMMULT 16
+
+
+typedef struct mem_struct {
+ struct mem_struct *next; /* link to next struct */
+ char * real_address; /* address assigned */
+ char * address; /* address returned */
+ unsigned long size; /* size allocated */
+ char file[20]; /* Allocation file name */
+ int line; /* Allocation line number */
+} memlist_t;
+
+memlist_t * memlist = NULL;
+
+int Free_Count = 0, Alloc_Count = 0;
+int Now_Alloc_Count = 0, Max_Alloc_Count = 0;
+unsigned long Mem_Current = 0, Mem_Max = 0;
+
+#ifdef HAVE_PTHREAD
+SH_MUTEX_RECURSIVE(mutex_mem);
+#endif
+
+/* define MEM_LOG to an absolute filename to enable this */
+#ifdef MEM_LOG
+void sh_mem_dump ()
+{
+ memlist_t * this = memlist;
+ FILE * fd;
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_mem);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_mem);
+
+ fd = fopen(MEM_LOG, "w");
+ if (!fd)
+ {
+ perror(MEM_LOG);
+ _exit(EXIT_FAILURE);
+ }
+
+ while (this != NULL)
+ {
+ fprintf (fd, "## %20s %5d %ld\n", this->file, this->line, this->size);
+ fprintf (fd, "%10p %8ld\n", (void *)this->address, this->size);
+ this = this->next;
+ }
+ sl_fclose(FIL__, __LINE__, fd);
+
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_mem);
+ _exit(EXIT_SUCCESS);
+}
+#else
+void sh_mem_dump ()
+{
+ return;
+}
+#endif
+
+memlist_t ** sh_dummy_114_merrlist;
+
+void sh_mem_stat ()
+{
+ memlist_t * this;
+ memlist_t * merrlist = NULL;
+
+ SL_ENTER(_("sh_mem_stat"));
+
+ sh_dummy_114_merrlist = (memlist_t **) &merrlist;
+
+ if (Alloc_Count == Free_Count)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MSTAMP,
+ Mem_Max, Mem_Current);
+ SL_RET0(_("sh_mem_stat"));
+ }
+
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_MSTAMP2,
+ Alloc_Count, Free_Count, Max_Alloc_Count);
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_MSTAMP,
+ Mem_Max, Mem_Current);
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_mem);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_mem);
+
+ this = memlist;
+
+ while (this != NULL)
+ {
+ memlist_t * merr = calloc(1,sizeof(memlist_t));
+
+ memcpy(merr, this, sizeof(memlist_t));
+ merr->next = merrlist;
+ merrlist = merr;
+
+ this = this->next;
+ }
+
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_mem);
+
+ while (merrlist != NULL)
+ {
+ memlist_t * tmp = merrlist;
+ merrlist = merrlist->next;
+
+ sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_NOTFREE,
+ tmp->size, tmp->file, tmp->line);
+ free(tmp);
+ }
+
+ SL_RET0(_("sh_mem_stat"));
+}
+
+memlist_t ** sh_dummy_168_merrlist;
+
+void sh_mem_check ()
+{
+ memlist_t * this;
+ memlist_t * merrlist = NULL;
+ memlist_t * merr;
+ long nerr = 0;
+
+ SL_ENTER(_("sh_mem_check"));
+
+ sh_dummy_168_merrlist = (memlist_t **) &merrlist;
+
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MSTAMP,
+ Mem_Max, Mem_Current);
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_mem);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_mem);
+
+ this = memlist;
+
+ while (this != NULL)
+ {
+ if ( this->address == NULL )
+ {
+ merr = calloc (1,sizeof(memlist_t));
+
+ memcpy(merr, this, sizeof(memlist_t));
+ merr->size = 2;
+
+ merr->next = merrlist;
+ merrlist = merr;
+ ++nerr;
+ }
+ else
+ {
+ if ( this->address[this->size] != CHECKBYTE )
+ {
+ merr = calloc(1, sizeof(memlist_t));
+
+ memcpy(merr, this, sizeof(memlist_t));
+ merr->size = 1;
+
+ merr->next = merrlist;
+ merrlist = merr;
+ ++nerr;
+ }
+ if ( this->real_address[SH_MEMMULT-1] != CHECKBYTE )
+ {
+ merr = calloc(1, sizeof(memlist_t));
+
+ memcpy(merr, this, sizeof(memlist_t));
+ merr->size = 0;
+
+ merr->next = merrlist;
+ merrlist = merr;
+ ++nerr;
+ }
+ }
+ this = this->next;
+ }
+
+
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_mem);
+
+ while (merrlist != NULL)
+ {
+ memlist_t * tmp = merrlist;
+ merrlist = merrlist->next;
+
+ if (tmp->size == 2)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MNULL,
+ tmp->file, tmp->line, FIL__, __LINE__);
+ if (tmp->size == 1)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MOVER,
+ tmp->file, tmp->line, FIL__, __LINE__);
+ else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MUNDER,
+ tmp->file, tmp->line, FIL__, __LINE__);
+ free(tmp);
+ SH_ABORT;
+ _exit (EXIT_FAILURE);
+ }
+
+ SL_RET0(_("sh_mem_check"));
+}
+
+void * sh_mem_malloc (size_t size, char * file, int line)
+{
+ void * the_realAddress;
+ void * theAddress;
+ memlist_t * this;
+
+ SL_ENTER(_("sh_mem_malloc"));
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_mem);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_mem);
+
+ the_realAddress = calloc(1,size + 2 * SH_MEMMULT);
+
+ if ( the_realAddress == NULL )
+ {
+ (void) safe_logger (0, 0, NULL);
+
+ /* use _exit() rather than exit() - we malloc() in atexit() functions
+ */
+ _exit (EXIT_FAILURE);
+ }
+
+ /* --- Set check bytes. ---
+ */
+ theAddress = ((char *) the_realAddress + SH_MEMMULT);
+
+ memset(the_realAddress, CHECKBYTE, SH_MEMMULT);
+ memset(theAddress, CHECKBYTE, size + 1);
+ memset(theAddress, 0, 1);
+
+ ++Alloc_Count;
+ ++Now_Alloc_Count;
+
+ if (Max_Alloc_Count < Now_Alloc_Count)
+ Max_Alloc_Count = Now_Alloc_Count;
+
+ Mem_Current += size;
+ Mem_Max = ( (Mem_Current > Mem_Max) ? Mem_Current : Mem_Max);
+
+ this = calloc(1,sizeof(memlist_t));
+
+ if ( this == NULL)
+ {
+ (void) safe_logger(0, 0, NULL);
+
+ _exit(EXIT_FAILURE);
+ }
+ else
+ {
+ /* make list entry */
+
+ this->real_address = the_realAddress;
+ this->address = theAddress;
+ this->size = size;
+ this->line = line;
+ sl_strlcpy(this->file, file, 20);
+
+ this->next = memlist;
+ memlist = this;
+ }
+
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_mem);
+ SL_RETURN( theAddress, _("sh_mem_malloc"));
+}
+
+static void ** sh_mem_dummy_a;
+static memlist_t ** sh_mem_merr_3;
+
+void sh_mem_free (void * aa, char * file, int line)
+{
+ memlist_t * this;
+ memlist_t * before;
+ memlist_t * merr;
+ memlist_t * merrlist = NULL;
+ unsigned long size = 0;
+ void * a;
+ volatile int flag = 0;
+
+ SL_ENTER(_("sh_mem_free"));
+
+ a = aa;
+ sh_mem_dummy_a = &a;
+ sh_mem_merr_3 = (memlist_t **) &merrlist;
+
+
+ if ( a == NULL )
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MNULL,
+ file, line, FIL__, __LINE__);
+ SH_ABORT;
+ _exit (EXIT_FAILURE);
+ SL_RET0(_("sh_mem_free"));
+ }
+
+ SH_MUTEX_RECURSIVE_INIT(mutex_mem);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_mem);
+
+ this = memlist;
+ before = memlist;
+
+ /* -- Find record. --
+ */
+ while (this != NULL)
+ {
+ if (this->address == a)
+ break;
+ before = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ {
+ flag = 1;
+ goto out;
+ }
+ else
+ {
+ a = this->real_address;
+
+ if ( this->address[this->size] != CHECKBYTE )
+ {
+ merr = calloc(1, sizeof(memlist_t));
+
+ memcpy(merr, this, sizeof(memlist_t));
+ merr->size = 1;
+
+ merr->next = merrlist;
+ merrlist = merr;
+ }
+
+ if ( this->real_address[SH_MEMMULT-1] != CHECKBYTE )
+ {
+ merr = calloc(1,sizeof(memlist_t));
+
+ memcpy(merr, this, sizeof(memlist_t));
+ merr->size = 0;
+
+ merr->next = merrlist;
+ merrlist = merr;
+ }
+
+ size = this->size;
+
+ if (this == memlist)
+ memlist = this->next;
+ else
+ before->next = this->next;
+ }
+
+ free(a);
+ if (this)
+ free(this);
+
+ ++Free_Count;
+ --Now_Alloc_Count;
+
+ Mem_Current -= size;
+ out:
+ ; /* label at end of compound statement */
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_mem);
+
+ while (merrlist != NULL)
+ {
+ memlist_t * tmp = merrlist;
+ merrlist = merrlist->next;
+
+ if (tmp->size == 1)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MOVER,
+ tmp->file, tmp->line, file, line);
+ else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MUNDER,
+ tmp->file, tmp->line, file, line);
+ free(tmp);
+ SH_ABORT;
+ _exit (EXIT_FAILURE);
+ }
+
+ if (flag != 0)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MREC,
+ file, line);
+
+ SL_RET0(_("sh_mem_free"));
+}
+
+#else
+
+void sh_mem_free (void * a)
+{
+ SL_ENTER(_("sh_mem_free"));
+
+ if (a)
+ {
+ free(a);
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_MNULL);
+ SH_ABORT;
+ }
+ SL_RET0(_("sh_mem_free"));
+}
+
+void * sh_mem_malloc (size_t size)
+{
+ void * theAddress;
+
+ SL_ENTER(_("sh_mem_malloc"));
+
+ theAddress = calloc(1,size);
+
+ if ( theAddress != NULL )
+ {
+ SL_RETURN( theAddress, _("sh_mem_malloc"));
+ }
+ else
+ {
+ (void) safe_logger(0, 0, NULL);
+
+ /* use _exit() rather than exit() - we malloc() in atexit()
+ */
+ SH_ABORT;
+ _exit (EXIT_FAILURE);
+ }
+}
+#endif
diff --git a/src/sh_modules.c b/src/sh_modules.c
new file mode 100644
index 0000000..4b4322d
--- /dev/null
+++ b/src/sh_modules.c
@@ -0,0 +1,193 @@
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <time.h>
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+#include "sh_modules.h"
+#include "sh_pthread.h"
+
+#include "sh_utmp.h"
+#include "sh_mounts.h"
+#include "sh_userfiles.h"
+#include "sh_suidchk.h"
+#include "sh_processcheck.h"
+#include "sh_portcheck.h"
+#include "sh_logmon.h"
+#include "sh_registry.h"
+#include "sh_fInotify.h"
+
+sh_mtype modList[] = {
+#ifdef SH_USE_UTMP
+ {
+ N_("UTMP"),
+ -1,
+ SH_MODFL_NOTIMER,
+ sh_utmp_init,
+ sh_utmp_timer,
+ sh_utmp_check,
+ sh_utmp_end,
+ sh_utmp_reconf,
+
+ N_("[Utmp]"),
+ sh_utmp_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef SH_USE_MOUNTS
+ {
+ N_("MOUNTS"),
+ -1,
+ 0,
+ sh_mounts_init,
+ sh_mounts_timer,
+ sh_mounts_check,
+ sh_mounts_cleanup,
+ sh_mounts_reconf,
+
+ N_("[Mounts]"),
+ sh_mounts_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef SH_USE_USERFILES
+ {
+ N_("USERFILES"),
+ -1,
+ 0,
+ sh_userfiles_init,
+ sh_userfiles_timer,
+ sh_userfiles_check,
+ sh_userfiles_cleanup,
+ sh_userfiles_reconf,
+
+ N_("[UserFiles]"),
+ sh_userfiles_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef SH_USE_SUIDCHK
+ {
+ N_("SUIDCHECK"),
+ -1,
+ 0,
+ sh_suidchk_init,
+ sh_suidchk_timer,
+ sh_suidchk_check,
+ sh_suidchk_end,
+ sh_suidchk_reconf,
+
+ N_("[SuidCheck]"),
+ sh_suidchk_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef SH_USE_PROCESSCHECK
+ {
+ N_("PROCESSCHECK"),
+ -1,
+ 0,
+ sh_prochk_init,
+ sh_prochk_timer,
+ sh_prochk_check,
+ sh_prochk_cleanup,
+ sh_prochk_reconf,
+
+ N_("[ProcessCheck]"),
+ sh_prochk_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef SH_USE_PORTCHECK
+ {
+ N_("PORTCHECK"),
+ -1,
+ 0,
+ sh_portchk_init,
+ sh_portchk_timer,
+ sh_portchk_check,
+ sh_portchk_cleanup,
+ sh_portchk_reconf,
+
+ N_("[PortCheck]"),
+ sh_portchk_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef USE_LOGFILE_MONITOR
+ {
+ N_("LOGMON"),
+ -1,
+ 0,
+ sh_log_check_init,
+ sh_log_check_timer,
+ sh_log_check_check,
+ sh_log_check_cleanup,
+ sh_log_check_reconf,
+
+ N_("[Logmon]"),
+ sh_log_check_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#ifdef USE_REGISTRY_CHECK
+ {
+ N_("REGISTRY"),
+ -1,
+ 0,
+ sh_reg_check_init,
+ sh_reg_check_timer,
+ sh_reg_check_run,
+ sh_reg_check_cleanup,
+ sh_reg_check_reconf,
+
+ N_("[Registry]"),
+ sh_reg_check_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+#if defined(HAVE_SYS_INOTIFY_H)
+ {
+ N_("INOTIFY"),
+ -1,
+ SH_MODFL_NEEDPAUSED,
+ sh_fInotify_init,
+ sh_fInotify_timer,
+ sh_fInotify_run,
+ sh_fInotify_cleanup,
+ sh_fInotify_reconf,
+
+ N_("[Inotify]"),
+ sh_fInotify_table,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+#endif
+
+ {
+ NULL,
+ -1,
+ 0,
+
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+
+ NULL,
+ NULL,
+ PTHREAD_MUTEX_INITIALIZER,
+ },
+};
+
+#endif
+
diff --git a/src/sh_mounts.c b/src/sh_mounts.c
new file mode 100644
index 0000000..736fa7b
--- /dev/null
+++ b/src/sh_mounts.c
@@ -0,0 +1,824 @@
+/*
+ * File: sh_mounts.c
+ * Desc: A module for Samhain; checks for mounts present and options on them.
+ * Auth: Cian Synnott <cian.synnott@eircom.net>
+ *
+ */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+/* Used in the call tracing macros to keep track of where we are in the code */
+#undef FIL__
+#define FIL__ _("sh_mounts.c")
+
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_error.h"
+#include "sh_modules.h"
+#include "sh_mounts.h"
+
+#ifdef SH_USE_MOUNTS
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+/*
+ * #ifdef HAVE_STRING_H
+ * #include <string.h>
+ * #endif
+ */
+
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+/* Prototypes for configuration functions */
+int sh_mounts_config_activate (const char * opt);
+int sh_mounts_config_timer (const char * opt);
+int sh_mounts_config_mount (const char * opt);
+int sh_mounts_config_sevmnt (const char * opt);
+int sh_mounts_config_sevopt (const char * opt);
+
+/* Prototype for the function to read info on mounted filesystems */
+static struct sh_mounts_mnt *readmounts(void);
+
+/* Table for configuration options, and pointers to the functions that will
+ * configure them. Each function is passed the string resulting from stripping
+ * the option and the "equals" from the config file; e.g. MountCheckActive=1 in
+ * the configuration file will result in the string "1" being passed to
+ * sh_mounts_config_activate() */
+sh_rconf sh_mounts_table[] = {
+ {
+ N_("mountcheckactive"),
+ sh_mounts_config_activate
+ },
+ {
+ N_("mountcheckinterval"),
+ sh_mounts_config_timer
+ },
+ {
+ N_("checkmount"),
+ sh_mounts_config_mount
+ },
+ {
+ N_("severitymountmissing"),
+ sh_mounts_config_sevmnt
+ },
+ {
+ N_("severityoptionmissing"),
+ sh_mounts_config_sevopt
+ },
+ {
+ NULL,
+ NULL
+ },
+};
+
+/* Structures for storing my configuration information, and functions for
+ * manipulating them */
+struct sh_mounts_mnt {
+ char * path;
+ struct sh_mounts_opt * opts;
+ struct sh_mounts_mnt * next;
+};
+
+struct sh_mounts_opt {
+ char * opt;
+ struct sh_mounts_opt * next;
+};
+
+/* Return the mount structure whose path matches 'mnt' or NULL if not found */
+static
+struct sh_mounts_mnt *sh_mounts_mnt_member(struct sh_mounts_mnt *m, char *mnt)
+{
+ struct sh_mounts_mnt *it;
+
+ for (it = m; it != NULL; it = it->next) {
+ if (0 == sl_strcmp(it->path, mnt)) {
+ return it;
+ }
+ }
+ return NULL;
+}
+
+/* Return the opt structure whose option matches 'opt' or NULL if not found */
+static
+struct sh_mounts_opt *sh_mounts_opt_member(struct sh_mounts_opt *o, char *opt)
+{
+ struct sh_mounts_opt *it;
+
+ for (it = o; it != NULL; it = it->next) {
+ /* if (!strcmp(it->opt, opt)) { */
+ if (0 == sl_strcmp(it->opt, opt)) {
+ return it;
+ }
+ }
+ return NULL;
+}
+
+static
+void sh_mounts_opt_free(struct sh_mounts_opt *o) {
+ if (o != NULL) {
+ sh_mounts_opt_free(o->next);
+ SH_FREE(o->opt);
+ SH_FREE(o);
+ }
+}
+
+static
+void sh_mounts_mnt_free(struct sh_mounts_mnt *m) {
+ if (m != NULL) {
+ sh_mounts_mnt_free(m->next);
+ sh_mounts_opt_free(m->opts);
+ SH_FREE(m->path);
+ SH_FREE(m);
+ }
+}
+
+/* Some configuration variables I'll be using */
+static time_t lastcheck = (time_t) 0;
+static int ShMountsActive = S_FALSE;
+static time_t ShMountsInterval = 86400;
+static int ShMountsSevMnt = SH_ERR_ERR;
+static int ShMountsSevOpt = SH_ERR_ERR;
+
+static struct sh_mounts_mnt *mountlist = NULL;
+
+/* Module initialisation
+ * This is called once at the start of each samhain run.
+ * Non-configuration setup code should be placed here. */
+int sh_mounts_init (struct mod_type * arg)
+{
+ (void) arg;
+ SL_ENTER(_("sh_mounts_init"));
+
+ /* This is a little odd. Because we've built the configured mount list at
+ * this point, if we've set the module inactive, we need to free the list -
+ * otherwise when we reconf() with it set active, we'll end up with a
+ * duplicated list. Interesting. */
+ if (ShMountsActive == S_FALSE) {
+ sh_mounts_mnt_free(mountlist);
+ mountlist = NULL;
+ SL_RETURN(-1, _("sh_mounts_init"));
+ }
+
+ SL_RETURN(0, _("sh_mounts_init"));
+}
+
+/* Module timer
+ * This timer function is called periodically with the current time to see if
+ * it is time to run the module's "check" function. On nonzero return, the
+ * check is run. */
+int sh_mounts_timer (time_t tcurrent)
+{
+ SL_ENTER(_("sh_mounts_timer"));
+
+ if ((time_t) (tcurrent - lastcheck) >= ShMountsInterval) {
+ lastcheck = tcurrent;
+ SL_RETURN(-1, _("sh_mounts_timer"));
+ }
+
+ SL_RETURN(0, _("sh_mounts_timer"));
+}
+
+/* Module check
+ * The business end of things. This is the actual check code for this module.
+ * Everything you want to do periodically should go here. */
+int sh_mounts_check ()
+{
+ struct sh_mounts_mnt *memlist;
+ struct sh_mounts_mnt *cfgmnt, *mnt;
+ struct sh_mounts_opt *cfgopt, *opt;
+
+ SL_ENTER(_("sh_mounts_check"));
+
+ /* Log the check run. For each message type you want, you need to define it
+ * as an enum in sh_cat.h, and then set it up in terms of priority and format
+ * string in sh_cat.c */
+ sh_error_handle(-1, FIL__, __LINE__, 0, MSG_MNT_CHECK);
+
+ /* Read the list of mounts from memory */
+ memlist = readmounts();
+
+ if (memlist == NULL) {
+ sh_error_handle(-1, FIL__, __LINE__, 0, MSG_MNT_MEMLIST);
+ }
+
+ /* For each mount we are configured to check, run through the list of mounted
+ * filesystems and compare the pathnames */
+ for (cfgmnt = mountlist; cfgmnt != NULL; cfgmnt = cfgmnt->next) {
+ mnt = sh_mounts_mnt_member(memlist, cfgmnt->path);
+
+ if (mnt) {
+ for (cfgopt = cfgmnt->opts; cfgopt != NULL; cfgopt = cfgopt->next) {
+ opt = sh_mounts_opt_member(mnt->opts, cfgopt->opt);
+
+ if (!opt) {
+ sh_error_handle(ShMountsSevOpt, FIL__, __LINE__, 0, MSG_MNT_OPTMISS,
+ cfgmnt->path, cfgopt->opt);
+ }
+ }
+ }
+
+ else {
+ sh_error_handle(ShMountsSevMnt, FIL__, __LINE__, 0, MSG_MNT_MNTMISS,
+ cfgmnt->path);
+ }
+ }
+
+ /* Make sure to clean up after ourselves */
+ sh_mounts_mnt_free(memlist);
+
+ SL_RETURN(0, _("sh_mounts_check"));
+}
+
+/* Module cleanup
+ * The end of the tour - when samhain is shutting down, this is run. */
+int sh_mounts_cleanup ()
+{
+ SL_ENTER(_("sh_mounts_cleanup"));
+ sh_mounts_mnt_free(mountlist);
+ mountlist = NULL;
+ SL_RETURN( (0), _("sh_mounts_cleanup"));
+}
+
+/* Module reconfiguration
+ * Run on receipt of a HUP.
+ */
+int sh_mounts_reconf()
+{
+ SL_ENTER(_("sh_mounts_null"));
+ sh_mounts_mnt_free(mountlist);
+ mountlist = NULL;
+
+ /* re-set defaults
+ */
+ ShMountsActive = S_FALSE;
+ ShMountsInterval = 86400;
+ ShMountsSevMnt = 7;
+ ShMountsSevOpt = 7;
+
+ SL_RETURN( (0), _("sh_mounts_null"));
+}
+
+/* Module configuration
+ * These functions are called when the configuration file is being parsed. */
+
+/* Configure to check a particular mount */
+int sh_mounts_config_mount (const char * opt_in)
+{
+ struct sh_mounts_mnt *m;
+ struct sh_mounts_opt *o;
+ char *sp, *temp, *opt;
+
+ SL_ENTER(_("sh_mounts_config_mount"));
+
+ /* It's probably best to make a copy of opt before messing about with it
+ * via string functions. Good practice and all that. */
+ temp = sh_util_strdup(opt_in);
+
+ /* Since we're going to "consume" this new buffer, it'll be good to have a
+ * reference to it's allocated memory so we can free it later. Let's use
+ * temp for that, and "opt" for consumption */
+ opt = temp;
+
+ m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof(struct sh_mounts_mnt));
+
+ /* First, strip out the mount path. */
+ m->path = sh_util_strdup(sh_util_strsep(&opt, " \t"));
+ m->opts = NULL;
+
+ /* Now get all of the mount options - they can be delimited by comma or
+ * whitespace */
+ while (opt != NULL) {
+ sp = sh_util_strsep(&opt, ", \t");
+
+ /* This just catches multiple separators appearing together */
+ if (*sp == '\0') {
+ continue;
+ }
+
+ o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
+ o->next = m->opts;
+ m->opts = o;
+
+ o->opt = sh_util_strdup(sp);
+ }
+
+ /* Add to the list of configured mounts */
+ m->next = mountlist;
+ mountlist = m;
+
+ /* Free the string buffer we allocated earlier */
+ SH_FREE(temp);
+
+ SL_RETURN(0, _("sh_mounts_config_mount"));
+}
+
+/* Simply sets our boolean as to whether this module is active */
+int sh_mounts_config_activate (const char * opt)
+{
+ int i;
+ SL_ENTER(_("sh_mounts_config_activate"));
+ i = sh_util_flagval(opt, &ShMountsActive);
+ SL_RETURN(i, _("sh_mounts_config_activate"));
+}
+
+/* Sets up our timer */
+int sh_mounts_config_timer (const char * opt)
+{
+ long val;
+ int retval = 0;
+
+ SL_ENTER(_("sh_mounts_config_timer"));
+ val = strtol (opt, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ sh_error_handle (-1, FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("mounts timer"), opt);
+ retval = -1;
+ }
+ val = (val <= 0 ? 86400 : val);
+
+ ShMountsInterval = (time_t) val;
+
+ SL_RETURN(retval, _("sh_mounts_config_timer"));
+}
+
+/* Configure severity for "mount missing" messages */
+int sh_mounts_config_sevmnt (const char * opt)
+{
+ int retval = 0;
+ char tmp[32];
+
+
+ SL_ENTER(_("sh_mounts_config_sevmnt"));
+ tmp[0] = '='; tmp[1] = '\0';
+ (void) sl_strlcat (tmp, opt, 32);
+ retval = sh_error_set_level (tmp, &ShMountsSevMnt);
+ SL_RETURN(retval, _("sh_mounts_config_sevmnt"));
+}
+
+int sh_mounts_config_sevopt (const char * opt)
+{
+ int retval = 0;
+ char tmp[32];
+
+ SL_ENTER(_("sh_mounts_config_sevopt"));
+ tmp[0] = '='; tmp[1] = '\0';
+ (void) sl_strlcat (tmp, opt, 32);
+ retval = sh_error_set_level (tmp, &ShMountsSevOpt);
+ SL_RETURN(retval, _("sh_mounts_config_sevopt"));
+}
+
+
+/*
+ * Below here we have the code for actually reading options on mounted fs's
+ * I've just got code here to work on FreeBSD, Linux and Solaris. I'm sure
+ * others could be added. Note that some small bits of the OS-specific code
+ * are from mountlist.c in GNU fileutils.
+ */
+
+/* FreeBSD includes */
+#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#endif
+
+/* Linux includes */
+#ifdef HOST_IS_LINUX
+#include <stdio.h>
+#include <mntent.h>
+#endif
+
+/* Solaris includes */
+#ifdef HOST_IS_SOLARIS
+#include <stdio.h>
+#include <sys/mnttab.h>
+#endif
+
+/* HP_UX includes */
+#ifdef HOST_IS_HPUX
+#include <stdio.h>
+#include <mntent.h>
+#endif
+
+/* AIX includes and helper routines (from gnome-vfs-unix-mounts.c */
+#if 0
+#ifdef HOST_IS_AIX
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/* gnome-vfs-unix-mounts.c - read and monitor fstab/mtab
+
+ Copyright (C) 2003 Red Hat, Inc
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Alexander Larsson <alexl@redhat.com>
+*/
+
+/* read character, ignoring comments (begin with '*', end with '\n' */
+static int aix_fs_getc (FILE *fd)
+{
+ int c;
+
+ while ((c = getc (fd)) == '*') {
+ while (((c = getc (fd)) != '\n') && (c != EOF)) {} /* do nothing */
+ }
+}
+
+/* eat all continuous spaces in a file */
+static int aix_fs_ignorespace (FILE *fd)
+{
+ int c;
+
+ while ((c = aix_fs_getc (fd)) != EOF) {
+ if (! (isascii(c) && isspace (c)) ) {
+ ungetc (c,fd);
+ return c;
+ }
+ }
+
+ return EOF;
+}
+
+/* read one word from file */
+static int aix_fs_getword (FILE *fd, char *word, int len)
+{
+ int c;
+ int i = 0;
+
+ --len;
+
+ aix_fs_ignorespace (fd);
+
+ while (((c = aix_fs_getc (fd)) != EOF) && !( isascii(c) && isspace(c) ))
+ {
+ if (c == '"')
+ {
+ while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
+ {
+ *word++ = c; ++i;
+ if (i == len)
+ break;
+ }
+ }
+ else
+ {
+ *word++ = c; ++i;
+ }
+ if (i == len)
+ break;
+ }
+ *word = 0;
+
+ return c;
+}
+
+/* PATH_MAX is in sys/limits.h, included via stdio.h
+ */
+typedef struct {
+ char mnt_mount[PATH_MAX];
+ char mnt_special[PATH_MAX];
+ char mnt_fstype[16];
+ char mnt_options[128];
+} AixMountTableEntry;
+
+/* read mount points properties */
+static int aix_fs_get (FILE *fd, AixMountTableEntry *prop)
+{
+ /* Need space for PATH_MAX + ':' (terminating '\0' is in PATH_MAX; SUSv3)
+ */
+ static char word[PATH_MAX+1] = { 0 };
+ char value[PATH_MAX];
+
+ /* reset */
+
+ if (fd == NULL)
+ {
+ word[0] = '\0';
+ return 0;
+ }
+
+ /* read stanza */
+
+ if (word[0] == 0) {
+ if (aix_fs_getword (fd, word, (PATH_MAX+1)) == EOF)
+ return EOF;
+ }
+
+ word[strlen(word) - 1] = 0;
+ sl_strlcpy (prop->mnt_mount, word, PATH_MAX);
+
+ /* read attributes and value */
+
+ while (aix_fs_getword (fd, word, (PATH_MAX+1)) != EOF) {
+ /* test if is attribute or new stanza */
+
+ if (word[strlen(word) - 1] == ':') {
+ return 0;
+ }
+
+ /* read "=" */
+ aix_fs_getword (fd, value, PATH_MAX);
+
+ /* read value */
+ aix_fs_getword (fd, value, PATH_MAX);
+
+ if (strcmp (word, "dev") == 0) {
+ sl_strlcpy (prop->mnt_special, value, PATH_MAX);
+ } else if (strcmp (word, "vfs") == 0) {
+ sl_strlcpy (prop->mnt_fstype, value, 16);
+ } else if (strcmp (word, "options") == 0) {
+ sl_strlcpy(prop->mnt_options, value, 128);
+ }
+ }
+
+ return 0;
+}
+
+/* end AIX helper routines */
+#endif
+#endif
+
+#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
+
+/* FreeBSD returns flags instead of strings as mount options, so we'll convert
+ * them here. */
+static
+struct sh_mounts_opt * getoptlist(int flags) {
+ struct sh_mounts_opt *list, *o;
+ int i;
+
+ struct {char *opt; int flag;} table[] = {
+#ifdef MNT_RDONLY
+ {"ro", MNT_RDONLY},
+#endif
+#ifdef MNT_NOEXEC
+ {"noexec", MNT_NOEXEC},
+#endif
+#ifdef MNT_NOSUID
+ {"nosuid", MNT_NOSUID},
+#endif
+#ifdef MNT_NODEV
+ {"nodev", MNT_NODEV},
+#endif
+#ifdef MNT_SYNCHRONOUS
+ {"sync", MNT_SYNCHRONOUS},
+#endif
+#ifdef MNT_ASYNC
+ {"async", MNT_ASYNC},
+#endif
+#ifdef MNT_LOCAL
+ {"local", MNT_LOCAL},
+#endif
+#ifdef MNT_QUOTA
+ {"quota", MNT_QUOTA},
+#endif
+#ifdef MNT_NOATIME
+ {"noatime", MNT_NOATIME},
+#endif
+ {"bound", -1}
+ };
+
+ SL_ENTER(_("getoptlist"));
+
+ list = NULL;
+
+ /* Add any flags found to the list */
+ for (i = 0; table[i].flag != -1; i++) {
+ if (flags & table[i].flag) {
+ o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
+ o->opt = sh_util_strdup(table[i].opt);
+ o->next = list;
+ list = o;
+ }
+ }
+
+ SL_RETURN(list, _("getoptlist"));
+}
+
+/* Solaris & Linux return identical option string formats */
+#else
+
+/* We just separate the options out by parsing for commas */
+static
+struct sh_mounts_opt * getoptlist(char *opt)
+{
+ struct sh_mounts_opt *list, *o;
+ char *sp, *temp;
+
+ SL_ENTER(_("getoptlist"));
+
+ /* See the comments in sh_mounts_config_mount() above for the reasons for
+ * this arcane little zig-zag */
+ temp = sh_util_strdup(opt);
+ opt = temp;
+
+ list = NULL;
+
+ /* For each option, add to the list */
+ while (opt != NULL) {
+ sp = sh_util_strsep(&opt, ", \t");
+
+ if (*sp == '\0') {
+ continue;
+ }
+
+ o = (struct sh_mounts_opt *) SH_ALLOC(sizeof(struct sh_mounts_opt));
+ o->next = list;
+ list = o;
+
+ o->opt = sh_util_strdup(sp);
+ }
+
+ SH_FREE(temp);
+
+ SL_RETURN(list, _("getoptlist"));
+}
+
+#endif
+
+/* Read the list of mounts from whereever is appropriate to the OS and return
+ * it. Return NULL on error. */
+static struct sh_mounts_mnt * readmounts(void) {
+ struct sh_mounts_mnt *list, *m;
+
+ SL_ENTER(_("readmounts"));
+ m = NULL; /* use it to avoid compiler warning */
+ list = m;
+
+/* The Open/FreeBSD way */
+#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD)
+{
+ struct statfs *fsp;
+ int entries;
+
+ entries = getmntinfo(&fsp, MNT_NOWAIT);
+ if (entries < 0) {
+ SL_RETURN((NULL), _("readmounts"));
+ }
+
+ for (; entries-- > 0; fsp++) {
+ m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
+ m->path = sh_util_strdup(fsp->f_mntonname);
+ m->opts = getoptlist(fsp->f_flags);
+
+ m->next = list;
+ list = m;
+ }
+}
+#endif
+
+/* The Linux way */
+#ifdef HOST_IS_LINUX
+{
+ struct mntent *mp;
+ FILE *tab = setmntent(_PATH_MOUNTED, "r");
+
+ if (tab == NULL) {
+ SL_RETURN((NULL), _("readmounts"));
+ }
+
+ mp = getmntent(tab);
+ while (mp != NULL) {
+ m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
+ m->path = sh_util_strdup(mp->mnt_dir);
+ m->opts = getoptlist(mp->mnt_opts);
+
+ m->next = list;
+ list = m;
+
+ mp = getmntent(tab);
+ }
+
+ (void) endmntent(tab);
+}
+#endif
+
+/* The Solaris way */
+#ifdef HOST_IS_SOLARIS
+{
+ struct mnttab mp;
+ FILE *tab = fopen(MNTTAB, "r");
+
+ if (tab == NULL) {
+ SL_RETURN((NULL), _("readmounts"));
+ }
+
+ while (!getmntent(tab, &mp)) {
+ m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
+ m->path = sh_util_strdup(mp.mnt_mountp);
+ m->opts = getoptlist(mp.mnt_mntopts);
+
+ m->next = list;
+ list = m;
+ }
+
+ sl_fclose(FIL__, __LINE__, tab);
+}
+#endif
+
+
+/* The HP-UX way */
+#ifdef HOST_IS_HPUX
+{
+ struct mntent *mp;
+ FILE *tab = setmntent(MNT_MNTTAB, "r");
+
+ if (tab == NULL) {
+ SL_RETURN((NULL), _("readmounts"));
+ }
+
+ mp = getmntent(tab);
+ while (mp != NULL) {
+ m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
+ m->path = sh_util_strdup(mp->mnt_dir);
+ m->opts = getoptlist(mp->mnt_opts);
+
+ m->next = list;
+ list = m;
+
+ mp = getmntent(tab);
+ }
+
+ (void) endmntent(tab);
+}
+#endif
+
+/* The AIX way */
+#if 0
+#ifdef HOST_IS_AIX
+{
+ AixMountTableEntry mntent;
+ FILE *tab = fopen("/etc/filesystems", "r");
+
+ if (tab == NULL) {
+ SL_RETURN((NULL), _("readmounts"));
+ }
+
+ while (!aix_fs_get (tab, &mntent))
+ {
+ m = (struct sh_mounts_mnt *) SH_ALLOC(sizeof (struct sh_mounts_mnt));
+ m->path = sh_util_strdup(mntent.mnt_mount);
+ m->opts = getoptlist(mntent.mnt_options);
+
+ m->next = list;
+ list = m;
+
+ mntent.mnt_mount[0] = '\0';
+ mntent.mnt_special[0] = '\0';
+ mntent.mnt_fstype[0] = '\0';
+ mntent.mnt_options[0] = '\0';
+ }
+
+ (void) sl_fclose(FIL__, __LINE__, tab);
+ aix_fs_get (NULL, NULL); /* reset */
+}
+#endif
+#endif
+
+ SL_RETURN((list), _("readmounts"));
+
+}
+
+
+/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+/* #ifdef SH_USE_MOUNTS */
+#endif
+
diff --git a/src/sh_nmail.c b/src/sh_nmail.c
new file mode 100644
index 0000000..f7d55bd
--- /dev/null
+++ b/src/sh_nmail.c
@@ -0,0 +1,1032 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2008 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
+#define _XOPEN_SOURCE 500
+#endif
+
+#if defined(GCC_VERSION_MAJOR) && !defined(__clang__)
+#if (GCC_VERSION_MAJOR > 4) || ((GCC_VERSION_MAJOR == 4) && (GCC_VERSION_MINOR > 8))
+#pragma GCC diagnostic ignored "-Wclobbered"
+#endif
+#endif
+
+#include <string.h>
+#include <time.h>
+
+#if defined(SH_WITH_MAIL)
+
+#undef FIL__
+#define FIL__ _("sh_nmail.c")
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_mem.h"
+#include "sh_mail.h"
+#include "sh_tiger.h"
+#include "sh_string.h"
+#include "sh_utils.h"
+#include "sh_fifo.h"
+#include "sh_filter.h"
+#include "sh_mail_int.h"
+
+SH_MUTEX_INIT(mutex_listall, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_INIT(mutex_flush_l, PTHREAD_MUTEX_INITIALIZER);
+
+/* Pointer to last address */
+
+static struct alias * last = NULL;
+
+/* List of mail recipients */
+
+static struct alias * recipient_list = NULL;
+
+static struct alias * compiled_recipient_list = NULL;
+static sh_filter_type compiled_mail_filter = SH_FILT_INIT;
+
+/* List of mail aliases */
+
+static struct alias * alias_list = NULL;
+
+/* List of all recipients */
+
+struct alias * all_recipients = NULL;
+
+/* Check if addr is in list. If list is all_recipients,
+ * must iterate over ->all_next instead of ->next
+ */
+static int check_double (const char * str, struct alias * list, int isAll)
+{
+ if (str && list)
+ {
+ struct alias * item = list;
+
+ while (item)
+ {
+ if (0 == strcmp(sh_string_str(item->recipient), str))
+ return -1;
+ if (isAll)
+ item = item->all_next;
+ else
+ item = item->next;
+ }
+ }
+ return 0;
+}
+
+/* Add recipient to 'list' AND to all_recipients. If
+ * it already is in all_recipients, mark it as an alias
+ * (isAlias = 1).
+ */
+struct alias * add_recipient_intern(const char * str,
+ struct alias * list)
+{
+ if (str)
+ {
+ struct alias * new = SH_ALLOC(sizeof(struct alias));
+ new->next = list;
+ new->mx_list = NULL;
+ new->mail_filter = NULL;
+ new->recipient_list = NULL;
+ new->severity = (-1);
+ new->send_mail = 0;
+ new->isAlias = 0;
+ new->recipient = sh_string_new_from_lchar(str, strlen(str));
+ list = new;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_listall);
+ if (0 != check_double(str, all_recipients, S_TRUE))
+ {
+ new->isAlias = 1;
+ }
+ new->all_next = all_recipients;
+ all_recipients = new;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
+ }
+ return list;
+}
+
+int sh_nmail_close_recipient(const char * str)
+{
+ (void) str;
+
+ if (last)
+ {
+ last = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+/* Add a single recipient. Must not be in in
+ * recipient_list already, and not in all_recipients.
+ */
+int sh_nmail_add_recipient(const char * str)
+{
+ /* return error if duplicate, or
+ * already defined within an alias list.
+ */
+ if (0 == check_double(str, recipient_list, S_FALSE) &&
+ 0 == check_double(str, all_recipients, S_TRUE))
+ {
+ recipient_list = add_recipient_intern(str, recipient_list);
+ last = recipient_list;
+ return 0;
+ }
+ return -1;
+}
+
+/* Add a compiled-in address. These share the compiled_mail_filter
+ */
+int sh_nmail_add_compiled_recipient(const char * str)
+{
+ if (0 == check_double(str, compiled_recipient_list, S_FALSE))
+ {
+ compiled_recipient_list =
+ add_recipient_intern(str, compiled_recipient_list);
+ if (compiled_recipient_list)
+ compiled_recipient_list->mail_filter = &compiled_mail_filter;
+ last = compiled_recipient_list;
+ return 0;
+ }
+ return -1;
+}
+
+/* Add an alias; format is name ":" comma-delimited_list_of_recipients
+ */
+int sh_nmail_add_alias(const char * str)
+{
+#define SH_ALIASES_RECP_NUM 256
+ size_t lengths[SH_ALIASES_RECP_NUM];
+ unsigned int nfields = SH_ALIASES_RECP_NUM;
+ char * new = sh_util_strdup(str);
+ char * p = strchr(new, ':');
+ char * q;
+
+ if (p && strlen(p) > 1)
+ {
+ unsigned int i;
+ char ** array;
+
+ *p = '\0'; q = p; ++p;
+ if (strlen(new) > 0)
+ {
+ /* strip trailing space
+ */
+ --q; while ((q != new) && *q == ' ') { *q = '\0'; --q; }
+ }
+ else
+ {
+ goto err;
+ }
+
+ if (0 == check_double(new, alias_list, S_FALSE))
+ {
+ array = split_array_list(p, &nfields, lengths);
+
+ if (array && nfields > 0)
+ {
+ struct alias * newalias = NULL;
+
+ /* Enforce that all list members are defined already
+ */
+ int nflag = 0;
+
+ for (i = 0; i < nfields; ++i) {
+ if (0 == check_double(array[i], all_recipients, S_TRUE))
+ nflag = 1; /* not in all_recipients --> bad */
+ }
+
+ if (nflag == 0)
+ {
+ newalias = SH_ALLOC(sizeof(struct alias));
+ newalias->recipient_list = NULL;
+ newalias->mail_filter = NULL;
+ newalias->mx_list = NULL;
+ newalias->severity = (-1);
+
+ /* This is the alias */
+ newalias->recipient = sh_string_new_from_lchar(new, strlen(new));
+
+ for (i = 0; i < nfields; ++i)
+ {
+ if (lengths[i] > 0 &&
+ 0 == check_double(array[i], newalias->recipient_list, S_FALSE))
+ {
+ newalias->recipient_list =
+ add_recipient_intern(array[i], newalias->recipient_list);
+ }
+ }
+ }
+
+ SH_FREE(array);
+
+ if (newalias == NULL || newalias->recipient_list == NULL)
+ {
+ if (newalias)
+ SH_FREE(newalias);
+ goto err;
+ }
+
+ newalias->next = alias_list;
+ alias_list = newalias;
+ last = alias_list;
+
+ SH_FREE(new);
+ return 0;
+ }
+ }
+ }
+ err:
+ SH_FREE(new);
+ return -1;
+}
+
+
+/* <<<<<<<<<<<<<<< Recipient List >>>>>>>>>>>>>>>>>>>>>> */
+
+static struct alias * find_list (const char * alias, int * single)
+{
+ struct alias * list = NULL;
+
+ *single = 0;
+
+ if (!alias)
+ {
+ list = all_recipients;
+ }
+ else
+ {
+ struct alias * test = alias_list;
+
+ while (test)
+ {
+ if (0 == strcmp(alias, sh_string_str(test->recipient)))
+ {
+ list = test->recipient_list;
+ break;
+ }
+ test = test->next;
+ }
+
+ if (!list)
+ {
+ test = recipient_list;
+ while (test)
+ {
+ if (0 == strcmp(alias, sh_string_str(test->recipient)))
+ {
+ list = test;
+ *single = 1;
+ break;
+ }
+ test = test->next;
+ }
+ }
+
+ if (!list)
+ {
+ test = compiled_recipient_list;
+ while (test)
+ {
+ if (0 == strcmp(alias, sh_string_str(test->recipient)))
+ {
+ list = test;
+ *single = 1;
+ break;
+ }
+ test = test->next;
+ }
+ }
+ }
+ return list;
+}
+
+/* Returns zero (no) or one (yes). Used to tag messages that are
+ * valid for a given recipient (or mailing list alias).
+ */
+int sh_nmail_valid_message_for_alias (int level,
+ const char * message,
+ const char * alias,
+ const void * rcv_info)
+{
+ const struct alias * rcv = (const struct alias *) rcv_info;
+
+ if (!alias || 0 == strcmp(alias, sh_string_str(rcv->recipient)))
+ {
+ if ((level & rcv->severity) == 0)
+ {
+ return 0;
+ }
+
+ if (rcv->mail_filter)
+ {
+ if (0 != sh_filter_filter(message, rcv->mail_filter))
+ {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* Returns number of recipients */
+
+static
+int sh_nmail_compute_recipients (int level, const char * message,
+ const char * alias, int flagit)
+{
+ struct alias * list = NULL;
+ int single = 0;
+ int retval = 0;
+
+ if (flagit)
+ {
+ list = all_recipients;
+ while (list)
+ {
+ list->send_mail = 0;
+ list = list->all_next;
+ }
+ list = NULL;
+ }
+
+ if (message)
+ {
+ int flag = 0;
+
+ list = find_list (alias, &single);
+ if (list == all_recipients)
+ flag = 1;
+
+ while (list)
+ {
+ /* Check severity
+ */
+ if ((list->severity & level) == 0)
+ {
+ if (single) break;
+ if (flag)
+ list = list->all_next;
+ else
+ list = list->next;
+ continue;
+ }
+
+ /* Check filter
+ */
+ if (list->mail_filter &&
+ 0 != sh_filter_filter(message, list->mail_filter))
+ {
+ if (single) break;
+ if (flag)
+ list = list->all_next;
+ else
+ list = list->next;
+ continue;
+ }
+
+ /* Mark the entry
+ */
+ if (flag)
+ {
+ /* Don't mark aliases
+ */
+ if (flagit && list->isAlias == 0)
+ {
+ list->send_mail = 1;
+ }
+ list = list->all_next;
+ }
+ else
+ {
+ if (flagit)
+ list->send_mail = 1;
+ list = list->next;
+ }
+ ++retval;
+ }
+ }
+ return retval;
+}
+
+/* Is not called from same(recursively) or different thread
+ */
+static
+int sh_nmail_flag_recipients (int level, const char * message,
+ const char * alias)
+{
+ int retval = 0;
+
+ if (message)
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_listall);
+ retval = sh_nmail_compute_recipients (level, message, alias, 1);
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
+ }
+ return retval;
+}
+
+/* Can be called from same thread with mutex_listall held via sh_nmail_flush()
+ */
+static
+int sh_nmail_test_recipients (int level, const char * message,
+ const char * alias)
+{
+ int retval = 0;
+
+ if (message)
+ {
+ if (0 == SH_MUTEX_TRYLOCK_UNSAFE(mutex_flush_l))
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_listall);
+ retval = sh_nmail_compute_recipients (level, message, alias, 0);
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_flush_l);
+ }
+ }
+ return retval;
+}
+
+/* <<<<<<<<<<<<<<<<<<< Mail the message >>>>>>>>>>>>>>>>>>>>>> */
+
+SH_MUTEX_RECURSIVE(mutex_nmail_msg);
+SH_MUTEX_STATIC(nmail_lock, PTHREAD_MUTEX_INITIALIZER);
+
+/*
+ * First test list of recipients, then call sh_mail_pushstack().
+ */
+int sh_nmail_pushstack (int level, const char * message,
+ const char * alias)
+{
+ int retval = 0;
+
+ if (0 != sh_nmail_test_recipients (level, message, alias))
+ {
+ retval = sh_mail_pushstack(level, message, alias);
+ }
+ return retval;
+}
+
+static int nmail_count = 0;
+
+/*
+ * First mark list of recipients, then call sh_mail_msg().
+ */
+int sh_nmail_msg (int level, const char * message,
+ const char * alias)
+{
+ volatile int retval = 0;
+
+ /* Need to:
+ * -- wait if different thread, and
+ * -- fail if same thread. */
+ SH_MUTEX_RECURSIVE_INIT(mutex_nmail_msg);
+ SH_MUTEX_RECURSIVE_LOCK(mutex_nmail_msg);
+
+ /* Only same thread beyond this point. We fail
+ * if count > 0 already. */
+ if (0 == SH_MUTEX_TRYLOCK_UNSAFE(nmail_lock))
+ {
+ ++nmail_count;
+ if (nmail_count != 1)
+ {
+ --nmail_count;
+ SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
+ goto cleanup;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
+
+ if (0 != sh_nmail_flag_recipients (level, message, alias))
+ {
+ /* Need to keep info for sh_nmail_pushstack()
+ */
+ SH_MUTEX_LOCK(mutex_listall);
+ retval = sh_mail_msg(message);
+ SH_MUTEX_UNLOCK(mutex_listall);
+
+ if (retval != 0)
+ {
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ retval, MSG_E_SUBGEN,
+ _("could not mail immediately"),
+ _("sh_nmail_msg") );
+ sh_mail_pushstack(level, message, alias);
+ }
+ }
+ SH_MUTEX_LOCK_UNSAFE(nmail_lock);
+ --nmail_count;
+ SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
+ }
+ cleanup:
+ ; /* label at end of compound statement */
+ SH_MUTEX_RECURSIVE_UNLOCK(mutex_nmail_msg);
+ return retval;
+}
+
+static int sh_nmail_flush_int (void);
+
+int sh_nmail_flush ()
+{
+ int retval = 0;
+
+ if (0 == SH_MUTEX_TRYLOCK_UNSAFE(nmail_lock))
+ {
+ ++nmail_count;
+ if (nmail_count != 1)
+ {
+ --nmail_count;
+ SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
+ return retval;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
+
+ retval = sh_nmail_flush_int ();
+
+ SH_MUTEX_LOCK_UNSAFE(nmail_lock);
+ --nmail_count;
+ SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
+ }
+ return retval;
+}
+
+/* warning: variable ‘list’ might be clobbered by ‘longjmp’ or ‘vfork’*/
+static struct alias ** list_dummy;
+
+/*
+ * Loop over all recipients in stack.
+ * For each distinct one, mark all messages for sending.
+ * Then call sh_mail_msg().
+ */
+
+static int sh_nmail_flush_int ()
+{
+ int retval = 0;
+ sh_string * msg = NULL;
+ sh_string * smsg = NULL;
+ struct alias * list;
+ struct alias * dlist;
+
+ /* warning: variable ‘list’ might be clobbered by ‘longjmp’ or ‘vfork’*/
+ list_dummy = &list;
+
+ SH_MUTEX_LOCK(mutex_listall);
+
+ /* Reset recipient list
+ */
+ list = all_recipients;
+ while (list)
+ {
+ list->send_mail = 0;
+ list = list->all_next;
+ }
+
+ /* Check (i) compiled recipients, (b) aliases, (c) single recipients.
+ * For each, tag all messages, then call sh_mail_msg with
+ * appropriate address list.
+ */
+
+ reset_list(fifo_mail);
+
+ /* Compiled recipients. These share threshold and filter,
+ * hence only the first recipient needs to be tested.
+ */
+ list = compiled_recipient_list;
+
+ if (list)
+ {
+ msg = tag_list(fifo_mail, sh_string_str(list->recipient),
+ sh_nmail_valid_message_for_alias, list, S_TRUE);
+ }
+
+ if (msg)
+ {
+ while (list)
+ {
+ list->send_mail = 1;
+ list = list->next;
+ }
+
+ list = compiled_recipient_list;
+
+ SH_MUTEX_LOCK(mutex_flush_l);
+ (void) sh_mail_msg(sh_string_str(msg));
+ SH_MUTEX_UNLOCK(mutex_flush_l);
+
+ sh_string_destroy(&msg);
+
+ list = compiled_recipient_list;
+ while (list)
+ {
+ list->send_mail = 0;
+ list = list->next;
+ }
+ }
+
+ /* Aliases
+ */
+ list = alias_list;
+
+ while (list) {
+
+ /* Work through the recipient list. As smsg stores last msg,
+ * we send a batch whenever msg != smsg, and continue from
+ * that point in the recipient list.
+ */
+ struct alias * lnew;
+
+ while (list)
+ {
+ msg = tag_list(fifo_mail, sh_string_str(list->recipient),
+ sh_nmail_valid_message_for_alias, list, S_FALSE);
+
+ if (msg)
+ {
+ if (!smsg) /* init */
+ {
+ smsg = sh_string_copy(msg);
+ }
+ else
+ {
+ if (0 != strcmp(sh_string_str(smsg), sh_string_str(msg)))
+ {
+ /*
+ * Don't set list = list->next here, since we want
+ * to continue with this recipient in the next batch.
+ */
+ sh_string_destroy(&msg);
+ break;
+ }
+ }
+ lnew = list->recipient_list;
+ while (lnew)
+ {
+ lnew->send_mail = 1;
+ lnew= lnew->next;
+ }
+ sh_string_destroy(&msg);
+ }
+ list = list->next;
+ }
+
+ /* Continue here if smsg != msg */
+
+ if (smsg)
+ {
+ SH_MUTEX_LOCK(mutex_flush_l);
+ (void) sh_mail_msg(sh_string_str(smsg));
+ SH_MUTEX_UNLOCK(mutex_flush_l);
+ sh_string_destroy(&smsg);
+ }
+
+ /* Reset old list of recipients (up to current point in list)
+ * and then continue with list from current point on.
+ */
+ dlist = alias_list;
+ while (dlist)
+ {
+ lnew = dlist->recipient_list;
+ while (lnew)
+ {
+ lnew->send_mail = 0;
+ lnew = lnew->next;
+ }
+ dlist = dlist->next;
+ }
+ }
+
+
+ /* Single recipients
+ */
+ list = recipient_list;
+
+ while (list) {
+
+ /* Work through the recipient list. As smsg stores last msg,
+ * we send a batch whenever msg != smsg, and continue from
+ * that point in the recipient list.
+ */
+
+ while (list)
+ {
+ msg = tag_list(fifo_mail, sh_string_str(list->recipient),
+ sh_nmail_valid_message_for_alias, list, S_TRUE);
+
+ if (msg)
+ {
+ if (!smsg) /* init */
+ {
+ smsg = sh_string_copy(msg);
+ }
+ else
+ {
+ if (0 != strcmp(sh_string_str(smsg), sh_string_str(msg)))
+ {
+ /*
+ * Don't set list = list->next here, since we want
+ * to continue with this recipient in the next batch.
+ */
+ sh_string_destroy(&msg);
+ break;
+ }
+ }
+ list->send_mail = 1;
+ sh_string_destroy(&msg);
+ }
+ list = list->next;
+ }
+
+ /* Continue here if smsg != msg */
+
+ if (smsg)
+ {
+ SH_MUTEX_LOCK(mutex_flush_l);
+ (void) sh_mail_msg(sh_string_str(smsg));
+ SH_MUTEX_UNLOCK(mutex_flush_l);
+ sh_string_destroy(&smsg);
+ }
+
+ /* Reset old list of recipients (up to current point in list)
+ * and then continue with list from current point on.
+ */
+ dlist = recipient_list;
+ while (dlist)
+ {
+ dlist->send_mail = 0;
+ dlist = dlist->next;
+ }
+ }
+
+ /* Remove all mails for which no recipient failed
+ */
+
+ sh.mailNum.alarm_last -= commit_list(fifo_mail);
+ SH_MUTEX_UNLOCK(mutex_listall);
+
+ return retval;
+}
+
+
+
+/* <<<<<<<<<<<<<<<<<<< Severity >>>>>>>>>>>>>>>>>>>>>> */
+
+/*
+ * -- set severity threshold for recipient or alias
+ */
+int sh_nmail_set_severity (const char * str)
+{
+ if (last == recipient_list || last == alias_list)
+ {
+ if (0 == sh_error_set_level(str, &(last->severity)))
+ {
+ /* All recipients in alias share the severity
+ */
+ if (last == alias_list)
+ {
+ struct alias * ptr = last->recipient_list;
+
+ while (ptr)
+ {
+ ptr->severity = last->severity;
+ ptr = ptr->next;
+ }
+ }
+ return 0;
+ }
+ }
+ return (-1);
+}
+
+/* <<<<<<<<<<<<<<<<<<< Filters >>>>>>>>>>>>>>>>>>>>>> */
+
+
+int sh_nmail_add_generic (const char * str, int flag)
+{
+ if (last)
+ {
+ if (NULL == last->mail_filter)
+ last->mail_filter = sh_filter_alloc();
+
+ /* All recipients in alias share the mail filter
+ */
+ if (last == alias_list)
+ {
+ struct alias * ptr = last->recipient_list;
+
+ while (ptr)
+ {
+ ptr->mail_filter = last->mail_filter;
+ ptr = ptr->next;
+ }
+ }
+
+ return (sh_filter_add (str, last->mail_filter, flag));
+ }
+ return (-1);
+}
+
+/*
+ * -- add keywords to the OR filter
+ */
+int sh_nmail_add_or (const char * str)
+{
+ return sh_nmail_add_generic(str, SH_FILT_OR);
+}
+
+/*
+ * -- add keywords to the AND filter
+ */
+int sh_nmail_add_and (const char * str)
+{
+ return sh_nmail_add_generic(str, SH_FILT_AND);
+}
+
+/*
+ * -- add keywords to the NOT filter
+ */
+int sh_nmail_add_not (const char * str)
+{
+ return sh_nmail_add_generic(str, SH_FILT_NOT);
+}
+
+
+/* <<<<<<<<<<<<<<<<<<< Mailkey per Alias >>>>>>>>>>>>>>>>>>>>>>>>> */
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#include "zAVLTree.h"
+
+zAVLTree * mailkeys = NULL;
+
+struct alias_mailkey {
+ char * alias;
+ unsigned int mailcount;
+ time_t id_audit;
+ char mailkey_old[KEY_LEN+1];
+ char mailkey_new[KEY_LEN+1];
+};
+
+static zAVLKey sh_nmail_getkey(void const *item)
+{
+ const struct alias_mailkey * t = (const struct alias_mailkey *) item;
+ return (zAVLKey) t->alias;
+}
+
+/* Return mailkey for alias. If there's no key yet, create it and
+ * store it in the AVL tree.
+ * This is called from sh_mail_msg,
+ * which is called from sh_nmail_msg,
+ * which is protected by a mutex.
+ */
+int sh_nmail_get_mailkey (const char * alias, char * buf, size_t bufsiz,
+ time_t * id_audit)
+{
+ char hashbuf[KEYBUF_SIZE];
+
+ start:
+
+ if (mailkeys)
+ {
+ struct alias_mailkey * t;
+
+ if (!alias)
+ t = (struct alias_mailkey *) zAVLSearch (mailkeys, _("(null)"));
+ else
+ t = (struct alias_mailkey *) zAVLSearch (mailkeys, alias);
+
+ if (t)
+ {
+ /* iterate the key
+ */
+ (void) sl_strlcpy(t->mailkey_new,
+ sh_tiger_hash (t->mailkey_old, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ (void) sl_strlcpy(buf, t->mailkey_new, bufsiz);
+ ++(t->mailcount);
+ }
+ else
+ {
+ t = SH_ALLOC(sizeof(struct alias_mailkey));
+
+ MLOCK(t, sizeof(struct alias_mailkey));
+
+ if (!alias)
+ t->alias = sh_util_strdup(_("(null)"));
+ else
+ t->alias = sh_util_strdup(alias);
+
+ t->mailcount = 0;
+ t->id_audit = time(NULL);
+
+ BREAKEXIT(sh_util_keyinit);
+ (void) sh_util_keyinit (t->mailkey_old, KEY_LEN+1);
+
+ /* iterate the key
+ */
+ (void) sl_strlcpy(t->mailkey_new,
+ sh_tiger_hash (t->mailkey_old, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ (void) sl_strlcpy(buf, t->mailkey_new, bufsiz);
+ (void) zAVLInsert(mailkeys, t);
+ }
+
+ /* X(n) -> X(n-1)
+ */
+ (void) sl_strlcpy (t->mailkey_old, t->mailkey_new, KEY_LEN+1);
+
+ *id_audit = t->id_audit;
+
+ return (t->mailcount);
+ }
+
+ mailkeys = zAVLAllocTree (sh_nmail_getkey, zAVL_KEY_STRING);
+ goto start;
+}
+
+/* <<<<<<<<<<<<<<<<<<< Free for Reconfigure >>>>>>>>>>>>>>>>>>>>>> */
+
+
+static void free_recipient_list(struct alias * list)
+{
+ struct alias * new;
+ sh_filter_type * p = NULL;
+
+ while (list)
+ {
+ new = list;
+ list = new->next;
+ if (new->mx_list)
+ free_mx(new->mx_list);
+ if (new->mail_filter)
+ {
+ sh_filter_free(new->mail_filter);
+ if (!p || p != new->mail_filter)
+ {
+ p = new->mail_filter;
+ SH_FREE(new->mail_filter);
+ }
+ }
+ sh_string_destroy(&(new->recipient));
+ SH_FREE(new);
+ }
+}
+
+/* Free everything to prepare for reconfigure
+ */
+void sh_nmail_free()
+{
+ SH_MUTEX_LOCK_UNSAFE(mutex_listall);
+ all_recipients = NULL;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
+
+ free_recipient_list(recipient_list);
+ recipient_list = NULL;
+
+ sh_filter_free(&compiled_mail_filter);
+
+ while (alias_list)
+ {
+ struct alias * item = alias_list;
+
+ alias_list = item->next;
+
+ sh_string_destroy(&(item->recipient));
+ free_recipient_list(item->recipient_list);
+ if (item->mail_filter)
+ {
+ sh_filter_free(item->mail_filter);
+ /* SH_FREE(item->mail_filter); */
+ }
+ SH_FREE(item);
+ }
+ alias_list = NULL;
+
+ last = compiled_recipient_list;
+ return;
+}
+
+/* defined(SH_WITH_MAIL) */
+#endif
diff --git a/src/sh_port2proc.c b/src/sh_port2proc.c
new file mode 100644
index 0000000..61357f1
--- /dev/null
+++ b/src/sh_port2proc.c
@@ -0,0 +1,1080 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2008 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
+#define NEED_ADD_DIRENT
+
+#if defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
+
+/* #define DEBUG_P2P 1 */
+
+#include "samhain.h"
+#include "sh_utils.h"
+
+/****************************************************************************
+ *
+ * >>> COMMON CODE <<<
+ *
+ ****************************************************************************/
+#if defined(__linux__) || defined(__FreeBSD__)
+
+#include "sh_error_min.h"
+#include "sh_pthread.h"
+#include "sh_ipvx.h"
+
+#define FIL__ _("sh_port2proc.c")
+
+struct sock_store {
+ unsigned long sock;
+ size_t pid;
+ char * path;
+ char * user;
+ struct sock_store * next;
+};
+
+/* /proc:
+ * linux: /proc/pid/exe
+ * freebsd: /proc/pid/file
+ * solaris10: /proc/pid/path/a.out
+ */
+static void get_user_and_path (struct sock_store * add)
+{
+ extern char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
+
+ char path[128];
+ char * buf;
+ struct stat sbuf;
+ int len;
+ char * tmp;
+
+ sl_snprintf (path, sizeof(path), "/proc/%ld/exe", (unsigned long) add->pid);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
+ {
+ goto linkread;
+ }
+
+ sl_snprintf (path, sizeof(path), "/proc/%ld/file", (unsigned long) add->pid);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
+ {
+ goto linkread;
+ }
+
+ sl_snprintf (path, sizeof(path), "/proc/%ld/path/a.out", (unsigned long) add->pid);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
+ {
+ goto linkread;
+ }
+
+ return;
+
+ linkread:
+
+ buf = SH_ALLOC(PATH_MAX);
+ len = readlink(path, buf, PATH_MAX); /* flawfinder: ignore */
+ len = (len >= PATH_MAX) ? (PATH_MAX-1) : len;
+
+ if (len > 0)
+ {
+ buf[len] = '\0';
+ add->path = buf;
+ }
+ else
+ {
+ SH_FREE(buf);
+ }
+
+ add->user = SH_ALLOC(USER_MAX);
+ tmp = sh_unix_getUIDname (SH_ERR_ALL, sbuf.st_uid, add->user, USER_MAX);
+
+ if (!tmp)
+ sl_snprintf (add->user, USER_MAX, "%ld", (unsigned long) sbuf.st_uid);
+
+ return;
+}
+
+#endif
+
+/****************************************************************************
+ *
+ * >>> LINUX CODE <<<
+ *
+ ****************************************************************************/
+
+#if defined(__linux__)
+
+static size_t sh_minpid = 0x0001;
+static size_t sh_maxpid = 0x8000;
+
+#ifndef HAVE_LSTAT
+#define lstat(x,y) stat(x,y)
+#endif /* HAVE_LSTAT */
+
+#if defined(S_IFLNK) && !defined(S_ISLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#else
+# if !defined(S_ISLNK)
+# define S_ISLNK(mode) (0)
+# endif
+#endif
+
+#if defined(__linux__)
+#define PROC_PID_MAX _("/proc/sys/kernel/pid_max")
+
+static int proc_max_pid (size_t * procpid)
+{
+ char * ret;
+ unsigned long pid;
+ FILE * fd;
+ char str[128];
+ char * ptr;
+
+ SL_ENTER(_("proc_max_pid"));
+
+ if (0 == access(PROC_PID_MAX, R_OK)) /* flawfinder: ignore */
+ {
+ if (NULL != (fd = fopen(PROC_PID_MAX, "r")))
+ {
+ str[0] = '\0';
+ ret = fgets(str, 128, fd);
+ if (ret && *str != '\0')
+ {
+ pid = strtoul(str, &ptr, 0);
+ if (*ptr == '\0' || *ptr == '\n')
+ {
+ sl_fclose(FIL__, __LINE__, fd);
+ *procpid = (size_t) pid;
+ SL_RETURN(0, _("proc_max_pid"));
+ }
+ }
+ sl_fclose(FIL__, __LINE__, fd);
+ }
+ }
+ SL_RETURN((-1), _("proc_max_pid"));
+}
+#else
+static int proc_max_pid(size_t * procpid)
+{
+ *procpid = sh_maxpid;
+ return 0;
+}
+#endif
+
+static struct sock_store * socklist = NULL;
+
+static void del_sock_all()
+{
+ struct sock_store * del = socklist;
+
+ while (del)
+ {
+ socklist = del->next;
+ if (del->path)
+ SH_FREE(del->path);
+ if (del->user)
+ SH_FREE(del->user);
+ SH_FREE(del);
+ del = socklist;
+ }
+ socklist = NULL;
+ return;
+}
+
+static void add_sock(unsigned long sock, size_t pid)
+{
+ struct sock_store * add = SH_ALLOC(sizeof(struct sock_store));
+
+ add->sock = sock;
+ add->pid = pid;
+ add->path = NULL;
+ add->user = NULL;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ get_user_and_path(add);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ add->next = socklist;
+ socklist = add;
+ return;
+}
+
+static void check_and_add_sock(char * fbuf, size_t pid)
+{
+ if (0 == strncmp(_("socket:["), fbuf, 8))
+ {
+ char * end;
+ unsigned long sock;
+ size_t len = strlen(fbuf);
+ if (fbuf[len-1] == ']')
+ fbuf[len-1] = '\0';
+ sock = strtoul(&fbuf[8], &end, 0);
+ if (*end == '\0' && fbuf[8] != '\0')
+ {
+ add_sock(sock, pid);
+ }
+ }
+}
+
+static void fetch_socks(size_t pid)
+{
+ char path[128];
+ DIR * dir;
+ sl_snprintf(path, sizeof(path), _("/proc/%lu/fd"), (unsigned long) pid);
+
+ dir = opendir(path);
+ if (dir)
+ {
+ struct dirent *entry;
+ while (NULL != (entry = readdir(dir)))
+ {
+ char fpath[384];
+ char fbuf[64];
+ int ret;
+ /* /proc/PID/fd/N-> socket:[15713] */
+ sl_snprintf(fpath, sizeof(fpath), _("%s/%s"), path, entry->d_name);
+ ret = readlink(fpath, fbuf, sizeof(fbuf)-1); /* flawfinder: ignore */
+ if (ret > 0)
+ {
+ fbuf[ret] = '\0';
+ check_and_add_sock(fbuf, pid);
+ }
+ }
+ closedir(dir);
+ }
+}
+
+int sh_port2proc_prepare()
+{
+ size_t i;
+
+ if (0 != proc_max_pid(&sh_maxpid))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Failed to detect max_pid"),
+ _("sh_port2proc"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN ((-1), _("sh_port2proc"));
+ }
+
+ /* Delete old socket list and re-create it
+ */
+ del_sock_all();
+
+ for (i = sh_minpid; i < sh_maxpid; ++i)
+ {
+ fetch_socks(i);
+ }
+
+ return 0;
+}
+
+void sh_port2proc_finish()
+{
+ /* Delete old socket list
+ */
+ del_sock_all();
+ return;
+}
+
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* returns the command and fills the 'user' array
+ */
+static char * port2proc_query(char * file, int proto, int domain,
+ struct sh_sockaddr * saddr, int sport,
+ unsigned long * pid, char * user, size_t userlen)
+{
+ FILE * fd;
+
+ fd = fopen(file, "r");
+
+ *pid = 0;
+
+#ifdef DEBUG_P2P
+ {
+ char errmsg[256];
+ char siface[SH_IP_BUF];
+ sh_ipvx_ntoa(siface, sizeof(siface), saddr);
+ sl_snprintf(errmsg, sizeof(errmsg),
+ "query, file=%s, proto=%d, port=%d, iface=%s\n",
+ file, proto, sport, siface);
+ fprintf(stderr, "%s", errmsg);
+ }
+#endif
+
+ if (fd)
+ {
+ unsigned int n, i, port, niface, inode, istatus;
+ char line[512];
+ char ip_port[128];
+ char iface[SH_IP_BUF];
+
+ while (NULL != fgets(line, sizeof(line), fd))
+ {
+
+#ifdef DEBUG_P2P
+ {
+ fprintf(stderr, "%s", line);
+ }
+#endif
+
+ if (4 == sscanf(line,
+ "%u: %127s %*X:%*X %X %*X:%*X %*X:%*X %*X %*d %*d %u %*s",
+ &n, ip_port, &istatus, &inode))
+ {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ struct sh_sockaddr ss;
+
+ char * p;
+
+ ip_port[127] = '\0';
+
+ p = strchr(ip_port, ':');
+
+ if (p)
+ {
+ *p = '\0'; ++p;
+ port = (unsigned int) strtoul(p, NULL, 16);
+ sl_strlcpy(iface, ip_port, sizeof(iface));
+ }
+ else
+ {
+ continue;
+ }
+
+ niface = 0;
+
+ switch (domain)
+ {
+ case AF_INET:
+ addr4.sin_addr.s_addr = (int) strtol(iface, NULL, 16);
+ niface = (unsigned int) addr4.sin_addr.s_addr;
+ sh_ipvx_save(&ss, AF_INET, (struct sockaddr *)&addr4);
+ break;
+
+ case AF_INET6:
+ sscanf(iface,
+ "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
+ &addr6.sin6_addr.s6_addr[3], &addr6.sin6_addr.s6_addr[2], &addr6.sin6_addr.s6_addr[1], &addr6.sin6_addr.s6_addr[0],
+ &addr6.sin6_addr.s6_addr[7], &addr6.sin6_addr.s6_addr[6], &addr6.sin6_addr.s6_addr[5], &addr6.sin6_addr.s6_addr[4],
+ &addr6.sin6_addr.s6_addr[11], &addr6.sin6_addr.s6_addr[10], &addr6.sin6_addr.s6_addr[9], &addr6.sin6_addr.s6_addr[8],
+ &addr6.sin6_addr.s6_addr[15], &addr6.sin6_addr.s6_addr[14], &addr6.sin6_addr.s6_addr[13], &addr6.sin6_addr.s6_addr[12]);
+
+ for (i = 0; i < 16; ++i)
+ {
+ if (0 != (unsigned int) addr6.sin6_addr.s6_addr[i])
+ ++niface;
+ }
+ sh_ipvx_save(&ss, AF_INET6, (struct sockaddr *)&addr6);
+ break;
+ }
+
+#ifdef DEBUG_P2P
+ {
+ char a[SH_IP_BUF];
+ char b[SH_IP_BUF];
+
+ sh_ipvx_ntoa(a, sizeof(a), &ss);
+ sh_ipvx_ntoa(b, sizeof(b), saddr);
+
+ fprintf(stderr, " -> inode %u, iface/port %s,%u, status %u, searching %s,%u, %u\n",
+ inode, a, port, istatus, b, sport,
+ proto == IPPROTO_TCP ? 0x0a : 0x07);
+ }
+#endif
+
+ if (proto == IPPROTO_TCP && istatus != 0x0a)
+ continue;
+ if (proto == IPPROTO_UDP && istatus == 0x01)
+ continue;
+
+#ifdef DEBUG_P2P
+ {
+ fprintf(stderr, "check iface %u..\n", iface);
+ }
+#endif
+
+ if ((proto == IPPROTO_UDP || niface == 0 || 0 == sh_ipvx_cmp(&ss, saddr)) &&
+ port == (unsigned int)sport)
+ {
+ struct sock_store * new = socklist;
+
+#ifdef DEBUG_P2P
+ {
+ fprintf(stderr, "found it\n");
+ }
+#endif
+
+ while (new)
+ {
+#ifdef DEBUG_P2P
+ {
+ fprintf(stderr, "searching inode %u: %lu\n",
+ inode, new->sock);
+ }
+#endif
+ if (inode == new->sock)
+ {
+#ifdef DEBUG_P2P
+ {
+ fprintf(stderr, "found it: path=(%s), user=(%s)\n",
+ new->path == NULL ? "NULL" : new->path,
+ new->user == NULL ? "NULL" : new->user);
+ }
+#endif
+ sl_fclose(FIL__, __LINE__, fd);
+ *pid = (unsigned long) new->pid;
+ if (new->path)
+ {
+ if (new->user)
+ sl_strlcpy(user, new->user, userlen);
+ else
+ sl_strlcpy(user, "-", userlen);
+ return sh_util_strdup(new->path);
+ }
+ goto err_out;
+ }
+ new = new->next;
+ }
+ }
+ }
+ }
+ sl_fclose(FIL__, __LINE__, fd);
+ }
+ err_out:
+ sl_strlcpy(user, "-", userlen);
+ return sh_util_strdup("-");
+}
+
+/* returns the command and fills the 'user' array
+ */
+char * sh_port2proc_query(int proto, struct sh_sockaddr * saddr, int sport,
+ unsigned long * pid, char * user, size_t userlen)
+{
+ char file[32];
+ char * ret;
+
+ if (proto == IPPROTO_TCP)
+ {
+ sl_strlcpy(file, _("/proc/net/tcp"), sizeof(file));
+ ret = port2proc_query(file, proto, AF_INET, saddr, sport, pid, user, userlen);
+
+ if (ret[0] == '-' && ret[1] == '\0')
+ {
+ SH_FREE(ret);
+ sl_strlcpy(file, _("/proc/net/tcp6"), sizeof(file));
+ ret = port2proc_query(file, proto, AF_INET6, saddr, sport, pid, user, userlen);
+ }
+ return ret;
+ }
+ else
+ {
+ char * ret;
+ sl_strlcpy(file, _("/proc/net/udp"), sizeof(file));
+ ret = port2proc_query(file, proto, AF_INET, saddr, sport, pid, user, userlen);
+
+ if (ret[0] == '-' && ret[1] == '\0')
+ {
+ SH_FREE(ret);
+ sl_strlcpy(file, _("/proc/net/udp6"), sizeof(file));
+ ret = port2proc_query(file, proto, AF_INET6, saddr, sport, pid, user, userlen);
+ }
+ return ret;
+ }
+}
+
+
+/****************************************************************************
+ *
+ * >>> FREEBSD CODE <<<
+ *
+ ****************************************************************************/
+
+#elif defined(__FreeBSD__)
+
+/* Uses code from sockstat.c. Error and memory handling modified.
+ * Only required functions from sockstat.c are included.
+ */
+
+/*-
+ * Copyright (c) 2002 Dag-Erling Co<EF>dan Sm<F8>rgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/sockstat/sockstat.c,v 1.13.2.1.4.1 2008/10/02 02:57:24 kensmith Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/user.h>
+
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_var.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+static int opt_4 = 1; /* Show IPv4 sockets */
+static int opt_6 = 1; /* Show IPv6 sockets */
+static int opt_c = 0; /* Show connected sockets */
+static int opt_l = 1; /* Show listening sockets */
+static int opt_v = 0; /* Verbose mode */
+
+struct sock {
+ void *socket;
+ void *pcb;
+ int vflag;
+ int family;
+ int proto;
+
+ struct sockaddr_storage laddr;
+ struct sockaddr_storage faddr;
+ struct sock *next;
+};
+
+#define HASHSIZE 1009
+static struct sock *sockhash[HASHSIZE];
+
+static struct xfile *xfiles;
+static int nxfiles;
+
+
+static void * xrealloc(void * buf, size_t len0, size_t len)
+{
+ if (len > 0)
+ {
+ void * xbuf = SH_ALLOC(len);
+ if (buf)
+ {
+ if (len0 <= len)
+ memcpy(xbuf, buf, len0);
+ else
+ memset(xbuf, '\0', len);
+ SH_FREE(buf);
+ }
+ return xbuf;
+ }
+ SH_FREE(buf);
+ return NULL;
+}
+
+/* Sets address and port in struct sockaddr_storage *sa
+ */
+static void
+sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port)
+{
+ struct sockaddr_in *sin4;
+ struct sockaddr_in6 *sin6;
+
+ bzero(sa, sizeof *sa);
+ switch (af) {
+ case AF_INET:
+ sin4 = (struct sockaddr_in *)sa;
+ sin4->sin_len = sizeof *sin4;
+ sin4->sin_family = af;
+ sin4->sin_port = port;
+ sin4->sin_addr = *(struct in_addr *)addr;
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_len = sizeof *sin6;
+ sin6->sin6_family = af;
+ sin6->sin6_port = port;
+ sin6->sin6_addr = *(struct in6_addr *)addr;
+ break;
+ default:
+ return;
+ }
+}
+
+/* Get socket information from the kernel.
+ */
+static void
+gather_inet(int proto)
+{
+ struct xinpgen *xig, *exig;
+ struct xinpcb *xip;
+ struct xtcpcb *xtp;
+ struct inpcb *inp;
+ struct xsocket *so;
+ struct sock *sock;
+ char varname[32];
+ size_t len, bufsize, bufsize0;
+ void *buf;
+ int hash, retry, vflag;
+
+ vflag = 0;
+ if (opt_4)
+ vflag |= INP_IPV4;
+ if (opt_6)
+ vflag |= INP_IPV6;
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ sl_strlcpy(varname, _("net.inet.tcp.pcblist"), sizeof(varname));
+ break;
+ case IPPROTO_UDP:
+ sl_strlcpy(varname, _("net.inet.udp.pcblist"), sizeof(varname));
+ break;
+ case IPPROTO_DIVERT:
+ sl_strlcpy(varname, _("net.inet.divert.pcblist"), sizeof(varname));
+ break;
+ default:
+ return;
+ }
+
+ buf = NULL;
+ bufsize = 8192;
+ bufsize0 = bufsize;
+ retry = 5;
+ do {
+ for (;;) {
+ buf = xrealloc(buf, bufsize0, bufsize);
+ bufsize0 = bufsize;
+ len = bufsize;
+ if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
+ break;
+ if (errno == ENOENT)
+ goto out;
+ if (errno != ENOMEM)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__,
+ 0, MSG_E_SUBGEN,
+ _("sysctlbyname()"),
+ _("gather_inet"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(buf);
+ return;
+ }
+ bufsize *= 2;
+ }
+ xig = (struct xinpgen *)buf;
+ exig = (struct xinpgen *)(void *)
+ ((char *)buf + len - sizeof *exig);
+ if (xig->xig_len != sizeof *xig ||
+ exig->xig_len != sizeof *exig)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("struct xinpgen size mismatch"),
+ _("gather_inet"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ goto out;
+ }
+
+ } while (xig->xig_gen != exig->xig_gen && retry--);
+
+ if (xig->xig_gen != exig->xig_gen && opt_v)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("data may be inconsistent"),
+ _("gather_inet"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ for (;;) {
+ xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
+ if (xig >= exig)
+ break;
+ switch (proto) {
+ case IPPROTO_TCP:
+ xtp = (struct xtcpcb *)xig;
+ if (xtp->xt_len != sizeof *xtp) {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("struct xtcpcb size mismatch"),
+ _("gather_inet"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ goto out;
+ }
+ inp = &xtp->xt_inp;
+ so = &xtp->xt_socket;
+ break;
+ case IPPROTO_UDP:
+ case IPPROTO_DIVERT:
+ xip = (struct xinpcb *)xig;
+ if (xip->xi_len != sizeof *xip) {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("struct xinpcb size mismatch"),
+ _("gather_inet"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ goto out;
+ }
+ inp = &xip->xi_inp;
+ so = &xip->xi_socket;
+ break;
+ default:
+ return;
+ }
+ if ((inp->inp_vflag & vflag) == 0)
+ continue;
+ if (inp->inp_vflag & INP_IPV4) {
+ if ((inp->inp_fport == 0 && !opt_l) ||
+ (inp->inp_fport != 0 && !opt_c))
+ continue;
+ } else if (inp->inp_vflag & INP_IPV6) {
+#ifndef in6p_fport
+#define in6p_fport inp_fport
+#endif
+ if ((inp->in6p_fport == 0 && !opt_l) ||
+ (inp->in6p_fport != 0 && !opt_c))
+ continue;
+ } else {
+ if (opt_v) {
+ char errmsg[64];
+ sl_snprintf(errmsg, sizeof(errmsg),
+ _("invalid vflag 0x%x"), inp->inp_vflag);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errmsg,
+ _("gather_inet"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ continue;
+ }
+ }
+
+ sock = SH_ALLOC(sizeof *sock);
+ memset(sock, '\0', sizeof (*sock));
+
+#ifndef in6p_lport
+#define in6p_lport inp_lport
+#endif
+ sock->socket = so->xso_so;
+ sock->proto = proto;
+ if (inp->inp_vflag & INP_IPV4) {
+ sock->family = AF_INET;
+ sockaddr(&sock->laddr, sock->family,
+ &inp->inp_laddr, inp->inp_lport);
+ sockaddr(&sock->faddr, sock->family,
+ &inp->inp_faddr, inp->inp_fport);
+ } else if (inp->inp_vflag & INP_IPV6) {
+ sock->family = AF_INET6;
+ sockaddr(&sock->laddr, sock->family,
+ &inp->in6p_laddr, inp->in6p_lport);
+ sockaddr(&sock->faddr, sock->family,
+ &inp->in6p_faddr, inp->in6p_fport);
+ }
+ sock->vflag = inp->inp_vflag;
+
+ hash = (int)((uintptr_t)sock->socket % HASHSIZE);
+ sock->next = sockhash[hash];
+ sockhash[hash] = sock;
+ }
+out:
+ if (buf)
+ SH_FREE(buf);
+}
+
+static void
+getfiles(void)
+{
+ size_t len;
+ size_t len0;
+
+ xfiles = SH_ALLOC(len = sizeof *xfiles);
+ len0 = len;
+
+ while (sysctlbyname(_("kern.file"), xfiles, &len, 0, 0) == -1) {
+ if (errno != ENOMEM)
+ {
+ volatile int status = errno;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("sysctlbyname()"),
+ _("getfiles"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ len *= 2;
+ xfiles = xrealloc(xfiles, len0, len);
+ len0 = len;
+ }
+ if (len > 0 && xfiles->xf_size != sizeof *xfiles)
+ if (errno != ENOMEM)
+ {
+ volatile int status = errno;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("struct xfile size mismatch"),
+ _("getfiles"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ nxfiles = len / sizeof *xfiles;
+}
+
+static const char *
+getprocname(pid_t pid)
+{
+ static struct kinfo_proc proc;
+ size_t len;
+ int mib[4];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = (int)pid;
+ len = sizeof proc;
+ if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
+ /* Do not warn if the process exits before we get its name. */
+ if (errno != ESRCH)
+ {
+ volatile int status = errno;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("sysctl()"),
+ _("getfiles"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ return ("-");
+ }
+ return (proc.ki_ocomm);
+}
+
+char * sh_port2proc_query(int proto, struct sh_sockaddr * saddr, int sport,
+ unsigned long * pid, char * user, size_t userlen)
+{
+ int n, hash;
+ struct xfile *xf;
+ struct in_addr * haddr = NULL;
+ struct in6_addr * haddr6 = NULL;
+ struct sock * s;
+ struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
+
+ *pid = 0;
+
+ for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) {
+
+ if (xf->xf_data == NULL)
+ continue;
+
+ /* Find the socket in sockhash[] that corresponds to it
+ */
+ hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
+ for (s = sockhash[hash]; s != NULL; s = s->next)
+ if ((void *)s->socket == xf->xf_data)
+ break;
+
+ if (!s)
+ continue;
+
+ if (s->proto != proto)
+ continue;
+
+ if (s->family != AF_INET && s->family != AF_INET6)
+ continue;
+
+ if (s->family == AF_INET &&
+ (sport != ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port)))
+ continue;
+
+ if (s->family == AF_INET6 &&
+ (sport != ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port)))
+ continue;
+
+ if (s->family == AF_INET)
+ haddr = &((struct sockaddr_in *)(&s->laddr))->sin_addr;
+ if (s->family == AF_INET6)
+ haddr6 = &((struct sockaddr_in6 *)(&s->laddr))->sin6_addr;
+
+
+ if ( (s->family == AF_INET &&
+ (haddr->s_addr == (saddr->sin).sin_addr.s_addr ||
+ sh_ipvx_isany(saddr) ||
+ inet_lnaof(*haddr) == INADDR_ANY))
+ ||
+ (s->family == AF_INET6 &&
+ (0 == memcmp(haddr6->s6_addr, &((saddr->sin6).sin6_addr.s6_addr), 16) ||
+ 0 == memcmp(haddr6->s6_addr, &(anyaddr.s6_addr), 16) ||
+ sh_ipvx_isany(saddr) ))
+ )
+ {
+ struct sock_store try;
+
+ *pid = xf->xf_pid;
+
+ try.pid = xf->xf_pid;
+ try.path = NULL;
+ try.user = NULL;
+ get_user_and_path (&try); /* Try to get info from /proc */
+
+ if (try.path == NULL)
+ {
+ extern char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
+ char * tmp = sh_unix_getUIDname (SH_ERR_ALL, xf->xf_uid, user, userlen);
+ if (!tmp)
+ sl_snprintf (user, userlen, "%ld", (unsigned long) xf->xf_uid);
+ return sh_util_strdup(getprocname(xf->xf_pid));
+ }
+ else
+ {
+ sl_strlcpy(user, try.user, userlen);
+ SH_FREE(try.user);
+ return try.path;
+ }
+ }
+ }
+ sl_strlcpy(user, "-", userlen);
+ return sh_util_strdup("-");
+}
+
+static void sockdel(struct sock * sock)
+{
+ if (sock)
+ {
+ if (sock->next)
+ sockdel(sock->next);
+ SH_FREE(sock);
+ }
+ return;
+}
+
+int sh_port2proc_prepare()
+{
+ int i;
+
+ if (xfiles)
+ {
+ SH_FREE(xfiles);
+ xfiles = NULL;
+ }
+
+ for (i = 0; i < HASHSIZE; ++i)
+ {
+ sockdel(sockhash[i]);
+ sockhash[i] = NULL;
+ }
+
+ /* Inet connections
+ */
+ gather_inet(IPPROTO_TCP);
+ gather_inet(IPPROTO_UDP);
+ gather_inet(IPPROTO_DIVERT);
+
+ getfiles();
+
+ return 0;
+}
+
+void sh_port2proc_finish()
+{
+ return;
+}
+
+#else /* !defined(__linux__) && !defined(__FreeBSD__) */
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_ipvx.h"
+
+char * sh_port2proc_query(int proto, struct sh_sockaddr * saddr, int sport,
+ unsigned long * pid, char * user, size_t userlen)
+{
+ (void) proto;
+ (void) saddr;
+ (void) sport;
+
+ *pid = 0;
+
+ sl_strlcpy(user, "-", userlen);
+ return sh_util_strdup("-");
+}
+
+int sh_port2proc_prepare()
+{
+ return 0;
+}
+
+void sh_port2proc_finish()
+{
+ return;
+}
+#endif
+
+#endif /* defined(SH_USE_PORTCHECK) */
diff --git a/src/sh_portcheck.c b/src/sh_portcheck.c
new file mode 100644
index 0000000..507f028
--- /dev/null
+++ b/src/sh_portcheck.c
@@ -0,0 +1,2186 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2006 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/***************************************************************************
+ *
+ * This file provides a module for samhain to check for open ports
+ * on the local machine.
+ *
+ */
+
+
+/* #define TEST_ONLY */
+#ifndef TEST_ONLY
+#include "config_xor.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define PORTCHK_VERSION "1.0"
+
+#if defined(TEST_ONLY) || (defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)))
+
+
+#define PORTMAP
+#ifdef HAVE_RPC_RPC_H
+#include <rpc/rpc.h>
+#ifdef HAVE_RPC_RPCENT_H
+#include <rpc/rpcent.h>
+#endif
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#endif
+#include <netdb.h>
+
+/*
+ * struct pmaplist {
+ * struct pmap pml_map;
+ * struct pmaplist *pml_next;
+ * };
+ */
+
+/* struct pmap {
+ * long unsigned pm_prog;
+ * long unsigned pm_vers;
+ * long unsigned pm_prot;
+ * long unsigned pm_port;
+ * };
+ */
+
+/* TIME_WAIT ? 60-240 seconds */
+
+#if !defined(TEST_ONLY)
+
+#define FIL__ _("sh_portcheck.c")
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_mem.h"
+#include "sh_calls.h"
+#include "sh_utils.h"
+#include "sh_modules.h"
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+#include "sh_pthread.h"
+#include "sh_ipvx.h"
+
+/* the size of an interface string
+ */
+#define SH_INTERFACE_SIZE SH_IP_BUF
+
+#define SH_PORT_NOT 0
+#define SH_PORT_REQ 1
+#define SH_PORT_OPT 2
+#define SH_PORT_IGN 3
+#define SH_PORT_BLACKLIST 4
+
+static char * sh_port_type2str (int type)
+{
+ if (type == 0) return _("not");
+ if (type == 1) return _("req");
+ if (type == 2) return _("opt");
+ if (type == 3) return _("ign");
+ if (type == 4) return _("blc");
+ return _("???");
+}
+
+#define SH_PORT_MISS 0
+#define SH_PORT_ISOK 1
+#define SH_PORT_UNKN 2
+
+#define SH_PORT_NOREPT 0
+#define SH_PORT_REPORT 1
+
+#define SH_PROTO_TCP 0
+#define SH_PROTO_UDP 1
+#define SH_PROTO_STR(a) (((a) == IPPROTO_TCP) ? _("tcp") : _("udp"))
+
+struct sh_portentry {
+ int port;
+ char interface[SH_INTERFACE_SIZE];
+ char * service;
+ char * error;
+ int flag; /* required or not */
+ int status; /* missing or not */
+ struct sh_portentry * next;
+};
+
+static struct sh_portentry * portlist_tcp = NULL;
+static struct sh_portentry * portlist_udp = NULL;
+
+
+#define SH_PORTCHK_INTERVAL 300
+
+static int sh_portchk_check_udp = 1;
+static int sh_portchk_active = 1;
+static int sh_portchk_interval = SH_PORTCHK_INTERVAL;
+
+static int sh_portchk_minport = -1;
+static int sh_portchk_maxport = -1;
+
+struct sh_port {
+ int port;
+ struct sh_sockaddr * paddr;
+ struct sh_port * next;
+};
+
+static struct sh_port * blacklist_tcp = NULL;
+static struct sh_port * blacklist_udp = NULL;
+
+SH_MUTEX_STATIC(mutex_port_check, PTHREAD_MUTEX_INITIALIZER);
+
+static int sh_portchk_severity = SH_ERR_SEVERE;
+
+extern char * sh_port2proc_query(int proto, struct sh_sockaddr * saddr, int sport,
+ unsigned long * pid, char * user, size_t userlen);
+extern int sh_port2proc_prepare();
+extern void sh_port2proc_finish();
+
+#endif
+
+/* Exported interface to add ignoreable ports as 'iface:portlist'
+ */
+static int sh_portchk_add_ignore (const char * str);
+
+/* Exported interface to add required ports as 'iface:portlist'
+ */
+static int sh_portchk_add_required (const char * str);
+
+/* Exported interface to add optional ports as 'iface:portlist'
+ */
+static int sh_portchk_add_optional (const char * str);
+
+/* Exported interface to add blacklisted ports as 'iface:portlist'
+ */
+static int sh_portchk_add_blacklist (const char * str);
+
+/* Exported interface to add an ethernet interface
+ */
+static int sh_portchk_add_interface (const char * str);
+
+/* verify whether port/interface is blacklisted (do not check)
+ */
+static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * haddr, int proto);
+
+#ifndef TEST_ONLY
+
+static int sh_portchk_set_interval (const char * c)
+{
+ int retval = 0;
+ long val;
+
+ SL_ENTER(_("sh_portchk_set_interval"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("port check interval"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ retval = -1;
+ }
+ else
+ {
+ sh_portchk_interval = (time_t) val;
+ }
+ SL_RETURN(retval, _("sh_portchk_set_interval"));
+}
+
+static int sh_portchk_set_port_minmax (const char * c, int * setthis)
+{
+ int retval = 0;
+ long val;
+
+ SL_ENTER(_("sh_portchk_set_port_minmax"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val < 0 || val > 65535)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("port check port minmax"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ retval = -1;
+ }
+ else
+ {
+ *setthis = (int) val;
+ }
+ SL_RETURN(retval, _("sh_portchk_set_port_minmax"));
+}
+
+
+static int sh_portchk_set_minport (const char * str)
+{
+ return sh_portchk_set_port_minmax (str, &sh_portchk_minport);
+}
+
+static int sh_portchk_set_maxport (const char * str)
+{
+ return sh_portchk_set_port_minmax (str, &sh_portchk_maxport);
+}
+
+static int sh_portchk_set_active (const char * str)
+{
+ return sh_util_flagval(str, &sh_portchk_active);
+}
+
+static int sh_portchk_set_udp (const char * str)
+{
+ return sh_util_flagval(str, &sh_portchk_check_udp);
+}
+
+static int sh_portchk_set_severity (const char * str)
+{
+ char tmp[32];
+ tmp[0] = '='; tmp[1] = '\0';
+ sl_strlcat (tmp, str, 32);
+ return sh_error_set_level (tmp, &sh_portchk_severity);
+}
+
+sh_rconf sh_portchk_table[] = {
+ {
+ N_("severityportcheck"),
+ sh_portchk_set_severity,
+ },
+ {
+ N_("portcheckrequired"),
+ sh_portchk_add_required,
+ },
+ {
+ N_("portcheckoptional"),
+ sh_portchk_add_optional,
+ },
+ {
+ N_("portcheckignore"),
+ sh_portchk_add_ignore,
+ },
+ {
+ N_("portcheckskip"),
+ sh_portchk_add_blacklist,
+ },
+ {
+ N_("portcheckactive"),
+ sh_portchk_set_active,
+ },
+ {
+ N_("portcheckinterface"),
+ sh_portchk_add_interface,
+ },
+ {
+ N_("portcheckinterval"),
+ sh_portchk_set_interval,
+ },
+ {
+ N_("portcheckminport"),
+ sh_portchk_set_minport,
+ },
+ {
+ N_("portcheckmaxport"),
+ sh_portchk_set_maxport,
+ },
+ {
+ N_("portcheckudp"),
+ sh_portchk_set_udp,
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+#endif
+
+/* Interface to initialize port check
+ */
+int sh_portchk_init (struct mod_type * arg);
+
+/* Interface to reset port check
+ */
+int sh_portchk_reset (void);
+
+/* Interface to run port check
+ */
+int sh_portchk_check (void);
+
+
+static char * check_services (int port, int proto);
+
+#ifdef TEST_ONLY
+
+static int portchk_debug = 0;
+#define SH_ALLOC malloc
+#define SH_FREE free
+#define sh_util_strdup strdup
+#define sl_strlcpy strncpy
+#define _(a) a
+
+#else
+
+static int portchk_debug = 0;
+
+#endif
+
+#ifdef HAVE_RPC_RPC_H
+static char * sh_getrpcbynumber (int number, char * buf, size_t len)
+{
+ FILE * fp;
+
+ if (NULL != (fp = fopen(_("/etc/rpc"), "r")))
+ {
+ sh_string * s = sh_string_new(0);
+ while (0 < sh_string_read(s, fp, 1024))
+ {
+ char * p = sh_string_str(s);
+ while (*p && (*p == ' ' || *p == '\t')) ++p; /* skip whitespace */
+ if (*p == '\0' || *p == '#')
+ continue; /* skip comment */
+ else
+ {
+ size_t lengths[3];
+ unsigned int fields = 3;
+ char * q = sh_string_str(s);
+ char ** splits = split_array_ws(q, &fields, lengths);
+
+ if (fields >= 2)
+ {
+ int n = atoi(splits[1]);
+ if (n == number)
+ {
+ sl_strlcpy(buf, splits[0], len);
+ SH_FREE(splits);
+ sh_string_destroy(&s);
+ sl_fclose(FIL__, __LINE__, fp);
+ return buf;
+ }
+ }
+ SH_FREE(splits);
+ }
+ }
+ sh_string_destroy(&s);
+ sl_fclose(FIL__, __LINE__, fp);
+ }
+ return NULL;
+}
+#endif
+
+static char * sh_getservbyport (int port, const char * proto_in, char * buf, size_t len)
+{
+ FILE * fp;
+ char proto[8];
+
+ sl_strlcpy(proto, proto_in, sizeof(proto));
+
+ if (NULL != (fp = fopen(_("/etc/services"), "r")))
+ {
+ sh_string * s = sh_string_new(0);
+ while (0 < sh_string_read(s, fp, 1024))
+ {
+ char * p = sh_string_str(s);
+ while (*p && (*p == ' ' || *p == '\t')) ++p; /* skip whitespace */
+ if (*p == '\0' || *p == '#')
+ continue; /* skip comment */
+ else
+ {
+ size_t lengths[3];
+ unsigned int fields = 3;
+ char * q = sh_string_str(s);
+ char ** splits = split_array_ws(q, &fields, lengths);
+
+ if (fields >= 2)
+ {
+ char * end;
+ long n = strtol(splits[1], &end, 10);
+ if (n == port && end && (*end == '/' || *end == ','))
+ {
+ ++end;
+ if (0 == strcmp(end, proto))
+ {
+ sl_strlcpy(buf, splits[0], len);
+ SH_FREE(splits);
+ sh_string_destroy(&s);
+ sl_fclose(FIL__, __LINE__, fp);
+ return buf;
+ }
+ }
+ }
+ SH_FREE(splits);
+ }
+ }
+ sh_string_destroy(&s);
+ sl_fclose(FIL__, __LINE__, fp);
+ }
+ return NULL;
+}
+
+static void sh_portchk_add_to_list (int proto,
+ int port, struct sh_sockaddr * paddr,
+ char * service,
+ int flag, int status)
+{
+ struct sh_portentry * new = SH_ALLOC (sizeof(struct sh_portentry));
+
+ new->port = port;
+ sh_ipvx_ntoa(new->interface, SH_INTERFACE_SIZE, paddr);
+ new->status = status;
+ new->flag = flag;
+
+ new->error = NULL;
+
+ if (portchk_debug)
+ fprintf(stderr, _("add to list: port %d/%s %d %d (%s) %s\n"),
+ port, SH_PROTO_STR(proto), flag, status, service ? service : _("undef"),
+ new->interface);
+
+ if (service)
+ new->service = sh_util_strdup (service);
+ else
+ new->service = NULL;
+ if (proto == IPPROTO_TCP)
+ {
+ new->next = portlist_tcp;
+ portlist_tcp = new;
+ }
+ else
+ {
+ new->next = portlist_udp;
+ portlist_udp = new;
+ }
+ return;
+}
+
+/* Reset the list by setting all entries to UNKN.
+ * In the next cycle we will check, and set found ports to ISOK.
+ * Thereafter, we check for entries that are still UNKN.
+ */
+static void sh_portchk_reset_lists (void)
+{
+ struct sh_portentry * portlist;
+
+ portlist = portlist_tcp;
+ while (portlist)
+ {
+ if (portlist->status != SH_PORT_MISS)
+ portlist->status = SH_PORT_UNKN;
+ portlist = portlist->next;
+ }
+ portlist = portlist_udp;
+ while (portlist)
+ {
+ if (portlist->status != SH_PORT_MISS)
+ portlist->status = SH_PORT_UNKN;
+ portlist = portlist->next;
+ }
+ return;
+}
+
+static struct sh_portentry * sh_portchk_kill_list (struct sh_portentry * head)
+{
+ if (head)
+ {
+ if (head->next)
+ sh_portchk_kill_list (head->next);
+
+ if (head->service)
+ SH_FREE(head->service);
+ SH_FREE(head);
+ }
+ return NULL;
+}
+
+static struct sh_port * sh_portchk_kill_blacklist (struct sh_port * head)
+{
+ if (head)
+ {
+ if (head->next)
+ sh_portchk_kill_blacklist (head->next);
+
+ SH_FREE(head->paddr);
+ SH_FREE(head);
+ }
+ return NULL;
+}
+
+/* These variables are not used anywhere. They only exist
+ * to assign &pre, &ptr to them, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+void * sh_dummy_531_pre = NULL;
+void * sh_dummy_532_ptr = NULL;
+
+/* check the list of open ports for any that are marked as UNKN
+ */
+static void sh_portchk_check_list (struct sh_portentry ** head,
+ int proto, int report)
+{
+ struct sh_portentry * ptr = *head;
+ struct sh_portentry * pre = *head;
+ char errbuf[256];
+
+ /* Take the address to keep gcc from putting them into registers.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_531_pre = (void*) &pre;
+ sh_dummy_532_ptr = (void*) &ptr;
+
+ while (ptr)
+ {
+ if (portchk_debug && report)
+ fprintf(stderr, _("check list: port %d/%s %d %d\n"),
+ ptr->port, SH_PROTO_STR(proto), ptr->flag, ptr->status);
+
+ if (ptr->status == SH_PORT_UNKN)
+ {
+ /* Don't report missing ports that are marked as optional
+ */
+ if (ptr->flag != SH_PORT_OPT && ptr->flag != SH_PORT_IGN)
+ {
+ snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
+ ptr->interface, ptr->port, SH_PROTO_STR(proto),
+ ptr->service ? ptr->service : check_services(ptr->port, proto));
+#ifdef TEST_ONLY
+ if (report == SH_PORT_REPORT)
+ fprintf(stderr, _("%s\n"), errbuf);
+#else
+ if (report == SH_PORT_REPORT)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
+ MSG_PORT_MISS, errbuf);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+#endif
+ }
+
+ ptr->status = SH_PORT_MISS;
+
+ if ((ptr->flag != SH_PORT_REQ) && (ptr->flag != SH_PORT_OPT) && (ptr->flag != SH_PORT_IGN))
+ {
+ if (portchk_debug && report)
+ fprintf(stderr, _("removing: port %d/%s %d %d\n"),
+ ptr->port, SH_PROTO_STR(proto), ptr->flag, ptr->status);
+
+ if (ptr == *head)
+ {
+ *head = ptr->next;
+ if (ptr->service)
+ SH_FREE(ptr->service);
+ SH_FREE(ptr);
+ ptr = *head;
+ pre = *head;
+ continue;
+ }
+ else if (ptr->next == NULL)
+ {
+ pre->next = NULL;
+ if (ptr->service)
+ SH_FREE(ptr->service);
+ SH_FREE(ptr);
+ return;
+ }
+ else
+ {
+ pre->next = ptr->next;
+ if (ptr->service)
+ SH_FREE(ptr->service);
+ SH_FREE(ptr);
+ ptr = pre->next;
+ continue;
+ }
+ }
+ }
+ pre = ptr;
+ ptr = ptr->next;
+ }
+
+ sh_dummy_532_ptr = NULL;
+ sh_dummy_531_pre = NULL;
+
+ return;
+}
+
+
+static struct sh_portentry * sh_portchk_get_from_list (int proto, int port,
+ struct sh_sockaddr * paddr, char * service)
+{
+ struct sh_portentry * portlist;
+ char str_addr[SH_IP_BUF];
+
+ if (proto == IPPROTO_TCP)
+ portlist = portlist_tcp;
+ else
+ portlist = portlist_udp;
+
+ sh_ipvx_ntoa(str_addr, sizeof(str_addr), paddr);
+
+ if (service)
+ {
+ while (portlist)
+ {
+ if (portlist->service &&
+ 0 == strcmp(service, portlist->service) &&
+ ( 0 == strcmp(portlist->interface, str_addr) ||
+ sh_ipvx_isany(paddr) ))
+ return portlist;
+ portlist = portlist->next;
+ }
+ }
+ else
+ {
+ while (portlist)
+ {
+ if (port == portlist->port &&
+ (0 == strcmp(portlist->interface, str_addr) ||
+ sh_ipvx_isany(paddr) ))
+ return portlist;
+ portlist = portlist->next;
+ }
+ }
+ return NULL;
+}
+
+
+static void sh_portchk_cmp_to_list (int proto, int port,
+ struct sh_sockaddr * paddr, char * service)
+{
+ struct sh_portentry * portent;
+ char errbuf[256];
+
+
+ portent = sh_portchk_get_from_list (proto, port, paddr, service);
+
+ if (service)
+ {
+ if (!portent)
+ {
+ char * path;
+ unsigned long qpid;
+ char user[USER_MAX];
+ char saddr[SH_IP_BUF];
+
+ sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
+
+ snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
+ saddr, port, SH_PROTO_STR(proto), service);
+
+ if (portchk_debug)
+ fprintf(stderr, _("cmp_to_list: open port: %s:%d/%s (%s)\n"),
+ saddr, port, SH_PROTO_STR(proto), service);
+
+#ifndef TEST_ONLY
+ path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
+ MSG_PORT_NEW, errbuf, path, qpid, user);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(path);
+#endif
+ /*
+ * was not there, thus it is not in 'required' or 'optional' list
+ */
+ sh_portchk_add_to_list (proto, port, paddr, service, SH_PORT_NOT, SH_PORT_ISOK);
+ }
+ else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
+ {
+ char * path;
+ unsigned long qpid;
+ char user[USER_MAX];
+ char saddr[SH_IP_BUF];
+
+ sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
+
+ snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s), was %d/%s"),
+ saddr, port, SH_PROTO_STR(proto), service, portent->port, SH_PROTO_STR(proto));
+#ifdef TEST_ONLY
+ fprintf(stderr, _("service: %s\n"), errbuf);
+#else
+ path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
+ MSG_PORT_RESTART, errbuf, path, qpid, user);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(path);
+#endif
+
+ portent->status = SH_PORT_ISOK;
+ }
+ else if (port != portent->port && (-1) != portent->port)
+ {
+ char * path;
+ unsigned long qpid;
+ char user[USER_MAX];
+ char saddr[SH_IP_BUF];
+
+ sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
+
+ snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s), was %d/%s"),
+ saddr, port, SH_PROTO_STR(proto), service, portent->port, SH_PROTO_STR(proto));
+#ifdef TEST_ONLY
+ fprintf(stderr, _("service: %s\n"), errbuf);
+#else
+ path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
+ MSG_PORT_NEWPORT, errbuf, path, qpid, user);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(path);
+#endif
+ portent->port = port;
+ portent->status = SH_PORT_ISOK;
+ }
+ else
+ {
+ portent->status = SH_PORT_ISOK;
+ }
+ }
+ else
+ {
+ if (!portent)
+ {
+ char * path;
+ unsigned long qpid;
+ char user[USER_MAX];
+ char saddr[SH_IP_BUF];
+
+ if (portchk_debug)
+ fprintf(stderr, _("call to sh_ipvx_ntoa (port %d)\n"), port);
+
+ sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
+
+ snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
+ saddr, port, SH_PROTO_STR(proto), check_services(port, proto));
+
+ if (portchk_debug)
+ fprintf(stderr, _("cmp_to_list: open port: %s:%d/%s (%s) check_services\n"),
+ saddr, port, SH_PROTO_STR(proto), check_services(port, proto));
+
+#ifndef TEST_ONLY
+ path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
+ MSG_PORT_NEW, errbuf, path, qpid, user);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(path);
+#endif
+
+ /* was not there, thus it is not in 'required' or 'optional' list
+ */
+ sh_portchk_add_to_list (proto, port, paddr, service, SH_PORT_NOT, SH_PORT_ISOK);
+ }
+ else if (portent->status == SH_PORT_MISS && portent->flag != SH_PORT_IGN)
+ {
+ char * path;
+ unsigned long qpid;
+ char user[USER_MAX];
+ char saddr[SH_IP_BUF];
+
+ sh_ipvx_ntoa(saddr, sizeof(saddr), paddr);
+
+ snprintf (errbuf, sizeof(errbuf), _("port: %s:%d/%s (%s)"),
+ saddr, port, SH_PROTO_STR(proto), check_services(port, proto));
+#ifdef TEST_ONLY
+ fprintf(stderr, _("port : %s\n"), errbuf);
+#else
+ path = sh_port2proc_query(proto, paddr, port, &qpid, user, sizeof(user));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_portchk_severity, FIL__, __LINE__, 0,
+ MSG_PORT_RESTART, errbuf, path, qpid, user);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(path);
+#endif
+
+ portent->status = SH_PORT_ISOK;
+ }
+ else
+ {
+ portent->status = SH_PORT_ISOK;
+ }
+ }
+
+ return;
+}
+
+
+/* Returns a static buffer containing the name of the service
+ * running on port <port> (from /etc/services)
+ * Returns NULL on failure
+ */
+static char * check_services (int port, int proto)
+{
+ static char buf[256];
+ char * service = sh_getservbyport(port, SH_PROTO_STR(proto), buf, sizeof(buf));
+
+ if (!service)
+ {
+ snprintf (buf, sizeof(buf), "%s",_("unknown"));
+ }
+ return buf;
+}
+
+/* Returns a static buffer containing the name of the service
+ * running on port <port> at <address> (from portmap daemon)
+ * Returns NULL on failure
+ */
+static char * check_rpc_list (int port, struct sockaddr_in * address,
+ unsigned long prot)
+{
+#if defined(HAVE_RPC_RPC_H) && defined(HAVE_PMAP_GETMAPS)
+ struct pmaplist * head;
+ char *r;
+ static char buf[256];
+
+ head = pmap_getmaps(address);
+
+ if (head)
+ {
+ do /* while (head != NULL) */
+ {
+ if ((head->pml_map.pm_prot == prot) &&
+ (port == (int)head->pml_map.pm_port))
+ {
+ r = sh_getrpcbynumber((int)head->pml_map.pm_prog,
+ buf, sizeof(buf));
+ if (r)
+ {
+ return buf;
+ }
+ else
+ {
+ snprintf (buf, sizeof(buf), "RPC_%lu",
+ (unsigned long)head->pml_map.pm_prog);
+ return buf;
+ }
+ }
+ head = head->pml_next;
+ }
+ while (head != NULL);
+ }
+#else
+ (void) port;
+ (void) address;
+ (void) prot;
+#endif
+ return NULL;
+}
+
+static int check_port_udp_internal (int fd, int port, struct sh_sockaddr * paddr)
+{
+ int retval;
+ char * p = NULL;
+ char buf[8];
+#ifndef TEST_ONLY
+ char errmsg[256];
+ int nerr;
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+ char ipbuf[SH_IP_BUF];
+
+ sh_ipvx_set_port(paddr, port);
+
+ do {
+ retval = connect(fd, sh_ipvx_sockaddr_cast(paddr), SH_SSP_LEN(paddr));
+ } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
+
+ if (retval == -1)
+ {
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("connect"));
+#else
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+
+ nerr = errno;
+ sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/udp on %15s: %s"),
+ port, ipbuf, sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
+ errmsg, _("connect"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ }
+ else
+ {
+ do {
+ retval = send (fd, buf, 0, 0);
+ } while (retval < 0 && errno == EINTR);
+
+ if (retval == -1 && errno == ECONNREFUSED)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ if (portchk_debug)
+ fprintf(stderr, _("check port_udp: %5d/udp on %15s established/time_wait\n"),
+ port, ipbuf);
+ }
+ else
+ {
+ /* Only the second send() may catch the error
+ */
+ do {
+ retval = send (fd, buf, 0, 0);
+ } while (retval < 0 && errno == EINTR);
+
+ if (retval == -1 && errno == ECONNREFUSED)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ if (portchk_debug)
+ fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"),
+ port, ipbuf);
+ }
+ else if (retval != -1)
+ {
+ /* Try to get service name from portmap
+ */
+ if (paddr->ss_family == AF_INET)
+ {
+ p = check_rpc_list (port,
+ (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr),
+ IPPROTO_UDP);
+ }
+
+ sh_portchk_cmp_to_list (IPPROTO_UDP, port, paddr, p ? p : NULL);
+
+ /* If not an RPC service, try to get name from /etc/services
+ */
+ if (!p)
+ p = check_services(port, IPPROTO_UDP);
+
+ if (portchk_debug)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ fprintf(stderr, _("check port_udp: %5d/udp on %15s open %s\n"),
+ port, ipbuf, p);
+ }
+
+ }
+ else
+ {
+ if (portchk_debug)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ fprintf(stderr, _("check port_udp: %5d/udp on %15s ERRNO %d\n"),
+ port, ipbuf, errno);
+ }
+ }
+ }
+ }
+ sl_close_fd (FIL__, __LINE__, fd);
+ return 0;
+}
+
+static int check_port_tcp_internal (int fd, int port, struct sh_sockaddr * paddr)
+{
+ int retval;
+ int flags;
+ char * p = NULL;
+#ifndef TEST_ONLY
+ char errmsg[256];
+ int nerr;
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+ char ipbuf[SH_IP_BUF];
+
+ sh_ipvx_set_port(paddr, port);
+
+ do {
+ retval = connect(fd, sh_ipvx_sockaddr_cast(paddr), SH_SSP_LEN(paddr));
+ } while (retval < 0 && (errno == EINTR || errno == EINPROGRESS));
+
+ if (retval == -1 && errno == ECONNREFUSED)
+ {
+ if (portchk_debug)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ fprintf(stderr, _("check port_tcp: %5d on %15s closed\n"),
+ port, ipbuf);
+ }
+ }
+ else if (retval == -1)
+ {
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("connect"));
+#else
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ nerr = errno;
+ sl_snprintf(errmsg, sizeof(errmsg), _("check port: %5d/tcp on %15s: %s"),
+ port, ipbuf, sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN,
+ errmsg, _("connect"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ }
+ else
+ {
+ /* Try to get service name from portmap
+ */
+ if (paddr->ss_family == AF_INET)
+ {
+ p = check_rpc_list (port,
+ (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr),
+ IPPROTO_TCP);
+ }
+
+ sh_portchk_cmp_to_list (IPPROTO_TCP, port, paddr, p ? p : NULL);
+
+ /* If not an RPC service, try to get name from /etc/services
+ */
+ if (!p)
+ p = check_services(port, IPPROTO_TCP);
+
+ if (portchk_debug)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr);
+ fprintf(stderr, _("check port_tcp: %5d on %15s open %s\n"),
+ port, ipbuf, p);
+ }
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+ /* prepare to close connection gracefully
+ */
+ if (port == 22) /* ssh */
+ {
+ flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
+ retval = write (fd, _("SSH-2.0-Foobar"), 14);
+ if (retval > 0) retval = write (fd, "\r\n", 2);
+ }
+ else if (port == 25) /* smtp */
+ {
+ flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
+ retval = write (fd, _("QUIT"), 4);
+ if (retval > 0) retval = write (fd, "\r\n", 2);
+ }
+ else if (port == 79) /* finger */
+ {
+ flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
+ retval = write (fd, "\r\n", 2);
+ }
+ else if (port == 110) /* pop3 */
+ {
+ flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
+ retval = write (fd, _("QUIT"), 4);
+ if (retval > 0) retval = write (fd, "\r\n", 2);
+ }
+ else if (port == 143) /* imap */
+ {
+ flags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, flags | O_NONBLOCK);
+ retval = write (fd, _("A01 LOGOUT"), 10);
+ if (retval > 0) retval = write (fd, "\r\n", 2);
+ }
+
+ if (portchk_debug && retval < 0)
+ fprintf(stderr, _("check port: error writing to port %5d\n"),
+ port);
+ }
+ sl_close_fd (FIL__, __LINE__, fd);
+ return 0;
+}
+
+/* typedef uint32_t in_addr_t;
+ * struct in_addr
+ * {
+ * in_addr_t s_addr;
+ * };
+ */
+
+#define SH_IFACE_MAX 16
+
+struct portchk_interfaces {
+ struct sh_sockaddr iface[SH_IFACE_MAX];
+ int used;
+};
+
+static struct portchk_interfaces iface_list;
+static int iface_initialized = 0;
+
+#ifdef TEST_ONLY
+static char * portchk_hostname = NULL;
+#else
+static char * portchk_hostname = sh.host.name;
+#endif
+
+static int sh_portchk_init_internal (void)
+{
+ volatile int i, j; /* might be clobbered by ‘longjmp’ or ‘vfork’*/
+ char errbuf[256];
+#if defined(USE_IPVX)
+ struct addrinfo hints;
+ struct addrinfo *res;
+#else
+ struct hostent * hent;
+#endif
+ char ipbuf[SH_IP_BUF];
+
+ if (portchk_debug)
+ fprintf(stderr, _("checking ports on: %s\n"), portchk_hostname ? portchk_hostname : _("NULL"));
+
+ if (!portchk_hostname)
+ return -1;
+
+ if (sh_portchk_active == S_FALSE)
+ return -1;
+
+ SH_MUTEX_LOCK(mutex_port_check);
+ if (iface_initialized == 0)
+ {
+ iface_list.used = 0;
+ iface_initialized = 1;
+ }
+
+#if !defined(USE_IPVX)
+ SH_MUTEX_LOCK(mutex_resolv);
+ hent = sh_gethostbyname(portchk_hostname);
+ i = 0;
+ while (hent && hent->h_addr_list[i] && (iface_list.used < SH_IFACE_MAX))
+ {
+ struct sockaddr_in sin;
+ struct sh_sockaddr iface_tmp;
+
+ memcpy(&(sin.sin_addr.s_addr), hent->h_addr_list[i], sizeof(in_addr_t));
+ sh_ipvx_save(&iface_tmp, AF_INET, (struct sockaddr *)&sin);
+
+ for (j = 0; j < iface_list.used; ++j)
+ {
+ if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list.iface[j])))
+ {
+ goto next_iface;
+ }
+ }
+
+ sh_ipvx_save(&(iface_list.iface[iface_list.used]),
+ AF_INET, (struct sockaddr *)&sin);
+
+ if (portchk_debug)
+ {
+ char buf[256];
+ sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list.iface[iface_list.used]));
+ fprintf(stderr, _("added interface[%d]: %s\n"), i, buf);
+ }
+ ++iface_list.used;
+
+ next_iface:
+ ++i;
+ }
+ SH_MUTEX_UNLOCK(mutex_resolv);
+#else
+ memset(&hints, '\0', sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ if (0 == getaddrinfo(portchk_hostname, NULL, &hints, &res))
+ {
+ struct addrinfo *p = res;
+ struct sh_sockaddr iface_tmp;
+
+ while ((p != NULL) && (iface_list.used < SH_IFACE_MAX))
+ {
+ sh_ipvx_save(&iface_tmp, p->ai_family, p->ai_addr);
+
+ for (j = 0; j < iface_list.used; ++j)
+ {
+ if (portchk_debug)
+ {
+ char buf1[256], buf2[256];
+ sh_ipvx_ntoa(buf1, sizeof(buf1), &(iface_list.iface[j]));
+ sh_ipvx_ntoa(buf2, sizeof(buf2), &iface_tmp);
+ fprintf(stderr, _("check interface[%d]: %s vs %s\n"), j, buf1, buf2);
+ }
+ if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list.iface[j])))
+ {
+ if (portchk_debug)
+ fprintf(stderr, _("skipping interface[%d]\n"), j);
+ goto next_iface;
+ }
+ }
+ sh_ipvx_save(&(iface_list.iface[iface_list.used]),
+ p->ai_family, p->ai_addr);
+
+ if (portchk_debug)
+ {
+ char buf[256];
+ sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list.iface[iface_list.used]));
+ fprintf(stderr, _("added interface[%d]: %s\n"), iface_list.used, buf);
+ }
+
+ ++iface_list.used;
+
+ next_iface:
+ p = p->ai_next;
+ }
+ freeaddrinfo(res);
+ }
+#endif
+
+ for (i = 0; i < iface_list.used; ++i)
+ {
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &(iface_list.iface[i]));
+ sl_snprintf(errbuf, sizeof(errbuf), _("added interface: %s"), ipbuf);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf, _("sh_portchk_init"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_MUTEX_UNLOCK(mutex_port_check);
+
+ return 0;
+}
+
+int sh_portchk_init (struct mod_type * arg)
+{
+#ifndef HAVE_PTHREAD
+ (void) arg;
+#endif
+
+ if (sh_portchk_active == S_FALSE)
+ return SH_MOD_FAILED;
+ if (!portchk_hostname)
+ return SH_MOD_FAILED;
+
+#ifdef HAVE_PTHREAD
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ return SH_MOD_THREAD;
+ else
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ return SH_MOD_THREAD;
+ }
+#endif
+ return sh_portchk_init_internal();
+}
+
+
+
+#if !defined(TEST_ONLY)
+int sh_portchk_reconf (void)
+{
+ SH_MUTEX_LOCK(mutex_port_check);
+ iface_initialized = 0;
+ sh_portchk_active = 1;
+ sh_portchk_check_udp = 1;
+ sh_portchk_interval = SH_PORTCHK_INTERVAL;
+
+ sh_portchk_minport = -1;
+ sh_portchk_maxport = -1;
+
+ portlist_udp = sh_portchk_kill_list (portlist_udp);
+ portlist_tcp = sh_portchk_kill_list (portlist_tcp);
+
+ blacklist_udp = sh_portchk_kill_blacklist (blacklist_udp);
+ blacklist_tcp = sh_portchk_kill_blacklist (blacklist_tcp);
+ sh_port2proc_finish();
+
+ SH_MUTEX_UNLOCK(mutex_port_check);
+ return 0;
+}
+
+int sh_portchk_cleanup (void)
+{
+ return sh_portchk_reconf ();
+}
+
+int sh_portchk_timer (time_t tcurrent)
+{
+ static time_t lastcheck = 0;
+
+ SL_ENTER(_("sh_portchk_timer"));
+ if ((time_t) (tcurrent - lastcheck) >= sh_portchk_interval)
+ {
+ lastcheck = tcurrent;
+ SL_RETURN((-1), _("sh_portchk_timer"));
+ }
+ SL_RETURN(0, _("sh_portchk_timer"));
+}
+#endif
+
+static int check_port_generic (int port, int domain, int type, int protocol)
+{
+ volatile int i = 0;
+ int sock = -1;
+ int flag = 1; /* non-zero to enable an option */
+ struct sh_sockaddr paddr;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ /* Check all interfaces for this host
+ */
+ while (i < iface_list.used)
+ {
+ memcpy(&paddr, &(iface_list.iface[i]), sizeof(paddr));
+
+ if (paddr.ss_family != domain)
+ {
+ ++i;
+ continue;
+ }
+
+ if (0 != sh_portchk_is_blacklisted(port, &paddr, protocol))
+ {
+ ++i;
+ continue;
+ }
+
+ if ((sock = socket(paddr.ss_family, type, protocol)) < 0 )
+ {
+ ++i;
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("socket"));
+#else
+
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT 0
+#endif
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT 0
+#endif
+ if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+#endif
+ continue;
+ }
+ if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &flag, sizeof(flag)) < 0 )
+ {
+ ++i;
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("setsockopt"));
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ continue;
+ }
+
+
+ if (protocol == IPPROTO_TCP)
+ check_port_tcp_internal(sock, port, &paddr);
+ else
+ check_port_udp_internal(sock, port, &paddr);
+
+ ++i;
+ }
+
+ return 0;
+}
+
+
+
+static int check_port_udp (int port, int domain)
+{
+ return check_port_generic(port, domain, SOCK_DGRAM, IPPROTO_UDP);
+}
+
+static int check_port_tcp (int port, int domain)
+{
+ return check_port_generic(port, domain, SOCK_STREAM, IPPROTO_TCP);
+}
+
+
+static int sh_portchk_scan_ports_generic (int min_port, int max_port_arg,
+ int domain, int type, int protocol)
+{
+ /*
+ int min_port = 1024;
+ int max_port = 65535;
+ */
+
+ volatile int port; /* might be clobbered by ‘longjmp’ or ‘vfork’*/
+ volatile int max_port = max_port_arg;
+ int retval;
+ int sock = -1;
+#if 0
+ int flag = 1; /* non-zero to enable an option */
+#endif
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ int addrlen4 = sizeof(addr4);
+ int addrlen6 = sizeof(addr6);
+
+ struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
+
+ char errbuf[SH_ERRBUF_SIZE];
+
+ if (min_port == -1)
+ min_port = 0;
+ if (max_port == -1)
+ max_port = 65535;
+
+ if (portchk_debug)
+ fprintf(stderr, _("scan_ports_generic %d-%d %s %s\n"),
+ min_port, max_port, (domain == AF_INET6) ? _("AF_INET6") : _("AF_INET"),
+ (protocol == IPPROTO_TCP) ? _("tcp") : _("udp"));
+
+ for (port = min_port; port <= max_port; ++port)
+ {
+ if ((sock = socket(domain, type, protocol)) < 0 )
+ {
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("socket"));
+#else
+#ifndef EPROTONOSUPPORT
+#define EPROTONOSUPPORT 0
+#endif
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT 0
+#endif
+ if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message(errno, errbuf, sizeof(errbuf)), _("socket"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+#endif
+ continue;
+ }
+
+#if 0
+ if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &flag, sizeof(flag)) < 0 )
+ {
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("setsockopt"));
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message(errno, errbuf, sizeof(errbuf)),_("setsockopt"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ continue;
+ }
+#endif
+
+ if (domain == AF_INET)
+ {
+ addr4.sin_family = AF_INET;
+ addr4.sin_port = htons(port);
+ addr4.sin_addr.s_addr = INADDR_ANY;
+ retval = bind (sock, (struct sockaddr *) &addr4, addrlen4);
+ }
+ else
+ {
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(port);
+ memcpy(&(addr6.sin6_addr.s6_addr), &anyaddr, sizeof(anyaddr));
+ retval = bind (sock, (struct sockaddr *) &addr6, addrlen6);
+ }
+
+ if (retval == 0)
+ {
+ /* we can bind the port, thus it is unused
+ */
+ sl_close_fd (FIL__, __LINE__, sock);
+ }
+ else
+ {
+ if (errno == EINVAL || errno == EADDRINUSE)
+ {
+ /* try to connect to the port
+ */
+ if (protocol == IPPROTO_TCP)
+ check_port_tcp(port, domain);
+ else
+ check_port_udp(port, domain);
+ }
+ else
+ {
+#ifdef TEST_ONLY
+ if (portchk_debug)
+ perror(_("bind"));
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message(errno, errbuf, sizeof(errbuf)), _("bind"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ }
+ sl_close_fd (FIL__, __LINE__, sock);
+ }
+ }
+ return 0;
+}
+
+static int sh_portchk_scan_ports_tcp (int min_port, int max_port)
+{
+#if defined(USE_IPVX)
+ sh_portchk_scan_ports_generic (min_port, max_port, AF_INET6,
+ SOCK_STREAM, IPPROTO_TCP);
+#endif
+ return sh_portchk_scan_ports_generic (min_port, max_port, AF_INET,
+ SOCK_STREAM, IPPROTO_TCP);
+}
+
+static int sh_portchk_scan_ports_udp (int min_port, int max_port)
+{
+#if defined(USE_IPVX)
+ sh_portchk_scan_ports_generic (min_port, max_port, AF_INET6,
+ SOCK_DGRAM, IPPROTO_UDP);
+#endif
+ return sh_portchk_scan_ports_generic (min_port, max_port, AF_INET,
+ SOCK_DGRAM, IPPROTO_UDP);
+}
+
+/* Subroutine to add an interface
+ */
+void * sh_dummy_1564_str = NULL; /* fix clobbered by.. warning */
+
+static int sh_portchk_add_interface (const char * str)
+{
+ struct sh_sockaddr saddr;
+ char errbuf[256];
+ char buf[64];
+
+ sh_dummy_1564_str = (void*) &str;
+
+ if (iface_initialized == 0)
+ {
+ iface_list.used = 0;
+ iface_initialized = 1;
+ }
+
+ do {
+
+ while (*str == ',' || *str == ' ' || *str == '\t') ++str;
+
+ if (*str)
+ {
+ char ipbuf[SH_IP_BUF];
+ unsigned int i = 0;
+ while (*str && i < (sizeof(buf)-1) &&
+ *str != ',' && *str != ' ' && *str != '\t')
+ {
+ buf[i] = *str; ++str; ++i;
+ }
+ buf[i] = '\0';
+
+ if (0 == sh_ipvx_aton(buf, &saddr))
+ return -1;
+
+ if (iface_list.used == SH_IFACE_MAX)
+ return -1;
+
+ sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &saddr);
+ sl_snprintf(errbuf, sizeof(errbuf), _("interface: %s"), ipbuf);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf, _("sh_portchk_add_interface"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ memcpy (&(iface_list.iface[iface_list.used]), &(saddr), sizeof(saddr));
+ ++iface_list.used;
+ }
+ } while (*str);
+
+ sh_dummy_1564_str = NULL;
+ return 0;
+}
+
+/* verify whether port/interface is blacklisted (do not check)
+ */
+static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * saddr,
+ int proto)
+{
+ struct sh_port * head;
+
+ if (proto == IPPROTO_TCP)
+ head = blacklist_tcp;
+ else
+ head = blacklist_udp;
+
+ while (head)
+ {
+ if (head->port == port)
+ {
+ if (sh_ipvx_isany(head->paddr) ||
+ 0 == sh_ipvx_cmp(head->paddr, saddr))
+ return 1;
+ else
+ return 0;
+ }
+ head = head->next;
+ }
+ return 0;
+}
+
+
+static int sh_portchk_blacklist(int port, struct sh_sockaddr * saddr, int proto)
+{
+ struct sh_port * black;
+ struct sh_port * head;
+
+ if (proto == IPPROTO_TCP)
+ head = blacklist_tcp;
+ else
+ head = blacklist_udp;
+
+ black = head;
+
+ while (black)
+ {
+ if (black->port == port &&
+ 0 == sh_ipvx_cmp(head->paddr, saddr))
+ return -1;
+ black = black->next;
+ }
+
+ black = SH_ALLOC (sizeof(struct sh_port));
+ black->paddr = SH_ALLOC (sizeof(struct sh_sockaddr));
+ black->port = port;
+ memcpy(black->paddr, saddr, sizeof(struct sh_sockaddr));
+ black->next = head;
+
+ if (proto == IPPROTO_TCP)
+ blacklist_tcp = black;
+ else
+ blacklist_udp = black;
+
+ if (portchk_debug)
+ {
+ int checkit = sh_portchk_is_blacklisted(port, saddr, proto);
+ fprintf(stderr, _("port blacklisted: %d %s\n"), port,
+ (checkit == 1) ? _("ok") : _("fail"));
+ }
+ return 0;
+}
+
+
+/* Subroutine to add a required or optional port/service
+ */
+static int sh_portchk_add_required_port_generic (char * service,
+ char * interface, int type)
+{
+ char buf[256] = { '\0' };
+ int proto;
+ char * p;
+ char * endptr;
+ unsigned long int port;
+ struct sh_sockaddr saddr;
+ struct sh_portentry * portent;
+
+ if (0 == sh_ipvx_aton(interface, &saddr))
+ return -1;
+
+ sl_strlcpy (buf, service, sizeof(buf));
+
+ p = strchr(buf, '/');
+ if (!p)
+ return -1;
+ if (0 == strcmp(p, _("/tcp")))
+ proto = IPPROTO_TCP;
+ else if (0 == strcmp(p, _("/udp")))
+ proto = IPPROTO_UDP;
+ else
+ return -1;
+
+ *p = '\0';
+ port = strtoul(buf, &endptr, 0);
+
+ if (portchk_debug)
+ {
+ char buf[SH_IP_BUF];
+ sh_ipvx_ntoa(buf, sizeof(buf), &saddr);
+ fprintf(stderr, _("add_port_generic: %s (%s) %d %s (%s)\n"),
+ interface, buf, (int) port, (proto == IPPROTO_TCP) ? _("tcp") : _("udp"),
+ sh_port_type2str(type));
+ }
+
+ /* Blacklisted ports
+ */
+ if (*endptr == '\0' && port <= 65535 && type == SH_PORT_BLACKLIST)
+ return (sh_portchk_blacklist(port, &saddr, proto));
+
+ if (*endptr != '\0')
+ {
+ portent = sh_portchk_get_from_list (proto, -1, &saddr, buf);
+ if (!portent)
+ {
+ if (portchk_debug)
+ fprintf(stderr, _("add_required_port %d\n"), (int) port);
+ sh_portchk_add_to_list (proto, -1, &saddr, buf, type, SH_PORT_UNKN);
+ }
+ else
+ {
+#ifdef TEST_ONLY
+ fprintf(stderr, "** WARNING: duplicate port definition %s/%s\n", buf, SH_PROTO_STR(proto));
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ return -1;
+ }
+ }
+ else if (port <= 65535)
+ {
+ portent = sh_portchk_get_from_list (proto, port, &saddr, NULL);
+ if (!portent)
+ {
+ if (portchk_debug)
+ fprintf(stderr, _("add_required_port: open port: %d/%s\n"),
+ (int) port, SH_PROTO_STR(proto));
+ sh_portchk_add_to_list (proto, port, &saddr, NULL, type, SH_PORT_UNKN);
+ }
+ else
+ {
+#ifdef TEST_ONLY
+ fprintf(stderr, "** WARNING: duplicate port definition %lu/%s\n", port, SH_PROTO_STR(proto));
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("duplicate port definition"), _("sh_portchk_add_required_port_generic"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ return -1;
+ }
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+/* Internal interface to add required or optional ports as 'iface:portlist'
+ */
+static int sh_portchk_add_required_generic (const char * str, int type)
+{
+ size_t ll = 0;
+ int status;
+
+ char * interface = NULL;
+ char * list;
+ char * p;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+#endif
+
+ if (!str)
+ return -1;
+
+ if (strchr(str, ':'))
+ {
+ char *last = strrchr(str, ':');
+ if (last != NULL)
+ {
+ size_t tolast = (last - str);
+ interface = SH_ALLOC(tolast+1);
+ sl_strlcpy(interface, str, tolast+1);
+ interface[tolast] = '\0';
+
+ ll = tolast;
+
+ while (str[ll] == ':' || str[ll] == ' ' || str[ll] == '\t')
+ ++ll;
+ }
+ }
+ else
+ {
+ interface = SH_ALLOC(8);
+ sl_strlcpy(interface, _("0.0.0.0"), 8);
+ interface[7] = '\0';
+ while (str[ll] == ' ' || str[ll] == '\t')
+ ++ll;
+ }
+
+ if (!interface)
+ return -1;
+
+ if (str[ll] == '\0')
+ {
+ SH_FREE(interface);
+ return -1;
+ }
+
+ if (portchk_debug)
+ fprintf(stderr, "add ports for interface: %s (%s)\n", interface, sh_port_type2str(type));
+
+ list = sh_util_strdup(&str[ll]);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ p = strtok_r (list, " ,\t", &saveptr);
+#else
+ p = strtok (list, " ,\t");
+#endif
+ if (!p)
+ {
+ SH_FREE(interface);
+ SH_FREE(list);
+ return -1;
+ }
+ while (p)
+ {
+ status = sh_portchk_add_required_port_generic (p, interface, type);
+
+ if (-1 == status)
+ {
+ SH_FREE(interface);
+ SH_FREE(list);
+ return -1;
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ p = strtok_r (NULL, " ,\t", &saveptr);
+#else
+ p = strtok (NULL, " ,\t");
+#endif
+ }
+ SH_FREE(interface);
+ SH_FREE(list);
+ return 0;
+}
+
+/* User interface to add required ports as 'iface:portlist'
+ */
+static int sh_portchk_add_required (const char * str)
+{
+ return sh_portchk_add_required_generic (str, SH_PORT_REQ);
+}
+
+/* User interface to add optional ports as 'iface:portlist'
+ */
+static int sh_portchk_add_optional (const char * str)
+{
+ return sh_portchk_add_required_generic (str, SH_PORT_OPT);
+}
+
+/* User interface to add ignoreable ports as 'iface:portlist'
+ */
+static int sh_portchk_add_ignore (const char * str)
+{
+ return sh_portchk_add_required_generic (str, SH_PORT_IGN);
+}
+
+/* User interface to add ports that should not be checked as 'iface:portlist'
+ */
+static int sh_portchk_add_blacklist (const char * str)
+{
+ return sh_portchk_add_required_generic (str, SH_PORT_BLACKLIST);
+}
+
+/* Interface to run port check
+ */
+int sh_portchk_check ()
+{
+ volatile int min_port;
+ static int noprivports = 0;
+
+ SH_MUTEX_LOCK(mutex_port_check);
+
+ min_port = (sh_portchk_minport == -1) ? 0 : sh_portchk_minport;
+
+ if (sh_portchk_active != S_FALSE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Checking for open ports"),
+ _("sh_portchk_check"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ sh_portchk_reset_lists();
+ if ((0 != geteuid()) && (min_port < 1024))
+ {
+ min_port = 1024;
+ if (noprivports == 0)
+ {
+#ifdef TEST_ONLY
+ fprintf(stderr, "** WARNING not scanning ports < 1024\n");
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("not scanning ports below 1024"),
+ _("sh_portchk_check"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+#endif
+ noprivports = 1;
+ }
+ }
+
+ sh_port2proc_prepare();
+
+ if (sh_portchk_check_udp == 1)
+ sh_portchk_scan_ports_udp(min_port, sh_portchk_maxport);
+ sh_portchk_scan_ports_tcp(min_port, sh_portchk_maxport);
+
+
+ sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_REPORT);
+ if (sh_portchk_check_udp == 1)
+ sh_portchk_check_list (&portlist_udp, IPPROTO_UDP, SH_PORT_REPORT);
+
+ }
+ SH_MUTEX_UNLOCK(mutex_port_check);
+ return 0;
+}
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_portcheck_lists (CuTest *tc)
+{
+#if defined(SH_USE_PORTCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
+ struct sh_sockaddr haddr_local;
+ struct sh_portentry * portent;
+ char buf[256];
+ char * p;
+
+#ifdef HAVE_RPC_RPC_H
+ p = sh_getrpcbynumber(0, buf, sizeof(buf));
+ CuAssertTrue(tc, p == NULL);
+
+ p = sh_getrpcbynumber(100000, buf, sizeof(buf));
+ CuAssertPtrNotNull(tc, p);
+ CuAssertTrue(tc, (0 == strcmp(p, "portmapper") || 0 == strcmp(p, "rpcbind")));
+ CuAssertTrue(tc, (0 == strcmp(buf, "portmapper") || 0 == strcmp(p, "rpcbind")));
+
+ p = sh_getrpcbynumber(100007, buf, sizeof(buf));
+ CuAssertPtrNotNull(tc, p);
+ CuAssertTrue(tc, 0 == strcmp(p, "ypbind"));
+ CuAssertTrue(tc, 0 == strcmp(buf, "ypbind"));
+#endif
+
+ p = sh_getservbyport(0, SH_PROTO_STR(IPPROTO_UDP), buf, sizeof(buf));
+ CuAssertTrue(tc, p == NULL);
+
+#if !defined(HOST_IS_CYGWIN)
+ p = sh_getservbyport(22, SH_PROTO_STR(IPPROTO_TCP), buf, sizeof(buf));
+ CuAssertPtrNotNull(tc, p);
+ CuAssertTrue(tc, 0 == strcmp(p, "ssh"));
+ CuAssertTrue(tc, 0 == strcmp(buf, "ssh"));
+#endif
+
+ p = sh_getservbyport(13, SH_PROTO_STR(IPPROTO_UDP), buf, sizeof(buf));
+ CuAssertPtrNotNull(tc, p);
+ CuAssertTrue(tc, 0 == strcmp(p, "daytime"));
+ CuAssertTrue(tc, 0 == strcmp(buf, "daytime"));
+
+ CuAssertTrue(tc, 0 != sh_ipvx_aton("127.0.0.1", &haddr_local));
+
+ sh_portchk_add_to_list (IPPROTO_TCP, 8000, &haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, NULL);
+ CuAssertPtrNotNull(tc, portent);
+
+ CuAssertTrue(tc, portent->port == 8000);
+ CuAssertTrue(tc, 0 == strcmp("127.0.0.1", portent->interface));
+ CuAssertTrue(tc, portent->status == SH_PORT_UNKN);
+ CuAssertTrue(tc, portent->flag == SH_PORT_NOT);
+
+ sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
+
+ CuAssertTrue(tc, NULL == portlist_tcp);
+
+ sh_portchk_add_to_list (IPPROTO_TCP, 8000, &haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, 8001, &haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, 8002, &haddr_local, NULL, SH_PORT_REQ, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, 8003, &haddr_local, NULL, SH_PORT_NOT, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, 8004, &haddr_local, NULL, SH_PORT_IGN, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo1", SH_PORT_NOT, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo2", SH_PORT_REQ, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo3", SH_PORT_NOT, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo4", SH_PORT_REQ, SH_PORT_UNKN);
+ sh_portchk_add_to_list (IPPROTO_TCP, -1, &haddr_local, "foo5", SH_PORT_IGN, SH_PORT_UNKN);
+
+ sh_portchk_check_list (&portlist_tcp, IPPROTO_TCP, SH_PORT_NOREPT);
+
+ CuAssertPtrNotNull(tc, portlist_tcp);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, NULL);
+ CuAssertPtrNotNull(tc, portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8001, &haddr_local, NULL);
+ CuAssertTrue(tc, NULL == portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8002, &haddr_local, NULL);
+ CuAssertPtrNotNull(tc, portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8003, &haddr_local, NULL);
+ CuAssertTrue(tc, NULL == portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8004, &haddr_local, NULL);
+ CuAssertPtrNotNull(tc, portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo1");
+ CuAssertTrue(tc, NULL == portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo2");
+ CuAssertPtrNotNull(tc, portent);
+ CuAssertTrue(tc, 0 == strcmp(portent->service, "foo2"));
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo3");
+ CuAssertTrue(tc, NULL == portent);
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo4");
+ CuAssertPtrNotNull(tc, portent);
+ CuAssertTrue(tc, 0 == strcmp(portent->service, "foo4"));
+
+ portent = sh_portchk_get_from_list(IPPROTO_TCP, 8000, &haddr_local, "foo5");
+ CuAssertPtrNotNull(tc, portent);
+ CuAssertTrue(tc, 0 == strcmp(portent->service, "foo5"));
+
+ CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 == sh_portchk_blacklist(666, &haddr_local, IPPROTO_UDP));
+ CuAssertTrue(tc, 0 != sh_portchk_blacklist(666, &haddr_local, IPPROTO_UDP));
+ CuAssertTrue(tc, 0 == sh_portchk_blacklist(667, &haddr_local, IPPROTO_UDP));
+ CuAssertTrue(tc, 0 == sh_portchk_blacklist(668, &haddr_local, IPPROTO_UDP));
+
+ CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, &haddr_local, IPPROTO_UDP));
+ CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, &haddr_local, IPPROTO_UDP));
+ CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, &haddr_local, IPPROTO_UDP));
+ CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, &haddr_local, IPPROTO_UDP));
+
+ CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(668, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(667, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 != sh_portchk_is_blacklisted(666, &haddr_local, IPPROTO_TCP));
+ CuAssertTrue(tc, 0 == sh_portchk_is_blacklisted(665, &haddr_local, IPPROTO_TCP));
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+#endif
+
+#ifdef TEST_ONLY
+
+void usage (char * pname)
+{
+ printf ("%s [-r|--required interface:portlist][-o|--optional interface:portlist][--no-udp][-d|--debug] hostname\n\n", pname);
+ printf (" Check local host for open ports; Version %s\n\n", PORTCHK_VERSION);
+ printf (" Interface: Numeric address for an interface, e.g. 127.0.0.1\n");
+ printf (" Portlist: List of ports or services, e.g. 22/tcp,nfs/udp,nlockmgr/udp\n");
+ printf (" required -> must be open\n");
+ printf (" optional -> may be open or closed\n");
+ printf (" RPC services must be specified with service **name**, others with **port number**\n\n");
+ printf (" Example:\n");
+ printf (" %s --required 192.168.1.2:22/tcp,nfs/udp,nlockmgr/udp\n\n", pname);
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ char * pname = argv[0];
+
+
+ /*
+ test_lists();
+
+ portlist_tcp = sh_portchk_kill_list (portlist_tcp);
+ portlist_udp = sh_portchk_kill_list (portlist_udp);
+ */
+
+ /* sh_portchk_add_required ("127.0.0.1 : nlockmgr/tcp, 5308/tcp, nfs/tcp"); */
+
+ while (argc > 1 && argv[1][0] == '-')
+ {
+ if (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))
+ {
+ usage(pname);
+ exit (0);
+ }
+ else if (0 == strcmp(argv[1], "--required") || 0 == strcmp(argv[1], "-r"))
+ {
+ if (argc < 3)
+ {
+ usage(pname);
+ exit (1);
+ }
+ sh_portchk_add_required (argv[2]);
+ --argc; ++argv;
+ }
+ else if (0 == strcmp(argv[1], "--optional") || 0 == strcmp(argv[1], "-o"))
+ {
+ if (argc < 3)
+ {
+ usage(pname);
+ exit (1);
+ }
+ sh_portchk_add_optional (argv[2]);
+ --argc; ++argv;
+ }
+ else if (0 == strcmp(argv[1], "--no-udp"))
+ {
+ sh_portchk_check_udp = 0;
+ }
+ else if (0 == strcmp(argv[1], "--debug") || 0 == strcmp(argv[1], "-d"))
+ {
+ portchk_debug = 1;
+ }
+ else
+ {
+ usage(pname);
+ exit (1);
+ }
+ --argc; ++argv;
+ }
+
+ if (argc < 2)
+ {
+ usage(pname);
+ exit (1);
+ }
+
+ portchk_hostname = argv[1];
+
+ if (0 != sh_portchk_init ())
+ {
+ usage(pname);
+ exit (1);
+ }
+
+ sh_portchk_check();
+
+ return 0;
+}
+#endif
diff --git a/src/sh_prelink.c b/src/sh_prelink.c
new file mode 100644
index 0000000..552ab62
--- /dev/null
+++ b/src/sh_prelink.c
@@ -0,0 +1,278 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2004 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+#include "samhain.h"
+#include "sh_tiger.h"
+#include "sh_extern.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+
+#undef FIL__
+#define FIL__ _("sh_prelink.c")
+
+static char * prelink_path = NULL;
+static char * prelink_hash = NULL;
+
+int sh_prelink_set_path (const char * str)
+{
+ SL_ENTER(_("sh_prelink_set_path"));
+ if (prelink_path != NULL)
+ SH_FREE(prelink_path);
+ if (str[0] != '/')
+ {
+ prelink_path = NULL;
+ SL_RETURN((-1), _("sh_prelink_set_path"));
+ }
+#ifdef SH_EVAL_SHELL
+ prelink_path = sh_util_strdup(str);
+ SL_RETURN(0, _("sh_prelink_set_path"));
+#else
+ prelink_path = NULL;
+ SL_RETURN((-1), _("sh_prelink_set_path"));
+#endif
+}
+
+int sh_prelink_set_hash (const char * str)
+{
+ size_t len;
+ SL_ENTER(_("sh_prelink_set_hash"));
+ if (prelink_hash != NULL)
+ SH_FREE(prelink_hash);
+ len = sl_strlen (str);
+ if (len != KEY_LEN)
+ {
+ prelink_hash = NULL;
+ SL_RETURN((-1), _("sh_prelink_set_hash"));
+ }
+ prelink_hash = SH_ALLOC(len+1);
+ (void) sl_strlcpy(prelink_hash, str, len+1);
+ SL_RETURN(0, _("sh_prelink_set_hash"));
+}
+
+int sh_prelink_iself (SL_TICKET fd, off_t size, int alert_timeout, char * path)
+{
+ long status;
+ char magic[4];
+ char * tmp;
+
+ /* 42 bytes is about the minimum an ELF binary might have
+ * (with plenty of hacks to reduce the size, such as interleaving
+ * the code with the header...)
+ */
+ if (size < 42)
+ return S_FALSE;
+
+ status = sl_read_timeout (fd, magic, 4, alert_timeout, S_FALSE);
+ (void) sl_rewind(fd);
+ if (status == 4)
+ {
+ /*@-usedef@*/
+ if (magic[0] == (char) 0x7f &&
+ magic[1] == 'E' &&
+ magic[2] == 'L' &&
+ magic[3] == 'F')
+ return S_TRUE;
+ /*@+usedef@*/
+ }
+ else
+ {
+ tmp = sh_util_safe_name (path);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGPATH,
+ _("Error reading file"), _("sh_prelink_iself"), tmp);
+ SH_FREE(path);
+ }
+ return S_FALSE;
+}
+
+extern int get_the_fd (SL_TICKET ticket);
+
+static void sh_prelink_fd(sh_tas_t * task)
+{
+ SL_TICKET ticket;
+ char * tmp;
+ char hashbuf[KEYBUF_SIZE];
+
+ if (task->com_ti != (-1))
+ {
+ (void) sl_close(task->com_ti);
+ task->com_fd = -1;
+ task->com_ti = -1;
+ }
+ ticket = sl_open_read(FIL__, __LINE__, task->command,
+ task->privileged == 0 ? SL_NOPRIV : SL_YESPRIV);
+ if (SL_ISERROR(ticket))
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ char errbuf2[SH_ERRBUF_SIZE];
+ sh_error_message(errno, errbuf2, sizeof(errbuf2));
+ sl_strlcpy(errbuf, sl_error_string(ticket), sizeof(errbuf));
+ tmp = sh_util_safe_name (task->command);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, ticket, MSG_E_READ, errbuf, errbuf2, tmp);
+ SH_FREE(tmp);
+ return;
+ }
+
+ if (*(task->checksum) == '\0' ||
+ 0 == sl_strcmp(task->checksum,
+ sh_tiger_hash (task->command, ticket, TIGER_NOLIM, hashbuf, sizeof(hashbuf))))
+ {
+ task->com_fd = get_the_fd(ticket);
+ task->com_ti = ticket;
+ }
+ else
+ {
+ tmp = sh_util_safe_name (task->command);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, ticket, MSG_E_HASH, tmp);
+ SH_FREE(tmp);
+ (void) sl_close(ticket);
+ }
+ return;
+}
+
+/* returns static storage
+ */
+int sh_prelink_run (char * path, char * file_hash, int alert_timeout, unsigned long mask)
+{
+ static int init = S_FALSE;
+ static int args_filled = 0;
+ static sh_tas_t task;
+
+ int status = 0;
+ char * p;
+
+ SL_ENTER(_("sh_prelink_run"));
+
+ /* reset if path == NULL
+ */
+ if (path == NULL)
+ {
+ if (init == S_FALSE)
+ {
+ SL_RETURN (0, _("sh_prelink_run"));
+ }
+ sh_ext_tas_free(&task);
+ init = S_FALSE;
+ args_filled = 0;
+ SL_RETURN (0, _("sh_prelink_run"));
+ }
+
+ /* initialize task structure
+ */
+ if (init == S_FALSE)
+ {
+ char dir[SH_PATHBUF];
+
+ sh_ext_tas_init(&task);
+ p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid, dir, sizeof(dir));
+ if (p)
+ {
+ (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
+ }
+ (void) sh_ext_tas_add_envv (&task, _("SHELL"),
+ _("/bin/sh"));
+ (void) sh_ext_tas_add_envv (&task, _("PATH"),
+ _("/sbin:/usr/sbin:/bin:/usr/bin"));
+ if (sh.timezone != NULL)
+ {
+ (void) sh_ext_tas_add_envv(&task, "TZ", sh.timezone);
+ }
+ if (prelink_path == NULL)
+ {
+ sh_ext_tas_command(&task, _("/usr/sbin/prelink"));
+ (void) sh_ext_tas_add_argv(&task, _("/usr/sbin/prelink"));
+ }
+ else
+ {
+ sh_ext_tas_command(&task, prelink_path);
+ (void) sh_ext_tas_add_argv(&task, prelink_path);
+ }
+ args_filled = sh_ext_tas_add_argv(&task, _("--verify"));
+
+ if (prelink_hash != NULL)
+ {
+ (void) sl_strlcpy(task.checksum, prelink_hash, KEY_LEN+1);
+ }
+ task.rw = 'r';
+ task.fork_twice = S_FALSE;
+
+ sh_prelink_fd(&task);
+
+ init = S_TRUE;
+ }
+
+ /* rm filename arg if set; fill in filename
+ */
+ if (args_filled == 3)
+ args_filled = sh_ext_tas_rm_argv(&task);
+ if (args_filled == 2)
+ args_filled = sh_ext_tas_add_argv(&task, path);
+ else
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, args_filled, MSG_E_SUBGEN,
+ _("Bad argument count"), _("sh_prelink_run"));
+ SL_RETURN ((-1), _("sh_prelink_run"));
+ }
+
+ /* open pipe
+ */
+ status = sh_ext_popen(&task);
+ if (status != 0)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Could not open pipe"), _("sh_prelink_run"));
+ SL_RETURN ((-1), _("sh_prelink_run"));
+ }
+
+ if (SL_ISERROR(task.pipeTI))
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, task.pipeTI, MSG_E_SUBGEN,
+ _("No valid ticket"), _("sh_prelink_run"));
+ SL_RETURN ((-1), _("sh_prelink_run"));
+ }
+
+ /* read from pipe
+ */
+ sl_read_timeout_prep (task.pipeTI);
+
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 length_nolim = TIGER_NOLIM;
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(mask);
+ sl_strlcpy(file_hash,
+ sh_tiger_generic_hash (path, task.pipeTI, &length_nolim, alert_timeout,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+
+ /* close pipe and return exit status
+ */
+ status = sh_ext_pclose(&task);
+ SL_RETURN ((status), _("sh_prelink_run"));
+}
+/* defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ */
+#endif
diff --git a/src/sh_prelude.c b/src/sh_prelude.c
new file mode 100644
index 0000000..74fda3a
--- /dev/null
+++ b/src/sh_prelude.c
@@ -0,0 +1,1470 @@
+/*
+ *
+ * Copyright (C) 2005 Yoann Vandoorselaere, Prelude IDS Technologies
+ * Rainer Wichmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * 28/04/2005 : R.W.:
+ * move libprelude 0.8 code to seperate file
+ *
+ * 23/04/2005 : R.W.:
+ * include libprelude 0.9 code from Yoann Vandoorselaere
+ */
+
+
+/*
+ * for strptime()
+ */
+#define _GNU_SOURCE 1
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#if TIME_WITH_SYS_TIME
+
+# include <sys/time.h>
+# include <time.h>
+
+#else
+
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+
+#endif
+
+#include <unistd.h>
+#include <syslog.h>
+#include <pwd.h>
+
+int sh_argc_store;
+char ** sh_argv_store;
+
+#if defined(HAVE_LIBPRELUDE)
+
+
+/*
+ * _() macros are samhain specific; they are used to replace string
+ * constants at runtime. This is part of the samhain stealth mode
+ * (fill string constants with encoded strings, decode at runtime).
+ */
+#define FIL__ _("sh_prelude.c")
+
+
+#include <libprelude/idmef.h>
+#include <libprelude/prelude.h>
+
+/*
+ * includes for samhain-specific functions (sl_strstr, sh_error_handle)
+ */
+#include "samhain.h"
+#include "sh_cat.h"
+#include "sh_error_min.h"
+#include "sh_prelude.h"
+#define SH_NEED_PWD_GRP 1
+#include "sh_static.h"
+char * sh_util_strdup (const char * str) SH_GNUC_MALLOC;
+/*
+ * When SH_USE_XML is set, value are formated using name="value".
+ * Otherwise, value is formatted using the format name=<value>.
+ */
+#ifdef SH_USE_XML
+# define VALUE_DELIM_START '"'
+# define VALUE_DELIM_END '"'
+#else
+# define VALUE_DELIM_START '<'
+# define VALUE_DELIM_END '>'
+#endif
+
+#define IDMEF_ANALYZER_MODEL _("Samhain")
+#define IDMEF_ANALYZER_CLASS _("Integrity Checker")
+#define IDMEF_ANALYZER_VERSION VERSION
+#define IDMEF_ANALYZER_MANUFACTURER _("http://www.la-samhna.de/samhain/")
+
+
+
+/*
+ * 0 = not initialized; -1 = failed; 1 = initialized
+ */
+static int initialized = 0;
+static int ready_for_init = 0;
+
+static char *profile = NULL;
+static prelude_client_t *client = NULL;
+
+static int severity_map[1 + (unsigned int) IDMEF_IMPACT_SEVERITY_HIGH] = {
+ /* 0: unused (?) */ 0,
+ /* 1: INFO */ 0,
+ /* 2: LOW */ SH_ERR_ALL|SH_ERR_INFO,
+ /* 3: MEDIUM */ SH_ERR_NOTICE|SH_ERR_WARN|SH_ERR_STAMP|SH_ERR_ERR,
+ /* 4: HIGH */ SH_ERR_SEVERE|SH_ERR_FATAL
+};
+
+/* returns 0/tiger, 1/sha1, or 2/md5
+ */
+extern int sh_tiger_get_hashtype(void);
+
+static void clear_and_set (int setpos, int flag)
+{
+ unsigned int i;
+ /* clear everywhere, and set at correct position */
+ for (i = 1; i < (1 + (unsigned int) IDMEF_IMPACT_SEVERITY_HIGH); ++i)
+ severity_map[i] &= ~flag;
+ severity_map[setpos] |= flag;
+ return;
+}
+
+static int set_prelude_severity_int (const char * str, int prelude_sev)
+{
+ char * p;
+ char * dup = strdup (str);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+#endif
+
+ if (!dup)
+ return -1;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ p = strtok_r (dup, ", \t", &saveptr);
+#else
+ p = strtok (dup, ", \t");
+#endif
+ if (p) {
+ do {
+ if (0 == strcmp (p, _("alert")))
+ clear_and_set (prelude_sev, SH_ERR_FATAL);
+ else if (0 == strcmp (p, _("crit")))
+ clear_and_set (prelude_sev, SH_ERR_SEVERE);
+ else if (0 == strcmp (p, _("err")))
+ clear_and_set (prelude_sev, SH_ERR_ERR);
+ else if (0 == strcmp (p, _("mark")))
+ clear_and_set (prelude_sev, SH_ERR_STAMP);
+ else if (0 == strcmp (p, _("warn")))
+ clear_and_set (prelude_sev, SH_ERR_WARN);
+ else if (0 == strcmp (p, _("notice")))
+ clear_and_set (prelude_sev, SH_ERR_NOTICE);
+ else if (0 == strcmp (p, _("debug")))
+ clear_and_set (prelude_sev, SH_ERR_ALL);
+ else if (0 == strcmp (p, _("info")))
+ clear_and_set (prelude_sev, SH_ERR_INFO);
+ else {
+ free (dup);
+ return -1;
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ p = strtok_r (NULL, ", \t", &saveptr);
+#else
+ p = strtok (NULL, ", \t");
+#endif
+ } while (p);
+ }
+ free(dup);
+ return 0;
+}
+
+int sh_prelude_map_info (const char * str)
+{
+ return (set_prelude_severity_int(str,(int)IDMEF_IMPACT_SEVERITY_INFO));
+}
+int sh_prelude_map_low (const char * str)
+{
+ return (set_prelude_severity_int(str,(int)IDMEF_IMPACT_SEVERITY_LOW));
+}
+int sh_prelude_map_medium (const char * str)
+{
+ return (set_prelude_severity_int(str,(int)IDMEF_IMPACT_SEVERITY_MEDIUM));
+}
+int sh_prelude_map_high (const char * str)
+{
+ return (set_prelude_severity_int(str,(int)IDMEF_IMPACT_SEVERITY_HIGH));
+}
+
+static idmef_impact_severity_t map_severity (int sam_sev)
+{
+ int i;
+ int max = 1 + (unsigned int) IDMEF_IMPACT_SEVERITY_HIGH;
+ idmef_impact_severity_t retval = IDMEF_IMPACT_SEVERITY_MEDIUM;
+
+ for (i = 0; i < max; ++i) {
+ if (severity_map[i] & sam_sev) {
+ retval = (idmef_impact_severity_t) i;
+ }
+ }
+ return retval;
+}
+
+static char *do_get_value(char *ptr, char delim_start, char delim_end)
+{
+ char *ret = NULL;
+#if defined(SH_WITH_SERVER)
+ int delim_start_count = 0;
+ int found = 0;
+#endif
+
+ ptr = strchr(ptr, delim_start);
+ if ( ! ptr )
+ return NULL;
+
+ ret = ++ptr;
+#if defined(SH_WITH_SERVER)
+ while ((*ptr != '\0') && (!found)){
+ if (*ptr == delim_end) {
+ if (delim_start_count == 0)
+ found = 1;
+ delim_start_count--;
+ }
+ else if (*ptr == delim_start)
+ delim_start_count++;
+ ptr++;
+ }
+ ptr = (found) ? ptr-1 : NULL ;
+#else
+ ptr = strchr(ptr, delim_end);
+#endif
+ if ( ! ptr )
+ return NULL;
+
+ *ptr = '\0';
+ ret = strdup(ret);
+ *ptr = delim_end;
+
+ return ret;
+}
+
+
+
+static char *get_value(char *msg, const char *toktmp, const char *toksuffix)
+{
+ char *ptr, tok[128];
+
+ snprintf(tok, sizeof(tok), "%s%s=", toktmp, (toksuffix) ? toksuffix : "");
+
+ ptr = strstr(msg, tok);
+ if ( ! ptr )
+ return NULL;
+
+ return do_get_value(ptr, VALUE_DELIM_START, VALUE_DELIM_END);
+}
+
+
+
+static char *get_time_value(char *msg, const char *toktmp, const char *toksuffix)
+{
+
+ char *ret, *ptr, tok[128];
+
+ snprintf(tok, sizeof(tok), "%s%s=", toktmp, (toksuffix) ? toksuffix : "");
+
+ ptr = strstr(msg, tok);
+ if ( ! ptr )
+ return NULL;
+
+#ifndef SH_USE_XML
+ ret = do_get_value(ptr, '[', ']');
+#else
+ ret = do_get_value(ptr, VALUE_DELIM_START, VALUE_DELIM_END);
+#endif
+
+ return ret;
+}
+
+
+
+
+#if 0
+void debug_print_message(idmef_message_t *msg)
+{
+ int ret;
+ prelude_io_t *fd;
+
+ ret = prelude_io_new(&fd);
+ if ( ret < 0 )
+ return;
+
+ prelude_io_set_file_io(fd, stderr);
+ idmef_message_print(idmef, fd);
+
+ prelude_io_destroy(fd);
+}
+#endif
+
+
+
+static int idmef_time_from_samhain(idmef_time_t **time, const char *str)
+{
+ int ret;
+ char *ptr;
+ time_t utc;
+ struct tm lt;
+
+ /*
+ * Samhain stamp are encoded in UTC.
+ */
+ ptr = strptime(str, _("%Y-%m-%dT%H:%M:%S"), &lt);
+ if ( ! ptr ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("could not format Samhain time"), _("idmef_time_from_samhain"));
+ return -1;
+ }
+
+ utc = prelude_timegm(&lt);
+
+ ret = idmef_time_new_from_time(time, &utc);
+ if ( ret < 0 )
+ return ret;
+
+ return 0;
+}
+
+/* flawfinder: ignore *//* is part of name, not access() */
+static void get_access_info(idmef_file_access_t *access, char * mode, int pos, int mpos)
+{
+ int got = 0;
+ int ret;
+ prelude_string_t *str;
+
+ do {
+ if ( mode[pos] == 'r' ) {
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_access_new_permission(access, &str, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ return;
+ prelude_string_set_dup(str, _("read"));
+ ++got;
+ }
+ else if ( mode[pos] == 'w' ) {
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_access_new_permission(access, &str, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ return;
+ prelude_string_set_dup(str, _("write"));
+ ++got;
+ }
+ else if ( mode[pos] == 'x' || mode[pos] == 's' || mode[pos] == 't') {
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_access_new_permission(access, &str, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ return;
+
+ if ( mode[pos] == 'x' && mode[0] == 'd' )
+ prelude_string_set_dup(str, _("search"));
+
+ else if ( mode[pos] == 'x' || mode[pos] == 't' )
+ prelude_string_set_dup(str, _("execute"));
+
+ else /* 's' */
+ prelude_string_set_dup(str, _("executeAs"));
+ ++got;
+ }
+ ++pos;
+ } while (pos <= mpos);
+
+ if ( got == 0 ) {
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_access_new_permission(access, &str, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ return;
+ prelude_string_set_dup(str, _("noAccess"));
+ }
+ return;
+}
+
+
+static void get_file_infos(idmef_target_t *target, char *msg,
+ idmef_file_category_t category)
+{
+ int ret;
+ int hashtype = 0;
+ char *ptr;
+ idmef_time_t *time;
+ idmef_file_t *file;
+ idmef_inode_t *inode;
+ prelude_string_t *str;
+ idmef_checksum_t *checksum;
+ idmef_file_access_t *access; /* flawfinder: ignore */
+ idmef_user_id_t *userid;
+ const char *suffix = (category == IDMEF_FILE_CATEGORY_CURRENT) ? "_new" : "_old";
+ char *mode = NULL;
+
+ ret = idmef_target_new_file(target, &file, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ return;
+ idmef_file_set_category(file, category);
+
+ ptr = get_value(msg, _("path"), NULL);
+ if ( ptr ) {
+ /*
+ * In term of IDMEF, this is the full path,
+ * including the name.
+ */
+ ret = idmef_file_new_path(file, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ return;
+ }
+ prelude_string_set_nodup(str, ptr);
+
+ ptr = strrchr(ptr, '/');
+ if ( ptr ) {
+ ret = idmef_file_new_name(file, &str);
+ if ( ret == 0 ) {
+ prelude_string_set_dup(str, ptr + 1);
+ }
+ }
+ }
+
+ ptr = get_value(msg, _("size"), suffix);
+ if ( ptr ) {
+ idmef_file_set_data_size(file, strtoul(ptr, NULL, 10));
+ free(ptr);
+ }
+
+ ptr = get_time_value(msg, _("mtime"), suffix);
+ if ( ptr ) {
+ ret = idmef_time_from_samhain(&time, ptr);
+ if ( ret == 0 ) {
+ idmef_file_set_modify_time(file, time);
+ }
+ free(ptr);
+ }
+
+ ptr = get_time_value(msg, _("ctime"), suffix);
+ if ( ptr ) {
+ ret = idmef_time_from_samhain(&time, ptr);
+ if ( ret == 0 ) {
+ idmef_file_set_create_time(file, time);
+ }
+ free(ptr);
+ }
+
+ ptr = get_value(msg, _("inode"), suffix);
+ if ( ptr ) {
+ ret = idmef_file_new_inode(file, &inode);
+ if ( ret == 0 ) {
+ char * dev = get_value(msg, _("dev"), suffix);
+ if (dev) {
+ char * q = strchr(dev, ',');
+ if (*q) {
+ *q = '\0'; ++q;
+ idmef_inode_set_major_device(inode, strtoul(dev, NULL, 0));
+ idmef_inode_set_minor_device(inode, strtoul( q, NULL, 0));
+ }
+ free(dev);
+ }
+ idmef_inode_set_number(inode, strtoul(ptr, NULL, 10));
+ }
+ free(ptr);
+ }
+
+ ptr = get_value(msg, _("chksum"), suffix);
+ if ( ptr ) {
+ ret = idmef_file_new_checksum(file, &checksum, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto get_mode;
+ }
+
+ hashtype = sh_tiger_get_hashtype();
+
+ if (hashtype == 0)
+ idmef_checksum_set_algorithm(checksum, IDMEF_CHECKSUM_ALGORITHM_TIGER);
+
+ else if (hashtype == 1)
+ idmef_checksum_set_algorithm(checksum, IDMEF_CHECKSUM_ALGORITHM_SHA1);
+
+ else if (hashtype == 2)
+ idmef_checksum_set_algorithm(checksum, IDMEF_CHECKSUM_ALGORITHM_MD5);
+
+ else
+ idmef_checksum_set_algorithm(checksum, IDMEF_CHECKSUM_ALGORITHM_TIGER);
+
+
+ ret = idmef_checksum_new_value(checksum, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto get_mode;
+ }
+
+ /* will be freed on destroy()
+ */
+ prelude_string_set_nodup(str, ptr);
+ }
+
+ get_mode:
+
+ mode = get_value(msg, _("mode"), suffix);
+ if ( mode ) {
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_new_file_access(file, &access, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ goto get_owner;
+
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_access_new_user_id(access, &userid);
+ if ( ret < 0 )
+ goto get_owner;
+ idmef_user_id_set_type(userid, IDMEF_USER_ID_TYPE_OTHER_PRIVS);
+
+ /* flawfinder: ignore *//* is part of name, not access() */
+ get_access_info ( access, mode, 7, 9 );
+ }
+
+ get_owner:
+
+ ptr = get_value(msg, _("owner"), suffix);
+ if ( ptr ) {
+ char * uid;
+
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_new_file_access(file, &access, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto get_group;
+ }
+
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_access_new_user_id(access, &userid);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto get_group;
+ }
+ idmef_user_id_set_type(userid, IDMEF_USER_ID_TYPE_USER_PRIVS);
+
+ ret = idmef_user_id_new_name(userid, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto get_group;
+ }
+ prelude_string_set_nodup(str, ptr);
+
+ uid = get_value(msg, _("iowner"), suffix);
+ if ( ! uid )
+ goto get_group;
+
+ idmef_user_id_set_number(userid, strtoul(uid, NULL, 0));
+
+ if ( mode ) {
+ /* flawfinder: ignore *//* is part of name, not access() */
+ get_access_info ( access, mode, 1, 3 );
+ }
+
+ free(uid);
+ /* Don't free(ptr) because of prelude_string_set_nodup(str, ptr) */
+ }
+
+ get_group:
+
+ ptr = get_value(msg, _("group"), suffix);
+ if ( ptr ) {
+ char *gid;
+
+ /* flawfinder: ignore *//* is part of name, not access() */
+ ret = idmef_file_new_file_access(file, &access, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto mode_free;
+ }
+
+ ret = idmef_file_access_new_user_id(access, &userid);/* flawfinder: ignore *//* is part of name, not access() */
+ if ( ret < 0 ) {
+ free(ptr);
+ goto mode_free;
+ }
+
+ idmef_user_id_set_type(userid, IDMEF_USER_ID_TYPE_GROUP_PRIVS);
+
+ ret = idmef_user_id_new_name(userid, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ goto mode_free;
+ }
+
+ prelude_string_set_nodup(str, ptr);
+
+ gid = get_value(msg, _("igroup"), suffix);
+ if ( ! gid )
+ goto mode_free;
+
+ idmef_user_id_set_number(userid, strtoul(gid, NULL, 0));
+
+ if ( mode ) {
+ get_access_info ( access, mode, 4, 6 ); /* flawfinder: ignore */
+ }
+
+ free(gid);
+ /* Don't free(ptr) because of prelude_string_set_nodup(str, ptr) */
+ }
+
+ mode_free:
+
+ if ( mode ) {
+ free ( mode );
+ }
+
+ return;
+}
+
+
+
+static int map_policy_to_class(char *msg, unsigned long msgid, idmef_impact_t *impact, prelude_string_t *out)
+{
+ char *ptr;
+ int ret, i;
+ struct tbl {
+ unsigned int msgid;
+ const char *name;
+ idmef_impact_type_t type;
+ } tbl[] = {
+
+#ifdef SH_USE_UTMP
+ { MSG_UT_LG1X, N_("User Login"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG1A, N_("User Login"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG1B, N_("User Login"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG2X, N_("Multiple User Login"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG2A, N_("Multiple User Login"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG2B, N_("Multiple User Login"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG3X, N_("User Logout"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG3A, N_("User Logout"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG3B, N_("User Logout"), IDMEF_IMPACT_TYPE_USER },
+ { MSG_UT_LG3C, N_("User Logout"), IDMEF_IMPACT_TYPE_USER },
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ { MSG_FI_MISS, N_("File Missing"), IDMEF_IMPACT_TYPE_FILE },
+ { MSG_FI_MISS2, N_("File Missing"), IDMEF_IMPACT_TYPE_FILE },
+ { MSG_FI_ADD, N_("File Added"), IDMEF_IMPACT_TYPE_FILE },
+ { MSG_FI_ADD2, N_("File Added"), IDMEF_IMPACT_TYPE_FILE },
+ { MSG_FI_CHAN, N_("File Modified"), IDMEF_IMPACT_TYPE_FILE },
+ { MSG_FI_NODIR, N_("File found where directory was expected"), IDMEF_IMPACT_TYPE_FILE },
+#endif
+
+#ifdef SH_USE_KERN
+ { MSG_KERN_POLICY, N_("Kernel Modified"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_KERN_POL_CO, N_("Kernel Modified"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_KERN_PROC, N_("Kernel Modified"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_KERN_GATE, N_("Kernel Modified"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_KERN_IDT, N_("Kernel Modified"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_KERN_SYSCALL, N_("Kernel Modified"), IDMEF_IMPACT_TYPE_OTHER },
+#endif
+
+#ifdef SH_USE_PORTCHECK
+ { MSG_PORT_MISS, N_("Service closed"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_PORT_NEW, N_("Service opened"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_PORT_RESTART, N_("Service restarted"), IDMEF_IMPACT_TYPE_OTHER },
+ { MSG_PORT_NEWPORT, N_("Service restarted"), IDMEF_IMPACT_TYPE_OTHER },
+#endif
+
+#ifdef SH_USE_SUIDCHK
+ { MSG_SUID_POLICY, N_("SUID/SGID File Detected"), IDMEF_IMPACT_TYPE_FILE },
+#endif
+ /*
+ * This must be the last table entry
+ */
+ { 0, NULL, IDMEF_IMPACT_TYPE_OTHER },
+ };
+
+ for ( i = 0; tbl[i].name != NULL; i++ ) {
+ if ( tbl[i].msgid != msgid )
+ continue;
+
+ idmef_impact_set_type(impact, tbl[i].type);
+ return prelude_string_cat(out, _(tbl[i].name));
+ }
+
+ /* some other message
+ */
+ ptr = get_value(msg, _("msg"), NULL);
+ if ( ! ptr ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("could not format Samhain message"), _("map_policy_to_class"));
+ return -1;
+ }
+
+#if defined(SH_WITH_SERVER)
+ /* when using yule, theres a msg=<... msg=<...> >*/
+ while ( (msg = get_value(ptr, _("msg"), NULL)) ) {
+ free(ptr);
+ ptr = msg;
+ }
+#endif
+
+ ret = prelude_string_cat(out, ptr);
+ free(ptr);
+
+ return ret;
+}
+
+
+#ifdef SH_USE_PORTCHECK
+static int get_service_info(char *msg, idmef_alert_t *alert)
+{
+ int ret;
+ long port;
+ char *ptr, *new, *tmp, *ip, *srv, *protocol, *end;
+ prelude_string_t *str;
+ idmef_address_t *address;
+ idmef_node_t *node;
+ idmef_user_t *user;
+ idmef_process_t *process;
+ idmef_service_t *service;
+ idmef_source_t *source = idmef_alert_get_next_source(alert, NULL);
+ struct passwd *pw;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+
+ new = sh_util_strdup(msg);
+
+ ptr = strstr(new, _("port: "));
+ if ( ! ptr ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("malformed Samhain port check message"), _("get_service_info"));
+ SH_FREE( new );
+ return -1;
+ }
+
+ ptr += 6; /* skip 'port: ', position on first byte of interface */
+ tmp = strchr(ptr, ':');
+ if ( ! tmp ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("malformed Samhain port check message (no port)"), _("get_service_info"));
+ SH_FREE( new );
+ return -1;
+ }
+ *tmp = '\0';
+
+ /* Get interface
+ */
+ ip = strdup(ptr);
+ if ( ip ) {
+ if ( ! source ) {
+ ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ip);
+ SH_FREE( new );
+ return ret;
+ }
+ }
+
+ ret = idmef_source_new_node(source, &node);
+ if ( ret < 0 ) {
+ free(ip);
+ SH_FREE( new );
+ return ret;
+ }
+
+ ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ip);
+ SH_FREE( new );
+ return ret;
+ }
+
+ ret = idmef_address_new_address(address, &str);
+ if ( ret < 0 ) {
+ free(ip);
+ SH_FREE( new );
+ return ret;
+ }
+
+ prelude_string_set_nodup(str, ip);
+ }
+
+ ptr = tmp;
+ ++ptr;
+ tmp = strchr(ptr, '/');
+ if ( ! tmp ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("malformed Samhain port check message (no protocol)"), _("get_service_info"));
+ SH_FREE( new );
+ return -1;
+ }
+ *tmp = '\0';
+
+ /* Get port number
+ */
+ port = strtol(ptr, &end, 0);
+ if ( *ptr && *end == '\0' && port >= 0 && port < 65536) {
+
+ char * tmpw;
+
+ if ( ! source ) {
+ ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ SH_FREE( new );
+ return ret;
+ }
+ }
+
+ ret = idmef_source_new_service(source, &service);
+ if ( ret < 0 ) {
+ SH_FREE( new );
+ return ret;
+ }
+
+ idmef_service_set_port(service, port);
+
+ ret = idmef_service_new_protocol(service, &str);
+ if ( ret < 0 ) {
+ SH_FREE( new );
+ return ret;
+ }
+
+ ++tmp;
+ if (*tmp) {
+ char * tmpw = tmp;
+ char tmpw_store;
+ while (*tmpw && !isblank((int) *tmpw)) ++tmpw;
+ tmpw_store = *tmpw; *tmpw = '\0';
+ protocol = strdup(tmp);
+ *tmpw = tmpw_store;
+ prelude_string_set_nodup(str, protocol);
+ }
+
+ }
+
+ ptr = tmp;
+ ++ptr;
+ ptr = strchr(ptr, '(');
+ if ( ! ptr ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("malformed Samhain port check message (no service)"), _("get_service_info"));
+ SH_FREE( new );
+ return -1;
+ }
+ ++ptr;
+ tmp = strchr(ptr, ')');
+ if ( ! tmp ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("malformed Samhain port check message (service not closed)"), _("get_service_info"));
+ SH_FREE( new );
+ return -1;
+ }
+ *tmp = '\0';
+
+ /* Get service
+ */
+ srv = strdup(ptr);
+ if ( srv ) {
+ if ( ! source ) {
+ ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(srv);
+ SH_FREE( new );
+ return ret;
+ }
+ }
+
+ if ( ! service ) {
+ ret = idmef_source_new_service(source, &service);
+ if ( ret < 0 ) {
+ free(srv);
+ SH_FREE( new );
+ return ret;
+ }
+ }
+
+ ret = idmef_service_new_name(service, &str);
+ if ( ret < 0 ) {
+ free(srv);
+ SH_FREE( new );
+ return ret;
+ }
+
+ prelude_string_set_nodup(str, srv);
+ }
+
+ SH_FREE( new );
+
+ ptr = get_value(msg, _("userid"), NULL);
+
+ if ( ptr ) {
+
+ idmef_user_id_t * user_id;
+
+ ret = idmef_source_new_user(source, &user);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ idmef_user_set_category(user, IDMEF_USER_CATEGORY_APPLICATION);
+
+ ret = idmef_user_new_user_id(user, &user_id, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_CURRENT_USER);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwnam_r(ptr, &pwd, buffer, SH_PWBUF_SIZE, &pw);
+#else
+ pw = sh_getpwnam(ptr);
+#endif
+ if ( pw )
+ idmef_user_id_set_number(user_id, pw->pw_uid);
+
+ ret = idmef_user_id_new_name(user_id, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ return ret;
+ }
+ prelude_string_set_nodup(str, ptr);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+
+
+ ptr = get_value(msg, _("path"), NULL);
+ tmp = get_value(msg, _("pid"), NULL);
+
+ if ( ptr ) {
+
+ /*
+ * In term of IDMEF, this is the full path,
+ * including the name.
+ */
+ ret = idmef_source_new_process(source, &process);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ ret = idmef_process_new_path(process, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+ prelude_string_set_nodup(str, ptr);
+
+
+ if ( NULL != strrchr(ptr, '/') ) {
+ ret = idmef_process_new_name(process, &str);
+ if ( ret == 0 ) {
+ ptr = strrchr(ptr, '/');
+ prelude_string_set_dup(str, ptr + 1);
+ }
+ } else {
+ ret = idmef_process_new_name(process, &str);
+ if ( ret == 0 ) {
+ prelude_string_set_dup(str, ptr);
+ }
+ }
+
+ idmef_process_set_pid(process, strtoul(tmp, NULL, 0));
+ }
+
+ if (tmp)
+ free(tmp);
+
+ return 0;
+}
+#endif
+
+static int get_login_info(char *msg, idmef_alert_t *alert)
+{
+ int ret;
+ char *ptr, *ip;
+ idmef_user_t *user;
+ idmef_node_t *node;
+ struct passwd *pw;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+ prelude_string_t *str;
+ idmef_user_id_t *user_id;
+ idmef_address_t *address;
+ idmef_target_t *target = idmef_alert_get_next_target(alert, NULL);
+ idmef_source_t *source = idmef_alert_get_next_source(alert, NULL);
+
+ ip = ptr = get_value(msg, _("ip"), NULL);
+ if ( ptr ) {
+ if ( ! source ) {
+ ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+ }
+
+ ret = idmef_source_new_node(source, &node);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ ret = idmef_address_new_address(address, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ prelude_string_set_nodup(str, ptr);
+ }
+
+ ptr = get_value(msg, _("host"), NULL);
+ if ( ptr ) {
+ if ( ip && strcmp(ptr, ip) == 0 )
+ free(ptr);
+ else {
+ if ( ! source ) {
+ ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+ }
+
+ ret = idmef_source_new_node(source, &node);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ ret = idmef_node_new_name(node, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ prelude_string_set_nodup(str, ptr);
+ }
+ }
+
+ ptr = get_value(msg, _("name"), NULL);
+ if ( ptr ) {
+ ret = idmef_target_new_user(target, &user);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ idmef_user_set_category(user, IDMEF_USER_CATEGORY_OS_DEVICE);
+
+ ret = idmef_user_new_user_id(user, &user_id, IDMEF_LIST_APPEND);
+ if ( ret < 0 ) {
+ free(ptr);
+ return ret;
+ }
+
+ idmef_user_id_set_type(user_id, IDMEF_USER_ID_TYPE_TARGET_USER);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwnam_r(ptr, &pwd, buffer, SH_PWBUF_SIZE, &pw);
+#else
+ pw = sh_getpwnam(ptr);
+#endif
+ if ( pw )
+ idmef_user_id_set_number(user_id, pw->pw_uid);
+
+ ret = idmef_user_id_new_name(user_id, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ return ret;
+ }
+ prelude_string_set_nodup(str, ptr);
+
+ ptr = get_value(msg, _("tty"), NULL);
+ if ( ptr ) {
+ ret = idmef_user_id_new_tty(user_id, &str);
+ if ( ret < 0 ) {
+ free(ptr);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ return ret;
+ }
+
+ prelude_string_set_nodup(str, ptr);
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+
+ ptr = get_time_value(msg, _("time"), NULL);
+ if ( ptr ) {
+ idmef_time_t *time;
+
+ ret = idmef_time_from_samhain(&time, ptr);
+ free(ptr);
+
+ if ( ret < 0 )
+ return ret;
+
+ idmef_alert_set_detect_time(alert, time);
+ }
+
+ return 0;
+}
+
+#if defined(SH_WITH_SERVER)
+static int node_set_address(idmef_node_t *node, const char *addr)
+{
+ int ret;
+ prelude_string_t *prelude_str;
+ idmef_address_t *idmef_addr;
+
+ ret = prelude_string_new(&prelude_str);
+ if ( ret < 0 )
+ goto err;
+
+ ret = prelude_string_set_ref(prelude_str, addr);
+ if ( ret < 0 )
+ goto err;
+
+ ret = idmef_address_new(&idmef_addr);
+ if ( ret < 0 )
+ goto err;
+
+ idmef_address_set_category(idmef_addr, IDMEF_ADDRESS_CATEGORY_IPV4_ADDR);
+ idmef_address_set_address(idmef_addr, prelude_str);
+ idmef_node_set_address(node, idmef_addr, 0);
+
+ return 0;
+ err:
+ return -1;
+}
+#endif
+
+
+static int samhain_alert_prelude(int priority, int sh_class,
+ char *message, unsigned long msgid,
+ char * inet_peer_ip)
+{
+ int ret;
+ idmef_time_t *time;
+ idmef_alert_t *alert;
+ idmef_message_t *idmef;
+ idmef_classification_t *classification;
+ idmef_assessment_t *assessment;
+ idmef_additional_data_t *data;
+ idmef_impact_t *impact;
+ idmef_target_t *target;
+ idmef_confidence_t *confidence;
+ prelude_string_t *str;
+#if defined(SH_WITH_SERVER)
+ idmef_node_t *node;
+#else
+ (void) inet_peer_ip;
+#endif
+
+ if ( !client || sh_class == STAMP)
+ return 0;
+
+ ret = idmef_message_new(&idmef);
+ if ( ret < 0 )
+ goto err;
+
+ ret = idmef_message_new_alert(idmef, &alert);
+ if ( ret < 0 )
+ goto err;
+
+ idmef_alert_set_analyzer(alert, idmef_analyzer_ref(prelude_client_get_analyzer(client)), IDMEF_LIST_PREPEND);
+
+ ret = idmef_time_new_from_gettimeofday(&time);
+ if ( ret < 0 )
+ goto err;
+ idmef_alert_set_detect_time(alert, time);
+
+ ret = idmef_time_new_from_gettimeofday(&time);
+ if ( ret < 0 )
+ goto err;
+ idmef_alert_set_create_time(alert, time);
+
+ ret = idmef_alert_new_classification(alert, &classification);
+ if ( ret < 0 )
+ goto err;
+
+ ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ goto err;
+
+ idmef_target_set_decoy(target, IDMEF_TARGET_DECOY_NO);
+
+#if defined(SH_WITH_SERVER)
+ if ( inet_peer_ip != NULL){
+ ret = idmef_target_new_node(target, &node);
+ if ( ret < 0 )
+ goto err;
+
+ ret = node_set_address(node, inet_peer_ip);
+ if ( ret < 0 )
+ goto err;
+
+ idmef_target_set_node(target, idmef_node_ref(node));
+ }
+ else
+#endif
+ if ( idmef_analyzer_get_node(prelude_client_get_analyzer(client)) ) {
+ idmef_node_ref(idmef_analyzer_get_node(prelude_client_get_analyzer(client)));
+ idmef_target_set_node(target, idmef_analyzer_get_node(prelude_client_get_analyzer(client)));
+ }
+
+ if ( strstr(message, _("path=")) ) {
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+ if ( msgid != MSG_FI_ADD && msgid != MSG_FI_ADD2 )
+ get_file_infos(target, message, IDMEF_FILE_CATEGORY_ORIGINAL);
+#endif
+
+ get_file_infos(target, message, IDMEF_FILE_CATEGORY_CURRENT);
+ }
+
+ ret = idmef_alert_new_assessment(alert, &assessment);
+ if ( ret < 0 )
+ goto err;
+
+ ret = idmef_assessment_new_impact(assessment, &impact);
+ if ( ret < 0 )
+ goto err;
+
+ ret = idmef_classification_new_text(classification, &str);
+ if ( ret < 0 )
+ goto err;
+
+ ret = get_login_info(message, alert);
+ if ( ret < 0 )
+ goto err;
+
+#ifdef SH_USE_PORTCHECK
+ if (msgid == MSG_PORT_MISS || msgid == MSG_PORT_NEW || msgid == MSG_PORT_RESTART || msgid == MSG_PORT_NEWPORT) {
+ ret = get_service_info(message, alert);
+ if ( ret < 0 )
+ goto err;
+ }
+#endif
+
+ map_policy_to_class(message, msgid, impact, str);
+
+#if 0
+ if ( priority == SH_ERR_SEVERE || priority == SH_ERR_FATAL )
+ idmef_impact_set_severity(impact, IDMEF_IMPACT_SEVERITY_HIGH);
+
+ else if ( priority == SH_ERR_ALL || priority == SH_ERR_INFO || priority == SH_ERR_NOTICE )
+ idmef_impact_set_severity(impact, IDMEF_IMPACT_SEVERITY_LOW);
+
+ else
+ idmef_impact_set_severity(impact, IDMEF_IMPACT_SEVERITY_MEDIUM);
+#endif
+ idmef_impact_set_severity(impact, map_severity(priority));
+
+ idmef_impact_set_completion(impact, IDMEF_IMPACT_COMPLETION_SUCCEEDED);
+
+ ret = idmef_assessment_new_confidence(assessment, &confidence);
+ if ( ret < 0 )
+ goto err;
+
+ idmef_confidence_set_rating(confidence, IDMEF_CONFIDENCE_RATING_HIGH);
+
+ ret = idmef_alert_new_additional_data(alert, &data, IDMEF_LIST_APPEND);
+ if ( ret < 0 )
+ goto err;
+
+ ret = idmef_additional_data_new_meaning(data, &str);
+ if ( ret < 0 )
+ goto err;
+
+ prelude_string_set_dup(str, _("Message generated by Samhain"));
+ idmef_additional_data_set_type(data, IDMEF_ADDITIONAL_DATA_TYPE_STRING);
+ idmef_additional_data_set_string_ref(data, message);
+
+ /* debug_print_message(idmef); */
+
+ prelude_client_send_idmef(client, idmef);
+ idmef_message_destroy(idmef);
+
+ return 0;
+
+ err:
+ idmef_message_destroy(idmef);
+ return -1;
+}
+
+
+int sh_prelude_alert(int priority, int sh_class, char *message, long msgflags, unsigned long msgid, char *inet_peer_ip)
+{
+ int ret;
+
+ (void) msgflags; /* fix compiler warning */
+
+ if ( initialized < 1 )
+ return -1;
+
+ ret = samhain_alert_prelude(priority, sh_class, message, msgid, inet_peer_ip);
+ if ( ret < 0 ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("Problem with IDMEF for prelude-ids support: alert lost"),
+ _("sh_prelude_alert"));
+ }
+
+ return ret;
+}
+
+
+
+int sh_prelude_set_profile(const char *arg)
+{
+ if ( profile ) {
+ free(profile);
+ profile = NULL;
+ }
+
+ if ( arg ) {
+ profile = strdup(arg);
+ if ( ! profile )
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Allow initialization of prelude; to be called
+ * after forking the daemon. Delays heartbeat
+ * start after config read until it is safe.
+ */
+void sh_prelude_reset(void)
+{
+ extern void sh_error_init_prelude();
+
+ ready_for_init = 1;
+ sh_error_init_prelude();
+ return;
+}
+
+
+
+void sh_prelude_stop(void)
+{
+ if (initialized < 1)
+ return;
+
+ if (sh.flag.isdaemon == S_TRUE)
+ prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_FAILURE);
+ else
+ prelude_client_destroy(client, PRELUDE_CLIENT_EXIT_STATUS_SUCCESS);
+
+ client = NULL;
+
+ prelude_deinit();
+
+ initialized = 0;
+ return;
+}
+
+
+
+int sh_prelude_init(void)
+{
+ int ret;
+ prelude_string_t *str;
+ idmef_analyzer_t *analyzer;
+ prelude_client_flags_t flags;
+#ifdef SH_NOFAILOVER
+ prelude_connection_pool_t *pool;
+ prelude_connection_pool_flags_t conn_flags;
+#endif
+
+ if (ready_for_init == 0)
+ return initialized;
+
+ if (initialized > 0)
+ return initialized;
+
+ prelude_thread_init(NULL);
+ prelude_init(&sh_argc_store, sh_argv_store);
+
+ ret = prelude_client_new(&client, profile ? profile : _("samhain"));
+ if ( ret < 0 ) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("Failed to initialize Prelude"), _("sh_prelude_init"));
+ initialized = -1;
+ return -1;
+ }
+
+ /*
+ * Enable automatic heartbeat sending.
+ */
+ flags = prelude_client_get_flags(client);
+ ret = prelude_client_set_flags(client, flags | PRELUDE_CLIENT_FLAGS_ASYNC_TIMER);
+
+ analyzer = prelude_client_get_analyzer(client);
+
+ ret = idmef_analyzer_new_model(analyzer, &str);
+ prelude_string_set_dup(str, IDMEF_ANALYZER_MODEL);
+
+ ret = idmef_analyzer_new_class(analyzer, &str);
+ prelude_string_set_dup(str, IDMEF_ANALYZER_CLASS);
+
+ ret = idmef_analyzer_new_version(analyzer, &str);
+ prelude_string_set_dup(str, IDMEF_ANALYZER_VERSION);
+
+#ifdef SH_NOFAILOVER
+ pool = prelude_client_get_connection_pool(client);
+ conn_flags = prelude_connection_pool_get_flags(pool);
+
+ conn_flags &= ~PRELUDE_CONNECTION_POOL_FLAGS_FAILOVER;
+ prelude_connection_pool_set_flags(pool, conn_flags);
+#endif
+
+ ret = prelude_client_start(client);
+ if ( ret < 0 ) {
+ prelude_perror(ret, _("error starting prelude client"));
+
+ if ( prelude_client_is_setup_needed(ret) )
+ prelude_client_print_setup_error(client);
+
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("Failed to start Prelude"), _("sh_prelude_init"));
+ initialized = -1;
+ return -1;
+ }
+
+ initialized = 1;
+ return 1;
+}
+
+/* HAVE_LIBPRELUDE_9 */
+#endif
+
diff --git a/src/sh_processcheck.c b/src/sh_processcheck.c
new file mode 100644
index 0000000..f5601c9
--- /dev/null
+++ b/src/sh_processcheck.c
@@ -0,0 +1,1557 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2006 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/***************************************************************************
+ *
+ * This file provides a module for samhain to check for hidden/faked/missing
+ * processes on the host.
+ *
+ */
+
+#include "config_xor.h"
+
+/* changed from 500 to 600 b/o FreeBSD (see sys/cdefs.h)
+ * which needs _POSIX_C_SOURCE >= 200112 for lstat()
+ */
+#if defined(__sun) || defined(__sun__) || defined(sun)
+#define _XOPEN_SOURCE 500
+#else
+#define _XOPEN_SOURCE 600
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <signal.h>
+#include <unistd.h>
+
+#ifdef _POSIX_PRIORITY_SCHEDULING
+#include <sched.h>
+#endif
+
+#ifdef HAVE_GETPRIORITY
+#include <errno.h>
+#include <sys/resource.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+
+#ifdef HAVE_REGEX_H
+#include <regex.h>
+#endif
+
+#include "samhain.h"
+#include "sh_modules.h"
+#include "sh_processcheck.h"
+#include "sh_utils.h"
+#include "sh_error.h"
+#include "sh_extern.h"
+#include "sh_calls.h"
+#include "sh_pthread.h"
+
+#ifdef SH_USE_PROCESSCHECK
+
+#define FIL__ _("sh_processcheck.c")
+
+#ifdef __linux__
+#define PS_THREADS
+#endif
+
+/* We won't want to build this into yule
+ */
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+SH_MUTEX_STATIC(mutex_proc_check, PTHREAD_MUTEX_INITIALIZER);
+
+/* sh_prochk_maxpid is one more than the largest pid
+ */
+static size_t sh_prochk_minpid = 0x0001;
+static size_t sh_prochk_maxpid = 0x8000;
+static size_t sh_prochk_size = 0;
+
+static int ShProchkActive = S_TRUE;
+static short * sh_prochk_res = NULL;
+
+static char * sh_prochk_pspath = NULL;
+static char * sh_prochk_psarg = NULL;
+
+#define SH_PROCHK_INTERVAL 300
+static time_t sh_prochk_interval = SH_PROCHK_INTERVAL;
+static int sh_prochk_severity = SH_ERR_SEVERE;
+static int sh_prochk_openvz = S_FALSE;
+
+static int sh_prochk_set_maxpid (const char * str);
+static int sh_prochk_set_minpid (const char * str);
+static int sh_prochk_set_active (const char *str);
+static int sh_prochk_add_process (const char *str);
+static int sh_prochk_set_pspath (const char *str);
+static int sh_prochk_set_psarg (const char *str);
+static int sh_prochk_set_interval(const char *str);
+static int sh_prochk_set_severity(const char *str);
+static int sh_prochk_set_openvz (const char *str);
+
+sh_rconf sh_prochk_table[] = {
+ {
+ N_("severityprocesscheck"),
+ sh_prochk_set_severity,
+ },
+ {
+ N_("processcheckexists"),
+ sh_prochk_add_process,
+ },
+ {
+ N_("processcheckactive"),
+ sh_prochk_set_active,
+ },
+ {
+ N_("processcheckminpid"),
+ sh_prochk_set_minpid,
+ },
+ {
+ N_("processcheckmaxpid"),
+ sh_prochk_set_maxpid,
+ },
+ {
+ N_("processcheckpspath"),
+ sh_prochk_set_pspath,
+ },
+ {
+ N_("processcheckpsarg"),
+ sh_prochk_set_psarg,
+ },
+ {
+ N_("processcheckinterval"),
+ sh_prochk_set_interval,
+ },
+ {
+ N_("processcheckisopenvz"),
+ sh_prochk_set_openvz,
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+#define SH_PROC_MISSING 1
+#define SH_PROC_FAKED 2
+#define SH_PROC_HIDDEN 4
+#define SH_PROC_EXISTS 8
+
+#ifndef HAVE_LSTAT
+#define lstat(x,y) stat(x,y)
+#endif /* HAVE_LSTAT */
+
+#if defined(S_IFLNK) && !defined(S_ISLNK)
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#else
+#if !defined(S_ISLNK)
+#define S_ISLNK(mode) (0)
+#endif
+#endif
+
+static const short SH_PR_PS = 0x0001;
+
+static const short SH_PR_GETSID = 0x0002;
+static const short SH_PR_KILL = 0x0004;
+static const short SH_PR_GETPGID = 0x0008;
+
+static const short SH_PR_LSTAT = 0x0010;
+static const short SH_PR_OPENDIR = 0x0020;
+static const short SH_PR_CHDIR = 0x0040;
+static const short SH_PR_SCHED = 0x0080;
+
+static const short SH_PR_PRIORITY = 0x0100;
+static const short SH_PR_STATVSF = 0x0200;
+
+static const short SH_PR_PS2 = 0x1000;
+static const short SH_PR_PS_ANY = 0x2000;
+static const short SH_PR_ALL = 0x4000;
+static const short SH_PR_ANY = 0x8000;
+
+/* /proc:
+ * linux: /proc/pid/exe
+ * freebsd: /proc/pid/file
+ * solaris10: /proc/pid/path/a.out
+ */
+static char * get_user_and_path (pid_t pid, char * user, size_t usrlen)
+{
+ extern char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
+
+ char path[128];
+ char * buf;
+ struct stat sbuf;
+ int len;
+ char * tmp;
+
+ sl_snprintf (path, sizeof(path), _("/proc/%ld/exe"), (unsigned long) pid);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
+ {
+ goto linkread;
+ }
+
+ sl_snprintf (path, sizeof(path), _("/proc/%ld/file"), (unsigned long) pid);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
+ {
+ goto linkread;
+ }
+
+ sl_snprintf (path, sizeof(path), _("/proc/%ld/path/a.out"), (unsigned long) pid);
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode))
+ {
+ goto linkread;
+ }
+
+ return NULL;
+
+ linkread:
+
+ buf = SH_ALLOC(PATH_MAX);
+ len = readlink(path, buf, PATH_MAX); /* flawfinder: ignore */
+ len = (len >= PATH_MAX) ? (PATH_MAX-1) : len;
+
+ if (len > 0)
+ {
+ buf[len] = '\0';
+ }
+ else
+ {
+ SH_FREE(buf);
+ return NULL;
+ }
+
+ tmp = sh_unix_getUIDname (SH_ERR_ALL, sbuf.st_uid, user, usrlen);
+
+ if (!tmp)
+ sl_snprintf (user, usrlen, "%ld", (unsigned long) sbuf.st_uid);
+
+ return buf;
+}
+
+
+struct watchlist {
+ char * str;
+ unsigned long pid;
+#ifdef HAVE_REGEX_H
+ regex_t preg;
+#endif
+ int seen;
+
+ struct watchlist *next;
+};
+
+static struct watchlist * process_check = NULL;
+
+static struct watchlist * list_missing = NULL;
+static struct watchlist * list_fake = NULL;
+static struct watchlist * list_hidden = NULL;
+
+/* recursively remove all list entries
+ */
+static void kill_list (struct watchlist * head)
+{
+ if (head->next)
+ kill_list (head->next);
+
+ if (head->str)
+ SH_FREE(head->str);
+ SH_FREE(head);
+
+ return;
+}
+
+
+/* check the list for old entries; clean out old entries; reset others
+ * Return number of non-obsolete entries
+ */
+static size_t clean_list (struct watchlist ** head_ptr)
+{
+ size_t count = 0;
+ struct watchlist * ptr = *head_ptr;
+ struct watchlist * pre = *head_ptr;
+
+ while (ptr)
+ {
+ if (ptr->seen == S_FALSE) /* obsolete entry */
+ {
+ if (ptr == pre) /* at head */
+ {
+ ptr = pre->next;
+ *head_ptr = pre->next;
+ if (pre->str)
+ SH_FREE(pre->str);
+ SH_FREE(pre);
+ pre = ptr;
+ }
+ else
+ {
+ pre->next = ptr->next;
+ if (ptr->str)
+ SH_FREE(ptr->str);
+ SH_FREE(ptr);
+ ptr = pre->next;
+ }
+ }
+ else
+ {
+ ++count;
+ ptr->seen = S_FALSE; /* reset status */
+ pre = ptr;
+ ptr = ptr->next;
+ }
+ }
+ return count;
+}
+
+/* check if process is in list; if not, add it and return false
+ */
+static int is_in_list (struct watchlist ** head_ptr,
+ char * str, unsigned long pid)
+{
+ struct watchlist * ptr = *head_ptr;
+
+ if (str)
+ {
+ while (ptr)
+ {
+ if (ptr->str && (0 == strcmp(str, ptr->str)))
+ {
+ ptr->seen = S_TRUE;
+ return S_TRUE;
+ }
+ ptr = ptr->next;
+ }
+ }
+ else
+ {
+ while (ptr)
+ {
+ if (ptr->pid == pid)
+ {
+ ptr->seen = S_TRUE;
+ return S_TRUE;
+ }
+ ptr = ptr->next;
+ }
+ }
+
+ ptr = SH_ALLOC(sizeof(struct watchlist));
+
+ if (str)
+ {
+ ptr->str = sh_util_strdup(str);
+ }
+ else
+ {
+ ptr->str = NULL;
+ ptr->pid = pid;
+ }
+ ptr->next = *head_ptr;
+ ptr->seen = S_TRUE;
+ *head_ptr = ptr;
+
+ return S_FALSE;
+}
+
+static int is_in_watchlist (const char *str, unsigned long num)
+{
+ struct watchlist * list = process_check;
+
+ while (list)
+ {
+#ifdef HAVE_REGEX_H
+ if (0 == regexec(&(list->preg), str, 0, NULL, 0))
+ {
+ list->seen = S_TRUE;
+ list->pid = num;
+ return S_TRUE;
+ }
+#else
+ if (strstr(str, list->str))
+ {
+ list->seen = S_TRUE;
+ list->pid = num;
+ return S_TRUE;
+ }
+#endif
+ list = list->next;
+ }
+ return S_FALSE;
+}
+
+/* These variables are not used anywhere. They only exist
+ * to assign &userold, &user to them, which keeps gcc from
+ * putting them into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+void * sh_dummy_413_watchlist = NULL;
+
+static void check_watchlist (short * res)
+{
+ struct watchlist * list = process_check;
+ char * tmp;
+ size_t indx;
+
+ /* Take the address to keep gcc from putting them into registers.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_413_watchlist = (void*) &list;
+
+ while (list)
+ {
+ if (list->seen == S_FALSE)
+ {
+ /* avoid repetition of messages
+ */
+ if (S_FALSE == is_in_list(&list_missing, list->str, 0))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (list->str);
+ sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
+ MSG_PCK_MISS,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ else
+ {
+ indx = list->pid - sh_prochk_minpid;
+
+ if (list->pid < sh_prochk_maxpid && list->pid >= sh_prochk_minpid &&
+ ((res[indx] & SH_PR_ANY) == 0) && /* not found */
+ ((res[indx] & SH_PR_PS) != 0) && /* seen in first ps */
+ ((res[indx] & SH_PR_PS2) != 0)) /* seen in second ps */
+ {
+ /* fake process, thus considered missing
+ */
+ if (S_FALSE == is_in_list(&list_missing, list->str, 0))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ tmp = sh_util_safe_name (list->str);
+ sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
+ MSG_PCK_MISS,
+ tmp);
+ SH_FREE(tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ list->seen = S_FALSE;
+ }
+ list = list->next;
+ }
+
+ sh_dummy_413_watchlist = NULL;
+ return;
+}
+
+/* Add 'str' to the list of watched processes for which
+ * existence should be checked.
+ */
+int sh_prochk_add_process (const char *str)
+{
+ struct watchlist *new;
+ int status;
+ char errbuf[256];
+
+ SL_ENTER(_("sh_prochk_add_process"));
+
+ if( str == NULL )
+ SL_RETURN(-1, _("sh_prochk_add_process") );
+
+ new = SH_ALLOC(sizeof(struct watchlist));
+ new->next = process_check;
+ new->str = sh_util_strdup(str);
+#ifdef HAVE_REGEX_H
+ status = regcomp(&(new->preg), str, REG_NOSUB|REG_EXTENDED);
+ if (status != 0)
+ {
+ regerror(status, &(new->preg), errbuf, sizeof(errbuf));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ errbuf, _("sh_processes_add_process"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(new->str);
+ SH_FREE(new);
+ SL_RETURN(-1, _("sh_prochk_add_process") );
+ }
+#endif
+ new->pid = 0;
+ new->seen = S_FALSE;
+
+ process_check = new;
+ SL_RETURN(0, _("sh_prochk_add_process") );
+}
+
+/* severity
+ */
+int sh_prochk_set_severity (const char * c)
+{
+ char tmp[32];
+ tmp[0] = '='; tmp[1] = '\0';
+ sl_strlcat (tmp, c, 32);
+ return sh_error_set_level (tmp, &sh_prochk_severity);
+}
+
+
+
+/* Path to ps
+ */
+int sh_prochk_set_pspath(const char *str)
+{
+ SL_ENTER(_("sh_prochk_set_pspath"));
+
+ if (!str || ('/' != str[0]))
+ SL_RETURN((-1), _("sh_prochk_set_pspath"));
+ if (sh_prochk_pspath)
+ SH_FREE(sh_prochk_pspath);
+#ifdef SH_EVAL_SHELL
+ sh_prochk_pspath = sh_util_strdup (str);
+ SL_RETURN((0), _("sh_prochk_set_pspath"));
+#else
+ sh_prochk_pspath = NULL;
+ SL_RETURN((-1), _("sh_prochk_set_pspath"));
+#endif
+}
+
+/* argument for ps
+ */
+int sh_prochk_set_psarg(const char *str)
+{
+ SL_ENTER(_("sh_prochk_set_psarg"));
+
+ if (sh_prochk_psarg)
+ SH_FREE(sh_prochk_psarg);
+#ifdef SH_EVAL_SHELL
+ sh_prochk_psarg = sh_util_strdup (str);
+ SL_RETURN((0), _("sh_prochk_set_psarg"));
+#else
+ (void) str;
+ sh_prochk_psarg = NULL;
+ SL_RETURN((-1), _("sh_prochk_set_psarg"));
+#endif
+}
+
+
+/* Decide if we're active.
+ */
+int sh_prochk_set_active(const char *str)
+{
+ int value;
+
+ SL_ENTER(_("sh_prochk_set_active"));
+
+ value = sh_util_flagval(str, &ShProchkActive);
+
+ SL_RETURN((value), _("sh_prochk_set_active"));
+}
+
+/* Are we on openvz.
+ */
+static int openvz_hidden = 0;
+
+int sh_prochk_set_openvz(const char *str)
+{
+ int value;
+
+ SL_ENTER(_("sh_prochk_set_openvz"));
+
+ value = sh_util_flagval(str, &sh_prochk_openvz);
+
+ if (sh_prochk_openvz != S_FALSE) {
+ openvz_hidden = 1;
+ }
+
+ SL_RETURN((value), _("sh_prochk_set_openvz"));
+}
+
+/* Minimum PID
+ */
+int sh_prochk_set_minpid(const char * str)
+{
+ size_t value;
+ char * foo;
+ int retval = 0;
+
+ SL_ENTER(_("sh_prochk_set_minpid"));
+
+ value = (size_t) strtoul(str, &foo, 0);
+ if (*foo != '\0')
+ retval = -1;
+ else
+ sh_prochk_minpid = value;
+
+ SL_RETURN((retval), _("sh_prochk_set_minpid"));
+}
+
+/* Maximum PID
+ */
+static int userdef_maxpid = 0;
+
+int sh_prochk_set_maxpid(const char * str)
+{
+ size_t value;
+ char * foo;
+ int retval = -1;
+
+ SL_ENTER(_("sh_prochk_set_maxpid"));
+
+ value = (size_t) strtoul(str, &foo, 0);
+
+ if (*foo == '\0' && S_TRUE == sl_ok_adds(value, 1)) {
+ sh_prochk_maxpid = value + 1;
+ userdef_maxpid = 1;
+ retval = 0;
+ }
+
+ SL_RETURN((retval), _("sh_prochk_set_maxpid"));
+}
+
+int sh_prochk_set_interval (const char * c)
+{
+ int retval = 0;
+ long val;
+
+ SL_ENTER(_("sh_prochk_set_interval"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("process check interval"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ retval = -1;
+ }
+ else
+ {
+ sh_prochk_interval = (time_t) val;
+ }
+ SL_RETURN(retval, _("sh_prochk_set_interval"));
+}
+
+
+
+/* Recurse to the end of the list and then free the data as we return
+ * back up towards the start, making sure to free any strdupped strings
+ */
+static void sh_prochk_free_list(struct watchlist *head)
+{
+ if ( head != NULL )
+ {
+ sh_prochk_free_list(head->next);
+ if (head->str)
+ SH_FREE(head->str);
+#ifdef HAVE_REGEX_H
+ regfree(&(head->preg));
+#endif
+ SH_FREE(head);
+ }
+ return;
+}
+
+#if defined(__linux__)
+#define PROC_PID_MAX _("/proc/sys/kernel/pid_max")
+
+static int proc_max_pid (size_t * procpid)
+{
+ char * ret;
+ unsigned long pid;
+ FILE * fd;
+ char str[128];
+ char * ptr;
+
+ SL_ENTER(_("proc_max_pid"));
+
+ if (userdef_maxpid != 0)
+ SL_RETURN((-1), _("proc_max_pid"));
+
+ if (0 == access(PROC_PID_MAX, R_OK)) /* flawfinder: ignore */
+ {
+ if (NULL != (fd = fopen(PROC_PID_MAX, "r")))
+ {
+ str[0] = '\0';
+ ret = fgets(str, 128, fd);
+ if (ret && *str != '\0')
+ {
+ pid = strtoul(str, &ptr, 0);
+ if (*ptr == '\0' || *ptr == '\n')
+ {
+ sl_fclose(FIL__, __LINE__, fd);
+ *procpid = (size_t) pid;
+ SL_RETURN(0, _("proc_max_pid"));
+ }
+ }
+ sl_fclose(FIL__, __LINE__, fd);
+ }
+ }
+ SL_RETURN((-1), _("proc_max_pid"));
+}
+#else
+static int proc_max_pid(size_t * dummy)
+{
+ (void) dummy;
+ return -1;
+}
+#endif
+
+static void sh_processes_tlist (char * list, size_t len, short res)
+{
+ if (res & SH_PR_PS) sl_strlcat(list, _(" ps(initial)"), len);
+ if (res & SH_PR_CHDIR) sl_strlcat(list, _(" chdir"), len);
+ if (res & SH_PR_OPENDIR) sl_strlcat(list, _(" opendir"), len);
+ if (res & SH_PR_LSTAT) sl_strlcat(list, _(" lstat"), len);
+ if (res & SH_PR_PRIORITY) sl_strlcat(list, _(" getpriority"), len);
+ if (res & SH_PR_SCHED) sl_strlcat(list, _(" sched_getparam"), len);
+ if (res & SH_PR_GETSID) sl_strlcat(list, _(" getsid"), len);
+ if (res & SH_PR_GETPGID) sl_strlcat(list, _(" getpgid"), len);
+ if (res & SH_PR_KILL) sl_strlcat(list, _(" kill"), len);
+ if (res & SH_PR_STATVSF) sl_strlcat(list, _(" statvfs"), len);
+ if (res & SH_PR_PS2) sl_strlcat(list, _(" ps(final)"), len);
+ return;
+}
+
+
+static short sh_processes_check (pid_t pid, short res)
+{
+ int have_checks = 0;
+ int need_checks = 0;
+#ifdef HAVE_PROCFS
+ char path[128];
+ struct stat buf;
+ DIR * dir;
+ int retval;
+#if defined(HAVE_STATVFS) && !defined(__FreeBSD__)
+ struct statvfs vfsbuf;
+#endif
+#endif
+
+#if !defined(sun) && !defined(__sun) && !defined(__sun__)
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ struct sched_param p;
+#endif
+#endif
+
+ if (0 == kill(pid, 0))
+ {
+ res |= SH_PR_KILL; res |= SH_PR_ANY; ++have_checks;
+ ++need_checks;
+ }
+ else if (errno != EPERM)
+ {
+ ++need_checks;
+ }
+
+
+#ifdef HAVE_GETPGID
+ if ((pid_t)-1 != getpgid(pid))
+ {
+ res |= SH_PR_GETPGID; res |= SH_PR_ANY; ++have_checks;
+ }
+ ++need_checks;
+#endif
+
+#ifdef HAVE_GETSID
+ if ((pid_t)-1 != getsid(pid))
+ {
+ res |= SH_PR_GETSID; res |= SH_PR_ANY; ++have_checks;
+ }
+ ++need_checks;
+#endif
+
+ /* sched_getparam() is broken on solaris 10, may segfault in librt
+ */
+#if !defined(sun) && !defined(__sun) && !defined(__sun__)
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ if (0 == sched_getparam (pid, &p))
+ {
+ res |= SH_PR_SCHED; res |= SH_PR_ANY; ++have_checks;
+ }
+ ++need_checks;
+#endif
+#endif
+
+#ifdef HAVE_GETPRIORITY
+ errno = 0;
+ if (((-1) == getpriority (PRIO_PROCESS, (int) pid)) && (errno == ESRCH));
+ else
+ {
+ res |= SH_PR_PRIORITY; res |= SH_PR_ANY; ++have_checks;
+ }
+ ++need_checks;
+#endif
+
+#ifdef HAVE_PROCFS
+ sl_snprintf (path, sizeof(path), "/proc/%ld", (unsigned long) pid);
+
+ do {
+ retval = lstat (path, &buf);
+ } while (retval < 0 && errno == EINTR);
+
+ if (0 == retval)
+ {
+ res |= SH_PR_LSTAT; res |= SH_PR_ANY; ++have_checks;
+ }
+ ++need_checks;
+
+ if (NULL != (dir = opendir(path)))
+ {
+ res |= SH_PR_OPENDIR; res |= SH_PR_ANY; ++have_checks;
+ closedir(dir);
+ }
+ ++need_checks;
+
+#if defined(HAVE_STATVFS) && !defined(__FreeBSD__)
+ do {
+ retval = statvfs (path, &vfsbuf);
+ } while (retval < 0 && errno == EINTR);
+
+ if (0 == retval)
+ {
+ res |= SH_PR_STATVSF; res |= SH_PR_ANY; ++have_checks;
+ }
+ ++need_checks;
+#endif
+
+#if !defined(SH_PROFILE)
+ if (0 == chdir(path))
+ {
+ res |= SH_PR_CHDIR; res |= SH_PR_ANY; ++have_checks;
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+ }
+ ++need_checks;
+#endif
+#endif
+
+ if (have_checks == need_checks)
+ {
+ res |= SH_PR_ALL;
+ }
+ return res;
+}
+
+extern int flag_err_debug;
+
+static int sh_processes_readps (FILE * in, short * res,
+ char * str, size_t len,
+ short flag, pid_t pid)
+{
+ int cc;
+ volatile unsigned int lnum = 0;
+ volatile unsigned long num = 0;
+ char c;
+ unsigned int pos = 0;
+#define SH_TWAIT_MAX 60
+ volatile unsigned int twait = 0;
+ char tstr[256];
+ enum { SKIP_TO_WS, SKIP_WS, SKIP_TO_WS2, SKIP_WS2, GET_NUM, SKIP_END, GET_NUM2 } line;
+
+ SL_ENTER(_("sh_processes_readps"));
+
+ if (!in) {
+ SL_RETURN((-1), _("sh_processes_readps"));
+ }
+
+ tstr[(sizeof(tstr)-1)] = '\0';
+ tstr[0] = '\0';
+ line = SKIP_END; /* Skip 1st line */
+
+ do
+ {
+ cc = fgetc(in);
+
+ if (EOF == cc)
+ {
+ if (feof(in))
+ {
+ break;
+ }
+ else if ((errno == EAGAIN) && (twait < SH_TWAIT_MAX))
+ {
+ clearerr(in);
+ retry_msleep(1, 0);
+ ++twait;
+ continue;
+ }
+#ifdef HOST_IS_OPENBSD
+ else if (errno == ENODEV)
+ {
+ clearerr(in);
+ continue;
+ }
+#endif
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message(errno, errbuf, sizeof(errbuf)),
+ _("sh_processes_readps"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ break;
+ }
+ }
+
+ c = (char) cc;
+
+ if (pos < (sizeof(tstr)-1))
+ {
+ tstr[pos] = c; ++pos;
+ }
+
+ switch(line)
+ {
+ case SKIP_END:
+ if (c == '\n')
+ {
+ tstr[pos-1] = '\0';
+ if (flag_err_debug == S_TRUE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, num,
+ MSG_E_SUBGEN,
+ tstr,
+ _("sh_processes_readps"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ /* fprintf(stderr, "<%ld> %s\n", num, tstr); */
+ line = SKIP_WS; pos = 0;
+ if (str != NULL && num == (unsigned long) pid)
+ sl_strlcpy(str, tstr, len);
+ if (lnum != 0)
+ is_in_watchlist (tstr, num);
+ ++lnum;
+ }
+ break;
+ case SKIP_TO_WS:
+ if (!isspace(cc))
+ break;
+ line = SKIP_WS;
+ /* fallthrough */
+ case SKIP_WS:
+ if (isspace(cc))
+ break;
+ num = 0;
+ line = GET_NUM;
+ /* fallthrough */
+ case GET_NUM:
+ if (isdigit(cc))
+ {
+ num = num * 10 + (c - '0');
+ break;
+ }
+ else if (isspace(cc))
+ {
+#ifdef PS_THREADS
+ num = 0;
+ line = SKIP_WS2;
+#else
+ if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
+ {
+ res[num - sh_prochk_minpid] |= flag;
+ }
+ line = SKIP_END;
+#endif
+ break;
+ }
+ else
+ {
+ line = SKIP_TO_WS;
+ break;
+ }
+ case SKIP_TO_WS2:
+ if (!isspace(cc))
+ break;
+ line = SKIP_WS2;
+ /* fallthrough */
+ case SKIP_WS2:
+ if (isspace(cc))
+ break;
+ num = 0;
+ line = GET_NUM2;
+ /* fallthrough */
+ case GET_NUM2:
+ if (isdigit(cc))
+ {
+ num = num * 10 + (c - '0');
+ break;
+ }
+ else if (isspace(cc))
+ {
+ if (num < sh_prochk_maxpid && num >= sh_prochk_minpid)
+ {
+ res[num - sh_prochk_minpid] |= flag;
+ }
+ line = SKIP_END;
+ break;
+ }
+ else
+ {
+ line = SKIP_TO_WS2;
+ break;
+ }
+ default:
+ SL_RETURN ((-1), _("sh_processes_readps"));
+ }
+ } while (1);
+
+ if (ferror(in))
+ {
+ SL_RETURN ((-1), _("sh_processes_readps"));
+ }
+
+ SL_RETURN ((0), _("sh_processes_readps"));
+}
+
+static int sh_processes_runps (short * res, char * str, size_t len,
+ short flag, pid_t pid)
+{
+ sh_tas_t task;
+
+ int status = 0;
+ char * p;
+ int retval = 0;
+ char dir[SH_PATHBUF];
+
+ SL_ENTER(_("sh_processes_runps"));
+
+ sh_ext_tas_init(&task);
+ p = sh_unix_getUIDdir (SH_ERR_ERR, task.run_user_uid, dir, sizeof(dir));
+ if (p)
+ {
+ (void) sh_ext_tas_add_envv (&task, _("HOME"), p);
+ }
+ (void) sh_ext_tas_add_envv (&task, _("SHELL"),
+ _("/bin/sh"));
+ (void) sh_ext_tas_add_envv (&task, _("PATH"),
+ _("/sbin:/usr/sbin:/bin:/usr/bin"));
+ if (sh.timezone != NULL)
+ {
+ (void) sh_ext_tas_add_envv(&task, "TZ", sh.timezone);
+ }
+
+ if (!sh_prochk_pspath)
+ sh_ext_tas_command(&task, PSPATH);
+ else
+ sh_ext_tas_command(&task, sh_prochk_pspath);
+
+ (void) sh_ext_tas_add_argv(&task, _("ps"));
+
+ if (!sh_prochk_psarg)
+ {
+#ifdef PS_THREADS
+ (void) sh_ext_tas_add_argv(&task, _("-eT"));
+#else
+ (void) sh_ext_tas_add_argv(&task, PSARG);
+#endif
+ }
+ else
+ {
+ (void) sh_ext_tas_add_argv(&task, sh_prochk_psarg);
+ }
+
+ task.rw = 'r';
+ task.fork_twice = S_FALSE;
+
+ status = sh_ext_popen(&task);
+ if (status != 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Could not open pipe"), _("sh_processes_runps"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN ((-1), _("sh_processes_runps"));
+ }
+
+ /* read from the open pipe
+ */
+ if (task.pipe != NULL)
+ {
+ retval = sh_processes_readps (task.pipe, res, str, len, flag, pid);
+ }
+
+ /* close pipe and return exit status
+ */
+ (void) sh_ext_pclose(&task);
+ sh_ext_tas_free (&task);
+ SL_RETURN ((retval), _("sh_processes_runps"));
+}
+
+/* Check whether there is a visible process
+ * with PID = i + 1024
+ */
+static size_t p_store = 0;
+
+static int openvz_ok(short * res, size_t i)
+{
+
+ if (sh_prochk_openvz == S_FALSE) {
+ return 0;
+ }
+
+ i += 1024;
+
+ if (i >= sh_prochk_size) {
+ return 0;
+ }
+
+ if ( ((res[i] & SH_PR_PS) || (res[i] & SH_PR_PS2)) && (res[i] & SH_PR_ANY))
+ {
+ /* This is a system process corresponding to a 'virtual'
+ * process that has a PID offset by 1024
+ */
+ return 1;
+ }
+
+ if (openvz_hidden > 0)
+ {
+ p_store = i;
+ --openvz_hidden;
+ return 1;
+ }
+ else if (i == p_store)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int sh_process_check_int (short * res)
+{
+ volatile size_t i;
+ size_t j;
+ char tests[512];
+ volatile int retval;
+
+ pid_t this_pid;
+
+ SL_ENTER(_("sh_process_check_int"));
+
+ this_pid = getpid();
+
+ if (!res)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Internal error: NULL argument, switching off"),
+ _("sh_process_check_int"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN ((-1), _("sh_process_check_int"));
+ }
+
+ retval = sh_processes_runps (res, NULL, 0, SH_PR_PS, 0);
+
+ for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
+ {
+ j = i - sh_prochk_minpid;
+ res[j] = sh_processes_check ((pid_t) i, res[j]);
+ }
+
+ retval += sh_processes_runps (res, NULL, 0, SH_PR_PS2, 0);
+
+ if (retval != 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Failed to run ps, switching off"),
+ _("sh_process_check_int"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN ((-1), _("sh_process_check_int"));
+ }
+
+ /* Evaluate results
+ */
+ for (i = sh_prochk_minpid; i != sh_prochk_maxpid; ++i)
+ {
+ /* don't check the current process
+ */
+ if (i == (size_t) this_pid)
+ continue;
+
+ j = i - sh_prochk_minpid;
+
+ if (((res[j] & SH_PR_PS) != 0) || ((res[j] & SH_PR_PS2) != 0))
+ {
+ res[j] |= SH_PR_PS_ANY;
+ }
+ else
+ {
+ res[j] &= ~SH_PR_PS_ANY;
+ }
+
+ tests[0] = '\0';
+
+ if ((res[j] & SH_PR_ANY) || (res[j] & SH_PR_PS_ANY))
+ {
+ /* list all tests where the pid was found
+ */
+ sh_processes_tlist (tests, sizeof(tests), res[j]);
+
+ /*
+ * case 1: in ps and found
+ */
+ if ((res[j] & SH_PR_PS_ANY) && (res[j] & SH_PR_ANY))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_OK,
+ (unsigned long) i, tests);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ /*
+ * case 2: not in ps and found
+ */
+ else if ((res[j] & SH_PR_PS_ANY) == 0)
+ {
+ res[j] = sh_processes_check ((pid_t) i, 0);
+ /*
+ * if still there, it is real and hidden
+ */
+ if ((res[j] & SH_PR_ANY) && !openvz_ok(res, j))
+ {
+ if (S_FALSE == is_in_list(&list_hidden, NULL, i))
+ {
+ char user[16];
+ char * aout;
+ char * safe;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ aout = get_user_and_path ((pid_t) i, user, sizeof(user));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ if (aout)
+ {
+ safe = sh_util_safe_name (aout);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
+ MSG_PCK_P_HIDDEN,
+ (unsigned long) i, tests, safe, user);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(safe);
+ SH_FREE(aout);
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
+ MSG_PCK_HIDDEN,
+ (unsigned long) i, tests);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ }
+ }
+
+ /*
+ * case 3: in ps, but not found
+ */
+ else
+ {
+ if (((res[j] & SH_PR_PS) != 0) && ((res[j] & SH_PR_PS2) != 0))
+ {
+ if (S_FALSE == is_in_list(&list_fake, NULL, i))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_prochk_severity, FIL__, __LINE__, 0,
+ MSG_PCK_FAKE,
+ (unsigned long) i, tests);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ }
+ }
+ } /* loop end */
+
+ check_watchlist (res);
+
+ SL_RETURN (0, _("sh_process_check_int"));
+}
+
+/* Initialise.
+ */
+static int sh_prochk_init_internal(void)
+{
+ SL_ENTER(_("sh_prochk_init"));
+
+ (void) proc_max_pid (&sh_prochk_maxpid);
+
+ if (sh_prochk_minpid > sh_prochk_maxpid)
+ ShProchkActive = S_FALSE;
+
+ /* We need to free anything allocated by the configuration functions if
+ * we find that the module is to be left inactive - otherwise _reconf()
+ * won't quite work.
+ */
+ if( ShProchkActive == S_FALSE )
+ {
+ sh_prochk_free_list(process_check);
+ process_check = NULL;
+ SL_RETURN(-1, _("sh_prochk_init"));
+ }
+
+ sh_prochk_size = sh_prochk_maxpid - sh_prochk_minpid;
+
+ if (sh_prochk_res == NULL)
+ {
+ sh_prochk_res = SH_ALLOC(sizeof(short) * sh_prochk_size);
+ }
+ memset (sh_prochk_res, 0, sizeof(short) * sh_prochk_size);
+
+ SL_RETURN(0, _("sh_prochk_init"));
+}
+
+int sh_prochk_init (struct mod_type * arg)
+{
+#ifndef HAVE_PTHREAD
+ (void) arg;
+#endif
+
+ if (ShProchkActive == S_FALSE)
+ return SH_MOD_FAILED;
+#ifdef HAVE_PTHREAD
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ return SH_MOD_THREAD;
+ else
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ sh_prochk_init_internal();
+ return SH_MOD_THREAD;
+ }
+#endif
+ return sh_prochk_init_internal();
+}
+
+int sh_prochk_timer(time_t tcurrent)
+{
+ static time_t lastcheck = 0;
+
+ SL_ENTER(_("sh_prochk_timer"));
+ if ((time_t) (tcurrent - lastcheck) >= sh_prochk_interval)
+ {
+ lastcheck = tcurrent;
+ SL_RETURN((-1), _("sh_prochk_timer"));
+ }
+ SL_RETURN(0, _("sh_prochk_timer"));
+}
+
+int sh_prochk_check(void)
+{
+ int status;
+
+ SL_ENTER(_("sh_prochk_check"));
+
+ SH_MUTEX_LOCK(mutex_proc_check);
+
+ status = 0;
+
+ if( ShProchkActive != S_FALSE )
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_PCK_CHECK,
+ (unsigned long) sh_prochk_minpid,
+ (unsigned long) (sh_prochk_maxpid-1));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ if (sh_prochk_res) {
+ memset (sh_prochk_res, 0, sizeof(short) * sh_prochk_size);
+ }
+ status = sh_process_check_int(sh_prochk_res);
+
+ if (status != 0)
+ ShProchkActive = S_FALSE;
+
+ /* clean out old entries which are not marked
+ * as missing/hidden/fake anymore
+ */
+ clean_list (&list_missing);
+ clean_list (&list_hidden);
+ clean_list (&list_fake);
+ }
+
+ SH_MUTEX_UNLOCK(mutex_proc_check);
+
+ SL_RETURN(status, _("sh_prochk_check"));
+}
+
+/* Free our lists and the associated memory
+ */
+int sh_prochk_cleanup(void)
+{
+ SL_ENTER(_("sh_prochk_cleanup"));
+
+ sh_prochk_reconf();
+
+ if (list_missing) {
+ kill_list(list_missing);
+ list_missing = NULL;
+ }
+ if (list_hidden) {
+ kill_list(list_hidden);
+ list_hidden = NULL;
+ }
+ if (list_fake) {
+ kill_list(list_fake);
+ list_fake = NULL;
+ }
+
+ SL_RETURN(0, _("sh_prochk_cleanup"));
+}
+
+/* Free our lists and the associated memory
+ */
+int sh_prochk_reconf(void)
+{
+ SL_ENTER(_("sh_prochk_reconf"));
+
+ SH_MUTEX_LOCK(mutex_proc_check);
+ userdef_maxpid = 0;
+ sh_prochk_maxpid = 0x8000;
+ sh_prochk_minpid = 0x0001;
+ sh_prochk_interval = SH_PROCHK_INTERVAL;
+ sh_prochk_openvz = S_FALSE;
+ p_store = 0;
+ openvz_hidden = 0;
+
+ sh_prochk_free_list(process_check);
+ process_check = NULL;
+ if (sh_prochk_res != NULL)
+ SH_FREE(sh_prochk_res);
+ sh_prochk_res = NULL;
+
+ if (sh_prochk_psarg)
+ SH_FREE(sh_prochk_psarg);
+ sh_prochk_psarg = NULL;
+ if (sh_prochk_pspath)
+ SH_FREE(sh_prochk_pspath);
+ sh_prochk_pspath = NULL;
+ SH_MUTEX_UNLOCK(mutex_proc_check);
+
+ SL_RETURN(0, _("sh_prochk_reconf"));
+}
+
+/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+/* #ifdef SH_USE_PROCESSCHECK */
+#endif
+
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_processcheck_watchlist_ok (CuTest *tc) {
+#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
+ CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
+ CuAssertTrue(tc,
+ S_TRUE == is_in_watchlist(" 1 ? 00:00:00 init", 0));
+ CuAssertTrue(tc,
+ S_FALSE == is_in_watchlist(" 1 ? 00:00:00 flix", 0));
+ CuAssertTrue(tc,
+ S_TRUE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/init -k start -DSSL", 0));
+ CuAssertTrue(tc,
+ S_FALSE == is_in_watchlist("25218 ? SNs 0:01 /usr/sbin/apache2 -k start -DSSL", 0));
+
+
+ sh_prochk_free_list(process_check);
+ process_check = NULL;
+ CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
+
+ CuAssertTrue(tc, 0 == sh_prochk_add_process("init"));
+ CuAssertTrue(tc, 0 == sh_prochk_add_process("ssh"));
+ CuAssertTrue(tc, 0 == sh_prochk_add_process("syslog"));
+ CuAssertTrue(tc, S_TRUE == is_in_watchlist("init", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_watchlist("ssh", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_watchlist("syslog", 0));
+
+ sh_prochk_free_list(process_check);
+ process_check = NULL;
+ CuAssertTrue(tc, S_FALSE == is_in_watchlist("init", 0));
+ CuAssertTrue(tc, S_FALSE == is_in_watchlist("ssh", 0));
+ CuAssertTrue(tc, S_FALSE == is_in_watchlist("syslog", 0));
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+
+void Test_processcheck_listhandle_ok (CuTest *tc) {
+#if defined(SH_USE_PROCESSCHECK) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
+ CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
+
+ if (list_missing)
+ kill_list(list_missing);
+ list_missing = NULL;
+
+ CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
+
+ if (list_missing)
+ kill_list(list_missing);
+ list_missing = NULL;
+
+ CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_FALSE == is_in_list(&list_missing, "foobar", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
+
+ CuAssertTrue(tc, 2 == clean_list(&list_missing));
+ CuAssertPtrNotNull(tc, list_missing);
+
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "init", 0));
+ CuAssertTrue(tc, S_TRUE == is_in_list(&list_missing, "foobar", 0));
+
+ CuAssertTrue(tc, 2 == clean_list(&list_missing));
+ CuAssertPtrNotNull(tc, list_missing);
+
+ CuAssertTrue(tc, 0 == clean_list(&list_missing));
+ CuAssertTrue(tc, NULL == list_missing);
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+
+
+/* #ifdef SH_CUTEST */
+#endif
+
diff --git a/src/sh_pthread.c b/src/sh_pthread.c
new file mode 100644
index 0000000..5e8d100
--- /dev/null
+++ b/src/sh_pthread.c
@@ -0,0 +1,323 @@
+#include "config_xor.h"
+
+#include "sh_pthread.h"
+
+#ifdef HAVE_PTHREAD
+
+#include <signal.h>
+#include "sh_calls.h"
+#include "sh_modules.h"
+extern volatile int sh_thread_pause_flag;
+
+SH_MUTEX_INIT(mutex_skey, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_INIT(mutex_resolv, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_INIT(mutex_pwent, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_INIT(mutex_readdir, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_INIT(mutex_thread_nolog, PTHREAD_MUTEX_INITIALIZER);
+
+int sh_pthread_setsigmask(int how, const void *set, void *oldset)
+{
+ return pthread_sigmask(how, (const sigset_t *)set, (sigset_t *)oldset);
+}
+
+void sh_pthread_mutex_unlock (void *arg)
+{
+ (void) pthread_mutex_unlock ((pthread_mutex_t *)arg);
+ return;
+}
+
+int sh_pthread_init_threadspecific(void)
+{
+ int rc = 0;
+#ifdef SH_STEALTH
+ do {
+ extern int sh_g_thread(void);
+
+ rc = sh_g_thread();
+ } while (0);
+#endif
+
+ return rc;
+}
+
+
+/*
+ * ---- Utilities for modules ----
+ */
+
+/* MODULES: init()
+ *
+ * #ifdef HAVE_PTHREAD
+ * if (arg != NULL)
+ * {
+ * if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ * return SH_MOD_THREAD;
+ * else
+ * return SH_MOD_FAILED;
+ * }
+ * #else
+ * return sh_utmp_init_internal();
+ * #endif
+ *
+ *
+ * sh_threaded_module_run(module_struct)
+ * -- calls internal init,
+ * -- polls timer,
+ * -- runs module check,
+ * -- runs sh_pthread_testcancel()
+ * -- returns (return == exit)
+ */
+
+#define SH_NUM_THREADS 16
+static pthread_t threads[SH_NUM_THREADS];
+static int ithread[SH_NUM_THREADS];
+static pthread_mutex_t create_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int sh_pthread_create(void *(*start_routine)(void*), void *arg)
+{
+ int rc, nthread = 1;
+ sigset_t signal_set;
+ int retval = 0;
+
+ pthread_mutex_lock(&create_mutex);
+
+ /* block all signals
+ */
+ sigfillset( &signal_set );
+#if defined(SCREW_IT_UP)
+ /*
+ * raise(SIGTRAP) sends to same thread, like
+ * pthread_kill(pthread_self(), sig); so we need to unblock the
+ * signal.
+ */
+ sigdelset( &signal_set, SIGTRAP );
+#endif
+ pthread_sigmask( SIG_BLOCK, &signal_set, NULL );
+
+ /* find a free slot in threads[]
+ */
+ while (nthread < SH_NUM_THREADS)
+ {
+ if (ithread[nthread] == 0)
+ break;
+ ++nthread;
+ if (nthread == SH_NUM_THREADS)
+ {
+ retval = -1;
+ goto err_out;
+ }
+ }
+
+ rc = pthread_create(&threads[nthread], NULL, start_routine, arg);
+ if (rc != 0)
+ {
+ retval = -1;
+ goto err_out;
+ }
+
+ ithread[nthread] = 1;
+
+ err_out:
+ pthread_sigmask( SIG_UNBLOCK, &signal_set, NULL );
+ pthread_mutex_unlock(&create_mutex);
+ return retval;
+}
+
+int sh_pthread_cancel_all()
+{
+ int i;
+ int ret = 0;
+
+ SH_MUTEX_LOCK(create_mutex);
+
+ for (i = 1; i < SH_NUM_THREADS; ++i)
+ {
+ if (ithread[i] != 0)
+ if (0 != pthread_cancel(threads[i]))
+ ithread[i] = 0;
+ }
+
+ for (i = 1; i < SH_NUM_THREADS; ++i)
+ {
+ if (ithread[i] != 0)
+ pthread_join(threads[i], NULL);
+ ithread[i] = 0;
+ }
+
+ SH_MUTEX_UNLOCK(create_mutex);
+ return ret;
+}
+
+/* ---- Utility functions for modules ----
+ */
+
+#undef S_TRUE
+#define S_TRUE 1
+#undef S_FALSE
+#define S_FALSE 0
+
+void sh_threaded_module_cleanup(void *arg)
+{
+ sh_mtype * this_module = (sh_mtype *) arg;
+ this_module->mod_cleanup();
+ this_module->initval = -1;
+ return;
+}
+
+void * sh_threaded_module_run(void *arg)
+{
+ sh_mtype * this_module = (sh_mtype *) arg;
+
+ /* First we lock the module. This ensures that it cannot be
+ * run twice.
+ */
+ pthread_cleanup_push(sh_pthread_mutex_unlock, (void*) &(this_module->mod_mutex));
+ pthread_mutex_lock(&(this_module->mod_mutex));
+
+ if (0 == sh_pthread_init_threadspecific())
+ {
+
+ if (0 == this_module->mod_init(NULL))
+ {
+ pthread_cleanup_push(sh_threaded_module_cleanup, arg);
+
+ while (1)
+ {
+ if (sh_thread_pause_flag != S_TRUE)
+ {
+ this_module->flags &= ~SH_MODFL_ISPAUSED;
+
+ if (0 != this_module->mod_timer(time(NULL)))
+ {
+ /* If module has been de-activated on reconfigure,
+ * mod_check() must return non-zero.
+ * The mod_cleanup() routine must then enable the
+ * module to be re-activated eventually.
+ */
+ if (0 != this_module->mod_check())
+ break;
+ pthread_testcancel();
+ }
+ }
+ else
+ {
+ this_module->flags |= SH_MODFL_ISPAUSED;
+ }
+ if (0 == (SH_MODFL_NOTIMER & this_module->flags) ||
+ sh_thread_pause_flag == S_TRUE)
+ retry_msleep(1,0);
+ }
+
+ pthread_cleanup_pop(1); /* notreached,but required */
+ }
+ }
+
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+
+/*
+ * ---- Implementation of recursive mutexes from libxml2 ----
+ */
+#if !defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
+/**
+ * libxml2 threads.c: set of generic threading related routines
+ *
+ * Gary Pennington <Gary.Pennington@uk.sun.com>
+ * daniel@veillard.com
+
+ * Except where otherwise noted in the source code (e.g. the files hash.c,
+ * list.c and the trio files, which are covered by a similar licence but
+ * with different Copyright notices) all the files are:
+ *
+ * Copyright (C) 1998-2003 Daniel Veillard. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is fur-
+ * nished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+ * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+ * NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Daniel Veillard shall not
+ * be used in advertising or otherwise to promote the sale, use or other deal-
+ * ings in this Software without prior written authorization from him.
+ */
+
+/* Modified NewRMutex -> InitRMutex. We use a static structure, rather than
+ * allocating one. Also dropped code for non-POSIX OSes.
+ */
+void sh_InitRMutex(struct sh_RMutex * tok)
+{
+ pthread_mutex_init(&tok->lock, NULL);
+ tok->held = 0;
+ tok->waiters = 0;
+ pthread_cond_init(&tok->cv, NULL);
+
+ return;
+}
+
+void sh_RMutexLock(struct sh_RMutex * tok)
+{
+ if (tok == NULL)
+ return;
+
+ pthread_mutex_lock(&tok->lock);
+ if (tok->held) {
+ if (pthread_equal(tok->tid, pthread_self())) {
+ tok->held++;
+ pthread_mutex_unlock(&tok->lock);
+ return;
+ } else {
+ tok->waiters++;
+ while (tok->held)
+ pthread_cond_wait(&tok->cv, &tok->lock);
+ tok->waiters--;
+ }
+ }
+ tok->tid = pthread_self();
+ tok->held = 1;
+ pthread_mutex_unlock(&tok->lock);
+}
+
+void sh_RMutexUnlock(void * arg)
+{
+ struct sh_RMutex * tok = (struct sh_RMutex *) arg;
+
+ if (tok == NULL)
+ return;
+
+ pthread_mutex_lock(&tok->lock);
+ tok->held--;
+ if (tok->held == 0) {
+ if (tok->waiters)
+ pthread_cond_signal(&tok->cv);
+ tok->tid = 0;
+ }
+ pthread_mutex_unlock(&tok->lock);
+}
+#endif
+
+#else
+
+#include <signal.h>
+
+int sh_pthread_setsigmask(int how, const void *set, void *oldset)
+{
+ return sigprocmask(how, (const sigset_t *)set, (sigset_t *)oldset);
+}
+
+
+#endif
diff --git a/src/sh_readconf.c b/src/sh_readconf.c
new file mode 100644
index 0000000..892be10
--- /dev/null
+++ b/src/sh_readconf.c
@@ -0,0 +1,1512 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+
+#include "samhain.h"
+#include "sh_calls.h"
+#include "sh_error.h"
+#include "sh_extern.h"
+#include "sh_unix.h"
+#include "sh_files.h"
+#include "sh_xfer.h"
+#include "sh_gpg.h"
+#include "sh_hash.h"
+#include "sh_dbIO.h"
+#include "sh_ignore.h"
+#include "sh_database.h"
+#include "sh_mail.h"
+#include "sh_modules.h"
+#include "sh_nmail.h"
+#include "sh_prelink.h"
+#ifdef HAVE_LIBPRELUDE
+#include "sh_prelude.h"
+#endif
+#include "sh_tiger.h"
+#include "sh_tools.h"
+#include "sh_utils.h"
+#include "sh_restrict.h"
+#include "sh_socket.h"
+
+extern int set_reverse_lookup (const char * c);
+
+#undef FIL__
+#define FIL__ _("sh_readconf.c")
+
+typedef enum {
+ SH_SECTION_NONE,
+ SH_SECTION_LOG,
+ SH_SECTION_MISC,
+ SH_SECTION_ATTRIBUTES,
+ SH_SECTION_READONLY,
+ SH_SECTION_LOGFILES,
+ SH_SECTION_LOGGROW,
+ SH_SECTION_NOIGNORE,
+ SH_SECTION_ALLIGNORE,
+ SH_SECTION_USER0,
+ SH_SECTION_USER1,
+ SH_SECTION_USER2,
+ SH_SECTION_USER3,
+ SH_SECTION_USER4,
+ SH_SECTION_PRELINK,
+#if defined (SH_WITH_MAIL)
+ SH_SECTION_MAIL,
+#endif
+#if defined (SH_WITH_CLIENT)
+ SH_SECTION_CLT,
+#endif
+#ifdef WITH_EXTERNAL
+ SH_SECTION_EXTERNAL,
+#endif
+#ifdef WITH_DATABASE
+ SH_SECTION_DATABASE,
+#endif
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ SH_SECTION_OTHER,
+#endif
+#ifdef SH_WITH_SERVER
+ SH_SECTION_CLIENTS,
+ SH_SECTION_SRV,
+#endif
+ SH_SECTION_THRESHOLD
+} ShSectionType;
+
+typedef struct str_ListSections {
+ const char * name;
+ int type;
+} sh_str_ListSections;
+
+struct str_ListSections tab_ListSections[] = {
+ { N_("[Log]"), SH_SECTION_LOG},
+ { N_("[Misc]"), SH_SECTION_MISC},
+ { N_("[Attributes]"), SH_SECTION_ATTRIBUTES},
+ { N_("[ReadOnly]"), SH_SECTION_READONLY},
+ { N_("[LogFiles]"), SH_SECTION_LOGFILES},
+ { N_("[GrowingLogFiles]"), SH_SECTION_LOGGROW},
+ { N_("[IgnoreAll]"), SH_SECTION_ALLIGNORE},
+ { N_("[IgnoreNone]"), SH_SECTION_NOIGNORE},
+ { N_("[User0]"), SH_SECTION_USER0},
+ { N_("[User1]"), SH_SECTION_USER1},
+ { N_("[User2]"), SH_SECTION_USER2},
+ { N_("[User3]"), SH_SECTION_USER3},
+ { N_("[User4]"), SH_SECTION_USER4},
+ { N_("[Prelink]"), SH_SECTION_PRELINK},
+#ifdef WITH_EXTERNAL
+ { N_("[External]"), SH_SECTION_EXTERNAL},
+#endif
+#ifdef WITH_DATABASE
+ { N_("[Database]"), SH_SECTION_DATABASE},
+#endif
+ { N_("[EventSeverity]"), SH_SECTION_THRESHOLD},
+#ifdef SH_WITH_SERVER
+ { N_("[Clients]"), SH_SECTION_CLIENTS},
+ { N_("[Server]"), SH_SECTION_SRV},
+#endif
+#if defined (SH_WITH_CLIENT)
+ { N_("[Client]"), SH_SECTION_CLT},
+#endif
+#if defined (SH_WITH_MAIL)
+ { N_("[Mail]"), SH_SECTION_MAIL},
+#endif
+ { NULL, SH_SECTION_NONE}
+};
+
+static char * sh_readconf_expand_value (const char * str)
+{
+#ifdef SH_EVAL_SHELL
+ char * tmp = sh_util_strdup(str);
+ char * out;
+ char * tmp_orig = tmp;
+
+ while (tmp && isspace((int)*tmp)) ++tmp;
+
+ if (tmp && tmp[0] == '$' && tmp[1] == '(')
+ {
+ size_t len = strlen(tmp);
+ while (isspace((int) tmp[len-1])) { tmp[len-1] = '\0'; --len; }
+ if (tmp[len-1] == ')')
+ {
+ tmp[len-1] = '\0';
+ out = sh_ext_popen_str(&tmp[2]);
+ SH_FREE(tmp_orig);
+ return out;
+ }
+ }
+ SH_FREE(tmp_orig);
+#endif
+ return sh_util_strdup(str);
+}
+
+enum {
+ SH_RC_ANY = 0,
+ SH_RC_HOST = 1,
+ SH_RC_SYSTEM = 2,
+ SH_RC_FILE = 3,
+ SH_RC_IFACE = 4,
+#ifdef SH_EVAL_SHELL
+ SH_RC_CMD = 5
+#endif
+};
+
+
+static int sh_readconf_cond_match(char * str, int line)
+{
+ int match = 0;
+ int negate = 1;
+ int cond_type = SH_RC_ANY;
+ char myident[3*SH_MINIBUF+3];
+ struct stat buf;
+
+ char * p = str;
+
+ if (*p == '!') { negate = 0; ++p; }
+ if (*p == '$') {
+ cond_type = SH_RC_SYSTEM; ++p; /* [!]$system */
+ }
+ else { /* *p == '@' */
+
+ ++p; while (isspace((int)*p)) ++p;
+
+ if (0 != strncasecmp(p, _("if "), 3)) {
+ cond_type = SH_RC_HOST; /* [!]$host */
+ }
+
+ else {
+
+ p += 3; while (isspace((int)*p)) ++p; /* skip the 'if\s+' */
+
+ if (0 == strncasecmp(p, _("not "), 4))
+ {
+ p += 4; while (isspace((int)*p)) ++p;
+ negate = 0;
+ match = 1;
+ }
+ else if (0 == strncmp(p, _("!"), 1))
+ {
+ ++p; while (isspace((int)*p)) ++p;
+ negate = 0;
+ match = 1;
+ }
+
+ if (0 == strncasecmp(p, _("file_exists "), 12))
+ {
+ p += 12; cond_type = SH_RC_FILE;
+ }
+ else if (0 == strncasecmp(p, _("interface_exists "), 17))
+ {
+ p += 17; cond_type = SH_RC_IFACE;
+ }
+ else if (0 == strncasecmp(p, _("hostname_matches "), 17))
+ {
+ p += 17; cond_type = SH_RC_HOST;
+ }
+ else if (0 == strncasecmp(p, _("system_matches "), 15))
+ {
+ p += 15; cond_type = SH_RC_SYSTEM;
+ }
+#ifdef SH_EVAL_SHELL
+ else if (0 == strncasecmp(p, _("command_succeeds "), 17))
+ {
+ p += 17; cond_type = SH_RC_CMD;
+ }
+#endif
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ sl_snprintf(errbuf, sizeof(errbuf),
+ _("Unsupported test at line %d of configuration file"),
+ line);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf,
+ _("sh_readconf_cond_match"));
+ return 0;
+ }
+ }
+ }
+
+ while (isspace((int)*p)) ++p;
+
+ switch (cond_type)
+ {
+ case SH_RC_HOST:
+ if (sl_strncmp (p, sh.host.name, strlen(sh.host.name)) == 0
+#ifdef HAVE_REGEX_H
+ || sh_util_regcmp (p, sh.host.name) == 0
+#endif
+ )
+ match = negate;
+ break;
+ case SH_RC_SYSTEM:
+ /*
+ * The system type, release, and machine.
+ */
+ sl_snprintf(myident, sizeof(myident), _("%s:%s:%s"),
+ sh.host.system, /* flawfinder: ignore */
+ sh.host.release, sh.host.machine);
+
+ if (sl_strncmp (p, myident, strlen(myident)) == 0
+#ifdef HAVE_REGEX_H
+ || sh_util_regcmp (p, myident) == 0
+#endif
+ )
+ match = negate;
+ break;
+ case SH_RC_FILE:
+ if (0 == retry_lstat(FIL__, __LINE__, p, &buf))
+ match = negate;
+ break;
+ case SH_RC_IFACE:
+ if (sh_tools_iface_is_present(p))
+ match = negate;
+ break;
+#ifdef SH_EVAL_SHELL
+ case SH_RC_CMD:
+ if (0 == sh_unix_run_command(p))
+ match = negate;
+ break;
+#endif
+ default:
+ /* do nothing */;
+ }
+ return match;
+}
+
+static int sh_readconf_is_end (char * str)
+{
+ int retval = 0;
+
+ if (str[0] == '@' || str[0] == '$')
+ {
+ char * p = str;
+ ++p; while (isspace((int)*p)) ++p;
+ if (
+ (0 == strncasecmp (p, _("end"), 3) && (p[3] == '\0' || isspace((int)p[3]))) ||
+ (0 == strncasecmp (p, _("fi"), 2) && (p[2] == '\0' || isspace((int)p[2])))
+ )
+ {
+ return 1;
+ }
+ }
+ return retval;
+}
+
+static int sh_readconf_is_else (char * str)
+{
+ int retval = 0;
+
+ if (str[0] == '@')
+ {
+ char * p = str;
+ ++p; while (isspace((int)*p)) ++p;
+ if ( 0 == strncasecmp (p, _("else"), 4) && (p[4] == '\0' || isspace((int)p[4])) )
+ {
+ return 1;
+ }
+ }
+ return retval;
+}
+
+static int sh_readconfig_line (char * line);
+
+static ShSectionType read_mode = SH_SECTION_NONE;
+
+static int conf_line = 0;
+
+/* --- Read the configuration file. ---
+ */
+int sh_readconf_read (void)
+{
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ /* This is for modules.
+ */
+ int modnum;
+#endif
+
+ int i;
+
+ SL_TICKET fd = -1;
+#if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO)
+ SL_TICKET fdTmp = -1;
+#endif
+#if defined(WITH_GPG) || defined(WITH_PGP)
+ SL_TICKET fdGpg = -1;
+#endif
+ char * tmp;
+
+#define SH_LINE_IN 16384
+ char * line_in;
+ char * line;
+
+ /* This is for nested conditionals.
+ */
+ int cond_depth = 0;
+ int cond_excl = 0;
+
+ int local_file = 1;
+ char local_flag = 'R';
+
+#if defined(WITH_GPG) || defined(WITH_PGP)
+ int signed_content = S_FALSE;
+ int true_content = S_FALSE;
+#endif
+#if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO)
+ int hidden_count = 0;
+#endif
+ uid_t euid;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_readconf_read"));
+
+ /* --- Open config file, exit on failure. ---
+ */
+#if defined(SH_WITH_CLIENT)
+ if (0 == sl_strcmp(file_path('C', 'R'), _("REQ_FROM_SERVER")))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_START);
+
+ fd = sh_xfer_request_file(_("CONF"));
+
+ if (!SL_ISERROR(fd))
+ {
+ local_file = 0;
+ }
+ else if (sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FBAD);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ else
+ {
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_TCP_FBAD);
+ sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_D_FAIL);
+ local_file = 1;
+ local_flag = 'I';
+ }
+ }
+#endif
+
+ /* Use a local configuration file.
+ */
+ if (local_file == 1)
+ {
+ if (0 != tf_trust_check (file_path('C', local_flag), SL_YESPRIV))
+ {
+ sl_get_euid(&euid);
+ dlog(1, FIL__, __LINE__,
+ _("The configuration file: %s is untrusted, i.e. an\nuntrusted user owns or can write to some directory in the path.\n"),
+ ( (NULL == file_path('C', local_flag))
+ ? _("(null)") : file_path('C', local_flag) ));
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_TRUST,
+ (long) euid,
+ ( (NULL == file_path('C', local_flag))
+ ? _("(null)") : file_path('C', local_flag) )
+ );
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ if (SL_ISERROR(fd = sl_open_read(FIL__, __LINE__,
+ file_path('C',local_flag),SL_YESPRIV)))
+ {
+ sl_get_euid(&euid);
+ dlog(1, FIL__, __LINE__,
+ _("Could not open the local configuration file for reading because\nof the following error: %s (errnum = %ld)\nIf this is a permission problem, you need to change file permissions\nto make the file readable for the effective UID: %d\n"),
+ sl_get_errmsg(), fd, (int) euid);
+ sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_NOACCESS,
+ (long) euid,
+ ( (NULL == file_path('C', local_flag))
+ ? _("(null)") : file_path('C', local_flag) )
+ );
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ }
+
+ /* Compute the checksum of the open file.
+ */
+ sl_strlcpy(sh.conf.hash,
+ sh_tiger_hash(file_path('C',local_flag), fd, TIGER_NOLIM,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ sl_rewind (fd);
+
+ line_in = SH_ALLOC(SH_LINE_IN);
+
+#if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO)
+ /* extract the data and copy to temporary file
+ */
+ fdTmp = open_tmp();
+
+ sh_unix_getline_stealth (0, NULL, 0); /* initialize */
+
+ while ( sh_unix_getline_stealth (fd, line_in, SH_LINE_IN-2) > 0) {
+ hidden_count++;
+ if (line_in[0] == '\n')
+ {
+ sl_write(fdTmp, line_in, 1);
+ }
+ else
+ {
+ sl_write_line(fdTmp, line_in, sl_strlen(line_in));
+ }
+#if defined(WITH_GPG) || defined(WITH_PGP)
+ if (0 == sl_strncmp(line_in, _("-----END PGP SIGNATURE-----"), 25))
+ break;
+#else
+ if (0 == sl_strncmp(line_in, _("[EOF]"), 5))
+ break;
+#endif
+ if (hidden_count > 1048576) /* arbitrary safeguard, 1024*1024 */
+ break;
+ }
+ sl_close(fd);
+ fd = fdTmp;
+ sl_rewind (fd);
+#endif
+
+#if defined(WITH_GPG) || defined(WITH_PGP)
+
+ /* extract the data and copy to temporary file
+ */
+ fdGpg = sh_gpg_extract_signed(fd);
+
+ sl_close(fd);
+ fd = fdGpg;
+
+ /* Validate signature of open file.
+ */
+ if (0 != sh_gpg_check_sign (fd, SIG_CONF))
+ {
+ SH_FREE(line_in);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ sl_rewind (fd);
+#endif
+
+
+ /* --- Start reading lines. ---
+ */
+ conf_line = 0;
+
+ while ( sh_unix_getline (fd, line_in, SH_LINE_IN-2) > 0) {
+
+ ++conf_line;
+
+ line = &(line_in[0]);
+
+ /* fprintf(stderr, "<%s>\n", line); */
+
+ /* Sun May 27 18:40:05 CEST 2001
+ */
+#if defined(WITH_GPG) || defined(WITH_PGP)
+ if (signed_content == S_FALSE)
+ {
+ if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNED MESSAGE-----")))
+ signed_content = S_TRUE;
+ else
+ continue;
+ }
+ else if (true_content == S_FALSE)
+ {
+ if (line[0] == '\n')
+ true_content = S_TRUE;
+ else
+ continue;
+ }
+ else if (signed_content == S_TRUE)
+ {
+ if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNATURE-----")))
+ break;
+ else if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNED MESSAGE-----")))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("second signed message in file"),
+ _("sh_readconf_read"));
+ dlog(1, FIL__, __LINE__,
+ _("There seems to be more than one signed message in the configuration\nfile. Please make sure there is only one signed message.\n"));
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1,
+ sh.prg_name);
+ SH_FREE(line_in);
+ aud_exit (FIL__, __LINE__,EXIT_FAILURE);
+ }
+ }
+#endif
+
+ /* Skip leading white space.
+ */
+ while (isspace((int)*line)) ++line;
+
+
+ /* Skip header etc.
+ */
+ if (line[0] == '#' || line[0] == '\0' || line[0] == ';' ||
+ (line[0] == '/' && line[1] == '/'))
+ continue;
+
+ /* Clip off trailing white space.
+ */
+ tmp = line + sl_strlen( line ); --tmp;
+ while( isspace((int) *tmp ) && tmp >= line ) *tmp-- = '\0';
+
+
+ /* --- an @host/@if/$system directive -------------- */
+
+ if (line[0] == '@' || (line[0] == '!' && line[1] == '@') ||
+ line[0] == '$' || (line[0] == '!' && line[1] == '$'))
+ {
+ if (sh_readconf_is_end(line))
+ {
+ if (0 == cond_depth) {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALD,
+ _("config file"),
+ (long) conf_line);
+ }
+ else {
+ if (cond_excl == cond_depth)
+ cond_excl = 0;
+ --cond_depth;
+ }
+ }
+ else if (sh_readconf_is_else(line))
+ {
+ if (0 == cond_depth) {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALD,
+ _("config file"),
+ (long) conf_line);
+ }
+ else if (cond_excl == cond_depth) {
+ cond_excl = 0;
+ }
+ else if (cond_excl == 0) {
+ cond_excl = cond_depth;
+ }
+ }
+ else
+ {
+ if (sh_readconf_cond_match(line, conf_line)) {
+ ++cond_depth;
+ }
+ else {
+ ++cond_depth;
+ if (cond_excl == 0)
+ cond_excl = cond_depth;
+ }
+ }
+ continue;
+ }
+
+ /* fprintf(stderr, "%d %s\n", cond_excl, line); */
+
+ /****************************************************
+ *
+ * Only carry on if this section is intended for us
+ *
+ ****************************************************/
+
+ if (cond_excl != 0) {
+ continue;
+ }
+
+ /* ------- starts a section ------------ */
+
+ else if (line[0] == '[')
+ {
+ read_mode = SH_SECTION_NONE;
+
+ if (0 == sl_strncasecmp (line, _("[EOF]"), 5)) {
+ goto nopel;
+ }
+
+ i = 0;
+
+ while (tab_ListSections[i].name != 0)
+ {
+ if (sl_strncasecmp (line, _(tab_ListSections[i].name),
+ sl_strlen(tab_ListSections[i].name)) == 0)
+ {
+ read_mode = tab_ListSections[i].type;
+ break;
+ }
+ ++i;
+ }
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (read_mode == SH_SECTION_NONE)
+ {
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ if (0 == sl_strncasecmp (line, _(modList[modnum].conf_section),
+ sl_strlen(modList[modnum].conf_section)) )
+ read_mode = SH_SECTION_OTHER;
+ }
+ }
+#endif
+ if (read_mode == SH_SECTION_NONE)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALHEAD,
+ (long) conf_line);
+ }
+ }
+
+ /* --- an %schedule directive ------------ */
+
+ else if (line[0] == '%' || (line[0] == '!' && line[1] == '%'))
+ {
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (line[0] == '!' && 0 == sl_strcasecmp(&(line[2]), _("SCHEDULE_TWO")))
+ set_dirList(1);
+ else if (0 == sl_strcasecmp(&(line[1]), _("SCHEDULE_TWO")))
+ set_dirList(2);
+#else
+ ;
+#endif
+ }
+
+ /* ------ no new section -------------- */
+
+
+ else if (read_mode != SH_SECTION_NONE)
+ {
+ if (0 != sh_readconfig_line (line))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALCONF,
+ (long) conf_line);
+ }
+ }
+ } /* while getline() */
+
+ nopel:
+
+ if (0 != cond_depth)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALDD,
+ _("config file"),
+ (long) conf_line);
+
+ sl_close (fd);
+
+ sh_error_fixup();
+
+ read_mode = SH_SECTION_NONE; /* reset b/o sighup reload */
+
+ SH_FREE(line_in);
+ SL_RETURN( 0, _("sh_readconf_read"));
+}
+
+int sh_readconf_set_path (char * which, const char * what)
+{
+ int len;
+ SL_ENTER( _("sh_readconf_set_path"));
+
+ if (which == NULL || what == NULL)
+ {
+ TPT((0, FIL__, __LINE__ , _("msg=<Input error>\n")));
+ SL_RETURN( -1, _("sh_readconf_set_path"));
+ }
+
+ if (0 == sl_strcmp(what, _("AUTO")))
+ {
+ len = sl_strlen(which);
+ if ( (len + sl_strlen(sh.host.name) + 2) > SH_PATHBUF)
+ {
+ TPT((0, FIL__, __LINE__ , _("msg=<Path too large: %s:%s>\n"),
+ which, sh.host.name));
+ SL_RETURN( -1, _("sh_readconf_set_path"));
+ }
+ else
+ {
+ which[len] = ':'; which[len+1] = '\0';
+ sl_strlcat(which, sh.host.name, SH_PATHBUF);
+ }
+ }
+ else /* not auto */
+ {
+ if (sl_strlen(what) > (SH_PATHBUF-1))
+ {
+ TPT((0, FIL__, __LINE__ , _("msg=<Path too large: %s>\n"), what));
+ SL_RETURN( -1, _("sh_readconf_set_path"));
+ }
+ else
+ {
+ sl_strlcpy(which, what, SH_PATHBUF);
+ }
+ }
+ SL_RETURN( 0, _("sh_readconf_set_path"));
+}
+
+int sh_readconf_set_database_path (const char * what)
+{
+ return (sh_readconf_set_path(sh.data.path, what));
+}
+
+int sh_readconf_set_logfile_path (const char * what)
+{
+ return (sh_readconf_set_path(sh.srvlog.name, what));
+}
+
+int sh_readconf_set_lockfile_path (const char * what)
+{
+ return( sh_readconf_set_path(sh.srvlog.alt, what));
+}
+
+
+
+
+typedef enum {
+ SET_MAILTIME,
+ SET_FILETIME
+} ShTimerItem;
+
+
+int sh_readconf_setTime (const char * str, ShTimerItem what)
+{
+ unsigned long i = atoi (str);
+
+ SL_ENTER( _("sh_readconf_setTime"));
+
+ if (i < LONG_MAX)
+ {
+ if (what == SET_MAILTIME)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Set mail timer to %ld>\n"), i));
+ sh.mailTime.alarm_interval = i;
+ }
+ else if (what == SET_FILETIME)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Set filecheck timer to %ld>\n"),i));
+ sh.fileCheck.alarm_interval = i;
+ }
+
+ SL_RETURN( 0, _("sh_readconf_setTime"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALL,
+ _("set timer"), (long) i);
+ SL_RETURN( (-1), _("sh_readconf_setTime"));
+ }
+}
+
+int sh_readconf_setMailtime (const char * c)
+{
+ return sh_readconf_setTime (c, SET_MAILTIME);
+}
+
+int sh_readconf_setFiletime (const char * c)
+{
+ return sh_readconf_setTime (c, SET_FILETIME);
+}
+
+int sh_readconf_set_nice (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_readconf_set_nice"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val < -20 || val > 20)
+ {
+ SL_RETURN((-1), _("sh_readconf_set_nice"));
+ }
+
+ val = (val < -19 ? -19 : val);
+ val = (val > 19 ? 19 : val);
+
+ sh.flag.nice = val;
+ SL_RETURN((0), _("sh_readconf_set_nice"));
+}
+
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+static int sh_readconf_set_delay (const char * c)
+{
+ unsigned long i = atol (c);
+
+ if (i > INT_MAX)
+ return -i;
+ sh.delayload = (int) i;
+ return 0;
+}
+#endif
+
+#ifdef FANCY_LIBCAP
+int sh_readconf_setCaps(const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_readconf_setCaps"));
+
+ i = sh_util_flagval(c, &sl_useCaps);
+ SL_RETURN((i), _("sh_readconf_setCaps"));
+}
+#endif
+
+typedef struct _cfg_options {
+ const char * optname;
+ ShSectionType section;
+ ShSectionType alt_section;
+ int (*func)(const char * opt);
+} cfg_options;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+extern int sh_set_schedule_one(const char * str);
+extern int sh_set_schedule_two(const char * str);
+extern int sh_set_silent_full (const char * str);
+#endif
+#if defined (SH_WITH_SERVER)
+extern int sh_socket_use (const char * c);
+extern int sh_socket_uid (const char * c);
+extern int sh_socket_password (const char * c);
+#endif
+
+cfg_options ext_table[] = {
+#if defined(WITH_EXTERNAL)
+ { N_("opencommand"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_setcommand },
+ { N_("closecommand"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_close_command },
+ { N_("setcommandline"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_add_argv },
+ { N_("setchecksum"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_checksum },
+ { N_("setdefault"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_add_default },
+ { N_("setenviron"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_add_environ },
+ { N_("setdeadtime"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_deadtime },
+ { N_("settype"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_type },
+ { N_("setcredentials"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_priv },
+ { N_("setfilternot"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_add_not },
+ { N_("setfilterand"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_add_and },
+ { N_("setfilteror"), SH_SECTION_EXTERNAL, SH_SECTION_NONE,
+ sh_ext_add_or },
+ { N_("externalseverity"),SH_SECTION_LOG, SH_SECTION_EXTERNAL,
+ sh_error_set_external },
+ { N_("externalclass"), SH_SECTION_LOG, SH_SECTION_EXTERNAL,
+ sh_error_external_mask },
+#endif
+
+#if defined(WITH_DATABASE)
+ { N_("usepersistent"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_use_persistent },
+ { N_("setdbname"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_set_database },
+ { N_("setdbtable"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_set_table },
+ { N_("setdbhost"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_set_host },
+ { N_("setdbuser"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_set_user },
+ { N_("setdbpassword"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_set_password },
+ { N_("addtodbhash"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ sh_database_add_to_hash },
+ { N_("databaseseverity"),SH_SECTION_LOG, SH_SECTION_DATABASE,
+ sh_error_set_database },
+ { N_("databaseclass"), SH_SECTION_LOG, SH_SECTION_DATABASE,
+ sh_error_database_mask },
+ { N_("setdbservertstamp"), SH_SECTION_DATABASE, SH_SECTION_NONE,
+ set_enter_wrapper },
+#endif
+
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ { N_("dir"), SH_SECTION_ATTRIBUTES, SH_SECTION_NONE,
+ sh_files_pushdir_attr },
+ { N_("file"), SH_SECTION_ATTRIBUTES, SH_SECTION_NONE,
+ sh_files_pushfile_attr },
+ { N_("dir"), SH_SECTION_READONLY, SH_SECTION_NONE,
+ sh_files_pushdir_ro },
+ { N_("file"), SH_SECTION_READONLY, SH_SECTION_NONE,
+ sh_files_pushfile_ro },
+ { N_("dir"), SH_SECTION_LOGFILES, SH_SECTION_NONE,
+ sh_files_pushdir_log },
+ { N_("file"), SH_SECTION_LOGFILES, SH_SECTION_NONE,
+ sh_files_pushfile_log },
+ { N_("dir"), SH_SECTION_LOGGROW, SH_SECTION_NONE,
+ sh_files_pushdir_glog },
+ { N_("file"), SH_SECTION_LOGGROW, SH_SECTION_NONE,
+ sh_files_pushfile_glog },
+ { N_("dir"), SH_SECTION_NOIGNORE, SH_SECTION_NONE,
+ sh_files_pushdir_noig },
+ { N_("file"), SH_SECTION_NOIGNORE, SH_SECTION_NONE,
+ sh_files_pushfile_noig },
+ { N_("dir"), SH_SECTION_ALLIGNORE, SH_SECTION_NONE,
+ sh_files_pushdir_allig },
+ { N_("file"), SH_SECTION_ALLIGNORE, SH_SECTION_NONE,
+ sh_files_pushfile_allig },
+
+ { N_("dir"), SH_SECTION_USER0, SH_SECTION_NONE,
+ sh_files_pushdir_user0 },
+ { N_("file"), SH_SECTION_USER0, SH_SECTION_NONE,
+ sh_files_pushfile_user0 },
+ { N_("dir"), SH_SECTION_USER1, SH_SECTION_NONE,
+ sh_files_pushdir_user1 },
+ { N_("file"), SH_SECTION_USER1, SH_SECTION_NONE,
+ sh_files_pushfile_user1 },
+ { N_("dir"), SH_SECTION_USER2, SH_SECTION_NONE,
+ sh_files_pushdir_user2 },
+ { N_("file"), SH_SECTION_USER2, SH_SECTION_NONE,
+ sh_files_pushfile_user2 },
+ { N_("dir"), SH_SECTION_USER3, SH_SECTION_NONE,
+ sh_files_pushdir_user3 },
+ { N_("file"), SH_SECTION_USER3, SH_SECTION_NONE,
+ sh_files_pushfile_user3 },
+ { N_("dir"), SH_SECTION_USER4, SH_SECTION_NONE,
+ sh_files_pushdir_user4 },
+ { N_("file"), SH_SECTION_USER4, SH_SECTION_NONE,
+ sh_files_pushfile_user4 },
+ { N_("dir"), SH_SECTION_PRELINK, SH_SECTION_NONE,
+ sh_files_pushdir_prelink },
+ { N_("file"), SH_SECTION_PRELINK, SH_SECTION_NONE,
+ sh_files_pushfile_prelink },
+
+ { N_("ignoreadded"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_ignore_add_new },
+ { N_("ignoremissing"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_ignore_add_del },
+ { N_("ignoremodified"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_ignore_add_mod },
+
+ { N_("skipchecksum"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_restrict_define },
+ { N_("filetype"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_restrict_add_ftype },
+
+
+ { N_("filecheckscheduleone"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_set_schedule_one },
+ { N_("filecheckscheduletwo"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_set_schedule_two },
+
+ { N_("usehardlinkcheck"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_check_hardlinks },
+ { N_("usersrccheck"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_use_rsrc },
+ { N_("hardlinkoffset"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_hle_reg },
+#if defined(USE_XATTR)
+ { N_("useselinuxcheck"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_setcheckselinux },
+#endif
+#if defined(USE_ACL)
+ { N_("useaclcheck"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_setcheckacl },
+#endif
+ { N_("loosedircheck"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_hash_loosedircheck },
+ { N_("addokchars"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_util_obscure_ok },
+ { N_("filenamesareutf8"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_util_obscure_utf8 },
+ { N_("setrecursionlevel"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_setrecursion },
+ { N_("checksumtest"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_util_setchecksum },
+ { N_("reportonlyonce"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_reportonce },
+ { N_("reportfulldetail"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_fulldetail },
+ { N_("uselocaltime"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_uselocaltime },
+
+ { N_("setnicelevel"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_set_nice },
+
+ { N_("startuploaddelay"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_set_delay },
+
+#if defined(FANCY_LIBCAP)
+ { N_("usecaps"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_setCaps },
+#endif
+
+ { N_("reportcheckflags"), SH_SECTION_MISC, SH_SECTION_NONE,
+ set_report_checkflags },
+
+ { N_("setdropcache"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sl_set_drop_cache },
+
+ { N_("setiolimit"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_set_io_limit },
+
+ { N_("versionstring"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_dbIO_version_string },
+
+ { N_("digestalgo"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_tiger_hashtype },
+
+ { N_("redefreadonly"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_readonly },
+
+ { N_("redeflogfiles"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_logfiles },
+
+ { N_("redefgrowinglogfiles"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_loggrow },
+
+ { N_("redefattributes"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_attributes },
+
+ { N_("redefignorenone"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_noignore },
+
+ { N_("redefignoreall"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_allignore },
+
+ { N_("redefuser0"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_user0 },
+
+ { N_("redefuser1"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_user1 },
+
+ { N_("redefuser2"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_user2 },
+
+ { N_("redefuser3"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_user3 },
+
+ { N_("redefuser4"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_user4 },
+
+ { N_("redefprelink"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_files_redef_prelink },
+
+
+ { N_("setprelinkpath"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelink_set_path },
+ { N_("setprelinkchecksum"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelink_set_hash },
+
+ { N_("setfullsilent"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_set_silent_full },
+
+ /* client or standalone
+ */
+#endif
+
+#ifdef SH_WITH_SERVER
+#ifdef INET_SYSLOG
+ { N_("setudpactive"), SH_SECTION_SRV, SH_SECTION_MISC,
+ set_syslog_active },
+#endif
+ { N_("setusesocket"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_socket_use },
+ { N_("setsocketallowuid"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_socket_uid },
+ { N_("setsocketpassword"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_socket_password },
+ { N_("setstripdomain"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_set_strip },
+ { N_("useseparatelogs"), SH_SECTION_SRV, SH_SECTION_MISC,
+ set_flag_sep_log },
+ { N_("setchrootdir"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_unix_set_chroot },
+ { N_("setclienttimelimit"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_set_time_limit },
+ { N_("setconnectiontimeout"),SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_set_timeout },
+ { N_("useclientseverity"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_use_clt_sev },
+ { N_("useclientclass"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_use_clt_class },
+ { N_("severitylookup"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_lookup_level },
+ { N_("setclientfromaccept"), SH_SECTION_SRV, SH_SECTION_MISC,
+ set_socket_peer },
+ { N_("setserverport"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_set_port },
+ { N_("setserverinterface"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_set_interface },
+ { N_("client"), SH_SECTION_CLIENTS, SH_SECTION_NONE,
+ sh_xfer_register_client },
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+ { N_("exportseverity"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_setexport },
+ { N_("exportclass"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_export_mask },
+#if defined(SH_WITH_SERVER)
+ { N_("setlogserver"), SH_SECTION_SRV, SH_SECTION_MISC,
+ sh_xfer_set_logserver },
+#else
+ { N_("setlogserver"), SH_SECTION_CLT, SH_SECTION_MISC,
+ sh_xfer_set_logserver },
+ { N_("setthrottle"), SH_SECTION_CLT, SH_SECTION_MISC,
+ sh_xfer_set_throttle_delay},
+ { N_("setdeltaretrycount"), SH_SECTION_CLT, SH_SECTION_MISC,
+ set_delta_retry_count},
+ { N_("setdeltaretryinterval"),SH_SECTION_CLT, SH_SECTION_MISC,
+ set_delta_retry_interval},
+#endif
+#endif
+ { N_("setfilechecktime"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_setFiletime },
+ { N_("setlooptime"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_util_setlooptime },
+
+#ifdef SH_WITH_MAIL
+ { N_("mailseverity"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_setseverity },
+ { N_("mailclass"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_mail_mask },
+ { N_("setmailtime"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_readconf_setMailtime },
+ { N_("setmailnum"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_mail_setNum },
+ { N_("setmailrelay"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_mail_set_relay },
+ { N_("setmailport"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_mail_set_port },
+ { N_("mailsingle"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_mail_setFlag },
+ { N_("mailsubject"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ set_mail_subject },
+ { N_("setmailsender"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_mail_set_sender },
+ { N_("setmailalias"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_add_alias },
+ { N_("setmailaddress"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_add_recipient },
+ { N_("closeaddress"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_close_recipient },
+ { N_("setaddrseverity"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_set_severity },
+ { N_("setmailfilternot"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_add_not },
+ { N_("setmailfilterand"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_add_and },
+ { N_("setmailfilteror"), SH_SECTION_MAIL, SH_SECTION_MISC,
+ sh_nmail_add_or },
+#endif
+ { N_("setbindaddress"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_calls_set_bind_addr },
+ { N_("daemon"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_setdeamon },
+ { N_("samhainpath"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_self_hash },
+ { N_("trusteduser"), SH_SECTION_MISC, SH_SECTION_NONE,
+ tf_add_trusted_user },
+ { N_("settimeserver"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_unix_settimeserver },
+
+ { N_("printseverity"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_setprint },
+ { N_("printclass"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_print_mask },
+
+ { N_("logseverity"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_setlog },
+ { N_("logclass"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_log_mask },
+
+ { N_("syslogseverity"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_set_syslog },
+ { N_("syslogclass"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_syslog_mask },
+#ifdef HAVE_LIBPRELUDE
+ { N_("preludeseverity"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_set_prelude },
+ { N_("preludeclass"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_error_prelude_mask },
+ { N_("preludeprofile"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelude_set_profile },
+ { N_("preludemaptoinfo"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelude_map_info },
+ { N_("preludemaptolow"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelude_map_low },
+ { N_("preludemaptomedium"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelude_map_medium },
+ { N_("preludemaptohigh"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_prelude_map_high },
+#endif
+
+ { N_("logcalls"), SH_SECTION_LOG, SH_SECTION_NONE,
+ sh_aud_set_functions },
+
+ { N_("messageheader"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_error_ehead },
+
+ { N_("setconsole"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_log_set_console },
+
+ { N_("setreportfile"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_efile_path },
+ { N_("setreportgroup"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_efile_group },
+
+#ifdef WITH_MESSAGE_QUEUE
+ { N_("messagequeueactive"),SH_SECTION_MISC, SH_SECTION_NONE,
+ enable_msgq },
+#endif
+
+ { N_("setreverselookup"), SH_SECTION_MISC, SH_SECTION_NONE,
+ set_reverse_lookup },
+
+ { N_("setdatabasepath"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_set_database_path },
+
+ { N_("setlogfilepath"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_set_logfile_path },
+
+ { N_("setlockfilepath"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_readconf_set_lockfile_path },
+
+ { N_("hidesetup"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_util_hidesetup },
+
+ { N_("syslogfacility"), SH_SECTION_LOG, SH_SECTION_MISC,
+ sh_log_set_facility },
+
+ { N_("syslogmapstampto"), SH_SECTION_LOG, SH_SECTION_MISC,
+ sh_log_set_stamp_priority },
+
+ { N_("mactype"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_util_sigtype },
+
+ { N_("avoidblock"), SH_SECTION_MISC, SH_SECTION_NONE,
+ sh_calls_set_sub },
+
+#ifdef SCREW_IT_UP
+ { N_("setsigtrapmaxduration"), SH_SECTION_MISC, SH_SECTION_MISC,
+ sh_sigtrap_max_duration_set },
+#endif
+
+ { NULL, 0, 0, NULL}
+};
+
+
+
+
+static int sh_readconfig_line (char * line)
+{
+ char * key;
+ const char * value;
+ char * value_dup;
+ char * tmp;
+ int i;
+ int good_opt = -1;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ int modnum, modkey;
+#endif
+
+ static const char *dummy = N_("dummy");
+
+ static const char *closing[] = {
+ N_("closecommand"),
+ N_("closeaddress"),
+ N_("logmonendgroup"),
+ N_("logmonendhost"),
+ NULL
+ };
+
+ static const char *ident[] = {
+ N_("severityreadonly"),
+ N_("severitylogfiles"),
+ N_("severitygrowinglogs"),
+ N_("severityignorenone"),
+ N_("severityignoreall"),
+ N_("severityattributes"),
+ N_("severitydirs"),
+ N_("severityfiles"),
+ N_("severitynames"),
+ N_("severityuser0"),
+ N_("severityuser1"),
+ N_("severityuser2"),
+ N_("severityuser3"),
+ N_("severityuser4"),
+ N_("severityprelink"),
+ NULL
+ };
+
+ static int identnum[] = {
+ SH_ERR_T_RO,
+ SH_ERR_T_LOGS,
+ SH_ERR_T_GLOG,
+ SH_ERR_T_NOIG,
+ SH_ERR_T_ALLIG,
+ SH_ERR_T_ATTR,
+ SH_ERR_T_DIR,
+ SH_ERR_T_FILE,
+ SH_ERR_T_NAME,
+ SH_ERR_T_USER0,
+ SH_ERR_T_USER1,
+ SH_ERR_T_USER2,
+ SH_ERR_T_USER3,
+ SH_ERR_T_USER4,
+ SH_ERR_T_PRELINK,
+ };
+
+ SL_ENTER(_("sh_readconf_line"));
+
+ /* convert to lowercase */
+
+ tmp = line;
+ while (*tmp != '=' && *tmp != '\0')
+ {
+ *tmp = tolower( (int) *tmp);
+ ++tmp;
+ }
+
+ key = line;
+
+ /* interpret line */
+
+ value = strchr(line, '=');
+
+ if (value == NULL || (*value) == '\0')
+ {
+ if (key != NULL)
+ {
+ i = 0;
+ while (closing[i] != NULL)
+ {
+ if (sl_strncmp(key,_(closing[i]),sl_strlen(closing[i])-1) == 0)
+ {
+ value = dummy;
+ goto ok_novalue;
+ }
+ ++i;
+ }
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: not key=value: %s>\n"),
+ line));
+ }
+ SL_RETURN(good_opt, _("sh_readconf_line"));
+ }
+ else
+ ++value;
+
+ /* skip leading whitespace
+ */
+ while ((*value) == ' ' || (*value) == '\t')
+ ++value;
+
+ if ((*value) == '\0') /* no value */
+ {
+ if (key != NULL)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: not key=value: %s>\n"),
+ line));
+ }
+ SL_RETURN(good_opt, _("sh_readconf_line"));
+ }
+
+ ok_novalue:
+
+ if (!sl_is_suid())
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ConfigFile: %s>\n"), line));
+ }
+
+ /* Expand shell expressions. This return allocated memory which we must free.
+ * If !defined(SH_EVAL_SHELL), this will reduce to a strdup.
+ */
+ value_dup = sh_readconf_expand_value(value);
+
+ if (!value_dup || (*value_dup) == '\0')
+ {
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<ConfigFile: empty after shell expansion: %s>\n"),
+ line));
+ SL_RETURN(good_opt, _("sh_readconf_line"));
+ }
+
+ value = value_dup;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (read_mode == SH_SECTION_OTHER)
+ {
+ for (modnum = 0; modList[modnum].name != NULL; ++modnum)
+ {
+ for (modkey = 0; modList[modnum].conf_table[modkey].the_opt != NULL;
+ ++modkey)
+ {
+ if (sl_strncmp (key,
+ _(modList[modnum].conf_table[modkey].the_opt),
+ sl_strlen(modList[modnum].conf_table[modkey].the_opt) ) == 0)
+ {
+ good_opt = 0;
+ if (0 != modList[modnum].conf_table[modkey].func(value))
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALS,
+ _(modList[modnum].conf_table[modkey].the_opt), value);
+ if (!sl_is_suid())
+ {
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<line = %s, option = %s>\n"), line,
+ _(modList[modnum].conf_table[modkey].the_opt)));
+ }
+ goto outburst;
+ }
+ }
+ }
+ }
+ outburst:
+#endif
+
+
+ if (read_mode == SH_SECTION_THRESHOLD)
+ {
+ i = 0;
+ while (ident[i] != NULL) {
+ if (sl_strncmp (key, _(ident[i]), sl_strlen(ident[i])) == 0)
+ {
+ good_opt = 0;
+ sh_error_set_iv (identnum[i], value);
+ break;
+ }
+ ++i;
+ }
+ }
+ else
+ {
+ i = 0;
+ while (ext_table[i].optname != NULL)
+ {
+ if ((ext_table[i].section == read_mode ||
+ ext_table[i].alt_section == read_mode) &&
+ sl_strncmp (key, _(ext_table[i].optname),
+ sl_strlen(ext_table[i].optname)) == 0)
+ {
+ good_opt = 0;
+ if (0 != ext_table[i].func (value))
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EINVALS,
+ _(ext_table[i].optname), value);
+ break;
+ }
+ ++i;
+ }
+ }
+
+ SH_FREE(value_dup);
+
+ SL_RETURN(good_opt, _("sh_readconf_line"));
+}
+
+
diff --git a/src/sh_registry.c b/src/sh_registry.c
new file mode 100644
index 0000000..16502a6
--- /dev/null
+++ b/src/sh_registry.c
@@ -0,0 +1,1013 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2010 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/***************************************************************************
+ *
+ * This file provides a module for samhain to check the MS Windows registry.
+ *
+ */
+
+#include "config_xor.h"
+
+#ifdef USE_REGISTRY_CHECK
+
+#include <windows.h>
+#include <stdio.h>
+#include <time.h>
+
+#define FIL__ _("sh_registry.c")
+
+/* We don't want to build this into yule
+ */
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+#include <sys/types.h>
+#include <regex.h>
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_modules.h"
+#include "sh_hash.h"
+#include "sh_tiger.h"
+
+static int check_key (char * name, int isSingle);
+
+static int sh_reg_set_active (const char *s);
+static int sh_reg_set_interval (const char * c);
+static int sh_reg_set_severity (const char *s);
+static int sh_reg_add_key (const char *s);
+static int sh_reg_add_hierarchy (const char *s);
+static int sh_reg_add_stop (const char *s);
+static int sh_reg_add_ign (const char *s);
+static int sh_reg_ign_time (const char *s);
+
+#define STOP_FALSE 0
+#define STOP_CHECK 1
+#define STOP_IGN 2
+
+sh_rconf sh_reg_check_table[] = {
+ {
+ N_("severitychange"),
+ sh_reg_set_severity,
+ },
+ {
+ N_("registrycheckactive"),
+ sh_reg_set_active,
+ },
+ {
+ N_("registrycheckinterval"),
+ sh_reg_set_interval,
+ },
+ {
+ N_("ignoretimestamponly"),
+ sh_reg_ign_time,
+ },
+ {
+ N_("singlekey"),
+ sh_reg_add_key,
+ },
+ {
+ N_("hierarchy"),
+ sh_reg_add_hierarchy,
+ },
+ {
+ N_("stopatkey"),
+ sh_reg_add_stop,
+ },
+ {
+ N_("ignorekey"),
+ sh_reg_add_ign,
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/* Runtime configuration */
+
+#define SH_REGISTRY_INTERVAL 300
+
+static int ShRegCheckActive = S_FALSE;
+static time_t sh_reg_check_interval = SH_REGISTRY_INTERVAL;
+static int sh_reg_check_severity = SH_ERR_SEVERE;
+static int ShRegIgnTime = S_FALSE;
+
+struct regkeylist {
+ char * name;
+ int stop;
+ int single;
+#ifdef HAVE_REGEX_H
+ regex_t preg;
+#endif
+
+ struct regkeylist *next;
+};
+
+static struct regkeylist * keylist = NULL;
+
+static int sh_reg_set_active(const char *s)
+{
+ int value;
+
+ SL_ENTER(_("sh_reg_set_active"));
+
+ value = sh_util_flagval(s, &ShRegCheckActive);
+
+ SL_RETURN((value), _("sh_reg_set_active"));
+}
+
+static int sh_reg_ign_time(const char *s)
+{
+ int value;
+
+ SL_ENTER(_("sh_reg_ign_time"));
+
+ value = sh_util_flagval(s, &ShRegIgnTime);
+
+ SL_RETURN((value), _("sh_reg_ign_time"));
+}
+
+static int sh_reg_set_interval (const char * c)
+{
+ int retval = 0;
+ long val;
+
+ SL_ENTER(_("sh_reg_set_interval"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("registry check interval"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ retval = -1;
+ }
+
+ sh_reg_check_interval = (time_t) val;
+ SL_RETURN(0, _("sh_reg_set_interval"));
+}
+
+static int sh_reg_set_severity (const char *s)
+{
+ char tmp[32];
+ tmp[0] = '='; tmp[1] = '\0';
+ sl_strlcat (tmp, s, 32);
+ return sh_error_set_level (tmp, &sh_reg_check_severity);
+}
+
+static int sh_reg_add_key_int (const char *s, int isSingle, int isStop)
+{
+ struct regkeylist * newkey;
+ size_t len = sl_strlen(s);
+
+ if (len > 0)
+ {
+ newkey = SH_ALLOC(sizeof(struct regkeylist));
+ newkey->single = isSingle;
+ newkey->stop = isStop;
+ newkey->name = NULL;
+
+ if (STOP_FALSE == isStop)
+ {
+ newkey->name = SH_ALLOC(len + 1);
+ sl_strlcpy(newkey->name, s, len+1);
+ }
+ else
+ {
+#ifdef HAVE_REGEX_H
+ int status = regcomp(&(newkey->preg), s, REG_NOSUB|REG_EXTENDED);
+ if (status != 0)
+ {
+ char errbuf[512];
+ char *p;
+ regerror(status, &(newkey->preg), errbuf, sizeof(errbuf));
+
+ sl_strlcat(errbuf, ": ", sizeof(errbuf));
+ p = sh_util_safe_name_keepspace(s);
+ sl_strlcat(errbuf, p, sizeof(errbuf));
+ SH_FREE(p);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ errbuf, _("sh_reg_add_key_int"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(newkey);
+ return -1;
+ }
+#else
+ newkey->name = SH_ALLOC(len + 1);
+ sl_strlcpy(newkey->name, s, len+1);
+#endif
+ }
+ newkey->next = keylist;
+ keylist = newkey;
+ return 0;
+ }
+ return -1;
+}
+
+static int sh_reg_add_key (const char *s)
+{
+ return sh_reg_add_key_int (s, S_TRUE, STOP_FALSE);
+}
+static int sh_reg_add_hierarchy (const char *s)
+{
+ return sh_reg_add_key_int (s, S_FALSE, STOP_FALSE);
+}
+static int sh_reg_add_stop (const char *s)
+{
+ return sh_reg_add_key_int (s, S_FALSE, STOP_CHECK);
+}
+static int sh_reg_add_ign (const char *s)
+{
+ return sh_reg_add_key_int (s, S_FALSE, STOP_IGN);
+}
+
+/* Module functions */
+
+int sh_reg_check_init(struct mod_type * arg)
+{
+#ifndef HAVE_PTHREAD
+ (void) arg;
+#endif
+
+ if (ShRegCheckActive == S_FALSE)
+ return SH_MOD_FAILED;
+#ifdef HAVE_PTHREAD
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ return SH_MOD_THREAD;
+ else
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ return SH_MOD_THREAD;
+ }
+#endif
+ return 0;
+}
+
+int sh_reg_check_timer(time_t tcurrent)
+{
+ static time_t lastcheck = 0;
+
+ SL_ENTER(_("sh_reg_check_timer"));
+ if ((time_t) (tcurrent - lastcheck) >= sh_reg_check_interval)
+ {
+ lastcheck = tcurrent;
+ SL_RETURN((-1), _("sh_reg_check_timer"));
+ }
+ SL_RETURN(0, _("sh_reg_check_timer"));
+}
+
+#define SH_REGFORM_NEW 1
+#define SH_REGFORM_OLD 2
+
+static char * format_changes(int flag, char * buf, size_t len,
+ time_t time_old, unsigned long size_old,
+ unsigned long keys_old, unsigned long values_old,
+ char * hash_old,
+ time_t time_new, unsigned long size_new,
+ unsigned long keys_new, unsigned long values_new,
+ char * hash_new)
+{
+ char timestr1[32];
+ char timestr2[32];
+ char timestr3[32];
+
+ char buf_old[512] = "";
+ char buf_new[512] = "";
+
+ if ((0 != (flag & SH_REGFORM_NEW)) && (NULL != hash_new))
+ {
+ (void) sh_unix_gmttime (time_new, timestr1, sizeof(timestr1));
+ (void) sh_unix_gmttime (keys_new, timestr2, sizeof(timestr2));
+ (void) sh_unix_gmttime (values_new, timestr3, sizeof(timestr3));
+
+#ifdef SH_USE_XML
+ sl_snprintf(buf_new, sizeof(buf_new),
+ "size_new=\"%lu\" mtime_new=\"%s\" ctime_new=\"%s\" atime_new=\"%s\" chksum_new=\"%s\"",
+ size_new, timestr1, timestr2, timestr3, hash_new);
+#else
+ sl_snprintf(buf_new, sizeof(buf_new),
+ "size_new=<%lu>, mtime_new=<%s>, ctime_new=<%s>, atime_new=<%s>, chksum_new=<%s>",
+ size_new, timestr1, timestr2, timestr3, hash_new);
+#endif
+ }
+
+ if ((0 != (flag & SH_REGFORM_OLD)) && (NULL != hash_old))
+ {
+ (void) sh_unix_gmttime (time_old, timestr1, sizeof(timestr1));
+ (void) sh_unix_gmttime (keys_old, timestr2, sizeof(timestr2));
+ (void) sh_unix_gmttime (values_old, timestr3, sizeof(timestr3));
+
+#ifdef SH_USE_XML
+ sl_snprintf(buf_old, sizeof(buf_old),
+ " size_old=\"%lu\" mtime_old=\"%s\" ctime_old=\"%s\" atime_old=\"%s\" chksum_old=\"%s\"",
+ size_old, timestr1, timestr2, timestr3, hash_old);
+#else
+ sl_snprintf(buf_old, sizeof(buf_old),
+ " size_old=<%lu>, mtime_old=<%s>, ctime_old=<%s>, atime_old=<%s>, chksum_old=<%s>",
+ size_old, timestr1, timestr2, timestr3, hash_old);
+#endif
+ }
+
+ sl_strlcpy(buf, buf_new, len);
+ sl_strlcat(buf, buf_old, len);
+
+ return buf;
+}
+
+static void report_missing_entry(const char * path)
+{
+ char * infobuf = SH_ALLOC(1024);
+ char * errbuf = SH_ALLOC(1024);
+ char * tmp = sh_util_safe_name (path);
+ char timestr[32];
+ struct store2db save;
+
+ memset(&save, '\0', sizeof(struct store2db));
+ sh_hash_db2pop (path, &save);
+
+ (void) sh_unix_gmttime (save.val1, timestr, sizeof(timestr));
+
+ sl_snprintf(infobuf, 1024, _("mtime=%s size=%lu subkeys=%lu values=%lu"),
+ timestr,
+ (unsigned long) save.val0,
+ (unsigned long) save.val2,
+ (unsigned long) save.val3);
+
+ (void) format_changes (SH_REGFORM_OLD, errbuf, 1024,
+ save.val1, save.val0, save.val2, save.val3, save.checksum,
+ 0, 0, 0, 0, NULL);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_reg_check_severity, FIL__, __LINE__, 0, MSG_REG_MISS,
+ infobuf, tmp, errbuf);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SH_FREE(tmp);
+ SH_FREE(errbuf);
+ SH_FREE(infobuf);
+ return;
+}
+
+int sh_reg_check_run(void)
+{
+ struct regkeylist *this = keylist;
+
+ if (this)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Checking the registry"),
+ _("sh_reg_check_run"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ while (this)
+ {
+ if (STOP_FALSE == this->stop)
+ {
+ /*
+ * -- Check key --
+ */
+ check_key (this->name, this->single);
+ }
+ this = this->next;
+ }
+ }
+ sh_hash_unvisited_custom ('H', report_missing_entry);
+
+ return 0;
+}
+
+int sh_reg_check_reconf(void)
+{
+ struct regkeylist *this;
+
+ while (keylist)
+ {
+ this = keylist;
+ keylist = keylist->next;
+
+ if (this->name)
+ SH_FREE(this->name);
+#ifdef HAVE_REGEX_H
+ if (STOP_FALSE != this->stop)
+ regfree(&(this->preg));
+#endif
+ SH_FREE(this);
+ }
+
+ sh_reg_check_interval = SH_REGISTRY_INTERVAL;
+
+ return 0;
+}
+
+int sh_reg_check_cleanup(void)
+{
+ sh_reg_check_reconf();
+ return 0;
+}
+
+/* >>>>>>>>>>>> Main check function <<<<<<<<<<<< */
+
+
+#include <windows.h>
+
+#define MAX_KEY_LENGTH (2*256)
+#define MAX_VALUE_NAME (2*16384)
+
+CHAR achValue[MAX_VALUE_NAME];
+
+unsigned long nKeys = 0;
+unsigned long nVals = 0;
+
+static int CheckThisSubkey (HKEY key, char * subkey, char * path,
+ int isSingle, int view);
+
+static time_t convertTime(FILETIME * ft)
+{
+ time_t result;
+
+ /* Shift high part up by 2^32
+ */
+ UINT64 date = ((UINT64)ft->dwHighDateTime) << 32;
+
+ /* Add low part
+ */
+ date |= (UINT64)ft->dwLowDateTime;
+
+ /* Subtract difference between Jan 1, 1601 and Jan 1, 1970
+ */
+ date -= ((UINT64)116444736) * ((UINT64)100) * ((UINT64)10000000);
+
+ /* Divide by number of 100-nanosecond intervals per second
+ */
+ date /= ((UINT64)10000000);
+
+ /* Convert to a time_t
+ */
+ result = (time_t) date;
+
+ return result;
+}
+
+#if !defined(KEY_WOW64_64KEY)
+#define KEY_WOW64_64KEY 0x0100;
+#endif
+#if !defined(KEY_WOW64_32KEY)
+#define KEY_WOW64_32KEY 0x0200;
+#endif
+
+
+#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
+
+int QueryKey(HKEY hKey, char * path, size_t pathlen, int isSingle)
+{
+ CHAR achKey[MAX_KEY_LENGTH]; /* buffer for subkey name */
+ DWORD cbName; /* size of name string */
+ /* CHAR achClass[MAX_PATH] = ""; *//* buffer for class name */
+ /* DWORD cchClassName = MAX_PATH/2;*//* size of class string */
+ DWORD cSubKeys=0; /* number of subkeys */
+ DWORD cbMaxSubKey; /* longest subkey size */
+ DWORD cchMaxClass; /* longest class string */
+ DWORD cValues; /* number of values for key */
+ DWORD cchMaxValue; /* longest value name */
+ DWORD cbMaxValueData; /* longest value data */
+ DWORD cbSecurityDescriptor; /* size of security descriptor */
+ FILETIME ftLastWriteTime; /* last write time */
+ DWORD lpType; /* type of data stored in value */
+ BYTE lpData[256]; /* buffer for data in value */
+ DWORD lpcbData; /* size of lpData buffer */
+ DWORD i, retCode;
+ DWORD cchValue = MAX_VALUE_NAME/2;
+
+ char hashbuf[KEYBUF_SIZE];
+ unsigned long totalSize = 0;
+ time_t fTime = 0;
+
+ char * tPath = NULL;
+ int doUpdate = S_FALSE;
+
+ retCode = RegQueryInfoKey(
+ hKey, /* key handle */
+ NULL /* achClass */, /* buffer for class name */
+ NULL /* &cchClassName */,/* size of class string */
+ NULL, /* reserved */
+ &cSubKeys, /* number of subkeys */
+ &cbMaxSubKey, /* longest subkey size */
+ &cchMaxClass, /* longest class string */
+ &cValues, /* number of values for this key */
+ &cchMaxValue, /* longest value name */
+ &cbMaxValueData, /* longest value data */
+ &cbSecurityDescriptor, /* security descriptor */
+ &ftLastWriteTime); /* last write time */
+
+ if (retCode != ERROR_SUCCESS)
+ {
+ return -1;
+ }
+
+ ++nKeys;
+
+ fTime = convertTime (&ftLastWriteTime);
+
+ /* Enumerate the subkeys, until RegEnumKeyEx fails. */
+
+ if (cSubKeys)
+ {
+ /*
+ * printf( "\nNumber of subkeys: %lu\n", (unsigned long) cSubKeys);
+ */
+
+ for (i=0; i<cSubKeys; i++)
+ {
+ cbName = MAX_KEY_LENGTH/2;
+ retCode = RegEnumKeyEx(hKey, i,
+ achKey,
+ &cbName,
+ NULL,
+ NULL,
+ NULL,
+ &ftLastWriteTime);
+
+ if (retCode == ERROR_SUCCESS && S_TRUE != isSingle)
+ {
+ /*
+ * _tprintf(TEXT("(%lu) %s\\%s\n"), (unsigned long) i+1,
+ * path, achKey);
+ */
+ CheckThisSubkey (hKey, achKey, path, isSingle, 0);
+ }
+ }
+ }
+
+ /* Enumerate the key values. */
+
+ if (cValues)
+ {
+ char hashtmp[3][KEYBUF_SIZE];
+
+ memset(hashbuf, '0', sizeof(hashbuf));
+
+ /* Loop over values and build checksum */
+
+ for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
+ {
+ LPBYTE lpDataAlloc = NULL;
+
+ cchValue = MAX_VALUE_NAME/2;
+ achValue[0] = '\0';
+ lpcbData = sizeof(lpData);
+ retCode = RegEnumValue(hKey, i,
+ achValue,
+ &cchValue,
+ NULL,
+ &lpType,
+ lpData,
+ &lpcbData);
+
+ if (retCode == ERROR_MORE_DATA)
+ {
+ lpDataAlloc = SH_ALLOC(lpcbData);
+
+ retCode = RegEnumValue(hKey, i,
+ achValue,
+ &cchValue,
+ NULL,
+ &lpType,
+ lpDataAlloc,
+ &lpcbData);
+ }
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ totalSize += lpcbData;
+
+ /* checksum(valuename) */
+ sh_tiger_hash (achValue, TIGER_DATA, cchValue,
+ hashtmp[0], KEYBUF_SIZE);
+
+ /* checksum(valuedata) */
+ if (NULL == lpDataAlloc)
+ {
+ sh_tiger_hash ((char*) lpData, TIGER_DATA, lpcbData,
+ hashtmp[1], KEYBUF_SIZE);
+ }
+ else
+ {
+ sh_tiger_hash ((char*) lpDataAlloc, TIGER_DATA, lpcbData,
+ hashtmp[1], KEYBUF_SIZE);
+ }
+
+ /* old_checksum */
+ memcpy(hashtmp[2], hashbuf, KEYBUF_SIZE);
+
+ /* hash(hash(valuename)+hash(valuedata)+old_hash) */
+ sh_tiger_hash ((char*) hashtmp, TIGER_DATA,
+ sizeof(hashtmp), hashbuf, sizeof(hashbuf));
+
+ ++nVals;
+ }
+
+ if (lpDataAlloc)
+ {
+ SH_FREE(lpDataAlloc);
+ }
+ }
+ }
+ else
+ {
+ /* no values */
+ sl_strlcpy(hashbuf, SH_KEY_NULL, sizeof(hashbuf));
+ }
+
+ /* Here we have:
+ * hashbuf [checksum over values],
+ * fTime [last write time],
+ * totalSize [size of all value data],
+ * cSubKeys [number of subkeys],
+ * cValues [number of values],
+ * path, pathlen [which may be up to 131072 (256*512) bytes]
+ */
+
+ if (pathlen > (PATH_MAX-1))
+ {
+ char hashbuf2[KEYBUF_SIZE];
+ char * p = strchr(path, '\\');
+
+ if (p)
+ {
+ char *q = p;
+
+ ++p;
+
+ tPath = SH_ALLOC(256 + KEYBUF_SIZE);
+ *q = '\0';
+ sl_strlcpy(tPath, path, 256); /* truncates */
+ *q = '\\';
+ sl_strlcat(tPath, "\\", 257);
+ (void) sh_tiger_hash(p, TIGER_DATA, sl_strlen(p),
+ hashbuf2, sizeof(hashbuf2));
+ sl_strlcat(tPath, hashbuf2, 256 + KEYBUF_SIZE);
+ }
+ }
+
+ if (sh.flag.checkSum == SH_CHECK_CHECK || sh.flag.update == S_TRUE)
+ {
+ struct store2db save;
+
+ memset(&save, '\0', sizeof(struct store2db));
+
+ if (tPath)
+ {
+ sh_hash_db2pop (tPath, &save);
+ }
+ else
+ {
+ sh_hash_db2pop (path, &save);
+ }
+
+ if (save.size == -1)
+ {
+ /* Not in database */
+
+ char * infobuf = SH_ALLOC(1024);
+ char * errbuf = SH_ALLOC(1024);
+ char * tmp = sh_util_safe_name ((tPath == NULL) ? path : tPath);
+ char timestr[32];
+
+ (void) sh_unix_gmttime (fTime, timestr, sizeof(timestr));
+
+ sl_snprintf(infobuf, 1024,
+ _("mtime=%s size=%lu subkeys=%lu values=%lu"),
+ timestr,
+ (unsigned long) totalSize,
+ (unsigned long) cSubKeys,
+ (unsigned long) cValues);
+
+ (void) format_changes (SH_REGFORM_NEW, errbuf, 1024,
+ 0, 0, 0, 0, NULL,
+ fTime, totalSize, cSubKeys, cValues, hashbuf);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_reg_check_severity, FIL__, __LINE__,
+ 0, MSG_REG_NEW,
+ infobuf, tmp, errbuf);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SH_FREE(tmp);
+ SH_FREE(errbuf);
+ SH_FREE(infobuf);
+
+ doUpdate = S_TRUE;
+ }
+ else if (save.val0 != totalSize ||
+ save.val2 != cSubKeys ||
+ save.val3 != cValues ||
+ 0 != strcmp(save.checksum, hashbuf) ||
+ ( (((time_t) save.val1) != fTime) && (ShRegIgnTime == S_FALSE)) )
+ {
+ /* Change detected */
+ char * infobuf = SH_ALLOC(1024);
+ char * errbuf = SH_ALLOC(1024);
+ char * tmp = sh_util_safe_name ((tPath == NULL) ? path : tPath);
+ char timestr_new[32];
+
+ (void) sh_unix_gmttime (fTime, timestr_new, sizeof(timestr_new));
+
+ sl_snprintf(infobuf, 1024,
+ _("mtime=%s size %lu->%lu subkeys %lu->%lu values %lu->%lu checksum %s"),
+ timestr_new,
+ (unsigned long) save.val0, (unsigned long) totalSize,
+ (unsigned long) save.val2, (unsigned long) cSubKeys,
+ (unsigned long) save.val3, (unsigned long) cValues,
+ (0 == strcmp(save.checksum, hashbuf)) ? _("good") : _("bad"));
+
+ (void) format_changes (SH_REGFORM_OLD|SH_REGFORM_NEW, errbuf, 1024,
+ save.val1, save.val0,
+ save.val2, save.val3, save.checksum,
+ fTime, totalSize,
+ cSubKeys, cValues, hashbuf);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(sh_reg_check_severity, FIL__, __LINE__,
+ 0, MSG_REG_CHANGE,
+ infobuf, tmp, errbuf);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SH_FREE(tmp);
+ SH_FREE(errbuf);
+ SH_FREE(infobuf);
+
+ doUpdate = S_TRUE;
+ }
+
+ }
+
+ if ( sh.flag.checkSum == SH_CHECK_INIT || doUpdate == S_TRUE /* change detected */ )
+ {
+ struct store2db save;
+
+ memset(&save, '\0', sizeof(struct store2db));
+
+ save.val0 = totalSize;
+ save.val1 = fTime;
+ save.val2 = cSubKeys;
+ save.val3 = cValues;
+ sl_strlcpy(save.checksum, hashbuf, KEY_LEN+1);
+
+ if (tPath)
+ {
+ sh_hash_push2db (tPath, &save);
+ }
+ else
+ {
+ sh_hash_push2db (path, &save);
+ }
+ }
+
+ /* Without this, freshly updated entries would get deleted
+ * as 'not seen'.
+ */
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ if (tPath)
+ sh_hash_set_visited (tPath);
+ else
+ sh_hash_set_visited (path);
+ }
+
+ if (tPath)
+ {
+ SH_FREE(tPath);
+ }
+
+ return 0;
+}
+
+static int check_for_stop (char * name)
+{
+ struct regkeylist *this = keylist;
+
+ while (this)
+ {
+ if (STOP_FALSE != this->stop)
+ {
+#ifdef HAVE_REGEX_H
+ if (0 == regexec(&(this->preg), name, 0, NULL, 0))
+ return this->stop;
+#else
+ if (0 == strcmp(this->name, name))
+ return this->stop;
+#endif
+ }
+ this = this->next;
+ }
+ return STOP_FALSE;
+}
+
+
+int CheckThisSubkey (HKEY key, char * subkey, char * path, int isSingle,
+ int view)
+{
+ HKEY hTestKey;
+ LONG qError;
+ char * newpath;
+ size_t len;
+ int retval = -1;
+
+ len = strlen(path) + 1 + strlen(subkey) + 1;
+ newpath = SH_ALLOC(len);
+ snprintf(newpath, len, "%s\\%s", path, subkey);
+
+ /* Check for stop condition, if not single key.
+ * Set flag to isSingle = S_TRUE if we should stop here.
+ */
+ if (S_TRUE != isSingle)
+ {
+ int isStop = check_for_stop(newpath);
+
+ if (STOP_CHECK == isStop)
+ {
+ isSingle = S_TRUE;
+ }
+ else if (STOP_IGN == isStop)
+ {
+ SH_FREE(newpath);
+ return 0;
+ }
+ }
+
+ len = strlen(path) + 1 + strlen(subkey) + 1;
+ newpath = SH_ALLOC(len);
+ snprintf(newpath, len, "%s\\%s", path, subkey);
+
+ qError = RegOpenKeyEx( key,
+ subkey,
+ 0,
+ (KEY_READ | view),
+ &hTestKey);
+
+
+ if (qError == ERROR_SUCCESS)
+ {
+ QueryKey(hTestKey, newpath, len-1, isSingle);
+ RegCloseKey(hTestKey);
+ retval = 0;
+ }
+ else
+ {
+ /* Error message */
+ LPVOID lpMsgBuf;
+
+ char * tmp = sh_util_safe_name (newpath);
+ size_t tlen = sl_strlen(tmp);
+
+ if (S_TRUE == sl_ok_adds(64, tlen))
+ {
+ char * errbuf;
+ size_t elen;
+
+ tlen += 64;
+
+ elen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ qError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ if (elen > 0 && S_TRUE == sl_ok_adds(elen, tlen))
+ {
+ tlen += elen;
+
+ errbuf = SH_ALLOC(elen + tlen);
+ sl_snprintf(errbuf, 64+tlen, _("Failed to open key %s: %s"),
+ tmp, lpMsgBuf);
+ LocalFree(lpMsgBuf);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf, _("CheckThisSubkey"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SH_FREE(errbuf);
+ }
+ }
+ sh_reg_add_ign (newpath);
+ SH_FREE(tmp);
+ }
+
+ SH_FREE(newpath);
+ return retval;
+}
+
+
+int check_key (char * key, int isSingle)
+{
+ HKEY topKey;
+ char * subkey;
+ char path[20] = "";
+ int pos = 0;
+
+ if (0 == strncmp(key, _("HKEY_CLASSES_ROOT"), 17))
+ {
+ topKey = HKEY_CLASSES_ROOT;
+ pos = 17;
+ strncpy(path, _("HKEY_CLASSES_ROOT"), sizeof(path));
+ }
+ else if (0 == strncmp(key, _("HKEY_CURRENT_USER"), 17))
+ {
+ topKey = HKEY_CURRENT_USER;
+ pos = 17;
+ strncpy(path, _("HKEY_CURRENT_USER"), sizeof(path));
+ }
+ else if (0 == strncmp(key, _("HKEY_LOCAL_MACHINE"), 18))
+ {
+ topKey = HKEY_LOCAL_MACHINE;
+ pos = 18;
+ strncpy(path, _("HKEY_LOCAL_MACHINE"), sizeof(path));
+ }
+ else if (0 == strncmp(key, _("HKEY_USERS"), 10))
+ {
+ topKey = HKEY_USERS;
+ pos = 10;
+ strncpy(path, _("HKEY_USERS"), sizeof(path));
+ }
+
+
+ if (pos > 0)
+ {
+ if (key[pos] == '\\')
+ {
+ ++pos;
+ subkey = &key[pos];
+ }
+ }
+ else
+ {
+
+ char * tmp = sh_util_safe_name_keepspace(key);
+ size_t tlen = sl_strlen(tmp);
+
+ if (S_TRUE == sl_ok_adds(64, tlen))
+ {
+ char * errbuf = SH_ALLOC(64 + tlen);
+
+ sl_snprintf(errbuf, 64+tlen, _("Invalid key %s"), tmp);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf, _("check_key"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SH_FREE(errbuf);
+ }
+ SH_FREE(tmp);
+ return -1;
+ }
+
+ /************************
+ if (ShCheckBothViews)
+ {
+ CheckThisSubkey (topKey, subkey, path, isSingle, KEY_WOW64_32KEY);
+ return CheckThisSubkey (topKey, subkey, path, isSingle, KEY_WOW64_64KEY);
+ }
+ *************************/
+
+ return CheckThisSubkey (topKey, subkey, path, isSingle, 0);
+}
+
+/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+/* #ifdef USE_REGISTRY_CHECK */
+#endif
+
diff --git a/src/sh_restrict.c b/src/sh_restrict.c
new file mode 100644
index 0000000..4e255e3
--- /dev/null
+++ b/src/sh_restrict.c
@@ -0,0 +1,686 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2011 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#ifndef NULL
+#if !defined(__cplusplus)
+#define NULL ((void*)0)
+#else
+#define NULL (0)
+#endif
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+#ifdef HAVE_REGEX_H
+#include <sys/types.h>
+#include <regex.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error_min.h"
+#include "sh_string.h"
+#include "sh_utils.h"
+#include "sh_restrict.h"
+
+#define FIL__ _("sh_restrict.c")
+
+#define SH_COND_NOT (1 << 0)
+#define SH_COND_PREFIX (1 << 1)
+#define SH_COND_REGEX (1 << 2)
+#define SH_COND_SIZE (1 << 3)
+#define SH_COND_PERM (1 << 4)
+#define SH_COND_FTYPE (1 << 5)
+#define SH_COND_PINCL (1 << 6)
+
+#define SH_COND_MAX 6
+
+struct sh_restrict_cond {
+
+ unsigned char cond_type[SH_COND_MAX];
+
+#ifdef HAVE_REGEX_H
+ regex_t * cond_preg[SH_COND_MAX];
+#endif
+
+ char * cond_str[SH_COND_MAX];
+
+ UINT64 cond_int[SH_COND_MAX];
+
+ struct sh_restrict_cond * next;
+};
+
+static struct sh_restrict_cond * sh_restrict_list = NULL;
+
+extern int matches_filetype(SL_TICKET ft, char * test_type);
+
+#ifdef HAVE_REGEX_H
+static int matches_regex (const char * path, const regex_t * regex)
+{
+ SL_ENTER(_("matches_regex"));
+
+ if (0 == regexec(regex, path, 0, NULL, 0))
+ {
+ SL_RETURN(1, _("matches_regex"));
+ }
+ SL_RETURN(0, _("matches_regex"));
+}
+#else
+static int matches_string (const char * path, const char * string)
+{
+ SL_ENTER(_("matches_string"));
+
+ if (NULL == strstr(path, string))
+ {
+ SL_RETURN(0, _("matches_string"));
+ }
+ SL_RETURN(1, _("matches_string"));
+}
+#endif
+
+static int matches_prefix (const char * path, const char * prefix)
+{
+ size_t path_len;
+ size_t pref_len;
+
+ SL_ENTER(_("matches_prefix"));
+
+ if (path && prefix)
+ {
+ path_len = sl_strlen(path);
+ pref_len = sl_strlen(prefix);
+
+ if (path_len >= pref_len)
+ {
+ if (0 == strncmp(path, prefix, pref_len))
+ {
+ SL_RETURN(1, _("matches_prefix"));
+ }
+ }
+ }
+ SL_RETURN(0, _("matches_prefix"));
+}
+
+static int exceeds_size (UINT64 size, UINT64 maxsize)
+{
+ SL_ENTER(_("exceeds_size"));
+
+ if (size > maxsize)
+ {
+ SL_RETURN(1, _("exceeds_size"));
+ }
+ SL_RETURN(0, _("exceeds_size"));
+}
+
+static int matches_perm (UINT64 perm, UINT64 needed_perm)
+{
+ SL_ENTER(_("matches_perm"));
+
+ if (needed_perm == (perm & 07777))
+ {
+ SL_RETURN(1, _("matches_perm"));
+ }
+ SL_RETURN(0, _("matches_perm"));
+}
+
+static int includes_perm (UINT64 perm, UINT64 needed_perm)
+{
+ UINT64 tmp = perm & 07777;
+
+ SL_ENTER(_("includes_perm"));
+
+ if (needed_perm == (tmp & needed_perm))
+ {
+ SL_RETURN(1, _("includes_perm"));
+ }
+ SL_RETURN(0, _("includes_perm"));
+}
+
+static int sh_restrict_test(const char * path,
+ UINT64 size, UINT64 perm, SL_TICKET fh,
+ struct sh_restrict_cond * current)
+{
+ int i;
+ unsigned char flag;
+ int res = 0;
+
+ (void) fh;
+
+ SL_ENTER(_("sh_restrict_test"));
+
+ for (i = 0; i < SH_COND_MAX; ++i)
+ {
+ flag = current->cond_type[i];
+
+ if (flag != 0)
+ {
+ if ((flag & (SH_COND_PREFIX)) != 0) {
+ res = matches_prefix(path, current->cond_str[i]);
+ }
+ else if ((flag & (SH_COND_REGEX)) != 0) {
+#ifdef HAVE_REGEX_H
+ res = matches_regex(path, current->cond_preg[i]);
+#else
+ res = matches_string(path, current->cond_str[i]);
+#endif
+ }
+ else if ((flag & (SH_COND_SIZE)) != 0) {
+ res = exceeds_size(size, current->cond_int[i]);
+ }
+ else if ((flag & (SH_COND_PERM)) != 0) {
+ res = matches_perm(perm, current->cond_int[i]);
+ }
+ else if ((flag & (SH_COND_PINCL)) != 0) {
+ res = includes_perm(perm, current->cond_int[i]);
+ }
+ else if ((flag & (SH_COND_FTYPE)) != 0) {
+ res = matches_filetype(fh, current->cond_str[i]);
+ }
+
+ /* Does condition hold?
+ */
+ if ((flag & (SH_COND_NOT)) != 0) {
+ /*
+ * Condition negated, ok if false (res == 0)
+ */
+ if (0 != res) {
+ SL_RETURN(0, _("sh_restrict_this"));
+ }
+ }
+ else {
+ /* Condition ok if true (res != 0) */
+ if (0 == res) {
+ SL_RETURN(0, _("sh_restrict_this"));
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* All conditions true, restricted
+ */
+ SL_RETURN(1, _("sh_restrict_this"));
+}
+
+/* >>>>>>>>>> Evaluate the list <<<<<<<<<< */
+
+int sh_restrict_this(const char * path, UINT64 size, UINT64 perm, SL_TICKET fh)
+{
+ struct sh_restrict_cond * current = sh_restrict_list;
+
+ SL_ENTER(_("sh_restrict_this"));
+
+ if (!current)
+ {
+ SL_RETURN(0, _("sh_restrict_this"));
+ }
+
+ while (current)
+ {
+ if (0 != sh_restrict_test(path, size, perm, fh, current))
+ {
+ /* The current conditions are true, restricted
+ */
+ SL_RETURN(1, _("sh_restrict_this"));
+ }
+ current = current->next;
+ }
+
+ SL_RETURN(0, _("sh_restrict_this"));
+}
+
+
+/* >>>>>>>>>> Purge the list <<<<<<<<<< */
+
+static void sh_restrict_delete (struct sh_restrict_cond * current)
+{
+ int i;
+
+ if (current->next)
+ {
+ sh_restrict_delete(current->next);
+ }
+
+ for (i = 0; i < SH_COND_MAX; ++i)
+ {
+ if (current->cond_str[i]) {
+ SH_FREE(current->cond_str[i]);
+ }
+#ifdef HAVE_REGEX_H
+ if (current->cond_preg[i]) {
+ regfree(current->cond_preg[i]);
+ SH_FREE(current->cond_preg[i]);
+ }
+#endif
+ }
+ SH_FREE(current);
+ return;
+}
+
+void sh_restrict_purge ()
+{
+ struct sh_restrict_cond * current = sh_restrict_list;
+
+ sh_restrict_list = NULL;
+ if (current)
+ sh_restrict_delete(current);
+
+ sh_restrict_add_ftype(NULL);
+
+ return;
+}
+
+/* >>>>>>>>>> Create the list <<<<<<<<<< */
+
+static char * get_com(char * str)
+{
+ char * s;
+ char * e;
+
+ /* skip leading WS
+ */
+ for (s = str; *s && isspace((int)*s); ++s) /* nothing */;
+
+ e = strchr(s, '(');
+ if (e && (e != s))
+ {
+ *e = '\0'; --e;
+ while ( (e != s) && isspace((int)*e) )
+ {
+ *e = '\0'; --e;
+ }
+ if (e != s)
+ return s;
+ }
+ return NULL;
+}
+
+static char * get_arg(char * str)
+{
+ char * s;
+ char * e;
+
+ s = strchr(str, '(');
+
+ if (s)
+ {
+ ++s;
+
+ /* skip leading WS
+ */
+ for (; *s && isspace((int)*s); ++s) /* nothing */;
+
+ e = strrchr(s, ')');
+ if (e && (e != s))
+ {
+ /* check that nothing follows */
+ char * u = e;
+ ++u; for (; *u && isspace((int)*u); ++u) /* nothing */;
+ if (*u != '\0') return NULL;
+
+ /* strip trailing space */
+ *e = '\0'; --e;
+ while ( (e != s) && isspace((int)*e) )
+ {
+ *e = '\0'; --e;
+ }
+
+ if (e != s)
+ return s;
+ }
+ }
+ return NULL;
+}
+
+static int set_cond(struct sh_restrict_cond * current, int i,
+ char * com, char * arg)
+{
+ if (!com || !arg || (i >= SH_COND_MAX))
+ return -1;
+
+ if (0 == strcmp(com, _("match_prefix")))
+ {
+ current->cond_str[i] = sh_util_strdup(arg);
+ current->cond_type[i] |= SH_COND_PREFIX;
+ }
+ else if (0 == strcmp(com, _("match_regex")))
+ {
+#ifdef HAVE_REGEX_H
+ regex_t * preg = SH_ALLOC(sizeof(regex_t));
+
+ if (0 != regcomp(preg, arg, REG_NOSUB|REG_EXTENDED))
+ {
+ SH_FREE(preg);
+ return (-1);
+ }
+ current->cond_preg[i] = preg;
+#else
+ current->cond_str[i] = sh_util_strdup(arg);
+#endif
+ current->cond_type[i] |= SH_COND_REGEX;
+ }
+ else if (0 == strcmp(com, _("size_exceeds")))
+ {
+ current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 0);
+ current->cond_type[i] |= SH_COND_SIZE;
+ }
+ else if (0 == strcmp(com, _("match_permission")))
+ {
+ current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
+ current->cond_type[i] |= SH_COND_PERM;
+ }
+ else if (0 == strcmp(com, _("have_permission")))
+ {
+ current->cond_int[i] = (UINT64) strtoul(arg, (char **) NULL, 8);
+ current->cond_type[i] |= SH_COND_PINCL;
+ }
+ else if (0 == strcmp(com, _("match_filetype")))
+ {
+ current->cond_str[i] = sh_util_strdup(arg);
+ current->cond_type[i] |= SH_COND_FTYPE;
+ }
+ else
+ {
+ return (-1);
+ }
+ return 0;
+}
+
+/* Format is [!]cond1(arg), cond2(arg), ...
+ */
+int sh_restrict_define(const char * str)
+{
+ SL_ENTER(_("sh_restrict_define"));
+
+ if (str)
+ {
+ size_t lengths[SH_COND_MAX];
+ unsigned int nfields = SH_COND_MAX;
+ char ** array;
+ sh_string * def = sh_string_new_from_lchar(str, strlen(str));
+
+ array = split_array_list(sh_string_str(def), &nfields, lengths);
+
+ if (array && nfields > 0)
+ {
+ char * p;
+ char * q;
+ unsigned int i;
+ struct sh_restrict_cond * current =
+ SH_ALLOC(sizeof(struct sh_restrict_cond));
+
+ current->next = NULL;
+ for (i = 0; i < SH_COND_MAX; ++i)
+ {
+ current->cond_int[i] = 0;
+ current->cond_type[i] = 0;
+ current->cond_str[i] = NULL;
+#ifdef HAVE_REGEX_H
+ current->cond_preg[i] = NULL;
+#endif
+ }
+
+ for (i = 0; i < nfields; ++i)
+ {
+ if (i == SH_COND_MAX)
+ {
+ sh_restrict_delete (current);
+ sh_string_destroy(&def);
+ SH_FREE(array);
+ SL_RETURN((-1), _("sh_restrict_define"));
+ }
+
+ p = array[i];
+
+ if (*p == '!')
+ {
+ current->cond_type[i] |= SH_COND_NOT;
+ ++p;
+ }
+
+ q = get_arg(p);
+ p = get_com(p);
+
+ if (!q || !p || (0 != set_cond(current, i, p, q)))
+ {
+ sh_restrict_delete (current);
+ sh_string_destroy(&def);
+ SH_FREE(array);
+ SL_RETURN((-1), _("sh_restrict_define"));
+ }
+ }
+
+ SH_FREE(array);
+
+ current->next = sh_restrict_list;
+ sh_restrict_list = current;
+ }
+
+ sh_string_destroy(&def);
+ SL_RETURN(0, _("sh_restrict_define"));
+ }
+
+ SL_RETURN((-1), _("sh_restrict_define"));
+}
+
+
+/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
+#endif
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_restrict (CuTest *tc) {
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+ char str[256];
+ char * p;
+ char * q;
+ int res;
+ SL_TICKET fd;
+ char buf[1024];
+
+ strcpy(str, "match(this)");
+ p = get_arg(str);
+ q = get_com(str);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertStrEquals(tc, "match", q);
+ CuAssertStrEquals(tc, "this", p);
+
+ strcpy(str, " match( this)");
+ p = get_arg(str);
+ q = get_com(str);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertStrEquals(tc, "match", q);
+ CuAssertStrEquals(tc, "this", p);
+
+ strcpy(str, " match ( this ) ");
+ p = get_arg(str);
+ q = get_com(str);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertStrEquals(tc, "match", q);
+ CuAssertStrEquals(tc, "this", p);
+
+ strcpy(str, " match (this ) ");
+ p = get_arg(str);
+ q = get_com(str);
+ CuAssertPtrNotNull(tc, p);
+ CuAssertPtrNotNull(tc, q);
+ CuAssertStrEquals(tc, "match", q);
+ CuAssertStrEquals(tc, "this", p);
+
+ strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg) ");
+ CuAssertTrue(tc, sh_restrict_list == NULL);
+ res = sh_restrict_define(str);
+ CuAssertIntEquals(tc,0,res);
+ CuAssertPtrNotNull(tc, sh_restrict_list);
+
+ sh_restrict_purge();
+ CuAssertTrue(tc, sh_restrict_list == NULL);
+
+ strcpy(str, "size_exceeds(800), match_prefix(/home), match_regex(.*\\.mpg), match_permission(0755) ");
+ CuAssertTrue(tc, sh_restrict_list == NULL);
+ res = sh_restrict_define(str);
+ CuAssertIntEquals(tc,0,res);
+ CuAssertPtrNotNull(tc, sh_restrict_list);
+
+ strcpy(str, "size_exceeds(800), match_prefix(/foo), have_permission(0100)");
+ res = sh_restrict_define(str);
+ CuAssertIntEquals(tc,0,res);
+ CuAssertPtrNotNull(tc, sh_restrict_list);
+
+ strcpy(str, "size_exceeds(800); match_prefix(/foo), have_permission(0100)");
+ res = sh_restrict_define(str);
+ CuAssertIntEquals(tc,-1,res);
+ CuAssertPtrNotNull(tc, sh_restrict_list);
+
+ res = sh_restrict_this("/home/foo.mpg", 1000, 0755, 0);
+ CuAssertIntEquals(tc,1,res);
+
+ res = sh_restrict_this("/foo.mpg", 1000, 0755, 0);
+ CuAssertIntEquals(tc,1,res);
+
+ /* size too small */
+ res = sh_restrict_this("/foo.mpg", 600, 0755, 0);
+ CuAssertIntEquals(tc,0,res);
+
+ /* no execute permission */
+ res = sh_restrict_this("/foo.mpg", 600, 0644, 0);
+ CuAssertIntEquals(tc,0,res);
+
+ /* regex does not match */
+ res = sh_restrict_this("/home/foo", 1000, 0755, 0);
+ CuAssertIntEquals(tc,0,res);
+
+ /* wrong permission */
+ res = sh_restrict_this("/home/foo.mpg", 1000, 0705, 0);
+ CuAssertIntEquals(tc,0,res);
+
+ /* size too small */
+ res = sh_restrict_this("/home/foo.mpg", 600, 0755, 0);
+ CuAssertIntEquals(tc,0,res);
+
+ /* wrong prefix */
+ res = sh_restrict_this("/hoff/foo.mpg", 1000, 0755, 0);
+ CuAssertIntEquals(tc,0,res);
+
+ sh_restrict_purge();
+ CuAssertTrue(tc, sh_restrict_list == NULL);
+
+ fd = sl_open_fastread(FIL__, __LINE__, "/bin/sh", SL_NOPRIV);
+ CuAssertTrue(tc, fd > 0);
+
+ strcpy(str, "match_prefix(/bin), match_filetype(EXECUTABLE:UNIX:ELF)");
+ res = sh_restrict_define(str);
+ CuAssertIntEquals(tc,0,res);
+ CuAssertPtrNotNull(tc, sh_restrict_list);
+
+#if !defined(HOST_IS_CYGWIN)
+ res = sh_restrict_this("/bin/sh", 1000, 0755, fd);
+ CuAssertIntEquals(tc,1,res);
+#endif
+
+ sl_close(fd);
+
+ sh_restrict_purge();
+ CuAssertTrue(tc, sh_restrict_list == NULL);
+
+ strcpy(str, "match_filetype(FILE:TEXT:COPYING)");
+ res = sh_restrict_define(str);
+ CuAssertIntEquals(tc,0,res);
+ CuAssertPtrNotNull(tc, sh_restrict_list);
+
+ p = getcwd(buf, sizeof(buf));
+ CuAssertPtrNotNull(tc, p);
+
+ strcpy(str, "0:0:0:FILE:TEXT:COPYING:Copying:=0a=53=41=4d=48=41=49=4e");
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+
+ sl_strlcat(buf, "/COPYING", sizeof(buf));
+ fd = sl_open_fastread(FIL__, __LINE__, buf, SL_NOPRIV);
+ CuAssertTrue(tc, fd > 0);
+
+ res = sh_restrict_this(buf, 1000, 0755, fd);
+ CuAssertIntEquals(tc,1,res);
+
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,-1,res);
+
+ sh_restrict_purge();
+ CuAssertTrue(tc, sh_restrict_list == NULL);
+
+ res = sh_restrict_add_ftype(str);
+ CuAssertIntEquals(tc,0,res);
+
+#else
+ (void) tc;
+/* #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
+#endif
+
+}
+#endif
+
+
diff --git a/src/sh_schedule.c b/src/sh_schedule.c
new file mode 100644
index 0000000..0954e6f
--- /dev/null
+++ b/src/sh_schedule.c
@@ -0,0 +1,454 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2002 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ gcc -Wall -O2 -o mysched sh_schedule.c -DTESTONLY
+ */
+#ifndef TESTONLY
+
+
+#undef FIL__
+#define FIL__ _("sh_schedule.c")
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+#define SCHEDULER_YES
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error_min.h"
+
+/* TESTONLY */
+#else
+
+#define SCHEDULER_YES
+#include <time.h>
+
+#endif
+
+#include "sh_schedule.h"
+
+
+
+#ifdef SCHEDULER_YES
+
+/************************************************
+ *
+ * Scheduler class - private area
+ *
+ ************************************************/
+
+
+static const int sh_schedule_max[5] = { 59, 23, 31, 12, 7 };
+static const int sh_schedule_min[5] = { 0, 0, 0, 0, 0 };
+
+static
+int test_val (int i, int min, int max, int min_step,
+ time_t * last, time_t now, int nval, int first_flag)
+{
+ /* don't miss a minute's task
+ * IDEA: set last = now after first check (? seems to work)
+ */
+ if (i == 0 && max == min && nval > max
+ /* && ( ((now - *last) > min_step) || (*last == (time_t)-1) ) */ )
+ {
+ if (*last == (time_t)-1)
+ {
+ /* fake execution at nval-max
+ */
+ *last = now - 60 * (nval-max);
+ return 0;
+ }
+ if ((int)(now - *last) > min_step)
+ return 1;
+ }
+
+ /* out of range
+ */
+ if (nval > max || nval < min)
+ return 0;
+
+ /* first call - invalid last_exec
+
+ if (*last == (time_t)-1)
+ return 1;
+ */
+
+ if (first_flag == 0)
+ return 1;
+
+
+ /* before min_step - too early (e.g. same minute)
+ */
+ if ((int)(now - *last) <= min_step)
+ return 0;
+
+ return 1;
+}
+
+static
+int test_sched_int (sh_schedule_t * isched)
+{
+ time_t now;
+ struct tm * tval;
+ int count, i, nval;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ struct tm time_tm;
+#endif
+
+ if (!isched)
+ return 0;
+
+ now = time(NULL);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ tval = localtime_r(&now, &time_tm);
+#else
+ tval = localtime(&now);
+#endif
+
+ if (!tval)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("localime() failed"), _("test_sched_int") );
+ return 0;
+ }
+
+ count = 0;
+ for (i = 0; i < 5; ++i)
+ {
+ if (i == 0) nval = tval->tm_min;
+ else if (i == 1) nval = tval->tm_hour;
+ else if (i == 2) nval = tval->tm_mday;
+ else if (i == 3) nval = tval->tm_mon;
+ else nval = tval->tm_wday;
+ count += test_val (i, isched->min[i], isched->max[i],
+ isched->min_step, &(isched->last_exec),
+ now, nval, isched->first);
+ }
+
+ if (count == 5)
+ {
+ isched->first = 1;
+ isched->last_exec = now;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* test a linked list of schedules
+ */
+int test_sched (sh_schedule_t * isched)
+{
+ sh_schedule_t * intern = isched;
+ int retval = 0;
+
+ while (intern != NULL)
+ {
+ if (test_sched_int(intern) == 1)
+ retval = 1;
+ intern = intern->next;
+ }
+ return retval;
+}
+
+static
+char DayNames[7][4] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
+static
+char MonNames[12][4] = { "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec" };
+
+static
+int parse_func (int i, char * p)
+{
+ int j, k, l;
+ char *tail;
+
+ errno = 0;
+ j = (int) strtol(p, &tail, 10);
+
+ if (errno != 0) /* overflow */
+ return -1;
+ if (j < 0)
+ return -1;
+ if (tail != p) /* numeric */
+ return j;
+ if (i < 3) /* names not allowed */
+ return -1;
+
+ if (i == 3)
+ {
+ for (j = 0; j < 12; ++j) {
+ l = 0;
+ /*@+charint@*//* Incompatible types for == (char, char): ??? */
+ for (k = 0; k < 3; ++k)
+ if (p[k] != '\0' && tolower((int) p[k]) == MonNames[j][k]) ++l;
+ /*@-charint@*/
+ if (l == 3)
+ return j;
+ }
+ }
+ if (i == 4)
+ {
+ for (j = 0; j < 7; ++j) {
+ l = 0;
+ /*@+charint@*//* Incompatible types for == (char, char): ??? */
+ for (k = 0; k < 3; ++k)
+ if (p[k] != '\0' && tolower((int) p[k]) == DayNames[j][k]) ++l;
+ /*@-charint@*/
+ if (l == 3)
+ return j;
+ }
+ }
+
+ return -1;
+}
+
+static
+int parse_token(int i, sh_schedule_t * isched, char * p)
+{
+ char * q;
+
+ if ( NULL != (q = strchr(p, ',')))
+ return -1;
+
+ if (*p == '*')
+ {
+ isched->min[i] = sh_schedule_min[i];
+ isched->max[i] = sh_schedule_max[i];
+ }
+ else
+ {
+ isched->min[i] = parse_func(i, p);
+ if (i == 4 && isched->min[i] == 7)
+ isched->min[i] = 0;
+ if (isched->min[i] < sh_schedule_min[i] ||
+ isched->min[i] > sh_schedule_max[i])
+ {
+ return -1;
+ }
+ if ( NULL != (q = strchr(p, '-')))
+ {
+ ++q;
+ isched->max[i] = parse_func(i, q);
+ if (i == 4 && isched->max[i] == 7)
+ isched->max[i] = 0;
+ if (isched->max[i] < sh_schedule_min[i] ||
+ isched->max[i] > sh_schedule_max[i] ||
+ isched->max[i] < isched->min[i])
+ {
+ return -1;
+ }
+ }
+ else
+ isched->max[i] = isched->min[i];
+ }
+
+ if ( NULL != (q = strchr(p, '/')))
+ {
+ ++q;
+ isched->step[i] = atoi(q);
+ if (isched->step[i] < 1 || isched->step[i] > sh_schedule_max[i])
+ {
+ return -1;
+ }
+ if (i == 4 && isched->step[i] == 7)
+ isched->step[i] = 6;
+ }
+ else
+ {
+ isched->step[i] = 1;
+ }
+
+ switch (i)
+ {
+ case 0:
+ if (isched->max[i] == isched->min[i])
+ isched->min_step = 3599;
+ else
+ isched->min_step = (isched->step[i] * 60) - 1;
+ break;
+ case 1:
+ if (isched->max[i] == isched->min[i])
+ {
+ /* fix for daylight saving time: subtract 3600 sec
+ */
+ if (isched->min_step == 3599)
+ isched->min_step = 86399 - 3600;
+ }
+ else
+ {
+ if (isched->min_step == 3599)
+ isched->min_step = (isched->step[i] * 3600) - 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static
+int parse_sched (const char * ssched, sh_schedule_t * isched)
+{
+ char * p;
+ char * copy;
+ int i = 0;
+ size_t len;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+#endif
+
+ if (!ssched || !isched)
+ return -1;
+
+ len = strlen(ssched)+1;
+#ifdef TESTONLY
+ copy = calloc(1,len); /* testonly code */
+#else
+ copy = SH_ALLOC(len);
+#endif
+ sl_strlcpy(copy, ssched, len);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ p = strtok_r(copy, " \t", &saveptr); /* parse crontab-style schedule */
+#else
+ p = strtok(copy, " \t"); /* parse crontab-style schedule */
+#endif
+
+ if (!p)
+ goto err;
+ if (parse_token(i, isched, p) == -1)
+ goto err;
+
+ for (i = 1; i < 5; ++i)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ p = strtok_r(NULL, " \t", &saveptr); /* parse crontab-style schedule */
+#else
+ p = strtok(NULL, " \t"); /* parse crontab-style schedule */
+#endif
+ if (!p)
+ goto err;
+ if (parse_token(i, isched, p) == -1)
+ goto err;
+ }
+
+ isched->last_exec = (time_t)-1;
+ isched->first = 0;
+ isched->next = NULL;
+
+#ifdef TESTONLY
+ free(copy);
+#else
+ SH_FREE(copy);
+#endif
+ return 0;
+
+ err:
+#ifdef TESTONLY
+ free(copy);
+#else
+ SH_FREE(copy);
+#endif
+ return -1;
+}
+
+int create_sched (const char * ssched, sh_schedule_t * isched)
+{
+ int j;
+
+ if (!isched || !ssched)
+ return -1;
+
+ j = parse_sched(ssched, isched);
+
+#ifdef TESTONLY
+ if (j == 0)
+ {
+ int i;
+ for (i = 0; i < 5; ++i)
+ printf("%2d MIN %3d MAX %3d STEP %3d\n",
+ i, isched->max[i], isched->min[i], isched->step[i]);
+ printf("MINSTEP %7d\n", isched->min_step);
+ printf("LASTEXEC %7ld\n", (long) isched->last_exec);
+ }
+#endif
+
+ return j;
+}
+
+/* #ifdef SCHEDULER_YES */
+#endif
+
+/**************************************************
+ *
+ * Schedule class - Test driver
+ *
+ **************************************************/
+#ifdef TESTONLY
+
+int main(int argc, char * argv[])
+{
+ sh_schedule_t isched;
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "Usage: %s 'schedule'\n", argv[0]);
+ exit (1);
+ }
+
+ if (create_sched(argv[1], &isched) < 0)
+ {
+ fprintf(stderr, "Bad schedule <%s>\n", argv[1]);
+ exit (1);
+ }
+
+ while (1 == 1)
+ {
+ if (test_sched(&isched))
+ printf("EXECUTE at: %s", ctime(&(isched.last_exec))); /* TESTONLY */
+ sleep (1); /* TESTONLY */
+ }
+ return 0;
+}
+#endif
diff --git a/src/sh_sem.c b/src/sh_sem.c
new file mode 100644
index 0000000..3de83b4
--- /dev/null
+++ b/src/sh_sem.c
@@ -0,0 +1,310 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000, 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H)
+#include "samhain.h"
+#include "sh_sem.h"
+#include "sh_error_min.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <unistd.h>
+
+#undef FIL__
+#define FIL__ _("sh_sem.c")
+
+typedef enum {
+ exit_ok = 0,
+ exit_fail = 1,
+ exit_time = 2,
+ exit_err = 3
+} sh_estat;
+
+#if 0
+/* FreeBSD 6.1 defines this in <sys/sem.h> too... */
+#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
+/* union semun is defined by including <sys/sem.h> */
+#else
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+ int val;
+ struct semid_ds *buf;
+ unsigned short *array;
+};
+#endif
+#endif
+
+#define SH_SEMVMX 32767
+
+static int get_semaphore (void)
+{
+ key_t key = ftok(DEFAULT_DATAROOT, '#');
+ int semid;
+
+ if (key < 0)
+ return -1;
+ semid = semget (key, 0, IPC_PRIVATE);
+ if (semid < 0)
+ return -1;
+ return semid;
+}
+
+static void sem_purge(int sem_id)
+{
+ if (sem_id != -1)
+ semctl(sem_id, 0, IPC_RMID, (int)0);
+ return;
+}
+
+static void sem_purge_stale()
+{
+ int stale_ID = get_semaphore();
+ if (stale_ID != -1)
+ sem_purge(stale_ID);
+ return;
+}
+
+static int report_err(int errnum, char * file, int line, char * func)
+{
+ char errbuf[SH_ERRBUF_SIZE];
+ sh_error_message(errnum, errbuf, sizeof(errbuf));
+ sh_error_handle((-1), file, line, errnum, MSG_E_SUBGEN,
+ errbuf, func);
+ return -1;
+}
+
+static int init_semaphore (int nsems)
+{
+ int i;
+ mode_t mask;
+ int semid;
+ int errnum;
+ key_t key = ftok(DEFAULT_DATAROOT, '#');
+
+ if (key < 0)
+ return report_err(errno, FIL__, __LINE__, _("ftok"));
+
+ mask = umask(0);
+ semid = semget (key, nsems, IPC_CREAT | IPC_EXCL | 0660);
+ errnum = errno;
+ umask(mask);
+
+ if (semid < 0)
+ return report_err(errnum, FIL__, __LINE__, _("semget"));
+ for (i=0; i<nsems; ++i)
+ if (semctl (semid, i, SETVAL, (int) 1) == -1)
+ return report_err(errnum, FIL__, __LINE__, _("semclt"));
+ return semid;
+}
+
+
+static int sem_set(int semid, int sem_no, int val)
+{
+ if (semid < 0)
+ return -1;
+ if (semctl (semid, sem_no, SETVAL, val) == -1)
+ return -1;
+ return 0;
+}
+
+static int sem_get(int semid, int sem_no)
+{
+ if (semid < 0)
+ return -1;
+ return semctl (semid, sem_no, GETVAL, (int) 0);
+}
+
+
+static int sem_change(int semid, int sem_no, int amount)
+{
+ struct sembuf tmp;
+ int retval;
+
+ tmp.sem_num = sem_no;
+ tmp.sem_flg = SEM_UNDO;
+ tmp.sem_op = amount;
+
+ do { retval = semop(semid, &tmp, 1);
+ } while (retval == -1 && errno == EINTR);
+
+ return retval;
+}
+
+static int sem_try_change(int semid, int sem_no, int amount)
+{
+ struct sembuf tmp;
+ int retval;
+
+ tmp.sem_num = sem_no;
+ tmp.sem_flg = IPC_NOWAIT|SEM_UNDO;
+ tmp.sem_op = amount;
+
+ do { retval = semop(semid, &tmp, 1);
+ } while (retval == -1 && errno == EINTR);
+
+ return retval;
+}
+
+#define SH_SEMAPHORE_EXTERN(S) int S = get_semaphore()
+#define SH_SEMAPHORE_INIT(S, N) int S = init_semaphore(N)
+#define SH_SEMAPHORE_TRYLOCK(S) sem_try_change(S, 0, SH_SEM_LOCK)
+#define SH_SEMAPHORE_LOCK(S) sem_change(S, 0, SH_SEM_LOCK)
+#define SH_SEMAPHORE_UNLOCK(S) sem_change(S, 0, SH_SEM_UNLOCK)
+#define SH_SEMAPHORE_PURGE(S) sem_purge(S)
+
+static int sem_ID = -1;
+
+void sh_sem_open()
+{
+ if (sh.flag.isdaemon != S_TRUE)
+ return;
+
+ if (sem_ID < 0)
+ {
+ sem_purge_stale();
+ sem_ID = init_semaphore(2);
+ sem_set(sem_ID, 1, (int) 0);
+ }
+
+ return;
+}
+
+void sh_sem_trylock()
+{
+ SH_SEMAPHORE_TRYLOCK(sem_ID);
+ return;
+}
+
+void sh_sem_lock()
+{
+ SH_SEMAPHORE_LOCK(sem_ID);
+ return;
+}
+
+void sh_sem_unlock (long val)
+{
+ if (val >= 0)
+ {
+ val = (val > SH_SEMVMX) ? SH_SEMVMX : val; /* signed short int maxval */
+ sem_set(sem_ID, 1, (int) val);
+ }
+ SH_SEMAPHORE_UNLOCK(sem_ID);
+ return;
+}
+
+void sh_sem_close()
+{
+ SH_SEMAPHORE_PURGE(sem_ID);
+ return;
+}
+
+static volatile int alarm_triggered = 0;
+static void alarm_handler(int sig)
+{
+ (void) sig;
+ alarm_triggered = 1;
+ return;
+}
+
+int sh_sem_wait(const char * wait)
+{
+ int rc, flag = 0;
+ int time_wait = atoi(wait);
+
+ SH_SEMAPHORE_EXTERN(sem_id);
+
+ if (time_wait < 0) { time_wait *= (-1); time_wait -= 1; flag = 1; }
+ if (time_wait < 0 || time_wait > (24*3600))
+ {
+ fprintf(stderr, _("Invalid argument <%d>.\n"), time_wait);
+ _exit(exit_err);
+ }
+ if (sem_id == -1)
+ {
+ if (flag && errno == ENOENT) {
+ do { retry_msleep(1, 0); rc = get_semaphore(); } while (rc == -1);
+ sem_id = rc;
+ } else {
+ if (errno == ENOENT) {
+ fputs(_("Samhain IPC not initialized.\n"), stderr);
+ _exit(exit_err); }
+ else if (errno == EACCES)
+ fputs(_("No permission to access Samhain IPC.\n"), stderr);
+ _exit(exit_err);
+ }
+ }
+
+ retry_msleep(0, 50);
+
+ if (time_wait > 0)
+ {
+ signal(SIGALRM, alarm_handler);
+ alarm(time_wait);
+ }
+ rc = SH_SEMAPHORE_LOCK(sem_id);
+ if (rc == -1 && errno == EINTR)
+ {
+ if (alarm_triggered)
+ {
+ fputs(_("Timeout on wait.\n"), stderr);
+ _exit(exit_time);
+ }
+ }
+ else if (rc == -1)
+ {
+ if (errno == EACCES)
+ fputs(_("No permission to access Samhain IPC.\n"), stderr);
+ else
+ perror(_("semop"));
+ _exit(exit_err);
+ }
+
+ rc = sem_get(sem_id, 1);
+ if (rc == 0)
+ _exit(exit_ok);
+ else if (rc == SH_SEMVMX)
+ fprintf(stdout, _("%d or more issues reported\n"), rc);
+ else
+ fprintf(stdout, _("%d issues reported\n"), rc);
+ _exit(exit_fail);
+}
+
+#else
+
+void sh_sem_open() { return; }
+void sh_sem_trylock() { return; }
+void sh_sem_lock() { return; }
+void sh_sem_unlock(long val) { (void) val; return; }
+void sh_sem_close() { return; }
+int sh_sem_wait(const char * wait)
+{
+ (void) wait;
+ fputs(_("Function not implemented (OS does not support SysV semaphores).\n"),
+ stderr);
+ exit(exit_err);
+}
+
+#endif /* defined(HAVE_SYS_SEM_H) && defined(HAVE_UNISTD_H) */
diff --git a/src/sh_socket.c b/src/sh_socket.c
new file mode 100644
index 0000000..f4e9f56
--- /dev/null
+++ b/src/sh_socket.c
@@ -0,0 +1,1401 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2003,2005 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+/* define if you want debug info
+ * #define SH_DEBUG_SOCKET
+ */
+
+#if defined(SH_WITH_SERVER) && defined(__linux__)
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#include "samhain.h"
+#include "sh_socket.h"
+#include "sh_error.h"
+#include "sh_unix.h"
+#include "sh_calls.h"
+#include "sh_guid.h"
+#include "sh_fifo.h"
+#include "sh_utils.h"
+
+#undef FIL__
+#define FIL__ _("sh_socket.c")
+
+#if defined (SH_WITH_CLIENT)
+
+#include <signal.h>
+
+typedef struct delta_tofetch {
+ char uuid[SH_UUID_BUF];
+ time_t last_time;
+ unsigned int count;
+} SH_DELTA_DB;
+
+static SH_DELTA_DB * parse_entry(SH_DELTA_DB * db, const char * str)
+{
+ long last_time;
+ unsigned int count;
+ char buf[SH_UUID_BUF];
+ int res = sscanf(str, _("%u:%ld:%36s"), &count, &last_time, buf);
+ if (res == 3)
+ {
+ db->count = count;
+ db->last_time = (time_t) last_time;
+ sl_strlcpy(db->uuid, buf, SH_UUID_BUF);
+ return db;
+ }
+ return NULL;
+}
+
+static char * unparse_entry(const SH_DELTA_DB * db, char * str, size_t len)
+{
+ int nbytes = sl_snprintf(str, len, _("%u:%ld:%s"),
+ db->count, (long) db->last_time, db->uuid);
+ if (nbytes < 0 || nbytes >= (int) len)
+ return NULL;
+ return str;
+}
+
+static SH_FIFO xfifo = SH_FIFO_INITIALIZER;
+
+int sh_socket_store_uuid(const char * cmd)
+{
+ char * p = sh_util_strdup(cmd);
+ char * q = strchr(cmd, ':');
+ char entry[SH_BUFSIZE];
+ SH_DELTA_DB db;
+
+ if (!q) { SH_FREE(p); return -1; }
+
+ ++q;
+
+ if (0 != sh_uuid_check(q)) { SH_FREE(p); return -1; }
+
+ db.count = 0;
+ db.last_time = (time_t) 0;
+ sl_strlcpy(db.uuid, q, SH_UUID_BUF);
+ SH_FREE(p);
+
+ if (NULL != unparse_entry(&db, entry, sizeof(entry)))
+ {
+ sh_fifo_push(&xfifo, entry);
+ return 0;
+ }
+ return -1;
+}
+
+static unsigned int try_interval = 60;
+static unsigned int try_max = 2;
+
+int set_delta_retry_interval(const char * str)
+{
+ long val = strtol (str, (char **)NULL, 10);
+
+ if (val < 0 || val > INT_MAX)
+ return -1;
+ try_interval = (unsigned int) val;
+ return 0;
+}
+int set_delta_retry_count(const char * str)
+{
+ long val = strtol (str, (char **)NULL, 10);
+
+ if (val < 0 || val > INT_MAX)
+ return -1;
+ try_max = (unsigned int) val;
+ return 0;
+}
+
+char * sh_socket_get_uuid(int * errflag, unsigned int * count, time_t * last)
+{
+ char * entry = sh_fifo_pop(&xfifo);
+ char * uuid = NULL;
+
+ if (entry)
+ {
+ SH_DELTA_DB db;
+ time_t now;
+
+ if (NULL == parse_entry(&db, entry))
+ {
+ SH_FREE(entry);
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Bad entry in fifo"),
+ _("sh_socket_get_uuid"));
+ *errflag = -1;
+ return NULL;
+ }
+
+ now = time(NULL);
+
+ if ( (db.count > 0) && ((unsigned long)(now - db.last_time) < try_interval) )
+ {
+ sh_fifo_push_tail(&xfifo, entry);
+ SH_FREE(entry);
+ *errflag = -1;
+ return NULL;
+ }
+
+ SH_FREE(entry);
+ uuid = sh_util_strdup(db.uuid);
+ *count = db.count;
+ *last = db.last_time;
+ }
+
+ *errflag = 0;
+ return uuid;
+}
+
+int sh_socket_return_uuid (const char * uuid, unsigned int count, time_t last)
+{
+ (void) last;
+
+ if (count < try_max)
+ {
+ char entry[SH_BUFSIZE];
+ SH_DELTA_DB db;
+ time_t now = time(NULL);
+
+ db.count = count + 1;
+ db.last_time = now;
+ sl_strlcpy(db.uuid, uuid, SH_UUID_BUF);
+
+ if (NULL != unparse_entry(&db, entry, sizeof(entry)))
+ return sh_fifo_push_tail(&xfifo, entry); /* >0 for success */
+ }
+ return -1;
+}
+
+void sh_socket_server_cmd(const char * srvcmd)
+{
+ SL_ENTER(_("sh_tools_server_cmd"));
+
+ if ((srvcmd == NULL) || (srvcmd[0] == '\0') || (sl_strlen(srvcmd) < 4))
+ {
+ SL_RET0(_("sh_socket_server_cmd"));
+ }
+
+ if (0 == strncmp(srvcmd, _("STOP"), 4))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<stop command from server>\n")));
+#ifdef SIGQUIT
+ raise(SIGQUIT);
+#else
+ sig_terminate = 1;
+ ++sig_raised;
+#endif
+ }
+
+ else if (0 == strncmp(srvcmd, _("RELOAD"), 6))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<reload command from server>\n")));
+#ifdef SIGHUP
+ raise(SIGHUP);
+#else
+ sig_config_read_again = 1;
+ ++sig_raised;
+#endif
+ }
+
+ else if (0 == strncmp(srvcmd, _("DELTA:"), 6))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<delta load command from server>\n")));
+
+ if (sh_socket_store_uuid(srvcmd) == 0)
+ {
+ ++sh_load_delta_flag;
+ ++sig_raised;
+ }
+ }
+
+ else if (0 == strncmp(srvcmd, _("SCAN"), 4))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<scan command from server>\n")));
+ if (sh.flag.isdaemon == S_TRUE)
+ {
+#ifdef SIGTTOU
+ raise(SIGTTOU);
+#else
+ sig_force_check = 1;
+ ++sig_raised;
+#endif
+ }
+ else
+ {
+ sig_force_check = 1;
+ ++sig_raised;
+ }
+ }
+
+ /* Unknown command
+ */
+ else
+ {
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ srvcmd,
+ _("sh_socket_server_cmd"));
+ }
+ SL_RET0(_("sh_socket_server_cmd"));
+}
+#endif /* #if defined (SH_WITH_CLIENT) */
+
+#if defined(SH_WITH_SERVER)
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <time.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
+#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
+#include <sys/param.h>
+#include <sys/ucred.h>
+#endif
+#endif
+
+
+int pf_unix_fd = -1;
+static char * sh_sockname = NULL;
+static char sh_sockpass_real[SOCKPASS_MAX+1];
+
+struct socket_cmd {
+ char cmd[SH_MAXMSGLEN];
+ char clt[SH_MAXMSGLEN];
+ char cti[81];
+ struct socket_cmd * next;
+};
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+#if !defined(AF_FILE)
+#define AF_FILE AF_UNIX
+#endif
+
+static struct socket_cmd * cmdlist = NULL;
+static struct socket_cmd * runlist = NULL;
+
+static int sh_socket_flaguse = S_FALSE;
+static int sh_socket_flaguid = 0;
+
+#include "sh_utils.h"
+
+/* The reload list stores information about
+ * reloads confirmed by clients (startup and/or
+ * runtime cinfiguration reloaded).
+ */
+struct reload_cmd {
+ char clt[SH_MAXMSGLEN];
+ time_t cti;
+ struct reload_cmd * next;
+};
+static struct reload_cmd * reloadlist = NULL;
+
+void sh_socket_add2reload (const char * clt)
+{
+ struct reload_cmd * new = reloadlist;
+
+ while (new)
+ {
+ if (0 == sl_strcmp(new->clt, clt))
+ {
+#ifdef SH_DEBUG_SOCKET
+ fprintf(stderr, "add2reload: time reset for %s\n", clt);
+#endif
+ sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
+ new->cti = time(NULL);
+ return;
+ }
+ new = new->next;
+ }
+
+ new = SH_ALLOC(sizeof(struct reload_cmd));
+#ifdef SH_DEBUG_SOCKET
+ fprintf(stderr, "add2reload: time set for %s\n", clt);
+#endif
+ sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
+ new->cti = time(NULL);
+
+ new->next = reloadlist;
+ reloadlist = new;
+
+ return;
+}
+
+#include "zAVLTree.h"
+#include "sh_html.h"
+#include "sh_tools.h"
+static void sh_socket_add2list (struct socket_cmd * in);
+
+static void sh_socket_probe4reload (void)
+{
+ struct reload_cmd * new;
+ struct socket_cmd cmd;
+
+ zAVLCursor avlcursor;
+ client_t * item;
+ extern zAVLTree * all_clients;
+
+ char * file;
+ unsigned long dummy;
+ struct stat buf;
+
+ for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
+ item = (client_t *) zAVLNext(&avlcursor))
+ {
+ if (item->status_now != CLT_INACTIVE)
+ {
+ int flag = 0;
+
+ file = get_client_conf_file (item->hostname, &dummy);
+
+ if (0 == stat (file, &buf))
+ {
+ new = reloadlist;
+ while (new)
+ {
+ if (0 == sl_strcmp(new->clt, item->hostname))
+ {
+ flag = 1; /* Client is in list already */
+
+ if (buf.st_mtime > new->cti)
+ {
+ /* reload */
+ sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
+ sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
+ sh_socket_add2list (&cmd);
+ }
+ break;
+ }
+ new = new->next;
+ }
+
+ if (flag == 0)
+ {
+ /* client is active, but start message has been missed; reload
+ */
+ sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
+ sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
+ sh_socket_add2list (&cmd);
+
+ /* Add the client to the reload list and set
+ * time to 0, since we don't know the startup time.
+ */
+ sh_socket_add2reload (item->hostname);
+ new = reloadlist;
+ while (new)
+ {
+ if (0 == sl_strcmp(new->clt, item->hostname))
+ {
+ new->cti = 0;
+ break;
+ }
+ new = new->next;
+ }
+ }
+ } /* if stat(file).. */
+ } /* if !CLT_INACTIVE */
+ } /* loop over clients */
+ return;
+}
+
+char * sh_get_sockpass (void)
+{
+ size_t j = 0;
+
+ while (skey->sh_sockpass[2*j] != '\0' && j < sizeof(sh_sockpass_real))
+ {
+ sh_sockpass_real[j] = skey->sh_sockpass[2*j];
+ ++j;
+ }
+ sh_sockpass_real[j] = '\0';
+
+ return sh_sockpass_real;
+}
+
+void sh_set_sockpass (void)
+{
+ int j;
+ for (j = 0; j < 15; ++j)
+ {
+ sh_sockpass_real[j] = '\0';
+ }
+}
+
+int sh_socket_use (const char * c)
+{
+ return sh_util_flagval(c, &sh_socket_flaguse);
+}
+
+int sh_socket_remove ()
+{
+ int retval = 0;
+#ifdef S_ISSOCK
+ struct stat sbuf;
+#endif
+
+ SL_ENTER(_("sh_socket_remove"));
+
+ if (NULL == sh_sockname)
+ {
+ SL_RETURN((retval),_("sh_socket_remove"));
+ }
+
+ if (0 != tf_trust_check (DEFAULT_PIDDIR, SL_YESPRIV))
+ {
+ SL_RETURN((-1),_("sh_socket_remove"));
+ }
+
+ if ( (retry_lstat(FIL__, __LINE__, sh_sockname, &sbuf) == 0) &&
+ (sbuf.st_uid == getuid()))
+ {
+#ifdef S_ISSOCK
+ if (S_ISSOCK (sbuf.st_mode))
+ {
+ retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
+ }
+#else
+ retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
+#endif
+ }
+ SL_RETURN((retval),_("sh_socket_remove"));
+}
+
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
+
+#define NEED_PASSWORD_AUTH
+#endif
+
+int sh_socket_uid (const char * c)
+{
+ uid_t val = (uid_t) strtol (c, (char **)NULL, 10);
+ sh_socket_flaguid = val;
+#if defined(NEED_PASSWORD_AUTH)
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("Config option SetSocketAllowUID not supported, use SetSocketPassword"),
+ _("sh_socket_uid"));
+#endif
+ return 0;
+}
+
+int sh_socket_password (const char * c)
+{
+#if defined(NEED_PASSWORD_AUTH)
+ int j, i;
+
+#define LCG(n) ((69069 * n) & 0xffffffffUL)
+
+ i = sl_strlen(c);
+ if (i > SOCKPASS_MAX) {
+ return -1;
+ }
+ for (j = 0; j < (2*SOCKPASS_MAX+1); ++j)
+ {
+ skey->sh_sockpass[j] = '\0';
+ }
+ for (j = 0; j < i; ++j)
+ {
+ skey->sh_sockpass[2*j] = c[j];
+ skey->sh_sockpass[(2*j)+1] = (LCG(c[j]) % 256);
+ }
+ return 0;
+#else
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("Config option SetSocketPassword not supported, use SetSocketAllowUID"),
+ _("sh_socket_password"));
+ (void) c;
+ return 0;
+#endif
+}
+
+
+int sh_socket_open_int ()
+{
+ struct sockaddr_un name;
+ size_t size;
+ int flags;
+#if defined(SO_PASSCRED)
+ socklen_t optval = 1;
+#endif
+ struct stat buf;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_socket_open_int"));
+
+ if (sh_socket_flaguse == S_FALSE)
+ {
+ SL_RETURN(0, _("sh_socket_open_int"));
+ }
+
+ if (sh_sockname == NULL)
+ {
+ size = sl_strlen(DEFAULT_PIDDIR) + 1 + sl_strlen(SH_INSTALL_NAME) + 6;
+ sh_sockname = SH_ALLOC(size); /* compile-time constant */
+ sl_strlcpy(sh_sockname, DEFAULT_PIDDIR, size);
+ sl_strlcat(sh_sockname, "/", size);
+ sl_strlcat(sh_sockname, SH_INSTALL_NAME, size);
+ sl_strlcat(sh_sockname, _(".sock"), size);
+ }
+
+ if (0 != sh_unix_check_piddir (sh_sockname))
+ {
+ SH_FREE(sh_sockname);
+ SL_RETURN((-1),_("sh_socket_open_int"));
+ }
+
+ pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ if ((pf_unix_fd) < 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_open_int: socket"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+
+ if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("PID dir path too long"),
+ _("sh_socket_open_int"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+
+ name.sun_family = AF_FILE;
+ sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
+
+ size = (offsetof (struct sockaddr_un, sun_path)
+ + strlen (name.sun_path) + 1);
+
+ flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
+
+ if (flags == 0)
+ {
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("Socket exists, trying to unlink it"),
+ _("sh_socket_open_int"));
+ if (sh_socket_remove() < 0)
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("Unlink of socket failed, maybe path not trusted"),
+ _("sh_socket_open_int"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+ }
+
+ if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_open_int: bind"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+
+#ifdef SO_PASSCRED
+ if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED,
+ &optval, sizeof(optval)))
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_open_int: setsockopt"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+#endif
+
+ flags = fcntl((pf_unix_fd), F_GETFL);
+ if (flags < 0)
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_open_int: fcntl1"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+
+ flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
+ if (flags < 0)
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_open_int: fcntl2"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+
+ if (0 != listen(pf_unix_fd, 5))
+ {
+ sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_open_int: listen"));
+ SL_RETURN( (-1), _("sh_socket_open_int"));
+ }
+ SL_RETURN( (0), _("sh_socket_open_int"));
+}
+
+
+/*
+ * Parts of the socket authentication code is copied from PostgreSQL:
+ *
+ * PostgreSQL Database Management System
+ * (formerly known as Postgres, then as Postgres95)
+ *
+ * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
+ *
+ * Portions Copyright (c) 1994, The Regents of the University of California
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without a written agreement
+ * is hereby granted, provided that the above copyright notice and this
+ * paragraph and the following two paragraphs appear in all copies.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
+ * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
+ * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+static int receive_message(int talkfd, struct msghdr * msg, size_t message_size)
+{
+ unsigned int retry = 0;
+ int nbytes;
+ char * message = msg->msg_iov->iov_base;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ do {
+ nbytes = recvmsg (talkfd, msg, 0);
+ if ((nbytes < 0) && (errno != EAGAIN))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: recvmsg"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return -1;
+ }
+ else if (nbytes < 0)
+ {
+ ++retry;
+ retry_msleep(0, 10);
+ }
+ } while ((nbytes < 0) && (retry < 3));
+
+ /* msg.msg_iov.iov_base, filled by recvmsg
+ */
+ message[message_size-1] = '\0';
+
+ if (nbytes < 0)
+ {
+ if (errno == EAGAIN)
+ {
+ /* no data */
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: recvfrom"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return 0;
+ }
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: recvfrom"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return -1;
+ }
+ return 0;
+}
+
+#if defined(HAVE_GETPEEREID)
+
+static int get_peer_uid(int talkfd)
+{
+ uid_t peer_uid;
+ gid_t peer_gid;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: getpeereid"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return -1;
+ }
+ return peer_uid;
+}
+
+#elif defined(SO_PEERCRED)
+
+static int get_peer_uid(int talkfd)
+{
+ char errbuf[SH_ERRBUF_SIZE];
+ struct ucred cr;
+#ifdef HAVE_SOCKLEN_T
+ socklen_t cl = sizeof(cr);
+#else
+ int cl = sizeof(cr);
+#endif
+
+ if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: getsockopt"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return -1;
+ }
+ return cr.uid;
+}
+
+#endif
+
+#if defined(NEED_PASSWORD_AUTH)
+char * check_password(char * message, int * client_uid, int talkfd)
+{
+ char * cmd = NULL;
+ char * eopw = NULL;
+ char * goodpassword = NULL;
+
+ goodpassword = sh_get_sockpass();
+ eopw = strchr(message, '@');
+ if (eopw)
+ *eopw = '\0';
+ /*
+ * message is null-terminated and >> goodpassword
+ */
+ if (0 == strcmp(goodpassword, message) &&
+ strlen(goodpassword) < (sizeof(message)/2))
+ {
+ *client_uid = sh_socket_flaguid;
+ cmd = &message[strlen(goodpassword)+1];
+ sh_set_sockpass();
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Bad password"),
+ _("sh_socket_read"));
+ sh_set_sockpass();
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return NULL;
+ }
+ return cmd;
+}
+#endif
+
+static int list_all (int talkfd, char * cmd);
+static int process_message(int talkfd, char * cmd, struct socket_cmd * srvcmd);
+
+static
+int sh_socket_read (struct socket_cmd * srvcmd)
+{
+ char message[SH_MAXMSG];
+ struct sockaddr_un name;
+ ACCEPT_TYPE_ARG3 size = sizeof(name);
+ int talkfd;
+ char * cmd = NULL;
+ int client_uid = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+ struct msghdr msg;
+ struct iovec iov;
+ int status;
+
+ if (pf_unix_fd < 0)
+ return 0;
+
+ iov.iov_base = (char *) &message;
+ iov.iov_len = sizeof(message);
+
+ memset (&msg, 0, sizeof (msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ /* the socket is non-blocking
+ * 'name' is the address of the sender socket
+ */
+ do {
+ talkfd = accept(pf_unix_fd, (struct sockaddr *) &name, &size);
+ } while (talkfd < 0 && errno == EINTR);
+
+ if ((talkfd < 0) && (errno == EAGAIN))
+ {
+ return 0;
+ }
+ else if (talkfd < 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: accept"));
+ return -1;
+ }
+
+ if (receive_message(talkfd, &msg, sizeof(message)) < 0)
+ return -1;
+
+ /* Authenticate request by peer uid or password.
+ */
+#if defined(HAVE_GETPEEREID)
+ client_uid = get_peer_uid(talkfd);
+ cmd = message;
+
+#elif defined(SO_PEERCRED)
+ client_uid = get_peer_uid(talkfd);
+ cmd = message;
+
+#elif defined(NEED_PASSWORD_AUTH)
+ cmd = check_password(message, &client_uid, talkfd);
+
+#else
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("Socket credentials not supported on this OS"),
+ _("sh_socket_read"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return -1;
+#endif
+
+ if (client_uid != sh_socket_flaguid)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
+ _("client does not have required uid"),
+ _("sh_socket_read: getsockopt"));
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return -1;
+ }
+
+ status = process_message(talkfd, cmd, srvcmd);
+
+ sl_close_fd(FIL__, __LINE__, talkfd);
+ return status;
+}
+
+static int check_valid_command(const char * str)
+{
+ unsigned int i = 0;
+ char * commands[] = { N_("DELTA"), N_("RELOAD"), N_("STOP"), N_("SCAN"),
+ N_("CANCEL"), N_("LISTALL"), N_("LIST"), N_("PROBE"), NULL };
+
+ while (commands[i])
+ {
+ if (0 == strcmp(_(commands[i]), str))
+ {
+ return 0;
+ }
+ ++i;
+ }
+ return -1;
+}
+
+static int send_reply (int fd, char * msg)
+{
+ int nbytes = send (fd, msg, strlen(msg) + 1, 0);
+
+ if (nbytes < 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("send_reply"));
+ return -1;
+ }
+
+ return nbytes;
+}
+
+static int process_message(int talkfd, char * cmd, struct socket_cmd * srvcmd)
+{
+ int nbytes;
+ char error_type[SH_ERRBUF_SIZE] = { '\0' };
+ char * clt = (cmd) ? strchr(cmd, ':') : NULL;
+
+ if (clt && 0 == strncmp(cmd, _("DELTA:"), 6))
+ {
+ /* DELTA:uuid:hostname
+ */
+ char * uuid = clt;
+
+ *uuid = '\0'; ++uuid;
+ clt = strchr(uuid, ':');
+ if (clt) { *clt = '\0'; ++clt; }
+
+ if (sh_uuid_check(uuid) < 0)
+ {
+ sl_strlcpy(error_type, _("!E:uuid-format:"), sizeof(error_type));
+ sl_strlcat(error_type, uuid, sizeof(error_type));
+ clt = NULL;
+ }
+
+ --uuid; *uuid = ':';
+ }
+ else if (clt && *clt == ':')
+ {
+ *clt = '\0'; ++clt;
+ if (check_valid_command(cmd) < 0)
+ {
+ sl_strlcpy(error_type, _("!E:cmd-invalid:"), sizeof(error_type));
+ sl_strlcat(error_type, cmd, sizeof(error_type));
+ clt = NULL;
+ }
+ }
+
+ if (clt != NULL)
+ {
+ if (sl_strlen(cmd) >= SH_MAXMSGLEN)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("Bad message format: command too long"),
+ _("sh_socket_read"));
+ sl_strlcpy(error_type, _("!E:cmd-toolong"), sizeof(error_type));
+ send_reply(talkfd, error_type);
+ return -1;
+ }
+ else if (sl_strlen(clt) >= SH_MAXMSGLEN)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("Bad message format: hostname too long"),
+ _("sh_socket_read"));
+ sl_strlcpy(error_type, _("!E:hostname-toolong"), sizeof(error_type));
+ send_reply(talkfd, error_type);
+ return -1;
+ }
+
+ if (0 == strncmp(cmd, _("LIST"), 4))
+ return list_all(talkfd, cmd);
+ else if (0 == strncmp(cmd, _("PROBE"), 4))
+ {
+ sh_socket_probe4reload();
+ sl_strlcpy(cmd, _("LIST"), 5);
+ return list_all(talkfd, cmd);
+ }
+
+ sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
+ sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
+ --clt; *clt = ':';
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("Bad message format"),
+ _("sh_socket_read"));
+ if (error_type[0] == '\0')
+ sl_strlcpy(error_type, _("!E:message-format"), sizeof(error_type));
+ send_reply(talkfd, error_type);
+ return -1;
+ }
+
+ /* Bounce the message back to the sender.
+ */
+ nbytes = send_reply(talkfd, cmd);
+
+ return nbytes;
+}
+
+static int list_all (int talkfd, char * cmd)
+{
+ int nbytes;
+ struct socket_cmd * list_cmd;
+ char message[SH_MAXMSG];
+ char errbuf[SH_ERRBUF_SIZE];
+
+ if (0 == strncmp(cmd, _("LISTALL"), 7))
+ {
+ list_cmd = runlist;
+ while (list_cmd)
+ {
+ sl_snprintf(message, sizeof(message), _("SENT %42s %32s %s"),
+ list_cmd->cmd, list_cmd->clt, list_cmd->cti);
+
+ nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
+ if (nbytes < 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: sendto"));
+ return -1;
+ }
+ list_cmd = list_cmd->next;
+ }
+ }
+
+ list_cmd = cmdlist;
+ while (list_cmd)
+ {
+ sl_snprintf(message, sizeof(message), _(">>>> %42s %32s %s"),
+ list_cmd->cmd, list_cmd->clt, list_cmd->cti);
+
+ nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
+ if (nbytes < 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ sh_error_message (errno, errbuf, sizeof(errbuf)),
+ _("sh_socket_read: sendto"));
+ return -1;
+ }
+ list_cmd = list_cmd->next;
+ }
+
+ send (talkfd, _("END"), 4, 0);
+ return 0;
+}
+
+static void sh_socket_add2list (struct socket_cmd * in)
+{
+ struct socket_cmd * new = cmdlist;
+ struct socket_cmd * last = cmdlist;
+
+ while (new)
+ {
+ /* Only skip identical commands.
+ */
+ if (0 == sl_strcmp(new->clt, in->clt) &&
+ 0 == sl_strcmp(new->cmd, in->cmd))
+ {
+ (void) sh_unix_time(0, new->cti, sizeof(new->cti));
+ return;
+ }
+ new = new->next;
+ }
+
+ new = SH_ALLOC(sizeof(struct socket_cmd));
+ sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
+ sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
+ (void) sh_unix_time(0, new->cti, sizeof(new->cti));
+ new->next = NULL;
+
+ if (last)
+ {
+ while (last->next) { last = last->next; }
+ last->next = new;
+ }
+ else
+ {
+ cmdlist = new;
+ }
+ return;
+}
+
+static void sh_socket_add2run (struct socket_cmd * in)
+{
+ struct socket_cmd * new = runlist;
+ struct socket_cmd * last = runlist;
+
+ while (new)
+ {
+ /* Only skip identical commands. First 5 will
+ * make all 'DELTA' identical.
+ */
+ if (0 == sl_strcmp(new->clt, in->clt) &&
+ 0 == sl_strncmp(new->cmd, in->cmd, 5))
+ {
+ sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
+ (void) sh_unix_time(0, new->cti, sizeof(new->cti));
+ return;
+ }
+ new = new->next;
+ }
+
+ new = SH_ALLOC(sizeof(struct socket_cmd));
+ sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
+ sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
+#ifdef SH_DEBUG_SOCKET
+ fprintf(stderr, "add2run: time set for %s\n", new->clt);
+#endif
+ (void) sh_unix_time(0, new->cti, sizeof(new->cti));
+ new->next = NULL;
+
+ if (last)
+ {
+ while (last->next) { last = last->next; }
+ last->next = new;
+ }
+ else
+ {
+ runlist = new;
+ }
+ return;
+}
+
+
+
+static void sh_socket_rm2list (const char * client_name, int remove_all)
+{
+ struct socket_cmd * old = cmdlist;
+ struct socket_cmd * new = cmdlist;
+
+ while (new)
+ {
+ if (0 == sl_strcmp(new->clt, client_name))
+ {
+ if ((new == cmdlist) && (new->next == NULL))
+ {
+ /* There is only one entry */
+ cmdlist = NULL;
+ SH_FREE(new);
+ return;
+ }
+ else if (new == cmdlist)
+ {
+ /* first entry: new = old = cmdlist */
+ cmdlist = new->next;
+ SH_FREE(new);
+ if (remove_all == S_FALSE)
+ return;
+ old = cmdlist;
+ new = cmdlist;
+ continue;
+ }
+ else
+ {
+ old->next = new->next;
+ SH_FREE(new);
+ if (remove_all == S_FALSE)
+ return;
+ new = old;
+ }
+ }
+ old = new;
+ new = new->next;
+ }
+ return;
+}
+
+/* poll the socket to gather input
+ */
+int sh_socket_poll()
+{
+ struct socket_cmd cmd;
+ char cancel_cmd[SH_MAXMSGLEN];
+
+ /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
+
+ if (pf_unix_fd < 0)
+ return 0;
+
+ sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
+
+ while (sh_socket_read (&cmd) > 0)
+ {
+ if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
+ sh_socket_rm2list (cmd.clt, S_TRUE);
+ else
+ sh_socket_add2list (&cmd);
+ }
+ return 0;
+}
+
+/* return the command associated with client_name
+ and remove the corresponding entry
+ */
+char * sh_socket_check(const char * client_name)
+{
+ struct socket_cmd * new = cmdlist;
+ static char out[SH_MAXMSGLEN];
+
+ while (new)
+ {
+ if (0 == sl_strcmp(new->clt, client_name))
+ {
+ sl_strlcpy(out, new->cmd, sizeof(out));
+ sh_socket_add2run (new);
+ sh_socket_rm2list (client_name, S_FALSE);
+ return out;
+ }
+ new = new->next;
+ }
+ return NULL;
+}
+/* #if defined (SH_WITH_SERVER)
+ */
+#endif
+
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_cmdlist (CuTest *tc) {
+
+#if defined (SH_WITH_SERVER)
+ struct socket_cmd cmd;
+ char * p;
+
+ sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+
+ sh_socket_add2list (&cmd);
+ p = sh_socket_check("one");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "RELOAD", p);
+
+ p = sh_socket_check("one");
+ CuAssertPtrEquals(tc, NULL, p);
+
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "DELTA", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ p = sh_socket_check("one");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "RELOAD", p);
+
+ sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ p = sh_socket_check("one");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "STOP", p);
+ p = sh_socket_check("one");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "DELTA", p);
+ p = sh_socket_check("one");
+ CuAssertPtrEquals(tc, NULL, p);
+
+ /* Test removal in correct order */
+ sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.cmd, "DELTA", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.cmd, "FOOBAR", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ sh_socket_rm2list ("one", S_FALSE);
+
+ p = sh_socket_check("one");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "STOP", p);
+
+ sh_socket_rm2list ("one", S_FALSE);
+
+ p = sh_socket_check("one");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "FOOBAR", p);
+
+ p = sh_socket_check("one");
+ CuAssertPtrEquals(tc, NULL, p);
+
+ sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
+ sl_strlcpy(cmd.cmd, "DELTA", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+ sl_strlcpy(cmd.cmd, "FOOBAR", sizeof(cmd.cmd));
+ sh_socket_add2list (&cmd);
+
+ sh_socket_rm2list ("one", S_TRUE);
+ p = sh_socket_check("one");
+ CuAssertPtrEquals(tc, NULL, p);
+
+ p = sh_socket_check("two");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "STOP", p);
+ p = sh_socket_check("two");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "RELOAD", p);
+ p = sh_socket_check("two");
+ CuAssertPtrEquals(tc, NULL, p);
+
+ p = sh_socket_check("three");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "STOP", p);
+ p = sh_socket_check("three");
+ CuAssertPtrNotNull(tc, p);
+ CuAssertStrEquals(tc, "RELOAD", p);
+ p = sh_socket_check("three");
+ CuAssertPtrEquals(tc, NULL, p);
+
+ p = sh_socket_check("four");
+ CuAssertPtrEquals(tc, NULL, p);
+#else
+ (void) tc;
+#endif
+}
+
+#endif /* #ifdef SH_CUTEST */
+
+
+
diff --git a/src/sh_srp.c b/src/sh_srp.c
new file mode 100644
index 0000000..ecc757c
--- /dev/null
+++ b/src/sh_srp.c
@@ -0,0 +1,812 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "samhain.h"
+
+#ifdef USE_SRP_PROTOCOL
+
+#if (defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER))
+
+#include "sh_tiger.h"
+#include "sh_mem.h"
+#include "sh_utils.h"
+#include "sh_srp.h"
+
+#if !defined(HAVE_LIBGMP) || !defined(HAVE_GMP_H)
+#include "bignum.h"
+#else
+
+#include <gmp.h>
+
+#define BIG_OK 0
+#define bigerr_t int
+int big_errno = BIG_OK;
+
+#define bignum MP_INT
+
+inline
+int big_create (bignum * a)
+{
+ mpz_init(a);
+ return 0;
+}
+
+inline
+int big_zerop (bignum * a)
+{
+ mpz_t b;
+ int i;
+ mpz_init_set_str(b, "0", 10);
+ i = mpz_cmp(a, b);
+ mpz_clear(b);
+ if (i)
+ return 0;
+ else
+ return 1;
+}
+
+inline
+int big_trunc (bignum * a, bignum * b, bignum * q, bignum *r)
+{
+ mpz_tdiv_qr(q, r, a, b);
+ return 0;
+}
+
+inline
+int big_exptmod (bignum * a, bignum * b, bignum * c, bignum *d)
+{
+ mpz_powm(d, a, b, c);
+ return 0;
+}
+
+char * get_str_internal = NULL;
+int siz_str_internal = 0;
+
+static
+char * big_string (bignum * a, int base)
+{
+ char * str = NULL;
+ int size;
+ int i;
+ str = mpz_get_str (str, base, a);
+
+ if (get_str_internal == NULL)
+ {
+ get_str_internal = calloc(1,512); /* only once */
+ if (get_str_internal)
+ {
+ siz_str_internal = 512;
+ }
+ else
+ {
+ if (str != NULL)
+ free(str);
+ return 0;
+ }
+ get_str_internal[0] = '\0';
+ }
+
+ if (str != NULL)
+ {
+ size = strlen(str) + 1;
+ if (size > siz_str_internal)
+ {
+ char * ptr = realloc (get_str_internal, size);
+ if (ptr)
+ get_str_internal = ptr;
+ else
+ { free(get_str_internal); get_str_internal = NULL; }
+ }
+ if (get_str_internal == NULL)
+ {
+ free(str);
+ return NULL;
+ }
+ siz_str_internal = size;
+ sl_strlcpy (get_str_internal, str, siz_str_internal);
+ for (i = 0; i < (size-1); ++i)
+ if (get_str_internal[i] >= 'a' && get_str_internal[i] <= 'f' )
+ get_str_internal[i] = get_str_internal[i] - 'a' + 'A';
+ free (str);
+ }
+ return get_str_internal;
+}
+
+inline
+int big_add(bignum * a, bignum * b, bignum * c)
+{
+ mpz_add(c, a, b);
+ return 0;
+}
+
+inline
+int big_sub(bignum * a, bignum * b, bignum * c)
+{
+ mpz_sub(c, a, b);
+ return 0;
+}
+
+inline
+int big_mul(bignum * a, bignum * b, bignum * c)
+{
+ mpz_mul(c, a, b);
+ return 0;
+}
+
+inline
+int big_greaterp(bignum * a, bignum * b)
+{
+ return mpz_cmp(a, b) > 0;
+}
+
+inline
+int big_set_big(bignum * a, bignum * b)
+{
+ mpz_set(b, a);
+ return 0;
+}
+
+
+inline
+int big_set_string(const char * str, int base, bignum * a)
+{
+ mpz_set_str (a, str, base);
+ return 0;
+}
+
+
+#define big_init_pkg() 0
+#define big_release_pkg()
+#define big_destroy mpz_clear
+
+/* #if defined(HAVE_LIBGMP)
+ */
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_srp.c")
+
+typedef struct sh_srp_struc {
+ char x[KEY_LEN+1];
+ bignum a;
+ bignum p;
+ bignum g;
+} sh_srp_t;
+
+static sh_srp_t sh_srp;
+
+void sh_srp_x (char * salt, char * password)
+{
+
+ char *combi;
+ size_t len, l2;
+ register int i;
+ unsigned char * dez = NULL;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_srp_x"));
+
+ /* patch by Andreas Piesk
+ */
+ if (password == NULL)
+ dez = (unsigned char *) &(skey->pw[0]);
+ else
+ dez = (unsigned char *) password;
+
+ for (i = 0; i < PW_LEN; ++i)
+ {
+ skey->vernam[i] = (char)(*dez);
+ ++dez;
+ }
+ skey->vernam[PW_LEN] = '\0';
+
+ (void) sl_strlcpy (skey->vernam,
+ sh_tiger_hash(skey->vernam, TIGER_DATA, PW_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN);
+ skey->vernam[KEY_LEN] = '\0';
+
+ len = sl_strlen(salt) + 1;
+ l2 = sl_strlen(skey->vernam);
+ if (sl_ok_adds(len, l2))
+ len += l2;
+
+ /* H(s,P)
+ */
+ combi = SH_ALLOC(len);
+ (void) sl_strlcpy (combi, salt, len);
+ (void) sl_strlcat (combi, skey->vernam, len);
+ (void) sl_strlcpy (sh_srp.x,
+ sh_tiger_hash(combi, TIGER_DATA,
+ (unsigned long) sl_strlen(combi),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ SH_FREE (combi);
+
+ SL_RET0(_("sh_srp_x"));
+}
+
+char * sh_srp_M (char * x1, char * x2, char * x3, char * hash, size_t size)
+{
+ char *combi;
+ size_t len, l2, l3;
+
+ SL_ENTER(_("sh_srp_M"));
+
+ ASSERT_RET((x1 != NULL && x2 != NULL && x3 !=NULL),
+ _("x1 != NULL && x2 != NULL && x3 !=NULL"), NULL);
+
+ len = sl_strlen(x1) + 1;
+ l2 = sl_strlen(x2);
+ l3 = sl_strlen(x3);
+
+ if (sl_ok_adds(len, l2))
+ len += l2;
+ if (sl_ok_adds(len, l3))
+ len += l3;
+
+ /* H(x1,x2,x3)
+ */
+ combi = SH_ALLOC(len);
+ (void) sl_strlcpy (combi, x1, len);
+ (void) sl_strlcat (combi, x2, len);
+ (void) sl_strlcat (combi, x3, len);
+ (void) sh_tiger_hash(combi, TIGER_DATA, (unsigned long) (len-1),
+ hash, size);
+ SH_FREE (combi);
+
+ SL_RETURN(hash, _("sh_srp_M"));
+}
+
+
+void sh_srp_exit()
+{
+ SL_ENTER(_("sh_srp_exit"));
+ big_destroy(&sh_srp.g);
+ big_destroy(&sh_srp.p);
+ big_destroy(&sh_srp.a);
+
+ big_release_pkg();
+
+ big_errno = BIG_OK;
+ SL_RET0(_("sh_srp_exit"));
+}
+
+
+int sh_srp_init()
+{
+ bigerr_t res;
+ char modulus[80*4];
+
+ SL_ENTER(_("sh_srp_init"));
+
+ big_errno = BIG_OK;
+
+ res = big_init_pkg();
+
+ if (res == BIG_OK)
+ {
+ res = big_create(&sh_srp.p);
+ if (res == BIG_OK)
+ res = big_create(&sh_srp.g);
+ if (res == BIG_OK)
+ res = big_create(&sh_srp.a);
+ if (res == BIG_OK)
+ {
+ (void) sl_strlcpy(modulus, SRP_MODULUS_1024_1, sizeof(modulus));
+ (void) sl_strlcat(modulus, SRP_MODULUS_1024_2, sizeof(modulus));
+ (void) sl_strlcat(modulus, SRP_MODULUS_1024_3, sizeof(modulus));
+ (void) sl_strlcat(modulus, SRP_MODULUS_1024_4, sizeof(modulus));
+ }
+ if (res == BIG_OK)
+ res = big_set_string (modulus, 16, &sh_srp.p);
+ if (res == BIG_OK)
+ res = big_set_string (SRP_GENERATOR_1024, 16, &sh_srp.g);
+ if (res == BIG_OK)
+ {
+ SL_RETURN (0, _("sh_srp_init"));
+ }
+ else
+ sh_srp_exit();
+ }
+ SL_RETURN ((-1), _("sh_srp_init"));
+}
+
+
+int sh_srp_make_a ()
+{
+ UINT32 randl[6];
+ int i;
+ int res;
+ char hash[KEY_LEN+1];
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_srp_make_a"));
+
+ for (i = 0; i < 6; ++i)
+ randl[i] = (UINT32) taus_get ();
+
+ (void) sl_strlcpy (hash,
+ sh_tiger_hash((char *)&randl[0], TIGER_DATA,
+ (unsigned long) 6*sizeof(UINT32),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ hash[KEY_LEN] = '\0';
+
+ res = big_set_string (hash, 16, &sh_srp.a);
+ if (res == BIG_OK)
+ {
+ SL_RETURN((0), _("sh_srp_make_a"));
+ }
+ else
+ {
+ SL_RETURN((-1), _("sh_srp_make_a"));
+ }
+}
+
+/* return 0 if AB is NOT zero
+ */
+int sh_srp_check_zero (char * AB_str)
+{
+ bignum AB, q, r;
+ bigerr_t res;
+ int val;
+
+ SL_ENTER(_("sh_srp_check_zero"));
+
+ ASSERT_RET((AB_str != NULL), _("AB_str != NULL"), (-1));
+
+ res = big_create(&AB);
+ if (res == BIG_OK)
+ res = big_create(&q);
+ if (res == BIG_OK)
+ res = big_create(&r);
+
+ if (res == BIG_OK)
+ res = big_set_string (AB_str, 16, &AB);
+ if (res == BIG_OK)
+ res = big_trunc(&AB, &sh_srp.p, &q, &r); /* is last one the remainder ? */
+
+ if (res != BIG_OK) val = (-1);
+ else if (0 != big_zerop(&AB) ) val = (-1); /* 0 != (sign == 0) */
+ else if (0 != big_zerop(&r) ) val = (-1); /* 0 != (sign == 0) */
+ else val = 0;
+
+ big_destroy(&AB);
+ big_destroy(&q);
+ big_destroy(&r);
+
+ SL_RETURN((val), _("sh_srp_check_zero"));
+}
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+
+char * sh_srp_A ()
+{
+ bignum A;
+ char *str;
+ char *combi;
+ bigerr_t res;
+
+ SL_ENTER(_("sh_srp_A"));
+
+ res = big_create(&A);
+
+ if (res == BIG_OK)
+ res = big_exptmod (&sh_srp.g, &sh_srp.a, &sh_srp.p, &A);
+
+ if (res == BIG_OK)
+ str = big_string (&A, 16);
+ else
+ str = NULL;
+
+ if (str != NULL)
+ combi = sh_util_strdup(str);
+ else
+ combi = NULL;
+
+ big_destroy(&A);
+ SL_RETURN(combi, _("sh_srp_A"));
+}
+
+/* #ifdef SH_WITH_CLIENT */
+#endif
+
+#ifdef SH_WITH_SERVER
+
+char * sh_srp_B (char * verifier)
+{
+ bignum B, v, t, dummy;
+ char *str;
+ char *combi;
+ bigerr_t res;
+
+ SL_ENTER(_("sh_srp_B"));
+
+ ASSERT_RET((verifier != NULL), _("verifier != NULL"), (NULL));
+
+ res = big_create(&dummy);
+
+ if (res == BIG_OK)
+ res = big_create(&t);
+ if (res == BIG_OK)
+ res = big_create(&v);
+ if (res == BIG_OK)
+ res = big_create(&B);
+
+ if (res == BIG_OK)
+ res = big_exptmod (&sh_srp.g, &sh_srp.a, &sh_srp.p, &t);
+
+ if (res == BIG_OK)
+ big_set_string (verifier, 16, &v);
+
+ if (res == BIG_OK)
+ res = big_add (&t, &v, &dummy);
+
+ if (res == BIG_OK)
+ {
+ if ( big_greaterp(&dummy, &sh_srp.p) )
+ res = big_sub(&dummy, &sh_srp.p, &B);
+ else
+ res = big_set_big(&dummy, &B);
+ }
+
+ if (res == BIG_OK)
+ str = big_string (&B, 16);
+ else
+ str = NULL;
+
+ if (str != NULL)
+ combi = sh_util_strdup(str);
+ else
+ combi = NULL;
+
+ big_destroy(&B);
+ big_destroy(&v);
+ big_destroy(&t);
+ big_destroy(&dummy);
+
+ SL_RETURN(combi, _("sh_srp_B"));
+}
+/* #ifdef SH_WITH_SERVER */
+#endif
+
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+char * sh_srp_S_c (char * u_str, char * B_str)
+{
+ bignum u, B, x, t, base, z1, z2;
+ char *str;
+ char *combi;
+ bigerr_t res;
+
+ SL_ENTER(_("sh_srp_S_c"));
+
+ ASSERT_RET((u_str != NULL && B_str != NULL),
+ _("u_str != NULL && B_str != NULL"), (NULL));
+
+ big_errno = BIG_OK;
+
+ res = big_create(&z2);
+ if (res == BIG_OK)
+ res = big_create(&z1);
+ if (res == BIG_OK)
+ res = big_create(&base);
+ if (res == BIG_OK)
+ res = big_create(&t);
+ if (res == BIG_OK)
+ res = big_create(&x);
+ if (res == BIG_OK)
+ res = big_create(&B);
+ if (res == BIG_OK)
+ res = big_create(&u);
+
+ if (res == BIG_OK)
+ res = big_set_string (B_str, 16, &B);
+ if (res == BIG_OK)
+ res = big_set_string (sh_srp.x, 16, &x);
+ if (res == BIG_OK)
+ res = big_set_string (u_str, 16, &u);
+
+ /* the base (B - g^x)
+ */
+ if (res == BIG_OK)
+ res = big_exptmod (&sh_srp.g, &x, &sh_srp.p, &t);
+
+ if (res == BIG_OK)
+ {
+ if ( big_greaterp(&B, &t) != 0)
+ {
+ res = big_sub(&B, &t, &base);
+ }
+ else
+ {
+ res = big_add(&B, &sh_srp.p, &z2);
+ if (res == BIG_OK)
+ res = big_sub(&z2, &t, &base);
+ }
+ }
+
+ /* the exponent (a + ux)
+ */
+ if (res == BIG_OK)
+ res = big_mul (&u, &x, &t);
+ if (res == BIG_OK)
+ res = big_trunc(&t, &sh_srp.p, &z1, &z2); /* is last one the remainder ? */
+ if (res == BIG_OK)
+ res = big_add(&sh_srp.a, &z2, &z1);
+ if (res == BIG_OK)
+ {
+ if ( big_greaterp(&z1, &sh_srp.p) != 0)
+ res = big_sub(&z1, &sh_srp.p, &z2);
+ else
+ res = big_set_big(&z1, &z2);
+ }
+
+ if (res == BIG_OK)
+ res = big_exptmod (&base, &z2, &sh_srp.p, &t);
+
+ if (res == BIG_OK)
+ str = big_string (&t, 16);
+ else
+ str = NULL;
+
+ if (str != NULL)
+ combi = sh_util_strdup(str);
+ else
+ combi = NULL;
+
+ big_destroy(&z1);
+ big_destroy(&z2);
+ big_destroy(&base);
+ big_destroy(&t);
+ big_destroy(&x);
+ big_destroy(&B);
+ big_destroy(&u);
+
+ SL_RETURN(combi, _("sh_srp_S_c"));
+}
+
+/* #ifdef SH_WITH_CLIENT */
+#endif
+
+#ifdef SH_WITH_SERVER
+
+
+char * sh_srp_S_s (char * u_str, char * A_str, char * v_str)
+{
+ bignum u, A, v, t, base, z1, z2;
+ char *str;
+ char *combi;
+ bigerr_t res;
+
+ SL_ENTER(_("sh_srp_S_s"));
+
+ ASSERT_RET((u_str != NULL && A_str != NULL && v_str != NULL),
+ _("u_str != NULL && A_str != NULL && v_str != NULL"),
+ (NULL));
+
+ big_errno = BIG_OK;
+
+ res = big_create(&z2);
+ if (res == BIG_OK)
+ res = big_create(&z1);
+ if (res == BIG_OK)
+ res = big_create(&base);
+ if (res == BIG_OK)
+ res = big_create(&t);
+ if (res == BIG_OK)
+ res = big_create(&v);
+ if (res == BIG_OK)
+ res = big_create(&A);
+ if (res == BIG_OK)
+ res = big_create(&u);
+
+ if (res == BIG_OK)
+ res = big_set_string (A_str, 16, &A);
+ if (res == BIG_OK)
+ res = big_set_string (v_str, 16, &v);
+ if (res == BIG_OK)
+ res = big_set_string (u_str, 16, &u);
+
+ /* the base (Av^u)
+ */
+ if (res == BIG_OK)
+ res = big_exptmod (&v, &u, &sh_srp.p, &t);
+ if (res == BIG_OK)
+ res = big_mul (&A, &t, &z1);
+ if (res == BIG_OK)
+ res = big_trunc(&z1, &sh_srp.p, &z2, &base); /* is last the remainder ? */
+
+ if (res == BIG_OK)
+ res = big_exptmod (&base, &sh_srp.a, &sh_srp.p, &t);
+
+ if (res == BIG_OK)
+ str = big_string (&t, 16);
+ else
+ str = NULL;
+
+ if (str != NULL)
+ combi = sh_util_strdup(str);
+ else
+ combi = NULL;
+
+ big_destroy(&z1);
+ big_destroy(&z2);
+ big_destroy(&base);
+ big_destroy(&t);
+ big_destroy(&v);
+ big_destroy(&A);
+ big_destroy(&u);
+
+ SL_RETURN(combi, _("sh_srp_S_s"));
+}
+
+/* #ifdef SH_WITH_SERVER */
+#endif
+
+
+char * sh_srp_verifier (void)
+{
+ bignum x, v;
+ char *combi;
+ char *str;
+ bigerr_t res;
+
+ SL_ENTER(_("sh_srp_verifier"));
+
+ res = big_create(&x);
+ if (res == BIG_OK)
+ res = big_create(&v);
+
+ if (res == BIG_OK)
+ res = big_set_string (sh_srp.x, 16, &x);
+
+ if (res == BIG_OK)
+ res = big_exptmod (&sh_srp.g, &x, &sh_srp.p, &v);
+
+ if (res == BIG_OK)
+ str = big_string (&v, 16);
+ else
+ str = NULL;
+
+ if (str != NULL)
+ combi = sh_util_strdup(str);
+ else
+ combi = NULL;
+
+ big_destroy(&x);
+ big_destroy(&v);
+
+ SL_RETURN(combi, _("sh_srp_verifier"));
+}
+
+
+/* #if (defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER)) */
+
+#endif
+
+/* #ifdef USE_SRP_PROTOCOL */
+
+#endif
+
+
+#ifdef SH_CUTEST
+#include "CuTest.h"
+
+void Test_srp (CuTest *tc)
+{
+#if defined(USE_SRP_PROTOCOL) && (defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER))
+
+ int result;
+ char modulus[80*4];
+ bignum a, b, c;
+ bigerr_t res;
+ char *str = NULL;
+
+ res = sh_srp_init();
+ CuAssertTrue(tc, res == 0);
+
+ (void) sl_strlcpy(modulus, SRP_MODULUS_1024_1, sizeof(modulus));
+ (void) sl_strlcat(modulus, SRP_MODULUS_1024_2, sizeof(modulus));
+ (void) sl_strlcat(modulus, SRP_MODULUS_1024_3, sizeof(modulus));
+ (void) sl_strlcat(modulus, SRP_MODULUS_1024_4, sizeof(modulus));
+
+ res = big_create(&a);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ /* Check plain zero
+ */
+ result = sh_srp_check_zero ("0");
+ CuAssertTrue(tc, result != 0);
+
+ res = big_set_string ("0", 16, &a);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ result = sh_srp_check_zero (big_string(&a, 16));
+ CuAssertTrue(tc, result != 0);
+
+ /* Check modulus (equals 0 % M)
+ */
+ result = sh_srp_check_zero (modulus);
+ CuAssertTrue(tc, result != 0);
+
+ res = big_set_string (modulus, 16, &a);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ result = sh_srp_check_zero (big_string(&a, 16));
+ CuAssertTrue(tc, result != 0);
+
+ /* Check non-zero
+ */
+ modulus[0] = 'a';
+
+ result = sh_srp_check_zero (modulus);
+ CuAssertTrue(tc, result == 0);
+
+ res = big_set_string (modulus, 16, &a);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ result = sh_srp_check_zero (big_string(&a, 16));
+ CuAssertTrue(tc, result == 0);
+
+ modulus[0] = 'f';
+
+ /* Check multiple of modulus
+ */
+ res = big_set_string (modulus, 16, &a);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ res = big_create(&b);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ res = big_create(&c);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ res = big_set_string ("deadbeef", 16, &b);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ res = big_mul (&a, &b, &c);
+ CuAssertTrue(tc, res == BIG_OK);
+
+ str = strdup(big_string (&c, 16));
+ CuAssertPtrNotNull(tc, str);
+
+ result = sh_srp_check_zero (str);
+ CuAssertTrue(tc, result != 0);
+
+#else
+ (void) tc; /* fix compiler warning */
+#endif
+ return;
+}
+#endif
+
+
+
diff --git a/src/sh_static.c b/src/sh_static.c
new file mode 100644
index 0000000..99ce783
--- /dev/null
+++ b/src/sh_static.c
@@ -0,0 +1,2075 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Nov 6, 2003 Initial version.
+ *
+ * NOTE: This implementation is quite strict about requiring all
+ * field seperators. It also does not allow leading whitespace
+ * except when processing the numeric fields. glibc is more
+ * lenient. See the various glibc difference comments below.
+ *
+ * TODO:
+ * Move to dynamic allocation of (currently staticly allocated)
+ * buffers; especially for the group-related functions since
+ * large group member lists will cause error returns.
+ *
+ */
+
+/* Jul 20, 2004 Adapted for samhain. Rainer Wichmann.
+ *
+ * Stripped all unneeded code.
+ */
+
+#include "config_xor.h"
+
+#if defined(SH_COMPILE_STATIC) && defined(__linux__)
+
+#define _GNU_SOURCE
+#include <features.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stddef.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "sh_pthread.h"
+
+extern int sl_close_fd (const char * file, int line, int fd);
+extern int sl_fclose (const char * file, int line, FILE * fp);
+
+
+#ifndef _PATH_PASSWD
+#define _PATH_PASSWD "/etc/passwd"
+#endif
+#ifndef _PATH_GROUP
+#define _PATH_GROUP "/etc/group"
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_static.c")
+
+extern int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz);
+extern int sl_strlcat(char * dst, /*@null@*/const char * src, size_t siz);
+
+
+/**********************************************************************/
+/* Sizes for staticly allocated buffers. */
+
+#define PWD_BUFFER_SIZE 256
+#define GRP_BUFFER_SIZE 3584
+#define GRP_BUFFER_SIZE_MALLOC 32768
+
+/**********************************************************************/
+/* Prototypes for internal functions. */
+
+static int __parsepwent(void *pw, char *line);
+static int __parsegrent(void *gr, char *line);
+
+static int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
+ char *__restrict line_buff,
+ size_t buflen, FILE *f);
+
+#undef GETXXKEY_R_FUNC
+#undef GETXXKEY_R_PARSER
+#undef GETXXKEY_R_ENTTYPE
+#undef GETXXKEY_R_TEST
+#undef DO_GETXXKEY_R_KEYTYPE
+#undef DO_GETXXKEY_R_PATHNAME
+#define GETXXKEY_R_FUNC sh_getpwnam_r
+#define GETXXKEY_R_PARSER __parsepwent
+#define GETXXKEY_R_ENTTYPE struct passwd
+#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
+#define DO_GETXXKEY_R_KEYTYPE const char *__restrict
+#define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
+
+int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
+ GETXXKEY_R_ENTTYPE *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ GETXXKEY_R_ENTTYPE **__restrict result)
+{
+ FILE *stream;
+ int rv;
+
+ *result = NULL;
+
+ if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
+ rv = errno;
+ } else {
+ /* __STDIO_SET_USER_LOCKING(stream); */
+ do {
+ if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
+ buffer, buflen, stream))
+ ) {
+ if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
+ *result = resultbuf;
+ break;
+ }
+ } else {
+ if (rv == ENOENT) { /* end-of-file encountered. */
+ rv = 0;
+ }
+ break;
+ }
+ } while (1);
+ sl_fclose(FIL__, __LINE__, stream);
+ }
+
+ return rv;
+}
+
+#undef GETXXKEY_R_FUNC
+#undef GETXXKEY_R_PARSER
+#undef GETXXKEY_R_ENTTYPE
+#undef GETXXKEY_R_TEST
+#undef DO_GETXXKEY_R_KEYTYPE
+#undef DO_GETXXKEY_R_PATHNAME
+#define GETXXKEY_R_FUNC sh_getgrnam_r
+#define GETXXKEY_R_PARSER __parsegrent
+#define GETXXKEY_R_ENTTYPE struct group
+#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
+#define DO_GETXXKEY_R_KEYTYPE const char *__restrict
+#define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
+
+int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
+ GETXXKEY_R_ENTTYPE *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ GETXXKEY_R_ENTTYPE **__restrict result)
+{
+ FILE *stream;
+ int rv;
+
+ *result = NULL;
+
+ if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
+ rv = errno;
+ } else {
+ /* __STDIO_SET_USER_LOCKING(stream); */
+ do {
+ if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
+ buffer, buflen, stream))
+ ) {
+ if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
+ *result = resultbuf;
+ break;
+ }
+ } else {
+ if (rv == ENOENT) { /* end-of-file encountered. */
+ rv = 0;
+ }
+ break;
+ }
+ } while (1);
+ sl_fclose(FIL__, __LINE__, stream);
+ }
+
+ return rv;
+}
+
+#undef GETXXKEY_R_FUNC
+#undef GETXXKEY_R_PARSER
+#undef GETXXKEY_R_ENTTYPE
+#undef GETXXKEY_R_TEST
+#undef DO_GETXXKEY_R_KEYTYPE
+#undef DO_GETXXKEY_R_PATHNAME
+#define GETXXKEY_R_FUNC sh_getpwuid_r
+#define GETXXKEY_R_PARSER __parsepwent
+#define GETXXKEY_R_ENTTYPE struct passwd
+#define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
+#define DO_GETXXKEY_R_KEYTYPE uid_t
+#define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
+
+int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
+ GETXXKEY_R_ENTTYPE *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ GETXXKEY_R_ENTTYPE **__restrict result)
+{
+ FILE *stream;
+ int rv;
+
+ *result = NULL;
+
+ if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
+ rv = errno;
+ } else {
+ /* __STDIO_SET_USER_LOCKING(stream); */
+ do {
+ if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
+ buffer, buflen, stream))
+ ) {
+ if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
+ *result = resultbuf;
+ break;
+ }
+ } else {
+ if (rv == ENOENT) { /* end-of-file encountered. */
+ rv = 0;
+ }
+ break;
+ }
+ } while (1);
+ sl_fclose(FIL__, __LINE__, stream);
+ }
+
+ return rv;
+}
+
+#undef GETXXKEY_R_FUNC
+#undef GETXXKEY_R_PARSER
+#undef GETXXKEY_R_ENTTYPE
+#undef GETXXKEY_R_TEST
+#undef DO_GETXXKEY_R_KEYTYPE
+#undef DO_GETXXKEY_R_PATHNAME
+#define GETXXKEY_R_FUNC sh_getgrgid_r
+#define GETXXKEY_R_PARSER __parsegrent
+#define GETXXKEY_R_ENTTYPE struct group
+#define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
+#define DO_GETXXKEY_R_KEYTYPE gid_t
+#define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
+
+int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
+ GETXXKEY_R_ENTTYPE *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ GETXXKEY_R_ENTTYPE **__restrict result)
+{
+ FILE *stream;
+ int rv;
+
+ *result = NULL;
+
+ if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
+ rv = errno;
+ } else {
+ /* __STDIO_SET_USER_LOCKING(stream); */
+ do {
+ if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
+ buffer, buflen, stream))
+ ) {
+ if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
+ *result = resultbuf;
+ break;
+ }
+ } else {
+ if (rv == ENOENT) { /* end-of-file encountered. */
+ rv = 0;
+ }
+ break;
+ }
+ } while (1);
+ sl_fclose(FIL__, __LINE__, stream);
+ }
+
+ return rv;
+}
+
+struct passwd * sh_getpwuid(uid_t uid)
+{
+ static char buffer[PWD_BUFFER_SIZE];
+ static struct passwd resultbuf;
+ struct passwd *result;
+
+ sh_getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
+ return result;
+}
+
+struct passwd * getpwuid(uid_t uid)
+{
+ return sh_getpwuid(uid);
+}
+
+struct group * sh_getgrgid(gid_t gid)
+{
+ static char buffer[GRP_BUFFER_SIZE];
+ static struct group resultbuf;
+ struct group *result;
+
+ sh_getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
+ return result;
+}
+
+struct group * getgrgid(gid_t gid)
+{
+ return sh_getgrgid(gid);
+}
+
+struct passwd * sh_getpwnam(const char *name)
+{
+ static char buffer[PWD_BUFFER_SIZE];
+ static struct passwd resultbuf;
+ struct passwd *result;
+
+ sh_getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
+ return result;
+}
+
+struct group * sh_getgrnam(const char *name)
+{
+ static char buffer[GRP_BUFFER_SIZE];
+ static struct group resultbuf;
+ struct group *result;
+
+ sh_getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
+ return result;
+}
+
+SH_MUTEX_STATIC(pwf_lock, PTHREAD_MUTEX_INITIALIZER);
+
+
+static FILE *pwf = NULL;
+
+void sh_setpwent(void)
+{
+ SH_MUTEX_LOCK(pwf_lock);
+ if (pwf) {
+ rewind(pwf);
+ }
+ SH_MUTEX_UNLOCK(pwf_lock);
+}
+
+void sh_endpwent(void)
+{
+ SH_MUTEX_LOCK(pwf_lock);
+ if (pwf) {
+ sl_fclose(FIL__, __LINE__, pwf);
+ pwf = NULL;
+ }
+ SH_MUTEX_UNLOCK(pwf_lock);
+}
+
+
+static int sh_getpwent_r(struct passwd *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct passwd **__restrict result)
+{
+ int rv;
+
+ SH_MUTEX_LOCK(pwf_lock);
+
+ *result = NULL; /* In case of error... */
+
+ if (!pwf) {
+ if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
+ rv = errno;
+ goto ERR;
+ }
+ /* __STDIO_SET_USER_LOCKING(pwf); */
+ }
+
+ if (!(rv = __pgsreader(__parsepwent, resultbuf,
+ buffer, buflen, pwf))) {
+ *result = resultbuf;
+ }
+
+ ERR:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_UNLOCK(pwf_lock);
+
+ return rv;
+}
+
+SH_MUTEX_STATIC(grf_lock, PTHREAD_MUTEX_INITIALIZER);
+
+static FILE *grf = NULL;
+
+void sh_setgrent(void)
+{
+ SH_MUTEX_LOCK(grf_lock);
+ if (grf) {
+ rewind(grf);
+ }
+ SH_MUTEX_UNLOCK(grf_lock);
+}
+
+void sh_endgrent(void)
+{
+ SH_MUTEX_LOCK(grf_lock);
+ if (grf) {
+ sl_fclose(FIL__, __LINE__, grf);
+ grf = NULL;
+ }
+ SH_MUTEX_UNLOCK(grf_lock);
+}
+
+static int sh_getgrent_r(struct group *__restrict resultbuf,
+ char *__restrict buffer, size_t buflen,
+ struct group **__restrict result)
+{
+ int rv;
+
+ SH_MUTEX_LOCK(grf_lock);
+
+ *result = NULL; /* In case of error... */
+
+ if (!grf) {
+ if (!(grf = fopen(_PATH_GROUP, "r"))) {
+ rv = errno;
+ goto ERR;
+ }
+ /* __STDIO_SET_USER_LOCKING(grf); */
+ }
+
+ if (!(rv = __pgsreader(__parsegrent, resultbuf,
+ buffer, buflen, grf))) {
+ *result = resultbuf;
+ }
+
+ ERR:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_UNLOCK(grf_lock);
+
+ return rv;
+}
+
+
+struct passwd * sh_getpwent(void)
+{
+ static char line_buff[PWD_BUFFER_SIZE];
+ static struct passwd pwd;
+ struct passwd *result;
+
+ sh_getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
+ return result;
+}
+
+
+struct group * sh_getgrent(void)
+{
+ static char line_buff[GRP_BUFFER_SIZE];
+ static struct group gr;
+ struct group *result;
+
+ sh_getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
+ return result;
+}
+
+int sh_initgroups(const char *user, gid_t gid)
+{
+ FILE *grf;
+ gid_t *group_list;
+ int num_groups, rv;
+ char **m;
+ struct group group;
+
+ char * buff = calloc(1,GRP_BUFFER_SIZE_MALLOC);
+
+ rv = -1;
+
+ /* We alloc space for 8 gids at a time. */
+ if (((group_list = calloc(8,sizeof(gid_t *))) != NULL)
+ && ((grf = fopen(_PATH_GROUP, "r")) != NULL)
+ ) {
+
+ /* __STDIO_SET_USER_LOCKING(grf); */
+
+ *group_list = gid;
+ num_groups = 1;
+
+ while (!__pgsreader(__parsegrent, &group, buff, GRP_BUFFER_SIZE_MALLOC, grf)) {
+ assert(group.gr_mem); /* Must have at least a NULL terminator. */
+ if (group.gr_gid != gid) {
+ for (m=group.gr_mem ; *m ; m++) {
+ if (!strcmp(*m, user)) {
+ if (!(num_groups & 7)) {
+ gid_t *tmp = (gid_t *)
+ realloc(group_list,
+ (num_groups+8) * sizeof(gid_t *));
+ if (!tmp) {
+ rv = -1;
+ goto DO_CLOSE;
+ }
+ group_list = tmp;
+ }
+ group_list[num_groups++] = group.gr_gid;
+ break;
+ }
+ }
+ }
+ }
+
+ rv = setgroups(num_groups, group_list);
+ DO_CLOSE:
+ sl_fclose(FIL__, __LINE__, grf);
+ }
+
+ /* group_list will be NULL if initial malloc failed, which may trigger
+ * warnings from various malloc debuggers. */
+ free(group_list);
+ free(buff);
+ return rv;
+}
+
+
+/**********************************************************************/
+/* Internal uClibc functions. */
+/**********************************************************************/
+
+static const unsigned char pw_off[] = {
+ offsetof(struct passwd, pw_name), /* 0 */
+ offsetof(struct passwd, pw_passwd), /* 1 */
+ offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
+ offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
+ offsetof(struct passwd, pw_gecos), /* 4 */
+ offsetof(struct passwd, pw_dir), /* 5 */
+ offsetof(struct passwd, pw_shell) /* 6 */
+};
+
+static int __parsepwent(void *data, char *line)
+{
+ char *endptr;
+ char *p;
+ int i;
+
+ i = 0;
+ do {
+ p = ((char *) ((struct passwd *) data)) + pw_off[i];
+
+ if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
+ *((char **) p) = line;
+ if (i==6) {
+ return 0;
+ }
+ /* NOTE: glibc difference - glibc allows omission of
+ * ':' seperators after the gid field if all remaining
+ * entries are empty. We require all separators. */
+ if (!(line = strchr(line, ':'))) {
+ break;
+ }
+ } else {
+ unsigned long t = strtoul(line, &endptr, 10);
+ /* Make sure we had at least one digit, and that the
+ * failing char is the next field seperator ':'. See
+ * glibc difference note above. */
+ /* TODO: Also check for leading whitespace? */
+ if ((endptr == line) || (*endptr != ':')) {
+ break;
+ }
+ line = endptr;
+ if (i & 1) { /* i == 3 -- gid */
+ *((gid_t *) p) = t;
+ } else { /* i == 2 -- uid */
+ *((uid_t *) p) = t;
+ }
+ }
+
+ *line++ = 0;
+ ++i;
+ } while (1);
+
+ return -1;
+}
+
+static const unsigned char gr_off[] = {
+ offsetof(struct group, gr_name), /* 0 */
+ offsetof(struct group, gr_passwd), /* 1 */
+ offsetof(struct group, gr_gid) /* 2 - not a char ptr */
+};
+
+static int __parsegrent(void *data, char *line)
+{
+ char *endptr;
+ char *p;
+ int i;
+ char **members;
+ char *end_of_buf;
+
+ end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
+ i = 0;
+ do {
+ p = ((char *) ((struct group *) data)) + gr_off[i];
+
+ if (i < 2) {
+ *((char **) p) = line;
+ if (!(line = strchr(line, ':'))) {
+ break;
+ }
+ *line++ = 0;
+ ++i;
+ } else {
+ *((gid_t *) p) = strtoul(line, &endptr, 10);
+
+ /* NOTE: glibc difference - glibc allows omission of the
+ * trailing colon when there is no member list. We treat
+ * this as an error. */
+
+ /* Make sure we had at least one digit, and that the
+ * failing char is the next field seperator ':'. See
+ * glibc difference note above. */
+ if ((endptr == line) || (*endptr != ':')) {
+ break;
+ }
+
+ i = 1; /* Count terminating NULL ptr. */
+ p = endptr;
+
+ if (p[1]) { /* We have a member list to process. */
+ /* Overwrite the last ':' with a ',' before counting.
+ * This allows us to test for initial ',' and adds
+ * one ',' so that the ',' count equals the member
+ * count. */
+ *p = ',';
+ do {
+ /* NOTE: glibc difference - glibc allows and trims leading
+ * (but not trailing) space. We treat this as an error. */
+ /* NOTE: glibc difference - glibc allows consecutive and
+ * trailing commas, and ignores "empty string" users. We
+ * treat this as an error. */
+ if (*p == ',') {
+ ++i;
+ *p = 0; /* nul-terminate each member string. */
+ if (!*++p || (*p == ',') || isspace(*p)) {
+ goto ERR;
+ }
+ }
+ } while (*++p);
+ }
+
+ /* Now align (p+1), rounding up. */
+ /* Assumes sizeof(char **) is a power of 2. */
+ members = (char **)( (((intptr_t) p) + sizeof(char **))
+ & ~((intptr_t)(sizeof(char **) - 1)) );
+
+ if (((char *)(members + i)) > end_of_buf) { /* No space. */
+ break;
+ }
+
+ ((struct group *) data)->gr_mem = members;
+
+ if (--i) {
+ p = endptr; /* Pointing to char prior to first member. */
+ do {
+ *members++ = ++p;
+ if (!--i) break;
+ while (*++p) {}
+ } while (1);
+ }
+ *members = NULL;
+
+ return 0;
+ }
+ } while (1);
+
+ ERR:
+ return -1;
+}
+
+/* Reads until if EOF, or until if finds a line which fits in the buffer
+ * and for which the parser function succeeds.
+ *
+ * Returns 0 on success and ENOENT for end-of-file (glibc concession).
+ */
+
+static int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
+ char *__restrict line_buff, size_t buflen, FILE *f)
+{
+ size_t line_len; /* int -> size_t R.W. */
+ int skip;
+ int rv = ERANGE;
+
+ if (buflen < PWD_BUFFER_SIZE) {
+ errno = rv;
+ } else {
+ /* __STDIO_THREADLOCK(f); */
+
+ skip = 0;
+ do {
+ if (!fgets(line_buff, buflen, f)) {
+ if (feof(f)) {
+ rv = ENOENT;
+ }
+ break;
+ }
+
+ line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
+ if (line_buff[line_len] == '\n') {
+ line_buff[line_len] = 0;
+ } else if (line_len + 2 == buflen) { /* line too long */
+ rv = ERANGE;
+ break;
+ /*
+ ++skip;
+ continue;
+ */
+ }
+
+ if (skip) {
+ --skip;
+ continue;
+ }
+
+ /* NOTE: glibc difference - glibc strips leading whitespace from
+ * records. We do not allow leading whitespace. */
+
+ /* Skip empty lines, comment lines, and lines with leading
+ * whitespace. */
+ if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
+ if (__parserfunc == __parsegrent) { /* Do evil group hack. */
+ /* The group entry parsing function needs to know where
+ * the end of the buffer is so that it can construct the
+ * group member ptr table. */
+ ((struct group *) data)->gr_name = line_buff + buflen;
+ }
+
+ if (!__parserfunc(data, line_buff)) {
+ rv = 0;
+ break;
+ }
+ }
+ } while (1);
+
+ /* __STDIO_THREADUNLOCK(f); */
+ }
+
+ return rv;
+}
+
+/* resolv.c: DNS Resolver
+ *
+ * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
+ * The Silver Hammer Group, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+*/
+
+/*
+ * Portions Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ *
+ * 5-Oct-2000 W. Greathouse wgreathouse@smva.com
+ * Fix memory leak and memory corruption.
+ * -- Every name resolution resulted in
+ * a new parse of resolv.conf and new
+ * copy of nameservers allocated by
+ * strdup.
+ * -- Every name resolution resulted in
+ * a new read of resolv.conf without
+ * resetting index from prior read...
+ * resulting in exceeding array bounds.
+ *
+ * Limit nameservers read from resolv.conf
+ *
+ * Add "search" domains from resolv.conf
+ *
+ * Some systems will return a security
+ * signature along with query answer for
+ * dynamic DNS entries.
+ * -- skip/ignore this answer
+ *
+ * Include arpa/nameser.h for defines.
+ *
+ * General cleanup
+ *
+ * 20-Jun-2001 Michal Moskal <malekith@pld.org.pl>
+ * partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
+ * functions added), IPv6 nameservers are also supported.
+ *
+ * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
+ * more IPv6 support (IPv6 support for gethostbyaddr();
+ * address family parameter and improved IPv6 support for get_hosts_byname
+ * and read_etc_hosts; getnameinfo() port from glibc; defined
+ * defined ip6addr_any and in6addr_loopback)
+ *
+ * 2-Feb-2002 Erik Andersen <andersee@debian.org>
+ * Added gethostent(), sethostent(), and endhostent()
+ *
+ * 17-Aug-2002 Manuel Novoa III <mjn3@codepoet.org>
+ * Fixed __read_etc_hosts_r to return alias list, and modified buffer
+ * allocation accordingly. See MAX_ALIASES and ALIAS_DIM below.
+ * This fixes the segfault in the Python 2.2.1 socket test.
+ *
+ * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
+ * Fixed __decode_dotted to count the terminating null character
+ * in a host name.
+ *
+ * 02-Oct-2003 Tony J. White <tjw@tjw.org>
+ * Lifted dn_expand() and dependent ns_name_uncompress(), ns_name_unpack(),
+ * and ns_name_ntop() from glibc 2.3.2 for compatibility with ipsec-tools
+ * and openldap.
+ *
+ */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* sl_close_fd(FIL__, __LINE__, )
+ */
+#include <unistd.h>
+
+/* 'struct hostent'
+ */
+#include <netdb.h>
+
+/* constanst like HFIXEDSZ
+ */
+#include <arpa/nameser.h>
+
+SH_MUTEX_STATIC(resolv_lock, PTHREAD_MUTEX_INITIALIZER);
+
+#define __UCLIBC_HAS_IPV6__
+#define MAX_RECURSE 5
+#define REPLY_TIMEOUT 10
+#define MAX_RETRIES 3
+#define MAX_SERVERS 3
+#define MAX_SEARCH 4
+#define MAX_ALIASES 5
+
+/* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
+#define ALIAS_DIM (2 + MAX_ALIASES + 1)
+
+static int __nameservers;
+static char * __nameserver[MAX_SERVERS];
+static int __searchdomains;
+static char * __searchdomain[MAX_SEARCH];
+
+#undef DEBUG
+/*#define DEBUG*/
+
+#ifdef DEBUG
+/* flawfinder: ignore *//* definition of debug macro */
+#define DPRINTF(X,args...) fprintf(stderr, X, ##args)
+#else
+#define DPRINTF(X,args...)
+#endif /* DEBUG */
+
+struct resolv_header {
+ int id;
+ int qr,opcode,aa,tc,rd,ra,rcode;
+ int qdcount;
+ int ancount;
+ int nscount;
+ int arcount;
+};
+
+struct resolv_question {
+ char * dotted;
+ int qtype;
+ int qclass;
+};
+
+struct resolv_answer {
+ char * dotted;
+ int atype;
+ int aclass;
+ int ttl;
+ int rdlength;
+ unsigned char * rdata;
+ int rdoffset;
+};
+
+enum etc_hosts_action {
+ GET_HOSTS_BYNAME = 0,
+ GETHOSTENT,
+ GET_HOSTS_BYADDR,
+};
+
+static int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
+{
+ if (maxlen < HFIXEDSZ)
+ return -1;
+
+ dest[0] = (h->id & 0xff00) >> 8;
+ dest[1] = (h->id & 0x00ff) >> 0;
+ dest[2] = (h->qr ? 0x80 : 0) |
+ ((h->opcode & 0x0f) << 3) |
+ (h->aa ? 0x04 : 0) |
+ (h->tc ? 0x02 : 0) |
+ (h->rd ? 0x01 : 0);
+ dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
+ dest[4] = (h->qdcount & 0xff00) >> 8;
+ dest[5] = (h->qdcount & 0x00ff) >> 0;
+ dest[6] = (h->ancount & 0xff00) >> 8;
+ dest[7] = (h->ancount & 0x00ff) >> 0;
+ dest[8] = (h->nscount & 0xff00) >> 8;
+ dest[9] = (h->nscount & 0x00ff) >> 0;
+ dest[10] = (h->arcount & 0xff00) >> 8;
+ dest[11] = (h->arcount & 0x00ff) >> 0;
+
+ return HFIXEDSZ;
+}
+
+static int __decode_header(unsigned char *data, struct resolv_header *h)
+{
+ h->id = (data[0] << 8) | data[1];
+ h->qr = (data[2] & 0x80) ? 1 : 0;
+ h->opcode = (data[2] >> 3) & 0x0f;
+ h->aa = (data[2] & 0x04) ? 1 : 0;
+ h->tc = (data[2] & 0x02) ? 1 : 0;
+ h->rd = (data[2] & 0x01) ? 1 : 0;
+ h->ra = (data[3] & 0x80) ? 1 : 0;
+ h->rcode = data[3] & 0x0f;
+ h->qdcount = (data[4] << 8) | data[5];
+ h->ancount = (data[6] << 8) | data[7];
+ h->nscount = (data[8] << 8) | data[9];
+ h->arcount = (data[10] << 8) | data[11];
+
+ return HFIXEDSZ;
+}
+
+static int __length_dotted(const unsigned char *data, int offset)
+{
+ int orig_offset = offset;
+ int l;
+
+ if (!data)
+ return -1;
+
+ do {
+
+ if (offset < INT_MAX)
+ offset++;
+ else
+ return -1;
+
+ l = data[offset];
+
+ if ((l & 0xc0) == (0xc0)) {
+ if (offset < INT_MAX)
+ offset++;
+ else
+ return -1;
+ break;
+ }
+
+ if (offset <= (INT_MAX - l))
+ offset += l;
+ else
+ return -1;
+
+ } while (l);
+
+ return offset - orig_offset;
+}
+
+static int __length_question(unsigned char *message, int offset)
+{
+ int i;
+
+ i = __length_dotted(message, offset);
+ if (i < 0)
+ return i;
+ if (i < (INT_MAX - 4))
+ return i + 4;
+ else
+ return -1;
+}
+
+/* Decode a dotted string from nameserver transport-level encoding.
+ This routine understands compressed data. */
+
+static int __decode_dotted(const unsigned char *data, int offset,
+ char *dest, int maxlen)
+{
+ int l;
+ int measure = 1;
+ int total = 0;
+ int used = 0;
+
+ if (!data)
+ return -1;
+ if ((offset < 0) || (offset > (PACKETSZ-1)))
+ return -1;
+ while ((l=data[offset])) {
+ if (offset < (PACKETSZ-1)) offset++;
+ else return -1;
+ if (measure)
+ { if (total < INT_MAX) total++; else return -1; }
+ if ((l & 0xc0) == (0xc0)) {
+ if (measure)
+ { if (total < INT_MAX) total++; else return -1; }
+ /* compressed item, redirect */
+ offset = ((l & 0x3f) << 8) | data[offset];
+ if ((offset < 0) || (offset > (PACKETSZ-1)))
+ return -1;
+ measure = 0;
+ continue;
+ }
+
+ if (used >= (INT_MAX - l))
+ return -1;
+
+ if ((used + l + 1) >= maxlen)
+ return -1;
+
+ memcpy(dest + used, data + offset, l);
+
+ if (offset <= ((PACKETSZ-1) - l))
+ offset += l;
+ else
+ return -1;
+
+ if (used <= (INT_MAX - l))
+ used += l;
+ else
+ return -1;
+ if (measure)
+ { if (total <= (INT_MAX -l)) total += l; else return -1; }
+
+ if (used >= maxlen)
+ return -1;
+ if (data[offset] != 0)
+ dest[used++] = '.';
+ else
+ dest[used++] = '\0';
+ }
+
+ /* The null byte must be counted too */
+ if (measure) {
+ if (total < INT_MAX) total++; else return -1;
+ }
+
+ DPRINTF("Total decode len = %d\n", total);
+
+ return total;
+}
+
+static int __decode_answer(unsigned char *message, int offset,
+ struct resolv_answer *a)
+{
+ char temp[256];
+ int i = 0;
+
+ i = __decode_dotted(message, offset, temp, sizeof(temp));
+ if (i < 0 || i > PACKETSZ)
+ return -1;
+
+ if (offset <= ((PACKETSZ - 10) - i))
+ message += offset + i;
+ else
+ return -1;
+
+ a->dotted = strdup(temp);
+ a->atype = (message[0] << 8) | message[1];
+ message += 2;
+ a->aclass = (message[0] << 8) | message[1];
+ message += 2;
+ a->ttl = (message[0] << 24) |
+ (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
+ message += 4;
+ a->rdlength = (message[0] << 8) | message[1];
+ message += 2;
+ a->rdata = message;
+ a->rdoffset = offset + i + RRFIXEDSZ;
+
+ DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
+
+ if (RRFIXEDSZ <= (INT_MAX - i))
+ i += RRFIXEDSZ;
+ else
+ return -1;
+ if (a->rdlength <= (INT_MAX - i))
+ return i + a->rdlength;
+ else
+ return -1;
+}
+
+
+/* Encode a dotted string into nameserver transport-level encoding.
+ This routine is fairly dumb, and doesn't attempt to compress
+ the data */
+
+static int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
+{
+ unsigned int used = 0;
+
+ while (dotted && *dotted) {
+ char *c = strchr(dotted, '.');
+ unsigned int l = c ? (unsigned int)(c - dotted) : strlen(dotted);
+
+ if (l >= ((unsigned int)maxlen - used - 1))
+ return -1;
+
+ dest[used++] = l;
+ memcpy(dest + used, dotted, l);
+ used += l;
+
+ if (c)
+ dotted = c + 1;
+ else
+ break;
+ }
+
+ if (maxlen < 1)
+ return -1;
+
+ dest[used++] = 0;
+
+ return used;
+}
+
+static int __encode_question(struct resolv_question *q,
+ unsigned char *dest, int maxlen)
+{
+ int i;
+
+ i = __encode_dotted(q->dotted, dest, maxlen);
+ if (i < 0)
+ return i;
+
+ dest += i;
+ if (maxlen < i)
+ return -1;
+ maxlen -= i;
+
+ if (maxlen < 4)
+ return -1;
+
+ dest[0] = (q->qtype & 0xff00) >> 8;
+ dest[1] = (q->qtype & 0x00ff) >> 0;
+ dest[2] = (q->qclass & 0xff00) >> 8;
+ dest[3] = (q->qclass & 0x00ff) >> 0;
+
+ if (i <= (INT_MAX - 4))
+ return i + 4;
+ else
+ return -1;
+}
+
+
+/* Just for the record, having to lock __dns_lookup() just for these two globals
+ * is pretty lame. I think these two variables can probably be de-global-ized,
+ * which should eliminate the need for doing locking here... Needs a closer
+ * look anyways. */
+static int ns=0, id=1;
+
+static int __dns_lookup(const char *name, int type, int nscount, char **nsip,
+ unsigned char **outpacket, struct resolv_answer *a)
+{
+ int i, j, len, fd, pos, rc;
+ struct timeval tv;
+ fd_set fds;
+ struct resolv_header h;
+ struct resolv_question q;
+ int retries = 0;
+ unsigned char * packet = calloc(1,PACKETSZ);
+ char *dns, *lookup = calloc(1,MAXDNAME);
+ int variant = 0;
+ struct sockaddr_in sa;
+#ifdef __UCLIBC_HAS_IPV6__
+ int v6;
+ struct sockaddr_in6 sa6;
+#endif
+
+ fd = -1;
+
+ if (!packet || !lookup || !nscount)
+ goto fail;
+
+ DPRINTF("Looking up type %d answer for '%s'\n", type, name);
+
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ ns %= nscount;
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+
+ while (retries++ < MAX_RETRIES) {
+ if (fd != -1)
+ sl_close_fd(FIL__, __LINE__, fd);
+
+ memset(packet, 0, PACKETSZ);
+
+ memset(&h, 0, sizeof(h));
+
+ /* Mess with globals while under lock */
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ ++id;
+ id &= 0xffff;
+ h.id = id;
+ dns = nsip[ns];
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+
+ h.qdcount = 1;
+ h.rd = 1;
+
+ DPRINTF("encoding header\n", h.rd);
+
+ i = __encode_header(&h, packet, PACKETSZ);
+ if (i < 0)
+ goto fail;
+
+ sl_strlcpy(lookup,name,MAXDNAME);
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ if (variant < __searchdomains && strchr(lookup, '.') == NULL)
+ {
+ sl_strlcat(lookup,".", MAXDNAME);
+ sl_strlcat(lookup,__searchdomain[variant], MAXDNAME);
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+ DPRINTF("lookup name: %s\n", lookup);
+ q.dotted = (char *)lookup;
+ q.qtype = type;
+ q.qclass = C_IN; /* CLASS_IN */
+
+ j = __encode_question(&q, packet+i, PACKETSZ-i);
+ if (j < 0)
+ goto fail;
+
+ len = i + j;
+
+ DPRINTF("On try %d, sending query to port %d of machine %s\n",
+ retries, NAMESERVER_PORT, dns);
+
+#ifdef __UCLIBC_HAS_IPV6__
+ v6 = inet_pton(AF_INET6, dns, &sa6.sin6_addr) > 0;
+ fd = socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#else
+ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#endif
+ if (fd < 0) {
+ continue;
+ }
+
+ /* Connect to the UDP socket so that asyncronous errors are returned */
+#ifdef __UCLIBC_HAS_IPV6__
+ if (v6) {
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_port = htons(NAMESERVER_PORT);
+ /* sa6.sin6_addr is already here */
+ rc = connect(fd, (struct sockaddr *) &sa6, sizeof(sa6));
+ } else {
+#endif
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(NAMESERVER_PORT);
+ sa.sin_addr.s_addr = inet_addr(dns);
+ rc = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
+#ifdef __UCLIBC_HAS_IPV6__
+ }
+#endif
+ if (rc < 0) {
+ if (errno == ENETUNREACH) {
+ /* routing error, presume not transient */
+ goto tryall;
+ } else
+ /* retry */
+ continue;
+ }
+
+ DPRINTF("Transmitting packet of length %d, id=%d, qr=%d\n",
+ len, h.id, h.qr);
+
+ send(fd, packet, len, 0);
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = REPLY_TIMEOUT;
+ tv.tv_usec = 0;
+ if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
+ DPRINTF("Timeout\n");
+
+ /* timed out, so retry send and receive,
+ * to next nameserver on queue */
+ goto again;
+ }
+
+ i = recv(fd, packet, 512, 0);
+ if (i < HFIXEDSZ) {
+ /* too short ! */
+ goto again;
+ }
+
+ /* ok because we have checked that recv at least HFIXEDSZ */
+ __decode_header(packet, &h);
+
+ DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
+
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ if ((h.id != id) || (!h.qr)) {
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+ /* unsolicited */
+ goto again;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+
+
+ DPRINTF("Got response %s\n", "(i think)!");
+ DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
+ h.qdcount, h.ancount, h.nscount, h.arcount);
+ DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
+ h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
+
+ if ((h.rcode) || (h.ancount < 1)) {
+ /* negative result, not present */
+ goto again;
+ }
+
+ pos = HFIXEDSZ;
+
+ for (j = 0; j < h.qdcount; j++) {
+ DPRINTF("Skipping question %d at %d\n", j, pos);
+ i = __length_question(packet, pos);
+ DPRINTF("Length of question %d is %d\n", j, i);
+ if (i < 0)
+ goto again;
+ pos += i;
+ if (pos >= PACKETSZ)
+ goto again;
+ }
+ DPRINTF("Decoding answer at pos %d\n", pos);
+
+ for (j=0;j<h.ancount;j++)
+ {
+ i = __decode_answer(packet, pos, a);
+
+ if (i<0) {
+ DPRINTF("failed decode %d\n", i);
+ goto again;
+ }
+ /* For all but T_SIG, accept first answer */
+ if (a->atype != T_SIG)
+ break;
+
+ DPRINTF("skipping T_SIG %d\n", i);
+ free(a->dotted);
+ pos += i;
+ if (pos >= PACKETSZ)
+ goto again;
+ }
+
+ DPRINTF("Answer name = |%s|\n", a->dotted);
+ DPRINTF("Answer type = |%d|\n", a->atype);
+
+ sl_close_fd(FIL__, __LINE__, fd);
+
+ if (outpacket)
+ *outpacket = packet;
+ else
+ free(packet);
+ free(lookup);
+ return (0); /* success! */
+
+ tryall:
+ /* if there are other nameservers, give them a go,
+ otherwise return with error */
+ {
+ int sdomains;
+
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ sdomains=__searchdomains;
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+ variant = 0;
+ if (retries >= nscount*(sdomains+1))
+ goto fail;
+ }
+
+ again:
+ /* if there are searchdomains, try them or fallback as passed */
+ {
+ int sdomains;
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ sdomains=__searchdomains;
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+
+ if (variant < sdomains) {
+ /* next search */
+ variant++;
+ } else {
+ /* next server, first search */
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ ns = (ns + 1) % nscount;
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+ variant = 0;
+ }
+ }
+ }
+
+fail:
+ if (fd != -1)
+ sl_close_fd(FIL__, __LINE__, fd);
+ if (lookup)
+ free(lookup);
+ if (packet)
+ free(packet);
+ return -1;
+}
+
+static void __open_etc_hosts(FILE **fp)
+{
+ if ((*fp = fopen("/etc/hosts", "r")) == NULL) {
+ *fp = fopen("/etc/config/hosts", "r");
+ }
+ return;
+}
+
+static int __read_etc_hosts_r(FILE * fp, const char * name, int type,
+ enum etc_hosts_action action,
+ struct hostent * result_buf,
+ char * buf, size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
+{
+ struct in_addr *in=NULL;
+ struct in_addr **addr_list=NULL;
+#ifdef __UCLIBC_HAS_IPV6__
+ struct in6_addr *in6=NULL;
+ struct in6_addr **addr_list6=NULL;
+#endif /* __UCLIBC_HAS_IPV6__ */
+ char *cp;
+ char **alias;
+ int aliases, i;
+ int ret=HOST_NOT_FOUND;
+
+ if (buflen < sizeof(char *)*(ALIAS_DIM))
+ return ERANGE;
+ alias=(char **)buf;
+ buf+=sizeof(char **)*(ALIAS_DIM);
+ buflen-=sizeof(char **)*(ALIAS_DIM);
+
+ if (action!=GETHOSTENT) {
+#ifdef __UCLIBC_HAS_IPV6__
+ char *p=buf;
+ size_t len=buflen;
+#endif /* __UCLIBC_HAS_IPV6__ */
+ *h_errnop=NETDB_INTERNAL;
+ if (buflen < sizeof(*in))
+ return ERANGE;
+ in=(struct in_addr*)buf;
+ buf+=sizeof(*in);
+ buflen-=sizeof(*in);
+
+ if (buflen < sizeof(*addr_list)*2)
+ return ERANGE;
+ addr_list=(struct in_addr **)buf;
+ buf+=sizeof(*addr_list)*2;
+ buflen-=sizeof(*addr_list)*2;
+
+#ifdef __UCLIBC_HAS_IPV6__
+ if (len < sizeof(*in6))
+ return ERANGE;
+ in6=(struct in6_addr*)p;
+ p+=sizeof(*in6);
+ len-=sizeof(*in6);
+
+ if (len < sizeof(*addr_list6)*2)
+ return ERANGE;
+ addr_list6=(struct in6_addr**)p;
+ p+=sizeof(*addr_list6)*2;
+ len-=sizeof(*addr_list6)*2;
+
+ if (len < buflen) {
+ buflen=len;
+ buf=p;
+ }
+#endif /* __UCLIBC_HAS_IPV6__ */
+
+ if (buflen < 80)
+ return ERANGE;
+
+ __open_etc_hosts(&fp);
+ if (fp == NULL) {
+ result=NULL;
+ return errno;
+ }
+ }
+
+ *h_errnop=HOST_NOT_FOUND;
+ while (fgets(buf, buflen, fp)) {
+ if ((cp = strchr(buf, '#')))
+ *cp = '\0';
+ DPRINTF("Looking at: %s\n", buf);
+ aliases = 0;
+
+ cp = buf;
+ while (*cp) {
+ while (*cp && isspace(*cp))
+ *cp++ = '\0';
+ if (!*cp)
+ continue;
+ if (aliases < (2+MAX_ALIASES))
+ alias[aliases++] = cp;
+ while (*cp && !isspace(*cp))
+ cp++;
+ }
+ alias[aliases] = 0;
+
+ if (aliases < 2)
+ continue; /* syntax error really */
+
+ if (action==GETHOSTENT) {
+ /* Return whatever the next entry happens to be. */
+ break;
+ } else if (action==GET_HOSTS_BYADDR) {
+ if (strcmp(name, alias[0]) != 0)
+ continue;
+ } else {
+ /* GET_HOSTS_BYNAME */
+ for (i = 1; i < aliases; i++)
+ if (strcasecmp(name, alias[i]) == 0)
+ break;
+ if (i >= aliases)
+ continue;
+ }
+
+ if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
+ DPRINTF("Found INET\n");
+ addr_list[0] = in;
+ addr_list[1] = 0;
+ result_buf->h_name = alias[1];
+ result_buf->h_addrtype = AF_INET;
+ result_buf->h_length = sizeof(*in);
+ result_buf->h_addr_list = (char**) addr_list;
+ result_buf->h_aliases = alias + 2;
+ *result=result_buf;
+ ret=NETDB_SUCCESS;
+#ifdef __UCLIBC_HAS_IPV6__
+ } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
+ DPRINTF("Found INET6\n");
+ addr_list6[0] = in6;
+ addr_list6[1] = 0;
+ result_buf->h_name = alias[1];
+ result_buf->h_addrtype = AF_INET6;
+ result_buf->h_length = sizeof(*in6);
+ result_buf->h_addr_list = (char**) addr_list6;
+ result_buf->h_aliases = alias + 2;
+ *result=result_buf;
+ ret=NETDB_SUCCESS;
+#endif /* __UCLIBC_HAS_IPV6__ */
+ } else {
+ DPRINTF("Error\n");
+ ret=TRY_AGAIN;
+ break; /* bad ip address */
+ }
+
+ if (action!=GETHOSTENT) {
+ sl_fclose(FIL__, __LINE__, fp);
+ }
+ return ret;
+ }
+ if (action!=GETHOSTENT) {
+ sl_fclose(FIL__, __LINE__, fp);
+ }
+ return ret;
+}
+
+/*
+ * we currently read formats not quite the same as that on normal
+ * unix systems, we can have a list of nameservers after the keyword.
+ */
+int __get_hosts_byname_r(const char * name, int type,
+ struct hostent * result_buf,
+ char * buf, size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
+{
+ return(__read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME, result_buf, buf, buflen, result, h_errnop));
+}
+
+static int __open_nameservers(void)
+{
+ FILE *fp;
+ int i;
+#define RESOLV_ARGS 5
+ char szBuffer[128], *p, *argv[RESOLV_ARGS];
+ int argc;
+
+ SH_MUTEX_LOCK(resolv_lock);
+ if (__nameservers > 0) {
+ goto the_end;
+ }
+
+ if ((fp = fopen("/etc/resolv.conf", "r")) ||
+ (fp = fopen("/etc/config/resolv.conf", "r"))) {
+
+ while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
+
+ for (p = szBuffer; *p && isspace(*p); p++)
+ /* skip white space */;
+ if (*p == '\0' || *p == '\n' || *p == '#') /* skip comments etc */
+ continue;
+ argc = 0;
+ while (*p && argc < RESOLV_ARGS) {
+ argv[argc++] = p;
+ while (*p && !isspace(*p) && *p != '\n')
+ p++;
+ while (*p && (isspace(*p) || *p == '\n')) /* remove spaces */
+ *p++ = '\0';
+ }
+
+ if (strcmp(argv[0], "nameserver") == 0) {
+ for (i = 1; i < argc && __nameservers < MAX_SERVERS; i++) {
+ __nameserver[__nameservers++] = strdup(argv[i]);
+ DPRINTF("adding nameserver %s\n", argv[i]);
+ }
+ }
+
+ /* domain and search are mutually exclusive, the last one wins */
+ if (strcmp(argv[0],"domain")==0 || strcmp(argv[0],"search")==0) {
+ while (__searchdomains > 0) {
+ free(__searchdomain[--__searchdomains]);
+ __searchdomain[__searchdomains] = NULL;
+ }
+ for (i=1; i < argc && __searchdomains < MAX_SEARCH; i++) {
+ __searchdomain[__searchdomains++] = strdup(argv[i]);
+ DPRINTF("adding search %s\n", argv[i]);
+ }
+ }
+ }
+ sl_fclose(FIL__, __LINE__, fp);
+ } else {
+ DPRINTF("failed to open %s\n", "resolv.conf");
+ }
+ DPRINTF("nameservers = %d\n", __nameservers);
+ the_end:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_UNLOCK(resolv_lock);
+ /* cppcheck-suppress resourceLeak */
+ return 0;
+}
+
+static int sh_gethostbyname_r(const char * name,
+ struct hostent * result_buf,
+ char * buf, size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
+{
+ struct in_addr *in;
+ struct in_addr **addr_list;
+ unsigned char *packet;
+ struct resolv_answer a;
+ int i;
+ int nest = 0;
+ int __nameserversXX;
+ char ** __nameserverXX;
+
+ __open_nameservers();
+
+ *result=NULL;
+ if (!name)
+ return EINVAL;
+
+ /* do /etc/hosts first */
+ if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
+ buf, buflen, result, h_errnop))==0)
+ return i;
+ switch (*h_errnop) {
+ case HOST_NOT_FOUND:
+ case NO_ADDRESS:
+ break;
+ case NETDB_INTERNAL:
+ if (errno == ENOENT) {
+ break;
+ }
+ /* else fall through */
+ default:
+ return i;
+ }
+
+ DPRINTF("Nothing found in /etc/hosts\n");
+
+ *h_errnop = NETDB_INTERNAL;
+ if (buflen < sizeof(*in))
+ return ERANGE;
+ in=(struct in_addr*)buf;
+ buf+=sizeof(*in);
+ buflen-=sizeof(*in);
+
+ if (buflen < sizeof(*addr_list)*2)
+ return ERANGE;
+ addr_list=(struct in_addr**)buf;
+ buf+=sizeof(*addr_list)*2;
+ buflen-=sizeof(*addr_list)*2;
+
+ addr_list[0] = in;
+ addr_list[1] = 0;
+
+ if (buflen<256)
+ return ERANGE;
+ strncpy(buf, name, buflen);
+
+ /* First check if this is already an address */
+ if (inet_aton(name, in)) {
+ result_buf->h_name = buf;
+ result_buf->h_addrtype = AF_INET;
+ result_buf->h_length = sizeof(*in);
+ result_buf->h_addr_list = (char **) addr_list;
+ *result=result_buf;
+ *h_errnop = NETDB_SUCCESS;
+ return NETDB_SUCCESS;
+ }
+
+ for (;;) {
+
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ __nameserversXX=__nameservers;
+ __nameserverXX=__nameserver;
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+ i = __dns_lookup(buf, T_A, __nameserversXX, __nameserverXX, &packet, &a);
+
+ if (i < 0) {
+ *h_errnop = HOST_NOT_FOUND;
+ DPRINTF("__dns_lookup\n");
+ return TRY_AGAIN;
+ }
+
+ strncpy(buf, a.dotted, buflen);
+ free(a.dotted);
+
+ if (a.atype == T_CNAME) { /* CNAME */
+ DPRINTF("Got a CNAME in gethostbyname()\n");
+ i = __decode_dotted(packet, a.rdoffset, buf, buflen);
+ free(packet);
+
+ if (i < 0) {
+ *h_errnop = NO_RECOVERY;
+ DPRINTF("__decode_dotted\n");
+ return -1;
+ }
+ if (++nest > MAX_RECURSE) {
+ *h_errnop = NO_RECOVERY;
+ DPRINTF("recursion\n");
+ return -1;
+ }
+ continue;
+ } else if (a.atype == T_A) { /* ADDRESS */
+ memcpy(in, a.rdata, sizeof(*in));
+ result_buf->h_name = buf;
+ result_buf->h_addrtype = AF_INET;
+ result_buf->h_length = sizeof(*in);
+ result_buf->h_addr_list = (char **) addr_list;
+ free(packet);
+ break;
+ } else {
+ free(packet);
+ *h_errnop=HOST_NOT_FOUND;
+ return TRY_AGAIN;
+ }
+ }
+
+ *result=result_buf;
+ *h_errnop = NETDB_SUCCESS;
+ return NETDB_SUCCESS;
+}
+
+struct hostent * sh_gethostbyname(const char *name)
+{
+ static struct hostent h;
+ static char buf[sizeof(struct in_addr) +
+ sizeof(struct in_addr *)*2 +
+ sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */];
+ struct hostent *hp;
+
+ sh_gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
+
+ return hp;
+}
+
+static int __get_hosts_byaddr_r(const char * addr, int len, int type,
+ struct hostent * result_buf,
+ char * buf, size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
+{
+#ifndef __UCLIBC_HAS_IPV6__
+ char ipaddr[INET_ADDRSTRLEN];
+#else
+ char ipaddr[INET6_ADDRSTRLEN];
+#endif /* __UCLIBC_HAS_IPV6__ */
+
+ switch (type) {
+ case AF_INET:
+ if (len != sizeof(struct in_addr))
+ return 0;
+ break;
+#ifdef __UCLIBC_HAS_IPV6__
+ case AF_INET6:
+ if (len != sizeof(struct in6_addr))
+ return 0;
+ break;
+#endif /* __UCLIBC_HAS_IPV6__ */
+ default:
+ return 0;
+ }
+
+ inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
+
+ return(__read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
+ result_buf, buf, buflen, result, h_errnop));
+}
+
+static int sh_gethostbyaddr_r (const void *addr, socklen_t len, int type,
+ struct hostent * result_buf,
+ char * buf, size_t buflen,
+ struct hostent ** result,
+ int * h_errnop)
+
+{
+ struct in_addr *in;
+ struct in_addr **addr_list;
+#ifdef __UCLIBC_HAS_IPV6__
+ char *qp;
+ size_t plen;
+ struct in6_addr *in6;
+ struct in6_addr **addr_list6;
+#endif /* __UCLIBC_HAS_IPV6__ */
+ unsigned char *packet;
+ struct resolv_answer a;
+ int i;
+ int nest = 0;
+ int __nameserversXX;
+ char ** __nameserverXX;
+
+ *result=NULL;
+ if (!addr)
+ return EINVAL;
+
+ switch (type) {
+ case AF_INET:
+ if (len != sizeof(struct in_addr))
+ return EINVAL;
+ break;
+#ifdef __UCLIBC_HAS_IPV6__
+ case AF_INET6:
+ if (len != sizeof(struct in6_addr))
+ return EINVAL;
+ break;
+#endif /* __UCLIBC_HAS_IPV6__ */
+ default:
+ return EINVAL;
+ }
+
+ /* do /etc/hosts first */
+ if ((i=__get_hosts_byaddr_r(addr, len, type, result_buf,
+ buf, buflen, result, h_errnop))==0)
+ return i;
+ switch (*h_errnop) {
+ case HOST_NOT_FOUND:
+ case NO_ADDRESS:
+ break;
+ default:
+ return i;
+ }
+
+ __open_nameservers();
+
+#ifdef __UCLIBC_HAS_IPV6__
+ qp=buf;
+ plen=buflen;
+#endif /* __UCLIBC_HAS_IPV6__ */
+
+ *h_errnop = NETDB_INTERNAL;
+ if (buflen < sizeof(*in))
+ return ERANGE;
+ in=(struct in_addr*)buf;
+ buf+=sizeof(*in);
+ buflen-=sizeof(*in);
+
+ if (buflen < sizeof(*addr_list)*2)
+ return ERANGE;
+ addr_list=(struct in_addr**)buf;
+ buf+=sizeof(*addr_list)*2;
+ buflen-=sizeof(*addr_list)*2;
+
+#ifdef __UCLIBC_HAS_IPV6__
+ if (plen < sizeof(*in6))
+ return ERANGE;
+ in6=(struct in6_addr*)qp;
+ qp+=sizeof(*in6);
+ plen-=sizeof(*in6);
+
+ if (plen < sizeof(*addr_list6)*2)
+ return ERANGE;
+ addr_list6=(struct in6_addr**)qp;
+ qp+=sizeof(*addr_list6)*2;
+ plen-=sizeof(*addr_list6)*2;
+
+ if (plen < buflen) {
+ buflen=plen;
+ buf=qp;
+ }
+#endif /* __UCLIBC_HAS_IPV6__ */
+
+ if (buflen<256)
+ return ERANGE;
+
+ if(type == AF_INET) {
+ const unsigned char *tmp_addr = (const unsigned char *)addr;
+
+ memcpy(&in->s_addr, addr, len);
+
+ addr_list[0] = in;
+
+ sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
+ tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
+#ifdef __UCLIBC_HAS_IPV6__
+ } else {
+ memcpy(in6->s6_addr, addr, len);
+
+ addr_list6[0] = in6;
+ qp = buf;
+
+ for (i = len - 1; i >= 0; i--) {
+ qp += sprintf(qp, "%x.%x.", in6->s6_addr[i] & 0xf,
+ (in6->s6_addr[i] >> 4) & 0xf);
+ }
+ strcpy(qp, "ip6.int");
+#endif /* __UCLIBC_HAS_IPV6__ */
+ }
+
+ addr_list[1] = 0;
+
+ for (;;) {
+
+ SH_MUTEX_LOCK_UNSAFE(resolv_lock);
+ __nameserversXX=__nameservers;
+ __nameserverXX=__nameserver;
+ SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
+ i = __dns_lookup(buf, T_PTR, __nameserversXX, __nameserverXX, &packet, &a);
+
+ if (i < 0) {
+ *h_errnop = HOST_NOT_FOUND;
+ return TRY_AGAIN;
+ }
+
+ strncpy(buf, a.dotted, buflen);
+ free(a.dotted);
+
+ if (a.atype == T_CNAME) { /* CNAME */
+ DPRINTF("Got a CNAME in gethostbyaddr()\n");
+ i = __decode_dotted(packet, a.rdoffset, buf, buflen);
+ free(packet);
+
+ if (i < 0) {
+ *h_errnop = NO_RECOVERY;
+ return -1;
+ }
+ if (++nest > MAX_RECURSE) {
+ *h_errnop = NO_RECOVERY;
+ return -1;
+ }
+ continue;
+ } else if (a.atype == T_PTR) { /* ADDRESS */
+ i = __decode_dotted(packet, a.rdoffset, buf, buflen);
+ free(packet);
+
+ result_buf->h_name = buf;
+ result_buf->h_addrtype = type;
+
+ if(type == AF_INET) {
+ result_buf->h_length = sizeof(*in);
+#ifdef __UCLIBC_HAS_IPV6__
+ } else {
+ result_buf->h_length = sizeof(*in6);
+#endif /* __UCLIBC_HAS_IPV6__ */
+ }
+
+ result_buf->h_addr_list = (char **) addr_list;
+ break;
+ } else {
+ free(packet);
+ *h_errnop = NO_ADDRESS;
+ return TRY_AGAIN;
+ }
+ }
+
+ *result=result_buf;
+ *h_errnop = NETDB_SUCCESS;
+ return NETDB_SUCCESS;
+}
+
+struct hostent * sh_gethostbyaddr (const void *addr, socklen_t len, int type)
+{
+ static struct hostent h;
+ static char buf[
+#ifndef __UCLIBC_HAS_IPV6__
+ sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
+#else
+ sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
+#endif /* __UCLIBC_HAS_IPV6__ */
+ sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */];
+ struct hostent *hp;
+
+ sh_gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
+
+ return hp;
+}
+
+/* NEED_STATIC_LIBS */
+#else
+
+/* include something to avoid empty compilation unit */
+#include <stdio.h>
+
+#endif
+
diff --git a/src/sh_string.c b/src/sh_string.c
new file mode 100644
index 0000000..a898dd9
--- /dev/null
+++ b/src/sh_string.c
@@ -0,0 +1,1055 @@
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "sh_string.h"
+#include "sh_mem.h"
+
+#undef FIL__
+#define FIL__ _("sh_string.c")
+
+extern int sl_ok_adds (size_t a, size_t b);
+#define S_TRUE 1
+#define S_FALSE 0
+
+#include <ctype.h>
+#include <errno.h>
+
+/* Split array at delim in at most nfields fields.
+ * Empty fields are returned as empty (zero-length) strings.
+ * Leading and trailing WS are removed from token.
+ * The number of fields is returned in 'nfields', their
+ * lengths in 'lengths'.
+ * A single delimiter will return two empty fields.
+ */
+char ** split_array(char *line, unsigned int * nfields,
+ char delim, size_t * lengths)
+{
+ char *a, *e, *s;
+ unsigned int i = 0;
+ int flag = 0;
+ char **arr;
+ unsigned int maxfields = (*nfields);
+
+ arr = SH_ALLOC((maxfields+1) * sizeof (char*));
+
+ e = line;
+
+ do
+ {
+ /* skip leading WS
+ */
+ for (s=e; *s && isspace((int)*s); ++s) /* nothing */;
+
+ if (*s)
+ {
+ /* move a to next delim
+ */
+ for (a=s; *a && *a != delim; ++a) /* nothing */;
+
+ /* set e to next after delim
+ */
+ if (*a == delim)
+ {
+ e = a+1;
+ flag = 1;
+ }
+ else /* (!*a) */
+ {
+ e = a;
+ flag = 0;
+ }
+
+ if (a != line)
+ {
+ if (i < (maxfields -1))
+ {
+
+ /* chop off trailing WS
+ */
+ for (a--; isspace((int)*a) && a > s; a--) /* do nothing */;
+
+ /* terminate string
+ */
+ ++a; *a = '\0';
+ }
+ else
+ {
+ /* If nfields < actual fields, last string
+ * will be remainder, therefore skip to end.
+ */
+ if ( *a )
+ {
+ do {
+ a++;
+ } while ( *a );
+ }
+ }
+ }
+ else
+ {
+ *a = '\0';
+ }
+ }
+ else /* (!*s) */
+ {
+ a = s;
+ /* (i == 0) handles the special case of splitting the empty string */
+ if (flag || i == 0)
+ {
+ flag = 0;
+ goto setnext;
+ }
+ break;
+ }
+
+ setnext:
+ lengths[i] = (size_t) (a-s); /* a >= s always */
+ arr[i] = s;
+ ++i;
+
+ } while (i < maxfields);
+
+ *nfields = i;
+ arr[i] = NULL;
+
+ return arr;
+}
+
+/* Split array at whitespace in at most nfields fields.
+ * Multiple whitespaces are collapsed.
+ * Empty fields are returned as empty (zero-length) strings.
+ * The number of fields is returned in nfields.
+ * An empty string will return zero fields.
+ * If nfields < actual fields, last string will be remainder.
+ */
+
+#define SH_SPLIT_LIST 0
+#define SH_SPLIT_WS 1
+
+char ** split_array_ws_int (char *line,
+ unsigned int * nfields, size_t * lengths,
+ const char *delim, int isList)
+{
+ char *a, *e, *s;
+ unsigned int i = 0;
+ char **arr;
+ unsigned int maxfields = (*nfields);
+
+ arr = SH_ALLOC((maxfields+1) * sizeof (char*));
+
+ e = line;
+
+ do
+ {
+ s = e;
+
+ /* skip leading WS
+ */
+ if (isList == SH_SPLIT_WS)
+ {
+ if ( *s && isspace((int)*s) )
+ {
+ do {
+ ++s;
+ } while ( *s && isspace((int)*s) );
+ }
+ }
+ else
+ {
+ if ( *s && strchr(delim, (int)*s))
+ {
+ do {
+ ++s;
+ } while ( *s && strchr(delim, (int)*s));
+ }
+
+ }
+
+ if (*s)
+ {
+
+ /* s is at non-ws, move a to next ws
+ */
+ a = s;
+ if (isList == SH_SPLIT_WS)
+ {
+ do {
+ a++;
+ } while ( *a && (!isspace((int)*a)) );
+ }
+ else
+ {
+ do {
+ a++;
+ } while ( *a && NULL == strchr(delim, (int)*a));
+ }
+
+ /* next token, *a is either ws or '\0'
+ */
+ e = ( (*a) ? a+1 : a);
+
+ /* terminate and set arr[i]
+ */
+ if (i < (maxfields-1))
+ {
+ *a = '\0';
+ }
+ else
+ {
+ /* If nfields < actual fields, last
+ * string will be remainder. Therefore
+ * skip to end.
+ */
+ if ( *a )
+ {
+ do {
+ a++;
+ } while ( *a );
+ }
+ }
+ lengths[i] = (size_t)(a-s); /* a >= s always */
+ arr[i] = s;
+ ++i;
+ }
+ else /* if (!*s) */
+ {
+ break;
+ }
+
+ } while (i < maxfields);
+
+ *nfields = i;
+ arr[i] = NULL;
+
+ return arr;
+}
+
+char ** split_array_ws (char *line,
+ unsigned int * nfields, size_t * lengths)
+{
+ return split_array_ws_int (line, nfields, lengths, NULL, SH_SPLIT_WS);
+}
+
+char ** split_array_list (char *line,
+ unsigned int * nfields, size_t * lengths)
+{
+ return split_array_ws_int (line, nfields, lengths, ", \t", SH_SPLIT_LIST);
+}
+
+char ** split_array_token (char *line,
+ unsigned int * nfields, size_t * lengths,
+ const char * token)
+{
+ return split_array_ws_int (line, nfields, lengths, token, SH_SPLIT_LIST);
+}
+
+/* return a split() of a list contained in 'PREFIX\s*( list ).*'
+ */
+char ** split_array_braced (char *line, const char * prefix,
+ unsigned int * nfields, size_t * lengths)
+{
+ char * s = line;
+ char * p;
+ unsigned int sind = (prefix) ? strlen(prefix) : 0;
+
+ while ( *s && isspace((int)*s) ) ++s;
+ if (prefix && 0 != strncmp(s, prefix, strlen(prefix)))
+ return NULL;
+ s = &s[sind];
+ while ( *s && isspace((int)*s) ) ++s;
+ if (!s || (*s != '('))
+ return NULL;
+ ++s;
+ p = strchr(s, ')');
+ if (!p || (*p == *s))
+ return NULL;
+ *p = '\0';
+ return split_array_list (s, nfields, lengths);
+}
+
+#define SH_STRING_PARCEL 120
+
+static
+size_t sh_string_read_int(sh_string * s, FILE * fp, size_t maxlen, char *start);
+
+size_t sh_string_read(sh_string * s, FILE * fp, size_t maxlen)
+{
+ return sh_string_read_int(s, fp, maxlen, NULL);
+}
+
+size_t sh_string_read_cont(sh_string * s, FILE * fp, size_t maxlen, char *cont)
+{
+ return sh_string_read_int(s, fp, maxlen, cont);
+}
+
+static char * sh_str_fgets (char *s, int size, FILE *fp)
+{
+ char * ret;
+ do {
+ clearerr(fp);
+ ret = fgets(s, size, fp);
+ } while (ret == NULL && ferror(fp) && errno == EAGAIN);
+
+ return ret;
+}
+
+size_t sh_string_read_int(sh_string * s, FILE * fp, size_t maxlen, char *start)
+{
+
+ /* case 0) start != NULL and first char not in 'start'
+ */
+ if (start)
+ {
+ int first;
+
+ do {
+ clearerr(fp);
+ first = fgetc(fp);
+ } while (first == EOF && ferror(fp) && errno == EAGAIN);
+
+ if (first == EOF)
+ {
+ sh_string_truncate(s, 0);
+ if (ferror(fp))
+ return -1;
+ return 0;
+ }
+
+ if (NULL == strchr(start, first))
+ {
+ ungetc(first, fp);
+ return 0;
+ }
+ ungetc(first, fp);
+ }
+
+ /* case 1) EOF or error
+ */
+ if (sh_str_fgets(s->str, s->siz, fp) == NULL)
+ {
+ sh_string_truncate(s, 0);
+ if (ferror(fp))
+ return -1;
+ return 0;
+ }
+
+ /* case 2) end of line reached. strlen should always be > 0
+ * because of the '\n', but we check.
+ */
+ s->len = strlen(s->str);
+ if (s->len > 0 && (s->str)[s->len-1] == '\n')
+ {
+ (s->str)[s->len-1] = '\0';
+ --(s->len);
+ return (s->len + 1);
+ }
+
+ /* case 3) incomplete string
+ */
+ for (;;) {
+
+ if (maxlen > 0 && (s->siz+SH_STRING_PARCEL) > maxlen)
+ {
+ if (s->siz < maxlen)
+ sh_string_grow(s, (maxlen-s->siz));
+ else
+ return -2;
+ }
+ else
+ {
+ sh_string_grow(s, 0);
+ }
+
+ if (sh_str_fgets(&(s->str[s->len]), (s->siz - s->len), fp) == NULL)
+ {
+ if (ferror(fp))
+ {
+ sh_string_truncate(s, 0);
+ return -1;
+ }
+ return s->len;
+ }
+
+ s->len += strlen( &(s->str[s->len]) );
+ if (s->len > 0 && s->str[s->len-1] == '\n')
+ {
+ (s->str)[s->len-1] = '\0';
+ --(s->len);
+ return (s->len + 1);
+ }
+ }
+
+ /* notreached */
+}
+
+sh_string * sh_string_cat_lchar(sh_string * s, const char * str, size_t len)
+{
+ if (sl_ok_adds(len, s->siz) == S_TRUE)
+ {
+ if ((len + 1 + s->len) > s->siz)
+ {
+ sh_string_grow(s, ((len+1+s->len) - s->siz) );
+ }
+ memcpy(&(s->str[s->len]), str, len);
+ s->len += len;
+ s->str[s->len] = '\0';
+ return s;
+ }
+
+ return NULL;
+}
+
+sh_string * sh_string_set_from_char(sh_string * s, const char * str)
+{
+ size_t len = strlen(str);
+
+ if ((len+1) > s->siz)
+ {
+ sh_string_grow(s, ((len+1) - s->siz) );
+ }
+ memcpy(s->str, str, (len+1));
+ s->len = len;
+ return s;
+}
+
+sh_string * sh_string_add_from_char(sh_string * s, const char * str)
+{
+ size_t len = strlen(str);
+ size_t avail = (s->siz - s->len);
+
+ if ((len+1) > avail)
+ {
+ (void) sh_string_grow(s, ((len+1) - avail) );
+ }
+ memcpy(&(s->str[s->len]), str, (len+1));
+ s->len += len;
+ return s;
+}
+
+sh_string * sh_string_new_from_lchar(const char * str, size_t len)
+{
+ sh_string * s;
+ s = SH_ALLOC(sizeof(sh_string));
+ s->str = SH_ALLOC(len+1);
+ if (str)
+ memcpy(s->str, str, len);
+ else
+ s->str[0] = '\0';
+ s->str[len] = '\0';
+ s->siz = len+1;
+ s->len = len;
+ return s;
+}
+
+sh_string * sh_string_new_from_lchar3(const char * str1, size_t len1,
+ const char * str2, size_t len2,
+ const char * str3, size_t len3)
+{
+ sh_string * s;
+ size_t len = 0;
+
+ if (sl_ok_adds(len1, len2) == S_TRUE)
+ len = len1 + len2;
+ else
+ return NULL;
+ if (sl_ok_adds( len, len3) == S_TRUE)
+ len = len + len3;
+ else
+ return NULL;
+
+ s = SH_ALLOC(sizeof(sh_string));
+ s->str = SH_ALLOC(len+1);
+
+ memcpy(s->str, str1, len1);
+ memcpy(&s->str[len1], str2, len2);
+ memcpy(&s->str[len1+len2], str3, len3);
+
+ s->str[len] = '\0';
+ s->siz = len+1;
+ s->len = len;
+ return s;
+}
+
+sh_string * sh_string_grow(sh_string * s, size_t increase)
+{
+ char * new;
+
+ if (increase == 0)
+ increase = SH_STRING_PARCEL;
+
+ if (s && sl_ok_adds(s->siz, increase) == S_TRUE)
+ {
+ new = SH_ALLOC(s->siz + increase);
+
+ if (s->str)
+ {
+ memcpy(new, s->str, s->len+1);
+ SH_FREE(s->str);
+ }
+ else
+ {
+ new[0] = '\0';
+ }
+ s->str = new;
+ s->siz += increase;
+ return s;
+ }
+ return NULL;
+}
+
+sh_string * sh_string_truncate(sh_string * s, size_t len)
+{
+ if (s)
+ {
+ if (s->str && (s->len > len) )
+ {
+ s->len = len;
+ (s->str)[len] = '\0';
+ }
+ return s;
+ }
+ return NULL;
+}
+
+void sh_string_destroy(sh_string ** s)
+{
+ if (s)
+ {
+ if ((*s) && (*s)->str)
+ SH_FREE ((*s)->str);
+ SH_FREE(*s);
+ *s = NULL;
+ }
+ return;
+}
+
+sh_string * sh_string_new(size_t size)
+{
+ sh_string * s;
+ s = SH_ALLOC (sizeof(sh_string));
+ if (size == 0)
+ size = SH_STRING_PARCEL;
+ s->str = SH_ALLOC (size);
+ s->str[0] = '\0';
+ s->siz = size;
+ s->len = 0;
+ return s;
+}
+
+/* Replaces fields in s with 'replacement'. Fields are given
+ * in the ordered array ovector, comprising ovecnum pairs
+ * ovector[i], ovector[i+1] which list offset of first char
+ * of field, offset of first char after field (this is how
+ * the pcre library does it).
+ */
+sh_string * sh_string_replace(const sh_string * s,
+ const int * ovector, int ovecnum,
+ const char * replacement, size_t rlen)
+{
+ sh_string * r = NULL;
+ char * p;
+ long tlen;
+ size_t len;
+ int end = 0;
+ int start = 0;
+ size_t oldlen = 0;
+ size_t newlen = 0;
+ long diff;
+ int i, curr, last;
+
+ for (i = 0; i < ovecnum; ++i)
+ {
+ start = ovector[2*i]; /* offset of first char of substring */
+ if (start >= end)
+ {
+ end = ovector[2*i+1]; /* offset of first char after substring end*/
+
+ if (end > start && (unsigned int)end <= (s->len + 1))
+ {
+ oldlen += (end - start);
+ newlen += rlen;
+ }
+ else /* inconsistency detected */
+ {
+ return NULL;
+ }
+ }
+ else /* overlap detected */
+ {
+ return NULL;
+ }
+ }
+
+ diff = newlen - oldlen;
+
+ if ((diff > 0) && ((s->len + 1 + diff) > s->siz))
+ {
+ r = sh_string_new_from_lchar(sh_string_str(s),
+ sh_string_len(s));
+ r = sh_string_grow(r, diff);
+ }
+ else
+ {
+ r = sh_string_new_from_lchar(sh_string_str(s),
+ sh_string_len(s));
+ }
+
+
+ curr = -1;
+
+ for (i = 0; i < ovecnum; ++i)
+ {
+ if (ovector[2*i] >= 0)
+ {
+ curr = 2*i;
+ break;
+ }
+ }
+
+ if (r && ovecnum > 0 && ovector[curr] >= 0)
+ {
+ r->len = 0; r->str[0] = '\0'; p = r->str;
+
+ /* First part, until start of first replacement
+ */
+ if (r->siz > (unsigned int)ovector[curr]) {
+ memcpy(p, s->str, (size_t)ovector[curr]);
+ p += ovector[curr];
+ r->len += ovector[curr];
+ }
+ if (r->siz > (r->len + rlen)) {
+ memcpy(p, replacement, rlen);
+ p += rlen;
+ r->len += rlen;
+ }
+ *p = '\0';
+
+ last = curr + 1;
+
+ for (i = 1; i < ovecnum; ++i)
+ {
+ if (ovector[2*i] < 0)
+ continue;
+
+ curr = 2*i;
+
+ /* From end of last replacement to start of this */
+ tlen = (long)(ovector[curr] - ovector[last]);
+ if (tlen >= 0)
+ {
+ len = (size_t) tlen;
+
+ if (tlen > 0 && r->siz > (r->len + len))
+ {
+ memcpy(p, &(s->str[ovector[last]]), (size_t)len);
+ p += len;
+ r->len += len;
+ }
+
+ /* The replacement */
+ if (r->siz > (r->len + rlen)) {
+ memcpy(p, replacement, rlen);
+ p += rlen;
+ r->len += rlen;
+ }
+
+ /* null terminate */
+ *p = '\0';
+
+ last = curr + 1;
+ }
+ }
+
+ /* Last part, after last replacement; includes terminating null
+ */
+ if (last > 0)
+ {
+ /* If not, nothing has been replaced, and r is still a copy of s
+ */
+ tlen = (long)((s->len + 1) - ovector[last]);
+ if (tlen > 0)
+ {
+ len = (size_t)tlen;
+ if (r->siz >= (r->len + len)) {
+ memcpy(p, &(s->str[ovector[2*i -1]]), (size_t)len);
+ p += (len - 1);
+ r->len += (len - 1);
+ *p = '\0';
+ }
+ }
+ }
+
+ }
+
+ return r;
+}
+
+
+#ifdef SH_CUTEST
+#include <stdlib.h>
+#include "CuTest.h"
+
+void Test_string (CuTest *tc) {
+ int status, i, max = 120;
+ FILE * fp;
+ sh_string * s = NULL;
+ sh_string * t;
+ static char template[] = "/tmp/xtest.XXXXXX";
+ char ** array;
+ char test[128];
+ size_t lengths[16];
+ unsigned int iarr;
+ int ovector[16];
+ int ovecnum;
+
+ s = sh_string_new(0);
+ CuAssertPtrNotNull(tc, s);
+ sh_string_destroy(&s);
+ CuAssertTrue(tc, s == NULL);
+
+ s = sh_string_new(0);
+ CuAssertPtrNotNull(tc, s);
+
+ status = mkstemp(template);
+ CuAssertTrue(tc, status >= 0);
+
+ fp = fdopen(status, "r+");
+ CuAssertPtrNotNull(tc, fp);
+
+ for (i = 0; i < 80; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 0 */
+ for (i = 0; i < 118; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 1 */
+ for (i = 0; i < 119; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 2 */
+ for (i = 0; i < 120; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 3 */
+ for (i = 0; i < 121; ++i) { fputc ('a', fp); } fputc ('\n', fp); /* 4 */
+ for (i = 0; i < 238; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+ for (i = 0; i < 239; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+ for (i = 0; i < 240; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+ for (i = 0; i < 241; ++i) { fputc ('a', fp); } fputc ('\n', fp);
+
+ rewind(fp);
+
+ for (i = 0; i < 9; ++i)
+ {
+ status = sh_string_read(s, fp, max);
+
+ switch (i) {
+ case 0:
+ CuAssertTrue(tc, s->len == 80);
+ CuAssertTrue(tc, s->siz == 120);
+ CuAssertTrue(tc, status == 81);
+ break;
+ case 1:
+ CuAssertTrue(tc, s->len == 118);
+ CuAssertTrue(tc, s->siz == 120);
+ CuAssertTrue(tc, status == 119);
+ break;
+ case 2:
+ CuAssertTrue(tc, s->len == 119);
+ CuAssertTrue(tc, s->siz == 120);
+ CuAssertTrue(tc, status == -2); /* no terminating '\n', truncated */
+ break;
+ case 3:
+ CuAssertTrue(tc, s->len == 120);
+ CuAssertTrue(tc, s->siz == 240);
+ CuAssertTrue(tc, status == 121);
+ break;
+ case 4:
+ CuAssertTrue(tc, s->len == 121);
+ CuAssertTrue(tc, s->siz == 240);
+ CuAssertTrue(tc, status == 122);
+ break;
+ case 5:
+ CuAssertTrue(tc, s->len == 238);
+ CuAssertTrue(tc, s->siz == 240);
+ CuAssertTrue(tc, status == 239);
+ break;
+ case 6:
+ CuAssertTrue(tc, s->len == 239);
+ CuAssertTrue(tc, s->siz == 240);
+ CuAssertTrue(tc, status == -2); /* no terminating '\n', truncated */
+ break;
+ default:
+ CuAssertTrue(tc, s->len == 239);
+ CuAssertTrue(tc, s->siz == 240);
+ CuAssertTrue(tc, status == -2);
+ }
+ if (status == -2) /* read in rest of string */
+ { max = 240; sh_string_read(s, fp, max); }
+ }
+
+ rewind(fp);
+
+ sh_string_truncate(s, 0);
+ CuAssertTrue(tc, s->len == 0);
+
+ for (i = 0; i < 9; ++i)
+ {
+ status = sh_string_read(s, fp, 240);
+ if (status == -2)
+ sh_string_read(s, fp, 240);
+ else
+ {
+ for (status = 0; status < (int)s->len; ++status)
+ {
+ if (s->str[status] != 'a')
+ {
+ CuFail(tc, "unexpected character");
+ }
+ }
+ }
+ }
+
+ status = fclose(fp);
+ CuAssertTrue(tc, status == 0);
+ status = remove(template);
+ CuAssertTrue(tc, status == 0);
+
+ iarr = 10; strcpy(test, "|a1|| a2| |a3 |a4|a5|");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,9,(int)iarr);
+ CuAssertStrEquals(tc,"", array[0]);
+ CuAssertStrEquals(tc,"a1", array[1]);
+ CuAssertStrEquals(tc,"", array[2]);
+ CuAssertStrEquals(tc,"a2", array[3]);
+ CuAssertStrEquals(tc,"", array[4]);
+ CuAssertStrEquals(tc,"a3", array[5]);
+ CuAssertStrEquals(tc,"a4", array[6]);
+ CuAssertStrEquals(tc,"a5", array[7]);
+ CuAssertStrEquals(tc,"", array[8]);
+
+ CuAssertIntEquals(tc, 0, (int)lengths[0]);
+ CuAssertIntEquals(tc, 2, (int)lengths[1]);
+ CuAssertIntEquals(tc, 0, (int)lengths[2]);
+ CuAssertIntEquals(tc, 2, (int)lengths[3]);
+ CuAssertIntEquals(tc, 0, (int)lengths[4]);
+ CuAssertIntEquals(tc, 2, (int)lengths[5]);
+ CuAssertIntEquals(tc, 2, (int)lengths[6]);
+ CuAssertIntEquals(tc, 2, (int)lengths[7]);
+ CuAssertIntEquals(tc, 0, (int)lengths[8]);
+
+ iarr = 10; strcpy(test, "a1|| a2| |a3 |a4|a5|");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,8,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+ CuAssertStrEquals(tc,"", array[1]);
+ CuAssertStrEquals(tc,"a2", array[2]);
+ CuAssertStrEquals(tc,"", array[3]);
+ CuAssertStrEquals(tc,"a3", array[4]);
+ CuAssertStrEquals(tc,"a4", array[5]);
+ CuAssertStrEquals(tc,"a5", array[6]);
+ CuAssertStrEquals(tc,"", array[7]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+ CuAssertIntEquals(tc, 0, (int)lengths[1]);
+ CuAssertIntEquals(tc, 2, (int)lengths[2]);
+ CuAssertIntEquals(tc, 0, (int)lengths[3]);
+ CuAssertIntEquals(tc, 2, (int)lengths[4]);
+ CuAssertIntEquals(tc, 2, (int)lengths[5]);
+ CuAssertIntEquals(tc, 2, (int)lengths[6]);
+ CuAssertIntEquals(tc, 0, (int)lengths[7]);
+
+ iarr = 10; strcpy(test, " a1|| a2 | |a3 |a4|a5");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,7,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+ CuAssertStrEquals(tc,"", array[1]);
+ CuAssertStrEquals(tc,"a2", array[2]);
+ CuAssertStrEquals(tc,"", array[3]);
+ CuAssertStrEquals(tc,"a3", array[4]);
+ CuAssertStrEquals(tc,"a4", array[5]);
+ CuAssertStrEquals(tc,"a5", array[6]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+ CuAssertIntEquals(tc, 0, (int)lengths[1]);
+ CuAssertIntEquals(tc, 2, (int)lengths[2]);
+ CuAssertIntEquals(tc, 0, (int)lengths[3]);
+ CuAssertIntEquals(tc, 2, (int)lengths[4]);
+ CuAssertIntEquals(tc, 2, (int)lengths[5]);
+ CuAssertIntEquals(tc, 2, (int)lengths[6]);
+
+ iarr = 10; strcpy(test, "a1|| a2 | |a3 |a4|a5 ");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,7,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+ CuAssertStrEquals(tc,"", array[1]);
+ CuAssertStrEquals(tc,"a2", array[2]);
+ CuAssertStrEquals(tc,"", array[3]);
+ CuAssertStrEquals(tc,"a3", array[4]);
+ CuAssertStrEquals(tc,"a4", array[5]);
+ CuAssertStrEquals(tc,"a5", array[6]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+ CuAssertIntEquals(tc, 0, (int)lengths[1]);
+ CuAssertIntEquals(tc, 2, (int)lengths[2]);
+ CuAssertIntEquals(tc, 0, (int)lengths[3]);
+ CuAssertIntEquals(tc, 2, (int)lengths[4]);
+ CuAssertIntEquals(tc, 2, (int)lengths[5]);
+ CuAssertIntEquals(tc, 2, (int)lengths[6]);
+
+ iarr = 10; strcpy(test, "|");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,2,(int)iarr);
+ CuAssertStrEquals(tc,"", array[0]);
+ CuAssertStrEquals(tc,"", array[1]);
+
+ CuAssertIntEquals(tc, 0, (int)lengths[0]);
+ CuAssertIntEquals(tc, 0, (int)lengths[1]);
+
+ iarr = 10; strcpy(test, "|||");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,4,(int)iarr);
+ CuAssertStrEquals(tc,"", array[0]);
+ CuAssertStrEquals(tc,"", array[1]);
+ CuAssertStrEquals(tc,"", array[2]);
+ CuAssertStrEquals(tc,"", array[3]);
+
+ CuAssertIntEquals(tc, 0, (int)lengths[0]);
+ CuAssertIntEquals(tc, 0, (int)lengths[1]);
+ CuAssertIntEquals(tc, 0, (int)lengths[2]);
+ CuAssertIntEquals(tc, 0, (int)lengths[3]);
+
+ iarr = 10; strcpy(test, " a1 ");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,1,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+
+ iarr = 10; strcpy(test, "");
+ array = split_array(test, &iarr, '|', lengths);
+ CuAssertIntEquals(tc,1,(int)iarr);
+ CuAssertStrEquals(tc,"", array[0]);
+
+ CuAssertIntEquals(tc, 0, (int)lengths[0]);
+
+ /* WS separated */
+
+ iarr = 10; strcpy(test, "a1");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,1,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+
+ iarr = 10; strcpy(test, " a1");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,1,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+
+ iarr = 10; strcpy(test, " a1 ");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,1,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+
+ iarr = 10; strcpy(test, " ");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,0,(int)iarr);
+ CuAssertTrue(tc, array[0] == NULL);
+
+ iarr = 10; strcpy(test, " a1 a2");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,2,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+ CuAssertStrEquals(tc,"a2", array[1]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+ CuAssertIntEquals(tc, 2, (int)lengths[1]);
+
+ iarr = 10; strcpy(test, " a1 a2 ");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,2,(int)iarr);
+ CuAssertStrEquals(tc,"a1", array[0]);
+ CuAssertStrEquals(tc,"a2", array[1]);
+
+ CuAssertIntEquals(tc, 2, (int)lengths[0]);
+ CuAssertIntEquals(tc, 2, (int)lengths[1]);
+
+ iarr = 10; strcpy(test, "");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,0,(int)iarr);
+ CuAssertTrue(tc, array[0] == NULL);
+
+ iarr = 3; strcpy(test, " this is a test for remainder");
+ array = split_array_ws (test, &iarr, lengths);
+ CuAssertIntEquals(tc,3,(int)iarr);
+ CuAssertStrEquals(tc,"this", array[0]);
+ CuAssertStrEquals(tc,"is", array[1]);
+ CuAssertStrEquals(tc,"a test for remainder", array[2]);
+ for (i = 0; i < 3; ++i)
+ {
+ CuAssertIntEquals(tc, (int)strlen(array[i]), lengths[i] );
+ }
+
+ /* split_array_list */
+ iarr = 6; strcpy(test, " this(a) is_a(test);for(b),remainder(test)foo(bar)");
+ array = split_array_list (test, &iarr, lengths);
+ CuAssertIntEquals(tc,3,(int)iarr);
+ CuAssertStrEquals(tc,"this(a)", array[0]);
+ CuAssertStrEquals(tc,"is_a(test);for(b)", array[1]);
+ CuAssertStrEquals(tc,"remainder(test)foo(bar)", array[2]);
+ for (i = 0; i < 3; ++i)
+ {
+ CuAssertIntEquals(tc, (int)strlen(array[i]), lengths[i] );
+ }
+
+
+ /* string replace */
+ s = sh_string_new_from_lchar3 ("abc ", 4, "def ", 4, "ghi ", 4);
+ ovecnum = 2;
+ ovector[0] = 0; ovector[1] = 2;
+ ovector[2] = 4; ovector[3] = 11;
+
+ t = sh_string_replace(s, ovector, ovecnum,
+ "___", 3);
+ CuAssertPtrNotNull(tc, t);
+ CuAssertStrEquals(tc, "___c ___ ", t->str);
+ CuAssertIntEquals(tc, 9, (int)t->len);
+
+ ovector[0] = 0; ovector[1] = 2;
+ ovector[2] = 4; ovector[3] = 12;
+ t = sh_string_replace(s, ovector, ovecnum,
+ "___", 3);
+ CuAssertPtrNotNull(tc, t);
+ CuAssertStrEquals(tc, "___c ___", t->str);
+ CuAssertIntEquals(tc, 8, (int)t->len);
+
+ ovector[0] = 0; ovector[1] = 0;
+ ovector[2] = 0; ovector[3] = 0;
+ t = sh_string_replace(s, ovector, ovecnum,
+ "___", 3);
+ CuAssertTrue(tc, t == NULL);
+
+ ovector[0] = 0; ovector[1] = 3;
+ ovector[2] = 3; ovector[3] = 6;
+ t = sh_string_replace(s, ovector, ovecnum,
+ "___", 3);
+
+ CuAssertPtrNotNull(tc, t);
+ CuAssertStrEquals(tc, "______f ghi ", t->str);
+ CuAssertIntEquals(tc, 12, (int)t->len);
+
+ ovector[0] = 4; ovector[1] = 5;
+ ovector[2] = 11; ovector[3] = 12;
+ t = sh_string_replace(s, ovector, ovecnum,
+ "___", 3);
+ CuAssertPtrNotNull(tc, t);
+ CuAssertStrEquals(tc, "abc ___ef ghi___", t->str);
+ CuAssertIntEquals(tc, 16, (int)t->len);
+
+ t = sh_string_replace(s, ovector, 0,
+ "___", 3);
+ CuAssertPtrNotNull(tc, t);
+ CuAssertStrEquals(tc, s->str, t->str);
+ CuAssertIntEquals(tc, (int)s->len, (int)t->len);
+
+}
+
+#endif
diff --git a/src/sh_sub.c b/src/sh_sub.c
new file mode 100644
index 0000000..b90ce6d
--- /dev/null
+++ b/src/sh_sub.c
@@ -0,0 +1,525 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2011 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+/* 0->1 for debug */
+#if 0
+#define SH_SUB_DBG 1
+#endif
+
+#ifndef NULL
+#if !defined(__cplusplus)
+#define NULL ((void*)0)
+#else
+#define NULL (0)
+#endif
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+#include "samhain.h"
+#include "sh_pthread.h"
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+#define FIL__ _("sh_sub.c")
+
+static pid_t sh_child_pid = -1;
+static pid_t sh_wait_ret = 1;
+
+static int parent2child[2];
+static int child2parent[2];
+
+SH_MUTEX_STATIC(mutex_sub, PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_STATIC(mutex_sub_work, PTHREAD_MUTEX_INITIALIZER);
+
+static void wait_for_command();
+static ssize_t sh_sub_read(int fd, void *buf, size_t count);
+
+void sh_kill_sub()
+{
+ SH_MUTEX_LOCK(mutex_sub);
+
+ if (sh_child_pid != -1)
+ {
+ int status;
+#ifdef WCONTINUED
+ int wflags = WNOHANG|WUNTRACED|WCONTINUED;
+#else
+ int wflags = WNOHANG|WUNTRACED;
+#endif
+
+ close (parent2child[1]);
+ close (child2parent[0]);
+
+ /* Let's be rude. */
+ kill(sh_child_pid, SIGKILL);
+
+ retry_msleep(1,0);
+
+ if (sh_wait_ret == 0)
+ sh_wait_ret = waitpid( -1, &status, wflags);
+ else
+ sh_wait_ret = waitpid(sh_child_pid, &status, wflags);
+
+ sh_child_pid = -1;
+ }
+
+ SH_MUTEX_UNLOCK(mutex_sub);
+ return;
+}
+
+static int sh_create_sub()
+{
+ pid_t res;
+ volatile int retval = 0;
+
+ SH_MUTEX_LOCK(mutex_sub);
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+ if (sh_child_pid == -1)
+ {
+ sigset_t signal_set_new;
+ sigset_t signal_set_old;
+
+ sigfillset ( &signal_set_new );
+ sigemptyset( &signal_set_old );
+
+ /* Create pipes. */
+ res = pipe (parent2child);
+ if (res == 0)
+ res = pipe (child2parent);
+
+ if (res != 0)
+ goto out;
+
+ SH_SETSIGMASK(SIG_BLOCK, &signal_set_new, &signal_set_old);
+
+ res = fork();
+
+ if (res == 0)
+ {
+ /* Child process. */
+#ifdef _SC_OPEN_MAX
+ int fdlimit = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ int fdlimit = OPEN_MAX;
+#else
+ int fdlimit = _POSIX_OPEN_MAX;
+#endif
+#endif
+ int sflags, i, fd = 0;
+ struct sigaction act;
+
+ /* zero private information
+ */
+ memset(skey, 0, sizeof(sh_key_t));
+
+ close (parent2child[1]);
+ close (child2parent[0]);
+
+ sflags = fcntl(parent2child[0], F_GETFL, 0);
+ fcntl(parent2child[0], F_SETFL, sflags | O_NONBLOCK);
+ sflags = fcntl(child2parent[1], F_GETFL, 0);
+ fcntl(child2parent[1], F_SETFL, sflags | O_NONBLOCK);
+
+ /* close inherited file descriptors
+ */
+ if (fdlimit < 0)
+ fdlimit = 20; /* POSIX lower limit */
+ while (fd < fdlimit)
+ {
+ if (fd != parent2child[0] && fd != child2parent[1])
+ close(fd);
+ ++fd;
+ }
+
+ /*
+ for (i = 0; i < 3; ++i)
+ {
+ if ( fcntl(i, F_GETFL, 0) == (-1))
+ (void) open(_("/dev/null"), O_RDWR, 0);
+ }
+ */
+
+ /* reset signal handling
+ */
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigemptyset( &act.sa_mask );
+
+ for (i = 1; i < NSIG; ++i)
+ sigaction(i, &act, NULL);
+ SH_SETSIGMASK(SIG_UNBLOCK, &signal_set_new, NULL);
+
+ wait_for_command();
+
+ _exit(0);
+ }
+ else if (res > 0)
+ {
+ /* Parent process. */
+ int sflags;
+
+ SH_SETSIGMASK(SIG_SETMASK, &signal_set_old, NULL);
+
+ close (parent2child[0]);
+ close (child2parent[1]);
+
+ sflags = fcntl(parent2child[1], F_GETFL, 0);
+ fcntl(parent2child[1], F_SETFL, sflags | O_NONBLOCK);
+ sflags = fcntl(child2parent[0], F_GETFL, 0);
+ fcntl(child2parent[0], F_SETFL, sflags | O_NONBLOCK);
+
+ sh_child_pid = res;
+ }
+ else
+ {
+ /* Failure. */
+
+ SH_SETSIGMASK(SIG_SETMASK, &signal_set_old, NULL);
+
+ close (parent2child[0]);
+ close (parent2child[1]);
+
+ close (child2parent[0]);
+ close (child2parent[1]);
+
+ retval = -1;
+ }
+ }
+
+ out:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_UNLOCK(mutex_sub);
+ return retval;
+}
+
+#define SH_SUB_BUF (PIPE_BUF-1)
+struct sh_sub_in {
+ char command;
+ char path[SH_SUB_BUF];
+};
+
+struct sh_sub_out {
+ int retval;
+ int errnum;
+ struct stat sbuf;
+};
+
+#define SH_COM_STAT 0
+#define SH_COM_LSTAT 1
+
+static ssize_t sh_sub_write(int fd, const void *buf, size_t count)
+{
+ const char * mbuf = (const char *) buf;
+ ssize_t rcount;
+ int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
+ int tti = 1;
+
+ do {
+
+ rcount = write(fd, mbuf, count);
+ if (rcount > 0)
+ {
+ count -= rcount; mbuf += rcount; --ttl;
+ }
+
+ if (count > 0)
+ {
+ if (ttl > 0)
+ {
+ retry_msleep(0, tti);
+ tti *= 9;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ } while (count > 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
+
+ if (count > 0)
+ return -1;
+ return 0;
+}
+
+static void wait_for_command()
+{
+ int ret;
+ struct pollfd fds;
+ struct sh_sub_in inbuf;
+ struct sh_sub_out outbuf;
+
+ fds.fd = parent2child[0];
+ fds.events = POLLIN;
+
+ do {
+
+ do {
+ ret = poll(&fds, 1, -1);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret > 0)
+ {
+ ret = sh_sub_read(parent2child[0], &inbuf, sizeof(inbuf));
+
+ if (ret == 0)
+ {
+ if (inbuf.command == SH_COM_LSTAT)
+ {
+ do {
+ outbuf.retval = lstat(inbuf.path, &(outbuf.sbuf));
+ } while (outbuf.retval < 0 && errno == EAGAIN);
+ }
+ else
+ {
+ do {
+ outbuf.retval = stat(inbuf.path, &(outbuf.sbuf));
+ } while (outbuf.retval < 0 && errno == EAGAIN);
+ }
+
+ outbuf.errnum = errno;
+
+ ret = sh_sub_write(child2parent[1], &outbuf, sizeof(outbuf));
+ if (ret < 0)
+ {
+ return;
+ }
+ }
+ else /* sh_sub_read() < 0 */
+ {
+ return;
+ }
+ }
+ } while (1 == 1);
+}
+
+#ifndef ETIMEDOUT
+#define ETIMEDOUT EIO
+#endif
+
+static ssize_t sh_sub_read(int fd, void *buf, size_t count)
+{
+ char * mbuf = (char *) buf;
+ ssize_t rcount;
+ int ttl = 5; /* 0, 1, 9, 81, 729 millisec */
+ int tti = 1;
+
+ do {
+ rcount = read(fd, mbuf, count);
+
+ if (rcount > 0)
+ {
+ count -= rcount; mbuf += rcount; --ttl;
+ }
+
+ if (count > 0)
+ {
+ if (ttl > 0)
+ {
+ retry_msleep(0, tti);
+ tti *= 9;
+ }
+ else
+ {
+ if (rcount >= 0)
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+ } while (count > 0 &&
+ (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR));
+
+ if (count > 0)
+ return -1;
+
+ return 0;
+}
+
+#ifdef SH_SUB_DBG
+#include <stdarg.h>
+static void debug_it (const char *fmt, ...)
+{
+ char msg[256];
+ va_list ap;
+
+ int fd = open("debug.it", O_CREAT|O_WRONLY|O_APPEND, 0666);
+
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap); /* flawfinder: ignore */
+ va_end(ap);
+
+ write(fd, msg, strlen(msg));
+ write(fd, "\n", 1);
+ close(fd);
+ return;
+}
+#endif
+
+static int sh_sub_stat_int(const char *path, struct stat *buf, char command)
+{
+ int retval;
+ volatile int sflag = 0;
+ struct sh_sub_in inbuf;
+ struct sh_sub_out outbuf;
+ struct pollfd pfds;
+
+ size_t len = strlen(path) + 1;
+
+ if (len > SH_SUB_BUF)
+ {
+ if (command == SH_COM_LSTAT)
+ {
+ do {
+ retval = lstat(path, buf);
+ } while (retval < 0 && errno == EAGAIN);
+
+ return retval;
+ }
+ else
+ {
+ do {
+ retval = stat(path, buf);
+ } while (retval < 0 && errno == EAGAIN);
+
+ return retval;
+ }
+ }
+
+ sl_strlcpy(inbuf.path, path, SH_SUB_BUF);
+ inbuf.command = command;
+
+ start:
+
+#ifdef SH_SUB_DBG
+ debug_it("%d sh_child_pid %d\n", (int)getpid(), (int) sh_child_pid);
+#endif
+
+ if (sh_child_pid == -1)
+ sh_create_sub();
+
+#ifdef SH_SUB_DBG
+ debug_it("%d stat_sub %s (%d)\n", (int)getpid(), inbuf.path, (int) sh_child_pid);
+#endif
+
+ SH_MUTEX_LOCK(mutex_sub_work);
+
+ retval = sh_sub_write(parent2child[1], &inbuf, sizeof(inbuf));
+ if (retval < 0)
+ {
+ int error = errno;
+ sh_kill_sub();
+ errno = error;
+ sflag = 1;
+ goto end;
+ }
+
+#ifdef SH_SUB_DBG
+ debug_it("%d stat_sub polling..\n", (int)getpid());
+#endif
+
+ pfds.fd = child2parent[0];
+ pfds.events = POLLIN;
+
+ do {
+ retval = poll(&pfds, 1, 300 * 1000);
+ } while (retval < 0 && errno == EINTR);
+
+ if (retval <= 0)
+ {
+ int error = errno;
+ sh_kill_sub();
+ errno = (retval == 0) ? ETIMEDOUT : error;
+ sflag = -1;
+ goto end;
+ }
+
+#ifdef SH_SUB_DBG
+ debug_it("%d stat_sub reading..\n", (int)getpid());
+#endif
+
+ retval = sh_sub_read (child2parent[0], &outbuf, sizeof(outbuf));
+ if (retval < 0)
+ {
+ int error = errno;
+ sh_kill_sub();
+ errno = error;
+ sflag = 1;
+ goto end;
+ }
+
+ end:
+ ; /* 'label at end of compound statement' */
+ SH_MUTEX_UNLOCK(mutex_sub_work);
+
+ if (sflag == 0)
+ {
+#ifdef SH_SUB_DBG
+ debug_it("%d stat_sub done..\n", (int)getpid());
+#endif
+ memcpy(buf, &(outbuf.sbuf), sizeof(struct stat));
+ errno = outbuf.errnum;
+ return outbuf.retval;
+ }
+ else if (sflag == 1)
+ {
+#ifdef SH_SUB_DBG
+ debug_it("%d stat_sub error..\n", (int)getpid());
+#endif
+ /* could not read, thus subprocess may have gone */
+ sflag = 0;
+ goto start;
+ }
+
+ return -1;
+}
+
+int sh_sub_stat (const char *path, struct stat *buf)
+{
+ return sh_sub_stat_int(path, buf, SH_COM_STAT);
+}
+
+int sh_sub_lstat(const char *path, struct stat *buf)
+{
+ return sh_sub_stat_int(path, buf, SH_COM_LSTAT);
+}
+
diff --git a/src/sh_suidchk.c b/src/sh_suidchk.c
new file mode 100644
index 0000000..d9cc1f9
--- /dev/null
+++ b/src/sh_suidchk.c
@@ -0,0 +1,2537 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2001 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifdef HAVE_SCHED_H
+#include <sched.h>
+#endif
+
+#ifdef SH_USE_SUIDCHK
+
+#undef FIL__
+#define FIL__ _("sh_suidchk.c")
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
+#define NEED_ADD_DIRENT
+
+#include "samhain.h"
+#include "sh_pthread.h"
+#include "sh_utils.h"
+#include "sh_error.h"
+#include "sh_modules.h"
+#include "sh_suidchk.h"
+#include "sh_hash.h"
+#include "sh_dbIO.h"
+#include "sh_unix.h"
+#include "sh_files.h"
+#include "sh_schedule.h"
+#include "sh_calls.h"
+#include "zAVLTree.h"
+
+
+sh_rconf sh_suidchk_table[] = {
+ {
+ N_("severitysuidcheck"),
+ sh_suidchk_set_severity
+ },
+ {
+ N_("suidcheckactive"),
+ sh_suidchk_set_activate
+ },
+ {
+ N_("suidcheckinterval"),
+ sh_suidchk_set_timer
+ },
+ {
+ N_("suidcheckschedule"),
+ sh_suidchk_set_schedule
+ },
+ {
+ N_("suidcheckexclude"),
+ sh_suidchk_set_exclude
+ },
+ {
+ N_("suidcheckfps"),
+ sh_suidchk_set_fps
+ },
+ {
+ N_("suidcheckyield"),
+ sh_suidchk_set_yield
+ },
+ {
+ N_("suidchecknosuid"),
+ sh_suidchk_set_nosuid
+ },
+ {
+ N_("suidcheckquarantinefiles"),
+ sh_suidchk_set_quarantine
+ },
+ {
+ N_("suidcheckquarantinemethod"),
+ sh_suidchk_set_qmethod
+ },
+ {
+ N_("suidcheckquarantinedelete"),
+ sh_suidchk_set_qdelete
+ },
+ {
+ NULL,
+ NULL
+ },
+};
+
+
+static time_t lastcheck = (time_t) 0;
+static int ShSuidchkActive = S_TRUE;
+static time_t ShSuidchkInterval = 7200;
+static unsigned long ShSuidchkFps = 0;
+static int ShSuidchkNosuid = S_FALSE;
+static int ShSuidchkYield = S_FALSE;
+static int ShSuidchkQEnable = S_FALSE;
+static int ShSuidchkQMethod = SH_Q_CHANGEPERM;
+static int ShSuidchkQDelete = S_FALSE;
+static int ShSuidchkSeverity = SH_ERR_SEVERE;
+
+static time_t FileLimNow = 0;
+static time_t FileLimStart = 0;
+static unsigned long FileLimNum = 0;
+static unsigned long FileLimTotal = 0;
+
+static sh_schedule_t * ShSuidchkSched = NULL;
+
+
+static zAVLTree * ShSuidchkExclude = NULL;
+static void sh_suid_exclude_free()
+{
+ zAVL_string_reset(ShSuidchkExclude);
+ ShSuidchkExclude = NULL;
+ return;
+}
+static int sh_suid_exclude_add(const char * str)
+{
+ size_t len;
+ int ret;
+ char * key = sh_util_strdup(str);
+
+ len = sl_strlen (key);
+ if (len && key[len-1] == '/')
+ {
+ key[len-1] = '\0';
+ }
+ ret = zAVL_string_set(&ShSuidchkExclude, key);
+ SH_FREE(key);
+ return ret;
+}
+
+
+static char *
+filesystem_type (char * path, char * relpath, struct stat * statp);
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+SH_MUTEX_STATIC(mutex_suid_check, PTHREAD_MUTEX_INITIALIZER);
+
+extern unsigned long sh_files_maskof (int class);
+
+static void set_defaults (void)
+{
+ ShSuidchkActive = S_TRUE;
+ ShSuidchkInterval = 7200;
+ ShSuidchkFps = 0;
+ ShSuidchkNosuid = S_FALSE;
+ ShSuidchkYield = S_FALSE;
+ ShSuidchkQEnable = S_FALSE;
+ ShSuidchkQMethod = SH_Q_CHANGEPERM;
+ ShSuidchkQDelete = S_FALSE;
+ ShSuidchkSeverity = SH_ERR_SEVERE;
+ if (ShSuidchkExclude != NULL)
+ sh_suid_exclude_free();
+
+ FileLimNow = 0;
+ FileLimStart = 0;
+ FileLimNum = 0;
+ FileLimTotal = 0;
+
+ return;
+}
+
+/* Recursively descend into the directory to make sure that
+ * there is no symlink in the path.
+ *
+ * Use retry_lstat_ns() here because we cannot chdir the subprocess
+ * that does the lstat().
+ */
+static int do_truncate_int (char * path, int depth)
+{
+ char * q;
+ struct stat one;
+ struct stat two;
+ int fd;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ if (depth > 99)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("do_truncate: max depth 99 exceeded"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return -1;
+ }
+ ++depth;
+ if (path[0] != '/')
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("do_truncate: not an absolute path"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return -1;
+ }
+ ++path;
+ q = strchr(path, '/');
+ if (q)
+ {
+ *q = '\0';
+ if (0 != retry_lstat_ns(FIL__, __LINE__, path, &one))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ *q = '/';
+ return -1;
+ }
+ if (/*@-usedef@*/!S_ISDIR(one.st_mode)/*@+usedef@*/)
+
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("Possible race: not a directory"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ *q = '/';
+ return -1;
+ }
+
+
+ if (0 != chdir(path))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ *q = '/';
+ return -1;
+ }
+ *q = '/';
+ if (0 != retry_lstat_ns(FIL__, __LINE__, ".", &two))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return -1;
+ }
+ if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
+ (one.st_ino != two.st_ino) ||
+ (!S_ISDIR(two.st_mode))/*@+usedef@*/)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("Possible race: lstat(dir) != lstat(.)"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return -1;
+ }
+
+
+ return (do_truncate_int(q, depth));
+ }
+ else
+ {
+ /* no more '/', so this is the file
+ */
+ if (*path == '\0')
+ return -1;
+ if (0 != retry_lstat_ns(FIL__, __LINE__, path, &one))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return -1;
+ }
+ fd = open(path, O_RDWR);
+ if (-1 == fd)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return -1;
+ }
+ if (0 != retry_fstat(FIL__, __LINE__, fd, &two))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ if (/*@-usedef@*/(one.st_dev != two.st_dev) ||
+ (one.st_ino != two.st_ino)/*@+usedef@*/)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("Possible race: lstat != fstat"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ if (!S_ISREG(two.st_mode))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("Possible race: not a regular file"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ if ((0 == (two.st_mode & S_ISUID)) && (0 == (two.st_mode & S_ISGID)))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("Possible race: not a suid/sgid file"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ if (ShSuidchkQDelete == S_FALSE)
+ {
+ if ((two.st_mode & S_ISUID) > 0)
+ two.st_mode -= S_ISUID;
+ if ((two.st_mode & S_ISGID) > 0)
+ two.st_mode -= S_ISGID;
+#ifdef HAVE_FCHMOD
+ if (-1 == /*@-unrecog@*/fchmod(fd, two.st_mode)/*@+unrecog@*/)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+#else
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ _("The fchmod() function is not available"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+#endif
+ if (two.st_nlink > 1)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0,
+ MSG_SUID_ERROR,
+ _("Not truncated because hardlink count gt 1"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ /* The man page says: 'POSIX has ftruncate'
+ */
+ if (-1 == /*@-unrecog@*/ftruncate(fd, 0)/*@+unrecog@*/)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ }
+ else
+ {
+ if (-1 == retry_aud_unlink(FIL__, __LINE__, path))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ (void) sl_close_fd(FIL__, __LINE__, fd);
+ return -1;
+ }
+ }
+ (void) sl_close_fd (FIL__, __LINE__, fd);
+ return (0);
+ }
+}
+
+static int do_truncate (const char * path_in)
+{
+ volatile int caperr;
+ int result;
+ char * path;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ if (0 != chdir("/"))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (0 != (caperr = sl_get_cap_qdel()))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_get_cap_qdel"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ path = sh_util_strdup (path_in);
+ result = do_truncate_int (path, 0);
+ SH_FREE(path);
+
+ if (0 != (caperr = sl_drop_cap_qdel()))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_drop_cap_qdel"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (0 != chdir("/"))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno,
+ MSG_SUID_ERROR,
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ return result;
+}
+
+/* This variable is not used anywhere. It only exists
+ * to assign &dirlist to it, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+static void * sh_dummy_tmp = NULL;
+
+static void sh_q_delete(const char * fullpath)
+{
+ int status;
+ char * msg;
+ char * tmp;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_tmp = (void*) &tmp;
+
+ if (do_truncate (fullpath) == -1)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("Problem quarantining file. File NOT quarantined. errno = %ld"),
+ status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ else
+ {
+ tmp = sh_util_safe_name(fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__, 0,
+ MSG_SUID_QREPORT,
+ _("Quarantine method applied"),
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ }
+ return;
+}
+
+/* This variable is not used anywhere. It only exists
+ * to assign &dirlist to it, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+static void * sh_dummy_mtmp = NULL;
+static void * sh_dummy_mmsg = NULL;
+
+static void sh_q_move(const char * fullpath, file_type * theFile,
+ const char * timestrc, const char * timestra,
+ const char * timestrm)
+{
+ volatile int status;
+ int readFile = -1;
+ volatile int writeFile = -1;
+ struct stat fileInfo;
+ ssize_t count;
+ char * msg;
+ char * tmp;
+ char * basetmp;
+ char * filetmp;
+ char buffer[1024];
+ char * dir = SH_ALLOC(PATH_MAX+1);
+ mode_t umask_old;
+ FILE * filePtr = NULL;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_mtmp = (void*) &tmp;
+ sh_dummy_mmsg = (void*) &msg;
+
+ (void) sl_strlcpy (dir, DEFAULT_QDIR, PATH_MAX+1);
+
+ if (retry_stat (FIL__, __LINE__, dir, &fileInfo) != 0)
+ {
+ /* Quarantine directory does not exist,
+ */
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("Problem quarantining file. File NOT quarantined. errno = %ld (stat)"),
+ status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ else
+ {
+ if (retry_lstat (FIL__, __LINE__,
+ fullpath, &fileInfo) == -1)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld(stat)"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT,
+ msg, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ else
+ {
+ basetmp = sh_util_strdup(fullpath);
+ filetmp = SH_ALLOC(PATH_MAX+1);
+ tmp = sh_util_basename(basetmp);
+
+ (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s",
+ DEFAULT_QDIR, tmp);
+ SH_FREE(tmp);
+ SH_FREE(basetmp);
+
+ readFile = open (fullpath, O_RDONLY);
+ if (readFile != -1)
+ writeFile = open (filetmp, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IXUSR);
+
+ if ((readFile == -1) || (writeFile == -1))
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE, _("Problem quarantining file. File NOT quarantined. errno = %ld (open)"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__, status,
+ MSG_SUID_QREPORT,
+ msg, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ else
+ {
+ /* sizeof(buffer) is 1024
+ */
+ while ((count = (int) read (readFile, buffer, sizeof (buffer))) > 0)
+ {
+ if ((int) write (writeFile, buffer, (size_t) count) != count)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("I/O error. errno = %ld (write)"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__,
+ __LINE__,
+ status,
+ MSG_SUID_QREPORT,
+ msg, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ }
+ }
+
+ (void) sl_close_fd (FIL__, __LINE__, readFile);
+ (void) fchmod(writeFile, S_IRUSR | S_IWUSR | S_IXUSR);
+ (void) sl_close_fd (FIL__, __LINE__, writeFile);
+
+ if (do_truncate (fullpath) == -1)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("Problem quarantining file. File NOT quarantined. errno = %ld"),
+ status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__, status,
+ MSG_SUID_QREPORT,
+ msg, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ else
+ {
+ tmp = sh_util_basename(fullpath);
+
+ (void) sl_snprintf(filetmp, PATH_MAX+1, "%s/%s.info",
+ DEFAULT_QDIR,
+ tmp);
+
+ SH_FREE(tmp);
+ /*
+ * avoid chmod by setting umask
+ */
+ umask_old = umask (0077);
+ filePtr = fopen (filetmp, "w+");
+
+ /*@-usedef@*/
+ if (filePtr)
+ {
+ fprintf(filePtr,
+ _("File Info:\n filename=%s\n size=%lu\n owner=%s(%d)\n group=%s(%d)\n ctime=%s\n atime=%s\n mtime=%s\n"),
+ fullpath,
+ (unsigned long) theFile->size,
+ theFile->c_owner, (int) theFile->owner,
+ theFile->c_group, (int) theFile->group,
+ timestrc, timestra, timestrm);
+ (void) sl_fclose (FIL__, __LINE__, filePtr);
+ }
+ /*@+usedef@*/
+ umask (umask_old);
+
+ tmp = sh_util_safe_name(fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__,__LINE__,
+ 0, MSG_SUID_QREPORT,
+ _("Quarantine method applied"),
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ }
+ SH_FREE(filetmp);
+ }
+ }
+ SH_FREE(dir);
+ return;
+}
+
+/* This variable is not used anywhere. It only exists
+ * to assign &dirlist to it, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+static void * sh_dummy_ctmp = NULL;
+static void * sh_dummy_cmsg = NULL;
+
+static void sh_q_changeperm(const char * fullpath)
+{
+ volatile int caperr;
+ volatile int status;
+ char * msg;
+ char * tmp;
+ struct stat fileInfo;
+ struct stat fileInfo_F;
+ int cperm_status = 0;
+ volatile int file_d = -1;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_ctmp = (void*) &tmp;
+ sh_dummy_cmsg = (void*) &msg;
+
+ if (retry_lstat(FIL__, __LINE__, fullpath, &fileInfo) == -1)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ cperm_status = -1;
+ }
+
+ if (cperm_status == 0)
+ {
+ if (0 != (caperr = sl_get_cap_qdel()))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__,
+ caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_get_cap_qdel"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ cperm_status = -1;
+ }
+ }
+
+ if (cperm_status == 0)
+ {
+ file_d = aud_open (FIL__, __LINE__, SL_YESPRIV,
+ fullpath, O_RDONLY, 0);
+ if (-1 == file_d)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE, _("I/O error. errno = %ld"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ cperm_status = -1;
+ }
+ }
+
+ if (cperm_status == 0)
+ {
+ if (retry_fstat(FIL__, __LINE__, file_d, &fileInfo_F) == -1)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("I/O error. errno = %ld"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ cperm_status = -1;
+ }
+ }
+
+ if (cperm_status == 0)
+ {
+ if (fileInfo_F.st_ino != fileInfo.st_ino ||
+ fileInfo_F.st_dev != fileInfo.st_dev ||
+ fileInfo_F.st_mode != fileInfo.st_mode)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("Race detected. errno = %ld"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ cperm_status = -1;
+ }
+ }
+
+ if ((fileInfo.st_mode & S_ISUID) > 0)
+ fileInfo.st_mode -= S_ISUID;
+ if ((fileInfo.st_mode & S_ISGID) > 0)
+ fileInfo.st_mode -= S_ISGID;
+
+ if (cperm_status == 0)
+ {
+ if (fchmod(file_d, fileInfo.st_mode) == -1)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("Problem quarantining file. File NOT quarantined. errno = %ld"),
+ status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT,
+ msg, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ else
+ {
+ tmp = sh_util_safe_name(fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ 0,
+ MSG_SUID_QREPORT,
+ _("Quarantine method applied"),
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ }
+ }
+
+ if (0 != (caperr = sl_drop_cap_qdel()))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__,
+ caperr, MSG_E_SUBGEN,
+ sh_error_message (caperr, errbuf, sizeof(errbuf)),
+ _("sl_drop_cap_qdel"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (file_d != -1)
+ {
+ do {
+ status = sl_close_fd (FIL__, __LINE__, file_d);
+ } while (status == -1 && errno == EINTR);
+
+ if (-1 == status)
+ {
+ status = errno;
+ msg = SH_ALLOC(SH_BUFSIZE);
+ tmp = sh_util_safe_name(fullpath);
+
+ (void) sl_snprintf(msg, SH_BUFSIZE,
+ _("I/O error. errno = %ld"), status);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity,
+ FIL__, __LINE__,
+ status,
+ MSG_SUID_QREPORT, msg,
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ }
+ }
+ return;
+}
+
+static void report_file (const char * tmpcat, file_type * theFile,
+ char * timestrc, char * timestra, char * timestrm)
+{
+ char * msg = SH_ALLOC(SH_BUFSIZE);
+ char * tmp = sh_util_safe_name(tmpcat);
+
+ msg[0] = '\0';
+ /*@-usedef@*/
+
+#ifdef SH_USE_XML
+ (void) sl_snprintf(msg, SH_BUFSIZE, _("owner_new=\"%s\" iowner_new=\"%ld\" group_new=\"%s\" igroup_new=\"%ld\" size_new=\"%lu\" ctime_new=\"%s\" atime_new=\"%s\" mtime_new=\"%s\""),
+ theFile->c_owner, theFile->owner,
+ theFile->c_group, theFile->group,
+ (unsigned long) theFile->size,
+ timestrc, timestra, timestrm);
+#else
+ (void) sl_snprintf(msg, SH_BUFSIZE, _("owner_new=<%s>, iowner_new=<%ld>, group_new=<%s>, igroup_new=<%ld>, filesize=<%lu>, ctime=<%s>, atime=<%s>, mtime=<%s>"),
+ theFile->c_owner, theFile->owner,
+ theFile->c_group, theFile->group,
+ (unsigned long) theFile->size,
+ timestrc, timestra, timestrm);
+#endif
+ /*@+usedef@*/
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
+ 0, MSG_SUID_POLICY,
+ _("suid/sgid file not in database"),
+ tmp, msg );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(msg);
+ return;
+}
+
+/* This variable is not used anywhere. It only exists
+ * to assign &dirlist to it, which keeps gcc from
+ * putting it into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+static void * sh_dummy_dirlist = NULL;
+static void * sh_dummy_itmp = NULL;
+
+
+static
+int sh_suidchk_check_internal (char * iname)
+{
+ DIR * thisDir = NULL;
+ struct dirent * thisEntry;
+ char * tmpcat;
+ char * tmp;
+ char timestrc[32];
+ char timestra[32];
+ char timestrm[32];
+ struct stat buf;
+ volatile int status;
+ int fflags;
+ char * fs;
+ volatile long sl_status;
+ file_type * theFile = NULL;
+ char fileHash[2*(KEY_LEN + 1)];
+
+ struct sh_dirent * dirlist;
+ struct sh_dirent * dirlist_orig;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_suidchk_check_internal"));
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_dirlist = (void*) &dirlist;
+ sh_dummy_itmp = (void*) &tmp;
+
+ if (iname == NULL)
+ {
+ TPT((0, FIL__, __LINE__ , _("msg=<directory name is NULL>\n")));
+ SL_RETURN( (-1), _("sh_suidchk_check_internal"));
+ }
+
+ if (sig_urgent > 0) {
+ SL_RETURN( (0), _("sh_suidchk_check_internal"));
+ }
+
+ thisDir = opendir (iname);
+
+ if (thisDir == NULL)
+ {
+ status = errno;
+ tmp = sh_util_safe_name(iname);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_DIR], FIL__, __LINE__, status,
+ MSG_E_OPENDIR,
+ sh_error_message (status, errbuf, sizeof(errbuf)), tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SL_RETURN( (-1), _("sh_suidchk_check_internal"));
+ }
+
+ /* Loop over directory entries
+ */
+ SH_MUTEX_LOCK(mutex_readdir);
+
+ dirlist = NULL;
+ dirlist_orig = NULL;
+
+ do {
+
+ thisEntry = readdir (thisDir);
+
+ if (thisEntry != NULL) {
+
+ if (sl_strcmp (thisEntry->d_name, ".") == 0)
+ continue;
+
+ if (sl_strcmp (thisEntry->d_name, "..") == 0)
+ continue;
+
+ dirlist = addto_sh_dirlist (thisEntry, dirlist);
+ }
+
+ } while (thisEntry != NULL);
+
+ SH_MUTEX_UNLOCK(mutex_readdir);
+
+ closedir(thisDir);
+
+ dirlist_orig = dirlist;
+
+ sl_status = SL_ENONE;
+
+ do {
+
+ /* If the directory is empty, dirlist = NULL
+ */
+ if (!dirlist)
+ break;
+
+ if (sig_urgent > 0) {
+ SL_RETURN( (0), _("sh_suidchk_check_internal"));
+ }
+
+ tmpcat = SH_ALLOC(PATH_MAX);
+ (void) sl_strlcpy(tmpcat, iname, PATH_MAX);
+
+ if ((sl_strlen(tmpcat) != sl_strlen(iname)) || (tmpcat[0] == '\0'))
+ {
+ sl_status = SL_ETRUNC;
+ }
+ else
+ {
+ if (tmpcat[1] != '\0')
+ sl_status = sl_strlcat(tmpcat, "/", PATH_MAX);
+ }
+
+ if (! SL_ISERROR(sl_status))
+ sl_status = sl_strlcat(tmpcat, dirlist->sh_d_name, PATH_MAX);
+
+ if (SL_ISERROR(sl_status))
+ {
+ tmp = sh_util_safe_name(tmpcat);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, (int) sl_status,
+ MSG_E_SUBGPATH,
+ _("path too long"),
+ _("sh_suidchk_check_internal"), tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ SH_FREE(tmpcat);
+ dirlist = dirlist->next;
+ continue;
+ }
+
+ ++FileLimNum;
+ ++FileLimTotal;
+
+ /* Rate limit (Fps == Files per second)
+ */
+ if ((ShSuidchkFps > 0 && FileLimNum > ShSuidchkFps) &&
+ (ShSuidchkYield == S_FALSE))
+ {
+ FileLimNum = 0;
+ FileLimNow = time(NULL);
+
+ if ( (FileLimNow - FileLimStart) > 0 &&
+ FileLimTotal/(FileLimNow - FileLimStart) > ShSuidchkFps )
+ (void) retry_msleep((int)((FileLimTotal/(FileLimNow-FileLimStart))/
+ ShSuidchkFps) , 0);
+ }
+
+ status = (int) retry_lstat(FIL__, __LINE__, tmpcat, &buf);
+
+ if (status != 0)
+ {
+ volatile int elevel = SH_ERR_ERR;
+ size_t tlen;
+
+ status = errno;
+ tmp = sh_util_safe_name(tmpcat);
+ tlen = strlen(tmp);
+ if (tlen >= 6 && 0 == strcmp(&tmp[tlen-6], _("/.gvfs")))
+ elevel = SH_ERR_NOTICE;
+ else if (tlen >= 5 && 0 == strcmp(&tmp[tlen-5], _("/gvfs")))
+ elevel = SH_ERR_NOTICE;
+
+ /* If we are scanning a temporary directory where dirs and files
+ * can be created/deleted, an lstat() error is something which
+ * may occur frequently. As a missing dir/file is not an important
+ * problem for the suidcheck, the error level is only SH_ERR_NOTICE.
+ */
+ if (status == ENOENT)
+ elevel = SH_ERR_NOTICE;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (elevel, FIL__, __LINE__, status, MSG_ERR_LSTAT,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp);
+ }
+ else
+ {
+ if (/*@-usedef@*/S_ISDIR(buf.st_mode)/*@+usedef@*/ &&
+ (ShSuidchkExclude == NULL ||
+ NULL == zAVL_string_get(ShSuidchkExclude, tmpcat)))
+ {
+ /* fs is a STATIC string or NULL
+ */
+ fs = filesystem_type (tmpcat, tmpcat, &buf);
+ if (fs != NULL
+#ifndef SH_SUIDTESTDIR
+ &&
+ 0 != strncmp (_("afs"), fs, 3) &&
+ 0 != strncmp (_("devfs"), fs, 5) &&
+ 0 != strncmp (_("fdesc"), fs, 5) &&
+ 0 != strncmp (_("iso9660"), fs, 7) &&
+ 0 != strncmp (_("cd9660"), fs, 6) &&
+ 0 != strncmp (_("lustre"), fs, 6) &&
+ 0 != strncmp (_("mmfs"), fs, 4) &&
+ 0 != strncmp (_("msdos"), fs, 5) &&
+ 0 != strncmp (_("nfs"), fs, 3) &&
+ 0 != strncmp (_("proc"), fs, 4) &&
+ 0 != strncmp (_("sysfs"), fs, 5) &&
+ 0 != strncmp (_("vfat"), fs, 4)
+#endif
+ )
+ {
+ if ((ShSuidchkNosuid == S_TRUE) ||
+ (0 != strncmp (_("nosuid"), fs, 6)))
+ /* fprintf(stderr, "%s: %s\n", fs, tmpcat); */
+ (void) sh_suidchk_check_internal(tmpcat);
+ }
+ }
+ else if (S_ISREG(buf.st_mode) &&
+ (0 !=(S_ISUID & buf.st_mode) ||
+#if defined(HOST_IS_LINUX)
+ (0 !=(S_ISGID & buf.st_mode) &&
+ 0 !=(S_IXGRP & buf.st_mode))
+#else
+ 0 !=(S_ISGID & buf.st_mode)
+#endif
+ )
+ )
+ {
+ int dummy;
+ int class;
+ unsigned long check_flags = 0;
+
+ theFile = SH_ALLOC(sizeof(file_type));
+
+ (void) sl_strlcpy (theFile->fullpath, tmpcat, PATH_MAX);
+ theFile->check_flags = sh_files_maskof(SH_LEVEL_READONLY);
+ CLEAR_SH_FFLAG_REPORTED(theFile->file_reported);
+ theFile->attr_string = NULL;
+ theFile->link_path = NULL;
+
+ sh_files_search_file(tmpcat, &class, &check_flags, &dummy);
+ if ((check_flags & MODI_PREL) != 0)
+ MODI_SET(theFile->check_flags, MODI_PREL);
+
+ status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO],
+ dirlist->sh_d_name,
+ theFile, fileHash, 0);
+
+ tmp = sh_util_safe_name(tmpcat);
+
+ if (status != 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity, FIL__, __LINE__,
+ 0, MSG_E_SUBGPATH,
+ _("Could not check suid/sgid file"),
+ _("sh_suidchk_check_internal"),
+ tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+
+ if ( sh.flag.update == S_TRUE &&
+ (sh.flag.checkSum == SH_CHECK_INIT ||
+ sh.flag.checkSum == SH_CHECK_CHECK))
+ {
+ int compret;
+
+ /* Updating database. Report new files that
+ * are not in database already. Then compare
+ * to database and report changes.
+ */
+ if (-1 == sh_hash_have_it (tmpcat))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__,
+ 0, MSG_SUID_FOUND, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ 0, MSG_SUID_FOUND, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ compret = sh_hash_compdata (SH_LEVEL_READONLY,
+ theFile, fileHash,
+ _("[SuidCheck]"),
+ ShSuidchkSeverity);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ if (compret == 0)
+ {
+ sh_hash_pushdata_memory (theFile, fileHash); /* no call to sh_error_handle */
+ }
+
+ sh_hash_set_flag(tmpcat, SH_FFLAG_SUIDCHK); /* no call to sh_error_handle */
+
+ }
+
+ else if (sh.flag.checkSum == SH_CHECK_INIT &&
+ sh.flag.update == S_FALSE )
+ {
+ /* Running init. Report on files detected.
+ */
+ sh_dbIO_data_write (theFile, fileHash); /* no call to sh_error_handle */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__,
+ 0, MSG_SUID_FOUND, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ else if (sh.flag.checkSum == SH_CHECK_CHECK )
+ {
+ /* Running file check. Report on new files
+ * detected, and quarantine them.
+ */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
+ 0, MSG_SUID_FOUND, tmp );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ fflags = sh_hash_getflags(tmpcat); /* no call to sh_error_handle */
+
+ if ( (-1 == fflags) || (!SH_FFLAG_SUIDCHK_SET(fflags)))
+ {
+ if (-1 == fflags)
+ {
+ (void) sh_unix_gmttime (theFile->ctime, timestrc, sizeof(timestrc));
+ (void) sh_unix_gmttime (theFile->atime, timestra, sizeof(timestra));
+ (void) sh_unix_gmttime (theFile->mtime, timestrm, sizeof(timestrm));
+
+ report_file(tmpcat, theFile, timestrc, timestra, timestrm);
+ }
+ /* Quarantine file according to configured method
+ */
+ if (ShSuidchkQEnable == S_TRUE)
+ {
+ switch (ShSuidchkQMethod)
+ {
+ case SH_Q_DELETE:
+ sh_q_delete(theFile->fullpath);
+ break;
+ case SH_Q_CHANGEPERM:
+ sh_q_changeperm(theFile->fullpath);
+ break;
+ case SH_Q_MOVE:
+ sh_q_move(theFile->fullpath, theFile, timestrc, timestra, timestrm);
+ break;
+ default:
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShSuidchkSeverity, FIL__,
+ __LINE__, 0, MSG_SUID_QREPORT,
+ _("Bad quarantine method"), tmp);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ break;
+ }
+ }
+ else
+ {
+ /* 1.8.1 push file to in-memory database
+ */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_hash_compdata (SH_LEVEL_READONLY,
+ theFile, fileHash,
+ _("[SuidCheck]"),
+ ShSuidchkSeverity);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ sh_hash_set_flag(tmpcat, SH_FFLAG_SUIDCHK); /* no call to sh_error_handle */
+
+ }
+ }
+ else
+ {
+ /* File exists. Check for modifications.
+ */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_hash_compdata (SH_LEVEL_READONLY,
+ theFile, fileHash,
+ _("[SuidCheck]"),
+ ShSuidchkSeverity);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_hash_set_flag(tmpcat, SH_FFLAG_SUIDCHK); /* no call to sh_error_handle */
+
+ }
+ }
+ }
+ SH_FREE(tmp);
+ if (theFile->attr_string) SH_FREE(theFile->attr_string);
+ if (theFile->link_path) SH_FREE(theFile->link_path);
+ SH_FREE(theFile);
+ }
+ }
+ SH_FREE(tmpcat);
+
+
+#ifdef HAVE_SCHED_YIELD
+ if (ShSuidchkYield == S_TRUE)
+ {
+ if (sched_yield() == -1)
+ {
+ status = errno;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Failed to release time slice"),
+ _("sh_suidchk_check_internal") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+#endif
+
+ dirlist = dirlist->next;
+
+ } while (dirlist != NULL);
+
+
+ kill_sh_dirlist (dirlist_orig);
+
+ SL_RETURN( (0), _("sh_suidchk_check_internal"));
+}
+
+/*************
+ *
+ * module init
+ *
+ *************/
+int sh_suidchk_init (struct mod_type * arg)
+{
+#ifndef HAVE_PTHREAD
+ (void) arg;
+#endif
+
+ if (ShSuidchkActive == S_FALSE)
+ return SH_MOD_FAILED;
+
+#ifdef HAVE_PTHREAD
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ return SH_MOD_THREAD;
+ else
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ return SH_MOD_THREAD;
+ }
+#endif
+
+ return (0);
+}
+
+
+/*************
+ *
+ * module cleanup
+ *
+ *************/
+int sh_suidchk_end ()
+{
+ return (0);
+}
+
+
+/*************
+ *
+ * module timer
+ *
+ *************/
+int sh_suidchk_timer (time_t tcurrent)
+{
+ if (sh.flag.checkSum == SH_CHECK_INIT)
+ return -1;
+
+ /* One-shot (not daemon and not loop forever)
+ */
+ if (sh.flag.isdaemon != S_TRUE && sh.flag.loop == S_FALSE)
+ return -1;
+
+ if (ShSuidchkSched != NULL)
+ {
+ return test_sched(ShSuidchkSched);
+ }
+ if ((time_t) (tcurrent - lastcheck) >= ShSuidchkInterval)
+ {
+ lastcheck = tcurrent;
+ return (-1);
+ }
+ return 0;
+}
+
+/*************
+ *
+ * module check
+ *
+ *************/
+
+int sh_suidchk_check ()
+{
+ volatile int status;
+
+ SL_ENTER(_("sh_suidchk_check"));
+
+ if (ShSuidchkActive == S_FALSE)
+ SL_RETURN(-1, _("sh_suidchk_check"));
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
+ _("Checking for SUID programs"),
+ _("sh_suidchk_check") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ FileLimNow = time(NULL);
+ FileLimStart = FileLimNow;
+ FileLimNum = 0;
+ FileLimTotal = 0;
+
+#ifdef SH_SUIDTESTDIR
+ status = sh_suidchk_check_internal (SH_SUIDTESTDIR);
+#else
+ status = sh_suidchk_check_internal ("/");
+#endif
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_SUID_SUMMARY,
+ FileLimTotal,
+ (long) (time(NULL) - FileLimStart) );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+
+ SL_RETURN(status, _("sh_suidchk_check"));
+}
+
+/*************
+ *
+ * module setup
+ *
+ *************/
+
+int sh_suidchk_set_severity (const char * c)
+{
+ int retval;
+ char tmp[32];
+
+ SL_ENTER(_("sh_suidchk_set_severity"));
+ tmp[0] = '='; tmp[1] = '\0';
+ (void) sl_strlcat (tmp, c, 32);
+ retval = sh_error_set_level (tmp, &ShSuidchkSeverity);
+ SL_RETURN(retval, _("sh_suidchk_set_severity"));
+}
+
+int sh_suidchk_set_exclude (const char * c)
+{
+ int ret = 0;
+ SL_ENTER(_("sh_suidchk_set_exclude"));
+
+ if (c == NULL || c[0] == '\0')
+ {
+ SL_RETURN(-1, _("sh_suidchk_set_exclude"));
+ }
+
+ if (0 == sl_strncmp(c, _("NULL"), 4))
+ {
+ if (ShSuidchkExclude != NULL)
+ sh_suid_exclude_free();
+ SL_RETURN(0, _("sh_suidchk_set_exclude"));
+ }
+
+ ret = sh_suid_exclude_add(c);
+
+ SL_RETURN(ret, _("sh_suidchk_set_exclude"));
+}
+
+int sh_suidchk_set_timer (const char * c)
+{
+ volatile long val;
+
+ SL_ENTER(_("sh_suidchk_set_timer"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("suidchk timer"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ val = (val <= 0 ? 7200 : val);
+
+ ShSuidchkInterval = (time_t) val;
+ SL_RETURN( 0, _("sh_suidchk_set_timer"));
+}
+
+
+static void sh_suidchk_free_schedule (void)
+{
+ sh_schedule_t * current = ShSuidchkSched;
+ sh_schedule_t * next = NULL;
+
+ while (current != NULL)
+ {
+ next = current->next;
+ SH_FREE(current);
+ current = next;
+ }
+ ShSuidchkSched = NULL;
+ return;
+}
+
+int sh_suidchk_reconf ()
+{
+ SH_MUTEX_LOCK(mutex_suid_check);
+ sh_suidchk_free_schedule();
+ set_defaults();
+ SH_MUTEX_UNLOCK(mutex_suid_check);
+ return 0;
+}
+
+int sh_suidchk_set_schedule (const char * str)
+{
+ int status;
+ sh_schedule_t * newSched = NULL;
+
+ SL_ENTER(_("sh_suidchk_set_schedule"));
+
+ /*
+ if (ShSuidchkSched != NULL)
+ {
+ SH_FREE(ShSuidchkSched);
+ ShSuidchkSched = NULL;
+ }
+ */
+
+ if (0 == sl_strncmp(str, _("NULL"), 4))
+ {
+ (void) sh_suidchk_free_schedule ();
+ return 0;
+ }
+
+ newSched = SH_ALLOC(sizeof(sh_schedule_t));
+ status = create_sched(str, newSched);
+ if (status != 0)
+ {
+ SH_FREE(newSched);
+ newSched = NULL;
+ }
+ else
+ {
+ newSched->next = ShSuidchkSched;
+ ShSuidchkSched = newSched;
+ }
+ SL_RETURN( status, _("sh_suidchk_set_schedule"));
+}
+
+
+
+int sh_suidchk_set_fps (const char * c)
+{
+ volatile long val;
+
+ SL_ENTER(_("sh_suidchk_set_fps"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val < 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("suidchk fps"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ val = (val < 0 ? 0 : val);
+
+ ShSuidchkFps = val;
+ SL_RETURN( 0, _("sh_suidchk_set_fps"));
+}
+
+int sh_suidchk_set_yield (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_suidchk_set_yield"));
+#ifdef HAVE_SCHED_YIELD
+ i = sh_util_flagval(c, &ShSuidchkYield);
+#else
+ (void) c; /* cast to void to avoid compiler warning */
+ i = -1;
+#endif
+ SL_RETURN(i, _("sh_suidchk_set_yield"));
+}
+
+int sh_suidchk_set_activate (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_suidchk_set_activate"));
+ i = sh_util_flagval(c, &ShSuidchkActive);
+ SL_RETURN(i, _("sh_suidchk_set_activate"));
+}
+
+int sh_suidchk_set_nosuid (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_suidchk_set_nosuid"));
+ i = sh_util_flagval(c, &ShSuidchkNosuid);
+ SL_RETURN(i, _("sh_suidchk_set_nosuid"));
+}
+
+int sh_suidchk_set_quarantine (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_suidchk_set_quarantine"));
+ i = sh_util_flagval(c, &ShSuidchkQEnable);
+ SL_RETURN(i, _("sh_suidchk_set_quarantine"));
+}
+
+int sh_suidchk_set_qdelete (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_suidchk_set_qdelete"));
+ i = sh_util_flagval(c, &ShSuidchkQDelete);
+ SL_RETURN(i, _("sh_suidchk_set_qdelete"));
+}
+
+int sh_suidchk_set_qmethod (const char * c)
+{
+ volatile long val;
+ volatile int ret = 0;
+ struct stat buf;
+
+ SL_ENTER(_("sh_suidchk_set_qmethod"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val < 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("suidchk qmethod"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ ret = -1;
+ }
+ else
+ {
+ switch (val)
+ {
+ case SH_Q_DELETE:
+ ShSuidchkQMethod = SH_Q_DELETE;
+ break;
+ case SH_Q_CHANGEPERM:
+ ShSuidchkQMethod = SH_Q_CHANGEPERM;
+ break;
+ case SH_Q_MOVE:
+ if (retry_stat (FIL__, __LINE__, DEFAULT_QDIR, &buf) != 0)
+ {
+ if (mkdir (DEFAULT_QDIR, 0750) == -1)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL,
+ MSG_SUID_ERROR,
+ _("Unable to create quarantine directory"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ }
+ ShSuidchkQMethod = SH_Q_MOVE;
+ break;
+ default:
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("suidchk qmethod"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ ShSuidchkQMethod = -1;
+ ret = -1;
+ break;
+ }
+ }
+
+ SL_RETURN( ret, _("sh_suidchk_set_qmethod"));
+}
+
+#if defined(FSTYPE_STATFS) || defined(FSTYPE_AIX_STATFS)
+/* dirname.c -- return all but the last element in a path
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Return the leading directories part of PATH,
+ allocated with malloc. If out of memory, return 0.
+ Assumes that trailing slashes have already been
+ removed. */
+
+char * sh_dirname (const char * path)
+{
+ char *newpath;
+ char *slash;
+ int length; /* Length of result, not including NUL. */
+
+ slash = strrchr (path, '/');
+ if (slash == NULL)
+ {
+ /* File is in the current directory. */
+ path = ".";
+ length = 1;
+ }
+ else
+ {
+ /* Remove any trailing slashes from the result. */
+ while (slash > path && *slash == '/')
+ --slash;
+
+ length = slash - path + 1;
+ }
+ newpath = (char *) SH_ALLOC (length + 1);
+ if (newpath == NULL)
+ return NULL;
+ strncpy (newpath, path, length);
+ newpath[length] = '\0';
+ return newpath;
+}
+/* #ifdef FSTYPE_STATFS */
+#endif
+
+/* fstype.c -- determine type of filesystems that files are on
+ Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
+
+/* Modified by R. Wichmann:
+ - replaced error() by sh_error_handle()
+ - replaced xstrdup() by sl_strdup()
+ - replaced strstr() by sl_strstr()
+ - some additions to recognize nosuid fs
+*/
+
+/* modetype.h -- file type bits definitions for POSIX systems
+ Requires sys/types.h sys/stat.h.
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* POSIX.1 doesn't mention the S_IFMT bits; instead, it uses S_IStype
+ test macros. To make storing file types more convenient, define
+ them; the values don't need to correspond to what the kernel uses,
+ because of the way we use them. */
+#ifndef S_IFMT /* Doesn't have traditional Unix macros. */
+#define S_IFBLK 1
+#define S_IFCHR 2
+#define S_IFDIR 4
+#define S_IFREG 8
+#ifdef S_ISLNK
+#define S_IFLNK 16
+#endif
+#ifdef S_ISFIFO
+#define S_IFIFO 32
+#endif
+#ifdef S_ISSOCK
+#define S_IFSOCK 64
+#endif
+#endif /* !S_IFMT */
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISREG
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISSOCK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#endif
+
+/* Do the reverse: define the POSIX.1 macros for traditional Unix systems
+ that don't have them. */
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
+#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
+#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
+#endif
+
+
+static char *filesystem_type_uncached (char *path, char *relpath,
+ struct stat *statp);
+
+#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
+static int xatoi (const char *cp);
+#endif
+
+#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+#include <mntent.h>
+#if !defined(MOUNTED)
+# if defined(MNT_MNTTAB) /* HP-UX. */
+# define MOUNTED MNT_MNTTAB
+# endif
+# if defined(MNTTABNAME) /* Dynix. */
+# define MOUNTED MNTTABNAME
+# endif
+#endif
+#endif
+
+#ifdef FSTYPE_GETMNT /* Ultrix. */
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+#endif
+
+#ifdef FSTYPE_USG_STATFS /* SVR3. */
+#include <sys/statfs.h>
+#include <sys/fstyp.h>
+#endif
+
+#ifdef FSTYPE_STATVFS /* SVR4. */
+#include <sys/statvfs.h>
+#include <sys/fstyp.h>
+#endif
+
+#ifdef FSTYPE_STATFS /* 4.4BSD. */
+#include <sys/param.h> /* NetBSD needs this. */
+#include <sys/mount.h>
+
+#ifndef MFSNAMELEN /* NetBSD defines this. */
+static char *
+fstype_to_string (t)
+ short t;
+{
+#ifdef INITMOUNTNAMES /* Defined in 4.4BSD, not in NET/2. */
+ static char *mn[] = INITMOUNTNAMES;
+ if (t >= 0 && t <= MOUNT_MAXTYPE)
+ return mn[t];
+ else
+ return "?";
+#else /* !INITMOUNTNAMES */
+ switch (t)
+ {
+#ifdef MOUNT_UFS
+ case MOUNT_UFS:
+ return _("ufs");
+#endif
+#ifdef MOUNT_ISO9660
+ case MOUNT_ISO9660:
+ return _("iso9660fs");
+#endif
+#ifdef MOUNT_CD9660
+ case MOUNT_CD9660:
+ return _("cd9660");
+#endif
+#ifdef MOUNT_NFS
+ case MOUNT_NFS:
+ return _("nfs");
+#endif
+#ifdef MOUNT_PC
+ case MOUNT_PC:
+ return _("pc");
+#endif
+#ifdef MOUNT_MFS
+ case MOUNT_MFS:
+ return _("mfs");
+#endif
+#ifdef MOUNT_LO
+ case MOUNT_LO:
+ return _("lofs");
+#endif
+#ifdef MOUNT_TFS
+ case MOUNT_TFS:
+ return _("tfs");
+#endif
+#ifdef MOUNT_TMP
+ case MOUNT_TMP:
+ return _("tmp");
+#endif
+#ifdef MOUNT_MSDOS
+ case MOUNT_MSDOS:
+ return _("msdos");
+#endif
+#ifdef MOUNT_LFS
+ case MOUNT_LFS:
+ return _("lfs");
+#endif
+#ifdef MOUNT_LOFS
+ case MOUNT_LOFS:
+ return _("lofs");
+#endif
+#ifdef MOUNT_FDESC
+ case MOUNT_FDESC:
+ return _("fdesc");
+#endif
+#ifdef MOUNT_PORTAL
+ case MOUNT_PORTAL:
+ return _("portal");
+#endif
+#ifdef MOUNT_NULL
+ case MOUNT_NULL:
+ return _("null");
+#endif
+#ifdef MOUNT_UMAP
+ case MOUNT_UMAP:
+ return _("umap");
+#endif
+#ifdef MOUNT_KERNFS
+ case MOUNT_KERNFS:
+ return _("kernfs");
+#endif
+#ifdef MOUNT_PROCFS
+ case MOUNT_PROCFS:
+ return _("procfs");
+#endif
+#ifdef MOUNT_DEVFS
+ case MOUNT_DEVFS:
+ return _("devfs");
+#endif
+#ifdef MOUNT_EXT2FS
+ case MOUNT_EXT2FS:
+ return _("ext2fs");
+#endif
+#ifdef MOUNT_UNION
+ case MOUNT_UNION:
+ return _("union");
+#endif
+ default:
+ return "?";
+ }
+#endif /* !INITMOUNTNAMES */
+}
+#endif /* !MFSNAMELEN */
+#endif /* FSTYPE_STATFS */
+
+#ifdef FSTYPE_AIX_STATFS /* AIX. */
+#include <sys/vmount.h>
+#include <sys/statfs.h>
+
+#define FSTYPE_STATFS /* Otherwise like 4.4BSD. */
+#define f_type f_vfstype
+
+static char *
+fstype_to_string (t)
+ short t;
+{
+ switch (t)
+ {
+ case MNT_AIX:
+ return _("aix"); /* AIX 4.3: NFS filesystems are actually MNT_AIX. */
+#ifdef MNT_NAMEFS
+ case MNT_NAMEFS:
+ return _("namefs");
+#endif
+ case MNT_NFS:
+ return _("nfs");
+ case MNT_JFS:
+ return _("jfs");
+ case MNT_CDROM:
+ return _("cdrom");
+#ifdef MNT_PROCFS
+ case MNT_PROCFS:
+ return _("procfs");
+#endif
+#ifdef MNT_SFS
+ case MNT_SFS:
+ return _("sfs");
+#endif
+#ifdef MNT_CACHEFS
+ case MNT_CACHEFS:
+ return _("cachefs");
+#endif
+#ifdef MNT_NFS3
+ case MNT_NFS3:
+ return _("nfs3");
+#endif
+#ifdef MNT_AUTOFS
+ case MNT_AUTOFS:
+ return _("autofs");
+#endif
+#ifdef MNT_VXFS
+ case MNT_VXFS:
+ return _("vxfs");
+#endif
+#ifdef MNT_VXODM
+ case MNT_VXODM:
+ return _("veritasfs");
+#endif
+#ifdef MNT_UDF
+ case MNT_UDF:
+ return _("udfs");
+#endif
+#ifdef MNT_NFS4
+ case MNT_NFS4:
+ return _("nfs4");
+#endif
+#ifdef MNT_RFS4
+ case MNT_RFS4:
+ return _("nfs4");
+#endif
+#ifdef MNT_CIFS
+ case MNT_CIFS:
+ return _("cifs");
+#endif
+ default:
+ return "?";
+ }
+}
+#endif /* FSTYPE_AIX_STATFS */
+
+#ifdef AFS
+#include <netinet/in.h>
+#include <afs/venus.h>
+#if __STDC__
+/* On SunOS 4, afs/vice.h defines this to rely on a pre-ANSI cpp. */
+#undef _VICEIOCTL
+#define _VICEIOCTL(id) ((unsigned int ) _IOW('V', id, struct ViceIoctl))
+#endif
+#ifndef _IOW
+/* AFS on Solaris 2.3 doesn't get this definition. */
+#include <sys/ioccom.h>
+#endif
+
+static int
+in_afs (path)
+ char *path;
+{
+ static char space[2048];
+ struct ViceIoctl vi;
+
+ vi.in_size = 0;
+ vi.out_size = sizeof (space);
+ vi.out = space;
+
+ if (pioctl (path, VIOC_FILE_CELL_NAME, &vi, 1)
+ && (errno == EINVAL || errno == ENOENT))
+ return 0;
+ return 1;
+}
+#endif /* AFS */
+
+/* Nonzero if the current filesystem's type is known. */
+static int fstype_known = 0;
+
+/* Return a static string naming the type of filesystem that the file PATH,
+ described by STATP, is on.
+ RELPATH is the file name relative to the current directory.
+ Return "unknown" if its filesystem type is unknown. */
+
+static char *
+filesystem_type (char * path, char * relpath, struct stat * statp)
+{
+ static char *current_fstype = NULL;
+ static dev_t current_dev;
+
+ if (current_fstype != NULL)
+ {
+ if ((0 != fstype_known) && statp->st_dev == current_dev)
+ return current_fstype; /* Cached value. */
+ SH_FREE (current_fstype);
+ }
+ current_dev = statp->st_dev;
+ current_fstype = filesystem_type_uncached (path, relpath, statp);
+ return current_fstype;
+}
+
+/* Return a newly allocated string naming the type of filesystem that the
+ file PATH, described by STATP, is on.
+ RELPATH is the file name relative to the current directory.
+ Return "unknown" if its filesystem type is unknown. */
+
+void * sh_dummy_2229_type;
+
+static char *
+filesystem_type_uncached (path, relpath, statp)
+ char *path;
+ char *relpath;
+ struct stat *statp;
+{
+ char * type = NULL;
+#ifdef MFSNAMELEN /* NetBSD. */
+ static char my_tmp_type[64];
+#endif
+
+#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+ char *table = MOUNTED;
+ FILE *mfp;
+ struct mntent *mnt;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_2229_type = (void *) &type;
+
+ if (path == NULL || relpath == NULL)
+ return NULL;
+
+ mfp = setmntent (table, "r");
+ if (mfp == NULL)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("setmntent() failed"),
+ _("filesystem_type_uncached") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return NULL;
+ }
+
+ /* Find the entry with the same device number as STATP, and return
+ that entry's fstype. */
+ while (type == NULL && (mnt = getmntent (mfp)) != NULL)
+ {
+ const char *devopt;
+ dev_t dev;
+ struct stat disk_stats;
+
+#ifdef MNTTYPE_IGNORE
+ if (0 == strcmp (mnt->mnt_type, MNTTYPE_IGNORE))
+ continue;
+#endif
+
+ /* Newer systems like SunOS 4.1 keep the dev number in the mtab,
+ in the options string. For older systems, we need to stat the
+ directory that the filesystem is mounted on to get it.
+
+ Unfortunately, the HPUX 9.x mnttab entries created by automountq
+ contain a dev= option but the option value does not match the
+ st_dev value of the file (maybe the lower 16 bits match?). */
+
+#if !defined(hpux) && !defined(__hpux__)
+ devopt = sl_strstr (mnt->mnt_opts, "dev=");
+ if (devopt)
+ {
+ if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
+ dev = (dev_t) xatoi (devopt + 6);
+ else
+ dev = (dev_t) xatoi (devopt + 4);
+ }
+ else
+#endif /* not hpux */
+ {
+ if (stat (mnt->mnt_dir, &disk_stats) == -1)
+ {
+ char errmsg[256];
+ volatile int elevel = SH_ERR_ERR;
+ size_t tlen = strlen(mnt->mnt_dir);
+
+ if (tlen >= 6 && 0 == strcmp(&((mnt->mnt_dir)[tlen-6]), _("/.gvfs")))
+ elevel = SH_ERR_NOTICE;
+ else if (tlen >= 5 && 0 == strcmp(&((mnt->mnt_dir)[tlen-5]), _("/gvfs")))
+ elevel = SH_ERR_NOTICE;
+
+ sl_snprintf(errmsg, sizeof(errmsg), _("stat(%s) failed"),
+ mnt->mnt_dir);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (elevel, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errmsg,
+ _("filesystem_type_uncached") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return NULL;
+ }
+ dev = disk_stats.st_dev;
+ }
+
+ if (dev == statp->st_dev)
+ {
+ /* check for the "nosuid" option
+ */
+#ifdef HAVE_HASMNTOPT
+ if (NULL == hasmntopt(mnt, "nosuid") || (ShSuidchkNosuid == S_TRUE))
+ type = mnt->mnt_type;
+ else
+ type = _("nosuid"); /* hasmntopt (nosuid) */
+#else
+ type = mnt->mnt_type;
+#endif
+ }
+ }
+
+ if (endmntent (mfp) == 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("endmntent() failed"),
+ _("filesystem_type_uncached") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+#endif
+
+#ifdef FSTYPE_GETMNT /* Ultrix. */
+ int offset = 0;
+ struct fs_data fsd;
+
+ if (path == NULL || relpath == NULL)
+ return NULL;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_2229_type = (void*) &type;
+
+ while (type == NULL
+ && getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, 0) > 0)
+ {
+ if (fsd.fd_req.dev == statp->st_dev)
+ type = gt_names[fsd.fd_req.fstype];
+ }
+#endif
+
+#ifdef FSTYPE_USG_STATFS /* SVR3. */
+ struct statfs fss;
+ char typebuf[FSTYPSZ];
+
+ if (path == NULL || relpath == NULL)
+ return NULL;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_2229_type = (void*) &type;
+
+ if (statfs (relpath, &fss, sizeof (struct statfs), 0) == -1)
+ {
+ /* Don't die if a file was just removed. */
+ if (errno != ENOENT)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("statfs() failed"),
+ _("filesystem_type_uncached") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return NULL;
+ }
+ }
+ else if (!sysfs (GETFSTYP, fss.f_fstyp, typebuf))
+ type = typebuf;
+#endif
+
+#ifdef FSTYPE_STATVFS /* SVR4. */
+ struct statvfs fss;
+
+ if (path == NULL || relpath == NULL)
+ return NULL;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_2229_type = (void*) &type;
+
+ if (statvfs (relpath, &fss) == -1)
+ {
+ /* Don't die if a file was just removed. */
+ if (errno != ENOENT)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("statvfs() failed"),
+ _("filesystem_type_uncached") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return NULL;
+ }
+ }
+ else
+ {
+ type = fss.f_basetype;
+
+ /* patch by Konstantin Khrooschev <nathoo@co.ru>
+ */
+ if( (fss.f_flag & ST_NOSUID) && (ShSuidchkNosuid == S_FALSE))
+ type = _("nosuid");
+ }
+ (void) statp; /* fix compiler warning */
+#endif
+
+#ifdef FSTYPE_STATFS /* 4.4BSD. */
+ struct statfs fss;
+ char *p;
+#if defined(MNT_VISFLAGMASK) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
+ int flags;
+#endif
+ /* char * sh_dirname(const char *path); */
+
+ if (path == NULL || relpath == NULL)
+ return NULL;
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_2229_type = (void*) &type;
+
+ if (S_ISLNK (statp->st_mode))
+ p = sh_dirname (relpath);
+ else
+ p = relpath;
+
+ if (statfs (p, &fss) == -1)
+ {
+ /* Don't die if symlink to nonexisting file, or a file that was
+ just removed. */
+ if (errno != ENOENT)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ _("statfs() failed"),
+ _("filesystem_type_uncached") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ return NULL;
+ }
+ }
+ else
+ {
+
+#ifdef MFSNAMELEN /* NetBSD. */
+ /* MEMORY LEAK !!!
+ * type = sh_util_strdup (fss.f_fstypename);
+ */
+ sl_strlcpy (my_tmp_type, fss.f_fstypename, 64);
+ type = my_tmp_type;
+#else
+ type = fstype_to_string (fss.f_type);
+#endif
+
+#ifdef HAVE_STRUCT_STATFS_F_FLAGS
+#ifdef MNT_VISFLAGMASK
+ flags = fss.f_flags & MNT_VISFLAGMASK;
+ if ((flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
+#else
+ if ((fss.f_flags & MNT_NOSUID) && (ShSuidchkNosuid == S_FALSE))
+#endif
+ type = _("nosuid");
+#endif
+ }
+ if (p != relpath)
+ SH_FREE (p);
+#endif
+
+#ifdef AFS
+ if ((!type || !strcmp (type, "xx")) && in_afs (relpath))
+ type = "afs";
+#endif
+
+ /* An unknown value can be caused by an ENOENT error condition.
+ Don't cache those values. */
+ fstype_known = (int)(type != NULL);
+
+ return sh_util_strdup (type ? type : "unknown");
+}
+
+#ifdef FSTYPE_MNTENT /* 4.3BSD etc. */
+/* Return the value of the hexadecimal number represented by CP.
+ No prefix (like '0x') or suffix (like 'h') is expected to be
+ part of CP. */
+
+static int
+xatoi (cp)
+ const char *cp;
+{
+ int val;
+
+ val = 0;
+ while (*cp != '\0')
+ {
+ /*@+charint@*/
+ if (*cp >= 'a' && *cp <= 'f')
+ val = val * 16 + *cp - 'a' + 10;
+ else if (*cp >= 'A' && *cp <= 'F')
+ val = val * 16 + *cp - 'A' + 10;
+ else if (*cp >= '0' && *cp <= '9')
+ val = val * 16 + *cp - '0';
+ else
+ break;
+ /*@-charint@*/
+ cp++;
+ }
+ return val;
+}
+#endif
+
+
+
+#endif
+
+
+/* #ifdef SH_USE_UTMP */
+#endif
+
+
+
diff --git a/src/sh_tiger0.c b/src/sh_tiger0.c
new file mode 100644
index 0000000..aea8158
--- /dev/null
+++ b/src/sh_tiger0.c
@@ -0,0 +1,1866 @@
+#include "config_xor.h"
+
+#define USE_MD5
+#define USE_SHA1
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#include "sh_tiger.h"
+
+#include "sh_unix.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_pthread.h"
+#include "sh_string.h"
+
+#define PRIV_MAX 32768
+
+#if defined(TIGER_64_BIT)
+#if defined(HAVE_LONG_64)
+typedef unsigned long int word64;
+#elif defined(HAVE_LONG_LONG_64)
+typedef unsigned long long int word64;
+#else
+#error No 64 bit type found !
+#endif
+#endif
+
+#if defined(HAVE_INT_32)
+typedef unsigned int sh_word32;
+#define MYFORMAT (_("%08X%08X%08X%08X%08X%08X"))
+#define GPGFORMAT (_("%08X %08X %08X %08X %08X %08X"))
+#elif defined(HAVE_LONG_32)
+typedef unsigned long sh_word32;
+#define MYFORMAT (_("%08lX%08lX%08lX%08lX%08lX%08lX"))
+#define GPGFORMAT (_("%08lX %08lX %08lX %08lX %08lX %08lX"))
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short sh_word32;
+#define MYFORMAT (_("%08X%08X%08X%08X%08X%08X"))
+#define GPGFORMAT (_("%08X %08X %08X %08X %08X %08X"))
+#else
+#error No 32 bit type found !
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#undef SH_GNUC_ALIGN8
+#define SH_GNUC_ALIGN8 __attribute__((aligned(8)))
+#else
+#undef SH_GNUC_ALIGN8
+#define SH_GNUC_ALIGN8
+#endif
+
+
+typedef unsigned char sh_byte;
+
+#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
+
+#undef FIL__
+#define FIL__ _("sh_tiger0.c")
+
+#if defined(TIGER_64_BIT)
+
+void tiger_t(const word64 *str, word64 length, word64 * res);
+void tiger(const word64 *str, word64 length, word64 * res);
+
+#ifdef TIGER_DBG
+static void tiger_dbg(word64 res[3], int step,
+ unsigned long nblocks, unsigned long ncount)
+{
+ return;
+}
+#endif
+#else
+void tiger(const sh_word32 *str, sh_word32 length, sh_word32 * res);
+void tiger_t(const sh_word32 *str, sh_word32 length, sh_word32 * res);
+
+#ifdef TIGER_DBG
+static
+void tiger_dbg(sh_word32 res[6], int step,
+ unsigned long nblocks, unsigned long ncount)
+{
+ fprintf(stderr,
+ _("ST %d BLK %2ld CT %2ld %08lX %08lX %08lX %08lX %08lX %08lX\n"),
+ step,
+ nblocks,
+ ncount,
+ (sh_word32)(res[1]),
+ (sh_word32)(res[0]),
+ (sh_word32)(res[3]),
+ (sh_word32)(res[2]),
+ (sh_word32)(res[5]),
+ (sh_word32)(res[4]) );
+}
+#endif
+#endif
+
+/* this is the wrapper function -- not part of the tiger reference
+ * implementation
+ */
+
+/* static sh_byte buffer[PRIV_MAX + 72]; */
+
+#if defined(TIGER_64_BIT)
+static
+word64 * sh_tiger_hash_val (const char * filename, TigerType what,
+ UINT64 * Length, int timeout, word64 * res)
+#else
+static
+sh_word32 * sh_tiger_hash_val (const char * filename, TigerType what,
+ UINT64 * Length, int timeout, sh_word32 * res)
+#endif
+{
+ SL_TICKET fd;
+ sh_string * content = NULL;
+ int i, j, tt;
+ int count = 0;
+ int blk;
+ char * tmp;
+ sh_byte * bptr;
+ sh_byte SH_GNUC_ALIGN8 bbuf[64];
+ UINT64 bcount = 0;
+
+ sh_byte * buffer = SH_ALLOC(PRIV_MAX + 72);
+
+ unsigned long pages_read;
+ uid_t euid;
+
+ unsigned long ncount = 0, nblocks = 0;
+ unsigned long t, msb, lsb;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ /*@-nestedextern@*/
+ extern long IO_Limit;
+ /*@+nestedextern@*/
+#endif
+
+#if defined(TIGER_64_BIT)
+#define TIGER_CAST (const word64*)
+ /* word64 res[3]; */
+ res[0]= (word64) 0x0123456789ABCDEFLL;
+ res[1]= (word64) 0xFEDCBA9876543210LL;
+ res[2]= (word64) 0xF096A5B4C3B2E187LL;
+#else
+#define TIGER_CAST (const sh_word32*)
+ /* sh_word32 res[6]; */
+ res[0]= (sh_word32) 0x89ABCDEF;
+ res[1]= (sh_word32) 0x01234567;
+ res[2]= (sh_word32) 0x76543210;
+ res[3]= (sh_word32) 0xFEDCBA98;
+ res[4]= (sh_word32) 0xC3B2E187;
+ res[5]= (sh_word32) 0xF096A5B4;
+#endif
+
+ SL_ENTER(_("sh_tiger_hash_val"));
+
+ if (what >= TIGER_FILE)
+ {
+ if (what > TIGER_FILE)
+ {
+ fd = what;
+ content = sl_get_content(fd);
+ TPT((0,FIL__, __LINE__, _("msg=<TIGER_FD>, fd=<%ld>\n"), fd));
+ }
+ else
+ {
+ TPT((0,FIL__, __LINE__, _("msg=<TIGER_FILE>, path=<%s>\n"),
+ (filename == NULL ? _("(null)") : filename) ));
+ fd = sl_open_read (FIL__, __LINE__, filename, SL_YESPRIV);
+ }
+
+ if (SL_ISERROR (fd))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<SL_ISERROR (%ld)>\n"), fd));
+ tmp = sh_util_safe_name (filename);
+ (void) sl_get_euid(&euid);
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, (int)fd,
+ MSG_E_ACCESS, (long) euid, tmp);
+ SH_FREE(tmp);
+ SH_FREE(buffer);
+ *Length = 0;
+ SL_RETURN( NULL, _("sh_tiger_hash_val"));
+ }
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ if (skey->mlock_failed == S_FALSE)
+ {
+ if ( (-1) == sh_unix_mlock(FIL__, __LINE__,
+ (char *)buffer,
+ (PRIV_MAX)*sizeof(sh_byte)))
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ skey->mlock_failed = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+ }
+#else
+ if (skey->mlock_failed == S_FALSE)
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ skey->mlock_failed = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+#endif
+
+#ifdef TIGER_DBG
+ tiger_dbg (res, 0, nblocks, ncount);
+#endif
+
+ pages_read = 0;
+
+ while (1)
+ {
+ if (timeout > 0)
+ count = sl_read_timeout (fd, buffer, PRIV_MAX, timeout, S_TRUE);
+ else
+ count = sl_read (fd, buffer, PRIV_MAX);
+
+ ++pages_read;
+
+ if (SL_ISERROR (count))
+ {
+ int error = errno;
+
+ if (sig_termfast == 1) {
+ sh_unix_munlock((char *)buffer, (PRIV_MAX)*sizeof(sh_byte));
+ SH_FREE(buffer);
+ *Length = 0;
+ SL_RETURN( NULL, _("sh_tiger_hash_val"));
+ }
+ TPT((0, FIL__ , __LINE__ , _("msg=<SL_ISERROR (%ld)>\n"), count));
+ tmp = sh_util_safe_name (filename);
+ if (count == SL_TIMEOUT)
+ {
+ if (timeout != 7) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, count,
+ MSG_E_TIMEOUT, timeout, tmp);
+ }
+ }
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ char errbuf2[SH_ERRBUF_SIZE];
+ sl_strlcpy(errbuf, sl_error_string(count), sizeof(errbuf));
+ sh_error_message(error, errbuf2, sizeof(errbuf2));
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__,
+ count, MSG_E_READ, errbuf, errbuf2, tmp);
+ }
+ SH_FREE(tmp);
+ memset (bbuf, 0, 64);
+ memset (buffer, 0, PRIV_MAX);
+
+ sh_unix_munlock((char *)buffer, (PRIV_MAX)*sizeof(sh_byte));
+ SH_FREE(buffer);
+ *Length = 0;
+ SL_RETURN( NULL, _("sh_tiger_hash_val"));
+ }
+
+ if (content)
+ sh_string_cat_lchar(content, (char*)buffer, count);
+
+ bcount += count;
+
+ if (*Length != TIGER_NOLIM)
+ {
+ if (bcount > *Length)
+ {
+ count = count - (bcount - (*Length));
+ bcount = *Length;
+ count = (count < 0) ? 0 : count;
+ }
+ }
+
+ blk = (count / 64); /* number of 64-byte words */
+
+ /* nblocks += blk; number of 64-byte words
+ * count cannot be negative here, see 'if (SL_ISERROR (count))'
+ */
+ tt = blk*64;
+
+ ncount = (unsigned long) (count - tt);
+
+ nblocks += blk;
+ /* MAY_LOCK */
+ sh.statistics.bytes_hashed += tt;
+
+ tt = 0;
+ for (i = 0; i < blk; ++i)
+ {
+ bptr = &buffer[tt]; tt += 64;
+
+ tiger_t(TIGER_CAST bptr, 64, res);
+
+#ifdef TIGER_DBG
+ tiger_dbg (res, 3, nblocks, ncount);
+#endif
+ }
+
+ if (blk < (PRIV_MAX / 64)) /* this must be (PRIV_MAX / 64) */
+ break;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if (sig_termfast == 1)
+ {
+ memset (bbuf, 0, 64);
+ memset (buffer, 0, PRIV_MAX);
+ sh_unix_munlock((char *)buffer, (PRIV_MAX)*sizeof(sh_byte));
+ SH_FREE(buffer);
+ *Length = 0;
+ SL_RETURN( NULL, _("sh_tiger_hash_val"));
+ }
+ if ((IO_Limit) > 0 && (pages_read == 32)) /* check for I/O limit */
+ {
+ sh_unix_io_pause ();
+ pages_read = 0;
+ }
+#endif
+ }
+
+ TPT((0, FIL__, __LINE__ , _("msg=<Last block.>\n")));
+
+ /* copy incomplete block
+ */
+ j = 0;
+ for (i = 0; i < 64; i += 4)
+ {
+ bbuf[i] = (sh_byte) '\0';
+ bbuf[i+1] = (sh_byte) '\0';
+ bbuf[i+2] = (sh_byte) '\0';
+ bbuf[i+3] = (sh_byte) '\0';
+ }
+ for (i = (count/64) * 64; i < count; ++i)
+ /*@-usedef@*/bbuf[j++] = buffer[i];/*@+usedef@*/
+
+#ifdef TIGER_DBG
+ tiger_dbg (res, 5, nblocks, ncount);
+#endif
+
+ msb = 0;
+ t = nblocks;
+ if( (lsb = t << 6) < t )
+ msb++;
+ msb += t >> 26;
+ t = lsb;
+ if( (lsb = t + ncount) < t )
+ msb++;
+ t = lsb;
+ if( (lsb = t << 3) < t )
+ msb++;
+ msb += t >> 29;
+
+ if( j < 56 )
+ {
+ bbuf[j++] = (sh_byte) 0x01; ++ncount;
+ while( j < 56 )
+ { bbuf[j++] = (sh_byte) 0; ++ncount; }
+ }
+ else
+ {
+ bbuf[j++] = (sh_byte) 0x01;
+ while( j < 64 )
+ bbuf[j++] = (sh_byte) 0;
+ tiger_t(TIGER_CAST bbuf, 64, res);
+ /* MAY_LOCK */
+ sh.statistics.bytes_hashed += 64;
+ ++nblocks;
+#ifdef TIGER_DBG
+ ncount = 0;
+#endif
+ sl_memset(bbuf, 0, 56 );
+ }
+
+#ifdef TIGER_DBG
+ tiger_dbg (res, 6, nblocks, ncount);
+#endif
+
+ bbuf[56] = (sh_byte) (lsb );
+ bbuf[57] = (sh_byte) (lsb >> 8);
+ bbuf[58] = (sh_byte) (lsb >> 16);
+ bbuf[59] = (sh_byte) (lsb >> 24);
+ bbuf[60] = (sh_byte) (msb );
+ bbuf[61] = (sh_byte) (msb >> 8);
+ bbuf[62] = (sh_byte) (msb >> 16);
+ bbuf[63] = (sh_byte) (msb >> 24);
+
+ tiger_t(TIGER_CAST bbuf, 64, res);
+ sh.statistics.bytes_hashed += 64;
+
+#ifdef TIGER_DBG
+ tiger_dbg (res, 7, nblocks, ncount);
+#endif
+
+ sl_memset (bbuf, '\0', sizeof(bbuf));
+ sl_memset (buffer, '\0', sizeof(buffer));
+
+ if (what == TIGER_FILE)
+ (void) sl_close (fd);
+ sh_unix_munlock((char *)buffer, (PRIV_MAX)*sizeof(sh_byte));
+ SH_FREE(buffer);
+ *Length = bcount;
+ SL_RETURN( res, _("sh_tiger_hash_val"));
+ }
+
+ if (what == TIGER_DATA && filename != NULL)
+ {
+ tiger(TIGER_CAST filename, (sh_word32) *Length, res);
+ sh_unix_munlock((char *)buffer, (PRIV_MAX)*sizeof(sh_byte));
+ SH_FREE(buffer);
+ SL_RETURN(res, _("sh_tiger_hash_val"));
+ }
+ sh_unix_munlock((char *)buffer, (PRIV_MAX)*sizeof(sh_byte));
+ SH_FREE(buffer);
+ *Length = 0;
+ SL_RETURN( NULL, _("sh_tiger_hash_val"));
+}
+
+/* Thu Oct 18 18:53:33 CEST 2001
+ */
+
+#ifdef USE_MD5
+/*@-type@*/
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ * according to the definition of MD5 in RFC 1321 from April 1992.
+ * Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ *
+ * NOTE: The canonical source of this file is maintained with the GNU C
+ * Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+/* Hacked to work with samhain by R. Wichmann */
+
+typedef UINT32 md5_uint32;
+
+
+/* Structure to save state of computation between the single steps. */
+typedef struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+} md5Param;
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+static void md5_init_ctx (struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+static void md5_process_block (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+static void md5_process_bytes (const void *buffer, size_t len,
+ struct md5_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf);
+
+#if WORDS_BIGENDIAN
+static md5_uint32 swapu32(md5_uint32 n)
+{
+ return ( ((n & 0xffU) << 24) |
+ ((n & 0xff00U) << 8) |
+ ((n & 0xff0000U) >> 8) |
+ ((n & 0xff000000U) >> 24) );
+}
+#define SWAP(n) swapu32(n)
+#else
+#define SWAP(n) (n)
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+static void md5_init_ctx(struct md5_ctx *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP(ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP(ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP(ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP(ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static void *md5_finish_ctx(struct md5_ctx *ctx, void *resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+ md5_uint32 temp;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy(&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ temp = SWAP(ctx->total[0] << 3);
+ memcpy(&(ctx->buffer[bytes + pad]), &temp, sizeof(temp));
+ temp = SWAP((ctx->total[1] << 3) | (ctx->total[0] >> 29));
+ memcpy(&(ctx->buffer[bytes + pad + 4]), &temp, sizeof(temp));
+
+ /* Process last bytes. */
+ md5_process_block(ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx(ctx, resbuf);
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *md5_buffer(const char *buffer, size_t len, void *resblock)
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx(&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes(buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx(&ctx, resblock);
+}
+
+static void md5_process_bytes(const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0) {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy(&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (left_over + add > 64) {
+ md5_process_block(ctx->buffer, (left_over + add) & ~63, ctx);
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ (left_over + add) & 63);
+ ctx->buflen = (left_over + add) & 63;
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len > 64) {
+ md5_process_block(buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0) {
+ memcpy(ctx->buffer, buffer, len);
+ ctx->buflen = len;
+ }
+}
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof(md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp) {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+ /* Round 1. */
+ OP(A, B, C, D, 7, 0xd76aa478);
+ OP(D, A, B, C, 12, 0xe8c7b756);
+ OP(C, D, A, B, 17, 0x242070db);
+ OP(B, C, D, A, 22, 0xc1bdceee);
+ OP(A, B, C, D, 7, 0xf57c0faf);
+ OP(D, A, B, C, 12, 0x4787c62a);
+ OP(C, D, A, B, 17, 0xa8304613);
+ OP(B, C, D, A, 22, 0xfd469501);
+ OP(A, B, C, D, 7, 0x698098d8);
+ OP(D, A, B, C, 12, 0x8b44f7af);
+ OP(C, D, A, B, 17, 0xffff5bb1);
+ OP(B, C, D, A, 22, 0x895cd7be);
+ OP(A, B, C, D, 7, 0x6b901122);
+ OP(D, A, B, C, 12, 0xfd987193);
+ OP(C, D, A, B, 17, 0xa679438e);
+ OP(B, C, D, A, 22, 0x49b40821);
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP(FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP(FG, D, A, B, C, 10, 9, 0x02441453);
+ OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP(FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP(FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP(FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP(FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP(FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+
+
+/*----------------------------------------------------------------------------
+ *--------end of md5.c
+ *----------------------------------------------------------------------------*/
+
+
+int md5Reset(register md5Param* p)
+{
+ unsigned int i;
+
+ md5_init_ctx(p);
+
+ for (i = 0; i < 16; i += 8)
+ {
+ p->buffer[i] = 0x00;
+ p->buffer[i+1] = 0x00;
+ p->buffer[i+2] = 0x00;
+ p->buffer[i+3] = 0x00;
+ p->buffer[i+4] = 0x00;
+ p->buffer[i+5] = 0x00;
+ p->buffer[i+6] = 0x00;
+ p->buffer[i+7] = 0x00;
+ }
+
+ return 0;
+}
+
+int md5Update(md5Param* p, const sh_byte* data, int size)
+{
+ md5_process_bytes(data, size, p);
+ return 0;
+}
+
+static void md5Finish(md5Param* p, void *resblock)
+{
+ (void) md5_finish_ctx(p, resblock);
+}
+
+int md5Digest(md5Param* p, md5_uint32* data)
+{
+ md5Finish(p, data);
+ (void) md5Reset(p);
+ return 0;
+}
+/*@+type@*/
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+static int md5_stream(char * filename, void *resblock,
+ UINT64 * Length, int timeout, SL_TICKET fd)
+{
+ /* Important: BLOCKSIZE must be a multiple of 64. */
+ static const int BLOCKSIZE = 8192;
+ struct md5_ctx ctx;
+ char * buffer = SH_ALLOC(8264); /* BLOCKSIZE + 72 AIX compiler chokes */
+ size_t sum;
+
+ char * tmp;
+ uid_t euid;
+ UINT64 bcount = 0;
+ sh_string * content;
+
+ unsigned long pages_read;
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ /*@-nestedextern@*/
+ extern long IO_Limit;
+ /*@+nestedextern@*/
+#endif
+
+ /* Initialize the computation context. */
+ (void) md5Reset (&ctx);
+
+ if (SL_ISERROR (fd))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<SL_ISERROR (%ld)>\n"), fd));
+ tmp = sh_util_safe_name (filename);
+ (void) sl_get_euid(&euid);
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, fd,
+ MSG_E_ACCESS, (long) euid, tmp);
+ SH_FREE(tmp);
+ *Length = 0;
+ SH_FREE(buffer);
+ return -1;
+ }
+
+ pages_read = 0;
+
+ content = sl_get_content(fd);
+
+ /* Iterate over full file contents. */
+ while (1) {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ off_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do {
+
+ n = (off_t) sl_read_timeout (fd, buffer + sum,
+ (size_t) BLOCKSIZE - sum, timeout, S_FALSE);
+
+ if (SL_ISERROR (n))
+ {
+ int error = errno;
+
+ if (sig_termfast == 1)
+ {
+ SH_FREE(buffer);
+ return -1;
+ }
+ TPT((0, FIL__ , __LINE__ , _("msg=<SL_ISERROR (%ld)>\n"), n));
+ tmp = sh_util_safe_name (filename);
+ if (n == SL_TIMEOUT)
+ {
+ if (timeout != 7) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, n, MSG_E_TIMEOUT,
+ timeout, tmp);
+ }
+ }
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ char errbuf2[SH_ERRBUF_SIZE];
+ sl_strlcpy(errbuf, sl_error_string(n), sizeof(errbuf));
+ sh_error_message(error, errbuf2, sizeof(errbuf2));
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, n,
+ MSG_E_READ, errbuf, errbuf2, tmp);
+ }
+ SH_FREE(tmp);
+ *Length = 0;
+ SH_FREE(buffer);
+ return -1;
+ }
+
+ if (content)
+ sh_string_cat_lchar(content, buffer, n);
+
+ bcount += n;
+
+ if (*Length != TIGER_NOLIM)
+ {
+ if (bcount > *Length)
+ {
+ n = n - (bcount - (*Length));
+ bcount = *Length;
+ n = (n < 0) ? 0 : n;
+ }
+ }
+
+ sum += n;
+ }
+ while (sum < (size_t) BLOCKSIZE
+ && n != 0);
+
+ ++pages_read;
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block(buffer, BLOCKSIZE, &ctx);
+ sh.statistics.bytes_hashed += BLOCKSIZE;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if ((IO_Limit) > 0 && (pages_read == 32)) /* check for I/O limit */
+ {
+ sh_unix_io_pause ();
+ pages_read = 0;
+ }
+ if (sig_termfast == 1)
+ {
+ *Length = 0;
+ SH_FREE(buffer);
+ return -1;
+ }
+#endif
+ }
+
+ /* Add the last bytes if necessary. */
+ if (sum > 0)
+ {
+ md5_process_bytes(buffer, sum, &ctx);
+ sh.statistics.bytes_hashed += BLOCKSIZE;
+ }
+
+ /* Construct result in desired memory. */
+ (void) md5Digest(&ctx, resblock);
+
+ *Length = bcount;
+ SH_FREE(buffer);
+ return 0;
+}
+
+static
+char * sh_tiger_md5_hash (char * filename, TigerType what,
+ UINT64 * Length, int timeout, char * out, size_t len)
+{
+ int cnt;
+ char outbuf[KEY_LEN+1];
+ unsigned char md5buffer[16];
+
+ (void) md5_stream (filename, md5buffer, Length, timeout, what);
+
+ /*@-bufferoverflowhigh -usedef@*/
+ for (cnt = 0; cnt < 16; ++cnt)
+ sprintf (&outbuf[cnt*2], _("%02X"), /* known to fit */
+ (unsigned int) md5buffer[cnt]);
+ /*@+bufferoverflowhigh +usedef@*/
+ for (cnt = 32; cnt < KEY_LEN; ++cnt)
+ outbuf[cnt] = '0';
+ outbuf[KEY_LEN] = '\0';
+
+ sl_strlcpy(out, outbuf, len);
+ return out;
+}
+
+/* USE_MD5 */
+#endif
+
+/***************************************************************
+ *
+ * SHA1
+ *
+ ***************************************************************/
+
+#ifdef USE_SHA1
+/*@-type@*/
+
+typedef unsigned char sha_word8;
+typedef sh_word32 sha_word32;
+
+/* The SHA block size and message digest sizes, in bytes */
+
+#define SHA_DATASIZE 64
+#define SHA_DATALEN 16
+#define SHA_DIGESTSIZE 20
+#define SHA_DIGESTLEN 5
+/* The structure for storing SHA info */
+
+typedef struct sha_ctx {
+ sha_word32 digest[SHA_DIGESTLEN]; /* Message digest */
+ sha_word32 count_l, count_h; /* 64-bit block count */
+ sha_word8 block[SHA_DATASIZE]; /* SHA data buffer */
+ int index; /* index into buffer */
+} SHA_CTX;
+
+static void sha_init(struct sha_ctx *ctx);
+static void sha_update(struct sha_ctx *ctx, sha_word8 *buffer,sha_word32 len);
+static void sha_final(struct sha_ctx *ctx);
+static void sha_digest(struct sha_ctx *ctx, sha_word8 *s);
+
+
+/* The SHA f()-functions. The f1 and f3 functions can be optimized to
+ save one boolean operation each - thanks to Rich Schroeppel,
+ rcs@cs.arizona.edu for discovering this */
+
+/*#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) // Rounds 0-19 */
+#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
+#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
+/*#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) // Rounds 40-59 */
+#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
+#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
+
+/* The SHA Mysterious Constants */
+
+#define K1 0x5A827999L /* Rounds 0-19 */
+#define K2 0x6ED9EBA1L /* Rounds 20-39 */
+#define K3 0x8F1BBCDCL /* Rounds 40-59 */
+#define K4 0xCA62C1D6L /* Rounds 60-79 */
+
+/* SHA initial values */
+
+#define h0init 0x67452301L
+#define h1init 0xEFCDAB89L
+#define h2init 0x98BADCFEL
+#define h3init 0x10325476L
+#define h4init 0xC3D2E1F0L
+
+/* 32-bit rotate left - kludged with shifts */
+
+#define ROTL(n,X) ( ( (X) << (n) ) | ( (X) >> ( 32 - (n) ) ) )
+
+/* The initial expanding function. The hash function is defined over an
+ 80-word expanded input array W, where the first 16 are copies of the input
+ data, and the remaining 64 are defined by
+
+ W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
+
+ This implementation generates these values on the fly in a circular
+ buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+ optimization.
+
+ The updated SHA changes the expanding function by adding a rotate of 1
+ bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
+ for this information */
+
+#define expand(W,i) ( W[ i & 15 ] = \
+ ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
+ W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
+
+
+/* The prototype SHA sub-round. The fundamental sub-round is:
+
+ a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
+ b' = a;
+ c' = ROTL( 30, b );
+ d' = c;
+ e' = d;
+
+ but this is implemented by unrolling the loop 5 times and renaming the
+ variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
+ This code is then replicated 20 times for each of the 4 functions, using
+ the next 20 values from the W[] array each time */
+
+#define subRound(a, b, c, d, e, f, k, data) \
+ ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
+
+/* Initialize the SHA values */
+
+static void sha_init(struct sha_ctx *ctx)
+{
+ /* Set the h-vars to their initial values */
+ ctx->digest[ 0 ] = h0init;
+ ctx->digest[ 1 ] = h1init;
+ ctx->digest[ 2 ] = h2init;
+ ctx->digest[ 3 ] = h3init;
+ ctx->digest[ 4 ] = h4init;
+
+ /* Initialize bit count */
+ ctx->count_l = ctx->count_h = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+/* Perform the SHA transformation. Note that this code, like MD5, seems to
+ break some optimizing compilers due to the complexity of the expressions
+ and the size of the basic block. It may be necessary to split it into
+ sections, e.g. based on the four subrounds
+
+ Note that this function destroys the data area */
+
+static void sha_transform(struct sha_ctx *ctx, sha_word32 *data )
+{
+ register sha_word32 A, B, C, D, E; /* Local vars */
+
+ /* Set up first buffer and local data buffer */
+ A = ctx->digest[0];
+ B = ctx->digest[1];
+ C = ctx->digest[2];
+ D = ctx->digest[3];
+ E = ctx->digest[4];
+
+ /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+ subRound( A, B, C, D, E, f1, K1, data[ 0] );
+ subRound( E, A, B, C, D, f1, K1, data[ 1] );
+ subRound( D, E, A, B, C, f1, K1, data[ 2] );
+ subRound( C, D, E, A, B, f1, K1, data[ 3] );
+ subRound( B, C, D, E, A, f1, K1, data[ 4] );
+ subRound( A, B, C, D, E, f1, K1, data[ 5] );
+ subRound( E, A, B, C, D, f1, K1, data[ 6] );
+ subRound( D, E, A, B, C, f1, K1, data[ 7] );
+ subRound( C, D, E, A, B, f1, K1, data[ 8] );
+ subRound( B, C, D, E, A, f1, K1, data[ 9] );
+ subRound( A, B, C, D, E, f1, K1, data[10] );
+ subRound( E, A, B, C, D, f1, K1, data[11] );
+ subRound( D, E, A, B, C, f1, K1, data[12] );
+ subRound( C, D, E, A, B, f1, K1, data[13] );
+ subRound( B, C, D, E, A, f1, K1, data[14] );
+ subRound( A, B, C, D, E, f1, K1, data[15] );
+ subRound( E, A, B, C, D, f1, K1, expand( data, 16 ) );
+ subRound( D, E, A, B, C, f1, K1, expand( data, 17 ) );
+ subRound( C, D, E, A, B, f1, K1, expand( data, 18 ) );
+ subRound( B, C, D, E, A, f1, K1, expand( data, 19 ) );
+
+ subRound( A, B, C, D, E, f2, K2, expand( data, 20 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 21 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 22 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 23 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 24 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( data, 25 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 26 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 27 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 28 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 29 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( data, 30 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 31 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 32 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 33 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 34 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( data, 35 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 36 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 37 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 38 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 39 ) );
+
+ subRound( A, B, C, D, E, f3, K3, expand( data, 40 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 41 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 42 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 43 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 44 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( data, 45 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 46 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 47 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 48 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 49 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( data, 50 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 51 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 52 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 53 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 54 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( data, 55 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 56 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 57 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 58 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 59 ) );
+
+ subRound( A, B, C, D, E, f4, K4, expand( data, 60 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 61 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 62 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 63 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 64 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( data, 65 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 66 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 67 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 68 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 69 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( data, 70 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 71 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 72 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 73 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 74 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( data, 75 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 76 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 77 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 78 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 79 ) );
+
+ /* Build message digest */
+ ctx->digest[0] += A;
+ ctx->digest[1] += B;
+ ctx->digest[2] += C;
+ ctx->digest[3] += D;
+ ctx->digest[4] += E;
+}
+
+#if 1
+
+#ifndef EXTRACT_UCHAR
+#define EXTRACT_UCHAR(p) (*(unsigned char *)(p))
+#endif
+
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8) \
+ | EXTRACT_UCHAR(s+1)) << 8) \
+ | EXTRACT_UCHAR(s+2)) << 8) \
+ | EXTRACT_UCHAR(s+3))
+#else
+sha_word32 STRING2INT(word8 *s)
+{
+ sha_word32 r;
+ int i;
+
+ for (i = 0, r = 0; i < 4; i++, s++)
+ r = (r << 8) | *s;
+ return r;
+}
+#endif
+
+static void sha_block(struct sha_ctx *ctx, sha_word8 *block)
+{
+ sha_word32 data[SHA_DATALEN];
+ int i;
+
+ /* Update block count */
+ /*@-boolops@*/
+ if (!++ctx->count_l)
+ ++ctx->count_h;
+ /*@+boolops@*/
+
+ /* Endian independent conversion */
+ for (i = 0; i<SHA_DATALEN; i++, block += 4)
+ data[i] = STRING2INT(block);
+
+ sha_transform(ctx, data);
+}
+
+static void sha_update(struct sha_ctx *ctx, sha_word8 *buffer, sha_word32 len)
+{
+ if (ctx->index != 0)
+ { /* Try to fill partial block */
+ unsigned left = SHA_DATASIZE - ctx->index;
+ if (len < left)
+ {
+ memmove(ctx->block + ctx->index, buffer, len);
+ ctx->index += len;
+ return; /* Finished */
+ }
+ else
+ {
+ memmove(ctx->block + ctx->index, buffer, left);
+ sha_block(ctx, ctx->block);
+ buffer += left;
+ len -= left;
+ }
+ }
+ while (len >= SHA_DATASIZE)
+ {
+ sha_block(ctx, buffer);
+ buffer += SHA_DATASIZE;
+ len -= SHA_DATASIZE;
+ }
+ /*@-predboolint@*/
+ if ((ctx->index = len)) /* This assignment is intended */
+ /*@+predboolint@*/
+ /* Buffer leftovers */
+ memmove(ctx->block, buffer, len);
+}
+
+/* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern
+ 1 0* (64-bit count of bits processed, MSB-first) */
+
+static void sha_final(struct sha_ctx *ctx)
+{
+ sha_word32 data[SHA_DATALEN];
+ int i;
+ int words;
+
+ i = ctx->index;
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ ctx->block[i++] = 0x80;
+
+ /* Fill rest of word */
+ /*@-predboolint@*/
+ for( ; i & 3; i++)
+ ctx->block[i] = 0;
+ /*@+predboolint@*/
+
+ /* i is now a multiple of the word size 4 */
+ /*@-shiftimplementation@*/
+ words = i >> 2;
+ /*@+shiftimplementation@*/
+ for (i = 0; i < words; i++)
+ data[i] = STRING2INT(ctx->block + 4*i);
+
+ if (words > (SHA_DATALEN-2))
+ { /* No room for length in this block. Process it and
+ * pad with another one */
+ for (i = words ; i < SHA_DATALEN; i++)
+ data[i] = 0;
+ sha_transform(ctx, data);
+ for (i = 0; i < (SHA_DATALEN-2); i++)
+ data[i] = 0;
+ }
+ else
+ for (i = words ; i < SHA_DATALEN - 2; i++)
+ data[i] = 0;
+ /* Theres 512 = 2^9 bits in one block */
+ /*@-shiftimplementation@*/
+ data[SHA_DATALEN-2] = (ctx->count_h << 9) | (ctx->count_l >> 23);
+ data[SHA_DATALEN-1] = (ctx->count_l << 9) | (ctx->index << 3);
+ /*@+shiftimplementation@*/
+ sha_transform(ctx, data);
+}
+
+static void sha_digest(struct sha_ctx *ctx, sha_word8 *s)
+{
+ int i;
+
+ for (i = 0; i < SHA_DIGESTLEN; i++)
+ {
+ *s++ = ctx->digest[i] >> 24;
+ *s++ = 0xff & (ctx->digest[i] >> 16);
+ *s++ = 0xff & (ctx->digest[i] >> 8);
+ *s++ = 0xff & ctx->digest[i];
+ }
+}
+/*@+type@*/
+
+#include "sh_checksum.h"
+
+#define SH_VAR_SHA1 0
+#define SH_VAR_SHA256 1
+
+/* Compute SHA1 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+static int SHA_stream(char * filename, void *resblock,
+ UINT64 * Length, int timeout, SL_TICKET fd, int variant)
+{
+ /* Important: BLOCKSIZE must be a multiple of 64. */
+ static const int BLOCKSIZE = 4096;
+ struct sha_ctx ctx;
+ SHA256_CTX ctx_sha2;
+ char * buffer = SH_ALLOC(4168); /* BLOCKSIZE + 72 AIX compiler chokes */
+ off_t sum = 0;
+ char * tmp;
+ uid_t euid;
+ UINT64 bcount = 0;
+ sh_string * content;
+
+ unsigned long pages_read;
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ /*@-nestedextern@*/
+ extern long IO_Limit;
+ /*@+nestedextern@*/
+#endif
+
+ /* Initialize the computation context. */
+ if (variant == SH_VAR_SHA256)
+ (void) SHA256_Init(&ctx_sha2);
+ else
+ (void) sha_init(&ctx);
+
+ if (SL_ISERROR (fd))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<SL_ISERROR (%ld)>\n"), fd));
+ tmp = sh_util_safe_name (filename);
+ (void) sl_get_euid(&euid);
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, fd,
+ MSG_E_ACCESS, (long) euid, tmp);
+ SH_FREE(tmp);
+ *Length = 0;
+ SH_FREE(buffer);
+ return -1;
+ }
+
+ /* Iterate over full file contents. */
+
+ pages_read = 0;
+
+ content = sl_get_content(fd);
+
+ while (1 == 1) {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ off_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do {
+ n = (off_t) sl_read_timeout(fd, buffer + sum,
+ (size_t) BLOCKSIZE - sum, timeout, S_FALSE);
+
+ if (SL_ISERROR (n))
+ {
+ int error = errno;
+
+ if (sig_termfast == 1)
+ {
+ SH_FREE(buffer);
+ return -1;
+ }
+
+ TPT((0, FIL__ , __LINE__ , _("msg=<SL_ISERROR (%ld)>\n"), n));
+ tmp = sh_util_safe_name (filename);
+ if (n == SL_TIMEOUT)
+ {
+ if (timeout != 7) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, n, MSG_E_TIMEOUT,
+ timeout, tmp);
+ }
+ }
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ char errbuf2[SH_ERRBUF_SIZE];
+ sl_strlcpy(errbuf, sl_error_string(n), sizeof(errbuf));
+ sh_error_message(error, errbuf2, sizeof(errbuf2));
+ sh_error_handle (ShDFLevel[SH_ERR_T_FILE], FIL__, __LINE__, n,
+ MSG_E_READ, errbuf, errbuf2, tmp);
+ }
+ SH_FREE(tmp);
+ *Length = 0;
+ SH_FREE(buffer);
+ return -1;
+ }
+
+ if (content)
+ sh_string_cat_lchar(content, buffer, n);
+
+ bcount += n;
+
+ if (*Length != TIGER_NOLIM)
+ {
+ if (bcount > *Length)
+ {
+ n = n - (bcount - (*Length));
+ bcount = *Length;
+ n = (n < 0) ? 0 : n;
+ }
+ }
+
+ sum += n;
+ }
+ while (sum < (off_t)BLOCKSIZE
+ && n != 0);
+
+ ++pages_read;
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ if (variant == SH_VAR_SHA256)
+ SHA256_Update(&ctx_sha2, (sha2_byte*) buffer, (size_t) BLOCKSIZE);
+ else
+ sha_update(&ctx, (sha_word8*) buffer, (sha_word32) BLOCKSIZE);
+ sh.statistics.bytes_hashed += BLOCKSIZE;
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+ if ((IO_Limit) > 0 && (pages_read == 32)) /* check for I/O limit */
+ {
+ sh_unix_io_pause ();
+ pages_read = 0;
+ }
+ if (sig_termfast == 1)
+ {
+ *Length = 0;
+ SH_FREE(buffer);
+ return -1;
+ }
+#endif
+
+ }
+
+ /* Add the last bytes if necessary. */
+ if (sum > 0)
+ {
+ if (variant == SH_VAR_SHA256)
+ SHA256_Update(&ctx_sha2, (sha2_byte*) buffer, (size_t) sum);
+ else
+ sha_update(&ctx, (sha_word8*) buffer, (sha_word32) sum);
+ sh.statistics.bytes_hashed += sum;
+ }
+
+ /* Construct result in desired memory. */
+ if (variant == SH_VAR_SHA256)
+ {
+ SHA256_End(&ctx_sha2, resblock);
+ }
+ else
+ {
+ sha_final (&ctx);
+ sha_digest (&ctx, resblock);
+ }
+
+ *Length = bcount;
+ SH_FREE(buffer);
+ return 0;
+}
+
+
+static char * sh_tiger_sha1_hash (char * filename, TigerType what,
+ UINT64 * Length, int timeout,
+ char * out, size_t len)
+{
+ int cnt;
+ char outbuf[KEY_LEN+1];
+ unsigned char sha1buffer[20];
+
+ (void) SHA_stream (filename, sha1buffer, Length, timeout, what, SH_VAR_SHA1);
+
+ /*@-bufferoverflowhigh -usedef@*/
+ for (cnt = 0; cnt < 20; ++cnt)
+ sprintf (&outbuf[cnt*2], _("%02X"), /* known to fit */
+ (unsigned int) sha1buffer[cnt]);
+ /*@+bufferoverflowhigh +usedef@*/
+ for (cnt = 40; cnt < KEY_LEN; ++cnt)
+ outbuf[cnt] = '0';
+ outbuf[KEY_LEN] = '\0';
+
+ sl_strlcpy(out, outbuf, len);
+ return out;
+}
+
+static char * sh_tiger_sha256_hash (char * filename, TigerType what,
+ UINT64 * Length, int timeout,
+ char * out, size_t len)
+{
+ char outbuf[KEYBUF_SIZE];
+
+ (void) SHA_stream (filename, outbuf, Length, timeout, what, SH_VAR_SHA256);
+
+ sl_strlcpy(out, outbuf, len);
+ return out;
+}
+
+/* ifdef USE_SHA1 */
+#endif
+
+static int hash_type = SH_TIGER192;
+
+int sh_tiger_get_hashtype ()
+{
+ return hash_type;
+}
+
+void sh_tiger_get_mask_hashtype(unsigned long * mask)
+{
+ if (hash_type == SH_TIGER192)
+ *mask |= MODI_TIGER192;
+ else if (hash_type == SH_SHA1)
+ *mask |= MODI_SHA1;
+ else if (hash_type == SH_MD5)
+ *mask |= MODI_MD5;
+ else if (hash_type == SH_SHA256)
+ *mask |= MODI_SHA256;
+ return;
+}
+
+void sh_tiger_set_hashtype_mask(unsigned long mask)
+{
+ unsigned long type = mask & MODI_HASHTYPE;
+
+ if (type == MODI_TIGER192)
+ hash_type = SH_TIGER192;
+ else if (type == MODI_SHA1)
+ hash_type = SH_SHA1;
+ else if (type == MODI_MD5)
+ hash_type = SH_MD5;
+ else if (type == MODI_SHA256)
+ hash_type = SH_SHA256;
+ return;
+}
+
+
+int sh_tiger_hashtype (const char * c)
+{
+ SL_ENTER( _("sh_tiger_hashtype"));
+
+ if (!c)
+ {
+ SL_RETURN( -1, _("sh_tiger_hashtype"));
+ }
+
+ if (0 == strcmp(c, _("TIGER192")))
+ hash_type = SH_TIGER192;
+#ifdef USE_SHA1
+ else if (0 == strcmp(c, _("SHA1")))
+ hash_type = SH_SHA1;
+#endif
+#ifdef USE_MD5
+ else if (0 == strcmp(c, _("MD5")))
+ hash_type = SH_MD5;
+#endif
+#ifdef USE_SHA1
+ else if (0 == strcmp(c, _("SHA256")))
+ hash_type = SH_SHA256;
+#endif
+ else
+ {
+ SL_RETURN( -1, _("sh_tiger_hashtype"));
+ }
+ SL_RETURN( 0, _("sh_tiger_hashtype"));
+}
+
+static char * sh_tiger_hash_internal (const char * filename, TigerType what,
+ UINT64 * Length, int timeout,
+ char * out, size_t len);
+
+char * sh_tiger_hash (const char * filename, TigerType what,
+ UINT64 Length, char * out, size_t len)
+{
+ UINT64 local_length = Length;
+ char * retval = sh_tiger_hash_internal (filename, what, &local_length, 0, out,len);
+ return retval;
+}
+
+char * sh_tiger_generic_hash (char * filename, TigerType what,
+ UINT64 * Length, int timeout,
+ char * out, size_t len)
+{
+#ifdef USE_SHA1
+ if (hash_type == SH_SHA1)
+ return sh_tiger_sha1_hash (filename, what, Length, timeout, out, len);
+#endif
+#ifdef USE_MD5
+ if (hash_type == SH_MD5)
+ return sh_tiger_md5_hash (filename, what, Length, timeout, out, len);
+#endif
+#ifdef USE_SHA1
+ if (hash_type == SH_SHA256)
+ return sh_tiger_sha256_hash (filename, what, Length, timeout, out, len);
+#endif
+ return sh_tiger_hash_internal (filename, what, Length, timeout, out, len);
+}
+
+/*
+ * ------- end new --------- */
+
+static char * sh_tiger_hash_internal (const char * filename, TigerType what,
+ UINT64 * Length, int timeout,
+ char * out, size_t len)
+{
+#if defined(TIGER_64_BIT)
+ word64 res[3];
+#else
+ sh_word32 res[6];
+#endif
+
+ SL_ENTER( _("sh_tiger_hash_internal"));
+
+ SH_VALIDATE_GE(len, (KEY_LEN+1));
+
+ if (NULL != sh_tiger_hash_val (filename, what, Length, timeout, res))
+ {
+#if defined(TIGER_64_BIT)
+ sl_snprintf(out, len,
+ MYFORMAT,
+ (sh_word32)(res[0]>>32),
+ (sh_word32)(res[0]),
+ (sh_word32)(res[1]>>32),
+ (sh_word32)(res[1]),
+ (sh_word32)(res[2]>>32),
+ (sh_word32)(res[2]) );
+#else
+ sl_snprintf(out, len,
+ MYFORMAT,
+ (sh_word32)(res[1]),
+ (sh_word32)(res[0]),
+ (sh_word32)(res[3]),
+ (sh_word32)(res[2]),
+ (sh_word32)(res[5]),
+ (sh_word32)(res[4]) );
+#endif
+ out[len-1] = '\0';
+ SL_RETURN( out, _("sh_tiger_hash_internal"));
+
+ }
+
+ SL_RETURN( SH_KEY_NULL, _("sh_tiger_hash_internal"));
+}
+
+char * sh_tiger_hash_gpg (const char * filename, TigerType what,
+ UINT64 Length)
+{
+ size_t len;
+ char * out;
+ char outhash[48+6+1];
+#if defined(TIGER_64_BIT)
+ word64 res[3];
+#else
+ sh_word32 res[6];
+#endif
+ UINT64 local_length = Length;
+
+ SL_ENTER(_("sh_tiger_hash_gpg"));
+
+ if (NULL != sh_tiger_hash_val (filename, what, &local_length, 0, res))
+ {
+#if defined(TIGER_64_BIT)
+ sl_snprintf(outhash,
+ sizeof(outhash),
+ GPGFORMAT,
+ (sh_word32)(res[0]>>32),
+ (sh_word32)(res[0]),
+ (sh_word32)(res[1]>>32),
+ (sh_word32)(res[1]),
+ (sh_word32)(res[2]>>32),
+ (sh_word32)(res[2]) );
+#else
+ sl_snprintf(outhash,
+ sizeof(outhash),
+ GPGFORMAT,
+ (sh_word32)(res[1]),
+ (sh_word32)(res[0]),
+ (sh_word32)(res[3]),
+ (sh_word32)(res[2]),
+ (sh_word32)(res[5]),
+ (sh_word32)(res[4]) );
+#endif
+ outhash[sizeof(outhash)-1] = '\0';
+ }
+ else
+ {
+ sl_strlcpy(outhash,
+ _("00000000 00000000 00000000 00000000 00000000 00000000"),
+ sizeof(outhash));
+ }
+
+ if (what == TIGER_FILE && sl_ok_adds(sl_strlen (filename), (2 + 48 + 6)))
+ len = sl_strlen (filename) + 2 + 48 + 6;
+ else
+ len = 48 + 6;
+
+ out = SH_ALLOC(len + 1);
+
+ if (what == TIGER_FILE)
+ {
+ (void) sl_strlcpy (out, filename, len+1);
+ (void) sl_strlcat (out, _(": "), len+1);
+ (void) sl_strlcat (out, outhash, len+1);
+ }
+ else
+ {
+ (void) sl_strlcpy (out, outhash, len+1);
+ }
+ SL_RETURN( out, _("sh_tiger_hash_gpg"));
+}
+
+
+UINT32 * sh_tiger_hash_uint32 (char * filename,
+ TigerType what,
+ UINT64 Length, UINT32 * out, size_t len)
+{
+#if defined(TIGER_64_BIT)
+ word64 res[3];
+#else
+ sh_word32 res[6];
+#endif
+ UINT64 local_length = Length;
+
+ SL_ENTER(_("sh_tiger_hash_uint32"));
+
+ SH_VALIDATE_GE(len, 6);
+
+ out[0] = 0; out[1] = 0; out[2] = 0;
+ out[3] = 0; out[4] = 0; out[5] = 0;
+
+ if (NULL != sh_tiger_hash_val (filename, what, &local_length, 0, res))
+ {
+#if defined(TIGER_64_BIT)
+ out[0] = (UINT32)(res[0]>>32);
+ out[1] = (UINT32)(res[0]);
+ out[2] = (UINT32)(res[1]>>32);
+ out[3] = (UINT32)(res[1]);
+ out[4] = (UINT32)(res[2]>>32);
+ out[5] = (UINT32)(res[2]);
+#else
+ out[0] = (UINT32)(res[1]);
+ out[1] = (UINT32)(res[0]);
+ out[2] = (UINT32)(res[3]);
+ out[3] = (UINT32)(res[2]);
+ out[4] = (UINT32)(res[5]);
+ out[5] = (UINT32)(res[4]);
+#endif
+ }
+
+ SL_RETURN(out, _("sh_tiger_hash_uint32"));
+}
+
+
+
+
diff --git a/src/sh_tiger1.c b/src/sh_tiger1.c
new file mode 100644
index 0000000..b29c009
--- /dev/null
+++ b/src/sh_tiger1.c
@@ -0,0 +1,349 @@
+/* Do not include ANY system headers here. The implementation is */
+/* somehow flawed - maybe something gets overlayed by definitions */
+/* in the system headers. Results will become incorrect. */
+
+#include "config_xor.h"
+
+/* we already inline in the function used for file checksums */
+/* #define UNROLL_COMPRESS */
+#undef UNROLL_COMPRESS
+
+#if !defined(TIGER_64_BIT)
+
+/* Tiger: A Fast New Hash Function
+ *
+ * Ross Anderson and Eli Biham
+ *
+ * From the homepage (http://www.cs.technion.ac.il/~biham/Reports/Tiger/):
+ *
+ * Tiger has no usage restrictions nor patents. It can be used freely,
+ * with the reference implementation, with other implementations or with
+ * a modification to the reference implementation (as long as it still
+ * implements Tiger). We only ask you to let us know about your
+ * implementation and to cite the origin of Tiger and of the reference
+ * implementation.
+ *
+ *
+ * The authors' home pages can be found both in
+ * http://www.cs.technion.ac.il/~biham/ and in
+ * http://www.cl.cam.ac.uk/users/rja14/.
+ * The authors' email addresses are biham@cs.technion.ac.il
+ * and rja14@cl.cam.ac.uk.
+ */
+
+
+#if defined(HAVE_INT_32)
+typedef unsigned int sh_word32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long sh_word32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short sh_word32;
+#else
+#error No 32 bit type found !
+#endif
+
+typedef unsigned char sh_byte;
+
+/* Big endian: */
+#ifdef WORDS_BIGENDIAN
+#define BIG_ENDIAN
+#endif
+
+/* The number of passes of the hash function. */
+/* Three passes are recommended. */
+/* Use four passes when you need extra security. */
+/* Must be at least three. */
+#define PASSES 3
+
+extern sh_word32 tiger_table[4*256][2];
+
+#define t1 (tiger_table)
+#define t2 (tiger_table+256)
+#define t3 (tiger_table+256*2)
+#define t4 (tiger_table+256*3)
+
+#define sub64(s0, s1, p0, p1) \
+ temps0 = (p0); \
+ tcarry = s0 < temps0; \
+ s0 -= temps0; \
+ s1 -= (p1) + tcarry;
+
+#define add64(s0, s1, p0, p1) \
+ temps0 = (p0); \
+ s0 += temps0; \
+ tcarry = s0 < temps0; \
+ s1 += (p1) + tcarry;
+
+#define xor64(s0, s1, p0, p1) \
+ s0 ^= (p0); \
+ s1 ^= (p1);
+
+#define mul5(s0, s1) \
+ tempt0 = s0<<2; \
+ tempt1 = (s1<<2)|(s0>>30); \
+ add64(s0, s1, tempt0, tempt1);
+
+#define mul7(s0, s1) \
+ tempt0 = s0<<3; \
+ tempt1 = (s1<<3)|(s0>>29); \
+ sub64(tempt0, tempt1, s0, s1); \
+ s0 = tempt0; \
+ s1 = tempt1;
+
+#define mul9(s0, s1) \
+ tempt0 = s0<<3; \
+ tempt1 = (s1<<3)|(s0>>29); \
+ add64(s0, s1, tempt0, tempt1);
+
+#define save_abc \
+ aa0 = a0; \
+ aa1 = a1; \
+ bb0 = b0; \
+ bb1 = b1; \
+ cc0 = c0; \
+ cc1 = c1;
+
+#define roundX(a0,a1,b0,b1,c0,c1,x0,x1) \
+ xor64(c0, c1, x0, x1); \
+ temp0 = t1[((c0)>>(0*8))&0xFF][0] ; \
+ temp1 = t1[((c0)>>(0*8))&0xFF][1] ; \
+ temp0 ^= t2[((c0)>>(2*8))&0xFF][0] ; \
+ temp1 ^= t2[((c0)>>(2*8))&0xFF][1] ; \
+ temp0 ^= t3[((c1)>>(0*8))&0xFF][0] ; \
+ temp1 ^= t3[((c1)>>(0*8))&0xFF][1] ; \
+ temp0 ^= t4[((c1)>>(2*8))&0xFF][0] ; \
+ temp1 ^= t4[((c1)>>(2*8))&0xFF][1] ; \
+ sub64(a0, a1, temp0, temp1); \
+ temp0 = t4[((c0)>>(1*8))&0xFF][0] ; \
+ temp1 = t4[((c0)>>(1*8))&0xFF][1] ; \
+ temp0 ^= t3[((c0)>>(3*8))&0xFF][0] ; \
+ temp1 ^= t3[((c0)>>(3*8))&0xFF][1] ; \
+ temp0 ^= t2[((c1)>>(1*8))&0xFF][0] ; \
+ temp1 ^= t2[((c1)>>(1*8))&0xFF][1] ; \
+ temp0 ^= t1[((c1)>>(3*8))&0xFF][0] ; \
+ temp1 ^= t1[((c1)>>(3*8))&0xFF][1] ; \
+ add64(b0, b1, temp0, temp1);
+
+
+#define round5(a0,a1,b0,b1,c0,c1,x0,x1) \
+ roundX(a0,a1,b0,b1,c0,c1,x0,x1); \
+ mul5(b0, b1);
+
+#define round7(a0,a1,b0,b1,c0,c1,x0,x1) \
+ roundX(a0,a1,b0,b1,c0,c1,x0,x1); \
+ mul7(b0, b1);
+
+#define round9(a0,a1,b0,b1,c0,c1,x0,x1) \
+ roundX(a0,a1,b0,b1,c0,c1,x0,x1); \
+ mul9(b0, b1);
+
+
+/* mixed with key_schedule
+ */
+#define pass5(a0,a1,b0,b1,c0,c1) \
+ round5(a0,a1,b0,b1,c0,c1,x00,x01); \
+ sub64(x00, x01, x70^0xA5A5A5A5, x71^0xA5A5A5A5); \
+ round5(b0,b1,c0,c1,a0,a1,x10,x11); \
+ xor64(x10, x11, x00, x01); \
+ round5(c0,c1,a0,a1,b0,b1,x20,x21); \
+ add64(x20, x21, x10, x11); \
+ round5(a0,a1,b0,b1,c0,c1,x30,x31); \
+ sub64(x30, x31, x20^((~x10)<<19), ~x21^(((x11)<<19)|((x10)>>13))); \
+ round5(b0,b1,c0,c1,a0,a1,x40,x41); \
+ xor64(x40, x41, x30, x31); \
+ round5(c0,c1,a0,a1,b0,b1,x50,x51); \
+ add64(x50, x51, x40, x41); \
+ round5(a0,a1,b0,b1,c0,c1,x60,x61); \
+ sub64(x60, x61, ~x50^(((x40)>>23)|((x41)<<9)), x51^((~x41)>>23)); \
+ round5(b0,b1,c0,c1,a0,a1,x70,x71);
+
+/* mixed with key_schedule
+ */
+#define pass7(a0,a1,b0,b1,c0,c1) \
+ round7(a0,a1,b0,b1,c0,c1,x00,x01); \
+ sub64(x00, x01, x70^0xA5A5A5A5, x71^0xA5A5A5A5); \
+ round7(b0,b1,c0,c1,a0,a1,x10,x11); \
+ xor64(x10, x11, x00, x01); \
+ round7(c0,c1,a0,a1,b0,b1,x20,x21); \
+ add64(x20, x21, x10, x11); \
+ round7(a0,a1,b0,b1,c0,c1,x30,x31); \
+ sub64(x30, x31, x20^((~x10)<<19), ~x21^(((x11)<<19)|((x10)>>13))); \
+ round7(b0,b1,c0,c1,a0,a1,x40,x41); \
+ xor64(x40, x41, x30, x31); \
+ round7(c0,c1,a0,a1,b0,b1,x50,x51); \
+ add64(x50, x51, x40, x41); \
+ round7(a0,a1,b0,b1,c0,c1,x60,x61); \
+ sub64(x60, x61, ~x50^(((x40)>>23)|((x41)<<9)), x51^((~x41)>>23)); \
+ round7(b0,b1,c0,c1,a0,a1,x70,x71);
+
+/* mixed with key_schedule
+ */
+#define pass9(a0,a1,b0,b1,c0,c1) \
+ round9(a0,a1,b0,b1,c0,c1,x00,x01); \
+ sub64(x00, x01, x70^0xA5A5A5A5, x71^0xA5A5A5A5); \
+ round9(b0,b1,c0,c1,a0,a1,x10,x11); \
+ xor64(x10, x11, x00, x01); \
+ round9(c0,c1,a0,a1,b0,b1,x20,x21); \
+ add64(x20, x21, x10, x11); \
+ round9(a0,a1,b0,b1,c0,c1,x30,x31); \
+ sub64(x30, x31, x20^((~x10)<<19), ~x21^(((x11)<<19)|((x10)>>13))); \
+ round9(b0,b1,c0,c1,a0,a1,x40,x41); \
+ xor64(x40, x41, x30, x31); \
+ round9(c0,c1,a0,a1,b0,b1,x50,x51); \
+ add64(x50, x51, x40, x41); \
+ round9(a0,a1,b0,b1,c0,c1,x60,x61); \
+ sub64(x60, x61, ~x50^(((x40)>>23)|((x41)<<9)), x51^((~x41)>>23)); \
+ round9(b0,b1,c0,c1,a0,a1,x70,x71);
+
+#define key_schedule \
+ xor64(x70, x71, x60, x61); \
+ add64(x00, x01, x70, x71); \
+ sub64(x10, x11, x00^((~x70)<<19), ~x01^(((x71)<<19)|((x70)>>13))); \
+ xor64(x20, x21, x10, x11); \
+ add64(x30, x31, x20, x21); \
+ sub64(x40, x41, ~x30^(((x20)>>23)|((x21)<<9)), x31^((~x21)>>23)); \
+ xor64(x50, x51, x40, x41); \
+ add64(x60, x61, x50, x51); \
+ sub64(x70, x71, x60^0x89ABCDEF, x61^0x01234567);
+
+#define feedforward \
+ xor64(a0, a1, aa0, aa1); \
+ sub64(b0, b1, bb0, bb1); \
+ add64(c0, c1, cc0, cc1);
+
+#define compress \
+ pass5(a0,a1,b0,b1,c0,c1); \
+ key_schedule; \
+ pass7(c0,c1,a0,a1,b0,b1); \
+ key_schedule; \
+ pass9(b0,b1,c0,c1,a0,a1); \
+ feedforward
+
+#define tiger_compress_macro(str, state) \
+{ \
+ register sh_word32 a0, a1, b0, b1, c0, c1; \
+ sh_word32 aa0, aa1, bb0, bb1, cc0, cc1; \
+ sh_word32 x00, x01, x10, x11, x20, x21, x30, x31, \
+ x40, x41, x50, x51, x60, x61, x70, x71; \
+ sh_word32 temp0, temp1, tempt0, tempt1, temps0, tcarry; \
+\
+ a0 = state[0]; \
+ a1 = state[1]; \
+ b0 = state[2]; \
+ b1 = state[3]; \
+ c0 = state[4]; \
+ c1 = state[5]; \
+\
+ save_abc \
+\
+ x00=str[0*2]; x01=str[0*2+1]; x10=str[1*2]; x11=str[1*2+1]; \
+ x20=str[2*2]; x21=str[2*2+1]; x30=str[3*2]; x31=str[3*2+1]; \
+ x40=str[4*2]; x41=str[4*2+1]; x50=str[5*2]; x51=str[5*2+1]; \
+ x60=str[6*2]; x61=str[6*2+1]; x70=str[7*2]; x71=str[7*2+1]; \
+\
+ compress; \
+\
+ state[0] = a0; \
+ state[1] = a1; \
+ state[2] = b0; \
+ state[3] = b1; \
+ state[4] = c0; \
+ state[5] = c1; \
+}
+
+#if defined(UNROLL_COMPRESS)
+/* The compress function is inlined */
+#define tiger_compress(str, state) \
+ tiger_compress_macro(((sh_word32*)str), ((sh_word32*)state))
+
+#else
+
+void
+tiger_compress(sh_word32 *str, sh_word32 state[6])
+{
+ tiger_compress_macro(((sh_word32*)str), ((sh_word32*)state));
+}
+#endif
+
+void
+tiger_t(const sh_word32 *str, sh_word32 length, sh_word32 res[6])
+{
+ register sh_word32 i;
+#ifdef BIG_ENDIAN
+ register sh_word32 j;
+ sh_byte temp[64];
+#endif
+
+ for(i=length; i>=64; i-=64)
+ {
+#ifdef BIG_ENDIAN
+ for(j=0; j<64; j++)
+ temp[j^3] = ((sh_byte*)str)[j];
+ tiger_compress_macro(((sh_word32*)temp), res);
+#else
+ tiger_compress_macro(str, res);
+#endif
+ str += 16;
+ }
+}
+
+
+void tiger(sh_word32 *str, sh_word32 length, sh_word32 res[6])
+{
+ register sh_word32 i, j;
+ sh_byte temp[64];
+
+ /*
+ * res[0]=0x89ABCDEF;
+ * res[1]=0x01234567;
+ * res[2]=0x76543210;
+ * res[3]=0xFEDCBA98;
+ * res[4]=0xC3B2E187;
+ * res[5]=0xF096A5B4;
+ */
+
+ for(i=length; i>=64; i-=64)
+ {
+#ifdef BIG_ENDIAN
+ for(j=0; j<64; j++)
+ temp[j^3] = ((sh_byte*)str)[j];
+ tiger_compress(((sh_word32*)temp), res);
+#else
+ tiger_compress(str, res);
+#endif
+ str += 16;
+ }
+
+#ifdef BIG_ENDIAN
+ for(j=0; j<i; j++)
+ temp[j^3] = ((sh_byte*)str)[j];
+
+ temp[j^3] = 0x01;
+ j++;
+ for(; j&7; j++)
+ temp[j^3] = 0;
+#else
+ for(j=0; j<i; j++)
+ temp[j] = ((sh_byte*)str)[j];
+
+ temp[j++] = 0x01;
+ for(; j&7; j++)
+ temp[j] = 0;
+#endif
+ if(j>56)
+ {
+ for(; j<64; j++)
+ temp[j] = 0;
+ tiger_compress(((sh_word32*)temp), res);
+ j=0;
+ }
+
+ for(; j<56; j++)
+ temp[j] = 0;
+ ((sh_word32*)(&(temp[56])))[0] = ((sh_word32)length)<<3;
+ ((sh_word32*)(&(temp[56])))[1] = 0;
+ tiger_compress(((sh_word32*)temp), res);
+}
+
+#endif
+
diff --git a/src/sh_tiger1.s b/src/sh_tiger1.s
new file mode 100644
index 0000000..9fa1134
--- /dev/null
+++ b/src/sh_tiger1.s
@@ -0,0 +1,5756 @@
+ .file "sh_tiger1.c"
+ .text
+.globl tiger_compress
+ .type tiger_compress, @function
+tiger_compress:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $1140, %esp
+ movl 12(%ebp), %ecx
+ movl 12(%ebp), %esi
+ call __i686.get_pc_thunk.bx
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl 8(%ebp), %eax
+ movl (%ecx), %edi
+ movl 12(%ebp), %ecx
+ movl %edi, -1088(%ebp)
+ movl 4(%esi), %edx
+ movl 12(%ebp), %esi
+ movl %edx, -1092(%ebp)
+ movl 8(%ecx), %edi
+ movl 12(%ebp), %ecx
+ movl %edi, -1096(%ebp)
+ movl 12(%esi), %edx
+ movl -1096(%ebp), %esi
+ movl %edx, -1100(%ebp)
+ movl 16(%ecx), %edx
+ movl 20(%ecx), %edi
+ movl %esi, -16(%ebp)
+ movl %edx, -20(%ebp)
+ movl %edi, -1104(%ebp)
+ movl (%eax), %ecx
+ movl %ecx, -24(%ebp)
+ movl 4(%eax), %edi
+ movl %edi, -28(%ebp)
+ movl 8(%eax), %esi
+ movl %esi, -32(%ebp)
+ movl 12(%eax), %ecx
+ movl %ecx, -36(%ebp)
+ movl 16(%eax), %edi
+ movl %edi, -40(%ebp)
+ movl 20(%eax), %esi
+ movl %esi, -44(%ebp)
+ movl 24(%eax), %ecx
+ movl %ecx, -48(%ebp)
+ movl 28(%eax), %edi
+ movl %edi, -52(%ebp)
+ movl 32(%eax), %esi
+ movl %esi, -56(%ebp)
+ movl 36(%eax), %ecx
+ movl %ecx, -60(%ebp)
+ movl 40(%eax), %edi
+ movl %edi, -64(%ebp)
+ movl 44(%eax), %esi
+ movl %esi, -68(%ebp)
+ movl 48(%eax), %ecx
+ movl %ecx, -72(%ebp)
+ movl 52(%eax), %edi
+ movl %edi, -76(%ebp)
+ movl 56(%eax), %esi
+ movl -28(%ebp), %edi
+ movl %esi, -80(%ebp)
+ movl 60(%eax), %ecx
+ movl -24(%ebp), %eax
+ movl -1104(%ebp), %esi
+ movl %ecx, -84(%ebp)
+ xorl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ movl %edx, -152(%ebp)
+ movl %edx, %eax
+ xorl %edi, %esi
+ movl %esi, -156(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl %ecx, %esi
+ movl 2048(%eax,%ecx), %edx
+ movl (%ecx,%edi,8), %ecx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -156(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -156(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -1088(%ebp), %edi
+ cmpl %ecx, -1088(%ebp)
+ setb %al
+ subl %ecx, %edi
+ movl %edi, -168(%ebp)
+ movl -1092(%ebp), %ecx
+ addl %eax, %edx
+ subl %edx, %ecx
+ movl -152(%ebp), %edx
+ movl %ecx, -172(%ebp)
+ movzbl %dh, %eax
+ leal 0(,%eax,8), %ecx
+ movl %edx, %eax
+ movl 6144(%ecx,%esi), %edi
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6148(%ecx,%esi), %ecx
+ movl 4096(%eax,%esi), %edx
+ xorl %edi, %edx
+ movl 4100(%eax,%esi), %edi
+ movl -156(%ebp), %eax
+ xorl %edi, %ecx
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %edx
+ movl 2052(%eax,%esi), %edi
+ movl -156(%ebp), %eax
+ xorl %edi, %ecx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %edx
+ movl 4(%esi,%eax,8), %edi
+ movl -1096(%ebp), %esi
+ xorl %eax, %eax
+ xorl %edi, %ecx
+ addl %edx, %esi
+ cmpl %edx, %esi
+ movl -1100(%ebp), %edx
+ setb %al
+ movl %esi, %edi
+ leal (%ecx,%eax), %eax
+ addl %edx, %eax
+ leal 0(,%esi,4), %ecx
+ movl %eax, %edx
+ movl %eax, -160(%ebp)
+ addl %ecx, %esi
+ shrl $30, %edi
+ movl %esi, -164(%ebp)
+ sall $2, %edx
+ xorl %eax, %eax
+ orl %edi, %edx
+ cmpl %ecx, %esi
+ movl -80(%ebp), %edi
+ setb %al
+ xorl %ecx, %ecx
+ addl %eax, %edx
+ movl -160(%ebp), %eax
+ xorl $-1515870811, %edi
+ movl -24(%ebp), %esi
+ addl %eax, %edx
+ movl -84(%ebp), %eax
+ cmpl %edi, -24(%ebp)
+ movl %edx, -184(%ebp)
+ movl -32(%ebp), %edx
+ setb %cl
+ xorl $-1515870811, %eax
+ subl %edi, %esi
+ addl %ecx, %eax
+ movl %esi, -196(%ebp)
+ movl -28(%ebp), %ecx
+ movl -36(%ebp), %edi
+ movl -172(%ebp), %esi
+ subl %eax, %ecx
+ movl -168(%ebp), %eax
+ movl %ecx, -200(%ebp)
+ movl tiger_table@GOT(%ebx), %ecx
+ xorl %edi, %esi
+ movl %esi, -180(%ebp)
+ xorl %edx, %eax
+ movzbl %al,%edi
+ movl %eax, -176(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl %ecx, %esi
+ movl 2048(%eax,%ecx), %edx
+ movl (%ecx,%edi,8), %ecx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -180(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -180(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -164(%ebp), %edi
+ cmpl %ecx, -164(%ebp)
+ setb %al
+ subl %ecx, %edi
+ movl %edi, -204(%ebp)
+ movl -176(%ebp), %ecx
+ movl -184(%ebp), %edi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %edi
+ movl %edi, -208(%ebp)
+ leal 0(,%eax,8), %edi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%edi,%esi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -180(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -180(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -152(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -156(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ movl %edx, -188(%ebp)
+ leal 0(,%edi,4), %ecx
+ addl %ecx, %edi
+ movl %edi, -192(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -188(%ebp), %edi
+ setb %al
+ addl %eax, %edx
+ movl -32(%ebp), %ecx
+ addl %edi, %edx
+ movl -200(%ebp), %eax
+ movl %edx, -220(%ebp)
+ movl -36(%ebp), %edi
+ movl -196(%ebp), %edx
+ xorl %eax, %edi
+ xorl %edx, %ecx
+ movl %edi, -240(%ebp)
+ movl -40(%ebp), %edx
+ movl %ecx, -232(%ebp)
+ movl -204(%ebp), %eax
+ movl -44(%ebp), %ecx
+ movl -208(%ebp), %edi
+ xorl %edx, %eax
+ movl %eax, -212(%ebp)
+ xorl %ecx, %edi
+ movl %edi, -216(%ebp)
+ movzbl %al,%edi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -216(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -216(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -192(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -192(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -244(%ebp)
+ movl -220(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -212(%ebp), %edx
+ movl %edi, -248(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -216(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -216(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -176(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -180(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,4), %ecx
+ movl %edx, -224(%ebp)
+ addl %ecx, %edi
+ shrl $30, %eax
+ movl %edi, -228(%ebp)
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -224(%ebp), %ecx
+ setb %al
+ movl -232(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -232(%ebp), %eax
+ movl -240(%ebp), %ecx
+ movl %edx, -260(%ebp)
+ movl -40(%ebp), %edx
+ addl %eax, %edx
+ movl %edx, -236(%ebp)
+ xorl %eax, %eax
+ cmpl %edi, %edx
+ movl -44(%ebp), %edi
+ setb %al
+ addl %ecx, %eax
+ movl -48(%ebp), %edx
+ addl %edi, %eax
+ movl -52(%ebp), %ecx
+ movl %eax, -272(%ebp)
+ movl -248(%ebp), %edi
+ movl -244(%ebp), %eax
+ xorl %ecx, %edi
+ xorl %edx, %eax
+ movl %edi, -256(%ebp)
+ movzbl %al,%edi
+ movl %eax, -252(%ebp)
+ shrl $13, %eax
+ movl (%esi,%edi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -256(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -256(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -228(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -228(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -276(%ebp)
+ movl -260(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -252(%ebp), %edx
+ movl %edi, -280(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -256(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -256(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -212(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -216(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,4), %ecx
+ movl %edx, -264(%ebp)
+ addl %ecx, %edi
+ shrl $30, %eax
+ movl %edi, -268(%ebp)
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ setb %al
+ addl %eax, %edx
+ movl -264(%ebp), %eax
+ movl -236(%ebp), %edi
+ addl %eax, %edx
+ movl -232(%ebp), %eax
+ movl %edx, -292(%ebp)
+ movl -48(%ebp), %edx
+ notl %eax
+ sall $19, %eax
+ xorl %edi, %eax
+ cmpl %eax, -48(%ebp)
+ setb %cl
+ movzbl %cl, %edi
+ subl %eax, %edx
+ movl -232(%ebp), %ecx
+ movl -240(%ebp), %eax
+ movl %edx, -304(%ebp)
+ movl -272(%ebp), %edx
+ shrl $13, %ecx
+ sall $19, %eax
+ orl %ecx, %eax
+ notl %edx
+ xorl %eax, %edx
+ movl -52(%ebp), %eax
+ addl %edi, %edx
+ movl -60(%ebp), %ecx
+ subl %edx, %eax
+ movl -280(%ebp), %edi
+ movl %eax, -308(%ebp)
+ movl -56(%ebp), %edx
+ movl -276(%ebp), %eax
+ xorl %ecx, %edi
+ xorl %edx, %eax
+ movl %eax, -284(%ebp)
+ movl %edi, -288(%ebp)
+ movzbl %al,%edi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -288(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -288(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -268(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -268(%ebp)
+ movl -292(%ebp), %edi
+ setb %al
+ addl %eax, %edx
+ subl %ecx, %esi
+ subl %edx, %edi
+ movl %esi, -312(%ebp)
+ movl -284(%ebp), %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ movl %edi, -316(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -288(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -288(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -252(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -256(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,4), %ecx
+ movl %edx, -296(%ebp)
+ addl %ecx, %edi
+ shrl $30, %eax
+ movl %edi, -300(%ebp)
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -296(%ebp), %edi
+ setb %al
+ movl -56(%ebp), %ecx
+ addl %eax, %edx
+ addl %edi, %edx
+ movl %edx, -328(%ebp)
+ movl -304(%ebp), %edx
+ xorl %edx, %ecx
+ movl %ecx, -340(%ebp)
+ movl -308(%ebp), %eax
+ movl -60(%ebp), %edi
+ movl -64(%ebp), %edx
+ movl -68(%ebp), %ecx
+ xorl %eax, %edi
+ movl %edi, -348(%ebp)
+ movl -312(%ebp), %eax
+ movl -316(%ebp), %edi
+ xorl %edx, %eax
+ xorl %ecx, %edi
+ movl %edi, -324(%ebp)
+ movzbl %al,%edi
+ movl %eax, -320(%ebp)
+ shrl $13, %eax
+ movl (%esi,%edi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -324(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -324(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -300(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -300(%ebp)
+ movl -328(%ebp), %edi
+ setb %al
+ addl %eax, %edx
+ subl %ecx, %esi
+ subl %edx, %edi
+ movl %esi, -352(%ebp)
+ movl -320(%ebp), %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ movl %edi, -356(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -324(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -324(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -284(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -288(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,4), %ecx
+ movl %edx, -332(%ebp)
+ addl %ecx, %edi
+ shrl $30, %eax
+ movl %edi, -336(%ebp)
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -332(%ebp), %ecx
+ setb %al
+ movl -340(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -340(%ebp), %eax
+ movl -348(%ebp), %ecx
+ movl %edx, -368(%ebp)
+ movl -64(%ebp), %edx
+ addl %eax, %edx
+ movl %edx, -344(%ebp)
+ xorl %eax, %eax
+ cmpl %edi, %edx
+ movl -68(%ebp), %edi
+ setb %al
+ addl %ecx, %eax
+ movl -72(%ebp), %edx
+ addl %edi, %eax
+ movl -76(%ebp), %ecx
+ movl %eax, -380(%ebp)
+ movl -356(%ebp), %edi
+ movl -352(%ebp), %eax
+ xorl %ecx, %edi
+ xorl %edx, %eax
+ movl %edi, -364(%ebp)
+ movzbl %al,%edi
+ movl %eax, -360(%ebp)
+ shrl $13, %eax
+ movl (%esi,%edi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -364(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -364(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -336(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -336(%ebp)
+ movl -368(%ebp), %edi
+ setb %al
+ addl %eax, %edx
+ subl %ecx, %esi
+ subl %edx, %edi
+ movl %esi, -384(%ebp)
+ movl -360(%ebp), %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ movl %edi, -388(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -364(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -364(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -320(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ setb %al
+ leal 0(,%edi,4), %ecx
+ addl %eax, %edx
+ movl -324(%ebp), %eax
+ movl %edi, %esi
+ shrl $30, %esi
+ addl %ecx, %edi
+ addl %eax, %edx
+ xorl %eax, %eax
+ movl %edx, -372(%ebp)
+ sall $2, %edx
+ orl %esi, %edx
+ movl %edi, -376(%ebp)
+ cmpl %ecx, %edi
+ movl -372(%ebp), %esi
+ setb %al
+ movl -344(%ebp), %ecx
+ addl %eax, %edx
+ addl %esi, %edx
+ movl -340(%ebp), %eax
+ notl %ecx
+ movl %edx, -400(%ebp)
+ movl -348(%ebp), %edx
+ shrl $23, %eax
+ movl -72(%ebp), %edi
+ sall $9, %edx
+ movl -380(%ebp), %esi
+ orl %edx, %eax
+ xorl %eax, %ecx
+ xorl %edx, %edx
+ cmpl %ecx, -72(%ebp)
+ movl -348(%ebp), %eax
+ notl %eax
+ setb %dl
+ subl %ecx, %edi
+ shrl $23, %eax
+ movl %edi, -412(%ebp)
+ movl -76(%ebp), %ecx
+ xorl %esi, %eax
+ addl %edx, %eax
+ movl -80(%ebp), %edx
+ movl -84(%ebp), %edi
+ subl %eax, %ecx
+ movl -384(%ebp), %eax
+ movl -388(%ebp), %esi
+ movl %ecx, -416(%ebp)
+ xorl %edx, %eax
+ movl tiger_table@GOT(%ebx), %ecx
+ movl %eax, -392(%ebp)
+ xorl %edi, %esi
+ movzbl %al,%edi
+ movl %esi, -396(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl %ecx, %esi
+ movl 2048(%eax,%ecx), %edx
+ movl (%ecx,%edi,8), %ecx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -396(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -396(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -376(%ebp), %edi
+ cmpl %ecx, -376(%ebp)
+ setb %al
+ addl %eax, %edx
+ movl -400(%ebp), %eax
+ subl %ecx, %edi
+ movl %edi, -488(%ebp)
+ subl %edx, %eax
+ movl %eax, -492(%ebp)
+ movl -392(%ebp), %ecx
+ movzbl %ch, %edi
+ movl %ecx, %eax
+ sall $3, %edi
+ shrl $24, %eax
+ movl %edi, -88(%ebp)
+ sall $3, %eax
+ movl 4096(%eax,%esi), %ecx
+ movl -88(%ebp), %edx
+ movl %esi, %edi
+ movl %ecx, -1116(%ebp)
+ movl 4100(%eax,%esi), %eax
+ xorl 6144(%edx,%esi), %ecx
+ movl %eax, %edx
+ movl -88(%ebp), %eax
+ xorl 6148(%eax,%esi), %edx
+ movl -396(%ebp), %eax
+ movzbl %ah, %eax
+ movl %eax, -1112(%ebp)
+ sall $3, %eax
+ xorl 2048(%eax,%esi), %ecx
+ xorl 2052(%eax,%esi), %edx
+ movl -396(%ebp), %eax
+ shrl $24, %eax
+ xorl (%esi,%eax,8), %ecx
+ xorl 4(%esi,%eax,8), %edx
+ movl -360(%ebp), %esi
+ xorl %eax, %eax
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -364(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl %edx, -404(%ebp)
+ leal 0(,%esi,4), %ecx
+ movl %esi, %eax
+ shrl $30, %eax
+ addl %ecx, %esi
+ sall $2, %edx
+ movl %esi, -408(%ebp)
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ setb %al
+ movl -412(%ebp), %ecx
+ addl %eax, %edx
+ movl -404(%ebp), %eax
+ movl -416(%ebp), %esi
+ addl %eax, %edx
+ xorl %eax, %eax
+ movl %edx, -504(%ebp)
+ movl -80(%ebp), %edx
+ xorl %ecx, %edx
+ movl %edx, -420(%ebp)
+ movl -84(%ebp), %ecx
+ xorl %esi, %ecx
+ movl %ecx, -428(%ebp)
+ movl -196(%ebp), %esi
+ addl %edx, %esi
+ movl %esi, -424(%ebp)
+ cmpl %edx, %esi
+ setb %al
+ addl %ecx, %eax
+ addl -200(%ebp), %eax
+ movl %eax, -432(%ebp)
+ movl %edx, %eax
+ notl %eax
+ sall $19, %eax
+ xorl %edx, %edx
+ xorl %esi, %eax
+ cmpl %eax, -232(%ebp)
+ setb %dl
+ movl %edx, -436(%ebp)
+ movl -232(%ebp), %esi
+ movl -436(%ebp), %edx
+ subl %eax, %esi
+ movl %ecx, %eax
+ movl -420(%ebp), %ecx
+ movl %esi, -440(%ebp)
+ movl -432(%ebp), %esi
+ sall $19, %eax
+ shrl $13, %ecx
+ orl %ecx, %eax
+ notl %esi
+ xorl %eax, %esi
+ movl -240(%ebp), %ecx
+ addl %edx, %esi
+ movl -272(%ebp), %edx
+ subl %esi, %ecx
+ movl -440(%ebp), %eax
+ movl %ecx, -444(%ebp)
+ movl -236(%ebp), %esi
+ xorl %ecx, %edx
+ movl %edx, -456(%ebp)
+ movl -304(%ebp), %edx
+ xorl %eax, %esi
+ movl %esi, -448(%ebp)
+ movl -456(%ebp), %ecx
+ xorl %eax, %eax
+ addl %esi, %edx
+ cmpl %esi, %edx
+ setb %al
+ movl %edx, -452(%ebp)
+ addl %ecx, %eax
+ movl -308(%ebp), %ecx
+ addl %ecx, %eax
+ movl %edx, %ecx
+ notl %ecx
+ movl %eax, -460(%ebp)
+ movl %esi, %eax
+ movl -456(%ebp), %esi
+ shrl $23, %eax
+ xorl %edx, %edx
+ sall $9, %esi
+ orl %esi, %eax
+ xorl %eax, %ecx
+ movl -340(%ebp), %esi
+ cmpl %ecx, -340(%ebp)
+ movl -456(%ebp), %eax
+ setb %dl
+ subl %ecx, %esi
+ movl -460(%ebp), %ecx
+ notl %eax
+ movl %esi, -464(%ebp)
+ shrl $23, %eax
+ xorl %ecx, %eax
+ movl -344(%ebp), %ecx
+ addl %edx, %eax
+ movl -348(%ebp), %edx
+ xorl %esi, %ecx
+ movl -380(%ebp), %esi
+ subl %eax, %edx
+ movl %edx, -468(%ebp)
+ movl %ecx, -472(%ebp)
+ xorl %edx, %esi
+ movl -412(%ebp), %edx
+ movl %esi, -480(%ebp)
+ addl %ecx, %edx
+ cmpl %ecx, %edx
+ movl %edx, -476(%ebp)
+ setb %cl
+ movzbl %cl, %eax
+ addl %esi, %eax
+ movl -476(%ebp), %edx
+ movl -416(%ebp), %esi
+ movl -420(%ebp), %ecx
+ xorl $-1985229329, %edx
+ addl %esi, %eax
+ movl %eax, -484(%ebp)
+ xorl %eax, %eax
+ cmpl %edx, -420(%ebp)
+ setb %al
+ subl %edx, %ecx
+ movl %ecx, -524(%ebp)
+ movl -484(%ebp), %esi
+ movl -428(%ebp), %ecx
+ movl -424(%ebp), %edx
+ xorl $19088743, %esi
+ addl %eax, %esi
+ subl %esi, %ecx
+ movl -432(%ebp), %eax
+ movl -492(%ebp), %esi
+ movl %ecx, -528(%ebp)
+ movl -488(%ebp), %ecx
+ xorl %eax, %esi
+ movl %esi, -500(%ebp)
+ xorl %edx, %ecx
+ movl -408(%ebp), %esi
+ movl %ecx, -496(%ebp)
+ movl %ecx, %eax
+ movzbl %cl,%edx
+ movl %edx, -92(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %ecx
+ movl %ecx, -1120(%ebp)
+ movl 2052(%eax,%edi), %eax
+ xorl (%edi,%edx,8), %ecx
+ movl %eax, %edx
+ movl -92(%ebp), %eax
+ xorl 4(%edi,%eax,8), %edx
+ movzbl -500(%ebp),%eax
+ sall $3, %eax
+ xorl 4096(%eax,%edi), %ecx
+ xorl 4100(%eax,%edi), %edx
+ movl -500(%ebp), %eax
+ shrl $13, %eax
+ andl $2040, %eax
+ xorl 6144(%eax,%edi), %ecx
+ xorl 6148(%eax,%edi), %edx
+ xorl %eax, %eax
+ cmpl %ecx, -408(%ebp)
+ setb %al
+ addl %eax, %edx
+ movl -504(%ebp), %eax
+ subl %ecx, %esi
+ movl %esi, -532(%ebp)
+ subl %edx, %eax
+ movl -496(%ebp), %edx
+ movl %eax, -536(%ebp)
+ movzbl %dh, %esi
+ movl %edx, %eax
+ sall $3, %esi
+ shrl $24, %eax
+ sall $3, %eax
+ movl %esi, -96(%ebp)
+ movl 4096(%eax,%edi), %ecx
+ movl -96(%ebp), %esi
+ movl %ecx, -1124(%ebp)
+ movl 4100(%eax,%edi), %eax
+ xorl 6144(%esi,%edi), %ecx
+ movl %eax, %edx
+ movl -500(%ebp), %eax
+ xorl 6148(%esi,%edi), %edx
+ movzbl %ah, %eax
+ movl %eax, -1112(%ebp)
+ sall $3, %eax
+ movl -392(%ebp), %esi
+ xorl 2048(%eax,%edi), %ecx
+ xorl 2052(%eax,%edi), %edx
+ movl -500(%ebp), %eax
+ shrl $24, %eax
+ xorl (%edi,%eax,8), %ecx
+ xorl 4(%edi,%eax,8), %edx
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl %esi, -508(%ebp)
+ setb %al
+ movl -396(%ebp), %ecx
+ movzbl %al, %esi
+ addl %esi, %edx
+ movl -508(%ebp), %eax
+ addl %ecx, %edx
+ movl -508(%ebp), %esi
+ movl %edx, -512(%ebp)
+ movl -512(%ebp), %ecx
+ shrl $29, %eax
+ movl -508(%ebp), %edx
+ sall $3, %ecx
+ sall $3, %edx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl -508(%ebp), %edx
+ setb %al
+ subl %esi, %edx
+ movl %edx, -516(%ebp)
+ movl -512(%ebp), %esi
+ movl -524(%ebp), %edx
+ addl %esi, %eax
+ xorl $-1515870811, %edx
+ subl %eax, %ecx
+ movl %ecx, -520(%ebp)
+ xorl %eax, %eax
+ cmpl %edx, -424(%ebp)
+ movl -424(%ebp), %ecx
+ movl -528(%ebp), %esi
+ setb %al
+ subl %edx, %ecx
+ xorl $-1515870811, %esi
+ movl %ecx, -564(%ebp)
+ movl -432(%ebp), %ecx
+ addl %eax, %esi
+ movl -440(%ebp), %edx
+ movl -444(%ebp), %eax
+ subl %esi, %ecx
+ movl %ecx, -568(%ebp)
+ movl -532(%ebp), %ecx
+ movl -536(%ebp), %esi
+ xorl %edx, %ecx
+ xorl %eax, %esi
+ movl %ecx, %eax
+ movl %esi, -544(%ebp)
+ movzbl %cl,%edx
+ shrl $13, %eax
+ movl %edx, -100(%ebp)
+ andl $2040, %eax
+ movl -516(%ebp), %esi
+ movl %ecx, -540(%ebp)
+ movl 2048(%eax,%edi), %ecx
+ movl %ecx, -1128(%ebp)
+ movl 2052(%eax,%edi), %eax
+ xorl (%edi,%edx,8), %ecx
+ movl %eax, %edx
+ movl -100(%ebp), %eax
+ xorl 4(%edi,%eax,8), %edx
+ movzbl -544(%ebp),%eax
+ sall $3, %eax
+ xorl 4096(%eax,%edi), %ecx
+ xorl 4100(%eax,%edi), %edx
+ movl -544(%ebp), %eax
+ shrl $13, %eax
+ andl $2040, %eax
+ xorl 6144(%eax,%edi), %ecx
+ xorl 6148(%eax,%edi), %edx
+ xorl %eax, %eax
+ cmpl %ecx, -516(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -572(%ebp)
+ addl %eax, %edx
+ movl -520(%ebp), %eax
+ subl %edx, %eax
+ movl -540(%ebp), %edx
+ movl %eax, -576(%ebp)
+ movzbl %dh, %esi
+ movl %edx, %eax
+ sall $3, %esi
+ shrl $24, %eax
+ sall $3, %eax
+ movl %esi, -104(%ebp)
+ movl 4096(%eax,%edi), %ecx
+ movl -104(%ebp), %esi
+ movl %ecx, -1132(%ebp)
+ movl 4100(%eax,%edi), %eax
+ xorl 6144(%esi,%edi), %ecx
+ movl %eax, %edx
+ movl -544(%ebp), %eax
+ xorl 6148(%esi,%edi), %edx
+ movzbl %ah, %eax
+ movl %eax, -1112(%ebp)
+ sall $3, %eax
+ xorl 2048(%eax,%edi), %ecx
+ xorl 2052(%eax,%edi), %edx
+ movl -544(%ebp), %eax
+ shrl $24, %eax
+ xorl (%edi,%eax,8), %ecx
+ xorl 4(%edi,%eax,8), %edx
+ movl -496(%ebp), %eax
+ addl %ecx, %eax
+ movl %eax, -548(%ebp)
+ cmpl %ecx, %eax
+ setb %cl
+ movzbl %cl, %eax
+ movl -500(%ebp), %ecx
+ addl %eax, %edx
+ movl -548(%ebp), %eax
+ addl %ecx, %edx
+ shrl $29, %eax
+ movl %edx, -552(%ebp)
+ movl -552(%ebp), %ecx
+ movl -548(%ebp), %edx
+ sall $3, %ecx
+ sall $3, %edx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl -548(%ebp), %edx
+ setb %al
+ subl -548(%ebp), %edx
+ movl %edx, -556(%ebp)
+ movl -552(%ebp), %edx
+ addl %edx, %eax
+ subl %eax, %ecx
+ movl -440(%ebp), %edx
+ movl -568(%ebp), %eax
+ movl %ecx, -560(%ebp)
+ movl -564(%ebp), %ecx
+ xorl %ecx, %edx
+ movl %edx, -604(%ebp)
+ movl -444(%ebp), %ecx
+ xorl %eax, %ecx
+ movl %ecx, -612(%ebp)
+ movl -448(%ebp), %edx
+ movl -572(%ebp), %eax
+ movl -456(%ebp), %ecx
+ xorl %edx, %eax
+ movl -576(%ebp), %edx
+ movl %eax, -580(%ebp)
+ xorl %ecx, %edx
+ movzbl %al,%ecx
+ movl %edx, -584(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl %ecx, -108(%ebp)
+ movl 2048(%eax,%edi), %esi
+ movl -108(%ebp), %edx
+ movl 2052(%eax,%edi), %eax
+ movl %esi, %ecx
+ movl -556(%ebp), %esi
+ xorl (%edi,%edx,8), %ecx
+ movl %eax, %edx
+ movl -108(%ebp), %eax
+ xorl 4(%edi,%eax,8), %edx
+ movzbl -584(%ebp),%eax
+ sall $3, %eax
+ xorl 4096(%eax,%edi), %ecx
+ xorl 4100(%eax,%edi), %edx
+ movl -584(%ebp), %eax
+ shrl $13, %eax
+ andl $2040, %eax
+ xorl 6144(%eax,%edi), %ecx
+ xorl 6148(%eax,%edi), %edx
+ xorl %eax, %eax
+ cmpl %ecx, -556(%ebp)
+ setb %al
+ addl %eax, %edx
+ movl -560(%ebp), %eax
+ subl %ecx, %esi
+ movl %esi, -616(%ebp)
+ subl %edx, %eax
+ movl -580(%ebp), %edx
+ movl %eax, -620(%ebp)
+ movzbl %dh, %esi
+ movl %edx, %eax
+ sall $3, %esi
+ shrl $24, %eax
+ sall $3, %eax
+ movl %esi, -112(%ebp)
+ movl 4096(%eax,%edi), %ecx
+ movl -112(%ebp), %esi
+ movl %ecx, -1140(%ebp)
+ movl 4100(%eax,%edi), %eax
+ xorl 6144(%esi,%edi), %ecx
+ movl %eax, %edx
+ movl -584(%ebp), %eax
+ xorl 6148(%esi,%edi), %edx
+ movzbl %ah, %eax
+ movl %eax, -1112(%ebp)
+ sall $3, %eax
+ xorl 2048(%eax,%edi), %ecx
+ xorl 2052(%eax,%edi), %edx
+ movl -584(%ebp), %eax
+ shrl $24, %eax
+ xorl (%edi,%eax,8), %ecx
+ xorl 4(%edi,%eax,8), %edx
+ movl -540(%ebp), %eax
+ addl %ecx, %eax
+ movl %eax, -588(%ebp)
+ cmpl %ecx, %eax
+ setb %cl
+ movzbl %cl, %eax
+ movl -544(%ebp), %ecx
+ addl %eax, %edx
+ movl -588(%ebp), %eax
+ addl %ecx, %edx
+ shrl $29, %eax
+ movl %edx, -592(%ebp)
+ movl -592(%ebp), %ecx
+ movl -588(%ebp), %edx
+ sall $3, %ecx
+ sall $3, %edx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl -588(%ebp), %edx
+ setb %al
+ subl -588(%ebp), %edx
+ movl %edx, -596(%ebp)
+ movl -592(%ebp), %edx
+ addl %edx, %eax
+ subl %eax, %ecx
+ movl -448(%ebp), %edx
+ movl -604(%ebp), %eax
+ movl %ecx, -600(%ebp)
+ movl -604(%ebp), %ecx
+ addl %eax, %edx
+ movl %edx, -608(%ebp)
+ xorl %eax, %eax
+ cmpl %ecx, %edx
+ movl -612(%ebp), %edx
+ setb %al
+ movl -456(%ebp), %ecx
+ addl %edx, %eax
+ addl %ecx, %eax
+ movl -452(%ebp), %edx
+ movl %eax, -644(%ebp)
+ movl -616(%ebp), %eax
+ movl -460(%ebp), %ecx
+ xorl %edx, %eax
+ movl -620(%ebp), %edx
+ movl %eax, -624(%ebp)
+ xorl %ecx, %edx
+ movzbl %al,%ecx
+ movl %edx, -628(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl %ecx, -116(%ebp)
+ movl 2048(%eax,%edi), %esi
+ movl -116(%ebp), %edx
+ movl 2052(%eax,%edi), %eax
+ movl %esi, %ecx
+ movl -596(%ebp), %esi
+ xorl (%edi,%edx,8), %ecx
+ movl %eax, %edx
+ movl -116(%ebp), %eax
+ xorl 4(%edi,%eax,8), %edx
+ movzbl -628(%ebp),%eax
+ sall $3, %eax
+ xorl 4096(%eax,%edi), %ecx
+ xorl 4100(%eax,%edi), %edx
+ movl -628(%ebp), %eax
+ shrl $13, %eax
+ andl $2040, %eax
+ xorl 6144(%eax,%edi), %ecx
+ xorl 6148(%eax,%edi), %edx
+ xorl %eax, %eax
+ cmpl %ecx, -596(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -652(%ebp)
+ addl %eax, %edx
+ movl -600(%ebp), %eax
+ subl %edx, %eax
+ movl -624(%ebp), %edx
+ movl %eax, -656(%ebp)
+ movzbl %dh, %esi
+ movl %edx, %eax
+ sall $3, %esi
+ shrl $24, %eax
+ sall $3, %eax
+ movl %esi, -120(%ebp)
+ movl 4096(%eax,%edi), %ecx
+ movl -120(%ebp), %esi
+ movl %ecx, -1148(%ebp)
+ movl 4100(%eax,%edi), %eax
+ xorl 6144(%esi,%edi), %ecx
+ movl %eax, %edx
+ movl -628(%ebp), %eax
+ xorl 6148(%esi,%edi), %edx
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -628(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -580(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -584(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl %edx, -632(%ebp)
+ movl %esi, %eax
+ movl -632(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ shrl $29, %eax
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -632(%ebp), %esi
+ movl %edx, -636(%ebp)
+ xorl %edx, %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -604(%ebp), %eax
+ movl -452(%ebp), %esi
+ movl %ecx, -640(%ebp)
+ movl -608(%ebp), %ecx
+ notl %eax
+ sall $19, %eax
+ xorl %ecx, %eax
+ movl -604(%ebp), %ecx
+ cmpl %eax, -452(%ebp)
+ setb %dl
+ subl %eax, %esi
+ movl %esi, -680(%ebp)
+ movl -612(%ebp), %eax
+ shrl $13, %ecx
+ movl %edx, -648(%ebp)
+ movl -644(%ebp), %esi
+ movl -648(%ebp), %edx
+ sall $19, %eax
+ orl %ecx, %eax
+ notl %esi
+ xorl %eax, %esi
+ movl -460(%ebp), %eax
+ addl %edx, %esi
+ subl %esi, %eax
+ movl %eax, -684(%ebp)
+ movl -464(%ebp), %ecx
+ movl -652(%ebp), %eax
+ movl -468(%ebp), %edx
+ movl -656(%ebp), %esi
+ xorl %ecx, %eax
+ movl %eax, -660(%ebp)
+ movzbl %al,%ecx
+ xorl %edx, %esi
+ movl %esi, -664(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl %ecx, -124(%ebp)
+ movl %ecx, %esi
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%ecx,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -664(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -664(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -636(%ebp), %esi
+ cmpl %ecx, -636(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -688(%ebp)
+ movl -660(%ebp), %ecx
+ addl %eax, %edx
+ movl -640(%ebp), %eax
+ movzbl %ch, %esi
+ sall $3, %esi
+ movl %esi, -128(%ebp)
+ subl %edx, %eax
+ movl -128(%ebp), %esi
+ movl %eax, -692(%ebp)
+ movl %ecx, %eax
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6144(%esi,%edi), %ecx
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -664(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -664(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -624(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -628(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ shrl $29, %eax
+ movl %edx, -668(%ebp)
+ movl -668(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl %edx, -672(%ebp)
+ movl -668(%ebp), %esi
+ movl -464(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -468(%ebp), %esi
+ movl %ecx, -676(%ebp)
+ movl -684(%ebp), %eax
+ movl -680(%ebp), %ecx
+ xorl %eax, %esi
+ xorl %ecx, %edx
+ movl -688(%ebp), %eax
+ movl %edx, -716(%ebp)
+ movl -472(%ebp), %ecx
+ movl -480(%ebp), %edx
+ movl %esi, -724(%ebp)
+ movl -692(%ebp), %esi
+ xorl %ecx, %eax
+ movl %eax, -696(%ebp)
+ movzbl %al,%ecx
+ shrl $13, %eax
+ movl %ecx, -132(%ebp)
+ xorl %edx, %esi
+ andl $2040, %eax
+ movl %esi, -700(%ebp)
+ movl 2048(%eax,%edi), %edx
+ movl %ecx, %esi
+ movl (%edi,%ecx,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -700(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -700(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -672(%ebp), %esi
+ cmpl %ecx, -672(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -728(%ebp)
+ movl -696(%ebp), %ecx
+ addl %eax, %edx
+ movl -676(%ebp), %eax
+ movzbl %ch, %esi
+ subl %edx, %eax
+ movl %eax, -732(%ebp)
+ sall $3, %esi
+ movl %ecx, %eax
+ movl %esi, -136(%ebp)
+ movl -136(%ebp), %esi
+ shrl $24, %eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 6144(%esi,%edi), %ecx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -700(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -700(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -660(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -664(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ shrl $29, %eax
+ movl %edx, -704(%ebp)
+ movl -704(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl %edx, -708(%ebp)
+ movl -704(%ebp), %esi
+ movl -472(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -716(%ebp), %eax
+ movl %ecx, -712(%ebp)
+ movl -716(%ebp), %ecx
+ movl -480(%ebp), %esi
+ addl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edx
+ movl %edx, -720(%ebp)
+ movl -724(%ebp), %edx
+ setb %al
+ movl -476(%ebp), %ecx
+ addl %edx, %eax
+ addl %esi, %eax
+ movl %eax, -756(%ebp)
+ movl -728(%ebp), %eax
+ movl -484(%ebp), %edx
+ movl -732(%ebp), %esi
+ xorl %ecx, %eax
+ movzbl %al,%ecx
+ movl %eax, -736(%ebp)
+ xorl %edx, %esi
+ shrl $13, %eax
+ movl %esi, -740(%ebp)
+ andl $2040, %eax
+ movl %ecx, %esi
+ movl %ecx, -140(%ebp)
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%ecx,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -740(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -740(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -708(%ebp), %esi
+ cmpl %ecx, -708(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -760(%ebp)
+ movl -736(%ebp), %ecx
+ addl %eax, %edx
+ movl -712(%ebp), %eax
+ movzbl %ch, %esi
+ sall $3, %esi
+ movl %esi, -144(%ebp)
+ subl %edx, %eax
+ movl -144(%ebp), %esi
+ movl %eax, -764(%ebp)
+ movl %ecx, %eax
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6144(%esi,%edi), %ecx
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -740(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl %edi, %esi
+ movl 2048(%eax,%edi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -740(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -696(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -700(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ movl %edx, -744(%ebp)
+ shrl $29, %eax
+ movl -744(%ebp), %ecx
+ leal 0(,%edi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %edi, %edx
+ setb %al
+ subl %edi, %edx
+ movl -744(%ebp), %edi
+ movl %edx, -748(%ebp)
+ movl -724(%ebp), %edx
+ addl %edi, %eax
+ subl %eax, %ecx
+ movl -716(%ebp), %eax
+ sall $9, %edx
+ movl %ecx, -752(%ebp)
+ movl -720(%ebp), %ecx
+ shrl $23, %eax
+ orl %edx, %eax
+ movl -476(%ebp), %edi
+ notl %ecx
+ xorl %eax, %ecx
+ xorl %eax, %eax
+ movl -756(%ebp), %edx
+ cmpl %ecx, -476(%ebp)
+ setb %al
+ subl %ecx, %edi
+ movl %edi, -788(%ebp)
+ movl -724(%ebp), %edi
+ movl -484(%ebp), %ecx
+ notl %edi
+ shrl $23, %edi
+ xorl %edx, %edi
+ addl %eax, %edi
+ movl -524(%ebp), %edx
+ subl %edi, %ecx
+ movl %ecx, -792(%ebp)
+ movl -760(%ebp), %ecx
+ xorl %edx, %ecx
+ movl %ecx, -768(%ebp)
+ movl -528(%ebp), %eax
+ movl -764(%ebp), %edi
+ xorl %eax, %edi
+ movl %ecx, %eax
+ shrl $13, %eax
+ movl %edi, -772(%ebp)
+ andl $2040, %eax
+ movzbl %cl,%edi
+ movl 2048(%eax,%esi), %edx
+ movl (%esi,%edi,8), %ecx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -772(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -772(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -748(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -748(%ebp)
+ movl -752(%ebp), %edi
+ setb %al
+ addl %eax, %edx
+ subl %ecx, %esi
+ subl %edx, %edi
+ movl %esi, -860(%ebp)
+ movl -768(%ebp), %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ movl %edi, -864(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -772(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -772(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ movl -740(%ebp), %esi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -736(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ setb %al
+ leal 0(,%edi,8), %ecx
+ addl %eax, %edx
+ addl %esi, %edx
+ movl %edi, %eax
+ movl %edx, -776(%ebp)
+ shrl $29, %eax
+ movl -776(%ebp), %esi
+ sall $3, %esi
+ orl %eax, %esi
+ xorl %eax, %eax
+ cmpl %edi, %ecx
+ setb %al
+ subl %edi, %ecx
+ movl %ecx, -780(%ebp)
+ movl -776(%ebp), %edx
+ movl -788(%ebp), %ecx
+ movl -568(%ebp), %edi
+ addl %edx, %eax
+ movl -524(%ebp), %edx
+ subl %eax, %esi
+ xorl %eax, %eax
+ xorl %ecx, %edx
+ movl %esi, -784(%ebp)
+ movl -528(%ebp), %ecx
+ movl -792(%ebp), %esi
+ movl %edx, -796(%ebp)
+ xorl %esi, %ecx
+ movl -564(%ebp), %esi
+ movl %ecx, -804(%ebp)
+ addl %edx, %esi
+ cmpl %edx, %esi
+ movl %esi, -800(%ebp)
+ setb %al
+ addl %ecx, %eax
+ addl %edi, %eax
+ movl %eax, -808(%ebp)
+ movl %edx, %eax
+ notl %eax
+ sall $19, %eax
+ xorl %esi, %eax
+ movl -604(%ebp), %esi
+ cmpl %eax, -604(%ebp)
+ setb %dl
+ movzbl %dl, %edi
+ subl %eax, %esi
+ movl %ecx, %edx
+ movl -796(%ebp), %ecx
+ movl %esi, -812(%ebp)
+ movl -808(%ebp), %esi
+ sall $19, %edx
+ movl -612(%ebp), %eax
+ shrl $13, %ecx
+ orl %ecx, %edx
+ notl %esi
+ movl -680(%ebp), %ecx
+ xorl %edx, %esi
+ addl %edi, %esi
+ movl -812(%ebp), %edi
+ subl %esi, %eax
+ movl %eax, -816(%ebp)
+ movl -608(%ebp), %esi
+ movl -684(%ebp), %edx
+ xorl %edi, %esi
+ movl -644(%ebp), %edi
+ addl %esi, %ecx
+ movl %ecx, -824(%ebp)
+ movl %esi, -820(%ebp)
+ xorl %eax, %edi
+ cmpl %esi, %ecx
+ movl %edi, -828(%ebp)
+ setb %al
+ movzbl %al, %ecx
+ addl %edi, %ecx
+ movl %esi, %eax
+ addl %edx, %ecx
+ movl %ecx, -832(%ebp)
+ movl -824(%ebp), %ecx
+ movl %edi, %esi
+ sall $9, %esi
+ xorl %edx, %edx
+ shrl $23, %eax
+ orl %esi, %eax
+ notl %ecx
+ xorl %eax, %ecx
+ cmpl %ecx, -716(%ebp)
+ movl %edi, %eax
+ movl -716(%ebp), %esi
+ notl %eax
+ movl -724(%ebp), %edi
+ setb %dl
+ subl %ecx, %esi
+ movl -832(%ebp), %ecx
+ shrl $23, %eax
+ movl %esi, -836(%ebp)
+ xorl %ecx, %eax
+ addl %edx, %eax
+ subl %eax, %edi
+ movl %edi, -840(%ebp)
+ movl -720(%ebp), %edx
+ movl -788(%ebp), %ecx
+ xorl %esi, %edx
+ movl -756(%ebp), %esi
+ addl %edx, %ecx
+ movl %edx, -844(%ebp)
+ movl %ecx, -848(%ebp)
+ xorl %edi, %esi
+ cmpl %edx, %ecx
+ movl %esi, -852(%ebp)
+ setb %al
+ movl -792(%ebp), %edx
+ movzbl %al, %eax
+ movl %ecx, %edi
+ addl %esi, %eax
+ addl %edx, %eax
+ xorl $-1985229329, %edi
+ movl -796(%ebp), %esi
+ movl %eax, -856(%ebp)
+ xorl %ecx, %ecx
+ cmpl %edi, -796(%ebp)
+ movl -856(%ebp), %eax
+ movl -800(%ebp), %edx
+ setb %cl
+ xorl $19088743, %eax
+ subl %edi, %esi
+ movl %esi, -884(%ebp)
+ addl %ecx, %eax
+ movl -804(%ebp), %ecx
+ movl -808(%ebp), %edi
+ movl -864(%ebp), %esi
+ subl %eax, %ecx
+ movl %ecx, -888(%ebp)
+ movl -860(%ebp), %eax
+ movl tiger_table@GOT(%ebx), %ecx
+ xorl %edi, %esi
+ xorl %edx, %eax
+ movzbl %al,%edi
+ movl %eax, -868(%ebp)
+ shrl $13, %eax
+ andl $2040, %eax
+ movl %esi, -872(%ebp)
+ movl 2048(%eax,%ecx), %edx
+ movl %ecx, %esi
+ movl (%ecx,%edi,8), %ecx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -872(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -872(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -780(%ebp), %edi
+ cmpl %ecx, -780(%ebp)
+ setb %al
+ subl %ecx, %edi
+ movl %edi, -892(%ebp)
+ movl -868(%ebp), %ecx
+ movl -784(%ebp), %edi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %edi
+ movl %edi, -896(%ebp)
+ leal 0(,%eax,8), %edi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%edi,%esi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -872(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -872(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -768(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -772(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ movl %edx, -876(%ebp)
+ leal 0(,%edi,8), %ecx
+ addl %ecx, %edi
+ movl %edi, -880(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -876(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl -812(%ebp), %eax
+ addl %ecx, %edx
+ movl -816(%ebp), %edi
+ movl %edx, -908(%ebp)
+ movl -892(%ebp), %edx
+ movl -896(%ebp), %ecx
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %edi, %ecx
+ movl %ecx, -904(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ movl %edx, -900(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%esi), %edx
+ movl (%esi,%edi,8), %ecx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -904(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -904(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -880(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -880(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -920(%ebp)
+ movl -908(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -900(%ebp), %edx
+ movl %edi, -924(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -904(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -904(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -868(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -872(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,8), %ecx
+ movl %edx, -912(%ebp)
+ addl %ecx, %edi
+ shrl $29, %eax
+ movl %edi, -916(%ebp)
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -912(%ebp), %ecx
+ setb %al
+ movl -828(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -820(%ebp), %eax
+ movl -924(%ebp), %ecx
+ movl %edx, -936(%ebp)
+ movl -920(%ebp), %edx
+ xorl %edi, %ecx
+ movl %ecx, -932(%ebp)
+ xorl %eax, %edx
+ movl %edx, %eax
+ movl %edx, -928(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -932(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -932(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -916(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -916(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -948(%ebp)
+ movl -936(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -928(%ebp), %edx
+ movl %edi, -952(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -932(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -932(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -900(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -904(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,8), %ecx
+ movl %edx, -940(%ebp)
+ addl %ecx, %edi
+ shrl $29, %eax
+ movl %edi, -944(%ebp)
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -940(%ebp), %ecx
+ setb %al
+ movl -832(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -824(%ebp), %eax
+ movl -952(%ebp), %ecx
+ movl %edx, -964(%ebp)
+ movl -948(%ebp), %edx
+ xorl %edi, %ecx
+ movl %ecx, -960(%ebp)
+ xorl %eax, %edx
+ movl %edx, %eax
+ movl %edx, -956(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -960(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -960(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -944(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -944(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -976(%ebp)
+ movl -964(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -956(%ebp), %edx
+ movl %edi, -980(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -960(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -960(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -928(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -932(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,8), %ecx
+ movl %edx, -968(%ebp)
+ addl %ecx, %edi
+ shrl $29, %eax
+ movl %edi, -972(%ebp)
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -968(%ebp), %ecx
+ setb %al
+ movl -840(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -836(%ebp), %eax
+ movl -980(%ebp), %ecx
+ movl %edx, -992(%ebp)
+ movl -976(%ebp), %edx
+ xorl %edi, %ecx
+ movl %ecx, -988(%ebp)
+ xorl %eax, %edx
+ movl %edx, %eax
+ movl %edx, -984(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -988(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -988(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -972(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -972(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -1004(%ebp)
+ movl -992(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -984(%ebp), %edx
+ movl %edi, -1008(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -988(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -988(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -956(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -960(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,8), %ecx
+ movl %edx, -996(%ebp)
+ addl %ecx, %edi
+ shrl $29, %eax
+ movl %edi, -1000(%ebp)
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -996(%ebp), %ecx
+ setb %al
+ movl -852(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -844(%ebp), %eax
+ movl -1008(%ebp), %ecx
+ movl %edx, -1020(%ebp)
+ movl -1004(%ebp), %edx
+ xorl %edi, %ecx
+ movl %ecx, -1016(%ebp)
+ xorl %eax, %edx
+ movl %edx, %eax
+ movl %edx, -1012(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -1016(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -1016(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -1000(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -1000(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -1032(%ebp)
+ movl -1020(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -1012(%ebp), %edx
+ movl %edi, -1036(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -1016(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -1016(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ movl %esi, -148(%ebp)
+ xorl %edi, %edx
+ movl -984(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -988(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl %edx, -1024(%ebp)
+ leal 0(,%edi,8), %ecx
+ movl %edi, %eax
+ shrl $29, %eax
+ addl %ecx, %edi
+ sall $3, %edx
+ movl %edi, -1028(%ebp)
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -1024(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl -848(%ebp), %eax
+ movl -856(%ebp), %edi
+ addl %ecx, %edx
+ movl -1036(%ebp), %ecx
+ movl %edx, -1048(%ebp)
+ movl -1032(%ebp), %edx
+ xorl %edi, %ecx
+ movl %ecx, -1044(%ebp)
+ xorl %eax, %edx
+ movl %edx, %eax
+ movl %edx, -1040(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -1044(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -1044(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -1028(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -1028(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -1060(%ebp)
+ movl -1048(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -1040(%ebp), %edx
+ movl %edi, -1064(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -1044(%ebp), %eax
+ movzbl %ah, %edi
+ leal 0(,%edi,8), %eax
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -1044(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ movl -1012(%ebp), %edi
+ addl %ecx, %edi
+ cmpl %ecx, %edi
+ movl -1016(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %edi, %eax
+ addl %ecx, %edx
+ leal 0(,%edi,8), %ecx
+ movl %edx, -1052(%ebp)
+ addl %ecx, %edi
+ shrl $29, %eax
+ movl %edi, -1056(%ebp)
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %edi
+ movl -1052(%ebp), %ecx
+ setb %al
+ movl -888(%ebp), %edi
+ addl %eax, %edx
+ addl %ecx, %edx
+ movl -884(%ebp), %eax
+ movl -1064(%ebp), %ecx
+ movl %edx, -1076(%ebp)
+ movl -1060(%ebp), %edx
+ xorl %edi, %ecx
+ movl %ecx, -1072(%ebp)
+ xorl %eax, %edx
+ movl %edx, %eax
+ movl %edx, -1068(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%edi
+ andl $2040, %eax
+ movl (%esi,%edi,8), %ecx
+ movl 2048(%eax,%esi), %edx
+ movl 2052(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 4(%esi,%edi,8), %edx
+ xorl %eax, %edx
+ movzbl -1072(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 4100(%eax,%esi), %edi
+ movl -1072(%ebp), %eax
+ xorl %edi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 6148(%eax,%esi), %edi
+ xorl %eax, %eax
+ movl -1056(%ebp), %esi
+ xorl %edi, %edx
+ cmpl %ecx, -1056(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -1080(%ebp)
+ movl -1076(%ebp), %edi
+ addl %eax, %edx
+ movl tiger_table@GOT(%ebx), %ecx
+ subl %edx, %edi
+ movl -1068(%ebp), %edx
+ movl %edi, -1084(%ebp)
+ movl %edx, %eax
+ movzbl %dh, %esi
+ shrl $24, %eax
+ leal 0(,%esi,8), %edi
+ movl %ecx, %esi
+ sall $3, %eax
+ movl 4096(%eax,%ecx), %edx
+ movl 6144(%edi,%ecx), %ecx
+ movl 4100(%eax,%esi), %eax
+ xorl %edx, %ecx
+ movl 6148(%edi,%esi), %edx
+ xorl %eax, %edx
+ movl -1072(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl -148(%ebp), %esi
+ movl 2048(%eax,%esi), %edi
+ xorl %edi, %ecx
+ movl 2052(%eax,%esi), %edi
+ movl -1072(%ebp), %eax
+ xorl %edi, %edx
+ shrl $24, %eax
+ movl (%esi,%eax,8), %edi
+ xorl %edi, %ecx
+ movl 4(%esi,%eax,8), %edi
+ movl -1040(%ebp), %esi
+ xorl %eax, %eax
+ xorl %edi, %edx
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -1044(%ebp), %edi
+ setb %al
+ addl %eax, %edx
+ leal 0(,%esi,8), %ecx
+ addl %edx, %edi
+ movl %esi, %eax
+ leal 0(,%edi,8), %edx
+ addl %ecx, %esi
+ shrl $29, %eax
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ setb %al
+ addl %eax, %edx
+ leal (%edi,%edx), %ecx
+ movl -1088(%ebp), %edi
+ movl -1092(%ebp), %edx
+ xorl %esi, %edi
+ movl -16(%ebp), %esi
+ xorl %edx, %ecx
+ cmpl %esi, -1068(%ebp)
+ movl %ecx, -1108(%ebp)
+ movl -16(%ebp), %edx
+ movl -1068(%ebp), %esi
+ movl -1100(%ebp), %ecx
+ setb %al
+ subl %edx, %esi
+ movl -1072(%ebp), %edx
+ movzbl %al, %eax
+ addl %ecx, %eax
+ movl -1080(%ebp), %ecx
+ subl %eax, %edx
+ movl -20(%ebp), %eax
+ addl %eax, %ecx
+ xorl %eax, %eax
+ cmpl -20(%ebp), %ecx
+ setb %al
+ addl -1104(%ebp), %eax
+ addl -1084(%ebp), %eax
+ movl %eax, -1152(%ebp)
+ movl 12(%ebp), %eax
+ movl %edi, (%eax)
+ movl -1108(%ebp), %edi
+ movl %esi, 8(%eax)
+ movl %edx, 12(%eax)
+ movl %edi, 4(%eax)
+ movl %ecx, 16(%eax)
+ movl -1152(%ebp), %edx
+ movl %edx, 20(%eax)
+ addl $1140, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ ret
+ .size tiger_compress, .-tiger_compress
+.globl tiger_t
+ .type tiger_t, @function
+tiger_t:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ subl $1032, %esp
+ movl 12(%ebp), %eax
+ call __i686.get_pc_thunk.bx
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl %eax, -16(%ebp)
+ cmpl $63, %eax
+ jbe .L8
+ movl tiger_table@GOT(%ebx), %edi
+.L6:
+ movl 16(%ebp), %esi
+ movl 16(%ebp), %edx
+ movl (%esi), %ecx
+ movl 16(%ebp), %esi
+ movl %ecx, -948(%ebp)
+ movl 4(%edx), %eax
+ movl 16(%ebp), %edx
+ movl %eax, -952(%ebp)
+ movl 8(%esi), %ecx
+ movl 16(%ebp), %esi
+ movl %ecx, -956(%ebp)
+ movl 12(%edx), %eax
+ movl -956(%ebp), %edx
+ movl %eax, -960(%ebp)
+ movl 16(%esi), %eax
+ movl 20(%esi), %ecx
+ movl %edx, -20(%ebp)
+ movl 8(%ebp), %esi
+ movl 8(%ebp), %edx
+ movl %eax, -24(%ebp)
+ movl %ecx, -964(%ebp)
+ movl (%esi), %ecx
+ movl %ecx, -968(%ebp)
+ movl 4(%edx), %esi
+ movl 8(%ebp), %ecx
+ movl %esi, -972(%ebp)
+ movl 8(%ecx), %edx
+ movl 8(%ebp), %esi
+ movl %edx, -976(%ebp)
+ movl 12(%esi), %ecx
+ movl 8(%ebp), %edx
+ movl %ecx, -980(%ebp)
+ movl 16(%edx), %esi
+ movl %esi, -984(%ebp)
+ movl 8(%ebp), %ecx
+ movl 8(%ebp), %esi
+ movl 20(%ecx), %edx
+ movl %edx, -988(%ebp)
+ movl 24(%esi), %ecx
+ movl 8(%ebp), %edx
+ movl %ecx, -992(%ebp)
+ movl 28(%edx), %esi
+ movl 8(%ebp), %ecx
+ movl %esi, -996(%ebp)
+ movl 32(%ecx), %edx
+ movl 8(%ebp), %esi
+ movl %edx, -1000(%ebp)
+ movl 36(%esi), %ecx
+ movl 8(%ebp), %edx
+ movl %ecx, -1004(%ebp)
+ movl 40(%edx), %esi
+ movl 8(%ebp), %ecx
+ movl %esi, -1008(%ebp)
+ movl 44(%ecx), %edx
+ movl 8(%ebp), %esi
+ movl %edx, -1012(%ebp)
+ movl 48(%esi), %ecx
+ movl 8(%ebp), %edx
+ movl %ecx, -1016(%ebp)
+ movl 52(%edx), %esi
+ movl 8(%ebp), %ecx
+ movl %esi, -1020(%ebp)
+ movl 56(%ecx), %edx
+ movl 8(%ebp), %esi
+ movl %edx, -1024(%ebp)
+ movl -968(%ebp), %edx
+ movl 60(%esi), %ecx
+ xorl %edx, %eax
+ movl %ecx, -1028(%ebp)
+ movl %eax, -28(%ebp)
+ movl -972(%ebp), %esi
+ movl -964(%ebp), %ecx
+ movl -28(%ebp), %eax
+ xorl %esi, %ecx
+ shrl $13, %eax
+ movzbl -28(%ebp),%esi
+ movl %ecx, -32(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ movl (%edi,%esi,8), %ecx
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -32(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -32(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -948(%ebp), %esi
+ cmpl %ecx, -948(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -44(%ebp)
+ movl -952(%ebp), %ecx
+ addl %eax, %edx
+ subl %edx, %ecx
+ movl -28(%ebp), %edx
+ movl %ecx, -48(%ebp)
+ movzbl %dh, %eax
+ leal 0(,%eax,8), %ecx
+ movl %edx, %eax
+ movl 6144(%ecx,%edi), %esi
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6148(%ecx,%edi), %ecx
+ movl 4096(%eax,%edi), %edx
+ xorl %esi, %edx
+ movl 4100(%eax,%edi), %esi
+ movl -32(%ebp), %eax
+ xorl %esi, %ecx
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %edx
+ movl 2052(%eax,%edi), %esi
+ movl -32(%ebp), %eax
+ xorl %esi, %ecx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %edx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %ecx
+ movl -956(%ebp), %esi
+ addl %edx, %esi
+ cmpl %edx, %esi
+ movl -960(%ebp), %edx
+ setb %al
+ leal (%ecx,%eax), %eax
+ addl %edx, %eax
+ movl %eax, -36(%ebp)
+ leal 0(,%esi,4), %ecx
+ movl %eax, %edx
+ movl %esi, %eax
+ sall $2, %edx
+ addl %ecx, %esi
+ movl %esi, -40(%ebp)
+ shrl $30, %eax
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ setb %al
+ addl %eax, %edx
+ movl -36(%ebp), %eax
+ xorl %ecx, %ecx
+ movl -968(%ebp), %esi
+ addl %eax, %edx
+ movl -1028(%ebp), %eax
+ movl %edx, -60(%ebp)
+ movl -1024(%ebp), %edx
+ xorl $-1515870811, %edx
+ cmpl %edx, -968(%ebp)
+ setb %cl
+ subl %edx, %esi
+ movl %esi, -72(%ebp)
+ movl -972(%ebp), %esi
+ xorl $-1515870811, %eax
+ addl %ecx, %eax
+ movl -976(%ebp), %edx
+ movl -980(%ebp), %ecx
+ subl %eax, %esi
+ movl -44(%ebp), %eax
+ movl %esi, -76(%ebp)
+ movl -48(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -52(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -56(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -56(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -56(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -40(%ebp), %esi
+ cmpl %ecx, -40(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -80(%ebp)
+ movl -52(%ebp), %ecx
+ addl %eax, %edx
+ movl -60(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -84(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -56(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -56(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -28(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -32(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -64(%ebp)
+ leal 0(,%esi,4), %ecx
+ addl %ecx, %esi
+ movl %esi, -68(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -64(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -976(%ebp), %ecx
+ addl %esi, %edx
+ movl -76(%ebp), %eax
+ movl %edx, -96(%ebp)
+ movl -980(%ebp), %esi
+ movl -72(%ebp), %edx
+ xorl %eax, %esi
+ xorl %edx, %ecx
+ movl %esi, -116(%ebp)
+ movl -984(%ebp), %edx
+ movl %ecx, -108(%ebp)
+ movl -80(%ebp), %eax
+ movl -988(%ebp), %ecx
+ movl -84(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -88(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -92(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -92(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -92(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -68(%ebp), %esi
+ cmpl %ecx, -68(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -120(%ebp)
+ movl -88(%ebp), %ecx
+ addl %eax, %edx
+ movl -96(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -124(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -92(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -92(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -52(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -56(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -100(%ebp)
+ leal 0(,%esi,4), %ecx
+ addl %ecx, %esi
+ movl %esi, -104(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -100(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl -108(%ebp), %eax
+ addl %ecx, %edx
+ movl -108(%ebp), %esi
+ movl %edx, -136(%ebp)
+ movl -984(%ebp), %edx
+ movl -116(%ebp), %ecx
+ addl %eax, %edx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ movl %edx, -112(%ebp)
+ movl -988(%ebp), %esi
+ setb %al
+ addl %ecx, %eax
+ movl -992(%ebp), %edx
+ movl -996(%ebp), %ecx
+ addl %esi, %eax
+ movl -124(%ebp), %esi
+ movl %eax, -148(%ebp)
+ movl -120(%ebp), %eax
+ xorl %ecx, %esi
+ movl %esi, -132(%ebp)
+ xorl %edx, %eax
+ movzbl %al,%esi
+ movl %eax, -128(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -132(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -132(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -104(%ebp), %esi
+ cmpl %ecx, -104(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -152(%ebp)
+ movl -128(%ebp), %ecx
+ addl %eax, %edx
+ movl -136(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -156(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -132(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -132(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -88(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -92(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -140(%ebp)
+ leal 0(,%esi,4), %ecx
+ addl %ecx, %esi
+ movl %esi, -144(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ setb %al
+ movl -112(%ebp), %esi
+ addl %eax, %edx
+ movl -140(%ebp), %eax
+ addl %eax, %edx
+ movl -108(%ebp), %eax
+ movl %edx, -168(%ebp)
+ movl -992(%ebp), %edx
+ notl %eax
+ sall $19, %eax
+ xorl %esi, %eax
+ cmpl %eax, -992(%ebp)
+ setb %cl
+ movzbl %cl, %esi
+ subl %eax, %edx
+ movl -108(%ebp), %ecx
+ movl -116(%ebp), %eax
+ movl %edx, -180(%ebp)
+ movl -148(%ebp), %edx
+ shrl $13, %ecx
+ sall $19, %eax
+ orl %ecx, %eax
+ notl %edx
+ xorl %eax, %edx
+ movl -996(%ebp), %eax
+ addl %esi, %edx
+ movl -1004(%ebp), %ecx
+ subl %edx, %eax
+ movl -156(%ebp), %esi
+ movl %eax, -184(%ebp)
+ movl -1000(%ebp), %edx
+ movl -152(%ebp), %eax
+ xorl %ecx, %esi
+ movl %esi, -164(%ebp)
+ xorl %edx, %eax
+ movzbl %al,%esi
+ movl %eax, -160(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -164(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -164(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -144(%ebp), %esi
+ cmpl %ecx, -144(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -188(%ebp)
+ movl -168(%ebp), %esi
+ addl %eax, %edx
+ subl %edx, %esi
+ movl %esi, -192(%ebp)
+ movl -160(%ebp), %ecx
+ movzbl %ch, %eax
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6144(%esi,%edi), %ecx
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -164(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -164(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -128(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -132(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ leal 0(,%esi,4), %ecx
+ movl %edx, -172(%ebp)
+ addl %ecx, %esi
+ shrl $30, %eax
+ movl %esi, -176(%ebp)
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -172(%ebp), %esi
+ setb %al
+ movl -1000(%ebp), %ecx
+ addl %eax, %edx
+ addl %esi, %edx
+ movl -184(%ebp), %eax
+ movl -1004(%ebp), %esi
+ movl %edx, -204(%ebp)
+ movl -180(%ebp), %edx
+ xorl %eax, %esi
+ movl %esi, -224(%ebp)
+ movl -188(%ebp), %eax
+ xorl %edx, %ecx
+ movl %ecx, -216(%ebp)
+ movl -1008(%ebp), %edx
+ movl -1012(%ebp), %ecx
+ movl -192(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -196(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -200(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -200(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -200(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -176(%ebp), %esi
+ cmpl %ecx, -176(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -228(%ebp)
+ movl -196(%ebp), %ecx
+ movl -204(%ebp), %esi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -232(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -200(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -200(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -160(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -164(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -208(%ebp)
+ leal 0(,%esi,4), %ecx
+ addl %ecx, %esi
+ movl %esi, -212(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -208(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl -216(%ebp), %eax
+ addl %ecx, %edx
+ movl -216(%ebp), %esi
+ movl %edx, -244(%ebp)
+ movl -1008(%ebp), %edx
+ movl -224(%ebp), %ecx
+ addl %eax, %edx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ movl %edx, -220(%ebp)
+ movl -1012(%ebp), %esi
+ setb %al
+ addl %ecx, %eax
+ movl -1016(%ebp), %edx
+ movl -1020(%ebp), %ecx
+ addl %esi, %eax
+ movl -232(%ebp), %esi
+ movl %eax, -256(%ebp)
+ movl -228(%ebp), %eax
+ xorl %ecx, %esi
+ movl %esi, -240(%ebp)
+ xorl %edx, %eax
+ movzbl %al,%esi
+ movl %eax, -236(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -240(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -240(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -212(%ebp), %esi
+ cmpl %ecx, -212(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -260(%ebp)
+ movl -236(%ebp), %ecx
+ movl -244(%ebp), %esi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -264(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -240(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -240(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -196(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -200(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -248(%ebp)
+ leal 0(,%esi,4), %ecx
+ addl %ecx, %esi
+ movl %esi, -252(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -248(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -216(%ebp), %eax
+ addl %esi, %edx
+ movl -220(%ebp), %ecx
+ movl %edx, -276(%ebp)
+ movl -224(%ebp), %edx
+ shrl $23, %eax
+ notl %ecx
+ movl -1016(%ebp), %esi
+ sall $9, %edx
+ orl %edx, %eax
+ xorl %eax, %ecx
+ xorl %edx, %edx
+ cmpl %ecx, -1016(%ebp)
+ movl -224(%ebp), %eax
+ setb %dl
+ subl %ecx, %esi
+ movl -256(%ebp), %ecx
+ notl %eax
+ movl %esi, -288(%ebp)
+ shrl $23, %eax
+ movl -1020(%ebp), %esi
+ xorl %ecx, %eax
+ addl %edx, %eax
+ movl -1028(%ebp), %ecx
+ subl %eax, %esi
+ movl -1024(%ebp), %edx
+ movl -260(%ebp), %eax
+ movl %esi, -292(%ebp)
+ movl -264(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -268(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -272(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -272(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -272(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -252(%ebp), %esi
+ cmpl %ecx, -252(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -360(%ebp)
+ movl -268(%ebp), %ecx
+ addl %eax, %edx
+ movl -276(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -364(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -272(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -272(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -236(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -240(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -280(%ebp)
+ leal 0(,%esi,4), %ecx
+ addl %ecx, %esi
+ movl %esi, -284(%ebp)
+ shrl $30, %eax
+ sall $2, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -280(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl -288(%ebp), %esi
+ addl %ecx, %edx
+ movl %edx, -376(%ebp)
+ movl -1024(%ebp), %edx
+ xorl %esi, %edx
+ movl %edx, -296(%ebp)
+ movl -72(%ebp), %ecx
+ movl -292(%ebp), %eax
+ movl -1028(%ebp), %esi
+ addl %edx, %ecx
+ movl %ecx, -300(%ebp)
+ xorl %eax, %esi
+ cmpl %edx, %ecx
+ movl %esi, -304(%ebp)
+ setb %al
+ movl -76(%ebp), %ecx
+ movzbl %al, %eax
+ addl %esi, %eax
+ addl %ecx, %eax
+ movl %eax, -308(%ebp)
+ movl -300(%ebp), %esi
+ movl %edx, %eax
+ notl %eax
+ movl -108(%ebp), %edx
+ sall $19, %eax
+ xorl %esi, %eax
+ cmpl %eax, -108(%ebp)
+ setb %cl
+ movzbl %cl, %esi
+ subl %eax, %edx
+ movl -296(%ebp), %ecx
+ movl -304(%ebp), %eax
+ movl %edx, -312(%ebp)
+ movl -308(%ebp), %edx
+ shrl $13, %ecx
+ sall $19, %eax
+ orl %ecx, %eax
+ notl %edx
+ xorl %eax, %edx
+ movl -112(%ebp), %ecx
+ addl %esi, %edx
+ movl -116(%ebp), %esi
+ subl %edx, %esi
+ movl -312(%ebp), %edx
+ movl %esi, -316(%ebp)
+ xorl %edx, %ecx
+ movl -148(%ebp), %edx
+ movl %ecx, -320(%ebp)
+ xorl %esi, %edx
+ movl -180(%ebp), %esi
+ movl %edx, -328(%ebp)
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl %esi, -324(%ebp)
+ setb %al
+ movl -184(%ebp), %ecx
+ movzbl %al, %eax
+ addl %edx, %eax
+ addl %ecx, %eax
+ movl %eax, -332(%ebp)
+ movl -320(%ebp), %eax
+ sall $9, %edx
+ movl %esi, %ecx
+ notl %ecx
+ movl -216(%ebp), %esi
+ shrl $23, %eax
+ orl %edx, %eax
+ xorl %eax, %ecx
+ xorl %edx, %edx
+ cmpl %ecx, -216(%ebp)
+ movl -328(%ebp), %eax
+ setb %dl
+ subl %ecx, %esi
+ movl -332(%ebp), %ecx
+ notl %eax
+ movl %esi, -336(%ebp)
+ shrl $23, %eax
+ xorl %ecx, %eax
+ addl %edx, %eax
+ movl -336(%ebp), %esi
+ movl -224(%ebp), %edx
+ movl -220(%ebp), %ecx
+ subl %eax, %edx
+ xorl %esi, %ecx
+ movl %edx, -340(%ebp)
+ movl %ecx, -344(%ebp)
+ movl -256(%ebp), %eax
+ xorl %edx, %eax
+ movl %eax, -352(%ebp)
+ movl -288(%ebp), %edx
+ movl -352(%ebp), %esi
+ xorl %eax, %eax
+ addl %ecx, %edx
+ cmpl %ecx, %edx
+ movl %edx, -348(%ebp)
+ movl -292(%ebp), %ecx
+ setb %al
+ addl %esi, %eax
+ xorl $-1985229329, %edx
+ movl -296(%ebp), %esi
+ addl %ecx, %eax
+ xorl %ecx, %ecx
+ cmpl %edx, -296(%ebp)
+ movl %eax, -356(%ebp)
+ movl -356(%ebp), %eax
+ setb %cl
+ subl %edx, %esi
+ xorl $19088743, %eax
+ addl %ecx, %eax
+ movl %esi, -392(%ebp)
+ movl -304(%ebp), %esi
+ movl -300(%ebp), %edx
+ movl -308(%ebp), %ecx
+ subl %eax, %esi
+ movl -360(%ebp), %eax
+ movl %esi, -396(%ebp)
+ movl -364(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -368(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -372(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -372(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -372(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -284(%ebp), %esi
+ cmpl %ecx, -284(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -400(%ebp)
+ movl -376(%ebp), %esi
+ addl %eax, %edx
+ subl %edx, %esi
+ movl %esi, -404(%ebp)
+ movl -368(%ebp), %ecx
+ movzbl %ch, %eax
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6144(%esi,%edi), %ecx
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -372(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -372(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -268(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -272(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ shrl $29, %eax
+ movl %edx, -380(%ebp)
+ movl -380(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl %edx, -384(%ebp)
+ movl -380(%ebp), %esi
+ movl -392(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ xorl $-1515870811, %edx
+ movl %ecx, -388(%ebp)
+ xorl %ecx, %ecx
+ cmpl %edx, -300(%ebp)
+ movl -300(%ebp), %esi
+ movl -396(%ebp), %eax
+ setb %cl
+ subl %edx, %esi
+ xorl $-1515870811, %eax
+ movl %esi, -428(%ebp)
+ movl -308(%ebp), %esi
+ addl %ecx, %eax
+ movl -312(%ebp), %edx
+ movl -316(%ebp), %ecx
+ subl %eax, %esi
+ movl %esi, -432(%ebp)
+ movl -400(%ebp), %eax
+ movl -404(%ebp), %esi
+ xorl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -412(%ebp)
+ movzbl %al,%esi
+ movl %eax, -408(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -412(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -412(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -384(%ebp), %esi
+ cmpl %ecx, -384(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -436(%ebp)
+ movl -408(%ebp), %ecx
+ movl -388(%ebp), %esi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -440(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -412(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -412(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -368(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -372(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -416(%ebp)
+ shrl $29, %eax
+ movl -416(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -416(%ebp), %esi
+ movl %edx, -420(%ebp)
+ movl -428(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -316(%ebp), %esi
+ movl -432(%ebp), %eax
+ movl %ecx, -424(%ebp)
+ movl -312(%ebp), %ecx
+ xorl %eax, %esi
+ movl %esi, -472(%ebp)
+ movl -436(%ebp), %eax
+ xorl %edx, %ecx
+ movl %ecx, -464(%ebp)
+ movl -320(%ebp), %edx
+ movl -328(%ebp), %ecx
+ movl -440(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -444(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -448(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -448(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -448(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -420(%ebp), %esi
+ cmpl %ecx, -420(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -476(%ebp)
+ movl -444(%ebp), %ecx
+ movl -424(%ebp), %esi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -480(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -448(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -448(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -408(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -412(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -452(%ebp)
+ shrl $29, %eax
+ movl -452(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -452(%ebp), %esi
+ movl %edx, -456(%ebp)
+ movl -320(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -464(%ebp), %eax
+ movl -464(%ebp), %esi
+ movl %ecx, -460(%ebp)
+ addl %eax, %edx
+ movl -472(%ebp), %ecx
+ movl %edx, -468(%ebp)
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ movl -328(%ebp), %esi
+ setb %al
+ addl %ecx, %eax
+ movl -324(%ebp), %edx
+ addl %esi, %eax
+ movl -332(%ebp), %ecx
+ movl %eax, -504(%ebp)
+ movl -480(%ebp), %esi
+ movl -476(%ebp), %eax
+ xorl %ecx, %esi
+ xorl %edx, %eax
+ movl %esi, -488(%ebp)
+ movzbl %al,%esi
+ movl %eax, -484(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -488(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -488(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -456(%ebp), %esi
+ cmpl %ecx, -456(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -508(%ebp)
+ movl -484(%ebp), %ecx
+ movl -460(%ebp), %esi
+ addl %eax, %edx
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -512(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -488(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -488(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -444(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -448(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -492(%ebp)
+ shrl $29, %eax
+ movl -492(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -468(%ebp), %esi
+ movl %edx, -496(%ebp)
+ movl -492(%ebp), %edx
+ addl %edx, %eax
+ subl %eax, %ecx
+ movl -464(%ebp), %eax
+ movl -324(%ebp), %edx
+ movl %ecx, -500(%ebp)
+ notl %eax
+ sall $19, %eax
+ xorl %esi, %eax
+ cmpl %eax, -324(%ebp)
+ setb %cl
+ movzbl %cl, %esi
+ subl %eax, %edx
+ movl -464(%ebp), %ecx
+ movl -472(%ebp), %eax
+ movl %edx, -536(%ebp)
+ movl -504(%ebp), %edx
+ shrl $13, %ecx
+ sall $19, %eax
+ orl %ecx, %eax
+ notl %edx
+ xorl %eax, %edx
+ movl -332(%ebp), %eax
+ addl %esi, %edx
+ movl -340(%ebp), %ecx
+ subl %edx, %eax
+ movl -512(%ebp), %esi
+ movl %eax, -540(%ebp)
+ movl -336(%ebp), %edx
+ movl -508(%ebp), %eax
+ xorl %ecx, %esi
+ xorl %edx, %eax
+ movl %eax, -516(%ebp)
+ movl %esi, -520(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -520(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -520(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -496(%ebp), %esi
+ cmpl %ecx, -496(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -544(%ebp)
+ movl -516(%ebp), %ecx
+ addl %eax, %edx
+ movl -500(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -548(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -520(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -520(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -484(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -488(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -524(%ebp)
+ shrl $29, %eax
+ movl -524(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -524(%ebp), %esi
+ movl %edx, -528(%ebp)
+ movl -536(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl %ecx, -532(%ebp)
+ movl -336(%ebp), %ecx
+ xorl %edx, %ecx
+ movl %ecx, -572(%ebp)
+ movl -540(%ebp), %eax
+ movl -340(%ebp), %esi
+ movl -344(%ebp), %edx
+ movl -352(%ebp), %ecx
+ xorl %eax, %esi
+ movl %esi, -580(%ebp)
+ movl -544(%ebp), %eax
+ movl -548(%ebp), %esi
+ xorl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -556(%ebp)
+ movzbl %al,%esi
+ movl %eax, -552(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -556(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -556(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -528(%ebp), %esi
+ cmpl %ecx, -528(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -584(%ebp)
+ movl -552(%ebp), %ecx
+ addl %eax, %edx
+ movl -532(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -588(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -556(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -556(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -516(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -520(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -560(%ebp)
+ movl -560(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ shrl $29, %eax
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -560(%ebp), %esi
+ movl %edx, -564(%ebp)
+ movl -344(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -572(%ebp), %eax
+ movl -572(%ebp), %esi
+ movl %ecx, -568(%ebp)
+ addl %eax, %edx
+ movl -580(%ebp), %ecx
+ movl %edx, -576(%ebp)
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ movl -352(%ebp), %esi
+ setb %al
+ addl %ecx, %eax
+ movl -348(%ebp), %edx
+ addl %esi, %eax
+ movl -356(%ebp), %ecx
+ movl %eax, -612(%ebp)
+ movl -588(%ebp), %esi
+ movl -584(%ebp), %eax
+ xorl %ecx, %esi
+ xorl %edx, %eax
+ movl %esi, -596(%ebp)
+ movzbl %al,%esi
+ movl %eax, -592(%ebp)
+ shrl $13, %eax
+ movl (%edi,%esi,8), %ecx
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -596(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -596(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -564(%ebp), %esi
+ cmpl %ecx, -564(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -616(%ebp)
+ movl -592(%ebp), %ecx
+ addl %eax, %edx
+ movl -568(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -620(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -596(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -596(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -552(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -556(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -600(%ebp)
+ movl -600(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ shrl $29, %eax
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl -600(%ebp), %esi
+ movl %edx, -604(%ebp)
+ movl -580(%ebp), %edx
+ addl %esi, %eax
+ subl %eax, %ecx
+ movl -572(%ebp), %eax
+ sall $9, %edx
+ movl %ecx, -608(%ebp)
+ movl -576(%ebp), %ecx
+ shrl $23, %eax
+ orl %edx, %eax
+ xorl %edx, %edx
+ notl %ecx
+ xorl %eax, %ecx
+ movl -348(%ebp), %esi
+ movl -580(%ebp), %eax
+ cmpl %ecx, -348(%ebp)
+ notl %eax
+ setb %dl
+ subl %ecx, %esi
+ movl -612(%ebp), %ecx
+ shrl $23, %eax
+ movl %esi, -644(%ebp)
+ movl -356(%ebp), %esi
+ xorl %ecx, %eax
+ addl %edx, %eax
+ movl -396(%ebp), %ecx
+ movl -392(%ebp), %edx
+ subl %eax, %esi
+ movl -616(%ebp), %eax
+ movl %esi, -648(%ebp)
+ movl -620(%ebp), %esi
+ xorl %edx, %eax
+ movl %eax, -624(%ebp)
+ xorl %ecx, %esi
+ movl %esi, -628(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -628(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -628(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -604(%ebp), %esi
+ cmpl %ecx, -604(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -716(%ebp)
+ movl -608(%ebp), %esi
+ addl %eax, %edx
+ subl %edx, %esi
+ movl %esi, -720(%ebp)
+ movl -624(%ebp), %ecx
+ movzbl %ch, %eax
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ sall $3, %eax
+ movl 6144(%esi,%edi), %ecx
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -628(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -628(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -592(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -596(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ shrl $29, %eax
+ movl %edx, -632(%ebp)
+ movl -632(%ebp), %ecx
+ leal 0(,%esi,8), %edx
+ sall $3, %ecx
+ orl %eax, %ecx
+ xorl %eax, %eax
+ cmpl %esi, %edx
+ setb %al
+ subl %esi, %edx
+ movl %edx, -636(%ebp)
+ movl -632(%ebp), %edx
+ movl -644(%ebp), %esi
+ addl %edx, %eax
+ movl -392(%ebp), %edx
+ subl %eax, %ecx
+ movl %ecx, -640(%ebp)
+ movl -428(%ebp), %ecx
+ movl -648(%ebp), %eax
+ xorl %esi, %edx
+ movl -396(%ebp), %esi
+ addl %edx, %ecx
+ movl %ecx, -656(%ebp)
+ movl %edx, -652(%ebp)
+ xorl %eax, %esi
+ cmpl %edx, %ecx
+ movl %esi, -660(%ebp)
+ setb %al
+ movl -432(%ebp), %ecx
+ movzbl %al, %eax
+ addl %esi, %eax
+ addl %ecx, %eax
+ movl %eax, -664(%ebp)
+ movl -656(%ebp), %esi
+ movl %edx, %eax
+ notl %eax
+ movl -464(%ebp), %edx
+ sall $19, %eax
+ xorl %esi, %eax
+ cmpl %eax, -464(%ebp)
+ setb %cl
+ movzbl %cl, %esi
+ subl %eax, %edx
+ movl -652(%ebp), %ecx
+ movl -660(%ebp), %eax
+ movl %edx, -668(%ebp)
+ movl -664(%ebp), %edx
+ shrl $13, %ecx
+ sall $19, %eax
+ orl %ecx, %eax
+ notl %edx
+ xorl %eax, %edx
+ addl %esi, %edx
+ movl -472(%ebp), %esi
+ subl %edx, %esi
+ movl %esi, -672(%ebp)
+ movl -668(%ebp), %edx
+ movl -468(%ebp), %ecx
+ xorl %edx, %ecx
+ movl -504(%ebp), %edx
+ movl %ecx, -676(%ebp)
+ xorl %esi, %edx
+ movl -536(%ebp), %esi
+ movl %edx, -684(%ebp)
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl %esi, -680(%ebp)
+ setb %al
+ movl -540(%ebp), %ecx
+ movzbl %al, %eax
+ addl %edx, %eax
+ addl %ecx, %eax
+ movl %eax, -688(%ebp)
+ movl -676(%ebp), %eax
+ sall $9, %edx
+ movl %esi, %ecx
+ notl %ecx
+ movl -572(%ebp), %esi
+ shrl $23, %eax
+ orl %edx, %eax
+ xorl %eax, %ecx
+ xorl %edx, %edx
+ cmpl %ecx, -572(%ebp)
+ movl -684(%ebp), %eax
+ setb %dl
+ subl %ecx, %esi
+ movl -688(%ebp), %ecx
+ notl %eax
+ movl %esi, -692(%ebp)
+ shrl $23, %eax
+ xorl %ecx, %eax
+ addl %edx, %eax
+ movl -580(%ebp), %edx
+ movl -692(%ebp), %esi
+ movl -576(%ebp), %ecx
+ subl %eax, %edx
+ movl -612(%ebp), %eax
+ movl %edx, -696(%ebp)
+ xorl %esi, %ecx
+ movl %ecx, -700(%ebp)
+ xorl %edx, %eax
+ movl -644(%ebp), %edx
+ movl %eax, -708(%ebp)
+ movl -708(%ebp), %esi
+ xorl %eax, %eax
+ addl %ecx, %edx
+ cmpl %ecx, %edx
+ movl -648(%ebp), %ecx
+ movl %edx, -704(%ebp)
+ setb %al
+ addl %esi, %eax
+ xorl $-1985229329, %edx
+ addl %ecx, %eax
+ movl -652(%ebp), %esi
+ movl %eax, -712(%ebp)
+ xorl %ecx, %ecx
+ movl -712(%ebp), %eax
+ cmpl %edx, -652(%ebp)
+ setb %cl
+ subl %edx, %esi
+ movl %esi, -740(%ebp)
+ movl -660(%ebp), %esi
+ xorl $19088743, %eax
+ addl %ecx, %eax
+ movl -656(%ebp), %edx
+ subl %eax, %esi
+ movl %esi, -744(%ebp)
+ movl -716(%ebp), %eax
+ xorl %edx, %eax
+ movl %eax, -724(%ebp)
+ movl -664(%ebp), %ecx
+ movl -720(%ebp), %esi
+ xorl %ecx, %esi
+ movl %esi, -728(%ebp)
+ movzbl %al,%esi
+ shrl $13, %eax
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -728(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -728(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -636(%ebp), %esi
+ cmpl %ecx, -636(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -748(%ebp)
+ movl -724(%ebp), %ecx
+ addl %eax, %edx
+ movl -640(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -752(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -728(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -728(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -624(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -628(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -732(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -736(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -732(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ addl %esi, %edx
+ movl %edx, -764(%ebp)
+ movl -668(%ebp), %eax
+ movl -748(%ebp), %edx
+ movl -672(%ebp), %ecx
+ movl -752(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, -756(%ebp)
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -760(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ andl $2040, %eax
+ movl (%edi,%esi,8), %ecx
+ movl 2048(%eax,%edi), %edx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -760(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -760(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -736(%ebp), %esi
+ cmpl %ecx, -736(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -776(%ebp)
+ movl -756(%ebp), %ecx
+ addl %eax, %edx
+ movl -764(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -780(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -760(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -760(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -724(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -728(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -768(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -772(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -768(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -676(%ebp), %eax
+ addl %esi, %edx
+ movl -684(%ebp), %ecx
+ movl %edx, -792(%ebp)
+ movl -776(%ebp), %edx
+ movl -780(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -788(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ movl %edx, -784(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%esi,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -788(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -788(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -772(%ebp), %esi
+ cmpl %ecx, -772(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -804(%ebp)
+ movl -784(%ebp), %ecx
+ addl %eax, %edx
+ movl -792(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -808(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -788(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -788(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -756(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -760(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -796(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -800(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -796(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -680(%ebp), %eax
+ addl %esi, %edx
+ movl -688(%ebp), %ecx
+ movl %edx, -820(%ebp)
+ movl -804(%ebp), %edx
+ movl -808(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -816(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ movl %edx, -812(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%esi,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -816(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -816(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -800(%ebp), %esi
+ cmpl %ecx, -800(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -832(%ebp)
+ movl -812(%ebp), %ecx
+ addl %eax, %edx
+ movl -820(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -836(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -816(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -816(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -784(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -788(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -824(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -828(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -824(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -692(%ebp), %eax
+ addl %esi, %edx
+ movl -696(%ebp), %ecx
+ movl %edx, -848(%ebp)
+ movl -832(%ebp), %edx
+ movl -836(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -844(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ movl %edx, -840(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%esi,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -844(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -844(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -828(%ebp), %esi
+ cmpl %ecx, -828(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -860(%ebp)
+ movl -840(%ebp), %ecx
+ addl %eax, %edx
+ movl -848(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -864(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -844(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -844(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -812(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -816(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -852(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -856(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -852(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -700(%ebp), %eax
+ addl %esi, %edx
+ movl -708(%ebp), %ecx
+ movl %edx, -876(%ebp)
+ movl -860(%ebp), %edx
+ movl -864(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -872(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ movl %edx, -868(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%esi,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -872(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -872(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -856(%ebp), %esi
+ cmpl %ecx, -856(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -888(%ebp)
+ movl -868(%ebp), %ecx
+ addl %eax, %edx
+ movl -876(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -892(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -872(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -872(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -840(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -844(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -880(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -884(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -880(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -704(%ebp), %eax
+ addl %esi, %edx
+ movl -712(%ebp), %ecx
+ movl %edx, -904(%ebp)
+ movl -888(%ebp), %edx
+ movl -892(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -900(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ movl %edx, -896(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%esi,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -900(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -900(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -884(%ebp), %esi
+ cmpl %ecx, -884(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -916(%ebp)
+ movl -896(%ebp), %ecx
+ addl %eax, %edx
+ movl -904(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -920(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -900(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -900(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -868(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -872(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -908(%ebp)
+ leal 0(,%esi,8), %ecx
+ addl %ecx, %esi
+ movl %esi, -912(%ebp)
+ shrl $29, %eax
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ movl -908(%ebp), %esi
+ setb %al
+ addl %eax, %edx
+ movl -740(%ebp), %eax
+ addl %esi, %edx
+ movl -744(%ebp), %ecx
+ movl %edx, -932(%ebp)
+ movl -916(%ebp), %edx
+ movl -920(%ebp), %esi
+ xorl %eax, %edx
+ movl %edx, %eax
+ xorl %ecx, %esi
+ movl %esi, -928(%ebp)
+ shrl $13, %eax
+ movzbl %dl,%esi
+ movl %edx, -924(%ebp)
+ andl $2040, %eax
+ movl 2048(%eax,%edi), %edx
+ movl (%edi,%esi,8), %ecx
+ movl 2052(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 4(%edi,%esi,8), %edx
+ xorl %eax, %edx
+ movzbl -928(%ebp),%eax
+ sall $3, %eax
+ movl 4096(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 4100(%eax,%edi), %esi
+ movl -928(%ebp), %eax
+ xorl %esi, %edx
+ shrl $13, %eax
+ andl $2040, %eax
+ movl 6144(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 6148(%eax,%edi), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -912(%ebp), %esi
+ cmpl %ecx, -912(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl %esi, -940(%ebp)
+ movl -924(%ebp), %ecx
+ addl %eax, %edx
+ movl -932(%ebp), %esi
+ movzbl %ch, %eax
+ subl %edx, %esi
+ movl %esi, -944(%ebp)
+ leal 0(,%eax,8), %esi
+ movl %ecx, %eax
+ shrl $24, %eax
+ movl 6144(%esi,%edi), %ecx
+ sall $3, %eax
+ movl 4096(%eax,%edi), %edx
+ movl 4100(%eax,%edi), %eax
+ xorl %edx, %ecx
+ movl 6148(%esi,%edi), %edx
+ xorl %eax, %edx
+ movl -928(%ebp), %eax
+ movzbl %ah, %esi
+ leal 0(,%esi,8), %eax
+ movl 2048(%eax,%edi), %esi
+ xorl %esi, %ecx
+ movl 2052(%eax,%edi), %esi
+ movl -928(%ebp), %eax
+ xorl %esi, %edx
+ shrl $24, %eax
+ movl (%edi,%eax,8), %esi
+ xorl %esi, %ecx
+ movl 4(%edi,%eax,8), %esi
+ xorl %eax, %eax
+ xorl %esi, %edx
+ movl -896(%ebp), %esi
+ addl %ecx, %esi
+ cmpl %ecx, %esi
+ movl -900(%ebp), %ecx
+ setb %al
+ addl %eax, %edx
+ movl %esi, %eax
+ addl %ecx, %edx
+ movl %edx, -936(%ebp)
+ leal 0(,%esi,8), %ecx
+ shrl $29, %eax
+ addl %ecx, %esi
+ sall $3, %edx
+ orl %eax, %edx
+ xorl %eax, %eax
+ cmpl %ecx, %esi
+ setb %al
+ addl %eax, %edx
+ movl -936(%ebp), %eax
+ movl -20(%ebp), %ecx
+ addl %edx, %eax
+ movl -948(%ebp), %edx
+ xorl %edx, %esi
+ movl %esi, -1032(%ebp)
+ movl -952(%ebp), %esi
+ movl -960(%ebp), %edx
+ xorl %esi, %eax
+ movl -924(%ebp), %esi
+ movl %eax, -1036(%ebp)
+ xorl %eax, %eax
+ cmpl %ecx, -924(%ebp)
+ setb %al
+ subl %ecx, %esi
+ movl -928(%ebp), %ecx
+ addl %edx, %eax
+ movl -964(%ebp), %edx
+ subl %eax, %ecx
+ movl -24(%ebp), %eax
+ movl %ecx, -1040(%ebp)
+ movl -940(%ebp), %ecx
+ addl %eax, %ecx
+ xorl %eax, %eax
+ cmpl -24(%ebp), %ecx
+ setb %al
+ addl %edx, %eax
+ movl -944(%ebp), %edx
+ addl %edx, %eax
+ movl -1032(%ebp), %edx
+ movl %eax, -1044(%ebp)
+ movl 16(%ebp), %eax
+ movl %edx, (%eax)
+ movl -1036(%ebp), %edx
+ movl %esi, 8(%eax)
+ movl %edx, 4(%eax)
+ movl -1040(%ebp), %esi
+ movl %ecx, 16(%eax)
+ movl %esi, 12(%eax)
+ movl -1044(%ebp), %edx
+ movl %edx, 20(%eax)
+ subl $64, -16(%ebp)
+ addl $64, 8(%ebp)
+ cmpl $63, -16(%ebp)
+ ja .L6
+.L8:
+ addl $1032, %esp
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ ret
+ .size tiger_t, .-tiger_t
+.globl tiger
+ .type tiger, @function
+tiger:
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %edi
+ pushl %esi
+ subl $72, %esp
+ movl 12(%ebp), %edi
+ movl 8(%ebp), %esi
+ cmpl $63, %edi
+ jbe .L33
+.L42:
+ movl %esi, (%esp)
+ movl 16(%ebp), %eax
+ subl $64, %edi
+ addl $64, %esi
+ movl %eax, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ ja .L132
+.L33:
+ xorl %ecx, %ecx
+ cmpl %edi, %ecx
+ jb .L140
+.L35:
+ movb $1, -72(%ecx,%ebp)
+ leal 1(%ecx), %edx
+ testb $7, %dl
+ je .L37
+.L44:
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ jne .L135
+.L37:
+ cmpl $56, %edx
+ jbe .L23
+ cmpl $63, %edx
+ jbe .L141
+.L39:
+ movl 16(%ebp), %ecx
+ leal -72(%ebp), %edx
+ movl %edx, (%esp)
+ movl %ecx, 4(%esp)
+ call tiger_compress
+ xorl %edx, %edx
+.L23:
+ cmpl $55, %edx
+ ja .L41
+ movb $0, -72(%ebp,%edx)
+ movl %edx, %eax
+ leal 1(%edx), %ecx
+ notl %eax
+ andl $7, %eax
+ cmpl $55, %ecx
+ ja .L41
+ testl %eax, %eax
+ je .L46
+ cmpl $1, %eax
+ je .L143
+ cmpl $2, %eax
+ je .L144
+ cmpl $3, %eax
+ je .L145
+ cmpl $4, %eax
+ je .L146
+ cmpl $5, %eax
+ je .L147
+ cmpl $6, %eax
+ je .L148
+ movb $0, -72(%ebp,%ecx)
+ leal 2(%edx), %ecx
+.L148:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L147:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L146:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L145:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L144:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L143:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+ cmpl $55, %ecx
+ ja .L41
+.L46:
+ movb $0, -72(%ebp,%ecx)
+ movb $0, -71(%ecx,%ebp)
+ movb $0, -70(%ecx,%ebp)
+ movb $0, -69(%ecx,%ebp)
+ movb $0, -68(%ecx,%ebp)
+ movb $0, -67(%ecx,%ebp)
+ movb $0, -66(%ecx,%ebp)
+ movb $0, -65(%ecx,%ebp)
+ addl $8, %ecx
+ cmpl $55, %ecx
+ ja .L41
+ jmp .L46
+.L141:
+ movb $0, -72(%ebp,%edx)
+ movl %edx, %eax
+ leal 1(%edx), %ecx
+ notl %eax
+ andl $7, %eax
+ cmpl $63, %ecx
+ ja .L39
+ testl %eax, %eax
+ je .L45
+ cmpl $1, %eax
+ je .L149
+ cmpl $2, %eax
+ je .L150
+ cmpl $3, %eax
+ je .L151
+ cmpl $4, %eax
+ je .L152
+ cmpl $5, %eax
+ je .L153
+ cmpl $6, %eax
+ je .L154
+ movb $0, -72(%ebp,%ecx)
+ leal 2(%edx), %ecx
+.L154:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L153:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L152:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L151:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L150:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+.L149:
+ movb $0, -72(%ebp,%ecx)
+ incl %ecx
+ cmpl $63, %ecx
+ ja .L39
+.L45:
+ movb $0, -72(%ebp,%ecx)
+ movb $0, -71(%ecx,%ebp)
+ movb $0, -70(%ecx,%ebp)
+ movb $0, -69(%ecx,%ebp)
+ movb $0, -68(%ecx,%ebp)
+ movb $0, -67(%ecx,%ebp)
+ movb $0, -66(%ecx,%ebp)
+ movb $0, -65(%ecx,%ebp)
+ addl $8, %ecx
+ cmpl $63, %ecx
+ ja .L39
+ jmp .L45
+.L135:
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ movb $0, -72(%ebp,%edx)
+ incl %edx
+ testb $7, %dl
+ je .L37
+ jmp .L44
+.L140:
+ movl %ecx, %eax
+ notl %eax
+ addl %edi, %eax
+ movl %eax, %edx
+ andl $7, %edx
+ movzbl (%esi,%ecx), %eax
+ movb %al, -72(%ebp,%ecx)
+ incl %ecx
+ cmpl %edi, %ecx
+ jae .L35
+ testl %edx, %edx
+ je .L43
+ cmpl $1, %edx
+ je .L155
+ cmpl $2, %edx
+ je .L156
+ cmpl $3, %edx
+ je .L157
+ cmpl $4, %edx
+ je .L158
+ cmpl $5, %edx
+ je .L159
+ cmpl $6, %edx
+ je .L160
+ movzbl (%esi,%ecx), %edx
+ movb %dl, -72(%ebp,%ecx)
+ incl %ecx
+.L160:
+ movzbl (%esi,%ecx), %eax
+ movb %al, -72(%ebp,%ecx)
+ incl %ecx
+.L159:
+ movzbl (%esi,%ecx), %edx
+ movb %dl, -72(%ebp,%ecx)
+ incl %ecx
+.L158:
+ movzbl (%esi,%ecx), %eax
+ movb %al, -72(%ebp,%ecx)
+ incl %ecx
+.L157:
+ movzbl (%esi,%ecx), %edx
+ movb %dl, -72(%ebp,%ecx)
+ incl %ecx
+.L156:
+ movzbl (%esi,%ecx), %eax
+ movb %al, -72(%ebp,%ecx)
+ incl %ecx
+.L155:
+ movzbl (%esi,%ecx), %edx
+ movb %dl, -72(%ebp,%ecx)
+ incl %ecx
+ cmpl %edi, %ecx
+ jae .L35
+.L43:
+ movzbl (%esi,%ecx), %edx
+ movb %dl, -72(%ebp,%ecx)
+ leal 1(%ecx), %edx
+ movzbl (%esi,%edx), %eax
+ movb %al, -72(%ebp,%edx)
+ leal 2(%ecx), %edx
+ movzbl (%esi,%edx), %eax
+ movb %al, -72(%ebp,%edx)
+ leal 3(%ecx), %edx
+ movzbl (%esi,%edx), %eax
+ movb %al, -72(%ebp,%edx)
+ leal 4(%ecx), %edx
+ movzbl (%esi,%edx), %eax
+ movb %al, -72(%ebp,%edx)
+ leal 5(%ecx), %edx
+ movzbl (%esi,%edx), %eax
+ movb %al, -72(%ebp,%edx)
+ leal 6(%ecx), %edx
+ movzbl (%esi,%edx), %eax
+ movb %al, -72(%ebp,%edx)
+ leal 7(%ecx), %edx
+ addl $8, %ecx
+ movzbl (%esi,%edx), %eax
+ cmpl %edi, %ecx
+ movb %al, -72(%ebp,%edx)
+ jae .L35
+ jmp .L43
+.L132:
+ movl %esi, (%esp)
+ movl 16(%ebp), %ecx
+ subl $64, %edi
+ addl $64, %esi
+ movl %ecx, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ movl %esi, (%esp)
+ movl 16(%ebp), %eax
+ subl $64, %edi
+ addl $64, %esi
+ movl %eax, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ movl %esi, (%esp)
+ movl 16(%ebp), %edx
+ subl $64, %edi
+ addl $64, %esi
+ movl %edx, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ movl %esi, (%esp)
+ movl 16(%ebp), %ecx
+ subl $64, %edi
+ addl $64, %esi
+ movl %ecx, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ movl %esi, (%esp)
+ movl 16(%ebp), %eax
+ subl $64, %edi
+ addl $64, %esi
+ movl %eax, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ movl %esi, (%esp)
+ movl 16(%ebp), %edx
+ subl $64, %edi
+ addl $64, %esi
+ movl %edx, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ movl %esi, (%esp)
+ movl 16(%ebp), %ecx
+ subl $64, %edi
+ addl $64, %esi
+ movl %ecx, 4(%esp)
+ call tiger_compress
+ cmpl $63, %edi
+ jbe .L33
+ jmp .L42
+.L41:
+ movl $0, -12(%ebp)
+ movl 12(%ebp), %eax
+ leal -72(%ebp), %esi
+ movl %esi, (%esp)
+ movl 16(%ebp), %edi
+ sall $3, %eax
+ movl %edi, 4(%esp)
+ movl %eax, -16(%ebp)
+ call tiger_compress
+ addl $72, %esp
+ popl %esi
+ popl %edi
+ popl %ebp
+ ret
+ .size tiger, .-tiger
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+ .hidden __i686.get_pc_thunk.bx
+ .type __i686.get_pc_thunk.bx, @function
+__i686.get_pc_thunk.bx:
+ movl (%esp), %ebx
+ ret
+ .section .note.GNU-stack,"",@progbits
+ .ident "GCC: (GNU) 3.4.0"
diff --git a/src/sh_tiger1_64.c b/src/sh_tiger1_64.c
new file mode 100644
index 0000000..9218d8a
--- /dev/null
+++ b/src/sh_tiger1_64.c
@@ -0,0 +1,498 @@
+/* Do not include ANY system headers here. The implementation is */
+/* somehow flawed - maybe something gets overlayed by definitions */
+/* in the system headers. Results will become incorrect. */
+
+#include "config_xor.h"
+
+#if defined(__clang__)
+#undef TIGER_OPT_ASM
+#endif
+
+#if defined(TIGER_64_BIT)
+
+#if defined(GCC_VERSION_MAJOR) && !defined(__clang__)
+#if ((GCC_VERSION_MAJOR == 4) && (GCC_VERSION_MINOR > 6))
+#pragma GCC optimize ("O1")
+#endif
+#endif
+
+
+/* #if defined(HAVE_LONG_64) || defined(HAVE_LONG_LONG_64) */
+
+#undef USE_MEMSET
+
+/* Big endian: */
+#ifdef WORDS_BIGENDIAN
+#define BIG_ENDIAN
+#endif
+
+/* Tiger: A Fast New Hash Function
+ *
+ * Ross Anderson and Eli Biham
+ *
+ * From the homepage (http://www.cs.technion.ac.il/~biham/Reports/Tiger/):
+ *
+ * Tiger has no usage restrictions nor patents. It can be used freely,
+ * with the reference implementation, with other implementations or with
+ * a modification to the reference implementation (as long as it still
+ * implements Tiger). We only ask you to let us know about your
+ * implementation and to cite the origin of Tiger and of the reference
+ * implementation.
+ *
+ *
+ * The authors' home pages can be found both in
+ * http://www.cs.technion.ac.il/~biham/ and in
+ * http://www.cl.cam.ac.uk/users/rja14/.
+ * The authors' email addresses are biham@cs.technion.ac.il
+ * and rja14@cl.cam.ac.uk.
+ */
+
+#if defined(HAVE_LONG_64)
+typedef unsigned long int word64;
+#elif defined(HAVE_LONG_LONG_64)
+typedef unsigned long long int word64;
+#else
+#error No 64 bit type found !
+#endif
+
+#if defined(HAVE_INT_32)
+typedef unsigned int sh_word32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long sh_word32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short sh_word32;
+#else
+#error No 32 bit type found !
+#endif
+
+typedef unsigned char sh_byte;
+
+#if defined(TIGER_OPT_ASM)
+#define TIGER_ASM64_2 1
+#else
+#define TIGER_C 1
+#endif
+
+/* The number of passes of the hash function. */
+/* Three passes are recommended. */
+/* Use four passes when you need extra security. */
+/* Must be at least three. */
+#define PASSES 3
+
+extern word64 tiger_table[4*256];
+
+/* Volatile can help if compiler is smart enough to use memory operand */
+static /*volatile*/ const word64 XOR_CONST1=0xA5A5A5A5A5A5A5A5LL;
+static /*volatile*/ const word64 XOR_CONST2=0x0123456789ABCDEFLL;
+
+#define t1 (tiger_table)
+#define t2 (tiger_table+256)
+#define t3 (tiger_table+256*2)
+#define t4 (tiger_table+256*3)
+
+#define pass_start
+#define pass_end
+
+
+
+#define save_abc \
+ aa = a; \
+ bb = b; \
+ cc = c;
+
+#ifdef TIGER_C
+
+#define BN(x,n) (((x)>>((n)*8))&0xFF)
+
+
+/* Depending on outer code one of these two can be better*/
+#define roundX(a,b,c,x) \
+ c ^= x; \
+ a -= t1[BN(c,0)] ^ t2[BN(c,2)] ^ \
+ t3[BN(c,4)] ^ t4[BN(c,6)] ; \
+ b += t4[BN(c,1)] ^ t3[BN(c,3)] ^ \
+ t2[BN(c,5)] ^ t1[BN(c,7)] ;
+
+#define round5(a,b,c,x) roundX(a,b,c,x) b = b+b*4;
+#define round7(a,b,c,x) roundX(a,b,c,x) b = b*8-b;
+#define round9(a,b,c,x) roundX(a,b,c,x) b = b+b*8;
+
+#endif
+
+
+#ifdef TIGER_OPT_ASM
+
+#define MASK0 0xFFL
+#define MASK8 0xFF00L
+#define MASK16 0xFF0000L
+#define MASK32 0xFF00000000LL
+#define MASK40 0xFF0000000000LL
+#define MASK48 0xFF000000000000LL
+
+#define roundstart __asm__ (
+
+/* a will be moved into different reg each round
+ * using register substitution feature of GCC asm
+ * b will be moved in 2-nd pass rounds only
+ */
+
+
+#define roundend(a,b,c,x) \
+ : "+r" (a), "+r" (b), "+r" (c) \
+ : "r" (a), "r" (b), "r" (c), "m" (x), "r" (&tiger_table),\
+ "i" (MASK0), "i" (MASK8), "i" (MASK16), "r" (MASK32), "r" (MASK40), "r" (MASK48) \
+ : "3", "%rax","%rbx","%rcx","%rdx","%rsi", "%edi", "%r8" );
+
+
+/* c ^= x;
+ a -= t1[BN(c,0)] ^ t2[BN(c,2)] ^
+ t3[BN(c,4)] ^ t4[BN(c,6)] ;
+ b += t4[BN(c,1)] ^ t3[BN(c,3)] ^
+ t2[BN(c,5)] ^ t1[BN(c,7)] ; */
+
+#define roundX(a,b,c,x) \
+" movl %10, %%ebx \n"\
+" movq %11, %%rcx \n"\
+" movq %13, %%rdx \n"\
+" movq %6, %%r8 \n"\
+" xorq %%r8, %2 \n" \
+" andq %2, %%rbx \n"\
+" andq %2, %%rcx \n"\
+" andq %2, %%rdx \n"\
+" shrl $(16-3), %%ebx \n"\
+" shrq $(32-3), %%rcx \n"\
+" shrq $(48-3), %%rdx \n"\
+" movzbl %2b, %%eax \n"\
+" movzwl %2w, %%edi \n"\
+" movq (%7,%%rax,8), %%rsi \n"\
+" shrl $(8), %%edi \n" \
+" movq %2, %%rax \n" \
+" xorq (2048*1)(%7,%%rbx), %%rsi \n"\
+" movq %2, %%rbx \n"\
+" shrl $24, %%eax \n"\
+" andq %12, %%rbx \n"\
+" xorq (2048*2)(%7,%%rcx), %%rsi \n"\
+" shrq $(40-3), %%rbx \n"\
+" movq %2, %%rcx \n"\
+" xorq (2048*3)(%7,%%rdx), %%rsi \n"\
+" movq (2048*3)(%7,%%rdi,8), %%rdx \n"\
+" shrq $56, %%rcx \n"\
+" xorq (2048*2)(%7,%%rax,8), %%rdx \n"\
+" xorq (2048*1)(%7,%%rbx), %%rdx \n" \
+" subq %%rsi, %0 \n"\
+" xorq (%7,%%rcx,8), %%rdx \n"\
+" addq %%rdx, %1 \n"
+
+#define round5(a,b,c,x) \
+ roundstart \
+ roundX(a,b,c,x) \
+ /* b*=5; */ \
+ "leaq (%1,%1,4), %1\n" \
+ roundend(a,b,c,x)
+
+
+#define round7(a,b,c,x) \
+ roundstart \
+ roundX(a,b,c,x) \
+ roundend(a,b,c,x) \
+ /* b*=7; */ \
+ __asm__ ( \
+ "leaq (%1,%1,8), %0\n" \
+ "addq %1, %1 \n" \
+ "subq %1, %0 " \
+ :"=&r" (b): "r"(b): "1" );
+
+#define round9(a,b,c,x) \
+ roundstart \
+ roundX(a,b,c,x) \
+ "leaq (%1,%1,8), %1\n" \
+ roundend(a,b,c,x)
+
+#endif
+
+
+
+
+/* ============== Common macros ================== */
+
+#define key_schedule \
+ x0 -= x7 ^ XOR_CONST1; \
+ x1 ^= x0; \
+ x2 += x1;\
+ x3 -= x2 ^ ((~x1)<<19);\
+ x4 ^= x3;\
+ x5 += x4;\
+ x6 -= x5 ^ ((~x4)>>23); \
+ x7 ^= x6; \
+ x0 += x7; \
+ x1 -= x0 ^ ((~x7)<<19); \
+ x2 ^= x1; \
+ x3 += x2; \
+ x4 -= x3 ^ ((~x2)>>23); \
+ x5 ^= x4; \
+ x6 += x5; \
+ x7 -= x6 ^ XOR_CONST2;
+
+#define pass5n(a,b,c) \
+ round5(a,b,c,x0) \
+ x0 -= x7 ^ XOR_CONST1; \
+ round5(b,c,a,x1) \
+ x1 ^= x0; \
+ round5(c,a,b,x2) \
+ x2 += x1; \
+ round5(a,b,c,x3) \
+ x3 -= x2 ^ ((~x1)<<19); \
+ round5(b,c,a,x4) \
+ x4 ^= x3; \
+ round5(c,a,b,x5) \
+ x5 += x4; \
+ round5(a,b,c,x6) \
+ x6 -= x5 ^ ((~x4)>>23); \
+ round5(b,c,a,x7) \
+ x7 ^= x6; \
+ x0 += x7; \
+ x1 -= x0 ^ ((~x7)<<19); \
+ x2 ^= x1; \
+ x3 += x2; \
+ x4 -= x3 ^ ((~x2)>>23); \
+ x5 ^= x4; \
+ x6 += x5; \
+ x7 -= x6 ^ XOR_CONST2;
+
+#define pass7n(a,b,c) \
+ round7(a,b,c,x0) \
+ x0 -= x7 ^ XOR_CONST1; \
+ round7(b,c,a,x1) \
+ x1 ^= x0; \
+ round7(c,a,b,x2) \
+ x2 += x1; \
+ round7(a,b,c,x3) \
+ x3 -= x2 ^ ((~x1)<<19); \
+ round7(b,c,a,x4) \
+ x4 ^= x3; \
+ round7(c,a,b,x5) \
+ x5 += x4; \
+ round7(a,b,c,x6) \
+ x6 -= x5 ^ ((~x4)>>23); \
+ round7(b,c,a,x7) \
+ x7 ^= x6; \
+ x0 += x7; \
+ x1 -= x0 ^ ((~x7)<<19); \
+ x2 ^= x1; \
+ x3 += x2; \
+ x4 -= x3 ^ ((~x2)>>23); \
+ x5 ^= x4; \
+ x6 += x5; \
+ x7 -= x6 ^ XOR_CONST2;
+
+#define pass5(a,b,c) \
+ pass_start \
+ round5(a,b,c,x0) \
+ round5(b,c,a,x1) \
+ round5(c,a,b,x2) \
+ round5(a,b,c,x3) \
+ round5(b,c,a,x4) \
+ round5(c,a,b,x5) \
+ round5(a,b,c,x6) \
+ round5(b,c,a,x7) \
+ pass_end
+
+#define pass7(a,b,c) \
+ pass_start \
+ round7(a,b,c,x0) \
+ round7(b,c,a,x1) \
+ round7(c,a,b,x2) \
+ round7(a,b,c,x3) \
+ round7(b,c,a,x4) \
+ round7(c,a,b,x5) \
+ round7(a,b,c,x6) \
+ round7(b,c,a,x7) \
+ pass_end
+
+
+#define pass9(a,b,c) \
+ pass_start \
+ round9(a,b,c,x0) \
+ round9(b,c,a,x1) \
+ round9(c,a,b,x2) \
+ round9(a,b,c,x3) \
+ round9(b,c,a,x4) \
+ round9(c,a,b,x5) \
+ round9(a,b,c,x6) \
+ round9(b,c,a,x7) \
+ pass_end
+
+#define feedforward \
+ a ^= aa; \
+ b -= bb; \
+ c += cc;
+
+
+/* This version works ok with C variant and also with new asm version
+ * that just wastes a register r8
+ * reason? who knows, write forwarding is faster than keeping value
+ * in register? :)
+ */
+#define compress \
+ save_abc \
+ pass5n(a,b,c) \
+ pass7n(c,a,b) \
+ pass9(b,c,a) \
+ for(pass_no=3; pass_no<PASSES; pass_no++) { \
+ key_schedule \
+ pass9(a,b,c) \
+ tmpa=a; a=c; c=b; b=tmpa; \
+ } \
+ feedforward
+
+#define compress_old \
+ save_abc \
+ pass5(a,b,c) \
+ key_schedule \
+ pass7(c,a,b) \
+ key_schedule \
+ pass9(b,c,a) \
+ for(pass_no=3; pass_no<PASSES; pass_no++) { \
+ key_schedule \
+ pass9(a,b,c) \
+ tmpa=a; a=c; c=b; b=tmpa; \
+ } \
+ feedforward
+
+#define tiger_compress_macro(str, state) \
+{ \
+ register word64 a, b, c; \
+ register word64 tmpa; \
+ word64 aa, bb, cc; \
+ word64 x0, x1, x2, x3, x4, x5, x6, x7; \
+ int pass_no; \
+\
+ a = state[0]; \
+ b = state[1]; \
+ c = state[2]; \
+\
+ x0=str[0]; x1=str[1]; x2=str[2]; x3=str[3]; \
+ x4=str[4]; x5=str[5]; x6=str[6]; x7=str[7]; \
+\
+ compress; \
+\
+ state[0] = a; \
+ state[1] = b; \
+ state[2] = c; \
+}
+
+void tiger_compress(const word64 *str, word64 state[3])
+{
+ tiger_compress_macro(((const word64*)str), ((word64*)state));
+}
+
+void tiger_t(const word64 *str, word64 length, word64 res[3])
+{
+ register word64 i;
+
+#ifdef BIG_ENDIAN
+ register word64 j = 0;
+ unsigned char temp[64];
+#endif
+
+ /*
+ * res[0]=0x0123456789ABCDEFLL;
+ * res[1]=0xFEDCBA9876543210LL;
+ * res[2]=0xF096A5B4C3B2E187LL;
+ */
+
+ for(i=length; i>=64; i-=64)
+ {
+#ifdef BIG_ENDIAN
+ for(j=0; j<64; j++)
+ temp[j^7] = ((sh_byte*)str)[j];
+ tiger_compress(((word64*)temp), res);
+#else
+ tiger_compress(str, res);
+#endif
+ str += 8;
+ }
+}
+
+void tiger(const word64 *str, word64 length, word64 res[3])
+{
+ register word64 i;
+ register word64 j = 0;
+ union {
+ word64 w64_temp[8];
+ unsigned char temp[64];
+ } dd;
+ union {
+ word64 itmp;
+ unsigned char ctmp[8];
+ } uu;
+
+ /*
+ * res[0]=0x0123456789ABCDEFLL;
+ * res[1]=0xFEDCBA9876543210LL;
+ * res[2]=0xF096A5B4C3B2E187LL;
+ */
+
+ for(i=length; i>=64; i-=64)
+ {
+#ifdef BIG_ENDIAN
+ for(j=0; j<64; j++)
+ dd.temp[j^7] = ((sh_byte*)str)[j];
+ tiger_compress((dd.w64_temp), res);
+#else
+ tiger_compress(str, res);
+#endif
+ str += 8;
+ }
+
+#ifdef BIG_ENDIAN
+ for(j=0; j<i; j++)
+ dd.temp[j^7] = ((sh_byte*)str)[j];
+
+ dd.temp[j^7] = 0x01;
+ j++;
+ for(; j&7; j++)
+ dd.temp[j^7] = 0;
+#else
+
+#ifndef USE_MEMSET
+ for(j=0; j<i; j++)
+ dd.temp[j] = ((const sh_byte*)str)[j];
+#else
+ memcpy( dd.temp, str, j=i );
+#endif
+ dd.temp[j++] = 0x01;
+ for(; j&7; j++)
+ dd.temp[j] = 0;
+
+#endif
+
+ if(j>56)
+ {
+#ifndef USE_MEMSET
+ for(; j<64; j++)
+ dd.temp[j] = 0;
+#else
+ memset( (dd.temp)+j, 0, 64-j);
+#endif
+ tiger_compress((dd.w64_temp), res);
+ j=0;
+ }
+
+#ifndef USE_MEMSET
+ for(; j<56; j++)
+ dd.temp[j] = 0;
+#else
+ memset( (dd.temp)+j, 0, 56-j);
+#endif
+
+ /* Avoid gcc warning for type-punned pointer
+ */
+ uu.itmp = ((word64)length)<<3;
+ for (j=0; j<8; j++)
+ dd.temp[56+j] = uu.ctmp[j];
+
+ tiger_compress((dd.w64_temp), res);
+}
+
+#endif
diff --git a/src/sh_tiger2.c b/src/sh_tiger2.c
new file mode 100644
index 0000000..326246f
--- /dev/null
+++ b/src/sh_tiger2.c
@@ -0,0 +1,561 @@
+/* Tiger: A Fast New Hash Function
+ *
+ * Ross Anderson and Eli Biham
+ *
+ * From the homepage (http://www.cs.technion.ac.il/~biham/Reports/Tiger/):
+ *
+ * Tiger has no usage restrictions nor patents. It can be used freely,
+ * with the reference implementation, with other implementations or with
+ * a modification to the reference implementation (as long as it still
+ * implements Tiger). We only ask you to let us know about your
+ * implementation and to cite the origin of Tiger and of the reference
+ * implementation.
+ *
+ *
+ * The authors' home pages can be found both in
+ * http://www.cs.technion.ac.il/~biham/ and in
+ * http://www.cl.cam.ac.uk/users/rja14/.
+ * The authors' email addresses are biham@cs.technion.ac.il
+ * and rja14@cl.cam.ac.uk.
+ */
+
+#include "config_xor.h"
+
+
+#if !defined(TIGER_64_BIT)
+
+/* #if !defined(HAVE_LONG_64) && !defined(HAVE_LONG_LONG_64) */
+
+/* sboxes32.c: Tiger S boxes for 32-bit-only compilers */
+#if defined(HAVE_INT_32)
+typedef unsigned int sh_word32;
+#elif defined(HAVE_LONG_32)
+typedef unsigned long sh_word32;
+#elif defined(HAVE_SHORT_32)
+typedef unsigned short sh_word32;
+#else
+#error No 32 bit type found !
+#endif
+
+sh_word32 tiger_table[4*256][2] = {
+ { 0xF7E90C5E, 0x02AAB17C /* 0 */}, { 0xE243A8EC, 0xAC424B03 /* 1 */},
+ { 0x0DD5FCD3, 0x72CD5BE3 /* 2 */}, { 0xF6F97F3A, 0x6D019B93 /* 3 */},
+ { 0xD21F9193, 0xCD9978FF /* 4 */}, { 0x708029E2, 0x7573A1C9 /* 5 */},
+ { 0x922A83C3, 0xB164326B /* 6 */}, { 0x04915870, 0x46883EEE /* 7 */},
+ { 0x7103ECE6, 0xEAACE305 /* 8 */}, { 0x08A3535C, 0xC54169B8 /* 9 */},
+ { 0x8DDEC47C, 0x4CE75491 /* 10 */}, { 0xDC0DF40C, 0x0AA2F4DF /* 11 */},
+ { 0xA74DBEFA, 0x10B76F18 /* 12 */}, { 0x5AD1AB6A, 0xC6CCB623 /* 13 */},
+ { 0x572FE2FF, 0x13726121 /* 14 */}, { 0x199D921E, 0x1A488C6F /* 15 */},
+ { 0xDA0007CA, 0x4BC9F9F4 /* 16 */}, { 0xE85241C7, 0x26F5E6F6 /* 17 */},
+ { 0xEA5947B6, 0x859079DB /* 18 */}, { 0xC99E8C92, 0x4F1885C5 /* 19 */},
+ { 0xA96F864B, 0xD78E761E /* 20 */}, { 0x52B5C17D, 0x8E36428C /* 21 */},
+ { 0x373063C1, 0x69CF6827 /* 22 */}, { 0x9BB4C56E, 0xB607C93D /* 23 */},
+ { 0x0E76B5EA, 0x7D820E76 /* 24 */}, { 0xF07FDC42, 0x645C9CC6 /* 25 */},
+ { 0x243342E0, 0xBF38A078 /* 26 */}, { 0x9D2E7D04, 0x5F6B343C /* 27 */},
+ { 0x600B0EC6, 0xF2C28AEB /* 28 */}, { 0x7254BCAC, 0x6C0ED85F /* 29 */},
+ { 0xA4DB4FE5, 0x71592281 /* 30 */}, { 0xCE0FED9F, 0x1967FA69 /* 31 */},
+ { 0xB96545DB, 0xFD5293F8 /* 32 */}, { 0xF2A7600B, 0xC879E9D7 /* 33 */},
+ { 0x0193194E, 0x86024892 /* 34 */}, { 0x2D9CC0B3, 0xA4F9533B /* 35 */},
+ { 0x15957613, 0x9053836C /* 36 */}, { 0xFC357BF1, 0xDB6DCF8A /* 37 */},
+ { 0x7A370F57, 0x18BEEA7A /* 38 */}, { 0x50B99066, 0x037117CA /* 39 */},
+ { 0x74424A35, 0x6AB30A97 /* 40 */}, { 0xE325249B, 0xF4E92F02 /* 41 */},
+ { 0x061CCAE1, 0x7739DB07 /* 42 */}, { 0xECA42A05, 0xD8F3B49C /* 43 */},
+ { 0x51382F73, 0xBD56BE3F /* 44 */}, { 0x43B0BB28, 0x45FAED58 /* 45 */},
+ { 0x11BF1F83, 0x1C813D5C /* 46 */}, { 0xD75FA169, 0x8AF0E4B6 /* 47 */},
+ { 0x87AD9999, 0x33EE18A4 /* 48 */}, { 0xB1C94410, 0x3C26E8EA /* 49 */},
+ { 0xC0A822F9, 0xB510102B /* 50 */}, { 0x0CE6123B, 0x141EEF31 /* 51 */},
+ { 0x59DDB154, 0xFC65B900 /* 52 */}, { 0xC5E0E607, 0xE0158640 /* 53 */},
+ { 0x26C3A3CF, 0x884E0798 /* 54 */}, { 0x23C535FD, 0x930D0D95 /* 55 */},
+ { 0x4E9A2B00, 0x35638D75 /* 56 */}, { 0x40469DD5, 0x4085FCCF /* 57 */},
+ { 0x8BE23A4C, 0xC4B17AD2 /* 58 */}, { 0x6A3E6A2E, 0xCAB2F0FC /* 59 */},
+ { 0x6B943FCD, 0x2860971A /* 60 */}, { 0x12E30446, 0x3DDE6EE2 /* 61 */},
+ { 0xE01765AE, 0x6222F32A /* 62 */}, { 0x478308FE, 0x5D550BB5 /* 63 */},
+ { 0xA0EDA22A, 0xA9EFA98D /* 64 */}, { 0x86C40DA7, 0xC351A716 /* 65 */},
+ { 0x9C867C84, 0x1105586D /* 66 */}, { 0xFDA22853, 0xDCFFEE85 /* 67 */},
+ { 0x2C5EEF76, 0xCCFBD026 /* 68 */}, { 0x8990D201, 0xBAF294CB /* 69 */},
+ { 0x2AFAD975, 0xE69464F5 /* 70 */}, { 0xDF133E14, 0x94B013AF /* 71 */},
+ { 0x2823C958, 0x06A7D1A3 /* 72 */}, { 0x30F61119, 0x6F95FE51 /* 73 */},
+ { 0x462C06C0, 0xD92AB34E /* 74 */}, { 0x887C71D2, 0xED7BDE33 /* 75 */},
+ { 0x6518393E, 0x79746D6E /* 76 */}, { 0x5D713329, 0x5BA41938 /* 77 */},
+ { 0x48A97564, 0x7C1BA6B9 /* 78 */}, { 0x7BFDAC67, 0x31987C19 /* 79 */},
+ { 0x4B053D02, 0xDE6C23C4 /* 80 */}, { 0xD002D64D, 0x581C49FE /* 81 */},
+ { 0x38261571, 0xDD474D63 /* 82 */}, { 0xE473D062, 0xAA4546C3 /* 83 */},
+ { 0x9455F860, 0x928FCE34 /* 84 */}, { 0xCAAB94D9, 0x48161BBA /* 85 */},
+ { 0x770E6F68, 0x63912430 /* 86 */}, { 0x02C6641C, 0x6EC8A5E6 /* 87 */},
+ { 0x337DDD2B, 0x87282515 /* 88 */}, { 0x034B701B, 0x2CDA6B42 /* 89 */},
+ { 0x81CB096D, 0xB03D37C1 /* 90 */}, { 0x66C71C6F, 0xE1084382 /* 91 */},
+ { 0xEB51B255, 0x2B3180C7 /* 92 */}, { 0x96C08BBC, 0xDF92B82F /* 93 */},
+ { 0xA632F3BA, 0x5C68C8C0 /* 94 */}, { 0x1C3D0556, 0x5504CC86 /* 95 */},
+ { 0x5FB26B8F, 0xABBFA4E5 /* 96 */}, { 0xB3BACEB4, 0x41848B0A /* 97 */},
+ { 0xAA445D32, 0xB334A273 /* 98 */}, { 0xA85AD881, 0xBCA696F0 /* 99 */},
+ { 0xB528D56C, 0x24F6EC65 /* 100 */}, { 0x90F4524A, 0x0CE1512E /* 101 */},
+ { 0x5506D35A, 0x4E9DD79D /* 102 */}, { 0xC6CE9779, 0x258905FA /* 103 */},
+ { 0x3E109B33, 0x2019295B /* 104 */}, { 0x73A054CC, 0xF8A9478B /* 105 */},
+ { 0x34417EB0, 0x2924F2F9 /* 106 */}, { 0x536D1BC4, 0x3993357D /* 107 */},
+ { 0x1DB6FF8B, 0x38A81AC2 /* 108 */}, { 0x7D6016BF, 0x47C4FBF1 /* 109 */},
+ { 0x7667E3F5, 0x1E0FAADD /* 110 */}, { 0x938BEB96, 0x7ABCFF62 /* 111 */},
+ { 0x8FC179C9, 0xA78DAD94 /* 112 */}, { 0x2911E50D, 0x8F1F98B7 /* 113 */},
+ { 0x27121A91, 0x61E48EAE /* 114 */}, { 0x31859808, 0x4D62F7AD /* 115 */},
+ { 0xEF5CEAEB, 0xECEBA345 /* 116 */}, { 0xBC9684CE, 0xF5CEB25E /* 117 */},
+ { 0xB7F76221, 0xF633E20C /* 118 */}, { 0xAB8293E4, 0xA32CDF06 /* 119 */},
+ { 0xA5EE2CA4, 0x985A202C /* 120 */}, { 0xCC8A8FB1, 0xCF0B8447 /* 121 */},
+ { 0x979859A3, 0x9F765244 /* 122 */}, { 0xA1240017, 0xA8D516B1 /* 123 */},
+ { 0xBB5DC726, 0x0BD7BA3E /* 124 */}, { 0xB86ADB39, 0xE54BCA55 /* 125 */},
+ { 0x6C478063, 0x1D7A3AFD /* 126 */}, { 0xE7669EDD, 0x519EC608 /* 127 */},
+ { 0xD149AA23, 0x0E5715A2 /* 128 */}, { 0x848FF194, 0x177D4571 /* 129 */},
+ { 0x41014C22, 0xEEB55F32 /* 130 */}, { 0x3A6E2EC2, 0x0F5E5CA1 /* 131 */},
+ { 0x75F5C361, 0x8029927B /* 132 */}, { 0xC3D6E436, 0xAD139FAB /* 133 */},
+ { 0x4CCF402F, 0x0D5DF1A9 /* 134 */}, { 0xBEA5DFC8, 0x3E8BD948 /* 135 */},
+ { 0xBD3FF77E, 0xA5A0D357 /* 136 */}, { 0x1F74F645, 0xA2D12E25 /* 137 */},
+ { 0x5E81A082, 0x66FD9E52 /* 138 */}, { 0x7F687A49, 0x2E0C90CE /* 139 */},
+ { 0xBA973BC5, 0xC2E8BCBE /* 140 */}, { 0xE509745F, 0x000001BC /* 141 */},
+ { 0xE6DAB3D6, 0x423777BB /* 142 */}, { 0xAEF06EB5, 0xD1661C7E /* 143 */},
+ { 0x4DAACFD8, 0xA1781F35 /* 144 */}, { 0x2B16AFFC, 0x2D11284A /* 145 */},
+ { 0xFA891D1F, 0xF1FC4F67 /* 146 */}, { 0xCB920ADA, 0x73ECC25D /* 147 */},
+ { 0xC2A12651, 0xAE610C22 /* 148 */}, { 0xD356B78A, 0x96E0A810 /* 149 */},
+ { 0x2FE7870F, 0x5A9A381F /* 150 */}, { 0xE94E5530, 0xD5AD62ED /* 151 */},
+ { 0x368D1427, 0xD225E5E8 /* 152 */}, { 0xC7AF4631, 0x65977B70 /* 153 */},
+ { 0xDE39D74F, 0x99F889B2 /* 154 */}, { 0x54E1D143, 0x233F30BF /* 155 */},
+ { 0xD9A63C97, 0x9A9675D3 /* 156 */}, { 0xF334F9A8, 0x5470554F /* 157 */},
+ { 0x4A4F5688, 0x166ACB74 /* 158 */}, { 0xB2E4AEAD, 0x70C74CAA /* 159 */},
+ { 0x6F294D12, 0xF0D09164 /* 160 */}, { 0x684031D1, 0x57B82A89 /* 161 */},
+ { 0x61BE0B6B, 0xEFD95A5A /* 162 */}, { 0x69F2F29A, 0x2FBD12E9 /* 163 */},
+ { 0xFEFF9FE8, 0x9BD37013 /* 164 */}, { 0xD6085A06, 0x3F9B0404 /* 165 */},
+ { 0x166CFE15, 0x4940C1F3 /* 166 */}, { 0xCDF3DEFB, 0x09542C4D /* 167 */},
+ { 0x85CD5CE3, 0xB4C52183 /* 168 */}, { 0x4462A641, 0xC935B7DC /* 169 */},
+ { 0x8ED3B63F, 0x3417F8A6 /* 170 */}, { 0x5B215B40, 0xB8095929 /* 171 */},
+ { 0x3B8C8572, 0xF99CDAEF /* 172 */}, { 0xF8FCB95D, 0x018C0614 /* 173 */},
+ { 0x1A3ACDF3, 0x1B14ACCD /* 174 */}, { 0x00BB732D, 0x84D471F2 /* 175 */},
+ { 0x95E8DA16, 0xC1A3110E /* 176 */}, { 0xBF1A82B8, 0x430A7220 /* 177 */},
+ { 0x39DF210E, 0xB77E090D /* 178 */}, { 0x3CD05E9D, 0x5EF4BD9F /* 179 */},
+ { 0x7E57A444, 0x9D4FF6DA /* 180 */}, { 0x83D4A5F8, 0xDA1D60E1 /* 181 */},
+ { 0x17998E47, 0xB287C384 /* 182 */}, { 0x1BB31886, 0xFE3EDC12 /* 183 */},
+ { 0x980CCBEF, 0xC7FE3CCC /* 184 */}, { 0x189BFD03, 0xE46FB590 /* 185 */},
+ { 0x9A4C57DC, 0x3732FD46 /* 186 */}, { 0x7CF1AD65, 0x7EF700A0 /* 187 */},
+ { 0xA31D8859, 0x59C64468 /* 188 */}, { 0xD45B61F6, 0x762FB0B4 /* 189 */},
+ { 0x99047718, 0x155BAED0 /* 190 */}, { 0x3D50BAA6, 0x68755E4C /* 191 */},
+ { 0x22D8B4DF, 0xE9214E7F /* 192 */}, { 0x2EAC95F4, 0x2ADDBF53 /* 193 */},
+ { 0xB4BD0109, 0x32AE3909 /* 194 */}, { 0xB08E3450, 0x834DF537 /* 195 */},
+ { 0x4220728D, 0xFA209DA8 /* 196 */}, { 0x9EFE23F7, 0x9E691D9B /* 197 */},
+ { 0xC4AE8D7F, 0x0446D288 /* 198 */}, { 0xE169785B, 0x7B4CC524 /* 199 */},
+ { 0x35CA1385, 0x21D87F01 /* 200 */}, { 0x137B8AA5, 0xCEBB400F /* 201 */},
+ { 0x580796BE, 0x272E2B66 /* 202 */}, { 0x25C2B0DE, 0x36122641 /* 203 */},
+ { 0xAD1EFBB2, 0x057702BD /* 204 */}, { 0xACF84BE9, 0xD4BABB8E /* 205 */},
+ { 0x641BC67B, 0x91583139 /* 206 */}, { 0x8036E024, 0x8BDC2DE0 /* 207 */},
+ { 0xF49F68ED, 0x603C8156 /* 208 */}, { 0xDBEF5111, 0xF7D236F7 /* 209 */},
+ { 0x8AD21E80, 0x9727C459 /* 210 */}, { 0x670A5FD7, 0xA08A0896 /* 211 */},
+ { 0x09EBA9CB, 0xCB4A8F43 /* 212 */}, { 0x0F7036A1, 0x81AF564B /* 213 */},
+ { 0x78199ABD, 0xC0B99AA7 /* 214 */}, { 0x3FC8E952, 0x959F1EC8 /* 215 */},
+ { 0x794A81B9, 0x8C505077 /* 216 */}, { 0x056338F0, 0x3ACAAF8F /* 217 */},
+ { 0x627A6778, 0x07B43F50 /* 218 */}, { 0xF5ECCC77, 0x4A44AB49 /* 219 */},
+ { 0xB679EE98, 0x3BC3D6E4 /* 220 */}, { 0xCF14108C, 0x9CC0D4D1 /* 221 */},
+ { 0x206BC8A0, 0x4406C00B /* 222 */}, { 0xC8D72D89, 0x82A18854 /* 223 */},
+ { 0x5C3C432C, 0x67E366B3 /* 224 */}, { 0x102B37F2, 0xB923DD61 /* 225 */},
+ { 0xD884271D, 0x56AB2779 /* 226 */}, { 0xFF1525AF, 0xBE83E1B0 /* 227 */},
+ { 0x217E49A9, 0xFB7C65D4 /* 228 */}, { 0x6D48E7D4, 0x6BDBE0E7 /* 229 */},
+ { 0x45D9179E, 0x08DF8287 /* 230 */}, { 0xDD53BD34, 0x22EA6A9A /* 231 */},
+ { 0x5622200A, 0xE36E141C /* 232 */}, { 0x8CB750EE, 0x7F805D1B /* 233 */},
+ { 0x9F58E837, 0xAFE5C7A5 /* 234 */}, { 0x4FB1C23C, 0xE27F996A /* 235 */},
+ { 0x0775F0D0, 0xD3867DFB /* 236 */}, { 0x6E88891A, 0xD0E673DE /* 237 */},
+ { 0xAFB86C25, 0x123AEB9E /* 238 */}, { 0xC145B895, 0x30F1D5D5 /* 239 */},
+ { 0xEE7269E7, 0xBB434A2D /* 240 */}, { 0xF931FA38, 0x78CB67EC /* 241 */},
+ { 0x323BBF9C, 0xF33B0372 /* 242 */}, { 0xFB279C74, 0x52D66336 /* 243 */},
+ { 0x0AFB4EAA, 0x505F33AC /* 244 */}, { 0xA2CCE187, 0xE8A5CD99 /* 245 */},
+ { 0x1E2D30BB, 0x53497480 /* 246 */}, { 0xD5876D90, 0x8D2D5711 /* 247 */},
+ { 0x91BC038E, 0x1F1A4128 /* 248 */}, { 0x82E56648, 0xD6E2E71D /* 249 */},
+ { 0x497732B7, 0x74036C3A /* 250 */}, { 0x6361F5AB, 0x89B67ED9 /* 251 */},
+ { 0xF1EA02A2, 0xFFED95D8 /* 252 */}, { 0x1464D43D, 0xE72B3BD6 /* 253 */},
+ { 0x0BDC4820, 0xA6300F17 /* 254 */}, { 0xED78A77A, 0xEBC18760 /* 255 */},
+ { 0x05A12138, 0xE6A6BE5A /* 256 */}, { 0xB4F87C98, 0xB5A122A5 /* 257 */},
+ { 0x140B6990, 0x563C6089 /* 258 */}, { 0x391F5DD5, 0x4C46CB2E /* 259 */},
+ { 0xC9B79434, 0xD932ADDB /* 260 */}, { 0x2015AFF5, 0x08EA70E4 /* 261 */},
+ { 0x3E478CF1, 0xD765A667 /* 262 */}, { 0xAB278D99, 0xC4FB757E /* 263 */},
+ { 0x2D6E0692, 0xDF11C686 /* 264 */}, { 0x0D7F3B16, 0xDDEB84F1 /* 265 */},
+ { 0xA665EA04, 0x6F2EF604 /* 266 */}, { 0xF0E0DFB3, 0x4A8E0F0F /* 267 */},
+ { 0x3DBCBA51, 0xA5EDEEF8 /* 268 */}, { 0x0EA4371E, 0xFC4F0A2A /* 269 */},
+ { 0x5CB38429, 0xE83E1DA8 /* 270 */}, { 0xBA1B1CE2, 0xDC8FF882 /* 271 */},
+ { 0x8353E80D, 0xCD45505E /* 272 */}, { 0xD4DB0717, 0x18D19A00 /* 273 */},
+ { 0xA5F38101, 0x34A0CFED /* 274 */}, { 0x8887CAF2, 0x0BE77E51 /* 275 */},
+ { 0xB3C45136, 0x1E341438 /* 276 */}, { 0x9089CCF9, 0xE05797F4 /* 277 */},
+ { 0xF2591D14, 0xFFD23F9D /* 278 */}, { 0x8595C5CD, 0x543DDA22 /* 279 */},
+ { 0x99052A33, 0x661F81FD /* 280 */}, { 0xDB0F7B76, 0x8736E641 /* 281 */},
+ { 0x418E5307, 0x15227725 /* 282 */}, { 0x162EB2FA, 0xE25F7F46 /* 283 */},
+ { 0x6C13D9FE, 0x48A8B212 /* 284 */}, { 0x92E76EEA, 0xAFDC5417 /* 285 */},
+ { 0xC6D1898F, 0x03D912BF /* 286 */}, { 0x1B83F51B, 0x31B1AAFA /* 287 */},
+ { 0xE42AB7D9, 0xF1AC2796 /* 288 */}, { 0xFCD2EBAC, 0x40A3A7D7 /* 289 */},
+ { 0x0AFBBCC5, 0x1056136D /* 290 */}, { 0x9A6D0C85, 0x7889E1DD /* 291 */},
+ { 0x2A7974AA, 0xD3352578 /* 292 */}, { 0x078AC09B, 0xA7E25D09 /* 293 */},
+ { 0xEAC6EDD0, 0xBD4138B3 /* 294 */}, { 0x71EB9E70, 0x920ABFBE /* 295 */},
+ { 0x4FC2625C, 0xA2A5D0F5 /* 296 */}, { 0x0B1290A3, 0xC054E36B /* 297 */},
+ { 0x62FE932B, 0xF6DD59FF /* 298 */}, { 0x11A8AC7D, 0x35373545 /* 299 */},
+ { 0x72FADCD4, 0xCA845E91 /* 300 */}, { 0x329D20DC, 0x84F82B60 /* 301 */},
+ { 0xCD672F18, 0x79C62CE1 /* 302 */}, { 0xD124642C, 0x8B09A2AD /* 303 */},
+ { 0x19D9E726, 0xD0C1E96A /* 304 */}, { 0x4BA9500C, 0x5A786A9B /* 305 */},
+ { 0x634C43F3, 0x0E020336 /* 306 */}, { 0xEB66D822, 0xC17B474A /* 307 */},
+ { 0xEC9BAAC2, 0x6A731AE3 /* 308 */}, { 0xE0840258, 0x8226667A /* 309 */},
+ { 0x91CAECA5, 0x67D45676 /* 310 */}, { 0x4875ADB5, 0x1D94155C /* 311 */},
+ { 0x5B813FDF, 0x6D00FD98 /* 312 */}, { 0xB774CD06, 0x51286EFC /* 313 */},
+ { 0x1FA744AF, 0x5E883447 /* 314 */}, { 0xE761AE2E, 0xF72CA0AE /* 315 */},
+ { 0xAEE8E09A, 0xBE40E4CD /* 316 */}, { 0x5118F665, 0xE9970BBB /* 317 */},
+ { 0x33DF1964, 0x726E4BEB /* 318 */}, { 0x29199762, 0x703B0007 /* 319 */},
+ { 0xF5EF30A7, 0x4631D816 /* 320 */}, { 0x1504A6BE, 0xB880B5B5 /* 321 */},
+ { 0x7ED84B6C, 0x641793C3 /* 322 */}, { 0xF6E97D96, 0x7B21ED77 /* 323 */},
+ { 0x2EF96B73, 0x77630631 /* 324 */}, { 0xE86FF3F4, 0xAE528948 /* 325 */},
+ { 0x86A3F8F8, 0x53DBD7F2 /* 326 */}, { 0x4CFC1063, 0x16CADCE7 /* 327 */},
+ { 0xFA52C6DD, 0x005C19BD /* 328 */}, { 0x64D46AD3, 0x68868F5D /* 329 */},
+ { 0xCF1E186A, 0x3A9D512C /* 330 */}, { 0x385660AE, 0x367E62C2 /* 331 */},
+ { 0x77DCB1D7, 0xE359E7EA /* 332 */}, { 0x749ABE6E, 0x526C0773 /* 333 */},
+ { 0xD09F734B, 0x735AE5F9 /* 334 */}, { 0x8A558BA8, 0x493FC7CC /* 335 */},
+ { 0x3041AB45, 0xB0B9C153 /* 336 */}, { 0x470A59BD, 0x321958BA /* 337 */},
+ { 0x5F46C393, 0x852DB00B /* 338 */}, { 0xD336B0E5, 0x91209B2B /* 339 */},
+ { 0x659EF19F, 0x6E604F7D /* 340 */}, { 0x782CCB24, 0xB99A8AE2 /* 341 */},
+ { 0xC814C4C7, 0xCCF52AB6 /* 342 */}, { 0xBE11727B, 0x4727D9AF /* 343 */},
+ { 0x0121B34D, 0x7E950D0C /* 344 */}, { 0x70AD471F, 0x756F4356 /* 345 */},
+ { 0x615A6849, 0xF5ADD442 /* 346 */}, { 0x80B9957A, 0x4E87E099 /* 347 */},
+ { 0x50AEE355, 0x2ACFA1DF /* 348 */}, { 0xFD2FD556, 0xD898263A /* 349 */},
+ { 0xD80C8FD6, 0xC8F4924D /* 350 */}, { 0x754A173A, 0xCF99CA3D /* 351 */},
+ { 0xAF91BF3C, 0xFE477BAC /* 352 */}, { 0xD690C12D, 0xED5371F6 /* 353 */},
+ { 0x5E687094, 0x831A5C28 /* 354 */}, { 0x3708A0A4, 0xC5D3C90A /* 355 */},
+ { 0x17D06580, 0x0F7F9037 /* 356 */}, { 0xB8FDF27F, 0x19F9BB13 /* 357 */},
+ { 0x4D502843, 0xB1BD6F1B /* 358 */}, { 0x8FFF4012, 0x1C761BA3 /* 359 */},
+ { 0xE2E21F3B, 0x0D1530C4 /* 360 */}, { 0xA7372C8A, 0x8943CE69 /* 361 */},
+ { 0xFEB5CE66, 0xE5184E11 /* 362 */}, { 0xBD736621, 0x618BDB80 /* 363 */},
+ { 0x8B574D0B, 0x7D29BAD6 /* 364 */}, { 0x25E6FE5B, 0x81BB613E /* 365 */},
+ { 0xBC07913F, 0x071C9C10 /* 366 */}, { 0x09AC2D97, 0xC7BEEB79 /* 367 */},
+ { 0x3BC5D757, 0xC3E58D35 /* 368 */}, { 0xF38F61E8, 0xEB017892 /* 369 */},
+ { 0x9B1CC21A, 0xD4EFFB9C /* 370 */}, { 0xF494F7AB, 0x99727D26 /* 371 */},
+ { 0x956B3E03, 0xA3E063A2 /* 372 */}, { 0x4AA09C30, 0x9D4A8B9A /* 373 */},
+ { 0x00090FB4, 0x3F6AB7D5 /* 374 */}, { 0x57268AC0, 0x9CC0F2A0 /* 375 */},
+ { 0xEDBF42D1, 0x3DEE9D2D /* 376 */}, { 0x7960A972, 0x330F49C8 /* 377 */},
+ { 0x87421B41, 0xC6B27202 /* 378 */}, { 0x7C00369C, 0x0AC59EC0 /* 379 */},
+ { 0xCB353425, 0xEF4EAC49 /* 380 */}, { 0xEF0129D8, 0xF450244E /* 381 */},
+ { 0xCAF4DEB6, 0x8ACC46E5 /* 382 */}, { 0x989263F7, 0x2FFEAB63 /* 383 */},
+ { 0x5D7A4578, 0x8F7CB9FE /* 384 */}, { 0x4E634635, 0x5BD8F764 /* 385 */},
+ { 0xBF2DC900, 0x427A7315 /* 386 */}, { 0x2125261C, 0x17D0C4AA /* 387 */},
+ { 0x93518E50, 0x3992486C /* 388 */}, { 0xA2D7D4C3, 0xB4CBFEE0 /* 389 */},
+ { 0x2C5DDD8D, 0x7C75D620 /* 390 */}, { 0xE35B6C61, 0xDBC295D8 /* 391 */},
+ { 0x02032B19, 0x60B369D3 /* 392 */}, { 0xDCE44132, 0xCE42685F /* 393 */},
+ { 0xDDF65610, 0x06F3DDB9 /* 394 */}, { 0xB5E148F0, 0x8EA4D21D /* 395 */},
+ { 0x2FCD496F, 0x20B0FCE6 /* 396 */}, { 0x58B0EE31, 0x2C1B9123 /* 397 */},
+ { 0x18F5A308, 0xB28317B8 /* 398 */}, { 0x9CA6D2CF, 0xA89C1E18 /* 399 */},
+ { 0x6AAADBC8, 0x0C6B1857 /* 400 */}, { 0x1299FAE3, 0xB65DEAA9 /* 401 */},
+ { 0x7F1027E7, 0xFB2B794B /* 402 */}, { 0x443B5BEB, 0x04E4317F /* 403 */},
+ { 0x5939D0A6, 0x4B852D32 /* 404 */}, { 0xFB207FFC, 0xD5AE6BEE /* 405 */},
+ { 0x81C7D374, 0x309682B2 /* 406 */}, { 0x94C3B475, 0xBAE309A1 /* 407 */},
+ { 0x13B49F05, 0x8CC3F97B /* 408 */}, { 0xF8293967, 0x98A9422F /* 409 */},
+ { 0x1076FF7C, 0x244B16B0 /* 410 */}, { 0x663D67EE, 0xF8BF571C /* 411 */},
+ { 0xEEE30DA1, 0x1F0D6758 /* 412 */}, { 0x7ADEB9B7, 0xC9B611D9 /* 413 */},
+ { 0x7B6C57A2, 0xB7AFD588 /* 414 */}, { 0x6B984FE1, 0x6290AE84 /* 415 */},
+ { 0xACC1A5FD, 0x94DF4CDE /* 416 */}, { 0xC5483AFF, 0x058A5BD1 /* 417 */},
+ { 0x42BA3C37, 0x63166CC1 /* 418 */}, { 0xB2F76F40, 0x8DB8526E /* 419 */},
+ { 0x6F0D6D4E, 0xE1088003 /* 420 */}, { 0x971D311D, 0x9E0523C9 /* 421 */},
+ { 0xCC7CD691, 0x45EC2824 /* 422 */}, { 0xE62382C9, 0x575B8359 /* 423 */},
+ { 0xC4889995, 0xFA9E400D /* 424 */}, { 0x45721568, 0xD1823ECB /* 425 */},
+ { 0x8206082F, 0xDAFD983B /* 426 */}, { 0x2386A8CB, 0xAA7D2908 /* 427 */},
+ { 0x03B87588, 0x269FCD44 /* 428 */}, { 0x28BDD1E0, 0x1B91F5F7 /* 429 */},
+ { 0x040201F6, 0xE4669F39 /* 430 */}, { 0x8CF04ADE, 0x7A1D7C21 /* 431 */},
+ { 0xD79CE5CE, 0x65623C29 /* 432 */}, { 0x96C00BB1, 0x23684490 /* 433 */},
+ { 0x9DA503BA, 0xAB9BF187 /* 434 */}, { 0xA458058E, 0xBC23ECB1 /* 435 */},
+ { 0xBB401ECC, 0x9A58DF01 /* 436 */}, { 0xA85F143D, 0xA070E868 /* 437 */},
+ { 0x7DF2239E, 0x4FF18830 /* 438 */}, { 0x1A641183, 0x14D565B4 /* 439 */},
+ { 0x52701602, 0xEE133374 /* 440 */}, { 0x3F285E09, 0x950E3DCF /* 441 */},
+ { 0xB9C80953, 0x59930254 /* 442 */}, { 0x8930DA6D, 0x3BF29940 /* 443 */},
+ { 0x53691387, 0xA955943F /* 444 */}, { 0xA9CB8784, 0xA15EDECA /* 445 */},
+ { 0x352BE9A0, 0x29142127 /* 446 */}, { 0xFF4E7AFB, 0x76F0371F /* 447 */},
+ { 0x274F2228, 0x0239F450 /* 448 */}, { 0x1D5E868B, 0xBB073AF0 /* 449 */},
+ { 0xC10E96C1, 0xBFC80571 /* 450 */}, { 0x68222E23, 0xD2670885 /* 451 */},
+ { 0x8E80B5B0, 0x9671A3D4 /* 452 */}, { 0xE193BB81, 0x55B5D38A /* 453 */},
+ { 0xA18B04B8, 0x693AE2D0 /* 454 */}, { 0xADD5335F, 0x5C48B4EC /* 455 */},
+ { 0x4916A1CA, 0xFD743B19 /* 456 */}, { 0x34BE98C4, 0x25770181 /* 457 */},
+ { 0x3C54A4AD, 0xE77987E8 /* 458 */}, { 0xDA33E1B9, 0x28E11014 /* 459 */},
+ { 0x226AA213, 0x270CC59E /* 460 */}, { 0x6D1A5F60, 0x71495F75 /* 461 */},
+ { 0x60AFEF77, 0x9BE853FB /* 462 */}, { 0xF7443DBF, 0xADC786A7 /* 463 */},
+ { 0x73B29A82, 0x09044561 /* 464 */}, { 0xC232BD5E, 0x58BC7A66 /* 465 */},
+ { 0x673AC8B2, 0xF306558C /* 466 */}, { 0xB6C9772A, 0x41F639C6 /* 467 */},
+ { 0x9FDA35DA, 0x216DEFE9 /* 468 */}, { 0x1C7BE615, 0x11640CC7 /* 469 */},
+ { 0x565C5527, 0x93C43694 /* 470 */}, { 0x46777839, 0xEA038E62 /* 471 */},
+ { 0x5A3E2469, 0xF9ABF3CE /* 472 */}, { 0x0FD312D2, 0x741E768D /* 473 */},
+ { 0xCED652C6, 0x0144B883 /* 474 */}, { 0xA33F8552, 0xC20B5A5B /* 475 */},
+ { 0xC3435A9D, 0x1AE69633 /* 476 */}, { 0x088CFDEC, 0x97A28CA4 /* 477 */},
+ { 0x1E96F420, 0x8824A43C /* 478 */}, { 0x6EEEA746, 0x37612FA6 /* 479 */},
+ { 0xF9CF0E5A, 0x6B4CB165 /* 480 */}, { 0xA0ABFB4A, 0x43AA1C06 /* 481 */},
+ { 0xF162796B, 0x7F4DC26F /* 482 */}, { 0x54ED9B0F, 0x6CBACC8E /* 483 */},
+ { 0xD2BB253E, 0xA6B7FFEF /* 484 */}, { 0xB0A29D4F, 0x2E25BC95 /* 485 */},
+ { 0xDEF1388C, 0x86D6A58B /* 486 */}, { 0x76B6F054, 0xDED74AC5 /* 487 */},
+ { 0x2B45805D, 0x8030BDBC /* 488 */}, { 0xE94D9289, 0x3C81AF70 /* 489 */},
+ { 0x9E3100DB, 0x3EFF6DDA /* 490 */}, { 0xDFCC8847, 0xB38DC39F /* 491 */},
+ { 0x8D17B87E, 0x12388552 /* 492 */}, { 0x40B1B642, 0xF2DA0ED2 /* 493 */},
+ { 0xD54BF9A9, 0x44CEFADC /* 494 */}, { 0x433C7EE6, 0x1312200E /* 495 */},
+ { 0x3A78C748, 0x9FFCC84F /* 496 */}, { 0x248576BB, 0xF0CD1F72 /* 497 */},
+ { 0x3638CFE4, 0xEC697405 /* 498 */}, { 0x0CEC4E4C, 0x2BA7B67C /* 499 */},
+ { 0xE5CE32ED, 0xAC2F4DF3 /* 500 */}, { 0x26EA4C11, 0xCB33D143 /* 501 */},
+ { 0xC77E58BC, 0xA4E9044C /* 502 */}, { 0xD934FCEF, 0x5F513293 /* 503 */},
+ { 0x06E55444, 0x5DC96455 /* 504 */}, { 0x317DE40A, 0x50DE418F /* 505 */},
+ { 0x69DDE259, 0x388CB31A /* 506 */}, { 0x55820A86, 0x2DB4A834 /* 507 */},
+ { 0x84711AE9, 0x9010A91E /* 508 */}, { 0xB1498371, 0x4DF7F0B7 /* 509 */},
+ { 0xC0977179, 0xD62A2EAB /* 510 */}, { 0xAA8D5C0E, 0x22FAC097 /* 511 */},
+ { 0xF1DAF39B, 0xF49FCC2F /* 512 */}, { 0x6FF29281, 0x487FD5C6 /* 513 */},
+ { 0xFCDCA83F, 0xE8A30667 /* 514 */}, { 0xD2FCCE63, 0x2C9B4BE3 /* 515 */},
+ { 0x93FBBBC2, 0xDA3FF74B /* 516 */}, { 0xFE70BA66, 0x2FA165D2 /* 517 */},
+ { 0x970E93D4, 0xA103E279 /* 518 */}, { 0xB0E45E71, 0xBECDEC77 /* 519 */},
+ { 0x3985E497, 0xCFB41E72 /* 520 */}, { 0x5EF75017, 0xB70AAA02 /* 521 */},
+ { 0x3840B8E0, 0xD42309F0 /* 522 */}, { 0x35898579, 0x8EFC1AD0 /* 523 */},
+ { 0xE2B2ABC5, 0x96C6920B /* 524 */}, { 0x375A9172, 0x66AF4163 /* 525 */},
+ { 0xCA7127FB, 0x2174ABDC /* 526 */}, { 0x4A72FF41, 0xB33CCEA6 /* 527 */},
+ { 0x083066A5, 0xF04A4933 /* 528 */}, { 0xD7289AF5, 0x8D970ACD /* 529 */},
+ { 0x31C8C25E, 0x8F96E8E0 /* 530 */}, { 0x76875D47, 0xF3FEC022 /* 531 */},
+ { 0x056190DD, 0xEC7BF310 /* 532 */}, { 0xBB0F1491, 0xF5ADB0AE /* 533 */},
+ { 0x0FD58892, 0x9B50F885 /* 534 */}, { 0x58B74DE8, 0x49754883 /* 535 */},
+ { 0x91531C61, 0xA3354FF6 /* 536 */}, { 0x81D2C6EE, 0x0702BBE4 /* 537 */},
+ { 0x7DEDED98, 0x89FB2405 /* 538 */}, { 0x8596E902, 0xAC307513 /* 539 */},
+ { 0x172772ED, 0x1D2D3580 /* 540 */}, { 0x8E6BC30D, 0xEB738FC2 /* 541 */},
+ { 0x63044326, 0x5854EF8F /* 542 */}, { 0x5ADD3BBE, 0x9E5C5232 /* 543 */},
+ { 0x325C4623, 0x90AA53CF /* 544 */}, { 0x349DD067, 0xC1D24D51 /* 545 */},
+ { 0xA69EA624, 0x2051CFEE /* 546 */}, { 0x862E7E4F, 0x13220F0A /* 547 */},
+ { 0x04E04864, 0xCE393994 /* 548 */}, { 0x7086FCB7, 0xD9C42CA4 /* 549 */},
+ { 0x8A03E7CC, 0x685AD223 /* 550 */}, { 0xAB2FF1DB, 0x066484B2 /* 551 */},
+ { 0xEFBF79EC, 0xFE9D5D70 /* 552 */}, { 0x9C481854, 0x5B13B9DD /* 553 */},
+ { 0xED1509AD, 0x15F0D475 /* 554 */}, { 0x0EC79851, 0x0BEBCD06 /* 555 */},
+ { 0x183AB7F8, 0xD58C6791 /* 556 */}, { 0x52F3EEE4, 0xD1187C50 /* 557 */},
+ { 0xE54E82FF, 0xC95D1192 /* 558 */}, { 0xB9AC6CA2, 0x86EEA14C /* 559 */},
+ { 0x53677D5D, 0x3485BEB1 /* 560 */}, { 0x1F8C492A, 0xDD191D78 /* 561 */},
+ { 0xA784EBF9, 0xF60866BA /* 562 */}, { 0xA2D08C74, 0x518F643B /* 563 */},
+ { 0xE1087C22, 0x8852E956 /* 564 */}, { 0xC410AE8D, 0xA768CB8D /* 565 */},
+ { 0xBFEC8E1A, 0x38047726 /* 566 */}, { 0xCD3B45AA, 0xA67738B4 /* 567 */},
+ { 0xEC0DDE19, 0xAD16691C /* 568 */}, { 0x80462E07, 0xC6D43193 /* 569 */},
+ { 0x0BA61938, 0xC5A5876D /* 570 */}, { 0xA58FD840, 0x16B9FA1F /* 571 */},
+ { 0x3CA74F18, 0x188AB117 /* 572 */}, { 0xC99C021F, 0xABDA2F98 /* 573 */},
+ { 0x134AE816, 0x3E0580AB /* 574 */}, { 0x73645ABB, 0x5F3B05B7 /* 575 */},
+ { 0x5575F2F6, 0x2501A2BE /* 576 */}, { 0x4E7E8BA9, 0x1B2F7400 /* 577 */},
+ { 0x71E8D953, 0x1CD75803 /* 578 */}, { 0x62764E30, 0x7F6ED895 /* 579 */},
+ { 0x596F003D, 0xB15926FF /* 580 */}, { 0xA8C5D6B9, 0x9F65293D /* 581 */},
+ { 0xD690F84C, 0x6ECEF04D /* 582 */}, { 0xFF33AF88, 0x4782275F /* 583 */},
+ { 0x3F820801, 0xE4143308 /* 584 */}, { 0x9A1AF9B5, 0xFD0DFE40 /* 585 */},
+ { 0x2CDB396B, 0x4325A334 /* 586 */}, { 0xB301B252, 0x8AE77E62 /* 587 */},
+ { 0x6655615A, 0xC36F9E9F /* 588 */}, { 0x92D32C09, 0x85455A2D /* 589 */},
+ { 0x49477485, 0xF2C7DEA9 /* 590 */}, { 0x33A39EBA, 0x63CFB4C1 /* 591 */},
+ { 0x6EBC5462, 0x83B040CC /* 592 */}, { 0xFDB326B0, 0x3B9454C8 /* 593 */},
+ { 0x87FFD78C, 0x56F56A9E /* 594 */}, { 0x99F42BC6, 0x2DC2940D /* 595 */},
+ { 0x6B096E2D, 0x98F7DF09 /* 596 */}, { 0x3AD852BF, 0x19A6E01E /* 597 */},
+ { 0xDBD4B40B, 0x42A99CCB /* 598 */}, { 0x45E9C559, 0xA59998AF /* 599 */},
+ { 0x07D93186, 0x366295E8 /* 600 */}, { 0xFAA1F773, 0x6B48181B /* 601 */},
+ { 0x157A0A1D, 0x1FEC57E2 /* 602 */}, { 0xF6201AD5, 0x4667446A /* 603 */},
+ { 0xCFB0F075, 0xE615EBCA /* 604 */}, { 0x68290778, 0xB8F31F4F /* 605 */},
+ { 0xCE22D11E, 0x22713ED6 /* 606 */}, { 0x2EC3C93B, 0x3057C1A7 /* 607 */},
+ { 0x7C3F1F2F, 0xCB46ACC3 /* 608 */}, { 0x02AAF50E, 0xDBB893FD /* 609 */},
+ { 0x600B9FCF, 0x331FD92E /* 610 */}, { 0x48EA3AD6, 0xA498F961 /* 611 */},
+ { 0x8B6A83EA, 0xA8D8426E /* 612 */}, { 0xB7735CDC, 0xA089B274 /* 613 */},
+ { 0x1E524A11, 0x87F6B373 /* 614 */}, { 0xCBC96749, 0x118808E5 /* 615 */},
+ { 0xB19BD394, 0x9906E4C7 /* 616 */}, { 0x9B24A20C, 0xAFED7F7E /* 617 */},
+ { 0xEB3644A7, 0x6509EADE /* 618 */}, { 0xE8EF0EDE, 0x6C1EF1D3 /* 619 */},
+ { 0xE9798FB4, 0xB9C97D43 /* 620 */}, { 0x740C28A3, 0xA2F2D784 /* 621 */},
+ { 0x6197566F, 0x7B849647 /* 622 */}, { 0xB65F069D, 0x7A5BE3E6 /* 623 */},
+ { 0x78BE6F10, 0xF96330ED /* 624 */}, { 0x7A076A15, 0xEEE60DE7 /* 625 */},
+ { 0xA08B9BD0, 0x2B4BEE4A /* 626 */}, { 0xC7B8894E, 0x6A56A63E /* 627 */},
+ { 0xBA34FEF4, 0x02121359 /* 628 */}, { 0x283703FC, 0x4CBF99F8 /* 629 */},
+ { 0x0CAF30C8, 0x39807135 /* 630 */}, { 0xF017687A, 0xD0A77A89 /* 631 */},
+ { 0x9E423569, 0xF1C1A9EB /* 632 */}, { 0x2DEE8199, 0x8C797628 /* 633 */},
+ { 0xDD1F7ABD, 0x5D1737A5 /* 634 */}, { 0x09A9FA80, 0x4F53433C /* 635 */},
+ { 0xDF7CA1D9, 0xFA8B0C53 /* 636 */}, { 0x886CCB77, 0x3FD9DCBC /* 637 */},
+ { 0xA91B4720, 0xC040917C /* 638 */}, { 0xF9D1DCDF, 0x7DD00142 /* 639 */},
+ { 0x4F387B58, 0x8476FC1D /* 640 */}, { 0xF3316503, 0x23F8E7C5 /* 641 */},
+ { 0xE7E37339, 0x032A2244 /* 642 */}, { 0x50F5A74B, 0x5C87A5D7 /* 643 */},
+ { 0x3698992E, 0x082B4CC4 /* 644 */}, { 0xB858F63C, 0xDF917BEC /* 645 */},
+ { 0x5BF86DDA, 0x3270B8FC /* 646 */}, { 0x29B5DD76, 0x10AE72BB /* 647 */},
+ { 0x7700362B, 0x576AC94E /* 648 */}, { 0xC61EFB8F, 0x1AD112DA /* 649 */},
+ { 0xC5FAA427, 0x691BC30E /* 650 */}, { 0xCC327143, 0xFF246311 /* 651 */},
+ { 0x30E53206, 0x3142368E /* 652 */}, { 0xE02CA396, 0x71380E31 /* 653 */},
+ { 0x0AAD76F1, 0x958D5C96 /* 654 */}, { 0xC16DA536, 0xF8D6F430 /* 655 */},
+ { 0x1BE7E1D2, 0xC8FFD13F /* 656 */}, { 0x004DDBE1, 0x7578AE66 /* 657 */},
+ { 0x067BE646, 0x05833F01 /* 658 */}, { 0x3BFE586D, 0xBB34B5AD /* 659 */},
+ { 0xA12B97F0, 0x095F34C9 /* 660 */}, { 0x25D60CA8, 0x247AB645 /* 661 */},
+ { 0x017477D1, 0xDCDBC6F3 /* 662 */}, { 0xDECAD24D, 0x4A2E14D4 /* 663 */},
+ { 0xBE0A1EEB, 0xBDB5E6D9 /* 664 */}, { 0x794301AB, 0x2A7E70F7 /* 665 */},
+ { 0x270540FD, 0xDEF42D8A /* 666 */}, { 0xA34C22C1, 0x01078EC0 /* 667 */},
+ { 0xF4C16387, 0xE5DE511A /* 668 */}, { 0xBD9A330A, 0x7EBB3A52 /* 669 */},
+ { 0xAA7D6435, 0x77697857 /* 670 */}, { 0x03AE4C32, 0x004E8316 /* 671 */},
+ { 0xAD78E312, 0xE7A21020 /* 672 */}, { 0x6AB420F2, 0x9D41A70C /* 673 */},
+ { 0xEA1141E6, 0x28E06C18 /* 674 */}, { 0x984F6B28, 0xD2B28CBD /* 675 */},
+ { 0x446E9D83, 0x26B75F6C /* 676 */}, { 0x4D418D7F, 0xBA47568C /* 677 */},
+ { 0xE6183D8E, 0xD80BADBF /* 678 */}, { 0x5F166044, 0x0E206D7F /* 679 */},
+ { 0x11CBCA3E, 0xE258A439 /* 680 */}, { 0xB21DC0BC, 0x723A1746 /* 681 */},
+ { 0xF5D7CDD3, 0xC7CAA854 /* 682 */}, { 0x3D261D9C, 0x7CAC3288 /* 683 */},
+ { 0x23BA942C, 0x7690C264 /* 684 */}, { 0x478042B8, 0x17E55524 /* 685 */},
+ { 0x56A2389F, 0xE0BE4776 /* 686 */}, { 0x67AB2DA0, 0x4D289B5E /* 687 */},
+ { 0x8FBBFD31, 0x44862B9C /* 688 */}, { 0x9D141365, 0xB47CC804 /* 689 */},
+ { 0x2B91C793, 0x822C1B36 /* 690 */}, { 0xFB13DFD8, 0x4EB14655 /* 691 */},
+ { 0x14E2A97B, 0x1ECBBA07 /* 692 */}, { 0x5CDE5F14, 0x6143459D /* 693 */},
+ { 0xD5F0AC89, 0x53A8FBF1 /* 694 */}, { 0x1C5E5B00, 0x97EA04D8 /* 695 */},
+ { 0xD4FDB3F3, 0x622181A8 /* 696 */}, { 0x572A1208, 0xE9BCD341 /* 697 */},
+ { 0x43CCE58A, 0x14112586 /* 698 */}, { 0xA4C6E0A4, 0x9144C5FE /* 699 */},
+ { 0x65CF620F, 0x0D33D065 /* 700 */}, { 0x9F219CA1, 0x54A48D48 /* 701 */},
+ { 0x6D63C821, 0xC43E5EAC /* 702 */}, { 0x72770DAF, 0xA9728B3A /* 703 */},
+ { 0x20DF87EF, 0xD7934E7B /* 704 */}, { 0x1A3E86E5, 0xE35503B6 /* 705 */},
+ { 0xC819D504, 0xCAE321FB /* 706 */}, { 0xAC60BFA6, 0x129A50B3 /* 707 */},
+ { 0x7E9FB6C3, 0xCD5E68EA /* 708 */}, { 0x9483B1C7, 0xB01C9019 /* 709 */},
+ { 0xC295376C, 0x3DE93CD5 /* 710 */}, { 0x2AB9AD13, 0xAED52EDF /* 711 */},
+ { 0xC0A07884, 0x2E60F512 /* 712 */}, { 0xE36210C9, 0xBC3D86A3 /* 713 */},
+ { 0x163951CE, 0x35269D9B /* 714 */}, { 0xD0CDB5FA, 0x0C7D6E2A /* 715 */},
+ { 0xD87F5733, 0x59E86297 /* 716 */}, { 0x898DB0E7, 0x298EF221 /* 717 */},
+ { 0xD1A5AA7E, 0x55000029 /* 718 */}, { 0xB5061B45, 0x8BC08AE1 /* 719 */},
+ { 0x6C92703A, 0xC2C31C2B /* 720 */}, { 0xAF25EF42, 0x94CC596B /* 721 */},
+ { 0x22540456, 0x0A1D73DB /* 722 */}, { 0xD9C4179A, 0x04B6A0F9 /* 723 */},
+ { 0xAE3D3C60, 0xEFFDAFA2 /* 724 */}, { 0xB49496C4, 0xF7C8075B /* 725 */},
+ { 0x1D1CD4E3, 0x9CC5C714 /* 726 */}, { 0x218E5534, 0x78BD1638 /* 727 */},
+ { 0xF850246A, 0xB2F11568 /* 728 */}, { 0x9502BC29, 0xEDFABCFA /* 729 */},
+ { 0xDA23051B, 0x796CE5F2 /* 730 */}, { 0xDC93537C, 0xAAE128B0 /* 731 */},
+ { 0xEE4B29AE, 0x3A493DA0 /* 732 */}, { 0x416895D7, 0xB5DF6B2C /* 733 */},
+ { 0x122D7F37, 0xFCABBD25 /* 734 */}, { 0x105DC4B1, 0x70810B58 /* 735 */},
+ { 0xF7882A90, 0xE10FDD37 /* 736 */}, { 0x518A3F5C, 0x524DCAB5 /* 737 */},
+ { 0x8451255B, 0x3C9E8587 /* 738 */}, { 0x19BD34E2, 0x40298281 /* 739 */},
+ { 0x5D3CECCB, 0x74A05B6F /* 740 */}, { 0x42E13ECA, 0xB6100215 /* 741 */},
+ { 0x2F59E2AC, 0x0FF979D1 /* 742 */}, { 0xE4F9CC50, 0x6037DA27 /* 743 */},
+ { 0x0DF1847D, 0x5E92975A /* 744 */}, { 0xD3E623FE, 0xD66DE190 /* 745 */},
+ { 0x7B568048, 0x5032D6B8 /* 746 */}, { 0x8235216E, 0x9A36B7CE /* 747 */},
+ { 0x24F64B4A, 0x80272A7A /* 748 */}, { 0x8C6916F7, 0x93EFED8B /* 749 */},
+ { 0x4CCE1555, 0x37DDBFF4 /* 750 */}, { 0x4B99BD25, 0x4B95DB5D /* 751 */},
+ { 0x69812FC0, 0x92D3FDA1 /* 752 */}, { 0x90660BB6, 0xFB1A4A9A /* 753 */},
+ { 0x46A4B9B2, 0x730C1969 /* 754 */}, { 0x7F49DA68, 0x81E289AA /* 755 */},
+ { 0x83B1A05F, 0x64669A0F /* 756 */}, { 0x9644F48B, 0x27B3FF7D /* 757 */},
+ { 0x8DB675B3, 0xCC6B615C /* 758 */}, { 0xBCEBBE95, 0x674F20B9 /* 759 */},
+ { 0x75655982, 0x6F312382 /* 760 */}, { 0x3E45CF05, 0x5AE48871 /* 761 */},
+ { 0x54C21157, 0xBF619F99 /* 762 */}, { 0x40A8EAE9, 0xEABAC460 /* 763 */},
+ { 0xF2C0C1CD, 0x454C6FE9 /* 764 */}, { 0x6412691C, 0x419CF649 /* 765 */},
+ { 0x265B0F70, 0xD3DC3BEF /* 766 */}, { 0xC3578A9E, 0x6D0E60F5 /* 767 */},
+ { 0x26323C55, 0x5B0E6085 /* 768 */}, { 0xFA1B59F5, 0x1A46C1A9 /* 769 */},
+ { 0x7C4C8FFA, 0xA9E245A1 /* 770 */}, { 0xDB2955D7, 0x65CA5159 /* 771 */},
+ { 0xCE35AFC2, 0x05DB0A76 /* 772 */}, { 0xA9113D45, 0x81EAC77E /* 773 */},
+ { 0xB6AC0A0D, 0x528EF88A /* 774 */}, { 0x597BE3FF, 0xA09EA253 /* 775 */},
+ { 0xAC48CD56, 0x430DDFB3 /* 776 */}, { 0xF45CE46F, 0xC4B3A67A /* 777 */},
+ { 0xFBE2D05E, 0x4ECECFD8 /* 778 */}, { 0xB39935F0, 0x3EF56F10 /* 779 */},
+ { 0x9CD619C6, 0x0B22D682 /* 780 */}, { 0x74DF2069, 0x17FD460A /* 781 */},
+ { 0x8510ED40, 0x6CF8CC8E /* 782 */}, { 0x3A6ECAA7, 0xD6C824BF /* 783 */},
+ { 0x1A817049, 0x61243D58 /* 784 */}, { 0xBBC163A2, 0x048BACB6 /* 785 */},
+ { 0x7D44CC32, 0xD9A38AC2 /* 786 */}, { 0xAAF410AB, 0x7FDDFF5B /* 787 */},
+ { 0xA804824B, 0xAD6D495A /* 788 */}, { 0x2D8C9F94, 0xE1A6A74F /* 789 */},
+ { 0x35DEE8E3, 0xD4F78512 /* 790 */}, { 0x6540D893, 0xFD4B7F88 /* 791 */},
+ { 0x2AA4BFDA, 0x247C2004 /* 792 */}, { 0x17D1327C, 0x096EA1C5 /* 793 */},
+ { 0x361A6685, 0xD56966B4 /* 794 */}, { 0x1221057D, 0x277DA5C3 /* 795 */},
+ { 0xA43ACFF7, 0x94D59893 /* 796 */}, { 0xCDC02281, 0x64F0C51C /* 797 */},
+ { 0xFF6189DB, 0x3D33BCC4 /* 798 */}, { 0x4CE66AF1, 0xE005CB18 /* 799 */},
+ { 0x1DB99BEA, 0xFF5CCD1D /* 800 */}, { 0xFE42980F, 0xB0B854A7 /* 801 */},
+ { 0x718D4B9F, 0x7BD46A6A /* 802 */}, { 0x22A5FD8C, 0xD10FA8CC /* 803 */},
+ { 0x2BE4BD31, 0xD3148495 /* 804 */}, { 0xCB243847, 0xC7FA975F /* 805 */},
+ { 0x5846C407, 0x4886ED1E /* 806 */}, { 0x1EB70B04, 0x28CDDB79 /* 807 */},
+ { 0xF573417F, 0xC2B00BE2 /* 808 */}, { 0x2180F877, 0x5C959045 /* 809 */},
+ { 0xF370EB00, 0x7A6BDDFF /* 810 */}, { 0xD6D9D6A4, 0xCE509E38 /* 811 */},
+ { 0x647FA702, 0xEBEB0F00 /* 812 */}, { 0x76606F06, 0x1DCC06CF /* 813 */},
+ { 0xA286FF0A, 0xE4D9F28B /* 814 */}, { 0xC918C262, 0xD85A305D /* 815 */},
+ { 0x32225F54, 0x475B1D87 /* 816 */}, { 0x68CCB5FE, 0x2D4FB516 /* 817 */},
+ { 0xD72BBA20, 0xA679B9D9 /* 818 */}, { 0x912D43A5, 0x53841C0D /* 819 */},
+ { 0xBF12A4E8, 0x3B7EAA48 /* 820 */}, { 0xF22F1DDF, 0x781E0E47 /* 821 */},
+ { 0x0AB50973, 0xEFF20CE6 /* 822 */}, { 0x9DFFB742, 0x20D261D1 /* 823 */},
+ { 0x062A2E39, 0x16A12B03 /* 824 */}, { 0x39650495, 0x1960EB22 /* 825 */},
+ { 0xD50EB8B8, 0x251C16FE /* 826 */}, { 0xF826016E, 0x9AC0C330 /* 827 */},
+ { 0x953E7671, 0xED152665 /* 828 */}, { 0xA6369570, 0x02D63194 /* 829 */},
+ { 0x94B1C987, 0x5074F083 /* 830 */}, { 0x90B25CE1, 0x70BA598C /* 831 */},
+ { 0x0B9742F6, 0x794A1581 /* 832 */}, { 0xFCAF8C6C, 0x0D5925E9 /* 833 */},
+ { 0xD868744E, 0x3067716C /* 834 */}, { 0xE8D7731B, 0x910AB077 /* 835 */},
+ { 0x5AC42F61, 0x6A61BBDB /* 836 */}, { 0xF0851567, 0x93513EFB /* 837 */},
+ { 0x9E83E9D5, 0xF494724B /* 838 */}, { 0x5C09648D, 0xE887E198 /* 839 */},
+ { 0x75370CFD, 0x34B1D3C6 /* 840 */}, { 0xBC0D255D, 0xDC35E433 /* 841 */},
+ { 0x34131BE0, 0xD0AAB842 /* 842 */}, { 0xB48B7EAF, 0x08042A50 /* 843 */},
+ { 0x44A3AB35, 0x9997C4EE /* 844 */}, { 0x201799D0, 0x829A7B49 /* 845 */},
+ { 0xB7C54441, 0x263B8307 /* 846 */}, { 0xFD6A6CA6, 0x752F95F4 /* 847 */},
+ { 0x2C08C6E5, 0x92721740 /* 848 */}, { 0xA795D9EE, 0x2A8AB754 /* 849 */},
+ { 0x2F72943D, 0xA442F755 /* 850 */}, { 0x19781208, 0x2C31334E /* 851 */},
+ { 0xEAEE6291, 0x4FA98D7C /* 852 */}, { 0x665DB309, 0x55C3862F /* 853 */},
+ { 0x5D53B1F3, 0xBD061017 /* 854 */}, { 0x40413F27, 0x46FE6CB8 /* 855 */},
+ { 0xDF0CFA59, 0x3FE03792 /* 856 */}, { 0x2EB85E8F, 0xCFE70037 /* 857 */},
+ { 0xADBCE118, 0xA7BE29E7 /* 858 */}, { 0xDE8431DD, 0xE544EE5C /* 859 */},
+ { 0x41F1873E, 0x8A781B1B /* 860 */}, { 0xA0D2F0E7, 0xA5C94C78 /* 861 */},
+ { 0x77B60728, 0x39412E28 /* 862 */}, { 0xAFC9A62C, 0xA1265EF3 /* 863 */},
+ { 0x6A2506C5, 0xBCC2770C /* 864 */}, { 0xDCE1CE12, 0x3AB66DD5 /* 865 */},
+ { 0x4A675B37, 0xE65499D0 /* 866 */}, { 0x81BFD216, 0x7D8F5234 /* 867 */},
+ { 0xEC15F389, 0x0F6F64FC /* 868 */}, { 0x8B5B13C8, 0x74EFBE61 /* 869 */},
+ { 0x14273E1D, 0xACDC82B7 /* 870 */}, { 0x03199D17, 0xDD40BFE0 /* 871 */},
+ { 0xE7E061F8, 0x37E99257 /* 872 */}, { 0x04775AAA, 0xFA526269 /* 873 */},
+ { 0x463D56F9, 0x8BBBF63A /* 874 */}, { 0x43A26E64, 0xF0013F15 /* 875 */},
+ { 0x879EC898, 0xA8307E9F /* 876 */}, { 0x150177CC, 0xCC4C27A4 /* 877 */},
+ { 0xCA1D3348, 0x1B432F2C /* 878 */}, { 0x9F6FA013, 0xDE1D1F8F /* 879 */},
+ { 0x47A7DDD6, 0x606602A0 /* 880 */}, { 0xCC1CB2C7, 0xD237AB64 /* 881 */},
+ { 0x25FCD1D3, 0x9B938E72 /* 882 */}, { 0x8E0FF476, 0xEC4E0370 /* 883 */},
+ { 0x3D03C12D, 0xFEB2FBDA /* 884 */}, { 0xEE43889A, 0xAE0BCED2 /* 885 */},
+ { 0xEBFB4F43, 0x22CB8923 /* 886 */}, { 0x3CF7396D, 0x69360D01 /* 887 */},
+ { 0xD2D4E022, 0x855E3602 /* 888 */}, { 0xD01F784C, 0x073805BA /* 889 */},
+ { 0x3852F546, 0x33E17A13 /* 890 */}, { 0x8AC7B638, 0xDF487405 /* 891 */},
+ { 0x678AA14A, 0xBA92B29C /* 892 */}, { 0x6CFAADCD, 0x0CE89FC7 /* 893 */},
+ { 0x08339E34, 0x5F9D4E09 /* 894 */}, { 0x1F5923B9, 0xF1AFE929 /* 895 */},
+ { 0x0F4A265F, 0x6E3480F6 /* 896 */}, { 0xB29B841C, 0xEEBF3A2A /* 897 */},
+ { 0x8F91B4AD, 0xE21938A8 /* 898 */}, { 0x45C6D3C3, 0x57DFEFF8 /* 899 */},
+ { 0xF62CAAF2, 0x2F006B0B /* 900 */}, { 0x6F75EE78, 0x62F479EF /* 901 */},
+ { 0x1C8916A9, 0x11A55AD4 /* 902 */}, { 0x84FED453, 0xF229D290 /* 903 */},
+ { 0x16B000E6, 0x42F1C27B /* 904 */}, { 0x9823C074, 0x2B1F7674 /* 905 */},
+ { 0xC2745360, 0x4B76ECA3 /* 906 */}, { 0xB91691BD, 0x8C98F463 /* 907 */},
+ { 0xF1ADE66A, 0x14BCC93C /* 908 */}, { 0x6D458397, 0x8885213E /* 909 */},
+ { 0x274D4711, 0x8E177DF0 /* 910 */}, { 0x503F2951, 0xB49B73B5 /* 911 */},
+ { 0xC3F96B6B, 0x10168168 /* 912 */}, { 0x63CAB0AE, 0x0E3D963B /* 913 */},
+ { 0x55A1DB14, 0x8DFC4B56 /* 914 */}, { 0x6E14DE5C, 0xF789F135 /* 915 */},
+ { 0x4E51DAC1, 0x683E68AF /* 916 */}, { 0x8D4B0FD9, 0xC9A84F9D /* 917 */},
+ { 0x52A0F9D1, 0x3691E03F /* 918 */}, { 0xE1878E80, 0x5ED86E46 /* 919 */},
+ { 0x99D07150, 0x3C711A0E /* 920 */}, { 0x0C4E9310, 0x5A0865B2 /* 921 */},
+ { 0xE4F0682E, 0x56FBFC1F /* 922 */}, { 0x105EDF9B, 0xEA8D5DE3 /* 923 */},
+ { 0x2379187A, 0x71ABFDB1 /* 924 */}, { 0xBEE77B9C, 0x2EB99DE1 /* 925 */},
+ { 0x33CF4523, 0x21ECC0EA /* 926 */}, { 0x1805C7A1, 0x59A4D752 /* 927 */},
+ { 0x56AE7C72, 0x3896F5EB /* 928 */}, { 0xB18F75DC, 0xAA638F3D /* 929 */},
+ { 0xABE9808E, 0x9F39358D /* 930 */}, { 0xC00B72AC, 0xB7DEFA91 /* 931 */},
+ { 0x62492D92, 0x6B5541FD /* 932 */}, { 0xF92E4D5B, 0x6DC6DEE8 /* 933 */},
+ { 0xC4BEEA7E, 0x353F57AB /* 934 */}, { 0xDA5690CE, 0x735769D6 /* 935 */},
+ { 0x42391484, 0x0A234AA6 /* 936 */}, { 0x28F80D9D, 0xF6F95080 /* 937 */},
+ { 0x7AB3F215, 0xB8E319A2 /* 938 */}, { 0x51341A4D, 0x31AD9C11 /* 939 */},
+ { 0x7BEF5805, 0x773C22A5 /* 940 */}, { 0x07968633, 0x45C7561A /* 941 */},
+ { 0x249DBE36, 0xF913DA9E /* 942 */}, { 0x78A64C68, 0xDA652D9B /* 943 */},
+ { 0x3BC334EF, 0x4C27A97F /* 944 */}, { 0xE66B17F4, 0x76621220 /* 945 */},
+ { 0x9ACD7D0B, 0x96774389 /* 946 */}, { 0xE0ED6782, 0xF3EE5BCA /* 947 */},
+ { 0x00C879FC, 0x409F7536 /* 948 */}, { 0xB5926DB6, 0x06D09A39 /* 949 */},
+ { 0x317AC588, 0x6F83AEB0 /* 950 */}, { 0x86381F21, 0x01E6CA4A /* 951 */},
+ { 0xD19F3025, 0x66FF3462 /* 952 */}, { 0xDDFD3BFB, 0x72207C24 /* 953 */},
+ { 0xE2ECE2EB, 0x4AF6B6D3 /* 954 */}, { 0xC7EA08DE, 0x9C994DBE /* 955 */},
+ { 0xB09A8BC4, 0x49ACE597 /* 956 */}, { 0xCF0797BA, 0xB38C4766 /* 957 */},
+ { 0xC57C2A75, 0x131B9373 /* 958 */}, { 0x61931E58, 0xB1822CCE /* 959 */},
+ { 0x09BA1C0C, 0x9D7555B9 /* 960 */}, { 0x937D11D2, 0x127FAFDD /* 961 */},
+ { 0xC66D92E4, 0x29DA3BAD /* 962 */}, { 0x54C2ECBC, 0xA2C1D571 /* 963 */},
+ { 0x82F6FE24, 0x58C5134D /* 964 */}, { 0x5B62274F, 0x1C3AE351 /* 965 */},
+ { 0x01CB8126, 0xE907C82E /* 966 */}, { 0x13E37FCB, 0xF8ED0919 /* 967 */},
+ { 0xC80046C9, 0x3249D8F9 /* 968 */}, { 0xE388FB63, 0x80CF9BED /* 969 */},
+ { 0x116CF19E, 0x1881539A /* 970 */}, { 0x6BD52457, 0x5103F3F7 /* 971 */},
+ { 0xAE47F7A8, 0x15B7E6F5 /* 972 */}, { 0xD47E9CCF, 0xDBD7C6DE /* 973 */},
+ { 0x0228BB1A, 0x44E55C41 /* 974 */}, { 0x5EDB4E99, 0xB647D425 /* 975 */},
+ { 0xB8AAFC30, 0x5D11882B /* 976 */}, { 0x29D3212A, 0xF5098BBB /* 977 */},
+ { 0xE90296B3, 0x8FB5EA14 /* 978 */}, { 0x57DD025A, 0x677B9421 /* 979 */},
+ { 0xA390ACB5, 0xFB58E7C0 /* 980 */}, { 0x83BD4A01, 0x89D3674C /* 981 */},
+ { 0x4BF3B93B, 0x9E2DA4DF /* 982 */}, { 0x8CAB4829, 0xFCC41E32 /* 983 */},
+ { 0xBA582C52, 0x03F38C96 /* 984 */}, { 0x7FD85DB2, 0xCAD1BDBD /* 985 */},
+ { 0x6082AE83, 0xBBB442C1 /* 986 */}, { 0xA5DA9AB0, 0xB95FE86B /* 987 */},
+ { 0x3771A93F, 0xB22E0467 /* 988 */}, { 0x493152D8, 0x845358C9 /* 989 */},
+ { 0x97B4541E, 0xBE2A4886 /* 990 */}, { 0xD38E6966, 0x95A2DC2D /* 991 */},
+ { 0x923C852B, 0xC02C11AC /* 992 */}, { 0x0DF2A87B, 0x2388B199 /* 993 */},
+ { 0x1B4F37BE, 0x7C8008FA /* 994 */}, { 0x4D54E503, 0x1F70D0C8 /* 995 */},
+ { 0x7ECE57D4, 0x5490ADEC /* 996 */}, { 0xD9063A3A, 0x002B3C27 /* 997 */},
+ { 0x8030A2BF, 0x7EAEA384 /* 998 */}, { 0xED2003C0, 0xC602326D /* 999 */},
+ { 0x69A94086, 0x83A7287D /* 1000 */}, { 0x30F57A8A, 0xC57A5FCB /* 1001 */},
+ { 0x79EBE779, 0xB56844E4 /* 1002 */}, { 0x05DCBCE9, 0xA373B40F /* 1003 */},
+ { 0x88570EE2, 0xD71A786E /* 1004 */}, { 0xBDE8F6A0, 0x879CBACD /* 1005 */},
+ { 0xC164A32F, 0x976AD1BC /* 1006 */}, { 0x9666D78B, 0xAB21E25E /* 1007 */},
+ { 0xE5E5C33C, 0x901063AA /* 1008 */}, { 0x48698D90, 0x9818B344 /* 1009 */},
+ { 0x3E1E8ABB, 0xE36487AE /* 1010 */}, { 0x893BDCB4, 0xAFBDF931 /* 1011 */},
+ { 0x5FBBD519, 0x6345A0DC /* 1012 */}, { 0x9B9465CA, 0x8628FE26 /* 1013 */},
+ { 0x3F9C51EC, 0x1E5D0160 /* 1014 */}, { 0xA15049B7, 0x4DE44006 /* 1015 */},
+ { 0xF776CBB1, 0xBF6C70E5 /* 1016 */}, { 0xEF552BED, 0x411218F2 /* 1017 */},
+ { 0x705A36A3, 0xCB0C0708 /* 1018 */}, { 0x4F986044, 0xE74D1475 /* 1019 */},
+ { 0x0EA8280E, 0xCD56D943 /* 1020 */}, { 0x535F5065, 0xC12591D7 /* 1021 */},
+ { 0x720AEF96, 0xC83223F1 /* 1022 */}, { 0x7363A51F, 0xC3A0396F /* 1023 */}
+ };
+
+#else
+void dummy_2 (int a)
+{
+ (void) a;
+ return;
+}
+#endif
diff --git a/src/sh_tiger2_64.c b/src/sh_tiger2_64.c
new file mode 100644
index 0000000..548df09
--- /dev/null
+++ b/src/sh_tiger2_64.c
@@ -0,0 +1,561 @@
+/* Tiger: A Fast New Hash Function
+ *
+ * Ross Anderson and Eli Biham
+ *
+ * From the homepage (http://www.cs.technion.ac.il/~biham/Reports/Tiger/):
+ *
+ * Tiger has no usage restrictions nor patents. It can be used freely,
+ * with the reference implementation, with other implementations or with
+ * a modification to the reference implementation (as long as it still
+ * implements Tiger). We only ask you to let us know about your
+ * implementation and to cite the origin of Tiger and of the reference
+ * implementation.
+ *
+ *
+ * The authors' home pages can be found both in
+ * http://www.cs.technion.ac.il/~biham/ and in
+ * http://www.cl.cam.ac.uk/users/rja14/.
+ * The authors' email addresses are biham@cs.technion.ac.il
+ * and rja14@cl.cam.ac.uk.
+ */
+
+#include "config_xor.h"
+
+#if defined(TIGER_64_BIT)
+
+/* #if defined(HAVE_LONG_64) || defined(HAVE_LONG_LONG_64) */
+
+/*@-type@*/
+/* sboxes.c: Tiger S boxes */
+
+#if defined(HAVE_LONG_64)
+typedef unsigned long int word64;
+#elif defined(HAVE_LONG_LONG_64)
+typedef unsigned long long int word64;
+#else
+#error No 64 bit type found !
+#endif
+
+word64 tiger_table[4*256] = {
+ 0x02AAB17CF7E90C5ELL /* 0 */, 0xAC424B03E243A8ECLL /* 1 */,
+ 0x72CD5BE30DD5FCD3LL /* 2 */, 0x6D019B93F6F97F3ALL /* 3 */,
+ 0xCD9978FFD21F9193LL /* 4 */, 0x7573A1C9708029E2LL /* 5 */,
+ 0xB164326B922A83C3LL /* 6 */, 0x46883EEE04915870LL /* 7 */,
+ 0xEAACE3057103ECE6LL /* 8 */, 0xC54169B808A3535CLL /* 9 */,
+ 0x4CE754918DDEC47CLL /* 10 */, 0x0AA2F4DFDC0DF40CLL /* 11 */,
+ 0x10B76F18A74DBEFALL /* 12 */, 0xC6CCB6235AD1AB6ALL /* 13 */,
+ 0x13726121572FE2FFLL /* 14 */, 0x1A488C6F199D921ELL /* 15 */,
+ 0x4BC9F9F4DA0007CALL /* 16 */, 0x26F5E6F6E85241C7LL /* 17 */,
+ 0x859079DBEA5947B6LL /* 18 */, 0x4F1885C5C99E8C92LL /* 19 */,
+ 0xD78E761EA96F864BLL /* 20 */, 0x8E36428C52B5C17DLL /* 21 */,
+ 0x69CF6827373063C1LL /* 22 */, 0xB607C93D9BB4C56ELL /* 23 */,
+ 0x7D820E760E76B5EALL /* 24 */, 0x645C9CC6F07FDC42LL /* 25 */,
+ 0xBF38A078243342E0LL /* 26 */, 0x5F6B343C9D2E7D04LL /* 27 */,
+ 0xF2C28AEB600B0EC6LL /* 28 */, 0x6C0ED85F7254BCACLL /* 29 */,
+ 0x71592281A4DB4FE5LL /* 30 */, 0x1967FA69CE0FED9FLL /* 31 */,
+ 0xFD5293F8B96545DBLL /* 32 */, 0xC879E9D7F2A7600BLL /* 33 */,
+ 0x860248920193194ELL /* 34 */, 0xA4F9533B2D9CC0B3LL /* 35 */,
+ 0x9053836C15957613LL /* 36 */, 0xDB6DCF8AFC357BF1LL /* 37 */,
+ 0x18BEEA7A7A370F57LL /* 38 */, 0x037117CA50B99066LL /* 39 */,
+ 0x6AB30A9774424A35LL /* 40 */, 0xF4E92F02E325249BLL /* 41 */,
+ 0x7739DB07061CCAE1LL /* 42 */, 0xD8F3B49CECA42A05LL /* 43 */,
+ 0xBD56BE3F51382F73LL /* 44 */, 0x45FAED5843B0BB28LL /* 45 */,
+ 0x1C813D5C11BF1F83LL /* 46 */, 0x8AF0E4B6D75FA169LL /* 47 */,
+ 0x33EE18A487AD9999LL /* 48 */, 0x3C26E8EAB1C94410LL /* 49 */,
+ 0xB510102BC0A822F9LL /* 50 */, 0x141EEF310CE6123BLL /* 51 */,
+ 0xFC65B90059DDB154LL /* 52 */, 0xE0158640C5E0E607LL /* 53 */,
+ 0x884E079826C3A3CFLL /* 54 */, 0x930D0D9523C535FDLL /* 55 */,
+ 0x35638D754E9A2B00LL /* 56 */, 0x4085FCCF40469DD5LL /* 57 */,
+ 0xC4B17AD28BE23A4CLL /* 58 */, 0xCAB2F0FC6A3E6A2ELL /* 59 */,
+ 0x2860971A6B943FCDLL /* 60 */, 0x3DDE6EE212E30446LL /* 61 */,
+ 0x6222F32AE01765AELL /* 62 */, 0x5D550BB5478308FELL /* 63 */,
+ 0xA9EFA98DA0EDA22ALL /* 64 */, 0xC351A71686C40DA7LL /* 65 */,
+ 0x1105586D9C867C84LL /* 66 */, 0xDCFFEE85FDA22853LL /* 67 */,
+ 0xCCFBD0262C5EEF76LL /* 68 */, 0xBAF294CB8990D201LL /* 69 */,
+ 0xE69464F52AFAD975LL /* 70 */, 0x94B013AFDF133E14LL /* 71 */,
+ 0x06A7D1A32823C958LL /* 72 */, 0x6F95FE5130F61119LL /* 73 */,
+ 0xD92AB34E462C06C0LL /* 74 */, 0xED7BDE33887C71D2LL /* 75 */,
+ 0x79746D6E6518393ELL /* 76 */, 0x5BA419385D713329LL /* 77 */,
+ 0x7C1BA6B948A97564LL /* 78 */, 0x31987C197BFDAC67LL /* 79 */,
+ 0xDE6C23C44B053D02LL /* 80 */, 0x581C49FED002D64DLL /* 81 */,
+ 0xDD474D6338261571LL /* 82 */, 0xAA4546C3E473D062LL /* 83 */,
+ 0x928FCE349455F860LL /* 84 */, 0x48161BBACAAB94D9LL /* 85 */,
+ 0x63912430770E6F68LL /* 86 */, 0x6EC8A5E602C6641CLL /* 87 */,
+ 0x87282515337DDD2BLL /* 88 */, 0x2CDA6B42034B701BLL /* 89 */,
+ 0xB03D37C181CB096DLL /* 90 */, 0xE108438266C71C6FLL /* 91 */,
+ 0x2B3180C7EB51B255LL /* 92 */, 0xDF92B82F96C08BBCLL /* 93 */,
+ 0x5C68C8C0A632F3BALL /* 94 */, 0x5504CC861C3D0556LL /* 95 */,
+ 0xABBFA4E55FB26B8FLL /* 96 */, 0x41848B0AB3BACEB4LL /* 97 */,
+ 0xB334A273AA445D32LL /* 98 */, 0xBCA696F0A85AD881LL /* 99 */,
+ 0x24F6EC65B528D56CLL /* 100 */, 0x0CE1512E90F4524ALL /* 101 */,
+ 0x4E9DD79D5506D35ALL /* 102 */, 0x258905FAC6CE9779LL /* 103 */,
+ 0x2019295B3E109B33LL /* 104 */, 0xF8A9478B73A054CCLL /* 105 */,
+ 0x2924F2F934417EB0LL /* 106 */, 0x3993357D536D1BC4LL /* 107 */,
+ 0x38A81AC21DB6FF8BLL /* 108 */, 0x47C4FBF17D6016BFLL /* 109 */,
+ 0x1E0FAADD7667E3F5LL /* 110 */, 0x7ABCFF62938BEB96LL /* 111 */,
+ 0xA78DAD948FC179C9LL /* 112 */, 0x8F1F98B72911E50DLL /* 113 */,
+ 0x61E48EAE27121A91LL /* 114 */, 0x4D62F7AD31859808LL /* 115 */,
+ 0xECEBA345EF5CEAEBLL /* 116 */, 0xF5CEB25EBC9684CELL /* 117 */,
+ 0xF633E20CB7F76221LL /* 118 */, 0xA32CDF06AB8293E4LL /* 119 */,
+ 0x985A202CA5EE2CA4LL /* 120 */, 0xCF0B8447CC8A8FB1LL /* 121 */,
+ 0x9F765244979859A3LL /* 122 */, 0xA8D516B1A1240017LL /* 123 */,
+ 0x0BD7BA3EBB5DC726LL /* 124 */, 0xE54BCA55B86ADB39LL /* 125 */,
+ 0x1D7A3AFD6C478063LL /* 126 */, 0x519EC608E7669EDDLL /* 127 */,
+ 0x0E5715A2D149AA23LL /* 128 */, 0x177D4571848FF194LL /* 129 */,
+ 0xEEB55F3241014C22LL /* 130 */, 0x0F5E5CA13A6E2EC2LL /* 131 */,
+ 0x8029927B75F5C361LL /* 132 */, 0xAD139FABC3D6E436LL /* 133 */,
+ 0x0D5DF1A94CCF402FLL /* 134 */, 0x3E8BD948BEA5DFC8LL /* 135 */,
+ 0xA5A0D357BD3FF77ELL /* 136 */, 0xA2D12E251F74F645LL /* 137 */,
+ 0x66FD9E525E81A082LL /* 138 */, 0x2E0C90CE7F687A49LL /* 139 */,
+ 0xC2E8BCBEBA973BC5LL /* 140 */, 0x000001BCE509745FLL /* 141 */,
+ 0x423777BBE6DAB3D6LL /* 142 */, 0xD1661C7EAEF06EB5LL /* 143 */,
+ 0xA1781F354DAACFD8LL /* 144 */, 0x2D11284A2B16AFFCLL /* 145 */,
+ 0xF1FC4F67FA891D1FLL /* 146 */, 0x73ECC25DCB920ADALL /* 147 */,
+ 0xAE610C22C2A12651LL /* 148 */, 0x96E0A810D356B78ALL /* 149 */,
+ 0x5A9A381F2FE7870FLL /* 150 */, 0xD5AD62EDE94E5530LL /* 151 */,
+ 0xD225E5E8368D1427LL /* 152 */, 0x65977B70C7AF4631LL /* 153 */,
+ 0x99F889B2DE39D74FLL /* 154 */, 0x233F30BF54E1D143LL /* 155 */,
+ 0x9A9675D3D9A63C97LL /* 156 */, 0x5470554FF334F9A8LL /* 157 */,
+ 0x166ACB744A4F5688LL /* 158 */, 0x70C74CAAB2E4AEADLL /* 159 */,
+ 0xF0D091646F294D12LL /* 160 */, 0x57B82A89684031D1LL /* 161 */,
+ 0xEFD95A5A61BE0B6BLL /* 162 */, 0x2FBD12E969F2F29ALL /* 163 */,
+ 0x9BD37013FEFF9FE8LL /* 164 */, 0x3F9B0404D6085A06LL /* 165 */,
+ 0x4940C1F3166CFE15LL /* 166 */, 0x09542C4DCDF3DEFBLL /* 167 */,
+ 0xB4C5218385CD5CE3LL /* 168 */, 0xC935B7DC4462A641LL /* 169 */,
+ 0x3417F8A68ED3B63FLL /* 170 */, 0xB80959295B215B40LL /* 171 */,
+ 0xF99CDAEF3B8C8572LL /* 172 */, 0x018C0614F8FCB95DLL /* 173 */,
+ 0x1B14ACCD1A3ACDF3LL /* 174 */, 0x84D471F200BB732DLL /* 175 */,
+ 0xC1A3110E95E8DA16LL /* 176 */, 0x430A7220BF1A82B8LL /* 177 */,
+ 0xB77E090D39DF210ELL /* 178 */, 0x5EF4BD9F3CD05E9DLL /* 179 */,
+ 0x9D4FF6DA7E57A444LL /* 180 */, 0xDA1D60E183D4A5F8LL /* 181 */,
+ 0xB287C38417998E47LL /* 182 */, 0xFE3EDC121BB31886LL /* 183 */,
+ 0xC7FE3CCC980CCBEFLL /* 184 */, 0xE46FB590189BFD03LL /* 185 */,
+ 0x3732FD469A4C57DCLL /* 186 */, 0x7EF700A07CF1AD65LL /* 187 */,
+ 0x59C64468A31D8859LL /* 188 */, 0x762FB0B4D45B61F6LL /* 189 */,
+ 0x155BAED099047718LL /* 190 */, 0x68755E4C3D50BAA6LL /* 191 */,
+ 0xE9214E7F22D8B4DFLL /* 192 */, 0x2ADDBF532EAC95F4LL /* 193 */,
+ 0x32AE3909B4BD0109LL /* 194 */, 0x834DF537B08E3450LL /* 195 */,
+ 0xFA209DA84220728DLL /* 196 */, 0x9E691D9B9EFE23F7LL /* 197 */,
+ 0x0446D288C4AE8D7FLL /* 198 */, 0x7B4CC524E169785BLL /* 199 */,
+ 0x21D87F0135CA1385LL /* 200 */, 0xCEBB400F137B8AA5LL /* 201 */,
+ 0x272E2B66580796BELL /* 202 */, 0x3612264125C2B0DELL /* 203 */,
+ 0x057702BDAD1EFBB2LL /* 204 */, 0xD4BABB8EACF84BE9LL /* 205 */,
+ 0x91583139641BC67BLL /* 206 */, 0x8BDC2DE08036E024LL /* 207 */,
+ 0x603C8156F49F68EDLL /* 208 */, 0xF7D236F7DBEF5111LL /* 209 */,
+ 0x9727C4598AD21E80LL /* 210 */, 0xA08A0896670A5FD7LL /* 211 */,
+ 0xCB4A8F4309EBA9CBLL /* 212 */, 0x81AF564B0F7036A1LL /* 213 */,
+ 0xC0B99AA778199ABDLL /* 214 */, 0x959F1EC83FC8E952LL /* 215 */,
+ 0x8C505077794A81B9LL /* 216 */, 0x3ACAAF8F056338F0LL /* 217 */,
+ 0x07B43F50627A6778LL /* 218 */, 0x4A44AB49F5ECCC77LL /* 219 */,
+ 0x3BC3D6E4B679EE98LL /* 220 */, 0x9CC0D4D1CF14108CLL /* 221 */,
+ 0x4406C00B206BC8A0LL /* 222 */, 0x82A18854C8D72D89LL /* 223 */,
+ 0x67E366B35C3C432CLL /* 224 */, 0xB923DD61102B37F2LL /* 225 */,
+ 0x56AB2779D884271DLL /* 226 */, 0xBE83E1B0FF1525AFLL /* 227 */,
+ 0xFB7C65D4217E49A9LL /* 228 */, 0x6BDBE0E76D48E7D4LL /* 229 */,
+ 0x08DF828745D9179ELL /* 230 */, 0x22EA6A9ADD53BD34LL /* 231 */,
+ 0xE36E141C5622200ALL /* 232 */, 0x7F805D1B8CB750EELL /* 233 */,
+ 0xAFE5C7A59F58E837LL /* 234 */, 0xE27F996A4FB1C23CLL /* 235 */,
+ 0xD3867DFB0775F0D0LL /* 236 */, 0xD0E673DE6E88891ALL /* 237 */,
+ 0x123AEB9EAFB86C25LL /* 238 */, 0x30F1D5D5C145B895LL /* 239 */,
+ 0xBB434A2DEE7269E7LL /* 240 */, 0x78CB67ECF931FA38LL /* 241 */,
+ 0xF33B0372323BBF9CLL /* 242 */, 0x52D66336FB279C74LL /* 243 */,
+ 0x505F33AC0AFB4EAALL /* 244 */, 0xE8A5CD99A2CCE187LL /* 245 */,
+ 0x534974801E2D30BBLL /* 246 */, 0x8D2D5711D5876D90LL /* 247 */,
+ 0x1F1A412891BC038ELL /* 248 */, 0xD6E2E71D82E56648LL /* 249 */,
+ 0x74036C3A497732B7LL /* 250 */, 0x89B67ED96361F5ABLL /* 251 */,
+ 0xFFED95D8F1EA02A2LL /* 252 */, 0xE72B3BD61464D43DLL /* 253 */,
+ 0xA6300F170BDC4820LL /* 254 */, 0xEBC18760ED78A77ALL /* 255 */,
+ 0xE6A6BE5A05A12138LL /* 256 */, 0xB5A122A5B4F87C98LL /* 257 */,
+ 0x563C6089140B6990LL /* 258 */, 0x4C46CB2E391F5DD5LL /* 259 */,
+ 0xD932ADDBC9B79434LL /* 260 */, 0x08EA70E42015AFF5LL /* 261 */,
+ 0xD765A6673E478CF1LL /* 262 */, 0xC4FB757EAB278D99LL /* 263 */,
+ 0xDF11C6862D6E0692LL /* 264 */, 0xDDEB84F10D7F3B16LL /* 265 */,
+ 0x6F2EF604A665EA04LL /* 266 */, 0x4A8E0F0FF0E0DFB3LL /* 267 */,
+ 0xA5EDEEF83DBCBA51LL /* 268 */, 0xFC4F0A2A0EA4371ELL /* 269 */,
+ 0xE83E1DA85CB38429LL /* 270 */, 0xDC8FF882BA1B1CE2LL /* 271 */,
+ 0xCD45505E8353E80DLL /* 272 */, 0x18D19A00D4DB0717LL /* 273 */,
+ 0x34A0CFEDA5F38101LL /* 274 */, 0x0BE77E518887CAF2LL /* 275 */,
+ 0x1E341438B3C45136LL /* 276 */, 0xE05797F49089CCF9LL /* 277 */,
+ 0xFFD23F9DF2591D14LL /* 278 */, 0x543DDA228595C5CDLL /* 279 */,
+ 0x661F81FD99052A33LL /* 280 */, 0x8736E641DB0F7B76LL /* 281 */,
+ 0x15227725418E5307LL /* 282 */, 0xE25F7F46162EB2FALL /* 283 */,
+ 0x48A8B2126C13D9FELL /* 284 */, 0xAFDC541792E76EEALL /* 285 */,
+ 0x03D912BFC6D1898FLL /* 286 */, 0x31B1AAFA1B83F51BLL /* 287 */,
+ 0xF1AC2796E42AB7D9LL /* 288 */, 0x40A3A7D7FCD2EBACLL /* 289 */,
+ 0x1056136D0AFBBCC5LL /* 290 */, 0x7889E1DD9A6D0C85LL /* 291 */,
+ 0xD33525782A7974AALL /* 292 */, 0xA7E25D09078AC09BLL /* 293 */,
+ 0xBD4138B3EAC6EDD0LL /* 294 */, 0x920ABFBE71EB9E70LL /* 295 */,
+ 0xA2A5D0F54FC2625CLL /* 296 */, 0xC054E36B0B1290A3LL /* 297 */,
+ 0xF6DD59FF62FE932BLL /* 298 */, 0x3537354511A8AC7DLL /* 299 */,
+ 0xCA845E9172FADCD4LL /* 300 */, 0x84F82B60329D20DCLL /* 301 */,
+ 0x79C62CE1CD672F18LL /* 302 */, 0x8B09A2ADD124642CLL /* 303 */,
+ 0xD0C1E96A19D9E726LL /* 304 */, 0x5A786A9B4BA9500CLL /* 305 */,
+ 0x0E020336634C43F3LL /* 306 */, 0xC17B474AEB66D822LL /* 307 */,
+ 0x6A731AE3EC9BAAC2LL /* 308 */, 0x8226667AE0840258LL /* 309 */,
+ 0x67D4567691CAECA5LL /* 310 */, 0x1D94155C4875ADB5LL /* 311 */,
+ 0x6D00FD985B813FDFLL /* 312 */, 0x51286EFCB774CD06LL /* 313 */,
+ 0x5E8834471FA744AFLL /* 314 */, 0xF72CA0AEE761AE2ELL /* 315 */,
+ 0xBE40E4CDAEE8E09ALL /* 316 */, 0xE9970BBB5118F665LL /* 317 */,
+ 0x726E4BEB33DF1964LL /* 318 */, 0x703B000729199762LL /* 319 */,
+ 0x4631D816F5EF30A7LL /* 320 */, 0xB880B5B51504A6BELL /* 321 */,
+ 0x641793C37ED84B6CLL /* 322 */, 0x7B21ED77F6E97D96LL /* 323 */,
+ 0x776306312EF96B73LL /* 324 */, 0xAE528948E86FF3F4LL /* 325 */,
+ 0x53DBD7F286A3F8F8LL /* 326 */, 0x16CADCE74CFC1063LL /* 327 */,
+ 0x005C19BDFA52C6DDLL /* 328 */, 0x68868F5D64D46AD3LL /* 329 */,
+ 0x3A9D512CCF1E186ALL /* 330 */, 0x367E62C2385660AELL /* 331 */,
+ 0xE359E7EA77DCB1D7LL /* 332 */, 0x526C0773749ABE6ELL /* 333 */,
+ 0x735AE5F9D09F734BLL /* 334 */, 0x493FC7CC8A558BA8LL /* 335 */,
+ 0xB0B9C1533041AB45LL /* 336 */, 0x321958BA470A59BDLL /* 337 */,
+ 0x852DB00B5F46C393LL /* 338 */, 0x91209B2BD336B0E5LL /* 339 */,
+ 0x6E604F7D659EF19FLL /* 340 */, 0xB99A8AE2782CCB24LL /* 341 */,
+ 0xCCF52AB6C814C4C7LL /* 342 */, 0x4727D9AFBE11727BLL /* 343 */,
+ 0x7E950D0C0121B34DLL /* 344 */, 0x756F435670AD471FLL /* 345 */,
+ 0xF5ADD442615A6849LL /* 346 */, 0x4E87E09980B9957ALL /* 347 */,
+ 0x2ACFA1DF50AEE355LL /* 348 */, 0xD898263AFD2FD556LL /* 349 */,
+ 0xC8F4924DD80C8FD6LL /* 350 */, 0xCF99CA3D754A173ALL /* 351 */,
+ 0xFE477BACAF91BF3CLL /* 352 */, 0xED5371F6D690C12DLL /* 353 */,
+ 0x831A5C285E687094LL /* 354 */, 0xC5D3C90A3708A0A4LL /* 355 */,
+ 0x0F7F903717D06580LL /* 356 */, 0x19F9BB13B8FDF27FLL /* 357 */,
+ 0xB1BD6F1B4D502843LL /* 358 */, 0x1C761BA38FFF4012LL /* 359 */,
+ 0x0D1530C4E2E21F3BLL /* 360 */, 0x8943CE69A7372C8ALL /* 361 */,
+ 0xE5184E11FEB5CE66LL /* 362 */, 0x618BDB80BD736621LL /* 363 */,
+ 0x7D29BAD68B574D0BLL /* 364 */, 0x81BB613E25E6FE5BLL /* 365 */,
+ 0x071C9C10BC07913FLL /* 366 */, 0xC7BEEB7909AC2D97LL /* 367 */,
+ 0xC3E58D353BC5D757LL /* 368 */, 0xEB017892F38F61E8LL /* 369 */,
+ 0xD4EFFB9C9B1CC21ALL /* 370 */, 0x99727D26F494F7ABLL /* 371 */,
+ 0xA3E063A2956B3E03LL /* 372 */, 0x9D4A8B9A4AA09C30LL /* 373 */,
+ 0x3F6AB7D500090FB4LL /* 374 */, 0x9CC0F2A057268AC0LL /* 375 */,
+ 0x3DEE9D2DEDBF42D1LL /* 376 */, 0x330F49C87960A972LL /* 377 */,
+ 0xC6B2720287421B41LL /* 378 */, 0x0AC59EC07C00369CLL /* 379 */,
+ 0xEF4EAC49CB353425LL /* 380 */, 0xF450244EEF0129D8LL /* 381 */,
+ 0x8ACC46E5CAF4DEB6LL /* 382 */, 0x2FFEAB63989263F7LL /* 383 */,
+ 0x8F7CB9FE5D7A4578LL /* 384 */, 0x5BD8F7644E634635LL /* 385 */,
+ 0x427A7315BF2DC900LL /* 386 */, 0x17D0C4AA2125261CLL /* 387 */,
+ 0x3992486C93518E50LL /* 388 */, 0xB4CBFEE0A2D7D4C3LL /* 389 */,
+ 0x7C75D6202C5DDD8DLL /* 390 */, 0xDBC295D8E35B6C61LL /* 391 */,
+ 0x60B369D302032B19LL /* 392 */, 0xCE42685FDCE44132LL /* 393 */,
+ 0x06F3DDB9DDF65610LL /* 394 */, 0x8EA4D21DB5E148F0LL /* 395 */,
+ 0x20B0FCE62FCD496FLL /* 396 */, 0x2C1B912358B0EE31LL /* 397 */,
+ 0xB28317B818F5A308LL /* 398 */, 0xA89C1E189CA6D2CFLL /* 399 */,
+ 0x0C6B18576AAADBC8LL /* 400 */, 0xB65DEAA91299FAE3LL /* 401 */,
+ 0xFB2B794B7F1027E7LL /* 402 */, 0x04E4317F443B5BEBLL /* 403 */,
+ 0x4B852D325939D0A6LL /* 404 */, 0xD5AE6BEEFB207FFCLL /* 405 */,
+ 0x309682B281C7D374LL /* 406 */, 0xBAE309A194C3B475LL /* 407 */,
+ 0x8CC3F97B13B49F05LL /* 408 */, 0x98A9422FF8293967LL /* 409 */,
+ 0x244B16B01076FF7CLL /* 410 */, 0xF8BF571C663D67EELL /* 411 */,
+ 0x1F0D6758EEE30DA1LL /* 412 */, 0xC9B611D97ADEB9B7LL /* 413 */,
+ 0xB7AFD5887B6C57A2LL /* 414 */, 0x6290AE846B984FE1LL /* 415 */,
+ 0x94DF4CDEACC1A5FDLL /* 416 */, 0x058A5BD1C5483AFFLL /* 417 */,
+ 0x63166CC142BA3C37LL /* 418 */, 0x8DB8526EB2F76F40LL /* 419 */,
+ 0xE10880036F0D6D4ELL /* 420 */, 0x9E0523C9971D311DLL /* 421 */,
+ 0x45EC2824CC7CD691LL /* 422 */, 0x575B8359E62382C9LL /* 423 */,
+ 0xFA9E400DC4889995LL /* 424 */, 0xD1823ECB45721568LL /* 425 */,
+ 0xDAFD983B8206082FLL /* 426 */, 0xAA7D29082386A8CBLL /* 427 */,
+ 0x269FCD4403B87588LL /* 428 */, 0x1B91F5F728BDD1E0LL /* 429 */,
+ 0xE4669F39040201F6LL /* 430 */, 0x7A1D7C218CF04ADELL /* 431 */,
+ 0x65623C29D79CE5CELL /* 432 */, 0x2368449096C00BB1LL /* 433 */,
+ 0xAB9BF1879DA503BALL /* 434 */, 0xBC23ECB1A458058ELL /* 435 */,
+ 0x9A58DF01BB401ECCLL /* 436 */, 0xA070E868A85F143DLL /* 437 */,
+ 0x4FF188307DF2239ELL /* 438 */, 0x14D565B41A641183LL /* 439 */,
+ 0xEE13337452701602LL /* 440 */, 0x950E3DCF3F285E09LL /* 441 */,
+ 0x59930254B9C80953LL /* 442 */, 0x3BF299408930DA6DLL /* 443 */,
+ 0xA955943F53691387LL /* 444 */, 0xA15EDECAA9CB8784LL /* 445 */,
+ 0x29142127352BE9A0LL /* 446 */, 0x76F0371FFF4E7AFBLL /* 447 */,
+ 0x0239F450274F2228LL /* 448 */, 0xBB073AF01D5E868BLL /* 449 */,
+ 0xBFC80571C10E96C1LL /* 450 */, 0xD267088568222E23LL /* 451 */,
+ 0x9671A3D48E80B5B0LL /* 452 */, 0x55B5D38AE193BB81LL /* 453 */,
+ 0x693AE2D0A18B04B8LL /* 454 */, 0x5C48B4ECADD5335FLL /* 455 */,
+ 0xFD743B194916A1CALL /* 456 */, 0x2577018134BE98C4LL /* 457 */,
+ 0xE77987E83C54A4ADLL /* 458 */, 0x28E11014DA33E1B9LL /* 459 */,
+ 0x270CC59E226AA213LL /* 460 */, 0x71495F756D1A5F60LL /* 461 */,
+ 0x9BE853FB60AFEF77LL /* 462 */, 0xADC786A7F7443DBFLL /* 463 */,
+ 0x0904456173B29A82LL /* 464 */, 0x58BC7A66C232BD5ELL /* 465 */,
+ 0xF306558C673AC8B2LL /* 466 */, 0x41F639C6B6C9772ALL /* 467 */,
+ 0x216DEFE99FDA35DALL /* 468 */, 0x11640CC71C7BE615LL /* 469 */,
+ 0x93C43694565C5527LL /* 470 */, 0xEA038E6246777839LL /* 471 */,
+ 0xF9ABF3CE5A3E2469LL /* 472 */, 0x741E768D0FD312D2LL /* 473 */,
+ 0x0144B883CED652C6LL /* 474 */, 0xC20B5A5BA33F8552LL /* 475 */,
+ 0x1AE69633C3435A9DLL /* 476 */, 0x97A28CA4088CFDECLL /* 477 */,
+ 0x8824A43C1E96F420LL /* 478 */, 0x37612FA66EEEA746LL /* 479 */,
+ 0x6B4CB165F9CF0E5ALL /* 480 */, 0x43AA1C06A0ABFB4ALL /* 481 */,
+ 0x7F4DC26FF162796BLL /* 482 */, 0x6CBACC8E54ED9B0FLL /* 483 */,
+ 0xA6B7FFEFD2BB253ELL /* 484 */, 0x2E25BC95B0A29D4FLL /* 485 */,
+ 0x86D6A58BDEF1388CLL /* 486 */, 0xDED74AC576B6F054LL /* 487 */,
+ 0x8030BDBC2B45805DLL /* 488 */, 0x3C81AF70E94D9289LL /* 489 */,
+ 0x3EFF6DDA9E3100DBLL /* 490 */, 0xB38DC39FDFCC8847LL /* 491 */,
+ 0x123885528D17B87ELL /* 492 */, 0xF2DA0ED240B1B642LL /* 493 */,
+ 0x44CEFADCD54BF9A9LL /* 494 */, 0x1312200E433C7EE6LL /* 495 */,
+ 0x9FFCC84F3A78C748LL /* 496 */, 0xF0CD1F72248576BBLL /* 497 */,
+ 0xEC6974053638CFE4LL /* 498 */, 0x2BA7B67C0CEC4E4CLL /* 499 */,
+ 0xAC2F4DF3E5CE32EDLL /* 500 */, 0xCB33D14326EA4C11LL /* 501 */,
+ 0xA4E9044CC77E58BCLL /* 502 */, 0x5F513293D934FCEFLL /* 503 */,
+ 0x5DC9645506E55444LL /* 504 */, 0x50DE418F317DE40ALL /* 505 */,
+ 0x388CB31A69DDE259LL /* 506 */, 0x2DB4A83455820A86LL /* 507 */,
+ 0x9010A91E84711AE9LL /* 508 */, 0x4DF7F0B7B1498371LL /* 509 */,
+ 0xD62A2EABC0977179LL /* 510 */, 0x22FAC097AA8D5C0ELL /* 511 */,
+ 0xF49FCC2FF1DAF39BLL /* 512 */, 0x487FD5C66FF29281LL /* 513 */,
+ 0xE8A30667FCDCA83FLL /* 514 */, 0x2C9B4BE3D2FCCE63LL /* 515 */,
+ 0xDA3FF74B93FBBBC2LL /* 516 */, 0x2FA165D2FE70BA66LL /* 517 */,
+ 0xA103E279970E93D4LL /* 518 */, 0xBECDEC77B0E45E71LL /* 519 */,
+ 0xCFB41E723985E497LL /* 520 */, 0xB70AAA025EF75017LL /* 521 */,
+ 0xD42309F03840B8E0LL /* 522 */, 0x8EFC1AD035898579LL /* 523 */,
+ 0x96C6920BE2B2ABC5LL /* 524 */, 0x66AF4163375A9172LL /* 525 */,
+ 0x2174ABDCCA7127FBLL /* 526 */, 0xB33CCEA64A72FF41LL /* 527 */,
+ 0xF04A4933083066A5LL /* 528 */, 0x8D970ACDD7289AF5LL /* 529 */,
+ 0x8F96E8E031C8C25ELL /* 530 */, 0xF3FEC02276875D47LL /* 531 */,
+ 0xEC7BF310056190DDLL /* 532 */, 0xF5ADB0AEBB0F1491LL /* 533 */,
+ 0x9B50F8850FD58892LL /* 534 */, 0x4975488358B74DE8LL /* 535 */,
+ 0xA3354FF691531C61LL /* 536 */, 0x0702BBE481D2C6EELL /* 537 */,
+ 0x89FB24057DEDED98LL /* 538 */, 0xAC3075138596E902LL /* 539 */,
+ 0x1D2D3580172772EDLL /* 540 */, 0xEB738FC28E6BC30DLL /* 541 */,
+ 0x5854EF8F63044326LL /* 542 */, 0x9E5C52325ADD3BBELL /* 543 */,
+ 0x90AA53CF325C4623LL /* 544 */, 0xC1D24D51349DD067LL /* 545 */,
+ 0x2051CFEEA69EA624LL /* 546 */, 0x13220F0A862E7E4FLL /* 547 */,
+ 0xCE39399404E04864LL /* 548 */, 0xD9C42CA47086FCB7LL /* 549 */,
+ 0x685AD2238A03E7CCLL /* 550 */, 0x066484B2AB2FF1DBLL /* 551 */,
+ 0xFE9D5D70EFBF79ECLL /* 552 */, 0x5B13B9DD9C481854LL /* 553 */,
+ 0x15F0D475ED1509ADLL /* 554 */, 0x0BEBCD060EC79851LL /* 555 */,
+ 0xD58C6791183AB7F8LL /* 556 */, 0xD1187C5052F3EEE4LL /* 557 */,
+ 0xC95D1192E54E82FFLL /* 558 */, 0x86EEA14CB9AC6CA2LL /* 559 */,
+ 0x3485BEB153677D5DLL /* 560 */, 0xDD191D781F8C492ALL /* 561 */,
+ 0xF60866BAA784EBF9LL /* 562 */, 0x518F643BA2D08C74LL /* 563 */,
+ 0x8852E956E1087C22LL /* 564 */, 0xA768CB8DC410AE8DLL /* 565 */,
+ 0x38047726BFEC8E1ALL /* 566 */, 0xA67738B4CD3B45AALL /* 567 */,
+ 0xAD16691CEC0DDE19LL /* 568 */, 0xC6D4319380462E07LL /* 569 */,
+ 0xC5A5876D0BA61938LL /* 570 */, 0x16B9FA1FA58FD840LL /* 571 */,
+ 0x188AB1173CA74F18LL /* 572 */, 0xABDA2F98C99C021FLL /* 573 */,
+ 0x3E0580AB134AE816LL /* 574 */, 0x5F3B05B773645ABBLL /* 575 */,
+ 0x2501A2BE5575F2F6LL /* 576 */, 0x1B2F74004E7E8BA9LL /* 577 */,
+ 0x1CD7580371E8D953LL /* 578 */, 0x7F6ED89562764E30LL /* 579 */,
+ 0xB15926FF596F003DLL /* 580 */, 0x9F65293DA8C5D6B9LL /* 581 */,
+ 0x6ECEF04DD690F84CLL /* 582 */, 0x4782275FFF33AF88LL /* 583 */,
+ 0xE41433083F820801LL /* 584 */, 0xFD0DFE409A1AF9B5LL /* 585 */,
+ 0x4325A3342CDB396BLL /* 586 */, 0x8AE77E62B301B252LL /* 587 */,
+ 0xC36F9E9F6655615ALL /* 588 */, 0x85455A2D92D32C09LL /* 589 */,
+ 0xF2C7DEA949477485LL /* 590 */, 0x63CFB4C133A39EBALL /* 591 */,
+ 0x83B040CC6EBC5462LL /* 592 */, 0x3B9454C8FDB326B0LL /* 593 */,
+ 0x56F56A9E87FFD78CLL /* 594 */, 0x2DC2940D99F42BC6LL /* 595 */,
+ 0x98F7DF096B096E2DLL /* 596 */, 0x19A6E01E3AD852BFLL /* 597 */,
+ 0x42A99CCBDBD4B40BLL /* 598 */, 0xA59998AF45E9C559LL /* 599 */,
+ 0x366295E807D93186LL /* 600 */, 0x6B48181BFAA1F773LL /* 601 */,
+ 0x1FEC57E2157A0A1DLL /* 602 */, 0x4667446AF6201AD5LL /* 603 */,
+ 0xE615EBCACFB0F075LL /* 604 */, 0xB8F31F4F68290778LL /* 605 */,
+ 0x22713ED6CE22D11ELL /* 606 */, 0x3057C1A72EC3C93BLL /* 607 */,
+ 0xCB46ACC37C3F1F2FLL /* 608 */, 0xDBB893FD02AAF50ELL /* 609 */,
+ 0x331FD92E600B9FCFLL /* 610 */, 0xA498F96148EA3AD6LL /* 611 */,
+ 0xA8D8426E8B6A83EALL /* 612 */, 0xA089B274B7735CDCLL /* 613 */,
+ 0x87F6B3731E524A11LL /* 614 */, 0x118808E5CBC96749LL /* 615 */,
+ 0x9906E4C7B19BD394LL /* 616 */, 0xAFED7F7E9B24A20CLL /* 617 */,
+ 0x6509EADEEB3644A7LL /* 618 */, 0x6C1EF1D3E8EF0EDELL /* 619 */,
+ 0xB9C97D43E9798FB4LL /* 620 */, 0xA2F2D784740C28A3LL /* 621 */,
+ 0x7B8496476197566FLL /* 622 */, 0x7A5BE3E6B65F069DLL /* 623 */,
+ 0xF96330ED78BE6F10LL /* 624 */, 0xEEE60DE77A076A15LL /* 625 */,
+ 0x2B4BEE4AA08B9BD0LL /* 626 */, 0x6A56A63EC7B8894ELL /* 627 */,
+ 0x02121359BA34FEF4LL /* 628 */, 0x4CBF99F8283703FCLL /* 629 */,
+ 0x398071350CAF30C8LL /* 630 */, 0xD0A77A89F017687ALL /* 631 */,
+ 0xF1C1A9EB9E423569LL /* 632 */, 0x8C7976282DEE8199LL /* 633 */,
+ 0x5D1737A5DD1F7ABDLL /* 634 */, 0x4F53433C09A9FA80LL /* 635 */,
+ 0xFA8B0C53DF7CA1D9LL /* 636 */, 0x3FD9DCBC886CCB77LL /* 637 */,
+ 0xC040917CA91B4720LL /* 638 */, 0x7DD00142F9D1DCDFLL /* 639 */,
+ 0x8476FC1D4F387B58LL /* 640 */, 0x23F8E7C5F3316503LL /* 641 */,
+ 0x032A2244E7E37339LL /* 642 */, 0x5C87A5D750F5A74BLL /* 643 */,
+ 0x082B4CC43698992ELL /* 644 */, 0xDF917BECB858F63CLL /* 645 */,
+ 0x3270B8FC5BF86DDALL /* 646 */, 0x10AE72BB29B5DD76LL /* 647 */,
+ 0x576AC94E7700362BLL /* 648 */, 0x1AD112DAC61EFB8FLL /* 649 */,
+ 0x691BC30EC5FAA427LL /* 650 */, 0xFF246311CC327143LL /* 651 */,
+ 0x3142368E30E53206LL /* 652 */, 0x71380E31E02CA396LL /* 653 */,
+ 0x958D5C960AAD76F1LL /* 654 */, 0xF8D6F430C16DA536LL /* 655 */,
+ 0xC8FFD13F1BE7E1D2LL /* 656 */, 0x7578AE66004DDBE1LL /* 657 */,
+ 0x05833F01067BE646LL /* 658 */, 0xBB34B5AD3BFE586DLL /* 659 */,
+ 0x095F34C9A12B97F0LL /* 660 */, 0x247AB64525D60CA8LL /* 661 */,
+ 0xDCDBC6F3017477D1LL /* 662 */, 0x4A2E14D4DECAD24DLL /* 663 */,
+ 0xBDB5E6D9BE0A1EEBLL /* 664 */, 0x2A7E70F7794301ABLL /* 665 */,
+ 0xDEF42D8A270540FDLL /* 666 */, 0x01078EC0A34C22C1LL /* 667 */,
+ 0xE5DE511AF4C16387LL /* 668 */, 0x7EBB3A52BD9A330ALL /* 669 */,
+ 0x77697857AA7D6435LL /* 670 */, 0x004E831603AE4C32LL /* 671 */,
+ 0xE7A21020AD78E312LL /* 672 */, 0x9D41A70C6AB420F2LL /* 673 */,
+ 0x28E06C18EA1141E6LL /* 674 */, 0xD2B28CBD984F6B28LL /* 675 */,
+ 0x26B75F6C446E9D83LL /* 676 */, 0xBA47568C4D418D7FLL /* 677 */,
+ 0xD80BADBFE6183D8ELL /* 678 */, 0x0E206D7F5F166044LL /* 679 */,
+ 0xE258A43911CBCA3ELL /* 680 */, 0x723A1746B21DC0BCLL /* 681 */,
+ 0xC7CAA854F5D7CDD3LL /* 682 */, 0x7CAC32883D261D9CLL /* 683 */,
+ 0x7690C26423BA942CLL /* 684 */, 0x17E55524478042B8LL /* 685 */,
+ 0xE0BE477656A2389FLL /* 686 */, 0x4D289B5E67AB2DA0LL /* 687 */,
+ 0x44862B9C8FBBFD31LL /* 688 */, 0xB47CC8049D141365LL /* 689 */,
+ 0x822C1B362B91C793LL /* 690 */, 0x4EB14655FB13DFD8LL /* 691 */,
+ 0x1ECBBA0714E2A97BLL /* 692 */, 0x6143459D5CDE5F14LL /* 693 */,
+ 0x53A8FBF1D5F0AC89LL /* 694 */, 0x97EA04D81C5E5B00LL /* 695 */,
+ 0x622181A8D4FDB3F3LL /* 696 */, 0xE9BCD341572A1208LL /* 697 */,
+ 0x1411258643CCE58ALL /* 698 */, 0x9144C5FEA4C6E0A4LL /* 699 */,
+ 0x0D33D06565CF620FLL /* 700 */, 0x54A48D489F219CA1LL /* 701 */,
+ 0xC43E5EAC6D63C821LL /* 702 */, 0xA9728B3A72770DAFLL /* 703 */,
+ 0xD7934E7B20DF87EFLL /* 704 */, 0xE35503B61A3E86E5LL /* 705 */,
+ 0xCAE321FBC819D504LL /* 706 */, 0x129A50B3AC60BFA6LL /* 707 */,
+ 0xCD5E68EA7E9FB6C3LL /* 708 */, 0xB01C90199483B1C7LL /* 709 */,
+ 0x3DE93CD5C295376CLL /* 710 */, 0xAED52EDF2AB9AD13LL /* 711 */,
+ 0x2E60F512C0A07884LL /* 712 */, 0xBC3D86A3E36210C9LL /* 713 */,
+ 0x35269D9B163951CELL /* 714 */, 0x0C7D6E2AD0CDB5FALL /* 715 */,
+ 0x59E86297D87F5733LL /* 716 */, 0x298EF221898DB0E7LL /* 717 */,
+ 0x55000029D1A5AA7ELL /* 718 */, 0x8BC08AE1B5061B45LL /* 719 */,
+ 0xC2C31C2B6C92703ALL /* 720 */, 0x94CC596BAF25EF42LL /* 721 */,
+ 0x0A1D73DB22540456LL /* 722 */, 0x04B6A0F9D9C4179ALL /* 723 */,
+ 0xEFFDAFA2AE3D3C60LL /* 724 */, 0xF7C8075BB49496C4LL /* 725 */,
+ 0x9CC5C7141D1CD4E3LL /* 726 */, 0x78BD1638218E5534LL /* 727 */,
+ 0xB2F11568F850246ALL /* 728 */, 0xEDFABCFA9502BC29LL /* 729 */,
+ 0x796CE5F2DA23051BLL /* 730 */, 0xAAE128B0DC93537CLL /* 731 */,
+ 0x3A493DA0EE4B29AELL /* 732 */, 0xB5DF6B2C416895D7LL /* 733 */,
+ 0xFCABBD25122D7F37LL /* 734 */, 0x70810B58105DC4B1LL /* 735 */,
+ 0xE10FDD37F7882A90LL /* 736 */, 0x524DCAB5518A3F5CLL /* 737 */,
+ 0x3C9E85878451255BLL /* 738 */, 0x4029828119BD34E2LL /* 739 */,
+ 0x74A05B6F5D3CECCBLL /* 740 */, 0xB610021542E13ECALL /* 741 */,
+ 0x0FF979D12F59E2ACLL /* 742 */, 0x6037DA27E4F9CC50LL /* 743 */,
+ 0x5E92975A0DF1847DLL /* 744 */, 0xD66DE190D3E623FELL /* 745 */,
+ 0x5032D6B87B568048LL /* 746 */, 0x9A36B7CE8235216ELL /* 747 */,
+ 0x80272A7A24F64B4ALL /* 748 */, 0x93EFED8B8C6916F7LL /* 749 */,
+ 0x37DDBFF44CCE1555LL /* 750 */, 0x4B95DB5D4B99BD25LL /* 751 */,
+ 0x92D3FDA169812FC0LL /* 752 */, 0xFB1A4A9A90660BB6LL /* 753 */,
+ 0x730C196946A4B9B2LL /* 754 */, 0x81E289AA7F49DA68LL /* 755 */,
+ 0x64669A0F83B1A05FLL /* 756 */, 0x27B3FF7D9644F48BLL /* 757 */,
+ 0xCC6B615C8DB675B3LL /* 758 */, 0x674F20B9BCEBBE95LL /* 759 */,
+ 0x6F31238275655982LL /* 760 */, 0x5AE488713E45CF05LL /* 761 */,
+ 0xBF619F9954C21157LL /* 762 */, 0xEABAC46040A8EAE9LL /* 763 */,
+ 0x454C6FE9F2C0C1CDLL /* 764 */, 0x419CF6496412691CLL /* 765 */,
+ 0xD3DC3BEF265B0F70LL /* 766 */, 0x6D0E60F5C3578A9ELL /* 767 */,
+ 0x5B0E608526323C55LL /* 768 */, 0x1A46C1A9FA1B59F5LL /* 769 */,
+ 0xA9E245A17C4C8FFALL /* 770 */, 0x65CA5159DB2955D7LL /* 771 */,
+ 0x05DB0A76CE35AFC2LL /* 772 */, 0x81EAC77EA9113D45LL /* 773 */,
+ 0x528EF88AB6AC0A0DLL /* 774 */, 0xA09EA253597BE3FFLL /* 775 */,
+ 0x430DDFB3AC48CD56LL /* 776 */, 0xC4B3A67AF45CE46FLL /* 777 */,
+ 0x4ECECFD8FBE2D05ELL /* 778 */, 0x3EF56F10B39935F0LL /* 779 */,
+ 0x0B22D6829CD619C6LL /* 780 */, 0x17FD460A74DF2069LL /* 781 */,
+ 0x6CF8CC8E8510ED40LL /* 782 */, 0xD6C824BF3A6ECAA7LL /* 783 */,
+ 0x61243D581A817049LL /* 784 */, 0x048BACB6BBC163A2LL /* 785 */,
+ 0xD9A38AC27D44CC32LL /* 786 */, 0x7FDDFF5BAAF410ABLL /* 787 */,
+ 0xAD6D495AA804824BLL /* 788 */, 0xE1A6A74F2D8C9F94LL /* 789 */,
+ 0xD4F7851235DEE8E3LL /* 790 */, 0xFD4B7F886540D893LL /* 791 */,
+ 0x247C20042AA4BFDALL /* 792 */, 0x096EA1C517D1327CLL /* 793 */,
+ 0xD56966B4361A6685LL /* 794 */, 0x277DA5C31221057DLL /* 795 */,
+ 0x94D59893A43ACFF7LL /* 796 */, 0x64F0C51CCDC02281LL /* 797 */,
+ 0x3D33BCC4FF6189DBLL /* 798 */, 0xE005CB184CE66AF1LL /* 799 */,
+ 0xFF5CCD1D1DB99BEALL /* 800 */, 0xB0B854A7FE42980FLL /* 801 */,
+ 0x7BD46A6A718D4B9FLL /* 802 */, 0xD10FA8CC22A5FD8CLL /* 803 */,
+ 0xD31484952BE4BD31LL /* 804 */, 0xC7FA975FCB243847LL /* 805 */,
+ 0x4886ED1E5846C407LL /* 806 */, 0x28CDDB791EB70B04LL /* 807 */,
+ 0xC2B00BE2F573417FLL /* 808 */, 0x5C9590452180F877LL /* 809 */,
+ 0x7A6BDDFFF370EB00LL /* 810 */, 0xCE509E38D6D9D6A4LL /* 811 */,
+ 0xEBEB0F00647FA702LL /* 812 */, 0x1DCC06CF76606F06LL /* 813 */,
+ 0xE4D9F28BA286FF0ALL /* 814 */, 0xD85A305DC918C262LL /* 815 */,
+ 0x475B1D8732225F54LL /* 816 */, 0x2D4FB51668CCB5FELL /* 817 */,
+ 0xA679B9D9D72BBA20LL /* 818 */, 0x53841C0D912D43A5LL /* 819 */,
+ 0x3B7EAA48BF12A4E8LL /* 820 */, 0x781E0E47F22F1DDFLL /* 821 */,
+ 0xEFF20CE60AB50973LL /* 822 */, 0x20D261D19DFFB742LL /* 823 */,
+ 0x16A12B03062A2E39LL /* 824 */, 0x1960EB2239650495LL /* 825 */,
+ 0x251C16FED50EB8B8LL /* 826 */, 0x9AC0C330F826016ELL /* 827 */,
+ 0xED152665953E7671LL /* 828 */, 0x02D63194A6369570LL /* 829 */,
+ 0x5074F08394B1C987LL /* 830 */, 0x70BA598C90B25CE1LL /* 831 */,
+ 0x794A15810B9742F6LL /* 832 */, 0x0D5925E9FCAF8C6CLL /* 833 */,
+ 0x3067716CD868744ELL /* 834 */, 0x910AB077E8D7731BLL /* 835 */,
+ 0x6A61BBDB5AC42F61LL /* 836 */, 0x93513EFBF0851567LL /* 837 */,
+ 0xF494724B9E83E9D5LL /* 838 */, 0xE887E1985C09648DLL /* 839 */,
+ 0x34B1D3C675370CFDLL /* 840 */, 0xDC35E433BC0D255DLL /* 841 */,
+ 0xD0AAB84234131BE0LL /* 842 */, 0x08042A50B48B7EAFLL /* 843 */,
+ 0x9997C4EE44A3AB35LL /* 844 */, 0x829A7B49201799D0LL /* 845 */,
+ 0x263B8307B7C54441LL /* 846 */, 0x752F95F4FD6A6CA6LL /* 847 */,
+ 0x927217402C08C6E5LL /* 848 */, 0x2A8AB754A795D9EELL /* 849 */,
+ 0xA442F7552F72943DLL /* 850 */, 0x2C31334E19781208LL /* 851 */,
+ 0x4FA98D7CEAEE6291LL /* 852 */, 0x55C3862F665DB309LL /* 853 */,
+ 0xBD0610175D53B1F3LL /* 854 */, 0x46FE6CB840413F27LL /* 855 */,
+ 0x3FE03792DF0CFA59LL /* 856 */, 0xCFE700372EB85E8FLL /* 857 */,
+ 0xA7BE29E7ADBCE118LL /* 858 */, 0xE544EE5CDE8431DDLL /* 859 */,
+ 0x8A781B1B41F1873ELL /* 860 */, 0xA5C94C78A0D2F0E7LL /* 861 */,
+ 0x39412E2877B60728LL /* 862 */, 0xA1265EF3AFC9A62CLL /* 863 */,
+ 0xBCC2770C6A2506C5LL /* 864 */, 0x3AB66DD5DCE1CE12LL /* 865 */,
+ 0xE65499D04A675B37LL /* 866 */, 0x7D8F523481BFD216LL /* 867 */,
+ 0x0F6F64FCEC15F389LL /* 868 */, 0x74EFBE618B5B13C8LL /* 869 */,
+ 0xACDC82B714273E1DLL /* 870 */, 0xDD40BFE003199D17LL /* 871 */,
+ 0x37E99257E7E061F8LL /* 872 */, 0xFA52626904775AAALL /* 873 */,
+ 0x8BBBF63A463D56F9LL /* 874 */, 0xF0013F1543A26E64LL /* 875 */,
+ 0xA8307E9F879EC898LL /* 876 */, 0xCC4C27A4150177CCLL /* 877 */,
+ 0x1B432F2CCA1D3348LL /* 878 */, 0xDE1D1F8F9F6FA013LL /* 879 */,
+ 0x606602A047A7DDD6LL /* 880 */, 0xD237AB64CC1CB2C7LL /* 881 */,
+ 0x9B938E7225FCD1D3LL /* 882 */, 0xEC4E03708E0FF476LL /* 883 */,
+ 0xFEB2FBDA3D03C12DLL /* 884 */, 0xAE0BCED2EE43889ALL /* 885 */,
+ 0x22CB8923EBFB4F43LL /* 886 */, 0x69360D013CF7396DLL /* 887 */,
+ 0x855E3602D2D4E022LL /* 888 */, 0x073805BAD01F784CLL /* 889 */,
+ 0x33E17A133852F546LL /* 890 */, 0xDF4874058AC7B638LL /* 891 */,
+ 0xBA92B29C678AA14ALL /* 892 */, 0x0CE89FC76CFAADCDLL /* 893 */,
+ 0x5F9D4E0908339E34LL /* 894 */, 0xF1AFE9291F5923B9LL /* 895 */,
+ 0x6E3480F60F4A265FLL /* 896 */, 0xEEBF3A2AB29B841CLL /* 897 */,
+ 0xE21938A88F91B4ADLL /* 898 */, 0x57DFEFF845C6D3C3LL /* 899 */,
+ 0x2F006B0BF62CAAF2LL /* 900 */, 0x62F479EF6F75EE78LL /* 901 */,
+ 0x11A55AD41C8916A9LL /* 902 */, 0xF229D29084FED453LL /* 903 */,
+ 0x42F1C27B16B000E6LL /* 904 */, 0x2B1F76749823C074LL /* 905 */,
+ 0x4B76ECA3C2745360LL /* 906 */, 0x8C98F463B91691BDLL /* 907 */,
+ 0x14BCC93CF1ADE66ALL /* 908 */, 0x8885213E6D458397LL /* 909 */,
+ 0x8E177DF0274D4711LL /* 910 */, 0xB49B73B5503F2951LL /* 911 */,
+ 0x10168168C3F96B6BLL /* 912 */, 0x0E3D963B63CAB0AELL /* 913 */,
+ 0x8DFC4B5655A1DB14LL /* 914 */, 0xF789F1356E14DE5CLL /* 915 */,
+ 0x683E68AF4E51DAC1LL /* 916 */, 0xC9A84F9D8D4B0FD9LL /* 917 */,
+ 0x3691E03F52A0F9D1LL /* 918 */, 0x5ED86E46E1878E80LL /* 919 */,
+ 0x3C711A0E99D07150LL /* 920 */, 0x5A0865B20C4E9310LL /* 921 */,
+ 0x56FBFC1FE4F0682ELL /* 922 */, 0xEA8D5DE3105EDF9BLL /* 923 */,
+ 0x71ABFDB12379187ALL /* 924 */, 0x2EB99DE1BEE77B9CLL /* 925 */,
+ 0x21ECC0EA33CF4523LL /* 926 */, 0x59A4D7521805C7A1LL /* 927 */,
+ 0x3896F5EB56AE7C72LL /* 928 */, 0xAA638F3DB18F75DCLL /* 929 */,
+ 0x9F39358DABE9808ELL /* 930 */, 0xB7DEFA91C00B72ACLL /* 931 */,
+ 0x6B5541FD62492D92LL /* 932 */, 0x6DC6DEE8F92E4D5BLL /* 933 */,
+ 0x353F57ABC4BEEA7ELL /* 934 */, 0x735769D6DA5690CELL /* 935 */,
+ 0x0A234AA642391484LL /* 936 */, 0xF6F9508028F80D9DLL /* 937 */,
+ 0xB8E319A27AB3F215LL /* 938 */, 0x31AD9C1151341A4DLL /* 939 */,
+ 0x773C22A57BEF5805LL /* 940 */, 0x45C7561A07968633LL /* 941 */,
+ 0xF913DA9E249DBE36LL /* 942 */, 0xDA652D9B78A64C68LL /* 943 */,
+ 0x4C27A97F3BC334EFLL /* 944 */, 0x76621220E66B17F4LL /* 945 */,
+ 0x967743899ACD7D0BLL /* 946 */, 0xF3EE5BCAE0ED6782LL /* 947 */,
+ 0x409F753600C879FCLL /* 948 */, 0x06D09A39B5926DB6LL /* 949 */,
+ 0x6F83AEB0317AC588LL /* 950 */, 0x01E6CA4A86381F21LL /* 951 */,
+ 0x66FF3462D19F3025LL /* 952 */, 0x72207C24DDFD3BFBLL /* 953 */,
+ 0x4AF6B6D3E2ECE2EBLL /* 954 */, 0x9C994DBEC7EA08DELL /* 955 */,
+ 0x49ACE597B09A8BC4LL /* 956 */, 0xB38C4766CF0797BALL /* 957 */,
+ 0x131B9373C57C2A75LL /* 958 */, 0xB1822CCE61931E58LL /* 959 */,
+ 0x9D7555B909BA1C0CLL /* 960 */, 0x127FAFDD937D11D2LL /* 961 */,
+ 0x29DA3BADC66D92E4LL /* 962 */, 0xA2C1D57154C2ECBCLL /* 963 */,
+ 0x58C5134D82F6FE24LL /* 964 */, 0x1C3AE3515B62274FLL /* 965 */,
+ 0xE907C82E01CB8126LL /* 966 */, 0xF8ED091913E37FCBLL /* 967 */,
+ 0x3249D8F9C80046C9LL /* 968 */, 0x80CF9BEDE388FB63LL /* 969 */,
+ 0x1881539A116CF19ELL /* 970 */, 0x5103F3F76BD52457LL /* 971 */,
+ 0x15B7E6F5AE47F7A8LL /* 972 */, 0xDBD7C6DED47E9CCFLL /* 973 */,
+ 0x44E55C410228BB1ALL /* 974 */, 0xB647D4255EDB4E99LL /* 975 */,
+ 0x5D11882BB8AAFC30LL /* 976 */, 0xF5098BBB29D3212ALL /* 977 */,
+ 0x8FB5EA14E90296B3LL /* 978 */, 0x677B942157DD025ALL /* 979 */,
+ 0xFB58E7C0A390ACB5LL /* 980 */, 0x89D3674C83BD4A01LL /* 981 */,
+ 0x9E2DA4DF4BF3B93BLL /* 982 */, 0xFCC41E328CAB4829LL /* 983 */,
+ 0x03F38C96BA582C52LL /* 984 */, 0xCAD1BDBD7FD85DB2LL /* 985 */,
+ 0xBBB442C16082AE83LL /* 986 */, 0xB95FE86BA5DA9AB0LL /* 987 */,
+ 0xB22E04673771A93FLL /* 988 */, 0x845358C9493152D8LL /* 989 */,
+ 0xBE2A488697B4541ELL /* 990 */, 0x95A2DC2DD38E6966LL /* 991 */,
+ 0xC02C11AC923C852BLL /* 992 */, 0x2388B1990DF2A87BLL /* 993 */,
+ 0x7C8008FA1B4F37BELL /* 994 */, 0x1F70D0C84D54E503LL /* 995 */,
+ 0x5490ADEC7ECE57D4LL /* 996 */, 0x002B3C27D9063A3ALL /* 997 */,
+ 0x7EAEA3848030A2BFLL /* 998 */, 0xC602326DED2003C0LL /* 999 */,
+ 0x83A7287D69A94086LL /* 1000 */, 0xC57A5FCB30F57A8ALL /* 1001 */,
+ 0xB56844E479EBE779LL /* 1002 */, 0xA373B40F05DCBCE9LL /* 1003 */,
+ 0xD71A786E88570EE2LL /* 1004 */, 0x879CBACDBDE8F6A0LL /* 1005 */,
+ 0x976AD1BCC164A32FLL /* 1006 */, 0xAB21E25E9666D78BLL /* 1007 */,
+ 0x901063AAE5E5C33CLL /* 1008 */, 0x9818B34448698D90LL /* 1009 */,
+ 0xE36487AE3E1E8ABBLL /* 1010 */, 0xAFBDF931893BDCB4LL /* 1011 */,
+ 0x6345A0DC5FBBD519LL /* 1012 */, 0x8628FE269B9465CALL /* 1013 */,
+ 0x1E5D01603F9C51ECLL /* 1014 */, 0x4DE44006A15049B7LL /* 1015 */,
+ 0xBF6C70E5F776CBB1LL /* 1016 */, 0x411218F2EF552BEDLL /* 1017 */,
+ 0xCB0C0708705A36A3LL /* 1018 */, 0xE74D14754F986044LL /* 1019 */,
+ 0xCD56D9430EA8280ELL /* 1020 */, 0xC12591D7535F5065LL /* 1021 */,
+ 0xC83223F1720AEF96LL /* 1022 */, 0xC3A0396F7363A51FLL /* 1023 */};
+
+#else
+
+void dummy_2_64 (int a)
+{
+ (void) a;
+ return;
+}
+
+#endif
diff --git a/src/sh_tools.c b/src/sh_tools.c
new file mode 100644
index 0000000..6485a58
--- /dev/null
+++ b/src/sh_tools.c
@@ -0,0 +1,2279 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* Must be early on FreeBSD
+ */
+#include <sys/types.h>
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+#include <sys/socket.h>
+
+#ifdef HOST_IS_HPUX
+#define _XOPEN_SOURCE_EXTENDED
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#define SH_REAL_SET
+
+#include "samhain.h"
+#include "sh_mem.h"
+#include "sh_error.h"
+#include "sh_tools.h"
+#include "sh_utils.h"
+#include "sh_tiger.h"
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+#include "sh_pthread.h"
+#include "sh_ipvx.h"
+
+#undef FIL__
+#define FIL__ _("sh_tools.c")
+
+static int tools_debug = 0;
+
+#ifdef SH_ENCRYPT
+#include "rijndael-api-fst.h"
+char * errorExplain (int err_num, char * buffer, size_t len)
+{
+ char * p;
+
+ if (err_num == BAD_KEY_DIR)
+ p = (_("Key direction is invalid"));
+ else if (err_num == BAD_KEY_MAT)
+ p = (_("Key material not of correct length"));
+ else if (err_num == BAD_KEY_INSTANCE)
+ p = (_("Key passed is not valid"));
+ else if (err_num == BAD_CIPHER_MODE)
+ p = (_("Params struct passed to rijndael_cipherInit invalid"));
+ else if (err_num == BAD_CIPHER_STATE)
+ p = (_("Cipher in wrong state"));
+ else if (err_num == BAD_BLOCK_LENGTH)
+ p = (_("Bad block length"));
+ else if (err_num == BAD_CIPHER_INSTANCE)
+ p = (_("Bad cipher instance"));
+ else if (err_num == BAD_DATA)
+ p = (_("Data contents are invalid"));
+ else
+ p = (_("Unknown error"));
+ sl_strlcpy (buffer, p, len);
+ return buffer;
+}
+
+#endif
+
+/* --- check for an interface ---
+ */
+int sh_tools_iface_is_present(char *str)
+{
+#if defined(USE_IPVX)
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ int res;
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+ res = getaddrinfo (str, _("2543"), &hints, &ai);
+
+ if (res == 0)
+ {
+ struct addrinfo *p = ai;
+ while (p != NULL)
+ {
+ int fd = socket (p->ai_family, p->ai_socktype,
+ p->ai_protocol);
+
+ if (fd < 0)
+ {
+ freeaddrinfo (ai);
+ return 0;
+ }
+
+ if (bind (fd, p->ai_addr, p->ai_addrlen) != 0)
+ {
+ /* bind() fails for access reasons, iface exists
+ */
+ if (errno == EACCES || errno == EADDRINUSE)
+ {
+ sl_close_fd (FIL__, __LINE__, fd);
+ freeaddrinfo (ai);
+ return 1;
+ }
+
+ sl_close_fd (FIL__, __LINE__, fd);
+ freeaddrinfo (ai);
+ return 0;
+ }
+
+ sl_close_fd (FIL__, __LINE__, fd);
+ freeaddrinfo (ai);
+ return 1;
+ /* p = p->ai_next; */
+ }
+ }
+#else
+ struct sockaddr_in sin;
+ int sd;
+
+ memset(&sin, '\0', sizeof(sin));
+ sin.sin_family = AF_INET;
+ if (inet_aton(str, &(sin.sin_addr)))
+ {
+ sin.sin_port = htons(2543);
+
+ if (-1 == (sd = socket(AF_INET, SOCK_STREAM, 0)))
+ {
+ return 0;
+ }
+
+ if (-1 == bind(sd, (struct sockaddr *)&sin, sizeof(sin)))
+ {
+ int retval = 0;
+
+ /* bind() fails for access reasons, iface exists
+ */
+ if (errno == EACCES || errno == EADDRINUSE)
+ retval = 1;
+ sl_close_fd (FIL__, __LINE__, sd);
+ return retval;
+ }
+
+ /* bind() succeeds, iface exists
+ */
+ sl_close_fd(FIL__, __LINE__, sd);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/* --- recode all \blah escapes to qp (quoted printable) '=XX' format, and
+ * also code all remaining unprintable chars ---
+ */
+#define SH_PUT_4(p, a, b, c) (p)[0] = (a); (p)[1] = (b); (p)[2] = (c);
+
+char * sh_tools_safe_name (const char * instr, int flag)
+{
+ unsigned char c, d;
+ const char * p;
+ char tmp[4];
+ char * outstr;
+ size_t len = 1;
+ int i = 0;
+ unsigned char val_octal = '\0';
+ static char ctable[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ SL_ENTER(_("sh_tools_safe_name"));
+
+ if (instr)
+ {
+ len = strlen(instr);
+ if (sl_ok_muls (3, len) && sl_ok_adds ((3*len), 4))
+ {
+ len = (3 * len) + 4;
+ p = instr;
+ }
+ else
+ {
+ len = 1;
+ p = NULL;
+ }
+ }
+ else
+ {
+ p = NULL;
+ }
+
+ outstr = SH_ALLOC(len);
+
+ outstr[0] = '\0';
+ tmp[3] = '\0';
+
+#if !defined(SH_USE_XML)
+ (void) flag; /* fix compiler warning */
+#endif
+
+ if (!p)
+ goto end;
+
+ while (*p)
+ {
+ c = *p;
+
+ if (*p == '\n')
+ {
+ outstr[i] = ' '; ++i; ++p;
+ continue;
+ }
+
+#ifdef SH_USE_XML
+ if (flag == 1)
+ {
+ if ((*p) == '"')
+ {
+ SH_PUT_4(&outstr[i], '=', '2', '2');
+ i+=3; ++p;
+ continue;
+ }
+ else if ((*p) == '&')
+ {
+ SH_PUT_4(&outstr[i], '=', '2', '6');
+ i+=3; ++p;
+ continue;
+ }
+ else if ((*p) == '<')
+ { /* left angle */
+ SH_PUT_4(&outstr[i], '=', '3', 'c');
+ i+=3; ++p;
+ continue;
+ }
+ else if ((*p) == '>')
+ { /* right angle */
+ SH_PUT_4(&outstr[i], '=', '3', 'e');
+ i+=3; ++p;
+ continue;
+ }
+ }
+#endif
+
+ if ( (*p) != '\\' && (*p) != '&' && (*p) != '=' && (*p) != '\'')
+ {
+ outstr[i] = *p; ++i;
+ ++p;
+
+ if (c < 32 || c > 126)
+ {
+ --i;
+ d = c % 16; c = c / 16;
+ outstr[i] = '='; ++i;
+ outstr[i] = ctable[c]; ++i;
+ outstr[i] = ctable[d]; ++i;
+ }
+
+ continue;
+ }
+ else if ((*p) == '\'')
+ {
+ SH_PUT_4(&outstr[i], '=', '2', '7');
+ i+=3; ++p;
+ }
+ else if (*p == '=')
+ {
+ if (p[1] != '"' && p[1] != '<')
+ {
+ SH_PUT_4(&outstr[i], '=', '3', 'd');
+ i+=3; ++p;
+ }
+ else
+ { outstr[i] = *p; ++i; ++p; }
+ }
+ else if (*p == '\\')
+ {
+ ++p;
+ if (!p)
+ break;
+ if (!(*p))
+ break;
+
+
+
+ switch (*p) {
+ case '\\':
+ SH_PUT_4(&outstr[i], '=', '5', 'c');
+ i+=3; ++p;
+ break;
+ case 'n':
+ SH_PUT_4(&outstr[i], '=', '0', 'a');
+ i+=3; ++p;
+ break;
+ case 'b':
+ SH_PUT_4(&outstr[i], '=', '0', '8');
+ i+=3; ++p;
+ break;
+ case 'r':
+ SH_PUT_4(&outstr[i], '=', '0', 'd');
+ i+=3; ++p;
+ break;
+ case 't':
+ SH_PUT_4(&outstr[i], '=', '0', '9');
+ i+=3; ++p;
+ break;
+ case 'v':
+ SH_PUT_4(&outstr[i], '=', '0', 'b');
+ i+=3; ++p;
+ break;
+ case 'f':
+ SH_PUT_4(&outstr[i], '=', '0', 'c');
+ i+=3; ++p;
+ break;
+ case '\'':
+ SH_PUT_4(&outstr[i], '=', '2', '7');
+ i+=3; ++p;
+ break;
+ case '"': /* also encode quoted '"' */
+ SH_PUT_4(&outstr[i], '=', '2', '2');
+ i+=3; ++p;
+ break;
+ case ' ':
+ SH_PUT_4(&outstr[i], '=', '2', '0');
+ i+=3; ++p;
+ break;
+ default:
+ if (strlen(p) < 3) /* certainly not an octal number, skip */
+ {
+ p += strlen(p);
+ }
+ else
+ {
+ tmp[0] = p[0]; tmp[1] = p[1]; tmp[2] = p[2];
+ val_octal = (unsigned char) strtoul(tmp, (char **)NULL, 8);
+ if (val_octal != '\0') {
+ c = val_octal;
+ d = c % 16; c = c / 16;
+ outstr[i] = '='; ++i;
+ outstr[i] = ctable[c]; ++i;
+ outstr[i] = ctable[d]; ++i;
+ }
+ p += 3;
+ }
+ }
+ }
+ else if (*p == '&')
+ {
+ ++p;
+ if (!p || !(*p))
+ {
+ outstr[i] = '&'; ++i;
+ break;
+ }
+
+ if (p[0] == 'a' && p[1] == 'm' && p[2] == 'p' && p[3] == ';')
+ {
+ SH_PUT_4(&outstr[i], '=', '2', '6');
+ i+=3; p += 4;
+ }
+ else if (p[0] == 'q' && p[1] == 'u' && p[2] == 'o' && p[3] == 't' &&
+ p[4] == ';')
+ {
+ SH_PUT_4(&outstr[i], '=', '2', '2');
+ i+=3; p += 5;
+ }
+ else if (p[0] == 'l' && p[1] == 't' && p[2] == ';')
+ {
+ SH_PUT_4(&outstr[i], '=', '3', 'c');
+ i+=3; p += 3;
+ }
+ else if (p[0] == 'g' && p[1] == 't' && p[2] == ';')
+ {
+ SH_PUT_4(&outstr[i], '=', '3', 'e');
+ i+=3; p += 3;
+ }
+ else /* conserve the '&' */
+ {
+ outstr[i] = '&'; ++i;
+ }
+ }
+ else
+ {
+ outstr[i] = *p; ++i;
+ ++p;
+ }
+ } /* while (p && *p) */
+
+ end:
+
+ outstr[i] = '\0';
+ SL_RETURN( outstr, _("sh_tools_safe_name"));
+}
+
+
+/* extern int h_errno; */
+
+char * sh_tools_errmessage (int tellme, char * errbuf, size_t len)
+{
+ char * p = NULL;
+#ifdef HOST_NOT_FOUND
+ if (tellme == HOST_NOT_FOUND)
+ p = _("The specified host is unknown: ");
+#endif
+#ifdef NO_ADDRESS
+ if (tellme == NO_ADDRESS)
+ p = _("The requested name is valid but does not have an IP address: ");
+#endif
+#ifdef NO_RECOVERY
+ if (tellme == NO_RECOVERY)
+ p = _("A non-recoverable name server error occurred: ");
+#endif
+#ifdef TRY_AGAIN
+ if (tellme == TRY_AGAIN)
+ p = _("A temporary error occurred on an authoritative name server. The specified host is unknown: ");
+#endif
+ if (!p) p = _("Unknown error");
+ sl_strlcpy(errbuf, p, len);
+ return errbuf;
+}
+
+#if defined (SH_WITH_SERVER)
+
+int get_open_max ()
+{
+ int value;
+
+#ifdef _SC_OPEN_MAX
+ value = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ value = OPEN_MAX;
+#else
+ value = _POSIX_OPEN_MAX;
+#endif
+#endif
+
+ if (value < 0)
+ value = 8; /* POSIX lower limit */
+
+ if (value > 4096)
+ value = 4096;
+
+ return value;
+}
+
+#endif
+
+typedef struct _sin_cache {
+ char * address;
+ struct sh_sockaddr saddr;
+ struct _sin_cache * next;
+} sin_cache;
+
+static sin_cache * conn_cache = NULL;
+static int cached_addr = 0;
+
+void delete_cache()
+{
+ sin_cache * check_cache = conn_cache;
+ sin_cache * old_entry;
+
+ SL_ENTER(_("delete_cache"));
+
+ while (check_cache != NULL)
+ {
+ old_entry = check_cache;
+ check_cache = check_cache->next;
+ SH_FREE(old_entry->address);
+ SH_FREE(old_entry);
+ }
+
+ cached_addr = 0;
+
+ conn_cache = NULL;
+ SL_RET0(_("delete_cache"));
+}
+
+int DoReverseLookup = S_TRUE;
+
+int set_reverse_lookup (const char * c)
+{
+ return sh_util_flagval(c, &DoReverseLookup);
+}
+
+#if !defined(USE_IPVX)
+int connect_port (char * address, int port,
+ char * ecall, int * errnum, char * errmsg, int errsiz)
+{
+ struct in_addr haddr; /* host address from numeric */
+ /* host details returned by the DNS */
+ struct hostent *host_entry = NULL;
+ struct sockaddr_in sinr; /* socket to the remote host */
+
+ char * host_name;
+
+ volatile int fd = (-1);
+ int status;
+ volatile int fail = 0;
+ int cached = 0;
+
+ int retval;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ sin_cache * check_cache = conn_cache;
+
+ SL_ENTER(_("connect_port"));
+
+ if (tools_debug)
+ fprintf(stderr, _("-00- <%s> <%d> no IPv6 support\n"), address, port);
+
+ if (errsiz > 0) errmsg[0] = '\0';
+
+ /* paranoia -- should not happen
+ */
+ if (cached_addr > 128)
+ delete_cache();
+
+ if (check_cache != NULL)
+ {
+ while (check_cache && check_cache->address)
+ {
+ if (tools_debug)
+ fprintf(stderr, _("-01- <%s> <%s>\n"),
+ address, check_cache->address);
+
+ if ( 0 == sl_strncmp(check_cache->address,
+ address, sl_strlen(address)) )
+ {
+ memcpy (&sinr, &((check_cache->saddr).sin), sizeof(struct sockaddr_in));
+ sinr.sin_family = AF_INET;
+ sinr.sin_port = htons (port);
+ cached = 1;
+ break;
+ }
+ if (tools_debug)
+ {
+ char eaddr[SH_IP_BUF];
+ sl_strlcpy(eaddr,
+ inet_ntoa(*(struct in_addr *) &(sinr.sin_addr)),
+ sizeof(eaddr));
+ fprintf(stderr, _("-02- <AF_INET> <%s> <%d> <%d>\n"),
+ eaddr,
+ port, cached);
+ }
+ if (check_cache->next)
+ check_cache = check_cache->next;
+ else
+ check_cache = NULL;
+ }
+ }
+
+ /* only use gethostbyname() if neccessary
+ */
+ if (cached == 0)
+ {
+ if (tools_debug)
+ fputs(_("-03- not cached\n"), stderr);
+#ifdef HAVE_INET_ATON
+ if (0 == inet_aton(address, &haddr))
+#else
+ if ((unsigned long)-1 == (haddr.s_addr = inet_addr(address)))
+#endif
+ {
+ SH_MUTEX_LOCK(mutex_resolv);
+
+ host_name = NULL;
+
+ host_entry = sh_gethostbyname(address);
+
+ if (host_entry == NULL || host_entry->h_addr == NULL)
+ {
+ sl_strlcpy(ecall, _("gethostbyname"), SH_MINIBUF);
+#ifndef NO_H_ERRNO
+ *errnum = h_errno;
+#else
+ *errnum = 666;
+#endif
+ (void) sh_tools_errmessage (*errnum, errmsg, errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ fail = (-1);
+ }
+ else
+ {
+ sinr.sin_family = AF_INET;
+ sinr.sin_port = htons (port);
+ sinr.sin_addr = *(struct in_addr *) host_entry->h_addr;
+
+ if (tools_debug)
+ fprintf(stderr,
+ _("-04- <%s> <%s> hostent->h_name %s <%s> hostent->h_addr\n"),
+ address,
+ (host_entry->h_name == NULL) ? _("NULL") : host_entry->h_name,
+ (host_entry->h_addrtype == AF_INET) ? _("AF_INET") : _("AF_INET6"),
+ inet_ntoa(*(struct in_addr *) &(sinr.sin_addr)));
+
+ /* reverse DNS lookup
+ */
+ if (DoReverseLookup == S_TRUE)
+ {
+ if (host_entry->h_name == NULL)
+ {
+ host_name = SH_ALLOC(1);
+ host_name[0] = '\0';
+ }
+ else
+ {
+ host_name = sh_util_strdup(host_entry->h_name);
+ }
+
+ host_entry = sh_gethostbyaddr ((char *) &sinr.sin_addr,
+ sizeof(struct in_addr),
+ AF_INET);
+ if (host_entry == NULL || host_entry->h_name == NULL)
+ {
+ sl_strlcpy(ecall, _("gethostbyaddr"), SH_MINIBUF);
+#ifndef NO_H_ERRNO
+ *errnum = h_errno;
+#else
+ *errnum = 666;
+#endif
+ (void) sh_tools_errmessage (*errnum, errmsg, errsiz);
+ sl_strlcat(errmsg,
+ inet_ntoa (*(struct in_addr *) &(sinr.sin_addr)),
+ errsiz);
+ fail = (-1);
+ }
+ else
+ {
+ *errnum = 0;
+ if (sl_strlen(host_entry->h_name) == 0 ||
+ (*errnum = sl_strcasecmp(host_name,host_entry->h_name)) != 0)
+ {
+ if (*errnum)
+ sl_strlcpy(ecall, _("strcmp"), SH_MINIBUF);
+ else
+ sl_strlcpy(ecall, _("strlen"), SH_MINIBUF);
+ sl_strlcpy(errmsg, _("Reverse lookup failed: "),
+ errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ sl_strlcat(errmsg, _(" vs "), errsiz);
+ sl_strlcat(errmsg,
+ inet_ntoa (*(struct in_addr *) &(sinr.sin_addr)),
+ errsiz);
+ fail = -1;
+ }
+ }
+ }
+ }
+ SH_MUTEX_UNLOCK(mutex_resolv);
+ if (host_name) SH_FREE(host_name);
+ }
+
+ else /* address was numeric */
+ {
+ sinr.sin_family = AF_INET;
+ sinr.sin_port = htons (port);
+ sinr.sin_addr = haddr;
+
+ if (tools_debug)
+ fprintf(stderr,
+ _("-04- <%s> is_numeric AF_INET <%s> \n"),
+ address,
+ inet_ntoa(*(struct in_addr *) &(sinr.sin_addr)));
+ }
+
+
+ if (fail != -1)
+ {
+ /* put it into the cache
+ */
+ check_cache = SH_ALLOC(sizeof(sin_cache));
+ check_cache->address = SH_ALLOC(sl_strlen(address) + 1);
+ sl_strlcpy (check_cache->address, address, sl_strlen(address) + 1);
+
+ sh_ipvx_save(&(check_cache->saddr), AF_INET, (struct sockaddr *) &sinr);
+
+ ++cached_addr;
+
+ if (conn_cache)
+ {
+ if (conn_cache->next)
+ check_cache->next = conn_cache->next;
+ else
+ check_cache->next = NULL;
+ conn_cache->next = check_cache;
+ }
+ else
+ {
+ check_cache->next = NULL;
+ conn_cache = check_cache;
+ }
+ }
+ }
+
+
+ if (fail != (-1))
+ {
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ fail = (-1);
+ status = errno;
+ sl_strlcpy(ecall, _("socket"), SH_MINIBUF);
+ *errnum = status;
+ sl_strlcpy(errmsg, sh_error_message (status, errbuf, sizeof(errbuf)), errsiz);
+ sl_strlcat(errmsg, _(", address "), errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ }
+ }
+
+ if (fail != (-1)) {
+
+ if ( retry_connect(FIL__, __LINE__, fd,
+ (struct sockaddr *) &sinr, sizeof(sinr)) < 0)
+ {
+ status = errno;
+ sl_strlcpy(ecall, _("connect"), SH_MINIBUF);
+ *errnum = status;
+ sl_strlcpy(errmsg, sh_error_message (status, errbuf, sizeof(errbuf)), errsiz);
+ sl_strlcat(errmsg,
+ (sinr.sin_family == AF_INET) ? _(", AF_INET ") : _(", AF_INET6 "),
+ errsiz);
+ sl_strlcat(errmsg, _(", address "), errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ sl_close_fd(FIL__, __LINE__, fd);
+ fail = (-1);
+ }
+ }
+
+ retval = (fail < 0) ? (-1) : fd;
+ SL_RETURN(retval, _("connect_port"));
+}
+#else
+int connect_port (char * address, int port,
+ char * ecall, int * errnum, char * errmsg, int errsiz)
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ struct sh_sockaddr ss;
+ sin_cache * check_cache = conn_cache;
+ int cached = 0;
+ int fail = 0;
+ int fd = -1;
+ int status = 0;
+
+ int retval;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("connect_port"));
+
+ /* paranoia -- should not happen
+ */
+ if (cached_addr > 128)
+ delete_cache();
+
+ if (tools_debug)
+ fprintf(stderr, _("-00- <%s> <%d>\n"), address, port);
+
+ if (check_cache != NULL)
+ {
+ while (check_cache && check_cache->address)
+ {
+ if (tools_debug)
+ fprintf(stderr, _("-01- <%s> <%s>\n"),
+ address, check_cache->address);
+
+ if ( 0 == sl_strcmp(check_cache->address, address) )
+ {
+ memcpy (&ss, &(check_cache->saddr), sizeof(struct sh_sockaddr));
+ switch (ss.ss_family)
+ {
+ case AF_INET:
+ sin = &(ss.sin);
+ sin->sin_port = htons (port);
+ cached = 1;
+ break;
+ case AF_INET6:
+ sin6 = &(ss.sin6);
+ sin6->sin6_port = htons (port);
+ cached = 1;
+ break;
+ default:
+ break;
+ }
+ if (tools_debug)
+ {
+ char eaddr[SH_IP_BUF];
+ sh_ipvx_ntoa(eaddr, sizeof(eaddr), &ss);
+ fprintf(stderr, _("-02- <%s> <%s> <%d> <%d>\n"),
+ (ss.ss_family == AF_INET) ? _("AF_INET") : _("AF_INET6"),
+ eaddr,
+ port, cached);
+ }
+ break;
+ }
+ if (check_cache->next)
+ check_cache = check_cache->next;
+ else
+ check_cache = NULL;
+ }
+ }
+
+ if (cached != 0)
+ {
+ if (tools_debug)
+ fputs(_("-03- cached\n"), stderr);
+ fd = socket(ss.ss_family, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ status = errno;
+ fail = (-1);
+ sl_strlcpy(ecall, _("socket"), SH_MINIBUF);
+ *errnum = status;
+ sl_strlcpy(errmsg, sh_error_message (status, errbuf, sizeof(errbuf)), errsiz);
+ sl_strlcat(errmsg, _(", address "), errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ }
+
+
+ if (fail != (-1))
+ {
+ int addrlen = SH_SS_LEN(ss);
+
+ if ( retry_connect(FIL__, __LINE__, fd,
+ sh_ipvx_sockaddr_cast(&ss), addrlen) < 0)
+ {
+ status = errno;
+ sl_strlcpy(ecall, _("connect"), SH_MINIBUF);
+ *errnum = status;
+ sl_strlcpy(errmsg, sh_error_message (status, errbuf, sizeof(errbuf)), errsiz);
+ sl_strlcat(errmsg, _(", address "), errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ sl_close_fd(FIL__, __LINE__, fd);
+ fail = (-1);
+ }
+ }
+
+ if (fail != 0)
+ {
+ delete_cache();
+ cached = 0;
+ }
+ }
+
+ if (cached == 0)
+ {
+ int res;
+ char sport[32];
+ struct addrinfo *ai;
+ struct addrinfo hints;
+
+ if (tools_debug)
+ fputs(_("-03- not cached\n"), stderr);
+
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_flags = AI_ADDRCONFIG;
+#if defined(AI_CANONNAME)
+ hints.ai_flags |= AI_CANONNAME;
+#endif
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ sl_snprintf(sport, sizeof(sport), "%d", port);
+
+ res = getaddrinfo (address, sport, &hints, &ai);
+ if (res != 0)
+ {
+ fail = (-1);
+ status = errno;
+ sl_strlcpy(ecall, _("getaddrinfo"), SH_MINIBUF);
+ *errnum = status;
+ sl_strlcpy(errmsg, gai_strerror (res), errsiz);
+ sl_strlcat(errmsg, _(", address "), errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ }
+
+ if (fail != (-1) && (DoReverseLookup == S_TRUE) && !sh_ipvx_is_numeric(address))
+ {
+ struct addrinfo *p = ai;
+ int success = 0;
+ char hostname[SH_BUFSIZE];
+ const char * canonical;
+
+
+#if defined(AI_CANONNAME)
+ if (ai->ai_canonname && strlen(ai->ai_canonname) > 0)
+ {
+ canonical = ai->ai_canonname;
+ if (tools_debug)
+ fprintf(stderr, _("-04- <%s> <%s> ai->ai_canonname\n"),
+ address, canonical);
+ }
+ else
+ {
+ canonical = address;
+ if (tools_debug)
+ fprintf(stderr, _("-04- <%s> <%s> defined ai_canonname\n"),
+ address, canonical);
+ }
+#else
+ canonical = address;
+ if (tools_debug)
+ fprintf(stderr, _("-04- <%s> <%s> not defined ai_canonname\n"),
+ address, canonical);
+#endif
+
+ while (p != NULL)
+ {
+ int e = getnameinfo (p->ai_addr, p->ai_addrlen,
+ hostname, sizeof(hostname),
+ NULL, 0, NI_NAMEREQD);
+
+ if (e == 0)
+ {
+ if (tools_debug)
+ {
+ fprintf(stderr, _("-05- <%s> <%s> <%s>\n"),
+ (p->ai_family == AF_INET) ? _("AF_INET") : _("AF_INET6"),
+ sh_ipvx_print_sockaddr (p->ai_addr, p->ai_family),
+ hostname);
+ }
+
+ if (sl_strcasecmp(hostname, canonical) == 0)
+ {
+ if (tools_debug)
+ fprintf(stderr, _("-06- <%s> <%s> match\n"),
+ hostname, canonical);
+ success = 1;
+ break;
+ }
+
+ }
+
+ p = p->ai_next;
+ }
+
+ if (success == 0)
+ {
+ sl_strlcpy(ecall, _("strcmp"), SH_MINIBUF);
+ sl_strlcpy(errmsg, _("Reverse lookup failed: "),
+ errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ fail = -1;
+ freeaddrinfo (ai);
+ }
+ }
+
+ if (fail != (-1))
+ {
+ struct addrinfo *p = ai;
+
+ while (p != NULL)
+ {
+ if ( (SOCK_STREAM == p->ai_socktype) &&
+ ((p->ai_family == AF_INET) || (p->ai_family == AF_INET6)) )
+ {
+
+ fd = socket(p->ai_family, SOCK_STREAM, 0);
+
+ if (fd != (-1))
+ {
+ if (retry_connect(FIL__, __LINE__, fd,
+ p->ai_addr, p->ai_addrlen) >= 0)
+ {
+ /* put it into the cache
+ */
+ check_cache = SH_ALLOC(sizeof(sin_cache));
+ check_cache->address = SH_ALLOC(sl_strlen(address) + 1);
+ sl_strlcpy (check_cache->address, address, sl_strlen(address) + 1);
+
+ sh_ipvx_save(&(check_cache->saddr), p->ai_family, p->ai_addr);
+
+ ++cached_addr;
+
+ if (conn_cache)
+ {
+ if (conn_cache->next)
+ check_cache->next = conn_cache->next;
+ else
+ check_cache->next = NULL;
+ conn_cache->next = check_cache;
+ }
+ else
+ {
+ check_cache->next = NULL;
+ conn_cache = check_cache;
+ }
+
+ freeaddrinfo (ai);
+ goto end;
+ }
+ status = errno;
+ sl_close_fd(FIL__, __LINE__, fd);
+ }
+ else
+ {
+ status = errno;
+ }
+ }
+ p = p->ai_next;
+ }
+ fail = (-1);
+ freeaddrinfo (ai);
+
+ sl_strlcpy(ecall, _("connect"), SH_MINIBUF);
+ *errnum = status;
+ sl_strlcpy(errmsg, sh_error_message (status, errbuf, sizeof(errbuf)), errsiz);
+ sl_strlcat(errmsg, _(", address "), errsiz);
+ sl_strlcat(errmsg, address, errsiz);
+ }
+ }
+
+ end:
+ retval = (fail < 0) ? (-1) : fd;
+ SL_RETURN(retval, _("connect_port"));
+
+}
+#endif
+
+int connect_port_2 (char * address1, char * address2, int port,
+ char * ecall, int * errnum, char * errmsg, int errsiz)
+{
+ int retval = (-1);
+
+ SL_ENTER(_("connect_port_2"));
+
+ errmsg[0] = '\0';
+ *errnum = 0;
+
+ if (address1 != NULL && address1[0] != '\0')
+ retval = connect_port (address1, port,
+ ecall, errnum,
+ errmsg, errsiz);
+
+ if (retval < 0 && address2 != NULL && address2[0] != '\0')
+ {
+ /* can't use sh_error_handle here, as this would cause an infinite
+ * loop if called from sh_unix_time
+ */
+ TPT(( 0, FIL__, __LINE__, _("msg=<Using alternative server %s.>\n"),
+ address2));
+ retval = connect_port (address2, port,
+ ecall, errnum,
+ errmsg, errsiz);
+ }
+
+ if ((retval < 0) &&
+ (address1 == NULL || address1[0] == '\0') &&
+ (address1 == NULL || address1[0] == '\0'))
+ {
+ sl_strlcpy(ecall, _("connect_port_2"), SH_MINIBUF);
+ sl_strlcpy(errmsg, _("No server address known"), errsiz);
+ }
+ SL_RETURN(retval, _("connect_port_2"));
+ /* return retval; */
+}
+
+#if defined(HAVE_NTIME) || defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+static
+int sh_write_select(int type, int sockfd,
+ char *buf, int nbytes,
+ int * w_error, int timeout)
+{
+ int countbytes, count;
+ fd_set fds;
+ struct timeval tv;
+ int select_now;
+ int num_sel;
+
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_write_select"));
+
+ FD_ZERO(&fds);
+ FD_SET(sockfd, &fds);
+
+ countbytes = 0;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ select_now = 0;
+
+ *w_error = 0;
+
+ while ( countbytes < nbytes ) {
+
+ FD_ZERO(&fds);
+ FD_SET(sockfd, &fds);
+
+ if (type == SH_DO_WRITE)
+ {
+ if ( (num_sel = select (sockfd+1, NULL, &fds, NULL, &tv)) == -1)
+ {
+ if (sig_raised == 1)
+ {
+ sig_raised = 2;
+ continue;
+ }
+ if ( errno == EINTR || errno == EINPROGRESS ) /* try again */
+ continue;
+ *w_error = errno;
+
+ sh_error_message(*w_error, errbuf, sizeof(errbuf));
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ errbuf,
+ _("sh_write_select (ws)") );
+ TPT(( 0, FIL__, __LINE__, _("msg=<select: %s>\n"), errbuf ));
+ SL_RETURN( countbytes, _("sh_write_select"));
+ }
+ }
+ else
+ {
+ if ( (num_sel = select (sockfd+1, &fds, NULL, NULL, &tv)) == -1)
+ {
+ if (sig_raised == 1)
+ {
+ sig_raised = 2;
+ continue;
+ }
+ if ( errno == EINTR || errno == EINPROGRESS ) /* try again */
+ continue;
+ *w_error = errno;
+
+ sh_error_message(*w_error, errbuf, sizeof(errbuf));
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ errbuf,
+ _("sh_write_select (rs)") );
+ TPT(( 0, FIL__, __LINE__, _("msg=<select: %s>\n"), errbuf ));
+ SL_RETURN( countbytes, _("sh_write_select"));
+ }
+ }
+
+ /* on Linux, timeout is modified to reflect the amount of
+ * time not slept
+ */
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+
+ /* let's not hang on forever
+ */
+ if (num_sel == 0)
+ {
+ ++select_now; /* timeout */
+ if ( select_now > timeout ) /* 5 minutes */
+ {
+#ifdef ETIMEDOUT
+ *w_error = ETIMEDOUT;
+#else
+ *w_error = 0;
+#endif
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Timeout>\n")));
+ SL_RETURN( countbytes, _("sh_write_select"));
+ }
+ }
+
+ if ( FD_ISSET (sockfd, &fds) )
+ {
+ if (type == SH_DO_WRITE)
+ count = write (sockfd, buf, nbytes-countbytes);
+ else
+ count = read (sockfd, buf, nbytes-countbytes);
+
+ if (count > 0)
+ {
+ countbytes += count;
+ buf += count; /* move buffer pointer forward */
+ if (countbytes < nbytes) FD_SET( sockfd, &fds );
+ }
+ else if (count < 0 && errno == EINTR)
+ {
+ FD_SET( sockfd, &fds );
+ }
+ else if (count < 0)
+ {
+ *w_error = errno;
+
+ sh_error_message(*w_error, errbuf, sizeof(errbuf));
+ sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, errno, MSG_E_SUBGEN,
+ errbuf,
+ (type == SH_DO_WRITE) ?
+ _("sh_write_select (w)") : _("sh_write_select (r)"));
+ TPT(( 0, FIL__, __LINE__, _("msg=<count < 0>\n")));
+ SL_RETURN( countbytes, _("sh_write_select"));
+ }
+ else /* count == 0 */
+ {
+ *w_error = errno;
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<count == 0>\n")));
+ SL_RETURN( countbytes, _("sh_write_select"));
+ }
+ }
+ }
+
+ *w_error = 0;
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<count = %d>\n"), countbytes));
+ SL_RETURN( countbytes, _("sh_write_select"));
+}
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+unsigned long write_port (int sockfd, char *buf, unsigned long nbytes,
+ int * w_error, int timeout)
+{
+ unsigned long bytes;
+
+ SL_ENTER(_("write_port"));
+
+ bytes = sh_write_select(SH_DO_WRITE, sockfd, buf, nbytes, w_error, timeout);
+ if (*w_error != 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ sh_error_handle((-1), FIL__, __LINE__, *w_error, MSG_TCP_NETRP,
+ sh_error_message (*w_error, errbuf, sizeof(errbuf)),
+ (long) sockfd, _("write_port"));
+ }
+ SL_RETURN( bytes, _("write_port"));
+}
+#endif
+
+#if defined(HAVE_NTIME) || defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+unsigned long read_port (int sockfd, char *buf, unsigned long nbytes,
+ int * w_error, int timeout)
+{
+ unsigned long bytes;
+
+ SL_ENTER(_("read_port"));
+
+ bytes = sh_write_select(SH_DO_READ, sockfd, buf, nbytes, w_error, timeout);
+ if (*w_error != 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ sh_error_handle((-1), FIL__, __LINE__, *w_error, MSG_TCP_NETRP,
+ sh_error_message (*w_error, errbuf, sizeof(errbuf)),
+ (long) sockfd, _("read_port"));
+ }
+ SL_RETURN( bytes, _("read_port"));
+}
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+int check_request_nerr (char * have, char * need)
+{
+ SL_ENTER(_("check_request_nerr"));
+ ASSERT_RET((have != NULL && need != NULL),
+ _("have != NULL && need != NULL"), (-1))
+
+ if ( (have[0] == need[0]) && (have[1] == need[1]) &&
+ (have[2] == need[2]) && (have[3] == need[3]))
+ SL_RETURN(0, _("check_request_nerr"));
+ SL_RETURN((-1), _("check_request_nerr"));
+}
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+int check_request (char * have, char * need)
+{
+ char first[21], second[5];
+ int i;
+
+ SL_ENTER(_("check_request"));
+ i = check_request_nerr (have, need);
+
+ if (i == 0)
+ SL_RETURN(0, _("check_request"));
+
+ for (i = 0; i < 4; ++i)
+ {
+ second[i] = need[i];
+ sprintf(&first[i*4], _("%c%03o"), /* known to fit */
+ '\\', (unsigned char) have[i]);
+ }
+
+ first[20] = '\0'; second[4] = '\0';
+
+ sh_error_handle((-1), FIL__, __LINE__, EINVAL, MSG_E_NETST,
+ second, first);
+ SL_RETURN((-1), _("check_request"));
+}
+#endif
+
+#if defined (SH_WITH_SERVER)
+
+int check_request_s (char * have, char * need, char * clt)
+{
+ char first[21], second[5];
+ int i;
+
+ SL_ENTER(_("check_request_s"));
+ i = check_request_nerr (have, need);
+
+ if (i == 0)
+ SL_RETURN( (0), _("check_request_s"));
+
+ for (i = 0; i < 4; ++i)
+ {
+ second[i] = need[i];
+ sprintf(&first[i*4], _("%c%03o"), /* known to fit */
+ '\\', (unsigned char) have[i]);
+ }
+ first[20] = '\0'; second[4] = '\0';
+ sh_error_handle((-1), FIL__, __LINE__, EINVAL, MSG_E_NETST1,
+ second, first, clt);
+ SL_RETURN( (-1), _("check_request_s"));
+}
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined (SH_WITH_SERVER)
+
+#if defined (SH_WITH_CLIENT)
+
+static int probe_done = S_FALSE;
+static unsigned char probe_flag = '\0';
+
+void sh_tools_probe_reset()
+{
+ probe_done = S_FALSE;
+ probe_flag = '\0';
+ return;
+}
+
+static int probe_ok(int flag)
+{
+ (void) flag;
+ if ((probe_flag & SH_PROTO_IVA) != 0)
+ return S_TRUE;
+ return S_FALSE;
+}
+
+static unsigned char probe_header_set(unsigned char protocol)
+{
+ if (probe_done || (protocol & SH_PROTO_SRP) == 0)
+ return 0;
+
+ return (char) SH_PROTO_IVA;
+}
+
+static void probe_header_get(unsigned char protocol)
+{
+ if (probe_done || (protocol & SH_PROTO_SRP) == 0)
+ return;
+
+ /* If the server doesn't know about it,
+ * it will simply mirror it back. */
+
+ if ((protocol & SH_PROTO_IVA) != 0)
+ {
+ /* probe was mirrored */;
+ }
+ else
+ {
+ /* probe was UNset */
+ probe_flag |= SH_PROTO_IVA;
+ }
+ probe_done = S_TRUE;
+ return;
+}
+
+#else
+static unsigned char probe_header_set(unsigned char protocol) {
+ (void) protocol; return 0; }
+static void probe_header_get(unsigned char protocol) {
+ (void) protocol; return; }
+void sh_tools_probe_reset() { return; }
+
+unsigned char sh_tools_probe_store(unsigned char protocol, int * probe_flag)
+{
+ if ((protocol & SH_PROTO_SRP) == 0)
+ return protocol;
+
+ if ((protocol & SH_PROTO_IVA) != 0)
+ {
+ /* probe received */
+ *probe_flag |= SH_PROTO_IVA;
+ protocol &= ~SH_PROTO_IVA;
+ }
+ return protocol;
+}
+
+static int probe_ok(int flag)
+{
+ if ((flag & SH_PROTO_IVA) != 0)
+ return S_TRUE;
+ return S_FALSE;
+}
+#endif
+
+
+void get_header (unsigned char * head, unsigned long * bytes, char * u)
+{
+ SL_ENTER(_("get_header"));
+
+ probe_header_get(head[0]);
+
+ *bytes =
+ (256 * (unsigned int)head[1] + (unsigned int)head[2]);
+
+ if (u != NULL)
+ {
+ u[0] = head[3];
+ u[1] = head[4];
+ u[2] = head[5];
+ u[3] = head[6];
+ u[4] = '\0';
+ }
+
+ SL_RET0(_("get_header"));
+}
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+#ifdef SH_ENCRYPT
+#define TRANS_BYTES 65120
+#else
+#define TRANS_BYTES 65280
+#endif
+
+void put_header (unsigned char * head, const int protocol,
+ unsigned long * length, char * u)
+{
+ unsigned char probe = probe_header_set(protocol);
+
+ /* static long transfer_limit = (8 * SH_BUFSIZE); V0.8 */
+ static unsigned long transfer_limit = TRANS_BYTES + 6 + KEY_LEN;
+
+ SL_ENTER(_("put_header"));
+
+ head[0] = protocol|probe;
+
+ ASSERT((*length < transfer_limit), _("*length < transfer_limit"))
+
+ if (*length > transfer_limit)
+ *length = transfer_limit;
+
+ head[1] = (unsigned int)(*length/256);
+ head[2] = (unsigned int)(*length-256 * head[1]);
+ if (u == NULL)
+ {
+ head[3] = 0x01;
+ head[4] = 0x01;
+ head[5] = 0x01;
+ head[6] = 0x01;
+ }
+ else
+ {
+ head[3] = u[0];
+ head[4] = u[1];
+ head[5] = u[2];
+ head[6] = u[3];
+ }
+
+ SL_RET0(_("put_header"));
+}
+
+/* ------------------------------------------
+ *
+ * version 2 client/server protocol
+ *
+ * ------------------------------------------
+ *
+ * header : flag size[2]
+ *
+ * payload: random_pad[8] protocol[4] size[4] payload[payload_size] padding
+ *
+ * full_size <= 8192; payload_size <= 8176 (511*16); msg_size <= 8128 (508*16)
+ * (msg_size = payload_size - key_len = payload_size - 48)
+ */
+
+/*
+ * only SH_V2_FULLSIZE is used, and only once
+ */
+
+#define SH_V2_FULLSIZE 1024
+
+#ifdef SH_ENCRYPT
+#include "rijndael-api-fst.h"
+#endif
+
+void sh_tools_show_header (unsigned char * head, char sign)
+{
+#define SH_IS_ASCII(c) (((c) & ~0x7f) == 0)
+
+
+ int msg_size = (256 * (unsigned int)head[1] + (unsigned int)head[2]);
+ char code[32];
+ char * p = &code[0];
+
+ memset (code, ' ', 32); /* space */
+
+ if ((head[0] & SH_PROTO_SRP) != 0) { p[0]='S';p[1]='R';p[2]='P';}
+ p += 4;
+ if ((head[0] & SH_PROTO_MSG) != 0) { p[0]='M';p[1]='S';p[2]='G';}
+ p += 4;
+ if ((head[0] & SH_PROTO_BIG) != 0) { p[0]='B';p[1]='I';p[2]='G';}
+ p += 4;
+ if ((head[0] & SH_PROTO_END) != 0) { p[0]='E';p[1]='N';p[2]='D';}
+ p += 4;
+ if ((head[0] & SH_PROTO_ENC) != 0) { p[0]='E';p[1]='N';p[2]='C';}
+ p += 4;
+ if ((head[0] & SH_PROTO_EN2) != 0) { p[0]='E';p[1]='N';p[2]='2';}
+ code[23] = '\0';
+
+ if (SH_IS_ASCII(head[3]) && isalpha(head[3]) &&
+ SH_IS_ASCII(head[4]) && isalpha(head[4]) &&
+ SH_IS_ASCII(head[5]) && isalpha(head[5]) &&
+ SH_IS_ASCII(head[6]) && isalpha(head[6])) {
+ fprintf(stderr, _("%c %3o %s %5d %c %c %c %c\n"), sign,
+ head[0], code, msg_size, head[3], head[4], head[5], head[6]);
+ } else {
+ fprintf(stderr, _("%c %3o %s %5d %2X %2X %2X %2X\n"), sign,
+ head[0], code, msg_size, head[3], head[4], head[5], head[6]);
+ }
+ return;
+}
+
+#ifdef SH_ENCRYPT
+
+/*
+ * #define DEBUG_EN2
+ *
+ * ingest version 1 7-byte header and payload, return version2 header/payload
+ * last 4 bytes of outgoing header are set to dummy value
+ */
+char * sh_tools_makePack (unsigned char * header, int flag,
+ char * payload, unsigned long payload_size,
+ keyInstance * keyInstE)
+{
+ BYTE inBlock[B_SIZ];
+ BYTE outBlock[B_SIZ];
+ char ivBlock[B_SIZ];
+
+ UINT32 rpad[3];
+ unsigned char head[16];
+ double epad;
+ unsigned long i_epad = 0;
+ unsigned long i_blk = payload_size / 16;
+ unsigned long i_blkmax = SH_V2_FULLSIZE / 16;
+ unsigned long pads = 0;
+ size_t full_size;
+ char * full_ret;
+
+ unsigned char * p;
+ int j;
+ cipherInstance cipherInst;
+ int err_num;
+ int blkfac;
+ int oflow = 0;
+ char expbuf[SH_ERRBUF_SIZE];
+
+ /*
+ SL_REQUIRE (i_blk*16 == payload_size, _("payload_size % 16 != 0"));
+ */
+ if ((i_blk * 16) != payload_size) ++i_blk;
+
+ /* random_pad
+ */
+ rpad[1] = taus_get ();
+ memcpy (head, &rpad[1], 4);
+ rpad[0] = taus_get ();
+ memcpy (&head[4], &rpad[0], 4);
+ rpad[2] = taus_get ();
+ memcpy (&head[8], &rpad[2], 4);
+
+ /* size (payload)
+ */
+ head[12] = header[1];
+ head[13] = header[2];
+ head[14] = '\0';
+ head[15] = '\0';
+
+ if (i_blk < i_blkmax)
+ {
+ pads = i_blkmax - i_blk;
+ epad = taus_get_double (&rpad);
+ i_epad = (unsigned long) (pads * epad);
+ }
+
+ full_size = 16; /* head */
+ if (sl_ok_muls(i_blk, 16) && sl_ok_adds(full_size, (i_blk*16)))
+ full_size = full_size + (i_blk*16); /* payload */
+ else
+ oflow = 1;
+ if (sl_ok_adds(full_size, (i_epad*16)))
+ full_size = full_size + (i_epad*16); /* pad */
+ else
+ i_epad = 0;
+
+ if (oflow)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("integer overflow"),
+ _("sh_tools_makePack"));
+ }
+
+ full_ret = SH_ALLOC(full_size);
+
+ memcpy(full_ret, head, 16);
+ if (payload != NULL && !oflow)
+ memcpy(&full_ret[16], payload, payload_size);
+
+ if ((i_blk*16) > payload_size && !oflow)
+ {
+ memset(&full_ret[16+payload_size], '\0', (i_blk*16) - payload_size);
+ payload_size = i_blk * 16;
+ }
+ memset(&full_ret[16+payload_size], '\0', i_epad*16);
+
+ /* rewrite header
+ */
+ header[1] = (unsigned int)(full_size/256);
+ header[2] = (unsigned int)(full_size - (256 * header[1]));
+
+ p = (unsigned char *) full_ret;
+ blkfac = full_size / B_SIZ;
+
+ err_num = rijndael_cipherInit (&cipherInst, MODE_CBC, NULL);
+
+ if (err_num < 0) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("sh_tools_makePack: rijndael_cipherInit")); }
+
+ if (probe_ok(flag)) {
+ memcpy(inBlock, p, B_SIZ);
+ err_num = rijndael_blockEncrypt(&cipherInst, keyInstE,
+ inBlock, 128, outBlock);
+ if (err_num >= 0) {
+ memcpy(p, outBlock, B_SIZ); p += B_SIZ;
+ memcpy(ivBlock, outBlock, sizeof(ivBlock));
+ err_num = rijndael_cipherInit (&cipherInst, MODE_CBC, ivBlock);
+ if (err_num >= 0) {
+ err_num = rijndael_blockEncrypt(&cipherInst, keyInstE,
+ p, 128*(blkfac-1), p);
+ }
+ }
+ }
+
+ else {
+ for (j = 0; j < blkfac; ++j) {
+ memcpy(inBlock, p, B_SIZ);
+ err_num = rijndael_blockEncrypt(&cipherInst, keyInstE,
+ inBlock, 128, outBlock);
+
+ if (err_num < 0) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("sh_tools_makePack: rijndael_blockEncrypt"));
+ break; }
+
+ memcpy(p, outBlock, B_SIZ);
+ p += B_SIZ;
+ }
+ }
+
+ return full_ret;
+}
+
+/* write a 7-byte header and return payload as expected by version 1
+ * last 4 bytes of incoming header are dummy
+ */
+char * sh_tools_revertPack (unsigned char * header, int flag, char * message,
+ keyInstance * keyInstD,
+ unsigned long message_size)
+{
+ BYTE inBlock[B_SIZ];
+ BYTE outBlock[B_SIZ];
+ char ivBlock[B_SIZ];
+ unsigned long msg_size;
+ char * msg_ret;
+
+ unsigned char * p;
+ int j;
+ cipherInstance cipherInst;
+ int err_num;
+ int blkfac;
+ char expbuf[SH_ERRBUF_SIZE];
+
+ msg_size = (256 * (unsigned int)header[1] + (unsigned int)header[2]);
+ if (msg_size > message_size)
+ msg_size = message_size;
+
+ p = (unsigned char *) message; blkfac = msg_size / 16;
+
+ err_num = rijndael_cipherInit (&cipherInst, MODE_CBC, NULL);
+
+ if (err_num < 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("sh_tools_revertPack: rijndael_cipherInit"));
+ }
+
+ if (probe_ok(flag)) {
+ memcpy(inBlock, p, B_SIZ);
+ err_num = rijndael_blockDecrypt(&cipherInst, keyInstD,
+ inBlock, 128, outBlock);
+ if (err_num >= 0) {
+ memcpy(p, outBlock, B_SIZ); p += B_SIZ;
+ memcpy(ivBlock, inBlock, sizeof(ivBlock));
+ err_num = rijndael_cipherInit (&cipherInst, MODE_CBC, ivBlock);
+ if (err_num >= 0) {
+ err_num = rijndael_blockDecrypt(&cipherInst, keyInstD,
+ p, 128*(blkfac-1), p);
+ }
+ }
+ }
+
+ else {
+ for (j = 0; j < blkfac; ++j) {
+ memcpy(inBlock, p, B_SIZ);
+ err_num = rijndael_blockDecrypt(&cipherInst, keyInstD,
+ inBlock, 128, outBlock);
+
+ if (err_num < 0) {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("sh_tools_revertPack: rijndael_blockDecrypt"));
+ break; }
+
+ memcpy(p, outBlock, B_SIZ);
+ p += B_SIZ;
+ }
+ }
+
+ /* rewrite size in header
+ */
+ header[1] = message[12];
+ header[2] = message[13];
+ msg_size = (256 * (unsigned int)header[1] + (unsigned int)header[2]);
+
+ if (msg_size > (message_size-16))
+ {
+ msg_size = message_size-16;
+ header[1] = (unsigned int)(msg_size/256);
+ header[2] = (unsigned int)(msg_size - (256 * header[1]));
+ }
+
+ /* payload
+ */
+ msg_ret = SH_ALLOC(msg_size+1);
+ if (msg_size > 0)
+ memcpy(msg_ret, &message[16], msg_size);
+ msg_ret[msg_size] = '\0';
+
+ SH_FREE(message);
+ return msg_ret;
+}
+#endif /* #ifdef SH_ENCRYPT */
+
+int sh_tools_hash_add(char * key, char * buf, int buflen)
+{
+ char * theSig;
+ char sigbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_tools_hash_add"));
+
+ theSig = sh_util_siggen (key, buf, buflen, sigbuf, sizeof(sigbuf));
+ sl_strlcat(buf, theSig, buflen + KEY_LEN + 1);
+
+ SL_RETURN((0), _("sh_tools_hash_add"));
+}
+
+
+/* return 0 (== FALSE) if no match, else 1 (== TRUE)
+ */
+int sh_tools_hash_vfy(char * key, char * buf, int buflen)
+{
+ char hash[KEY_LEN+1];
+ register int i;
+ char * theSig;
+ char sigbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_tools_hash_vfy"));
+
+ theSig = sh_util_siggen (key, buf, buflen, sigbuf, sizeof(sigbuf));
+ sl_strlcpy(hash, theSig, KEY_LEN+1);
+
+ for (i = 0; i < KEY_LEN; ++i)
+ {
+ if (buf[buflen + i] != hash[i])
+ SL_RETURN((0), _("sh_tools_hash_vfy"));
+ }
+
+ SL_RETURN((1), _("sh_tools_hash_vfy"));
+}
+
+#endif /* defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER) */
+
+
+/* ------------------------------------------ */
+
+#if defined (SH_WITH_SERVER)
+
+/* add a checksum to a buffer; put checksum in front
+ */
+char * hash_me (char * key, char * buf, int buflen)
+{
+ char hash[KEY_LEN+1];
+ char * temp = NULL;
+ register int i;
+ int total = 0;
+ char * theSig;
+ char sigbuf[KEYBUF_SIZE];
+
+
+ SL_ENTER(_("hash_me"));
+
+#ifdef DEBUG_EN2
+ fprintf(stderr, "hash_me <%s> <%d>\n",
+ (key == NULL) ? "NULL" : key, buflen);
+#endif
+ /* key = H(NSRV,NCLT,SK)
+ */
+ ASSERT_RET((key != NULL), _("key != NULL"), (NULL));
+ ASSERT_RET((buflen >= 0), _("buflen >= 0"), (NULL));
+
+ theSig = sh_util_siggen (key, buf, buflen, sigbuf, sizeof(sigbuf));
+ sl_strlcpy(hash, theSig, KEY_LEN+1);
+
+ if (sl_ok_adds(buflen, KEY_LEN))
+ {
+ total = KEY_LEN + buflen;
+ temp = SH_ALLOC (total);
+
+ for (i = 0; i < KEY_LEN; ++i)
+ temp[i] = hash[i];
+
+ for (i = 0; i < buflen; ++i)
+ temp[i+KEY_LEN] = buf[i];
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("integer overflow"),
+ _("hash_me"));
+ temp = sh_util_strdup(buf);
+ }
+ SL_RETURN(temp, _("hash_me"));
+}
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+/* verify the checksum of a buffer; checksum comes first
+ */
+int hash_check(char * key,
+ char * buf, int buflen)
+{
+ char hash[KEY_LEN+1];
+ register int i;
+ char * theSig;
+ char sigbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("hash_check"));
+
+#ifdef DEBUG_EN2
+ fprintf(stderr, "hash_check <%s> <%d>\n",
+ (key == NULL) ? "NULL" : key, buflen);
+#endif
+ theSig = sh_util_siggen (key, &buf[KEY_LEN], buflen-KEY_LEN,
+ sigbuf, sizeof(sigbuf));
+ sl_strlcpy(hash, theSig, KEY_LEN+1);
+
+ for (i = 0; i < KEY_LEN; ++i)
+ {
+ if (buf[i] != hash[i])
+ SL_RETURN((-1), _("hash_check"));
+ }
+ SL_RETURN((0), _("hash_check"));
+}
+
+#endif
+
+#if defined (SH_WITH_SERVER)
+
+char * get_client_conf_file (const char * peer, unsigned long * length)
+{
+ char * ret;
+ int status;
+ struct stat buf;
+ char * base;
+
+ SL_ENTER(_("get_client_conf_file"));
+
+ base = sh_util_strdup(DEFAULT_DATAROOT);
+ ret = sh_util_strconcat(base, _("/rc."), peer, NULL);
+ if (!ret)
+ { SH_FREE(base); *length = 0; SL_RETURN(NULL, _("get_client_conf_file")); }
+
+ status = retry_stat (FIL__, __LINE__, ret, &buf);
+ if (status == 0)
+ goto lab_end;
+ else
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_ACCESS,
+ (long) sh.effective.uid, ret);
+
+ SH_FREE(ret); ret = sh_util_strconcat(base, _("/rc"), NULL);
+ if (!ret)
+ { SH_FREE(base); *length = 0; SL_RETURN(NULL, _("get_client_conf_file")); }
+
+ status = retry_stat (FIL__, __LINE__, ret, &buf);
+ if (status == 0)
+ goto lab_end;
+ else
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_ACCESS,
+ (long) sh.effective.uid, ret);
+
+ SH_FREE(base); SH_FREE(ret); *length=0;
+ SL_RETURN(NULL, _("get_client_conf_file"));
+
+ lab_end:
+ if (buf.st_size > 0x7fffffff)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("File too large"), _("get_client_conf_file"));
+ SH_FREE(base); SH_FREE(ret); *length = 0;
+ SL_RETURN(NULL, _("get_client_conf_file"));
+ }
+
+ SH_FREE(base); *length = (unsigned long) buf.st_size;
+ SL_RETURN(ret, _("get_client_conf_file"));
+}
+
+char * get_client_data_file (const char * peer, unsigned long * length)
+{
+ char * ret;
+ int status;
+ struct stat buf;
+ char * base;
+
+ SL_ENTER(_("get_client_data_file"));
+
+ base = sh_util_strdup(DEFAULT_DATAROOT);
+ ret = sh_util_strconcat(base, _("/file."), peer, NULL);
+ if (!ret)
+ { SH_FREE(base); *length = 0; SL_RETURN(NULL, _("get_client_data_file")); }
+
+ status = retry_stat (FIL__, __LINE__, ret, &buf);
+ if (status == 0)
+ goto lab1_end;
+ else
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_ACCESS,
+ (long) sh.effective.uid, ret);
+
+ SH_FREE(ret);
+ ret = sh_util_strconcat(base, _("/file"), NULL);
+ if (!ret)
+ { SH_FREE(base); *length = 0; SL_RETURN(NULL, _("get_client_data_file")); }
+
+ status = retry_stat (FIL__, __LINE__, ret, &buf);
+ if (status == 0)
+ goto lab1_end;
+ else
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_ACCESS,
+ (long) sh.effective.uid, ret);
+
+ *length = 0; SH_FREE(base); SH_FREE(ret);
+ SL_RETURN(NULL, _("get_client_data_file"));
+
+ lab1_end:
+ if (buf.st_size > 0x7fffffff)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("File too large"), _("get_client_data_file"));
+ SH_FREE(base); SH_FREE(ret); *length = 0;
+ SL_RETURN(NULL, _("get_client_data_file"));
+ }
+
+ *length = (unsigned long) buf.st_size; SH_FREE(base);
+ SL_RETURN(ret, _("get_client_data_file"));
+}
+
+char * get_client_uuid_file (const char * peer, unsigned long * length, const char * uuid)
+{
+ char * ret;
+ int status;
+ struct stat buf;
+ char * base;
+
+ SL_ENTER(_("get_client_uuid_file"));
+
+ base = sh_util_strdup(DEFAULT_DATAROOT);
+ ret = sh_util_strconcat(base, _("/file."), peer, ".", uuid, NULL);
+ SH_FREE(base);
+ if (!ret)
+ { *length = 0; SL_RETURN(NULL, _("get_client_uuid_file")); }
+
+ status = retry_stat (FIL__, __LINE__, ret, &buf);
+ if (status != 0)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_ACCESS,
+ (long) sh.effective.uid, ret);
+ SH_FREE(ret); *length = 0;
+ SL_RETURN(NULL, _("get_client_uuid_file"));
+ }
+ else if (buf.st_size > 0x7fffffff)
+ {
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("File too large"), _("get_client_uuid_file"));
+ SH_FREE(ret); *length = 0;
+ SL_RETURN(NULL, _("get_client_data_file"));
+ }
+
+ *length = (unsigned long) buf.st_size;
+ SL_RETURN(ret, _("get_client_uuid_file"));
+}
+
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER) || defined(SH_STEALTH) || defined(WITH_GPG) || defined(WITH_PGP)
+
+/* --------- secure temporary file ------------ */
+
+SL_TICKET open_tmp ()
+{
+ SL_TICKET fd;
+ UINT32 ticks;
+ char * file;
+ struct stat buf;
+ int error;
+ int status = BAD;
+ char * my_tmp_dir;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("open_tmp"));
+
+#if defined(SH_TMPDIR)
+ my_tmp_dir = sh_util_strdup(SH_TMPDIR);
+#else
+#if defined(SH_WITH_SERVER)
+ my_tmp_dir = sh_util_strdup(DEFAULT_LOGDIR);
+#else
+ my_tmp_dir = sh_util_strdup(sh.effective.home);
+#endif
+#endif
+
+ if (0 != tf_trust_check (my_tmp_dir, SL_YESPRIV))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The directory for temporary files: %s is untrusted, i.e. an\nuntrusted user owns or can write to some directory in the path.\n"),
+ my_tmp_dir);
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_TRUST,
+ (long) sh.effective.uid,
+ my_tmp_dir);
+ SH_FREE(my_tmp_dir);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ do {
+
+ /* create random filename in effective users home directory
+ */
+ ticks = taus_get ();
+ if (my_tmp_dir[0] == '/' && my_tmp_dir[1] == '\0')
+ file = sh_util_strconcat (my_tmp_dir,
+ sh_tiger_hash( (char *) &ticks, TIGER_DATA, 4,
+ hashbuf, sizeof(hashbuf)),
+ NULL);
+ else
+ file = sh_util_strconcat (my_tmp_dir,
+ "/",
+ sh_tiger_hash( (char *) &ticks, TIGER_DATA, 4,
+ hashbuf, sizeof(hashbuf)),
+ NULL);
+
+ /* check whether it already exists (paranoia)
+ */
+ errno = 0;
+ status = retry_lstat(FIL__, __LINE__, file, &buf);
+ error = errno;
+
+ if ( (status < 0) && (error == ENOENT) ) /* file does not exist */
+ status = GOOD;
+ else if (status < 0) /* unexpected error condition */
+ {
+ SH_FREE (file);
+ SH_FREE(my_tmp_dir);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
+ _("Error (lstat) while opening temporary file"), _("open_tmp"));
+ TPT(( 0, FIL__, __LINE__, _("msg=<Unexpected error %d>\n"), error));
+ SL_RETURN((-1), _("open_tmp"));
+ }
+ else /* file exists */
+ {
+ status = BAD;
+ TPT(( 0, FIL__, __LINE__, _("msg=<Temporary file exists already>\n")));
+ }
+
+ if (status == GOOD)
+ {
+ if (0 == tf_trust_check (file, SL_YESPRIV))
+ status = GOOD;
+ else
+ {
+ status = BAD;
+ TPT(( 0, FIL__, __LINE__, _("msg=<Temporary file untrusted>\n")));
+ }
+ }
+
+ if (status == BAD)
+ SH_FREE (file);
+
+ } while (status == BAD);
+
+ fd = sl_open_safe_rdwr (FIL__, __LINE__, file, SL_YESPRIV);
+ if (SL_ISERROR(fd))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_SUBGEN,
+ _("Error opening temporary file"), _("open_tmp"));
+ TPT(( 0, FIL__, __LINE__, _("msg=<Error %d temporary file %s>\n"),
+ fd, file));
+ }
+
+ SH_FREE (file);
+ SH_FREE(my_tmp_dir);
+
+ if (!SL_ISERROR(fd)) {
+ sl_unlink(fd);
+ }
+
+ if (!SL_ISERROR(fd))
+ SL_RETURN((fd), _("open_tmp"));
+ else
+ SL_RETURN((-1), _("open_tmp"));
+}
+
+
+int close_tmp (SL_TICKET fd)
+{
+ SL_ENTER(_("close_tmp"));
+
+ if (SL_ISERROR(sl_close (fd)))
+ SL_RETURN((-1), _("close_tmp"));
+ SL_RETURN((0), _("close_tmp"));
+}
+
+int rewind_tmp (SL_TICKET fd)
+{
+ SL_ENTER(_("rewind_tmp"));
+
+ if (SL_ISERROR(sl_rewind (fd)))
+ SL_RETURN((-1), _("rewind_tmp"));
+ SL_RETURN((0), _("rewind_tmp"));
+}
+#endif
+
+/********************************************************
+ * Search rotated logfile
+ */
+#include <unistd.h>
+#include <libgen.h>
+#include <dirent.h>
+
+char * sh_rotated_log_search(const char * path, struct stat * buf)
+{
+
+ size_t size;
+ int i;
+ char * searchpath;
+ struct stat sbuf;
+ DIR * dp;
+ char * dname;
+ char * bname;
+
+ dname = sh_util_dirname(path);
+ bname = sh_util_basename(path);
+
+ size = strlen(dname) + strlen(bname) + 4;
+ searchpath = SH_ALLOC(size);
+
+ for (i = 0; i < 2; ++i)
+ {
+ snprintf(searchpath, size, "%s/%s.%1d", dname, bname, i);
+ if (0 == stat(searchpath, &sbuf) && sbuf.st_ino == buf->st_ino)
+ {
+ SH_FREE(dname);
+ SH_FREE(bname);
+ return searchpath;
+ }
+ }
+
+ SH_FREE(searchpath);
+
+ if (NULL != (dp = opendir(dname)))
+ {
+ struct dirent * de;
+
+ while (NULL != (de = readdir(dp)))
+ {
+ if (0 == strcmp(de->d_name, ".") || 0 == strcmp(de->d_name, ".."))
+ continue;
+
+ size = strlen(dname) + strlen(de->d_name) + 2;
+ searchpath = SH_ALLOC(size);
+ snprintf(searchpath, size, "%s/%s", dname, de->d_name);
+
+ if (0 == stat(searchpath, &sbuf) && sbuf.st_ino == buf->st_ino)
+ {
+ SH_FREE(dname);
+ SH_FREE(bname);
+ closedir(dp);
+ return searchpath;
+ }
+
+ SH_FREE(searchpath);
+ }
+ closedir(dp);
+ }
+
+ SH_FREE(dname);
+ SH_FREE(bname);
+
+ return NULL;
+}
+
diff --git a/src/sh_unix.c b/src/sh_unix.c
new file mode 100644
index 0000000..c383bef
--- /dev/null
+++ b/src/sh_unix.c
@@ -0,0 +1,5709 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <unistd.h>
+/* need to undef these, since the #define's may be picked up from
+ * linux/wait.h, and will clash with a typedef in sys/wait.h
+ */
+#undef P_ALL
+#undef P_PID
+#undef P_PGID
+#include <sys/wait.h>
+
+/*********************
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+**********************/
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_unix.h"
+#include "sh_utils.h"
+#include "sh_mem.h"
+#include "sh_hash.h"
+#include "sh_tools.h"
+#include "sh_restrict.h"
+#include "sh_ipvx.h"
+#include "sh_tiger.h"
+#include "sh_prelink.h"
+#include "sh_pthread.h"
+#include "sh_sem.h"
+
+/* moved here from far below
+ */
+#include <netdb.h>
+
+#define SH_NEED_PWD_GRP
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+#if defined(S_IFLNK) && !defined(S_ISLNK)
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#else
+#if !defined(S_ISLNK)
+#define S_ISLNK(mode) (0)
+#endif
+#endif
+
+#if defined(S_IFSOCK) && !defined(S_ISSOCK)
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#else
+#if !defined(S_ISSOCK)
+#define S_ISSOCK(mode) (0)
+#endif
+#endif
+
+#if defined(S_IFDOOR) && !defined(S_ISDOOR)
+#define S_ISDOOR(mode) (((mode) & S_IFMT) == S_IFDOOR)
+#else
+#if !defined(S_ISDOOR)
+#define S_ISDOOR(mode) (0)
+#endif
+#endif
+
+#if defined(S_IFPORT) && !defined(S_ISPORT)
+#define S_ISPORT(mode) (((mode) & S_IFMT) == S_IFPORT)
+#else
+#if !defined(S_ISPORT)
+#define S_ISPORT(mode) (0)
+#endif
+#endif
+
+#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
+
+#undef FIL__
+#define FIL__ _("sh_unix.c")
+
+unsigned long mask_PRELINK = MASK_PRELINK_;
+unsigned long mask_USER0 = MASK_USER_;
+unsigned long mask_USER1 = MASK_USER_;
+unsigned long mask_USER2 = MASK_USER_;
+unsigned long mask_USER3 = MASK_USER_;
+unsigned long mask_USER4 = MASK_USER_;
+unsigned long mask_ALLIGNORE = MASK_ALLIGNORE_;
+unsigned long mask_ATTRIBUTES = MASK_ATTRIBUTES_;
+unsigned long mask_LOGFILES = MASK_LOGFILES_;
+unsigned long mask_LOGGROW = MASK_LOGGROW_;
+unsigned long mask_READONLY = MASK_READONLY_;
+unsigned long mask_NOIGNORE = MASK_NOIGNORE_;
+
+
+extern char **environ;
+
+int sh_unix_maskreset()
+{
+ mask_PRELINK = MASK_PRELINK_;
+ mask_USER0 = MASK_USER_;
+ mask_USER1 = MASK_USER_;
+ mask_USER2 = MASK_USER_;
+ mask_USER3 = MASK_USER_;
+ mask_USER4 = MASK_USER_;
+ mask_ALLIGNORE = MASK_ALLIGNORE_;
+ mask_ATTRIBUTES = MASK_ATTRIBUTES_;
+ mask_LOGFILES = MASK_LOGFILES_;
+ mask_LOGGROW = MASK_LOGGROW_;
+ mask_READONLY = MASK_READONLY_;
+ mask_NOIGNORE = MASK_NOIGNORE_;
+ return 0;
+}
+
+
+#ifdef SYS_SIGLIST_DECLARED
+/* extern const char * const sys_siglist[]; */
+#else
+char * sh_unix_siglist (int signum)
+{
+ switch (signum)
+ {
+#ifdef SIGHUP
+ case SIGHUP:
+ return _("Hangup");
+#endif
+#ifdef SIGINT
+ case SIGINT:
+ return _("Interrupt");
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT:
+ return _("Quit");
+#endif
+#ifdef SIGILL
+ case SIGILL:
+ return _("Illegal instruction");
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP:
+ return _("Trace/breakpoint trap");
+#endif
+#ifdef SIGABRT
+ case SIGABRT:
+ return _("IOT trap/Abort");
+#endif
+#ifdef SIGBUS
+ case SIGBUS:
+ return _("Bus error");
+#endif
+#ifdef SIGFPE
+ case SIGFPE:
+ return _("Floating point exception");
+#endif
+#ifdef SIGUSR1
+ case SIGUSR1:
+ return _("User defined signal 1");
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV:
+ return _("Segmentation fault");
+#endif
+#ifdef SIGUSR2
+ case SIGUSR2:
+ return _("User defined signal 2");
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE:
+ return _("Broken pipe");
+#endif
+#ifdef SIGALRM
+ case SIGALRM:
+ return _("Alarm clock");
+#endif
+#ifdef SIGTERM
+ case SIGTERM:
+ return _("Terminated");
+#endif
+#ifdef SIGSTKFLT
+ case SIGSTKFLT:
+ return _("Stack fault");
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD:
+ return _("Child exited");
+#endif
+#ifdef SIGCONT
+ case SIGCONT:
+ return _("Continued");
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP:
+ return _("Stopped");
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP:
+ return _("Stop typed at tty");
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN:
+ return _("Stopped (tty input)");
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU:
+ return _("Stopped (tty output)");
+#endif
+#ifdef SIGURG
+ case SIGURG:
+ return _("Urgent condition");
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU:
+ return _("CPU time limit exceeded");
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ:
+ return _("File size limit exceeded");
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM:
+ return _("Virtual time alarm");
+#endif
+#ifdef SIGPROF
+ case SIGPROF:
+ return _("Profile signal");
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH:
+ return _("Window size changed");
+#endif
+#ifdef SIGIO
+ case SIGIO:
+ return _("Possible I/O");
+#endif
+#ifdef SIGPWR
+ case SIGPWR:
+ return _("Power failure");
+#endif
+#ifdef SIGUNUSED
+ case SIGUNUSED:
+ return _("Unused signal");
+#endif
+ }
+ return _("Unknown");
+}
+#endif
+
+
+/* Log from within a signal handler without using any
+ * functions that are not async signal safe.
+ *
+ * This is the safe_itoa helper function.
+ */
+char * safe_itoa(int i, char * str, int size)
+{
+ unsigned int u;
+ int iisneg = 0;
+ char *p = &str[size-1];
+
+ *p = '\0';
+ if (i < 0) {
+ iisneg = 1;
+ u = ((unsigned int)(-(1+i))) + 1;
+ } else {
+ u = i;
+ }
+ do {
+ --p;
+ *p = '0' + (u % 10);
+ u /= 10;
+ } while (u && (p != str));
+ if ((iisneg == 1) && (p != str)) {
+ --p;
+ *p = '-';
+ }
+ return p;
+}
+
+/* Log from within a signal handler without using any
+ * functions that are not async signal safe.
+ *
+ * This is the safe_logger function.
+ * Arguments: signal (signal number), method (0=logger, 1=stderr), thepid (pid)
+ */
+extern int OnlyStderr;
+
+int safe_logger (int thesignal, int method, char * details)
+{
+ unsigned int i = 0;
+ int status = -1;
+ struct stat buf;
+ pid_t newpid;
+ char str[128];
+ char * p;
+
+ char l0[64], l1[64], l2[64], l3[64];
+ char a0[32];
+ char e0[128];
+ char msg[128];
+
+ char * locations[] = { NULL, NULL, NULL, NULL, NULL };
+ char * envp[] = { NULL, NULL };
+ char * argp[] = { NULL, NULL, NULL };
+
+ pid_t thepid = getpid();
+
+ if ((sh.flag.isdaemon == S_FALSE) || (OnlyStderr == S_TRUE))
+ method = 1;
+
+ /* seems that solaris cc needs this way of initializing ...
+ */
+ locations[0] = l0;
+ locations[1] = l1;
+ locations[2] = l2;
+ locations[3] = l3;
+
+ envp[0] = e0;
+ argp[0] = a0;
+
+ sl_strlcpy(msg, _("samhain["), 128);
+ p = safe_itoa((int) thepid, str, 128);
+ if (p && *p)
+ sl_strlcat(msg, p, 128);
+ if (thesignal == 0)
+ {
+ if (details == NULL) {
+ sl_strlcat(msg, _("]: out of memory"), 128);
+ } else {
+ sl_strlcat(msg, _("]: "), 128);
+ sl_strlcat(msg, details, 128);
+ }
+ }
+ else
+ {
+ sl_strlcat(msg, _("]: exit on signal "), 128);
+ p = safe_itoa(thesignal, str, 128);
+ if (p && *p)
+ sl_strlcat(msg, p, 128);
+ }
+
+ if (method == 1) {
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+ int retval = 0;
+ do {
+ retval = write(STDERR_FILENO, msg, strlen(msg));
+ } while (retval < 0 && errno == EINTR);
+ do {
+ retval = write(STDERR_FILENO, "\n", 1);
+ } while (retval < 0 && errno == EINTR);
+ return 0;
+ }
+
+ sl_strlcpy (l0, _("/usr/bin/logger"), 64);
+ sl_strlcpy (l1, _("/usr/sbin/logger"), 64);
+ sl_strlcpy (l2, _("/usr/ucb/logger"), 64);
+ sl_strlcpy (l3, _("/bin/logger"), 64);
+
+ sl_strlcpy (a0, _("logger"), 32);
+ sl_strlcpy (e0,
+ _("PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/ucb:/usr/local/bin"),
+ 128);
+
+ while (locations[i] != NULL) {
+ status = stat(locations[i], &buf);
+ if (status == 0)
+ break;
+ ++i;
+ }
+
+ if (locations[i] != NULL) {
+ argp[1] = msg;
+ newpid = fork();
+ if (newpid == 0) {
+ execve(locations[i], argp, envp);
+ _exit(1);
+ }
+ else if (newpid > 0) {
+ waitpid(newpid, &status, WUNTRACED);
+ }
+ }
+ return 0;
+}
+
+void safe_fatal (const char * details,
+ const char * file, int line)
+{
+ char msg[128];
+ char str[128];
+ char * p;
+ int thesignal = 0;
+ int method = 0;
+
+ p = safe_itoa((int) line, str, 128);
+ sl_strlcpy(msg, _("FATAL: "), 128);
+ sl_strlcat(msg, file, 128);
+ sl_strlcat(msg, ": ", 128);
+ if (p && (*p)) {
+ sl_strlcat(msg, p , 128);
+ sl_strlcat(msg, ": ", 128);
+ }
+ sl_strlcat(msg, details, 128);
+ (void) safe_logger (thesignal, method, msg);
+
+ close_ipc ();
+ raise(SIGKILL);
+}
+
+extern char sh_sig_msg[64];
+
+volatile int immediate_exit_normal = 0;
+
+#if defined(SA_SIGACTION_WORKS)
+static
+void sh_unix_sigexit (int mysignal, siginfo_t * signal_info, void * signal_add)
+#else
+static
+void sh_unix_sigexit (int mysignal)
+#endif
+{
+
+#if defined(SA_SIGACTION_WORKS)
+ if (signal_info != NULL && signal_info->si_code == SI_USER &&
+ mysignal != SIGTERM && mysignal != SIGINT)
+ {
+ return;
+ }
+
+ /* avoid compiler warning (unused var)
+ */
+ (void) signal_add;
+#endif
+
+ /*
+ * Block re-entry
+ */
+ if (immediate_exit_normal > 0)
+ {
+ ++immediate_exit_normal;
+ if ((skey != NULL) && (immediate_exit_normal == 2))
+ memset (skey, '\0', sizeof(sh_key_t));
+ if (immediate_exit_normal == 2)
+ {
+ int val_return;
+
+ do {
+ val_return = chdir ("/");
+ } while (val_return < 0 && errno == EINTR);
+
+ close_ipc ();
+ safe_logger (mysignal, 0, NULL);
+ }
+ raise(SIGKILL);
+ }
+ else
+ {
+ immediate_exit_normal = 1;
+ }
+
+#ifdef SYS_SIGLIST_DECLARED
+ strncpy (sh_sig_msg, sys_siglist[mysignal], 40);
+#else
+ strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40);
+#endif
+ sh_sig_msg[63] = '\0';
+
+ ++sig_raised;
+ ++sig_urgent;
+ sig_termfast = 1;
+ return;
+}
+
+volatile int immediate_exit_fast = 0;
+
+#if defined(SA_SIGACTION_WORKS)
+static
+void sh_unix_sigexit_fast (int mysignal, siginfo_t * signal_info,
+ void * signal_add)
+#else
+static
+void sh_unix_sigexit_fast (int mysignal)
+#endif
+{
+#if defined(SL_DEBUG) && (defined(USE_SYSTEM_MALLOC) || !defined(USE_MALLOC_LOCK))
+ int retval;
+#endif
+
+#if defined(SA_SIGACTION_WORKS)
+ if (signal_info != NULL && signal_info->si_code == SI_USER)
+ {
+ return;
+ }
+#endif
+
+ /* avoid compiler warning (unused var)
+ */
+#if defined(SA_SIGACTION_WORKS)
+ (void) signal_add;
+#endif
+
+ /* Check whether the heap is ok; otherwise _exit
+ */
+#if !defined(SL_DEBUG) || (!defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK))
+ ++immediate_exit_fast;
+ if (skey != NULL && immediate_exit_fast < 2)
+ memset (skey, '\0', sizeof(sh_key_t));
+ if (immediate_exit_fast < 2)
+ safe_logger (mysignal, 0, NULL);
+ raise(SIGKILL);
+#else
+
+ /* debug code
+ */
+ if (immediate_exit_fast == 1)
+ {
+ ++immediate_exit_fast;
+ if (skey != NULL)
+ memset (skey, '\0', sizeof(sh_key_t));
+ close_ipc ();
+ safe_logger (mysignal, 0, NULL);
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+ raise(SIGFPE);
+ }
+ else if (immediate_exit_fast == 2)
+ {
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+ raise(SIGFPE);
+ }
+ else if (immediate_exit_fast != 0)
+ {
+ raise(SIGKILL);
+ }
+
+ ++immediate_exit_fast;
+
+ /* The FPE|BUS|SEGV|ILL signals leave the system in an undefined
+ * state, thus it is best to exit immediately.
+ */
+#ifdef SYS_SIGLIST_DECLARED
+ strncpy (sh_sig_msg, sys_siglist[mysignal], 40);
+#else
+ strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40);
+#endif
+ sh_sig_msg[63] = '\0';
+
+ sl_stack_print();
+
+ /* Try to push out an error message.
+ */
+ sh_error_handle ((-1), FIL__, __LINE__, mysignal, MSG_EXIT_NORMAL,
+ sh.prg_name, sh_sig_msg);
+
+ if (skey != NULL)
+ memset (skey, '\0', sizeof(sh_key_t));
+ close_ipc ();
+
+ do {
+ retval = chdir ("/");
+ } while (retval < 0 && errno == EINTR);
+
+ raise(SIGFPE);
+#endif
+}
+
+
+static
+void sh_unix_sigaction (int mysignal)
+{
+ ++sig_raised;
+#ifdef SIGUSR1
+ if (mysignal == SIGUSR1)
+ sig_debug_switch = 1;
+#endif
+#ifdef SIGUSR2
+ if (mysignal == SIGUSR2)
+ {
+ ++sig_suspend_switch;
+ ++sig_urgent;
+ }
+#endif
+#ifdef SIGHUP
+ if (mysignal == SIGHUP)
+ sig_config_read_again = 1;
+#endif
+#ifdef SIGTTOU
+ if (mysignal == SIGTTOU) {
+ sig_force_check = 1; sh_sem_trylock(); }
+#endif
+#ifdef SIGTSTP
+ if (mysignal == SIGTSTP) {
+ sig_force_check = 1; sig_force_silent = 1; sh_sem_trylock(); }
+#endif
+#ifdef SIGTTIN
+ if (mysignal == SIGTTIN)
+ sig_fresh_trail = 1;
+#endif
+#ifdef SIGABRT
+ if (mysignal == SIGABRT)
+ sig_fresh_trail = 1;
+#endif
+#ifdef SIGQUIT
+ if (mysignal == SIGQUIT)
+ sig_terminate = 1;
+#endif
+#ifdef SIGTERM
+ if (mysignal == SIGTERM)
+ {
+ strncpy (sh_sig_msg, _("Terminated"), 40);
+ sig_termfast = 1;
+ ++sig_urgent;
+ }
+#endif
+
+ return;
+}
+
+void sh_unix_ign_sigpipe()
+{
+ struct sigaction ignact;
+
+ ignact.sa_handler = SIG_IGN; /* signal action */
+ sigemptyset( &ignact.sa_mask ); /* set an empty mask */
+ ignact.sa_flags = 0; /* init sa_flags */
+
+#ifdef SIGPIPE
+ retry_sigaction(FIL__, __LINE__, SIGPIPE, &ignact, NULL);
+#endif
+
+ return;
+}
+static
+void sh_unix_siginstall (int goDaemon)
+{
+ struct sigaction act, act_fast, act2, oldact, ignact;
+#if defined (SH_WITH_SERVER)
+ (void) goDaemon;
+#endif
+
+ SL_ENTER(_("sh_unix_siginstall"));
+
+ ignact.sa_handler = SIG_IGN; /* signal action */
+ sigemptyset( &ignact.sa_mask ); /* set an empty mask */
+ ignact.sa_flags = 0; /* init sa_flags */
+
+#if defined(SA_SIGACTION_WORKS)
+ act.sa_sigaction = &sh_unix_sigexit; /* signal action */
+#else
+ act.sa_handler = &sh_unix_sigexit; /* signal action */
+#endif
+
+ sigfillset ( &act.sa_mask ); /* set a full mask */
+
+
+ /* Block all but deadly signals.
+ */
+#ifdef SIGILL
+ sigdelset ( &act.sa_mask, SIGILL );
+#endif
+#ifndef SL_DEBUG
+#ifdef SIGFPE
+ sigdelset ( &act.sa_mask, SIGFPE );
+#endif
+#endif
+#ifdef SIGSEGV
+ sigdelset ( &act.sa_mask, SIGSEGV );
+#endif
+#ifdef SIGBUS
+ sigdelset ( &act.sa_mask, SIGBUS );
+#endif
+
+#if defined(SA_SIGACTION_WORKS)
+ act_fast.sa_sigaction = &sh_unix_sigexit_fast; /* signal action */
+#else
+ act_fast.sa_handler = &sh_unix_sigexit_fast; /* signal action */
+#endif
+
+ sigfillset ( &act_fast.sa_mask ); /* set a full mask */
+
+#ifdef SIGILL
+ sigdelset ( &act_fast.sa_mask, SIGILL );
+#endif
+#ifndef SL_DEBUG
+#ifdef SIGFPE
+ sigdelset ( &act_fast.sa_mask, SIGFPE );
+#endif
+#endif
+#ifdef SIGSEGV
+ sigdelset ( &act_fast.sa_mask, SIGSEGV );
+#endif
+#ifdef SIGBUS
+ sigdelset ( &act_fast.sa_mask, SIGBUS );
+#endif
+
+
+ /* Use siginfo to verify origin of signal, if possible.
+ */
+#if defined(SA_SIGACTION_WORKS)
+ act.sa_flags = SA_SIGINFO;
+ act_fast.sa_flags = SA_SIGINFO;
+#else
+ act.sa_flags = 0;
+ act_fast.sa_flags = 0;
+#endif
+
+ /* Do not block the signal from being received in its handler ...
+ * (is this a good or a bad idea ??).
+ */
+#if defined(SA_NOMASK)
+ act_fast.sa_flags |= SA_NOMASK;
+#elif defined(SA_NODEFER)
+ act_fast.sa_flags |= SA_NODEFER;
+#endif
+
+
+ act2.sa_handler = &sh_unix_sigaction; /* signal action */
+ sigemptyset( &act2.sa_mask ); /* set an empty mask */
+ act2.sa_flags = 0; /* init sa_flags */
+
+ /* signals to control the daemon */
+
+#ifdef SIGHUP
+ retry_sigaction(FIL__, __LINE__, SIGHUP, &act2, &oldact);
+#endif
+#ifdef SIGABRT
+ retry_sigaction(FIL__, __LINE__, SIGABRT, &act2, &oldact);
+#endif
+#ifdef SIGUSR1
+ retry_sigaction(FIL__, __LINE__, SIGUSR1, &act2, &oldact);
+#endif
+#ifdef SIGUSR2
+ retry_sigaction(FIL__, __LINE__, SIGUSR2, &act2, &oldact);
+#endif
+#ifdef SIGQUIT
+ retry_sigaction(FIL__, __LINE__, SIGQUIT, &act2, &oldact);
+#endif
+#ifdef SIGTERM
+ retry_sigaction(FIL__, __LINE__, SIGTERM, &act, &oldact);
+#endif
+
+ /* fatal signals that may cause termination */
+
+#ifdef SIGILL
+ retry_sigaction(FIL__, __LINE__, SIGILL, &act_fast, &oldact);
+#endif
+#ifndef SL_DEBUG
+#ifdef SIGFPE
+ retry_sigaction(FIL__, __LINE__, SIGFPE, &act_fast, &oldact);
+#endif
+#endif
+#ifdef SIGSEGV
+ retry_sigaction(FIL__, __LINE__, SIGSEGV, &act_fast, &oldact);
+#endif
+#ifdef SIGBUS
+ retry_sigaction(FIL__, __LINE__, SIGBUS, &act_fast, &oldact);
+#endif
+
+ /* other signals */
+
+#ifdef SIGINT
+ retry_sigaction(FIL__, __LINE__, SIGINT, &act, &oldact);
+#endif
+#ifdef SIGPIPE
+ retry_sigaction(FIL__, __LINE__, SIGPIPE, &ignact, &oldact);
+#endif
+#ifdef SIGALRM
+ retry_sigaction(FIL__, __LINE__, SIGALRM, &ignact, &oldact);
+#endif
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+#ifdef SIGTTOU
+ if (goDaemon == 1)
+ retry_sigaction(FIL__, __LINE__, SIGTTOU, &act2, &oldact);
+ else
+ retry_sigaction(FIL__, __LINE__, SIGTTOU, &ignact, &oldact);
+#endif
+#ifdef SIGTSTP
+ if (goDaemon == 1)
+ retry_sigaction(FIL__, __LINE__, SIGTSTP, &act2, &oldact);
+ else
+ retry_sigaction(FIL__, __LINE__, SIGTSTP, &ignact, &oldact);
+#endif
+#ifdef SIGTTIN
+ if (goDaemon == 1)
+ retry_sigaction(FIL__, __LINE__, SIGTTIN, &act2, &oldact);
+ else
+ retry_sigaction(FIL__, __LINE__, SIGTTIN, &ignact, &oldact);
+#endif
+#else
+#ifdef SIGTSTP
+ retry_sigaction(FIL__, __LINE__, SIGTSTP, &ignact, &oldact);
+#endif
+#ifdef SIGTTOU
+ retry_sigaction(FIL__, __LINE__, SIGTTOU, &ignact, &oldact);
+#endif
+#ifdef SIGTTIN
+ retry_sigaction(FIL__, __LINE__, SIGTTIN, &ignact, &oldact);
+#endif
+#endif
+
+#ifdef SIGTRAP
+#if !defined(SCREW_IT_UP)
+ retry_sigaction(FIL__, __LINE__, SIGTRAP, &act, &oldact);
+#endif
+#endif
+
+#ifdef SIGPOLL
+ retry_sigaction(FIL__, __LINE__, SIGPOLL, &ignact, &oldact);
+#endif
+#if defined(SIGPROF) && !defined(SH_PROFILE)
+ retry_sigaction(FIL__, __LINE__, SIGPROF, &ignact, &oldact);
+#endif
+#ifdef SIGSYS
+ retry_sigaction(FIL__, __LINE__, SIGSYS, &act, &oldact);
+#endif
+#ifdef SIGURG
+ retry_sigaction(FIL__, __LINE__, SIGURG, &ignact, &oldact);
+#endif
+#if defined(SIGVTALRM) && !defined(SH_PROFILE)
+ retry_sigaction(FIL__, __LINE__, SIGVTALRM, &ignact, &oldact);
+#endif
+#ifdef SIGXCPU
+ retry_sigaction(FIL__, __LINE__, SIGXCPU, &act, &oldact);
+#endif
+#ifdef SIGXFSZ
+ retry_sigaction(FIL__, __LINE__, SIGXFSZ, &act, &oldact);
+#endif
+
+#ifdef SIGEMT
+ retry_sigaction(FIL__, __LINE__, SIGEMT, &ignact, &oldact);
+#endif
+#ifdef SIGSTKFLT
+ retry_sigaction(FIL__, __LINE__, SIGSTKFLT, &act, &oldact);
+#endif
+#ifdef SIGIO
+ retry_sigaction(FIL__, __LINE__, SIGIO, &ignact, &oldact);
+#endif
+#ifdef SIGPWR
+ retry_sigaction(FIL__, __LINE__, SIGPWR, &act, &oldact);
+#endif
+
+#ifdef SIGLOST
+ retry_sigaction(FIL__, __LINE__, SIGLOST, &ignact, &oldact);
+#endif
+#ifdef SIGUNUSED
+ retry_sigaction(FIL__, __LINE__, SIGUNUSED, &ignact, &oldact);
+#endif
+
+ SL_RET0(_("sh_unix_siginstall"));
+}
+
+/* ---------------------------------------------------------------- */
+
+/* checksum the own binary
+ */
+int sh_unix_self_hash (const char * c)
+{
+ char message[512];
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_unix_self_hash"));
+
+ if (c == NULL)
+ {
+ sh.exec.path[0] = '\0';
+ SL_RETURN((0), _("sh_unix_self_hash"));
+ }
+ sl_strlcpy(sh.exec.path, c, SH_PATHBUF);
+
+ sl_strlcpy(sh.exec.hash,
+ sh_tiger_hash (c, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ sl_snprintf(message, 512, _("%s has checksum: %s"),
+ sh.exec.path, sh.exec.hash);
+ message[511] = '\0';
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ message, _("sh_unix_self_hash"));
+ if (0 == sl_strcmp(sh.exec.hash, SH_KEY_NULL ))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Could not checksum my own executable because of the\nfollowing error: %s: %s\n\nPossible reasons include:\n Wrong path in configure file option SamhainPath=/path/to/executable\n No read permission for the effective UID: %d\n"),
+ sh.exec.path, sl_get_errmsg(), (int) sl_ret_euid());
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_NOACCESS,
+ (long) sh.real.uid, c);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ SL_RETURN((0), _("sh_unix_self_hash"));
+}
+
+int sh_unix_self_check ()
+{
+ char newhash[KEY_LEN+1];
+ char message[512];
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_unix_self_check"));
+ if (sh.exec.path[0] == '\0')
+ SL_RETURN((0), _("sh_unix_self_check"));
+
+ sl_strlcpy(newhash,
+ sh_tiger_hash (sh.exec.path, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ if (0 == sl_strncmp(sh.exec.hash, newhash, KEY_LEN))
+ {
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Checksum ok"), _("sh_unix_self_check"));
+ SL_RETURN((0), _("sh_unix_self_check"));
+ }
+
+ if (0 == sl_strncmp(SH_KEY_NULL, newhash, KEY_LEN))
+ {
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Could not read samhain executable"), _("sh_unix_self_check"));
+ SL_RETURN((0), _("sh_unix_self_check"));
+ }
+
+ dlog(1, FIL__, __LINE__,
+ _("The checksum of the executable: %s has changed since startup (%s -> %s).\n"),
+ sh.exec.path, sh.exec.hash, newhash);
+
+ sl_snprintf(message, 512,
+ _("The checksum of %s has changed since startup (%s -> %s)"),
+ sh.exec.path, sh.exec.hash, newhash);
+ message[511] = '\0';
+
+ sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ message, _("sh_unix_self_check"));
+ sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_E_AUTH,
+ sh.exec.path);
+ SL_RETURN((-1), _("sh_unix_self_check"));
+}
+
+
+/* ---------------------------------------------------------------- */
+
+long sh_group_to_gid (const char * g, int * fail)
+{
+ struct group * w;
+ gid_t gid = 0;
+ int status = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct group grp;
+ char * buffer;
+ static size_t gbufsize = SH_GRBUF_SIZE;
+#endif
+
+ *fail = -1;
+
+ if (g)
+ {
+ size_t i;
+ size_t len = strlen(g);
+
+ *fail = 0;
+
+ for (i = 0; i < len; ++i)
+ {
+ char c = g[i];
+
+ if (!isdigit((int) c))
+ goto is_a_name;
+ }
+ return atol(g);
+
+ is_a_name:
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+
+ buffer = SH_ALLOC(gbufsize);
+ status = sh_getgrnam_r(g, &grp, buffer, gbufsize, &w);
+
+ if ((status == ERANGE) && (w == NULL))
+ {
+ if (S_TRUE == sl_ok_adds( gbufsize, SH_GRBUF_SIZE ))
+ {
+ SH_FREE(buffer);
+ gbufsize += SH_GRBUF_SIZE;
+ goto is_a_name;
+ }
+ }
+
+#else
+
+ errno = 0;
+ w = sh_getgrnam(g);
+ status = errno;
+
+#endif
+
+ if ((status == ERANGE) && (w == NULL))
+ {
+ static int seen = 0;
+
+ if (seen == 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("sh_group_to_gid"), (long) -1, _("line too long in group entry"));
+ ++seen;
+ }
+ *fail = -1;
+ }
+ else if (w == NULL)
+ {
+ char * tmp = sh_util_strdup(g);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("sh_group_to_gid"), tmp);
+ SH_FREE(tmp);
+ *fail = -1;
+ }
+ else
+ {
+ gid = w->gr_gid;
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+
+ return gid;
+}
+
+/* ---------------------------------------------------------------- */
+
+
+/* added Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann */
+static int tf_add_trusted_user_int(const char * c)
+{
+ struct passwd * w;
+ int count;
+ uid_t pwid = (uid_t)-1;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+
+ SL_ENTER(_("tf_add_trusted_user_int"));
+
+ /* First check for a user name.
+ */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwnam_r(c, &pwd, buffer, SH_PWBUF_SIZE, &w);
+#else
+ w = sh_getpwnam(c);
+#endif
+
+ if ((w != NULL) && ((pwid = w->pw_uid) > 0))
+ goto succe;
+
+ /* Failed, so check for a numerical value.
+ */
+ pwid = strtol(c, (char **)NULL, 10);
+ if (pwid > 0 && pwid < 65535)
+ goto succe;
+
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("add trusted user"), c);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN((-1), _("tf_add_trusted_user_int"));
+
+ succe:
+ count = sl_trust_add_user(pwid);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN((count), _("tf_add_trusted_user_int"));
+}
+
+int tf_add_trusted_user(const char * c)
+{
+ int i;
+ char * q;
+ char * p = sh_util_strdup (c);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ char * saveptr;
+#endif
+
+ SL_ENTER(_("tf_add_trusted_user"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ q = strtok_r(p, ", \t", &saveptr);
+#else
+ q = strtok(p, ", \t");
+#endif
+ if (!q)
+ {
+ SH_FREE(p);
+ SL_RETURN((-1), _("tf_add_trusted_user"));
+ }
+ while (q)
+ {
+ i = tf_add_trusted_user_int(q);
+ if (SL_ISERROR(i))
+ {
+ SH_FREE(p);
+ SL_RETURN((i), _("tf_add_trusted_user"));
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
+ q = strtok_r(NULL, ", \t", &saveptr);
+#else
+ q = strtok(NULL, ", \t");
+#endif
+ }
+ SH_FREE(p);
+ SL_RETURN((0), _("tf_add_trusted_user"));
+}
+
+extern uid_t sl_trust_baduid(void);
+extern gid_t sl_trust_badgid(void);
+
+#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__)
+int tf_trust_check (const char * file, int mode)
+{
+ (void) file;
+ (void) mode;
+ return 0;
+}
+#else
+int tf_trust_check (const char * file, int mode)
+{
+ char * tmp;
+ char * tmp2;
+ char * p;
+ int status;
+ int level;
+ uid_t ff_euid = (uid_t) -1;
+
+ SL_ENTER(_("tf_trust_check"));
+
+ if (mode == SL_YESPRIV)
+ sl_get_euid(&ff_euid);
+ else
+ sl_get_ruid(&ff_euid);
+
+#if defined(SH_WITH_SERVER)
+ if (0 == sl_ret_euid()) /* privileges not dropped yet */
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ struct passwd * tempres;
+ sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
+#endif
+
+ if (!tempres)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("User %s does not exist. Please add the user to your system.\n"),
+ DEFAULT_IDENT);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ else
+ {
+ ff_euid = tempres->pw_uid;
+ }
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ SH_FREE(buffer);
+#endif
+ }
+#endif
+
+ status = sl_trustfile_euid(file, ff_euid);
+
+ if ( SL_ENONE != status)
+ {
+ if (status == SL_ESTAT)
+ level = SH_ERR_ALL;
+ else
+ level = SH_ERR_ERR;
+
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ if (p && *p != '\0')
+ {
+ tmp2 = sh_util_safe_name (sl_trust_errfile());
+ sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST2,
+ sl_error_string(status), tmp, tmp2);
+ SH_FREE(tmp2);
+ }
+ else
+ {
+ sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST1,
+ sl_error_string(status), tmp);
+ }
+ SH_FREE(tmp);
+
+ if (status == SL_EBADUID || status == SL_EBADGID ||
+ status == SL_EBADOTH || status == SL_ETRUNC ||
+ status == SL_EINTERNAL )
+ {
+ switch (status) {
+ case SL_EINTERNAL:
+ dlog(1, FIL__, __LINE__,
+ _("An internal error occured in the trustfile function.\n"));
+ break;
+ case SL_ETRUNC:
+ tmp = sh_util_safe_name (file);
+ dlog(1, FIL__, __LINE__,
+ _("A filename truncation occured in the trustfile function.\nProbably the normalized filename for %s\nis too long. This may be due e.g. to deep or circular softlinks.\n"),
+ tmp);
+ SH_FREE(tmp);
+ break;
+ case SL_EBADOTH:
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ dlog(1, FIL__, __LINE__,
+ _("The path element: %s\nin the filename: %s is world writeable.\n"),
+ p, tmp);
+ SH_FREE(tmp);
+ break;
+ case SL_EBADUID:
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ dlog(1, FIL__, __LINE__,
+ _("The owner (UID = %ld) of the path element: %s\nin the filename: %s\nis not in the list of trusted users.\nTo fix the problem, you can:\n - run ./configure again with the option --with-trusted=0,...,UID\n where UID is the UID of the untrusted user, or\n - use the option TrustedUser=UID in the configuration file.\n"),
+ (UID_CAST)sl_trust_baduid(), p, tmp);
+ SH_FREE(tmp);
+ break;
+ case SL_EBADGID:
+ tmp = sh_util_safe_name (file);
+ p = sl_trust_errfile();
+ dlog(1, FIL__, __LINE__,
+ _("The path element: %s\nin the filename: %s\nis group writeable (GID = %ld), and at least one of the group\nmembers (UID = %ld) is not in the list of trusted users.\nTo fix the problem, you can:\n - run ./configure again with the option --with-trusted=0,...,UID\n where UID is the UID of the untrusted user, or\n - use the option TrustedUser=UID in the configuration file.\n"),
+ p, tmp, (UID_CAST)sl_trust_badgid(),
+ (UID_CAST)sl_trust_baduid());
+ SH_FREE(tmp);
+ break;
+ default:
+ break;
+ }
+
+ SL_RETURN((-1), _("tf_trust_check"));
+ }
+ }
+
+ SL_RETURN((0), _("tf_trust_check"));
+}
+#endif
+
+#ifdef HAVE_INITGROUPS
+#ifdef HOST_IS_OSF
+int sh_unix_initgroups ( char * in_user, gid_t in_gid)
+#else
+int sh_unix_initgroups (const char * in_user, gid_t in_gid)
+#endif
+{
+ int status = -1;
+ status = sh_initgroups (in_user, in_gid);
+ if (status < 0)
+ {
+ if (errno == EPERM)
+ return 0;
+ if (errno == EINVAL)
+ return 0;
+ return -1;
+ }
+ return 0;
+}
+#else
+int sh_unix_initgroups (const char * in_user, gid_t in_gid)
+{
+ (void) in_user;
+ (void) in_gid;
+ return 0;
+}
+#endif
+
+#ifdef HAVE_INITGROUPS
+char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
+int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid)
+{
+ int status = -1;
+ char user[SH_MINIBUF];
+
+ SL_ENTER(_("sh_unix_initgroups2"));
+
+ if (NULL == sh_unix_getUIDname (SH_ERR_ERR, in_pid, user, sizeof(user)))
+ SL_RETURN((-1), _("sh_unix_initgroups2"));
+ status = sh_initgroups (user, in_gid);
+ if (status < 0)
+ {
+ if (errno == EPERM)
+ status = 0;
+ if (errno == EINVAL)
+ status = 0;
+ }
+ SL_RETURN((status), _("sh_unix_initgroups2"));
+}
+#else
+int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid)
+{
+ (void) in_pid;
+ (void) in_gid;
+ return 0;
+}
+#endif
+
+void sh_unix_closeall (int fd, int except, int inchild)
+{
+ int fdx = fd;
+#ifdef _SC_OPEN_MAX
+ int fdlimit = sysconf (_SC_OPEN_MAX);
+#else
+#ifdef OPEN_MAX
+ int fdlimit = OPEN_MAX;
+#else
+ int fdlimit = _POSIX_OPEN_MAX;
+#endif
+#endif
+
+ SL_ENTER(_("sh_unix_closeall"));
+
+ /* can't happen - so fix it :-(
+ */
+ if (fdlimit < 0)
+ fdlimit = 20; /* POSIX lower limit */
+
+ if (fdlimit > 65536)
+ fdlimit = 65536;
+
+ if (!inchild)
+ sl_dropall (fdx, except);
+ else
+ sl_dropall_dirty (fdx, except);
+
+ /* Close everything from fd (inclusive) up to fdlimit (exclusive).
+ */
+ while (fd < fdlimit)
+ {
+ if (fd == except)
+ fd++;
+ else if (slib_do_trace != 0 && fd == slib_trace_fd)
+ fd++;
+ else
+ sl_close_fd(FIL__, __LINE__, fd++);
+ }
+
+ SL_RET0(_("sh_unix_closeall"));
+}
+
+static void sh_unix_setlimits(void)
+{
+ struct rlimit limits;
+
+ SL_ENTER(_("sh_unix_setlimits"));
+
+ limits.rlim_cur = RLIM_INFINITY;
+ limits.rlim_max = RLIM_INFINITY;
+
+#ifdef RLIMIT_CPU
+ setrlimit (RLIMIT_CPU, &limits);
+#endif
+#ifdef RLIMIT_FSIZE
+ setrlimit (RLIMIT_FSIZE, &limits);
+#endif
+#ifdef RLIMIT_DATA
+ setrlimit (RLIMIT_DATA, &limits);
+#endif
+#ifdef RLIMIT_STACK
+ setrlimit (RLIMIT_STACK, &limits);
+#endif
+#ifdef RLIMIT_RSS
+ setrlimit (RLIMIT_RSS, &limits);
+#endif
+#ifdef RLIMIT_NPROC
+ setrlimit (RLIMIT_NPROC, &limits);
+#endif
+#ifdef RLIMIT_MEMLOCK
+ setrlimit (RLIMIT_MEMLOCK, &limits);
+#endif
+
+#if !defined(SL_DEBUG)
+ /* no core dumps
+ */
+ limits.rlim_cur = 0;
+ limits.rlim_max = 0;
+#ifdef RLIMIT_CORE
+ setrlimit (RLIMIT_CORE, &limits);
+#endif
+#else
+#ifdef RLIMIT_CORE
+ setrlimit (RLIMIT_CORE, &limits);
+#endif
+#endif
+
+ limits.rlim_cur = 1024;
+ limits.rlim_max = 1024;
+
+#if defined(RLIMIT_NOFILE)
+ setrlimit (RLIMIT_NOFILE, &limits);
+#elif defined(RLIMIT_OFILE)
+ setrlimit (RLIMIT_OFILE, &limits);
+#endif
+
+ SL_RET0(_("sh_unix_setlimits"));
+}
+
+static void sh_unix_copyenv(void)
+{
+ char ** env0 = environ;
+ char ** env1;
+ int envlen = 0;
+ size_t len;
+
+ SL_ENTER(_("sh_unix_copyenv"));
+
+ while (env0 != NULL && env0[envlen] != NULL) {
+ /* printf("%2d: %s\n", envlen, env0[envlen]); */
+ ++envlen;
+ }
+ ++envlen;
+
+ /* printf("-> %2d: slots allocated\n", envlen); */
+ env1 = calloc(1,sizeof(char *) * envlen); /* only once */
+ if (env1 == NULL)
+ {
+ fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
+ SL_RET0(_("sh_unix_copyenv"));
+ }
+ env0 = environ;
+ envlen = 0;
+
+ while (env0 != NULL && env0[envlen] != NULL) {
+ len = strlen(env0[envlen]) + 1;
+ env1[envlen] = calloc(1,len); /* only once */
+ if (env1[envlen] == NULL)
+ {
+ int i;
+ fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
+ for (i = 0; i < envlen; ++i) free(env1[len]);
+ free(env1);
+ SL_RET0(_("sh_unix_copyenv"));
+ }
+ sl_strlcpy(env1[envlen], env0[envlen], len);
+ ++envlen;
+ }
+ env1[envlen] = NULL;
+
+ environ = env1;
+ SL_RET0(_("sh_unix_copyenv"));
+}
+
+/* delete all environment variables
+ */
+static void sh_unix_zeroenv(void)
+{
+ char * c;
+ char ** env;
+
+ SL_ENTER(_("sh_unix_zeroenv"));
+
+ sh_unix_copyenv();
+ env = environ;
+
+ while (env != NULL && *env != NULL) {
+ c = strchr ((*env), '=');
+#ifdef WITH_MYSQL
+ /*
+ * Skip the MYSQL_UNIX_PORT environment variable; MySQL may need it.
+ */
+ if (0 == sl_strncmp((*env), _("MYSQL_UNIX_PORT="), 16))
+ {
+ ++(env);
+ continue;
+ }
+ if (0 == sl_strncmp((*env), _("MYSQL_TCP_PORT="), 15))
+ {
+ ++(env);
+ continue;
+ }
+ if (0 == sl_strncmp((*env), _("MYSQL_HOME="), 11))
+ {
+ ++(env);
+ continue;
+ }
+#endif
+#ifdef WITH_ORACLE
+ /*
+ * Skip the ORACLE_HOME and TNS_ADMIN environment variables;
+ * Oracle may need them.
+ */
+ if (0 == sl_strncmp((*env), _("ORACLE_HOME="), 12))
+ {
+ ++(env);
+ continue;
+ }
+ if (0 == sl_strncmp((*env), _("TNS_ADMIN="), 10))
+ {
+ ++(env);
+ continue;
+ }
+#endif
+ /*
+ * Skip the TZ environment variable.
+ */
+ if (0 == sl_strncmp((*env), _("TZ="), 3))
+ {
+ ++(env);
+ continue;
+ }
+ ++(env);
+ if (c != NULL)
+ {
+ ++c;
+ while ((*c) != '\0') {
+ (*c) = '\0';
+ ++c;
+ }
+ }
+ }
+
+#ifdef HAVE_TZSET
+ tzset();
+#endif
+
+ SL_RET0(_("sh_unix_zeroenv"));
+}
+
+
+static void sh_unix_resettimer(void)
+{
+ struct itimerval this_timer;
+
+ SL_ENTER(_("sh_unix_resettimer"));
+
+ this_timer.it_value.tv_sec = 0;
+ this_timer.it_value.tv_usec = 0;
+
+ this_timer.it_interval.tv_sec = 0;
+ this_timer.it_interval.tv_usec = 0;
+
+ setitimer(ITIMER_REAL, &this_timer, NULL);
+#if !defined(SH_PROFILE)
+ setitimer(ITIMER_VIRTUAL, &this_timer, NULL);
+ setitimer(ITIMER_PROF, &this_timer, NULL);
+#endif
+
+ SL_RET0(_("sh_unix_resettimer"));
+}
+
+static void sh_unix_resetsignals(void)
+{
+ int sig_num;
+#ifdef NSIG
+ int max_sig = NSIG;
+#else
+ int max_sig = 255;
+#endif
+ int test;
+ int status;
+ struct sigaction act;
+#if !defined(SH_PROFILE)
+ struct sigaction oldact;
+#endif
+
+ sigset_t set_proc;
+
+ SL_ENTER(_("sh_unix_resetsignals"));
+ /*
+ * Reset the current signal mask (inherited from parent process).
+ */
+
+ sigfillset(&set_proc);
+
+ do {
+ errno = 0;
+ test = SH_SETSIGMASK(SIG_UNBLOCK, &set_proc, NULL);
+ } while (test < 0 && errno == EINTR);
+
+ /*
+ * Reset signal handling.
+ */
+
+ act.sa_handler = SIG_DFL; /* signal action */
+ sigemptyset( &act.sa_mask ); /* set an empty mask */
+ act.sa_flags = 0; /* init sa_flags */
+
+ for (sig_num = 1; sig_num <= max_sig; ++sig_num)
+ {
+#if !defined(SH_PROFILE)
+ test = retry_sigaction(FIL__, __LINE__, sig_num, &act, &oldact);
+#else
+ test = 0;
+#endif
+ if ((test == -1) && (errno != EINVAL))
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ status = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_SIG,
+ sh_error_message (status, errbuf, sizeof(errbuf)), sig_num);
+ }
+ }
+
+ SL_RET0(_("sh_unix_resetsignals"));
+}
+
+/* Get the local hostname (FQDN)
+ */
+static char * sh_tolower (char * s)
+{
+ char * ret = s;
+ if (s)
+ {
+ for (; *s; ++s)
+ {
+ *s = tolower((unsigned char) *s);
+ }
+ }
+ return ret;
+}
+
+
+#include <sys/socket.h>
+
+/* Required for BSD
+ */
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <arpa/inet.h>
+
+const char * sh_unix_h_name (struct hostent * host_entry)
+{
+ char ** p;
+ if (strchr(host_entry->h_name, '.')) {
+ return host_entry->h_name;
+ } else {
+ for (p = host_entry->h_aliases; *p; ++p) {
+ if (strchr(*p, '.'))
+ return *p;
+ }
+ }
+ return host_entry->h_name;
+}
+
+/* uname() on FreeBSD is broken, because the 'nodename' buf is too small
+ * to hold a valid (leftmost) domain label.
+ */
+#if defined(HAVE_UNAME) && !defined(HOST_IS_FREEBSD)
+#include <sys/utsname.h>
+void sh_unix_localhost()
+{
+ struct utsname buf;
+ int i;
+ unsigned int ddot;
+ int len;
+ char * p;
+ char hostname[256];
+ char numeric[SH_IP_BUF];
+ char * canonical;
+
+
+ SL_ENTER(_("sh_unix_localhost"));
+
+ (void) uname (&buf);
+ /* flawfinder: ignore */ /* ff bug, ff sees system() */
+ sl_strlcpy (sh.host.system, buf.sysname, SH_MINIBUF);
+ sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF);
+ sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF);
+
+ /* Workaround for cases where nodename could be
+ * a truncated FQDN.
+ */
+ if (strlen(buf.nodename) == (sizeof(buf.nodename)-1))
+ {
+ p = strchr(buf.nodename, '.');
+ if (NULL != p) {
+ *p = '\0';
+ sl_strlcpy(hostname, buf.nodename, 256);
+ } else {
+#ifdef HAVE_GETHOSTNAME
+ if (0 != gethostname(hostname, 256))
+ {
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("nodename returned by uname may be truncated"),
+ _("sh_unix_localhost"));
+ sl_strlcpy (hostname, buf.nodename, 256);
+ }
+ else
+ {
+ hostname[255] = '\0';
+ }
+#else
+ sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("nodename returned by uname may be truncated"),
+ _("sh_unix_localhost"));
+ sl_strlcpy(hostname, buf.nodename, 256);
+#endif
+ }
+ }
+ else
+ {
+ sl_strlcpy(hostname, buf.nodename, 256);
+ }
+
+ canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric));
+
+ if (canonical == NULL)
+ {
+ sl_strlcpy (sh.host.name, hostname, SH_PATHBUF);
+ sh_tolower (sh.host.name);
+ }
+ else
+ {
+ sl_strlcpy (sh.host.name, canonical, SH_PATHBUF);
+ SH_FREE(canonical);
+ }
+
+ /* check whether it looks like a FQDN
+ */
+ len = sl_strlen(sh.host.name);
+ ddot = 0;
+ for (i = 0; i < len; ++i)
+ if (sh.host.name[i] == '.') ++ddot;
+
+ if (ddot == 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ sl_strlcpy (sh.host.name, numeric, SH_PATHBUF);
+ SL_RET0(_("sh_unix_localhost"));
+ }
+
+ if (sh_ipvx_is_numeric(sh.host.name))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ }
+
+ SL_RET0(_("sh_unix_localhost"));
+}
+
+#else
+
+/*
+ * --FreeBSD code
+ */
+#if defined(HAVE_UNAME)
+#include <sys/utsname.h>
+#endif
+void sh_unix_localhost()
+{
+#if defined(HAVE_UNAME)
+ struct utsname buf;
+#endif
+ int i;
+ int ddot;
+ int len;
+ char hostname[1024];
+ char numeric[SH_IP_BUF];
+ char * canonical;
+
+ SL_ENTER(_("sh_unix_localhost"));
+
+#if defined(HAVE_UNAME)
+ (void) uname (&buf);
+ /* flawfinder: ignore */ /* ff bug, ff sees system() */
+ sl_strlcpy (sh.host.system, buf.sysname, SH_MINIBUF);
+ sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF);
+ sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF);
+#endif
+
+ (void) gethostname (hostname, 1024);
+ hostname[1023] = '\0';
+
+ canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric));
+
+ if (canonical == NULL)
+ {
+ sl_strlcpy (sh.host.name, hostname, SH_PATHBUF);
+ sh_tolower (sh.host.name);
+ }
+ else
+ {
+ sl_strlcpy (sh.host.name, canonical, SH_PATHBUF);
+ SH_FREE(canonical);
+ }
+
+ /* check whether it looks like a FQDN
+ */
+ len = sl_strlen(sh.host.name);
+ ddot = 0;
+ for (i = 0; i < len; ++i)
+ if (sh.host.name[i] == '.') ++ddot;
+ if (ddot == 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ sl_strlcpy (sh.host.name, numeric, SH_PATHBUF);
+ SL_RET0(_("sh_unix_localhost"));
+ }
+
+ if (sh_ipvx_is_numeric(sh.host.name))
+ {
+ dlog(1, FIL__, __LINE__,
+ _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
+ hostname, sh.host.name);
+ }
+
+ SL_RET0(_("sh_unix_localhost"));
+}
+#endif
+
+
+void sh_unix_memlock()
+{
+ SL_ENTER(_("sh_unix_memlock"));
+
+ /* do this before dropping privileges
+ */
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ if (skey->mlock_failed == S_FALSE)
+ {
+ if ( (-1) == sh_unix_mlock( FIL__, __LINE__,
+ (char *) skey, sizeof (sh_key_t)) )
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ skey->mlock_failed = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+ }
+#else
+ if (skey->mlock_failed == S_FALSE)
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ skey->mlock_failed = S_TRUE;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ }
+#endif
+
+ SL_RET0(_("sh_unix_memlock"));
+}
+
+#ifdef SH_WITH_SERVER
+char * chroot_dir = NULL;
+
+int sh_unix_set_chroot(const char * str)
+{
+ size_t len;
+ static int block = 0;
+
+ if (block == 1)
+ return 0;
+
+ if (str && *str == '/')
+ {
+ len = strlen(str) + 1;
+ chroot_dir = calloc(1,strlen(str) + 1); /* only once */
+ if (!chroot_dir)
+ {
+ fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
+ return 1;
+ }
+ sl_strlcpy(chroot_dir, str, len);
+ block = 1;
+ return 0;
+ }
+ return 1;
+}
+
+int sh_unix_chroot(void)
+{
+ int status;
+
+ if (chroot_dir != NULL)
+ {
+ status = retry_aud_chdir(FIL__, __LINE__, chroot_dir);
+ if ( (-1) == status )
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ status = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR,
+ sh_error_message (status, errbuf, sizeof(errbuf)), chroot_dir);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ /* flawfinder: ignore */
+ return (chroot(chroot_dir));
+ }
+ return 0;
+}
+/* #ifdef SH_WITH_SERVER */
+#else
+int sh_unix_chroot(void) { return 0; }
+#endif
+
+/* daemon mode
+ */
+static int block_setdeamon = 0;
+
+int sh_unix_setdeamon(const char * dummy)
+{
+ int res = 0;
+
+ SL_ENTER(_("sh_unix_setdeamon"));
+
+ if (block_setdeamon != 0)
+ SL_RETURN((0),_("sh_unix_setdeamon"));
+
+ if (dummy == NULL)
+ sh.flag.isdaemon = S_TRUE;
+ else
+ res = sh_util_flagval (dummy, &sh.flag.isdaemon);
+
+ if (sh.flag.opts == S_TRUE)
+ block_setdeamon = 1;
+
+ SL_RETURN(res, _("sh_unix_setdeamon"));
+}
+#if defined(HAVE_LIBPRELUDE)
+#include "sh_prelude.h"
+#endif
+
+int sh_unix_setnodeamon(const char * dummy)
+{
+ int res = 0;
+
+ SL_ENTER(_("sh_unix_setnodeamon"));
+
+ if (block_setdeamon != 0)
+ SL_RETURN((0),_("sh_unix_setmodeamon"));
+
+ if (dummy == NULL)
+ sh.flag.isdaemon = S_FALSE;
+ else
+ res = sh_util_flagval (dummy, &sh.flag.isdaemon);
+
+ if (sh.flag.opts == S_TRUE)
+ block_setdeamon = 1;
+
+ SL_RETURN(res, _("sh_unix_setnodeamon"));
+}
+
+int sh_unix_init(int goDaemon)
+{
+ int status;
+ uid_t uid;
+ pid_t oldpid = getpid();
+#if defined(SH_WITH_SERVER)
+ extern int sh_socket_open_int (void);
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+
+ extern void sh_kill_sub();
+
+ SL_ENTER(_("sh_unix_init"));
+
+ /* fork twice, exit the parent process
+ */
+ if (goDaemon == 1) {
+
+ switch (aud_fork(FIL__, __LINE__)) {
+ case 0: break; /* child process continues */
+ case -1: SL_RETURN((-1),_("sh_unix_init")); /* error */
+ default: /* parent process exits */
+ sh_kill_sub();
+ aud__exit(FIL__, __LINE__, 0);
+ }
+
+ /* Child processes do not inherit page locks across a fork.
+ * Error in next fork would return in this (?) thread of execution.
+ */
+ sh_unix_memlock();
+
+ setsid(); /* should not fail */
+ sh.pid = (UINT64) getpid();
+
+ switch (aud_fork(FIL__, __LINE__)) {
+ case 0: break; /* child process continues */
+ case -1: SL_RETURN((-1),_("sh_unix_init")); /* error */
+ default: /* parent process exits */
+ sh_kill_sub();
+ aud__exit(FIL__, __LINE__, 0);
+ }
+
+ /* Child processes do not inherit page locks across a fork.
+ */
+ sh_unix_memlock();
+ sh.pid = (UINT64) getpid();
+
+ } else {
+ setsid(); /* should not fail */
+ }
+
+ /* set working directory
+ */
+#ifdef SH_PROFILE
+ status = 0;
+#else
+ status = retry_aud_chdir(FIL__, __LINE__, "/");
+#endif
+ if ( (-1) == status )
+ {
+ status = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR,
+ sh_error_message (status, errbuf, sizeof(errbuf)), "/");
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* reset timers
+ */
+ sh_unix_resettimer();
+
+ /* signal handlers
+ */
+ sh_unix_resetsignals();
+#if defined(SCREW_IT_UP)
+ sh_sigtrap_prepare();
+#endif
+ sh_unix_siginstall (goDaemon);
+
+ /* set file creation mask
+ */
+ (void) umask (0); /* should not fail */
+
+ /* set resource limits to maximum, and
+ * core dump size to zero
+ */
+ sh_unix_setlimits();
+
+ /* zero out the environment (like PATH='\0')
+ */
+ sh_unix_zeroenv();
+
+ if (goDaemon == 1)
+ {
+ /* Close first tree file descriptors
+ */
+ sl_close_fd (FIL__, __LINE__, 0); /* if running as daemon */
+ sl_close_fd (FIL__, __LINE__, 1); /* if running as daemon */
+ sl_close_fd (FIL__, __LINE__, 2); /* if running as daemon */
+
+ /* Enable full error logging
+ */
+ sh_error_only_stderr (S_FALSE);
+
+ /* open first three streams to /dev/null
+ */
+ status = aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 0);
+ if (status < 0)
+ {
+ status = errno;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ sh_error_message(status, errbuf, sizeof(errbuf)), _("open"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ status = retry_aud_dup(FIL__, __LINE__, 0);
+ if (status >= 0)
+ retry_aud_dup(FIL__, __LINE__, 0);
+
+ if (status < 0)
+ {
+ status = errno;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ sh_error_message(status, errbuf, sizeof(errbuf)), _("dup"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ sh_error_enable_unsafe (S_TRUE);
+#if defined(HAVE_LIBPRELUDE)
+ sh_prelude_reset ();
+#endif
+
+ /* --- wait until parent has exited ---
+ */
+ while (1 == 1)
+ {
+ errno = 0;
+ if (0 > aud_kill (FIL__, __LINE__, oldpid, 0) && errno == ESRCH)
+ {
+ break;
+ }
+ retry_msleep(0, 1);
+ }
+
+ /* write PID file
+ */
+ status = sh_unix_write_pid_file();
+ if (status < 0)
+ {
+ sl_get_euid(&uid);
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_PIDFILE,
+ (long) uid, sh.srvlog.alt);
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+#if defined(SH_WITH_SERVER)
+ sh_socket_open_int ();
+#endif
+ }
+ else
+ {
+ sh_error_enable_unsafe (S_TRUE);
+#if defined(HAVE_LIBPRELUDE)
+ sh_prelude_reset ();
+#endif
+#if defined(SH_WITH_SERVER)
+ sh_socket_open_int ();
+#endif
+ }
+
+ /* chroot (this is a no-op if no chroot dir is specified
+ */
+ status = sh_unix_chroot();
+ if (status < 0)
+ {
+ status = errno;
+ sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+ sh_error_message(status, errbuf, sizeof(errbuf)), _("chroot"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ /* drop capabilities
+ */
+ sl_drop_cap();
+
+ SL_RETURN((0),_("sh_unix_init"));
+}
+
+/* --- run a command, securely --- */
+
+int sh_unix_run_command (const char * str)
+{
+ pid_t pid;
+ char * arg[4];
+ char * env[5];
+ char * path = sh_util_strdup(_("/bin/sh"));
+
+ int status = -1;
+
+ arg[0] = sh_util_strdup(_("/bin/sh"));
+ arg[1] = sh_util_strdup(_("-c"));
+ arg[2] = sh_util_strdup(str);
+ arg[3] = NULL;
+
+ env[0] = sh_util_strdup(_("PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb"));
+ env[1] = sh_util_strdup(_("SHELL=/bin/sh"));
+ env[2] = sh_util_strdup(_("IFS= \t\n"));
+ if (getenv("TZ")) { /* flawfinder: ignore */
+ char * tz = sh_util_strdup(getenv("TZ")); /* flawfinder: ignore */
+ size_t tzlen = strlen(tz);
+ if (S_TRUE == sl_ok_adds (4, tzlen)) {
+ env[3] = SH_ALLOC(4+tzlen);
+ sl_strlcpy(env[3], "TZ=", 4);
+ sl_strlcat(env[3], tz , 4+tzlen);
+ } else {
+ env[3] = NULL;
+ }
+ } else {
+ env[3] = NULL;
+ }
+ env[4] = NULL;
+
+ pid = fork();
+
+ if (pid == (pid_t)(-1))
+ {
+ return -1;
+ }
+
+ else if (pid == 0) /* child */
+ {
+ memset(skey, 0, sizeof(sh_key_t));
+ (void) umask(S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
+ sh_unix_closeall (3, -1, S_TRUE); /* in child process */
+ execve(path, arg, env);
+ _exit(EXIT_FAILURE);
+ }
+
+ else /* parent */
+ {
+ int r;
+
+ while((r = waitpid(pid, &status, WUNTRACED)) != pid && r != -1) ;
+
+#if !defined(USE_UNO)
+ if (r == -1 || !WIFEXITED(status))
+ {
+ status = -1;
+ }
+ else
+ {
+ status = WEXITSTATUS(status);
+ }
+#endif
+ }
+
+ return status;
+}
+
+/********************************************************
+ *
+ * TIME
+ *
+ ********************************************************/
+
+/* Figure out the time offset of the current timezone
+ * in a portable way.
+ */
+char * t_zone(const time_t * xx)
+{
+ struct tm aa;
+ struct tm bb;
+
+ struct tm * aptr;
+ struct tm * bptr;
+
+ int sign = 0;
+ int diff = 0;
+ int hh, mm;
+ static char tz[64];
+
+ SL_ENTER(_("t_zone"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
+ aptr = gmtime_r (xx, &aa);
+#else
+ aptr = gmtime(xx);
+ if (aptr)
+ memcpy (&aa, aptr, sizeof(struct tm));
+#endif
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ bptr = localtime_r (xx, &bb);
+#else
+ bptr = localtime(xx);
+ if (bptr)
+ memcpy (&bb, bptr, sizeof(struct tm));
+#endif
+
+ if (bptr && aptr)
+ {
+ /* Check for datum wrap-around.
+ */
+ if ((aa.tm_mday == 1) && (aa.tm_mday < bb.tm_mday) && (aa.tm_hour < bb.tm_hour))
+ sign = ( 1);
+ else if (aa.tm_year < bb.tm_year)
+ sign = (-1);
+ else if (aa.tm_mon < bb.tm_mon)
+ sign = (-1);
+ else if (aa.tm_mday < bb.tm_mday)
+ sign = (-1);
+ else if (bb.tm_year < aa.tm_year)
+ sign = ( 1);
+ else if (bb.tm_mon < aa.tm_mon)
+ sign = ( 1);
+ else if (bb.tm_mday < aa.tm_mday)
+ sign = ( 1);
+
+ diff = aa.tm_hour * 60 + aa.tm_min;
+ diff = (bb.tm_hour * 60 + bb.tm_min) - diff;
+ diff = diff - (sign * 24 * 60); /* datum wrap-around correction */
+ hh = diff / 60;
+ mm = diff - (hh * 60);
+ sprintf (tz, _("%+03d%02d"), hh, mm); /* known to fit */
+ }
+ else
+ {
+ sprintf (tz, _("%+03d%02d"), 0, 0);
+ }
+ SL_RETURN(tz, _("t_zone"));
+}
+
+unsigned long sh_unix_longtime ()
+{
+ return ((unsigned long)time(NULL));
+}
+
+#ifdef HAVE_GETTIMEOFDAY
+unsigned long sh_unix_notime ()
+{
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+
+ return ((unsigned long)(tv.tv_sec + tv.tv_usec * 10835 + getpid() + getppid()));
+
+}
+#endif
+
+static int count_dev_time = 0;
+
+void reset_count_dev_time(void)
+{
+ count_dev_time = 0;
+ return;
+}
+
+int sh_unix_settimeserver (const char * address)
+{
+
+ SL_ENTER(_("sh_unix_settimeserver"));
+
+ if (address != NULL && count_dev_time < 2
+ && sl_strlen(address) < SH_PATHBUF)
+ {
+ if (count_dev_time == 0)
+ sl_strlcpy (sh.srvtime.name, address, SH_PATHBUF);
+ else
+ sl_strlcpy (sh.srvtime.alt, address, SH_PATHBUF);
+
+ ++count_dev_time;
+ SL_RETURN((0), _("sh_unix_settimeserver"));
+ }
+ SL_RETURN((-1), _("sh_unix_settimeserver"));
+}
+
+
+#ifdef HAVE_NTIME
+#define UNIXEPOCH 2208988800UL /* difference between Unix time and net time
+ * The UNIX EPOCH starts in 1970.
+ */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#endif
+
+/* Timeserver service. */
+/* define is missing on HP-UX 10.20 */
+#ifndef IPPORT_TIMESERVER
+#define IPPORT_TIMESERVER 37
+#endif
+
+char * sh_unix_time (time_t thetime, char * buffer, size_t len)
+{
+
+ int status;
+ char AsciiTime[81]; /* local time */
+ time_t time_now;
+ struct tm * time_ptr;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ struct tm time_tm;
+#endif
+#ifdef SH_USE_XML
+ static char deftime[] = N_("0000-00-00T00:00:00"); /* default time */
+#else
+ static char deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */
+#endif
+
+#ifdef HAVE_NTIME
+ int fd; /* network file descriptor */
+ u_char net_time[4]; /* remote time in network format */
+ static int failerr = 0; /* no net time */
+ int fail = 0; /* no net time */
+ int errflag;
+ char errmsg[256];
+ char error_call[SH_MINIBUF];
+ int error_num;
+#endif
+
+ SL_ENTER(_("sh_unix_time"));
+
+#ifdef HAVE_NTIME
+ if (thetime == 0)
+ {
+ if (sh.srvtime.name[0] == '\0')
+ {
+ fail = 1;
+ (void) time (&time_now);
+ }
+ else /* have a timeserver address */
+ {
+ /* don't call timeserver more than once per second */
+ static time_t time_old = 0;
+ time_t time_new;
+ static time_t time_saved = 0;
+ (void) time (&time_new);
+ if ((time_new == time_old) && (time_saved != 0))
+ {
+ time_now = time_saved;
+ goto end;
+ }
+ time_old = time_new;
+
+
+ fd = connect_port_2 (sh.srvtime.name, sh.srvtime.alt,
+ IPPORT_TIMESERVER,
+ error_call, &error_num, errmsg, sizeof(errmsg));
+ if (fd >= 0)
+ {
+ if (4 != read_port (fd, (char *) net_time, 4, &errflag, 2))
+ {
+ fail = 1;
+ sh_error_handle ((-1), FIL__, __LINE__, errflag,
+ MSG_E_NLOST,
+ _("time"), sh.srvtime.name);
+ }
+ sl_close_fd(FIL__, __LINE__, fd);
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, error_num,
+ MSG_E_NET, errmsg, error_call,
+ _("time"), sh.srvtime.name);
+ fail = 1;
+ }
+
+ if (fail == 0)
+ {
+ unsigned long ltmp;
+ UINT32 ttmp;
+ memcpy(&ttmp, net_time, sizeof(UINT32)); ltmp = ttmp;
+ time_now = ntohl(ltmp) - UNIXEPOCH;
+ time_saved = time_now;
+
+ if (failerr == 1) {
+ failerr = 0;
+ sh_error_handle ((-1), FIL__, __LINE__, 0,
+ MSG_E_NEST,
+ _("time"), sh.srvtime.name);
+ }
+ }
+ else
+ {
+ (void) time (&time_now);
+ time_saved = 0;
+
+ if (failerr == 0)
+ {
+ failerr = 1;
+ sh_error_handle ((-1), FIL__, __LINE__, errflag,
+ MSG_SRV_FAIL,
+ _("time"), sh.srvtime.name);
+ }
+ }
+ end:
+ ; /* 'label at end of compound statement' */
+ }
+ }
+ else
+ {
+ time_now = thetime;
+ }
+
+ /* #ifdef HAVE_NTIME */
+#else
+
+ if (thetime == 0)
+ {
+ (void) time (&time_now);
+ }
+ else
+ {
+ time_now = thetime;
+ }
+
+ /* #ifdef HAVE_NTIME */
+#endif
+
+ if (time_now == (-1) )
+ {
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN(buffer, _("sh_unix_time"));
+ }
+ else
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&time_now, &time_tm);
+#else
+ time_ptr = localtime (&time_now);
+#endif
+ }
+ if (time_ptr != NULL)
+ {
+ status = strftime (AsciiTime, sizeof(AsciiTime),
+#ifdef SH_USE_XML
+ _("%Y-%m-%dT%H:%M:%S%%s"),
+#else
+ _("[%Y-%m-%dT%H:%M:%S%%s]"),
+#endif
+ time_ptr);
+
+ sl_snprintf(buffer, len, AsciiTime, t_zone(&time_now));
+
+ if ( (status == 0) || (status == sizeof(AsciiTime)) )
+ {
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN( buffer, _("sh_unix_time"));
+ }
+ else
+ {
+ SL_RETURN(buffer, _("sh_unix_time"));
+ }
+ }
+
+ /* last resort
+ */
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN( buffer, _("sh_unix_time"));
+}
+
+static int sh_unix_use_localtime = S_FALSE;
+
+/* whether to use localtime for file timestamps in logs
+ */
+int sh_unix_uselocaltime (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_unix_uselocaltime"));
+ i = sh_util_flagval(c, &(sh_unix_use_localtime));
+
+ SL_RETURN(i, _("sh_unix_uselocaltime"));
+}
+
+char * sh_unix_gmttime (time_t thetime, char * buffer, size_t len)
+{
+
+ int status;
+
+ struct tm * time_ptr;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
+ struct tm time_tm;
+#endif
+ char AsciiTime[81]; /* GMT time */
+#ifdef SH_USE_XML
+ static char deftime[] = N_("0000-00-00T00:00:00"); /* default time */
+#else
+ static char deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */
+#endif
+
+ SL_ENTER(_("sh_unix_gmttime"));
+
+ if (sh_unix_use_localtime == S_FALSE)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
+ time_ptr = gmtime_r (&thetime, &time_tm);
+#else
+ time_ptr = gmtime (&thetime);
+#endif
+ }
+ else
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
+ time_ptr = localtime_r (&thetime, &time_tm);
+#else
+ time_ptr = localtime (&thetime);
+#endif
+ }
+ if (time_ptr != NULL)
+ {
+ status = strftime (AsciiTime, 80,
+#ifdef SH_USE_XML
+ _("%Y-%m-%dT%H:%M:%S"),
+#else
+ _("[%Y-%m-%dT%H:%M:%S]"),
+#endif
+ time_ptr);
+
+ if ( (status == 0) || (status == 80) )
+ sl_strlcpy(buffer, _(deftime), len);
+ else
+ sl_strlcpy(buffer, AsciiTime, len);
+ SL_RETURN( buffer, _("sh_unix_gmttime"));
+ }
+
+ /* last resort
+ */
+ sl_strlcpy(buffer, _(deftime), len);
+ SL_RETURN( buffer, _("sh_unix_gmttime"));
+}
+
+
+char * sh_unix_getUIDdir (int level, uid_t uid, char * out, size_t len)
+{
+ struct passwd * tempres;
+ int status = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_unix_getUIDdir"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ errno = 0;
+ tempres = sh_getpwuid(uid);
+ status = errno;
+#endif
+
+ if (tempres == NULL) {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("completely missing"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( NULL, _("sh_unix_getUIDdir"));
+ }
+
+ if (tempres->pw_dir != NULL) {
+ sl_strlcpy(out, tempres->pw_dir, len);
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( out, _("sh_unix_getUIDdir"));
+ } else {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("pw_dir"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( NULL, _("sh_unix_getUIDdir"));
+ }
+}
+
+/* ------------------- Caching ----------------*/
+#include "zAVLTree.h"
+
+#define CACHE_GID 0
+#define CACHE_UID 1
+
+struct user_id {
+ char * name;
+ uid_t id;
+ struct user_id * next;
+};
+
+static struct user_id * uid_list = NULL;
+static struct user_id * gid_list = NULL;
+
+SH_MUTEX_STATIC(mutex_cache, PTHREAD_MUTEX_INITIALIZER);
+
+static void sh_userid_free(struct user_id * item)
+{
+ while (item)
+ {
+ struct user_id * user = item;
+ item = item->next;
+
+ SH_FREE(user->name);
+ SH_FREE(user);
+ }
+ return;
+}
+
+void sh_userid_destroy ()
+{
+ struct user_id * tmp_uid;
+ struct user_id * tmp_gid;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_cache);
+ tmp_gid = gid_list;
+ gid_list = NULL;
+ tmp_uid = uid_list;
+ uid_list = NULL;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_cache);
+
+ sh_userid_free(tmp_uid);
+ sh_userid_free(tmp_gid);
+ return;
+}
+
+static void sh_userid_additem(struct user_id * list, struct user_id * item)
+{
+ if (list)
+ {
+ while (list && list->next)
+ list = list->next;
+ list->next = item;
+ }
+ return;
+}
+
+static void sh_userid_add(uid_t id, char * username, int which)
+{
+ size_t len;
+ struct user_id * user = SH_ALLOC(sizeof(struct user_id));
+
+ if (username)
+ len = strlen(username) + 1;
+ else
+ len = 1;
+
+ user->name = SH_ALLOC(len);
+ user->id = id;
+ if (username)
+ sl_strlcpy(user->name, username, len);
+ else
+ user->name[0] = '\0';
+ user->next = NULL;
+
+ SH_MUTEX_LOCK(mutex_cache);
+ if (which == CACHE_UID)
+ {
+ if (!uid_list)
+ uid_list = user;
+ else
+ sh_userid_additem(uid_list, user);
+ }
+ else
+ {
+ if (!gid_list)
+ gid_list = user;
+ else
+ sh_userid_additem(gid_list, user);
+ }
+ SH_MUTEX_UNLOCK(mutex_cache);
+
+ return;
+}
+
+static char * sh_userid_search(struct user_id * list, uid_t id)
+{
+ while (list)
+ {
+ if (list->id == id)
+ return list->name;
+ list = list->next;
+ }
+ return NULL;
+}
+
+static char * sh_userid_get (uid_t id, int which, char * out, size_t len)
+{
+ char * user = NULL;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_cache);
+ if (which == CACHE_UID)
+ user = sh_userid_search(uid_list, id);
+ else
+ user = sh_userid_search(gid_list, id);
+ if (user)
+ {
+ sl_strlcpy(out, user, len);
+ user = out;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_cache);
+
+ return user;
+}
+
+/* --------- end caching code --------- */
+
+char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len)
+{
+ struct passwd * tempres;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ struct passwd pwd;
+ char * buffer;
+#endif
+ int status = 0;
+ char errbuf[SH_ERRBUF_SIZE];
+ char * tmp;
+
+ SL_ENTER(_("sh_unix_getUIDname"));
+
+ tmp = sh_userid_get(uid, CACHE_UID, out, len);
+
+ if (tmp)
+ {
+ if (tmp[0] != '\0')
+ {
+ SL_RETURN( out, _("sh_unix_getUIDname"));
+ }
+ else
+ {
+ SL_RETURN( NULL, _("sh_unix_getUIDname"));
+ }
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ buffer = SH_ALLOC(SH_PWBUF_SIZE);
+ sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ errno = 0;
+ tempres = sh_getpwuid(uid);
+ status = errno;
+#endif
+
+ if (tempres == NULL)
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("completely missing"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ sh_userid_add(uid, NULL, CACHE_UID);
+ SL_RETURN( NULL, _("sh_unix_getUIDname"));
+ }
+
+
+ if (tempres->pw_name != NULL)
+ {
+
+ sl_strlcpy(out, tempres->pw_name, len);
+ sh_userid_add(uid, out, CACHE_UID);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN( out, _("sh_unix_getUIDname"));
+ }
+ else
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getpwuid"), (long) uid, _("pw_user"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+ SL_RETURN( NULL, _("sh_unix_getUIDname"));
+ }
+ /* notreached */
+}
+
+char * sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len)
+{
+ struct group * tempres;
+ int status = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ struct group grp;
+ char * buffer;
+#endif
+ char errbuf[SH_ERRBUF_SIZE];
+ char * tmp;
+
+ SL_ENTER(_("sh_unix_getGIDname"));
+
+ tmp = sh_userid_get((uid_t)gid, CACHE_GID, out, len);
+
+ if (tmp)
+ {
+ if (tmp[0] != '\0')
+ {
+ SL_RETURN( out, _("sh_unix_getGIDname"));
+ }
+ else
+ {
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ buffer = SH_ALLOC(SH_GRBUF_SIZE);
+ status = sh_getgrgid_r(gid, &grp, buffer, SH_GRBUF_SIZE, &tempres);
+#else
+ errno = 0;
+ tempres = sh_getgrgid(gid);
+ status = errno;
+#endif
+
+ if (status == ERANGE)
+ {
+ static int seen = 0;
+
+ if (seen == 0)
+ {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getgrgid"), (long) gid, _("line too long in group entry"));
+ ++seen;
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ sh_userid_add(gid, NULL, CACHE_GID);
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+
+ if (tempres == NULL)
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getgrgid"), (long) gid, _("completely missing"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ sh_userid_add(gid, NULL, CACHE_GID);
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+
+ if (tempres->gr_name != NULL)
+ {
+
+ sl_strlcpy(out, tempres->gr_name, len);
+ sh_userid_add((uid_t)gid, out, CACHE_GID);
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN( out, _("sh_unix_getGIDname"));
+ }
+ else
+ {
+ sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
+ sh_error_message(status, errbuf, sizeof(errbuf)),
+ _("getgrgid"), (long) gid, _("gr_name"));
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ SH_FREE(buffer);
+#endif
+
+ SL_RETURN( NULL, _("sh_unix_getGIDname"));
+ }
+ /* notreached */
+}
+
+int sh_unix_getUser ()
+{
+ char * p;
+ uid_t seuid, sruid;
+ char user[USER_MAX];
+ char dir[SH_PATHBUF];
+
+ SL_ENTER(_("sh_unix_getUser"));
+
+ seuid = geteuid();
+
+ sh.effective.uid = seuid;
+
+ p = sh_unix_getUIDdir (SH_ERR_ERR, seuid, dir, sizeof(dir));
+
+ if (p == NULL)
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ else
+ {
+ if (sl_strlen(p) >= SH_PATHBUF) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
+ _("getpwuid"), (long) seuid, _("pw_home"));
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ } else {
+ sl_strlcpy ( sh.effective.home, p, SH_PATHBUF);
+ }
+ }
+
+ sruid = getuid();
+
+ sh.real.uid = sruid;
+
+ p = sh_unix_getUIDname (SH_ERR_ERR, sruid, user, sizeof(user));
+ if (p == NULL)
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ else
+ {
+ if (sl_strlen(p) >= USER_MAX) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
+ _("getpwuid"), (long) sruid, _("pw_user"));
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ } else {
+ sl_strlcpy ( sh.real.user, p, USER_MAX);
+ }
+ }
+
+ p = sh_unix_getUIDdir (SH_ERR_ERR, sruid, dir, sizeof(dir));
+
+ if (p == NULL)
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ else
+ {
+ if (sl_strlen(p) >= SH_PATHBUF) {
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
+ _("getpwuid"), (long) sruid, _("pw_home"));
+ SL_RETURN((-1), _("sh_unix_getUser"));
+ } else {
+ sl_strlcpy ( sh.real.home, p, SH_PATHBUF);
+ }
+ }
+
+ SL_RETURN((0), _("sh_unix_getUser"));
+
+ /* notreached */
+}
+
+
+int sh_unix_getline (SL_TICKET fd, char * line, int sizeofline)
+{
+ register int count;
+ register int n = 0;
+ char c;
+
+ SL_ENTER(_("sh_unix_getline"));
+
+ if (sizeofline < 2) {
+ line[0] = '\0';
+ SL_RETURN((0), _("sh_unix_getline"));
+ }
+
+ --sizeofline;
+
+ while (n < sizeofline) {
+
+ count = sl_read (fd, &c, 1);
+
+ /* end of file
+ */
+ if (count < 1) {
+ line[n] = '\0';
+ n = -1;
+ break;
+ }
+
+ if (/* c != '\0' && */ c != '\n') {
+ line[n] = c;
+ ++n;
+ } else if (c == '\n') {
+ if (n > 0) {
+ line[n] = '\0';
+ break;
+ } else {
+ line[n] = '\n'; /* get newline only if only char on line */
+ ++n;
+ line[n] = '\0';
+ break;
+ }
+ } else {
+ line[n] = '\0';
+ break;
+ }
+
+ }
+
+
+ line[sizeofline] = '\0'; /* make sure line is terminated */
+ SL_RETURN((n), _("sh_unix_getline"));
+}
+
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+/**************************************************************
+ *
+ * --- FILE INFO ---
+ *
+ **************************************************************/
+
+#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS)
+
+#if defined(__linux__)
+
+/* --- Determine ext2fs file attributes. ---
+ */
+#include <sys/ioctl.h>
+#if defined(HAVE_EXT2FS_EXT2_FS_H)
+#include <ext2fs/ext2_fs.h>
+#else
+#include <linux/ext2_fs.h>
+#endif
+
+/* __linux__ includes */
+#endif
+
+static
+int sh_unix_getinfo_attr (char * name,
+ unsigned long * flags,
+ char * c_attr,
+ int fd, struct stat * buf)
+{
+
+/* TAKEN FROM:
+ *
+ * lsattr.c - List file attributes on an ext2 file system
+ *
+ * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr>
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * This file can be redistributed under the terms of the GNU General
+ * Public License
+ */
+
+#ifdef HAVE_STAT_FLAGS
+
+ SL_ENTER(_("sh_unix_getinfo_attr"));
+
+ *flags = 0;
+
+ /* cast to void to avoid compiler warning about unused parameters */
+ (void) fd;
+ (void) name;
+
+#ifdef UF_NODUMP
+ if (buf->st_flags & UF_NODUMP) {
+ *flags |= UF_NODUMP;
+ c_attr[0] = 'd';
+ }
+#endif
+#ifdef UF_IMMUTABLE
+ if (buf->st_flags & UF_IMMUTABLE) {
+ *flags |= UF_IMMUTABLE;
+ c_attr[1] = 'i';
+ }
+#endif
+#ifdef UF_APPEND
+ if (buf->st_flags & UF_APPEND) {
+ *flags |= UF_APPEND;
+ c_attr[2] = 'a';
+ }
+#endif
+#ifdef UF_NOUNLINK
+ if (buf->st_flags & UF_NOUNLINK) {
+ *flags |= UF_NOUNLINK;
+ c_attr[3] = 'u';
+ }
+#endif
+#ifdef UF_OPAQUE
+ if (buf->st_flags & UF_OPAQUE) {
+ *flags |= UF_OPAQUE;
+ c_attr[4] = 'o';
+ }
+#endif
+#ifdef SF_ARCHIVED
+ if (buf->st_flags & SF_ARCHIVED) {
+ *flags |= SF_ARCHIVED;
+ c_attr[5] = 'R';
+ }
+
+#endif
+#ifdef SF_IMMUTABLE
+ if (buf->st_flags & SF_IMMUTABLE) {
+ *flags |= SF_IMMUTABLE;
+ c_attr[6] = 'I';
+ }
+#endif
+#ifdef SF_APPEND
+ if (buf->st_flags & SF_APPEND) {
+ *flags |= SF_APPEND;
+ c_attr[7] = 'A';
+ }
+#endif
+#ifdef SF_NOUNLINK
+ if (buf->st_flags & SF_NOUNLINK) {
+ *flags |= SF_NOUNLINK;
+ c_attr[8] = 'U';
+ }
+#endif
+
+ /* ! HAVE_STAT_FLAGS */
+#else
+
+#ifdef HAVE_EXT2_IOCTLS
+ int /* fd, */ r, f;
+
+ SL_ENTER(_("sh_unix_getinfo_attr"));
+
+ *flags = 0;
+ (void) buf;
+
+ /* open() -> aud_open() R.Wichmann
+ fd = aud_open (FIL__, __LINE__, SL_YESPRIV, name, O_RDONLY|O_NONBLOCK, 0);
+ */
+
+ if (fd == -1 || name == NULL)
+ SL_RETURN(-1, _("sh_unix_getinfo_attr"));
+
+
+ r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);
+ /* sl_close_fd (FIL__, __LINE__, fd); */
+
+ if (r == -1)
+ SL_RETURN(-1, _("sh_unix_getinfo_attr"));
+
+ if (f == 0)
+ SL_RETURN(0, _("sh_unix_getinfo_attr"));
+
+ *flags = f;
+
+/* ! HAVE_EXT2_IOCTLS */
+#else
+
+ SL_ENTER(_("sh_unix_getinfo_attr"));
+
+ *flags = 0; /* modified by R.Wichmann */
+
+/* ! HAVE_EXT2_IOCTLS */
+#endif
+/*
+ * END
+ *
+ * lsattr.c - List file attributes on an ext2 file system
+ */
+
+ if (*flags == 0)
+ goto theend;
+
+#ifdef EXT2_SECRM_FL
+ if ( (*flags & EXT2_SECRM_FL) != 0 ) c_attr[0] = 's';
+#endif
+#ifdef EXT2_UNRM_FL
+ if ( (*flags & EXT2_UNRM_FL) != 0 ) c_attr[1] = 'u';
+#endif
+#ifdef EXT2_SYNC_FL
+ if ( (*flags & EXT2_SYNC_FL) != 0 ) c_attr[2] = 'S';
+#endif
+#ifdef EXT2_IMMUTABLE_FL
+ if ( (*flags & EXT2_IMMUTABLE_FL) != 0) c_attr[3] = 'i';
+#endif
+#ifdef EXT2_APPEND_FL
+ if ( (*flags & EXT2_APPEND_FL) != 0 ) c_attr[4] = 'a';
+#endif
+#ifdef EXT2_NODUMP_FL
+ if ( (*flags & EXT2_NODUMP_FL) != 0 ) c_attr[5] = 'd';
+#endif
+#ifdef EXT2_NOATIME_FL
+ if ( (*flags & EXT2_NOATIME_FL) != 0) c_attr[6] = 'A';
+#endif
+#ifdef EXT2_COMPR_FL
+ if ( (*flags & EXT2_COMPR_FL) != 0 ) c_attr[7] = 'c';
+#endif
+
+#ifdef EXT2_TOPDIR_FL
+ if ( (*flags & EXT2_TOPDIR_FL) != 0 ) c_attr[8] = 'T';
+#endif
+#ifdef EXT2_DIRSYNC_FL
+ if ( (*flags & EXT2_DIRSYNC_FL) != 0 ) c_attr[9] = 'D';
+#endif
+#ifdef EXT2_NOTAIL_FL
+ if ( (*flags & EXT2_NOTAIL_FL) != 0 ) c_attr[10] = 't';
+#endif
+#ifdef EXT2_JOURNAL_DATA_FL
+ if ( (*flags & EXT2_JOURNAL_DATA_FL) != 0) c_attr[11] = 'j';
+#endif
+
+ theend:
+ /* ext2 */
+#endif
+
+ c_attr[12] = '\0';
+
+ SL_RETURN(0, _("sh_unix_getinfo_attr"));
+}
+
+/* defined(__linux__) || defined(HAVE_STAT_FLAGS) */
+#endif
+
+/* determine file type
+ */
+static
+int sh_unix_getinfo_type (struct stat * buf,
+ ShFileType * type,
+ char * c_mode)
+{
+ SL_ENTER(_("sh_unix_getinfo_type"));
+
+ if ( S_ISREG(buf->st_mode) ) {
+ (*type) = SH_FILE_REGULAR;
+ c_mode[0] = '-';
+ }
+ else if ( S_ISLNK(buf->st_mode) ) {
+ (*type) = SH_FILE_SYMLINK;
+ c_mode[0] = 'l';
+ }
+ else if ( S_ISDIR(buf->st_mode) ) {
+ (*type) = SH_FILE_DIRECTORY;
+ c_mode[0] = 'd';
+ }
+ else if ( S_ISCHR(buf->st_mode) ) {
+ (*type) = SH_FILE_CDEV;
+ c_mode[0] = 'c';
+ }
+ else if ( S_ISBLK(buf->st_mode) ) {
+ (*type) = SH_FILE_BDEV;
+ c_mode[0] = 'b';
+ }
+ else if ( S_ISFIFO(buf->st_mode) ) {
+ (*type) = SH_FILE_FIFO;
+ c_mode[0] = '|';
+ }
+ else if ( S_ISSOCK(buf->st_mode) ) {
+ (*type) = SH_FILE_SOCKET;
+ c_mode[0] = 's';
+ }
+ else if ( S_ISDOOR(buf->st_mode) ) {
+ (*type) = SH_FILE_DOOR;
+ c_mode[0] = 'D';
+ }
+ else if ( S_ISPORT(buf->st_mode) ) {
+ (*type) = SH_FILE_PORT;
+ c_mode[0] = 'P';
+ }
+ else {
+ (*type) = SH_FILE_UNKNOWN;
+ c_mode[0] = '?';
+ }
+
+ SL_RETURN(0, _("sh_unix_getinfo_type"));
+}
+
+int sh_unix_get_ftype(char * fullpath)
+{
+ char c_mode[CMODE_SIZE];
+ struct stat buf;
+ ShFileType type;
+ int res;
+
+ SL_ENTER(_("sh_unix_get_ftype"));
+
+ res = retry_lstat(FIL__, __LINE__, fullpath, &buf);
+
+ if (res < 0)
+ SL_RETURN(SH_FILE_UNKNOWN, _("sh_unix_getinfo_type"));
+
+ sh_unix_getinfo_type (&buf, &type, c_mode);
+
+ SL_RETURN(type, _("sh_unix_get_ftype"));
+}
+
+
+static
+int sh_unix_getinfo_mode (struct stat *buf,
+ unsigned int * mode,
+ char * c_mode)
+{
+
+ SL_ENTER(_("sh_unix_getinfo_mode"));
+
+ (*mode) = buf->st_mode;
+
+ /* make 'ls'-like string */
+
+ if ( (buf->st_mode & S_IRUSR) != 0 ) c_mode[1] = 'r';
+ if ( (buf->st_mode & S_IWUSR) != 0 ) c_mode[2] = 'w';
+ if ( (buf->st_mode & S_IXUSR) != 0 ) {
+ if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 's';
+ else c_mode[3] = 'x';
+ } else {
+ if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 'S';
+ }
+
+ if ( (buf->st_mode & S_IRGRP) != 0 ) c_mode[4] = 'r';
+ if ( (buf->st_mode & S_IWGRP) != 0 ) c_mode[5] = 'w';
+ if ( (buf->st_mode & S_IXGRP) != 0 ) {
+ if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 's';
+ else c_mode[6] = 'x';
+ } else {
+ if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 'S';
+ }
+
+ if ( (buf->st_mode & S_IROTH) != 0 ) c_mode[7] = 'r';
+ if ( (buf->st_mode & S_IWOTH) != 0 ) c_mode[8] = 'w';
+#ifdef S_ISVTX /* not POSIX */
+ if ( (buf->st_mode & S_IXOTH) != 0 ) {
+ if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 't';
+ else c_mode[9] = 'x';
+ } else {
+ if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 'T';
+ }
+#else
+ if ( (buf->st_mode & S_IXOTH) != 0 ) c_mode[9] = 'x';
+#endif
+
+ SL_RETURN(0, _("sh_unix_getinfo_mode"));
+}
+
+
+long IO_Limit = 0;
+
+void sh_unix_io_pause ()
+{
+ long runtime;
+ float someval;
+ unsigned long sometime;
+
+ if (IO_Limit == 0)
+ {
+ return;
+ }
+ else
+ {
+ runtime = (long) (time(NULL) - sh.statistics.time_start);
+
+ if (runtime > 0 && (long)(sh.statistics.bytes_hashed/runtime) > IO_Limit)
+ {
+ someval = sh.statistics.bytes_hashed - (IO_Limit * runtime);
+ someval /= (float) IO_Limit;
+ if (someval < 1.0)
+ {
+ someval *= 1000; /* milliseconds in a second */
+ sometime = (unsigned long) someval;
+ retry_msleep(0, sometime);
+ }
+ else
+ {
+ sometime = (unsigned long) someval;
+ retry_msleep (sometime, 0);
+ }
+ }
+ }
+ return;
+}
+
+int sh_unix_set_io_limit (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_unix_set_io_limit"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val < 0)
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("set I/O limit"), c);
+
+ val = (val < 0 ? 0 : val);
+
+ IO_Limit = val * 1024;
+ SL_RETURN( 0, _("sh_unix_set_io_limit"));
+}
+
+/* obtain file info
+ */
+extern int flag_err_debug;
+
+#include "sh_ignore.h"
+
+int sh_unix_checksum_size (char * filename, off_t size, int is_max_size,
+ char * fileHash, int alert_timeout, SL_TICKET fd, unsigned long mask)
+{
+ file_type * tmpFile;
+ int status;
+
+ SL_ENTER(_("sh_unix_checksum_size"));
+
+ tmpFile = SH_ALLOC(sizeof(file_type));
+ tmpFile->link_path = NULL;
+
+ if (sh.flag.checkSum != SH_CHECK_INIT)
+ {
+ /* lookup file in database */
+ if (is_max_size == S_TRUE) {
+ status = sh_hash_get_it (filename, tmpFile, NULL);
+ if ((status != 0) || (tmpFile->size > size)) {
+ goto out;
+ }
+ } else {
+ tmpFile->size = size;
+ }
+ }
+ else
+ {
+ tmpFile->size = size;
+ }
+
+ /* if last <= current get checksum */
+ if (tmpFile->size <= size)
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 local_length = (UINT64) (tmpFile->size < 0 ? 0 : tmpFile->size);
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(mask);
+ sl_strlcpy(fileHash,
+ sh_tiger_generic_hash (filename, fd, &(local_length),
+ alert_timeout, hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ /* return */
+ if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
+ SH_FREE(tmpFile);
+ SL_RETURN( 0, _("sh_unix_checksum_size"));
+ }
+
+ out:
+ if (tmpFile->link_path) SH_FREE(tmpFile->link_path);
+ SH_FREE(tmpFile);
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ SL_RETURN( -1, _("sh_unix_checksum_size"));
+}
+
+/********************************************************
+ * Search rotated logfile
+ */
+extern char * sh_rotated_log_search(const char * path, struct stat * buf);
+
+int sh_check_rotated_log (const char * path,
+ UINT64 old_size, UINT64 old_inode, const char * old_hash, unsigned long mask)
+{
+ struct stat obuf;
+ UINT64 length_nolim = TIGER_NOLIM;
+ int retval = S_FALSE;
+
+ if (old_size != length_nolim)
+ {
+ char hashbuf[KEYBUF_SIZE];
+ char * rotated_file;
+
+ obuf.st_ino = old_inode;
+ rotated_file = sh_rotated_log_search(path, &obuf);
+
+ if (rotated_file && (0 != strcmp(path, rotated_file)))
+ {
+ SL_TICKET fd = sl_open_fastread (FIL__, __LINE__, rotated_file, SL_YESPRIV);
+ if (!SL_ISERROR(fd))
+ {
+ sh_unix_checksum_size (rotated_file, old_size, S_FALSE,
+ hashbuf, 120 /* alert_timeout */, fd, mask);
+
+ sl_close(fd);
+
+ if (strncmp (old_hash, hashbuf, KEY_LEN) == 0) {
+ retval = S_TRUE;
+ }
+ }
+ SH_FREE(rotated_file);
+ }
+ }
+ return retval;
+}
+
+
+int sh_unix_check_selinux = S_FALSE;
+int sh_unix_check_acl = S_FALSE;
+
+#ifdef USE_ACL
+
+#include <sys/acl.h>
+static char * sh_unix_getinfo_acl (char * path, int fd, struct stat * buf)
+{
+ /* system.posix_acl_access, system.posix_acl_default
+ */
+ char * out = NULL;
+ char * collect = NULL;
+ char * tmp;
+ char * out_compact;
+ ssize_t len;
+ acl_t result;
+
+ SL_ENTER(_("sh_unix_getinfo_acl"));
+
+ result = (fd == -1) ?
+ acl_get_file (path, ACL_TYPE_ACCESS) :
+ acl_get_fd (fd);
+
+ if (result)
+ {
+ out = acl_to_text (result, &len);
+ if (out && (len > 0)) {
+ out_compact = sh_util_acl_compact (out, len);
+ acl_free(out);
+ if (out_compact)
+ {
+ collect = sh_util_strconcat (_("acl_access:"), out_compact, NULL);
+ SH_FREE(out_compact);
+ }
+ }
+ acl_free(result);
+ }
+
+
+ if ( S_ISDIR(buf->st_mode) )
+ {
+ result = acl_get_file (path, ACL_TYPE_DEFAULT);
+
+ if (result)
+ {
+ out = acl_to_text (result, &len);
+ if (out && (len > 0)) {
+ out_compact = sh_util_acl_compact (out, len);
+ acl_free(out);
+ if (out_compact) {
+ if (collect) {
+ tmp = sh_util_strconcat (_("acl_default:"),
+ out_compact, ":", collect, NULL);
+ SH_FREE(collect);
+ }
+ else {
+ tmp = sh_util_strconcat (_("acl_default:"), out_compact, NULL);
+ }
+ SH_FREE(out_compact);
+ collect = tmp;
+ }
+ }
+ acl_free(result);
+ }
+ }
+
+ SL_RETURN((collect),_("sh_unix_getinfo_acl"));
+}
+#endif
+
+#ifdef USE_XATTR
+
+#include <attr/xattr.h>
+static char * sh_unix_getinfo_xattr_int (char * path, int fd, char * name)
+{
+ char * out = NULL;
+ char * tmp = NULL;
+ size_t size = 256;
+ ssize_t result;
+
+ SL_ENTER(_("sh_unix_getinfo_xattr_int"));
+
+ out = SH_ALLOC(size);
+
+ result = (fd == -1) ?
+ lgetxattr (path, name, out, size-1) :
+ fgetxattr (fd, name, out, size-1);
+
+ if (result == -1 && errno == ERANGE)
+ {
+ SH_FREE(out);
+ result = (fd == -1) ?
+ lgetxattr (path, name, NULL, 0) :
+ fgetxattr (fd, name, NULL, 0);
+ size = result + 1;
+ out = SH_ALLOC(size);
+ result = (fd == -1) ?
+ lgetxattr (path, name, out, size-1) :
+ fgetxattr (fd, name, out, size-1);
+ }
+
+ if ((result > 0) && ((size_t)result < size))
+ {
+ out[size-1] = '\0';
+ tmp = out;
+ }
+ else
+ {
+ SH_FREE(out);
+ }
+
+ SL_RETURN((tmp),_("sh_unix_getinfo_xattr_int"));
+}
+
+
+static char * sh_unix_getinfo_xattr (char * path, int fd, struct stat * buf)
+{
+ /* system.posix_acl_access, system.posix_acl_default, security.selinux
+ */
+ char * tmp;
+ char * out = NULL;
+ char * collect = NULL;
+
+ SL_ENTER(_("sh_unix_getinfo_xattr"));
+
+#ifdef USE_ACL
+ /*
+ * we need the acl_get_fd/acl_get_file functions, getxattr will only
+ * yield the raw bytes
+ */
+ if (sh_unix_check_acl == S_TRUE)
+ {
+ out = sh_unix_getinfo_acl(path, fd, buf);
+
+ if (out)
+ {
+ collect = out;
+ }
+ }
+#else
+ (void) buf;
+#endif
+
+ if (sh_unix_check_selinux == S_TRUE)
+ {
+ out = sh_unix_getinfo_xattr_int(path, fd, _("security.selinux"));
+
+ if (out)
+ {
+ if (collect) {
+ tmp = sh_util_strconcat(_("selinux:"), out, ":", collect, NULL);
+ SH_FREE(collect);
+ }
+ else {
+ tmp = sh_util_strconcat(_("selinux:"), out, NULL);
+ }
+ SH_FREE(out);
+ collect = tmp;
+ }
+ }
+
+ SL_RETURN((collect),_("sh_unix_getinfo_xattr"));
+}
+#endif
+
+#ifdef USE_XATTR
+int sh_unix_setcheckselinux (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_unix_setcheckselinux"));
+ i = sh_util_flagval(c, &(sh_unix_check_selinux));
+
+ SL_RETURN(i, _("sh_unix_setcheckselinux"));
+}
+#endif
+
+#ifdef USE_ACL
+int sh_unix_setcheckacl (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_unix_setcheckacl"));
+ i = sh_util_flagval(c, &(sh_unix_check_acl));
+
+ SL_RETURN(i, _("sh_unix_setcheckacl"));
+}
+#endif
+
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+
+static void * sh_dummy_filename;
+static void * sh_dummy_tmp;
+static void * sh_dummy_tmp2;
+
+int sh_unix_getinfo (int level, const char * filename, file_type * theFile,
+ char * fileHash, int policy)
+{
+ char timestr[81];
+ long runtim;
+ struct stat buf;
+ struct stat lbuf;
+ struct stat fbuf;
+ volatile int stat_return;
+ volatile int stat_errno = 0;
+
+ ShFileType type;
+ unsigned int mode;
+ char * tmp;
+ char * tmp2;
+
+ char * linknamebuf;
+ volatile int linksize;
+
+ extern int get_the_fd (SL_TICKET ticket);
+
+ volatile SL_TICKET rval_open;
+ volatile int err_open = 0;
+
+ volatile int fd;
+ volatile int fstat_return;
+ volatile int fstat_errno = 0;
+ volatile int try = 0;
+
+ sh_string * content = NULL;
+
+ time_t tend;
+ time_t tstart;
+
+
+ char * path = NULL;
+
+ volatile int alert_timeout = 120;
+
+ path = theFile->fullpath;
+
+ SL_ENTER(_("sh_unix_getinfo"));
+
+ if (!MODI_INITIALIZED(theFile->check_flags))
+ {
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
+ _("Uninitialized check mask"), _("sh_unix_getinfo"),
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ SL_RETURN((-1),_("sh_unix_getinfo"));
+ }
+
+ /* Take the address to keep gcc from putting it into a register.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_filename = (void *) &filename;
+ sh_dummy_tmp = (void *) &tmp;
+ sh_dummy_tmp2 = (void *) &tmp2;
+
+ /* --- Stat the file, and get checksum. ---
+ */
+ tstart = time(NULL);
+
+ stat_return = retry_lstat (FIL__, __LINE__,
+ path /* theFile->fullpath */, &buf);
+
+ if (stat_return)
+ stat_errno = errno;
+
+ theFile->link_path = NULL;
+
+ try_again:
+
+ fd = -1;
+ fstat_return = -1;
+ rval_open = -1;
+
+ if (stat_return == 0 && S_ISREG(buf.st_mode))
+ {
+ rval_open = sl_open_fastread (FIL__, __LINE__,
+ path /* theFile->fullpath */, SL_YESPRIV);
+ if (SL_ISERROR(rval_open))
+ {
+ char * stale = sl_check_stale();
+
+ if (stale)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, err_open, MSG_E_SUBGEN,
+ stale, _("sh_unix_getinfo_open"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (errno == EBADF && try == 0) /* obsolete, but we keep this, just in case */
+ {
+ ++try;
+ goto try_again;
+ }
+ err_open = errno;
+ }
+
+ alert_timeout = 120; /* this is per 8K block now ! */
+
+ if (path[1] == 'p' && path[5] == '/' && path[2] == 'r' &&
+ path[3] == 'o' && path[4] == 'c' && path[0] == '/')
+ {
+ /* seven is magic */
+ alert_timeout = 7;
+ }
+
+ fd = get_the_fd(rval_open);
+ }
+
+ tend = time(NULL);
+
+ /* An unprivileged user may slow lstat/open to a crawl
+ * with clever path/symlink setup
+ */
+ if ((tend - tstart) > (time_t) /* 60 */ 6)
+ {
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_TOOLATE,
+ (long)(tend - tstart), tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ }
+
+ if (fd >= 0)
+ {
+ fstat_return = retry_fstat (FIL__, __LINE__, fd, &fbuf);
+
+ if (fstat_return)
+ {
+ char * stale;
+
+ fstat_errno = errno;
+
+ stale = sl_check_stale();
+
+ if (stale)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, fstat_errno,
+ MSG_E_SUBGEN,
+ stale, _("sh_unix_getinfo_fstat"));
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ if (try == 0) /* obsolete, but we keep this, just in case */
+ {
+ ++try;
+ sl_close(rval_open);
+ goto try_again;
+ }
+ }
+ }
+ else
+ {
+ fd = -1;
+ }
+
+
+ /* --- case 1: lstat failed ---
+ */
+ if (stat_return != 0)
+ {
+ stat_return = errno;
+ if (!SL_ISERROR(rval_open))
+ sl_close(rval_open);
+ if (sh.flag.checkSum == SH_CHECK_INIT ||
+ (sh_hash_have_it (theFile->fullpath) >= 0 &&
+ (!SH_FFLAG_REPORTED_SET(theFile->file_reported))))
+ {
+ if (S_FALSE == sh_ignore_chk_del(theFile->fullpath)) {
+ int flags = sh_hash_getflags (theFile->fullpath);
+
+ if ((flags >= 0) && (flags & SH_FFLAG_ENOENT) == 0) {
+ char errbuf[SH_ERRBUF_SIZE];
+ uid_t euid;
+ (void) sl_get_euid(&euid);
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT,
+ _("lstat"),
+ sh_error_message (stat_errno, errbuf, sizeof(errbuf)),
+ (long) euid,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ sh_hash_set_flag (theFile->fullpath, SH_FFLAG_ENOENT);
+ }
+ }
+ }
+ SL_RETURN((-1),_("sh_unix_getinfo"));
+ }
+
+ /* --- case 2: not a regular file ---
+ */
+ else if (! S_ISREG(buf.st_mode))
+ {
+ if (fileHash != NULL)
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+
+ /* --- case 3a: a regular file, fstat ok ---
+ */
+ else if (fstat_return == 0 &&
+ buf.st_mode == fbuf.st_mode &&
+ buf.st_ino == fbuf.st_ino &&
+ buf.st_uid == fbuf.st_uid &&
+ buf.st_gid == fbuf.st_gid &&
+ buf.st_dev == fbuf.st_dev )
+ {
+ if (fileHash != NULL)
+ {
+ if ((theFile->check_flags & MODI_CHK) == 0 ||
+ sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size,
+ (UINT64) fbuf.st_mode, rval_open))
+ {
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else if ((theFile->check_flags & MODI_PREL) != 0 &&
+ S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size,
+ alert_timeout, theFile->fullpath))
+ {
+ if (0 != sh_prelink_run (theFile->fullpath,
+ fileHash, alert_timeout, theFile->check_flags))
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 length_current = TIGER_NOLIM;
+
+ if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX))
+ {
+ sl_init_content (rval_open, fbuf.st_size);
+ }
+
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags);
+ sl_strlcpy(fileHash,
+ sh_tiger_generic_hash (theFile->fullpath,
+ rval_open, &length_current,
+ alert_timeout,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ content = sl_get_content(rval_open);
+ content = sh_string_copy(content);
+
+ if ((theFile->check_flags & MODI_SGROW) != 0)
+ {
+ /* Update size so it matches the one for which the checksum
+ has been computed */
+ fbuf.st_size = length_current;
+ buf.st_size = fbuf.st_size;
+ sl_rewind(rval_open);
+ sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE,
+ &fileHash[KEY_LEN + 1],
+ alert_timeout, rval_open, theFile->check_flags);
+ }
+ }
+ }
+ }
+
+ /* --- case 3b: a regular file, fstat ok, but different ---
+ */
+ else if (fstat_return == 0 && S_ISREG(fbuf.st_mode))
+ {
+ memcpy (&buf, &fbuf, sizeof( struct stat ));
+
+ if (fileHash != NULL)
+ {
+ if ((theFile->check_flags & MODI_CHK) == 0 ||
+ sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size,
+ (UINT64) fbuf.st_mode, rval_open))
+ {
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else if (policy == SH_LEVEL_PRELINK &&
+ S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size,
+ alert_timeout, theFile->fullpath))
+ {
+ if (0 != sh_prelink_run (theFile->fullpath,
+ fileHash, alert_timeout, theFile->check_flags))
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+ }
+ else
+ {
+ char hashbuf[KEYBUF_SIZE];
+ UINT64 length_current = TIGER_NOLIM;
+
+ if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX))
+ {
+ sl_init_content (rval_open, fbuf.st_size);
+ }
+
+ if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags);
+ sl_strlcpy(fileHash,
+ sh_tiger_generic_hash (theFile->fullpath, rval_open,
+ &length_current,
+ alert_timeout,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN + 1);
+
+ content = sl_get_content(rval_open);
+ content = sh_string_copy(content);
+
+ if ((theFile->check_flags & MODI_SGROW) != 0)
+ {
+ /* Update size so it matches the one for which the checksum
+ has been computed */
+ fbuf.st_size = length_current;
+ buf.st_size = fbuf.st_size;
+ sl_rewind(rval_open);
+ sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE,
+ &fileHash[KEY_LEN + 1],
+ alert_timeout, rval_open, theFile->check_flags);
+ }
+ }
+ }
+ }
+
+ /* --- case 4: a regular file, fstat failed ---
+ */
+
+ else /* fstat_return != 0 or !S_ISREG(fbuf.st_mode) or open() failed */
+ {
+ uid_t euid;
+
+ if (fileHash != NULL)
+ sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
+
+ if ((theFile->check_flags & MODI_CHK) != 0)
+ {
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+
+
+ if (fd >= 0 && fstat_return != 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ (void) sl_get_euid(&euid);
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT,
+ _("fstat"),
+ sh_error_message (fstat_errno, errbuf, sizeof(errbuf)),
+ (long) euid,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else if (fd >= 0 && !S_ISREG(fbuf.st_mode))
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, fstat_errno,
+ MSG_E_NOTREG, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ char errbuf2[SH_ERRBUF_SIZE];
+ sl_strlcpy(errbuf, sl_error_string(rval_open), sizeof(errbuf));
+ sh_error_message(err_open, errbuf2, sizeof(errbuf2));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, err_open,
+ MSG_E_READ, errbuf, errbuf2, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_FREE(tmp2);
+ }
+ }
+
+
+ /* --- Determine file type. ---
+ */
+ memset (theFile->c_mode, '-', CMODE_SIZE-1);
+ theFile->c_mode[CMODE_SIZE-1] = '\0';
+
+ memset (theFile->link_c_mode, '-', CMODE_SIZE-1);
+ theFile->link_c_mode[CMODE_SIZE-1] = '\0';
+
+ sh_unix_getinfo_type (&buf, &type, theFile->c_mode);
+ theFile->type = type;
+
+#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
+
+ /* --- Determine file attributes. ---
+ */
+ memset (theFile->c_attributes, '-', ATTRBUF_SIZE);
+ theFile->c_attributes[ATTRBUF_USED] = '\0';
+ theFile->attributes = 0;
+
+#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS)
+ if (theFile->c_mode[0] != 'c' && theFile->c_mode[0] != 'b' &&
+ theFile->c_mode[0] != 'l' )
+ sh_unix_getinfo_attr(theFile->fullpath,
+ &theFile->attributes, theFile->c_attributes,
+ fd, &buf);
+#endif
+#endif
+
+#if defined(USE_XATTR) && defined(USE_ACL)
+ if (sh_unix_check_selinux == S_TRUE || sh_unix_check_acl == S_TRUE)
+ theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf);
+#elif defined(USE_XATTR)
+ if (sh_unix_check_selinux == S_TRUE)
+ theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf);
+#elif defined(USE_ACL)
+ if (sh_unix_check_acl == S_TRUE)
+ theFile->attr_string = sh_unix_getinfo_acl (theFile->fullpath, fd, &buf);
+#else
+ theFile->attr_string = NULL;
+#endif
+
+ if (!SL_ISERROR(rval_open))
+ sl_close(rval_open);
+
+
+ /* --- I/O limit. ---
+ */
+ if (IO_Limit > 0)
+ {
+ runtim = (long) (time(NULL) - sh.statistics.time_start);
+
+ if (runtim > 0 && (long)(sh.statistics.bytes_hashed/runtim) > IO_Limit)
+ retry_msleep(1, 0);
+ }
+
+ /* --- Determine permissions. ---
+ */
+ sh_unix_getinfo_mode (&buf, &mode, theFile->c_mode);
+
+ /* --- Trivia. ---
+ */
+ theFile->dev = buf.st_dev;
+ theFile->ino = buf.st_ino;
+ theFile->mode = buf.st_mode;
+ theFile->hardlinks = buf.st_nlink;
+ theFile->owner = buf.st_uid;
+ theFile->group = buf.st_gid;
+ theFile->rdev = buf.st_rdev;
+ theFile->size = buf.st_size;
+ theFile->blksize = (unsigned long) buf.st_blksize;
+ theFile->blocks = (unsigned long) buf.st_blocks;
+ theFile->atime = buf.st_atime;
+ theFile->mtime = buf.st_mtime;
+ theFile->ctime = buf.st_ctime;
+
+
+ /* --- Owner and group. ---
+ */
+
+ if (NULL == sh_unix_getGIDname(SH_ERR_ALL, buf.st_gid, theFile->c_group, GROUP_MAX+1)) {
+
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+
+ if (policy == SH_LEVEL_ALLIGNORE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT,
+ MSG_FI_NOGRP,
+ (long) buf.st_gid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT,
+ MSG_FI_NOGRP,
+ (long) buf.st_gid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_FREE(tmp2);
+ sl_snprintf(theFile->c_group, GROUP_MAX+1, "%d", (long) buf.st_gid);
+ }
+
+
+ if (NULL == sh_unix_getUIDname(SH_ERR_ALL, buf.st_uid, theFile->c_owner, USER_MAX+1)) {
+
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+
+ if (policy == SH_LEVEL_ALLIGNORE)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT,
+ MSG_FI_NOUSR,
+ (long) buf.st_uid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT,
+ MSG_FI_NOUSR,
+ (long) buf.st_uid, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ SH_FREE(tmp2);
+ sl_snprintf(theFile->c_owner, USER_MAX+1, "%d", (long) buf.st_uid);
+ }
+
+ /* --- Output the file. ---
+ */
+ if (flag_err_debug == S_TRUE)
+ {
+ tmp2 = sh_util_safe_name ((filename == NULL) ?
+ theFile->fullpath : filename);
+ (void) sh_unix_time(theFile->mtime, timestr, sizeof(timestr));
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LIST,
+ theFile->c_mode,
+ theFile->hardlinks,
+ theFile->c_owner,
+ theFile->c_group,
+ (unsigned long) theFile->size,
+ timestr,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ }
+
+ /* --- Check for links. ---
+ */
+ if (theFile->c_mode[0] == 'l')
+ {
+ linknamebuf = SH_ALLOC(PATH_MAX);
+
+ /* flawfinder: ignore */
+ linksize = readlink (theFile->fullpath, linknamebuf, PATH_MAX-1);
+
+ if (linksize < (PATH_MAX-1) && linksize >= 0)
+ linknamebuf[linksize] = '\0';
+ else
+ linknamebuf[PATH_MAX-1] = '\0';
+
+ if (linksize < 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ linksize = errno;
+ tmp2 = sh_util_safe_name (theFile->fullpath);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, linksize, MSG_FI_RDLNK,
+ sh_error_message (linksize, errbuf, sizeof(errbuf)), tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ SH_FREE(linknamebuf);
+ theFile->link_path = sh_util_strdup("-");
+ SL_RETURN((-1),_("sh_unix_getinfo"));
+ }
+
+ if (linknamebuf[0] == '/')
+ {
+ theFile->link_path = sh_util_strdup (linknamebuf);
+ }
+ else
+ {
+ tmp = sh_util_dirname(theFile->fullpath);
+ if (tmp) {
+ theFile->link_path = SH_ALLOC(PATH_MAX);
+ sl_strlcpy (theFile->link_path, tmp, PATH_MAX);
+ SH_FREE(tmp);
+ } else {
+ theFile->link_path = SH_ALLOC(PATH_MAX);
+ theFile->link_path[0] = '\0';
+ }
+ /*
+ * Only attach '/' if not root directory. Handle "//", which
+ * according to POSIX is implementation-defined, and may be
+ * different from "/" (however, three or more '/' will collapse
+ * to one).
+ */
+ tmp = theFile->link_path; while (*tmp == '/') ++tmp;
+ if (*tmp != '\0')
+ {
+ sl_strlcat (theFile->link_path, "/", PATH_MAX);
+ }
+ sl_strlcat (theFile->link_path, linknamebuf, PATH_MAX);
+ }
+
+ /* stat the link
+ */
+ stat_return = retry_lstat (FIL__, __LINE__, theFile->link_path, &lbuf);
+
+ /* check for error
+ */
+ if (stat_return != 0)
+ {
+ stat_return = errno;
+ tmp = sh_util_safe_name (theFile->fullpath);
+ tmp2 = sh_util_safe_name (theFile->link_path);
+ if (stat_return != ENOENT)
+ {
+ uid_t euid;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ (void) sl_get_euid(&euid);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (level, FIL__, __LINE__, stat_return,
+ MSG_FI_STAT,
+ _("lstat (link target)"),
+ sh_error_message (stat_return,errbuf, sizeof(errbuf)),
+ (long) euid,
+ tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ else
+ {
+ /* a dangling link -- everybody seems to have plenty of them
+ */
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DLNK,
+ tmp, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ theFile->linkisok = BAD;
+ SH_FREE(tmp);
+ SH_FREE(tmp2);
+ SH_FREE(linknamebuf);
+ /*
+ * changed Tue Feb 10 16:16:13 CET 2004:
+ * add dangling symlinks into database
+ * SL_RETURN((-1),_("sh_unix_getinfo"));
+ */
+ theFile->linkmode = 0;
+ SL_RETURN((0),_("sh_unix_getinfo"));
+ }
+
+ theFile->linkisok = GOOD;
+
+
+ /* --- Determine file type. ---
+ */
+ sh_unix_getinfo_type (&lbuf, &type, theFile->link_c_mode);
+ theFile->type = type;
+
+ /* --- Determine permissions. ---
+ */
+ sh_unix_getinfo_mode (&lbuf, &mode, theFile->link_c_mode);
+ theFile->linkmode = lbuf.st_mode;
+
+ /* --- Output the link. ---
+ */
+ if (theFile->linkisok == GOOD)
+ {
+ tmp2 = sh_util_safe_name (linknamebuf);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LLNK,
+ theFile->link_c_mode, tmp2);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tmp2);
+ }
+ SH_FREE(linknamebuf);
+ }
+ else /* not a link, theFile->c_mode[0] != 'l' */
+ {
+ if (content)
+ {
+#ifdef HAVE_LIBZ
+ unsigned long clen;
+ unsigned char * compressed;
+#ifdef HAVE_COMPRESSBOUND
+ clen = compressBound(sh_string_len(content));
+#else
+ if (sh_string_len(content) > 10*SH_TXT_MAX)
+ clen = SH_TXT_MAX;
+ else
+ clen = 13 + (int)(1.0001*sh_string_len(content));
+#endif
+ compressed = SH_ALLOC(clen);
+ if (Z_OK == compress(compressed, &clen,
+ (unsigned char *) sh_string_str(content),
+ sh_string_len(content)))
+ {
+ if (clen < SH_TXT_MAX)
+ {
+ sh_util_base64_enc_alloc (&(theFile->link_path),
+ (char *) compressed, clen);
+ }
+ else
+ {
+ char tmsg[128];
+ char * tpath = sh_util_safe_name (theFile->fullpath);
+ sl_snprintf(tmsg, sizeof(tmsg),
+ _("compressed file too large (%lu bytes)"),
+ clen);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, -1,
+ MSG_E_SUBGPATH, tmsg,
+ _("sh_unix_getinfo"), tpath);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SH_FREE(tpath);
+ }
+ }
+ SH_FREE(compressed);
+#endif
+ sh_string_destroy(&content);
+ }
+ }
+ SL_RETURN((0),_("sh_unix_getinfo"));
+}
+
+/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+int sh_unix_unlock(char * lockfile, char * flag)
+{
+ int error = 0;
+
+ SL_ENTER(_("sh_unix_unlock"));
+
+ if (sh.flag.isdaemon == S_FALSE && flag == NULL)
+ SL_RETURN((0),_("sh_unix_unlock"));
+
+ /* --- Logfile is not locked to us. ---
+ */
+ if (sh.flag.islocked == BAD && flag != NULL)
+ SL_RETURN((-1),_("sh_unix_unlock"));
+
+ /* --- Check whether the directory is secure. ---
+ */
+ if (0 != tf_trust_check (lockfile, SL_YESPRIV))
+ SL_RETURN((-1),_("sh_unix_unlock"));
+
+ /* --- Delete the lock file. ---
+ */
+ error = retry_aud_unlink (FIL__, __LINE__, lockfile);
+
+ if (error == 0)
+ {
+ if (flag != NULL)
+ sh.flag.islocked = BAD; /* not locked anymore */
+ }
+ else if (flag != NULL)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ error = errno;
+ sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_UNLNK,
+ sh_error_message(error, errbuf, sizeof(errbuf)),
+ lockfile);
+ SL_RETURN((-1),_("sh_unix_unlock"));
+ }
+ SL_RETURN((0),_("sh_unix_unlock"));
+}
+
+int sh_unix_check_piddir (char * pidpath)
+{
+ static struct stat buf;
+ int status = 0;
+ char * pid_dir;
+
+ SL_ENTER(_("sh_unix_check_piddir"));
+
+ pid_dir = sh_util_dirname (pidpath);
+
+ status = retry_lstat (FIL__, __LINE__, pid_dir, &buf);
+
+ if (status < 0 && errno == ENOENT)
+ {
+ status = mkdir (pid_dir, 0777);
+ if (status < 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ _("Cannot create PID directory"),
+ _("sh_unix_check_piddir"));
+ SH_FREE(pid_dir);
+ SL_RETURN((-1),_("sh_unix_check_piddir"));
+ }
+ }
+ else if (!S_ISDIR(buf.st_mode))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ _("Path of PID directory refers to a non-directory object"),
+ _("sh_unix_check_piddir"));
+ SH_FREE(pid_dir);
+ SL_RETURN((-1),_("sh_unix_check_piddir"));
+ }
+ SH_FREE(pid_dir);
+ SL_RETURN((0),_("sh_unix_check_piddir"));
+}
+
+int sh_unix_lock (char * lockfile, char * flag)
+{
+ int filed;
+ int errnum;
+ char myPid[64];
+ SL_TICKET fd;
+ extern int get_the_fd (SL_TICKET ticket);
+
+ SL_ENTER(_("sh_unix_lock"));
+
+ sprintf (myPid, "%ld\n", (long) sh.pid); /* known to fit */
+
+ if (flag == NULL) /* PID file, check for directory */
+ {
+ if (0 != sh_unix_check_piddir (lockfile))
+ {
+ SL_RETURN((-1),_("sh_unix_lock"));
+ }
+ }
+
+ fd = sl_open_safe_rdwr (FIL__, __LINE__,
+ lockfile, SL_YESPRIV); /* fails if file exists */
+
+ if (!SL_ISERROR(fd))
+ {
+ errnum = sl_write (fd, myPid, sl_strlen(myPid));
+ filed = get_the_fd(fd);
+ fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ sl_close (fd);
+
+ if (!SL_ISERROR(errnum))
+ {
+ if (flag != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_lock"));
+ }
+ }
+
+ TPT((0, FIL__, __LINE__, _("msg=<open pid file failed>\n")));
+ if (flag != NULL)
+ sh.flag.islocked = BAD;
+ SL_RETURN((-1),_("sh_unix_lock"));
+
+ /* notreached */
+}
+
+
+/* check whether file is locked
+ */
+int sh_unix_test_and_lock (char * filename, char * lockfile)
+{
+ static struct stat buf;
+ int status = 0;
+
+
+ SL_TICKET fd;
+ char line_in[128];
+
+ SL_ENTER(_("sh_unix_test_and_lock"));
+
+ status = retry_lstat (FIL__, __LINE__, lockfile, &buf);
+
+ /* --- No lock file found, try to lock. ---
+ */
+
+ if (status < 0 && errno == ENOENT)
+ {
+ if (0 == sh_unix_lock (lockfile, filename))
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot create PID file (1)") : _("Cannot create lock file (1)"),
+ _("sh_unix_test_and_lock"));
+ SL_RETURN((-1),_("sh_unix_test_and_lock"));
+ }
+ }
+ else if (status == 0 && buf.st_size == 0)
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ sh_unix_unlock (lockfile, filename);
+ if (filename != NULL)
+ sh.flag.islocked = BAD;
+ if (0 == sh_unix_lock (lockfile, filename))
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot create PID file (2)") : _("Cannot create lock file (2)"),
+ _("sh_unix_test_and_lock"));
+ SL_RETURN((-1),_("sh_unix_test_and_lock"));
+ }
+ }
+
+ /* --- Check on lock. ---
+ */
+
+ if (status >= 0)
+ {
+ fd = sl_open_read (FIL__, __LINE__, lockfile, SL_YESPRIV);
+ if (SL_ISERROR(fd))
+ sh_error_handle ((-1), FIL__, __LINE__, fd,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot open PID file for read") : _("Cannot open lock file for read"),
+ _("sh_unix_test_and_lock"));
+ }
+ else
+ fd = -1;
+
+ if (!SL_ISERROR(fd))
+ {
+ /* read the PID in the lock file
+ */
+ status = sl_read (fd, line_in, sizeof(line_in));
+ line_in[sizeof(line_in)-1] = '\0';
+
+ /* convert to numeric
+ */
+ if (status > 0)
+ {
+ errno = 0;
+ status = strtol(line_in, (char **)NULL, 10);
+ if (errno == ERANGE || status <= 0)
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Bad PID in PID file") : _("Bad PID in lock file"),
+ _("sh_unix_test_and_lock"));
+
+ status = -1;
+ }
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot read PID file") : _("Cannot read lock file"),
+ _("sh_unix_test_and_lock"));
+ }
+ sl_close(fd);
+
+ if (status > 0 && (unsigned int) status == sh.pid)
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+
+
+ /* --- Check whether the process exists. ---
+ */
+ if (status > 0)
+ {
+ errno = 0;
+ status = aud_kill (FIL__, __LINE__, status, 0);
+
+ /* Does not exist, so remove the stale lock
+ * and create a new one.
+ */
+ if (status < 0 && errno == ESRCH)
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ if (0 != sh_unix_unlock(lockfile, filename) && (filename !=NULL))
+ sh.flag.islocked = BAD;
+ else
+ {
+ if (0 == sh_unix_lock (lockfile, filename))
+ {
+ if (filename != NULL)
+ sh.flag.islocked = GOOD;
+ SL_RETURN((0),_("sh_unix_test_and_lock"));
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot create PID file (3)") : _("Cannot create lock file (3)"),
+ _("sh_unix_test_and_lock"));
+ }
+ if (filename != NULL)
+ sh.flag.islocked = BAD;
+ }
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, status,
+ MSG_E_SUBGEN,
+ (filename == NULL) ? _("Cannot remove stale PID file, PID may be a running process") : _("Cannot remove stale lock file, PID may be a running process"),
+ _("sh_unix_test_and_lock"));
+ if (filename != NULL)
+ sh.flag.islocked = BAD;
+ }
+ }
+ }
+ SL_RETURN((-1),_("sh_unix_testlock"));
+}
+
+/* write the PID file
+ */
+int sh_unix_write_pid_file()
+{
+ return sh_unix_test_and_lock(NULL, sh.srvlog.alt);
+}
+
+/* write lock for filename
+ */
+int sh_unix_write_lock_file(char * filename)
+{
+ size_t len;
+ int res;
+ char * lockfile;
+
+ if (filename == NULL)
+ return (-1);
+
+ len = sl_strlen(filename);
+ if (sl_ok_adds(len, 6))
+ len += 6;
+ lockfile = SH_ALLOC(len);
+ sl_strlcpy(lockfile, filename, len);
+ sl_strlcat(lockfile, _(".lock"), len);
+ res = sh_unix_test_and_lock(filename, lockfile);
+ SH_FREE(lockfile);
+ return res;
+}
+
+/* rm lock for filename
+ */
+int sh_unix_rm_lock_file(char * filename)
+{
+ size_t len;
+ int res;
+ char * lockfile;
+
+ if (filename == NULL)
+ return (-1);
+
+ len = sl_strlen(filename);
+ if (sl_ok_adds(len, 6))
+ len += 6;
+ lockfile = SH_ALLOC(len);
+ sl_strlcpy(lockfile, filename, len);
+ sl_strlcat(lockfile, _(".lock"), len);
+
+ res = sh_unix_unlock(lockfile, filename);
+ SH_FREE(lockfile);
+ return res;
+}
+
+/* rm lock for filename
+ */
+int sh_unix_rm_pid_file()
+{
+ return sh_unix_unlock(sh.srvlog.alt, NULL);
+}
+
+/* Test whether file exists
+ */
+int sh_unix_file_exists(char * path)
+{
+ struct stat buf;
+
+ SL_ENTER(_("sh_unix_file_exists"));
+
+ if (0 == retry_lstat(FIL__, __LINE__, path, &buf))
+ SL_RETURN( S_TRUE, _("sh_unix_file_exists"));
+ else
+ SL_RETURN( S_FALSE, _("sh_unix_file_exists"));
+}
+
+
+/* Test whether file exists, is a character device, and allows read
+ * access.
+ */
+int sh_unix_device_readable(int fd)
+{
+ struct stat buf;
+
+ SL_ENTER(_("sh_unix_device_readable"));
+
+ if (retry_fstat(FIL__, __LINE__, fd, &buf) == -1)
+ SL_RETURN( (-1), _("sh_unix_device_readable"));
+ else if ( S_ISCHR(buf.st_mode) && 0 != (S_IROTH & buf.st_mode) )
+ SL_RETURN( (0), _("sh_unix_device_readable"));
+ else
+ SL_RETURN( (-1), _("sh_unix_device_readable"));
+}
+
+static char preq[16];
+
+/* return true if database is remote
+ */
+int file_is_remote ()
+{
+ static int init = 0;
+ struct stat buf;
+
+ SL_ENTER(_("file_is_remote"));
+
+ if (init == 0)
+ {
+ sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16);
+ ++init;
+ }
+ if (0 == sl_strncmp (sh.data.path, preq, 15))
+ {
+ if (sh.data.path[15] != '\0') /* should be start of path */
+ {
+ if (0 == stat(&(sh.data.path[15]), &buf))
+ {
+ SL_RETURN( S_FALSE, _("file_is_remote"));
+ }
+ else
+ {
+ char * tmp = sh_util_safe_name (&(sh.data.path[15]));
+ sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGPATH,
+ _("No local baseline database at expected path"),
+ _("file_is_remote"),
+ tmp);
+ SH_FREE(tmp);
+ }
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN,
+ _("No local baseline database path known"),
+ _("file_is_remote"));
+ }
+ SL_RETURN( S_TRUE, _("file_is_remote"));
+ }
+ SL_RETURN( S_FALSE, _("file_is_remote"));
+}
+
+/* Return the path to the configuration/database file.
+ */
+char * file_path(char what, char flag)
+{
+ static int init = 0;
+
+ SL_ENTER(_("file_path"));
+
+ if (init == 0)
+ {
+ sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16);
+ ++init;
+ }
+
+ switch (what)
+ {
+
+ case 'C':
+ if (0 == sl_strncmp (sh.conf.path, preq, 15))
+ {
+#if defined(SH_WITH_SERVER)
+ if (sh.flag.isserver == S_TRUE && sl_strlen(sh.conf.path) == 15)
+ SL_RETURN( NULL, _("file_path"));
+ if (sh.flag.isserver == S_TRUE)
+ SL_RETURN( &(sh.conf.path[15]), _("file_path"));
+#endif
+ if (flag == 'R')
+ SL_RETURN( preq, _("file_path"));
+ if (flag == 'I')
+ {
+ if (sl_strlen(sh.conf.path) == 15)
+ SL_RETURN( NULL, _("file_path"));
+ else
+ SL_RETURN( &(sh.conf.path[15]), _("file_path"));
+ }
+ SL_RETURN ( preq, _("file_path"));
+ }
+ else
+ SL_RETURN( sh.conf.path, _("file_path"));
+ /* break; *//* unreachable */
+
+ case 'D':
+ if (0 == sl_strncmp (sh.data.path, preq, 15))
+ {
+ if (flag == 'R')
+ SL_RETURN( preq, _("file_path"));
+ if (flag == 'W' && sl_strlen(sh.data.path) == 15)
+ SL_RETURN (NULL, _("file_path"));
+ if (flag == 'W')
+ SL_RETURN( &(sh.data.path[15]), _("file_path"));
+ }
+ else
+ SL_RETURN( sh.data.path, _("file_path"));
+ break;
+
+ default:
+ SL_RETURN( NULL, _("file_path"));
+ }
+
+ return NULL; /* notreached */
+}
+/************************************************/
+/**** Mlock Utilities ****/
+/************************************************/
+
+#include <limits.h>
+
+int sh_unix_pagesize()
+{
+ int pagesize = 4096;
+#if defined(_SC_PAGESIZE)
+ pagesize = sysconf(_SC_PAGESIZE);
+#elif defined(_SC_PAGE_SIZE)
+ pagesize = sysconf(_SC_PAGE_SIZE);
+#elif defined(HAVE_GETPAGESIZE)
+ pagesize = getpagesize();
+#elif defined(PAGESIZE)
+ pagesize = PAGESIZE;
+#endif
+
+ return ((pagesize > 0) ? pagesize : 4096);
+}
+
+typedef struct sh_page_lt {
+ unsigned long page_start;
+ int page_refcount;
+ char file[64];
+ int line;
+ struct sh_page_lt * next;
+} sh_page_l;
+
+sh_page_l * sh_page_locked = NULL;
+volatile int page_locking = 0;
+
+unsigned long sh_unix_lookup_page (void * in_addr, size_t len, int * num_pages)
+{
+ int pagesize = sh_unix_pagesize();
+ unsigned long addr = (unsigned long) in_addr;
+
+ unsigned long pagebase;
+ unsigned long pagediff;
+ unsigned long pagenum = addr / pagesize;
+
+ SL_ENTER(_("sh_unix_lookup_page"));
+#if 0
+ fprintf(stderr, "mlock: --> base %ld, pagenum: %ld\n",
+ addr, pagenum);
+#endif
+
+ /* address of first page
+ */
+ pagebase = pagenum * pagesize;
+
+ /* number of pages
+ */
+ pagediff = (addr + len) - pagebase;
+ pagenum = pagediff / pagesize;
+ if (pagenum * pagesize < pagediff)
+ ++pagenum;
+
+#if 0
+ fprintf(stderr, "mlock: --> pagebase %ld, pagediff %ld, (addr + len) %ld\n",
+ pagebase, pagediff, (addr + len));
+#endif
+
+ *num_pages = pagenum;
+ SL_RETURN((pagebase), _("sh_unix_lookup_page"));
+}
+
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+
+SH_MUTEX_STATIC(mutex_mlock,PTHREAD_MUTEX_INITIALIZER);
+
+int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len)
+{
+ int num_pages;
+ int status = 0;
+ int pagesize;
+ sh_page_l * page_list;
+ unsigned long addr;
+#ifdef TEST_MLOCK
+ int i = 0;
+#endif
+
+ SL_ENTER(_("sh_unix_mlock"));
+
+ /* There's no cancellation point here, except if tracing is on
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
+
+ page_list = sh_page_locked;
+
+ if (0 != page_locking)
+ {
+ status = -1;
+ goto exit_mlock;
+ }
+
+ page_locking = 1;
+
+ pagesize = sh_unix_pagesize();
+ addr = sh_unix_lookup_page (in_addr, len, &num_pages);
+
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: addr %ld, base %ld, pages: %d, length %d\n",
+ (unsigned long) in_addr, addr, num_pages, len);
+#endif
+
+ /* increase refcount of locked pages
+ * addr is first page; num_pages is #(consecutive pages) to lock
+ */
+
+ while ((page_list != NULL) && (num_pages > 0))
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: check page %d: %ld [%d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+ if (page_list->page_start == addr)
+ {
+ page_list->page_refcount += 1;
+ num_pages -= 1;
+ addr += pagesize;
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: found page %d: %ld [%d], next page %ld\n",
+ i, page_list->page_start, page_list->page_refcount, addr);
+#endif
+ }
+#ifdef TEST_MLOCK
+ ++i;
+#endif
+ page_list = page_list->next;
+ }
+
+ /* mlock some more pages, if needed
+ */
+ while (num_pages > 0)
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "mlock: lock page %d: mlock %ld [num_pages %d]\n",
+ i, addr, num_pages);
+ ++i;
+#endif
+ page_list = SH_ALLOC(sizeof(sh_page_l));
+ page_list->page_start = addr;
+ page_list->page_refcount = 1;
+ sl_strlcpy(page_list->file, file, 64);
+ page_list->line = line;
+ status = mlock( (void *) addr, pagesize);
+ if (status != 0)
+ {
+#ifdef TEST_MLOCK
+ char errbuf[SH_ERRBUF_SIZE];
+ fprintf(stderr, "mlock: error: %s\n",
+ sh_error_message(errno, errbuf, sizeof(errbuf)));
+#endif
+ SH_FREE(page_list);
+ page_locking = 0;
+ goto exit_mlock;
+ }
+ page_list->next = sh_page_locked;
+ sh_page_locked = page_list;
+ num_pages -= 1;
+ addr += pagesize;
+ }
+ page_locking = 0;
+
+ exit_mlock:
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
+
+ SL_RETURN((status), _("sh_unix_mlock"));
+}
+#else
+int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len)
+{
+ (void) file; (void) line;
+ (void) in_addr; (void) len;
+ return -1;
+}
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+int sh_unix_munlock (void * in_addr, size_t len)
+{
+ int num_pages;
+ int unlocked;
+ int status;
+ int pagesize;
+ sh_page_l * page_list;
+ sh_page_l * page_last;
+ unsigned long addr;
+
+ int test_count;
+ int test_status;
+ int test_pages;
+
+#ifdef TEST_MLOCK
+ int i = 0;
+#endif
+
+ SL_ENTER(_("sh_unix_munlock"));
+
+ /* There's no cancellation point here, except if tracing is on
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
+
+ unlocked = 0;
+ status = 0;
+ page_list = sh_page_locked;
+
+ if (0 != page_locking)
+ {
+ status = -1;
+ goto exit_munlock;
+ }
+ page_locking = 1;
+
+ pagesize = sh_unix_pagesize();
+ addr = sh_unix_lookup_page (in_addr, len, &num_pages);
+
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: in_addr %ld, addr %ld, pages: %d, length %d\n",
+ (unsigned long) in_addr, addr, num_pages, len);
+#endif
+
+ test_pages = num_pages;
+
+ /* reduce refcount of locked pages
+ * addr is first page; num_pages is #(consecutive pages) to lock
+ */
+ while ((page_list != NULL) && (num_pages > 0))
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: page %d: %ld [%d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+
+ test_status = 0;
+ for (test_count = 0; test_count < test_pages; ++test_count)
+ {
+ if (page_list->page_start == (addr + (test_count * pagesize)))
+ {
+ test_status = 1;
+ break;
+ }
+ }
+
+ if (test_status == 1)
+ {
+ page_list->page_refcount -= 1;
+ if (page_list->page_refcount == 0)
+ {
+ status = munlock ( (void *) addr, pagesize);
+ ++unlocked;
+ }
+ num_pages -= 1;
+#ifdef TEST_MLOCK
+ fprintf(stderr,
+ "munlock: page %d: %ld [refcount %d], refcount reduced\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+ }
+#ifdef TEST_MLOCK
+ ++i;
+#endif
+ page_list = page_list->next;
+ }
+
+#ifdef TEST_MLOCK
+ i = 0;
+#endif
+
+ if (unlocked > 0)
+ {
+ page_list = sh_page_locked;
+ page_last = sh_page_locked;
+
+ while ((page_list != NULL) && (unlocked > 0))
+ {
+ if (page_list->page_refcount == 0)
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: remove page %d: %ld [refcount %d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+ if (page_last != page_list)
+ {
+ page_last->next = page_list->next;
+ SH_FREE(page_list);
+ page_list = page_last->next;
+ }
+ else
+ {
+ page_last = page_list->next;
+ if (page_list == sh_page_locked)
+ sh_page_locked = page_list->next;
+ SH_FREE(page_list);
+ page_list = page_last;
+ }
+ --unlocked;
+ }
+ else
+ {
+#ifdef TEST_MLOCK
+ fprintf(stderr, "munlock: skip page %d: %ld [refcount %d]\n",
+ i, page_list->page_start, page_list->page_refcount);
+#endif
+
+ page_last = page_list;
+ page_list = page_list->next;
+ }
+#ifdef TEST_MLOCK
+ ++i;
+#endif
+ }
+ }
+
+ page_locking = 0;
+
+ exit_munlock:
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
+ SL_RETURN((status), _("sh_unix_munlock"));
+}
+#else
+int sh_unix_munlock (void * in_addr, size_t len)
+{
+ (void) in_addr; (void) len;
+ return -1;
+}
+#endif
+
+int sh_unix_count_mlock()
+{
+ unsigned int i = 0;
+ char str[32][64];
+ sh_page_l * page_list;
+
+ SL_ENTER(_("sh_unix_count_mlock"));
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ /* There's no cancellation point here, except if tracing is on
+ */
+ SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
+#endif
+
+ page_list = sh_page_locked;
+
+ while (page_list != NULL)
+ {
+#ifdef WITH_TPT
+ if (i < 32)
+ sl_snprintf(str[i], 64, _("file: %s line: %d page: %d"),
+ page_list->file, page_list->line, i+1);
+#endif
+ page_list = page_list->next;
+ ++i;
+ }
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
+#endif
+
+#ifdef WITH_TPT
+ {
+ unsigned int j = 0;
+ while (j < i && j < 32)
+ {
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, j, MSG_E_SUBGEN,
+ str[j], _("sh_unix_count_mlock"));
+ ++j;
+ }
+ }
+#endif
+
+ sl_snprintf(str[0], 64, _("%d pages locked"), i);
+ sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, i, MSG_E_SUBGEN,
+ str[0], _("sh_unix_count_mlock"));
+ SL_RETURN((i), _("sh_unix_count_mlock"));
+}
+
+/************************************************/
+/************************************************/
+/**** Stealth Utilities ****/
+/************************************************/
+/************************************************/
+#ifdef SH_STEALTH
+
+void sh_unix_xor_code (char * str, int len)
+{
+ register int i;
+
+ for (i = 0; i < len; ++i) str[i] ^= (char) XOR_CODE;
+ return;
+}
+
+#if !defined(SH_STEALTH_MICRO)
+
+
+int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len,
+ unsigned long * bytes_read);
+unsigned long first_hex_block(SL_TICKET fd, unsigned long * max);
+
+/*
+ * --- Get hidden data from a block of hex data. ---
+ */
+int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len)
+{
+ int add_off = 0, llen;
+ static unsigned long off_data = 0;
+ static unsigned long max_data = 0;
+ static unsigned long bytes_read = 0;
+ static int stealth_init = BAD;
+
+ SL_ENTER(_("sh_unix_getline_stealth"));
+
+ if (str == NULL)
+ {
+ off_data = 0;
+ max_data = 0;
+ bytes_read = 0;
+ stealth_init = BAD;
+ SL_RETURN(0, _("sh_unix_getline_stealth"));
+ }
+
+ /* --- Initialize. ---
+ */
+ if (stealth_init == BAD)
+ {
+ off_data = first_hex_block(fd, &max_data);
+ if (off_data == 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The stealth config file does not contain any steganographically\nhidden data. This file must be an image file in _uncompressed_\npostscript format.\nTo hide data in it, use:\n samhain_stealth -s postscript_file orig_config_file\n mv postscript_file /path/to/config/file\n"));
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_P_NODATA,
+ _("Stealth config file."));
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ stealth_init = GOOD;
+ max_data += off_data;
+ }
+
+ /* --- Seek to proper position. ---
+ */
+ if (bytes_read >= max_data || add_off < 0)
+ {
+ dlog(1, FIL__, __LINE__,
+ _("The capacity of the container image file for the stealth config file seems to be too small. Your config file is likely truncated.\n"));
+ sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_P_NODATA,
+ _("Stealth config file."));
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ sl_seek(fd, off_data);
+
+ /* --- Read one line. ---
+ */
+ add_off = hideout_hex_block(fd, (unsigned char *) str, len, &bytes_read);
+ off_data += add_off;
+
+ llen = sl_strlen(str);
+ SL_RETURN(llen, _("sh_unix_getline_stealth"));
+}
+
+int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len,
+ unsigned long * bytes_read)
+{
+
+ register int i, j, k;
+ unsigned char c, e;
+ register int num;
+ unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+ unsigned long here = 0;
+ unsigned long retval = 0;
+ unsigned long bread = 0;
+
+ SL_ENTER(_("hideout_hex_block"));
+
+ ASSERT_RET((len > 1), _("len > 1"), (0));
+
+ --len;
+
+ i = 0;
+ while (i < len)
+ {
+ for (j = 0; j < 8; ++j)
+ {
+
+ /* --- Get a low byte, modify, read back. ---
+ */
+ for (k = 0; k < 2; ++k)
+ {
+ /* -- Skip whitespace. ---
+ */
+ c = ' ';
+ do {
+ do {
+ num = sl_read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0)
+ ++here;
+ else if (num == 0)
+ SL_RETURN((0), _("hideout_hex_block"));
+ else
+ SL_RETURN((-1), _("hideout_hex_block"));
+ } while (c == '\n' || c == '\t' || c == '\r' ||
+ c == ' ');
+ }
+
+
+ /* --- e is the value of the low byte. ---
+ */
+ e = (unsigned char) sh_util_hexchar( c );
+ if ((e & mask[7]) != 0) /* bit is set */
+ str[i] |= mask[j];
+ else /* bit is not set */
+ str[i] &= ~mask[j];
+
+ bread += 1;
+ }
+ if (str[i] == '\n') break;
+ ++i;
+ }
+
+ if (i != 0)
+ str[i] = '\0';
+ else
+ str[i+1] = '\0'; /* keep newline and terminate */
+ retval += here;
+ *bytes_read += (bread/8);
+
+ SL_RETURN(retval, _("hideout_hex_block"));
+}
+
+/* --- Get offset of first data block. ---
+ */
+unsigned long first_hex_block(SL_TICKET fd, unsigned long * max)
+{
+ unsigned int i;
+ long num = 1;
+ unsigned long lnum;
+ char c;
+ int nothex = 0;
+ unsigned long retval = 0;
+ unsigned int this_line = 0;
+ char theline[SH_BUFSIZE];
+
+ SL_ENTER(_("first_hex_block"));
+
+ *max = 0;
+
+ while (1)
+ {
+ theline[0] = '\0';
+ this_line = 0;
+ c = '\0';
+ while (c != '\n' && this_line < (sizeof(theline)-1))
+ {
+ do {
+ num = sl_read (fd, &c, 1);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0)
+ theline[this_line] = c;
+ else
+ SL_RETURN((0), _("first_hex_block"));
+ ++this_line;
+ }
+ theline[this_line] = '\0';
+
+ /* not only 'newline' */
+ if (this_line > 60)
+ {
+ nothex = 0;
+ i = 0;
+ while (nothex == 0 && i < (this_line-1))
+ {
+ if (! isxdigit((int)theline[i])) nothex = 1;
+ ++i;
+ }
+ if (nothex == 1) retval += this_line;
+ }
+ else
+ {
+ nothex = 1;
+ retval += this_line;
+ }
+
+ if (nothex == 0)
+ {
+ *max = 0;
+ do {
+ do {
+ num = sl_read (fd, theline, SH_BUFSIZE);
+ } while (num == 0 && errno == EINTR);
+ if (num > 0)
+ {
+ lnum = (unsigned long) num;
+ for (i = 0; i < lnum; ++i)
+ {
+ c = theline[i];
+ if (c == '\n' || c == '\t' || c == '\r' || c == ' ')
+ ;
+ else if (!isxdigit((int)c))
+ break;
+ else
+ *max += 1;
+ }
+ }
+ } while (num > 0);
+
+ *max /= 16;
+ SL_RETURN((retval), _("first_hex_block"));
+ }
+
+ }
+ /* SL_RETURN((0), _("first_hex_block")); *//* unreachable */
+}
+
+ /* if !defined(SH_STEALTH_MICRO) */
+#endif
+
+ /* ifdef SH_STEALTH */
+#endif
+
+/*
+ * anti-debugger code
+ */
+#if defined(SCREW_IT_UP)
+
+#if defined(HAVE_PTHREAD)
+
+static pthread_key_t gSigtrapVariables_key;
+static pthread_once_t gSigtrapVariables_key_once = PTHREAD_ONCE_INIT;
+
+static inline void make_gSigtrapVariables_key()
+{
+ (void) pthread_key_create(&gSigtrapVariables_key, free);
+}
+
+struct sh_sigtrap_variables * sh_sigtrap_variables_get()
+{
+ void * ptr;
+
+ (void) pthread_once(&gSigtrapVariables_key_once, make_gSigtrapVariables_key);
+
+ ptr = pthread_getspecific(gSigtrapVariables_key);
+ if (ptr == NULL) {
+ ptr = calloc(1,sizeof(struct sh_sigtrap_variables));
+ if (ptr == NULL) {
+ return NULL;
+ }
+ (void) pthread_setspecific(gSigtrapVariables_key, ptr);
+ }
+
+ return (struct sh_sigtrap_variables *) ptr;
+}
+
+/* !defined(HAVE_PTHREAD) */
+#else
+
+static struct sh_sigtrap_variables global_sigtrap_variables;
+struct sh_sigtrap_variables * sh_sigtrap_variables_get()
+{
+ return &global_sigtrap_variables;
+}
+
+#endif
+
+int sh_sigtrap_max_duration_set (const char * str)
+{
+ /* For security (prevent reloading with larger value)
+ * this value can only be set once.
+ */
+ static int once = 0;
+ int i;
+
+ SL_ENTER(_("sh_sigtrap_max_duration_set"));
+
+ i = atoi (str);
+
+ if (i >= 0 && once == 0)
+ {
+ sh.sigtrap_max_duration = i;
+ once = 1;
+ }
+ else
+ {
+ SL_RETURN ((-1), _("sh_sigtrap_max_duration_set"));
+ }
+ SL_RETURN( (0), _("sh_sigtrap_max_duration_set"));
+}
+
+void sh_sigtrap_handler (int signum)
+{
+ struct sh_sigtrap_variables * sigtrap_variables;
+ sigtrap_variables = sh_sigtrap_variables_get();
+ if (sigtrap_variables == NULL) {
+ /* Perhaps, it's better to not die, and to continue using Samhain,
+ even if this part does not work. */
+ return;
+ }
+
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+ long difftv;
+
+ gettimeofday(&tv, NULL);
+ difftv = (tv.tv_sec - sigtrap_variables->save_tv.tv_sec) * 1000000 +
+ (tv.tv_usec - sigtrap_variables->save_tv.tv_usec);
+ if (difftv > sh.sigtrap_max_duration)
+ raise(SIGKILL);
+ }
+#endif
+
+ sigtrap_variables->not_traced = signum;
+ /* cppcheck-suppress memleak */
+ return;
+}
+#endif
diff --git a/src/sh_userfiles.c b/src/sh_userfiles.c
new file mode 100644
index 0000000..ad28cbf
--- /dev/null
+++ b/src/sh_userfiles.c
@@ -0,0 +1,438 @@
+/*
+ * File: sh_userfiles.c
+ * Desc: A module for Samhain; adds files in user directories to the check list
+ * Auth: Jerry Connolly <jerry.connolly@eircom.net>
+ */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+
+#include "samhain.h"
+#include "sh_modules.h"
+#include "sh_userfiles.h"
+#include "sh_utils.h"
+#include "sh_schedule.h"
+#include "sh_error.h"
+#include "sh_hash.h"
+#include "sh_files.h"
+#define SH_NEED_PWD_GRP 1
+#include "sh_static.h"
+#include "sh_pthread.h"
+
+#ifdef SH_USE_USERFILES
+
+#define FIL__ _("sh_userfiles.c")
+
+/* We won't want to build this into yule */
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+static int ShUserfilesActive = S_TRUE;
+
+struct userfileslist {
+ char filename[PATH_MAX];
+ int level;
+
+ struct userfileslist *next;
+};
+
+struct userhomeslist {
+ char *pw_dir;
+
+ struct userhomeslist *next;
+};
+
+struct useruidlist {
+ unsigned long lower;
+ unsigned long upper;
+ struct useruidlist *next;
+};
+
+static struct userfileslist *userFiles = NULL;
+static struct userhomeslist *userHomes = NULL;
+static struct useruidlist *userUids = NULL;
+
+static void sh_userfiles_free_fileslist(struct userfileslist *head);
+static void sh_userfiles_free_homeslist(struct userhomeslist *head);
+static void sh_userfiles_free_uidslist (struct useruidlist *head);
+
+sh_rconf sh_userfiles_table[] = {
+ {
+ N_("userfilesname"),
+ sh_userfiles_add_file,
+ },
+ {
+ N_("userfilesactive"),
+ sh_userfiles_set_active,
+ },
+ {
+ N_("userfilescheckuids"),
+ sh_userfiles_set_uid,
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+static int sh_userfiles_check_uid (unsigned long uid)
+{
+ struct useruidlist * uids = userUids;
+
+ /* default is to include all
+ */
+ if (userUids == NULL)
+ return 1;
+
+ while (uids)
+ {
+ if ((uids->upper != 0) && (uid >= uids->lower) && (uid <= uids->upper))
+ return 1;
+ if ((uids->upper == 0) && (uid == uids->lower))
+ return 1;
+ uids = uids->next;
+ }
+ return 0;
+}
+
+int sh_userfiles_set_uid (const char * str)
+{
+ char * end;
+ const char * p = str;
+ unsigned long lower;
+ unsigned long upper = 0;
+ struct useruidlist * uids;
+
+ while ((p != NULL) && (*p != '\0'))
+ {
+ lower = strtoul(p, &end, 10);
+ if ( (lower == ULONG_MAX) || (end == p))
+ return -1;
+ p = end;
+ if (*p == '-')
+ {
+ ++p;
+ if (*p == '\0')
+ {
+ upper = ULONG_MAX;
+ p = NULL;
+ }
+ else
+ {
+ upper = strtoul(p, &end, 10);
+ if ( (upper == ULONG_MAX) || (end == p))
+ return -1;
+ p = end;
+ if ( (*p != ',') && (*p != '\0'))
+ return -1;
+ if (*p != '\0')
+ ++p;
+ }
+ }
+ else if (*p == '\0')
+ {
+ upper = 0;
+ p = NULL;
+ }
+ else if ((*p == ',') || (*p == ' ') || (*p == '\t'))
+ {
+ upper = 0;
+ ++p;
+ }
+ else
+ {
+ upper = strtoul(p, &end, 10);
+ if ( (upper == ULONG_MAX) || (end == p))
+ return -1;
+ p = end;
+ if ( (*p != ',') && (*p != ' ') && (*p != '\t') && (*p != '\0') )
+ return -1;
+ if (*p != '\0')
+ ++p;
+ }
+ uids = SH_ALLOC(sizeof(struct useruidlist));
+ uids->lower = lower;
+ uids->upper = upper;
+ uids->next = userUids;
+ userUids = uids;
+ /* fprintf(stderr, "range %lu %lu\n", lower, upper); */
+ }
+ return 0;
+}
+
+/* Add 'c' to the list of files (userFiles) relative to any given HOME
+ * directory that should be checked. */
+
+int sh_userfiles_add_file(const char *c) {
+ struct userfileslist *new;
+ char *s, *orig;
+ char *user_filename;
+
+ int default_level = SH_LEVEL_NOIGNORE;
+ char *separator = " ";
+
+ SL_ENTER(_("sh_userfiles_add_file"));
+
+ if( c == NULL )
+ SL_RETURN(-1, _("sh_userfiles_add_file") );
+
+ s = sh_util_strdup(c); /* Maybe c is needed elsewhere */
+ orig = s;
+
+ user_filename = sh_util_strsep(&s, separator);
+
+ if( user_filename == NULL || strlen(user_filename) > PATH_MAX )
+ SL_RETURN(-1, _("sh_userfiles_add_file") );
+
+ new = SH_ALLOC(sizeof(struct userfileslist));
+
+ (void) sl_strlcpy(new->filename, user_filename, PATH_MAX);
+ new->next = userFiles;
+ userFiles = new;
+
+ /* order is important here, since 'log' would match on 'glog'
+ * So, compare longest strings first */
+ if( s == NULL ) /* The default */ new->level = default_level;
+ else if ( strstr(s, _("attributes"))!= NULL ) new->level = SH_LEVEL_ATTRIBUTES;
+ else if ( strstr(s, _("allignore")) != NULL ) new->level = SH_LEVEL_ALLIGNORE;
+ else if ( strstr(s, _("noignore")) != NULL ) new->level = SH_LEVEL_NOIGNORE;
+ else if ( strstr(s, _("logfiles")) != NULL ) new->level = SH_LEVEL_LOGFILES;
+ else if ( strstr(s, _("readonly")) != NULL ) new->level = SH_LEVEL_READONLY;
+ else if ( strstr(s, _("loggrow")) != NULL ) new->level = SH_LEVEL_LOGGROW;
+ else if ( strstr(s, _("user0")) != NULL ) new->level = SH_LEVEL_USER0;
+ else if ( strstr(s, _("user1")) != NULL ) new->level = SH_LEVEL_USER1;
+ else if ( strstr(s, _("user2")) != NULL ) new->level = SH_LEVEL_USER2;
+ else if ( strstr(s, _("user3")) != NULL ) new->level = SH_LEVEL_USER3;
+ else if ( strstr(s, _("user4")) != NULL ) new->level = SH_LEVEL_USER4;
+ else if ( strstr(s, _("prelink")) != NULL ) new->level = SH_LEVEL_PRELINK;
+ else /* The default */ new->level = default_level;
+
+ SH_FREE(orig);
+
+ SL_RETURN(0, _("sh_userfiles_add_file") );
+}
+
+/* Decide if we're active.
+ */
+int sh_userfiles_set_active(const char *c) {
+ int value;
+
+ SL_ENTER(_("sh_userfiles_set_active"));
+ value = sh_util_flagval(c, &ShUserfilesActive);
+ SL_RETURN((value), _("sh_userfiles_set_active"));
+}
+
+/* Build the list of users, then use this to construct the filenames to
+ * be checked. */
+int sh_userfiles_init(struct mod_type * arg) {
+ struct passwd *cur_user;
+ struct userhomeslist *end;
+ struct userhomeslist *new;
+ struct userhomeslist *homes;
+ char * filepath;
+ (void) arg;
+
+ SL_ENTER(_("sh_userfiles_init"));
+
+ /* We need to free anything allocated by the configuration functions if
+ * we find that the module is to be left inactive - otherwise _reconf()
+ * won't quite work. */
+ if( ShUserfilesActive == S_FALSE ) {
+ sh_userfiles_free_homeslist(userHomes);
+ sh_userfiles_free_fileslist(userFiles);
+ userHomes = NULL;
+ userFiles = NULL;
+ SL_RETURN(-1, _("sh_userfiles_init"));
+ }
+
+ /* We build a list in here because the samhain internals want to use
+ * getpwent() too */
+ SH_MUTEX_LOCK(mutex_pwent);
+ /*@-unrecog@*/
+ sh_setpwent();
+ /*@+unrecog@*/
+ while( ( cur_user = /*@-unrecog@*/sh_getpwent()/*@+unrecog@*/ ) != NULL ) {
+ int found = 0;
+
+ if (0 == sh_userfiles_check_uid( (unsigned long) cur_user->pw_uid))
+ continue;
+
+ for( end = userHomes; end != NULL; end = end->next ) {
+ if( sl_strcmp( end->pw_dir, cur_user->pw_dir) == 0 ) {
+ found = 1; /* Found a match, so flag it and stop searching */
+ break;
+ }
+ }
+
+ if( found == 0 ) {
+ /* Didn't find it, so add to the front of the list */
+ new = SH_ALLOC(sizeof(struct userhomeslist) );
+ new->next = userHomes;
+ new->pw_dir = sh_util_strdup(cur_user->pw_dir);
+
+ userHomes = new;
+ }
+ }
+ sh_endpwent();
+ SH_MUTEX_UNLOCK(mutex_pwent);
+
+ filepath = SH_ALLOC(PATH_MAX);
+
+ for (homes = userHomes; homes != NULL; homes = homes->next ) {
+ struct userfileslist *file_ptr;
+
+ for (file_ptr = userFiles; file_ptr != NULL; file_ptr = file_ptr->next) {
+ (void) sl_strncpy(filepath, homes->pw_dir, PATH_MAX);
+ (void) sl_strncat(filepath, "/", PATH_MAX);
+ (void) sl_strncat(filepath, file_ptr->filename, PATH_MAX);
+
+ switch(file_ptr->level) {
+ case SH_LEVEL_READONLY:
+ (void) sh_files_pushfile_ro(filepath);
+ break;
+ case SH_LEVEL_LOGFILES:
+ (void) sh_files_pushfile_log(filepath);
+ break;
+ case SH_LEVEL_LOGGROW:
+ (void) sh_files_pushfile_glog(filepath);
+ break;
+ case SH_LEVEL_NOIGNORE:
+ (void) sh_files_pushfile_noig(filepath);
+ break;
+ case SH_LEVEL_ALLIGNORE:
+ (void) sh_files_pushfile_allig(filepath);
+ break;
+ case SH_LEVEL_ATTRIBUTES:
+ (void) sh_files_pushfile_attr(filepath);
+ break;
+ case SH_LEVEL_USER0:
+ (void) sh_files_pushfile_user0(filepath);
+ break;
+ case SH_LEVEL_USER1:
+ (void) sh_files_pushfile_user1(filepath);
+ break;
+ case SH_LEVEL_USER2:
+ (void) sh_files_pushfile_user2(filepath);
+ break;
+ case SH_LEVEL_USER3:
+ (void) sh_files_pushfile_user3(filepath);
+ break;
+ case SH_LEVEL_USER4:
+ (void) sh_files_pushfile_user4(filepath);
+ break;
+ case SH_LEVEL_PRELINK:
+ (void) sh_files_pushfile_prelink(filepath);
+ break;
+ default: /* Should not reach here */
+ break;
+ }
+ }
+ }
+
+ SH_FREE(filepath);
+
+ SL_RETURN(0, _("sh_userfiles_init"));
+}
+
+/* This is pretty much NULL; we don't do anything in our checking routine,
+ * so we never need to run it. Just use tcurrent to avoid compiler warnings. */
+int sh_userfiles_timer(time_t tcurrent) {
+ SL_ENTER(_("sh_userfiles_timer"));
+ tcurrent = 0;
+ SL_RETURN((int)tcurrent, _("sh_userfiles_timer"));
+}
+
+int sh_userfiles_check(void) {
+ SL_ENTER(_("sh_userfiles_check"));
+ SL_RETURN(0, _("sh_userfiles_check"));
+}
+
+/* Free our lists and the associated memory */
+
+int sh_userfiles_cleanup(void) {
+ SL_ENTER(_("sh_userfiles_cleanup"));
+
+ sh_userfiles_free_homeslist(userHomes);
+ sh_userfiles_free_fileslist(userFiles);
+ sh_userfiles_free_uidslist (userUids);
+
+ SL_RETURN(0, _("sh_userfiles_cleanup"));
+}
+
+/* As with sh_userfiles_cleanup, but in preparation for re-reading the
+ * configuration files */
+
+int sh_userfiles_reconf(void) {
+ SL_ENTER(_("sh_userfiles_reconf"));
+
+ sh_userfiles_free_homeslist(userHomes);
+ sh_userfiles_free_fileslist(userFiles);
+ sh_userfiles_free_uidslist (userUids);
+
+ userHomes = NULL;
+ userFiles = NULL;
+ userUids = NULL;
+
+ ShUserfilesActive = S_TRUE;
+
+ SL_RETURN(0, _("sh_userfiles_reconf"));
+}
+
+/* Recurse to the end of the list and then free the data as we return
+ * back up towards the start, making sure to free any strdupped strings
+ */
+
+static void sh_userfiles_free_homeslist(struct userhomeslist *head) {
+ if( head != NULL ) {
+ sh_userfiles_free_homeslist(head->next);
+ SH_FREE(head->pw_dir);
+ SH_FREE(head);
+ }
+}
+
+/* Recurse to the end of the list and then free the data as we return
+ * back up towards the start */
+
+static void sh_userfiles_free_fileslist(struct userfileslist *head) {
+ if( head != NULL ) {
+ sh_userfiles_free_fileslist(head->next);
+ SH_FREE(head);
+ }
+}
+
+/* Recurse to the end of the list and then free the data as we return
+ * back up towards the start */
+
+static void sh_userfiles_free_uidslist(struct useruidlist *head) {
+ if( head != NULL ) {
+ sh_userfiles_free_uidslist(head->next);
+ SH_FREE(head);
+ }
+}
+
+/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
+#endif
+
+/* #ifdef SH_USE_USERFILES */
+#endif
diff --git a/src/sh_utils.c b/src/sh_utils.c
new file mode 100644
index 0000000..4a162c2
--- /dev/null
+++ b/src/sh_utils.c
@@ -0,0 +1,2437 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+
+#include "samhain.h"
+#include "sh_error.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_tiger.h"
+#include "sh_entropy.h"
+#include "sh_pthread.h"
+
+#undef FIL__
+#define FIL__ _("sh_utils.c")
+
+UINT32 ErrFlag[2];
+
+int sh_util_flagval(const char * c, int * fval)
+{
+ SL_ENTER(_("sh_util_flagval"));
+ if (c == NULL)
+ SL_RETURN( (-1), _("sh_util_flagval"));
+ if ( c[0] == '1' || c[0] == 'y' || c[0] == 'Y' ||
+ c[0] == 't' || c[0] == 'T')
+ {
+ *fval = S_TRUE;
+ SL_RETURN( (0), _("sh_util_flagval"));
+ }
+ if ( c[0] == '0' || c[0] == 'n' || c[0] == 'N' ||
+ c[0] == 'f' || c[0] == 'F')
+ {
+ *fval = S_FALSE;
+ SL_RETURN( (0), _("sh_util_flagval"));
+ }
+ SL_RETURN( (-1), _("sh_util_flagval"));
+}
+
+int sh_util_timeout_check (SH_TIMEOUT * sh_timer)
+{
+ UINT64 now = (UINT64) time(NULL);
+ UINT64 dif;
+
+ if (sh_timer->flag_ok == S_FALSE)
+ {
+ /* first time
+ */
+ if (sh_timer->time_last == 0)
+ {
+ sh_timer->time_last = now;
+ return S_TRUE;
+ }
+ /* later on
+ */
+ dif = now - sh_timer->time_last;
+ if (dif < sh_timer->time_dist)
+ {
+ return S_FALSE;
+ }
+ sh_timer->time_last = now;
+ return S_TRUE;
+ }
+ sh_timer->time_last = now;
+ return S_FALSE;
+}
+
+static int sh_ask_update = S_FALSE;
+
+int sh_util_set_interactive(const char * str)
+{
+ (void) str;
+
+ sh_ask_update = S_TRUE;
+ sh_unix_setnodeamon(NULL);
+
+ return 0;
+}
+
+static char * sh_update_file = NULL;
+
+int sh_util_update_file (const char * str)
+{
+ if (str)
+ {
+ if (0 == access(str, R_OK)) /* flawfinder: ignore */
+ {
+ if (NULL != sh_update_file)
+ SH_FREE(sh_update_file);
+ sh_update_file = sh_util_strdup(str);
+ sh_ask_update = S_TRUE;
+ sh_unix_setnodeamon(NULL);
+ return 0;
+ }
+ else
+ {
+ char ebuf[SH_ERRBUF_SIZE];
+ int errnum = errno;
+
+ sh_error_message(errnum, ebuf, sizeof(ebuf));
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ ebuf, _("sh_util_update_file") );
+
+ return -1;
+ }
+ }
+
+ return -1;
+}
+
+
+#if !defined(STDIN_FILENO)
+#define STDIN_FILENO 0
+#endif
+#if !defined(STDERR_FILENO)
+#define STDERR_FILENO 0
+#endif
+
+/* Returns S_FALSE if no update desired
+ */
+int sh_util_update_checkfile(const char * path)
+{
+ FILE * fd = fopen(sh_update_file, "r");
+ char * line;
+
+ if (!fd)
+ {
+ uid_t euid;
+ int errnum = errno;
+ sl_get_euid(&euid);
+ sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_NOACCESS,
+ (long) euid, sh_update_file);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ return S_FALSE;
+ }
+
+ line = SH_ALLOC(8192);
+
+ while (NULL != fgets(line, 8192, fd))
+ {
+ char * nl = strrchr(line, '\n');
+
+ if (nl)
+ {
+ *nl = '\0';
+
+ /* Check for MS Windows line terminator
+ */
+ if (nl > line) --nl;
+ if (*nl == '\r')
+ *nl = '\0';
+ }
+
+ if (0 == sl_strcmp(line, path))
+ {
+ SH_FREE(line);
+ fclose(fd);
+ return S_TRUE;
+ }
+ }
+ SH_FREE(line);
+ fclose(fd);
+ return S_FALSE;
+}
+
+/* Returns S_FALSE if no update desired
+ */
+int sh_util_ask_update(const char * path)
+{
+ int inchar, c;
+ int i = S_TRUE;
+ char * tmp = NULL;
+
+ SL_ENTER(_("sh_util_ask_update"));
+
+ if (sh_ask_update != S_TRUE)
+ {
+ SL_RETURN(i, _("sh_util_ask_update"));
+ }
+
+ if (sh_update_file)
+ {
+ i = sh_util_update_checkfile(path);
+ SL_RETURN(i, _("sh_util_ask_update"));
+ }
+
+#ifdef HAVE_TTYNAME
+ if (!ttyname(STDIN_FILENO))
+ {
+ if (NULL != ttyname(STDERR_FILENO))
+ {
+ /* cppcheck-suppress leakReturnValNotUsed */
+ if (NULL == freopen(ttyname(STDERR_FILENO), "r", stdin))
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0,
+ MSG_E_SUBGEN,
+ _("Cannot continue: stdin is not a terminal"),
+ _("sh_util_ask_update"));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, 0,
+ MSG_E_SUBGEN,
+ _("Cannot continue: stdin is not a terminal"),
+ _("sh_util_ask_update"));
+ exit(EXIT_FAILURE);
+ }
+ }
+#endif
+
+ if (sh_ask_update == S_TRUE)
+ {
+ tmp = sh_util_safe_name (path);
+ fprintf (stderr, _("Update %s [Y/n] ? "), tmp);
+ SH_FREE(tmp);
+ while (1 == 1)
+ {
+ c = fgetc(stdin); inchar = c;
+ /*@+charintliteral@*/
+ while (c != '\n' && c != EOF)
+ c = fgetc(stdin);
+ /* fprintf(stderr, "CHAR (1): %c\n", inchar); */
+ if (inchar == 'Y' || inchar == 'y' || inchar == '\n')
+ {
+ break;
+ }
+ else if (inchar == 'n' || inchar == 'N')
+ {
+ i = S_FALSE;
+ break;
+ }
+ else
+ {
+ fprintf(stderr, "%s", _("Please answer y(es) or n(o)\n"));
+ }
+ /*@-charintliteral@*/
+ }
+ }
+
+ SL_RETURN(i, _("sh_util_ask_update"));
+}
+
+int sh_util_hidesetup(const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_util_hidesetup"));
+ i = sh_util_flagval(c, &(sh.flag.hidefile));
+
+ SL_RETURN(i, _("sh_util_hidesetup"));
+}
+
+char * sh_util_acl_compact(char * buf, ssize_t len)
+{
+ unsigned char * p = (unsigned char *) buf;
+ int state = 0;
+ ssize_t rem = 0;
+ char * out;
+
+ SH_VALIDATE_NE(buf, NULL);
+ SH_VALIDATE_GE(len, 0);
+
+ out = SH_ALLOC(len + 1);
+
+ while (*p != '\0') {
+
+ /* -- not at start or after newline
+ */
+ if (state == 1) {
+ if (*p == '\n' || *p == ' ' || *p == '\t' || *p == '#') {
+ while (*p != '\n') {
+ ++p;
+ if (*p == '\0') {
+ goto exit_it;
+ }
+ }
+ out[rem] = ','; ++rem; /* <-- ensures (rem > 0) is true */
+ while (p[1] == '\n') ++p; /* scan over consecutive newlines */
+ state = 0;
+ if (p[1] == '\0') {
+ out[rem-1] = '\0'; /* rem > 0 because of 4 lines above */
+ break;
+ }
+ }
+ else {
+ if (*p <= 0x7F && isgraph((int) *p)) {
+ out[rem] = (char) *p; ++rem;
+ }
+ }
+ }
+
+ /* -- at start or after newline
+ */
+ else /* if (state == 0) */ {
+ if (0 == strncmp((char *) p, "user", 4)) {
+ out[rem] = 'u'; ++rem;
+ p += 3;
+ } else if (0 == strncmp((char *) p, "group", 5)) {
+ out[rem] = 'g'; ++rem;
+ p += 4;
+ } else if (0 == strncmp((char *) p, "mask", 4)) {
+ out[rem] = 'm'; ++rem;
+ p += 3;
+ } else if (0 == strncmp((char *) p, "other", 5)) {
+ out[rem] = 'o';
+ p += 4; ++rem;
+ } else if (*p == '\0') {
+ if (rem > 0) { out[rem-1] = '\0'; }
+ break;
+ } else {
+ if (*p <= 0x7F && isprint((int) *p)) {
+ out[rem] = (char) *p; ++rem;
+ }
+ }
+ state = 1;
+ }
+ ++p;
+ }
+ exit_it:
+ out[rem] = '\0';
+ return out;
+}
+
+
+char * sh_util_strdup_l (const char * str, size_t len)
+{
+ char * p = NULL;
+
+ SL_ENTER(_("sh_util_strdup_l"));
+
+ SH_VALIDATE_NE(str, NULL);
+ SH_VALIDATE_NE(len, 0);
+
+ if (str && sl_ok_adds (len, 1))
+ {
+ p = SH_ALLOC (len + 1);
+ (void) memcpy (p, str, len+1);
+ }
+ else
+ {
+ safe_fatal(_("integer overflow in sh_util_strdup_l"), FIL__, __LINE__);
+ }
+ SL_RETURN( p, _("sh_util_strdup_l"));
+}
+
+char * sh_util_strdup (const char * str)
+{
+ char * p = NULL;
+ size_t len;
+
+ SL_ENTER(_("sh_util_strdup"));
+
+ SH_VALIDATE_NE(str, NULL);
+
+ if (str)
+ {
+ len = sl_strlen(str);
+ p = SH_ALLOC (len + 1);
+ (void) memcpy (p, str, len+1);
+ }
+ SL_RETURN( p, _("sh_util_strdup"));
+}
+
+char * sh_util_strdup_track (const char * str, char * file, int line)
+{
+ char * p = NULL;
+ size_t len;
+
+ SL_ENTER(_("sh_util_strdup_track"));
+
+ SH_VALIDATE_NE(str, NULL);
+
+ if (str)
+ {
+ len = sl_strlen(str);
+ p = SH_OALLOC (len + 1, file, line);
+ (void) memcpy (p, str, len+1);
+ }
+ SL_RETURN( p, _("sh_util_strdup_track"));
+}
+
+/* by the eircom.net computer incident
+ * response team
+ */
+char * sh_util_strsep (char **str, const char *delim)
+{
+ char *ret, *c;
+ const char *d;
+
+ SL_ENTER(_("sh_util_strsep"));
+ ret = *str;
+
+ SH_VALIDATE_NE(ret, NULL);
+
+ if (*str)
+ {
+ for (c = *str; *c != '\0'; c++) {
+ for (d = delim; *d != '\0'; d++) {
+ if (*c == *d) {
+ *c = '\0';
+ *str = c + 1;
+ SL_RETURN(ret, _("sh_util_strsep"));
+ }
+ }
+ }
+ }
+
+ /* If we get to here, there's no delimiters in the string */
+ *str = NULL;
+ SL_RETURN(ret, _("sh_util_strsep"));
+}
+
+
+/* returned string must be free'd by caller.
+ */
+char * sh_util_formatted (const char * formatt, st_format * ftab)
+{
+ struct tm * time_ptr;
+ size_t size;
+ size_t isiz;
+ char * fmt = NULL;
+ char * p;
+ char * q;
+ char * outstr;
+ int i;
+ int j;
+ time_t inpp;
+
+ char * clist[16] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ int nn = 0;
+
+ SL_ENTER(_("sh_util_formatted"));
+
+ if (formatt == NULL || ftab == NULL || *formatt == '\0')
+ SL_RETURN(NULL, _("sh_util_formatted"));
+
+ /* -- save the format (we overwrite it !!) --
+ */
+ size = sl_strlen(formatt);
+
+ if (!sl_ok_adds(size, 1))
+ SL_RETURN(NULL, _("sh_util_formatted"));
+
+ ++size;
+ fmt = SH_ALLOC(size);
+ (void) sl_strlcpy(fmt, formatt, size);
+
+ p = fmt;
+
+ j = 0;
+ while (ftab[j].fchar != '\0') {
+ if (ftab[j].type != S_FMT_STRING)
+ ftab[j].data_str = NULL;
+ ++j;
+ }
+
+ while (p != NULL && *p != '\0' && NULL != (q = strchr(p, '%')))
+ {
+ ++q;
+
+ /* fprintf(stderr, "p == %s q == %s\n", p, q); */
+
+ /* -- end of string is a '%' --
+ */
+ if (*q == '\0')
+ {
+ --q;
+ *q = '\0';
+ break;
+ }
+
+ i = 0;
+ j = 0;
+
+ /* -- search the format char in input table --
+ * put (nn < 16) here -> all remaining %foo will be
+ * converted to %%
+ */
+ while (ftab[j].fchar != '\0' && nn < 16)
+ {
+ if (ftab[j].fchar == *q)
+ {
+ /* -- Convert it to a string format (%s). --
+ */
+ *q = 's'
+;
+ i = 1;
+
+ switch(ftab[j].type) {
+
+ case S_FMT_STRING:
+ {
+ isiz = sl_strlen(ftab[j].data_str);
+ if (isiz > 0 && sl_ok_adds(size, isiz))
+ {
+ size += isiz;
+ clist[nn] = ftab[j].data_str;
+ ++nn;
+ }
+ else
+ *q = '%';
+ goto endsrch;
+ }
+ break;
+
+ case S_FMT_ULONG:
+ {
+ ftab[j].data_str = (char *) SH_ALLOC(64);
+ /*@-bufferoverflowhigh@*/
+ sprintf (ftab[j].data_str, "%lu", /* known to fit */
+ ftab[j].data_ulong);
+ /*@+bufferoverflowhigh@*/
+ isiz = sl_strlen(ftab[j].data_str);
+ if (isiz > 0 && sl_ok_adds(size, isiz))
+ {
+ size += isiz;
+ clist[nn] = ftab[j].data_str;
+ ++nn;
+ }
+ else
+ *q = '%';
+ goto endsrch;
+ }
+ break;
+
+ case S_FMT_LONG:
+ {
+ ftab[j].data_str = (char *) SH_ALLOC(64);
+ /*@-bufferoverflowhigh@*/
+ sprintf (ftab[j].data_str, "%ld", /* known to fit */
+ ftab[j].data_long);
+ /*@+bufferoverflowhigh@*/
+ isiz = sl_strlen(ftab[j].data_str);
+ if (isiz > 0 && sl_ok_adds(size, isiz))
+ {
+ size += isiz;
+ clist[nn] = ftab[j].data_str;
+ ++nn;
+ }
+ else
+ *q = '%';
+ goto endsrch;
+ }
+ break;
+
+ case S_FMT_TIME:
+ {
+ ftab[j].data_str = (char *) SH_ALLOC(64);
+ inpp = (time_t)ftab[j].data_ulong;
+ if (inpp != 0)
+ {
+ time_ptr = localtime (&(inpp));
+ if (time_ptr != NULL)
+ (void) strftime(ftab[j].data_str, 64,
+ _("%d-%m-%Y %H:%M:%S"), time_ptr);
+ else
+ (void) sl_strlcpy(ftab[j].data_str,
+ _("00-00-0000 00:00:00"), 64);
+ }
+ else
+ {
+ (void) sl_strlcpy(ftab[j].data_str,
+ _("(None)"), 64);
+ }
+ isiz = sl_strlen(ftab[j].data_str);
+ if (isiz > 0 && sl_ok_adds(size, isiz))
+ {
+ size += isiz;
+ clist[nn] = ftab[j].data_str;
+ ++nn;
+ }
+ else
+ *q = '%';
+ goto endsrch;
+ }
+ break;
+
+ default:
+ /* do nothing */;
+ }
+
+ }
+ ++j;
+ }
+
+ endsrch:
+
+ p = q;
+
+ /* -- not found -- */
+ if (i == 0)
+ {
+ *q = '%';
+ ++p;
+ }
+
+ }
+
+ /* -- Format string evaluated.
+ clist[] List of strings
+ size Total size of format string + clist[] strings
+ -- */
+
+ /* -- closing '\0' --
+ */
+ if (sl_ok_adds(size, 1))
+ size++;
+ outstr = (char *) SH_ALLOC(size);
+
+ /* -- print it --
+ */
+ (void) sl_snprintf( outstr, size, fmt,
+ clist[0], clist[1], clist[2], clist[3],
+ clist[4], clist[5], clist[6], clist[7],
+ clist[8], clist[9], clist[10], clist[11],
+ clist[12], clist[13], clist[14], clist[15]);
+ outstr[size-1] = '\0';
+
+ /* -- cleanup --
+ */
+ j = 0;
+ while (ftab[j].fchar != '\0') {
+ if (ftab[j].type != S_FMT_STRING && ftab[j].data_str != NULL)
+ SH_FREE(ftab[j].data_str);
+ ++j;
+ }
+ SH_FREE(fmt);
+
+ SL_RETURN(outstr, _("sh_util_formatted"));
+}
+
+/* read a hexchar, return int value (0-15)
+ * can't inline (AIX)
+ */
+int sh_util_hexchar( const char c )
+{
+ /*@+charint@*/
+ if ( c >= '0' && c <= '9' )
+ return c - '0';
+ else if ( c >= 'a' && c <= 'f' )
+ return c - 'a' + 10;
+ else if ( c >= 'A' && c <= 'F' )
+ return c - 'A' + 10;
+ else return -1;
+ /*@-charint@*/
+}
+
+char * sh_util_charhex( unsigned char i , char * i2h)
+{
+ int j, k;
+
+ j = i / 16;
+ k = i - (j*16);
+
+ if (j < 10) i2h[0] = '0'+j;
+ else i2h[0] = 'A'+(j-10);
+
+ if (k < 10) i2h[1] = '0'+k;
+ else i2h[1] = 'A'+(k-10);
+
+ return i2h;
+}
+
+/* read a hexadecimal key, convert to binary
+ */
+int sh_util_hextobinary (char * binary, const char * hex, int bytes)
+{
+ int i = 0, j, k, l = 0;
+ char c;
+
+#define SH_HEXCHAR(x, y) \
+ c = (x); \
+ if ( c >= '0' && c <= '9' ) \
+ y = c - '0'; \
+ else if ( c >= 'a' && c <= 'f' ) \
+ y = c - 'a' + 10; \
+ else if ( c >= 'A' && c <= 'F' ) \
+ y = c - 'A' + 10; \
+ else \
+ SL_RETURN((-1), _("sh_util_hextobinary"))
+
+
+ SL_ENTER(_("sh_util_hextobinary"));
+
+ if (bytes < 2)
+ SL_RETURN((-1), _("sh_util_hextobinary"));
+
+ while (i < (bytes-1))
+ {
+ SH_HEXCHAR(hex[i], k);
+ SH_HEXCHAR(hex[i+1], j);
+
+ binary[l] = (char)(k * 16 + j);
+ ++l; i+= 2;
+ }
+
+ SL_RETURN((0), _("sh_util_hextobinary"));
+}
+
+static void copy_four (unsigned char * dest, UINT32 in)
+{
+ UINT32 i, j;
+ int count;
+
+ SL_ENTER(_("copy_four"));
+ for (count = 0; count < 4; ++count)
+ {
+ i = in / 256;
+ j = in - (i*256);
+ dest[count] = (unsigned char) j;
+ in = i;
+ }
+ SL_RET0(_("copy_four"));
+}
+
+/* compute HMAC-TIGER
+ */
+static char * sh_util_hmac_tiger (char * hexkey,
+ char * text, size_t textlen,
+ char * res, size_t len)
+{
+ static char opad[KEY_BLOCK] = {
+ (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C,
+ (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C,
+ (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C,
+ (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C
+ };
+ static char ipad[KEY_BLOCK] = {
+ (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36,
+ (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36,
+ (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36,
+ (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36
+ };
+ static char zap[KEY_BLOCK] = {
+ (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00,
+ (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00,
+ (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00,
+ (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00
+ };
+ char K[KEY_BLOCK];
+ char outer[KEY_BLOCK];
+ char * inner;
+ UINT32 * h1;
+ UINT32 * h2;
+ UINT32 cc[KEY_LEN/4];
+ UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
+ char hashbuf[KEYBUF_SIZE];
+
+ int result;
+ size_t i;
+
+ SL_ENTER(_("sh_util_hmac_tiger"));
+
+ ASSERT((KEY_BLOCK <= (KEY_LEN/2)), _("KEY_BLOCK <= (KEY_LEN/2)"));
+
+ memcpy (K, zap, KEY_BLOCK);
+
+ result = sh_util_hextobinary (K, hexkey, KEY_LEN);
+
+ ASSERT((result >= 0), _("result >= 0"));
+
+ if ((result >= 0) && sl_ok_adds(textlen, KEY_BLOCK))
+ {
+ inner = (char *) SH_ALLOC (textlen + KEY_BLOCK);
+
+ for (i = 0; i < KEY_BLOCK; ++i)
+ {
+ outer[i] = K[i] ^ opad[i];
+ inner[i] = K[i] ^ ipad[i];
+ }
+ for (i = KEY_BLOCK; i < (KEY_BLOCK+textlen); ++i)
+ {
+ inner[i] = text[i - KEY_BLOCK];
+ }
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("integer overflow"),
+ _("sh_util_hmac_tiger"));
+ (void) sh_tiger_hash (NULL, TIGER_DATA, 0, hashbuf, sizeof(hashbuf));
+ sl_strlcpy(res, hashbuf, len);
+ SL_RETURN(res, _("sh_util_hmac_tiger"));
+ }
+
+ /* now compute the hash
+ */
+ h1 = sh_tiger_hash_uint32 ( outer, TIGER_DATA, KEY_BLOCK,
+ kbuf, KEY_BYT/sizeof(UINT32));
+ for (i = 0; i < (KEY_LEN/8); ++i)
+ copy_four ( (unsigned char *) &(cc[i]), h1[i]);
+
+ h2 = sh_tiger_hash_uint32 ( inner, TIGER_DATA,
+ (unsigned long) KEY_BLOCK+textlen,
+ kbuf, KEY_BYT/sizeof(UINT32));
+ for (i = KEY_LEN/8; i < (KEY_LEN/4); ++i)
+ copy_four ( (unsigned char *) &(cc[i]), h2[i - (KEY_LEN/8)]);
+
+ SH_FREE(inner);
+
+ (void) sh_tiger_hash ((char *) &cc[0],
+ TIGER_DATA,
+ (unsigned long) (KEY_LEN/4 * sizeof(UINT32)),
+ hashbuf, sizeof(hashbuf));
+
+ sl_strlcpy(res, hashbuf, len);
+ SL_RETURN(res, _("sh_util_hmac_tiger"));
+}
+
+static char * sh_util_hash_tiger ( char * hexkey,
+ char * text, size_t textlen,
+ char * res, size_t len)
+{
+ char h2[2*KEY_LEN+1];
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_util_hash_tiger"));
+
+ (void) sl_strlcpy(h2, hexkey, KEY_LEN+1);
+ (void) sl_strlcat(h2,
+ sh_tiger_hash(text, TIGER_DATA,
+ (unsigned long) textlen,
+ hashbuf, sizeof(hashbuf)),
+ 2*KEY_LEN+1
+ );
+
+ (void) sh_tiger_hash(h2, TIGER_DATA, 2*KEY_LEN, hashbuf, sizeof(hashbuf));
+
+ sl_strlcpy(res, hashbuf, len);
+ SL_RETURN(res, _("sh_util_hash_tiger"));
+}
+
+/* --- compute signature on data ---
+ */
+#define TYPE_HMAC 0
+#define TYPE_HASH 1
+
+static int sigtype = TYPE_HMAC;
+
+int sh_util_sigtype (const char * c)
+{
+ SL_ENTER(_("sh_util_sigtype"));
+ if (c == NULL)
+ SL_RETURN( -1, _("sh_util_sigtype"));
+
+ if (0 == strcmp(_("HMAC-TIGER"), c))
+ sigtype = TYPE_HMAC;
+ else if (0 == strcmp(_("HASH-TIGER"), c))
+ sigtype = TYPE_HASH;
+ else
+ SL_RETURN( -1, _("sh_util_sigtype"));
+
+ SL_RETURN( 0, _("sh_util_sigtype"));
+}
+
+char * sh_util_siggen (char * hexkey,
+ char * text, size_t textlen,
+ char * res, size_t len)
+{
+ char * p;
+
+ SL_ENTER(_("sh_util_siggen"));
+ if (sigtype == TYPE_HMAC)
+ p = sh_util_hmac_tiger (hexkey,
+ text, textlen, res, len);
+ else
+ p = sh_util_hash_tiger (hexkey,
+ text, textlen, res, len);
+ SL_RETURN(p, _("sh_util_siggen"));
+}
+
+
+/* a simple compressor
+ */
+size_t sh_util_compress (char * dest, char * src, size_t dest_size)
+{
+ char * add;
+ char * get;
+ size_t count = 0;
+ size_t dest_end;
+
+ SL_ENTER(_("sh_util_compress"));
+
+ if (dest_size == 0)
+ SL_RETURN((0), _("sh_util_compress"));
+
+ if ((dest == NULL) || (src == NULL))
+ SL_RETURN((0), _("sh_util_compress"));
+
+ dest_end = sl_strlen(dest);
+
+ if (dest_end > dest_size)
+ SL_RETURN((0), _("sh_util_compress"));
+
+ add = &dest[dest_end];
+ get = src;
+
+ while (count < (dest_size-dest_end))
+ {
+ if (isalnum((int) *get))
+ {
+ *add = *get;
+ ++add;
+ ++count;
+ }
+ ++get;
+ if (*get == '\0' && (count < (dest_size-dest_end)))
+ /* end of src reached */
+ {
+ *add = *get; /* copy the '\0' */
+ break; /* and stop copying */
+ }
+ }
+
+ dest[dest_size-1] = '\0'; /* paranoia */
+ SL_RETURN((count), _("sh_util_compress")); /* no of chars copied */
+}
+
+
+/* copy the four least significant bytes
+ */
+void sh_util_cpylong (char * dest, const char * src, int len )
+{
+ int i, j;
+ union
+ {
+ long l;
+ char c[sizeof(long)];
+ } u;
+#ifdef WORDS_BIGENDIAN
+ unsigned char swap;
+ unsigned char * ii = (unsigned char *) dest;
+#endif
+
+ SL_ENTER(_("sh_util_cpylong"));
+
+ u.l = 1;
+
+ /* MSB is first
+ */
+ if (sizeof(long)>4 &&/*@+charint@*/(u.c[sizeof(long)-1] == 1)/*@-charint@*/)
+ {
+ j = (int) (sizeof(long)-4);
+ for (i = 0; i < j; ++i) ++src;
+ }
+
+ i = 0;
+
+ while (i < 4)
+ {
+ *dest = (*src);
+ ++dest; ++src;
+ if (i == (len-1)) break;
+ ++i;
+ }
+#ifdef WORDS_BIGENDIAN
+ swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
+ swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
+#endif
+ SL_RET0(_("sh_util_cpylong"));
+}
+
+/* This is a maximally equidistributed combined Tausworthe
+ * generator. The sequence is,
+ *
+ * x_n = (s1_n ^ s2_n ^ s3_n)
+ *
+ * s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
+ * s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
+ * s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
+ *
+ * computed modulo 2^32. In the three formulas above '^' means
+ * exclusive-or (C-notation), not exponentiation. Note that the
+ * algorithm relies on the properties of 32-bit unsigned integers (it
+ * is formally defined on bit-vectors of length 32).
+ *
+ * Stolen from GSL (GNU scientific library) and modified somewhat.
+ * I am using UINT32, which is guaranteed to be 32 bits. Also made
+ * sure that the initialization vector is valid.
+ */
+
+
+/* interval [0, 4294967295]
+ */
+static UINT32 taus_get_long (void *vstate)
+{
+ UINT32 * state = (UINT32 *) vstate;
+
+ /*
+ if (skey->rngI == BAD)
+ (void)taus_seed();
+ */
+
+#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
+ /*@+ignorequals@*/
+ state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
+ state[1] = TAUSWORTHE (state[1], 2, 25, 4294967288UL, 4);
+ state[2] = TAUSWORTHE (state[2], 3, 11, 4294967280UL, 17);
+ /*@-ignorequals@*/
+ return (state[0] ^ state[1] ^ state[2]);
+}
+
+/* Hide the internal state of the PRNG by using its output as
+ * input for a one-way hash function.
+ */
+
+UINT32 taus_get ()
+{
+#define TAUS_SAMPLE 12
+
+ UINT32 taus_svec[TAUS_SAMPLE];
+ UINT32 retval;
+ UINT32 * res;
+ UINT32 * res_vec = &(skey->res_vec[0]);
+ static int res_num = 0;
+ register int i;
+ UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ if (res_num > 0)
+ {
+ retval = res_vec[res_num];
+ res_num = (res_num == 5) ? 0 : (res_num + 1);
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */
+ return retval;
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+
+ (void)taus_seed();
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ for (i = 0; i < (TAUS_SAMPLE/3); ++i)
+ {
+ taus_svec[i*3] = taus_get_long (&(skey->rng0[0]));
+ taus_svec[i*3+1] = taus_get_long (&(skey->rng1[0]));
+ taus_svec[i*3+2] = taus_get_long (&(skey->rng2[0]));
+ }
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+
+ res = sh_tiger_hash_uint32 ( (char *) &taus_svec[0],
+ TIGER_DATA,
+ (unsigned long)(TAUS_SAMPLE * sizeof(UINT32)),
+ kbuf, KEY_BYT/sizeof(UINT32));
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ for (i = 1; i < 6; ++i)
+ {
+ res_vec[i] = res[i];
+ }
+ retval = res[0];
+ res_num = 1;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+
+ memset(taus_svec, '\0', TAUS_SAMPLE * sizeof(UINT32));
+
+ return retval;
+}
+
+/* interval [0,1)
+ */
+double taus_get_double (void *vstate)
+{
+ return taus_get_long (vstate) / (4294967296.0 + 1.0) ;
+}
+
+#define LCG(n) ((69069 * n) & 0xffffffffUL)
+
+/* TAKE CARE: state[0], state[1], state[2] must be > 2,8,16, respectively
+ */
+static void taus_set_from_ulong (void *vstate, unsigned long int s)
+{
+ UINT32 *state = (UINT32 *) vstate;
+
+ if (s == 0)
+ s = 1; /* default seed is 1 */
+
+ state[0] = (UINT32)(LCG (s) | (UINT32) 0x03);
+ state[1] = (UINT32)(LCG (state[0]) | (UINT32) 0x09);
+ state[2] = (UINT32)(LCG (state[1]) | (UINT32) 0x17);
+
+ /* 'warm up'
+ */
+ (void) taus_get_long (state);
+ (void) taus_get_long (state);
+ (void) taus_get_long (state);
+ (void) taus_get_long (state);
+ (void) taus_get_long (state);
+ (void) taus_get_long (state);
+
+ return;
+}
+
+static void taus_set_from_state (void *vstate, void *init_state)
+{
+ UINT32 *state = (UINT32 *) vstate;
+ UINT32 *state0 = (UINT32 *) init_state;
+
+ state[0] = state0[0] | (UINT32) 0x03;
+ state[1] = state0[1] | (UINT32) 0x09;
+ state[2] = state0[2] | (UINT32) 0x17;
+
+ return;
+}
+
+
+int taus_seed ()
+{
+ char bufx[9 * sizeof(UINT32) + 1];
+ int status;
+ static unsigned long seed_time = 0;
+ static unsigned long seed_counter = 3000;
+ unsigned long gtime;
+
+ SL_ENTER(_("taus_seed"));
+
+ if (skey->rngI == GOOD)
+ {
+ ++seed_counter;
+
+ if ( ((sh_unix_longtime () - seed_time) < 1800) &&
+ ( seed_counter < 3000))
+ SL_RETURN( (0), _("taus_seed"));
+ }
+
+ seed_time = sh_unix_longtime ();
+ seed_counter = 0;
+
+ status = sh_entropy (24, bufx);
+
+ if (!SL_ISERROR(status))
+ {
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ memcpy (&skey->rng0[0], &bufx[0], 2*sizeof(UINT32));
+ memcpy (&skey->rng1[0], &bufx[2*sizeof(UINT32)], 2*sizeof(UINT32));
+ memcpy (&skey->rng2[0], &bufx[4*sizeof(UINT32)], 2*sizeof(UINT32));
+ memset (bufx, 0, 9 * sizeof(UINT32) + 1);
+
+ skey->rng0[2] = 0;
+ skey->rng1[2] = 0;
+ skey->rng2[2] = 0;
+
+ taus_set_from_state( &(skey->rng0[0]), &(skey->rng0[0]));
+ taus_set_from_state( &(skey->rng1[0]), &(skey->rng1[0]));
+ taus_set_from_state( &(skey->rng2[0]), &(skey->rng2[0]));
+
+ skey->rngI = GOOD;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+ SL_RETURN( (0), _("taus_seed"));
+ }
+
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_ES_ENT,
+ _("sh_entropy"));
+
+ /* emergency backup - unsafe !
+ */
+#ifdef HAVE_GETTIMEOFDAY
+ gtime = sh_unix_notime();
+#else
+ gtime = seed_time;
+#endif
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_skey);
+ taus_set_from_ulong ( &(skey->rng0[0]), LCG (gtime) );
+ taus_set_from_ulong ( &(skey->rng1[0]), LCG (skey->rng0[0]) );
+ taus_set_from_ulong ( &(skey->rng2[0]), LCG (skey->rng1[0]) );
+ skey->rngI = BAD;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
+
+ SL_RETURN( (-1), _("taus_seed"));
+}
+
+/*@+charint@*/
+static unsigned char new_key[] = { 0xA7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xA7 };
+/*@-charint@*/
+static void copy_four (unsigned char * dest, UINT32 in);
+
+int sh_util_set_newkey (const char * new_in)
+{
+ size_t i, j = 0;
+ size_t len;
+ SL_TICKET fp;
+ SL_TICKET fout;
+ char * key;
+ char * path = NULL;
+ char * outpath = NULL;
+ unsigned char * image = NULL;
+ long s = 0;
+ long ilen = 0;
+ long ii, k = 0;
+ UINT32 * h1;
+ char * new = NULL;
+
+ if (0 != sl_is_suid())
+ {
+ fprintf(stderr, "%s", _("ERROR: insufficient privilege\n"));
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1; /* braindead MAC OSX compiler needs this */
+ }
+
+ if (new_in == NULL || new_in[0] == '\0')
+ {
+ fprintf(stderr, "%s",
+ _("ERROR: no key given\n Argument must be 'key@path'\n"));
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1;
+ }
+
+ if (NULL == (new = calloc(1,strlen(new_in) + 1)))
+ goto bail_mem;
+ sl_strncpy(new, new_in, strlen(new_in) + 1);
+
+ key = new;
+ len = strlen(new);
+ for (i = 1; i < (len-2); ++i)
+ {
+ if (new[i] == '@' && new[i+1] == '/')
+ {
+ j = i+1; new[i] = '\0'; break;
+ }
+ }
+ if (j == 0)
+ {
+ fprintf(stderr, "%s",
+ _("ERROR: no path to executable given\n Argument must be 'key@path'\n"));
+ free(new);
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1;
+ }
+ else
+ path = &new[j];
+
+ len = strlen(path) + 1 + 4;
+ /*@-usedef@*/
+ if (NULL == (outpath = calloc(1,len)))
+ goto bail_mem;
+ /*@-usedef@*/
+ sl_snprintf (outpath, len, _("%s.out"), path);
+
+ fp = sl_open_read(FIL__, __LINE__, path, SL_NOPRIV);
+ if (SL_ISERROR(fp))
+ {
+ fprintf(stderr,
+ _("ERROR: cannot open %s for read (errnum = %ld)\n"), path, fp);
+ free(new); free (outpath);
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1;
+ }
+
+ fout = sl_open_write(FIL__, __LINE__, outpath, SL_NOPRIV);
+ if (SL_ISERROR(fout))
+ {
+ fprintf(stderr,
+ _("ERROR: cannot open %s (errnum = %ld)\n"), outpath, fout);
+ free(new); free (outpath);
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1;
+ }
+
+
+ image = calloc(1,4096);
+ if (!image)
+ goto bail_mem;
+ while (0 < (ii = sl_read (fp, &image[s], 4096)))
+ {
+ unsigned char * ptr;
+ ilen += ii;
+ s += 4096;
+ ptr = realloc (image, (size_t) (4096 + s));
+ if (ptr)
+ image = ptr;
+ else
+ { free(image); image = NULL; }
+ if (!image)
+ goto bail_mem;
+ }
+
+ printf(_("%ld bytes read\n"), ilen);
+
+
+ for (k = 0; k < (ilen - 8); ++k)
+ {
+ if (image[k] == new_key[0] &&
+ image[k+1] == new_key[1] &&
+ image[k+2] == new_key[2] &&
+ image[k+3] == new_key[3] &&
+ image[k+4] == new_key[4] &&
+ image[k+5] == new_key[5] &&
+ image[k+6] == new_key[6] &&
+ image[k+7] == new_key[7])
+ {
+ UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
+
+ printf("%s", _("old key found\n"));
+ h1 = sh_tiger_hash_uint32 (key, TIGER_DATA,
+ (unsigned long)strlen(key),
+ kbuf, KEY_BYT/sizeof(UINT32));
+ copy_four( (unsigned char *) &(image[k]), h1[0]);
+ copy_four( (unsigned char *) &(image[k+4]), h1[1]);
+ (void) sl_write (fout, image, ilen);
+ (void) sl_close (fout);
+ printf(_("new file %s written\n"), outpath);
+ free(new); free (outpath); free(image);
+ _exit (EXIT_SUCCESS);
+ /*@notreached@*/
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "%s",
+ _("ERROR: old key not found\n"));
+ free(new); free (outpath); free(image);
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1;
+
+
+ bail_mem:
+ fprintf(stderr, "%s",
+ _("ERROR: out of memory\n"));
+ if (new) free(new);
+ if (outpath) free (outpath);
+ if (image) free (image);
+ _exit (EXIT_FAILURE);
+ /*@notreached@*/
+ return -1;
+}
+
+
+
+
+/* A simple en-/decoder, based on Vernam cipher. We use the
+ * message as salt to hide the key by obtaining a different one-time
+ * pad each time.
+ * Should be safe against a listener on the network, but not against someone
+ * with read access to the binary.
+ */
+void sh_util_encode (char * data, char * salt, int mode, char fill)
+{
+ static char cc1[17] = N_("0123456789ABCDEF");
+ char cc[17] = "\0";
+ register int i, j, j1 = 0, j2 = 0, j3;
+ char * dez;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_util_encode"));
+
+ /* init
+ */
+ (void) sl_strlcpy( cc, _(cc1), sizeof(cc));
+
+ /* max 128 bits keyspace
+ */
+ memset (skey->vernam, (int)fill, KEY_LEN+1);
+
+ dez = (char *) &(skey->ErrFlag[0]);
+ sh_util_cpylong (skey->vernam, dez, 4);
+ dez = (char *) &(skey->ErrFlag[1]);
+ sh_util_cpylong (&skey->vernam[4], dez, 4);
+
+ skey->vernam[KEY_LEN] = '\0';
+
+ (void) sl_strlcpy(skey->vernam,
+ sh_tiger_hash(skey->vernam, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ (void) sl_strlcpy(skey->vernam,
+ sh_util_hmac_tiger (skey->vernam, salt, strlen(salt),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ (void) sl_strlcpy(skey->vernam,
+ sh_util_hmac_tiger (skey->vernam, (char*) new_key, 8,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ /* The following routine adds/subtracts data[j] and vernam[j] mod 16.
+ */
+ j = 0;
+ while (j < KEY_LEN)
+ {
+ for (i = 0; i < 16; ++i)
+ {
+ if (cc[i] == data[j]) j1 = i;
+ if (cc[i] == skey->vernam[j]) j2 = i;
+ }
+ if (mode == 0)
+ {
+ j3 = j1 + j2;
+ if (j3 > 15) j3 -= 16;
+ data[j] = cc[j3];
+ }
+ else
+ {
+ j3 = j1 - j2;
+ if (j3 < 0) j3 += 16;
+ data[j] = cc[j3];
+ }
+ ++j;
+ }
+ SL_RET0(_("sh_util_encode"));
+}
+
+/* server mode
+ */
+int sh_util_setserver (const char * dummy)
+{
+ SL_ENTER(_("sh_util_setserver"));
+
+ (void) dummy;
+ sh.flag.isserver = GOOD;
+ SL_RETURN((0),_("sh_util_setserver"));
+}
+
+
+int sh_util_setlooptime (const char * str)
+{
+ int i = atoi (str);
+
+ SL_ENTER(_("sh_util_setlooptime"));
+
+ if (i >= 0 && i < INT_MAX) {
+ sh.looptime = i;
+ SL_RETURN((0),_("sh_util_setlooptime"));
+ } else {
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("loop time"), str);
+ SL_RETURN((-1),_("sh_util_setlooptime"));
+ }
+}
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+int sh_util_setchecksum (const char * str)
+{
+ static int reject = 0;
+
+ SL_ENTER(_("sh_util_setchecksum"));
+
+ if (reject == 1)
+ SL_RETURN((0), _("sh_util_setchecksum"));
+ reject = 1;
+
+ if (sl_strncmp (str, _("init"), sizeof("init")-1) == 0)
+ {
+ sh.flag.checkSum = SH_CHECK_INIT;
+ }
+ else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
+ {
+ if (S_TRUE == file_is_remote())
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("checksum testing"), str);
+ SL_RETURN((-1), _("sh_util_setchecksum"));
+ }
+ else
+ {
+ sh.flag.checkSum = SH_CHECK_CHECK;
+ sh.flag.update = S_TRUE;
+ }
+ }
+ else if (sl_strncmp (str, _("check"), sizeof("check")-1) == 0)
+ {
+ sh.flag.checkSum = SH_CHECK_CHECK;
+ }
+ /*
+ else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
+ {
+ sh.flag.checkSum = SH_CHECK_INIT;
+ sh.flag.update = S_TRUE;
+ }
+ */
+ else if (sl_strncmp (str, _("none"), sizeof("none")-1) == 0)
+ {
+ sh.flag.checkSum = SH_CHECK_NONE;
+ }
+ else
+ {
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("checksum testing"), str);
+ SL_RETURN((-1), _("sh_util_setchecksum"));
+ }
+ SL_RETURN((0), _("sh_util_setchecksum"));
+}
+#endif
+
+/*@+charint@*/
+unsigned char TcpFlag[8][PW_LEN+1] = {
+#if (POS_TF == 1)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 2)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 3)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 4)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 5)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 6)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 7)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+ { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
+#if (POS_TF == 8)
+ { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
+#endif
+};
+/*@-charint@*/
+
+/* initialize a key to a random value
+ * rev 0.8
+ */
+int sh_util_keyinit (char * buf, long size)
+{
+ UINT32 bufy[6];
+ int i;
+ int status = 0;
+ char * p;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("sh_util_keyinit"));
+
+ ASSERT((size <= KEY_LEN+1), _("size <= KEY_LEN+1"))
+
+ if (size > KEY_LEN+1)
+ size = KEY_LEN+1;
+
+ /* seed / re-seed the PRNG if required
+ */
+ status = taus_seed ();
+
+ if (status == -1)
+ sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_ES_KEY1,
+ _("taus_seed"));
+
+ for (i = 0; i < 6; ++i)
+ bufy[i] = taus_get();
+
+ p = sh_tiger_hash ((char *) bufy, TIGER_DATA,
+ (unsigned long)(6*sizeof(UINT32)),
+ hashbuf, sizeof(hashbuf));
+
+ i = sl_strlcpy(buf, p, (size_t)size);
+
+ memset (bufy, 0, 6*sizeof(UINT32));
+
+ if ((status == 0) && (!SL_ISERROR(i)) )
+ SL_RETURN((0),_("sh_util_keyinit"));
+
+ if (SL_ISERROR(i))
+ sh_error_handle ((-1), FIL__, __LINE__, i, MSG_ES_KEY2,
+ _("sl_strlcpy"));
+
+ SL_RETURN((-1),_("sh_util_keyinit"));
+}
+
+#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
+
+static unsigned char sh_obscure_index[256];
+static int sh_obscure_no_check = S_FALSE;
+
+int sh_util_valid_utf8 (const unsigned char * str)
+{
+ const int sh_val_utf8_1 = 1;
+ const int sh_val_utf8_2 = 2;
+ const int sh_val_utf8_3 = 3;
+ const int sh_val_utf8_4 = 4;
+
+ size_t len = strlen((const char *)str);
+ size_t l = 0;
+ int typ = 0;
+ unsigned char c = '\0';
+ unsigned char c2[2] = { 0x00, 0x00 };
+ unsigned char c3[3] = { 0x00, 0x00, 0x00 };
+
+
+#define SH_VAL_UTF8_1 ((c != '\0') && ((c & 0x80) == 0x00))
+#define SH_VAL_UTF8_2 ((c != '\0') && ((c & 0xE0) == 0xC0)) /* 110x xxxx */
+#define SH_VAL_UTF8_3 ((c != '\0') && ((c & 0xF0) == 0xE0)) /* 1110 xxxx */
+#define SH_VAL_UTF8_4 ((c != '\0') && ((c & 0xF8) == 0xF0)) /* 1111 0xxx */
+#define SH_VAL_UTF8_N ((c != '\0') && ((c & 0xC0) == 0x80)) /* 10xx xxxx */
+#define SH_VAL_BAD ((c == '"') || (c == '\t') || (c == '\b') || \
+ (c == '\f') || (c == '\n') || \
+ (c == '\r') || (c == '\v') || iscntrl((int) c) || \
+ (c != ' ' && !isgraph ((int) c)))
+
+ while(l < len)
+ {
+ c = str[l];
+
+ if (SH_VAL_UTF8_1)
+ {
+ if (!(SH_VAL_BAD && (sh_obscure_index[c] != 1)))
+ {
+ typ = sh_val_utf8_1;
+ ++l; continue;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+ }
+ else if (SH_VAL_UTF8_2)
+ {
+ typ = sh_val_utf8_2;
+ c2[0] = c;
+ if ((c & 0x3e) != 0x00) /* !(overlong 2-byte seq.) */
+ {
+ ++l;
+ if (l != len) {
+ c = str[l];
+ if(SH_VAL_UTF8_N) {
+ c2[1] = c;
+ ++l; continue;
+ }
+ else {
+ return S_FALSE;
+ }
+ }
+ else {
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ return S_FALSE; /* overlong 2-byte seq. */
+ }
+ }
+ else if (SH_VAL_UTF8_3)
+ {
+ typ = sh_val_utf8_3;
+ c3[0] = c;
+ ++l; if (l == len) return S_FALSE; c = str[l];
+ if(!SH_VAL_UTF8_N) return S_FALSE;
+ if (((str[l-1] & 0x1F) == 0x00) && ((c & 0x60) == 0x00))
+ return S_FALSE; /* overlong 3-byte seq. */
+ c3[1] = c;
+ ++l; if (l == len) return S_FALSE; c = str[l];
+ if(!SH_VAL_UTF8_N) return S_FALSE;
+ c3[2] = c;
+ ++l; continue;
+ }
+ else if (SH_VAL_UTF8_4)
+ {
+ typ = sh_val_utf8_4;
+ ++l; if (l == len) return S_FALSE; c = str[l];
+ if(!SH_VAL_UTF8_N) return S_FALSE;
+ if (((str[l-1] & 0x0F) == 0x00) && ((c & 0x70) == 0x00))
+ return S_FALSE; /* overlong 4-byte seq. */
+ ++l; if (l == len) return S_FALSE; c = str[l];
+ if(!SH_VAL_UTF8_N) return S_FALSE;
+ ++l; if (l == len) return S_FALSE; c = str[l];
+ if(!SH_VAL_UTF8_N) return S_FALSE;
+ ++l; continue;
+ }
+ return S_FALSE;
+ }
+
+ /* last character is invisible (space or else)
+ */
+ if (typ == sh_val_utf8_1)
+ {
+ if (c != ' ')
+ return S_TRUE;
+ else
+ return S_FALSE;
+ }
+ else if (typ == sh_val_utf8_2)
+ {
+ if (c2[0] == 0xC2 && c2[1] == 0xA0) /* nbsp */
+ return S_FALSE;
+ else
+ return S_TRUE;
+ }
+ else if (typ == sh_val_utf8_3)
+ {
+ if (c3[0] == 0xE2)
+ {
+ if (c3[1] == 0x80 && c3[2] >= 0x80 && c3[2] <= 0x8F)
+ return S_FALSE; /* various spaces, left-to-right, right-to-left */
+ else if (c3[1] == 0x80 && (c3[2] == 0xA8 || c3[2] == 0xA9 ||
+ c3[2] == 0xAD || c3[2] == 0xAF))
+ return S_FALSE; /* line sep, para sep, zw word joiner, nnbsp */
+ else if (c3[1] == 0x81 && (c3[2] == 0xA0 || c3[2] == 0xA1 ||
+ c3[2] == 0x9F))
+ return S_FALSE; /* word joiner, function app, math space */
+ else
+ return S_TRUE;
+ }
+ else if (c3[0] == 0xE3 && c3[1] == 0x80 && c3[2] == 0x80)
+ {
+ return S_FALSE; /* ideographic space */
+ }
+ else if (c3[0] == 0xEF && c3[1] == 0xBB && c3[2] == 0xBF)
+ {
+ return S_FALSE; /* zwnbsp */
+ }
+ else
+ {
+ return S_TRUE;
+ }
+ }
+ else
+ {
+ return S_TRUE;
+ }
+}
+
+
+int sh_util_obscure_ok (const char * str)
+{
+ unsigned long i;
+ char * endptr = NULL;
+
+ SL_ENTER(_("sh_util_obscure_ok"));
+
+ if (0 == sl_strncmp("all", str, 3))
+ {
+ for (i = 0; i < 255; ++i)
+ {
+ sh_obscure_index[i] = (unsigned char)1;
+ }
+ sh_obscure_no_check = S_TRUE;
+ SL_RETURN(0, _("sh_util_obscure_ok"));
+ }
+
+ sh_obscure_no_check = S_FALSE;
+
+ for (i = 0; i < 255; ++i)
+ {
+ sh_obscure_index[i] = (unsigned char)0;
+ }
+
+ i = strtoul (str, &endptr, 0);
+ if (i > 255)
+ {
+ SL_RETURN(-1, _("sh_util_obscure_ok"));
+ }
+ sh_obscure_index[i] = (unsigned char)1;
+ if (*endptr == ',')
+ ++endptr;
+
+ while (*endptr != '\0')
+ {
+ i = strtoul (endptr, &endptr, 0);
+ if (i > 255)
+ {
+ SL_RETURN(-1, _("sh_util_obscure_ok"));
+ }
+ sh_obscure_index[i] = (unsigned char)1;
+ if (*endptr == ',')
+ ++endptr;
+ }
+ SL_RETURN(0, _("sh_util_obscure_ok"));
+}
+
+static int sh_obscure_check_utf8 = S_FALSE;
+
+int sh_util_obscure_utf8 (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_util_obscure_utf8"));
+ i = sh_util_flagval(c, &(sh_obscure_check_utf8));
+ if (sh_obscure_check_utf8 == S_TRUE)
+ sh_obscure_no_check = S_FALSE;
+ SL_RETURN(i, _("sh_util_obscure_utf8"));
+}
+
+
+int sh_util_obscurename (ShErrLevel level, const char * name_orig, int flag)
+{
+ const unsigned char * name = (const unsigned char *) name_orig;
+ char * safe;
+ unsigned int i;
+ size_t len = 0;
+
+ SL_ENTER(_("sh_util_obscurename"));
+
+ ASSERT_RET((name != NULL), _("name != NULL"), (0))
+
+ if (sh_obscure_no_check == S_FALSE)
+ {
+ if (sh_obscure_check_utf8 != S_TRUE)
+ {
+ /* -- Check name. --
+ */
+ while (*name != '\0')
+ {
+ if ( (*name) > 0x7F || (*name) == '"' || (*name) == '\t' ||
+ (*name) == '\b' || (*name) == '\f' ||
+ (*name) == '\n' || (*name) == '\r' ||
+ (*name) == '\v' || iscntrl((int) *name) ||
+ ((*name) != ' ' && !isgraph ((int) *name)) )
+ {
+ i = (unsigned char) *name;
+ if (sh_obscure_index[i] != (unsigned char)1)
+ {
+ goto err;
+ }
+ }
+ name++; ++len;
+ }
+
+ /* Check for blank at end of name
+ */
+ if ((len > 0) && (name_orig[len-1] == ' '))
+ {
+ goto err;
+ }
+ }
+ else
+ {
+ if (S_FALSE == sh_util_valid_utf8(name))
+ {
+ goto err;
+ }
+ SL_RETURN((0),_("sh_util_obscurename"));
+ }
+ }
+
+ SL_RETURN((0),_("sh_util_obscurename"));
+
+ err:
+
+ if (flag == S_TRUE)
+ {
+ safe = sh_util_safe_name (name_orig);
+ sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_OBSC,
+ safe);
+ SH_FREE(safe);
+ }
+ SL_RETURN((-1),_("sh_util_obscurename"));
+}
+
+#endif
+
+/* returns freshly allocated memory, return value should be free'd
+ */
+char * sh_util_dirname(const char * fullpath)
+{
+ char * retval;
+ size_t len;
+ char * tmp;
+
+ SL_ENTER(_("sh_util_dirname"));
+
+ ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
+ ASSERT_RET ((*fullpath == '/'), _("*fullpath == '/'"), (NULL))
+
+ retval = sh_util_strdup(fullpath);
+
+ tmp = retval;
+ while (*tmp == '/') ++tmp;
+
+ /* (1) only leading slashes -- return exact copy
+ */
+ if (*tmp == '\0')
+ {
+ SL_RETURN(retval, _("sh_util_dirname"));
+ }
+
+ /* (2) there are non-slash characters, so delete trailing slashes
+ */
+ len = sl_strlen (retval); /* retval[len] is terminating '\0' */
+
+ while (len > 1 && retval[len-1] == '/') /* delete trailing slash */
+ {
+ retval[len-1] = '\0';
+ --len;
+ }
+
+ /* (3) now delete all non-slash characters up to the preceding slash
+ */
+ while (len > 1 && retval[len-1] != '/') {
+ retval[len-1] = '\0';
+ --len;
+ }
+
+ /* (4a) only leading slashes left, so return this
+ */
+ if (&(retval[len]) == tmp)
+ {
+ SL_RETURN(retval, _("sh_util_dirname"));
+ }
+
+ /* (4b) strip trailing slash(es) of parent directory
+ */
+ while (len > 1 && retval[len-1] == '/') {
+ retval[len-1] = '\0';
+ --len;
+ }
+ SL_RETURN(retval, _("sh_util_dirname"));
+
+}
+
+/* returns freshly allocated memory, return value should be free'd
+ */
+char * sh_util_basename(const char * fullpath)
+{
+ char * retval = NULL;
+ const char * tmp;
+ char * tmp2;
+ char * c;
+ size_t len;
+
+ SL_ENTER(_("sh_util_basename"));
+
+ ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
+
+ tmp = fullpath; while (*tmp == '/') ++tmp;
+ if (*tmp == '\0')
+ {
+ retval = sh_util_strdup(fullpath);
+ }
+ else
+ {
+ tmp2 = sh_util_strdup(tmp);
+ len = sl_strlen (tmp2);
+
+ while (len > 1 && tmp2[len-1] == '/')
+ {
+ tmp2[len-1] = '\0';
+ --len;
+ }
+
+ if (tmp2) /* for llvm/clang analyzer */
+ {
+ c = strrchr(tmp2, '/');
+ if (c)
+ {
+ retval = sh_util_strdup(++c);
+ SH_FREE(tmp2);
+ }
+ else
+ {
+ retval = tmp2;
+ }
+ }
+ }
+
+ SL_RETURN(retval, _("sh_util_basename"));
+}
+
+#define SH_ESCAPE_SPACE 1
+#define SH_DONT_ESCAPE_SPACE 0
+char * sh_util_safe_name_int (const char * name, int escape_space);
+
+char * sh_util_safe_name (const char * name)
+{
+ return sh_util_safe_name_int (name, SH_ESCAPE_SPACE);
+}
+
+char * sh_util_safe_name_keepspace (const char * name)
+{
+ return sh_util_safe_name_int (name, SH_DONT_ESCAPE_SPACE);
+}
+
+/* returns freshly allocated memory, return value should be free'd
+ */
+char * sh_util_safe_name_int (const char * name, int escape_space)
+{
+ register int i = 0;
+ const char * p;
+ char * retval;
+ char oct[32];
+ char format[16];
+ size_t len;
+
+ SL_ENTER(_("sh_util_safe_name"));
+
+ if (name == NULL)
+ {
+ /* return an allocated array
+ */
+ retval = SH_ALLOC(7);
+ (void) sl_strlcpy(retval, _("(null)"), 7);
+ SL_RETURN(retval, _("sh_util_safe_name"));
+ }
+
+ /*
+ ASSERT_RET ((name != NULL), _("name != NULL"), _("NULL"))
+ */
+
+ len = sl_strlen(name);
+ p = name;
+
+#ifdef SH_USE_XML
+ if (sl_ok_muls (6, len) && sl_ok_adds ((6*len), 2))
+ { retval = SH_ALLOC(6 * len + 2); }
+ else
+ {
+ /* return an allocated array
+ */
+ retval = SH_ALLOC(11);
+ (void) sl_strlcpy(retval, _("(overflow)"), 11);
+ SL_RETURN(retval, _("sh_util_safe_name"));
+ }
+#else
+ if (sl_ok_muls (4, len) && sl_ok_adds ((4*len), 2))
+ { retval = SH_ALLOC(4 * len + 2); }
+ else
+ {
+ /* return an allocated array
+ */
+ retval = SH_ALLOC(11);
+ (void) sl_strlcpy(retval, _("(overflow)"), 11);
+ SL_RETURN(retval, _("sh_util_safe_name"));
+ }
+#endif
+
+ (void) sl_strncpy(format, _("%c%03o"), 16);
+
+ while (*p != '\0') {
+ /* Most frequent cases first
+ */
+ if ( ((*p) >= 'a' && (*p) <= 'z') || ((*p) == '/') || ((*p) == '.') ||
+ ((*p) >= '0' && (*p) <= '9') ||
+ ((*p) >= 'A' && (*p) <= 'Z')) {
+ retval[i] = *p;
+ } else if ( (*p) == '\\') { /* backslash */
+ retval[i] = '\\'; ++i;
+ retval[i] = '\\';
+ } else if ( (*p) == '\n') { /* newline */
+ retval[i] = '\\'; ++i;
+ retval[i] = 'n';
+ } else if ( (*p) == '\b') { /* backspace */
+ retval[i] = '\\'; ++i;
+ retval[i] = 'b';
+ } else if ( (*p) == '\r') { /* carriage return */
+ retval[i] = '\\'; ++i;
+ retval[i] = 'r';
+ } else if ( (*p) == '\t') { /* horizontal tab */
+ retval[i] = '\\'; ++i;
+ retval[i] = 't';
+ } else if ( (*p) == '\v') { /* vertical tab */
+ retval[i] = '\\'; ++i;
+ retval[i] = 'v';
+ } else if ( (*p) == '\f') { /* form-feed */
+ retval[i] = '\\'; ++i;
+ retval[i] = 'f';
+#ifdef WITH_DATABASE
+ } else if ( (*p) == '\'') { /* single quote */
+ retval[i] = '\\'; ++i;
+ retval[i] = '\'';
+#endif
+ } else if ( (*p) == ' ') { /* space */
+ if (escape_space) {
+ retval[i] = '\\'; ++i;
+ retval[i] = ' ';
+ }
+ else {
+ retval[i] = *p;
+ }
+#ifdef SH_USE_XML
+ } else if ( (*p) == '"') { /* double quote */
+ retval[i] = '&'; ++i;
+ retval[i] = 'q'; ++i;
+ retval[i] = 'u'; ++i;
+ retval[i] = 'o'; ++i;
+ retval[i] = 't'; ++i;
+ retval[i] = ';';
+ } else if ( (*p) == '&') { /* ampersand */
+ retval[i] = '&'; ++i;
+ retval[i] = 'a'; ++i;
+ retval[i] = 'm'; ++i;
+ retval[i] = 'p'; ++i;
+ retval[i] = ';';
+ } else if ( (*p) == '<') { /* left angle */
+ retval[i] = '&'; ++i;
+ retval[i] = 'l'; ++i;
+ retval[i] = 't'; ++i;
+ retval[i] = ';';
+ } else if ( (*p) == '>') { /* right angle */
+ retval[i] = '&'; ++i;
+ retval[i] = 'g'; ++i;
+ retval[i] = 't'; ++i;
+ retval[i] = ';';
+#else
+ } else if ( (*p) == '"') { /* double quote */
+ retval[i] = '\\'; ++i;
+ retval[i] = '\"';
+#endif
+ } else if (!isgraph ((int) *p)) { /* not printable */
+ /*@-bufferoverflowhigh -formatconst@*/
+ /* flawfinder: ignore */
+ sprintf(oct, format, '\\', /* known to fit */
+ (unsigned char) *p);
+ /*@+bufferoverflowhigh +formatconst@*/
+ retval[i] = oct[0]; ++i;
+ retval[i] = oct[1]; ++i;
+ retval[i] = oct[2]; ++i;
+ retval[i] = oct[3];
+ } else {
+ retval[i] = *p;
+ }
+ ++p;
+ ++i;
+ }
+ retval[i] = '\0';
+ SL_RETURN(retval, _("sh_util_safe_name"));
+}
+
+int sh_util_isnum (const char *str)
+{
+ const char *p = str;
+
+ SL_ENTER(_("sh_util_isnum"));
+
+ ASSERT_RET ((str != NULL), _("str != NULL"), (-1))
+
+ while (p) {
+ if (!isdigit((int) *p) )
+ SL_RETURN((-1), _("sh_util_isnum"));
+ ++p;
+ }
+ SL_RETURN((0), _("sh_util_isnum"));
+}
+
+char * sh_util_strconcat (const char * arg1, ...)
+{
+ size_t length, l2;
+ char * s;
+ char * strnew;
+ va_list vl;
+
+ SL_ENTER(_("sh_util_strconcat"));
+
+ ASSERT_RET ((arg1 != NULL), _("arg1 != NULL"), (NULL))
+
+ length = sl_strlen (arg1) + 1;
+
+ va_start (vl, arg1);
+ s = va_arg (vl, char * );
+ while (s != NULL)
+ {
+ l2 = sl_strlen (s);
+ if (sl_ok_adds(length, l2))
+ length += l2;
+ else
+ SL_RETURN(NULL, _("sh_util_strconcat"));
+ s = va_arg (vl, char * );
+ }
+ va_end (vl);
+
+ if (sl_ok_adds(length, 2))
+ strnew = SH_ALLOC( length + 2 );
+ else
+ SL_RETURN(NULL, _("sh_util_strconcat"));
+
+ strnew[0] = '\0';
+
+ (void) sl_strlcpy (strnew, arg1, length + 2);
+
+ va_start (vl, arg1);
+ s = va_arg (vl, char * );
+ while (s)
+ {
+ (void) sl_strlcat (strnew, s, length + 2);
+ s = va_arg (vl, char * );
+ }
+ va_end (vl);
+
+ SL_RETURN(strnew, _("sh_util_strconcat"));
+}
+
+static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()");
+static char bto64[65] = { '\0' };
+
+
+size_t sh_util_base64_enc (unsigned char * out,
+ const unsigned char * instr,
+ size_t lin)
+{
+ int ll;
+ unsigned char a, b, c;
+ size_t len = 0;
+ size_t j = 0;
+
+ start:
+ if (bto64[0] != '\0')
+ {
+ if (instr /* && *instr *//* need to handle binary data */)
+ {
+ if (lin == 0)
+ lin = strlen((const char *)instr);
+
+ if (lin > 0)
+ {
+ do {
+ ll = 0;
+
+ if (len < lin)
+ { a = *instr; ++instr; ++len; ++ll; }
+ else
+ { a = 0; }
+ if (len < lin)
+ { b = *instr; ++instr; ++len; ++ll; }
+ else
+ { b = 0; }
+ if (len < lin)
+ { c = *instr; ++instr; ++len; ++ll; }
+ else
+ { c = 0; }
+
+ *out = bto64[ a >> 2 ];
+ ++j; ++out;
+ *out = bto64[ ((a & 0x03) << 4) | ((b & 0xf0) >> 4) ];
+ ++j; ++out;
+ *out = (unsigned char) (ll > 1 ? bto64[ ((b & 0x0f) << 2) | ((c & 0xc0) >> 6) ] : '?');
+ ++j; ++out;
+ *out = (unsigned char) (ll > 2 ? bto64[ c & 0x3f ] : '?');
+ ++j; ++out;
+ } while (len < lin);
+ }
+ }
+ *out = '\0';
+ return j;
+ }
+
+ memcpy(bto64, _(bto64_0), 65);
+ goto start;
+}
+
+size_t sh_util_base64_enc_alloc (char **out, const char *in, size_t inlen)
+{
+ size_t outlen = SH_B64_SIZ(inlen);
+
+ if (inlen > outlen) /* overflow */
+ {
+ *out = NULL;
+ return 0;
+ }
+
+ *out = SH_ALLOC(outlen);
+ return sh_util_base64_enc((unsigned char *)*out, (const unsigned char *)in, inlen);
+}
+
+size_t sh_util_base64_dec (unsigned char *out,
+ const unsigned char *in,
+ size_t lin)
+{
+ size_t i;
+ unsigned char c;
+ unsigned char b;
+ size_t lout = 0;
+ unsigned int w = 0;
+
+ if (out && in)
+ {
+ if (lin == 0)
+ lin = strlen((const char *)in);
+
+ for (i = 0; i < lin; i++)
+ {
+ c = *in; ++in;
+ b = 0;
+
+ if ((c >= 'A') && (c <= 'Z'))
+ {
+ b = (c - 'A');
+ }
+ else if ((c >= 'a') && (c <= 'z'))
+ {
+ b = (c - 'a' + 26);
+ }
+ else if ((c >= '0') && (c <= '9'))
+ {
+ b = (c - '0' + 52);
+ }
+ else if (c == '(' || c == '+')
+ {
+ b = 62;
+ }
+ else if (c == ')' || c == '/')
+ {
+ b = 63;
+ }
+ else if (c == '?' || c == '=')
+ {
+ /* last byte was written to, but will now get
+ * truncated
+ */
+ if (lout > 0) --lout;
+ break;
+ }
+
+ if (w == 0)
+ {
+ *out = (b << 2) & 0xfc;
+ ++lout;
+ }
+ else if (w == 1)
+ {
+ *out |= (b >> 4) & 0x03;
+ ++out;
+ *out = (b << 4) & 0xf0;
+ ++lout;
+ }
+ else if (w == 2)
+ {
+ *out |= (b >> 2) & 0x0f;
+ ++out;
+ *out = (b << 6) & 0xc0;
+ ++lout;
+ }
+ else if (w == 3)
+ {
+ *out |= b & 0x3f;
+ ++out;
+ }
+
+ ++w;
+
+ if (w == 4)
+ {
+ w = 0;
+ }
+ }
+ *out = '\0';
+ }
+ return lout;
+}
+
+size_t sh_util_base64_dec_alloc (unsigned char **out, const unsigned char *in,
+ size_t lin)
+{
+ size_t lout = 3 * (lin / 4) + 2;
+
+ *out = SH_ALLOC(lout);
+
+ return sh_util_base64_dec (*out, in, lin);
+}
+
+
+#ifdef HAVE_REGEX_H
+
+#include <regex.h>
+
+int sh_util_regcmp (char * regex_str, char * in_str)
+{
+#if defined(REG_ESPACE)
+ int status = REG_ESPACE;
+#else
+ int status = -1;
+#endif
+ regex_t preg;
+ char * errbuf;
+
+ SL_ENTER(_("sh_util_regcmp"));
+
+ status = regcomp(&preg, regex_str, REG_NOSUB|REG_EXTENDED);
+
+ if (status == 0)
+ {
+ if ((status = regexec(&preg, in_str, 0, NULL, 0)) == 0)
+ {
+ regfree (&preg);
+ SL_RETURN((0), _("sh_util_regcmp"));
+ }
+ }
+
+ if (status != 0 && status != REG_NOMATCH)
+ {
+ errbuf = SH_ALLOC(BUFSIZ);
+ (void) regerror(status, &preg, errbuf, BUFSIZ);
+ errbuf[BUFSIZ-1] = '\0';
+ sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX,
+ errbuf, regex_str);
+ SH_FREE(errbuf);
+ }
+
+ regfree (&preg);
+ SL_RETURN((-1), _("sh_util_regcmp"));
+}
+
+#endif
+
+
+
+
+
+
+
+
diff --git a/src/sh_utmp.c b/src/sh_utmp.c
new file mode 100644
index 0000000..5c72209
--- /dev/null
+++ b/src/sh_utmp.c
@@ -0,0 +1,1272 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef HAVE_UTADDR
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef S_SPLINT_S
+#include <arpa/inet.h>
+#else
+#define AF_INET 2
+#endif
+#endif
+
+#ifdef SH_USE_UTMP
+
+#ifdef HAVE_UTMPX_H
+
+#ifdef S_SPLINT_S
+typedef pid_t __pid_t;
+#endif
+
+#include <utmpx.h>
+#define SH_UTMP_S utmpx
+#undef ut_name
+#define ut_name ut_user
+#ifdef HAVE_UTXTIME
+#undef ut_time
+#define ut_time ut_xtime
+#else
+#undef ut_time
+#define ut_time ut_tv.tv_sec
+#endif
+
+#else
+#include <utmp.h>
+#define SH_UTMP_S utmp
+#endif
+
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_utmp.c")
+
+#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
+
+
+#include "samhain.h"
+#include "sh_utils.h"
+#include "sh_error.h"
+#include "sh_modules.h"
+#include "sh_utmp.h"
+#include "sh_pthread.h"
+#include "sh_inotify.h"
+
+SH_MUTEX_EXTERN(mutex_thread_nolog);
+
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+#ifndef UT_LINESIZE
+#ifndef __UT_LINESIZE
+#define UT_LINESIZE 12
+#else
+#define UT_LINESIZE __UT_LINESIZE
+#endif
+#endif
+
+#ifndef UT_NAMESIZE
+#ifndef __UT_NAMESIZE
+#define UT_NAMESIZE 8
+#else
+#define UT_NAMESIZE __UT_NAMESIZE
+#endif
+#endif
+
+#ifndef UT_HOSTSIZE
+#ifndef __UT_HOSTSIZE
+#define UT_HOSTSIZE 16
+#else
+#define UT_HOSTSIZE __UT_HOSTSIZE
+#endif
+#endif
+
+#ifdef HAVE_UTMPX_H
+
+#ifndef _PATH_UTMP
+#ifdef UTMPX_FILE
+#define _PATH_UTMP UTMPX_FILE
+#else
+#error You must define UTMPX_FILE in the file config.h
+#endif
+#endif
+#ifndef _PATH_WTMP
+#ifdef WTMPX_FILE
+#define _PATH_WTMP WTMPX_FILE
+#else
+#error You must define WTMPX_FILE in the file config.h
+#endif
+#endif
+
+#else
+
+#ifndef _PATH_UTMP
+#ifdef UTMP_FILE
+#define _PATH_UTMP UTMP_FILE
+#else
+#error You must define UTMP_FILE in the file config.h
+#endif
+#endif
+#ifndef _PATH_WTMP
+#ifdef WTMP_FILE
+#define _PATH_WTMP WTMP_FILE
+#else
+#error You must define WTMP_FILE in the file config.h
+#endif
+#endif
+
+#endif
+
+typedef struct log_user {
+ char ut_tty[UT_LINESIZE+1];
+ char name[UT_NAMESIZE+1];
+ char ut_host[UT_HOSTSIZE+1];
+ char ut_ship[SH_IP_BUF]; /* IP address */
+ time_t time;
+ struct log_user * next;
+} blah_utmp;
+
+#ifdef HAVE_UTTYPE
+static char terminated_line[UT_HOSTSIZE];
+#endif
+
+static char * mode_path[] = { _PATH_WTMP, _PATH_WTMP, _PATH_UTMP };
+
+static struct SH_UTMP_S save_utmp;
+
+static void sh_utmp_logout_morechecks(struct log_user * user);
+static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut);
+static void sh_utmp_addlogin (struct SH_UTMP_S * ut);
+static void sh_utmp_check_internal(int mode);
+
+static int ShUtmpLoginSolo = SH_ERR_INFO;
+static int ShUtmpLoginMulti = SH_ERR_WARN;
+static int ShUtmpLogout = SH_ERR_INFO;
+static int ShUtmpActive = S_TRUE;
+static time_t ShUtmpInterval = 300;
+
+sh_rconf sh_utmp_table[] = {
+ {
+ N_("severityloginmulti"),
+ sh_utmp_set_login_multi
+ },
+ {
+ N_("severitylogin"),
+ sh_utmp_set_login_solo
+ },
+ {
+ N_("severitylogout"),
+ sh_utmp_set_logout_good
+ },
+ {
+ N_("logincheckactive"),
+ sh_utmp_set_login_activate
+ },
+ {
+ N_("logincheckinterval"),
+ sh_utmp_set_login_timer
+ },
+ {
+ N_("logincheckfirst"),
+ sh_login_set_checklevel
+ },
+ {
+ N_("logincheckoutlier"),
+ sh_login_set_siglevel
+ },
+ {
+ N_("logincheckdate"),
+ sh_login_set_def_allow
+ },
+ {
+ N_("logincheckuserdate"),
+ sh_login_set_user_allow
+ },
+ {
+ NULL,
+ NULL
+ },
+};
+
+static void set_defaults(void)
+{
+ ShUtmpLoginSolo = SH_ERR_INFO;
+ ShUtmpLoginMulti = SH_ERR_WARN;
+ ShUtmpLogout = SH_ERR_INFO;
+ ShUtmpActive = S_TRUE;
+ ShUtmpInterval = 300;
+
+ sh_login_reset();
+ return;
+}
+
+
+#if defined (HAVE_SETUTENT) && defined (USE_SETUTENT)
+
+#ifdef HAVE_UTMPX_H
+
+#define sh_utmp_utmpname utmpxname
+#define sh_utmp_setutent setutxent
+#define sh_utmp_endutent endutxent
+#define sh_utmp_getutent getutxent
+#define sh_utmp_getutid getutxid
+#define sh_utmp_getutline getutxline
+
+#else
+
+#define sh_utmp_utmpname utmpname
+#define sh_utmp_setutent setutent
+#define sh_utmp_endutent endutent
+#define sh_utmp_getutent getutent
+#define sh_utmp_getutid getutid
+#define sh_utmp_getutline getutline
+
+#endif
+
+#else
+
+/* BSD lacks getutent() etc.
+ * utmpname(), setutent(), and endutent() return void,
+ * so we do not perform much error handling.
+ * Errors must be recognized by getutent() returning NULL.
+ * Apparently, the application cannot check whether wtmp is empty,
+ * or whether there was an fopen() error.
+ */
+
+static FILE * sh_utmpfile = NULL;
+static char sh_utmppath[80] = _PATH_UTMP;
+
+/* sh_utmp_feed_forward is for optimizing
+ * (fseek instead of getutent loop)
+ */
+static long sh_utmp_feed_forward = 0;
+
+static void sh_utmp_utmpname(const char * str)
+{
+ SL_ENTER(_("sh_utmp_utmpname"));
+ if (sh_utmpfile != NULL)
+ {
+ (void) sl_fclose (FIL__, __LINE__, sh_utmpfile);
+ sh_utmpfile = NULL;
+ }
+
+ (void) sl_strlcpy (sh_utmppath, str, 80);
+ SL_RET0(_("sh_utmp_utmpname"));
+}
+
+static void sh_utmp_setutent(void)
+{
+ int error;
+ int fd;
+
+ SL_ENTER(_("sh_utmp_setutent"));
+
+ if (sh_utmpfile == NULL)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ fd = (int) aud_open (FIL__, __LINE__, SL_NOPRIV,
+ sh_utmppath, O_RDONLY, 0);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ if (fd >= 0)
+ {
+ sh_utmpfile = fdopen(fd, "r");
+ }
+
+ /* -- If (sh_utmpfile == NULL) then either the open() or the fdopen()
+ * has failed.
+ */
+ if (sh_utmpfile == NULL)
+ {
+ error = errno;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
+ (long) sh.real.uid, sh_utmppath);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RET0(_("sh_utmp_setutent"));
+ }
+ }
+ (void) fseek (sh_utmpfile, 0L, SEEK_SET);
+ if (-1 == fseek (sh_utmpfile, sh_utmp_feed_forward, SEEK_CUR))
+ {
+ sh_utmp_feed_forward = 0; /* modified Apr 4, 2004 */
+ (void) fseek (sh_utmpfile, 0L, SEEK_SET);
+ }
+ clearerr (sh_utmpfile);
+ SL_RET0(_("sh_utmp_setutent"));
+}
+
+static void sh_utmp_endutent(void)
+{
+ SL_ENTER(_("sh_utmp_endutent"));
+ if (NULL != sh_utmpfile)
+ (void) sl_fclose(FIL__, __LINE__, sh_utmpfile);
+ sh_utmpfile = NULL;
+ SL_RET0(_("sh_utmp_endutent"));
+}
+
+static struct SH_UTMP_S * sh_utmp_getutent(void)
+{
+ size_t in;
+ static struct SH_UTMP_S out;
+
+ SL_ENTER(_("sh_utmp_getutent"));
+
+ ASSERT_RET((sh_utmpfile != NULL), _("sh_utmpfile != NULL"), (NULL))
+
+ in = fread (&out, sizeof(struct SH_UTMP_S), 1, sh_utmpfile);
+
+ if (in != 1)
+ {
+ if (ferror (sh_utmpfile) != 0)
+ {
+ clearerr (sh_utmpfile);
+ SL_RETURN(NULL, _("sh_utmp_getutent"));
+ }
+ else
+ {
+ SL_RETURN(NULL, _("sh_utmp_getutent"));
+ }
+ }
+ SL_RETURN(&out, _("sh_utmp_getutent"));
+}
+
+#ifdef USE_UNUSED
+
+static struct SH_UTMP_S * sh_utmp_getutline(struct SH_UTMP_S * ut)
+{
+ struct SH_UTMP_S * out;
+
+ while (1) {
+ if ((out = sh_utmp_getutent()) == NULL) {
+ return NULL;
+ }
+#ifdef HAVE_UTTYPE
+ if (out->ut_type == USER_PROCESS || out->ut_type == LOGIN_PROCESS)
+ if (sl_strcmp(ut->ut_line, out->ut_line) == 0)
+ return out;
+#else
+ if ( 0 != sl_strncmp (out->ut_name, "reboot", 6) &&
+ 0 != sl_strncmp (out->ut_name, "shutdown", 8) &&
+ 0 != sl_strncmp (out->ut_name, "date", 4) )
+ return out;
+#endif
+ }
+ return NULL;
+}
+
+static struct SH_UTMP_S * sh_utmp_getutid(struct SH_UTMP_S * ut)
+{
+#ifdef HAVE_UTTYPE
+ struct SH_UTMP_S * out;
+
+ if (ut->ut_type == RUN_LVL || ut->ut_type == BOOT_TIME ||
+ ut->ut_type == NEW_TIME || ut->ut_type == OLD_TIME)
+ {
+ while (1) {
+ if ((out = sh_utmp_getutent()) == NULL) {
+ return NULL;
+ }
+ if (out->ut_type == ut->ut_type)
+ return out;
+ }
+ }
+ else if (ut->ut_type == INIT_PROCESS || ut->ut_type == LOGIN_PROCESS ||
+ ut->ut_type == USER_PROCESS || ut->ut_type == DEAD_PROCESS )
+ {
+ while (1) {
+ if ((out = sh_utmp_getutent()) == NULL) {
+ return NULL;
+ }
+ if (sl_strcmp(ut->ut_id, out->ut_id) == 0)
+ return out;
+ }
+ }
+#endif
+ return NULL;
+}
+/* #ifdef USE_UNUSED */
+#endif
+
+/* #ifdef HAVE_SETUTENT */
+#endif
+
+#ifdef HAVE_UTADDR
+#ifdef HAVE_UTADDR_V6
+static char * my_inet_ntoa(SINT32 * ut_addr_v6, char * buf, size_t buflen)
+{
+ struct in_addr in;
+
+ buf[0] = '\0';
+
+ if (0 == (ut_addr_v6[1] + ut_addr_v6[2] + ut_addr_v6[3]))
+ {
+ memcpy(&in, ut_addr_v6, sizeof(struct in_addr));
+ sl_strlcpy(buf, inet_ntoa(in), buflen);
+ }
+ else
+ {
+ inet_ntop(AF_INET6, ut_addr_v6, buf, buflen);
+ }
+ return buf;
+}
+#else
+static char * my_inet_ntoa(SINT32 ut_addr, char * buf, size_t buflen)
+{
+ struct in_addr in;
+
+ buf[0] = '\0';
+
+ memcpy(&in, ut_addr, sizeof(struct in_addr));
+ sl_strlcpy(buf, inet_ntoa(in), buflen);
+ return buf;
+}
+#endif
+/* #ifdef HAVE_UTADDR */
+#endif
+
+#if defined(__linux__) && !defined(ut_addr)
+#define ut_addr ut_addr_v6[0]
+#endif
+
+
+static struct log_user * userlist = NULL;
+static time_t lastcheck;
+static int init_done = 0;
+
+/*************
+ *
+ * module init
+ *
+ *************/
+
+static int sh_utmp_init_internal (void)
+{
+
+ SL_ENTER(_("sh_utmp_init"));
+ if (ShUtmpActive == BAD)
+ SL_RETURN( (-1), _("sh_utmp_init"));
+
+ /* do not re-initialize after a re-configuration
+ */
+ if (init_done == 1) {
+ SL_RETURN( (0), _("sh_utmp_init"));
+ }
+ lastcheck = time (NULL);
+ userlist = NULL;
+ memset (&save_utmp, 0, sizeof(struct SH_UTMP_S));
+ sh_utmp_check_internal (2); /* current logins */
+ sh_utmp_check_internal (0);
+ init_done = 1;
+ SL_RETURN( (0), _("sh_utmp_init"));
+}
+
+int sh_utmp_init (struct mod_type * arg)
+{
+#if !defined(HAVE_PTHREAD)
+ (void) arg;
+#endif
+ if (ShUtmpActive == BAD)
+ return SH_MOD_FAILED;
+#ifdef HAVE_PTHREAD
+ if (arg != NULL && arg->initval < 0 &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
+ return SH_MOD_THREAD;
+ else
+ return SH_MOD_FAILED;
+ }
+ else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
+ (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
+ {
+ return SH_MOD_THREAD;
+ }
+#endif
+ return sh_utmp_init_internal();
+}
+
+/*************
+ *
+ * module cleanup
+ *
+ *************/
+#ifdef HAVE_UTTYPE
+static int sh_utmp_login_clean(void);
+#endif
+
+#if defined(HAVE_PTHREAD)
+static sh_watches inotify_watch = SH_INOTIFY_INITIALIZER;
+#endif
+
+int sh_utmp_end ()
+{
+ struct log_user * user = userlist;
+ struct log_user * userold;
+
+ SL_ENTER(_("sh_utmp_end"));
+ while (user)
+ {
+ userold = user;
+ user = user->next;
+ SH_FREE(userold);
+ }
+ userlist = NULL;
+#ifdef HAVE_UTTYPE
+ (void) sh_utmp_login_clean();
+#endif
+ /* Reset the flag, such that the module
+ * can be re-enabled.
+ */
+ set_defaults();
+ init_done = 0;
+
+#if defined(HAVE_PTHREAD)
+ sh_inotify_remove(&inotify_watch);
+#endif
+
+ SL_RETURN( (0), _("sh_utmp_end"));
+}
+
+
+int sh_utmp_reconf()
+{
+ set_defaults();
+#if defined(HAVE_PTHREAD)
+ sh_inotify_remove(&inotify_watch);
+#endif
+ return 0;
+}
+
+
+/*************
+ *
+ * module timer
+ *
+ *************/
+int sh_utmp_timer (time_t tcurrent)
+{
+#if !defined(HAVE_PTHREAD)
+ retry_msleep(1, 0);
+
+ if ((time_t) (tcurrent - lastcheck) >= ShUtmpInterval)
+ {
+ lastcheck = tcurrent;
+ return (-1);
+ }
+ return 0;
+#else
+ int errnum = 0;
+
+ if ( (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE) &&
+ sh.flag.checkSum != SH_CHECK_INIT )
+ {
+ sh_inotify_wait_for_change(mode_path[1], &inotify_watch,
+ &errnum, ShUtmpInterval);
+ }
+
+ lastcheck = tcurrent;
+
+ if (SH_INOTIFY_ERROR(errnum))
+ {
+ char ebuf[SH_ERRBUF_SIZE];
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_message(errnum, ebuf, sizeof(ebuf));
+ sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
+ ebuf,
+ _("sh_utmp_timer") );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ return -1;
+#endif
+}
+
+/*************
+ *
+ * module check
+ *
+ *************/
+int sh_utmp_check ()
+{
+ SL_ENTER(_("sh_utmp_check"));
+ if (ShUtmpActive == BAD)
+ {
+#if defined(HAVE_PTHREAD)
+ sh_inotify_remove(&inotify_watch);
+#endif
+ SL_RETURN( (-1), _("sh_utmp_check"));
+ }
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_UT_CHECK);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_utmp_check_internal (1);
+
+ SL_RETURN(0, _("sh_utmp_check"));
+}
+
+/*************
+ *
+ * module setup
+ *
+ *************/
+
+int sh_utmp_set_login_solo (const char * c)
+{
+ int retval;
+ char tmp[32];
+
+ SL_ENTER(_("sh_utmp_set_login_solo"));
+ tmp[0] = '='; tmp[1] = '\0';
+ (void) sl_strlcat (tmp, c, 32);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ retval = sh_error_set_level (tmp, &ShUtmpLoginSolo);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN(retval, _("sh_utmp_set_login_solo"));
+}
+
+int sh_utmp_set_login_multi (const char * c)
+{
+ int retval;
+ char tmp[32];
+
+ SL_ENTER(_("sh_utmp_set_login_multi"));
+ tmp[0] = '='; tmp[1] = '\0';
+ (void) sl_strlcat (tmp, c, 32);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ retval = sh_error_set_level (tmp, &ShUtmpLoginMulti);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN(retval, _("sh_utmp_set_login_multi"));
+}
+
+int sh_utmp_set_logout_good (const char * c)
+{
+ int retval;
+ char tmp[32];
+
+ SL_ENTER(_("sh_utmp_set_logout_good"));
+ tmp[0] = '='; tmp[1] = '\0';
+ (void) sl_strlcat (tmp, c, 32);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ retval = sh_error_set_level (tmp, &ShUtmpLogout);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN(retval, _("sh_utmp_set_logout_good"));
+}
+
+int sh_utmp_set_login_timer (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_utmp_set_login_timer"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
+ _("utmp timer"), c);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RETURN((-1), _("sh_utmp_set_login_timer"));
+ }
+
+ ShUtmpInterval = (time_t) val;
+ SL_RETURN(0, _("sh_utmp_set_login_timer"));
+}
+
+int sh_utmp_set_login_activate (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_utmp_set_login_activate"));
+ i = sh_util_flagval(c, &ShUtmpActive);
+ SL_RETURN(i, _("sh_utmp_set_login_activate"));
+}
+
+#ifdef HAVE_UTTYPE
+struct login_ct {
+ char name[UT_NAMESIZE+1];
+ int nlogin;
+ struct login_ct * next;
+};
+
+static struct login_ct * login_ct_list = NULL;
+
+static int sh_utmp_login_clean(void)
+{
+ struct login_ct * list = login_ct_list;
+ struct login_ct * old;
+
+ login_ct_list = NULL;
+
+ while (list)
+ {
+ old = list;
+ list = list->next;
+ SH_FREE(old);
+ }
+ return 0;
+}
+
+/* add a username to the list of logged-in users
+ */
+static int sh_utmp_login_a(char * str)
+{
+ struct login_ct * list = login_ct_list;
+
+ while (list)
+ {
+ if (0 == sl_strcmp(list->name, str))
+ {
+ ++(list->nlogin);
+ return list->nlogin;
+ }
+ list = list->next;
+ }
+ list = SH_ALLOC(sizeof(struct login_ct));
+ (void) sl_strlcpy(list->name, str, UT_NAMESIZE+1);
+ list->nlogin = 1;
+ list->next = login_ct_list;
+ login_ct_list = list;
+ return 1;
+}
+
+static int sh_utmp_login_r(char * str)
+{
+ struct login_ct * list = login_ct_list;
+ struct login_ct * old = login_ct_list;
+
+ while (list)
+ {
+ if (0 == sl_strcmp(list->name, str))
+ {
+ list->nlogin -= 1;
+ if (list->nlogin > 0)
+ {
+ return list->nlogin;
+ }
+ if (login_ct_list == list) /* modified Apr 4, 2004 */
+ {
+ login_ct_list = list->next;
+ SH_FREE(list);
+ }
+ else
+ {
+ old->next = list->next;
+ SH_FREE(list);
+ }
+ return 0;
+ }
+ old = list;
+ list = list->next;
+ }
+ return 0;
+}
+
+#endif
+
+
+/* for each login:
+ * - allocate a log record
+ * - link device.ut_record -> log_record
+ * - link user.ut_record -> log_record
+ */
+
+#ifdef HAVE_UTTYPE
+static int sh_utmp_is_virtual (char * in_utline, char * in_uthost)
+{
+
+ if (in_uthost != NULL &&
+ in_utline != NULL &&
+ in_uthost[0] == ':' &&
+ in_uthost[1] == '0' &&
+ 0 == sl_strncmp(in_utline, _("pts/"), 4))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
+/* These variables are not used anywhere. They only exist
+ * to assign &userold, &user to them, which keeps gcc from
+ * putting them into a register, and avoids the 'clobbered
+ * by longjmp' warning. And no, 'volatile' proved insufficient.
+ */
+void * sh_dummy_850_userold = NULL;
+void * sh_dummy_851_user = NULL;
+
+
+static void sh_utmp_addlogin (struct SH_UTMP_S * ut)
+{
+ struct log_user * user = userlist;
+ struct log_user * userold = userlist;
+#ifdef HAVE_UTTYPE
+ struct log_user * username = userlist;
+#endif
+
+ char ttt[TIM_MAX];
+#ifdef HAVE_UTTYPE
+ volatile int status;
+#endif
+
+ SL_ENTER(_("sh_utmp_addlogin"));
+
+ if (ut->ut_line[0] == '\0')
+ SL_RET0(_("sh_utmp_addlogin"));
+
+ /* for some stupid reason, AIX repeats the wtmp entry for logouts
+ * with ssh
+ */
+ if (memcmp (&save_utmp, ut, sizeof(struct SH_UTMP_S)) == 0)
+ {
+ memset(&save_utmp, (int) '\0', sizeof(struct SH_UTMP_S));
+ SL_RET0(_("sh_utmp_addlogin"));
+ }
+ memcpy (&save_utmp, ut, sizeof(struct SH_UTMP_S));
+
+ /* Take the address to keep gcc from putting them into registers.
+ * Avoids the 'clobbered by longjmp' warning.
+ */
+ sh_dummy_850_userold = (void*) &userold;
+ sh_dummy_851_user = (void*) &user;
+
+ /* ------- find user --------
+ */
+ while (user != NULL)
+ {
+ if (0 == sl_strncmp((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE) )
+ break;
+ userold = user;
+ user = user->next;
+ }
+
+#ifdef HAVE_UTTYPE
+ while (username != NULL)
+ {
+ if (0 == sl_strncmp(username->name, ut->ut_name, UT_NAMESIZE) )
+ break;
+ username = username->next;
+ }
+#endif
+
+#ifdef HAVE_UTTYPE
+ /* ---------- LOGIN -------------- */
+ if (ut->ut_type == USER_PROCESS)
+ {
+ if (user == NULL)
+ {
+ user = SH_ALLOC(sizeof(struct log_user));
+ user->next = userlist;
+ userlist = (struct log_user *) user;
+ }
+ (void) sl_strlcpy((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE+1);
+ (void) sl_strlcpy((char*)(user->name), ut->ut_name, UT_NAMESIZE+1);
+#ifdef HAVE_UTHOST
+ (void) sl_strlcpy((char*)(user->ut_host), ut->ut_host, UT_HOSTSIZE+1);
+#else
+ user->ut_host[0] = '\0';
+#endif
+#ifdef HAVE_UTADDR
+#ifdef HAVE_UTADDR_V6
+ my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
+#else
+ my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
+#endif
+#endif
+ user->time = ut->ut_time;
+
+ if (username == NULL /* not yet logged in */
+ || 0 == sl_strncmp(ut->ut_line, _("ttyp"), 4) /* in virt. console */
+ || 0 == sl_strncmp(ut->ut_line, _("ttyq"), 4) /* in virt. console */
+ ) {
+ status = sh_utmp_login_a((char*)user->name);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (user->time, ttt, TIM_MAX);
+ sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ MSG_UT_LG1X,
+#elif defined(HAVE_UTHOST)
+ MSG_UT_LG1A,
+#else
+ MSG_UT_LG1B,
+#endif
+ user->name,
+ user->ut_tty,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ user->ut_host,
+ user->ut_ship,
+#elif defined(HAVE_UTHOST)
+ user->ut_host,
+#endif
+ ttt,
+ status
+ );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ } else
+ if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host))
+ {
+ status = sh_utmp_login_a((char*)user->name);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (user->time, ttt, TIM_MAX);
+ sh_error_handle( ShUtmpLoginMulti, FIL__, __LINE__, 0,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ MSG_UT_LG2X,
+#elif defined(HAVE_UTHOST)
+ MSG_UT_LG2A,
+#else
+ MSG_UT_LG2B,
+#endif
+ user->name,
+ user->ut_tty,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ user->ut_host,
+ user->ut_ship,
+#elif defined(HAVE_UTHOST)
+ user->ut_host,
+#endif
+ ttt,
+ status
+ );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+
+ sh_utmp_login_morechecks(ut);
+ goto out;
+ }
+
+
+ /* --------- LOGOUT ---------------- */
+ else if (ut->ut_name[0] == '\0'
+ || ut->ut_type == DEAD_PROCESS /* solaris does not clear ut_name */
+ )
+ {
+ if (user != NULL)
+ {
+#if defined(__linux__)
+ if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) {
+#endif
+ status = sh_utmp_login_r((char*)user->name);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
+ sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ MSG_UT_LG3X,
+#elif defined(HAVE_UTHOST)
+ MSG_UT_LG3A,
+#else
+ MSG_UT_LG3B,
+#endif
+ user->name,
+ user->ut_tty,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ user->ut_host,
+ user->ut_ship,
+#elif defined(HAVE_UTHOST)
+ user->ut_host,
+#endif
+ ttt,
+ status
+ );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ userold->next = user->next;
+ if (user == userlist)
+ userlist = user->next;
+ sh_utmp_logout_morechecks((struct log_user *)user);
+ SH_FREE((struct log_user *)user);
+ user = NULL;
+#if defined(__linux__)
+ }
+#endif
+ }
+ else
+ {
+ (void) sl_strlcpy(terminated_line, ut->ut_line, UT_HOSTSIZE);
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
+ sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
+ MSG_UT_LG3C,
+ terminated_line,
+ ttt, 0
+ );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ }
+ goto out;
+ }
+
+ /* default */
+ goto out;
+
+ /* #ifdef HAVE_UTTYPE */
+#else
+
+ if (user == NULL) /* probably a login */
+ {
+ user = SH_ALLOC(sizeof(struct log_user));
+ sl_strlcpy(user->ut_tty, ut->ut_line, UT_LINESIZE+1);
+ sl_strlcpy(user->name, ut->ut_name, UT_NAMESIZE+1);
+#ifdef HAVE_UTHOST
+ sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1);
+#endif
+#ifdef HAVE_UTADDR
+#ifdef HAVE_UTADDR_V6
+ my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF);
+#else
+ my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF);
+#endif
+#endif
+ user->time = ut->ut_time;
+ user->next = userlist;
+ userlist = user;
+
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (user->time, ttt, TIM_MAX);
+ sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ MSG_UT_LG1X,
+#elif defined(HAVE_UTHOST)
+ MSG_UT_LG1A,
+#else
+ MSG_UT_LG1B,
+#endif
+ user->name,
+ user->ut_tty,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ user->ut_host,
+ user->ut_ship,
+#elif defined(HAVE_UTHOST)
+ user->ut_host,
+#endif
+ ttt,
+ 1
+ );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_utmp_login_morechecks(ut);
+ }
+ else /* probably a logout */
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX);
+ sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ MSG_UT_LG2X,
+#elif defined(HAVE_UTHOST)
+ MSG_UT_LG2A,
+#else
+ MSG_UT_LG2B,
+#endif
+ user->name,
+ user->ut_tty,
+#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR)
+ user->ut_host,
+ user->ut_ship,
+#elif defined(HAVE_UTHOST)
+ user->ut_host,
+#endif
+ ttt,
+ 1
+ );
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ sh_utmp_logout_morechecks(user);
+ userold->next = user->next;
+ if (user == userlist) /* inserted Apr 4, 2004 */
+ userlist = user->next;
+ SH_FREE(user);
+ user = NULL;
+ }
+
+#endif
+
+ out:
+ sh_dummy_851_user = NULL;
+ sh_dummy_850_userold = NULL;
+
+ SL_RET0(_("sh_utmp_addlogin"));
+}
+
+static time_t lastmod = 0;
+static off_t lastsize = 0;
+static unsigned long lastread = 0;
+
+static void sh_utmp_check_internal (int mode)
+{
+ struct stat buf;
+ int error;
+ struct SH_UTMP_S * ut;
+ unsigned long this_read;
+ int val_retry;
+
+ SL_ENTER(_("sh_utmp_check_internal"));
+
+ /* error if no access
+ */
+ do {
+ val_retry = /*@-unrecog@*/lstat ( mode_path[mode], &buf)/*@+unrecog@*/;
+ } while (val_retry < 0 && errno == EINTR);
+
+ if (0 != val_retry)
+ {
+ error = errno;
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_ACCESS,
+ (long) sh.real.uid, mode_path[mode]);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ SL_RET0(_("sh_utmp_check_internal"));
+ }
+
+ /* modification time
+ */
+ if (mode < 2)
+ {
+ if (/*@-usedef@*/buf.st_mtime <= lastmod/*@+usedef@*/)
+ {
+ SL_RET0(_("sh_utmp_check_internal"));
+ }
+ else
+ lastmod = buf.st_mtime;
+ }
+
+ /* file size
+ */
+ if (/*@-usedef@*/buf.st_size < lastsize/*@+usedef@*/ && mode < 2)
+ {
+ SH_MUTEX_LOCK(mutex_thread_nolog);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_UT_ROT,
+ mode_path[mode]);
+ SH_MUTEX_UNLOCK(mutex_thread_nolog);
+ lastread = 0;
+#ifndef USE_SETUTENT
+ sh_utmp_feed_forward = 0L;
+#endif
+ }
+
+ if (mode < 2)
+ lastsize = buf.st_size;
+
+ if (buf.st_size == 0)
+ SL_RET0(_("sh_utmp_check_internal"));
+
+ sh_utmp_utmpname(mode_path[mode]);
+ sh_utmp_setutent();
+
+ /*
+ * feed forward if initializing
+ * we need to do this here
+ */
+ this_read = 0;
+
+ if (mode < 2)
+ {
+ while (this_read < lastread) {
+ (void) sh_utmp_getutent();
+ ++this_read;
+ }
+ }
+
+ /* start reading
+ */
+ this_read = 0;
+ while (1 == 1) {
+ ut = sh_utmp_getutent();
+ if (ut == NULL)
+ break;
+ /* modified: ut_user --> ut_name */
+ if (mode == 1 || (mode == 2 && ut->ut_name[0] != '\0'
+#ifdef HAVE_UTTYPE
+ && ut->ut_type != DEAD_PROCESS
+#endif
+ ))
+ sh_utmp_addlogin (ut);
+ ++this_read;
+ }
+
+ sh_utmp_endutent();
+
+ if (mode < 2)
+ {
+ lastread += this_read;
+#ifndef USE_SETUTENT
+ sh_utmp_feed_forward += (long) (this_read * sizeof(struct SH_UTMP_S));
+ lastread = 0;
+#endif
+ }
+
+ SL_RET0(_("sh_utmp_check_internal"));
+}
+
+extern void sh_ltrack_check(struct SH_UTMP_S * ut);
+
+static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut)
+{
+ sh_ltrack_check(ut);
+ return;
+}
+
+static void sh_utmp_logout_morechecks(struct log_user * user)
+{
+ (void) user;
+ return;
+}
+
+#endif
+
+
+/* #ifdef SH_USE_UTMP */
+#endif
+
+
+
diff --git a/src/sh_xfer_client.c b/src/sh_xfer_client.c
new file mode 100644
index 0000000..abc6504
--- /dev/null
+++ b/src/sh_xfer_client.c
@@ -0,0 +1,1638 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000, 2015 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+/* Must be early on FreeBSD
+ */
+#include <sys/types.h>
+
+/* must be .le. than (1020 * 64)
+ * (see sh_tools.c -- put_header)
+ *
+ * also: must be (N * 16), otherwise
+ * binary files cannot be transferred encrypted
+ *
+ * 65280 = (1020*64)
+ * #define TRANS_BYTES 8000 V0.8
+ */
+#ifdef SH_ENCRYPT
+#define TRANS_BYTES 65120
+#else
+#define TRANS_BYTES 65280
+#endif
+
+/* timeout for session key
+ */
+#define TIMEOUT_KEY 7200
+
+/* max time between connection attempts
+ */
+#define TIMEOUT_CON 2048
+
+/* #undef SRP_DEBUG */
+/* #define SRP_DEBUG */
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#ifndef S_SPLINT_S
+#include <arpa/inet.h>
+#endif
+
+#include "sh_ipvx.h"
+#include "samhain.h"
+#include "sh_tiger.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_xfer.h"
+#include "sh_srp.h"
+#include "sh_fifo.h"
+#include "sh_tools.h"
+#include "sh_entropy.h"
+#include "sh_html.h"
+#include "sh_nmail.h"
+#include "sh_socket.h"
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+
+#ifdef SH_ENCRYPT
+#include "rijndael-api-fst.h"
+char * sh_tools_makePack (unsigned char * header, int flag,
+ char * payload, unsigned long payload_size,
+ keyInstance * keyInstE);
+char * sh_tools_revertPack (unsigned char * header, int flag, char * message,
+ keyInstance * keyInstE,
+ unsigned long message_size);
+#endif
+
+/* define this if you want to debug the client/server communication */
+/* #define SH_DBG_PROT 1 */
+
+#ifdef SH_DBG_PROT
+#define SH_SHOWPROT(c,d) sh_tools_show_header((c), (d))
+#else
+#define SH_SHOWPROT(c,d)
+#endif
+
+/* the port client will be connecting to
+ */
+#ifndef SH_DEFAULT_PORT
+#define SH_DEFAULT_PORT 49777
+#endif
+
+#ifndef SH_SELECT_REPEAT
+#define SH_SELECT_REPEAT 60
+#endif
+
+#ifndef SH_HEADER_SIZE
+#define SH_HEADER_SIZE 7
+#endif
+
+#ifndef SH_CHALLENGE_SIZE
+#define SH_CHALLENGE_SIZE 9
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_xfer_client.c")
+
+extern int flag_err_debug;
+extern int flag_err_info;
+
+#ifndef SH_STANDALONE
+
+#if defined(WITH_TRACE) || defined(WITH_TPT)
+char * hu_trans(const char * ihu)
+{
+ static char ohu[17];
+ sprintf(ohu, _("%c%03o"), '\\', /* known to fit */
+ (unsigned char) ihu[0]);
+ sprintf(&(ohu[4]), _("%c%03o"), '\\', /* known to fit */
+ (unsigned char) ihu[1]);
+ sprintf(&(ohu[8]), _("%c%03o"), '\\', /* known to fit */
+ (unsigned char) ihu[2]);
+ sprintf(&(ohu[12]), _("%c%03o"), '\\', /* known to fit */
+ (unsigned char) ihu[3]);
+ ohu[16] = '\0';
+ return ohu;
+}
+#endif
+/* #ifndef SH_STANDALONE */
+#endif
+
+#if !defined(USE_SRP_PROTOCOL)
+void sh_passwd (char * salt, char * password, char * nounce, char *hash)
+{
+
+ char *combi;
+ size_t len;
+ unsigned char * tmp = NULL;
+ char hashbuf[KEYBUF_SIZE];
+
+ if (password == NULL)
+ {
+ tmp = (unsigned char *) &(skey->pw[0]);
+ memcpy(skey->vernam, tmp, PW_LEN);
+ sl_strlcpy (skey->vernam,
+ sh_tiger_hash(skey->vernam, TIGER_DATA, PW_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ }
+ else if (sl_strlen(password) < PW_LEN)
+ {
+ fprintf(stderr, _("Password has less than %d chars !\n"),
+ PW_LEN);
+ _exit(EXIT_FAILURE);
+ }
+ else
+ {
+ sl_strlcpy (skey->vernam, password, KEY_LEN+1);
+ }
+
+ len = sl_strlen(salt) + 1;
+ if (sl_ok_adds(len, sl_strlen(skey->vernam)))
+ len += sl_strlen(skey->vernam);
+ if (nounce != NULL && sl_ok_adds(len, sl_strlen(nounce)))
+ len += sl_strlen(nounce);
+
+ /* H(s,P)
+ */
+ combi = SH_ALLOC(len);
+ (void) sl_strlcpy (combi, salt, len);
+ (void) sl_strlcat (combi, skey->vernam, len);
+ if (nounce != NULL)
+ (void) sl_strlcat (combi, nounce, len);
+ (void) sl_strlcpy (hash,
+ sh_tiger_hash(combi, TIGER_DATA,
+ (unsigned long) sl_strlen(combi),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ SH_FREE (combi);
+ hash[KEY_LEN] = '\0';
+ return;
+}
+#endif
+
+#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
+
+/* Server addresses in use
+ */
+static int count_dev_server = 0;
+
+void reset_count_dev_server(void)
+{
+ count_dev_server = 0;
+ return;
+}
+
+int sh_xfer_set_logserver (const char * address)
+{
+ SL_ENTER(_("sh_xfer_set_logserver"));
+
+ if (address != NULL && count_dev_server < 2
+ && sl_strlen(address) < SH_PATHBUF && sl_strlen(address) > 0)
+ {
+ if (count_dev_server == 0)
+ (void) sl_strlcpy (sh.srvexport.name, address, SH_PATHBUF);
+ else
+ (void) sl_strlcpy (sh.srvexport.alt, address, SH_PATHBUF);
+
+ ++count_dev_server;
+ SL_RETURN (0, _("sh_xfer_set_logserver"));
+ }
+ SL_RETURN (-1, _("sh_xfer_set_logserver"));
+}
+
+static
+int xfer_send_intern (int mysocket, const int protocol, char * micro,
+ char * msgbuf, unsigned long length, int docrypt)
+{
+ unsigned long numbytes, countbytes;
+ int flag_err = 0;
+ unsigned char head[SH_HEADER_SIZE];
+ char * outbuf;
+#ifdef SH_ENCRYPT
+ char * msg2buf = NULL;
+#else
+ (void) docrypt;
+#endif
+
+ SL_ENTER(_("xfer_send_intern"));
+
+#ifdef SH_ENCRYPT
+ if ((S_TRUE == docrypt) && ((protocol & SH_PROTO_ENC) != 0))
+ {
+ put_header (head, protocol, &length, micro);
+ msg2buf = sh_tools_makePack (head, 0, msgbuf, length,
+ &(skey->keyInstE));
+ length = (unsigned long) (256 * (unsigned int)head[1] +
+ (unsigned int)head[2]);
+ outbuf = msg2buf;
+ }
+ else
+ {
+ outbuf = msgbuf;
+ put_header (head, protocol, &length, micro);
+ }
+#else
+ outbuf = msgbuf;
+ put_header (head, protocol, &length, micro);
+#endif
+
+ SH_SHOWPROT(head,'>');
+
+ numbytes = SH_HEADER_SIZE;
+ countbytes = write_port (mysocket, (char *)head, numbytes, &flag_err, 300);
+
+ if (countbytes == numbytes && outbuf != NULL)
+ {
+ numbytes = length;
+ countbytes = write_port (mysocket, outbuf, numbytes, &flag_err, 300);
+ }
+
+#ifdef SH_ENCRYPT
+ if (msg2buf != NULL)
+ SH_FREE(msg2buf);
+#endif
+
+ if (countbytes == numbytes)
+ SL_RETURN( 0, _("xfer_send_intern"));
+ else
+ SL_RETURN( flag_err, _("xfer_send_intern"));
+}
+
+static
+int xfer_send (int mysocket, const int protocol, char * micro,
+ char * msgbuf, unsigned long length)
+{
+ int i;
+ SL_ENTER(_("xfer_send"));
+ TPT(( 0, FIL__, __LINE__, _("msg=<Send.>\n")));
+ i = xfer_send_intern (mysocket, protocol, micro,
+ msgbuf, length, S_FALSE);
+ SL_RETURN(i, _("xfer_send"));
+}
+static
+int xfer_send_crypt (int mysocket, const int protocol, char * micro,
+ char * msgbuf, unsigned long length)
+{
+ int i;
+ SL_ENTER(_("xfer_send_crypt"));
+#ifdef SH_ENCRYPT
+ TPT(( 0, FIL__, __LINE__, _("msg=<Send encrypted.>\n")));
+#else
+ TPT(( 0, FIL__, __LINE__, _("msg=<Send.>\n")));
+#endif
+ i = xfer_send_intern (mysocket, protocol, micro,
+ msgbuf, length, S_TRUE);
+ SL_RETURN(i, _("xfer_send_crypt"));
+}
+
+
+/* receive answer, add a trailing NULL to terminate string
+ * decrypt answer
+ */
+static
+long xfer_receive_intern (int mysocket, const int protocol, char * micro,
+ char * msgbuf, unsigned long length,
+ int docrypt)
+{
+ unsigned long numbytes, countbytes;
+ int flag_err = -1;
+ unsigned char head[SH_HEADER_SIZE];
+#ifndef SH_ENCRYPT
+ (void) docrypt;
+#endif
+
+ SL_ENTER(_("xfer_receive_intern"));
+
+#ifdef SH_ENCRYPT
+ /* make sure length is not multiple of B_SIZ, see below
+ */
+ ASSERT_RET((length % B_SIZ != 0), _("length % 16 != 0"), flag_err);
+#endif
+
+ if (micro != NULL)
+ micro[4] = '\0';
+ if (msgbuf != NULL)
+ msgbuf[0] = '\0';
+
+ numbytes = SH_HEADER_SIZE;
+ countbytes = read_port (mysocket, (char *)head, numbytes, &flag_err, 300);
+
+ if (countbytes != numbytes)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<countbytes != numbytes>\n")));
+ SL_RETURN(flag_err, _("xfer_receive_intern"));
+ }
+ else if (msgbuf == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("msgbuf is NULL"), _("xfer_receive_intern"));
+ SL_RETURN((-1), _("xfer_receive_intern"));
+ }
+ else if (head[0] != protocol && (head[0] & SH_PROTO_SRP) == 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_MISMATCH);
+ SL_RETURN((-1), _("xfer_receive_intern"));
+ }
+ else
+ {
+ get_header (head, &numbytes, micro);
+ SH_SHOWPROT(head, '<');
+
+ if (numbytes > 0)
+ {
+ numbytes = (numbytes > length ? length : numbytes);
+
+ countbytes = read_port (mysocket, msgbuf, numbytes, &flag_err, 300);
+
+ if (countbytes < length)
+ msgbuf[countbytes] = '\0';
+ else
+ msgbuf[length-1] = '\0';
+
+ if (flag_err != 0)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<read error>\n")));
+ SL_RETURN((-1), _("xfer_receive_intern"));
+ }
+ }
+ }
+
+#ifdef SH_ENCRYPT
+ if ((S_TRUE == docrypt) && ((protocol & SH_PROTO_ENC) != 0))
+ {
+ unsigned long head_length;
+ char * tmp = SH_ALLOC((size_t)length);
+
+ memcpy(tmp, msgbuf, (size_t)length);
+ tmp = sh_tools_revertPack (head, 0, tmp, &(skey->keyInstD), countbytes);
+
+ head_length = (unsigned long) (256 * (unsigned int)head[1] +
+ (unsigned int)head[2]);
+
+ /*
+ * revertPack returns header with length <= (original_length-16), so
+ * the following msgbuf[length] = '\0' is always safe.
+ * Nevertheless, check for proper length.
+ */
+ if (head_length <= (length-1))
+ length = head_length;
+ else
+ --length;
+
+ memcpy(msgbuf, tmp, (size_t)length);
+ msgbuf[length] = '\0';
+ SH_FREE(tmp);
+ if (countbytes == numbytes)
+ countbytes = length; /* to avoid error on return, see below */
+ numbytes = length;
+ }
+#endif
+
+ if (countbytes == numbytes)
+ SL_RETURN(((long)numbytes), _("xfer_receive_intern"));
+ else
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<short read>\n")));
+ SL_RETURN(flag_err, _("xfer_receive_intern"));
+ }
+}
+
+static
+long xfer_receive (int mysocket, const int protocol, char * micro,
+ char * msgbuf, unsigned long length)
+{
+ long i;
+ SL_ENTER(_("xfer_receive"));
+ TPT(( 0, FIL__, __LINE__, _("msg=<Receive.>\n")));
+ i = xfer_receive_intern (mysocket, protocol, micro,
+ msgbuf, length, S_FALSE);
+ SL_RETURN(i, _("xfer_receive"));
+}
+
+static
+long xfer_receive_crypt (int mysocket, const int protocol, char * micro,
+ char * msgbuf, unsigned long length)
+{
+ long i;
+ SL_ENTER(_("xfer_receive_crypt"));
+#ifdef SH_ENCRYPT
+ TPT(( 0, FIL__, __LINE__, _("msg=<Receive encrypted.>\n")));
+#else
+ TPT(( 0, FIL__, __LINE__, _("msg=<Receive.>\n")));
+#endif
+ i = xfer_receive_intern (mysocket, protocol, micro,
+ msgbuf, length, S_TRUE);
+ SL_RETURN(i, _("xfer_receive_crypt"));
+}
+
+/**************************************************
+ *
+ *
+ * C L I E N T
+ *
+ *
+ ***************************************************/
+
+
+#include <time.h>
+
+static SH_FIFO * fifo = NULL;
+
+static long xfer_try_report (char * errmsg);
+
+unsigned int ServerPort = SH_DEFAULT_PORT;
+
+int sh_xfer_server_port (const char * str)
+{
+ unsigned long l;
+ char * endptr;
+
+ SL_ENTER(_("sh_xfer_server_port"));
+
+ l = strtoul (str, &endptr, 0);
+ if (l > 65535 || endptr == str)
+ {
+ SL_RETURN (-1, _("sh_xfer_server_port"));
+ }
+ ServerPort = (unsigned int) l;
+ SL_RETURN (0, _("sh_xfer_server_port"));
+}
+
+long sh_xfer_report (char * errmsg)
+{
+ static int have_server = S_TRUE;
+ long status;
+ char * popmsg;
+ static int nofail = S_TRUE;
+
+ SL_ENTER(_("sh_xfer_report"));
+
+ /* --- No log server available. ---
+ */
+ if (have_server == S_TRUE && sh.srvexport.name[0] == '\0')
+ {
+ have_server = S_FALSE;
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NONAME);
+ SL_RETURN (-1, _("sh_xfer_report"));
+ }
+ else if (have_server == BAD)
+ {
+ SL_RETURN (-1, _("sh_xfer_report"));
+ }
+
+ /* --- Allocate fifo. ---
+ */
+ if (fifo == NULL)
+ {
+ fifo = SH_ALLOC(sizeof(SH_FIFO));
+ fifo_init(fifo);
+ }
+
+ /* --- Check for messages on the queue, and send them first. ---
+ */
+ while (NULL != (popmsg = pop_list(fifo)) )
+ {
+ status = xfer_try_report (popmsg);
+ if (status != 0)
+ {
+ (void) push_tail_list (fifo, popmsg, 0, NULL);
+ SH_FREE(popmsg);
+ if (SH_FIFO_MAX == push_list (fifo, errmsg, 0,NULL))
+ SL_RETURN (-2, _("sh_xfer_report"));
+ SL_RETURN (-1, _("sh_xfer_report"));
+ }
+ SH_FREE(popmsg);
+ }
+
+ /* --- Now send the error message. ---
+ */
+ status = xfer_try_report (errmsg);
+ if (status != 0)
+ {
+ if (nofail == S_TRUE)
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
+ _("log server"), sh.srvexport.name);
+ nofail = S_FALSE;
+ if (SH_FIFO_MAX == push_list (fifo, errmsg, 0, NULL))
+ SL_RETURN (-2, _("sh_xfer_report"));
+ SL_RETURN (-1, _("sh_xfer_report"));
+ }
+
+ nofail = S_TRUE;
+ SL_RETURN (0, _("sh_xfer_report"));
+}
+
+static long xfer_try_report_int (char * errmsg, const int what);
+
+static long xfer_try_report (char * errmsg)
+{
+ long i;
+ SL_ENTER(_("xfer_try_report"));
+ i = xfer_try_report_int (errmsg, SH_PROTO_MSG);
+ SL_RETURN(i, _("xfer_try_report"));
+}
+
+long sh_xfer_request_file (const char * file)
+{
+ long i;
+ char tmp_file[64];
+ SL_ENTER(_("sh_xfer_request_file"));
+ sl_strlcpy(tmp_file, file, sizeof(tmp_file));
+ i = xfer_try_report_int (tmp_file, SH_PROTO_BIG);
+ SL_RETURN(i, _("sh_xfer_request_file"));
+}
+
+static unsigned long sh_throttle_delay = 0;
+
+int sh_xfer_set_throttle_delay (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_xfer_set_throttle_delay"));
+ val = strtol (c, (char **)NULL, 10);
+ if (val < 0)
+ SL_RETURN( (-1), _("sh_xfer_set_throttle_delay"));
+
+ val = (val > 1000) ? 1000 : val;
+
+ sh_throttle_delay = (unsigned long) val;
+ SL_RETURN( (0), _("sh_xfer_set_throttle_delay"));
+}
+
+static time_t xfer_timeout_val = 1;
+
+static int xfer_conn_state(int initialized, int conn_state)
+{
+ static time_t time_now = 1200;
+ static time_t time_last = 0;
+
+ if (initialized == S_FALSE || conn_state == S_FALSE)
+ {
+ xfer_timeout_val =
+ ((xfer_timeout_val > TIMEOUT_CON) ? TIMEOUT_CON : xfer_timeout_val);
+
+ /* --- Retry bad attempt only after some time. ---
+ */
+ time_now = time (NULL);
+ if ((time_now - time_last) < xfer_timeout_val)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<Within deadtime, no retry.>\n")));
+ return -1;
+ }
+ TPT(( 0, FIL__, __LINE__, _("msg=<Retry.>\n")));
+ }
+ time_last = time (NULL);
+ return 0;
+}
+
+static int xfer_connect(int * conn_state)
+{
+ char error_msg[256];
+ char error_call[SH_MINIBUF] = { 0 };
+ int error_num = 0;
+
+ int sockfd = connect_port_2 (sh.srvexport.name, sh.srvexport.alt, ServerPort,
+ error_call, &error_num, error_msg, 256);
+
+ if (sockfd < 3)
+ {
+ *conn_state = S_FALSE;
+ xfer_timeout_val *= 2;
+ sh_error_handle ((-1), FIL__, __LINE__, error_num,
+ MSG_E_NET, error_msg, error_call,
+ _("export"), sh.srvexport.name);
+ return -1;
+ }
+
+ *conn_state = S_TRUE;
+ return sockfd;
+}
+
+int xfer_greet_server(int sockfd, char * answer)
+{
+ int flag_err;
+ char head_u[5];
+ int theProto = SH_PROTO_SRP;
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<c/r: entry>\n")));
+
+ sl_strlcpy (answer, sh.host.name, 512);
+
+ flag_err = xfer_send (sockfd, theProto, _("SALT"),
+ answer, (unsigned long)sl_strlen(answer));
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<c/r: sent SALT, flag_err = %d>\n"),
+ flag_err));
+
+ /* get nonce from server
+ */
+ if (flag_err == 0)
+ {
+ flag_err = xfer_receive (sockfd, (char)theProto, head_u,
+ answer, 511);
+ flag_err = (flag_err < 0) ? flag_err : 0;
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<c/r: rcvt nonce, flag_err = %d>\n"),
+ flag_err));
+ }
+
+ if ( 0 != check_request (head_u, _("INIT")) )
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: u = %03o-%03o-%03o-%03o>\n"), head_u[0], head_u[1], head_u[2], head_u[3]));
+ flag_err = -1;
+ }
+ return flag_err;
+}
+
+
+#if !defined(USE_SRP_PROTOCOL)
+
+static int xfer_auth(int is_reinit, int * initialized,
+ int sockfd, char * answer)
+{
+ /**************************************************
+ *
+ * --- challenge/response authentication ---
+ *
+ **************************************************/
+
+ int flag_err = 0;
+ int theProto = 0;
+ char nounce[KEY_LEN+1];
+ char temp[2*KEY_LEN+1];
+ char nonce_u[KEY_LEN+1];
+ UINT32 ticks;
+
+ char head_u[5];
+ char foo_M1[KEY_LEN+1];
+ char hashbuf[KEYBUF_SIZE];
+#ifdef SH_ENCRYPT
+ int err_num;
+ char expbuf[SH_ERRBUF_SIZE];
+#endif
+
+ SL_REQUIRE((sockfd > 2), _("sockfd > 2"));
+
+ if (is_reinit == S_FALSE)
+ flag_err = xfer_greet_server(sockfd, answer);
+ else
+ sh_tools_probe_reset();
+
+ /* entry point for jump from message forward if session key must
+ * be re-initialized
+ */
+
+ if ( flag_err == 0 && sl_strlen(answer) > KEY_LEN )
+ (void) sl_strlcpy(nounce, &answer[KEY_LEN], KEY_LEN+1);
+ else
+ flag_err = (-1);
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<c/r: rcvt INIT, flag_err = %d>\n"),
+ flag_err));
+
+ /* verify random nonce v from server H(v, P)v
+ */
+ sh_passwd (nounce, NULL, NULL, temp);
+ if ( 0 != sl_strncmp(temp, answer, KEY_LEN))
+ flag_err = (-1);
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<c/r: vrfy nonce, flag_err = %d>\n"),
+ flag_err));
+
+
+ /* --- Create own nonce. ---
+ */
+ ticks = (UINT32) taus_get ();
+
+ (void) sl_strlcpy(nonce_u,
+ sh_tiger_hash((char *) &ticks,
+ TIGER_DATA,
+ (unsigned long)sizeof(UINT32),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ /* --- Form the message H(H(u,v),P)u ---
+ */
+ (void) sl_strlcpy(temp, nonce_u, 2*KEY_LEN+1);
+ (void) sl_strlcat(temp, nounce, 2*KEY_LEN+1);
+ (void) sl_strlcpy(temp,
+ sh_tiger_hash(temp,
+ TIGER_DATA,
+ (unsigned long)sl_strlen(temp),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ sh_passwd (temp, NULL, NULL, foo_M1);
+ (void) sl_strlcpy(temp, foo_M1, 2*KEY_LEN+1);
+ (void) sl_strlcat(temp, nonce_u, 2*KEY_LEN+1);
+
+ /* --- Send it to server. ---
+ */
+ if (flag_err == 0)
+ {
+ flag_err = xfer_send (sockfd,
+ (theProto|SH_PROTO_SRP),
+ _("PASS"), temp,
+ (unsigned long)sl_strlen(temp));
+ TPT(( 0, FIL__, __LINE__, _("msg=<c/r: sent PASS, flag_err = %d>\n"),
+ flag_err));
+ }
+
+ if (flag_err == 0)
+ {
+ flag_err = xfer_receive (sockfd,
+ (theProto|SH_PROTO_SRP),
+ head_u, answer, 511);
+ sh_passwd (nounce, NULL, nonce_u, foo_M1);
+ (void) sl_strlcpy (skey->session, foo_M1, KEY_LEN+1);
+#ifdef SH_ENCRYPT
+ err_num = rijndael_makeKey(&(skey->keyInstE),
+ (BYTE)DIR_ENCRYPT, 192, skey->session);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("xfer_try_report_int: makeKey"));
+
+ err_num = rijndael_makeKey(&(skey->keyInstD),
+ (BYTE)DIR_DECRYPT, 192, skey->session);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("xfer_try_report_int: make_key"));
+#endif
+ *initialized = S_TRUE;
+ }
+
+ if (*initialized == S_FALSE)
+ {
+ xfer_timeout_val *= 2;
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NOAUTH);
+ memset(answer, 0, 512);
+ MUNLOCK(answer, 512);
+ SH_FREE(answer);
+ return -1;
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_AUTH);
+ }
+ return 0;
+}
+#else
+
+static void noise()
+{
+ UINT32 n = taus_get();
+ retry_msleep(0, (n & 0x0000007F));
+ return;
+}
+
+
+static int xfer_auth(int is_reinit, int * initialized,
+ int sockfd, char * answer)
+{
+ /* This is the SRP authenticated key exchange protocol.
+ * Produces a session key skey->session.
+ */
+
+ int flag_err = 0;
+ int theProto = 0;
+
+ char head_u[5];
+ char u_real[SH_CHALLENGE_SIZE];
+ char * foo_A;
+ char * foo_Sc;
+ char * M;
+ char foo_M1[KEY_LEN+1];
+ char hashbuf[KEYBUF_SIZE];
+#ifdef SH_ENCRYPT
+ int err_num;
+ char expbuf[SH_ERRBUF_SIZE];
+#endif
+
+ SL_REQUIRE((sockfd > 2), _("sockfd > 2"));
+
+ if (is_reinit == S_FALSE)
+ flag_err = xfer_greet_server(sockfd, answer);
+ else
+ sh_tools_probe_reset();
+
+ /* Entry point for jump from message forward if session key must
+ * be re-initialized.
+ */
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: INIT>\n")));
+
+ if ( flag_err == 0 )
+ {
+ if (0 != sh_srp_init())
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_EBGN);
+ else
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: bignum initialized>\n")));
+
+ sh_srp_x (answer, NULL); /* x password */
+ sh_srp_make_a (); /* a random number */
+ foo_A = sh_srp_A(); /* g^a */
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: A = %s>\n"), foo_A));
+
+ if (foo_A == NULL)
+ flag_err = (-1);
+
+ noise();
+
+ if (flag_err == 0)
+ flag_err = xfer_send (sockfd,
+ (theProto|SH_PROTO_SRP),
+ _("PC01"),
+ foo_A, sl_strlen(foo_A)+1);
+ if (flag_err == 0)
+ {
+ flag_err = xfer_receive (sockfd,
+ (theProto|SH_PROTO_SRP),
+ head_u,
+ answer, 511);
+ flag_err = (flag_err < 0) ? flag_err : 0;
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: B = %s>\n"), answer));
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: u = %03o-%03o-%03o-%03o>\n"), head_u[0], head_u[1], head_u[2], head_u[3]));
+ }
+
+ /* u nounce */
+ /* B answer */
+ /* S = (B-g^x)^(a+ux) */
+
+
+ if (flag_err == 0)
+ {
+ noise();
+
+ if (0 != sh_srp_check_zero (answer))
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_EZERO);
+ else
+ {
+ sl_strlcpy(u_real, sh_tiger_hash(head_u, TIGER_DATA, 4,
+ hashbuf, sizeof(hashbuf)),
+ SH_CHALLENGE_SIZE);
+ foo_Sc = sh_srp_S_c (u_real, answer);
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: U = %s>\n"),
+ u_real));
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp:Sc = %s>\n"),
+ foo_Sc));
+
+ /* --- Now send H(A,B,H(Sc)) and check. ---
+ */
+ if (foo_Sc != NULL && 0 == sh_srp_check_zero (foo_Sc))
+ {
+ sh_srp_M(foo_A,
+ answer,
+ sh_tiger_hash(foo_Sc,
+ TIGER_DATA,
+ sl_strlen(foo_Sc),
+ hashbuf, sizeof(hashbuf)),
+ foo_M1, KEY_LEN+1);
+
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp:M1 = %s>\n"),
+ foo_M1));
+
+ flag_err = xfer_send(sockfd,
+ (theProto|SH_PROTO_SRP),
+ _("PC02"),
+ foo_M1, KEY_LEN+1);
+ }
+ else
+ flag_err = (-1);
+
+ if (flag_err == 0)
+ {
+ flag_err = xfer_receive(sockfd,
+ (theProto|SH_PROTO_SRP),
+ head_u,
+ answer, 511);
+ flag_err = (flag_err < 0) ? flag_err : 0;
+ TPT(( 0, FIL__, __LINE__, _("msg=<srp: M = %s>\n"),
+ answer));
+ }
+
+ if (flag_err == 0 && 0 == check_request (head_u, _("PARP")) )
+ {
+ /* ------ verify M2 = H(A, M1, K) --------
+ */
+ char M_buf[KEY_LEN+1];
+ M = sh_srp_M (foo_A, foo_M1,
+ sh_tiger_hash(foo_Sc,
+ TIGER_DATA,
+ sl_strlen(foo_Sc),
+ hashbuf, sizeof(hashbuf)),
+ M_buf, sizeof(M_buf)
+ );
+ if (M != NULL &&
+ 0 == sl_strncmp (answer, M, KEY_LEN+1))
+ {
+ sl_strlcpy (skey->session,
+ sh_tiger_hash(foo_Sc,
+ TIGER_DATA,
+ sl_strlen(foo_Sc),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<srp: Key = %s>\n"),
+ skey->session));
+
+#ifdef SH_ENCRYPT
+ err_num = rijndael_makeKey(&(skey->keyInstE),
+ DIR_ENCRYPT,
+ 192, skey->session);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1,
+ MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("xfer_try_report_int: makeKey"));
+ err_num = rijndael_makeKey(&(skey->keyInstD),
+ DIR_DECRYPT,
+ 192, skey->session);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1,
+ MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("xfer_try_report_int: makeKey"));
+#endif
+ *initialized = S_TRUE;
+ noise();
+ }
+ }
+ if (foo_Sc != NULL)
+ SH_FREE(foo_Sc);
+ }
+ }
+ if (foo_A != NULL)
+ SH_FREE(foo_A);
+ sh_srp_exit();
+ }
+ }
+
+ if (*initialized == S_FALSE)
+ {
+ xfer_timeout_val *= 2;
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NOAUTH);
+ memset(answer, '\0', 512);
+ MUNLOCK(answer, 512);
+ SH_FREE(answer);
+ return -1;
+ }
+ else
+ {
+ if (flag_err_info == S_TRUE)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_AUTH);
+ }
+ return 0;
+}
+#endif
+
+int xfer_check_server_cmd(char * answer, char * buffer)
+{
+ int flag_err;
+ size_t pos;
+ char sigbuf[KEYBUF_SIZE];
+
+ /* --- SERVER CMD --- */
+ if (answer[KEY_LEN] != '\0' &&
+ sl_strlen(answer) > (2*KEY_LEN))
+ {
+ pos = sl_strlen(answer) - (2*KEY_LEN);
+ /*
+ * buffer is >= 256
+ * answer has <= 255 bytes
+ */
+ (void) sl_strlcpy(buffer, &answer[KEY_LEN],
+ pos+1);
+ flag_err =
+ sl_strncmp(&answer[KEY_LEN+pos],
+ sh_util_siggen(skey->session,
+ buffer,
+ pos,
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN);
+
+ TPT((0, FIL__, __LINE__,
+ _("CONF RECV <%d> <%s>\n"),
+ flag_err, &answer[KEY_LEN]));
+
+ if (flag_err != 0) {
+ sh_error_handle((-1), FIL__, __LINE__,
+ flag_err,
+ MSG_TCP_NOCONF);
+ }
+#ifdef SH_WITH_CLIENT
+ else {
+ sh_socket_server_cmd(buffer);
+ }
+#endif
+ flag_err = 0;
+
+ } else {
+
+ TPT((0, FIL__, __LINE__,
+ _("CONF RECV <0> <[null]>\n")));
+
+ }
+ /* --- SERVER CMD END --- */
+ return 0;
+}
+
+
+
+int xfer_send_message(char * errmsg, int sockfd, char * answer)
+{
+ char hash[KEY_LEN+1];
+ size_t len;
+ char * buffer;
+ char nsrv[KEY_LEN+1];
+ char sigbuf[KEYBUF_SIZE];
+ char head_u[5];
+ int flag_err;
+
+ SL_REQUIRE((sockfd > 2), _("sockfd > 2"));
+
+ /* --- Save the challenge. ---
+ */
+ (void) sl_strlcpy(nsrv, answer, KEY_LEN + 1);
+
+ /* --- Hash(msg,challenge,sessionkey). ---
+ */
+ len = sl_strlen(errmsg) + sl_strlen(answer)
+ + KEY_LEN + 1;
+ len = (size_t)((len < 256) ? 256 : len);
+ buffer = SH_ALLOC(len);
+ MLOCK(buffer, len);
+ (void) sl_strlcpy(buffer, errmsg, len);
+ (void) sl_strlcat(buffer, answer, len);
+ (void) sl_strlcpy(hash,
+ sh_util_siggen (skey->session,
+ buffer,
+ sl_strlen(buffer),
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN+1);
+ TPT((0, FIL__, __LINE__, _("msg=<sign %s.>\n"),
+ sh_util_siggen(skey->session, buffer,
+ sl_strlen(buffer), sigbuf, sizeof(sigbuf))));
+
+ (void) sl_strlcpy(buffer, errmsg, len);
+ (void) sl_strlcat(buffer, hash, len);
+
+ flag_err =
+ xfer_send_crypt (sockfd,
+#ifdef SH_ENCRYPT
+ (char)(SH_PROTO_MSG|SH_PROTO_ENC),
+#else
+ (char)(SH_PROTO_MSG),
+#endif
+ _("MESG"),
+ buffer,
+ (unsigned long)(sl_strlen(buffer)+1));
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<Sent %s, status %d.>\n"),
+ answer, flag_err));
+
+ /* --- Get confirmation. ---
+ */
+ if (flag_err == 0)
+ {
+ flag_err = (int)
+ xfer_receive_crypt (sockfd,
+#ifdef SH_ENCRYPT
+ (char)(SH_PROTO_MSG|SH_PROTO_ENC|SH_PROTO_END),
+#else
+ (char)(SH_PROTO_MSG|SH_PROTO_END),
+#endif
+ head_u,
+ answer, 255);
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<Rcvt %s, u %s, status %d.>\n"),
+ answer, hu_trans(head_u), flag_err));
+ flag_err = (flag_err < 0) ? flag_err : 0;
+ }
+
+
+ /* --- Check confirmation. ---
+ */
+ if (flag_err == 0)
+ {
+ /* CLIENT CONF RECV
+ *
+ * first KEY_LEN bytes must be
+ * sig(skey->session (errmsg nsrv))
+ *
+ */
+ (void) sl_strlcpy(buffer, errmsg, len);
+ (void) sl_strlcat(buffer, nsrv, len);
+ flag_err = sl_strncmp(answer,
+ sh_util_siggen(skey->session,
+ buffer,
+ sl_strlen(buffer),
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN);
+ TPT((0, FIL__, __LINE__, _("msg=<sign %s.>\n"),
+ sh_util_siggen(skey->session, buffer,
+ sl_strlen(buffer), sigbuf, sizeof(sigbuf))));
+
+ if (flag_err != 0)
+ {
+#ifdef ENOMSG
+ flag_err = ENOMSG;
+#else
+ flag_err = EIO;
+#endif
+ sh_error_handle((-1), FIL__, __LINE__, flag_err,
+ MSG_TCP_NOCONF);
+ }
+ else
+ {
+#ifdef SH_ENCRYPT
+ flag_err = xfer_check_server_cmd(answer, buffer);
+#endif
+ if (flag_err_debug == S_TRUE)
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_TCP_CONF);
+ }
+ }
+
+ memset(buffer, 0, len);
+ MUNLOCK(buffer, len);
+ SH_FREE(buffer);
+
+ if (flag_err != 0)
+ return -1;
+ return 0;
+}
+
+
+static SL_TICKET xfer_get_file(int sockfd, char * answer,
+ char * nclt, char * foo_M1, const int theProto)
+{
+ /* --- Open a temporary file. ---
+ */
+ int flag_err = 0;
+ SL_TICKET sfd;
+
+ SL_REQUIRE((sockfd > 2), _("sockfd > 2"));
+
+ if ( (sfd = open_tmp ()) < 0)
+ {
+ flag_err = (-1);
+ sh_error_handle((-1), FIL__, __LINE__, flag_err, MSG_TCP_EFIL);
+ }
+ else
+ {
+ /* --- Read from socket into tmp file. ---
+ */
+ int transfercount = 0;
+ char head_u[5];
+
+ do {
+ flag_err = (int)
+ xfer_receive_crypt (sockfd,
+#ifdef SH_ENCRYPT
+ (char)(SH_PROTO_BIG|SH_PROTO_ENC),
+#else
+ (char)(SH_PROTO_BIG),
+#endif
+ head_u,
+ answer,
+ TRANS_BYTES + 255);
+
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<Received: %d bytes, marked %s.>\n"),
+ flag_err, hu_trans(head_u)));
+
+ if (flag_err > 0 && 0 == check_request_nerr(head_u, _("FILE")))
+ {
+ if (0 == hash_check (foo_M1, answer, flag_err))
+ {
+ (void) sl_write(sfd, &answer[KEY_LEN],
+ flag_err-KEY_LEN);
+ ++transfercount;
+
+ /* Delay for throughput throttling
+ */
+ if (sh_throttle_delay > 0)
+ retry_msleep(sh_throttle_delay/1000, sh_throttle_delay % 1000);
+
+ flag_err = xfer_send_crypt (sockfd, theProto,
+ _("RECV"),
+ nclt,
+ (unsigned long)sl_strlen(nclt));
+
+ }
+ else
+ {
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<File transfer: Hash check failed.>\n")));
+ break;
+ }
+ }
+ else
+ {
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<File transfer: No more data.>\n")));
+ break;
+ }
+ } while (transfercount < 32000); /* 64 Mbyte */
+
+ if (0 == check_request_nerr(head_u, _("EEOT")) &&
+ 0 < flag_err &&
+ 0 == hash_check (foo_M1, answer, (int)sl_strlen(answer)))
+ {
+ flag_err = xfer_send_crypt (sockfd, theProto,
+ _("EOTE"),
+ nclt,
+ (unsigned int) sl_strlen(nclt));
+
+ (void) rewind_tmp (sfd);
+ (void) sl_sync(sfd);
+ if (flag_err_info == S_TRUE)
+ sh_error_handle((-1), FIL__, __LINE__, flag_err, MSG_TCP_FOK);
+ }
+ else
+ {
+ (void) sl_close (sfd);
+ sfd = (-1);
+ }
+ }
+
+ return sfd;
+}
+
+static long xfer_try_report_int (char * errmsg, const int what)
+{
+ static int initialized = S_FALSE;
+ static int conn_state = S_TRUE;
+ int sockfd;
+ int flag_err = 0;
+ char * answer;
+ int theProto = 0;
+
+ UINT32 ticks;
+ char head_u[5];
+ char * buffer;
+ char nsrv[KEY_LEN+1];
+ char nclt[KEY_LEN+1];
+ char foo_M1[KEY_LEN+1];
+
+ char hashbuf[KEYBUF_SIZE];
+ char sigbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("xfer_try_report_int"));
+
+ /* --- No message to transmit. ---
+ */
+ if (errmsg == NULL && initialized == S_TRUE)
+ SL_RETURN( 0, _("xfer_try_report_int"));
+
+ /* --- Connection in bad state. ---
+ */
+ if (xfer_conn_state(initialized, conn_state) < 0)
+ SL_RETURN( (-1), _("xfer_try_report_int"));
+
+ /* --- Try to connect to log server. ---
+ */
+ sockfd = xfer_connect(&conn_state);
+ if (sockfd < 0)
+ SL_RETURN( (-1), _("xfer_try_report_int"));
+
+
+ /*************************
+ *
+ * initialization
+ *
+ */
+ flag_err = 0;
+ answer = SH_ALLOC(512);
+ MLOCK(answer, 512);
+
+ if (initialized == S_FALSE)
+ {
+ if (xfer_auth(S_FALSE, &initialized, sockfd, answer) < 0)
+ SL_RETURN( (-1), _("xfer_try_report_int"));
+ }
+
+ retry_send:
+
+ /* no message, just session key negotiated
+ */
+ if (errmsg == NULL)
+ {
+ xfer_timeout_val = 1;
+ memset(answer, 0, 512);
+ MUNLOCK(answer, 512);
+ SH_FREE(answer);
+ TPT(( 0, FIL__, __LINE__, _("msg=<No message.>\n")));
+ SL_RETURN( (0), _("xfer_try_report_int"));
+ }
+ else if (what == SH_PROTO_BIG)
+ {
+ MUNLOCK(answer, 512);
+ SH_FREE (answer);
+ answer = SH_ALLOC(TRANS_BYTES + 256);
+ MLOCK(answer, TRANS_BYTES + 256);
+ TPT(( 0, FIL__, __LINE__, _("msg=<File transfer.>\n")));
+ }
+
+ sl_strlcpy (answer,
+ sh_util_siggen(skey->session,
+ sh.host.name,
+ sl_strlen(sh.host.name),
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN+1);
+
+ TPT((0, FIL__, __LINE__, _("msg=<host %s>\n"), sh.host.name));
+ TPT((0, FIL__, __LINE__, _("msg=<ckey %s>\n"), skey->session));
+ TPT((0, FIL__, __LINE__, _("msg=<sign %s>\n"), answer));
+
+ sl_strlcat (answer, sh.host.name, 512);
+
+ TPT((0, FIL__, __LINE__, _("msg=<mesg %s>\n"), answer));
+
+ /***********************************************
+ *
+ * send the message
+ *
+ */
+
+ if (what == SH_PROTO_MSG)
+ theProto = SH_PROTO_MSG;
+ else if (what == SH_PROTO_BIG)
+ theProto = SH_PROTO_BIG;
+
+ /* --- Say HELO ---
+ */
+ flag_err = xfer_send (sockfd, theProto, _("HELO"),
+ answer, sl_strlen(answer));
+ TPT(( 0, FIL__, __LINE__, _("msg=<Sent %s, status %d.>\n"),
+ answer, flag_err));
+
+ if (flag_err == 0)
+ {
+ /* --- Get NSRV. ---
+ */
+ flag_err = (int) xfer_receive (sockfd, theProto, head_u, answer, 255);
+ TPT(( 0, FIL__, __LINE__, _("msg=<Rcvt %s, u %s, status %d.>\n"),
+ answer, hu_trans(head_u), flag_err));
+ flag_err = (flag_err < 0) ? flag_err : 0;
+ }
+
+ if (what == SH_PROTO_MSG)
+ {
+ if (flag_err == 0)
+ {
+ /* --- Re-negotiate key. ---
+ */
+ if (0 == check_request_nerr(head_u, _("INIT")))
+ {
+ flag_err = 0;
+ initialized = S_FALSE;
+ if (xfer_auth(S_TRUE, &initialized, sockfd, answer) == 0)
+ goto retry_send;
+ }
+
+ else if (0 == check_request(head_u, _("TALK")))
+ {
+ flag_err = xfer_send_message(errmsg, sockfd, answer);
+ }
+
+ else
+ {
+ /* --- Unexpected reply from server. ---
+ */
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_TCP_UNEXP);
+ flag_err = (-1);
+
+ }
+ }
+ }
+
+
+ else if (what == SH_PROTO_BIG)
+ {
+ if (flag_err == 0)
+ {
+
+ /* --- Re-negotiate key. ---
+ */
+ if (0 == check_request_nerr(head_u, _("INIT")))
+ {
+ flag_err = 0;
+ initialized = BAD;
+ if (xfer_auth(S_TRUE, &initialized, sockfd, answer) == 0)
+ goto retry_send;
+ }
+
+
+ else if (0 == check_request(head_u, _("NSRV")))
+ {
+ size_t buffersize;
+#ifdef SH_ENCRYPT
+ /* --- Set encryption flag. ---
+ */
+ theProto = (SH_PROTO_BIG|SH_PROTO_ENC);
+#endif
+
+ (void) sl_strlcpy(nsrv, answer, KEY_LEN+1);
+
+ /* --- Generate a nonce. ---
+ */
+ ticks = (UINT32) taus_get ();
+
+ (void) sl_strlcpy(nclt,
+ sh_tiger_hash((char *) &ticks,
+ TIGER_DATA,
+ (unsigned long)sizeof(UINT32),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ /* --- Compute H(nsrv, nclt, skey). ---
+ */
+ buffer = sh_util_strconcat (nsrv, nclt,
+ skey->session, NULL);
+ (void)sl_strlcpy(foo_M1,
+ sh_tiger_hash(buffer, TIGER_DATA,
+ (unsigned long)sl_strlen(buffer),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ memset (buffer, 0, sl_strlen(buffer));
+ SH_FREE(buffer);
+
+ /* --- Send (nclt, msg) ---
+ */
+ if (S_TRUE == sl_ok_adds(strlen(errmsg), strlen(nclt)+2+KEY_LEN))
+ {
+ buffersize = strlen(nclt)+strlen(errmsg)+2;
+
+#if !defined(SH_ENCRYPT)
+ buffersize += KEY_LEN;
+#endif
+ buffer = SH_ALLOC(buffersize);
+
+ sl_strlcpy(buffer, nclt, buffersize);
+ sl_strlcat(buffer, errmsg, buffersize);
+
+#if !defined(SH_ENCRYPT)
+ if (4 == sl_strlen(errmsg)) { /* backward compatibility */
+ buffersize = sl_strlen(buffer);
+ buffer[buffersize] = theProto; /* nctl//DATA//theProto */
+ buffer[buffersize+1] = '\0';
+ }
+ sh_tools_hash_add(foo_M1, buffer, buffersize+1);
+#endif
+
+ flag_err =
+ xfer_send_crypt (sockfd, (char) theProto, _("NCLT"),
+ buffer,
+ (unsigned long) sl_strlen(buffer));
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Sent %s, status %d.>\n"),
+ buffer, flag_err));
+ SH_FREE (buffer);
+ }
+ else {
+ flag_err = -1;
+ }
+ }
+ }
+
+ if (flag_err == 0)
+ {
+ /* --- Receive the file. ---
+ */
+ SL_TICKET sfd = xfer_get_file(sockfd, answer, nclt, foo_M1, theProto);
+ if (!SL_ISERROR(sfd))
+ {
+ (void) sl_close_fd (FIL__, __LINE__, sockfd);
+ memset(answer, 0, TRANS_BYTES + 256);
+ MUNLOCK(answer, TRANS_BYTES + 256);
+ SH_FREE(answer);
+ xfer_timeout_val = 1;
+
+ SL_RETURN( (sfd), _("xfer_try_report_int"));
+ }
+ }
+
+ (void) sl_close_fd (FIL__, __LINE__, sockfd);
+ memset(answer, 0, TRANS_BYTES + 256);
+ MUNLOCK(answer, TRANS_BYTES + 256);
+ SH_FREE(answer);
+ xfer_timeout_val *= 2;
+
+ SL_RETURN( (-1), _("xfer_try_report_int"));
+ }
+
+ (void) sl_close_fd (FIL__, __LINE__, sockfd);
+ memset(answer, 0, 512);
+ MUNLOCK(answer, 512);
+ SH_FREE(answer);
+
+#ifndef EIO
+#define EIO 5
+#endif
+
+
+#ifdef SH_ERROR_H
+ if (flag_err != 0)
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+ conn_state = S_FALSE;
+ xfer_timeout_val *= 2;
+ if (flag_err < 0 || NULL == sh_error_message(flag_err, errbuf, sizeof(errbuf)))
+ flag_err = EIO;
+ sh_error_handle((-1), FIL__, __LINE__, flag_err, MSG_TCP_ECONN,
+ sh_error_message(flag_err, errbuf, sizeof(errbuf)));
+ SL_RETURN( (-1), _("xfer_try_report_int"));
+ }
+#endif
+ xfer_timeout_val = 1;
+
+ SL_RETURN( (0), _("xfer_try_report_int"));
+}
+
+/* #ifdef SH_WITH_CLIENT */
+#endif
+
+
+
+
diff --git a/src/sh_xfer_server.c b/src/sh_xfer_server.c
new file mode 100644
index 0000000..0f7f1ab
--- /dev/null
+++ b/src/sh_xfer_server.c
@@ -0,0 +1,3778 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+/* Must be early on FreeBSD
+ */
+#include <sys/types.h>
+
+/* must be .le. than (1020 * 64)
+ * (see sh_tools.c -- put_header)
+ *
+ * also: must be (N * 16), otherwise
+ * binary files cannot be transferred encrypted
+ *
+ * 65280 = (1020*64)
+ * #define TRANS_BYTES 8000 V0.8
+ */
+#ifdef SH_ENCRYPT
+#define TRANS_BYTES 65120
+#else
+#define TRANS_BYTES 65280
+#endif
+
+/* timeout for session key
+ */
+#define TIMEOUT_KEY 7200
+
+/* max time between connection attempts
+ */
+#define TIMEOUT_CON 2048
+
+/* #undef SRP_DEBUG */
+/* #define SRP_DEBUG */
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+/*
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+*/
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <errno.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
+#include <sys/mman.h>
+#endif
+
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#ifndef S_SPLINT_S
+#include <arpa/inet.h>
+#endif
+
+#include "sh_ipvx.h"
+#include "samhain.h"
+#include "sh_tiger.h"
+#include "sh_utils.h"
+#include "sh_unix.h"
+#include "sh_xfer.h"
+#include "sh_srp.h"
+#include "sh_fifo.h"
+#include "sh_tools.h"
+#include "sh_entropy.h"
+#include "sh_html.h"
+#include "sh_nmail.h"
+#include "sh_socket.h"
+#define SH_NEED_GETHOSTBYXXX
+#include "sh_static.h"
+#include "sh_guid.h"
+
+#ifdef SH_ENCRYPT
+#include "rijndael-api-fst.h"
+char * sh_tools_makePack (unsigned char * header, int flag,
+ char * payload, unsigned long payload_size,
+ keyInstance * keyInstE);
+char * sh_tools_revertPack (unsigned char * header, int flag, char * message,
+ keyInstance * keyInstE,
+ unsigned long message_size);
+#endif
+
+/* define this if you want to debug the client/server communication */
+/* #define SH_DBG_PROT 1 */
+
+#ifdef SH_DBG_PROT
+#define SH_SHOWPROT(c,d) sh_tools_show_header((c), (d))
+#else
+#define SH_SHOWPROT(c,d)
+#endif
+
+/* the port client will be connecting to
+ */
+#ifndef SH_DEFAULT_PORT
+#define SH_DEFAULT_PORT 49777
+#endif
+
+#ifndef SH_SELECT_REPEAT
+#define SH_SELECT_REPEAT 60
+#endif
+
+#ifndef SH_HEADER_SIZE
+#define SH_HEADER_SIZE 7
+#endif
+
+#ifndef SH_CHALLENGE_SIZE
+#define SH_CHALLENGE_SIZE 9
+#endif
+
+#undef FIL__
+#define FIL__ _("sh_xfer_server.c")
+
+int clt_class = (-1);
+
+extern int flag_err_debug;
+extern int flag_err_info;
+
+
+#if defined (SH_WITH_SERVER)
+
+#if defined(WITH_TRACE) || defined(WITH_TPT)
+extern char * hu_trans(const char * ihu);
+#endif
+extern unsigned int ServerPort;
+#if !defined(USE_SRP_PROTOCOL)
+extern void sh_passwd (char * salt, char * password, char * nounce, char *hash);
+#endif
+
+static int StripDomain = S_TRUE;
+
+int sh_xfer_set_strip (const char * str)
+{
+ static int fromcl = 0;
+
+ if (fromcl == 1)
+ return 0;
+ else
+ return (sh_util_flagval(str, &StripDomain));
+}
+
+static char * sh_strip_domain (char *name)
+{
+ char * out = NULL;
+
+ SL_ENTER(_("sh_strip_domain"));
+
+ if (StripDomain == S_FALSE || strchr(name, '.') == NULL)
+ {
+ out = sh_util_strdup(name);
+ SL_RETURN( out, _("sh_strip_domain"));
+ }
+ else
+ {
+ /* check whether it is in dotted number format
+ * --> last part must be kept
+ */
+ if (0 != sh_ipvx_is_numeric(name))
+ {
+ out = sh_util_strdup(name);
+ SL_RETURN( out, _("sh_strip_domain"));
+ }
+ else
+ {
+ char * p;
+ out = sh_util_strdup(name);
+ p = strchr(out, '.');
+ if (p) *p = '\0';
+ SL_RETURN( out, _("sh_strip_domain"));
+ }
+ }
+
+ SL_RETURN( out, _("sh_strip_domain"));
+}
+
+#ifndef USE_SRP_PROTOCOL
+
+int sh_xfer_make_client (const char * str)
+{
+ /* char * safer; */
+ char key[KEY_LEN+1];
+ unsigned char in[PW_LEN+1];
+ int i = 0, j, k, l = 0;
+ char hashbuf[KEYBUF_SIZE];
+
+ if (sl_strlen(str) != (PW_LEN * 2))
+ {
+ fprintf(stderr,
+ _("Input must be a %d digit hexadecimal number"\
+ " (only 0-9, a-f, A-F allowed in input)\n"),
+ (PW_LEN * 2));
+ _exit(EXIT_FAILURE);
+ }
+
+ while (i < (PW_LEN * 2))
+ {
+ k = sh_util_hexchar(str[i]); j = sh_util_hexchar(str[i+1]);
+ if (k != -1 && j != -1)
+ {
+ in[l] = (k * 16 + j);
+ ++l; i+= 2;
+ }
+ else
+ {
+ fprintf(stderr, _("Invalid char %c\n"), str[i]);
+ _exit(EXIT_FAILURE);
+ }
+ }
+ in[PW_LEN] = '\0';
+
+ sl_strlcpy ((char *)key,
+ sh_tiger_hash ((char*)in, TIGER_DATA, PW_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ key[KEY_LEN] = '\0';
+
+ fprintf(stdout, _("Client entry: Client=HOSTNAME@00000000@%s\n"),
+ key);
+ fflush(stdout);
+
+ _exit(EXIT_SUCCESS);
+ return 0;
+}
+
+#else
+
+int sh_xfer_make_client (const char * str)
+{
+ char * foo_v;
+
+ char salt[17];
+ char key[KEY_LEN+1];
+ char in[PW_LEN];
+ int i = 0, j, k, l = 0;
+ char hashbuf[KEYBUF_SIZE];
+
+ if (sl_strlen(str) != (PW_LEN*2))
+ {
+ fprintf(stderr,
+ _("Input must be a %d digit hexadecimal number"\
+ " (only 0-9, a-f, A-F allowed in input)\n"),
+ (PW_LEN*2));
+ _exit(EXIT_FAILURE);
+ }
+
+ while (i < (PW_LEN*2))
+ {
+ k = sh_util_hexchar(str[i]); j = sh_util_hexchar(str[i+1]);
+ if (k != -1 && j != -1)
+ {
+ in[l] = (k * 16 + j);
+ ++l; i+= 2;
+ }
+ else
+ {
+ fprintf(stderr, _("Invalid char %c\n"), str[i]);
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+
+ if (0 == sh_srp_init())
+ {
+ sh_util_keyinit(key, KEY_LEN);
+ sl_strlcpy(salt, sh_tiger_hash(key, TIGER_DATA, KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ 17);
+ sh_srp_x (salt, in);
+ foo_v = sh_srp_verifier ();
+ fprintf(stdout, _("Client=HOSTNAME@%s@%s\n"),
+ salt, foo_v);
+ fflush(stdout);
+ SH_FREE(foo_v);
+ sh_srp_exit();
+ _exit(EXIT_SUCCESS);
+ }
+ fprintf(stdout, "%s",_("ERROR initializing BigNum library.\n"));
+ fflush (stdout);
+ _exit(EXIT_FAILURE);
+ return -1;
+}
+#endif
+
+
+int sh_xfer_create_password (const char * dummy)
+{
+ UINT32 val[2];
+ char output[KEY_LEN+1];
+ char hashbuf[KEYBUF_SIZE];
+
+ val[0] = taus_get ();
+ val[1] = taus_get ();
+
+ sl_strlcpy (output,
+ sh_tiger_hash((char *)(&val[0]), TIGER_DATA, 2*sizeof(UINT32),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN);
+
+ output[16] = '\0';
+
+ fprintf(stdout, _("%s\n"), output);
+ fflush (stdout);
+
+ if (dummy)
+ _exit(EXIT_SUCCESS);
+ else
+ _exit(EXIT_SUCCESS);
+ return (0); /* avoid compiler warning */
+}
+
+/* #if defined (SH_WITH_SERVER) */
+#endif
+
+/**************************************************
+ *
+ *
+ * S E R V E R
+ *
+ *
+ ***************************************************/
+
+#ifdef SH_WITH_SERVER
+
+#include "sh_readconf.h"
+
+
+#define CONN_FREE 0
+#define CONN_READING 1
+#define CONN_SENDING 2
+#define CONN_PAUSE 3
+#define CONN_BUSY 4
+
+char * clt_stat[] = {
+ N_("Inactive"),
+ N_("Started"),
+ N_("ILLEGAL"),
+ N_("FAILED"),
+ N_("Exited"),
+ N_("PANIC"),
+ N_("POLICY"),
+ N_("File_transfer"),
+ N_("Message"),
+ N_("TIMEOUT_EXCEEDED"),
+ N_("Suspended"),
+ N_("Filecheck"),
+};
+
+#include <time.h>
+
+/* in sh_html.h:
+ * typedef struct client_entry {
+ * } client_t;
+ */
+
+#include "zAVLTree.h"
+
+static char * sh_tolower (char * s)
+{
+ char * ret = s;
+ if (s)
+ {
+ for (; *s; ++s)
+ {
+ *s = tolower((unsigned char) *s);
+ }
+ }
+ return ret;
+}
+
+/* Function to return the key for indexing
+ * the argument
+ */
+zAVLKey sh_avl_key (void const * arg)
+{
+ const client_t * sa = (const client_t *) arg;
+ return (zAVLKey) sa->hostname;
+}
+
+zAVLTree * all_clients = NULL;
+
+void sh_xfer_html_write()
+{
+ SL_ENTER(_("sh_xfer_html_write"));
+ sh_html_write(all_clients);
+ SL_RET0(_("sh_xfer_html_write"));
+}
+
+
+int sh_xfer_use_clt_class (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_xfer_use_clt_class"));
+ i = sh_util_flagval(c, &(sh.flag.client_class));
+ SL_RETURN(i, _("sh_xfer_use_clt_class"));
+}
+
+int sh_xfer_use_clt_sev (const char * c)
+{
+ int i;
+ SL_ENTER(_("sh_xfer_use_clt_sev"));
+ i = sh_util_flagval(c, &(sh.flag.client_severity));
+ SL_RETURN(i, _("sh_xfer_use_clt_sev"));
+}
+
+
+/* the destructor
+ */
+void free_client(void * inptr)
+{
+ client_t * here;
+
+ SL_ENTER(_("free_client"));
+ if (inptr == NULL)
+ SL_RET0(_("free_client"));
+ else
+ here = (client_t *) inptr;
+
+ if (here->hostname != NULL)
+ SH_FREE(here->hostname);
+ if (here->salt != NULL)
+ SH_FREE(here->salt);
+ if (here->verifier != NULL)
+ SH_FREE(here->verifier);
+ SH_FREE(here);
+ SL_RET0(_("free_client"));
+}
+
+
+int sh_xfer_register_client (const char * str)
+{
+ client_t * newclt;
+ client_t * testclt;
+
+ const char * ptr;
+ int sepnum = 0;
+ int sep[2];
+ register int i = 0;
+ int siz_str = 0;
+
+ SL_ENTER(_("sh_xfer_register_client"));
+
+ ptr = str;
+ while (*ptr) {
+ if (*ptr == '@' && sepnum < 2 )
+ {
+ sep[sepnum] = i;
+ ++sepnum;
+ }
+ ++ptr; ++i;
+ }
+
+ if (all_clients == NULL)
+ {
+ all_clients = zAVLAllocTree (sh_avl_key, zAVL_KEY_STRING);
+ if (all_clients == NULL)
+ {
+ (void) safe_logger (0, 0, NULL);
+ aud__exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+ }
+
+ if ((sepnum == 2) && (sep[0] > 0) && (sep[1] > sep[0]))
+ {
+ newclt = SH_ALLOC (sizeof(client_t));
+ newclt->hostname = SH_ALLOC (sep[0]+1);
+ newclt->salt = SH_ALLOC (sep[1]-sep[0]);
+ newclt->verifier = SH_ALLOC (sl_strlen(str)-sep[1]+1);
+ newclt->exit_flag = 0;
+ newclt->dead_flag = 0;
+#ifdef SH_ENCRYPT
+ newclt->encf_flag = SH_PROTO_ENC;
+ newclt->ency_flag = SH_PROTO_ENC;
+#else
+ newclt->encf_flag = 0;
+ newclt->ency_flag = 0;
+#endif
+ newclt->ivst_flag = 0;
+ newclt->session_key[0] = '\0';
+ newclt->last_connect = (time_t) 0;
+ newclt->session_key_timer = (time_t) 0;
+ newclt->status_now = CLT_INACTIVE;
+ for (i = 0; i < CLT_MAX; ++i)
+ newclt->status_arr[i] = CLT_INACTIVE;
+ (void) sh_unix_time(0, newclt->timestamp[CLT_INACTIVE], TIM_MAX);
+
+ /* truncate */
+ sl_strlcpy(newclt->hostname, &str[0], sep[0]+1);
+ sh_tolower(newclt->hostname);
+
+ /* truncate */
+ sl_strlcpy(newclt->salt, &str[sep[0]+1], sep[1]-sep[0]);
+ sl_strlcpy(newclt->verifier, &str[sep[1]+1], sl_strlen(str)-sep[1]+1);
+
+ testclt = (client_t *) zAVLSearch (all_clients, newclt->hostname);
+
+ if (testclt != NULL)
+ {
+ SH_FREE(testclt->verifier);
+ siz_str = strlen (newclt->verifier) + 1;
+ testclt->verifier = SH_ALLOC (siz_str);
+ sl_strlcpy(testclt->verifier, newclt->verifier, siz_str);
+
+ SH_FREE(testclt->salt);
+ siz_str = strlen (newclt->salt) + 1;
+ testclt->salt = SH_ALLOC (siz_str);
+ sl_strlcpy(testclt->salt, newclt->salt, siz_str);
+
+ testclt->dead_flag = 0;
+
+ free_client(newclt);
+ SL_RETURN( 0, _("sh_xfer_register_client"));
+ }
+ else
+ {
+ if (0 == zAVLInsert (all_clients, newclt))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_CREG,
+ newclt->hostname,
+ newclt->salt, newclt->verifier);
+ SL_RETURN( 0, _("sh_xfer_register_client"));
+ }
+ }
+ }
+ SL_RETURN (-1, _("sh_xfer_register_client"));
+}
+
+typedef struct {
+ int state;
+ int fd;
+ char * buf;
+ unsigned char head[SH_HEADER_SIZE];
+ char challenge[SH_CHALLENGE_SIZE];
+ char peer[SH_MINIBUF+1];
+ client_t * client_entry;
+ char * K;
+ char * M1;
+ char * A;
+ int headcount;
+ unsigned long bytecount;
+ unsigned long bytes_to_send;
+ unsigned long bytes_to_get;
+ int pass;
+ unsigned long timer;
+
+ char * FileName;
+ unsigned long FileLength;
+ unsigned long FileSent;
+ char FileType[5];
+
+ struct sh_sockaddr addr_peer;
+} sh_conn_t;
+
+
+static char zap_challenge[SH_CHALLENGE_SIZE] = { 0 };
+
+void sh_xfer_do_free (sh_conn_t * conn)
+{
+ SL_ENTER(_("sh_xfer_do_free"));
+
+ if (conn->K != NULL)
+ {
+ SH_FREE(conn->K);
+ conn->K = NULL;
+ }
+ if (conn->A != NULL)
+ {
+ SH_FREE(conn->A);
+ conn->A = NULL;
+ }
+ if (conn->M1 != NULL)
+ {
+ SH_FREE(conn->M1);
+ conn->M1 = NULL;
+ }
+ if (conn->buf != NULL)
+ {
+ SH_FREE(conn->buf);
+ conn->buf = NULL;
+ }
+ if (conn->fd != (-1))
+ {
+ sl_close_fd (FIL__, __LINE__, conn->fd);
+ conn->fd = -1;
+ }
+ memcpy(conn->challenge, zap_challenge, SH_CHALLENGE_SIZE);
+ conn->state = CONN_FREE;
+ conn->headcount = 0;
+ conn->bytecount = 0;
+ conn->bytes_to_send = 0;
+ conn->bytes_to_get = 0;
+ conn->pass = 0;
+ conn->timer = 0;
+ conn->client_entry = NULL;
+
+ if (conn->FileName != NULL)
+ {
+ SH_FREE(conn->FileName);
+ conn->FileName = NULL;
+ }
+ conn->FileLength = 0;
+ conn->FileSent = 0;
+ conn->FileType[0] = '\0';
+ conn->FileType[1] = '\0';
+ conn->FileType[2] = '\0';
+ conn->FileType[3] = '\0';
+ conn->FileType[4] = '\0';
+
+ --server_status.conn_open;
+
+ SL_RET0(_("sh_xfer_do_free"));
+}
+
+/****************************************
+ *
+ * -- Reconfiguration. --
+ *
+ * (1) Mark all clients as 'dead'.
+ * (2) Reload configuration - clients
+ * in config are non-dead now.
+ * (3) Remove all clients still
+ * marked as 'dead'.
+ */
+
+/* -- Mark all clients as dead.
+ */
+void sh_xfer_mark_dead (void)
+{
+ zAVLCursor avlcursor;
+ client_t * item;
+
+ SL_ENTER(_("sh_xfer_mark_dead"));
+
+ for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
+ item = (client_t *) zAVLNext(&avlcursor))
+ {
+ item->dead_flag = 1;
+ }
+ SL_RET0(_("sh_xfer_mark_dead"));
+}
+
+
+/* -- Clean tree from dead clients.
+ */
+void sh_xfer_clean_tree (void)
+{
+ zAVLCursor avlcursor;
+ client_t * item;
+
+ SL_ENTER(_("sh_xfer_clean_tree"));
+
+ repeat_search:
+
+ for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
+ item = (client_t *) zAVLNext(&avlcursor))
+ {
+ if (item->dead_flag == 1)
+ {
+ zAVLDelete (all_clients, item->hostname);
+ free_client (item);
+ goto repeat_search;
+ }
+ }
+ SL_RET0(_("sh_xfer_clean_tree"));
+}
+
+/*
+ *
+ **********************************************/
+
+
+
+/* -- SERVER SEND FUNCTION. --
+ */
+void sh_xfer_prep_send_int (sh_conn_t * conn,
+ char * msg, unsigned long length,
+ char * u, char protocol,
+ int docrypt)
+{
+ /* register unsigned long i; */
+ unsigned long length2;
+
+#if !defined(SH_ENCRYPT)
+ (void) docrypt;
+#endif
+
+ SL_ENTER(_("sh_xfer_prep_send_int"));
+
+ TPT((0, FIL__, __LINE__, _("msg=<%s>, docrypt=<%d>\n"), msg, docrypt ));
+
+ length2 = length;
+
+ conn->headcount = 0;
+ conn->bytecount = 0;
+ conn->bytes_to_send = 0;
+ conn->bytes_to_get = 0;
+
+ if (conn->buf != NULL)
+ {
+ SH_FREE(conn->buf);
+ conn->buf = NULL;
+ }
+
+ put_header (conn->head, protocol, &length2, u);
+ SH_SHOWPROT(conn->head,'>');
+
+ TPT((0, FIL__, __LINE__, _("msg=<put_header done>\n") ));
+
+ if (msg == NULL)
+ length2 = 0;
+
+#ifdef SH_ENCRYPT
+ if ((S_TRUE == docrypt) && ((protocol & SH_PROTO_ENC) != 0))
+ {
+ TPT((0, FIL__, __LINE__, _("encrypting (version 2)\n")));
+
+ conn->buf = sh_tools_makePack (conn->head, conn->client_entry->ivst_flag,
+ msg, length2,
+ &(conn->client_entry->keyInstE));
+ }
+ else if (msg == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ _("msg is NULL"),
+ _("sh_xfer_prep_send_int: cipherInit"));
+ }
+ else
+ {
+ if ((length2 + 1) < length2) --length2;
+ conn->buf = SH_ALLOC(length2 + 1);
+
+ memcpy(conn->buf, msg, length2);
+ conn->buf[length2] = '\0';
+ TPT((0, FIL__, __LINE__, _("msg=<no encryption done>\n") ));
+ }
+#else
+ if ((length2 + 1) < length2) --length2;
+ conn->buf = SH_ALLOC(length2 + 1);
+
+ memcpy(conn->buf, msg, length2);
+ conn->buf[length2] = '\0';
+ TPT((0, FIL__, __LINE__, _("msg=<no encryption done>\n") ));
+#endif
+
+ conn->state = CONN_SENDING;
+ SL_RET0(_("sh_xfer_prep_send_int"));
+}
+
+/* -- Send/Receive. --
+ */
+void sh_xfer_prep_send (sh_conn_t * conn,
+ char * msg, unsigned long length,
+ char * u, char protocol)
+{
+ SL_ENTER(_("sh_xfer_prep_send"));
+ sh_xfer_prep_send_int (conn, msg, length, u, protocol, S_FALSE);
+ SL_RET0(_("sh_xfer_prep_send"));
+}
+
+void sh_xfer_send_crypt (sh_conn_t * conn,
+ char * msg, unsigned long length,
+ char * u, char protocol)
+{
+ SL_ENTER(_("sh_xfer_send_crypt"));
+ sh_xfer_prep_send_int (conn, msg, length, u, protocol, S_TRUE);
+ SL_RET0(_("sh_xfer_send_crypt"));
+}
+
+/* #include <sys/times.h> */
+
+#if defined(WITH_EXTERNAL)
+#include "sh_extern.h"
+#endif
+
+/* -- Update the client status. --
+ *
+ * Update the status array for the client,
+ * and eventually call external program.
+ */
+static void status_update (client_t * conn, int status)
+{
+#if defined(WITH_EXTERNAL)
+ char msg[2 * SH_MINIBUF + TIM_MAX + 3];
+#endif
+
+ SL_ENTER(_("status_update"));
+
+ if (conn == NULL ||
+ status < 0 || status >= CLT_MAX)
+ SL_RET0(_("status_update"));
+
+ conn->status_now = status;
+ conn->status_arr[status] = status;
+ (void) sh_unix_time(0, conn->timestamp[status], TIM_MAX);
+
+#if defined(WITH_EXTERNAL)
+ sl_snprintf(msg, sizeof(msg), _("%s %s %s"),
+ conn->hostname, conn->timestamp[status], _(clt_stat[status]));
+ sh_ext_execute('s', 'r', 'v', msg, 0);
+#endif
+
+ SL_RET0(_("status_update"));
+}
+
+static time_t time_client_limit = 86400;
+
+int sh_xfer_set_time_limit (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_xfer_set_time_limit"));
+
+ val = strtol (c, (char **)NULL, 10);
+ if (val <= 0)
+ SL_RETURN( (-1), _("sh_xfer_set_time_limit"));
+
+ time_client_limit = (time_t) val;
+ SL_RETURN( (0), _("sh_xfer_set_time_limit"));
+}
+
+
+/* -- Check for time limit exceeded. --
+ */
+static int client_time_check(void)
+{
+ zAVLCursor avlcursor;
+ client_t * item;
+
+ SL_ENTER(_("client_time_check"));
+
+ if (time_client_limit == (time_t) 0)
+ SL_RETURN( 0, _("client_time_check"));
+
+ for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
+ item = (client_t *) zAVLNext(&avlcursor))
+ {
+ if (item->exit_flag == 0 && item->last_connect != (time_t) 0)
+ {
+ if ( (time(NULL) - item->last_connect) > time_client_limit)
+ {
+ if (item->status_now != CLT_TOOLONG)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_TIMEXC,
+ item->hostname);
+ status_update (item, CLT_TOOLONG);
+ }
+ }
+ }
+ }
+ SL_RETURN( 0, _("client_time_check"));
+}
+
+static int lookup_err = SH_ERR_SEVERE;
+
+int sh_xfer_lookup_level (const char * c)
+{
+ int ci = sh_error_convert_level (c);
+
+ SL_ENTER(_("sh_xfer_lookup_level"));
+
+ if (ci >= 0)
+ {
+ lookup_err = ci;
+ SL_RETURN( 0, _("sh_xfer_lookup_level"));
+ }
+ else
+ SL_RETURN( (-1), _("sh_xfer_lookup_level"));
+}
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 127
+#endif
+
+int check_addr (const char * claim, struct sh_sockaddr * addr_peer)
+{
+ char h_name[MAXHOSTNAMELEN + 1];
+ char h_peer[MAXHOSTNAMELEN + 1];
+ char h_peer_IP[SH_IP_BUF];
+ char tmp_peer_IP[SH_IP_BUF];
+ char * canonical;
+ char numeric[SH_IP_BUF];
+
+ SL_ENTER(_("check_addr"));
+
+ if (claim == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("NULL input"), _("check_addr"));
+ SL_RETURN ((-1), _("check_addr"));
+ }
+
+ /* Make sure we have the canonical name for the client
+ */
+ canonical = sh_ipvx_canonical(claim, numeric, sizeof(numeric));
+
+ /* copy canonical name into h_name
+ */
+ if (canonical != NULL)
+ {
+ sl_strlcpy(h_name, canonical, MAXHOSTNAMELEN + 1);
+ SH_FREE(canonical);
+ }
+ else
+ {
+ sh_error_handle(lookup_err, FIL__, __LINE__, 0, MSG_TCP_RESCLT,
+ claim);
+ SL_RETURN ((0), _("check_addr"));
+ }
+
+
+ /* get canonical name of socket peer
+ */
+ canonical = sh_ipvx_addrtoname(addr_peer);
+
+ if (canonical)
+ {
+ if (0 == sl_strcmp(canonical, _("localhost")))
+ sl_strlcpy(h_peer, sh.host.name, MAXHOSTNAMELEN + 1);
+ else
+ sl_strlcpy(h_peer, canonical, MAXHOSTNAMELEN + 1);
+ SH_FREE(canonical);
+ }
+ else
+ {
+ sh_ipvx_ntoa (tmp_peer_IP, sizeof(tmp_peer_IP), addr_peer);
+ sh_error_handle(lookup_err, FIL__, __LINE__, 0, MSG_TCP_RESPEER,
+ claim, tmp_peer_IP);
+ SL_RETURN ((0), _("check_addr"));
+ }
+
+ sh_ipvx_ntoa (h_peer_IP, sizeof(h_peer_IP), addr_peer);
+
+ /* reverse lookup
+ */
+ if (0 == sh_ipvx_reverse_check_ok (h_peer, ServerPort, addr_peer))
+ {
+ sh_ipvx_ntoa (tmp_peer_IP, sizeof(tmp_peer_IP), addr_peer);
+
+ sh_error_handle(lookup_err, FIL__, __LINE__, 0, MSG_TCP_LOOKERS,
+ claim, h_peer, tmp_peer_IP);
+ SL_RETURN ((0), _("check_addr"));
+ }
+
+ /* Check whether claim and peer are identical
+ */
+ sh_tolower(h_peer); /* Canonical name of what the peer is */
+ sh_tolower(h_name); /* Canonical name of what the peer claims */
+
+ if ((0 == sl_strcmp(h_peer, h_name)) || (0 == sl_strcmp(h_peer_IP, h_name)))
+ {
+ SL_RETURN ((0), _("check_addr"));
+ }
+#if !defined(USE_IPVX)
+ else
+ {
+ struct hostent * he = sh_gethostbyname(h_peer);
+ int i = 0;
+ int flag = 0;
+
+ while (he->h_aliases[i] != NULL)
+ {
+ if (0 == sl_strcmp(sh_tolower(he->h_aliases[i]), h_name))
+ {
+ flag = 1;
+ break;
+ }
+ ++i;
+ }
+ if (flag == 0)
+ sh_error_handle(lookup_err, FIL__, __LINE__, 0, MSG_TCP_LOOKUP,
+ claim, h_peer);
+ }
+#endif
+
+ SL_RETURN ((0), _("check_addr"));
+}
+
+static int UseSocketPeer = S_FALSE;
+
+int set_socket_peer (const char * c)
+{
+ return sh_util_flagval(c, &UseSocketPeer);
+}
+
+
+/* -- Search register. --
+ */
+client_t * search_register(sh_conn_t * conn, int pos)
+{
+ client_t * this_client;
+ char peer_ip[SH_IP_BUF];
+ char numerical[SH_IP_BUF];
+ char peer_name[MAXHOSTNAMELEN+1];
+ char * search_string;
+
+ struct sh_sockaddr peer_addr;
+ char * canonical;
+
+ SL_ENTER(_("search_register"));
+
+ if (UseSocketPeer == S_TRUE)
+ {
+ memcpy(&peer_addr, &(conn->addr_peer), sizeof(struct sh_sockaddr));
+ sh_ipvx_ntoa (peer_ip, sizeof(peer_ip), &peer_addr);
+
+ /* get canonical name of socket peer
+ */
+ canonical = sh_ipvx_canonical(peer_ip, numerical, sizeof(numerical));
+
+ if (canonical != NULL)
+ {
+ if (0 == sl_strcmp(canonical, _("localhost")))
+ sl_strlcpy(peer_name, sh.host.name, MAXHOSTNAMELEN + 1);
+ else
+ sl_strlcpy(peer_name, canonical, MAXHOSTNAMELEN + 1);
+ SH_FREE(canonical);
+ }
+
+ if (0 == sh_ipvx_reverse_check_ok (peer_name, ServerPort, &peer_addr))
+ {
+ sl_strlcpy(peer_name, peer_ip, MAXHOSTNAMELEN + 1);
+ }
+
+ search_string = peer_name;
+ }
+ else
+ {
+ search_string = &(conn->buf[pos]);
+
+ if (0 != check_addr (search_string, &(conn->addr_peer)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Reverse lookup failed"), search_string);
+ sh_xfer_do_free (conn);
+ SL_RETURN( NULL, _("search_register"));
+ }
+ }
+
+ sh_tolower(search_string);
+
+ /* ---- search the register -----
+ */
+ this_client = zAVLSearch(all_clients, search_string);
+
+ if (this_client == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Not in client list"), search_string);
+ sh_xfer_do_free (conn);
+ SL_RETURN( NULL, _("search_register"));
+ }
+ if (this_client->exit_flag == 1)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<this_client->exit_flag == 1>\n")));
+ this_client->session_key_timer = (time_t) 0;
+ this_client->session_key[0] = '\0';
+ this_client->exit_flag = 0;
+ }
+ TPT((0, FIL__, __LINE__, _("msg=<search_register: client %s>\n"),
+ this_client->hostname));
+ TPT((0, FIL__, __LINE__, _("msg=<search_register: key %s>\n"),
+ this_client->session_key));
+ SL_RETURN( this_client, _("search_register"));
+}
+
+client_t * do_check_client(sh_conn_t * conn, int * retval)
+{
+ client_t * this_client = NULL;
+ char sigbuf[KEYBUF_SIZE];
+
+ *retval = 0;
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Client connect - HELO (1).>\n")));
+
+ if (conn->buf == NULL || sl_strlen(conn->buf) <= KEY_LEN)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NOCLT);
+ sh_xfer_do_free (conn);
+ return NULL;
+ }
+
+ /* ---- search the register -----
+ */
+
+ this_client = search_register (conn, KEY_LEN);
+ if (this_client == NULL)
+ return NULL;
+
+ /* ---- force authentication -----
+ */
+
+ if (this_client->session_key[0] == '\0' ||
+ (time(NULL) - this_client->session_key_timer)
+ > (time_t) TIMEOUT_KEY )
+ {
+ size_t len;
+
+ /* fake an auth request and jump there
+ */
+ conn->head[0] = (conn->head[0] | SH_PROTO_SRP);
+ conn->head[3] = 'S';
+ conn->head[4] = 'A';
+ conn->head[5] = 'L';
+ conn->head[6] = 'T';
+ if (flag_err_info == S_TRUE)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FAUTH,
+ &(conn->buf[KEY_LEN]));
+ len = sl_strlen(&(conn->buf[KEY_LEN])) + 1;
+ /* may overlap, thus only memmove is correct */
+ memmove(conn->buf, &(conn->buf[KEY_LEN]), len);
+ this_client->session_key[0] = '\0';
+ this_client->session_key_timer = (time_t) 1;
+ *retval = -1;
+ return NULL;
+ }
+
+ /* --- check whether hostname is properly signed ---
+ */
+ if (conn->K != NULL)
+ {
+ SH_FREE(conn->K);
+ conn->K = NULL;
+ }
+
+ conn->K = SH_ALLOC(KEY_LEN+1);
+
+ sl_strlcpy (conn->K,
+ sh_util_siggen(this_client->session_key,
+ &(conn->buf[KEY_LEN]),
+ sl_strlen(&(conn->buf[KEY_LEN])),
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN+1);
+
+ if (0 != sl_strncmp(conn->K, conn->buf, KEY_LEN))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<clt %s>\n"), conn->buf));
+ TPT((0, FIL__, __LINE__, _("msg=<srv %s>\n"), conn->K));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Signature mismatch"),
+ &(conn->buf[KEY_LEN]));
+
+ this_client->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+
+ sh_xfer_do_free (conn);
+ return NULL;
+ }
+ SH_FREE(conn->K);
+ conn->K = NULL;
+
+ return this_client;
+}
+
+/* ------------------------------------------------------
+ *
+ * FILE TRANSFER
+ *
+ * ------------------------------------------------------ */
+
+static void do_file_send_data(sh_conn_t * conn)
+{
+ char * read_buf = 0;
+ char * send_buf;
+ int bytes;
+ SL_TICKET sfd = -1;
+#ifdef SH_ENCRYPT
+ int blkfac;
+ int rem;
+ int send_bytes;
+#endif
+
+ if (conn == NULL || conn->FileName == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, sfd, MSG_TCP_NFILE,
+ conn->peer,
+ (conn->FileName == NULL) ?
+ _("(NULL)") : conn->FileName);
+ status_update (conn->client_entry, CLT_FAILED);
+ sh_xfer_do_free (conn);
+ return;
+ }
+
+ if (conn->FileSent == conn->FileLength)
+ {
+ send_buf = hash_me(conn->K, conn->peer, sl_strlen(conn->peer));
+#ifdef SH_ENCRYPT
+ sh_xfer_send_crypt (conn, send_buf, sl_strlen(conn->peer)+KEY_LEN,
+ _("EEOT"), SH_PROTO_BIG|conn->client_entry->encf_flag);
+#else
+ sh_xfer_send_crypt (conn, send_buf, sl_strlen(conn->peer)+KEY_LEN,
+ _("EEOT"), SH_PROTO_BIG);
+#endif
+ SH_FREE(send_buf);
+ }
+ else
+ {
+ bytes = -1;
+
+ sfd = sl_open_read(FIL__, __LINE__, conn->FileName, SL_YESPRIV);
+
+ if (!SL_ISERROR(sfd))
+ {
+ read_buf = SH_ALLOC(TRANS_BYTES);
+ if (conn->FileSent > 0)
+ sl_seek (sfd, (off_t) conn->FileSent);
+ bytes = sl_read (sfd, read_buf, TRANS_BYTES);
+ sl_close(sfd);
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, sfd,
+ MSG_E_ACCESS, (long) geteuid(), conn->FileName);
+ }
+
+ if (bytes >= 0)
+ {
+#ifdef SH_ENCRYPT
+ /* need to send N * B_SIZ bytes
+ */
+ blkfac = bytes / B_SIZ;
+ rem = bytes - (blkfac * B_SIZ);
+ if (rem != 0)
+ {
+ memset(&read_buf[bytes], '\n', (B_SIZ-rem));
+ ++blkfac;
+ send_bytes = blkfac * B_SIZ;
+ }
+ else
+ send_bytes = bytes;
+
+ send_buf = hash_me(conn->K, read_buf, send_bytes);
+
+ sh_xfer_send_crypt (conn, send_buf, send_bytes+KEY_LEN, _("FILE"),
+ SH_PROTO_BIG|conn->client_entry->encf_flag);
+#else
+ send_buf = hash_me(conn->K, read_buf, bytes);
+ sh_xfer_send_crypt (conn, send_buf, bytes+KEY_LEN, _("FILE"),
+ SH_PROTO_BIG);
+#endif
+ conn->FileSent += bytes;
+ if (send_buf) /* hash_me() *may* return NULL */
+ SH_FREE(send_buf);
+ SH_FREE(read_buf);
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NFILE, conn->peer,
+ (conn->FileName == NULL) ? _("(NULL)") : conn->FileName);
+ status_update (conn->client_entry, CLT_FAILED);
+ sh_xfer_do_free (conn);
+ }
+ }
+ return;
+}
+
+static void do_file_initial(sh_conn_t * conn)
+{
+ char * ptok;
+ char hashbuf[KEYBUF_SIZE];
+
+ /* --- get client nonce and compute hash ---
+ *
+ * K = H(NSRV, NCLT, session_key)
+ */
+ if (conn->A != NULL)
+ {
+ SH_FREE(conn->A);
+ conn->A = NULL;
+ }
+ conn->A = SH_ALLOC(3*KEY_LEN+1);
+ sl_strlcpy (conn->A, conn->K, KEY_LEN+1);
+ sl_strlcat(conn->A, conn->buf, /* truncate */
+ 2*KEY_LEN+1);
+ sl_strlcat(conn->A, conn->client_entry->session_key,
+ 3*KEY_LEN+1);
+ sl_strlcpy (conn->K, sh_tiger_hash(conn->A,TIGER_DATA,3*KEY_LEN,
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ SH_FREE(conn->A);
+ conn->A = NULL;
+
+
+ /* Warn about encryption mismatch
+ */
+#ifdef SH_ENCRYPT
+ if ((conn->client_entry->encf_flag != 0) && /* server */
+ ((conn->head[0] & SH_PROTO_ENC) == 0)) /* client */
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_MISENC,
+ _("file download"), _("version2"), _("none"));
+ }
+
+ else if ((conn->client_entry->encf_flag != 0) && /* server */
+ ((conn->head[0] & SH_MASK_ENC) != /* client */
+ conn->client_entry->encf_flag))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_MISENC,
+ _("file download"), _("version2"),
+ ((conn->head[0] & SH_PROTO_ENC) == SH_PROTO_ENC) ?
+ _("version2") : _("invalid"));
+ conn->client_entry->encf_flag = (conn->head[0] & SH_MASK_ENC);
+ }
+#else
+ if ((conn->head[0] & SH_PROTO_ENC) != 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_MISENC,
+ _("file download"), _("none"),
+ ((conn->head[0] & SH_PROTO_ENC) == SH_PROTO_ENC) ?
+ _("version2") : _("invalid"));
+ }
+#endif
+
+
+ if (conn->FileName != NULL)
+ {
+ SH_FREE(conn->FileName);
+ conn->FileName = NULL;
+ }
+
+ /* Determine what to send
+ */
+ if (0 == sl_strncmp (_("CONF"), &(conn->buf[KEY_LEN]), 4))
+ {
+ strcpy(conn->FileType, _("CONF")); /* known to fit */
+ conn->FileName = get_client_conf_file(conn->peer, &(conn->FileLength));
+ conn->FileSent = 0;
+ }
+ else if (0 == sl_strncmp (_("DATA"), &(conn->buf[KEY_LEN]), 4))
+ {
+ strcpy(conn->FileType, _("DATA")); /* known to fit */
+ conn->FileName = get_client_data_file(conn->peer, &(conn->FileLength));
+ conn->FileSent = 0;
+ }
+ else if (0 == sh_uuid_check(&(conn->buf[KEY_LEN])))
+ {
+ char * uuid = &(conn->buf[KEY_LEN]);
+ strcpy(conn->FileType, _("UUID")); /* known to fit */
+ conn->FileName = get_client_uuid_file(conn->peer, &(conn->FileLength), uuid);
+ conn->FileSent = 0;
+ }
+ else
+ {
+ ptok = sh_util_safe_name(&(conn->buf[KEY_LEN]));
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FFILE,
+ conn->peer,
+ ptok);
+ SH_FREE(ptok);
+ status_update (conn->client_entry, CLT_FAILED);
+ sh_xfer_do_free (conn);
+ }
+
+ return;
+}
+
+
+static int do_file_transfer(sh_conn_t * conn, int state)
+{
+ client_t * this_client;
+ UINT32 ticks;
+ char hashbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("do_file_transfer"));
+
+ if (state == SH_DO_READ) /* finished reading */
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<File transfer - entry.>\n")));
+
+ /* -- Client requests challenge. --
+ */
+ if (0 == check_request_nerr ((char *) &(conn->head[3]), _("HELO")))
+ {
+ int client_state;
+
+ this_client = do_check_client(conn, &client_state);
+ if (!this_client)
+ SL_RETURN(client_state, _("do_file_transfer"));
+
+ /* --- create and send a nonce ---
+ */
+
+ conn->client_entry = this_client;
+ sl_strlcpy (conn->peer, &(conn->buf[KEY_LEN]), SH_MINIBUF+1);
+
+ ticks = (UINT32) taus_get ();
+
+ if (conn->K != NULL)
+ {
+ SH_FREE(conn->K);
+ conn->K = NULL;
+ }
+ conn->K = SH_ALLOC(KEY_LEN+1);
+ sl_strlcpy (conn->K,
+ sh_tiger_hash ((char *) &ticks,
+ TIGER_DATA, sizeof(UINT32),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ TPT((0, FIL__, __LINE__, _("msg=<send nonce>\n")));
+ sh_xfer_prep_send (conn, conn->K, KEY_LEN+1, _("NSRV"),
+ SH_PROTO_BIG);
+ }
+
+ /* --- Client has send a message. Check state and message. ---
+ */
+ else if (0 == check_request_nerr((char *)&(conn->head[3]), _("NCLT")) &&
+ conn->client_entry != NULL &&
+ sl_strlen(conn->buf) > KEY_LEN &&
+ conn->K != NULL)
+ {
+
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<File transfer - NCLT (3).>\n")));
+
+ do_file_initial(conn);
+ do_file_send_data(conn);
+ }
+
+ else if (0 == check_request_nerr((char *)&(conn->head[3]),
+ _("RECV")) &&
+ conn->client_entry != NULL &&
+ conn->K != NULL &&
+ conn->FileName != NULL)
+ {
+
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<File transfer - RCVT (5+).>\n")));
+
+ do_file_send_data(conn);
+ }
+
+
+ else if (0 == check_request_nerr((char *)&(conn->head[3]),
+ _("EOTE")) &&
+ conn->client_entry != NULL)
+ {
+
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<File transfer - EOTE (7).>\n")));
+
+ if (flag_err_info == S_TRUE)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_OKFILE,
+ conn->peer);
+
+ if ((conn->client_entry->status_now != CLT_SUSPEND) &&
+ (conn->client_entry->status_now != CLT_TOOLONG))
+ { status_update (conn->client_entry, CLT_FILE); }
+ else
+ { conn->client_entry->session_key[0] = '\0'; }
+ conn->client_entry->last_connect = time (NULL);
+ sh_xfer_do_free (conn);
+ }
+
+
+ /* client does something unexpected
+ */
+ else /* ---- ??? ----- */
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FINV,
+ 1, conn->pass, conn->peer,
+ '\\', conn->head[3], '\\',conn->head[4],
+ '\\', conn->head[5], '\\',conn->head[6]);
+ status_update (conn->client_entry, CLT_FAILED);
+ sh_xfer_do_free (conn);
+ }
+ }
+
+ else if (state == SH_DO_WRITE) /* finished writing */
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<File transfer - (wait).>\n")));
+
+ /* challenge is sent, now wait for message from client
+ */
+ conn->headcount = 0;
+ conn->bytecount = 0;
+ conn->bytes_to_send = 0;
+ conn->bytes_to_get = 0;
+ if (conn->buf != NULL)
+ {
+ SH_FREE(conn->buf);
+ conn->buf = NULL;
+ }
+ conn->state = CONN_READING;
+ }
+ SL_RETURN(0, _("do_file_transfer"));
+}
+
+/* ------------------------------------------------------
+ *
+ * MESSAGE TRANSFER
+ *
+ * ------------------------------------------------------ */
+static int do_message_transfer(sh_conn_t * conn, int state)
+{
+ client_t * this_client;
+ char * cmd;
+ char hash[SH_MAXMSGLEN + KEY_LEN + KEY_LEN + 1];
+ char * buffer;
+ int clt_sev;
+ char * ptok;
+ UINT32 ticks;
+ size_t len;
+ int i;
+ char * test;
+ char sigbuf[KEYBUF_SIZE];
+
+ SL_ENTER(_("do_message_transfer"));
+
+ if (state == SH_DO_READ) /* finished reading */
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<File transfer - entry.>\n")));
+
+ /* -- Client requests challenge. --
+ */
+ if (0 == check_request_nerr ((char *) &(conn->head[3]), _("HELO")))
+ {
+ int client_state;
+
+ this_client = do_check_client(conn, &client_state);
+ if (!this_client)
+ SL_RETURN(client_state, _("do_message_transfer"));
+
+
+ /* -- create a nonce and send it --
+ */
+ conn->client_entry = this_client;
+ sl_strlcpy (conn->peer, &(conn->buf[KEY_LEN]), SH_MINIBUF+1);
+
+ ticks = (UINT32) taus_get ();
+
+ test = (char *) &ticks;
+ sh_util_cpylong (conn->challenge, test, 4);
+ conn->challenge[4] = '\0';
+ for (i = 0; i < 4; ++i)
+ if (conn->challenge[i] == '\0')
+ conn->challenge[i] = 0x01;
+
+ sh_xfer_prep_send (conn, conn->challenge, 5, _("TALK"),
+ SH_PROTO_MSG);
+ TPT(( 0, FIL__, __LINE__, _("msg=<Sent %s.>\n"),
+ hu_trans(conn->challenge)));
+ }
+
+ /* Client has send a message. Check whether we are in proper
+ * state, and verify message.
+ */
+ else if (0 ==
+ check_request_nerr((char *)&(conn->head[3]), _("MESG")) &&
+ conn->client_entry != NULL &&
+ conn->client_entry->session_key[0] != '\0' &&
+ (len = sl_strlen(conn->buf) - KEY_LEN) > 0 &&
+ sl_strlen(conn->challenge) == 4)
+ {
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<Message transfer - MESG (3).>\n")));
+
+#ifdef SH_ENCRYPT
+ if (conn->client_entry->encf_flag == 0) {
+ conn->client_entry->ency_flag = 0;
+ }
+ if ((conn->client_entry->ency_flag != 0) &&
+ ((conn->head[0] & SH_PROTO_ENC) == 0))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_MISENC,
+ _("message transfer"),
+ _("version2"),
+ _("none"));
+ }
+ else if ((conn->client_entry->ency_flag != 0) &&
+ ((conn->head[0] & SH_MASK_ENC) !=
+ conn->client_entry->ency_flag))
+ {
+ sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, 0,
+ MSG_TCP_MISENC,
+ _("message transfer"),
+ _("version2"),
+ ((conn->head[0] & SH_PROTO_ENC) == SH_PROTO_ENC) ? _("version2") : _("invalid"));
+ conn->client_entry->ency_flag =
+ (conn->head[0] & SH_MASK_ENC);
+ }
+#else
+ if ((conn->head[0] & SH_PROTO_ENC) != 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_TCP_MISENC,
+ _("message transfer"),
+ _("none"),
+ ((conn->head[0] & SH_PROTO_ENC) == SH_PROTO_ENC) ? _("version2") : _("invalid"));
+ }
+#endif
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Rcvt %s.>\n"), conn->buf));
+ /* get hash from message end, truncate message
+ */
+ sl_strlcpy(hash, &(conn->buf[len]), KEY_LEN+1);
+ conn->buf[len] = '\0';
+
+ /* verify hash
+ */
+ buffer = sh_util_strconcat(conn->buf, conn->challenge, NULL);
+ i = sl_strncmp(hash,
+ sh_util_siggen(conn->client_entry->session_key,
+ buffer,
+ sl_strlen(buffer),
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN);
+ TPT((0, FIL__, __LINE__, _("msg=<sign %s.>\n"),
+ sh_util_siggen(conn->client_entry->session_key,
+ buffer,
+ sl_strlen(buffer),
+ sigbuf, sizeof(sigbuf))));
+
+
+ if (0 != i)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ status_update (conn->client_entry, CLT_FAILED);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Msg signature mismatch"), conn->peer);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ SL_RETURN(0, _("do_message_transfer"));
+ }
+ else
+ {
+ conn->client_entry->last_connect = time (NULL);
+
+ if (NULL != sl_strstr(conn->buf, _("EXIT")))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ conn->client_entry->exit_flag = 1;
+ status_update (conn->client_entry, CLT_EXITED);
+ }
+ else if (NULL != sl_strstr(conn->buf, _("PANIC")))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ status_update (conn->client_entry, CLT_PANIC);
+ }
+ else if (NULL != sl_strstr(conn->buf, _("SUSPEND")))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ status_update (conn->client_entry, CLT_SUSPEND);
+ }
+ else if (NULL != sl_strstr(conn->buf, _("POLICY")))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ status_update (conn->client_entry, CLT_POLICY);
+ }
+ else if (NULL != sl_strstr(conn->buf,
+ _("File check completed")))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ status_update (conn->client_entry, CLT_CHECK);
+ }
+ else if (NULL != sl_strstr(conn->buf, _("START")))
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ sh_socket_add2reload (conn->client_entry->hostname);
+ if (conn->client_entry->status_now == CLT_SUSPEND) {
+ status_update (conn->client_entry, CLT_ILLEGAL);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_ILL,
+ conn->peer);
+ }
+ else
+ status_update (conn->client_entry, CLT_STARTED);
+ }
+ else
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<update status>\n")));
+ if (NULL != sl_strstr(conn->buf,
+ _("Runtime configuration reloaded")))
+ {
+ sh_socket_add2reload (conn->client_entry->hostname);
+ }
+ status_update (conn->client_entry, CLT_MSG);
+ }
+
+ TPT((0, FIL__, __LINE__, _("msg=<status updated>\n")));
+ clt_sev = atoi(conn->buf);
+ clt_class = (-1);
+ ptok = strchr(conn->buf, '?');
+ if (ptok != NULL)
+ {
+ ++ptok;
+ if (ptok != NULL && sh.flag.client_class == S_TRUE)
+ clt_class = atoi(ptok); /* is a global */
+ ptok = strchr(ptok, '?');
+ if (ptok != NULL)
+ ++ptok;
+ }
+ if (sh.flag.client_severity == S_FALSE)
+ clt_sev = (-1);
+
+ /* here we expect an xml formatted message, thus we don't
+ escape xml special chars (flag == 0) */
+ ptok =
+ sh_tools_safe_name ((ptok!=NULL) ? ptok : conn->buf, 0);
+
+ /* push client name to error routine
+ */
+#if defined(SH_WITH_SERVER) && defined(HAVE_LIBPRELUDE)
+ {
+ char peer_ip[SH_IP_BUF];
+ sh_ipvx_ntoa(peer_ip, sizeof(peer_ip), &(conn->addr_peer));
+ sh_error_set_peer_ip( peer_ip );
+ }
+#endif
+ {
+ char * pstrip = sh_strip_domain (conn->peer);
+ sh_error_set_peer(pstrip);
+ sh_error_handle(clt_sev, FIL__, __LINE__, 0, MSG_TCP_MSG,
+ pstrip,
+ ptok);
+ SH_FREE(pstrip);
+ sh_error_set_peer(NULL);
+ }
+#if defined(SH_WITH_SERVER) && defined(HAVE_LIBPRELUDE)
+ sh_error_set_peer_ip(NULL);
+#endif
+
+ TPT((0, FIL__, __LINE__, _("msg=<%s>\n"), ptok));
+ SH_FREE(ptok);
+ clt_class = (-1);
+ }
+ memset(buffer, '\0', sl_strlen(buffer));
+ SH_FREE(buffer);
+
+ /* SERVER CONF SEND
+ */
+ buffer = sh_util_strconcat(conn->buf,
+ conn->challenge,
+ NULL);
+ sl_strlcpy(hash,
+ sh_util_siggen ( conn->client_entry->session_key,
+ buffer,
+ sl_strlen(buffer),
+ sigbuf, sizeof(sigbuf)),
+ KEY_LEN+1);
+
+ /* --- SERVER CMD --- */
+ cmd = sh_socket_check (conn->peer);
+
+ if (cmd != NULL)
+ {
+ /* max cmd size is SH_MAXMSGLEN bytes
+ */
+ sl_strlcpy(&hash[KEY_LEN], cmd, SH_MAXMSGLEN);
+ sl_strlcat(&hash[KEY_LEN],
+ sh_util_siggen ( conn->client_entry->session_key,
+ &hash[KEY_LEN],
+ sl_strlen(&hash[KEY_LEN]),
+ sigbuf, sizeof(sigbuf)),
+ SH_MAXMSGLEN+KEY_LEN+1);
+
+ TPT((0, FIL__, __LINE__, _("CONF SEND <0> <%s>\n"),
+ &hash[KEY_LEN]));
+
+ } else {
+
+ TPT((0, FIL__, __LINE__, _("CONF SEND <0> <[NULL]>\n")));
+
+ }
+ /* --- SERVER CMD END --- */
+
+ TPT((0, FIL__, __LINE__, _("msg=<sign %s.>\n"),
+ sh_util_siggen(conn->client_entry->session_key,
+ buffer,
+ sl_strlen(buffer),
+ sigbuf, sizeof(sigbuf))));
+
+#ifdef SH_ENCRYPT
+ sh_xfer_send_crypt (conn, hash,
+ sl_strlen(hash) /* KEY_LEN */,
+ _("CONF"),
+ SH_PROTO_MSG|SH_PROTO_END|conn->client_entry->ency_flag);
+#else
+ sh_xfer_send_crypt (conn, hash,
+ sl_strlen(hash) /* KEY_LEN */,
+ _("CONF"),
+ SH_PROTO_MSG|SH_PROTO_END);
+#endif
+
+ memset(buffer, '\0', sl_strlen(buffer));
+ SH_FREE(buffer);
+
+ /* sh_xfer_do_free (conn); */
+ }
+
+ /* client does something unexpected
+ */
+ else /* ---- ??? ----- */
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FINV,
+ 2, conn->pass, conn->peer,
+ '\\', conn->head[3], '\\',conn->head[4],
+ '\\', conn->head[5], '\\',conn->head[6]);
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ }
+ }
+
+ else if (state == SH_DO_WRITE) /* finished writing */
+ {
+ if (0 != (conn->head[0] & SH_PROTO_END))
+ {
+ if (flag_err_debug == S_TRUE)
+ {
+ char * pstrip = sh_strip_domain (conn->peer);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_OKMSG,
+ pstrip);
+ SH_FREE(pstrip);
+ }
+ sh_xfer_do_free (conn);
+ SL_RETURN(0, _("do_message_transfer"));
+ }
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<Msg transfer - (wait).>\n")));
+
+ /* challenge is sent, now wait for message from client
+ */
+ conn->headcount = 0;
+ conn->bytecount = 0;
+ conn->bytes_to_send = 0;
+ conn->bytes_to_get = 0;
+ if (conn->buf != NULL)
+ {
+ SH_FREE(conn->buf);
+ conn->buf = NULL;
+ }
+ conn->state = CONN_READING;
+ }
+ TPT((0, FIL__, __LINE__, _("msg=<return>\n") ));
+ SL_RETURN(0, _("do_message_transfer"));
+}
+
+/* ------------------------------------------------------
+ *
+ * AUTHENTICATION
+ *
+ * ------------------------------------------------------ */
+
+static void check_probe(sh_conn_t * conn)
+{
+ if (conn && conn->client_entry)
+ {
+ /* If client has sent probe, change ivst_flag and clear probe in head[0].
+ */
+ conn->head[0] = sh_tools_probe_store(conn->head[0],
+ &(conn->client_entry->ivst_flag));
+ }
+}
+
+client_t * do_auth_start(sh_conn_t * conn)
+{
+ client_t * this_client;
+
+ TPT((0, FIL__, __LINE__,
+ _("msg=<Authentication - SALT (1).>\n")));
+
+ if (conn->buf == NULL || sl_strlen(conn->buf) == 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NOCLT);
+ sh_xfer_do_free (conn);
+ return NULL;
+ }
+
+ /* search the register
+ */
+
+ this_client = search_register (conn, 0);
+ if (NULL == this_client)
+ return NULL;
+
+ conn->client_entry = this_client;
+ sl_strlcpy (conn->peer, conn->buf, SH_MINIBUF+1);
+
+ if (0 != check_request_s((char *)&(conn->head[3]),
+ _("SALT"),conn->peer))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("No salt requested"), conn->peer);
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ return NULL;
+ }
+
+ check_probe(conn);
+ return this_client;
+}
+
+#if !defined(USE_SRP_PROTOCOL)
+
+int do_auth(sh_conn_t * conn)
+{
+ client_t * this_client;
+ UINT32 ticks;
+ char u[5] = "OOOO";
+#ifdef SH_ENCRYPT
+ int err_num;
+ char expbuf[SH_ERRBUF_SIZE];
+#endif
+ char hash[SH_MAXMSGLEN + KEY_LEN + KEY_LEN + 1];
+ char hashbuf[KEYBUF_SIZE];
+
+ /* first pass -- client request salt
+ */
+ if (conn->pass == 1)
+ {
+ this_client = do_auth_start(conn);
+
+ if (!this_client)
+ return -1;
+
+ /* -- create server nounce v --
+ */
+ ticks = (UINT32) taus_get ();
+
+ if (conn->A != NULL)
+ {
+ SH_FREE(conn->A);
+ conn->A = NULL;
+ }
+ conn->A = SH_ALLOC(KEY_LEN+1);
+
+ sl_strlcpy(conn->A,
+ sh_tiger_hash((char *) &ticks,
+ TIGER_DATA, sizeof(UINT32),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ u[0] = 'I'; u[1] = 'N'; u[2] = 'I'; u[3] = 'T'; u[4] = '\0';
+
+ if (conn->M1 != NULL)
+ {
+ SH_FREE(conn->M1);
+ conn->M1 = NULL;
+ }
+ conn->M1 = SH_ALLOC(2*KEY_LEN+1);
+
+ /* compute hash key H(v(server), P)v(server)
+ */
+ sh_passwd (conn->A, conn->client_entry->verifier,
+ NULL, conn->M1);
+
+ sl_strlcat(conn->M1, conn->A, 2*KEY_LEN+1);
+
+
+ /* --- send H(v(server), P)v(server) ----
+ */
+ sh_xfer_prep_send (conn,
+ conn->M1,
+ sl_strlen(conn->M1),
+ u,
+ (conn->head[0]|SH_PROTO_SRP));
+
+ SH_FREE(conn->M1);
+ conn->M1 = NULL;
+ }
+
+ /* client -- third pass
+ * Message is H(H(u,v),P)u
+ *
+ * A := v, verifier := H(password),
+ */
+ else if (conn->pass == 3 &&
+ conn->client_entry != NULL)
+ {
+
+ TPT((0, FIL__, __LINE__,
+ _("msg=<Authentication - PASS (3).>\n")));
+
+ if (0 != check_request_s((char *) &(conn->head[3]), _("PASS"),
+ conn->peer) ||
+ sl_strlen(conn->buf) <= KEY_LEN ||
+ conn->A == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Invalid client request"), conn->peer);
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ check_probe(conn);
+
+ /* store random nonce u from client
+ */
+ if (conn->K != NULL)
+ {
+ SH_FREE(conn->K);
+ conn->K = NULL;
+ }
+ conn->K = SH_ALLOC(KEY_LEN+1);
+ sl_strlcpy(conn->K, &(conn->buf[KEY_LEN]), KEY_LEN+1);
+
+ /* verify random nonce u from client
+ */
+ if (conn->M1 != NULL)
+ {
+ SH_FREE(conn->M1);
+ conn->M1 = NULL;
+ }
+ conn->M1 = sh_util_strconcat(conn->K, conn->A, NULL);
+
+ TPT((0, FIL__, __LINE__, _("msg=<c/r: K = %s>\n"), conn->K));
+ TPT((0, FIL__, __LINE__, _("msg=<c/r: A = %s>\n"), conn->A));
+ TPT((0, FIL__, __LINE__, _("msg=<c/r: M = %s>\n"), conn->M1));
+
+ sl_strlcpy(hash, sh_tiger_hash (conn->M1,
+ TIGER_DATA,
+ sl_strlen(conn->M1),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+ sh_passwd (hash, conn->client_entry->verifier, NULL, conn->M1);
+
+ TPT((0, FIL__, __LINE__, _("msg=<c/r: H = %s>\n"), hash));
+ TPT((0, FIL__, __LINE__, _("msg=<c/r: P = %s>\n"), conn->M1));
+
+ if ( 0 != sl_strncmp(conn->M1, conn->buf, KEY_LEN))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Session key mismatch"), conn->peer);
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ /* ---- compute hash key H(v, P, u) ----
+ */
+ sh_passwd (conn->A, conn->client_entry->verifier, conn->K,
+ conn->M1);
+
+ sl_strlcpy(conn->client_entry->session_key,
+ conn->M1, KEY_LEN+1);
+ TPT((0, FIL__, __LINE__, _("msg=<c/r: Key = %s>\n"),
+ conn->client_entry->session_key));
+
+#ifdef SH_ENCRYPT
+ err_num = rijndael_makeKey(&(conn->client_entry->keyInstE),
+ DIR_ENCRYPT, 192,
+ conn->client_entry->session_key);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("check_protocol: makeKey"));
+ err_num = rijndael_makeKey(&(conn->client_entry->keyInstD),
+ DIR_DECRYPT, 192,
+ conn->client_entry->session_key);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("check_protocol: makeKey"));
+#endif
+
+ if (conn->K != NULL) SH_FREE (conn->K);
+ conn->K = NULL;
+ if (conn->A != NULL) SH_FREE (conn->A);
+ conn->A = NULL;
+ if (conn->M1 != NULL) SH_FREE (conn->M1);
+ conn->M1 = NULL;
+
+ /* if (conn->client_entry->status_now == CLT_STARTED */
+ if (((conn->client_entry->status_now != CLT_INACTIVE) &&
+ (conn->client_entry->status_now != CLT_EXITED) &&
+ (conn->client_entry->status_now != CLT_SUSPEND))
+ && conn->client_entry->session_key_timer > (time_t) 1)
+ {
+ status_update (conn->client_entry, CLT_ILLEGAL);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_ILL,
+ conn->peer);
+ }
+ else if (conn->client_entry->session_key_timer == (time_t) 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NEW,
+ conn->peer);
+ if (conn->client_entry->status_now != CLT_SUSPEND)
+ status_update (conn->client_entry, CLT_STARTED);
+ }
+
+ conn->client_entry->session_key_timer = time (NULL);
+ conn->client_entry->last_connect = time (NULL);
+
+ /* put in read state
+ */
+ sh_xfer_prep_send (conn,
+ _("AUTH"),
+ 5,
+ _("AUTH"),
+ (conn->head[0]|SH_PROTO_SRP));
+
+ }
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FINV,
+ 3, conn->pass, conn->peer,
+ '\\', conn->head[3], '\\', conn->head[4],
+ '\\', conn->head[5], '\\', conn->head[6]);
+ sh_xfer_do_free (conn);
+ }
+ return 0;
+}
+
+#else
+
+static void noise()
+{
+ UINT32 n = taus_get();
+ retry_msleep(0, (n & 0x0000007F));
+ return;
+}
+
+/* use SRP */
+
+int do_auth(sh_conn_t * conn)
+{
+ client_t * this_client;
+ UINT32 ticks;
+ char u[5] = "OOOO";
+#ifdef SH_ENCRYPT
+ int err_num;
+ char expbuf[SH_ERRBUF_SIZE];
+#endif
+ size_t len;
+ char * test;
+ char * foo_B;
+ char * foo_Ss;
+ char hashbuf[KEYBUF_SIZE];
+
+ /* use SRP
+ */
+ if (conn->pass == 1)
+ {
+ this_client = do_auth_start(conn);
+ if (!this_client)
+ return -1;
+
+ u[0] = 'I'; u[1] = 'N'; u[2] = 'I'; u[3] = 'T'; u[4] = '\0';
+ sh_xfer_prep_send (conn,
+ conn->client_entry->salt,
+ sl_strlen(conn->client_entry->salt),
+ u,
+ (conn->head[0]|SH_PROTO_SRP));
+ }
+
+ /* client has sent A -- third pass
+ */
+ else if (conn->pass == 3 &&
+ conn->client_entry != NULL)
+ {
+
+ TPT((0, FIL__, __LINE__,
+ _("msg=<Authentication - PC01 (3).>\n")));
+
+ if (0 != check_request_s((char *)&(conn->head[3]),_("PC01"),conn->peer)||
+ conn->buf == NULL
+ )
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Invalid client request"), conn->peer);
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ check_probe(conn); noise();
+
+ if (0 != sh_srp_init())
+ {
+ status_update (conn->client_entry, CLT_FAILED);
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
+ MSG_TCP_EBGN);
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+
+ /* check A, only send B if correct
+ */
+ if ( sl_strlen(conn->buf) < SH_BUFSIZE &&
+ 0 == sh_srp_check_zero (conn->buf) )
+ {
+ len = sl_strlen(conn->buf)+1;
+
+ if (conn->A != NULL)
+ {
+ SH_FREE(conn->A);
+ conn->A = NULL;
+ }
+ conn->A = SH_ALLOC(len);
+ sl_strlcpy (conn->A, conn->buf, len);
+
+ /*
+ * compute B
+ */
+ if (0 != sh_srp_make_a ()) /* b random number */
+ {
+ status_update (conn->client_entry, CLT_FAILED);
+
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
+ MSG_TCP_EBGN);
+ sh_srp_exit();
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ foo_B = sh_srp_B /* B = v + g^b */
+ (conn->client_entry->verifier);
+
+ if (foo_B == NULL)
+ {
+ status_update (conn->client_entry, CLT_FAILED);
+
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
+ MSG_TCP_EBGN);
+ sh_srp_exit();
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ TPT((0, FIL__, __LINE__, _("msg=<srp: A = %s>\n"), conn->A));
+ TPT((0, FIL__, __LINE__, _("msg=<srp: B = %s>\n"), foo_B));
+
+ /*
+ * create nonce u
+ */
+ ticks = (UINT32) taus_get ();
+
+ test = (char *) &ticks;
+ sh_util_cpylong (u, test, 4); /* u nounce */
+ u[4] = '\0';
+ sl_strlcpy(conn->challenge,
+ sh_tiger_hash(u, TIGER_DATA, 4, hashbuf, sizeof(hashbuf)),
+ SH_CHALLENGE_SIZE);
+
+ TPT((0, FIL__, __LINE__, _("msg=<srp: u = %03o-%03o-%03o-%03o>\n"), u[0], u[1], u[2], u[3]));
+ TPT((0, FIL__, __LINE__, _("msg=<srp: U = %s>\n"),
+ conn->challenge));
+
+ /*
+ * compute the session key K and M1 = Hash(A,B,K)
+ */
+ foo_Ss = sh_srp_S_s (conn->challenge,
+ conn->A,
+ conn->client_entry->verifier);
+
+ if (foo_Ss == NULL || 0 != sh_srp_check_zero (foo_Ss))
+ {
+ status_update (conn->client_entry, CLT_FAILED);
+
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
+ MSG_TCP_EBGN);
+ sh_srp_exit();
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ if (conn->K != NULL)
+ {
+ SH_FREE(conn->K);
+ conn->K = NULL;
+ }
+ conn->K = SH_ALLOC(KEY_LEN+1);
+ sl_strlcpy(conn->K,
+ sh_tiger_hash(foo_Ss, TIGER_DATA,
+ sl_strlen(foo_Ss),
+ hashbuf, sizeof(hashbuf)),
+ KEY_LEN+1);
+
+ if (conn->M1 != NULL)
+ {
+ SH_FREE(conn->M1);
+ conn->M1 = NULL;
+ }
+ conn->M1 = SH_ALLOC(KEY_LEN+1);
+ sh_srp_M (conn->A, foo_B, conn->K, conn->M1, KEY_LEN+1);
+
+ TPT((0, FIL__, __LINE__, _("msg=<srp:Ss = %s>\n"), foo_Ss));
+ TPT((0, FIL__, __LINE__, _("msg=<srp: K = %s>\n"), conn->K));
+ TPT((0, FIL__, __LINE__, _("msg=<srp:M1 = %s>\n"),conn->M1));
+
+ /*
+ * send B
+ */
+ sh_xfer_prep_send (conn,
+ foo_B,
+ sl_strlen(foo_B)+1,
+ u,
+ (conn->head[0]|SH_PROTO_SRP));
+ if (foo_Ss != NULL)
+ {
+ SH_FREE(foo_Ss);
+ foo_Ss = NULL;
+ }
+ if (foo_B != NULL)
+ {
+ SH_FREE(foo_B);
+ foo_B = NULL;
+ }
+ }
+ else
+ {
+ status_update (conn->client_entry, CLT_FAILED);
+
+ sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0,
+ MSG_TCP_EZERO);
+ sh_xfer_do_free (conn);
+ }
+
+ sh_srp_exit();
+ }
+
+ /* client has sent M1 -- fifth pass
+ */
+ else if (conn->pass == 5 &&
+ conn->client_entry != NULL)
+ {
+ TPT((0, FIL__, __LINE__,
+ _("msg=<Authentication - PC02 (5).>\n")));
+
+ /* check that the state is valid
+ */
+ if (0 != check_request_s((char *)&(conn->head[3]), _("PC02"),
+ conn->peer) ||
+ conn->A == NULL || conn->K == NULL || conn->M1 == NULL)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Invalid client request"), conn->peer);
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+ sh_xfer_do_free (conn);
+ return -1;
+ }
+
+ check_probe(conn); noise();
+
+ /* ------ verify M1 = H(A, B, K) -------
+ * ----- send M2 = H(A, M1, K) -------
+ */
+ if (conn->buf != NULL &&
+ sl_strncmp(conn->buf, conn->M1, KEY_LEN) == 0)
+ {
+ /*
+ * send M2
+ */
+ char M_buf[KEY_LEN+1];
+ sh_xfer_prep_send (conn,
+ sh_srp_M (conn->A, conn->M1, conn->K,
+ M_buf, sizeof(M_buf)),
+ KEY_LEN+1,
+ _("PARP"),
+ (conn->head[0]|SH_PROTO_SRP));
+
+ if (conn->A != NULL) SH_FREE(conn->A); conn->A = NULL;
+ if (conn->M1 != NULL) SH_FREE(conn->M1); conn->M1 = NULL;
+ sl_strlcpy(conn->client_entry->session_key,
+ conn->K, KEY_LEN+1);
+ TPT((0, FIL__, __LINE__, _("msg=<key %s>\n"),
+ conn->client_entry->session_key));
+
+#ifdef SH_ENCRYPT
+ err_num = rijndael_makeKey(&(conn->client_entry->keyInstE),
+ DIR_ENCRYPT, 192,
+ conn->client_entry->session_key);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("sh_xfer_prep_send_int: makeKey"));
+ err_num = rijndael_makeKey(&(conn->client_entry->keyInstD),
+ DIR_DECRYPT, 192,
+ conn->client_entry->session_key);
+ if (err_num < 0)
+ sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
+ errorExplain(err_num, expbuf, sizeof(expbuf)),
+ _("sh_xfer_prep_send_int: makeKey"));
+#endif
+
+ if (conn->K != NULL) SH_FREE(conn->K); conn->K = NULL;
+
+ conn->client_entry->last_connect = time (NULL);
+
+ if (((conn->client_entry->status_now != CLT_INACTIVE) &&
+ (conn->client_entry->status_now != CLT_EXITED) &&
+ (conn->client_entry->status_now != CLT_SUSPEND))
+ && conn->client_entry->session_key_timer > (time_t) 1)
+ {
+ status_update (conn->client_entry, CLT_ILLEGAL);
+
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_TCP_ILL,
+ conn->peer);
+ }
+ else if (conn->client_entry->session_key_timer == (time_t) 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0,
+ MSG_TCP_NEW,
+ conn->peer);
+ if (conn->client_entry->status_now != CLT_SUSPEND)
+ status_update (conn->client_entry, CLT_STARTED);
+ }
+ conn->client_entry->session_key_timer = time (NULL);
+
+ }
+ else
+ {
+ status_update (conn->client_entry, CLT_FAILED);
+ conn->client_entry->session_key_timer =
+ time(NULL) - (2*TIMEOUT_KEY);
+
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN,
+ _("Session key mismatch"), conn->peer);
+ sh_xfer_do_free (conn);
+ }
+ }
+
+ else
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FINV,
+ 4, conn->pass, conn->peer,
+ '\\', conn->head[3], '\\', conn->head[4],
+ '\\', conn->head[5], '\\', conn->head[6]);
+ sh_xfer_do_free (conn);
+ }
+ return 0;
+}
+#endif
+
+/************************************************************************
+ *
+ * Here we check the message received, and decide on the answer to send
+ * (if any). The connection is in CONN_PAUSED state, thus we must:
+ * (i) define the proper reaction
+ * (ii) reset to CONN_READING or CONN_WRITING or CONN_FREE
+ * (iii) eventually reset the connection entry
+ *
+ *************************************************************************/
+static
+void check_protocol(sh_conn_t * conn, int state)
+{
+ SL_ENTER(_("check_protocol"));
+
+ /* seed / re-seed the PRNG if required
+ */
+ (void) taus_seed();
+
+ /* protocols:
+ * -- (iii) file transfer
+ * -- (ii) authenticated message transfer
+ * -- (i) SRP key exchange
+ */
+
+ /* --------- FILE TRANSFER -----------
+ */
+ if ( (conn->head[0] & SH_PROTO_SRP) == 0 &&
+ (conn->head[0] & SH_PROTO_BIG) != 0 /* is set */ )
+ {
+ /* nonzero means re-authentication is required
+ */
+ if (0 == do_file_transfer(conn, state))
+ SL_RET0(_("check_protocol"));
+ }
+ /* --------- END FILE TRANSFER ----------- */
+
+
+ /* --------- message exchange -----------
+ */
+ else if ((conn->head[0] & SH_PROTO_SRP) == 0 &&
+ (conn->head[0] & SH_PROTO_MSG) != 0 /* is set */ )
+ {
+ /* nonzero means re-authentication is required
+ */
+ if (0 == do_message_transfer(conn, state))
+ SL_RET0(_("check_protocol"));
+ }
+ /* --------- END MESSAGE TRANSFER ------ */
+
+ /* --------- authentication -----------
+ */
+ if ( (conn->head[0] & SH_PROTO_SRP) != 0 /* is set */ )
+ {
+ if (state == SH_DO_READ) /* finished reading */
+ {
+ do_auth(conn);
+ }
+
+ else if (state == SH_DO_WRITE) /* finished writing */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Authentication -- (wait).>\n")));
+
+ conn->headcount = 0;
+ conn->bytecount = 0;
+ conn->bytes_to_send = 0;
+ conn->bytes_to_get = 0;
+ if (conn->buf != NULL)
+ {
+ SH_FREE(conn->buf);
+ conn->buf = NULL;
+ }
+ conn->state = CONN_READING;
+ }
+ }
+ SL_RET0(_("check_protocol"));
+}
+
+
+/***********************************************************
+ *
+ * SERVER RECEIVE FUNCTION
+ *
+ ***********************************************************
+ */
+int sh_xfer_do_read (sh_conn_t * conn)
+{
+ unsigned long byteread; /* bytes read */
+
+ SL_ENTER(_("sh_xfer_do_read"));
+
+ if (conn->state == CONN_SENDING)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_SYNC,
+ conn->peer);
+ SL_RETURN( (-1), _("sh_xfer_do_read"));
+ }
+
+ if (conn->headcount < SH_HEADER_SIZE)
+ {
+ conn->bytes_to_get = SH_HEADER_SIZE - conn->headcount;
+ byteread = read (conn->fd, &(conn->head[conn->headcount]),
+ conn->bytes_to_get);
+ if (byteread > 0 || errno == EINTR)
+ {
+ if (byteread > 0)
+ conn->headcount += byteread;
+ if (conn->headcount == SH_HEADER_SIZE)
+ {
+ conn->bytes_to_get = (256 * (unsigned int)conn->head[1] +
+ (unsigned int)conn->head[2]);
+ SH_SHOWPROT(conn->head, '<');
+ conn->bytecount = 0;
+ }
+ }
+ else
+ goto conn_reset;
+ SL_RETURN( (0), _("sh_xfer_do_read"));
+ }
+
+ /* limit message size
+ */
+ conn->bytes_to_get = (conn->bytes_to_get > TRANS_BYTES) ?
+ TRANS_BYTES : conn->bytes_to_get;
+
+ if (conn->headcount == SH_HEADER_SIZE && conn->bytes_to_get > 0)
+ {
+ if ( conn->bytecount == 0)
+ {
+ if (conn->buf != NULL)
+ SH_FREE (conn->buf);
+ conn->buf = SH_ALLOC(conn->bytes_to_get + 1); /* <= TRANS_BYTES+1 */
+ }
+
+ byteread = read (conn->fd, &(conn->buf[conn->bytecount]),
+ conn->bytes_to_get - conn->bytecount);
+ if (byteread > 0 || errno == EINTR)
+ {
+ if (byteread > 0)
+ conn->bytecount += byteread;
+ if (conn->bytecount == conn->bytes_to_get)
+ {
+ ++conn->pass;
+ /* always terminate with NULL - we might use sl_strcmp() */
+ conn->buf[conn->bytecount] = '\0';
+ conn->state = CONN_PAUSE;
+
+#ifdef SH_ENCRYPT
+ if ((conn->head[0] & SH_PROTO_ENC) != 0)
+ {
+ conn->buf = sh_tools_revertPack (conn->head,
+ conn->client_entry->ivst_flag,
+ conn->buf,
+ &(conn->client_entry->keyInstD),
+ conn->bytecount);
+ }
+#endif
+ /* ------ HERE CALL check_protocol(conn) ------- */
+ check_protocol(conn, SH_DO_READ);
+ }
+ }
+ else
+ goto conn_reset;
+ }
+
+ else if (conn->headcount == SH_HEADER_SIZE && conn->bytes_to_get == 0)
+ {
+ if (conn->buf != NULL)
+ SH_FREE (conn->buf);
+ conn->buf = NULL;
+ conn->bytecount = 0;
+ ++conn->pass;
+ conn->state = CONN_PAUSE;
+ /* ------ HERE CALL check_protocol(conn) ------- */
+ check_protocol(conn, SH_DO_READ);
+ }
+
+ SL_RETURN( (0), _("sh_xfer_do_read"));
+
+ conn_reset:
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_RESET,
+ conn->peer);
+ sh_xfer_do_free ( conn );
+ SL_RETURN( (-1), _("sh_xfer_do_read"));
+}
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+/* send to the client
+ */
+int sh_xfer_do_write (sh_conn_t * conn)
+{
+ int flags;
+ long arg = 0;
+ long bytesent; /* bytes read */
+
+ SL_ENTER(_("sh_xfer_do_write"));
+
+ /* ---- consistency check ------
+ */
+ if (conn->state == CONN_READING)
+ {
+ sh_error_handle( (-1), FIL__, __LINE__, 0, MSG_TCP_SYNC,
+ conn->peer);
+ SL_RETURN( (-1), _("sh_xfer_do_write"));
+ }
+
+ flags = retry_fcntl (FIL__, __LINE__, conn->fd, F_GETFL, arg);
+ retry_fcntl (FIL__, __LINE__, conn->fd, F_SETFL, flags|O_NONBLOCK);
+
+ /* ---- send the header ------
+ */
+ if (conn->headcount < SH_HEADER_SIZE)
+ {
+ conn->bytes_to_send = SH_HEADER_SIZE - conn->headcount;
+ bytesent = write (conn->fd, &(conn->head[conn->headcount]),
+ conn->bytes_to_send);
+ if (bytesent >= 0 || errno == EINTR || errno == EAGAIN)
+ {
+ if (bytesent > 0)
+ conn->headcount += bytesent;
+ if (conn->headcount == SH_HEADER_SIZE)
+ conn->bytes_to_send =
+ (256 * (int)conn->head[1] + (int)conn->head[2]);
+ }
+ else
+ goto conn_reset_w;
+
+ if (conn->fd >= 0)
+ retry_fcntl (FIL__, __LINE__, conn->fd, F_SETFL, flags);
+ SL_RETURN( (0), _("sh_xfer_do_write"));
+ }
+
+ /* ---- send the body ------
+ */
+
+ if (conn->headcount == SH_HEADER_SIZE && conn->bytes_to_send > 0 &&
+ conn->buf != NULL)
+ {
+ bytesent = write (conn->fd, &(conn->buf[conn->bytecount]),
+ conn->bytes_to_send - conn->bytecount);
+ if (bytesent >= 0 || errno == EINTR || errno == EAGAIN)
+ {
+ if (bytesent > 0)
+ conn->bytecount += bytesent;
+ if (conn->bytecount == conn->bytes_to_send)
+ {
+ ++conn->pass;
+ conn->state = CONN_PAUSE;
+ /* ------ HERE CALL check_protocol(conn) ------- */
+ check_protocol(conn, SH_DO_WRITE);
+ }
+ }
+ else
+ goto conn_reset_w;
+ }
+
+ else if (conn->headcount == SH_HEADER_SIZE && conn->bytes_to_send == 0)
+ {
+ ++conn->pass;
+ conn->state = CONN_PAUSE;
+ /* ------ HERE CALL check_protocol(conn) ------- */
+ check_protocol(conn, SH_DO_WRITE);
+ }
+
+ if (conn->fd >= 0)
+ retry_fcntl (FIL__, __LINE__, conn->fd, F_SETFL, flags);
+ SL_RETURN( (0), _("sh_xfer_do_write"));
+
+ conn_reset_w:
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_RESET,
+ conn->peer);
+ sh_xfer_do_free ( conn );
+ SL_RETURN( (-1), _("sh_xfer_do_write"));
+}
+
+/* accept a connection from a client
+ */
+#include <syslog.h>
+#ifdef SH_USE_LIBWRAP
+#include <tcpd.h>
+
+#ifndef ALLOW_SEVERITY
+#define ALLOW_SEVERITY LOG_INFO
+#define DENY_SEVERITY LOG_WARNING
+#endif
+
+int allow_severity;
+int deny_severity;
+#endif
+
+#ifdef SH_USE_LIBWRAP
+static int check_libwrap(int rc, sh_conn_t * newconn)
+{
+ struct request_info request;
+ char errbuf[128];
+ char daemon[128];
+
+ sl_strlcpy(daemon, SH_INSTALL_NAME, sizeof(daemon));
+ request_init(&request, RQ_DAEMON, daemon, RQ_FILE, rc, 0);
+ fromhost(&request);
+ if (!hosts_access(&request))
+ {
+ sl_strlcpy(errbuf, _("Refused connection from "), sizeof(errbuf));
+ sl_strlcat(errbuf, eval_client(&request), sizeof(errbuf));
+
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ errbuf, _("libwrap"));
+ newconn->fd = -1;
+ newconn->state = CONN_FREE;
+ sl_close_fd(FIL__, __LINE__, rc);
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+int sh_xfer_accept (int sock, sh_conn_t * newconn)
+{
+ int errflag;
+ int rc;
+ struct sh_sockaddr addr;
+
+ /* handle AIX (size_t addrlen) in wrapper
+ */
+ int addrlen = sizeof(addr);
+
+ SL_ENTER(_("sh_xfer_accept"));
+
+ rc = retry_accept(FIL__, __LINE__, sock, &addr, &addrlen);
+
+ if (rc < 0)
+ {
+ char err_buf[SH_ERRBUF_SIZE];
+ errflag = errno;
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ sh_error_message(errflag,err_buf, sizeof(err_buf)), _("accept"));
+ newconn->fd = -1;
+ newconn->state = CONN_FREE;
+ SL_RETURN( (-1), _("sh_xfer_accept"));
+ }
+
+ if (addrlen == 0)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
+ _("Connecting entity unknown"), _("accept"));
+ newconn->fd = -1;
+ newconn->state = CONN_FREE;
+ sl_close_fd(FIL__, __LINE__, rc);
+ SL_RETURN( (-1), _("sh_xfer_accept"));
+ }
+
+#ifdef SH_USE_LIBWRAP
+ if (check_libwrap(rc, newconn) < 0)
+ SL_RETURN( (-1), _("sh_xfer_accept"));
+#endif
+
+ memcpy (&(newconn->addr_peer), &addr, sizeof(struct sh_sockaddr));
+
+ /* prepare for usage of connection
+ */
+ (void) retry_fcntl( FIL__, __LINE__, rc, F_SETFD, 1 );
+ newconn->fd = rc;
+ newconn->state = CONN_READING;
+ newconn->timer = (unsigned long) time (NULL);
+
+ if (flag_err_info == S_TRUE)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_CNEW, newconn->fd);
+
+ SL_RETURN( (0), _("sh_xfer_accept"));
+}
+
+extern char sh_sig_msg[64]; /* defined in sh_unix.c */
+
+/* ------------ port and interface -------
+ */
+static unsigned int server_port = SH_DEFAULT_PORT;
+
+int sh_xfer_set_port (const char * str)
+{
+ int retval = 0;
+ unsigned long i;
+ char * endptr;
+
+ SL_ENTER(_("sh_xfer_set_port"));
+ i = strtoul (str, &endptr, 0);
+ if (endptr == str) {
+ retval = -1;
+ } else if (i > 65535) {
+ retval = -1;
+ } else {
+ server_port = i;
+ }
+ SL_RETURN( (retval), _("sh_xfer_set_port"));
+}
+
+static struct sh_sockaddr server_interface;
+static int use_server_interface = 0;
+
+int sh_xfer_set_interface (const char * str)
+{
+ if (0 == strcmp(str, _("INADDR_ANY")))
+ {
+ use_server_interface = 0;
+ return 0;
+ }
+
+ if (0 == sh_ipvx_aton(str, &server_interface))
+ {
+ use_server_interface = 0;
+ return -1;
+ }
+
+ use_server_interface = 1;
+ return 0;
+}
+
+/* ------------ print error --------------
+ */
+struct sock_err_st {
+ char msg[128];
+ int errnum;
+ int port;
+ int line;
+ int euid;
+};
+
+static struct sock_err_st sock_err[2];
+
+void sh_xfer_printerr(char * str, int errnum, unsigned int port, int line)
+{
+ int slot = 0;
+
+ if (port != server_port)
+ slot = 1;
+ if (str == NULL)
+ sock_err[slot].msg[0] = '\0';
+ else
+ sl_strlcpy(sock_err[slot].msg, str, 128);
+ sock_err[slot].errnum = errnum;
+ sock_err[slot].port = port;
+ sock_err[slot].line = line;
+ sock_err[slot].euid = (int) geteuid();
+}
+
+int sh_xfer_printerr_final(int slot)
+{
+ char errbuf[SH_ERRBUF_SIZE];
+
+ SL_ENTER(_("sh_xfer_printerr_final"));
+ if (sock_err[slot].msg[0] != '\0')
+ {
+ dlog(1, FIL__, __LINE__,
+ _("Could not set up the listening socket for the server because of the\nfollowing error: %s\nPossible reasons include:\n - insufficient privilege for UID %d, or\n - the port %d is already used by another program.\n"),
+ sh_error_message(sock_err[slot].errnum, errbuf, sizeof(errbuf)),
+ sock_err[slot].euid,
+ sock_err[slot].port);
+ sh_error_handle((-1), FIL__, sock_err[slot].line,
+ sock_err[slot].errnum, MSG_EXIT_ABORTS,
+ sh_error_message(sock_err[slot].errnum, errbuf, sizeof(errbuf)),
+ sh.prg_name,
+ sock_err[slot].msg);
+ SL_RETURN((-1), _("sh_xfer_printerr_final"));
+ }
+ SL_RETURN(0, _("sh_xfer_printerr_final"));
+}
+
+#define TIME_OUT_DEF 900
+static unsigned long time_out_val = TIME_OUT_DEF;
+
+int sh_xfer_set_timeout (const char * c)
+{
+ long val;
+
+ SL_ENTER(_("sh_xfer_set_time_out"));
+
+ val = strtol (c, (char **)NULL, 10);
+
+ if (val == 0)
+ {
+ val = TIME_OUT_DEF;
+ }
+ else if (val < 0)
+ {
+ time_out_val = TIME_OUT_DEF;
+ SL_RETURN( (-1), _("sh_xfer_set_time_out"));
+ }
+
+ time_out_val = (unsigned long) val;
+ SL_RETURN( (0), _("sh_xfer_set_time_out"));
+}
+
+
+static sh_conn_t * conns = NULL;
+static int maxconn = 0; /* maximum number of simultaneous connections */
+
+
+#ifdef INET_SYSLOG
+#define INET_SUSPEND_TIME 180 /* equal to 3 minutes */
+#define SH_MINSOCK_DEFAULT 3
+int sh_xfer_syslog_sock[SH_SOCKMAX] = { -1 };
+extern int sh_xfer_recv_syslog_socket (int fd);
+int sh_xfer_syslog_sock_n = 0;
+#else
+#define SH_MINSOCK_DEFAULT 2
+#endif
+
+int SH_MINSOCK = SH_MINSOCK_DEFAULT;
+
+extern int pf_unix_fd;
+
+/* the tcp socket, and the function to establish it
+ */
+static int sh_tcp_sock[SH_SOCKMAX] = { -1 };
+static int sh_tcp_sock_n = 0;
+
+static int do_socket(int domain, int type, int protocol,
+ struct sockaddr * sa, int salen)
+{
+ int sock = -1;
+ int errnum = 0;
+ int flag = 1; /* non-zero to enable an option */
+
+ /* create the socket, bind() it and listen()
+ */
+ if ((sock = socket(domain, type, protocol)) < 0 )
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("socket"), errnum, server_port, __LINE__);
+ return -1;
+ }
+ (void) retry_fcntl( FIL__, __LINE__, sock, F_SETFD, 1 );
+
+ if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &flag, sizeof(flag)) < 0 )
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("setsockopt"), errnum, server_port, __LINE__);
+ sl_close_fd (FIL__, __LINE__, sock);
+ return -1;
+ }
+
+ if ( bind(sock, (struct sockaddr *) sa, salen) < 0)
+ {
+ if (errno != EADDRINUSE)
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("bind"), errnum, server_port, __LINE__);
+ sl_close_fd (FIL__, __LINE__, sock);
+ return -1;
+ }
+ else
+ {
+ sl_close_fd (FIL__, __LINE__, sock);
+ return -2;
+ }
+ }
+
+ if ( retry_fcntl( FIL__, __LINE__, sock, F_SETFL, O_NONBLOCK ) < 0 )
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("fcntl"), errnum, server_port, __LINE__);
+ sl_close_fd (FIL__, __LINE__, sock);
+ return -1;
+ }
+
+ if ( listen(sock, 64) < 0)
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("listen"), errnum, server_port, __LINE__);
+ sl_close_fd (FIL__, __LINE__, sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+int sh_create_tcp_socket (void)
+{
+#if defined(USE_IPVX)
+ struct addrinfo *ai;
+ struct addrinfo *p;
+ struct addrinfo hints;
+ char port[32];
+#else
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+#endif
+
+ int sock = -1;
+
+ SL_ENTER(_("sh_create_tcp_socket"));
+
+ sh_xfer_printerr (NULL, 0, server_port, __LINE__);
+
+#if defined(USE_IPVX)
+ if (use_server_interface == 0) /* INADDR_ANY, listen on all interfaces */
+ {
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = AF_UNSPEC;
+ sl_snprintf(port, sizeof(port), "%d", server_port);
+
+ if (getaddrinfo (NULL, port, &hints, &ai) != 0)
+ {
+ int errnum = errno;
+ sh_xfer_printerr (_("getaddrinfo"), errnum, server_port, __LINE__);
+ sl_close_fd (FIL__, __LINE__, sock);
+ SL_RETURN((-1), _("sl_create_tcp_socket"));
+ }
+
+ p = ai;
+
+ while (p != NULL && sh_tcp_sock_n < SH_SOCKMAX)
+ {
+ sock = do_socket(p->ai_family, p->ai_socktype, p->ai_protocol,
+ p->ai_addr, p->ai_addrlen);
+
+ if (sock >= 0) {
+ if (sh_tcp_sock_n < SH_SOCKMAX) {
+ sh_tcp_sock[sh_tcp_sock_n] = sock;
+ ++sh_tcp_sock_n;
+ }
+ else {
+ sl_close_fd (FIL__, __LINE__, sock);
+ }
+ } else if (sock == -1) {
+ freeaddrinfo (ai);
+ goto end;
+ }
+ p = p->ai_next;
+ }
+
+ freeaddrinfo (ai);
+ }
+ else
+ {
+ sh_ipvx_set_port(&server_interface, server_port);
+
+ sock = do_socket(server_interface.ss_family, SOCK_STREAM, 0,
+ sh_ipvx_sockaddr_cast(&server_interface),
+ SH_SS_LEN(server_interface));
+
+ if (sock >= 0) {
+ sh_tcp_sock[0] = sock;
+ sh_tcp_sock_n = 1;
+ }
+ }
+#else
+ if (use_server_interface == 0)
+ addr.sin_addr.s_addr = INADDR_ANY;
+ else
+ memcpy(&addr, sh_ipvx_sockaddr_cast(&server_interface), addrlen);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(server_port);
+
+ sock = do_socket(AF_INET, SOCK_STREAM, 0, (struct sockaddr *) &addr, addrlen);
+
+ if (sock >= 0) {
+ sh_tcp_sock[0] = sock;
+ sh_tcp_sock_n = 1;
+ }
+
+#endif
+
+#if defined(USE_IPVX)
+ end:
+#endif
+ if (sh_tcp_sock_n > 1)
+ SH_MINSOCK += (sh_tcp_sock_n - 1);
+
+ SL_RETURN((sh_tcp_sock_n), _("sl_create_tcp_socket"));
+}
+
+/*****************************************
+ *
+ * This is the server main loop.
+ *
+ * The server is set up for listening, and
+ * and starts a select() loop.
+ *
+ *****************************************/
+
+void sh_xfer_start_server()
+{
+#ifdef SH_USE_XML
+ extern int sh_log_file (char * message, char * inet_peer);
+#endif
+
+ /* Use volatile to circumvent a gcc4 problem on RH/CentOS 4.8 (?) */
+ volatile int sock = -1;
+ sh_conn_t * cx;
+ fd_set readset;
+ fd_set writeset;
+ struct timeval tv;
+ int num_sel;
+ int errnum;
+ int nowconn;
+ int status;
+ int high_fd = -1;
+ register int i;
+ long dummy = 0;
+ unsigned long time_now;
+ unsigned long time_last = 0;
+ unsigned long time_out = time_out_val;
+
+ time_t told;
+ time_t tcurrent;
+
+ unsigned long tchkold;
+
+ int setsize_fd;
+
+ int sock_tcp[2];
+ int sock_unix;
+#ifdef INET_SYSLOG
+ int sock_log[2];
+#endif
+
+ SL_ENTER(_("sh_xfer_start_server"));
+
+ if ( sh_xfer_printerr_final(0) < 0)
+ {
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ sock = sh_tcp_sock[0];
+
+ /* ****************************************************************
+ *
+ * This is a non-forking server. We use select() on the listen()
+ * socket to watch for new connections. For new connections, accept()
+ * will return a new socket that is put in the read/write filesets.
+ * Data about active connections are kept in the 'conns' table.
+ *
+ ******************************************************************/
+
+ /* The table to hold info on sockets.
+ * We reserve 6 file descriptors for misc. use.
+ * The POSIX lower limit on open files seems to be eight.
+ */
+ maxconn = get_open_max() - 6;
+
+ /* ugly fix for FreeBSD compiler warning; casting FD_SETSIZE in the
+ * conditional expression does not suppress the warning... */
+ setsize_fd = (int)FD_SETSIZE;
+ maxconn = (setsize_fd < maxconn) ? setsize_fd : maxconn;
+
+ if (maxconn < 0 || !sl_ok_muls(maxconn, sizeof(sh_conn_t)))
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_START_SRV,
+ 0, sock);
+ aud_exit (FIL__, __LINE__, EXIT_FAILURE);
+ }
+ conns = SH_ALLOC (sizeof(sh_conn_t) * maxconn);
+
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_START_SRV,
+ (maxconn-1), sock);
+
+ /* timer
+ */
+ tcurrent = (unsigned long) time (NULL);
+ told = tcurrent;
+
+ tchkold = tcurrent;
+
+ for (i = SH_MINSOCK; i < maxconn; ++i)
+ {
+ conns[i].buf = NULL;
+ conns[i].K = NULL;
+ conns[i].A = NULL;
+ conns[i].M1 = NULL;
+ conns[i].FileName = NULL;
+ conns[i].fd = -1;
+ sh_xfer_do_free ( &conns[i]);
+ }
+
+ /* status init
+ */
+ server_status.conn_open = 0;
+ server_status.conn_total = 0;
+ server_status.conn_max = maxconn-1;
+ server_status.start = time (NULL);
+ server_status.last = (time_t) 0;
+
+ nowconn = 1;
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ /* conns[0] is the listen() socket. Always in read mode.
+ */
+ sock = 0;
+
+ sock_tcp[0] = 0;
+ while (sock < sh_tcp_sock_n)
+ {
+ conns[sock].fd = sh_tcp_sock[sock];
+ conns[sock].state = CONN_READING;
+ /* high_fd = (sh_tcp_sock[sock] > high_fd) ? sh_tcp_sock[sock] : high_fd; */
+ ++sock;
+ }
+ sock_tcp[1] = sock;
+
+ conns[sock].fd = pf_unix_fd;
+ conns[sock].state = CONN_READING;
+ /* high_fd = (pf_unix_fd > high_fd) ? pf_unix_fd : high_fd; */
+
+ sock_unix = sock;
+
+ ++sock;
+
+#ifdef INET_SYSLOG
+ conns[sock].fd = -1;
+
+ if ( sh_xfer_printerr_final(1) < 0)
+ {
+ SH_FREE(conns);
+ conns = NULL;
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE);
+ }
+
+ sock_log[0] = sock;
+ sock_log[1] = sock;
+
+ if (sh_xfer_syslog_sock_n > 0)
+ {
+ int s2;
+ for (s2 = 0; s2 < sh_xfer_syslog_sock_n; ++s2)
+ {
+ conns[sock].fd = sh_xfer_syslog_sock[s2];
+ conns[sock].state = CONN_READING;
+ /* high_fd = (high_fd > conns[sock].fd) ? high_fd : conns[sock].fd; */
+ ++sock;
+ }
+ sock_log[1] = sock;
+
+ }
+#endif
+
+ sh_html_write(all_clients);
+
+ /* This is the select() loop.
+ */
+ while (1 == 1)
+ {
+
+ if (sig_raised > 0)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Process a signal.>\n")))
+
+ if (sig_termfast == 1) /* SIGTERM */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ strncpy (sh_sig_msg, _("SIGTERM"), 20);
+ --sig_raised; --sig_urgent;
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ }
+
+ if (sig_config_read_again == 1)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Re-read configuration.>\n")));
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_RECONF);
+
+
+ /* -- Delete the name server cache. --
+ */
+
+ delete_cache();
+#if defined(WITH_EXTERNAL)
+ /* -- Delete list of external tasks. --
+ */
+ (void) sh_ext_cleanup();
+#endif
+#if defined(SH_WITH_MAIL)
+ sh_nmail_free();
+#endif
+ /* - mark all clients dead
+ * - read configuration file
+ * - remove clients still dead
+ */
+ sh_xfer_mark_dead ();
+
+ reset_count_dev_console();
+ reset_count_dev_time();
+ sl_trust_purge_user();
+
+ (void) sh_readconf_read ();
+
+ for (i = SH_MINSOCK; i < maxconn; ++i)
+ if (conns[i].state != CONN_FREE &&
+ conns[i].client_entry != NULL &&
+ conns[i].client_entry->dead_flag == 1)
+ sh_xfer_do_free ( &conns[i]);
+ sh_xfer_clean_tree ();
+
+ sig_config_read_again = 0;
+ --sig_raised;
+ }
+
+ if (sig_fresh_trail == 1) /* SIGIOT */
+ {
+ /* Logfile access
+ */
+#ifdef SH_USE_XML
+ sh_log_file (NULL, NULL);
+#endif
+ TPT((0, FIL__, __LINE__, _("msg=<Logfile stop/restart.>\n")));
+ sh_error_only_stderr (S_TRUE);
+ sh_unix_rm_lock_file(sh.srvlog.name);
+ retry_msleep(3, 0);
+ sh.flag.log_start = S_TRUE;
+ sh_error_only_stderr (S_FALSE);
+ sig_fresh_trail = 0;
+ --sig_raised;
+ }
+
+
+ if (sig_terminate == 1 && nowconn < 2) /* SIGQUIT */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
+ strncpy (sh_sig_msg, _("SIGQUIT"), 20);
+ --sig_raised; --sig_urgent;
+ aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
+ }
+
+
+ if (sig_debug_switch == 1) /* SIGUSR1 */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Debug switch.>\n")));
+ sh_error_dbg_switch();
+ sig_debug_switch = 0;
+ --sig_raised;
+ }
+
+ if (sig_suspend_switch > 0) /* SIGUSR2 */
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Suspend switch.>\n")));
+ if (sh_global_suspend_flag == 1) {
+ sh_global_suspend_flag = 0;
+ } else {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_SUSPEND,
+ sh.prg_name);
+ sh_global_suspend_flag = 1;
+ }
+ --sig_suspend_switch;
+ --sig_raised; --sig_urgent;
+ }
+
+ sig_raised = (sig_raised < 0) ? 0 : sig_raised;
+ sig_urgent = (sig_urgent < 0) ? 0 : sig_urgent;
+ TPT((0, FIL__, __LINE__, _("msg=<End signal processing.>\n")));
+ }
+
+ if (sh_global_suspend_flag == 1)
+ {
+ (void) retry_msleep (1, 0);
+ continue;
+ }
+
+ /* Recompute the descriptor set. select() modifies it,
+ * thus we update it using the info from the connection table.
+ * Also recompute the number of open connections.
+ */
+ FD_ZERO( &readset );
+ FD_ZERO( &writeset );
+ high_fd = conns[0].fd;
+
+ for (sock = sock_tcp[0]; sock < sock_tcp[1]; ++sock)
+ {
+ FD_SET(conns[sock].fd, &readset );
+ high_fd = (high_fd > conns[sock].fd) ? high_fd : conns[sock].fd;
+ }
+
+ if (conns[sock_unix].fd > -1)
+ {
+ FD_SET(conns[sock_unix].fd, &readset );
+ high_fd = (high_fd > conns[sock_unix].fd) ? high_fd : conns[sock_unix].fd;
+ }
+
+#ifdef INET_SYSLOG
+ for (sock = sock_log[0]; sock < sock_log[1]; ++sock)
+ {
+ if (conns[sock].fd > -1)
+ {
+ FD_SET(conns[sock].fd, &readset );
+ high_fd = (high_fd > conns[sock].fd) ? high_fd : conns[sock].fd;
+ }
+ }
+#endif
+
+ time_now = (unsigned long) time (NULL);
+ nowconn = 1;
+
+ for (i = SH_MINSOCK; i < maxconn; ++i)
+ {
+ /* eliminate timed out connections
+ */
+ if (conns[i].state != CONN_FREE)
+ {
+ if (time_now-conns[i].timer > time_out)
+ {
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_TIMOUT,
+ conns[i].peer);
+ sh_xfer_do_free ( &conns[i]);
+ }
+ else
+ ++nowconn;
+ }
+
+
+ if (conns[i].state == CONN_READING)
+ {
+ FD_SET(conns[i].fd, &readset);
+ high_fd = (high_fd < conns[i].fd ? conns[i].fd : high_fd);
+ }
+ else if (conns[i].state == CONN_SENDING)
+ {
+ FD_SET(conns[i].fd, &writeset);
+ high_fd = (high_fd < conns[i].fd ? conns[i].fd : high_fd);
+ }
+ }
+
+ /* -- Exponentially reduce timeout limit if more than 1/2 full. --
+ */
+ /* Eliminate this, will cause problems when too much clients are
+ * starting up. */
+#if 0
+ if (nowconn > (maxconn/2))
+ time_out = ( (time_out/2) > 1) ? (time_out/2) : 1;
+ else
+ time_out = time_out_val;
+#endif
+
+
+ /* -- Do the select(). --
+ */
+ num_sel = select(high_fd+1, &readset, &writeset, NULL, &tv);
+ errnum = errno;
+
+ /* reset timeout - modified by select() on some systems
+ */
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+
+ if ( (time_now - time_last) > 2L)
+ {
+ time_last = time_now;
+ if (sh_html_write(all_clients) < 0)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_HTML);
+ }
+
+
+ /* Error handling.
+ */
+ if ( num_sel < 0 ) /* some error */
+ {
+ char errbuf[SH_ERRBUF_SIZE];
+
+ if (sig_raised == 1)
+ {
+ sig_raised = 2;
+ continue;
+ }
+
+ if ( errnum == EINTR)
+ continue; /* try again */
+
+ if ( errnum == EBADF)
+ {
+ /* seek and destroy the bad fd
+ */
+ for (i = SH_MINSOCK; i < high_fd; ++i)
+ {
+ if ((conns[i].state == CONN_READING) ||
+ (conns[i].state == CONN_SENDING))
+ {
+ if (-1 == retry_fcntl(FIL__, __LINE__,
+ conns[i].fd, F_GETFL, dummy))
+ sh_xfer_do_free ( &conns[i]);
+ }
+ }
+ continue;
+ }
+
+ sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_EXIT_ABORTS,
+ sh_error_message(errnum, errbuf, sizeof(errbuf)),
+ sh.prg_name,
+ _("select"));
+ aud_exit(FIL__, __LINE__, EXIT_FAILURE );
+ }
+
+
+ /* log the timestamp
+ */
+ if ((tcurrent - told) > sh.looptime )
+ {
+ told = tcurrent;
+#ifdef MEM_DEBUG
+ sh_mem_check();
+ sh_unix_count_mlock();
+#else
+ sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_STAMP);
+#endif
+ }
+
+#if defined(SH_WITH_MAIL)
+ /*
+ * flush the mail queue
+ */
+ if (tcurrent - sh.mailTime.alarm_last > sh.mailTime.alarm_interval)
+ {
+ TPT((0, FIL__, __LINE__, _("msg=<Flush mail queue.>\n")))
+ (void) sh_nmail_flush ();
+ sh.mailTime.alarm_last = tcurrent;
+ }
+#endif
+#ifdef MEM_DEBUG
+ sh_mem_dump();
+#endif
+
+ tcurrent = (unsigned long) time (NULL);
+
+ /* check for time limit exceeded
+ */
+ if ((tcurrent - tchkold) > (unsigned int) 3 )
+ {
+ tchkold = tcurrent;
+ client_time_check(/* all_clients */);
+ /* reset cache */
+ sh_userid_destroy();
+ }
+
+ /* seed / re-seed the PRNG if required
+ */
+ (void) taus_seed();
+
+ /* select() timeout handling.
+ */
+ if ( num_sel == 0 ) /* timeout - no connection */
+ {
+ if (sh_html_write(all_clients) < 0)
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_HTML);
+ continue;
+ }
+
+ /* New connection.
+ */
+ for (sock = sock_tcp[0]; sock < sock_tcp[1]; ++sock)
+ {
+ if ( FD_ISSET(conns[sock].fd , &readset )) /* a new connection */
+ {
+ --num_sel;
+ status = 0;
+ if (nowconn < maxconn && sig_terminate == 0 && sig_termfast == 0)
+ {
+ /* Find a free slot to accept the connection
+ */
+ i = SH_MINSOCK;
+ while (i < maxconn)
+ {
+ if (conns[i].state == CONN_FREE)
+ {
+ /* Here we run the accept() and copy the peer to
+ * the free slot.
+ */
+ status = sh_xfer_accept(conns[sock].fd, &conns[i]);
+
+ if (status == 0)
+ {
+ high_fd =
+ (high_fd > conns[i].fd ? high_fd : conns[i].fd);
+ ++server_status.conn_open;
+ ++server_status.conn_total;
+ server_status.last = time (NULL);
+ }
+ break;
+ }
+ ++i;
+ }
+ }
+ /* This re-runs select to accept data on the new
+ * connection, rather than first dealing with old
+ * connections.
+ */
+ if (status == 0)
+ continue;
+ }
+ }
+
+ /* check for commands on the socket
+ */
+ if (conns[sock_unix].fd > (-1) && FD_ISSET(conns[sock_unix].fd , &readset ))
+ {
+ sh_socket_poll();
+ }
+
+#ifdef INET_SYSLOG
+ for (sock = sock_log[0]; sock < sock_log[1]; ++sock)
+ {
+ if (conns[sock].fd > (-1) && FD_ISSET(conns[sock].fd , &readset ))
+ {
+ sh_xfer_recv_syslog_socket (conns[sock].fd);
+ }
+ }
+#endif
+
+ /* Check for pending read/write on the rest of the sockets.
+ */
+ for ( i = SH_MINSOCK; num_sel > 0 && i < maxconn; ++i )
+ {
+ if (sig_termfast == 1)
+ break;
+
+ cx = &conns[i];
+ if ( cx->state == CONN_READING &&
+ FD_ISSET( cx->fd, &readset ) )
+ {
+ --num_sel;
+ sh_xfer_do_read ( cx );
+ }
+ else if ( cx->state == CONN_SENDING &&
+ FD_ISSET( cx->fd, &writeset ) )
+ {
+ --num_sel;
+ sh_xfer_do_write ( cx );
+ }
+ }
+ /* continue */
+ }
+ /* notreached */
+}
+
+void free_client_tree (void)
+{
+ SL_ENTER(_("free_client_tree"));
+ zAVLFreeTree (all_clients, free_client);
+ SL_RET0(_("free_client_tree"));
+}
+
+void sh_xfer_free_all ()
+{
+ register int i;
+
+ SL_ENTER(_("sh_xfer_free_all"));
+
+ if (conns != NULL)
+ for (i = SH_MINSOCK; i < maxconn; ++i)
+ {
+ sh_xfer_do_free ( &conns[i]);
+ }
+
+
+ free_client_tree ();
+
+ if (conns != NULL)
+ SH_FREE (conns);
+
+ SL_RET0(_("sh_xfer_free_all"));
+}
+
+
+
+/* #ifdef SH_WITH_SERVER */
+#endif
+
+
+
+
+
+
diff --git a/src/sh_xfer_syslog.c b/src/sh_xfer_syslog.c
new file mode 100644
index 0000000..ab516f5
--- /dev/null
+++ b/src/sh_xfer_syslog.c
@@ -0,0 +1,481 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 1999, 2000 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+/* Must be early on FreeBSD
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef SH_WITH_SERVER
+
+#include "samhain.h"
+#include "sh_tools.h"
+#include "sh_utils.h"
+#include "sh_ipvx.h"
+
+#undef FIL__
+#define FIL__ _("sh_xfer_syslog.c")
+
+#ifdef INET_SYSLOG
+
+extern void sh_xfer_printerr(char * str, int errnum, unsigned int port, int line);
+extern int sh_xfer_syslog_sock[SH_SOCKMAX];
+extern int sh_xfer_syslog_sock_n;
+extern int SH_MINSOCK;
+
+/* Unlike Linux / FreeBSD, most systems don't define the stuff below
+ * in syslog.h
+ */
+
+#ifndef LOG_FAC
+#define LOG_FAC(p) (((p) & LOG_FACMASK) >> 3)
+#endif
+
+#ifndef LOG_PRI
+#define LOG_PRI(p) ((p) & LOG_PRIMASK)
+#endif
+
+typedef struct sh_code {
+ char *c_name;
+ int c_val;
+} SH_CODE;
+
+SH_CODE sh_facilitynames[] =
+{
+#ifdef LOG_AUTH
+ { N_("auth"), LOG_AUTH },
+#endif
+#ifdef LOG_AUTHPRIV
+ { N_("authpriv"), LOG_AUTHPRIV },
+#endif
+#ifdef LOG_CRON
+ { N_("cron"), LOG_CRON },
+#endif
+#ifdef LOG_DAEMON
+ { N_("daemon"), LOG_DAEMON },
+#endif
+#ifdef LOG_FTP
+ { N_("ftp"), LOG_FTP },
+#endif
+#ifdef LOG_KERN
+ { N_("kern"), LOG_KERN },
+#endif
+#ifdef LOG_LPR
+ { N_("lpr"), LOG_LPR },
+#endif
+#ifdef LOG_MAIL
+ { N_("mail"), LOG_MAIL },
+#endif
+#ifdef INTERNAL_MARK
+ { N_("mark"), INTERNAL_MARK }, /* INTERNAL */
+#endif
+#ifdef LOG_NEWS
+ { N_("news"), LOG_NEWS },
+#endif
+#ifdef LOG_AUTH
+ { N_("security"), LOG_AUTH }, /* DEPRECATED */
+#endif
+#ifdef LOG_SYSLOG
+ { N_("syslog"), LOG_SYSLOG },
+#endif
+#ifdef LOG_USER
+ { N_("user"), LOG_USER },
+#endif
+#ifdef LOG_UUCP
+ { N_("uucp"), LOG_UUCP },
+#endif
+#ifdef LOG_LOCAL0
+ { N_("local0"), LOG_LOCAL0 },
+#endif
+#ifdef LOG_LOCAL1
+ { N_("local1"), LOG_LOCAL1 },
+#endif
+#ifdef LOG_LOCAL2
+ { N_("local2"), LOG_LOCAL2 },
+#endif
+#ifdef LOG_LOCAL3
+ { N_("local3"), LOG_LOCAL3 },
+#endif
+#ifdef LOG_LOCAL4
+ { N_("local4"), LOG_LOCAL4 },
+#endif
+#ifdef LOG_LOCAL5
+ { N_("local5"), LOG_LOCAL5 },
+#endif
+#ifdef LOG_LOCAL6
+ { N_("local6"), LOG_LOCAL6 },
+#endif
+#ifdef LOG_LOCAL7
+ { N_("local7"), LOG_LOCAL7 },
+#endif
+ { NULL, -1 }
+};
+
+
+SH_CODE sh_prioritynames[] =
+{
+#ifdef LOG_ALERT
+ { N_("alert"), LOG_ALERT },
+#endif
+#ifdef LOG_CRIT
+ { N_("crit"), LOG_CRIT },
+#endif
+#ifdef LOG_DEBUG
+ { N_("debug"), LOG_DEBUG },
+#endif
+#ifdef LOG_EMERG
+ { N_("emerg"), LOG_EMERG },
+#endif
+#ifdef LOG_ERR
+ { N_("err"), LOG_ERR },
+#endif
+#ifdef LOG_ERR
+ { N_("error"), LOG_ERR }, /* DEPRECATED */
+#endif
+#ifdef LOG_INFO
+ { N_("info"), LOG_INFO },
+#endif
+#ifdef INTERNAL_NOPRI
+ { N_("none"), INTERNAL_NOPRI }, /* INTERNAL */
+#endif
+#ifdef LOG_NOTICE
+ { N_("notice"), LOG_NOTICE },
+#endif
+#ifdef LOG_EMERG
+ { N_("panic"), LOG_EMERG }, /* DEPRECATED */
+#endif
+#ifdef LOG_WARNING
+ { N_("warn"), LOG_WARNING }, /* DEPRECATED */
+#endif
+#ifdef LOG_WARNING
+ { N_("warning"), LOG_WARNING },
+#endif
+ { NULL, -1 }
+};
+
+static int enable_syslog_socket = S_FALSE;
+
+int sh_xfer_recv_syslog_socket (int fd)
+{
+ static time_t return_next = 0;
+ int priority = 0;
+ int fac, pri;
+ int i;
+ char * cfac = NULL;
+ char * cpri = NULL;
+ int res;
+ char * tmp;
+ char * bptr;
+ char * ptr = NULL;
+ char buf[1048];
+ struct sockaddr_in from;
+ char errbuf[SH_ERRBUF_SIZE];
+
+ struct sh_sockaddr ss;
+ struct sockaddr * sa = (struct sockaddr *) &from;
+ char namebuf[SH_BUFSIZE];
+
+ /* The 6th argument in recvfrom is *socklen_t in Linux and *BSD,
+ * but *int everywhere else. Because socklen_t is unsigned int, there
+ * should be no problem as long as sizeof(struct sockaddr_in) < INT_MAX ...
+ */
+ unsigned int fromlen = sizeof(from);
+
+ if (enable_syslog_socket == S_FALSE)
+ return 0;
+
+ SL_ENTER(_("sh_xfer_recv_syslog_socket"));
+
+ if (return_next > 0)
+ {
+ if ( (time(NULL) - return_next) < 2)
+ SL_RETURN( 0, _("sh_xfer_recv_syslog_socket"));
+ else
+ return_next = 0;
+ }
+
+ res = recvfrom(fd, buf, 1047, 0, (struct sockaddr *) &from, &fromlen);
+
+ sh_ipvx_save(&ss, sa->sa_family, (struct sockaddr *) &from);
+ sh_ipvx_ntoa(namebuf, sizeof(namebuf), &ss);
+
+ if (res > 0)
+ {
+ res = (res < 1047) ? res : 1047;
+ buf[res] = '\0';
+ if (res > 1 && buf[res-1] == '\n')
+ buf[res-1] = '\0';
+
+ /* here we expect an xml formatted message, thus we don't
+ escape xml special chars (flag == 0) */
+ /* commented out to not escape twice */
+ /* bptr = sh_tools_safe_name(buf, 0); */
+ bptr = buf;
+
+ if (!bptr || !(*bptr))
+ {
+ res = errno;
+ TPT(( 0, FIL__, __LINE__, _("msg=<UDP error: %d>\n"), res));
+ sh_error_handle((-1), FIL__, __LINE__, res, MSG_ERR_SYSLOG,
+ sh_error_message(res, errbuf, sizeof(errbuf)),
+ namebuf);
+ SL_RETURN( (-1), _("sh_xfer_recv_syslog_socket"));
+ }
+
+ TPT(( 0, FIL__, __LINE__, _("msg=<UDP message from %s>\n"), namebuf ));
+
+ ptr = bptr;
+ i = 0;
+ if (*ptr == '<')
+ {
+ ++ptr; ++i;
+ while (i < res &&
+ (unsigned char) *ptr > 47 && (unsigned char) *ptr < 58)
+ {
+ priority = 10 * priority + (*ptr - '0');
+ ++ptr;
+ ++i;
+ }
+ if (*ptr == '>')
+ ++ptr;
+ }
+ fac = LOG_FAC(priority);
+ i = 0;
+ while (sh_facilitynames[i].c_name != NULL)
+ {
+ if (sh_facilitynames[i].c_val == (fac<<3))
+ { cfac = sh_util_strdup(_(sh_facilitynames[i].c_name)); break; }
+ ++i;
+ }
+ pri = LOG_PRI(priority);
+ i = 0;
+ while (sh_prioritynames[i].c_name != NULL)
+ {
+ if (sh_prioritynames[i].c_val == pri)
+ { cpri = sh_util_strdup(_(sh_prioritynames[i].c_name)); break; }
+ ++i;
+ }
+
+ /* here we do not expect an xml formatted message, thus we escape
+ xml special chars (flag == 1) */
+ tmp = sh_tools_safe_name (ptr, 1);
+ sh_error_handle((-1), FIL__, __LINE__, 0, MSG_INET_SYSLOG,
+ namebuf,
+ (cfac == NULL) ? _("none") : cfac,
+ (cpri == NULL) ? _("none") : cpri,
+ (tmp == NULL) ? _("none") : tmp);
+ if (cfac != NULL)
+ SH_FREE(cfac);
+ if (cpri != NULL)
+ SH_FREE(cpri);
+ SH_FREE(tmp);
+ /* SH_FREE(bptr); */
+ }
+
+ else if (res < 0 && errno != EINTR)
+ {
+ res = errno;
+ TPT(( 0, FIL__, __LINE__, _("msg=<UDP error: %d>\n"), res));
+ sh_error_handle((-1), FIL__, __LINE__, res, MSG_ERR_SYSLOG,
+ sh_error_message(res, errbuf, sizeof(errbuf)),
+ namebuf);
+
+ /* don't accept anything the next 2 seconds
+ */
+ return_next = time(NULL);
+ SL_RETURN( (-1), _("sh_xfer_recv_syslog_socket"));
+ }
+ SL_RETURN( (0), _("sh_xfer_recv_syslog_socket"));
+}
+
+int set_syslog_active(const char * c)
+{
+ return sh_util_flagval(c, &enable_syslog_socket);
+}
+
+static int do_syslog_socket(int domain, int type, int protocol,
+ struct sockaddr * sa, int salen)
+{
+ int flag = 1; /* non-zero to enable an option */
+ int sock;
+ int errnum;
+ int res;
+
+ /* create the socket, bind() it and listen()
+ */
+ sock = socket(domain, type, protocol);
+
+ if (sock < 0)
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("syslog socket"), errnum, 514, __LINE__);
+ return -1;
+ }
+ (void) retry_fcntl( FIL__, __LINE__, sock, F_SETFD, 1 );
+
+ if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &flag, sizeof(flag)) < 0 )
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("syslog setsockopt SO_REUSEADDR"),
+ errnum, 514, __LINE__);
+ return -1;
+ }
+
+#if defined(SO_BSDCOMPAT)
+ if ( setsockopt(sock, SOL_SOCKET, SO_BSDCOMPAT,
+ (void *) &flag, sizeof(flag)) < 0 )
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("syslog setsockopt SO_BSDCOMPAT"),
+ errnum, 514, __LINE__);
+ return -1;
+ }
+#endif
+
+ res = bind(sock, sa, salen);
+
+ if ( res < 0)
+ {
+ errnum = errno;
+ sh_xfer_printerr (_("syslog bind"), errnum, 514, __LINE__);
+ sl_close_fd(FIL__, __LINE__, sock);
+ return -1;
+ }
+ return sock;
+}
+
+/* callerFlag == S_TRUE means override the enable_syslog_socket flag
+ */
+int sh_xfer_create_syslog_socket (int callerFlag)
+{
+ int sock;
+
+#if defined(USE_IPVX)
+ struct addrinfo *ai;
+ struct addrinfo *p;
+ struct addrinfo hints;
+#else
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+#endif
+
+ SL_ENTER(_("sh_xfer_create_syslog_socket"));
+
+ if (callerFlag == S_FALSE)
+ {
+ if (enable_syslog_socket == S_FALSE && sh_xfer_syslog_sock_n > 0)
+ {
+ /* user does not wish to use this facility
+ */
+ TPT(( 0, FIL__, __LINE__, _("msg=<close syslog socket>\n")));
+ for (sock = 0; sock < sh_xfer_syslog_sock_n; ++sock)
+ {
+ sl_close_fd(FIL__, __LINE__, sh_xfer_syslog_sock[sock]);
+ sh_xfer_syslog_sock[0] = -1;
+ }
+ }
+ SL_RETURN((-1), _("sh_xfer_create_syslog_socket"));
+ }
+
+ sh_xfer_printerr (NULL, 0, 514, __LINE__);
+
+#if !defined(USE_IPVX)
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(514);
+
+ sock = do_syslog_socket(AF_INET, SOCK_DGRAM, 0,
+ (struct sockaddr *) &addr, addrlen);
+
+ if (sock >= 0) {
+ sh_xfer_syslog_sock[0] = sock;
+ sh_xfer_syslog_sock_n = 1;
+ }
+
+#else
+ memset (&hints, '\0', sizeof (hints));
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_DGRAM;
+ if (getaddrinfo (NULL, "syslog", &hints, &ai) != 0)
+ {
+ int errnum = errno;
+ sh_xfer_printerr (_("getaddrinfo"), errnum, 514, __LINE__);
+ SL_RETURN((-1), _("sh_xfer_create_syslog_socket"));
+ }
+
+ p = ai;
+
+ while (p != NULL && sh_xfer_syslog_sock_n < SH_SOCKMAX)
+ {
+ sock = do_syslog_socket(p->ai_family, p->ai_socktype, p->ai_protocol,
+ p->ai_addr, p->ai_addrlen);
+
+ if (sock >= 0) {
+ if (sh_xfer_syslog_sock_n < SH_SOCKMAX) {
+ sh_xfer_syslog_sock[sh_xfer_syslog_sock_n] = sock;
+ ++sh_xfer_syslog_sock_n;
+ }
+ else {
+ sl_close_fd (FIL__, __LINE__, sock);
+ }
+ } else if (sock == -1) {
+ freeaddrinfo (ai);
+ goto end;
+ }
+ p = p->ai_next;
+ }
+ freeaddrinfo (ai);
+
+ end:
+#endif
+ if (sh_xfer_syslog_sock_n > 1)
+ SH_MINSOCK += (sh_xfer_syslog_sock_n - 1);
+
+ SL_RETURN((sh_xfer_syslog_sock_n), _("sh_xfer_create_syslog_socket"));
+}
+/* #ifdef INET_SYSLOG */
+#endif
+
+/* #ifdef SH_WITH_SERVER */
+#endif
diff --git a/src/simple-bignum.tar.bz2 b/src/simple-bignum.tar.bz2
new file mode 100644
index 0000000..2695323
--- /dev/null
+++ b/src/simple-bignum.tar.bz2
Binary files differ
diff --git a/src/slib.c b/src/slib.c
new file mode 100644
index 0000000..b0e84f5
--- /dev/null
+++ b/src/slib.c
@@ -0,0 +1,3195 @@
+#include "config_xor.h"
+
+#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE)
+#define _XOPEN_SOURCE 600
+#define _BSD_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <limits.h>
+#ifdef HAVE_STDINT_H
+/* for SIZE_MAX */
+#include <stdint.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE)
+#include <sys/mman.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef FD_SET
+#define NFDBITS 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#endif /* !FD_SET */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 32
+#endif
+#ifndef FD_ZERO
+#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p)))
+#endif
+
+#define SH_REAL_SET
+
+#include "slib.h"
+#include "sh_calls.h"
+#define SH_NEED_PWD_GRP 1
+#include "sh_static.h"
+#include "sh_pthread.h"
+#include "sh_string.h"
+
+#undef FIL__
+#define FIL__ _("slib.c")
+
+const uid_t sh_uid_neg = ((uid_t) -1);
+const gid_t sh_gid_neg = ((gid_t) -1);
+
+#undef BREAKEXIT
+#if defined(SCREW_IT_UP) && defined(__linux__) && defined(__i386__)
+
+#ifdef SH_DEBUG
+#define BREAKEXIT(expr) \
+ do { \
+ int ixi; \
+ for (ixi = 0; ixi < 8; ++ixi) { \
+ if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
+ { dlog(0, FIL__, __LINE__, _("BREAKEXIT")); _exit(EXIT_FAILURE); } \
+ } \
+ } \
+ while (1 == 0)
+#else
+#define BREAKEXIT(expr) \
+ do { \
+ int ixi; \
+ for (ixi = 0; ixi < 8; ++ixi) { \
+ if ((*(volatile unsigned *)((unsigned) expr + ixi) & 0xff) == 0xcc) \
+ _exit(EXIT_FAILURE); \
+ } \
+ } \
+ while (1 == 0)
+#endif
+
+#else
+#define BREAKEXIT(expr)
+#endif
+
+/****************************************************************
+ *
+ * The debug/trace subsystem
+ *
+ ****************************************************************/
+
+int slib_do_trace = 0;
+int slib_trace_fd = -1;
+
+static char trace_log[256] = { '\0' };
+static int trace_level = 0;
+static FILE * trace_fp = NULL;
+
+int sl_trace_use (const char * dummy)
+{
+ (void) dummy;
+ slib_do_trace = 1;
+ return 0;
+}
+
+int sl_trace_file (const char * str)
+{
+ if (!str)
+ return -1;
+ if (str[0] != '/')
+ return -1;
+ sl_strlcpy(trace_log, str, 256);
+ return 0;
+}
+
+FILE * sl_tracefile_open(const char * file, const char * mode)
+{
+ FILE * xp = NULL;
+ slib_trace_fd = open(file, O_WRONLY|O_CREAT|O_APPEND, 0600);
+ if (slib_trace_fd >= 0)
+ xp = fdopen(slib_trace_fd, mode);
+ return xp;
+}
+
+void sl_trace_in(const char * str, const char * file, int line)
+{
+ int i;
+ if (trace_log[0] == '\0')
+ {
+ fprintf(stderr, "++ ");
+ for (i = 0; i < trace_level; ++i)
+ fprintf(stderr, ". ");
+ fprintf(stderr, "[%2d] %s \t - File %c%s%c at line %d\n",
+ trace_level, str, 0x22, file, 0x22, line);
+ }
+ else if (!sl_is_suid())
+ {
+ if (!trace_fp)
+ trace_fp = sl_tracefile_open(trace_log, "a");
+ if (trace_fp)
+ {
+ fprintf(trace_fp, "++ ");
+ for (i = 0; i < trace_level; ++i)
+ fprintf(trace_fp, ". ");
+ fprintf(trace_fp, "[%2d] %s \t - File %c%s%c at line %d\n",
+ trace_level, str, 0x22, file, 0x22, line);
+ fflush(trace_fp);
+ }
+ else
+ {
+ perror(_("sl_trace_in: fopen"));
+ _exit(1);
+ }
+ }
+ ++trace_level;
+}
+
+void sl_trace_out(const char * str, const char * file, int line)
+{
+ int i;
+
+ --trace_level; if (trace_level < 0) trace_level = 0;
+
+ if (trace_log[0] == '\0')
+ {
+ fprintf(stderr, "-- ");
+ for (i = 0; i < trace_level; ++i)
+ fprintf(stderr, ". ");
+ fprintf(stderr, _("[%2d] %s \t - File %c%s%c at line %d\n"),
+ trace_level, str, 0x22, file, 0x22, line);
+ }
+ else if (!sl_is_suid())
+ {
+ if (!trace_fp)
+ trace_fp = sl_tracefile_open(trace_log, "a");
+ if (trace_fp)
+ {
+ fprintf(trace_fp, "-- ");
+ for (i = 0; i < trace_level; ++i)
+ fprintf(trace_fp, ". ");
+ fprintf(trace_fp, _("[%2d] %s \t - File %c%s%c at line %d\n"),
+ trace_level, str, 0x22, file, 0x22, line);
+ fflush(trace_fp);
+ }
+ else
+ {
+ perror(_("sl_trace_out: fopen"));
+ _exit(1);
+ }
+ }
+}
+
+extern int sh_log_console (const char * msg);
+
+static int dlogActive = 0;
+
+/* this is called from sh_error_setprint()
+ */
+void dlog_set_active(int flag)
+{
+ dlogActive = flag;
+}
+
+/* flag = 0 debug messages
+ * = 1 descriptive error messages
+ * = 3 backtrace
+ */
+int dlog (int flag, const char * file, int line, const char *fmt, ...)
+{
+ va_list ap;
+ char val[81];
+ char msg[512];
+ char tmp[512];
+ int retval = 0;
+ int i;
+
+#ifdef SH_STEALTH
+ /*
+ * do not even print descriptive failure messages in stealth mode
+ */
+ if (dlogActive == 0)
+ return 0;
+ if (dlogActive == 1 && flag == 0) /* debug requires debug level */
+ return 0;
+#else
+ if (dlogActive <= 1 && flag == 0) /* debug requires debug level */
+ return 0;
+#endif
+
+ if (flag == 1)
+ {
+ sl_snprintf (val, 81, _("\n--------- %10s "), file);
+ sl_strlcpy (msg, val, 80);
+ sl_snprintf (val, 81, _(" --- %6d ---------\n"), line);
+ sl_strlcat (msg, val, 80);
+ sh_log_console (msg);
+ }
+
+ va_start (ap, fmt);
+ if (flag == 1)
+ sl_strlcpy(tmp, fmt, 512);
+ else
+ sl_strlcpy(tmp, fmt, 256);
+ retval = strlen(tmp);
+ if (retval > 0 && tmp[retval-1] == '\n')
+ tmp[retval-1] = '\0';
+ retval = 0;
+ if (flag == 1)
+ {
+ sl_vsnprintf (msg, 511, tmp, ap);
+ }
+ else
+ {
+ sl_strlcpy (msg, "## ", 256);
+ for (i = 0; i < trace_level; ++i)
+ sl_strlcat (msg, ". ", 256);
+ sprintf (val, _("[%2d] "), trace_level);
+ sl_strlcat (msg, val, 256);
+ sl_vsnprintf (&msg[strlen(msg)], 255, tmp, ap);
+ sl_snprintf (tmp, 255, _(" \t - File %c%s%c at line %d"),
+ 0x22, file, 0x22, line);
+ sl_strlcat (msg, tmp, 512);
+ }
+ va_end (ap);
+ if (flag != 0 || sl_is_suid())
+ retval = sh_log_console (msg);
+ else
+ {
+ if (trace_log[0] == '\0')
+ {
+ /* sh_log_console (msg); */
+ fprintf(stderr, "%s\n", msg);
+ }
+ else
+ {
+ if (!trace_fp)
+ trace_fp = sl_tracefile_open(trace_log, "a");
+ if (trace_fp)
+ {
+ fprintf(trace_fp, "%s\n", msg);
+ }
+ else
+ {
+ perror(_("dlog: fopen"));
+ _exit(1);
+ }
+ }
+ }
+ if (flag == 1)
+ sh_log_console (_("\n----------------------------------------------\n"));
+ return retval;
+}
+
+extern char aud_err_message[64];
+static char alt_err_message[64];
+char * sl_get_errmsg()
+{
+ if (aud_err_message[0] == '\0')
+ {
+ sl_strlcpy(alt_err_message, sl_error_string(sl_errno), 64);
+ return &alt_err_message[0];
+ }
+ return &aud_err_message[0];
+}
+
+
+#if defined(SL_DEBUG)
+#define SL_MAX_MYSTACK 128
+
+static char sl_mystack[SL_MAX_MYSTACK][32];
+static int sl_mystack_count = 0;
+
+void sl_stack_push(char * c, char * file, int line )
+{
+ if (slib_do_trace)
+ sl_trace_in(c, file, line);
+ if (c && sl_mystack_count < SL_MAX_MYSTACK)
+ {
+ strncpy(sl_mystack[sl_mystack_count], c, 31);
+ sl_mystack[sl_mystack_count][31] = '\0';
+ ++sl_mystack_count;
+ /*
+ fprintf(stderr, "#%03d %s\n", sl_mystack_count,
+ sl_mystack[sl_mystack_count-1]);
+ */
+ }
+ return;
+}
+
+void sl_stack_pop(char * c, char * file, int line)
+{
+ if (slib_do_trace)
+ sl_trace_out(c, file, line);
+ if (sl_mystack_count > 0)
+ {
+ /*
+ fprintf(stderr, " <- #%03d %s\n", sl_mystack_count,
+ sl_mystack[sl_mystack_count-1]);
+ */
+ --sl_mystack_count;
+ }
+ return;
+}
+
+void sl_stack_print()
+{
+ int i;
+ /* FILE * dfile; */
+
+ if (sl_mystack_count > 0)
+ {
+ sh_log_console(_("\nBacktrace:\n"));
+ /* dlog(3, FIL__, __LINE__, _("\nBacktrace:\n")); */
+ for (i = 0; i < sl_mystack_count; ++i)
+ sh_log_console(sl_mystack[i]);
+ /* dlog(3, FIL__, __LINE__, _("#%03d %s\n"), i, sl_mystack[i]); */
+ }
+ return;
+}
+
+#endif
+
+
+/*
+ * The global errno.
+ * On error, this is set to the return value of the function.
+ */
+long int sl_errno;
+
+
+/* ----------------------------------------------------------------
+ *
+ * Capability routines
+ *
+ * ---------------------------------------------------------------- */
+
+int sl_useCaps = 0;
+
+#ifdef FANCY_LIBCAP
+#include <sys/capability.h>
+
+/*
+ * While these routines are tested and work, we don't use POSIX
+ * capabilities, as they don't seem to be useful (root can write
+ * to root-owned files anyway). Things would be more interesting
+ * if we could switch to a non-root UID with just a few capabilities
+ * enabled.
+ */
+int sl_drop_cap ()
+{
+ int error;
+ cap_t caps;
+ cap_flag_t capflag;
+ cap_flag_value_t capfval = CAP_CLEAR;
+ cap_value_t capvals_e[] =
+ {
+ CAP_CHOWN, CAP_FOWNER, CAP_FSETID,
+ CAP_LINUX_IMMUTABLE, CAP_MKNOD, CAP_NET_ADMIN,
+ CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
+ CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
+ CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
+ CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG,
+ CAP_SETGID, CAP_SETUID, CAP_KILL,
+ CAP_DAC_OVERRIDE,
+#if !defined(WITH_MESSAGE_QUEUE)
+ CAP_IPC_OWNER,
+#endif
+ CAP_SYS_MODULE, CAP_LEASE
+ };
+ cap_value_t capvals_p[] =
+ {
+ CAP_CHOWN, CAP_LEASE, CAP_FSETID,
+ CAP_LINUX_IMMUTABLE, CAP_MKNOD, CAP_NET_ADMIN,
+ CAP_NET_BIND_SERVICE, CAP_NET_BROADCAST, CAP_NET_RAW,
+ CAP_SYS_ADMIN, CAP_SYS_BOOT, CAP_SYS_CHROOT,
+ CAP_SYS_PACCT, CAP_SYS_PTRACE, CAP_SYS_RAWIO,
+ CAP_SYS_RESOURCE, CAP_SYS_TIME, CAP_SYS_TTY_CONFIG,
+#if !defined(WITH_EXTERNAL) && !defined(HAVE_UNIX_RANDOM)
+ CAP_SETGID, CAP_SETUID, CAP_KILL,
+#endif
+#if !defined(SH_USE_SUIDCHK)
+ CAP_DAC_OVERRIDE, CAP_FOWNER,
+#endif
+#if !defined(WITH_MESSAGE_QUEUE)
+ CAP_IPC_OWNER,
+#endif
+ CAP_SYS_MODULE
+ };
+
+ if (0 == sl_useCaps) /* 0 = S_FALSE */
+ {
+ return 0;
+ }
+
+ if(NULL == (caps = cap_get_proc()))
+ {
+ return errno;
+ }
+
+ capflag = CAP_EFFECTIVE;
+ if (0 != cap_set_flag(caps, capflag, sizeof(capvals_e)/sizeof(cap_value_t),
+ capvals_e, capfval))
+ {
+ error = errno;
+ cap_free(caps);
+ return error;
+ }
+ if (0 != cap_set_proc(caps))
+ {
+ error = errno;
+ cap_free(caps);
+ return error;
+ }
+
+ capflag = CAP_PERMITTED;
+ if (0 != cap_set_flag(caps, capflag, sizeof(capvals_p)/sizeof(cap_value_t),
+ capvals_p, capfval))
+ {
+ error = errno;
+ cap_free(caps);
+ return error;
+ }
+ if (0 != cap_set_proc(caps))
+ {
+ error = errno;
+ cap_free(caps);
+ return error;
+ }
+ cap_free(caps);
+ return 0;
+}
+
+int sl_drop_cap_int(int what)
+{
+#if defined(SL_DEBUG)
+ char * captext;
+#endif
+ cap_flag_t capflag = CAP_EFFECTIVE;
+ cap_flag_value_t capfval = CAP_CLEAR;
+ cap_value_t capvals_a[] = { CAP_SETGID, CAP_SETUID, CAP_KILL };
+ cap_value_t capvals_b[] = { CAP_DAC_OVERRIDE, CAP_FOWNER };
+ cap_value_t * capvals;
+ int nvals;
+ int error = 0;
+ cap_t caps = cap_get_proc();
+
+ if (0 == sl_useCaps) /* 0 = S_FALSE */
+ {
+ return 0;
+ }
+
+ if (caps == NULL)
+ {
+ return errno;
+ }
+
+ switch (what) {
+ case 1:
+ capvals = capvals_a;
+ nvals = 3;
+ capfval = CAP_CLEAR;
+ break;
+ case 2:
+ capvals = capvals_a;
+ nvals = 3;
+ capfval = CAP_SET;
+ break;
+ case 3:
+ capvals = capvals_b;
+ nvals = 2;
+ capfval = CAP_CLEAR;
+ break;
+ case 4:
+ capvals = capvals_b;
+ nvals = 2;
+ capfval = CAP_SET;
+ break;
+ default:
+ return (0);
+ }
+
+ if (0 != cap_set_flag(caps, capflag, nvals, capvals, capfval))
+ {
+ error = errno;
+ cap_free(caps);
+ return error;
+ }
+ if (0 != cap_set_proc(caps))
+ {
+ error = errno;
+ cap_free(caps);
+ return error;
+ }
+#if defined(SL_DEBUG)
+ captext = cap_to_text(caps, NULL);
+ TPT(( 0, FIL__, __LINE__, _("msg=<cap_int %d: %s>\n"), what, captext));
+ cap_free(captext);
+#endif
+ cap_free(caps);
+ return 0;
+}
+
+int sl_drop_cap_sub() { return sl_drop_cap_int(1); }
+int sl_get_cap_sub() { return sl_drop_cap_int(2); }
+int sl_drop_cap_qdel() { return sl_drop_cap_int(3); }
+int sl_get_cap_qdel() { return sl_drop_cap_int(4); }
+
+#else
+int sl_drop_cap () { return 0; }
+int sl_drop_cap_sub() { return 0; }
+int sl_get_cap_sub() { return 0; }
+int sl_drop_cap_qdel() { return 0; }
+int sl_get_cap_qdel() { return 0; }
+#endif
+
+/* ----------------------------------------------------------------
+ *
+ * String handling routines
+ *
+ * ---------------------------------------------------------------- */
+
+/*
+ * Have memset in a different translation unit (i.e. this) to prevent
+ * it to get optimized away
+ */
+void *sl_memset(void *s, int c, size_t n)
+{
+ return memset(s, c,n);
+}
+
+
+#if !defined (VA_COPY)
+#if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32))
+#define VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
+#elif defined (VA_COPY_AS_ARRAY)
+#define VA_COPY(ap1, ap2) memmove ((ap1), (ap2), sizeof (va_list))
+#else /* va_list is a pointer */
+#define VA_COPY(ap1, ap2) ((ap1) = (ap2))
+#endif
+#endif
+
+#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
+static
+size_t sl_printf_count (const char * fmt, va_list vl)
+{
+ size_t length = 1;
+ int fini = 0;
+ int islong = 0;
+ int islonglong = 0;
+ int islongdouble = 0;
+ char * string_arg;
+
+ SL_ENTER(_("sl_printf_count"));
+
+ if (fmt == NULL)
+ SL_IRETURN(SL_ENULL, _("sl_printf_count"));
+
+ while (*fmt) {
+
+ if ( (*fmt) == '%' ) { /* a format specifier */
+
+ fmt++; /* point to first char after '%' */
+
+ fini = 0;
+ islong = 0;
+ islongdouble = 0;
+
+ while (*fmt && (fini == 0) ) {
+
+ switch (*fmt) {
+
+ case '*': /* field width supplied by an integer */
+ length = length + va_arg (vl, int);
+ ++fmt;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ length = length + strtol (fmt, (char**) &fmt, 10);
+ /* strtol makes FastForward to first invalid char */
+ break;
+
+ case 'l': /* 'long' modifier */
+ if (islong == 0)
+ islong = 1;
+ else
+ {
+ islonglong = 1;
+ islong = 0;
+ }
+ ++fmt;
+ break;
+
+ case 'L': /* 'long double' modifier */
+#ifdef HAVE_LONG_DOUBLE
+ islongdouble = 1;
+#else
+ islong = 1;
+#endif
+ ++fmt;
+ break;
+
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (islonglong == 1)
+#ifdef HAVE_LONG_LONG
+ (void) va_arg (vl, long long);
+#else
+ (void) va_arg (vl, long);
+#endif
+ else if (islong == 1)
+ (void) va_arg (vl, long);
+ else
+ (void) va_arg (vl, int);
+ islong = 0;
+ islonglong = 0;
+ length = length + 24;
+ ++fmt;
+ fini = 1;
+ break;
+
+ case 'D':
+ case 'O':
+ case 'U':
+ (void) va_arg (vl, long);
+ length = length + 24;
+ fmt++;
+ fini = 1;
+ break;
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+#ifdef HAVE_LONG_DOUBLE
+ if (islongdouble == 1) {
+ (void) va_arg (vl, long double);
+ islongdouble = 0;
+ length = length + 20;
+ }
+ else
+#endif
+ (void) va_arg (vl, double);
+ length = length + 20;
+ fini = 1;
+ ++fmt;
+ break;
+
+ case 's':
+ string_arg = va_arg (vl, char *);
+ if (string_arg != NULL)
+ length = length + sl_strlen (string_arg);
+ else
+ length = length + 16;
+ fini = 1;
+ ++fmt;
+ break;
+
+ case 'c':
+ (void) va_arg (vl, int);
+ length = length + 1;
+ fini = 1;
+ ++fmt;
+ break;
+
+ case 'p':
+ case 'n':
+ (void) va_arg (vl, void * );
+ length = length + 32;
+ fini = 1;
+ ++fmt;
+ break;
+
+ case '%': /* %% will print '%' */
+ length = length + 1;
+ fini = 1;
+ ++fmt;
+ break;
+
+ default:
+ length = length + 1;
+ ++fmt;
+ break;
+
+ } /* end switch */
+ }
+ /* end parsing a single format specifier */
+ } else {
+ length = length + 1;
+ fmt++;
+ }
+ }
+ SL_IRETURN(length, _("sl_printf_count"));
+}
+#endif /* #ifndef HAVE_VSNPRINTF */
+
+/*
+ * An implementation of vsnprintf. va_start/va_end are in the caller
+ * function.
+ * Returns C99 (#bytes that would heve been written) on success.
+ */
+int sl_vsnprintf(char *str, size_t n,
+ const char *format, va_list vl )
+{
+ int len = 0;
+#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
+ size_t total;
+ va_list vl2;
+#endif
+
+ SL_ENTER(_("sl_vsnprintf"));
+ if (str == NULL || format == NULL)
+ SL_IRETURN(0, _("sl_vsnprintf"));
+
+#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
+ len = vsnprintf (str, n, format, vl); /* flawfinder: ignore */
+ str[n-1] = '\0';
+#else
+ VA_COPY (vl2, vl); /* save the argument list */
+ total = sl_printf_count (format, vl);
+ len = (int) total;
+ if (total < n)
+ {
+ /* flawfinder: ignore */
+ vsprintf (str, format, vl2); /* program has checked that it fits */
+ str[n-1] = '\0';
+ }
+ else
+ {
+ sl_strlcpy (str, format, n);
+ va_end(vl2);
+ SL_IRETURN(len, _("sl_vsnprintf"));
+ }
+ va_end(vl2);
+#endif
+ SL_IRETURN(len, _("sl_vsnprintf"));
+}
+
+/*
+ * An implementation of snprintf.
+ * Returns SL_ENONE on success.
+ * ENULL: src || format == NULL
+ * ERANGE: n out of range
+ * ETRUNC: truncated (unimplemented)
+ */
+int sl_snprintf(char *str, size_t n,
+ const char *format, ... )
+{
+ va_list vl;
+#if !defined(HAVE_VSNPRINTF) || defined(HAVE_BROKEN_VSNPRINTF)
+ size_t total = 0;
+ va_list vl2;
+#endif
+
+ SL_ENTER(_("sl_snprintf"));
+ if (str == NULL || format == NULL)
+ SL_IRETURN(SL_ENULL, _("sl_snprintf"));
+
+ va_start (vl, format);
+#if defined(HAVE_VSNPRINTF) && !defined(HAVE_BROKEN_VSNPRINTF)
+ /* flawfinder: ignore */
+ vsnprintf (str, n, format, vl);
+ str[n-1] = '\0';
+#else
+ VA_COPY (vl2, vl); /* save the argument list */
+ total = sl_printf_count (format, vl);
+ if (total < n)
+ {
+ /* flawfinder: ignore */
+ vsprintf (str, format, vl2); /* program has checked that it fits */
+ str[n-1] = '\0';
+ }
+ else
+ {
+ sl_strlcpy (str, format, n);
+ va_end(vl2);
+ va_end(vl);
+ SL_IRETURN(SL_ETRUNC, _("sl_snprintf"));
+ }
+ va_end(vl2);
+#endif
+ va_end(vl);
+ SL_IRETURN(SL_ENONE, _("sl_snprintf"));
+}
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns SL_NONE on success, errcode on failure.
+ *
+ * ENULL: dst == NULL
+ * ERANGE: siz out of range
+ * ETRUNC: src truncated
+ */
+int sl_strlcat(char * dst, /*@null@*/const char *src, size_t siz)
+{
+ register size_t dst_end;
+ register size_t dst_free;
+
+ register char * p;
+ register const char * q;
+
+ if (!(dst == NULL || src == NULL || *src == '\0'))
+ {
+ if (siz > 0)
+ {
+
+ /* How much free space do we have ?
+ */
+ dst_end = strlen(dst);
+ dst_free = siz - dst_end - 1;
+
+ p = &dst[dst_end];
+ q = src;
+
+ while (dst_free > 0 && *q != '\0')
+ {
+ *p++ = *q++;
+ --dst_free;
+ }
+
+ /* NULL terminate dst.
+ */
+ *p = '\0';
+
+ if (*q == '\0')
+ return SL_ENONE;
+ else
+ return SL_ETRUNC;
+ }
+ }
+ return SL_ENONE;
+}
+
+/*
+ * An alternative implementation of the OpenBSD strlcpy() function.
+ *
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns SL_NONE on success, errcode on failure.
+ *
+ * ENULL: dst == NULL
+ * ERANGE: siz out of range
+ * ETRUNC: src truncated
+ */
+int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz)
+{
+ /* SL_ENTER(_("sl_strlcpy")); */
+
+ if (!((dst == NULL) || (src == NULL)))
+ {
+ if (siz > 0) {
+ /* copy siz-1 characters
+ */
+ (void) strncpy(dst, src, siz-1);
+
+ /* NULL terminate
+ */
+ dst[siz-1] = '\0';
+ }
+ return SL_ENONE;
+ }
+ else if (src == NULL)
+ {
+ if (dst && siz > 0)
+ dst[0] = '\0';
+ return SL_ENONE;
+ }
+ else
+ {
+ return SL_ENULL;
+ }
+}
+
+/*
+ * A robust drop-in replacement of strncpy. strlcpy is preferable.
+ */
+char * sl_strncpy(char *dst, const char *src, size_t size)
+{
+
+#ifdef SL_FAIL_ON_ERROR
+ SL_REQUIRE(dst != NULL, _("dst != NULL"));
+ SL_REQUIRE(src != NULL, _("src != NULL"));
+ SL_REQUIRE(size > 0, _("size > 0"));
+#endif
+
+ if (dst == NULL)
+ {
+ sl_errno = SL_ENULL;
+ return (NULL);
+ }
+ if (size < 1)
+ {
+ sl_errno = SL_ERANGE;
+ return (dst);
+ }
+ if (!src)
+ {
+ sl_errno = SL_ENULL;
+ dst[0] = '\0';
+ }
+ else if (src[0] == '\0')
+ dst[0] = '\0';
+ else
+ strncpy(dst, src, size);
+
+ if (sl_strlen(src) >= size)
+ {
+ errno = ENOSPC;
+ dst[size-1] = '\0';
+ }
+ return (dst);
+}
+
+/*
+ * A robust drop-in replacement of strncat. strlcat is preferable.
+ */
+char * sl_strncat(char *dst, const char *src, size_t n)
+{
+#ifdef SL_FAIL_ON_ERROR
+ SL_REQUIRE(dst != NULL, _("dst != NULL"));
+ SL_REQUIRE(src != NULL, _("src != NULL"));
+ SL_REQUIRE(n > 0, _("n > 0"));
+#endif
+
+ if (dst == NULL)
+ {
+ sl_errno = SL_ENULL;
+ return (NULL);
+ }
+ if (n < 1)
+ {
+ sl_errno = SL_ERANGE;
+ return (dst);
+ }
+ if (!src)
+ {
+ sl_errno = SL_ENULL;
+ return (dst);
+ }
+ else if (src[0] == '\0')
+ dst[0] = '\0';
+ else
+ strncat(dst, src, n);
+
+ return (dst);
+}
+
+#include <ctype.h>
+int sl_strcasecmp(const char * one, const char * two)
+{
+#ifdef SL_FAIL_ON_ERROR
+ SL_REQUIRE (one != NULL, _("one != NULL"));
+ SL_REQUIRE (two != NULL, _("two != NULL"));
+#endif
+
+ if (one && two)
+ {
+ do {
+ if (*one && *two)
+ {
+ if (tolower((int) *one) == tolower((int) *two))
+ {
+ ++one; ++two;
+ }
+ else if (tolower((int) *one) < tolower((int) *two))
+ return -1;
+ else
+ return 1;
+ }
+ else if (*one == '\0' && *two == '\0')
+ return 0;
+ else if (*one == '\0')
+ return -1;
+ else
+ return 1;
+ } while (1 == 1);
+ }
+ else if (one == NULL && two != NULL)
+ return -1;
+ else if (one != NULL && two == NULL)
+ return 1;
+ else
+ return -7; /* default to not equal */
+}
+
+int sl_strcmp(const char * a, const char * b)
+{
+#ifdef SL_FAIL_ON_ERROR
+ SL_REQUIRE (a != NULL, _("a != NULL"));
+ SL_REQUIRE (b != NULL, _("b != NULL"));
+#endif
+
+ if (a != NULL && b != NULL)
+ return (strcmp(a, b));
+ else if (a == NULL && b != NULL)
+ return (-1);
+ else if (a != NULL && b == NULL)
+ return (1);
+ else
+ return (-7); /* default to not equal */
+}
+
+int sl_strncmp(const char * a, const char * b, size_t n)
+{
+#ifdef SL_FAIL_ON_ERROR
+ SL_REQUIRE (a != NULL, _("a != NULL"));
+ SL_REQUIRE (b != NULL, _("b != NULL"));
+ SL_REQUIRE (n > 0, _("n > 0"));
+#endif
+
+ if (a != NULL && b != NULL)
+ return (strncmp(a, b, n));
+ else if (a == NULL && b != NULL)
+ return (-1);
+ else if (a != NULL && b == NULL)
+ return (1);
+ else
+ return (-7); /* default to not equal */
+}
+
+int sl_strncasecmp(const char * a, const char * b, size_t n)
+{
+#ifdef SL_FAIL_ON_ERROR
+ SL_REQUIRE (a != NULL, _("a != NULL"));
+ SL_REQUIRE (b != NULL, _("b != NULL"));
+ SL_REQUIRE (n > 0, _("n > 0"));
+#endif
+
+ if (a != NULL && b != NULL)
+ return (strncasecmp(a, b, n));
+ else if (a == NULL && b != NULL)
+ return (-1);
+ else if (a != NULL && b == NULL)
+ return (1);
+ else
+ return (-7); /* default to not equal */
+}
+
+/* string searching
+ */
+
+char * sl_strstr (const char * haystack, const char * needle)
+{
+#ifndef HAVE_STRSTR
+ unsigned int i;
+ size_t needle_len;
+ size_t haystack_len;
+#endif
+
+ if (haystack == NULL || needle == NULL)
+ return NULL;
+ if (*needle == '\0' || *haystack == '\0')
+ return NULL;
+
+#if defined(HAVE_STRSTR)
+ return (strstr(haystack, needle));
+#else
+ needle_len = strlen(needle);
+ haystack_len = strlen(haystack);
+
+ for (i = 0; i <= (haystack_len-needle_len); ++i)
+ if (0 == sl_strncmp(&haystack[i], needle, needle_len))
+ return (needle);
+ return NULL;
+#endif
+}
+
+
+/* ----------------------------------------------------------------
+ *
+ * Privilege handling routines
+ *
+ * ---------------------------------------------------------------- */
+
+
+
+static uid_t euid;
+static uid_t ruid;
+static uid_t ruid_orig;
+static gid_t egid;
+static gid_t rgid;
+static gid_t rgid_orig;
+
+static int uids_are_stored = S_FALSE;
+static int suid_is_set = S_TRUE;
+
+#ifdef HAVE_SETRESUID
+extern int setresuid (uid_t truid, uid_t teuid, uid_t tsuid);
+extern int setresgid (gid_t trgid, gid_t tegid, gid_t tsgid);
+#endif
+
+
+/*
+ * This function returns true if the program is SUID.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_is_suid()
+{
+ if (uids_are_stored == S_FALSE)
+ {
+ if (getuid() == geteuid() && getgid() == getegid())
+ return (0); /* FALSE */
+ else
+ return (1); /* TRUE */
+ }
+ else
+ {
+ if (euid == ruid && egid == rgid)
+ return (0); /* FALSE */
+ else
+ return (1); /* TRUE */
+ }
+}
+
+/*
+ * This function returns the saved euid.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_get_euid(uid_t * ret)
+{
+ SL_ENTER(_("sl_get_euid"));
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ *ret = euid;
+ else
+ *ret = geteuid();
+ SL_IRETURN (SL_ENONE, _("sl_get_euid"));
+}
+
+uid_t sl_ret_euid()
+{
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ return (euid);
+ else
+ return (geteuid());
+}
+
+/*
+ * This function returns the saved egid.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_get_egid(gid_t * ret)
+{
+ SL_ENTER(_("sl_get_egid"));
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ *ret = egid;
+ else
+ *ret = getegid();
+ SL_IRETURN (SL_ENONE, _("sl_get_egid"));
+}
+
+/*
+ * This function returns the saved ruid.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_get_ruid(uid_t * ret)
+{
+ SL_ENTER(_("sl_get_ruid"));
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ *ret = ruid;
+ else
+ *ret = getuid();
+ SL_IRETURN (SL_ENONE, _("sl_get_ruid"));
+}
+
+/*
+ * This function returns the saved rgid.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_get_rgid(gid_t * ret)
+{
+ SL_ENTER(_("sl_get_rgid"));
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ *ret = rgid;
+ else
+ *ret = getgid();
+ SL_IRETURN (SL_ENONE, _("sl_get_rgid"));
+}
+
+/*
+ * This function returns the saved original ruid.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_get_ruid_orig(uid_t * ret)
+{
+ SL_ENTER(_("sl_get_ruid_orig"));
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ *ret = ruid_orig;
+ else
+ *ret = getuid();
+ SL_IRETURN (SL_ENONE, _("sl_get_ruid_orig"));
+}
+
+/*
+ * This function returns the saved original rgid.
+ * It calls abort() if the uid's are not saved already.
+ */
+int sl_get_rgid_orig(gid_t * ret)
+{
+ SL_ENTER(_("sl_get_rgid_orig"));
+ /* SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));*/
+ if (uids_are_stored == S_TRUE)
+ *ret = rgid_orig;
+ else
+ *ret = getgid();
+ SL_IRETURN (SL_ENONE, _("sl_get_rgid_orig"));
+}
+
+static int suid_warn_flag = 1;
+static void suid_warn(int a)
+{
+ fprintf(stderr, _("ERROR: open set/unset suid !!! %d\n"), a);
+ return;
+}
+
+/*
+ * This function sets the effective uid
+ * to the saved effective uid.
+ * It will abort on failure.
+ */
+int sl_set_suid ()
+{
+ int retval;
+
+ SL_ENTER(_("sl_set_suid"));
+
+ if (uids_are_stored == S_FALSE)
+ {
+ SL_IRETURN(SL_ENONE, _("sl_set_suid"));
+ }
+
+ SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));
+
+ if (ruid == euid && rgid == egid)
+ {
+ suid_is_set = S_TRUE;
+ SL_IRETURN(SL_ENONE, _("sl_set_suid"));
+ }
+ SL_REQUIRE(suid_is_set == S_FALSE, _("suid_is_set == S_FALSE"));
+
+#if defined(HAVE_SETRESUID)
+ retval = setresuid (sh_uid_neg, euid, sh_uid_neg);
+ if (retval == 0)
+ retval = setresgid (sh_gid_neg, egid, sh_gid_neg);
+
+#elif defined(HAVE_SETEUID)
+ retval = seteuid (egid);
+ if (retval == 0)
+ retval = setegid (euid);
+
+ /* on AIX, setreuid does not behave well for non-root users.
+ */
+#elif defined(HAVE_SETREUID)
+ retval = setreuid (ruid, euid);
+ if (retval == 0)
+ retval = setregid (rgid, egid);
+
+#else
+ retval = setuid (euid);
+ if (retval == 0)
+ retval = setgid (egid);
+#endif
+ if (suid_warn_flag == 1)
+ suid_warn(1);
+ suid_warn_flag = 1;
+
+ SL_REQUIRE(retval == 0, _("retval == 0"));
+ suid_is_set = S_TRUE;
+ SL_IRETURN(SL_ENONE, _("sl_set_suid"));
+}
+
+/*
+ * This function sets the effective uid to the real uid.
+ * It will abort on failure.
+ */
+int sl_unset_suid ()
+{
+ register int retval;
+
+ SL_ENTER(_("sl_unset_suid"));
+
+ if (uids_are_stored == S_FALSE)
+ {
+ SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
+ }
+
+ SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));
+
+ if (ruid == euid && rgid == egid)
+ {
+ suid_is_set = S_FALSE;
+ SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
+ }
+ SL_REQUIRE(suid_is_set == S_TRUE, _("suid_is_set == S_TRUE"));
+
+#if defined(HAVE_SETRESUID)
+ retval = setresgid (sh_gid_neg, rgid, sh_gid_neg);
+ if (retval == 0)
+ retval = setresuid (sh_uid_neg, ruid, sh_uid_neg);
+
+#elif defined(HAVE_SETEUID)
+ retval = setegid (rgid);
+ if (retval == 0)
+ retval = seteuid (ruid);
+
+#elif defined(HAVE_SETREUID)
+ retval = setregid (egid, rgid);
+ if (retval == 0)
+ retval = setreuid (euid, ruid);
+
+#else
+ retval = setgid (rgid);
+ if (retval == 0)
+ retval = setuid (ruid);
+#endif
+
+ if (suid_warn_flag == 0)
+ suid_warn(0);
+ suid_warn_flag = 0;
+
+ SL_REQUIRE(retval == 0, _("retval == 0"));
+ suid_is_set = S_FALSE;
+ SL_IRETURN(SL_ENONE, _("sl_unset_suid"));
+}
+
+
+/*
+ * This function saves the uid's.
+ */
+int sl_save_uids()
+{
+ SL_ENTER(_("sl_save_uids"));
+ if (uids_are_stored == S_TRUE)
+ SL_IRETURN(SL_EREPEAT, _("sl_save_uids"));
+
+ ruid_orig = getuid();
+ rgid_orig = getgid();
+ egid = getegid();
+ euid = geteuid();
+ ruid = ruid_orig;
+ rgid = rgid_orig;
+ uids_are_stored = S_TRUE;
+
+ SL_IRETURN(SL_ENONE, _("sl_save_uids"));
+}
+
+/*
+ * This function drops SUID privileges irrevocably.
+ * It set the effective uid to the original real uid.
+ */
+extern int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid);
+int sl_drop_privileges()
+{
+ SL_ENTER(_("sl_drop_privileges"));
+ SL_REQUIRE(uids_are_stored == S_TRUE, _("uids_are_stored == S_TRUE"));
+
+ SL_REQUIRE(setgid(rgid_orig) == 0, _("setgid(rgid_orig) == 0"));
+ SL_REQUIRE(sh_unix_initgroups2(ruid_orig, rgid_orig) == 0, _("sh_unix_initgroups2(ruid_orig,rgid_orig) == 0"));
+ SL_REQUIRE(setuid(ruid_orig) == 0, _("setuid(ruid_orig) == 0"));
+
+ /* make sure that setuid(0) fails
+ */
+ SL_REQUIRE(setuid(0) < 0, _("setuid(0) < 0"));
+
+ euid = ruid_orig;
+ egid = rgid_orig;
+ ruid = ruid_orig;
+ rgid = rgid_orig;
+
+ SL_IRETURN(SL_ENONE, _("sl_drop_privileges"));
+}
+
+/*
+ * Define a policy: Stay root.
+ * Do nothing if not SUID.
+ */
+int sl_policy_get_root()
+{
+ SL_ENTER(_("sl_policy_get_root"));
+ SL_REQUIRE(uids_are_stored == S_FALSE, _("uids_are_stored == S_FALSE"));
+
+ SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
+
+ if (euid != ruid || egid != rgid)
+ {
+ SL_REQUIRE(setgid(egid) == 0, _("setgid(egid) == 0"));
+ SL_REQUIRE(setuid(euid) == 0, _("setuid(euid) == 0"));
+ SL_REQUIRE(ruid == getuid() && rgid == getgid(),
+ _("ruid == getuid() && rgid == getgid()"));
+ ruid = euid;
+ rgid = egid;
+ }
+ suid_is_set = S_TRUE;
+ if (euid == 0)
+ {
+ SL_REQUIRE(sh_unix_initgroups2(euid, egid) == 0, _("sh_unix_initgroups2(euid,egid) == 0"));
+ }
+ SL_IRETURN(SL_ENONE, _("sl_policy_get_root"));
+}
+
+#include <pwd.h>
+
+/*
+ * Define a policy: Get real (irrevocably).
+ * This function drops SUID privileges irrevocably.
+ * Do nothing if not SUID (? not true - drops if root).
+ */
+
+int sl_policy_get_real(char * user)
+{
+ SL_ENTER(_("sl_policy_get_real"));
+ SL_REQUIRE(uids_are_stored == S_FALSE, _("uids_are_stored == S_FALSE"));
+ SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
+
+ if (euid == 0 || ruid == 0)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+ struct passwd * tempres;
+ buffer = calloc(1,SH_PWBUF_SIZE);
+ SL_REQUIRE (buffer != NULL, _("buffer != NULL"));
+ sh_getpwnam_r(user, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ struct passwd * tempres = sh_getpwnam(user);
+#endif
+
+ SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
+
+ rgid_orig = tempres->pw_gid;
+ ruid_orig = tempres->pw_uid;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ free(buffer);
+#endif
+ }
+ else
+ {
+ rgid_orig = rgid;
+ ruid_orig = ruid;
+ }
+
+ SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
+ _("sl_drop_privileges() == SL_ENONE"));
+
+ suid_is_set = S_TRUE;
+ SL_IRETURN(SL_ENONE, _("sl_policy_get_real"));
+}
+
+
+/*
+ * Define a policy: Get user.
+ * Drops privileges.
+ * Do nothing if not SUID.
+ */
+int sl_policy_get_user(const char * user)
+{
+ SL_ENTER(_("sl_policy_get_user"));
+
+ SL_REQUIRE(user != NULL, _("user != NULL"));
+ SL_REQUIRE(uids_are_stored == S_FALSE, _("uids_are_stored == S_FALSE"));
+ SL_REQUIRE (sl_save_uids() == SL_ENONE, _("sl_save_uids() == SL_ENONE"));
+
+#ifndef SH_ALLOW_SUID
+ if (euid != ruid || egid != rgid)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ struct passwd pwd;
+ char * buffer;
+ struct passwd * tempres;
+ buffer = calloc(1,SH_PWBUF_SIZE);
+ SL_REQUIRE (buffer != NULL, _("buffer != NULL"));
+ sh_getpwnam_r(user, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
+#else
+ struct passwd * tempres = sh_getpwnam(user);
+#endif
+
+ SL_REQUIRE (NULL != tempres, _("tempres != NULL"));
+
+ SL_REQUIRE (sl_drop_privileges() == SL_ENONE,
+ _("sl_drop_privileges() == SL_ENONE"));
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ free(buffer);
+#endif
+ }
+#endif
+ SL_IRETURN(SL_ENONE, _("sl_policy_get_user"));
+}
+
+
+
+/* ----------------------------------------------------------------
+ *
+ * File access routines
+ *
+ * ---------------------------------------------------------------- */
+
+#define TOFFSET 0x1234
+
+/* this would prevent opening files if the first 16 fds are open :( */
+/* #define MAXFD FOPEN_MAX */
+
+#define MAXFD 1024
+
+typedef struct openfiles {
+ SL_TICKET ticket; /* The unique ID. */
+ int fd; /* The file descriptor. */
+ FILE * stream; /* The file descriptor. */
+ char * path; /* The file path. */
+ int flush; /* Whether we want to flush the cache */
+ char ofile[SL_OFILE_SIZE]; /* origin file */
+ int oline; /* origin line */
+ sh_string * content; /* The file content */
+} SL_OFILE;
+
+static SL_OFILE * ofiles[MAXFD];
+
+static char stale_orig_file[64] = { '\0' };
+static int stale_orig_line = -1;
+static char stale_orig_mesg[128];
+
+static char badfd_orig_file[64] = { '\0' };
+static int badfd_orig_line = -1;
+static char badfd_orig_mesg[128];
+
+
+char * sl_check_stale()
+{
+ if (stale_orig_line == -1)
+ return NULL;
+ sl_snprintf(stale_orig_mesg, sizeof(stale_orig_mesg),
+ _("stale handle, %s, %d"), stale_orig_file, stale_orig_line);
+ stale_orig_file[0] = '\0';
+ stale_orig_line = -1;
+ return stale_orig_mesg;
+}
+
+char * sl_check_badfd()
+{
+ if (badfd_orig_line == -1)
+ return NULL;
+ sl_snprintf(badfd_orig_mesg, sizeof(badfd_orig_mesg),
+ _("close on file descriptor with allocated handle, %s, %d"),
+ badfd_orig_file, badfd_orig_line);
+ badfd_orig_file[0] = '\0';
+ badfd_orig_line = -1;
+ return badfd_orig_mesg;
+}
+
+typedef struct { volatile unsigned int atom; } atomic_t;
+static atomic_t nonce_counter = { TOFFSET };
+
+#if defined(__GNUC__) && (defined(__i486__) || defined(__x86_64__))
+/* from linux/include/asm-i386/atomic.h */
+static unsigned int atomic_add ( unsigned int i, atomic_t *var)
+{
+ unsigned int j = i;
+
+ __asm__ __volatile__ ("lock; xaddl %0, %1"
+ : "+r" (i), "+m" (var->atom)
+ : : "memory");
+ return j+i;
+}
+#else
+SH_MUTEX_STATIC(mutex_ticket, PTHREAD_MUTEX_INITIALIZER);
+
+static unsigned int atomic_add ( unsigned int i, atomic_t *var)
+{
+ volatile unsigned int j;
+
+ SH_MUTEX_LOCK_UNSAFE(mutex_ticket);
+ var->atom += i;
+ j = var->atom;
+ SH_MUTEX_UNLOCK_UNSAFE(mutex_ticket);
+
+ return j;
+}
+#endif
+
+static
+SL_TICKET sl_create_ticket (unsigned int myindex)
+{
+ unsigned int high; /* index */
+ unsigned int low; /* nonce */
+ SL_TICKET retval = SL_EINTERNAL;
+ unsigned int nonce;/* nonce */
+
+ SL_ENTER(_("sl_create_ticket"));
+
+ if (myindex >= MAXFD)
+ {
+ retval = SL_EINTERNAL01;
+ goto out_ticket;
+ }
+
+ /* mask out the high bit and check that it is not used
+ * -> verify that it fits into 16 bits as positive
+ */
+ high = (myindex + TOFFSET) & 0x7fff;
+
+ if (high != myindex + TOFFSET)
+ {
+ retval = SL_EINTERNAL02;
+ goto out_ticket;
+ }
+
+ nonce = atomic_add(1, &nonce_counter);
+
+ /* Wrap around the nonce counter.
+ * This is a dirty trick.
+ */
+ if (nonce > 0x7fff)
+ {
+ nonce_counter.atom = TOFFSET;
+ nonce = atomic_add(1, &nonce_counter);
+ }
+
+ low = nonce & 0xffff;
+
+ /* Overflow -> nonce too big.
+ */
+ if ((low != nonce) || low == 0)
+ {
+ retval = SL_EINTERNAL03;
+ goto out_ticket;
+ }
+
+ retval = (SL_TICKET) ((high << 16) | low);
+
+ out_ticket:
+ SL_RETURN (retval, _("sl_create_ticket"));
+}
+
+static
+int sl_read_ticket (SL_TICKET fno)
+{
+ register unsigned myindex;
+ register SL_OFILE *of;
+
+ myindex = ((fno >> 16) & 0xffff) - TOFFSET;
+ if (myindex >= MAXFD)
+ return (SL_ETICKET);
+
+ if (ofiles[myindex] == NULL)
+ return (SL_ETICKET);
+
+ if (ofiles[myindex]->ticket != fno)
+ return (SL_ETICKET);
+
+ if ((of = ofiles[myindex])->fd < 0 || of->fd >= MAXFD )
+ return (SL_EINTERNAL04);
+
+ if (((of->ticket) & 0xffff) == 0)
+ return (SL_EINTERNAL05);
+
+ return (myindex);
+}
+
+SL_TICKET sl_make_ticket (const char * ofile, int oline,
+ int fd, const char * filename, FILE * stream)
+{
+ size_t len;
+ SL_TICKET ticket;
+ SL_ENTER(_("sl_make_ticket"));
+ /* Make entry.
+ */
+ /* cppcheck-suppress arrayIndexOutOfBoundsCond */
+ if (fd >= MAXFD || fd < 0)
+ {
+ SL_IRETURN(SL_TOOMANY, _("sl_make_ticket"));
+ }
+
+ if (ofiles[fd] != NULL) /* stale entry */
+ {
+ /* SL_IRETURN(SL_EINTERNAL06, _("sl_make_ticket")); */
+ sl_strlcpy(stale_orig_file, ofiles[fd]->ofile, sizeof(stale_orig_file));
+ stale_orig_line = ofiles[fd]->oline;
+
+ if (ofiles[fd]->content)
+ sh_string_destroy(&(ofiles[fd]->content));
+ (void) free (ofiles[fd]->path);
+ (void) free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ }
+
+ if ( (ofiles[fd] = calloc(1,sizeof(SL_OFILE))) == NULL)
+ {
+ SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
+ }
+
+ len = sl_strlen(filename)+1;
+
+ if ( (ofiles[fd]->path = calloc(1,len) ) == NULL)
+ {
+ free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ SL_IRETURN(SL_EMEM, _("sl_make_ticket"));
+ }
+
+ /* Get a ticket.
+ */
+ ticket = sl_create_ticket((unsigned int)fd);
+
+ if (SL_ISERROR(ticket))
+ {
+ (void) free (ofiles[fd]->path);
+ (void) free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ SL_IRETURN(ticket, _("sl_make_ticket"));
+ }
+
+ sl_strlcpy (ofiles[fd]->path, filename, len);
+ ofiles[fd]->ticket = ticket;
+ ofiles[fd]->fd = fd;
+ ofiles[fd]->content = NULL;
+ ofiles[fd]->stream = stream;
+ ofiles[fd]->flush = S_FALSE;
+
+ sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE);
+ ofiles[fd]->oline = oline;
+
+ SL_IRETURN(ticket, _("sl_make_ticket"));
+}
+
+#define SL_OPEN_MIN 113
+#define SL_OPEN_FOR_READ 113
+#define SL_OPEN_FOR_WRITE 114
+#define SL_OPEN_FOR_RDWR 115
+#define SL_OPEN_FOR_WTRUNC 116
+#define SL_OPEN_FOR_RWTRUNC 117
+#define SL_OPEN_SAFE_RDWR 118
+#define SL_OPEN_FOR_FASTREAD 119
+#define SL_OPEN_MAX 119
+
+#if !defined(O_NOATIME)
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__PPC__))
+#define O_NOATIME 01000000
+#else
+ /*
+ * bitwise 'or' with zero does not modify any bit
+ */
+#define O_NOATIME 0
+#endif
+#endif
+
+static int o_noatime = O_NOATIME;
+static mode_t open_mode = (S_IWUSR|S_IRUSR|S_IRGRP);
+
+
+static
+int sl_open_file (const char * ofile, int oline,
+ const char *filename, int mode, int priv)
+{
+ struct stat lbuf;
+ struct stat buf;
+ int errval = 0;
+ int lstat_return;
+ int stat_return;
+ int fd;
+ int sflags;
+ size_t len;
+ SL_TICKET ticket;
+
+#if !defined(O_NONBLOCK)
+#if defined(O_NDELAY)
+#define O_NONBLOCK O_NDELAY
+#else
+#define O_NONBLOCK 0
+#endif
+#endif
+
+ SL_ENTER(_("sl_open_file"));
+
+ if (filename == NULL)
+ SL_IRETURN(SL_ENULL, _("sl_open_file"));
+ if (mode < SL_OPEN_MIN || mode > SL_OPEN_MAX)
+ SL_IRETURN(SL_EINTERNAL07, _("sl_open_file"));
+
+ /* "This system call always succeeds and the previous value of
+ * the mask is returned."
+ */
+ (void) umask (0);
+
+ if (mode == SL_OPEN_FOR_FASTREAD)
+ {
+ fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
+ O_RDONLY|O_NONBLOCK, 0, &o_noatime);
+ /*
+ if (fd >= 0) {
+ sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
+ }
+ */
+ if (fd < 0)
+ SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
+ goto createTicket;
+ }
+
+#ifdef USE_SUID
+ if (priv == SL_YESPRIV)
+ sl_set_suid();
+#endif
+ if (mode == SL_OPEN_FOR_READ)
+ lstat_return = retry_stat (FIL__, __LINE__, filename, &lbuf);
+ else
+ lstat_return = retry_lstat(FIL__, __LINE__, filename, &lbuf);
+ errval = errno;
+#ifdef USE_SUID
+ if (priv == SL_YESPRIV)
+ sl_unset_suid();
+#endif
+
+ if (lstat_return == -1)
+ {
+ lstat_return = ENOENT;
+ if ( (mode == SL_OPEN_FOR_READ && lstat_return == ENOENT) ||
+ (errval != ENOENT))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<lstat: %s> errno=<%d>\n"),
+ filename, errval));
+ errno = errval;
+ SL_IRETURN(SL_ESTAT, _("sl_open_file"));
+ }
+ }
+
+ if ( (mode != SL_OPEN_FOR_READ) && (lstat_return != ENOENT) &&
+ ( S_ISDIR(lbuf.st_mode) || (S_IWOTH & lbuf.st_mode) )
+ )
+ {
+ int retval = S_ISDIR(lbuf.st_mode) ? SL_EISDIR : SL_EBADOTH;
+ errno = 0;
+ SL_IRETURN(retval, _("sl_open_file"));
+ }
+
+ /* O_NOATIME has an effect for read(). But write() ?.
+ */
+ switch (mode)
+ {
+ case SL_OPEN_FOR_READ:
+ fd = aud_open_noatime (FIL__, __LINE__, priv, filename,
+ O_RDONLY|O_NONBLOCK, 0, &o_noatime);
+ errval = errno;
+ if (fd >= 0) {
+ sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags & ~O_NONBLOCK);
+ }
+ break;
+ case SL_OPEN_FOR_WRITE:
+ if (lstat_return == ENOENT)
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_WRONLY|O_CREAT|O_EXCL, open_mode);
+ else
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_WRONLY, open_mode);
+ errval = errno;
+ break;
+ case SL_OPEN_SAFE_RDWR:
+ if (lstat_return == ENOENT)
+ {
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_RDWR|O_CREAT|O_EXCL, open_mode);
+ errval = errno;
+ }
+ else
+ {
+ errno = errval;
+ SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
+ }
+ break;
+ case SL_OPEN_FOR_RDWR:
+ if (lstat_return == ENOENT)
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_RDWR|O_CREAT|O_EXCL, open_mode);
+ else
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_RDWR, open_mode);
+ errval = errno;
+ break;
+ case SL_OPEN_FOR_WTRUNC:
+ if (lstat_return == ENOENT)
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_WRONLY|O_CREAT|O_EXCL, open_mode);
+ else
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_WRONLY|O_TRUNC, open_mode);
+ errval = errno;
+ break;
+ case SL_OPEN_FOR_RWTRUNC:
+ if (lstat_return == ENOENT)
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_RDWR|O_CREAT|O_EXCL, open_mode);
+ else
+ fd = aud_open (FIL__, __LINE__, priv, filename,
+ O_RDWR|O_TRUNC, open_mode);
+ errval = errno;
+ break;
+ default:
+ errno = 0;
+ SL_IRETURN(SL_EINTERNAL08, _("sl_open_file"));
+ }
+
+ if (fd < 0)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s> errno=<%d>\n"),
+ filename, errval));
+ errno = errval;
+ SL_IRETURN(SL_EBADFILE, _("sl_open_file"));
+ }
+
+#ifdef USE_SUID
+ if (priv == SL_YESPRIV)
+ sl_set_suid();
+#endif
+ stat_return = retry_fstat(FIL__, __LINE__, fd, &buf);
+ errval = errno;
+#ifdef USE_SUID
+ if (priv == SL_YESPRIV)
+ sl_unset_suid();
+#endif
+
+ if (stat_return < 0)
+ {
+ sl_close_fd (FIL__, __LINE__, fd);
+ errno = errval;
+ SL_IRETURN(SL_EFSTAT, _("sl_open_file"));
+ }
+
+ errno = 0;
+
+ if (lstat_return != ENOENT && buf.st_ino != lbuf.st_ino)
+ {
+ sl_close_fd (FIL__, __LINE__, fd);
+ SL_IRETURN(SL_EBOGUS, _("sl_open_file"));
+ }
+
+ createTicket:
+
+ /* Make entry.
+ */
+ /* cppcheck-suppress arrayIndexOutOfBoundsCond */
+ if (fd >= MAXFD)
+ {
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_IRETURN(SL_TOOMANY, _("sl_open_file"));
+ }
+
+ if (ofiles[fd] != NULL) /* stale entry */
+ {
+ /*
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_IRETURN(SL_EINTERNAL09, _("sl_open_file"));
+ */
+ sl_strlcpy(stale_orig_file, ofiles[fd]->ofile, sizeof(stale_orig_file));
+ stale_orig_line = ofiles[fd]->oline;
+
+ if (ofiles[fd]->content)
+ sh_string_destroy(&(ofiles[fd]->content));
+ (void) free (ofiles[fd]->path);
+ (void) free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ }
+
+ if ( (ofiles[fd] = calloc(1,sizeof(SL_OFILE))) == NULL)
+ {
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_IRETURN(SL_EMEM, _("sl_open_file"));
+ }
+
+ len = sl_strlen(filename)+1;
+
+ if ( (ofiles[fd]->path = calloc(1,len) ) == NULL)
+ {
+ free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_IRETURN(SL_EMEM, _("sl_open_file"));
+ }
+
+ /* Get a ticket.
+ */
+ ticket = sl_create_ticket(fd);
+
+ if (SL_ISERROR(ticket))
+ {
+ (void) free (ofiles[fd]->path);
+ (void) free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ sl_close_fd(FIL__, __LINE__, fd);
+ SL_IRETURN(ticket, _("sl_open_file"));
+ }
+
+ sl_strlcpy (ofiles[fd]->path, filename, len);
+ ofiles[fd]->ticket = ticket;
+ ofiles[fd]->fd = fd;
+ ofiles[fd]->content = NULL;
+ ofiles[fd]->stream = NULL;
+ ofiles[fd]->flush = S_FALSE;
+
+ sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE);
+ ofiles[fd]->oline = oline;
+
+ SL_IRETURN(ticket, _("sl_open_file"));
+}
+
+FILE * sl_stream (SL_TICKET ticket, char * mode)
+{
+ int fd;
+
+ if (SL_ISERROR(fd = sl_read_ticket(ticket)))
+ return (NULL);
+
+ if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
+ ticket != ofiles[fd]->ticket || fd < 0)
+ return (NULL);
+
+ if (!ofiles[fd]->stream)
+ ofiles[fd]->stream = fdopen(fd, mode);
+
+ return ofiles[fd]->stream;
+}
+
+int get_the_fd (SL_TICKET ticket)
+{
+ int fd;
+
+ if (SL_ISERROR(fd = sl_read_ticket(ticket)))
+ return (fd);
+
+ if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
+ ticket != ofiles[fd]->ticket || fd < 0)
+ return (SL_EINTERNAL10);
+
+ return (fd);
+}
+
+static
+int check_fname_priv (const char * fname, int priv)
+{
+ SL_ENTER(_("check_fname_priv"));
+ if (fname == NULL)
+ SL_IRETURN(SL_ENULL, _("check_fname_priv"));
+ if (priv != SL_YESPRIV && priv != SL_NOPRIV)
+ SL_IRETURN(SL_EINTERNAL11, _("check_fname_priv"));
+ SL_IRETURN(SL_ENONE, _("check_fname_priv"));
+}
+
+SL_TICKET sl_open_write (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_write"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ SL_IRETURN(status, _("sl_open_write"));
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_WRITE, priv);
+ SL_IRETURN(status, _("sl_open_write"));
+}
+
+SL_TICKET sl_open_read (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_read"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ {
+ TPT(( 0, FIL__, __LINE__,
+ _("msg=<Error in check_fname_priv.> status=<%ld>\n"),
+ status));
+ SL_IRETURN(status, _("sl_open_read"));
+ }
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_READ, priv);
+ SL_IRETURN(status, _("sl_open_read"));
+}
+
+#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
+static int sl_check_mincore(int fd)
+{
+ /* Idea from Tobias Oetiker (http://insights.oetiker.ch/linux/fadvise.html)
+ */
+ struct stat fbuf;
+ int retval = -1;
+
+ if (0 == fstat(fd, &fbuf))
+ {
+ void *f_map;
+
+ f_map = mmap((void *)0, fbuf.st_size, PROT_NONE, MAP_SHARED, fd, 0);
+ if (MAP_FAILED != f_map)
+ {
+ extern int sh_unix_pagesize(void);
+ size_t i;
+ size_t page_size = sh_unix_pagesize();
+ size_t vec_size = (fbuf.st_size+page_size-1)/page_size;
+ unsigned char * vec = calloc(1, vec_size);
+
+ if (vec)
+ {
+ mincore(f_map, fbuf.st_size, vec);
+ /* imax = fbuf.st_size/page_size; */
+ for (i = 0; i <= vec_size; ++i)
+ {
+ if (vec[i]&1)
+ {
+ goto incore;
+ }
+ }
+ retval = 0;
+ incore:
+ free(vec);
+ }
+ munmap(f_map, fbuf.st_size);
+ }
+ }
+ return retval;
+}
+#endif
+
+static int sl_drop_cache = S_FALSE;
+
+int sl_set_drop_cache(const char * str)
+{
+ extern int sh_util_flagval(const char * c, int * fval);
+ return sh_util_flagval(str, &sl_drop_cache);
+}
+
+SL_TICKET sl_open_fastread (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_fastread"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ SL_IRETURN(status, _("sl_open_read"));
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_FASTREAD, priv);
+
+#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
+
+ if (S_FALSE != sl_drop_cache && !SL_ISERROR(status))
+ {
+ int fd = get_the_fd(status);
+ if (fd >= 0)
+ {
+ if (0 == sl_check_mincore(fd))
+ ofiles[fd]->flush = S_TRUE;
+ }
+ }
+
+#endif
+
+ SL_IRETURN(status, _("sl_open_fastread"));
+}
+
+SL_TICKET sl_open_rdwr (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_rdwr"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ SL_IRETURN(status, _("sl_open_rdwr"));
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_RDWR, priv);
+ SL_IRETURN(status, _("sl_open_rdwr"));
+}
+
+SL_TICKET sl_open_safe_rdwr (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_safe_rdwr"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ SL_IRETURN(status, _("sl_open_safe_rdwr"));
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_SAFE_RDWR, priv);
+ SL_IRETURN(status, _("sl_open_safe_rdwr"));
+}
+
+SL_TICKET sl_open_write_trunc (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_write_trunc"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ SL_IRETURN(status, _("sl_open_write_trunc"));
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_WTRUNC, priv);
+ SL_IRETURN(status, _("sl_open_write_trunc"));
+}
+
+SL_TICKET sl_open_rdwr_trunc (const char * ofile, int oline,
+ const char * fname, int priv)
+{
+ long status;
+ SL_ENTER(_("sl_open_rdwr_trunc"));
+
+ if (SL_ENONE != (status = check_fname_priv (fname, priv)))
+ SL_IRETURN(status, _("sl_open_rdwr_trunc"));
+
+ status = sl_open_file(ofile, oline, fname, SL_OPEN_FOR_RWTRUNC, priv);
+ SL_IRETURN(status, _("sl_open_rdwr_trunc"));
+}
+
+
+int sl_init_content (SL_TICKET ticket, size_t size)
+{
+ int fd;
+
+ if (SL_ISERROR(fd = sl_read_ticket(ticket)))
+ return (fd);
+
+ if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
+ ticket != ofiles[fd]->ticket || fd < 0)
+ return (SL_EINTERNAL12);
+
+ if (ofiles[fd]->content)
+ sh_string_destroy(&(ofiles[fd]->content));
+ ofiles[fd]->content = sh_string_new(size);
+
+ return SL_ENONE;
+}
+
+sh_string * sl_get_content (SL_TICKET ticket)
+{
+ int fd;
+
+ if (SL_ISERROR(fd = sl_read_ticket(ticket)))
+ return (NULL);
+
+ if (ofiles[fd] == NULL || fd != ofiles[fd]->fd ||
+ ticket != ofiles[fd]->ticket || fd < 0)
+ return (NULL);
+
+ return (ofiles[fd]->content);
+}
+
+int sl_lock (SL_TICKET ticket)
+{
+ int fd;
+ struct flock lock;
+ int retval;
+
+ SL_ENTER(_("sl_lock"));
+
+ if (SL_ISERROR(fd = get_the_fd (ticket)))
+ SL_IRETURN(fd, _("sl_lock"));
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+
+ /* F_SETLK returns if the lock cannot be obtained */
+ do {
+ retval = fcntl(fd, F_SETLK, &lock);
+ } while (retval < 0 && errno == EINTR);
+
+ if (retval < 0 && errno == EBADF)
+ SL_IRETURN(SL_ETICKET, _("sl_lock"));
+ else if (retval < 0)
+ SL_IRETURN(SL_EBADFILE, _("sl_lock"));
+ else
+ SL_IRETURN(SL_ENONE, _("sl_lock"));
+ }
+
+int sl_close (SL_TICKET ticket)
+{
+ register int fd;
+ FILE * fp = NULL;
+
+ SL_ENTER(_("sl_close"));
+
+ if (SL_ISERROR(fd = get_the_fd (ticket)))
+ SL_IRETURN(fd, _("sl_close"));
+
+ if (ofiles[fd] != NULL)
+ {
+#if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) && defined(POSIX_FADV_DONTNEED)
+ if (ofiles[fd]->flush == S_TRUE)
+ {
+ posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
+ }
+#endif
+ if (ofiles[fd]->content)
+ sh_string_destroy(&(ofiles[fd]->content));
+ (void) free (ofiles[fd]->path);
+ fp = ofiles[fd]->stream;
+ (void) free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ }
+
+ /* This may fail, but what to do then ?
+ */
+ if (fp)
+ {
+ if (0 != fclose (fp)) /* within sl_close */
+ {
+ TPT((0, FIL__, __LINE__,
+ _("msg=<Error fclosing file.>, fd=<%d>, err=<%s>\n"),
+ fd, strerror(errno)));
+ }
+ }
+ else
+ {
+ if (0 != close(fd)) /* within sl_close */
+ {
+ TPT((0, FIL__, __LINE__,
+ _("msg=<Error closing file.>, fd=<%d>, err=<%s>\n"),
+ fd, strerror(errno)));
+ }
+ }
+
+ SL_IRETURN(SL_ENONE, _("sl_close"));
+}
+
+int sl_close_fd (const char * file, int line, int fd)
+{
+ int ret = -1;
+
+ SL_ENTER(_("sl_close_fd"));
+
+ if (fd >= 0 && fd < MAXFD && ofiles[fd] != NULL) /* stale ofiles[fd] handle */
+ {
+ sl_strlcpy(badfd_orig_file, file, sizeof(badfd_orig_file));
+ badfd_orig_line = line;
+ }
+
+ ret = close(fd); /* within sl_close_fd wrapper */
+
+ SL_IRETURN(ret, _("sl_close_fd"));
+}
+
+int sl_fclose (const char * file, int line, FILE * fp)
+{
+ int ret = -1;
+ int fd;
+
+ SL_ENTER(_("sl_fclose"));
+
+ fd = fileno(fp);
+
+ if (fd >= 0 && fd < MAXFD && ofiles[fd] != NULL) /* stale ofiles[fd] handle */
+ {
+ sl_strlcpy(badfd_orig_file, file, sizeof(badfd_orig_file));
+ badfd_orig_line = line;
+ }
+
+ ret = fclose(fp); /* within sl_fclose wrapper */
+
+ SL_IRETURN(ret, _("sl_fclose"));
+}
+
+int sl_dropall(int fd, int except)
+{
+ while (fd < MAXFD)
+ {
+ if (ofiles[fd] != NULL && fd != except)
+ {
+ if (ofiles[fd]->content)
+ sh_string_destroy(&(ofiles[fd]->content));
+ if (ofiles[fd]->path != NULL)
+ (void) free (ofiles[fd]->path);
+ (void) free (ofiles[fd]);
+ ofiles[fd] = NULL;
+ }
+ ++fd;
+ }
+ return 0;
+}
+
+int sl_dropall_dirty(int fd, int except)
+{
+ while (fd < MAXFD)
+ {
+ if (ofiles[fd] != NULL && fd != except)
+ {
+ ofiles[fd] = NULL;
+ }
+ ++fd;
+ }
+ return 0;
+}
+
+
+int sl_unlink (SL_TICKET ticket)
+{
+ register int fd;
+
+ SL_ENTER(_("sl_unlink"));
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ SL_IRETURN(fd, _("sl_unlink"));
+
+ if (retry_aud_unlink(FIL__, __LINE__, ofiles[fd]->path) < 0)
+ SL_IRETURN(SL_EUNLINK, _("sl_unlink"));
+
+ SL_IRETURN(SL_ENONE, _("sl_unlink"));
+}
+
+
+int sl_seek (SL_TICKET ticket, off_t off_data)
+{
+ register int fd;
+
+ SL_ENTER(_("sl_seek"));
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ SL_IRETURN(fd, _("sl_seek"));
+
+ if (lseek(fd, off_data, SEEK_SET) == (off_t)-1)
+ SL_IRETURN(SL_EREWIND, _("sl_seek"));
+
+ SL_IRETURN(SL_ENONE, _("sl_seek"));
+}
+
+int sl_rewind (SL_TICKET ticket)
+{
+ register int fd;
+
+ SL_ENTER(_("sl_rewind"));
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ SL_IRETURN(fd, _("sl_rewind"));
+
+ if (lseek (fd, 0L, SEEK_SET) == (off_t)-1)
+ SL_IRETURN(SL_EREWIND, _("sl_rewind"));
+
+ SL_IRETURN(SL_ENONE, _("sl_rewind"));
+}
+
+int sl_forward (SL_TICKET ticket)
+{
+ register int fd;
+
+ SL_ENTER(_("sl_forward"));
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ SL_IRETURN(fd, _("sl_forward"));
+
+ if (lseek (fd, 0L, SEEK_END) == (off_t)-1)
+ SL_IRETURN(SL_EFORWARD, _("sl_forward"));
+
+ SL_IRETURN(SL_ENONE, _("sl_forward"));
+}
+
+
+int sl_sync (SL_TICKET ticket)
+{
+ register int fd;
+
+ SL_ENTER(_("sl_sync"));
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ SL_IRETURN(fd, _("sl_sync"));
+
+ if (fsync (fd) == -1)
+ SL_IRETURN(SL_ESYNC, _("sl_sync"));
+
+ SL_IRETURN(SL_ENONE, _("sl_sync"));
+}
+
+int sl_read_timeout_prep (SL_TICKET ticket)
+{
+ int fd;
+ int sflags;
+
+ SL_ENTER(_("sl_read_timeout_prep"));
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
+ SL_IRETURN(fd, _("sl_read_timeout_prep"));
+ }
+
+ /* set to non-blocking mode
+ */
+ sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
+
+ SL_IRETURN(SL_ENONE, _("sl_read_timeout_prep"));
+}
+
+
+int sl_read_timeout_fd (int fd, void * buf_in, size_t count,
+ int timeout, int is_nonblocking)
+{
+ int sflags = 0;
+ fd_set readfds;
+ struct timeval tv;
+ /* int sflags; */
+ int retval;
+ int error;
+
+ int byteread = 0;
+ int bytes = 0;
+ char * buf;
+
+ time_t tnow;
+ time_t tstart;
+ time_t tdiff;
+ extern volatile int sig_termfast;
+
+ if (is_nonblocking == S_FALSE)
+ {
+ /* set to non-blocking mode
+ */
+ sflags = retry_fcntl(FIL__, __LINE__, fd, F_GETFL, 0);
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags | O_NONBLOCK);
+ }
+
+ buf = (char *) buf_in;
+
+ tstart = time(NULL);
+ tdiff = 0;
+
+ while (count > 0)
+ {
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ tv.tv_sec = timeout - tdiff;
+ tv.tv_usec = 0;
+
+ retval = select (fd+1, &readfds, NULL, NULL, &tv);
+
+ if (retval > 0)
+ {
+ byteread = read (fd, buf, count);
+
+ if (byteread > 0)
+ {
+ bytes += byteread; count -= byteread;
+ buf += byteread;
+ if (count == 0)
+ break;
+ }
+ else if (byteread == 0)
+ {
+ /* zero indicates end of file */
+ break;
+ }
+ else
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ {
+ retry_msleep(1, 0);
+ tnow = time(NULL);
+ tdiff = tnow - tstart;
+ continue;
+ }
+ else
+ {
+ error = errno;
+ if (is_nonblocking == S_FALSE)
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
+ TPT(( 0, FIL__, __LINE__, _("msg=<read error>")));
+ errno = error;
+ return (SL_EREAD);
+ }
+ }
+ }
+ else if ((retval == -1) && (errno == EINTR || errno == EAGAIN))
+ {
+ retry_msleep(1, 0);
+ tnow = time(NULL);
+ tdiff = tnow - tstart;
+ continue;
+ }
+ else if (retval == 0)
+ {
+ if (is_nonblocking == S_FALSE)
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
+ TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
+ errno = 0;
+ if (bytes > 0)
+ return ((int) bytes);
+ return (SL_TIMEOUT);
+ }
+ else
+ {
+ error = errno;
+ if (is_nonblocking == S_FALSE)
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
+ TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
+ errno = error;
+ return (SL_EREAD);
+ }
+
+ if (sig_termfast == 1)
+ {
+ if (is_nonblocking == S_FALSE)
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
+ TPT(( 0, FIL__, __LINE__, _("msg=<terminated>")));
+ errno = 0;
+ return (SL_EREAD);
+ }
+
+ tnow = time(NULL);
+ tdiff = tnow - tstart;
+
+ if (tdiff > timeout)
+ {
+ if (is_nonblocking == S_FALSE)
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
+ TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
+ errno = 0;
+ if (bytes > 0)
+ return ((int) bytes);
+ return (SL_TIMEOUT);
+ }
+ }
+
+ if (is_nonblocking == S_FALSE)
+ retry_fcntl(FIL__, __LINE__, fd, F_SETFL, sflags);
+ return ((int) bytes);
+}
+
+int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count,
+ int timeout, int is_nonblocking)
+{
+ int fd, retval;
+
+ SL_ENTER(_("sl_read_timeout"));
+
+ if (buf_in == NULL || SL_ISERROR(fd = get_the_fd(ticket)))
+ {
+ if (buf_in == NULL)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
+ SL_IRETURN((SL_ENULL), _("sl_read_timeout"));
+ }
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
+ SL_IRETURN((fd), _("sl_read_timeout"));
+ }
+ }
+
+ retval = sl_read_timeout_fd (fd, buf_in, count, timeout, is_nonblocking);
+ SL_IRETURN((retval), _("sl_read_timeout"));
+}
+
+
+int sl_read (SL_TICKET ticket, void * buf_in, size_t count)
+{
+ int fd;
+ int byteread = 0;
+ int bytes = 0;
+
+ char * buf;
+
+ SL_ENTER(_("sl_read"));
+
+ if (count < 1)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
+ SL_IRETURN((SL_ERANGE), _("sl_read"));
+ }
+ if (buf_in == NULL)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
+ SL_IRETURN((SL_ENULL), _("sl_read"));
+ }
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
+ SL_IRETURN((fd), _("sl_read"));
+ }
+
+ buf = (char *) buf_in;
+
+ do
+ {
+ byteread = read (fd, buf, count);
+ if (byteread > 0)
+ {
+ bytes += byteread; count -= byteread;
+ buf += byteread;
+ }
+ } while ( byteread > 0 ||
+ ( byteread == -1 && (errno == EINTR || errno == EAGAIN))
+ );
+
+
+ if (byteread == (-1))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
+ SL_IRETURN((SL_EREAD), _("sl_read"));
+ }
+ SL_IRETURN((bytes), _("sl_read"));
+}
+
+int sl_read_fast (SL_TICKET ticket, void * buf_in, size_t count)
+{
+ int fd;
+ int byteread = 0;
+
+ char * buf;
+
+ SL_ENTER(_("sl_read_fast"));
+
+ if (count < 1)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<range error>")));
+ SL_IRETURN((SL_ERANGE), _("sl_read_fast"));
+ }
+ if (buf_in == NULL)
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<null buffer>")));
+ SL_IRETURN((SL_ENULL), _("sl_read_fast"));
+ }
+
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<ticket error> errno=<%d>"), fd));
+ SL_IRETURN((fd), _("sl_read_fast"));
+ }
+
+ buf = (char *) buf_in;
+
+ do
+ {
+ byteread = read (fd, buf, count);
+ if (byteread >= 0)
+ {
+ SL_IRETURN((byteread), _("sl_read_fast"));
+ }
+ } while ( byteread == -1 && (errno == EINTR || errno == EAGAIN));
+
+
+ if (byteread == (-1))
+ {
+ TPT(( 0, FIL__, __LINE__, _("msg=<read error> errno=<%d>\n"), errno));
+ SL_IRETURN((SL_EREAD), _("sl_read_fast"));
+ }
+ SL_IRETURN((0), _("sl_read_fast"));
+}
+
+
+int sl_write (SL_TICKET ticket, const void * msg_in, long nbytes)
+{
+ long bytewritten;
+ long bytecount;
+ int fd;
+
+ const char * msg;
+
+ SL_ENTER(_("sl_write"));
+
+ if (nbytes < 1)
+ SL_IRETURN(SL_ERANGE, _("sl_write"));
+ if (msg_in == NULL)
+ SL_IRETURN(SL_ENULL, _("sl_write"));
+ if (SL_ISERROR(fd = get_the_fd(ticket)))
+ SL_IRETURN(fd, _("sl_write"));
+
+ msg = (const char *) msg_in;
+
+ /* write
+ */
+ bytecount = 0;
+
+ while (bytecount < nbytes)
+ {
+ bytewritten = write (fd, msg, nbytes-bytecount);
+
+ if (bytewritten > 0)
+ {
+ bytecount += bytewritten;
+ msg += bytewritten; /* move buffer pointer forward */
+ }
+ else if (bytewritten <= 0)
+ {
+ if ( errno == EINTR || errno == EAGAIN) /* try again */
+ continue;
+ else
+ SL_IRETURN(SL_EWRITE, _("sl_write"));
+ }
+ }
+ SL_IRETURN(SL_ENONE, _("sl_write"));
+}
+
+int sl_write_line (SL_TICKET ticket, const void * msg, long nbytes)
+{
+ int status;
+
+ SL_ENTER(_("sl_write_line"));
+
+ status = sl_write(ticket, msg, nbytes);
+ if (!SL_ISERROR(status))
+ status = sl_write(ticket, "\n", 1);
+
+ SL_IRETURN(status, _("sl_write_line"));
+}
+
+int sl_write_line_fast (SL_TICKET ticket, void * msg, long nbytes)
+{
+ int status;
+ char * p = (char *) msg;
+
+ SL_ENTER(_("sl_write_line_fast"));
+
+ /* Here nbytes is strlen(msg), so p[nbytes] is the terminating '\0'
+ * Overwrite the terminator, write out, then write back the terminator.
+ */
+ p[nbytes] = '\n';
+ status = sl_write(ticket, msg, nbytes+1);
+ p[nbytes] = '\0';
+
+ SL_IRETURN(status, _("sl_write_line_fast"));
+}
+
+
+/* ----------------------------------------------------------------
+ *
+ * Trustfile interface
+ *
+ * ---------------------------------------------------------------- */
+
+extern uid_t rootonly[];
+extern unsigned int EUIDSLOT;
+extern unsigned int ORIG_EUIDSLOT;
+
+extern char tf_path[MAXFILENAME]; /* Error path for trust function. */
+extern uid_t tf_euid; /* Space for EUID of process. */
+
+char * sl_error_string(int errorcode)
+{
+
+ switch (errorcode)
+ {
+ case SL_EBOGUS:
+ return _("Bogus file, modified during access");
+ case SL_EWRITE:
+ return _("Write error");
+ case SL_EREAD:
+ return _("Read error");
+ case SL_ESYNC:
+ return _("Error in fsync()");
+ case SL_EFORWARD:
+ return _("Error in lseek()");
+ case SL_EREWIND:
+ return _("Error in lseek()");
+ case SL_EUNLINK:
+ return _("Error in unlink()");
+ case SL_EMEM:
+ return _("Out of memory");
+ case SL_EINTERNAL:
+ return _("Internal error");
+ case SL_EINTERNAL01:
+ return _("Internal error 01");
+ case SL_EINTERNAL02:
+ return _("Internal error 02");
+ case SL_EINTERNAL03:
+ return _("Internal error 03");
+ case SL_EINTERNAL04:
+ return _("Internal error 04");
+ case SL_EINTERNAL05:
+ return _("Internal error 05");
+ case SL_EINTERNAL06:
+ return _("Internal error 06");
+ case SL_EINTERNAL07:
+ return _("Internal error 07");
+ case SL_EINTERNAL08:
+ return _("Internal error 08");
+ case SL_EINTERNAL09:
+ return _("Internal error 09");
+ case SL_EINTERNAL10:
+ return _("Internal error 10");
+ case SL_EINTERNAL11:
+ return _("Internal error 11");
+ case SL_EINTERNAL12:
+ return _("Internal error 12");
+ case SL_ETICKET:
+ return _("Bad ticket");
+ case SL_EREPEAT:
+ return _("Illegal repeated use of function");
+ case SL_ERANGE:
+ return _("Argument out of range");
+ case SL_ENULL:
+ return _("Dereferenced NULL pointer");
+
+ case SL_EBADUID:
+ return _("Owner not trustworthy");
+ case SL_EBADGID:
+ return _("Group writeable and member not trustworthy");
+ case SL_EBADOTH:
+ return _("World writeable");
+ case SL_EISDIR:
+ return _("Is a directory");
+ case SL_EBADFILE:
+ return _("File access error");
+ case SL_EBADNAME:
+ return _("Invalid filename (prob. too long or null)");
+
+ case SL_ETRUNC:
+ return _("Truncation occured");
+ case SL_ESTAT:
+ return _("stat() failed");
+ case SL_EFSTAT:
+ return _("fstat() failed");
+ default:
+ return _("Unknown error");
+ }
+}
+
+
+
+char * sl_trust_errfile(void)
+{
+ return &tf_path[0];
+}
+
+extern uid_t tf_baduid;
+uid_t sl_trust_baduid(void)
+{
+ return tf_baduid;
+}
+
+extern gid_t tf_badgid;
+gid_t sl_trust_badgid(void)
+{
+ return tf_badgid;
+}
+
+
+static int trust_count = 0;
+
+int sl_trust_purge_user (void)
+{
+ unsigned int i;
+
+ EUIDSLOT = ORIG_EUIDSLOT;
+ trust_count = 0;
+
+ for (i = EUIDSLOT; i < (EUIDSLOT + 15); ++i)
+ rootonly[i] = sh_uid_neg;
+ return 0;
+}
+
+int sl_trust_add_user (uid_t pwid)
+{
+ SL_ENTER(_("sl_trust_add_user"));
+
+ if (trust_count == 15)
+ SL_IRETURN(SL_ERANGE, _("sl_trust_add_user"));
+
+ rootonly[EUIDSLOT] = pwid;
+ ++EUIDSLOT;
+ ++trust_count;
+
+ SL_IRETURN(SL_ENONE, _("sl_trust_add_user"));
+}
+
+#include "sh_mem.h"
+extern char * sh_util_strdup (const char * str);
+
+struct sl_trustfile_store {
+ char * filename;
+ uid_t teuid;
+ struct sl_trustfile_store * next;
+};
+
+static struct sl_trustfile_store * sl_trusted_files = NULL;
+
+static void sl_add_trusted_file(const char * filename, uid_t teuid)
+{
+ struct sl_trustfile_store *new = SH_ALLOC(sizeof(struct sl_trustfile_store));
+
+ new->filename = sh_util_strdup (filename);
+ new->teuid = teuid;
+ new->next = sl_trusted_files;
+
+ sl_trusted_files = new;
+ return;
+}
+
+static const char * sl_check_trusted_file(const char * filename, uid_t teuid)
+{
+ struct sl_trustfile_store *new = sl_trusted_files;
+
+ while (new)
+ {
+ if ((new->teuid == teuid) && (0 == strcmp(new->filename, filename)))
+ return filename;
+ new = new->next;
+ }
+
+ return NULL;
+}
+
+static void sl_clear_trusted_file(struct sl_trustfile_store * file)
+{
+ if (file)
+ {
+ if (file->next != NULL)
+ sl_clear_trusted_file(file->next);
+ SH_FREE(file->filename);
+ SH_FREE(file);
+ }
+ return;
+}
+
+int sl_trustfile_euid(const char * filename, uid_t teuid)
+{
+ long status;
+ static size_t old = 0;
+ static size_t now;
+
+ SL_ENTER(_("sl_trustfile_euid"));
+
+ tf_path[0] = '\0';
+ if (filename == NULL || filename[0] == '\0')
+ SL_IRETURN(SL_EBADNAME, _("sl_trustfile_euid"));
+
+ now = time(NULL);
+
+ if (now < (old + 300))
+ {
+ if (NULL != sl_check_trusted_file(filename, teuid))
+ {
+ sl_strlcpy(tf_path, filename, sizeof(tf_path));
+ SL_IRETURN(SL_ENONE, _("sl_trustfile_euid"));
+ }
+ }
+ else
+ {
+ sl_clear_trusted_file(sl_trusted_files);
+ sl_trusted_files = NULL;
+ old = now;
+ }
+
+ tf_euid = teuid;
+ status = sl_trustfile(filename, NULL, NULL);
+ if (status == SL_ENONE)
+ sl_add_trusted_file(filename, teuid);
+ SL_IRETURN(status, _("sl_trustfile_euid"));
+}
+
+/* ----------------------------------------------------------------
+ *
+ * Overflow tests
+ *
+ * ---------------------------------------------------------------- */
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (4294967295U)
+#endif
+
+int sl_ok_muli (int a, int b) /* a*b */
+{
+ if ((b == 0) || (a >= (INT_MIN / b) && a <= (INT_MAX / b)))
+ return S_TRUE; /* no overflow */
+ return S_FALSE;
+}
+
+int sl_ok_muls (size_t a, size_t b) /* a*b */
+{
+ if ((b == 0) || (a <= (SIZE_MAX / b)))
+ return S_TRUE; /* no overflow */
+ return S_FALSE;
+}
+
+int sl_ok_divi (int a, int b) /* a/b */
+{
+ (void) a;
+ if (b != 0)
+ return S_TRUE; /* no overflow */
+ return S_FALSE;
+}
+
+int sl_ok_addi (int a, int b) /* a+b */
+{
+ if (a >= 0 && b >= 0)
+ {
+ if (a <= (INT_MAX - b))
+ return S_TRUE; /* no overflow */
+ else
+ return S_FALSE;
+ }
+ else if (a < 0 && b < 0)
+ {
+ if (a >= (INT_MIN - b))
+ return S_TRUE; /* no overflow */
+ else
+ return S_FALSE;
+ }
+ return S_TRUE;
+}
+
+int sl_ok_adds (size_t a, size_t b) /* a+b */
+{
+ if (a <= (SIZE_MAX - b))
+ return S_TRUE; /* no overflow */
+ else
+ return S_FALSE;
+}
+
+int sl_ok_subi (int a, int b) /* a-b */
+{
+ if (a >= 0 && b < 0)
+ {
+ if (a <= (INT_MAX + b))
+ return S_TRUE; /* no overflow */
+ else
+ return S_FALSE;
+ }
+ else if (a < 0 && b >= 0)
+ {
+ if (a >= (INT_MIN + b))
+ return S_TRUE; /* no overflow */
+ else
+ return S_FALSE;
+ }
+ return S_TRUE;
+}
diff --git a/src/sstrip.c b/src/sstrip.c
new file mode 100644
index 0000000..a296561
--- /dev/null
+++ b/src/sstrip.c
@@ -0,0 +1,538 @@
+/* sstrip, version 2.0: Copyright (C) 1999-2001 by Brian Raiter, under the
+ * GNU General Public License. No warranty. See LICENSE for details.
+ */
+
+/* Modified for portability and 64bit/32bit elf executables, Rainer Wichmann */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#if !defined(__ia64) && !defined(__ia64__) && !defined(__itanium__) && \
+ !defined(__alpha) && !defined(__alpha__) && \
+ (defined(HAVE_ELF_H) || defined(HAVE_LINUX_ELF_H)) && \
+ (defined(__linux__) || defined(__FreeBSD__)) && \
+ (defined(__i386__) || defined(__i386) || defined(i386))
+
+/* || defined(__sun) || defined(__sun__) || defined(sun) */
+
+
+#if defined(HAVE_ELF_H)
+#include <elf.h>
+#else
+#include <linux/elf.h>
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifndef ELFCLASS32
+#define ELFCLASS32 1 /* 32-bit objects */
+#endif
+#ifndef ELFCLASS64
+#define ELFCLASS64 2 /* 64-bit objects */
+#endif
+
+
+
+/* The name of the program.
+ */
+static char const *progname;
+
+/* The name of the current file.
+ */
+static char const *filename;
+
+
+/* A simple error-handling function. FALSE is always returned for the
+ * convenience of the caller.
+ */
+static int err(char const *errmsg)
+{
+ fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg);
+ return FALSE;
+}
+
+/* A macro for I/O errors: The given error message is used only when
+ * errno is not set.
+ */
+#define ferr(msg) (err(errno ? strerror(errno) : (msg)))
+
+/* readelfheader() reads the ELF header into our global variable, and
+ * checks to make sure that this is in fact a file that we should be
+ * munging.
+ */
+static int readelfheader_32(int fd, Elf32_Ehdr *ehdr)
+{
+ errno = 0;
+ if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
+ return ferr("missing or incomplete ELF header.");
+
+ /* Check the ELF signature.
+ */
+ if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+ ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+ ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+ ehdr->e_ident[EI_MAG3] == ELFMAG3))
+ return err("missing ELF signature.");
+
+ /* Compare the file's class and endianness with the program's.
+ */
+#ifdef ELF_DATA
+ if (ehdr->e_ident[EI_DATA] != ELF_DATA)
+ return err("ELF file has different endianness.");
+#endif
+
+ if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
+ return FALSE;
+
+ /* Check the target architecture.
+ */
+#ifdef ELF_ARCH
+ if (ehdr->e_machine != ELF_ARCH)
+ return err("ELF file created for different architecture.");
+#endif
+
+ /* Verify the sizes of the ELF header and the program segment
+ * header table entries.
+ */
+ if (ehdr->e_ehsize != sizeof(Elf32_Ehdr))
+ return err("unrecognized ELF header size.");
+ if (ehdr->e_phentsize != sizeof(Elf32_Phdr))
+ return err("unrecognized program segment header size.");
+
+ /* Finally, check the file type.
+ */
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ return err("not an executable or shared-object library.");
+
+ return TRUE;
+}
+
+static int readelfheader_64(int fd, Elf64_Ehdr *ehdr)
+{
+ errno = 0;
+
+ if (lseek(fd, 0, SEEK_SET))
+ return ferr("could not rewind file");
+
+ if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
+ return ferr("missing or incomplete ELF header.");
+
+ /* Check the ELF signature.
+ */
+ if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
+ ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
+ ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
+ ehdr->e_ident[EI_MAG3] == ELFMAG3))
+ return err("missing ELF signature.");
+
+ /* Compare the file's class and endianness with the program's.
+ */
+#ifdef ELF_DATA
+ if (ehdr->e_ident[EI_DATA] != ELF_DATA)
+ return err("ELF file has different endianness.");
+#endif
+
+ if (ehdr->e_ident[EI_CLASS] != ELFCLASS64)
+ return err("ELF file has different word size.");
+
+ /* Check the target architecture.
+ */
+#ifdef ELF_ARCH
+ if (ehdr->e_machine != ELF_ARCH)
+ return err("ELF file created for different architecture.");
+#endif
+
+ /* Verify the sizes of the ELF header and the program segment
+ * header table entries.
+ */
+ if (ehdr->e_ehsize != sizeof(Elf64_Ehdr))
+ return err("unrecognized ELF header size.");
+ if (ehdr->e_phentsize != sizeof(Elf64_Phdr))
+ return err("unrecognized program segment header size.");
+
+ /* Finally, check the file type.
+ */
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
+ return err("not an executable or shared-object library.");
+
+ return TRUE;
+}
+
+/* readphdrtable() loads the program segment header table into memory.
+ */
+static int readphdrtable_32(int fd, Elf32_Ehdr const *ehdr, Elf32_Phdr **phdrs)
+{
+ size_t size;
+
+ if (!ehdr->e_phoff || !ehdr->e_phnum)
+ return err("ELF file has no program header table.");
+
+ size = ehdr->e_phnum * sizeof **phdrs;
+ if (!(*phdrs = calloc(1,size)))
+ return err("Out of memory!");
+
+ errno = 0;
+ if (read(fd, *phdrs, size) != (ssize_t)size)
+ return ferr("missing or incomplete program segment header table.");
+
+ return TRUE;
+}
+
+static int readphdrtable_64(int fd, Elf64_Ehdr const *ehdr, Elf64_Phdr **phdrs)
+{
+ size_t size;
+
+ if (!ehdr->e_phoff || !ehdr->e_phnum)
+ return err("ELF file has no program header table.");
+
+ size = ehdr->e_phnum * sizeof **phdrs;
+ if (!(*phdrs = calloc(1,size)))
+ return err("Out of memory!");
+
+ errno = 0;
+ if (read(fd, *phdrs, size) != (ssize_t)size)
+ return ferr("missing or incomplete program segment header table.");
+
+ return TRUE;
+}
+
+/* getmemorysize() determines the offset of the last byte of the file
+ * that is referenced by an entry in the program segment header table.
+ * (Anything in the file after that point is not used when the program
+ * is executing, and thus can be safely discarded.)
+ */
+static int getmemorysize_32(Elf32_Ehdr const *ehdr, Elf32_Phdr const *phdrs,
+ unsigned long *newsize)
+{
+ Elf32_Phdr const *phdr;
+ unsigned long size, n;
+ unsigned int i;
+
+ /* Start by setting the size to include the ELF header and the
+ * complete program segment header table.
+ */
+ size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs;
+ if (size < sizeof *ehdr)
+ size = sizeof *ehdr;
+
+ /* Then keep extending the size to include whatever data the
+ * program segment header table references.
+ */
+ for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
+ if (phdr->p_type != PT_NULL) {
+ n = phdr->p_offset + phdr->p_filesz;
+ if (n > size)
+ size = n;
+ }
+ }
+
+ *newsize = size;
+ return TRUE;
+}
+
+static int getmemorysize_64(Elf64_Ehdr const *ehdr, Elf64_Phdr const *phdrs,
+ unsigned long *newsize)
+{
+ Elf64_Phdr const *phdr;
+ unsigned long size, n;
+ unsigned int i;
+
+ /* Start by setting the size to include the ELF header and the
+ * complete program segment header table.
+ */
+ size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs;
+ if (size < sizeof *ehdr)
+ size = sizeof *ehdr;
+
+ /* Then keep extending the size to include whatever data the
+ * program segment header table references.
+ */
+ for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
+ if (phdr->p_type != PT_NULL) {
+ n = phdr->p_offset + phdr->p_filesz;
+ if (n > size)
+ size = n;
+ }
+ }
+
+ *newsize = size;
+ return TRUE;
+}
+
+/* truncatezeros() examines the bytes at the end of the file's
+ * size-to-be, and reduces the size to exclude any trailing zero
+ * bytes.
+ */
+static int truncatezeros(int fd, unsigned long *newsize)
+{
+ unsigned char contents[1024];
+ unsigned long size, n;
+
+ size = *newsize;
+ do {
+ n = sizeof contents;
+ if (n > size)
+ n = size;
+ if (lseek(fd, size - n, SEEK_SET) == (off_t)-1)
+ return ferr("cannot seek in file.");
+ if (read(fd, contents, n) != (ssize_t)n)
+ return ferr("cannot read file contents");
+ while (n && !contents[--n])
+ --size;
+ } while (size && !n);
+
+ /* Sanity check.
+ */
+ if (!size)
+ return err("ELF file is completely blank!");
+
+ *newsize = size;
+ return TRUE;
+}
+
+/* modifyheaders() removes references to the section header table if
+ * it was stripped, and reduces program header table entries that
+ * included truncated bytes at the end of the file.
+ */
+static int modifyheaders_32(Elf32_Ehdr *ehdr, Elf32_Phdr *phdrs,
+ unsigned long newsize)
+{
+ Elf32_Phdr *phdr;
+ unsigned int i;
+
+ /* If the section header table is gone, then remove all references
+ * to it in the ELF header.
+ */
+ if (ehdr->e_shoff >= newsize) {
+ ehdr->e_shoff = 0;
+ ehdr->e_shnum = 0;
+ ehdr->e_shentsize = 0;
+ ehdr->e_shstrndx = 0;
+ }
+
+ /* The program adjusts the file size of any segment that was
+ * truncated. The case of a segment being completely stripped out
+ * is handled separately.
+ */
+ for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
+ if (phdr->p_offset >= newsize) {
+ phdr->p_offset = newsize;
+ phdr->p_filesz = 0;
+ } else if (phdr->p_offset + phdr->p_filesz > newsize) {
+ phdr->p_filesz = newsize - phdr->p_offset;
+ }
+ }
+
+ return TRUE;
+}
+
+static int modifyheaders_64(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs,
+ unsigned long newsize)
+{
+ Elf64_Phdr *phdr;
+ unsigned int i;
+
+ /* If the section header table is gone, then remove all references
+ * to it in the ELF header.
+ */
+ if (ehdr->e_shoff >= newsize) {
+ ehdr->e_shoff = 0;
+ ehdr->e_shnum = 0;
+ ehdr->e_shentsize = 0;
+ ehdr->e_shstrndx = 0;
+ }
+
+ /* The program adjusts the file size of any segment that was
+ * truncated. The case of a segment being completely stripped out
+ * is handled separately.
+ */
+ for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) {
+ if (phdr->p_offset >= newsize) {
+ phdr->p_offset = newsize;
+ phdr->p_filesz = 0;
+ } else if (phdr->p_offset + phdr->p_filesz > newsize) {
+ phdr->p_filesz = newsize - phdr->p_offset;
+ }
+ }
+
+ return TRUE;
+}
+
+/* commitchanges() writes the new headers back to the original file
+ * and sets the file to its new size.
+ */
+static int commitchanges_32(int fd, Elf32_Ehdr const *ehdr, Elf32_Phdr *phdrs,
+ unsigned long newsize)
+{
+ size_t n;
+
+ /* Save the changes to the ELF header, if any.
+ */
+ if (lseek(fd, 0, SEEK_SET))
+ return ferr("could not rewind file");
+ errno = 0;
+ if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
+ return err("could not modify file");
+
+ /* Save the changes to the program segment header table, if any.
+ */
+ if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) {
+ err("could not seek in file.");
+ goto warning;
+ }
+ n = ehdr->e_phnum * sizeof *phdrs;
+ if (write(fd, phdrs, n) != (ssize_t)n) {
+ err("could not write to file");
+ goto warning;
+ }
+
+ /* Eleventh-hour sanity check: don't truncate before the end of
+ * the program segment header table.
+ */
+ if (newsize < ehdr->e_phoff + n)
+ newsize = ehdr->e_phoff + n;
+
+ /* Chop off the end of the file.
+ */
+ if (ftruncate(fd, newsize)) {
+ err("could not resize file");
+ goto warning;
+ }
+
+ return TRUE;
+
+ warning:
+ return err("ELF file may have been corrupted!");
+}
+
+static int commitchanges_64(int fd, Elf64_Ehdr const *ehdr, Elf64_Phdr *phdrs,
+ unsigned long newsize)
+{
+ size_t n;
+
+ /* Save the changes to the ELF header, if any.
+ */
+ if (lseek(fd, 0, SEEK_SET))
+ return ferr("could not rewind file");
+ errno = 0;
+ if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr)
+ return err("could not modify file");
+
+ /* Save the changes to the program segment header table, if any.
+ */
+ if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) {
+ err("could not seek in file.");
+ goto warning;
+ }
+ n = ehdr->e_phnum * sizeof *phdrs;
+ if (write(fd, phdrs, n) != (ssize_t)n) {
+ err("could not write to file");
+ goto warning;
+ }
+
+ /* Eleventh-hour sanity check: don't truncate before the end of
+ * the program segment header table.
+ */
+ if (newsize < ehdr->e_phoff + n)
+ newsize = ehdr->e_phoff + n;
+
+ /* Chop off the end of the file.
+ */
+ if (ftruncate(fd, newsize)) {
+ err("could not resize file");
+ goto warning;
+ }
+
+ return TRUE;
+
+ warning:
+ return err("ELF file may have been corrupted!");
+}
+
+/* main() loops over the cmdline arguments, leaving all the real work
+ * to the other functions.
+ */
+int main(int argc, char *argv[])
+{
+ int fd;
+ int is_32bit_elf;
+ Elf32_Ehdr ehdr32;
+ Elf32_Phdr *phdrs32 = NULL;
+ Elf64_Ehdr ehdr64;
+ Elf64_Phdr *phdrs64 = NULL;
+ unsigned long newsize;
+ char **arg;
+ int failures = 0;
+
+ if (argc < 2 || argv[1][0] == '-') {
+ printf("Usage: sstrip FILE...\n"
+ "sstrip discards all nonessential bytes from an executable.\n\n"
+ "Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n"
+ "This program is free software, licensed under the GNU\n"
+ "General Public License. There is absolutely no warranty.\n");
+ return EXIT_SUCCESS;
+ }
+
+ progname = argv[0];
+
+ for (arg = argv + 1 ; *arg != NULL ; ++arg) {
+ filename = *arg;
+
+ fd = open(*arg, O_RDWR);
+ if (fd < 0) {
+ ferr("can't open");
+ ++failures;
+ continue;
+ }
+
+ if (readelfheader_32(fd, &ehdr32)) {
+ is_32bit_elf = TRUE;
+ }
+ else if (readelfheader_64(fd, &ehdr64)) {
+ is_32bit_elf = FALSE;
+ }
+ else {
+ close(fd);
+ return EXIT_FAILURE;
+ }
+
+ if (is_32bit_elf) {
+ if (!(readphdrtable_32(fd, &ehdr32, &phdrs32) &&
+ getmemorysize_32(&ehdr32, phdrs32, &newsize) &&
+ truncatezeros(fd, &newsize) &&
+ modifyheaders_32(&ehdr32, phdrs32, newsize) &&
+ commitchanges_32(fd, &ehdr32, phdrs32, newsize)))
+ ++failures;
+ }
+ else {
+ if (!(readphdrtable_64(fd, &ehdr64, &phdrs64) &&
+ getmemorysize_64(&ehdr64, phdrs64, &newsize) &&
+ truncatezeros(fd, &newsize) &&
+ modifyheaders_64(&ehdr64, phdrs64, newsize) &&
+ commitchanges_64(fd, &ehdr64, phdrs64, newsize)))
+ ++failures;
+ }
+
+ close(fd);
+ }
+
+ return failures ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+#else
+
+int main()
+{
+ return (EXIT_SUCCESS);
+}
+
+#endif
diff --git a/src/t-test0.c b/src/t-test0.c
new file mode 100644
index 0000000..ed03554
--- /dev/null
+++ b/src/t-test0.c
@@ -0,0 +1,482 @@
+/*
+* Copyright (c) 1996-1999, 2001-2004 Wolfram Gloger
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that (i) the above copyright notices and this permission
+notice appear in all copies of the software and related documentation,
+and (ii) the name of Wolfram Gloger may not be used in any advertising
+or publicity relating to the software.
+
+THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
+INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
+OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * $Id: t-test1.c,v 1.2 2004/11/04 14:58:45 wg Exp $
+ * by Wolfram Gloger 1996-1999, 2001, 2004
+ * A multi-thread test for malloc performance, maintaining one pool of
+ * allocated bins per thread.
+ */
+/*
+ t-test[12] <n-total> <n-parallel> <n-allocs> <size-max> <bins>
+
+ n-total = total number of threads executed (default 10)
+ n-parallel = number of threads running in parallel (2)
+ n-allocs = number of malloc()'s / free()'s per thread (10000)
+ size-max = max. size requested with malloc() in bytes (10000)
+ bins = number of bins to maintain
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#if (defined __STDC__ && __STDC__) || defined __cplusplus
+# include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+
+/*
+#if !USE_MALLOC
+#include <malloc.h>
+#else
+#include "malloc.h"
+#endif
+*/
+
+#ifdef USE_SYSTEM_MALLOC
+extern void *memalign(size_t boundary, size_t size);
+/* #define memalign(a,b) malloc(b) */
+#else
+extern void *memalign(size_t boundary, size_t size);
+#endif
+
+static int verbose = 1;
+
+/* dummy for the samhain safe_fatal logger
+ */
+void safe_fatal(const char * details,
+ const char * file, int line)
+{
+ (void) file;
+ (void) line;
+ fputs("assert failed: ", stderr);
+ puts(details);
+ _exit(EXIT_FAILURE);
+}
+
+/* lran2.h
+ * by Wolfram Gloger 1996.
+ *
+ * A small, portable pseudo-random number generator.
+ */
+
+#ifndef _LRAN2_H
+#define _LRAN2_H
+
+#define LRAN2_MAX 714025l /* constants for portable */
+#define IA 1366l /* random number generator */
+#define IC 150889l /* (see e.g. `Numerical Recipes') */
+
+struct lran2_st {
+ long x, y, v[97];
+};
+
+static void
+lran2_init(struct lran2_st* d, long seed)
+{
+ long x;
+ int j;
+
+ x = (IC - seed) % LRAN2_MAX;
+ if(x < 0) x = -x;
+ for(j=0; j<97; j++) {
+ x = (IA*x + IC) % LRAN2_MAX;
+ d->v[j] = x;
+ }
+ d->x = (IA*x + IC) % LRAN2_MAX;
+ d->y = d->x;
+}
+
+#ifdef __GNUC__
+__inline__
+#endif
+static long
+lran2(struct lran2_st* d)
+{
+ int j = (d->y % 97);
+
+ d->y = d->v[j];
+ d->x = (IA*d->x + IC) % LRAN2_MAX;
+ d->v[j] = d->x;
+ return d->y;
+}
+
+#undef IA
+#undef IC
+
+#endif
+
+/*
+ * $Id: t-test.h,v 1.1 2004/11/04 14:32:21 wg Exp $
+ * by Wolfram Gloger 1996.
+ * Common data structures and functions for testing malloc performance.
+ */
+
+/* Testing level */
+#ifndef TEST
+#define TEST 99
+#endif
+
+/* For large allocation sizes, the time required by copying in
+ realloc() can dwarf all other execution times. Avoid this with a
+ size threshold. */
+#ifndef REALLOC_MAX
+#define REALLOC_MAX 2000
+#endif
+
+struct bin {
+ unsigned char *ptr;
+ unsigned long size;
+};
+
+#if TEST > 0
+
+static void
+mem_init(unsigned char *ptr, unsigned long size)
+{
+ unsigned long i, j;
+
+ if(size == 0) return;
+#if TEST > 3
+ memset(ptr, '\0', size);
+#endif
+ for(i=0; i<size; i+=2047) {
+ j = (unsigned long)ptr ^ i;
+ ptr[i] = ((j ^ (j>>8)) & 0xFF);
+ }
+ j = (unsigned long)ptr ^ (size-1);
+ ptr[size-1] = ((j ^ (j>>8)) & 0xFF);
+}
+
+static int
+mem_check(unsigned char *ptr, unsigned long size)
+{
+ unsigned long i, j;
+
+ if(size == 0) return 0;
+ for(i=0; i<size; i+=2047) {
+ j = (unsigned long)ptr ^ i;
+ if(ptr[i] != ((j ^ (j>>8)) & 0xFF)) return 1;
+ }
+ j = (unsigned long)ptr ^ (size-1);
+ if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) return 2;
+ return 0;
+}
+
+static int
+zero_check(unsigned* ptr, unsigned long size)
+{
+ unsigned char* ptr2;
+
+ while(size >= sizeof(*ptr)) {
+ if(*ptr++ != 0)
+ return -1;
+ size -= sizeof(*ptr);
+ }
+ ptr2 = (unsigned char*)ptr;
+ while(size > 0) {
+ if(*ptr2++ != 0)
+ return -1;
+ --size;
+ }
+ return 0;
+}
+
+#endif /* TEST > 0 */
+
+/* Allocate a bin with malloc(), realloc() or memalign(). r must be a
+ random number >= 1024. */
+int n_malloc=0, n_memalign=0, n_realloc=0, n_calloc=0;
+
+static void
+bin_alloc(struct bin *m, unsigned long size, int r)
+{
+#if TEST > 0
+ if(mem_check(m->ptr, m->size)) {
+ fprintf(stderr, "memory corrupt!\n");
+ exit(1);
+ }
+#endif
+ r %= 1024;
+ /*printf("%d ", r);*/
+ if(r < 4) { /* memalign */
+ if(m->size > 0) free(m->ptr);
+ m->ptr = (unsigned char *)memalign(sizeof(int) << r, size);
+ ++n_memalign;
+ } else if(r < 20) { /* calloc */
+ if(m->size > 0) free(m->ptr);
+ m->ptr = (unsigned char *)calloc(size, 1);
+#if TEST > 0
+ if(zero_check((unsigned*)m->ptr, size)) {
+ unsigned long i;
+ for(i=0; i<size; i++)
+ if(m->ptr[i] != 0)
+ break;
+ fprintf(stderr, "calloc'ed memory non-zero (ptr=%p, i=%ld)!\n", m->ptr, i);
+ exit(1);
+ }
+#endif
+ ++n_calloc;
+ } else if(r < 100 && m->size < REALLOC_MAX) { /* realloc */
+ if(m->size == 0) m->ptr = NULL;
+ m->ptr = realloc(m->ptr, size);
+ ++n_realloc;
+ } else { /* plain malloc */
+ if(m->size > 0) free(m->ptr);
+ m->ptr = (unsigned char *)malloc(size);
+ ++n_malloc;
+ }
+ if(!m->ptr) {
+ fprintf(stderr, "out of memory (r=%d, size=%ld)!\n", r, (long)size);
+ exit(1);
+ }
+ m->size = size;
+#if TEST > 0
+ mem_init(m->ptr, m->size);
+#endif
+}
+
+/* Free a bin. */
+
+static void
+bin_free(struct bin *m)
+{
+ if(m->size == 0) return;
+#if TEST > 0
+ if(mem_check(m->ptr, m->size)) {
+ fprintf(stderr, "memory corrupt!\n");
+ exit(1);
+ }
+#endif
+ free(m->ptr);
+ m->size = 0;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
+
+
+struct user_data {
+ int bins, max;
+ unsigned long size;
+ long seed;
+};
+
+/*
+ * $Id: thread-st.h$
+ * pthread version
+ * by Wolfram Gloger 2004
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+pthread_cond_t finish_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t finish_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#ifndef USE_PTHREADS_STACKS
+#define USE_PTHREADS_STACKS 0
+#endif
+
+#ifndef STACKSIZE
+#define STACKSIZE 32768
+#endif
+
+
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
+
+
+#define N_TOTAL 10
+#ifndef N_THREADS
+#define N_THREADS 2
+#endif
+#ifndef N_TOTAL_PRINT
+#define N_TOTAL_PRINT 50
+#endif
+#ifndef MEMORY
+#define MEMORY 8000000l
+#endif
+#define SIZE 10000
+#define I_MAX 10000
+#define ACTIONS_MAX 30
+#ifndef TEST_FORK
+#define TEST_FORK 0
+#endif
+
+#define RANDOM(d,s) (lran2(d) % (s))
+
+struct bin_info {
+ struct bin *m;
+ unsigned long size, bins;
+};
+
+#if TEST > 0
+
+void
+bin_test(struct bin_info *p)
+{
+ unsigned int b;
+
+ for(b=0; b<p->bins; b++) {
+ if(mem_check(p->m[b].ptr, p->m[b].size)) {
+ fprintf(stderr, "memory corrupt!\n");
+ abort();
+ }
+ }
+}
+
+#endif
+
+void
+malloc_test(unsigned long size, int bins, int max)
+{
+ unsigned int b;
+ int i, j, actions;
+ struct bin_info p;
+ struct lran2_st ld; /* data for random number generator */
+
+ lran2_init(&ld, ((long)max*size + getpid()) ^ bins);
+
+ p.m = (struct bin *)malloc(bins*sizeof(*p.m));
+ p.bins = bins;
+ p.size = size;
+
+ for(b=0; b<p.bins; b++) {
+ p.m[b].size = 0;
+ p.m[b].ptr = NULL;
+ if(RANDOM(&ld, 2) == 0)
+ bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
+ }
+ for(i=0; i<=max;) {
+#if TEST > 1
+ bin_test(&p);
+#endif
+ actions = RANDOM(&ld, ACTIONS_MAX);
+#if USE_MALLOC && MALLOC_DEBUG
+ if(actions < 2) { mallinfo(); }
+#endif
+ for(j=0; j<actions; j++) {
+ b = RANDOM(&ld, p.bins);
+ bin_free(&p.m[b]);
+ }
+ i += actions;
+ actions = RANDOM(&ld, ACTIONS_MAX);
+ for(j=0; j<actions; j++) {
+ b = RANDOM(&ld, p.bins);
+ bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
+#if TEST > 2
+ bin_test(&p);
+#endif
+ }
+
+ i += actions;
+ }
+ for(b=0; b<p.bins; b++)
+ bin_free(&p.m[b]);
+ free(p.m);
+ return;
+}
+
+int n_total=0, n_total_max=N_TOTAL, n_running;
+
+int
+main(int argc, char *argv[])
+{
+ int bins;
+ int n_thr=N_THREADS;
+ int i_max=I_MAX;
+ unsigned long size=SIZE;
+
+#if USE_MALLOC && USE_STARTER==2
+ ptmalloc_init();
+ printf("ptmalloc_init\n");
+#endif
+
+ if((argc > 1) && (0 == strcmp(argv[1], "-h") || 0 == strcmp(argv[1], "--help")))
+ {
+ printf("%s <n-total> <n-parallel> <n-allocs> <size-max> <bins>\n\n", argv[0]);
+ printf(" n-total = total number of threads executed (default 10)\n");
+ printf(" UNUSED n-parallel = number of threads running in parallel (2)\n");
+ printf(" n-allocs = number of malloc()'s / free()'s per thread (10000)\n");
+ printf(" size-max = max. size requested with malloc() in bytes (10000)\n");
+ printf(" bins = number of bins to maintain\n");
+ return 0;
+ }
+
+ if(argc > 1) n_total_max = atoi(argv[1]);
+ if(n_total_max < 1) n_thr = 1;
+ if(argc > 2) n_thr = atoi(argv[2]);
+ if(n_thr < 1) n_thr = 1;
+ if(n_thr > 100) n_thr = 100;
+ if(argc > 3) i_max = atoi(argv[3]);
+
+ if(argc > 4) size = atol(argv[4]);
+ if(size < 2) size = 2;
+
+ bins = MEMORY/(size*n_thr);
+ if(argc > 5) bins = atoi(argv[5]);
+ if(bins < 4) bins = 4;
+
+ printf("[total=%d threads=%d] i_max=%d size=%ld bins=%d\n",
+ n_total_max, n_thr, i_max, size, bins);
+
+ do {
+ n_total++;
+ malloc_test(size, bins, i_max);
+ if (verbose)
+ if(n_total%N_TOTAL_PRINT == 0)
+ printf("n_total = %8d - malloc %12d / memalign %12d / realloc %12d / calloc %12d\n",
+ n_total,
+ n_malloc, n_memalign, n_realloc, n_calloc);
+ } while (n_total < n_total_max);
+
+
+#if USE_MALLOC
+ malloc_stats();
+#endif
+ if (verbose)
+ printf("Done.\n");
+ return 0;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
diff --git a/src/t-test1.c b/src/t-test1.c
new file mode 100644
index 0000000..942f81d
--- /dev/null
+++ b/src/t-test1.c
@@ -0,0 +1,684 @@
+/*
+* Copyright (c) 1996-1999, 2001-2004 Wolfram Gloger
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that (i) the above copyright notices and this permission
+notice appear in all copies of the software and related documentation,
+and (ii) the name of Wolfram Gloger may not be used in any advertising
+or publicity relating to the software.
+
+THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
+INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
+DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
+OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/*
+ * $Id: t-test1.c,v 1.2 2004/11/04 14:58:45 wg Exp $
+ * by Wolfram Gloger 1996-1999, 2001, 2004
+ * A multi-thread test for malloc performance, maintaining one pool of
+ * allocated bins per thread.
+ */
+/*
+ t-test[12] <n-total> <n-parallel> <n-allocs> <size-max> <bins>
+
+ n-total = total number of threads executed (default 10)
+ n-parallel = number of threads running in parallel (2)
+ n-allocs = number of malloc()'s / free()'s per thread (10000)
+ size-max = max. size requested with malloc() in bytes (10000)
+ bins = number of bins to maintain
+*/
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#if (defined __STDC__ && __STDC__) || defined __cplusplus
+# include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+
+/*
+#if !USE_MALLOC
+#include <malloc.h>
+#else
+#include "malloc.h"
+#endif
+*/
+
+#ifdef USE_SYSTEM_MALLOC
+extern void *memalign(size_t boundary, size_t size);
+/* #define memalign(a,b) malloc(b) */
+#else
+extern void *memalign(size_t boundary, size_t size);
+#endif
+
+static int verbose = 1;
+
+/* dummy for the samhain safe_fatal logger
+ */
+void safe_fatal(const char * details,
+ const char * file, int line)
+{
+ (void) file;
+ (void) line;
+ fputs("assert failed: ", stderr);
+ puts(details);
+ _exit(EXIT_FAILURE);
+}
+
+/* lran2.h
+ * by Wolfram Gloger 1996.
+ *
+ * A small, portable pseudo-random number generator.
+ */
+
+#ifndef _LRAN2_H
+#define _LRAN2_H
+
+#define LRAN2_MAX 714025l /* constants for portable */
+#define IA 1366l /* random number generator */
+#define IC 150889l /* (see e.g. `Numerical Recipes') */
+
+struct lran2_st {
+ long x, y, v[97];
+};
+
+static void
+lran2_init(struct lran2_st* d, long seed)
+{
+ long x;
+ int j;
+
+ x = (IC - seed) % LRAN2_MAX;
+ if(x < 0) x = -x;
+ for(j=0; j<97; j++) {
+ x = (IA*x + IC) % LRAN2_MAX;
+ d->v[j] = x;
+ }
+ d->x = (IA*x + IC) % LRAN2_MAX;
+ d->y = d->x;
+}
+
+#ifdef __GNUC__
+__inline__
+#endif
+static long
+lran2(struct lran2_st* d)
+{
+ int j = (d->y % 97);
+
+ d->y = d->v[j];
+ d->x = (IA*d->x + IC) % LRAN2_MAX;
+ d->v[j] = d->x;
+ return d->y;
+}
+
+#undef IA
+#undef IC
+
+#endif
+
+/*
+ * $Id: t-test.h,v 1.1 2004/11/04 14:32:21 wg Exp $
+ * by Wolfram Gloger 1996.
+ * Common data structures and functions for testing malloc performance.
+ */
+
+/* Testing level */
+#ifndef TEST
+#define TEST 99
+#endif
+
+/* For large allocation sizes, the time required by copying in
+ realloc() can dwarf all other execution times. Avoid this with a
+ size threshold. */
+#ifndef REALLOC_MAX
+#define REALLOC_MAX 2000
+#endif
+
+struct bin {
+ unsigned char *ptr;
+ unsigned long size;
+};
+
+#if TEST > 0
+
+static void
+mem_init(unsigned char *ptr, unsigned long size)
+{
+ unsigned long i, j;
+
+ if(size == 0) return;
+#if TEST > 3
+ memset(ptr, '\0', size);
+#endif
+ for(i=0; i<size; i+=2047) {
+ j = (unsigned long)ptr ^ i;
+ ptr[i] = ((j ^ (j>>8)) & 0xFF);
+ }
+ j = (unsigned long)ptr ^ (size-1);
+ ptr[size-1] = ((j ^ (j>>8)) & 0xFF);
+}
+
+static int
+mem_check(unsigned char *ptr, unsigned long size)
+{
+ unsigned long i, j;
+
+ if(size == 0) return 0;
+ for(i=0; i<size; i+=2047) {
+ j = (unsigned long)ptr ^ i;
+ if(ptr[i] != ((j ^ (j>>8)) & 0xFF)) return 1;
+ }
+ j = (unsigned long)ptr ^ (size-1);
+ if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) return 2;
+ return 0;
+}
+
+static int
+zero_check(unsigned* ptr, unsigned long size)
+{
+ unsigned char* ptr2;
+
+ while(size >= sizeof(*ptr)) {
+ if(*ptr++ != 0)
+ return -1;
+ size -= sizeof(*ptr);
+ }
+ ptr2 = (unsigned char*)ptr;
+ while(size > 0) {
+ if(*ptr2++ != 0)
+ return -1;
+ --size;
+ }
+ return 0;
+}
+
+#endif /* TEST > 0 */
+
+/* Allocate a bin with malloc(), realloc() or memalign(). r must be a
+ random number >= 1024. */
+int n_malloc=0, n_memalign=0, n_realloc=0, n_calloc=0;
+
+static void
+bin_alloc(struct bin *m, unsigned long size, int r)
+{
+#if TEST > 0
+ if(mem_check(m->ptr, m->size)) {
+ fprintf(stderr, "memory corrupt!\n");
+ exit(1);
+ }
+#endif
+ r %= 1024;
+ /*printf("%d ", r);*/
+ if(r < 4) { /* memalign */
+ if(m->size > 0) free(m->ptr);
+ m->ptr = (unsigned char *)memalign(sizeof(int) << r, size);
+ ++n_memalign;
+ } else if(r < 20) { /* calloc */
+ if(m->size > 0) free(m->ptr);
+ m->ptr = (unsigned char *)calloc(size, 1);
+#if TEST > 0
+ if(zero_check((unsigned*)m->ptr, size)) {
+ unsigned long i;
+ for(i=0; i<size; i++)
+ if(m->ptr[i] != 0)
+ break;
+ fprintf(stderr, "calloc'ed memory non-zero (ptr=%p, i=%ld)!\n", m->ptr, i);
+ exit(1);
+ }
+#endif
+ ++n_calloc;
+ } else if(r < 100 && m->size < REALLOC_MAX) { /* realloc */
+ if(m->size == 0) m->ptr = NULL;
+ m->ptr = realloc(m->ptr, size);
+ ++n_realloc;
+ } else { /* plain malloc */
+ if(m->size > 0) free(m->ptr);
+ m->ptr = (unsigned char *)malloc(size);
+ ++n_malloc;
+ }
+ if(!m->ptr) {
+ fprintf(stderr, "out of memory (r=%d, size=%ld)!\n", r, (long)size);
+ exit(1);
+ }
+ m->size = size;
+#if TEST > 0
+ mem_init(m->ptr, m->size);
+#endif
+}
+
+/* Free a bin. */
+
+static void
+bin_free(struct bin *m)
+{
+ if(m->size == 0) return;
+#if TEST > 0
+ if(mem_check(m->ptr, m->size)) {
+ fprintf(stderr, "memory corrupt!\n");
+ exit(1);
+ }
+#endif
+ free(m->ptr);
+ m->size = 0;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
+
+
+struct user_data {
+ int bins, max;
+ unsigned long size;
+ long seed;
+};
+
+/*
+ * $Id: thread-st.h$
+ * pthread version
+ * by Wolfram Gloger 2004
+ */
+
+#include <pthread.h>
+#include <stdio.h>
+
+pthread_cond_t finish_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t finish_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#ifndef USE_PTHREADS_STACKS
+#define USE_PTHREADS_STACKS 0
+#endif
+
+#ifndef STACKSIZE
+#define STACKSIZE 32768
+#endif
+
+struct thread_st {
+ char *sp; /* stack pointer, can be 0 */
+ void (*func)(struct thread_st* st); /* must be set by user */
+ pthread_t id;
+ int flags;
+ struct user_data u;
+};
+
+static void
+mthread_init(void)
+{
+#if !defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)
+ extern int dnmalloc_pthread_init(void);
+ dnmalloc_pthread_init();
+#endif
+
+ if (verbose)
+ printf("Using posix threads.\n");
+ pthread_cond_init(&finish_cond, NULL);
+ pthread_mutex_init(&finish_mutex, NULL);
+}
+
+static void *
+mthread_wrapper(void *ptr)
+{
+ struct thread_st *st = (struct thread_st*)ptr;
+
+ /*printf("begin %p\n", st->sp);*/
+ st->func(st);
+ pthread_mutex_lock(&finish_mutex);
+ st->flags = 1;
+ pthread_mutex_unlock(&finish_mutex);
+ pthread_cond_signal(&finish_cond);
+ /*printf("end %p\n", st->sp);*/
+ return NULL;
+}
+
+/* Create a thread. */
+static int
+mthread_create(struct thread_st *st)
+{
+ st->flags = 0;
+ {
+ pthread_attr_t* attr_p = 0;
+#if USE_PTHREADS_STACKS
+ pthread_attr_t attr;
+
+ pthread_attr_init (&attr);
+ if(!st->sp)
+ st->sp = malloc(STACKSIZE+16);
+ if(!st->sp)
+ return -1;
+ if(pthread_attr_setstacksize(&attr, STACKSIZE))
+ fprintf(stderr, "error setting stacksize");
+ else
+ pthread_attr_setstackaddr(&attr, st->sp + STACKSIZE);
+ /*printf("create %p\n", st->sp);*/
+ attr_p = &attr;
+#endif
+ return pthread_create(&st->id, attr_p, mthread_wrapper, st);
+ }
+ return 0;
+}
+
+/* Wait for one of several subthreads to finish. */
+static void
+wait_for_thread(struct thread_st st[], int n_thr,
+ int (*end_thr)(struct thread_st*))
+{
+ int i;
+
+ pthread_mutex_lock(&finish_mutex);
+ for(;;) {
+ int term = 0;
+ for(i=0; i<n_thr; i++)
+ if(st[i].flags) {
+ /*printf("joining %p\n", st[i].sp);*/
+ if(pthread_join(st[i].id, NULL) == 0) {
+ st[i].flags = 0;
+ if(end_thr)
+ end_thr(&st[i]);
+ } else
+ fprintf(stderr, "can't join\n");
+ ++term;
+ }
+ if(term > 0)
+ break;
+ pthread_cond_wait(&finish_cond, &finish_mutex);
+ }
+ pthread_mutex_unlock(&finish_mutex);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
+
+
+#define N_TOTAL 10
+#ifndef N_THREADS
+#define N_THREADS 2
+#endif
+#ifndef N_TOTAL_PRINT
+#define N_TOTAL_PRINT 50
+#endif
+#ifndef MEMORY
+#define MEMORY 8000000l
+#endif
+#define SIZE 10000
+#define I_MAX 10000
+#define ACTIONS_MAX 30
+#ifndef TEST_FORK
+#define TEST_FORK 0
+#endif
+
+#define RANDOM(d,s) (lran2(d) % (s))
+
+struct bin_info {
+ struct bin *m;
+ unsigned long size, bins;
+};
+
+#if TEST > 0
+
+void
+bin_test(struct bin_info *p)
+{
+ unsigned int b;
+
+ for(b=0; b<p->bins; b++) {
+ if(mem_check(p->m[b].ptr, p->m[b].size)) {
+ fprintf(stderr, "memory corrupt!\n");
+ abort();
+ }
+ }
+}
+
+#endif
+
+void
+malloc_test(struct thread_st *st)
+{
+ unsigned int b;
+ int i, j, actions, pid = 1;
+ struct bin_info p;
+ struct lran2_st ld; /* data for random number generator */
+
+ lran2_init(&ld, st->u.seed);
+#if TEST_FORK>0
+ if(RANDOM(&ld, TEST_FORK) == 0) {
+ int status;
+
+#if !USE_THR
+ pid = fork();
+#else
+ pid = fork1();
+#endif
+ if(pid > 0) {
+ /*printf("forked, waiting for %d...\n", pid);*/
+ waitpid(pid, &status, 0);
+ printf("done with %d...\n", pid);
+ if(!WIFEXITED(status)) {
+ printf("child term with signal %d\n", WTERMSIG(status));
+ exit(1);
+ }
+ return;
+ }
+ exit(0);
+ }
+#endif
+ p.m = (struct bin *)malloc(st->u.bins*sizeof(*p.m));
+ p.bins = st->u.bins;
+ p.size = st->u.size;
+ for(b=0; b<p.bins; b++) {
+ p.m[b].size = 0;
+ p.m[b].ptr = NULL;
+ if(RANDOM(&ld, 2) == 0)
+ bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
+ }
+ for(i=0; i<=st->u.max;) {
+#if TEST > 1
+ bin_test(&p);
+#endif
+ actions = RANDOM(&ld, ACTIONS_MAX);
+#if USE_MALLOC && MALLOC_DEBUG
+ if(actions < 2) { mallinfo(); }
+#endif
+ for(j=0; j<actions; j++) {
+ b = RANDOM(&ld, p.bins);
+ bin_free(&p.m[b]);
+ }
+ i += actions;
+ actions = RANDOM(&ld, ACTIONS_MAX);
+ for(j=0; j<actions; j++) {
+ b = RANDOM(&ld, p.bins);
+ bin_alloc(&p.m[b], RANDOM(&ld, p.size) + 1, lran2(&ld));
+#if TEST > 2
+ bin_test(&p);
+#endif
+ }
+#if 0 /* Test illegal free()s while setting MALLOC_CHECK_ */
+ for(j=0; j<8; j++) {
+ b = RANDOM(&ld, p.bins);
+ if(p.m[b].ptr) {
+ int offset = (RANDOM(&ld, 11) - 5)*8;
+ char *rogue = (char*)(p.m[b].ptr) + offset;
+ /*printf("p=%p rogue=%p\n", p.m[b].ptr, rogue);*/
+ free(rogue);
+ }
+ }
+#endif
+ i += actions;
+ }
+ for(b=0; b<p.bins; b++)
+ bin_free(&p.m[b]);
+ free(p.m);
+ if(pid == 0)
+ exit(0);
+}
+
+int n_total=0, n_total_max=N_TOTAL, n_running;
+
+int
+my_end_thread(struct thread_st *st)
+{
+ /* Thread st has finished. Start a new one. */
+#if 0
+ printf("Thread %lx terminated.\n", (long)st->id);
+#endif
+ if(n_total >= n_total_max) {
+ n_running--;
+ } else if(st->u.seed++, mthread_create(st)) {
+ printf("Creating thread #%d failed.\n", n_total);
+ exit(1);
+ } else {
+ n_total++;
+ if (verbose)
+ if(n_total%N_TOTAL_PRINT == 0)
+ printf("n_total = %8d - malloc %12d / memalign %12d / realloc %12d / calloc %12d\n",
+ n_total,
+ n_malloc, n_memalign, n_realloc, n_calloc);
+
+ }
+ return 0;
+}
+
+#if 0
+/* Protect address space for allocation of n threads by LinuxThreads. */
+static void
+protect_stack(int n)
+{
+ char buf[2048*1024];
+ char* guard;
+ size_t guard_size = 2*2048*1024UL*(n+2);
+
+ buf[0] = '\0';
+ guard = (char*)(((unsigned long)buf - 4096)& ~4095UL) - guard_size;
+ printf("Setting up stack guard at %p\n", guard);
+ if(mmap(guard, guard_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
+ -1, 0)
+ != guard)
+ printf("failed!\n");
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int i, bins;
+ int n_thr=N_THREADS;
+ int i_max=I_MAX;
+ unsigned long size=SIZE;
+ struct thread_st *st;
+
+#if USE_MALLOC && USE_STARTER==2
+ ptmalloc_init();
+ printf("ptmalloc_init\n");
+#endif
+
+ if((argc > 1) && (0 == strcmp(argv[1], "-h") || 0 == strcmp(argv[1], "--help")))
+ {
+ printf("%s <n-total> <n-parallel> <n-allocs> <size-max> <bins>\n\n", argv[0]);
+ printf(" n-total = total number of threads executed (default 10)\n");
+ printf(" n-parallel = number of threads running in parallel (2)\n");
+ printf(" n-allocs = number of malloc()'s / free()'s per thread (10000)\n");
+ printf(" size-max = max. size requested with malloc() in bytes (10000)\n");
+ printf(" bins = number of bins to maintain\n");
+ return 0;
+ }
+
+ if(argc > 1) n_total_max = atoi(argv[1]);
+ if(n_total_max < 1) n_thr = 1;
+ if(argc > 2) n_thr = atoi(argv[2]);
+ if(n_thr < 1) n_thr = 1;
+ if(n_thr > 100) n_thr = 100;
+ if(argc > 3) i_max = atoi(argv[3]);
+
+ if(argc > 4) size = atol(argv[4]);
+ if(size < 2) size = 2;
+
+ bins = MEMORY/(size*n_thr);
+ if(argc > 5) bins = atoi(argv[5]);
+ if(bins < 4) bins = 4;
+
+ /*protect_stack(n_thr);*/
+
+ mthread_init();
+ printf("total=%d threads=%d i_max=%d size=%ld bins=%d\n",
+ n_total_max, n_thr, i_max, size, bins);
+
+ st = (struct thread_st *)malloc(n_thr*sizeof(*st));
+ if(!st) exit(-1);
+
+#if !defined NO_THREADS && (defined __sun__ || defined sun)
+ /* I know of no other way to achieve proper concurrency with Solaris. */
+ thr_setconcurrency(n_thr);
+#endif
+
+ /* Start all n_thr threads. */
+ for(i=0; i<n_thr; i++) {
+ st[i].u.bins = bins;
+ st[i].u.max = i_max;
+ st[i].u.size = size;
+ st[i].u.seed = ((long)i_max*size + i) ^ bins;
+ st[i].sp = 0;
+ st[i].func = malloc_test;
+ if(mthread_create(&st[i])) {
+ fprintf(stderr, "Creating thread #%d failed.\n", i);
+ n_thr = i;
+ exit(1);
+ }
+ if (verbose)
+ printf("Created thread %lx.\n", (long)st[i].id);
+ }
+
+ /* Start an extra thread so we don't run out of stacks. */
+ if(0) {
+ struct thread_st lst;
+ lst.u.bins = 10; lst.u.max = 20; lst.u.size = 8000; lst.u.seed = 8999;
+ lst.sp = 0;
+ lst.func = malloc_test;
+ if(mthread_create(&lst)) {
+ fprintf(stderr, "Creating thread #%d failed.\n", i);
+ exit(1);
+ } else {
+ wait_for_thread(&lst, 1, NULL);
+ }
+ }
+
+ for(n_running=n_total=n_thr; n_running>0;) {
+ wait_for_thread(st, n_thr, my_end_thread);
+ }
+ for(i=0; i<n_thr; i++) {
+ free(st[i].sp);
+ }
+ free(st);
+#if USE_MALLOC
+ malloc_stats();
+#endif
+ if (verbose)
+ printf("Done.\n");
+ return 0;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * End:
+ */
diff --git a/src/trustfile.c b/src/trustfile.c
new file mode 100644
index 0000000..402eee9
--- /dev/null
+++ b/src/trustfile.c
@@ -0,0 +1,1160 @@
+/* debug problems */
+/* #define TRUST_DEBUG */
+
+/* switch off full check */
+/* #define TEST_ONLY */
+
+/* standalone */
+/* #define TRUST_MAIN */
+/* $(CC) -DTRUST_MAIN -DSL_ALWAYS_TRUSTED=... */
+
+/* LINTLIBRARY */
+/*
+ * This is the file with all the library routines in it
+ *
+ * Author information:
+ * Matt Bishop
+ * Department of Computer Science
+ * University of California at Davis
+ * Davis, CA 95616-8562
+ * phone (916) 752-8060
+ * email bishop@cs.ucdavis.edu
+ *
+ * This code is placed in the public domain. I do ask that
+ * you keep my name associated with it, that you not represent
+ * it as written by you, and that you preserve these comments.
+ * This software is provided "as is" and without any guarantees
+ * of any sort.
+ *
+ * Compilation notes:
+ * * this does NOT use malloc(3), but fixed storage. this means we
+ * do lots of bounds checking, but it still is faster, and smaller,
+ * than forcing inclusion of malloc. All buffers etc. are of size
+ * MAXFILENAME (defined in trustfile.h); to get more room, recompile
+ * with this set larger.
+ * * if you support the following directory semantics, define STICKY;
+ * otherwise, undefine it
+ * "if a directory is both world-writeable AND has the sticky bit
+ * set, then ONLY the owner of an existing file may delete it"
+ * On some systems (eg, IRIX), you can delete the file under these
+ * conditions if the file is world writeable. Foor our purposes,
+ * this is irrelevant since if the file is world-writeable it is
+ * untrustworthy; either it can be replaced with another file (the
+ * IRIX version) or it can be altered (all versions).
+ * if this is true and STICKY is not set, the sticky bit is ignored
+ * and the directory will be flagged as untrustworthy, even when only
+ * a trusted user could delete the file
+ * * this uses a library call to get the name of the current working
+ * directory. Define the following to get the various versions:
+ * GETCWD for Solaris 2.x, SunOS 4.1.x, IRIX 5.x
+ * char *getcwd(char *buf, int bufsz);
+ * where buf is a buffer for the path name, and bufsz is
+ * the size of the buffer; if the size if too small, you
+ * get an error return (NULL)
+ * GETWD for Ultrix 4.4
+ * char *getwd(char *buf)
+ * where buf is a buffer for the path name, and it is
+ * assumed to be at lease as big as MAXPATHLEN.
+ * *** IMPORTANT NOTE ***
+ * Ultrix supports getcwd as well, but it uses popen to
+ * run the command "pwd" (according to the manual). This
+ * means it's vulnerable to a number of attacks if used
+ * in a privileged program. YOU DON'T WANT THIS.
+ * * the debugging flag DEBUG prints out each step of the file name
+ * checking, as well as info on symbolic links (if S_IFLNK defined),
+ * file name canonicalization, and user, group, and permission for
+ * each file or directory; this is useful if you want to be sure
+ * you're checking the right file
+ *
+ * Version information:
+ * 1.0 December 28, 1995 Matt Bishop
+ *
+ * 2.0 March 26, 2000 Rainer Wichmann -- adapted for slib.
+ */
+
+/* --- Why strcpy is safe here: ---- */
+
+/* The input path is checked once, and then either shortened [in dirz()],
+ * or safely expanded (symlinks) with bound checking.
+ * I.e., the path length can never exceed (MAXFILENAME-1), while the path
+ * is always copied between buffers of length MAXFILENAME.
+ */
+
+#ifndef TRUST_MAIN
+#include "config_xor.h"
+#include "sh_calls.h"
+#else
+#define UID_CAST long
+#define HAVE_GETPWENT
+#define SH_MUTEX_LOCK(a) ((void)0)
+#define SH_MUTEX_UNLOCK(a) ((void)0)
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+#if !defined(TRUST_MAIN)
+
+#include "slib.h"
+#define SH_NEED_PWD_GRP 1
+#include "sh_static.h"
+#include "sh_pthread.h"
+
+#else
+
+#define sh_getgrgid getgrgid
+#define sh_getgrgid_r getgrgid_r
+#define sh_getpwnam getpwnam
+#define sh_getpwnam_r getpwnam_r
+#define sh_getpwuid getpwuid
+#define sh_getpwuid_r getpwuid_r
+#define sh_getpwent getpwent
+#define sh_endpwent endpwent
+
+#define TRUST_DEBUG
+#define S_FALSE 0
+#define S_TRUE 1
+#define SL_ENTER(string)
+#define SL_IRETURN(a, b) return a
+#define retry_lstat(a,b,c,d) lstat(c,d)
+#define _(string) string
+#define N_(string) string
+#define MAXFILENAME 4096
+static int sl_errno = 0;
+#define SL_ENONE 0
+#define SL_ENULL -1024 /* Invalid use of NULL pointer. */
+#define SL_ERANGE -1025 /* Argument out of range. */
+#define SL_ETRUNC -1026 /* Result truncated. */
+#define SL_EINTERNAL -1028 /* Internal error. */
+#define SL_EBADFILE -1030 /* File access error. Check errno. */
+#define SL_EMEM -1032 /* Out of memory. */
+#define SL_EBADNAME -1040 /* Invalid name. */
+#define SL_ESTAT -1041 /* stat of file failed. Check errno. */
+#define SL_EBADUID -1050 /* Owner not trustworthy. */
+#define SL_EBADGID -1051 /* Group writeable and not trustworthy.*/
+#define SL_EBADOTH -1052 /* World writeable. */
+
+#endif
+
+
+#if defined(__linux__) || defined(__FreeBSD__)
+#define STICKY
+#endif
+
+#undef FIL__
+#define FIL__ _("trustfile.c")
+
+/*
+ * the get current working directory function
+ * every version of UNIX seems to have its own
+ * idea of how to do this, so we group them by
+ * arguments ...
+ * all must return a pointer to the right name
+ */
+
+
+#ifndef TRUST_MAIN
+
+#if defined(HAVE_GETCWD) && !defined(HAVE_BROKEN_GETCWD)
+#define CURDIR(buf,nbuf) getcwd((buf), (nbuf))
+#elif defined(HAVE_GETWD)
+#define CURDIR(buf,nbuf) getwd((buf))
+#endif
+
+#else
+
+#define CURDIR(buf,nbuf) getcwd((buf), (nbuf))
+
+#endif
+
+
+
+/*
+ * this checks to see if there are symbolic links
+ * assumes the link bit in the protection mask is called S_IFLNK
+ * (seems to be true on all UNIXes with them)
+ */
+#ifndef S_IFLNK
+#define lstat stat
+#endif
+
+
+/*
+ * these are useful global variables
+ *
+ * first set: who you gonna trust, by default?
+ * if the user does not specify a trusted or untrusted set of users,
+ * all users are considered untrusted EXCEPT:
+ * UID 0 -- root as root can do anything on most UNIX systems, this
+ * seems reasonable
+ * tf_euid -- programmer-selectable UID
+ * if the caller specifies a specific UID by putting
+ * it in this variable, it will be trusted; this is
+ * typically used to trust the effective UID of the
+ * process (note: NOT the real UID, which will cause all
+ * sorts of problems!) By default, this is set to -1,
+ * so if it's not set, root is the only trusted user
+ */
+
+/* modified Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann */
+
+
+#ifndef SL_ALWAYS_TRUSTED
+#define SL_ALWAYS_TRUSTED 0
+#endif
+uid_t test_rootonly[] = { SL_ALWAYS_TRUSTED };
+
+#define tf_uid_neg ((uid_t)-1)
+
+uid_t rootonly[] = { SL_ALWAYS_TRUSTED,
+ tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg,
+ tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg,
+ tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg,
+ tf_uid_neg, tf_uid_neg, tf_uid_neg, tf_uid_neg };
+
+uid_t tf_euid = tf_uid_neg;
+unsigned int EUIDSLOT = sizeof(test_rootonly)/sizeof(uid_t);
+unsigned int ORIG_EUIDSLOT = sizeof(test_rootonly)/sizeof(uid_t);
+
+char tf_path[MAXFILENAME]; /* error path for trust function */
+uid_t tf_baduid;
+gid_t tf_badgid;
+
+static
+int dirz(char *path)
+{
+ register char *p = path;/* points to rest of path to clean up */
+ register char *q; /* temp pointer for skipping over stuff */
+
+ static char swp[MAXFILENAME];
+
+ SL_ENTER(_("dirz"));
+ /*
+ * standard error checking
+ */
+ if (path == NULL)
+ SL_IRETURN(SL_ENULL, _("dirz"));
+ if (path[0] == '.')
+ SL_IRETURN(SL_EINTERNAL, _("dirz"));
+
+
+ /*
+ * loop over the path name until everything is checked
+ */
+ while(*p)
+ {
+ /* skip
+ */
+ if (*p != '/')
+ {
+ p++;
+ continue;
+ }
+
+ /* "/./" or "/."
+ */
+ if (p[1] == '.' && (p[2] == '/' || p[2] == '\0'))
+ {
+ /* yes -- delete "/."
+ */
+ (void) strcpy(swp, &p[2]); /* known to fit */
+ (void) strcpy(p, swp); /* known to fit */
+
+ /* special case "/." as full path name
+ */
+ if (p == path && *p == '\0')
+ {
+ *p++ = '/';
+ *p = '\0';
+ }
+ }
+
+ /* "//"
+ */
+ else if (p[1] == '/')
+ {
+ /* yes -- skip
+ */
+ for(q = &p[2]; *q == '/'; q++)
+ ;
+ (void) strcpy(swp, q); /* known to fit */
+ (void) strcpy(&p[1], swp); /* known to fit */
+ }
+
+ /* "/../" or "/.."
+ */
+ else if (p[1] == '.' && p[2] == '.' && (p[3] == '/' || p[3] == '\0'))
+ {
+ /* yes -- if it's root, delete .. only
+ */
+ if (p == path)
+ {
+ (void) strcpy(swp, &p[3]); /* known to fit */
+ (void) strcpy(p, swp); /* known to fit */
+ }
+ else
+ {
+ /* back up over previous component
+ */
+ q = p - 1;
+ while(q != path && *q != '/')
+ q--;
+ /* now wipe it out
+ */
+ (void) strcpy(swp, &p[3]); /* known to fit */
+ (void) strcpy(q, swp); /* known to fit */
+ p = q;
+ }
+ }
+ else
+ p++;
+ }
+ SL_IRETURN(SL_ENONE, _("dirz"));
+}
+
+
+
+/* not static to circumvent stupid gcc 4 bug */
+int getfname(const char *fname, char *rbuf, int rsz)
+{
+#ifndef TRUST_MAIN
+ register int status;
+#endif
+
+ SL_ENTER(_("getfname"));
+ /*
+ * do the initial checking
+ * NULL pointer
+ */
+ if (fname == NULL || rbuf == NULL)
+ SL_IRETURN(SL_ENULL, _("getfname"));
+ if (rsz <= 0)
+ SL_IRETURN(SL_ERANGE, _("getfname"));
+
+
+ /* already a full path name */
+ if (*fname == '/')
+ rbuf[0] = '\0';
+ else
+ {
+ if (CURDIR(rbuf, rsz) == NULL)
+ {
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "trustfile: getcwd failed\n");
+#endif
+ SL_IRETURN(SL_EBADNAME, _("getfname"));
+ }
+ }
+
+ /*
+ * append the file name and reduce
+ */
+ if (fname != NULL && *fname != '\0')
+ {
+#ifndef TRUST_MAIN
+ status = sl_strlcat(rbuf, "/", rsz);
+ if (status == SL_ENONE)
+ status = sl_strlcat(rbuf, fname, rsz);
+ if (status != SL_ENONE)
+ SL_IRETURN(status, _("getfname"));
+#else
+ strncat(rbuf, "/", rsz-strlen(rbuf)-1);
+ rbuf[rsz-1] = '\0';
+ strncat(rbuf, fname, rsz-strlen(rbuf)-1);
+ rbuf[rsz-1] = '\0';
+#endif
+ }
+ SL_IRETURN(dirz(rbuf), _("getfname"));
+}
+
+static
+int isin(uid_t n, uid_t *list)
+{
+ SL_ENTER(_("isin"));
+ if (list == NULL)
+ SL_IRETURN(S_FALSE, _("isin"));
+
+ while(*list != tf_uid_neg && *list != n)
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: owner_uid=%ld, trusted uid=%ld, no match\n",
+ (UID_CAST) n, (UID_CAST) *list);
+#endif
+ list++;
+ }
+
+ if (*list == tf_uid_neg)
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: owner_uid=%ld, no match with any trusted user --> ERROR\n",
+ (UID_CAST) n);
+#endif
+ SL_IRETURN(S_FALSE, _("isin"));
+ }
+
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: owner_uid=%ld, trusted_uid=%ld, match found --> OK\n",
+ (UID_CAST)n, (UID_CAST)*list);
+#endif
+ SL_IRETURN(S_TRUE, _("isin"));
+}
+
+/* comment added by R. Wichmann
+ * RETURN TRUE if ANYONE in ulist is group member
+ */
+/* not static to circumvent stupid gcc 4 bug */
+int isingrp(gid_t grp, uid_t *ulist, int * errval)
+{
+ struct passwd *w; /* info about group member */
+ register uid_t *u; /* points to current ulist member */
+ register char **p; /* points to current group member */
+ struct group *g; /* pointer to group information */
+
+ int status;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ struct group gr;
+ char * buffer = NULL;
+ struct passwd pwd;
+ char * pbuffer = NULL;
+#endif
+
+ SL_ENTER(_("isingrp"));
+
+ *errval = 0;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ buffer = calloc(1,SH_GRBUF_SIZE);
+ status = sh_getgrgid_r(grp, &gr, buffer, SH_GRBUF_SIZE, &g);
+#else
+ errno = 0;
+ g = sh_getgrgid(grp);
+ status = errno;
+#endif
+
+ if (g == NULL)
+ {
+ if (status == ERANGE)
+ *errval = status;
+
+ goto end_false;
+ }
+
+ /* this will return at the first match
+ */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ pbuffer = calloc(1,SH_PWBUF_SIZE);
+#endif
+
+ for(p = g->gr_mem; *p != NULL; p++)
+ {
+ for(u = ulist; *u != tf_uid_neg; u++)
+ {
+ /* map user name to UID and compare */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ sh_getpwnam_r(*p, &pwd, pbuffer, SH_PWBUF_SIZE, &w);
+#else
+ w = sh_getpwnam(*p);
+#endif
+
+#ifdef TRUST_MAIN
+ if (w != NULL && *u == (uid_t)(w->pw_uid) )
+ goto end_true;
+#else
+ if (w != NULL && *u == (uid_t)(w->pw_uid) )
+ {
+ goto end_true;
+ }
+#endif
+ }
+ }
+ /* added by R. Wichmann Fri Mar 30 08:16:14 CEST 2001:
+ * a user can have a GID but no entry in /etc/group
+ */
+ for(u = ulist; *u != tf_uid_neg; u++)
+ {
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
+ sh_getpwuid_r(*u, &pwd, pbuffer, SH_PWBUF_SIZE, &w);
+#else
+ w = sh_getpwuid(*u);
+#endif
+#ifdef TRUST_MAIN
+ if (w != NULL && grp == (gid_t)(w->pw_gid) )
+ goto end_true;
+#else
+ if (w != NULL && grp == (gid_t)(w->pw_gid) )
+ {
+ goto end_true;
+ }
+#endif
+ }
+
+ end_false:
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ if (buffer) free(buffer);
+ if (pbuffer) free(pbuffer);
+#endif
+ SL_IRETURN(S_FALSE, _("isingrp"));
+
+ end_true:
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ if (buffer) free(buffer);
+ if (pbuffer) free(pbuffer);
+#endif
+ SL_IRETURN(S_TRUE, _("isingrp"));
+}
+
+/* added by R. Wichmann Fri Mar 30 08:16:14 CEST 2001
+ * RETURN TRUE only if ALL group members are trusted
+ */
+/* not static to circumvent stupid gcc 4 bug */
+int onlytrustedingrp(gid_t grp, uid_t *ulist, int * errval)
+{
+ struct passwd *w; /* info about group member */
+ register uid_t *u; /* points to current ulist member */
+ register char **p; /* points to current group member */
+ struct group *g; /* pointer to group information */
+ register int flag = -1; /* group member found */
+
+ int status;
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ struct group gr;
+ char * buffer = NULL;
+ struct passwd pw;
+ char * pbuffer = NULL;
+#endif
+
+ int retval = S_FALSE;
+
+ SL_ENTER(_("onlytrustedingrp"));
+
+ *errval = 0;
+
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "trustfile: group writeable, group_gid: %ld\n",
+ (UID_CAST)grp);
+#endif
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ buffer = calloc(1,SH_GRBUF_SIZE);
+ status = sh_getgrgid_r(grp, &gr, buffer, SH_GRBUF_SIZE, &g);
+#else
+ errno = 0;
+ g = sh_getgrgid(grp);
+ status = errno;
+#endif
+
+ if (g == NULL)
+ {
+ if (status == ERANGE)
+ *errval = status;
+
+#ifdef TRUST_DEBUG
+ fprintf(stderr,
+ "trustfile: group_gid: %ld, no such group --> ERROR\n",
+ (UID_CAST)grp);
+#endif
+ retval = S_FALSE;
+ goto end_retval;
+ }
+
+ /* empty group -> no problem
+
+ if(g->gr_mem == NULL || g->gr_mem[0] == NULL )
+ SL_IRETURN(S_TRUE, _("onlytrustedingrp") );
+ */
+
+ /* check for untrusted members of the group
+ */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ pbuffer = calloc(1,SH_PWBUF_SIZE);
+#endif
+
+ for(p = g->gr_mem; *p != NULL; p++)
+ {
+ flag = -1;
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "trustfile: group_member: %s\n", *p);
+#endif
+ /* map user name to UID and compare
+ */
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
+ sh_getpwnam_r(*p, &pw, pbuffer, SH_PWBUF_SIZE, &w);
+#else
+ w = sh_getpwnam(*p);
+#endif
+
+ if (w == NULL) /* not a valid user, ignore */
+ {
+ flag = 0;
+ }
+ else /* check list of trusted users */
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: uid=%ld, checking whether it is trusted\n",
+ (UID_CAST)(w->pw_uid));
+#endif
+ for(u = ulist; *u != tf_uid_neg; u++)
+ {
+ if (*u == (w->pw_uid) )
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: uid=%ld, trusted_uid=%ld, match found --> OK\n",
+ (UID_CAST)(w->pw_uid), (UID_CAST)*u);
+#endif
+ flag = 0;
+ break;
+ }
+ else
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: uid=%ld, trusted_uid=%ld, no match\n",
+ (UID_CAST)(w->pw_uid), (UID_CAST)*u);
+#endif
+ ;
+ }
+ }
+ }
+ /* not found
+ */
+ if (flag == -1)
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: user=%s (gid %ld), not a trusted user --> ERROR\n", *p, (UID_CAST)grp);
+#endif
+ tf_baduid = w->pw_uid;
+ retval = S_FALSE;
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ if (pbuffer) free(pbuffer);
+#endif
+ goto end_retval;
+ }
+ }
+
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ if (pbuffer) free(pbuffer);
+#endif
+
+#ifndef TEST_ONLY
+#ifdef HAVE_GETPWENT
+ /* now check ALL users for their GID !!!
+ */
+ SH_MUTEX_LOCK(mutex_pwent);
+
+ while (NULL != (w = sh_getpwent()))
+ {
+ if (grp == (gid_t)(w->pw_gid))
+ {
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "trustfile: checking group member %s, uid %ld\n",
+ w->pw_name, (UID_CAST)w->pw_uid);
+#endif
+ /* is it a trusted user ?
+ */
+ flag = -1;
+ for(u = ulist; *u != tf_uid_neg; u++)
+ {
+ if (*u == (uid_t)(w->pw_uid))
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: uid=%ld, trusted_uid=%ld, match found --> OK\n",
+ (UID_CAST)(w->pw_uid), (UID_CAST)(*u));
+#endif
+ flag = 0;
+ break;
+ }
+ else
+ {
+#ifdef TRUST_DEBUG
+ fprintf (stderr,
+ "trustfile: uid=%ld, trusted_uid=%ld, no match\n",
+ (UID_CAST)(w->pw_uid), (UID_CAST)*u);
+#endif
+ ;
+ }
+ }
+ /* not found */
+ if (flag == -1)
+ {
+#ifdef TRUST_DEBUG
+ fprintf(stderr,"trustfile: group member %s not found in trusted users --> ERROR\n", w->pw_name);
+#endif
+ tf_baduid = w->pw_uid;
+ retval = S_FALSE;
+ goto out;
+ /* SL_IRETURN(S_FALSE, _("onlytrustedingrp")); */
+ }
+ }
+ }
+ retval = S_TRUE;
+
+ out:
+
+#ifdef HAVE_ENDPWENT
+ sh_endpwent();
+#endif
+
+ SH_MUTEX_UNLOCK(mutex_pwent);
+
+ /* TEST_ONLY */
+#endif
+ /* #ifdef HAVE_GETPWENT */
+#endif
+
+#ifdef TRUST_DEBUG
+ if (retval == S_TRUE)
+ fprintf(stderr,
+ "trustfile: group %ld: all members are trusted users --> OK\n",
+ (UID_CAST)grp);
+#endif
+ /* all found
+ */
+ end_retval:
+#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
+ if (buffer) free(buffer);
+#endif
+ SL_IRETURN(retval, _("onlytrustedingrp"));
+}
+
+int sl_trustfile(const char *fname, uid_t *okusers, uid_t *badusers)
+{
+ char * fexp = NULL; /* file name fully expanded */
+ register char *p; /* used to hold name to be checked */
+ struct stat stbuf; /* used to check file permissions */
+ char c; /* used to hold temp char */
+
+ int errgrp = 0;
+
+ SL_ENTER(_("sl_trustfile"));
+ if (fname == NULL)
+ SL_IRETURN(SL_EBADFILE, _("sl_trustfile"));
+
+ fexp = calloc(1, MAXFILENAME );
+ if (!fexp)
+ SL_IRETURN(SL_EMEM, _("sl_trustfile"));
+
+ p = fexp;
+
+ /*
+ * next expand to the full file name
+ * getfname sets sl_errno as appropriate
+ */
+#ifdef TRUST_MAIN
+ sl_errno = getfname(fname, fexp, MAXFILENAME);
+ if (sl_errno != 0)
+ {
+ free(fexp);
+ return sl_errno;
+ }
+#else
+ if (SL_ISERROR(getfname(fname, fexp, MAXFILENAME)))
+ {
+ free(fexp);
+ SL_IRETURN(sl_errno, _("sl_trustfile"));
+ }
+#endif
+
+ if (okusers == NULL && badusers == NULL)
+ {
+ okusers = rootonly;
+ rootonly[EUIDSLOT] = tf_euid;
+ }
+
+ /*
+ * now loop through the path a component at a time
+ * note we have to special-case root
+ */
+ while(*p)
+ {
+ /*
+ * get next component
+ */
+ while(*p && *p != '/')
+ p++;
+
+ /* save where you are
+ */
+ if (p == fexp)
+ {
+ /* keep the / if it's the root dir
+ */
+ c = p[1];
+ p[1] = '\0';
+ }
+ else
+ {
+ /* clobber the / if it isn't the root dir
+ */
+ c = *p;
+ *p = '\0';
+ }
+
+ /*
+ * now get the information
+ */
+ if (retry_lstat(FIL__, __LINE__, fexp, &stbuf) < 0)
+ {
+ (void) strncpy(tf_path, fexp, sizeof(tf_path));
+ tf_path[sizeof(tf_path)-1] = '\0';
+#ifdef TRUST_MAIN
+ fprintf(stderr, "---------------------------------------------\n");
+ fprintf(stderr, "trustfile: ESTAT: stat(%s) failed,\n", fexp);
+ fprintf(stderr, "maybe the file does not exist\n");
+ fprintf(stderr, "---------------------------------------------\n");
+#endif
+ free(fexp);
+ SL_IRETURN(SL_ESTAT, _("sl_trustfile"));
+ }
+
+#ifdef S_IFLNK
+ /*
+ * if it's a symbolic link, recurse
+ */
+ if ((stbuf.st_mode & S_IFLNK) == S_IFLNK)
+ {
+ /*
+ * this is tricky
+ * if the symlink is to an absolute path
+ * name, just call trustfile on it; but
+ * if it's a relative path name, it's
+ * interpreted WRT the current working
+ * directory AND NOT THE FILE NAME!!!!!
+ * so, we simply put /../ at the end of
+ * the file name, then append the symlink
+ * contents; trustfile will canonicalize
+ * this, and the /../ we added "undoes"
+ * the name of the symlink to put us in
+ * the current working directory, at
+ * which point the symlink contents (appended
+ * to the CWD) are interpreted correctly.
+ * got it?
+ */
+ char * csym; /* contents of symlink file */
+ char * full; /* "full" name of symlink */
+ char *b; /* used to copy stuff around */
+ const char *t; /* used to copy stuff around */
+ int lsym; /* num chars in symlink ref */
+ int i; /* trustworthy or not? */
+ const char * t_const;
+ char *end;
+
+ /*
+ * get what the symbolic link points to
+ *
+ * The original code does not check the return code of readlink(),
+ * and has an off-by-one error
+ * (MAXFILENAME instead of MAXFILENAME-1)
+ * R.W. Tue May 29 22:05:16 CEST 2001
+ */
+ csym = calloc(1, MAXFILENAME );
+ if (!csym)
+ {
+ free(fexp);
+ SL_IRETURN(SL_EMEM, _("sl_trustfile"));
+ }
+
+ lsym = readlink(fexp, csym, MAXFILENAME-1);
+ if (lsym >= 0)
+ csym[lsym] = '\0';
+ else
+ {
+#ifdef TRUST_MAIN
+ fprintf(stderr, "---------------------------------------------\n");
+ fprintf(stderr, "trustfile: EBADNAME: readlink(%s) failed\n",
+ fexp);
+ fprintf(stderr, "---------------------------------------------\n");
+#endif
+ free(csym);
+ free(fexp);
+ SL_IRETURN(SL_EBADNAME, _("sl_trustfile"));
+ }
+
+ full = calloc(1, MAXFILENAME );
+ if (!full)
+ {
+ free(csym);
+ free(fexp);
+ SL_IRETURN(SL_EMEM, _("sl_trustfile"));
+ }
+
+ /*
+ * relative or absolute referent?
+ */
+ if (csym[0] != '/')
+ {
+ /* pointer to one above last element
+ */
+ end = &full[MAXFILENAME-1]; ++end;
+
+ /* initialize pointers
+ */
+ b = full;
+
+ /* copy in base path
+ */
+ t = fexp;
+ while(*t && b < end)
+ *b++ = *t++;
+
+ /* smack on the /../
+ */
+ t_const = "/../"; t = (const char *)t_const;
+ while(*t && b < end)
+ *b++ = *t++;
+
+ /* append the symlink referent
+ */
+ t = csym;
+ while(*t && b < end)
+ *b++ = *t++;
+
+ /* see if we're too big
+ */
+ if (*t || b == end)
+ {
+ /* yes -- error
+ */
+ (void) strncpy(tf_path, fexp, sizeof(tf_path));
+ tf_path[sizeof(tf_path)-1] = '\0';
+#ifdef TRUST_MAIN
+ fprintf(stderr, "---------------------------------------------\n");
+ fprintf(stderr,
+ "trustfile: ETRUNC: normalized path too long (%s)\n",
+ fexp);
+ fprintf(stderr, "---------------------------------------------\n");
+#endif
+ free(full);
+ free(csym);
+ free(fexp);
+ SL_IRETURN(SL_ETRUNC, _("sl_trustfile"));
+ }
+ *b = '\0';
+ }
+ else
+ {
+ /* absolute -- just copy */
+ /* overflow can't occur as the arrays */
+ /* are the same size */
+ (void) strcpy(full, csym); /* known to fit */
+ }
+ /*
+ * now check out this file and its ancestors
+ */
+ if ((i = sl_trustfile(full, okusers, badusers)) != SL_ENONE)
+ {
+ free(full);
+ free(csym);
+ free(fexp);
+ SL_IRETURN(i, _("sl_trustfile"));
+ }
+
+ /*
+ * okay, this part is valid ... let's check the rest
+ * put the / back
+ */
+ if (p == fexp)
+ {
+ /* special case for root */
+ p[1] = c;
+ p++;
+ }
+ else
+ {
+ /* ordinary case for everything else */
+ *p = c;
+ if (*p)
+ p++;
+ }
+ free(full);
+ free(csym);
+ continue;
+ }
+#endif
+
+
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "\ntrustfile: checking path=%s\n", fexp);
+#endif
+ /*
+ * if the owner is not trusted then -- as the owner can
+ * change protection modes -- he/she can write to the
+ * file regardless of permissions, so bomb
+ */
+ if (((okusers != NULL && S_FALSE == isin((uid_t)stbuf.st_uid,okusers))||
+ (badusers != NULL && S_TRUE == isin((uid_t)stbuf.st_uid,badusers))))
+ {
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "---------------------------------------------\n");
+ fprintf(stderr, "trustfile: EBADUID %s (owner not trusted)\n",
+ fexp);
+ fprintf(stderr, "The owner of this file/directory is not in samhains\n");
+ fprintf(stderr, "list of trusted users.\n");
+ fprintf(stderr, "Please run ./configure again with the option\n");
+ fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n");
+ fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n");
+ fprintf(stderr, "---------------------------------------------\n");
+#endif
+ (void) strncpy(tf_path, fexp, sizeof(tf_path));
+ tf_path[sizeof(tf_path)-1] = '\0';
+
+ tf_baduid = (uid_t) stbuf.st_uid;
+ free(fexp);
+ SL_IRETURN(SL_EBADUID, _("sl_trustfile"));
+ }
+
+ /*
+ * if a group member can write but the
+ * member is not trusted, bomb; but if
+ * sticky bit semantics are honored, it's
+ * okay
+ */
+ /* Thu Mar 29 21:10:28 CEST 2001 Rainer Wichmann
+ * replace !isingrp() with onlytrustedingrp(), as isingrp()
+ * will return at the first trusted user, even if there are additional
+ * (untrusted) users in the group
+ */
+ if (((stbuf.st_mode & S_IWGRP) == S_IWGRP) &&
+ ((okusers != NULL && !onlytrustedingrp((gid_t)stbuf.st_gid,okusers,&errgrp))||
+ (badusers != NULL && isingrp((gid_t)stbuf.st_gid, badusers,&errgrp)))
+#ifdef STICKY
+ && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
+ (stbuf.st_mode&S_ISVTX) != S_ISVTX)
+#endif
+ )
+ {
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "---------------------------------------------\n");
+ fprintf(stderr,
+ "trustfile: EBADGID %ld %s (group member not trusted)\n",
+ (UID_CAST)stbuf.st_gid, fexp);
+ fprintf(stderr, "This file/directory is group writeable, and one of the group members\n");
+ fprintf(stderr, "is not in samhains list of trusted users.\n");
+ fprintf(stderr, "Please run ./configure again with the option\n");
+ fprintf(stderr, " ./configure [more options] --with-trusted=0,...,UID\n");
+ fprintf(stderr, "where UID is the UID of the (yet) untrusted user.\n");
+ fprintf(stderr, "---------------------------------------------\n");
+#endif
+ (void) strncpy(tf_path, fexp, sizeof(tf_path));
+ tf_path[sizeof(tf_path)-1] = '\0';
+
+ tf_badgid = (gid_t) stbuf.st_gid;
+ free(fexp);
+ SL_IRETURN((errgrp == ERANGE) ? SL_ERANGE : SL_EBADGID, _("sl_trustfile"));
+ }
+ /*
+ * if other can write, bomb; but if the sticky
+ * bit semantics are honored, it's okay
+ */
+ if (((stbuf.st_mode & S_IWOTH) == S_IWOTH)
+#ifdef STICKY
+ && ((stbuf.st_mode&S_IFDIR) != S_IFDIR ||
+ (stbuf.st_mode&S_ISVTX) != S_ISVTX)
+#endif
+ )
+ {
+#ifdef TRUST_DEBUG
+ fprintf(stderr, "---------------------------------------------\n");
+ fprintf(stderr, "trustfile: EBADOTH (world writeable): %s\n",
+ fexp);
+ fprintf(stderr, "This file/directory is world writeable.\n");
+ fprintf(stderr, "---------------------------------------------\n");
+#endif
+ (void) strncpy(tf_path, fexp, sizeof(tf_path));
+ tf_path[sizeof(tf_path)-1] = '\0';
+
+ free(fexp);
+ SL_IRETURN(SL_EBADOTH, _("sl_trustfile"));
+ }
+ /*
+ * put the / back
+ */
+ if (p == fexp)
+ {
+ /* special case for root */
+ p[1] = c;
+ p++;
+ }
+ else
+ {
+ /* ordinary case for everything else */
+ *p = c;
+ if (*p)
+ p++;
+ }
+ }
+ /*
+ * yes, it can be trusted
+ */
+ (void) strncpy(tf_path, fexp, sizeof(tf_path));
+ tf_path[sizeof(tf_path)-1] = '\0';
+
+ free(fexp);
+ SL_IRETURN(SL_ENONE, _("sl_trustfile"));
+}
+
+#ifdef TRUST_MAIN
+
+#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__)
+int main()
+{
+ return 0;
+}
+#else
+int main (int argc, char * argv[])
+{
+ int status;
+#if defined(SH_WITH_SERVER)
+ struct passwd * pass;
+#endif
+
+ if (argc < 2) {
+ fprintf(stderr, "%s: Usage: %s <fullpath>\n", argv[0], argv[0]);
+ return 1;
+ }
+
+ tf_path[0] = '\0';
+#if defined(SH_WITH_SERVER)
+ pass = sh_getpwnam(SH_IDENT); /* TESTONLY */
+ if (pass != NULL)
+ tf_euid = pass->pw_uid;
+ else
+ {
+ fprintf(stderr, "trustfile: ERROR: getpwnam(%s) failed\n",
+ SH_IDENT);
+ return 1;
+ }
+#else
+ tf_euid = geteuid();
+#endif
+
+ status = sl_trustfile(argv[1], NULL, NULL);
+ if (status != SL_ENONE)
+ {
+ fprintf(stderr, "trustfile: ERROR: not a trusted path: %s\n",
+ argv[1]);
+ return 1;
+ }
+ return 0;
+}
+#endif
+#endif
+
+
+
diff --git a/src/yulectl.c b/src/yulectl.c
new file mode 100644
index 0000000..50a837b
--- /dev/null
+++ b/src/yulectl.c
@@ -0,0 +1,649 @@
+/* SAMHAIN file system integrity testing */
+/* Copyright (C) 2003 Rainer Wichmann */
+/* */
+/* This program is free software; you can redistribute it */
+/* and/or modify */
+/* it under the terms of the GNU General Public License as */
+/* published by */
+/* the Free Software Foundation; either version 2 of the License, or */
+/* (at your option) any later version. */
+/* */
+/* This program is distributed in the hope that it will be useful, */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
+/* GNU General Public License for more details. */
+/* */
+/* You should have received a copy of the GNU General Public License */
+/* along with this program; if not, write to the Free Software */
+/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config_xor.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <signal.h>
+#include <pwd.h>
+
+#if !defined(AF_FILE)
+#define AF_FILE AF_UNIX
+#endif
+
+#define SH_MAXMSG 209
+
+#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
+ !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && \
+ !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
+#define SH_REQ_PASSWORD 1
+#endif
+
+static int sock = -1;
+static char password[15] = "";
+static int verbose = 0;
+
+#ifdef SH_STEALTH
+char * globber(const char * string);
+#define _(string) globber(string)
+#define N_(string) string
+#else
+#define _(string) string
+#define N_(string) string
+#endif
+
+#ifdef SH_STEALTH
+#ifndef SH_MAX_GLOBS
+#define SH_MAX_GLOBS 32
+#endif
+char * globber(const char * str)
+{
+ register int i, j;
+ static int count = -1;
+ static char glob[SH_MAX_GLOBS][128];
+
+ ++count; if (count > (SH_MAX_GLOBS-1) ) count = 0;
+ j = strlen(str);
+ if (j > 127) j = 127;
+
+ for (i = 0; i < j; ++i)
+ {
+ if (str[i] != '\n' && str[i] != '\t')
+ glob[count][i] = str[i] ^ XOR_CODE;
+ else
+ glob[count][i] = str[i];
+ }
+ glob[count][j] = '\0';
+ return glob[count];
+}
+#endif
+
+#define CLIENT _("yulectl")
+
+
+static int
+create_unix_socket ()
+{
+ int sock;
+
+ /* Create the socket. */
+
+ sock = socket (PF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ perror (_("ERROR: socket"));
+ return -1;
+ }
+
+ return sock;
+}
+
+static void
+termination_handler (int signum)
+{
+ /* Clean up. */
+ if (signum != 0)
+ {
+ if (verbose)
+ fprintf(stdout, _("# Terminated on signal %d\n"), signum);
+ }
+ if (sock >= 0 )
+ close (sock);
+ return;
+}
+
+static char * safe_copy(char * to, const char * from, size_t size)
+{
+ if (to && from)
+ {
+ strncpy (to, from, size);
+ if (size > 0)
+ to[size-1] = '\0';
+ else
+ *to = '\0';
+ }
+ return to;
+}
+
+
+static int send_to_server (char * serversock, char * message)
+{
+ struct sockaddr_un name;
+ int size;
+ int nbytes;
+
+ /* Initialize the server socket address.
+ */
+ name.sun_family = AF_UNIX;
+ strncpy (name.sun_path, serversock, sizeof(name.sun_path) - 1);
+ size = (offsetof (struct sockaddr_un, sun_path)
+ + strlen (name.sun_path) + 1);
+
+ nbytes = connect(sock, (struct sockaddr *) & name, size);
+ if (nbytes < 0)
+ {
+ perror (_("ERROR: connect"));
+ return -1;
+ }
+
+ /* Send the data.
+ */
+ nbytes = send (sock, message, strlen (message) + 1, 0);
+ if (nbytes < 0)
+ {
+ perror (_("ERROR: send"));
+ return -1;
+ }
+ return 0;
+}
+
+static int getline_from_server (int sock, char * buf, int size)
+{
+ int nbytes = 0;
+ int status = 0;
+ char * p = buf;
+
+ do {
+ status = read (sock, p, 1);
+ if (status <= 0)
+ {
+ buf[nbytes] = '\0';
+ return ((status == 0) ? nbytes : status);
+ }
+ else if (*p == '\0')
+ {
+ return nbytes;
+ }
+ ++nbytes; ++p;
+ } while (nbytes < size);
+ buf[size-1] = '\0';
+ return 0;
+}
+
+static int recv_from_server (char * message)
+{
+ int nbytes = 0;
+ char recvmsg[SH_MAXMSG];
+ int num = 0;
+ int good = -1;
+ char * p;
+
+ if (password[0] == '\0')
+ p = message;
+ else
+ p = &message[strlen(password)+1];
+
+ if (0 == strncmp(p, _("PROBE"), 5) ||
+ 0 == strncmp(p, _("LIST"), 4))
+ {
+ do {
+ nbytes = getline_from_server (sock, recvmsg, SH_MAXMSG);
+ if (nbytes < 0)
+ {
+ if (errno == EAGAIN)
+ return 0;
+ else
+ {
+ perror (_("ERROR: recv"));
+ return -1;
+ }
+ }
+ else if (nbytes == 0)
+ return 0;
+
+ if (recvmsg[0] == 'E' && recvmsg[1] == 'N' && recvmsg[2] == 'D')
+ {
+ if (verbose && (num == 0))
+ fprintf (stdout, "%s", _("# There are no pending commands.\n"));
+ return 0;
+ }
+ ++num;
+ fprintf (stdout, _("%03d: %s\n"), num, recvmsg);
+ } while (nbytes >= 0);
+ }
+ else
+ {
+ nbytes = recv (sock, recvmsg, SH_MAXMSG, 0);
+ if (nbytes < 0)
+ {
+ perror (_("ERROR: recv"));
+ return -1;
+ }
+ }
+
+ /* Print a diagnostic message. */
+ if (password[0] == '\0')
+ good = strcmp (message, recvmsg);
+ else
+ good = strcmp (&message[strlen(password)+1], recvmsg);
+
+ if (0 != good)
+ {
+ if (0 == strncmp(recvmsg, _("!E:"), 3))
+ {
+ fputs(recvmsg, stderr);
+ fputc('\n', stderr);
+ }
+ else
+ {
+ fputs (_("ERROR: Bounced message != original message.\n"), stderr);
+ }
+ return -1;
+ }
+ else
+ {
+ if (verbose)
+ fprintf (stdout, "%s", _("# Message received by server.\n"));
+ }
+
+ return 0;
+}
+
+static int check_uuid(const char * in)
+{
+ int i;
+ const char *cp;
+
+ if (!in || strlen(in) != 36)
+ return -1;
+ for (i=0, cp = in; i <= 36; i++,cp++) {
+ if ((i == 8) || (i == 13) || (i == 18) ||
+ (i == 23)) {
+ if (*cp == '-')
+ continue;
+ else
+ return -1;
+ }
+ if (i== 36)
+ if (*cp == 0)
+ continue;
+ if (!isxdigit(*cp))
+ return -1;
+ }
+ return 0;
+}
+
+static int check_command(const char * str)
+{
+ unsigned int i = 0;
+ char * commands[] = { N_("DELTA:"), N_("RELOAD"), N_("STOP"), N_("SCAN"),
+ N_("CANCEL"), N_("LISTALL"), N_("LIST"), N_("PROBE"), NULL };
+
+ while (commands[i])
+ {
+ size_t len = strlen(_(commands[i]));
+
+ if (0 == strncmp(_(commands[i]), str, len))
+ {
+ if (i == 0)
+ {
+ char * p = strchr(str, ':'); ++p;
+ if ( 0 == check_uuid(p) )
+ return 0;
+ }
+ else
+ {
+ if (len == strlen(str))
+ return 0;
+ }
+ }
+ ++i;
+ }
+
+ fprintf (stderr, _("ERROR: invalid command <%s>\n\n"), str);
+ return -1;
+}
+
+static void print_usage_and_exit(char * name, int exit_status)
+{
+ printf(_("\nUsage : %s [-v][-s server_socket] -c command <client_hostname>\n\n"),
+ name);
+
+ printf("%s", _("Purpose : send commands to the server via a socket,\n"));
+ printf("%s", _(" in particular commands that the server would\n"));
+ printf("%s", _(" transfer to the client <client_hostname> when\n"));
+ printf("%s", _(" this client connects to deliver a message.\n\n"));
+ printf("%s", _(" If password is required, it is read from\n"));
+ printf("%s", _(" $HOME/.yulectl_cred or taken from the environment\n"));
+ printf("%s", _(" variable YULECTL_PASSWORD (not recommended).\n\n"));
+
+ printf("%s", _("Commands: RELOAD reload configuration\n"));
+ printf("%s", _(" DELTA:<uuid> load delta database with given uuid\n"));
+ printf("%s", _(" STOP terminate\n"));
+ printf("%s", _(" SCAN initiate file system check\n"));
+ printf("%s", _(" CANCEL cancel pending command(s)\n"));
+ printf("%s", _(" LIST list queued commands\n"));
+ printf("%s", _(" LISTALL list queued and last sent commands\n"));
+ printf("%s", _(" PROBE probe all clients for necessity of reload\n"));
+ exit(exit_status);
+}
+
+char * rtrim(char * str)
+{
+ size_t len;
+
+ if (!str) return str;
+
+ len = strlen(str);
+ while (len > 0)
+ {
+ --len;
+ if (str[len] == '\n' || str[len] == '\r')
+ str[len] = '\0';
+ else
+ break;
+ }
+ return str;
+}
+
+static int get_home(char * home, size_t size)
+{
+ struct passwd * pwent;
+
+ pwent = getpwuid(geteuid());
+ if ((pwent == 0) || (pwent->pw_dir == NULL))
+ {
+ if (verbose)
+ fprintf (stderr, _("WARNING: no home directory for euid %ld\n"),
+ (long) geteuid());
+ if (NULL != getenv(_("HOME")))
+ {
+ safe_copy(home, getenv(_("HOME")), size);
+ }
+ else
+ {
+ fprintf (stderr, _("ERROR: no home directory for euid %ld (tried $HOME and password database).\n"), (long) geteuid());
+ return -1;
+ }
+ }
+ else
+ {
+ safe_copy(home, pwent->pw_dir, size);
+ }
+ return 0;
+}
+
+static int get_passwd(char * message2, size_t size)
+{
+ char home[4096];
+ FILE * fp;
+ char * pw;
+
+ /* 1) Password from environment
+ */
+ pw = getenv(_("YULECTL_PASSWORD"));
+ if (pw && strlen(pw) < 15)
+ {
+ strcpy(password, pw);
+ strcpy(message2, password);
+ return 0;
+ }
+
+ /* 2) Password from $HOME/.yule_cred
+ */
+ if (get_home(home, sizeof(home)) < 0)
+ return -1;
+
+ if ( (strlen(home) + strlen(_("/.yulectl_cred")) + 1) > 4096)
+ {
+ fprintf (stderr, "%s", _("ERROR: path for $HOME is too long.\n"));
+ return -1;
+ }
+ strcat(home, _("/.yulectl_cred"));
+ fp = fopen(home, "r");
+
+#if defined(SH_REQ_PASSWORD)
+ if (fp == NULL)
+ {
+ if (errno == ENOENT) {
+ fprintf (stderr,
+ _("ERROR No password file (%s) exists\n"),
+ home);
+ }
+ else {
+ fprintf (stderr,
+ _("ERROR: Password file (%s) not accessible for euid %ld uid %ld\n"),
+ home, (long)geteuid(), (long)getuid());
+ }
+ return -1;
+ }
+#else
+ if (fp == NULL)
+ return 0;
+#endif
+
+ if (NULL == fgets(message2, size, fp))
+ {
+ fprintf (stderr,
+ _("ERROR: empty or unreadable password file (%s).\n"),
+ home);
+ return -1;
+ }
+
+ (void) rtrim(message2);
+
+ if (strlen(message2) > 14)
+ {
+ fprintf (stderr, "%s",
+ _("ERROR: Password too long (max. 14 characters).\n"));
+ return -1;
+ }
+ strcpy(password, message2);
+ fclose(fp);
+
+ return 0;
+}
+
+static int fixup_message (char * message)
+{
+ char message_fixed[SH_MAXMSG] = { 0 };
+
+ if (get_passwd(message_fixed, sizeof(message_fixed)) < 0)
+ return -1;
+
+ if (strlen(message_fixed) > 0)
+ {
+ strcat(message_fixed, "@");
+
+ strncat(message_fixed, message, SH_MAXMSG - strlen(message_fixed) -1);
+ message_fixed[SH_MAXMSG-1] = '\0';
+ strcpy(message, message_fixed);
+ }
+ return 0;
+}
+
+static int fill_serversock(char * serversock, size_t size)
+{
+ int status;
+
+#ifdef HAVE_VSNPRINTF
+ status = snprintf(serversock, size, _("%s/%s.sock"),
+ DEFAULT_PIDDIR, SH_INSTALL_NAME);
+#else
+ if ((strlen(DEFAULT_PIDDIR) + strlen(SH_INSTALL_NAME) + 1 + 6) > size)
+ status = -1;
+ else
+ status = sprintf (serversock, _("%s/%s.sock"),
+ DEFAULT_PIDDIR, SH_INSTALL_NAME);
+#endif
+
+ if ((status < 0) || (status > (int)(size-1)))
+ {
+ fprintf(stderr, _("ERROR: Path too long (maximum %d): %s/%s.sock\n"),
+ (int) (size-1), DEFAULT_PIDDIR, SH_INSTALL_NAME);
+ return -1;
+ }
+ return 0;
+}
+
+static void checklen(char * command, char * str, size_t maxlen)
+{
+ if (strlen(str) > maxlen)
+ {
+ fprintf(stderr, _("ERROR: String too long (max %d): %s\n\n"),
+ (int) maxlen, str);
+ print_usage_and_exit (command, EXIT_FAILURE);
+ }
+ return;
+}
+
+static void checknull(char * command, char * str)
+{
+ if (str == NULL || str[0] == '\0') {
+ fprintf(stderr, "%s", _("ERROR: option with missing argument\n\n"));
+ print_usage_and_exit(command, EXIT_FAILURE);
+ }
+ return;
+}
+
+int
+main (int argc, char * argv[])
+{
+
+ char message[SH_MAXMSG] = "";
+ char serversock[256];
+ int status;
+ int num = 1;
+ int flag = 0;
+
+ if (fill_serversock(serversock, sizeof(serversock)) < 0)
+ return (EXIT_FAILURE);
+
+
+ while (argc > 1 && argv[num][0] == '-')
+ {
+ switch (argv[num][1])
+ {
+ case 'h':
+ print_usage_and_exit(argv[0], EXIT_SUCCESS);
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 's':
+ --argc; ++num;
+ checknull(argv[0], argv[num]);
+ checklen(argv[0], argv[num], sizeof(serversock)-1);
+ safe_copy (serversock, argv[num], sizeof(serversock));
+ break;
+ case 'c':
+ --argc; ++num;
+ checknull(argv[0], argv[num]);
+ checklen(argv[0], argv[num], SH_MAXMSG-1);
+ if (0 != check_command(argv[num]))
+ print_usage_and_exit(argv[0], EXIT_FAILURE);
+ safe_copy(message, argv[num], SH_MAXMSG);
+ strncat(message, ":", SH_MAXMSG-strlen(message)-1);
+ message[SH_MAXMSG-1] = '\0';
+ flag = 1;
+ break;
+ default:
+ fprintf(stderr, _("ERROR: unknown option -%c\n\n"), argv[num][1]);
+ print_usage_and_exit(argv[0], EXIT_FAILURE);
+ break;
+ }
+ --argc; ++num;
+ }
+
+ if (flag == 0) /* no command given */
+ print_usage_and_exit(argv[0], EXIT_FAILURE);
+
+ if (argc > 1)
+ {
+ checklen(argv[0], argv[num], SH_MAXMSG - strlen(message) - 1);
+ strncat (message, argv[num], SH_MAXMSG - strlen(message) - 1);
+ message[SH_MAXMSG-1] = '\0';
+ }
+ else
+ {
+ if (0 == strncmp(message, _("PROBE"), 5) ||
+ 0 == strncmp(message, _("LIST"), 4))
+ {
+ strncat (message, _("dummy"), SH_MAXMSG -strlen(message) - 1);
+ message[SH_MAXMSG-1] = '\0';
+ }
+ else
+ {
+ fprintf(stderr, "%s", _("ERROR: this command requires a hostname\n"));
+ print_usage_and_exit(argv[0], EXIT_FAILURE);
+ }
+ }
+
+ if (fixup_message(message) < 0)
+ return (EXIT_FAILURE);
+
+ /* Make the socket.
+ */
+ sock = create_unix_socket ();
+ if (sock < 0)
+ return (EXIT_FAILURE);
+
+ /* Set up termination handler.
+ */
+ signal (SIGINT, termination_handler);
+ signal (SIGHUP, termination_handler);
+ signal (SIGTERM, termination_handler);
+ signal (SIGQUIT, termination_handler);
+
+ /* Send the datagram.
+ */
+ status = send_to_server (serversock, message);
+ if (status < 0)
+ {
+ fprintf(stderr, "%s", _("ERROR: sending command to server failed\n"));
+ (void) termination_handler(0);
+ return (EXIT_FAILURE);
+ }
+
+ /* Wait for a reply.
+ */
+ if (verbose)
+ {
+ if (0 == strncmp(message, "LIST", 4))
+ fprintf(stdout, "%s", _("# Waiting for listing.\n"));
+ else
+ fprintf(stdout, "%s", _("# Waiting for confirmation.\n"));
+ }
+
+ status = recv_from_server (message);
+
+ if (status < 0)
+ {
+ fputs(_("ERROR: unexpected or no reply from server.\n"), stderr);
+ (void) termination_handler(0);
+ return (EXIT_FAILURE);
+ }
+
+ /* Clean up. */
+ (void) termination_handler(0);
+ return (EXIT_SUCCESS);
+}
+
diff --git a/src/zAVLTree.c b/src/zAVLTree.c
new file mode 100644
index 0000000..769d86b
--- /dev/null
+++ b/src/zAVLTree.c
@@ -0,0 +1,608 @@
+/*
+ * zAVLTree.c: Source code for zAVLTrees.
+ * Copyright (C) 1998,2001 Michael H. Buselli
+ * This is version 0.1.3 (alpha).
+ * Generated from $Id: xAVLTree.c.sh,v 1.5 2001/06/07 06:58:28 cosine Exp $
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * The author of this library can be reached at the following address:
+ * Michael H. Buselli
+ * 30051 N. Waukegan Rd. Apt. 103
+ * Lake Bluff, IL 60044-5412
+ *
+ * Or you can send email to <cosine@cosine.org>.
+ * The official web page for this product is:
+ * http://www.cosine.org/project/AVLTree/
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "zAVLTree.h"
+
+/* Interface for handling "string only" items rw 2014-06-26
+ */
+static zAVLKey zstring_key (void const * arg)
+{
+ return (zAVLKey) arg;
+}
+
+char * dummy_zfree_string;
+#ifdef __clang__
+char * dummy_zfree_str;
+#endif
+
+static void zfree_string (void * inptr)
+{
+#ifdef __clang__
+ dummy_zfree_str = (char *) inptr;
+#else
+ char * str = (char *) inptr;
+#endif
+
+ /* Take the address to circumvent gcc 4.9 optimizer bug */
+ dummy_zfree_string = (char *) &inptr;
+
+#ifdef __clang__
+ dummy_zfree_str[0] = '\0';
+ free (dummy_zfree_str);
+#else
+ str[0] = '\0';
+ free (inptr);
+#endif
+ return;
+}
+void zAVL_string_reset (zAVLTree * tree)
+{
+ if (tree)
+ zAVLFreeTree (tree, zfree_string);
+ return;
+}
+int zAVL_string_set (zAVLTree ** tree, const char * key)
+{
+ if (tree && key)
+ {
+ zAVLTree * itree = (*tree);
+ if (!itree)
+ {
+ itree = zAVLAllocTree (zstring_key, zAVL_KEY_STRING);
+ if (!itree)
+ {
+ return -1;
+ }
+ }
+ *tree = itree;
+ return zAVLInsert (itree, strdup(key));
+ }
+ return -1;
+}
+char * zAVL_string_get (zAVLTree * tree, const char * key)
+{
+ /* zAVLSearch() checks for NULL tree
+ */
+ if (key)
+ {
+ return ((char *) zAVLSearch (tree, key));
+ }
+ return NULL;
+}
+void zAVL_string_del (zAVLTree * tree, const char * key)
+{
+ /* zAVLSearch() checks for NULL tree
+ */
+ if (key)
+ {
+ char * item = ((char *) zAVLSearch (tree, key));
+ if (item)
+ {
+ zAVLDelete(tree, key);
+ zfree_string(item);
+ }
+ }
+ return;
+}
+
+
+
+/* Wed Nov 23 17:57:42 CET 2005 rw: introduce third argument in
+ * zAVLCloseSearchNode() to avoid redundant strcmp
+ */
+static zAVLNode *zAVLCloseSearchNode (zAVLTree const *avltree, zAVLKey key,
+ int * ok);
+static void zAVLRebalanceNode (zAVLTree *avltree, zAVLNode *avlnode);
+static void zAVLFreeBranch (zAVLNode *avlnode, void (freeitem)(void *item));
+static void zAVLFillVacancy (zAVLTree *avltree,
+ zAVLNode *origparent, zAVLNode **superparent,
+ zAVLNode *left, zAVLNode *right);
+
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define L_DEPTH(n) ((n)->left ? (n)->left->depth : 0)
+#define R_DEPTH(n) ((n)->right ? (n)->right->depth : 0)
+#define CALC_DEPTH(n) (MAX(L_DEPTH(n), R_DEPTH(n)) + 1)
+
+#define ZAVL_OK 1
+#define ZAVL_NO 0
+
+/* The comparison function. Was a macro, but this allows for more
+ * flexibility (non-string keys). The key is a (void *) now, and
+ * the type is stored in the zAVLTree struct. Oct 21, 2011, rw
+ */
+static int zAVLKey_cmp(const zAVLTree * tree, zAVLKey a, zAVLKey b)
+{
+ if (tree->keytype == zAVL_KEY_STRING)
+ {
+ return (strcmp((const char*)a, (const char *)b));
+ }
+ else /* zAVL_KEY_INT */
+ {
+ const int x = *((const int *)a);
+ const int y = *((const int *)b);
+
+ if (x > y) return 1;
+ else if (x < y) return -1;
+ else return 0;
+ }
+}
+
+/*
+ * AVLAllocTree:
+ * Allocate memory for a new AVL tree and set the getkey function for
+ * that tree. The getkey function should take an item and return an
+ * AVLKey that is to be used for indexing this object in the AVL tree.
+ * On success, a pointer to the malloced AVLTree is returned. If there
+ * was a malloc failure, then NULL is returned.
+ */
+zAVLTree *zAVLAllocTree (zAVLKey (*getkey)(void const *item), int keytype)
+{
+ zAVLTree *rc;
+
+ rc = calloc(1, sizeof(zAVLTree));
+ if (rc == NULL)
+ return NULL;
+
+ rc->top = NULL;
+ rc->count = 0;
+ rc->getkey = getkey;
+ rc->keytype = keytype;
+ return rc;
+}
+
+
+/*
+ * AVLFreeTree:
+ * Free all memory used by this AVL tree. If freeitem is not NULL, then
+ * it is assumed to be a destructor for the items reference in the AVL
+ * tree, and they are deleted as well.
+ */
+void zAVLFreeTree (zAVLTree *avltree, void (freeitem)(void *item))
+{
+ if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
+ return;
+ if (avltree->top)
+ zAVLFreeBranch(avltree->top, freeitem);
+ free(avltree);
+}
+
+
+/*
+ * AVLInsert:
+ * Create a new node and insert an item there.
+ *
+ * Returns 0 on success,
+ * -1 on malloc failure,
+ * 3 if duplicate key.
+ */
+int zAVLInsert (zAVLTree *avltree, void *item)
+{
+ zAVLNode *newnode;
+ zAVLNode *node;
+ zAVLNode *balnode;
+ zAVLNode *nextbalnode;
+ int ok;
+
+ newnode = calloc(1, sizeof(zAVLNode));
+ if (newnode == NULL)
+ return -1;
+
+ newnode->key = avltree->getkey(item);
+ newnode->item = item;
+ newnode->depth = 1;
+ newnode->left = NULL;
+ newnode->right = NULL;
+ newnode->parent = NULL;
+
+ if (avltree->top != NULL) {
+ node = zAVLCloseSearchNode(avltree, newnode->key, &ok);
+
+ if (ok == ZAVL_OK) { /* exists already */
+ free(newnode);
+ return 3;
+ }
+
+ newnode->parent = node;
+
+ if (zAVLKey_cmp(avltree, newnode->key, node->key) < 0) {
+ node->left = newnode;
+ node->depth = CALC_DEPTH(node);
+ }
+
+ else {
+ node->right = newnode;
+ node->depth = CALC_DEPTH(node);
+ }
+
+ for (balnode = node->parent; balnode; balnode = nextbalnode) {
+ nextbalnode = balnode->parent;
+ zAVLRebalanceNode(avltree, balnode);
+ }
+ }
+
+ else {
+ avltree->top = newnode;
+ }
+
+ avltree->count++;
+ return 0;
+}
+
+
+/*
+ * zAVLSearch:
+ * Return a pointer to the item with the given key in the AVL tree. If
+ * no such item is in the tree, then NULL is returned.
+ */
+void *zAVLSearch (zAVLTree const *avltree, zAVLKey key)
+{
+ zAVLNode *node;
+ int ok;
+
+ if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
+ return NULL;
+
+ node = zAVLCloseSearchNode(avltree, key, &ok);
+
+ if (node && ok == ZAVL_OK)
+ return node->item;
+
+ return NULL;
+}
+
+
+/*
+ * zAVLDelete:
+ * Deletes the node with the given key. Does not delete the item at
+ * that key. Returns 0 on success and -1 if a node with the given key
+ * does not exist.
+ */
+int zAVLDelete (zAVLTree *avltree, zAVLKey key)
+{
+ zAVLNode *avlnode;
+ zAVLNode *origparent;
+ zAVLNode **superparent;
+ int ok;
+
+ avlnode = zAVLCloseSearchNode(avltree, key, &ok);
+ if (avlnode == NULL || ok == ZAVL_NO) /* does not exist */
+ return -1;
+
+ origparent = avlnode->parent;
+
+ if (origparent) {
+ if (zAVLKey_cmp(avltree, avlnode->key, avlnode->parent->key) < 0)
+ superparent = &(avlnode->parent->left);
+ else
+ superparent = &(avlnode->parent->right);
+ }
+ else
+ superparent = &(avltree->top);
+
+ zAVLFillVacancy(avltree, origparent, superparent,
+ avlnode->left, avlnode->right);
+ free(avlnode);
+ avltree->count--;
+ return 0;
+}
+
+
+/*
+ * zAVLFirst:
+ * Initializes an zAVLCursor object and returns the item with the lowest
+ * key in the zAVLTree.
+ */
+void *zAVLFirst (zAVLCursor *avlcursor, zAVLTree const *avltree)
+{
+ const zAVLNode *avlnode;
+
+ if (NULL == avltree) /* R.W. Mon Nov 19 21:15:44 CET 2001 */
+ return NULL;
+
+ avlcursor->avltree = avltree;
+
+ if (avltree->top == NULL) {
+ avlcursor->curnode = NULL;
+ return NULL;
+ }
+
+ for (avlnode = avltree->top;
+ avlnode->left != NULL;
+ avlnode = avlnode->left);
+ avlcursor->curnode = avlnode;
+ return avlnode->item;
+}
+
+
+/*
+ * zAVLNext:
+ * Called after an zAVLFirst() call, this returns the item with the least
+ * key that is greater than the last item returned either by zAVLFirst()
+ * or a previous invokation of this function.
+ */
+void *zAVLNext (zAVLCursor *avlcursor)
+{
+ const zAVLNode *avlnode;
+
+ avlnode = avlcursor->curnode;
+
+ if (avlnode->right != NULL) {
+ for (avlnode = avlnode->right;
+ avlnode->left != NULL;
+ avlnode = avlnode->left);
+ avlcursor->curnode = avlnode;
+ return avlnode->item;
+ }
+
+ while (avlnode->parent && avlnode->parent->left != avlnode) {
+ avlnode = avlnode->parent;
+ }
+
+ if (avlnode->parent == NULL) {
+ avlcursor->curnode = NULL;
+ return NULL;
+ }
+
+ avlcursor->curnode = avlnode->parent;
+ return avlnode->parent->item;
+}
+
+
+/*
+ * zAVLCloseSearchNode:
+ * Return a pointer to the node closest to the given key.
+ * Returns NULL if the AVL tree is empty.
+ */
+static zAVLNode *zAVLCloseSearchNode (zAVLTree const *avltree, zAVLKey key,
+ int * ok)
+{
+ zAVLNode *node;
+
+ *ok = ZAVL_NO;
+
+ node = avltree->top;
+
+ if (!node)
+ return NULL;
+
+ for (;;) {
+ if (!zAVLKey_cmp(avltree, node->key, key))
+ {
+ *ok = ZAVL_OK;
+ return node;
+ }
+
+ if (zAVLKey_cmp(avltree, node->key, key) < 0) {
+ if (node->right)
+ node = node->right;
+ else
+ return node;
+ }
+
+ else {
+ if (node->left)
+ node = node->left;
+ else
+ return node;
+ }
+ }
+}
+
+
+/*
+ * zAVLRebalanceNode:
+ * Rebalances the AVL tree if one side becomes too heavy. This function
+ * assumes that both subtrees are AVL trees with consistant data. This
+ * function has the additional side effect of recalculating the depth of
+ * the tree at this node. It should be noted that at the return of this
+ * function, if a rebalance takes place, the top of this subtree is no
+ * longer going to be the same node.
+ */
+static void zAVLRebalanceNode (zAVLTree *avltree, zAVLNode *avlnode)
+{
+ long depthdiff;
+ zAVLNode *child;
+ zAVLNode *gchild;
+ zAVLNode *origparent;
+ zAVLNode **superparent;
+
+ origparent = avlnode->parent;
+
+ if (origparent) {
+ if (zAVLKey_cmp(avltree, avlnode->key, avlnode->parent->key) < 0)
+ superparent = &(avlnode->parent->left);
+ else
+ superparent = &(avlnode->parent->right);
+ }
+ else
+ superparent = &(avltree->top);
+
+ depthdiff = R_DEPTH(avlnode) - L_DEPTH(avlnode);
+
+ if (depthdiff <= -2 && avlnode->left) {
+ child = avlnode->left;
+
+ if (L_DEPTH(child) >= R_DEPTH(child)) {
+ avlnode->left = child->right;
+ if (avlnode->left != NULL)
+ avlnode->left->parent = avlnode;
+ avlnode->depth = CALC_DEPTH(avlnode);
+ child->right = avlnode;
+ if (child->right != NULL)
+ child->right->parent = child;
+ child->depth = CALC_DEPTH(child);
+ *superparent = child;
+ child->parent = origparent;
+ }
+
+ else {
+ gchild = child->right;
+ if (gchild)
+ {
+ avlnode->left = gchild->right;
+ if (avlnode->left != NULL)
+ avlnode->left->parent = avlnode;
+ avlnode->depth = CALC_DEPTH(avlnode);
+ child->right = gchild->left;
+ if (child->right != NULL)
+ child->right->parent = child;
+ child->depth = CALC_DEPTH(child);
+ gchild->right = avlnode;
+ if (gchild->right != NULL)
+ gchild->right->parent = gchild;
+ gchild->left = child;
+ if (gchild->left != NULL)
+ gchild->left->parent = gchild;
+ gchild->depth = CALC_DEPTH(gchild);
+ *superparent = gchild;
+ gchild->parent = origparent;
+ }
+ }
+ }
+
+ else if (depthdiff >= 2 && avlnode->right) {
+ child = avlnode->right;
+
+ if (R_DEPTH(child) >= L_DEPTH(child)) {
+ avlnode->right = child->left;
+ if (avlnode->right != NULL)
+ avlnode->right->parent = avlnode;
+ avlnode->depth = CALC_DEPTH(avlnode);
+ child->left = avlnode;
+ if (child->left != NULL)
+ child->left->parent = child;
+ child->depth = CALC_DEPTH(child);
+ *superparent = child;
+ child->parent = origparent;
+ }
+
+ else {
+ gchild = child->left;
+ if (gchild)
+ {
+ avlnode->right = gchild->left;
+ if (avlnode->right != NULL)
+ avlnode->right->parent = avlnode;
+ avlnode->depth = CALC_DEPTH(avlnode);
+ child->left = gchild->right;
+ if (child->left != NULL)
+ child->left->parent = child;
+ child->depth = CALC_DEPTH(child);
+ gchild->left = avlnode;
+ if (gchild->left != NULL)
+ gchild->left->parent = gchild;
+ gchild->right = child;
+ if (gchild->right != NULL)
+ gchild->right->parent = gchild;
+ gchild->depth = CALC_DEPTH(gchild);
+ *superparent = gchild;
+ gchild->parent = origparent;
+ }
+ }
+ }
+
+ else {
+ avlnode->depth = CALC_DEPTH(avlnode);
+ }
+}
+
+
+/*
+ * zAVLFreeBranch:
+ * Free memory used by this node and its item. If the freeitem argument
+ * is not NULL, then that function is called on the items to free their
+ * memory as well. In other words, the freeitem function is a
+ * destructor for the items in the tree.
+ */
+static void zAVLFreeBranch (zAVLNode *avlnode, void (freeitem)(void *item))
+{
+ if (avlnode->left)
+ zAVLFreeBranch(avlnode->left, freeitem);
+ if (avlnode->right)
+ zAVLFreeBranch(avlnode->right, freeitem);
+ if (freeitem) {
+ freeitem(avlnode->item);
+ avlnode->item = NULL;
+ }
+ free(avlnode);
+}
+
+
+/*
+ * zAVLFillVacancy:
+ * Given a vacancy in the AVL tree by it's parent, children, and parent
+ * component pointer, fill that vacancy.
+ */
+static void zAVLFillVacancy (zAVLTree *avltree,
+ zAVLNode *origparent, zAVLNode **superparent,
+ zAVLNode *left, zAVLNode *right)
+{
+ zAVLNode *avlnode;
+ zAVLNode *balnode;
+ zAVLNode *nextbalnode;
+
+ if (left == NULL) {
+ if (right)
+ right->parent = origparent;
+
+ *superparent = right;
+ balnode = origparent;
+ }
+
+ else {
+ for (avlnode = left; avlnode->right != NULL; avlnode = avlnode->right);
+
+ if (avlnode == left) {
+ balnode = avlnode;
+ }
+ else {
+ balnode = avlnode->parent;
+ balnode->right = avlnode->left;
+ if (balnode->right != NULL)
+ balnode->right->parent = balnode;
+ avlnode->left = left;
+ left->parent = avlnode;
+ }
+
+ avlnode->right = right;
+ if (right != NULL)
+ right->parent = avlnode;
+ *superparent = avlnode;
+ avlnode->parent = origparent;
+ }
+
+ for (; balnode; balnode = nextbalnode) {
+ nextbalnode = balnode->parent;
+ zAVLRebalanceNode(avltree, balnode);
+ }
+}
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/stamp-hdep b/stamp-hdep
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/stamp-hdep
@@ -0,0 +1 @@
+timestamp
diff --git a/stealth_template.jpg b/stealth_template.jpg
new file mode 100644
index 0000000..a75edbc
--- /dev/null
+++ b/stealth_template.jpg
Binary files differ
diff --git a/test/gnupg/public-key.asc b/test/gnupg/public-key.asc
new file mode 100644
index 0000000..90849a0
--- /dev/null
+++ b/test/gnupg/public-key.asc
@@ -0,0 +1,20 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mI0EVY1+9AEEAMgqIppswdch0ErLLXbRnDgCMwhwaTydnu4NwvyDGSpy+32ODwSC
+lDC+SdiU/tx/gHTqFaVS3WJo9KcEgFNzkypdI2WYx5/ZCUNKZXIibJLcwE89mhf5
+Y4Gv6vVSZgW3nh+PJCumZG/ljb0X1ZDakHO03BEQJ9UfKo8akLhTnSWbABEBAAG0
+OFRlc3RzdWl0ZSBTYW1oYWluICh0ZXN0aW5nIG9ubHkpIDxuby1yZXBseUBsYS1z
+YW1obmEuZGU+iLgEEwECACIFAlWNfvQCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B
+AheAAAoJEE7Znk6KCzN68b0D/A+ykm13KWjqMGNOf6SF6girei2nvxIMkN2AVks0
+SXQxIbcu/Wzue+fhdHc2BzJTnlC6h9l/5RUNK5+D6+NRfFfCy6d1bESoUMlGK69u
+QnZSb9qepomJos3K9CQasKAsR1uE1mwzT4S7LPcqj1MWKwTnhLEKfG7I5o9MKyE9
+4AvHuI0EVY1+9AEEAL37L+v5AKOrFspzgpKj450XIelkLdkKlqqR7yrQZ+nZKZ9+
+4nWjxs/f+tJLwR9/XeK8YMktpvJkvGHzMz21Wz54iq8EfsTy6fRawfVkePxNAAZT
+cwf4DfCCVTpfEtJnVqoWWzy6elqbkgViLB346jLTUenm6cy8OhBfd5DAibfJABEB
+AAGInwQYAQIACQUCVY1+9AIbDAAKCRBO2Z5Oigszek1JA/94Nkn3UdzNiEogp0hn
+Z6Baabkok/mxULymZ+XWLrDDl2pi84msITxO1tiicZ3nP8zohdFrftFrH1zdoU5h
+n+GgGhsk9Frhj0gXYeBRbZ4NE1EUVoeY/xfe8T+uRAxa6Y0dvlzVsBUH0EAd0L6E
+GUU+G9Edi2T82HPsjeYOg+UI6Q==
+=C5Xk
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/test/gnupg/pubring.gpg b/test/gnupg/pubring.gpg
new file mode 100644
index 0000000..67f07d7
--- /dev/null
+++ b/test/gnupg/pubring.gpg
Binary files differ
diff --git a/test/gnupg/random_seed b/test/gnupg/random_seed
new file mode 100644
index 0000000..c6eca1e
--- /dev/null
+++ b/test/gnupg/random_seed
Binary files differ
diff --git a/test/gnupg/secret-key.asc b/test/gnupg/secret-key.asc
new file mode 100644
index 0000000..c5333d2
--- /dev/null
+++ b/test/gnupg/secret-key.asc
@@ -0,0 +1,34 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQHYBFWNfvQBBADIKiKabMHXIdBKyy120Zw4AjMIcGk8nZ7uDcL8gxkqcvt9jg8E
+gpQwvknYlP7cf4B06hWlUt1iaPSnBIBTc5MqXSNlmMef2QlDSmVyImyS3MBPPZoX
++WOBr+r1UmYFt54fjyQrpmRv5Y29F9WQ2pBztNwRECfVHyqPGpC4U50lmwARAQAB
+AAP+MLRD8DRXZCvnnVNb0CYHr38lgL+tc6Dcu4rgr4WMuY350J6g29WUDlo26Lq0
+Wt2xWYFd2/jSQnBMW1lWije8jmuc58sx/Gi3uuNWtSXPQlIK7aa3K6nlX+sXN24C
+w0VAIpNfpXYPPkHUq8YKyPV+9a32LxxE2gG+ZDzQfzrlLPUCANtU22P0IYtDSyaW
+7WCB5rjU7aAywDTC3gXuCVntaZLySpnBcjPlO3n4z6rD/qvsnPqPceKsqLaydrY2
+4s/YcscCAOmg9PpOVZ7Zpj+7BYgkGCcT+lrzzGWhFXHtJhCxa10qZuDZc7kKoDo/
+/FpAtm9WbuLBu3LuEsC1taiXYhUcoo0CAIcVVYHpw6yGcNpf+NegQDLAudYiCLzK
+Lvt4KKns7gIQse3PBzGKuNc98X+MQVf2iL/35XIF/eGZtoObrPLSi8axnbQ4VGVz
+dHN1aXRlIFNhbWhhaW4gKHRlc3Rpbmcgb25seSkgPG5vLXJlcGx5QGxhLXNhbWhu
+YS5kZT6IuAQTAQIAIgUCVY1+9AIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQTtmeTooLM3rxvQP8D7KSbXcpaOowY05/pIXqCKt6Lae/EgyQ3YBWSzRJdDEh
+ty79bO575+F0dzYHMlOeULqH2X/lFQ0rn4Pr41F8V8LLp3VsRKhQyUYrr25CdlJv
+2p6miYmizcr0JBqwoCxHW4TWbDNPhLss9yqPUxYrBOeEsQp8bsjmj0wrIT3gC8ed
+AdgEVY1+9AEEAL37L+v5AKOrFspzgpKj450XIelkLdkKlqqR7yrQZ+nZKZ9+4nWj
+xs/f+tJLwR9/XeK8YMktpvJkvGHzMz21Wz54iq8EfsTy6fRawfVkePxNAAZTcwf4
+DfCCVTpfEtJnVqoWWzy6elqbkgViLB346jLTUenm6cy8OhBfd5DAibfJABEBAAEA
+A/sE2qaqTlXsWKI/8Pycl5Bowp8MshET0xfvasQkIWgOSwyrtRe/LryVMiFb/zCD
+iAMTmIGWklKKLfW8QPUFth0LK8c02jIRvCRAc8lr3V+CGmTqxWCPsYWnHxIINc03
+wECMbFHLCAUlKelN/DJIKoI0LJJVvzYEy5xt9SvNBJiW6wIAzKgYNJNAgRvQOeb5
+MxKjCybYoUjFKOfdAaJkTwE0xuSaxap5ZUUfIADXT/C6SpbAfywIBFj8gYrwyPPo
+a4eGcwIA7aSTYyglPlzXc9AbfRh1jiIT4/QhUL1BBvtCVAkfbX1/x5llHCf64bJe
+/j15bBJeGzLAjMIxcSblP4/IYGG90wIA44bpOk4G8Smt3NfDYviixhHSVXXc+GUq
+woCV09mbSwpHNBek7Nec+c53MTRuoj2XPMWrYyeX3LIVDShlbaWWopiziJ8EGAEC
+AAkFAlWNfvQCGwwACgkQTtmeTooLM3pNSQP/eDZJ91HczYhKIKdIZ2egWmm5KJP5
+sVC8pmfl1i6ww5dqYvOJrCE8TtbYonGd5z/M6IXRa37Rax9c3aFOYZ/hoBobJPRa
+4Y9IF2HgUW2eDRNRFFaHmP8X3vE/rkQMWumNHb5c1bAVB9BAHdC+hBlFPhvRHYtk
+/Nhz7I3mDoPlCOk=
+=5aNq
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/test/gnupg/secring.gpg b/test/gnupg/secring.gpg
new file mode 100644
index 0000000..2ae5e81
--- /dev/null
+++ b/test/gnupg/secring.gpg
Binary files differ
diff --git a/test/gnupg/trustdb.gpg b/test/gnupg/trustdb.gpg
new file mode 100644
index 0000000..c24ff7f
--- /dev/null
+++ b/test/gnupg/trustdb.gpg
Binary files differ
diff --git a/test/test.sh b/test/test.sh
new file mode 100755
index 0000000..701a114
--- /dev/null
+++ b/test/test.sh
@@ -0,0 +1,862 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# -----------------------------------------------------------------------
+# Be Bourne compatible
+# -----------------------------------------------------------------------
+
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# -----------------------------------------------------------------------
+# Make sure we support functions (from the autoconf manual)
+# -----------------------------------------------------------------------
+
+TSHELL="${TSHELL-/bin/sh}"
+if test x"$1" = "x--re-executed"
+then
+ shift
+elif "$TSHELL" -c 'foo () { (exit 0); exit 0; }; foo' >/dev/null 2>&1
+then
+ :
+else
+ for cmd in sh bash ash bsh ksh zsh sh5; do
+ X="$PATH:/bin:/usr/bin:/usr/afsws/bin:/usr/ucb:/usr/xpg4/bin";
+ OLD_IFS=${IFS}
+ IFS=':'; export IFS
+ for dir in $X; do
+ shell="$dir/$cmd"
+ if (test -f "$shell" || test -f "$shell.exe")
+ then
+ if "$shell" -c 'foo () { (exit 0); exit 0; }; foo' >/dev/null 2>&1
+ then
+ TSHELL="$shell"; export TSHELL
+ IFS=${OLD_IFS}; export IFS
+ exec "$shell" "$0" --re-executed ${1+"$@"}
+ fi
+ fi
+ done
+ IFS=${OLD_IFS}; export IFS
+ done
+ echo "-----------------------------------------------------------------"
+ echo "ERROR: Unable to locate a shell interpreter with function support" >&2
+ echo "-----------------------------------------------------------------"
+ { (exit 1); exit 1; }
+fi
+
+# -----------------------------------------------------------------------
+# Make sure we support 'let' (from the autoconf manual)
+# -----------------------------------------------------------------------
+
+TSHELL="${TSHELL-/bin/sh}"
+if test x"$1" = "x--re-run"
+then
+ shift
+elif "$TSHELL" -c 'a=5; let "a = a + 5"' >/dev/null 2>&1
+then
+ :
+else
+ for cmd in sh bash ash bsh ksh zsh sh5; do
+ X="$PATH:/bin:/usr/bin:/usr/afsws/bin:/usr/ucb:/usr/xpg4/bin";
+ OLD_IFS=${IFS}
+ IFS=':'; export IFS
+ for dir in $X; do
+ shell="$dir/$cmd"
+ if (test -f "$shell" || test -f "$shell.exe")
+ then
+ if "$shell" -c 'foo () { (exit 0); exit 0; }; foo' >/dev/null 2>&1
+ then
+ if "$shell" -c 'a=5; let "a = a + 5"' >/dev/null 2>&1
+ then
+ TSHELL="$shell"; export TSHELL
+ IFS=${OLD_IFS}; export IFS
+ exec "$shell" "$0" --re-run ${1+"$@"}
+ fi
+ fi
+ fi
+ done
+ IFS=${OLD_IFS}; export IFS
+ done
+ echo "-----------------------------------------------------------------"
+ echo "ERROR: Unable to locate a shell interpreter with support for 'let'" >&2
+ echo "-----------------------------------------------------------------"
+ { (exit 1); exit 1; }
+fi
+
+
+umask 0022
+
+isok=`test -t 1 2>&1 | wc -c`
+if [ "$isok" -eq 0 ]; then
+ test -t 1
+ isok=$?
+fi
+
+# The following two are the ANSI sequences for start and end embolden
+if [ x"$isok" = x0 ]; then
+ case $TERM in
+ vt*|ansi*|con*|xterm*|linux*|screen*|rxvt*)
+ S=''
+ R=
+ G=
+ B=
+ E=
+ ;;
+ *)
+ S=
+ R=
+ G=
+ B=
+ E=
+ ;;
+ esac
+fi
+
+
+usage() {
+ echo "test.sh [options] <test_number> [hostname]"
+ echo " [-q|--quiet|-v|--verbose] [-s|--stoponerr] [-n|--no-cleanup]"
+ echo " [--srcdir=top_srcdir] [--color=always|never|auto]"
+ echo
+ echo " ${S}test.sh 1${E} -- Compile with many different options"
+ echo " ${S}test.sh 2${E} -- Hash function (testrc_1)"
+ echo " ${S}test.sh 3${E} -- Standalone init/check"
+ echo " ${S}test.sh 4${E} -- Microstealth init/check"
+ echo " ${S}test.sh 5${E} -- External program call (testrc_1ext.in)"
+ echo " ${S}test.sh 6${E} -- Controlling the daemon"
+ echo " ${S}test.sh 7${E} -- GnuPG signed files / prelude log"
+ echo " ${S}test.sh 8${E} -- Suidcheck"
+ echo " ${S}test.sh 9${E} -- Process check"
+ echo " ${S}test.sh 10${E} -- Port check"
+ echo " ${S}test.sh 11${E} -- CL verify option"
+ echo " ${S}test.sh 12${E} -- CL create DeltaDB"
+ echo " ${S}test.sh 13${E} -- CL create/verify partial DB"
+
+ echo " ${S}test.sh 20${E} -- Test c/s init/check (testrc_2.in)"
+ echo " ${S}test.sh 21${E} -- Test full c/s init/check (testrc_2.in)"
+ echo " ${S}test.sh 22${E} -- Test full c/s w/gpg (testrc_2.in)"
+ echo " ${S}test.sh 23${E} -- Test full c/s w/mysql (testrc_2.in)"
+ echo " ${S}test.sh 24${E} -- Test full c/s w/postgres (testrc_2.in)"
+ echo " ${S}test.sh 25${E} -- Test server w/yulectl (testrc_2.in)"
+ echo " ${S}test.sh 26${E} -- Test c/s case one (testrc_2.in)"
+ echo " ${S}test.sh 27${E} -- Test c/s case two (testrc_2.in)"
+ echo " ${S}test.sh all${E} -- All tests"
+}
+scripts () {
+ echo
+ echo "Scripts used by tests:"
+ echo " (1) testcompile.sh (2) testhash.sh (3) testrun_1.sh (4) testrun_1a.sh"
+ echo " (5) testext.sh (6) testtimesrv.sh (7) testrun_1b.sh (8) testrun_1c.sh"
+ echo " (9) testrun_1d.sh (10) testrun_1e.sh (11) testrun_1f.sh (12) testrun_1g.sh"
+ echo " (13) testrun_1h.sh"
+ echo " (20) testrun_2.sh (21) testrun_2a.sh (22) testrun_2b.sh (23) testrun_2c.sh"
+ echo " (24) testrun_2d.sh (25) testrun_2e.sh (26) testrun_2f.sh (27) testrun_2g.sh"
+}
+
+#
+# Option parsing
+#
+verbose=
+quiet=
+stoponerr=
+color=auto
+cleanup=on
+doall=
+usevalgrind=
+
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -h|--help) usage; exit 0;;
+ --scripts) usage; scripts; exit 0;;
+ -v|--verbose) verbose=on; quiet= ;;
+ -q|--quiet) quiet=on; verbose= ;;
+ -s|--stoponerr) stoponerr=on;;
+ -n|--no-cleanup) cleanup= ;;
+ --really-all) doall=on;;
+ --valgrind) usevalgrind=on;;
+ --srcdir=*) TOP_SRCDIR=`echo $1 | sed s,--srcdir=,,`; export TOP_SRCDIR;;
+ --color=*)
+ arg=`echo $1 | sed s,--color=,,`
+ case $arg in
+ auto) ;;
+ never|none|no)
+ S=
+ R=
+ G=
+ B=
+ E=
+ ;;
+ always|yes)
+ S=''
+ R=
+ G=
+ G=
+ E=
+ ;;
+ *) echo "Invalid argument $1"; exit 1;;
+ esac
+ ;;
+ -*) echo "Invalid argument $1"; exit 1;;
+ *) break;;
+ esac
+ shift
+done
+
+export verbose
+export quiet
+export stoponerr
+export cleanup
+export doall
+export S; export R; export G; export B; export E;
+
+SCRIPTDIR=.
+
+#
+# 'make test' will copy the 'test' subdirectory and replace TEST_SRCDIR
+#
+TEST_SRCDIR="XXXSRCXXX";
+if test "x${TOP_SRCDIR}" = x; then
+ # not within source tree, and not called with 'make testN'
+ if test -f "${TEST_SRCDIR}/src/samhain.c"; then
+ TOP_SRCDIR="${TEST_SRCDIR}"; export TOP_SRCDIR
+ if test -f test/testcompile.sh; then
+ SCRIPTDIR=test
+ fi
+ # not within source tree, not called by 'make', and in 'test' subdir
+ elif test -f "../${TEST_SRCDIR}/src/samhain.c"; then
+ cd ..
+ SCRIPTDIR=test
+ TOP_SRCDIR="${TEST_SRCDIR}"; export TOP_SRCDIR
+ # within source tree, and not called with 'make testN'
+ else
+ if test -f ../src/samhain.c; then
+ cd ..
+ SCRIPTDIR=test
+ TOP_SRCDIR=.
+ export TOP_SRCDIR
+ elif test -f ./src/samhain.c; then
+ SCRIPTDIR=test
+ TOP_SRCDIR=.
+ export TOP_SRCDIR
+ else
+ echo "Please use --srcdir=DIR, where DIR should be the"
+ echo "top directory in the samhain source tree."
+ exit 1
+ fi
+ fi
+else
+ # called by make, or with --srcdir=TOP_SRCDIR
+ if test -f "${TOP_SRCDIR}/src/samhain.c"; then
+ SCRIPTDIR="${TOP_SRCDIR}/test"
+ elif test -f "../${TOP_SRCDIR}/src/samhain.c"; then
+ cd ..; SCRIPTDIR="${TOP_SRCDIR}/test"
+ else
+ echo "Please use --srcdir=DIR, where DIR should be the"
+ echo "top directory in the samhain source tree."
+ exit 1
+ fi
+fi
+
+export SCRIPTDIR
+
+PW_DIR=`pwd`; export PW_DIR
+
+#
+# group/world writeable will cause problems
+#
+chmod go-w .
+#
+#
+#
+if test x$UID != x -a x$UID != x0; then
+ TRUST="--with-trusted=0,2,$UID"
+else
+ TRUST="--with-trusted=0,2,1000"
+fi
+export TRUST
+#
+# find a good 'make'
+#
+MAKE=`which gmake`
+if test "x$?" = x1 ; then
+ MAKE="make -s -j 3"
+else
+ MAKE=`which gmake | sed -e "s%\([a-z:]\) .*%\1%g"`
+ if test "x$MAKE" = x; then
+ MAKE="make -s"
+ elif test "x$MAKE" = xno; then
+ MAKE="make -s"
+ else
+ if test "x$MAKE" = "xwhich:"; then
+ MAKE="make -s"
+ else
+ MAKE="gmake -s"
+ gmake -v >/dev/null 2>&1 || MAKE="make -s"
+ fi
+ fi
+fi
+export MAKE
+
+failcount=0
+okcount=0
+skipcount=0
+global_count=0
+last_count=0
+
+# args: #test, #total, status, optional msg
+log_msg ()
+{
+ if [ x"$COLUMNS" != x ]; then
+ TERMWIDTH=$COLUMNS
+ elif [ x"$COLS" != x ]; then
+ TERMWIDTH=$COLS
+ else
+ TERMWIDTH=80
+ fi
+ cols=66;
+ #
+ if [ $1 -eq 0 ]; then
+ msg=" ${4}"
+ else
+ if [ ${1} -eq 1 ]; then
+ global_count=${last_count}
+ fi
+ let "v = $1 + global_count" >/dev/null
+ last_count=${v}
+ dd=''; if [ $v -lt 10 ]; then dd=" "; fi
+ dt=''; if [ $2 -lt 10 ]; then dt=" "; fi
+ if [ -z "$4" ]; then
+ msg=" test ${dd}${v}/${dt}${2}"
+ else
+ msg=" test ${dd}${v}/${dt}${2} ${4}"
+ fi
+ fi
+ #
+ if [ x"$3" = xfailure ]; then
+ ccode=$R
+ elif [ x"$3" = xsuccess ]; then
+ ccode=$G
+ else
+ ccode=$B
+ fi
+ if [ -z "${R}" ]; then
+ echo " [${3}] ${msg}"
+ else
+ # len=${#...} is not bourne shell
+ # also, need to account for terminal control sequences
+ len=`echo "$msg" | awk '/1;30m/ { print length()-10; }; !/1;30m/ { print length();}'`
+ let "cols = cols - len" >/dev/null
+ if [ $cols -ge 0 ]; then
+ moveto='['$cols'C'
+ echo "${msg}${moveto}${ccode}[${3}]${E}"
+ else
+ echo "${msg}${ccode}[${3}]${E}"
+ fi
+ fi
+}
+
+log_fail () {
+ [ -z "$quiet" ] && log_msg "$1" "$2" failure "$3";
+ let "failcount = failcount + 1" >/dev/null;
+ test -z "$stoponerr" || exit 1;
+}
+log_ok () {
+ [ -z "$quiet" ] && log_msg "$1" "$2" success "$3";
+ let "okcount = okcount + 1" >/dev/null;
+}
+log_skip () {
+ [ -z "$quiet" ] && log_msg "$1" "$2" skipped "$3";
+ let "skipcount = skipcount + 1" >/dev/null;
+}
+
+log_msg_fail () { log_msg 0 0 failure "$1"; }
+log_msg_ok () { log_msg 0 0 success "$1"; }
+log_msg_skip () { log_msg 0 0 skipped "$1"; }
+
+log_start () {
+ if [ -z "$quiet" ]; then
+ echo;
+ echo "${S}__ START TEST ${1} __${E}";
+ echo;
+ fi
+}
+log_end () {
+ if [ -n "$verbose" ]; then
+ echo;
+ echo "${S}__ END TEST ${1} __${E}";
+ echo;
+ fi
+}
+
+# This looks silly, but with solaris10/i386 on vmware,
+# 'sleep' occasionally does not sleep...
+
+one_sec_sleep () {
+ onesdate=`date`
+ onestest=0
+ while [ $onestest -eq 0 ]; do
+ sleep 1
+ twosdate=`date`
+ if [ "x$twosdate" = "x$onesdate" ]; then
+ onestest=0
+ else
+ onestest=1
+ fi
+ done
+}
+
+five_sec_sleep () {
+ for f in 1 2 3 4 5; do
+ one_sec_sleep
+ done
+}
+
+do_cleanup () {
+ rm -f testrc_1.dyn
+ rm -f testrc_2
+ rm -f testrc_22
+ rm -f testrc_1ext
+ rm -f ./.samhain_file
+ rm -f file.*.*-*-*-*-*
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock*
+ test -d testrun_testdata && chmod -f -R 0700 testrun_testdata
+ test -d .quarantine && rm -rf .quarantine
+ rm -rf testrun_testdata
+ rm -f test_log_db
+ rm -f test_log_prelude
+ rm -f test_log_valgrind*
+ rm -f test_log_yulectl
+ rm -f yule.html
+ rm -f yule.html2
+ rm -f test_dnmalloc
+ rm -f tmp_list_file
+ rm -f test_filter.txt
+}
+
+print_summary ()
+{
+ # let "gcount = okcount + skipcount + failcount" >/dev/null;
+ gcount=$MAXTEST;
+ let "failcount = gcount - okcount - skipcount" >/dev/null;
+
+ [ -z "$quiet" ] && {
+ echo
+ echo "__ ${S}Tests: ${gcount} Ok: ${okcount} Skipped: ${skipcount} Failed: ${failcount}${E}"
+ }
+ if [ $failcount -eq 0 ]; then
+ [ -z "$quiet" ] && { echo "__ ${G}All tests passed successfully.${E}"; echo; }
+ elif [ $failcount -eq 1 ]; then
+ [ -z "$quiet" ] && { echo "__ ${R}There was 1 failure.${E}"; echo; }
+ else
+ [ -z "$quiet" ] && { echo "__ ${R}There were $failcount failures.${E}"; echo; }
+ fi
+ [ -z "$cleanup" ] || do_cleanup;
+}
+
+find_path () { (
+ save_IFS=$IFS; IFS=:
+
+ for dir in $PATH; do
+ IFS=$as_save_IFS
+ test -z "$dir" && dir=.
+ if test -f "$dir/$1"; then
+ echo "$dir/$1";
+ break;
+ fi
+ done
+ IFS=${save_IFS};
+); }
+
+find_hostname () {
+
+ uname -a | grep Linux >/dev/null
+ if [ $? -eq 0 ]; then
+ tmp=`hostname -f 2>/dev/null`
+ if [ $? -ne 0 ]; then
+ tmp=`hostname 2>/dev/null`
+ fi
+ else
+ tmp=`hostname 2>/dev/null`
+ fi
+ if [ -z "$tmp" ]; then
+ tmp="localhost"
+ fi
+ #
+ # first one is hostname, others are aliases
+ #
+ tmp2=`cat /etc/hosts | egrep "^ *[0123456789].* $tmp" | awk '{ print $2 }'`
+ if [ -z "$tmp2" ]; then
+ echo "$tmp"
+ else
+ echo "$tmp2"
+ fi
+}
+
+rm -f ./test_log
+
+# first one is hostname, others are aliases
+#
+hostname=`cat /etc/hosts | egrep "^ *127.0.0.1" | awk '{ print $2 }'`
+if [ x"$hostname" = xlocalhost ]; then
+ hostname="127.0.0.1"
+fi
+
+# Seems that 'valgrind' causes random hangs :-(
+#
+if [ -z "$usevalgrind" ]; then
+ VALGRIND=
+else
+ VALGRIND=`find_path valgrind`;
+fi
+[ -z "$VALGRIND" ] || {
+ VALGRIND="$VALGRIND --quiet --tool=memcheck --suppressions=.test.supp";
+ export VALGRIND;
+ [ -z "$verbose" ] || log_msg_ok "using valgrind"
+cat > ".test.supp" <<End-of-data
+#
+# there are unitialized bytes in the struct...
+#
+{
+ pushdata_01
+ Memcheck:Param
+ write(buf)
+ obj:/lib/ld-*.so
+ fun:sh_hash_pushdata
+ fun:sh_files_filecheck
+ fun:sh_dirs_chk
+}
+{
+ pushdata_02
+ Memcheck:Param
+ write(buf)
+ obj:/lib/ld-*.so
+ fun:sh_hash_pushdata
+ fun:sh_files_filecheck
+ fun:sh_files_checkdir
+}
+{
+ pushdata_03
+ Memcheck:Param
+ write(buf)
+ obj:/lib/ld-*.so
+ fun:sh_hash_pushdata
+ fun:sh_hash_writeout
+ fun:main
+}
+
+End-of-data
+}
+
+if test x$1 = x1; then
+ . ${SCRIPTDIR}/testcompile.sh
+ testcompile
+ print_summary
+ exit $?
+fi
+if test x$1 = x2; then
+ . ${SCRIPTDIR}/testhash.sh
+ testhash
+ print_summary
+ exit $?
+fi
+if test x$1 = x3; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ testrun1
+ print_summary
+ exit $?
+fi
+if test x$1 = x4; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1a.sh
+ testrun1a
+ print_summary
+ exit $?
+fi
+if test x$1 = x5; then
+ . ${SCRIPTDIR}/testext.sh
+ testext0
+ print_summary
+ exit $?
+fi
+if test x$1 = x6; then
+ . ${SCRIPTDIR}/testtimesrv.sh
+ testtime0
+ print_summary
+ exit $?
+fi
+if test x$1 = x7; then
+ . ${SCRIPTDIR}/testrun_1b.sh
+ testrun1b
+ print_summary
+ exit $?
+fi
+if test x$1 = x8; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1c.sh
+ testrun1c
+ print_summary
+ exit $?
+fi
+if test x$1 = x9; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1d.sh
+ testrun1d
+ print_summary
+ exit $?
+fi
+if test x$1 = x10; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1e.sh
+ testrun1e
+ print_summary
+ exit $?
+fi
+if test x$1 = x11; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1f.sh
+ testrun1f
+ print_summary
+ exit $?
+fi
+if test x$1 = x12; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1g.sh
+ testrun1g
+ print_summary
+ exit $?
+fi
+if test x$1 = x13; then
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1h.sh
+ testrun1h
+ print_summary
+ exit $?
+fi
+if test x$1 = x20; then
+ . ${SCRIPTDIR}/testrun_2.sh
+ testrun2 $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x21; then
+ . ${SCRIPTDIR}/testrun_2a.sh
+ testrun2a $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x22; then
+ . ${SCRIPTDIR}/testrun_2a.sh
+ . ${SCRIPTDIR}/testrun_2b.sh
+ testrun2b $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x23; then
+ . ${SCRIPTDIR}/testrun_2a.sh
+ . ${SCRIPTDIR}/testrun_2c.sh
+ testrun2c $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x24; then
+ . ${SCRIPTDIR}/testrun_2a.sh
+ . ${SCRIPTDIR}/testrun_2d.sh
+ testrun2d $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x25; then
+ . ${SCRIPTDIR}/testrun_2e.sh
+ testrun2e $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x26; then
+ . ${SCRIPTDIR}/testrun_2f.sh
+ testrun2f $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = x27; then
+ . ${SCRIPTDIR}/testrun_2g.sh
+ testrun2g $hostname
+ print_summary
+ exit $?
+fi
+if test x$1 = xall; then
+ TEST_MAX=0
+ . ${SCRIPTDIR}/testcompile.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testhash.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1a.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testext.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testtimesrv.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1b.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1c.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1d.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1e.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1f.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1g.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_1h.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2a.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2b.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2c.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2d.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2e.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2f.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ . ${SCRIPTDIR}/testrun_2g.sh
+ let "TEST_MAX = TEST_MAX + MAXTEST" >/dev/null
+ #
+ # ${SCRIPTDIR}/testtimesrv.sh
+ # ${SCRIPTDIR}/testrun_1b.sh
+ # ${SCRIPTDIR}/testrun_2.sh $2
+ # ${SCRIPTDIR}/testrun_2a.sh $2
+ #
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testcompile
+ testhash
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1
+ #
+ . ${SCRIPTDIR}/testrun_1a.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1a
+ #
+ testext0
+ #
+ . ${SCRIPTDIR}/testtimesrv.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testtime0
+ #
+ . ${SCRIPTDIR}/testrun_1b.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1b
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1c.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1c
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1d.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1d
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1e.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1e
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1f.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1f
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1g.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1g
+ #
+ . ${SCRIPTDIR}/testrun_1.sh
+ . ${SCRIPTDIR}/testrun_1h.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun1h
+ #
+ . ${SCRIPTDIR}/testrun_2.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2 $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2a.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2a $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2b.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2b $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2c.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2c $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2d.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2d $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2e.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2e $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2f.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2f $hostname
+ #
+ . ${SCRIPTDIR}/testrun_2g.sh
+ MAXTEST=${TEST_MAX}; export MAXTEST
+ testrun2g $hostname
+ #
+ print_summary
+ exit 0
+fi
+
+usage;
+
+exit 1;
+
+# gpg -a --clearsign --not-dash-escaped testrc.gpg
+# gpg -a --clearsign --not-dash-escaped .samhain_file
+# tar czvf foo.tgz testrc.gpg.asc .samhain_file.asc
+# cat foo.tgz >>test/test.sh
+
+__ARCHIVE_FOLLOWS__
+‹
+8MûÄñþw÷î½»ã;ÙŽ•ñ(Å#ÛêR 1ìÜœ[2?=^º0þ@€b¼~ËÒ^ÆÇR4ãcX–‚ôå¸3IÑvd BÊ’UY¯î÷ºöÿ)7]n bD‚11“QBpIH&yQ6‚EÙÎ/Àä"Ï
+¶@sü9!1“RÉÙeC+OªgMªÞ¾ÔQ ÓB’i Iýb±¦õç5Û–-ã\M‰Ç}.†TËæT#gž+’Œ÷c4l`g6Á’¬jg­x¼
+§+nhÔÝÁåð&
+»¸^HMøb[¼y'ñ…“ëhIæ¼ëw5o2ÒÐb!f|81½ž|·o @ @ @ ð.ò7–<Ì
diff --git a/test/test_ext.c.in b/test/test_ext.c.in
new file mode 100644
index 0000000..f2dbb82
--- /dev/null
+++ b/test/test_ext.c.in
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int main ()
+{
+ char line[256];
+ int flags;
+ FILE * foo = fopen ("MYPWDIR", "a");
+
+ flags = fcntl(STDIN_FILENO, F_GETFL);
+ fcntl(STDIN_FILENO, F_SETFL, flags|O_NONBLOCK);
+
+ xagain:
+ errno = 0;
+ while (NULL != fgets(line, 255, stdin))
+ {
+ fprintf (foo, "RECV: %s", line);
+ fflush (foo);
+ }
+ if (ferror(stdin) && errno == EAGAIN)
+ {
+ clearerr(stdin);
+ goto xagain;
+ }
+ fclose(foo);
+ return 0;
+}
+
+
diff --git a/test/testcompile.sh b/test/testcompile.sh
new file mode 100755
index 0000000..d7b2ed2
--- /dev/null
+++ b/test/testcompile.sh
@@ -0,0 +1,860 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+# dnmalloc + cppcheck + flawfinder + (38 * 2) - 8
+MAXTEST=79; export MAXTEST
+
+run_dnmalloc ()
+{
+ fail=0
+ if test x$1 = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE clean > /dev/null 2>> test_log
+ $MAKE test_dnmalloc > /dev/null 2>> test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make test_dnmalloc...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make test_dnmalloc...";
+ fail=1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ if [ x"$3" = xskip ]; then
+ [ -z "$quiet" ] && log_skip $2 ${MAXTEST} "test dnmalloc";
+ fi
+ fail=1
+ fi
+ if [ $fail -eq 1 ]; then
+ [ -z "$quiet" ] && log_fail $2 ${MAXTEST} "test dnmalloc";
+ return 1
+ fi
+ #
+ fail=0
+ ./test_dnmalloc >/dev/null
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "run 1 completed...";
+ ./test_dnmalloc 300 12 3000 150000 400 >/dev/null
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "run 2 completed...";
+ ./test_dnmalloc 1 1 4000 10000000 1000 >/dev/null
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "run 3 completed...";
+ ./test_dnmalloc 1 1 4000 10000000 1000 >/dev/null
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "run 4 completed...";
+ else
+ fail=1
+ fi
+ else
+ fail=1
+ fi
+ else
+ fail=1
+ fi
+ else
+ fail=1
+ fi
+ #
+ if test x$fail = x0; then
+ [ -z "$quiet" ] && log_ok $2 ${MAXTEST} "test dnmalloc";
+ return 0
+ else
+ [ -z "$quiet" ] && log_fail $2 ${MAXTEST} "test dnmalloc";
+ return 1
+ fi
+}
+
+run_cppcheck ()
+{
+ #
+ CPC=`find_path cppcheck`
+ #
+ if [ -z "$CPC" ]; then
+ log_skip $num ${MAXTEST} 'check w/cppcheck (not in PATH)'
+ return 0
+ fi
+ #
+ cd src/
+ stat=`cppcheck --quiet --inline-suppr --force -j 4 --template="{file},{line},{severity},{id},{message}" -I. -I.. -I../include sh_*.c samhain.c slib.c dnmalloc.c zAVLTree.c trustfile.c rijndael-*.c bignum.c 2>&1 | wc -l`
+ if [ $stat -ne 0 ]; then
+ cppcheck --quiet --inline-suppr --force -j 4 --template="{file},{line},{severity},{id},{message}" -I. -I.. -I../include sh_*.c samhain.c slib.c dnmalloc.c zAVLTree.c trustfile.c rijndael-*.c bignum.c >>../test_log 2>&1
+ retval=1
+ [ -z "$quiet" ] && log_fail $2 ${MAXTEST} "check w/cppcheck";
+ else
+ retval=0
+ [ -z "$quiet" ] && log_ok $2 ${MAXTEST} "check w/cppcheck";
+ fi
+ cd ..
+ return $retval
+}
+
+run_flawfinder ()
+{
+ flawfinder --minlevel=3 --quiet src/s*.c | \
+ egrep '^No hits found.' >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok $2 ${MAXTEST} "$TEST";
+ else
+ flawfinder --minlevel=3 --quiet src/s*.c >test_log 2>&1
+ [ -z "$quiet" ] && log_fail $2 ${MAXTEST} "$TEST";
+ return 1
+ fi
+}
+
+run_clang ()
+{
+ export CDIR=`pwd`;
+
+ if [ -z "$doall" ]; then
+ [ -z "$quiet" ] && log_skip $2 ${MAXTEST} "$TEST (clang)";
+ return 0
+ fi
+
+ CLANGPATH=`find_path clang`
+ if [ -n "$CLANGPATH" ]; then
+ CLANG_CC="$CLANGPATH"; export CLANG_CC
+ else
+ [ -z "$quiet" ] && log_skip $2 ${MAXTEST} "$TEST (clang)";
+ return 0
+ fi
+
+ SAVE_TEST="$TEST"
+ TEST="$TEST (clang)"
+ testmake $1 $2
+ retval=$?
+ CLANG_CC=""; export CLANG_CC
+ TEST="$SAVE_TEST"
+ return $retval
+}
+
+testmake ()
+{
+ fail=0
+ #
+ # Compiler warnings can be OS specific, but at least
+ # on Linux there should be none
+ #
+ isLinux=0
+ uname -a | grep Linux >/dev/null
+ if [ $? -eq 0 ]; then
+ isLinux=1
+ sed --in-place 's/-Wall/-Wall -Werror -Wpointer-arith -Wcast-qual/' Makefile
+ fi
+ #
+ if test x$1 = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure... $TEST";
+ $MAKE clean > /dev/null 2>> test_log
+ if [ -z "$CLANG_CC" ]; then
+ $MAKE cutest > /dev/null 2>> test_log
+ else
+ sed --in-place 's/-Wno-empty-body/-Wno-empty-body -Wno-invalid-source-encoding/g' Makefile
+ sed --in-place 's/-fno-strength-reduce//g' Makefile
+ $MAKE -e CC=$CLANG_CC -e BUILD_CC=$CLANG_CC cutest > /dev/null 2>> test_log
+ fi
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make cutest... $TEST";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make cutest... $TEST";
+ fail=1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure... $TEST";
+ if [ x"$3" = xskip ]; then
+ [ -z "$quiet" ] && log_skip $2 ${MAXTEST} "$TEST";
+ fi
+ fail=1
+ fi
+ if [ $isLinux -eq 1 ]; then
+ sed --in-place 's/-Wall -Werror/-Wall/' Makefile
+ fi
+ if [ $fail -eq 1 ]; then
+ [ -z "$quiet" ] && log_fail $2 ${MAXTEST} "$TEST";
+ return 1
+ fi
+ [ -z "$quiet" ] && log_ok $2 ${MAXTEST} "$TEST";
+ return 0
+}
+
+testcompile ()
+{
+ log_start "COMPILE"
+
+ num=0
+ numfail=0
+
+
+ C_LOGFILE=""
+
+ ls /lib/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ else
+ ls /usr/lib/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ else
+ ls /usr/lib/*/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ else
+ ls /usr/local/lib/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ fi
+ fi
+ fi
+ fi
+ if [ x"${C_LOGFILE}" = x ]; then
+ log_msg_ok "Not testing --enable-logfile-monitor";
+ fi
+
+ #
+ # test dnmalloc
+ #
+ TEST="${S}check dnmalloc${E}"
+ #
+ ${TOP_SRCDIR}/configure --quiet > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ #
+ run_dnmalloc 0 $num || let "numfail = numfail + 1" >/dev/null
+ #
+
+ #
+ # test dnmalloc
+ #
+ TEST="${S}check w/cppcheck${E}"
+ #
+ let "num = num + 1" >/dev/null
+ #
+ run_cppcheck 0 $num || let "numfail = numfail + 1" >/dev/null
+ #
+
+ #
+ # test flawfinder
+ #
+ TEST="${S}check w/flawfinder${E}"
+ #
+ #
+ let "num = num + 1" >/dev/null
+ FLAWFINDER=`find_path flawfinder`
+ #
+ if [ -z "$FLAWFINDER" ]; then
+ log_skip $num $MAXTEST 'check w/flawfinder (not in PATH)'
+ else
+ run_flawfinder 0 $num || let "numfail = numfail + 1" >/dev/null
+ fi
+ #
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/suidcheck w/procchk${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-suidcheck --enable-process-check > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone static w/suidcheck w/procchk${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-static --enable-suidcheck --enable-process-check ${C_LOGFILE} > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/procchk w/portchk${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-process-check --enable-port-check > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/procchk w/portchk w/static${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-process-check --enable-port-check --enable-static > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/procchk w/portchk w/stealth${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-stealth=164 --enable-process-check --enable-port-check > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/mounts-check w/userfiles${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-mounts-check --enable-userfiles > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/timeserver and w/msgqueue${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --enable-message-queue --with-timeserver=127.0.0.1 > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation with --with-nocl=PW
+ #
+ TEST="${S}standalone w/nocl w/logmon${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --enable-nocl="owl" --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test ${C_LOGFILE} > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/ debug
+ #
+ TEST="${S}standalone w/debug${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-debug --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num debug || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/ gpg
+ #
+ TEST="${S}standalone w/gpg${E}"
+ #
+ GPG=`find_path gpg`
+ let "num = num + 1" >/dev/null
+ #
+ if [ -z "$GPG" ]; then
+ log_skip $num $MAXTEST 'gpg not in PATH'
+ let "num = num + 1" >/dev/null
+ log_skip $num $MAXTEST 'gpg not in PATH'
+ else
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --with-gpg=$GPG --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ fi
+
+ #
+ # test standalone compilation w/stealth
+ #
+ TEST="${S}standalone w/stealth${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-stealth=128 --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/loginwatch
+ #
+ TEST="${S}standalone w/login-watch${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/mysql
+ #
+ TEST="${S}standalone w/mysql${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-xml-log --with-database=mysql --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num "skip" || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/mysql and stealth
+ #
+ TEST="${S}standalone w/mysql+stealth${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-xml-log --enable-stealth=128 --with-database=mysql --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num "skip" || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/postgresql
+ #
+ TEST="${S}standalone w/postgresql${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-xml-log --with-database=postgresql --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num "skip" || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation w/postgresql+stealth
+ #
+ TEST="${S}standalone w/postgresql+stealth${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-xml-log --enable-stealth=128 --with-database=postgresql --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num "skip" || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/o mail w/unix_rnd${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --disable-mail --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-rnd=unix > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone w/o external${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --disable-external-scripts --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ # echo; echo "${S}__ TEST CLIENT/SERVER __${E}"; echo;
+
+ #
+ # test client/server compilation
+ #
+ TEST="${S}client/server application w/timeserver${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --enable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-timeserver=127.0.0.1 > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-timeserver=127.0.0.1 > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test client/server compilation w/prelude
+ #
+ TEST="${S}client/server application w/prelude${E}"
+ #
+ if [ -z "$doall" ]; then
+ let "num = num + 1" >/dev/null
+ [ -z "$quiet" ] && log_skip $num ${MAXTEST} "$TEST";
+ let "num = num + 1" >/dev/null
+ [ -z "$quiet" ] && log_skip $num ${MAXTEST} "$TEST (smatch)";
+
+ let "num = num + 1" >/dev/null
+ [ -z "$quiet" ] && log_skip $num ${MAXTEST} "$TEST";
+ let "num = num + 1" >/dev/null
+ [ -z "$quiet" ] && log_skip $num ${MAXTEST} "$TEST (smatch)";
+ else
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --enable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-prelude > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-prelude > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ fi
+
+ #
+ # test client/server compilation
+ #
+ TEST="${S}client/server application static w/timeserver${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --enable-static --enable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-timeserver=127.0.0.1 ${C_LOGFILE} > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-static --enable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test --with-timeserver=127.0.0.1 > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ # test c/s compilation w/ gpg
+ #
+ TEST="${S}client/server application w/gpg${E}"
+ #
+ GPG=`find_path gpg`
+ let "num = num + 1" >/dev/null
+ #
+ if [ -z "$GPG" ]; then
+ log_skip $num $MAXTEST 'gpg not in PATH'
+ let "num = num + 1" >/dev/null
+ log_skip $num $MAXTEST 'gpg not in PATH'
+ let "num = num + 1" >/dev/null
+ log_skip $num $MAXTEST 'gpg not in PATH'
+ let "num = num + 1" >/dev/null
+ log_skip $num $MAXTEST 'gpg not in PATH'
+ else
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-srp --with-gpg=$GPG --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --enable-srp --with-gpg=$GPG --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test ${C_LOGFILE} > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ fi
+
+
+ #
+ # test client/server compilation
+ #
+ TEST="${S}client/server application w/o srp, w/udp${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-udp --disable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --disable-srp --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test client/server compilation w/ debug
+ #
+ TEST="${S}client/server application w/debug${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-debug --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num debug || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --enable-debug --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test ${C_LOGFILE} > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num debug || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test client/server compilation w/stealth
+ #
+ TEST="${S}client/server application w/stealth${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-srp --enable-stealth=128 --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --enable-srp --enable-stealth=128 --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test client/server compilation w/logwatch
+ #
+ TEST="${S}client/server application w/login-watch,udp,no_ipv6${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --enable-udp --disable-ipv6 --enable-srp --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --disable-ipv6 --enable-srp --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test client/server compilation
+ #
+ TEST="${S}client/server application w/o mail${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --disable-mail --enable-srp --enable-stealth=128 --enable-debug --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num debug || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --disable-mail --enable-srp --enable-stealth=128 --enable-debug --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num debug || let "numfail = numfail + 1" >/dev/null
+
+ #
+ # test client/server compilation
+ #
+ TEST="${S}client/server application w/o external${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=server --disable-srp --disable-external-scripts --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+ #
+ if test -r "Makefile"; then
+ $MAKE clean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-network=client --disable-srp --disable-external-scripts --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/samhainrc.test > /dev/null 2>> test_log
+ #
+ let "num = num + 1" >/dev/null
+ testmake $? $num || let "numfail = numfail + 1" >/dev/null
+ let "num = num + 1" >/dev/null
+ run_clang $? $num || let "numfail = numfail + 1" >/dev/null
+
+ log_end "COMPILE"
+}
diff --git a/test/testext.sh b/test/testext.sh
new file mode 100755
index 0000000..cae2fa9
--- /dev/null
+++ b/test/testext.sh
@@ -0,0 +1,163 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+MAXTEST=2; export MAXTEST
+
+testext0 ()
+{
+ COMP=`which gcc`
+ if test "x$?" = x1 ; then
+ COMP="cc"
+ else
+ COMP=`which gcc | sed -e "s%\([a-z:]\) .*%\1%g"`
+ if test "x$COMP" = x; then
+ COMP="cc"
+ elif test "x$COMP" = xno; then
+ COMP="cc"
+ else
+ if test "x$COMP" = "xwhich:"; then
+ COMP="cc"
+ else
+ COMP="gcc"
+ gcc -v >/dev/null 2>&1 || COMP="gcc"
+ fi
+ fi
+ fi
+ log_start "EXTERNAL PROGRAM"
+ [ -z "$verbose" ] || echo MAKE is $MAKE
+ [ -z "$verbose" ] || { echo COMP is $COMP; echo; }
+ #
+ # standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ ${MAKE} distclean >/dev/null
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$PW_DIR/testrc_1ext --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+ #
+ # prepare the program
+ #
+ cat test/test_ext.c.in | sed -e "s%MYPWDIR%$PW_DIR/test_ext.res%g" > test_ext.c
+
+ ${COMP} -o test_ext test_ext.c
+ if test "x$?" != x0; then
+ log_msg_fail "${COMP} -o test_ext test_ext.c"
+ return 1
+ fi
+ chmod +rx test_ext
+ if test "x$?" != x0; then
+ log_msg_fail "chmod +rx test_ext"
+ return 1
+ fi
+
+ # compute checksum and fix config file
+ #
+ cp test/testrc_1ext.in testrc_1ext
+ CHKSUM=`./samhain -H $PW_DIR/test_ext | awk '{ print $2$3$4$5$6$7}'`
+ echo "OpenCommand=$PW_DIR/test_ext" >> testrc_1ext
+ echo "SetType=log" >> testrc_1ext
+ echo "SetChecksum=$CHKSUM" >> testrc_1ext
+ echo "SetEnviron=TZ=Europe/Berlin" >> testrc_1ext
+ echo "SetFilterOr=ALERT" >> testrc_1ext
+ echo "CloseCommand" >> testrc_1ext
+ echo "OpenCommand=$PW_DIR/test_ext" >> testrc_1ext
+ echo "SetType=log" >> testrc_1ext
+ echo "SetChecksum=$CHKSUM" >> testrc_1ext
+ echo "SetFilterOr=ALERT" >> testrc_1ext
+ echo "CloseCommand" >> testrc_1ext
+
+ rm -f $PW_DIR/test_ext.res
+ rm -f $PW_DIR/pdbg.child
+ rm -f $PW_DIR/pdbg.main
+ ./samhain -p none
+
+ # The shell is too fast ...
+ one_sec_sleep
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Logged by external C program test_ext (filtered: ALERT only):${E}";
+ echo;
+ cat $PW_DIR/test_ext.res
+ echo
+ }
+
+ tmp=`cat $PW_DIR/test_ext.res | wc -l`
+ if [ $tmp -eq 8 ]; then
+ tmp=`egrep 'RECV: \[EOF\]' $PW_DIR/test_ext.res | wc -l`
+ if [ $tmp -eq 4 ]; then
+ tmp=`egrep 'RECV: ALERT' $PW_DIR/test_ext.res | wc -l`
+ if [ $tmp -eq 4 ]; then
+ log_ok 1 ${MAXTEST};
+ else
+ log_fail 1 ${MAXTEST};
+ fi
+ else
+ log_fail 1 ${MAXTEST};
+ fi
+ else
+ log_fail 1 ${MAXTEST};
+ fi
+
+ ORIGINAL="SetChecksum=${CHKSUM}"
+ REPLACEMENT="SetChecksum=DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
+
+ ex -s "$PW_DIR/testrc_1ext" <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+
+ rm -f $PW_DIR/test_ext.res
+ rm -f $PW_DIR/pdbg.child
+ rm -f $PW_DIR/pdbg.main
+ ./samhain -p none
+
+ one_sec_sleep
+
+ if [ -f $PW_DIR/test_ext.res ]; then
+ log_fail 2 ${MAXTEST};
+ else
+ log_ok 2 ${MAXTEST};
+ fi
+
+ rm -f $PW_DIR/.samhain_file
+ rm -f $LOGFILE
+ rm -f $PW_DIR/.samhain_lock
+
+ log_end "EXTERNAL PROGRAM"
+}
+
diff --git a/test/testhash.sh b/test/testhash.sh
new file mode 100755
index 0000000..c2e20f4
--- /dev/null
+++ b/test/testhash.sh
@@ -0,0 +1,135 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+
+MAXTEST=2; export MAXTEST
+
+testhash ()
+{
+ log_start "HASH FUNCTION"
+
+ C_LOGFILE=""
+
+ ls /lib/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ else
+ ls /usr/lib/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ else
+ ls /usr/lib/*/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ else
+ ls /usr/local/lib/libpcre* >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ C_LOGFILE=" --enable-logfile-monitor "
+ fi
+ fi
+ fi
+ fi
+ if [ x"${C_LOGFILE}" = x ]; then
+ log_msg_ok "Not testing --enable-logfile-monitor";
+ fi
+
+ #
+ # test standalone compilation
+ #
+ TEST="${S}standalone agent${E}"
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --enable-debug=gdb --quiet $TRUST --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file --enable-db-reload '--enable-login-watch' '--enable-mounts-check' ${C_LOGFILE} '--enable-port-check' '--enable-process-check' '--enable-message-queue' '--enable-suidcheck' '--disable-dnmalloc'
+ #
+ fail=0
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>> test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ fail=1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ fail=1
+ fi
+ #
+ if [ $fail -eq 1 ]; then
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST};
+ return 1
+ fi
+ #
+ echo "Test results of the TIGER hash algorithm" > testhash.tmp
+ echo >> testhash.tmp
+ echo "(use samhain -H string to test)" >> testhash.tmp
+ echo >> testhash.tmp
+ ./samhain -H "" >> testhash.tmp
+ ./samhain -H "abc" >> testhash.tmp
+ ./samhain -H "Tiger" >> testhash.tmp
+ ./samhain -H "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-" >> testhash.tmp
+ ./samhain -H "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789" >> testhash.tmp
+ ./samhain -H "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham" >> testhash.tmp
+ ./samhain -H "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge." >> testhash.tmp
+ ./samhain -H "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996." >> testhash.tmp
+ ./samhain -H "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-" >> testhash.tmp
+ #
+ RESU=`diff testhash.tmp ${SCRIPTDIR}/testtiger.txt 2>/dev/null`
+ if test "x${RESU}" = "x"; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST};
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST};
+ return 1
+ fi
+ #
+ #
+ #
+ TEST="${S}files${E}"
+ #
+ case $SCRIPTDIR in
+ /*)
+ testpath="${SCRIPTDIR}/testtiger.txt";;
+ *)
+ testpath="`pwd`/${SCRIPTDIR}/testtiger.txt";;
+ esac
+ #
+ RESU=`./samhain -H ${testpath}`
+ #
+ if test x"$RESU" = x"${testpath}: 8125E439 4E7E20F9 24FD8E37 BC4D90C7 FC67F40C 1681F05D"; then
+ [ -z "$quiet" ] && log_ok 2 ${MAXTEST};
+ else
+ [ -z "$quiet" ] && log_fail 2 ${MAXTEST};
+ return 1
+ fi
+ #
+ log_end "HASH FUNCTION"
+ return 0
+}
+
+
+
diff --git a/test/testit.sh b/test/testit.sh
new file mode 100755
index 0000000..3f8ab76
--- /dev/null
+++ b/test/testit.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+if test x$UID != x -a x$UID != x0; then
+ TRUST="--with-trusted=0,2,$UID"
+else
+ TRUST="--with-trusted=0,2,1000"
+fi
+export TRUST
+#
+PW_DIR=`pwd`; export PW_DIR
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+#
+OPTIONS="\
+--enable-db-reload \
+--enable-suidcheck \
+--enable-login-watch \
+--enable-mounts-check \
+--enable-logfile-monitor \
+--enable-process-check \
+--enable-port-check \
+--enable-xml-log \
+--enable-userfiles \
+--disable-shellexpand \
+--disable-ipv6 \
+"
+
+./configure --quiet $TRUST \
+ --prefix=$PW_DIR \
+ --localstatedir=$PW_DIR \
+ --with-config-file=$RCFILE \
+ --with-log-file=$LOGFILE \
+ --with-pid-file=$PW_DIR/.samhain_lock \
+ --with-data-file=$PW_DIR/.samhain_file $OPTIONS
+
+if [ $? -ne 0 ];
+then
+ echo "Configure failed"
+ exit 1
+fi
+
+make samhain
+
+if [ $? -ne 0 ];
+then
+ echo "Make failed"
+ exit 1
+fi
diff --git a/test/testrc_1 b/test/testrc_1
new file mode 100644
index 0000000..ee57b39
--- /dev/null
+++ b/test/testrc_1
@@ -0,0 +1,273 @@
+#####################################################################
+#
+# Configuration file template for samhain.
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#' are ignored
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+#
+# SETUP for file system checking:
+#
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) To each policy, you can assign a severity (further below).
+# (iii) To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+
+
+[Misc]
+RedefUser0=-ATM
+
+[Attributes]
+#
+# for these files, only changes in permissions and ownership are checked
+#
+#file=/etc/mtab
+#file=/etc/ssh_random_seed
+#file=/etc/asound.conf
+#file=/etc/resolv.conf
+#file=/etc/localtime
+#file=/etc/ioctl.save
+#file=/etc/passwd.backup
+#file=/etc/shadow.backup
+
+
+#
+# There are files in /etc that might change (see above),
+# thus changing the timestamps on the directory special file.
+# Put it here as 'file', and in the ReadOnly section as 'dir'.
+#
+file=/etc
+
+[GrowingLogFiles]
+#
+# for these files, changes in signature, timestamps, and increase in size
+# are ignored
+#
+# Example for shell-style wildcard pattern
+#
+#file=/var/log/n*
+
+[IgnoreAll]
+#dir=-1/etc
+
+[IgnoreNone]
+#dir=-1/etc
+
+[Attributes]
+# dir=/opt/gnome/bin/
+# file=/usr/bin/ssh
+
+
+[ReadOnly]
+#
+# for these files, only access time is ignored
+#
+#dir=/dev
+# dir=/usr/bin
+
+#dir=/usr/bin
+#dir=/lib
+#dir=/usr/lib
+
+#dir=/lib
+#dir=3/etc
+#dir=/tmp
+# file=/usr/bin/ssh
+# dir=1/home/rainer
+
+#[SuidCheck]
+#SuidCheckActive=T
+#SuidCheckExclude=/home
+
+[EventSeverity]
+#
+# Here you can assign severities to policy violations.
+# If this severity exceeds the treshold of a log facility (see below),
+# a policy violation will be logged to that facility.
+#
+# Severity for verification failures.
+#
+SeverityUser0=crit
+SeverityUser1=crit
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+#
+# We have a file in IgnoreAll that might or might not be present.
+# Setting the severity to 'info' prevents messages about deleted/new file.
+#
+SeverityIgnoreAll=warn
+
+#
+# Files : file access problems
+# Dirs : directory access problems
+# Names : suspect (non-printable) characters in a pathname
+#
+SeverityFiles=notice
+SeverityDirs=info
+SeverityNames=warn
+
+[Log]
+#
+# Set threshold severity for log facilities
+# Values: debug, info, notice, warn, mark, err, crit, alert, none.
+# 'mark' is used for timestamps.
+#
+# By default, everything equal to and above the threshold is logged.
+# The specifiers '*', '!', and '=' are interpreted as
+# 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+# at least on Linux).
+#
+# MailSeverity=*
+# MailSeverity=!warn
+# MailSeverity==crit
+#
+MailSeverity=none
+LogSeverity=warn
+SyslogSeverity=none
+#ExportSeverity=none
+PrintSeverity=info
+# Restrict to certain classes of messages
+# MailClass = RUN
+#PreludeSeverity = err
+
+# Which system calls to log (execve, utime, unlink, dup, chdir, open, kill,
+# exit, fork, setuid, setgid, pipe)
+#
+# LogCalls = open
+
+
+#[Kernel]
+#
+# Setings this to 1/true/yes will activate the check for loadable
+# kernel module rootkits (Linux only)
+#
+#KernelCheckActive=1
+#KernelCheckInterval = 20
+
+#[Utmp]
+#
+# 0 to switch off, 1 to activate
+#
+#LoginCheckActive=1
+
+# Severity for logins, multiple logins, logouts
+#
+#SeverityLogin=info
+#SeverityLoginMulti=warn
+#SeverityLogout=info
+
+# interval for login/logout checks
+#
+#LoginCheckInterval=60
+
+[Misc]
+#
+# whether to become a daemon process
+Daemon=no
+
+# Custom format for message header
+#
+# %S severity
+# %T timestamp
+# %C class
+#
+# %F source file
+# %L source line
+#
+# MessageHeader="%S %T - %F - %L "
+# MessageHeader="<log sev="%S" time="%T" "
+
+# the maximum time between client messages (seconds)
+# (this is a log server-only option; the default is 86400 sec = 1 day
+#
+# SetClientTimeLimit=1800
+
+# time till next file check (seconds)
+SetFilecheckTime=120
+
+# DigestAlgo=MD5
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# maximum time till next mail (seconds)
+SetMailTime=86400
+
+# maximum number of queued mails
+SetMailNum=10
+
+# where to send mail to
+SetMailAddress=root@localhost
+# MailSubject=* body %H # %M
+
+#TrustedUser=uucp,fax,fnet
+
+# Watch syslog port
+#
+# SetUDPActive = yes
+
+# mail relay host
+# SetMailRelay=localhost
+
+# The binary. Setting the path will allow
+# samhain to check for modifications between
+# startup and exit.
+#
+# SamhainPath=/usr/local/bin/samhain
+
+# where to get time from
+# SetTimeServer=www.yourdomain.de
+
+# where to export logs to
+# SetLogServer=localhost
+
+SetRecursionLevel=10
+
+#setdatabasepath=AUTO
+#setlogfilepath=AUTO
+#setlockfilepath=AUTO
+
+# timer for time stamps
+SetLoopTime=60
+
+# report in full detail on modified files
+#
+ReportFullDetail = no
+
+# trusted users (root and the effective user are always trusted)
+# TrustedUser=bin
+
+# whether to test signature of files (init/check/none)
+# - if 'none', then we have to decide this on the command line -
+#
+ChecksumTest=check
+
+# Set the facility for syslog
+#
+# SyslogFacility=LOG_MAIL
+
+# Don't log names of configuration/database files on startup
+#
+# HideSetup=yes
+
+
+# everything below is ignored
+[EOF]
diff --git a/test/testrc_1ext.in b/test/testrc_1ext.in
new file mode 100644
index 0000000..51d7f33
--- /dev/null
+++ b/test/testrc_1ext.in
@@ -0,0 +1,187 @@
+#####################################################################
+#
+# Configuration file template for samhain.
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#' are ignored
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+#
+# SETUP for file system checking:
+#
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) To each policy, you can assign a severity (further below).
+# (iii) To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+
+
+[Attributes]
+#
+# for these files, only changes in permissions and ownership are checked
+#
+
+#
+# There are files in /etc that might change, thus changing the directory
+# timestamps. Put it here as 'file', and in the ReadOnly section as 'dir'.
+#
+
+
+[GrowingLogFiles]
+#
+# for these files, changes in signature, timestamps, and increase in size
+# are ignored
+#
+
+
+[ReadOnly]
+#
+# for these files, only access time is ignored
+#
+#dir=/usr/bin
+#dir=/bin
+#dir=3/etc
+
+[EventSeverity]
+#
+# Here you can assign severities to policy violations.
+# If this severity exceeds the treshold of a log facility (see below),
+# a policy violation will be logged to that facility.
+#
+# Severity for verification failures.
+#
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+#
+# We have a file in IgnoreAll that might or might not be present.
+# Setting the severity to 'info' prevents messages about deleted/new file.
+#
+SeverityIgnoreAll=info
+
+#
+# Files : file access problems
+# Dirs : directory access problems
+# Names : suspect (non-printable) characters in a pathname
+#
+SeverityFiles=crit
+SeverityDirs=crit
+SeverityNames=warn
+
+[Log]
+#
+# Set threshold severity for log facilities
+# Values: debug, info, notice, warn, mark, err, crit, alert, none.
+# 'mark' is used for timestamps.
+#
+# By default, everything equal to and above the threshold is logged.
+# The specifiers '*', '!', and '=' are interpreted as
+# 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+# at least on Linux).
+#
+# MailSeverity=*
+# MailSeverity=!warn
+# MailSeverity==crit
+#
+MailSeverity=none
+PrintSeverity=none
+LogSeverity=none
+SyslogSeverity=none
+ExportSeverity=none
+ExternalSeverity=info
+
+
+
+[Utmp]
+#
+# 0 to switch off, 1 to activate
+#
+LoginCheckActive=1
+
+# Severity for logins, multiple logins, logouts
+#
+SeverityLogin=info
+SeverityLoginMulti=warn
+SeverityLogout=info
+
+# interval for login/logout checks
+#
+LoginCheckInterval=60
+
+[Misc]
+#
+# whether to become a daemon process
+Daemon=no
+
+# MessageHeader="%S %T - %F - %L :%C: "
+
+# the maximum time between client messages (seconds)
+# (this is a log server-only option; the default is 86400 sec = 1 day
+#
+# SetClientTimeLimit=1800
+
+# time till next file check (seconds)
+SetFilecheckTime=600
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# maximum time till next mail (seconds)
+SetMailTime=86400
+
+# maximum number of queued mails
+SetMailNum=10
+
+# where to send mail to
+SetMailAddress=root@localhost
+
+
+# mail relay host
+# SetMailRelay=relay.yourdomain.de
+
+# The binary. Setting the path will allow
+# samhain to check for modifications between
+# startup and exit.
+#
+# SamhainPath=/usr/local/bin/samhain
+
+# where to get time from
+# SetTimeServer=www.yourdomain.de
+
+# where to export logs to
+SetLogServer=localhost
+
+# timer for time stamps
+SetLoopTime=60
+
+# report in full detail on modified files
+#
+ReportFullDetail = no
+
+# trusted users (root and the effective user are always trusted)
+# TrustedUser=bin
+
+# whether to test signature of files (init/check/none)
+# - if 'none', then we have to decide this on the command line -
+#
+ChecksumTest=init
+
+[External]
+
+
+
diff --git a/test/testrc_2.in b/test/testrc_2.in
new file mode 100644
index 0000000..a41068e
--- /dev/null
+++ b/test/testrc_2.in
@@ -0,0 +1,216 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+NotDashEscaped: You need GnuPG to verify this message
+
+#####################################################################
+#
+# Configuration file template for samhain.
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#' are ignored
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+#
+# SETUP for file system checking:
+#
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) To each policy, you can assign a severity (further below).
+# (iii) To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+
+
+[ReadOnly]
+#
+# for these files, only access time is ignored
+#
+# dir=/usr/bin
+# dir=/bin
+
+file = /var
+file = /bin
+file = /usr
+file = /tmp
+file = /etc
+
+# hopefully does not exist
+file=/etc/toodleedoo
+
+dir=1/usr
+
+[EventSeverity]
+#
+# Here you can assign severities to policy violations.
+# If this severity exceeds the treshold of a log facility (see below),
+# a policy violation will be logged to that facility.
+#
+# Severity for verification failures.
+#
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+#
+# We have a file in IgnoreAll that might or might not be present.
+# Setting the severity to 'info' prevents messages about deleted/new file.
+#
+SeverityIgnoreAll=info
+
+#
+# Files : file access problems
+# Dirs : directory access problems
+# Names : suspect (non-printable) characters in a pathname
+#
+SeverityFiles=crit
+SeverityDirs=crit
+SeverityNames=warn
+
+[Log]
+#
+# Set threshold severity for log facilities
+# Values: debug, info, notice, warn, mark, err, crit, alert, none.
+# 'mark' is used for timestamps.
+#
+# By default, everything equal to and above the threshold is logged.
+# The specifiers '*', '!', and '=' are interpreted as
+# 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+# at least on Linux).
+#
+# MailSeverity=*
+# MailSeverity=!warn
+# MailSeverity==crit
+#
+MailSeverity=none
+PrintSeverity=info
+#PRINTClass = "RUN FIL STAMP"
+LogSeverity=none
+SyslogSeverity=none
+ExportSeverity=none
+DatabaseSeverity=none
+
+#databaseseverity=info
+
+[Database]
+# setdbname=samhain
+# setdbtable=log
+setdbuser=samhain
+setdbpassword=samhain
+#AddToDBHash=log_msg
+# AddToDBHash=log_host
+UsePersistent = True
+
+[Utmp]
+#
+# 0 to switch off, 1 to activate
+#
+LoginCheckActive=1
+
+# Severity for logins, multiple logins, logouts
+#
+SeverityLogin=info
+SeverityLoginMulti=warn
+SeverityLogout=info
+
+# interval for login/logout checks
+#
+LoginCheckInterval=60
+
+[Misc]
+#
+# whether to become a daemon process
+Daemon=no
+
+SetOutgoingIP = 127.0.0.1
+SetServerInterface = 127.0.0.1
+
+UseSeparateLogs=no
+
+SetUseSocket = yes
+SetSocketAllowUid=0
+SetSocketPassword=samhain
+
+SetClientFromAccept = yes
+
+SetUdpActive=no
+
+# the maximum time between client messages (seconds)
+# (this is a log server-only option; the default is 86400 sec = 1 day
+#
+# SetClientTimeLimit=1800
+
+UseClientSeverity = yes
+UseClientClass = yes
+
+# Format for message headers
+#
+# MessageHeader="%S %T %F %L "
+
+# priority for peer != address as notified by client
+# (lookup may fail on firewalled client)
+#
+# SeverityLookup = warn
+
+# time till next file check (seconds)
+SetFilecheckTime=600
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# maximum time till next mail (seconds)
+SetMailTime=86400
+
+# maximum number of queued mails
+SetMailNum=10
+
+# where to send mail to
+SetMailAddress=root@localhost
+
+# mail relay host
+# SetMailRelay=relay.yourdomain.de
+
+# The binary. Setting the path will allow
+# samhain to check for modifications between
+# startup and exit.
+#
+# SamhainPath=/usr/local/bin/samhain
+
+# where to get time from
+# SetTimeServer=www.yourdomain.de
+
+# where to export logs to
+SetLogServer=localhost
+
+# timer for time stamps
+SetLoopTime=10
+
+# trusted users (root and the effective user are always trusted)
+# TrustedUser=bin
+
+# whether to test signature of files (init/check/none)
+# - if 'none', then we have to decide this on the command line -
+#
+ChecksumTest=check
+
+
+[Clients]
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iEYEARECAAYFAlUTGCcACgkQGq0myA9XH2zINACfQb/Wfa19OBbHVkw9uBNMB+lF
+cwUAnR0Geb+sFDcv7JsrrTjY8htjPHd2
+=7wXO
+-----END PGP SIGNATURE-----
diff --git a/test/testrc_2.in.asc b/test/testrc_2.in.asc
new file mode 100644
index 0000000..a41068e
--- /dev/null
+++ b/test/testrc_2.in.asc
@@ -0,0 +1,216 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+NotDashEscaped: You need GnuPG to verify this message
+
+#####################################################################
+#
+# Configuration file template for samhain.
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#' are ignored
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+#
+# SETUP for file system checking:
+#
+# (i) There are several policies, each has its own section. Put files
+# into the section for the appropriate policy (see below).
+# (ii) To each policy, you can assign a severity (further below).
+# (iii) To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+
+
+[ReadOnly]
+#
+# for these files, only access time is ignored
+#
+# dir=/usr/bin
+# dir=/bin
+
+file = /var
+file = /bin
+file = /usr
+file = /tmp
+file = /etc
+
+# hopefully does not exist
+file=/etc/toodleedoo
+
+dir=1/usr
+
+[EventSeverity]
+#
+# Here you can assign severities to policy violations.
+# If this severity exceeds the treshold of a log facility (see below),
+# a policy violation will be logged to that facility.
+#
+# Severity for verification failures.
+#
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+#
+# We have a file in IgnoreAll that might or might not be present.
+# Setting the severity to 'info' prevents messages about deleted/new file.
+#
+SeverityIgnoreAll=info
+
+#
+# Files : file access problems
+# Dirs : directory access problems
+# Names : suspect (non-printable) characters in a pathname
+#
+SeverityFiles=crit
+SeverityDirs=crit
+SeverityNames=warn
+
+[Log]
+#
+# Set threshold severity for log facilities
+# Values: debug, info, notice, warn, mark, err, crit, alert, none.
+# 'mark' is used for timestamps.
+#
+# By default, everything equal to and above the threshold is logged.
+# The specifiers '*', '!', and '=' are interpreted as
+# 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+# at least on Linux).
+#
+# MailSeverity=*
+# MailSeverity=!warn
+# MailSeverity==crit
+#
+MailSeverity=none
+PrintSeverity=info
+#PRINTClass = "RUN FIL STAMP"
+LogSeverity=none
+SyslogSeverity=none
+ExportSeverity=none
+DatabaseSeverity=none
+
+#databaseseverity=info
+
+[Database]
+# setdbname=samhain
+# setdbtable=log
+setdbuser=samhain
+setdbpassword=samhain
+#AddToDBHash=log_msg
+# AddToDBHash=log_host
+UsePersistent = True
+
+[Utmp]
+#
+# 0 to switch off, 1 to activate
+#
+LoginCheckActive=1
+
+# Severity for logins, multiple logins, logouts
+#
+SeverityLogin=info
+SeverityLoginMulti=warn
+SeverityLogout=info
+
+# interval for login/logout checks
+#
+LoginCheckInterval=60
+
+[Misc]
+#
+# whether to become a daemon process
+Daemon=no
+
+SetOutgoingIP = 127.0.0.1
+SetServerInterface = 127.0.0.1
+
+UseSeparateLogs=no
+
+SetUseSocket = yes
+SetSocketAllowUid=0
+SetSocketPassword=samhain
+
+SetClientFromAccept = yes
+
+SetUdpActive=no
+
+# the maximum time between client messages (seconds)
+# (this is a log server-only option; the default is 86400 sec = 1 day
+#
+# SetClientTimeLimit=1800
+
+UseClientSeverity = yes
+UseClientClass = yes
+
+# Format for message headers
+#
+# MessageHeader="%S %T %F %L "
+
+# priority for peer != address as notified by client
+# (lookup may fail on firewalled client)
+#
+# SeverityLookup = warn
+
+# time till next file check (seconds)
+SetFilecheckTime=600
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# maximum time till next mail (seconds)
+SetMailTime=86400
+
+# maximum number of queued mails
+SetMailNum=10
+
+# where to send mail to
+SetMailAddress=root@localhost
+
+# mail relay host
+# SetMailRelay=relay.yourdomain.de
+
+# The binary. Setting the path will allow
+# samhain to check for modifications between
+# startup and exit.
+#
+# SamhainPath=/usr/local/bin/samhain
+
+# where to get time from
+# SetTimeServer=www.yourdomain.de
+
+# where to export logs to
+SetLogServer=localhost
+
+# timer for time stamps
+SetLoopTime=10
+
+# trusted users (root and the effective user are always trusted)
+# TrustedUser=bin
+
+# whether to test signature of files (init/check/none)
+# - if 'none', then we have to decide this on the command line -
+#
+ChecksumTest=check
+
+
+[Clients]
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iEYEARECAAYFAlUTGCcACgkQGq0myA9XH2zINACfQb/Wfa19OBbHVkw9uBNMB+lF
+cwUAnR0Geb+sFDcv7JsrrTjY8htjPHd2
+=7wXO
+-----END PGP SIGNATURE-----
diff --git a/test/testrun_1.sh b/test/testrun_1.sh
new file mode 100755
index 0000000..b00d92a
--- /dev/null
+++ b/test/testrun_1.sh
@@ -0,0 +1,1306 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+
+# --enable-login-watch --enable-xml-log
+# --enable-debug --enable-suidcheck --with-prelude
+
+BUILDOPTS="--quiet $TRUST --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file --enable-debug"
+export BUILDOPTS
+
+BASE="${PW_DIR}/testrun_testdata"; export BASE
+TDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c"; export TDIRS
+TFILES="x y z"; export TFILES
+
+###########################################################
+#
+# ---- [Define tests here] ----
+#
+
+# 1 for testing new tests
+testrun1_setup=0
+
+MAXTEST=15; export MAXTEST
+MAXTEST_3=15; export MAXTEST_3
+
+test_dirs () {
+ for ff in $CDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ fi
+ #
+ done
+ for ff in $NDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ done
+}
+
+
+TESTPOLICY_15="
+[Misc]
+DigestAlgo=SHA1
+RedefReadOnly = +TXT
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_15 () {
+ mod_testdata_1
+}
+chk_testdata_15 () {
+ chk_testdata_1
+}
+
+TESTPOLICY_14="
+[Misc]
+DigestAlgo=MD5
+RedefReadOnly = +TXT
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_14 () {
+ mod_testdata_1
+}
+chk_testdata_14 () {
+ chk_testdata_1
+}
+
+#
+# combine file check schedule with one-shot mode
+#
+TESTPOLICY_13="
+[ReadOnly]
+dir=99${BASE}
+"
+
+mod_testdata_13 () {
+ one_sec_sleep
+ echo "foobar" >"${BASE}/c/x"; # bad
+ chmod 0555 "${BASE}/a/y"; # bad
+ ORIGINAL='SetFilecheckTime=60'
+ REPLACEMENT='FileCheckScheduleOne = 6 12 * * *'
+ ex -s $RCFILE <<EOF
+%s/${ORIGINAL}/${REPLACEMENT}/g
+wq
+EOF
+}
+
+chk_testdata_13 () {
+ # CDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/c/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] -----M--T-.*${BASE}/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/y";
+ return 1
+ fi
+ CDIRS="a a/a a/b a/c c b a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ NDIRS="";
+ test_dirs;
+ return $?
+}
+
+TESTPOLICY_12="
+[ReadOnly]
+dir=99${BASE}
+[IgnoreAll]
+dir=-1${BASE}/b
+[Attributes]
+dir=1${BASE}/a
+"
+
+mod_testdata_12 () {
+ one_sec_sleep
+ echo "foobar" >"${BASE}/b/x"; # ok
+ echo "foobar" >"${BASE}/c/x"; # bad
+ echo "foobar" >"${BASE}/a/x"; # ok
+ chmod 0555 "${BASE}/a/a/x"; # bad
+ chmod 0555 "${BASE}/a/a/a/x";# ok
+ chmod 0555 "${BASE}/a/y"; # bad
+}
+
+chk_testdata_12 () {
+ # CDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 3 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/c/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/a/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/y";
+ return 1
+ fi
+ CDIRS="a a/a a/b a/c c";
+ NDIRS="b a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ test_dirs;
+ return $?
+}
+
+#
+# --- ACL/SELinux test case
+#
+TESTPOLICY_11="
+[Misc]
+UseAclCheck=yes
+UseSelinuxCheck=yes
+[ReadOnly]
+dir=99${BASE}
+[IgnoreAll]
+dir=-1${BASE}/b
+[Attributes]
+dir=1${BASE}/a
+[Misc]
+UseSelinuxCheck = no
+UseAclCheck = no
+"
+
+mod_testdata_11 () {
+ one_sec_sleep
+ setfacl -m 'user:nobody:r--' "${BASE}/b/x"; # ok (ign)
+ setfacl -m 'user:nobody:r--' "${BASE}/c/x"; # bad
+ setfacl -m 'user:nobody:r--' "${BASE}/a/x"; # bad
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/b/y"; # ok (ign)
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/a/a/a/x";# ok (depth)
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/a/x"; # bad
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/a/y"; # bad
+}
+
+chk_testdata_11 () {
+ # CDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] --------T-.*${BASE}/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/c/x";
+ return 1
+ fi
+ CDIRS="a a/a a/b a/c c";
+ NDIRS="b a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ test_dirs;
+ return $?
+}
+
+TESTPOLICY_10="
+[Misc]
+UseAclCheck=yes
+UseSelinuxCheck=yes
+[ReadOnly]
+dir=99${BASE}
+[IgnoreAll]
+dir=-1${BASE}/b
+[Attributes]
+dir=1${BASE}/a
+"
+
+mod_testdata_10 () {
+ one_sec_sleep
+ setfacl -m 'user:nobody:r--' "${BASE}/b/x"; # ok (ign)
+ setfacl -m 'user:nobody:r--' "${BASE}/c/x"; # bad
+ setfacl -m 'user:nobody:r--' "${BASE}/a/x"; # bad
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/b/y"; # ok (ign)
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/a/a/a/x";# ok (depth)
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/a/x"; # bad
+ setfattr -n 'security.selinux' -v "system_u:object_r:etc_t\000" "${BASE}/a/y"; # bad
+}
+
+chk_testdata_10 () {
+ # CDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 5 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] -----M--T-.*${BASE}/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/c/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/y";
+ return 1
+ fi
+ CDIRS="a a/a a/b a/c c";
+ NDIRS="b a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ test_dirs;
+ return $?
+}
+
+TESTPOLICY_9="
+[ReadOnly]
+dir=0${BASE}/b
+[Attributes]
+dir=2${BASE}/a/a
+"
+
+mod_testdata_9 () {
+ echo "foobar" >"${BASE}/b/x";
+ echo "foobar" >"${BASE}/a/x";
+ echo "foobar" >"${BASE}/x";
+}
+
+chk_testdata_9 () {
+ # CDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ CDIRS="b a/a a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ NDIRS="a c a/b a/c";
+ test_dirs;
+ return $?
+}
+
+TESTPOLICY_8="
+[ReadOnly]
+dir=1${BASE}
+[Attributes]
+dir=1${BASE}/a/a
+"
+
+mod_testdata_8 () {
+ echo "foobar" >"${BASE}/a/x";
+ chmod 0555 "${BASE}/a/a/a/b/x";
+}
+
+chk_testdata_8 () {
+ # CDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c";
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ CDIRS="a b c a/a a/a/a a/a/b a/a/c";
+ NDIRS="a/b a/c a/a/a/a a/a/a/b a/a/a/c";
+ test_dirs;
+ return $?
+}
+
+
+TESTPOLICY_7="
+[ReadOnly]
+dir=${BASE}
+[Attributes]
+dir=${BASE}/a/a
+[GrowingLogFiles]
+dir=${BASE}/a/a/a
+[IgnoreAll]
+file=${BASE}/a/a/a/z
+dir=${BASE}/b
+[Misc]
+IgnoreMissing=${BASE}/a/[[:alnum:]]+/[[:alnum:]]+\$
+IgnoreAdded=${BASE}/a/(b|c)/[[:alnum:]]+\$
+"
+
+mod_testdata_7 () {
+ one_sec_sleep
+ echo "foobar" >"${BASE}/a/a/a/z" # ok
+ echo "foobar" >"${BASE}/a/a/a/x" # bad
+ echo "foobar" >"${BASE}/a/a/x" # ok
+ echo "foobar" >"${BASE}/a/x" # bad
+ chmod 0555 "${BASE}/a" # bad
+ chmod 0555 "${BASE}/b" # ok
+
+ rm "${BASE}/a/c/z"
+ touch "${BASE}/a/c/zz2"
+}
+
+
+chk_testdata_7 () {
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 4 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ egrep "ERROR.*POLICY MISSING.*${BASE}/a/c/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/c/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/c/zz2" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/c/zz2";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[GrowingLogs\] C--------S.*${BASE}/a/a/a/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] -----M--T-.*${BASE}/a" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/a/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/x";
+ return 1
+ fi
+}
+
+
+TESTPOLICY_6="
+[ReadOnly]
+dir=${BASE}
+[Attributes]
+file=${BASE}/a/y
+file=${BASE}/b/y
+file=${BASE}/c/y
+file=${BASE}/a/a/y
+file=${BASE}/a/b/y
+file=${BASE}/a/c/y
+file=${BASE}/a/a/a/y
+file=${BASE}/a/a/b/y
+file=${BASE}/a/a/c/y
+file=${BASE}/a/a/a/a/y
+file=${BASE}/a/a/a/b/y
+file=${BASE}/a/a/a/c/y
+"
+
+mod_testdata_6 () {
+ one_sec_sleep
+ for ff in $TDIRS; do
+ echo "foobar" >"${BASE}/${ff}/x"
+ chmod 0555 "${BASE}/${ff}/y"
+ echo "foobar" >"${BASE}/${ff}/z"
+ done
+}
+
+chk_testdata_6 () {
+ count6=0
+ for ff in $TDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ fi
+ #
+ for gg in $TFILES; do
+ egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (checking)";
+ fi
+ tmp=`egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (multiple)";
+ fi
+ done
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/${ff}/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/x";
+ return 1
+ fi
+ let "count6 = count6 + 1" >/dev/null
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/${ff}/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/z";
+ return 1
+ fi
+ let "count6 = count6 + 1" >/dev/null
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/${ff}/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/y";
+ return 1
+ fi
+ let "count6 = count6 + 1" >/dev/null
+ done
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne $count6 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+}
+
+TESTPOLICY_5="
+[Attributes]
+dir=${BASE}
+file=${BASE}/a/a/c/x
+[ReadOnly]
+file=${BASE}/a/a/c/y
+[GrowingLogFiles]
+dir=${BASE}/a/a/c
+dir=${BASE}/a/a/b
+dir=${BASE}/a/b
+"
+
+mod_testdata_5 () {
+ mod_testdata_4
+ echo "1 This is a xxxx file" > "${BASE}/a/a/b/x" # GrowingLogFiles
+ echo "1 This is a test file" > "${BASE}/a/a/b/y" # GrowingLogFiles
+ echo "2 This is a test file" >> "${BASE}/a/a/b/y" # GrowingLogFiles
+ echo "1 This is a xxxx file bad" > "${BASE}/a/a/b/z" # GrowingLogFiles
+ echo "2 This is a xxxx file bad" >>"${BASE}/a/a/b/z" # GrowingLogFiles
+ echo "3 This is a xxxx file bad" >>"${BASE}/a/a/b/z" # GrowingLogFiles
+}
+
+chk_testdata_5 () {
+ for ff in $TDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ fi
+ #
+ for gg in $TFILES; do
+ egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (checking)";
+ fi
+ tmp=`egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (multiple)";
+ fi
+ done
+ done
+ egrep "CRIT.*POLICY \[GrowingLogs\] C---------.*${BASE}/a/a/b/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/b/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[GrowingLogs\] C---------.*${BASE}/a/a/b/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/b/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[GrowingLogs\] -----M----.*${BASE}/a/b/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[GrowingLogs\] -----M----.*${BASE}/a/a/c/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[GrowingLogs\] C--------S.*${BASE}/a/b/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/a/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/c/foo" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/foo";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*033\[1;30m" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/\033[1;30m";
+ return 1
+ fi
+ egrep "WARN.*Weird filename.*033\[1;30m" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/\033[1;30m";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/a/a/c/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/y";
+ return 1
+ fi
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 9 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+}
+
+
+TESTPOLICY_4="
+[Attributes]
+dir=${BASE}
+file=${BASE}/a/a/c/x
+[ReadOnly]
+file=${BASE}/a/a/c/y
+[LogFiles]
+dir=${BASE}/a/a/c
+dir=${BASE}/a/b
+"
+
+mod_testdata_4 () {
+ one_sec_sleep
+ echo "foobar" >> "${BASE}/a/a/x" # Attributes
+ echo "foobar" > "${BASE}/a/a/c/foo" # new within LogFiles
+ echo "foobar" >> "${BASE}/a/a/c/y" # ReadOnly
+ echo "foobar" >> "${BASE}/a/a/c/x" # Attributes
+ chmod 0555 "${BASE}/a/a/c/x" # Attributes
+ chmod 0555 "${BASE}/a/a/c/z" # LogFiles
+ echo "foobar" >> "${BASE}/a/b/x" # LogFiles
+ echo "" > "${BASE}/a/b/y" # LogFiles
+ chmod 0555 "${BASE}/a/b/z" # LogFiles
+ touch "${BASE}/a/a/" # non-printable character in filename
+}
+
+chk_testdata_4 () {
+ for ff in $TDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ fi
+ #
+ for gg in $TFILES; do
+ egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (checking)";
+ fi
+ tmp=`egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (multiple)";
+ fi
+ done
+ done
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/a/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[LogFiles\] -----M----.*${BASE}/a/b/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[LogFiles\] -----M----.*${BASE}/a/a/c/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/c/foo" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/foo";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*033\[1;30m" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/\033[1;30m";
+ return 1
+ fi
+ egrep "WARN.*Weird filename.*033\[1;30m" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/\033[1;30m";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/a/a/c/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/y";
+ return 1
+ fi
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 6 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+}
+
+TESTPOLICY_3="
+[Attributes]
+dir=${BASE}
+file=${BASE}/a/a/c/x
+[ReadOnly]
+file=${BASE}/a/a/c/y
+[IgnoreAll]
+dir=${BASE}/a/a/c
+"
+mod_testdata_3 () {
+ one_sec_sleep
+ echo "foobar" > "${BASE}/a/b/foo" # new within Attributes
+ chmod 0555 "${BASE}/a/b"
+ echo "foobar" > "${BASE}/a/a/c/foo" # new within IgnoreAll
+ echo "foobar" > "${BASE}/a/a/c/y" # ReadOnly
+ chmod 0555 "${BASE}/a/a/c/x" # Attributes
+ chmod 0555 "${BASE}/a/a/c/z" # IgnoreAll
+}
+
+chk_testdata_3 () {
+ for ff in $TDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ fi
+ #
+ for gg in $TFILES; do
+ egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (checking)";
+ fi
+ tmp=`egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (multiple)";
+ fi
+ done
+ done
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/b/foo" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/foo";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/c/foo" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/foo";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/b" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[Attributes\] -----M----.*${BASE}/a/a/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/a/a/c/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/y";
+ return 1
+ fi
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 5 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+}
+
+TESTPOLICY_2="
+[ReadOnly]
+dir=${BASE}
+file=${BASE}/a/a/c/x
+[IgnoreAll]
+dir=${BASE}/a/a/c
+"
+mod_testdata_2 () {
+ # mod_testdata_1;
+ one_sec_sleep
+ touch "${BASE}/a/a/x"
+ chmod 0555 "${BASE}/a/a/y"
+ mv "${BASE}/a/b/y" "${BASE}/a/b/yy";
+ echo "1 This is a test file" > "${BASE}/a/b/y";
+ echo "2 This is a test file" >> "${BASE}/a/b/y";
+ echo "4 This is a test file" >> "${BASE}/a/b/z";
+ rm "${BASE}/a/b/yy"; # mv/rm to force new inode
+ rm "${BASE}/a/b/l_y";
+ ln -s "${BASE}/a/b/x" "${BASE}/a/b/l_y";
+ echo "foobar" > "${BASE}/a/c/y"
+ rm "${BASE}/a/a/c/y"
+ echo "foobar" > "${BASE}/a/a/c/foo"
+ chmod 0555 "${BASE}/a/a/c/x"
+ chmod 0555 "${BASE}/a/a/c/z"
+}
+
+chk_testdata_2 () {
+ for ff in $TDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ fi
+ #
+ for gg in $TFILES; do
+ egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ if [ x"${ff}/${gg}" = x"a/a/c/y" ]; then :; else
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (checking)";
+ return 1
+ fi
+ fi
+ done
+ done
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/c/foo" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/foo";
+ return 1
+ fi
+ egrep "CRIT.*POLICY MISSING.*${BASE}/a/a/c/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] -----M--T-.*${BASE}/a/a/c/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/c/x";
+ return 1
+ fi
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 10 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+}
+
+TESTPOLICY_1="
+[Misc]
+RedefReadOnly = +TXT
+[ReadOnly]
+dir=${BASE}
+"
+
+mod_testdata_1 () {
+ one_sec_sleep
+ touch "${BASE}/a/a/x"
+ chmod 0555 "${BASE}/a/a/y"
+ mv "${BASE}/a/b/y" "${BASE}/a/b/yy";
+ echo "1 This is a test file" > "${BASE}/a/b/y";
+ echo "2 This is a test file" >> "${BASE}/a/b/y";
+ echo "4 This is a test file" >> "${BASE}/a/b/z";
+ rm "${BASE}/a/b/yy"; # mv/rm to force new inode
+ rm "${BASE}/a/b/l_y";
+ ln -s "${BASE}/a/b/x" "${BASE}/a/b/l_y";
+ echo "foobar" > "${BASE}/a/c/y"
+ #
+ mv "${BASE}/b/x" "${BASE}/b/xx"; # mv/rm to force new inode
+ mkdir "${BASE}/b/x"
+ rm "${BASE}/b/xx";
+ #
+ mv "${BASE}/b/y" "${BASE}/b/yy"; # mv/rm to force new inode
+ ln -s "${BASE}/b/z" "${BASE}/b/y"
+ rm "${BASE}/b/yy";
+ #
+ rm "${BASE}/b/l_x"; echo "1 This is a test file" > "${BASE}/b/l_x";
+}
+
+chk_testdata_1 () {
+ for ff in $TDIRS; do
+ #
+ egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (checking)";
+ return 1
+ fi
+ tmp=`egrep "Checking.*${BASE}/${ff}(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff} (multiple)";
+ return 1
+ fi
+ #
+ for gg in $TFILES; do
+ egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ if [ "${BASE}/${ff}" != "${BASE}/b" ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (checksum)";
+ return 1
+ fi
+ fi
+ tmp=`egrep "Checksum.*${BASE}/${ff}/${gg}" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 1 ]; then
+ if [ "${BASE}/${ff}" != "${BASE}/b" ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/${ff}/${gg} (multiple)";
+ return 1
+ fi
+ fi
+ done
+ done
+ #
+ #
+ #
+ egrep "CRIT.*POLICY \[ReadOnly\] ----H---T-.*${BASE}/b" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/b";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] CL-I-M--TS.*${BASE}/b/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/b/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] CL-.-M--TS.*${BASE}/b/l_x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/b/l_x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C--IHM--TS.*${BASE}/b/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/b/x";
+ return 1
+ fi
+ #
+ #
+ #
+ egrep "CRIT.*POLICY \[ReadOnly\] --------T-.*${BASE}/a/a/x" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/x";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] -----M--T-.*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] ---I----T-.*${BASE}/a/b/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] -L-I----T-.*${BASE}/a/b/l_y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/l_y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] --------T-.*${BASE}/a/b" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/a/b/z" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/b/z";
+ return 1
+ fi
+ egrep "CRIT.*POLICY \[ReadOnly\] C-------TS.*${BASE}/a/c/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/c/y";
+ return 1
+ fi
+ tmp=`grep CRIT $LOGFILE | wc -l`
+ if [ $tmp -ne 11 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count";
+ return 1
+ fi
+ for ff in x y z; do
+ ./samhain --list-file "${BASE}/a/a/${ff}" -d "$PW_DIR/.samhain_file" > "$PW_DIR/.samhain_tmp"
+ diff "$PW_DIR/.samhain_tmp" "${BASE}/a/a/${ff}" >/dev/null
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "diff $PW_DIR/.samhain_tmp ${BASE}/a/a/${ff}"
+ return 1
+ fi
+ done
+
+ return 0
+}
+
+
+##############################################################
+#
+# Common subroutines
+#
+
+mkconfig_misc ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ cat >> "${RCFILE}" <<End-of-data
+[Misc]
+Daemon=no
+SetFilecheckTime=60
+TrustedUser=uucp,fax,fnet
+SetRecursionLevel=10
+SetLoopTime=30
+ReportFullDetail = no
+ChecksumTest=check
+
+End-of-data
+}
+
+mkconfig_log ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ cat >> "${RCFILE}" <<End-of-data
+[Log]
+MailSeverity=none
+LogSeverity=warn
+SyslogSeverity=none
+PrintSeverity=info
+MailSeverity=none
+#Restrict to certain classes of messages
+#LogClass=RUN
+#PreludeSeverity=err
+#ExportSeverity=none
+
+End-of-data
+}
+
+mkconfig_sev ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ cat >> "${RCFILE}" <<End-of-data
+[EventSeverity]
+SeverityUser0=crit
+SeverityUser1=crit
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+SeverityIgnoreAll=crit
+SeverityFiles=err
+SeverityDirs=err
+SeverityNames=warn
+
+End-of-data
+}
+
+prep_testpolicy ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ eval echo '"$'"TESTPOLICY_$1"'"' >>"${RCFILE}"
+}
+
+prep_init ()
+{
+ rm -f ./.samhain_file
+ rm -f "${LOGFILE}"
+ rm -f ./.samhain_lock
+
+ rm -f "${RCFILE}"
+ mkconfig_sev
+ mkconfig_log
+ mkconfig_misc
+}
+
+run_init ()
+{
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./samhain -t init -p none 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+}
+
+run_check ()
+{
+ if [ "x$1" = "x" ]; then
+ logsev=debug
+ else
+ logsev=$1
+ fi
+ ${VALGRIND} ./samhain -t check -p none -l $logsev 2>>test_log_valgrind
+
+ if test x$? = x0; then
+
+ ./samhain -j -L $LOGFILE >"${LOGFILE}.tmp" && mv "${LOGFILE}.tmp" "${LOGFILE}"
+
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv logfile...";
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "check...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "check...";
+ return 1
+ fi
+}
+
+run_update ()
+{
+ ${VALGRIND} ./samhain -t update -p none -l debug 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "update...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "update...";
+ return 1
+ fi
+}
+
+run_check_after_update ()
+{
+ rm -rf $LOGFILE
+
+ ${VALGRIND} ./samhain -t check -p none -l debug 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ #
+ tmp=`./samhain -j -L $LOGFILE | grep CRIT | wc -l`
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "update not successful(?)";
+ return 1
+ fi
+ #
+ # wtmp may not be readable
+ #
+ tmp=`./samhain -j -L $LOGFILE | grep ERR | grep -v wtmp | wc -l`
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "errors during check";
+ return 1
+ fi
+ #
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+ #
+ [ -z "$verbose" ] || log_msg_ok "check(2)...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "check(2)...";
+ return 1
+ fi
+}
+
+prep_testdata ()
+{
+ if test -d "$BASE"; then
+ if [ -d "${BASE}" ]; then
+ chmod -f -R 0700 "${BASE}" || {
+ [ -z "$quiet" ] && log_msg_fail "chmod -f -R 0700 ${BASE}";
+ return 1;
+ }
+ fi
+ fi
+
+ rm -rf "${BASE}" || {
+ [ -z "$quiet" ] && log_msg_fail "rm -rf ${BASE}";
+ return 1;
+ }
+
+ mkdir "${BASE}" || {
+ [ -z "$quiet" ] && log_msg_fail "mkdir ${BASE}";
+ return 1;
+ }
+
+ echo "${BASE}" > ./tmp_list_file
+
+ for ff in $TDIRS; do
+ mkdir "${BASE}/${ff}" || {
+ [ -z "$quiet" ] && log_msg_fail "mkdir ${BASE}/${ff}";
+ return 1;
+ }
+ echo "${BASE}/${ff}" >> ./tmp_list_file
+ chmod 0755 "${BASE}/${ff}"
+ for gg in $TFILES; do
+ echo "1 This is a test file" > "${BASE}/${ff}/${gg}"
+ chmod 0644 "${BASE}/${ff}/${gg}"
+ echo "${BASE}/${ff}/${gg}" >> ./tmp_list_file
+ ln -s "${BASE}/${ff}/${gg}" "${BASE}/${ff}/l_${gg}"
+ echo "${BASE}/${ff}/l_${gg}" >> ./tmp_list_file
+ done
+ echo "2 This is a test file" >> "${BASE}/${ff}/y"
+ echo "2 This is a test file" >> "${BASE}/${ff}/z"
+ echo "3 This is a test file" >> "${BASE}/${ff}/z"
+ done
+}
+
+check_err ()
+{
+ if [ $1 -ne 0 ]; then
+ log_fail ${2} ${MAXTEST};
+ return 1
+ fi
+ return 0
+}
+
+testrun_internal ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }
+
+ tcount=1
+ POLICY=`eval echo '"$'"TESTPOLICY_$tcount"'"'`
+
+ until [ ${tcount} -gt ${MAXTEST_3} ]
+ do
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_testpolicy ${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval mod_testdata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval chk_testdata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $testrun1_setup -eq 0 ]; then
+ if [ $errval -eq 0 ]; then
+ run_update
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check_after_update
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ #
+ let "tcount = tcount + 1" >/dev/null
+ #
+ if [ $tcount -eq 10 ]; then
+ if [ -z "$doall" ]; then
+ log_skip 10 $MAXTEST 'ACL/SELinux test (or use --really-all)'
+ log_skip 11 $MAXTEST 'ACL/SELinux test (or use --really-all)'
+ let "tcount = tcount + 2" >/dev/null
+ else
+ # 'id -u' is posix
+ #
+ if test -f /usr/xpg4/bin/id
+ then
+ my_uid=`/usr/xpg4/bin/id -u`
+ else
+ my_uid=`id -u`
+ fi
+ #
+ if [ ${my_uid} -ne 0 ]; then
+ log_skip 10 $MAXTEST 'ACL/SELinux test (you are not root)'
+ log_skip 11 $MAXTEST 'ACL/SELinux test (you are not root)'
+ let "tcount = tcount + 2" >/dev/null
+ else
+
+ SETFATTR=`find_path setfattr`
+ if [ -z "$SETFATTR" ]; then
+ log_skip 10 $MAXTEST 'ACL/SELinux test (setfattr not in path)'
+ log_skip 11 $MAXTEST 'ACL/SELinux test (setfattr not in path)'
+ let "tcount = tcount + 2" >/dev/null
+ fi
+ fi
+ fi
+ fi
+ #
+ POLICY=`eval echo '"$'"TESTPOLICY_$tcount"'"'`
+ done
+
+ return 0
+}
+
+testrun1 ()
+{
+ log_start "RUN STANDALONE"
+ testrun_internal
+ log_end "RUN STANDALONE"
+ return 0
+}
+
+
+
diff --git a/test/testrun_1a.sh b/test/testrun_1a.sh
new file mode 100755
index 0000000..bad8c29
--- /dev/null
+++ b/test/testrun_1a.sh
@@ -0,0 +1,160 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+PREBUILDOPTS="--quiet $TRUST --enable-debug --enable-static --enable-xml-log --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+export PREBUILDOPTS
+
+MAXTEST=1; export MAXTEST
+
+testrun_stealth ()
+{
+ tcount=1
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ CONVERT=`find_path convert`
+ if [ x"$CONVERT" = x ]; then
+ [ -z "$verbose" ] || log_msg_fail "ImageMagick convert not found";
+ return 1
+ fi
+ "$CONVERT" --help | grep ImageMagick >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Convert utility is not ImageMagick convert";
+ return 1
+ fi
+ "${CONVERT}" +compress stealth_template.jpg stealth_template.ps
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Converting stealth_template.jpg failed";
+ return 1
+ fi
+
+ $MAKE samhain_stealth >/dev/null 2>>test_log
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "make samhain_stealth";
+ return 1
+ fi
+ capacity=`./samhain_stealth -i stealth_template.ps | awk '{ print $7 }'`
+
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_testpolicy 1
+ check_err $? ${tcount}; errval=$?
+ fi
+
+ if [ $errval -eq 0 ]; then
+ fill=`cat "${RCFILE}" | wc -c`
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ let "capacity = capacity - fill" >/dev/null
+ let "capacity = capacity - 100" >/dev/null
+ until [ "$capacity" -le 0 ]
+ do
+ echo "###############################" >>"${RCFILE}"
+ let "capacity = capacity - 32" >/dev/null
+ done
+
+ ./samhain_stealth -s stealth_template.ps "${RCFILE}" >/dev/null
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ cp stealth_template.ps "${RCFILE}"
+ check_err $? ${tcount}; errval=$?
+ fi
+
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval mod_testdata_1
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval chk_testdata_1
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $testrun1_setup -eq 0 ]; then
+ if [ $errval -eq 0 ]; then
+ run_update
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check_after_update
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ return 0
+}
+
+testrun1a ()
+{
+ log_start "RUN STANDALONE W/STEALTH"
+ #
+ # micro-stealth
+ #
+ #BUILDOPTS="$PREBUILDOPTS --enable-micro-stealth=137"; export BUILDOPTS
+ #testrun_internal
+
+ CONVERT=`find_path convert`
+ if [ x"$CONVERT" = x ]; then
+ log_skip 1 ${MAXTEST} "ImageMagick convert not found";
+ return 0
+ fi
+ BUILDOPTS="$PREBUILDOPTS --enable-stealth=137"; export BUILDOPTS
+ testrun_stealth
+ check_err $? ${tcount};
+ log_end "RUN STANDALONE W/STEALTH"
+ return 0
+}
+
diff --git a/test/testrun_1b.sh b/test/testrun_1b.sh
new file mode 100755
index 0000000..eda3ebf
--- /dev/null
+++ b/test/testrun_1b.sh
@@ -0,0 +1,467 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+MAXTEST=7; export MAXTEST
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+
+testrun1b_modrc ()
+{
+ ORIGINAL="\[EOF\]"
+ REPLACEMENT="\[PortCheck\]"
+ ex -s $RCFILE <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+
+ echo "PortCheckActive = yes" >>"$RCFILE"
+ echo "PortCheckInterface = 127.0.0.1" >>"$RCFILE"
+}
+
+testrun1b_internal ()
+{
+ BUILDOPTS="$1"
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null >&1
+ fi
+ #
+ # Bootstrapping
+ #
+ ${TOP_SRCDIR}/configure >/dev/null 2>/dev/null
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure (bootstrap)...";
+ $MAKE > /dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make (bootstrap)...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make (bootstrap)...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure (bootstrap)...";
+ return 1
+ fi
+ #
+ #
+ ${TOP_SRCDIR}/configure ${BUILDOPTS} 2>/dev/null | \
+ egrep 'use existing [./[:alnum:]]+ for gpg checksum' >/dev/null
+ #
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ SKIP=`awk '/^__ARCHIVE_FOLLOWS__/ { print NR + 1; exit 0; }' ${SCRIPTDIR}/test.sh`
+
+ tail -n "+$SKIP" ${SCRIPTDIR}/test.sh >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ tail -n "+$SKIP" ${SCRIPTDIR}/test.sh | gunzip -c - 2>/dev/null | tar xf - && \
+ mv "./testrc.gpg.asc" "$RCFILE"
+ else
+ tail "+$SKIP" ${SCRIPTDIR}/test.sh | gunzip -c - 2>/dev/null | tar xf - && \
+ mv "./testrc.gpg.asc" "$RCFILE"
+ fi
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "extract gpg signed files...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "extract gpg signed files...";
+ return 1
+ fi
+
+ if test "x$2" = "x"; then
+ :
+ else
+ CONVERT="$2"
+ if test -f "${TOP_SRCDIR}/stealth_template.jpg"; then
+ [ -z "$verbose" ] || log_msg_ok "convert..."
+ "${CONVERT}" +compress "${TOP_SRCDIR}/stealth_template.jpg" stealth_template.ps >/dev/null
+ else
+ [ -z "$quiet" ] && log_msg_fail "cannot find file stealth_template.jpg"
+ return 1
+ fi
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "${CONVERT} +compress ${TOP_SRCDIR}/stealth_template.jpg stealth_template.ps";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || log_msg_ok "hide..."
+ ./samhain_stealth -s stealth_template.ps "$RCFILE" >/dev/null
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "${CONVERT} +compress ${TOP_SRCDIR}/stealth_template.jpg stealth_template.ps";
+ return 1
+ fi
+
+ mv -f stealth_template.ps "$RCFILE"
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv -f stealth_template.ps $RCFILE";
+ return 1
+ fi
+
+ fi
+
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+
+ ./samhain -t init -p none -l info
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ mv $PW_DIR/.samhain_file.asc $PW_DIR/.samhain_file
+}
+
+testrun1b_nogpg ()
+{
+ BUILDOPTS="$1"
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null >&1
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS} 2>/dev/null
+ #
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+
+ cp "${SCRIPTDIR}/testrc_1" "${RCFILE}"
+
+ if test "x$2" = "xmodrc"; then
+ [ -z "$verbose" ] || log_msg_ok "mod rc...";
+ testrun1b_modrc
+ fi
+
+ ./samhain -t init -p none -l info
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+}
+
+do_test_1b () {
+
+ ./samhain -t check -p none -l info
+
+ if test x$? = x0; then
+ ./samhain -j -L $LOGFILE >"${LOGFILE}.tmp" && mv "${LOGFILE}.tmp" "${LOGFILE}"
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv logfile...";
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "check...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "check...";
+ return 1
+ fi
+ #
+ tmp=`egrep "Checking.*/etc(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "/etc";
+ return 1
+ fi
+ tmp=`egrep "Checking.*(>|\")" $LOGFILE 2>/dev/null | wc -l`
+ if [ $tmp -ne 10 ]; then
+ [ -z "$verbose" ] || log_msg_fail "checking";
+ return 1
+ fi
+ egrep "ADDED" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "init was incomplete";
+ return 1
+ fi
+ #
+ return 0
+}
+
+do_test_1b_2 () {
+
+ rm -f $PW_DIR/test_log_prelude
+
+ [ -z "$verbose" ] || { echo " starting prelude-manager.."; echo " ($PM --textmod -l $PW_DIR/test_log_prelude --listen 127.0.0.1:5500 >/dev/null 2>&1 &)"; }
+ "$PM" --textmod -l $PW_DIR/test_log_prelude --listen 127.0.0.1:5500 >/dev/null 2>&1 &
+ PID=$!
+
+ five_sec_sleep
+
+ ./samhain -t check -p none -l info --set-prelude-severity=info --prelude --server-addr 127.0.0.1:5500 >/dev/null
+
+ if test x$? = x0; then
+ ./samhain -j -L $LOGFILE >"${LOGFILE}.tmp" && mv "${LOGFILE}.tmp" "${LOGFILE}"
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv logfile...";
+ kill $PID
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "check...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "check...";
+ kill $PID
+ return 1
+ fi
+ #
+ tmp=`egrep 'File original:.*name=etc.*path=/etc' test_log_prelude 2>/dev/null | wc -l`
+ if [ $tmp -lt 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "/etc";
+ kill $PID
+ return 1
+ fi
+ tmp=`egrep 'Classification text: Checking' test_log_prelude 2>/dev/null | wc -l`
+ if [ $tmp -lt 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "checking";
+ kill $PID
+ return 1
+ fi
+ #
+ if test "x$2" = "xmodrc"; then
+ tmp=`egrep 'Classification text: Service opened' test_log_prelude 2>/dev/null | wc -l`
+ if [ $tmp -lt 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "service";
+ kill $PID
+ return 1
+ fi
+ tmp=`egrep 'Service: port=5500' test_log_prelude 2>/dev/null | wc -l`
+ if [ $tmp -lt 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "port 5500";
+ kill $PID
+ return 1
+ fi
+ fi
+ #
+ kill $PID
+ return 0
+}
+
+testrun1b ()
+{
+ log_start "RUN STANDALONE W/STEALTH W/GPG"
+ GPG=`find_path gpg`
+ if [ -z "$GPG" ]; then
+ log_skip 1 $MAXTEST 'gpg not found in $PATH'
+ log_skip 2 $MAXTEST 'gpg not found in $PATH'
+ log_skip 3 $MAXTEST 'gpg not found in $PATH'
+ log_skip 4 $MAXTEST 'gpg not found in $PATH'
+ log_skip 5 $MAXTEST 'gpg not found in $PATH'
+ log_skip 6 $MAXTEST 'gpg not found in $PATH'
+ log_skip 7 $MAXTEST 'gpg not found in $PATH'
+ else
+ eval "$GPG" --list-keys 0F571F6C >/dev/null 2>/dev/null
+ if [ $? -ne 0 ]; then
+ log_skip 1 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ log_skip 2 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ log_skip 3 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ log_skip 4 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ log_skip 5 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ log_skip 6 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ log_skip 7 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ else
+ #
+ # ------------- first test -------------
+ #
+ BUILDOPTS="--quiet $TRUST --enable-debug --with-gpg=${GPG} --enable-micro-stealth=137 --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_internal "${BUILDOPTS}"
+ do_test_1b
+ if [ $? -eq 0 ]; then
+ log_ok 1 $MAXTEST 'gpg signed config/database files'
+ else
+ log_fail 1 $MAXTEST 'gpg signed config/database files'
+ fi
+
+
+ #
+ # ------------- second test -------------
+ #
+ BUILDOPTS="--quiet $TRUST --enable-debug --with-gpg=${GPG} --with-checksum --enable-micro-stealth=137 --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_internal "${BUILDOPTS}"
+ do_test_1b
+ if [ $? -eq 0 ]; then
+ log_ok 2 $MAXTEST 'gpg signed config/database files'
+ else
+ log_fail 2 $MAXTEST 'gpg signed config/database files'
+ fi
+
+
+ #
+ # ------------- third test -------------
+ #
+ BUILDOPTS="--quiet $TRUST --enable-debug --with-gpg=${GPG} --with-checksum --with-fp=EF6CEF54701A0AFDB86AF4C31AAD26C80F571F6C --enable-micro-stealth=137 --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_internal "${BUILDOPTS}"
+ do_test_1b
+ if [ $? -eq 0 ]; then
+ log_ok 3 $MAXTEST 'gpg signed config/database files'
+ else
+ log_fail 3 $MAXTEST 'gpg signed config/database files'
+ fi
+
+
+ #
+ # ------------- fourth test -------------
+ #
+ PRECONV=`find_path convert`
+ "${PRECONV}" --help | grep ImageMagick >/dev/null 2>&1 && \
+ CONVERT="${PRECONV}"
+
+ if [ -z "$CONVERT" ]; then
+ log_skip 2 $MAXTEST 'ImageMagick convert not found in $PATH'
+ else
+ BUILDOPTS="--quiet $TRUST --enable-debug --with-gpg=${GPG} --with-checksum --enable-stealth=137 --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_internal "${BUILDOPTS}" "$CONVERT"
+ do_test_1b
+ if [ $? -eq 0 ]; then
+ log_ok 4 $MAXTEST 'gpg signed config/database files'
+ else
+ log_fail 4 $MAXTEST 'gpg signed config/database files'
+ fi
+ fi
+
+
+ #
+ # ------------- fifth test -------------
+ #
+ if ! test -d /var/run/prelude-manager
+ then
+ [ -z "$verbose" ] || log_msg_ok "create /var/run/prelude-manager...";
+ sudo mkdir /var/run/prelude-manager
+ sudo chown prelude:rainer /var/run/prelude-manager
+ sudo chmod 770 /var/run/prelude-manager
+ fi
+ #
+ PM=`find_path prelude-manager`
+ if [ -z "$PM" ]; then
+ log_skip 5 $MAXTEST 'prelude-manager not found in $PATH'
+ elif [ -z "$doall" ]; then
+ log_skip 5 $MAXTEST 'logging to prelude (or use --really-all)'
+ else
+ BUILDOPTS="--quiet $TRUST --enable-debug --with-prelude --with-gpg=${GPG} --with-checksum --enable-micro-stealth=137 --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_internal "${BUILDOPTS} CFLAGS=-DSH_NOFAILOVER=1"
+ do_test_1b_2
+ if [ $? -eq 0 ]; then
+ log_ok 5 $MAXTEST 'logging to prelude'
+ else
+ log_fail 5 $MAXTEST 'logging to prelude'
+ fi
+ fi
+
+ #
+ # ------------- sixth test -------------
+ #
+ if ! test -d /var/run/prelude-manager
+ then
+ [ -z "$verbose" ] || log_msg_ok "create /var/run/prelude-manager...";
+ sudo mkdir /var/run/prelude-manager
+ sudo chown prelude:rainer /var/run/prelude-manager
+ sudo chmod 770 /var/run/prelude-manager
+ fi
+ #
+ PM=`find_path prelude-manager`
+ if [ -z "$PM" ]; then
+ log_skip 6 $MAXTEST 'prelude-manager not found in $PATH'
+ elif [ -z "$doall" ]; then
+ log_skip 6 $MAXTEST 'logging to prelude (or use --really-all)'
+ else
+ BUILDOPTS="--quiet $TRUST --with-prelude --enable-login-watch --enable-mounts-check --enable-process-check --enable-port-check --enable-suidcheck --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_nogpg "${BUILDOPTS} CFLAGS=-DSH_NOFAILOVER=1"
+ do_test_1b_2
+ if [ $? -eq 0 ]; then
+ log_ok 6 $MAXTEST 'logging to prelude'
+ else
+ log_fail 6 $MAXTEST 'logging to prelude'
+ fi
+ fi
+
+ #
+ # ------------- seventh test -----------
+ #
+ if ! test -d /var/run/prelude-manager
+ then
+ [ -z "$verbose" ] || log_msg_ok "create /var/run/prelude-manager...";
+ sudo mkdir /var/run/prelude-manager
+ sudo chown prelude:rainer /var/run/prelude-manager
+ sudo chmod 770 /var/run/prelude-manager
+ fi
+ #
+ PM=`find_path prelude-manager`
+ if [ -z "$PM" ]; then
+ log_skip 7 $MAXTEST 'prelude-manager not found in $PATH'
+ elif [ -z "$doall" ]; then
+ log_skip 7 $MAXTEST 'logging to prelude (or use --really-all)'
+ else
+ BUILDOPTS="--quiet $TRUST --with-prelude --enable-login-watch --enable-mounts-check --enable-process-check --enable-port-check --enable-suidcheck --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+ testrun1b_nogpg "${BUILDOPTS} CFLAGS=-DSH_NOFAILOVER=1" "modrc"
+ do_test_1b_2
+ if [ $? -eq 0 ]; then
+ log_ok 7 $MAXTEST 'logging to prelude'
+ else
+ log_fail 7 $MAXTEST 'logging to prelude'
+ fi
+ fi
+
+ fi
+ fi
+ log_end "RUN STANDALONE W/STEALTH W/GPG"
+ return 0
+}
+
diff --git a/test/testrun_1c.sh b/test/testrun_1c.sh
new file mode 100755
index 0000000..48e521f
--- /dev/null
+++ b/test/testrun_1c.sh
@@ -0,0 +1,414 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+BUILDOPTS="--quiet $TRUST --enable-xml-log --enable-suidcheck --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+export BUILDOPTS
+
+MAXTEST=7; export MAXTEST
+
+## Quarantine SUID/SGID files if found
+#
+# SuidCheckQuarantineFiles = yes
+
+## Method for Quarantining files:
+# 0 - Delete or truncate the file.
+# 1 - Remove SUID/SGID permissions from file.
+# 2 - Move SUID/SGID file to quarantine dir.
+#
+# SuidCheckQuarantineMethod = 0
+
+## For method 0 and 2, really delete instead of truncating
+#
+# SuidCheckQuarantineDelete = yes
+
+SUIDPOLICY_7="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckExclude = ${BASE}/a/a
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = no
+SuidCheckQuarantineMethod = 2
+SuidCheckQuarantineDelete = yes
+"
+
+mod_suiddata_7 () {
+ one_sec_sleep
+ chmod 4444 "${BASE}/a/a/y"
+ chmod 4444 "${BASE}/a/a/a/y"
+ mkdir "${BASE}/a/abc"
+ touch "${BASE}/a/abc/y"
+ chmod 4444 "${BASE}/a/abc/y"
+}
+
+chk_suiddata_7 () {
+ one_sec_sleep
+ tmp=`ls -l "${BASE}/a/a/y" 2>/dev/null | awk '{ print $1}' | cut -c 1-10`
+ if [ "x$tmp" = "x-r-Sr--r--" ]; then
+ egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
+ return 1
+ fi
+ else
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (suid not kept)";
+ return 1
+ fi
+ tmp=`ls -l "${BASE}/a/a/a/y" 2>/dev/null | awk '{ print $1}' | cut -c 1-10`
+ if [ "x$tmp" = "x-r-Sr--r--" ]; then
+ egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/y";
+ return 1
+ fi
+ else
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/a/y (suid not kept)";
+ return 1
+ fi
+ tmp=`ls -l "${BASE}/a/abc/y" 2>/dev/null | awk '{ print $1}' | cut -c 1-10`
+ if [ "x$tmp" = "x-r-Sr--r--" ]; then
+ egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/abc/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/abc/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/abc/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/abc/y";
+ return 1
+ fi
+ return 0;
+ else
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/abc/y (suid not kept)";
+ return 1
+ fi
+}
+
+
+SUIDPOLICY_6="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = no
+SuidCheckQuarantineMethod = 2
+SuidCheckQuarantineDelete = yes
+"
+
+mod_suiddata_6 () {
+ one_sec_sleep
+ chmod 4755 "${BASE}/a/a/y"
+}
+
+chk_suiddata_6 () {
+ one_sec_sleep
+ tmp=`ls -l "${BASE}/a/a/y" 2>/dev/null | awk '{ print $1}' | cut -c 1-10`
+ if [ "x$tmp" = "x-rwsr-xr-x" ]; then
+ egrep "CRIT.*POLICY \[SuidCheck\].*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
+ return 1
+ fi
+ egrep "CRIT.*POLICY ADDED.*${BASE}/a/a/y" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y";
+ return 1
+ fi
+ return 0;
+ else
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (suid not kept)";
+ return 1
+ fi
+}
+
+SUIDPOLICY_5="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = yes
+SuidCheckQuarantineMethod = 2
+SuidCheckQuarantineDelete = yes
+"
+
+mod_suiddata_5 () {
+ one_sec_sleep
+ chmod 4755 "${BASE}/a/a/y"
+}
+
+chk_suiddata_5 () {
+ one_sec_sleep
+ if [ ! -f "${BASE}/a/a/x" ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/x (erroneously deleted)";
+ return 1
+ fi
+ if [ -f "${BASE}/a/a/y" ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not deleted)";
+ return 1
+ fi
+ if [ -f .quarantine/y ]; then
+ if [ -f .quarantine/y.info ]; then
+ return 0;
+ else
+ [ -z "$verbose" ] || log_msg_fail ".quarantine/y.info (missing)";
+ return 1
+ fi
+ else
+ [ -z "$verbose" ] || log_msg_fail ".quarantine/y (missing)";
+ return 1
+ fi
+}
+
+SUIDPOLICY_4="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = yes
+SuidCheckQuarantineMethod = 2
+SuidCheckQuarantineDelete = no
+"
+
+mod_suiddata_4 () {
+ one_sec_sleep
+ chmod 4755 "${BASE}/a/a/y"
+}
+
+chk_suiddata_4 () {
+ one_sec_sleep
+ tmp=`cat "${BASE}/a/a/y" 2>/dev/null | wc -c`
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not truncated)";
+ return 1
+ fi
+ if [ -f .quarantine/y ]; then
+ if [ -f .quarantine/y.info ]; then
+ return 0;
+ else
+ [ -z "$verbose" ] || log_msg_fail ".quarantine/y.info (missing)";
+ return 1
+ fi
+ else
+ [ -z "$verbose" ] || log_msg_fail ".quarantine/y (missing)";
+ return 1
+ fi
+}
+
+SUIDPOLICY_3="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = yes
+SuidCheckQuarantineMethod = 1
+SuidCheckQuarantineDelete = no
+"
+
+mod_suiddata_3 () {
+ one_sec_sleep
+ chmod 4755 "${BASE}/a/a/y"
+}
+
+chk_suiddata_3 () {
+ one_sec_sleep
+ tmp=`ls -l "${BASE}/a/a/y" 2>/dev/null | awk '{ print $1}' | cut -c 1-10`
+ if [ "x$tmp" = "x-rwxr-xr-x" ]; then
+ return 0;
+ else
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (suid not removed)";
+ return 1
+ fi
+}
+
+SUIDPOLICY_2="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = yes
+SuidCheckQuarantineMethod = 0
+SuidCheckQuarantineDelete = no
+"
+
+mod_suiddata_2 () {
+ one_sec_sleep
+ chmod 4755 "${BASE}/a/a/y"
+}
+
+chk_suiddata_2 () {
+ one_sec_sleep
+ tmp=`cat "${BASE}/a/a/y" 2>/dev/null | wc -c`
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not truncated)";
+ return 1
+ fi
+}
+
+SUIDPOLICY_1="
+[ReadOnly]
+file=${BASE}
+[SuidCheck]
+SuidCheckActive = yes
+SuidCheckInterval = 10
+SeveritySuidCheck = crit
+SuidCheckQuarantineFiles = yes
+SuidCheckQuarantineMethod = 0
+SuidCheckQuarantineDelete = yes
+"
+
+mod_suiddata_1 () {
+ one_sec_sleep
+ chmod 4755 "${BASE}/a/a/y"
+}
+
+chk_suiddata_1 () {
+ one_sec_sleep
+ if [ -f "${BASE}/a/a/y" ]; then
+ [ -z "$verbose" ] || log_msg_fail "${BASE}/a/a/y (not removed)";
+ return 1
+ fi
+}
+
+prep_suidpolicy ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ eval echo '"$'"SUIDPOLICY_$1"'"' >>"${RCFILE}"
+ if [ "x$1" = "x5" ]; then
+ chmod 4755 "${BASE}/a/a/x"
+ fi
+}
+
+testrun_internal_1c ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE 'DBGDEF=-DSH_SUIDTESTDIR=\"${BASE}\"' >/dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make DBGDEF=-DSH_SUIDTESTDIR=${BASE} ...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }
+
+ tcount=1
+ POLICY=`eval echo '"$'"SUIDPOLICY_$tcount"'"'`
+
+ until [ -z "$POLICY" ]
+ do
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_suidpolicy ${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval mod_suiddata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval chk_suiddata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $testrun1_setup -eq 0 ]; then
+ if [ $errval -eq 0 ]; then
+ run_update
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check_after_update
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ let "tcount = tcount + 1" >/dev/null
+ POLICY=`eval echo '"$'"SUIDPOLICY_$tcount"'"'`
+ done
+
+ return 0
+}
+
+testrun1c ()
+{
+ log_start "RUN STANDALONE W/SUIDCHK"
+ testrun_internal_1c
+ log_end "RUN STANDALONE W/SUIDCHK"
+ return 0
+}
+
diff --git a/test/testrun_1d.sh b/test/testrun_1d.sh
new file mode 100755
index 0000000..1b2292f
--- /dev/null
+++ b/test/testrun_1d.sh
@@ -0,0 +1,261 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+BUILDOPTS="--quiet $TRUST --enable-xml-log --enable-process-check --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+export BUILDOPTS
+
+MAXTEST=3; export MAXTEST
+
+PROCPOLICY_3="
+[ReadOnly]
+file=${BASE}
+[ProcessCheck]
+ProcessCheckActive = yes
+ProcessCheckPsPath = ${PW_DIR}/${SCRIPTDIR}/testrun_1d.sh
+ProcessCheckPsArg = --fake
+ProcessCheckMaxPid = 67000
+"
+
+chk_procdata_3 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[Process\] Fake pid: 66666[[:space:]]' $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Fake pid";
+ return 1
+ fi
+ egrep 'CRIT.*POLICY \[Process\] Fake pid: [012345789]+[[:space:]]' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Fake pids incorrect";
+ return 1
+ fi
+}
+
+PROCPOLICY_2="
+[ReadOnly]
+file=${BASE}
+[ProcessCheck]
+ProcessCheckActive = yes
+"
+
+chk_procdata_2 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[Process\] Hidden pid' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Hidden pids (ps)";
+ return 1
+ fi
+}
+
+
+PROCPOLICY_1="
+[ReadOnly]
+file=${BASE}
+[ProcessCheck]
+ProcessCheckActive = yes
+ProcessCheckPsPath = ${PW_DIR}/${SCRIPTDIR}/testrun_1d.sh
+ProcessCheckPsArg = --hide
+"
+
+
+chk_procdata_1 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[Process\] Hidden pid: [[:digit:]][[:space:]]' $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Hidden pids";
+ return 1
+ fi
+ egrep 'CRIT.*POLICY \[Process\] Hidden pid: [[:digit:]][[:digit:]]+[[:space:]]' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Hidden pids incorrect";
+ return 1
+ fi
+}
+
+prep_procpolicy ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ eval echo '"$'"PROCPOLICY_$1"'"' >>"${RCFILE}"
+}
+
+testrun_internal_1d ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ tcount=1
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }
+
+ POLICY=`eval echo '"$'"PROCPOLICY_$tcount"'"'`
+
+ until [ -z "$POLICY" ]
+ do
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_procpolicy ${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ for iseq in 0 1 2 3 4 5 6 7 8 9; do
+ rm -f "$LOGFILE"
+ if [ $errval -eq 0 ]; then
+ run_check info
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval chk_procdata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ done
+ #
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ let "tcount = tcount + 1" >/dev/null
+ POLICY=`eval echo '"$'"PROCPOLICY_$tcount"'"'`
+
+ done
+
+ return 0
+}
+
+testrun1d ()
+{
+ log_start "RUN STANDALONE W/PROCESSCHECK"
+ testrun_internal_1d
+ log_end "RUN STANDALONE W/PROCESSCHECK"
+ return 0
+}
+
+proc_pspath ()
+{
+ PS=ps
+ for ff in /usr/ucb /bin /usr/bin; do
+ if test -x "$ff/ps"; then
+ PS="$ff/ps"
+ break
+ fi
+ done
+ echo "$PS"
+}
+
+proc_psarg ()
+{
+ OS=`uname -s`
+ case $OS in
+ *Linux*|*linux*)
+ PSARG="-eT";;
+ *OpenBSD*)
+ PSARG="akx";;
+ *)
+ PS=`proc_pspath`
+ $PS ax >/dev/null 2>&1
+ if test $? -eq 0; then
+ one=`$PS ax | wc -l`
+ else
+ one=0
+ fi
+ $PS -e >/dev/null 2>&1
+ if test $? -eq 0; then
+ two=`$PS -e | wc -l`
+ else
+ two=0
+ fi
+ if test $one -ge $two
+ then
+ PSARG="ax"
+ else
+ PSARG="-e"
+ fi
+ ;;
+ esac
+ echo "$PSARG"
+}
+
+proc_hide()
+{
+ PSPATH=`proc_pspath`
+ PSARG=`proc_psarg`
+
+ "${PSPATH}" "${PSARG}" | egrep -v '^[[:space:]]*[[:digit:]]{1}[[:space:]]+'
+}
+
+proc_fake()
+{
+ FAKE_PID=2
+ PSPATH=`proc_pspath`
+ PSARG=`proc_psarg`
+
+ "${PSPATH}" "${PSARG}"
+ if [ x"${PSARG}" = x-eT ]; then
+ echo "66666 66666 pts/2 S 0:14 THIS_IS_FAKE"
+ else
+ echo "66666 pts/2 S 0:14 THIS_IS_FAKE"
+ fi
+}
+
+if [ "x$1" = "x--hide" ]; then
+ proc_hide;
+ exit 0;
+fi
+
+if [ "x$1" = "x--fake" ]; then
+ proc_fake;
+ exit 0;
+fi
+
diff --git a/test/testrun_1e.sh b/test/testrun_1e.sh
new file mode 100755
index 0000000..3cdd4cd
--- /dev/null
+++ b/test/testrun_1e.sh
@@ -0,0 +1,376 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+BUILDOPTS="--quiet $TRUST --enable-debug=gdb --enable-xml-log --enable-port-check --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+export BUILDOPTS
+
+MAXTEST=5; export MAXTEST
+
+PORTPOLICY_5="
+[ReadOnly]
+file=${BASE}
+[PortCheck]
+PortCheckActive = yes
+PortCheckUDP = no
+PortCheckInterface = 127.0.0.1
+"
+
+chk_portdata_5 () {
+ one_sec_sleep
+
+ if [ -z "$PM" ]; then
+ log_skip 5 $MAXTEST 'prelude-manager not found in $PATH'
+ elif [ -z "$doall" ]; then
+ log_skip 5 $MAXTEST 'logging to prelude (or use --really-all)'
+ else
+ tmp=`egrep 'Service: port=5500 .unknown. protocol=tcp' test_log_prelude 2>/dev/null | wc -l`
+ if [ $tmp -lt 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "port 5500";
+ [ -z "$quiet" ] && log_fail 5 ${MAXTEST};
+ return 1
+ fi
+ #
+ [ -z "$quiet" ] && log_ok 5 ${MAXTEST};
+ fi
+ return 0
+}
+
+refine_portpolicy_5 ()
+{
+ echo "PortCheckIgnore=2026/tcp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2027/udp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2028/tcp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2029/udp" >>"${RCFILE}"
+}
+
+PORTPOLICY_4="
+[ReadOnly]
+file=${BASE}
+[PortCheck]
+PortCheckActive = yes
+PortCheckUDP = no
+"
+
+chk_portdata_4 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[ServiceNew\]' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || egrep 'CRIT.*POLICY \[ServiceNew\]' $LOGFILE
+ [ -z "$verbose" ] || log_msg_fail "Open ports";
+ return 1
+ fi
+}
+
+refine_portpolicy_4 ()
+{
+ cat "$LOGFILE" | grep ServiceNew | sed 's/.*port: //' | awk '{ print $1 }' | \
+ while read line; do
+ echo "PortCheckSkip=$line" >>"${RCFILE}"
+ done
+ echo "PortCheckIgnore=2026/tcp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2027/udp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2028/tcp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2029/udp" >>"${RCFILE}"
+}
+
+PORTPOLICY_3="
+[ReadOnly]
+file=${BASE}
+[PortCheck]
+PortCheckActive = yes
+PortCheckUDP = no
+"
+
+chk_portdata_3 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[ServiceNew\]' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+
+ [ -z "$verbose" ] || log_msg_fail "Open ports";
+ return 1
+ fi
+}
+
+refine_portpolicy_3 ()
+{
+ cat "$LOGFILE" | grep ServiceNew | sed 's/.*port: //' | awk '{ print $1 }' | \
+ while read line; do
+ echo "PortCheckIgnore=$line" >>"${RCFILE}"
+ done
+ echo "PortCheckIgnore=2026/tcp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2027/udp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2028/tcp" >>"${RCFILE}"
+ echo "PortCheckIgnore=2029/udp" >>"${RCFILE}"
+}
+
+
+PORTPOLICY_2="
+[ReadOnly]
+file=${BASE}
+[PortCheck]
+PortCheckActive = yes
+PortCheckUDP = no
+"
+
+chk_portdata_2 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[ServiceNew\]' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+
+ [ -z "$verbose" ] || log_msg_fail "Open ports";
+ return 1
+ fi
+}
+
+refine_portpolicy_2 ()
+{
+ cat "$LOGFILE" | grep ServiceNew | sed 's/.*port: //' | awk '{ print $1 }' | \
+ while read line; do
+ echo "PortCheckOptional=$line" >>"${RCFILE}"
+ done
+}
+
+PORTPOLICY_1="
+[ReadOnly]
+file=${BASE}
+[PortCheck]
+PortCheckActive = yes
+PortCheckUDP = no
+"
+
+chk_portdata_1 () {
+ one_sec_sleep
+
+ egrep 'CRIT.*POLICY \[ServiceNew\]' $LOGFILE >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+
+ [ -z "$verbose" ] || log_msg_fail "Open ports";
+ return 1
+ fi
+}
+
+refine_portpolicy_1 ()
+{
+ cat "$LOGFILE" | grep ServiceNew | sed 's/.*port: //' | awk '{ print $1 }' | \
+ while read line; do
+ echo "PortCheckRequired=$line" >>"${RCFILE}"
+ done
+}
+
+prep_portpolicy ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ eval echo '"$'"PORTPOLICY_$1"'"' >>"${RCFILE}"
+}
+
+run_check_prelude()
+{
+ ./samhain -t check -p none -l info --set-prelude-severity=info --prelude --server-addr 127.0.0.1:5500 >/dev/null
+
+ if test x$? = x0; then
+
+ ./samhain -j -L $LOGFILE >"${LOGFILE}.tmp" && mv "${LOGFILE}.tmp" "${LOGFILE}"
+
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv logfile...";
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "check...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "check...";
+ return 1
+ fi
+}
+
+
+testrun_internal_1e ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ tcount=1
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }
+
+ POLICY=`eval echo '"$'"PORTPOLICY_$tcount"'"'`
+
+ until [ -z "$POLICY" ]
+ do
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_portpolicy ${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ eval refine_portpolicy_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ #
+ rm -f "$LOGFILE"
+ #
+ PRELUDEPID=0
+ #
+ if test ${tcount} -eq 5;
+ then
+
+ PM=`find_path prelude-manager`
+
+ if [ -z "$PM" ]; then
+ if [ $errval -eq 0 ]; then
+ run_check
+ check_err $? ${tcount}; errval=$?
+ fi
+ elif [ -z "$doall" ]; then
+ if [ $errval -eq 0 ]; then
+ run_check
+ check_err $? ${tcount}; errval=$?
+ fi
+ else
+ #
+ #
+ ${TOP_SRCDIR}/configure ${BUILDOPTS} --with-prelude
+ #
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>&1
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+ #
+ #
+ if ! test -d /var/run/prelude-manager
+ then
+ [ -z "$verbose" ] || log_msg_ok "create /var/run/prelude-manager...";
+ sudo mkdir /var/run/prelude-manager
+ sudo chown prelude:rainer /var/run/prelude-manager
+ sudo chmod 770 /var/run/prelude-manager
+ fi
+ if ! test -d /var/spool/prelude/samhain/global
+ then
+ [ -z "$verbose" ] || log_msg_ok "create /var/spool/prelude/samhain/global...";
+ sudo mkdir -p /var/spool/prelude/samhain/global
+ sudo chown prelude:rainer /var/spool/prelude/samhain/global
+ sudo chmod 770 /var/spool/prelude/samhain/global
+ fi
+
+ #
+ #
+ [ -z "$verbose" ] || { echo " starting prelude-manager.."; echo " ($PM --textmod -l $PW_DIR/test_log_prelude --listen 127.0.0.1:5500 >/dev/null 2>&1 &)"; }
+ "$PM" --textmod -l $PW_DIR/test_log_prelude --listen 127.0.0.1:5500 >/dev/null 2>&1 &
+ PRELUDEPID=$!
+ #
+ #
+ five_sec_sleep
+ #
+ #
+ if [ $errval -eq 0 ]; then
+ run_check_prelude
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+
+ else
+ if [ $errval -eq 0 ]; then
+ run_check
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ eval chk_portdata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ if test ${tcount} -ne 5; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ fi
+ let "tcount = tcount + 1" >/dev/null
+ POLICY=`eval echo '"$'"PORTPOLICY_$tcount"'"'`
+
+ if test $PRELUDEPID -ne 0;
+ then
+ kill $PRELUDEPID
+ fi
+
+ done
+
+ return 0
+}
+
+testrun1e ()
+{
+ log_start "RUN STANDALONE W/PORTCHECK"
+ testrun_internal_1e
+ log_end "RUN STANDALONE W/PORTCHECK"
+ return 0
+}
+
+
diff --git a/test/testrun_1f.sh b/test/testrun_1f.sh
new file mode 100755
index 0000000..6a2f5f3
--- /dev/null
+++ b/test/testrun_1f.sh
@@ -0,0 +1,292 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+
+# --enable-login-watch --enable-xml-log
+# --enable-debug --enable-suidcheck --with-prelude
+
+BUILDOPTS="--quiet $TRUST --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file --enable-debug --with-gpg=/usr/bin/gpg --with-keyid=0x8A0B337A --with-fp=DCCBBB6625591ECE2B8F3AC94ED99E4E8A0B337A"
+export BUILDOPTS
+
+BASE="${PW_DIR}/testrun_testdata"; export BASE
+TDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c"; export TDIRS
+TFILES="x y z"; export TFILES
+
+###########################################################
+#
+# ---- [Define tests here] ----
+#
+
+# 1 for testing new tests
+testrun1_setup=0
+
+MAXTEST=17; export MAXTEST
+
+TESTPOLICY_17="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_17 () {
+ one_sec_sleep
+ rm "${BASE}/a/a/c/x" # delete
+}
+
+TESTPOLICY_16="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_16 () {
+ one_sec_sleep
+ echo "foobar" > "${BASE}/foo" # new
+}
+
+prep_sign_file ()
+{
+ scripts/samhainadmin.pl -s ./test/gnupg/ -m R $1 >/dev/null
+ scripts/samhainadmin.pl -s ./test/gnupg/ -k 8A0B337A -m E $1 >/dev/null
+}
+
+
+run_check_CLverify ()
+{
+ if [ "x$1" = "x" ]; then
+ logsev=debug
+ else
+ logsev=$1
+ fi
+ if test -f ./.samhain_file; then
+ mv ./.samhain_file ./.samhain_file_clverify
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv ./.samhain_file ...";
+ return 1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "test -f ./.samhain_file ...";
+ return 1
+ fi
+
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./samhain -p =err --verify-database ./.samhain_file_clverify 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ if [ "x$2" != "xnullok" ]; then
+ [ -z "$quiet" ] && log_msg_fail "check (1)...";
+ return 1
+ fi
+ else
+ if [ "x$2" = "xnullok" ]; then
+ [ -z "$quiet" ] && log_msg_fail "check (1)...";
+ return 1
+ fi
+ fi
+
+ LL=`wc -l test_log_valgrind | awk '{ print $1; }'`
+ if ! test x$LL = x0; then
+ [ -z "$quiet" ] && log_msg_fail "check (2)...";
+ [ -z "$quiet" ] && cat test_log_valgrind
+ return 1
+ fi
+
+ [ -z "$verbose" ] || log_msg_ok "check...";
+}
+
+run_update_CLverify ()
+{
+ if test -f ./.samhain_file_clverify; then
+ mv ./.samhain_file_clverify ./.samhain_file
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "mv ./.samhain_file_clverify ...";
+ return 1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "test -f ./.samhain_file_clverify ...";
+ return 1
+ fi
+
+ ${VALGRIND} ./samhain -t update -p none -l debug 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "update...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "update...";
+ return 1
+ fi
+}
+
+run_check_after_update_CLverify ()
+{
+ rm -rf $LOGFILE
+
+ run_check_CLverify debug nullok
+}
+
+testrun_internal_CLverify ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }
+
+ tcount=1
+ POLICY=`eval echo '"$'"TESTPOLICY_$tcount"'"'`
+
+ until [ -z "$POLICY" ]
+ do
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_testpolicy ${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_sign_file "${RCFILE}"
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_sign_file ./.samhain_file
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval mod_testdata_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check_CLverify
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $testrun1_setup -eq 0 ]; then
+ if [ $errval -eq 0 ]; then
+ prep_sign_file "${RCFILE}"
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_update_CLverify
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_sign_file ./.samhain_file
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check_after_update_CLverify
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ #
+ let "tcount = tcount + 1" >/dev/null
+ #
+ if [ $tcount -eq 10 ]; then
+ if [ -z "$doall" ]; then
+ log_skip 10 $MAXTEST 'ACL/SELinux test (or use --really-all)'
+ log_skip 11 $MAXTEST 'ACL/SELinux test (or use --really-all)'
+ let "tcount = tcount + 2" >/dev/null
+ else
+ # 'id -u' is posix
+ #
+ if test -f /usr/xpg4/bin/id
+ then
+ my_uid=`/usr/xpg4/bin/id -u`
+ else
+ my_uid=`id -u`
+ fi
+ #
+ if [ ${my_uid} -ne 0 ]; then
+ log_skip 10 $MAXTEST 'ACL/SELinux test (you are not root)'
+ log_skip 11 $MAXTEST 'ACL/SELinux test (you are not root)'
+ let "tcount = tcount + 2" >/dev/null
+ else
+
+ SETFATTR=`find_path setfattr`
+ if [ -z "$SETFATTR" ]; then
+ log_skip 10 $MAXTEST 'ACL/SELinux test (setfattr not in path)'
+ log_skip 11 $MAXTEST 'ACL/SELinux test (setfattr not in path)'
+ let "tcount = tcount + 2" >/dev/null
+ fi
+ fi
+ fi
+ fi
+ #
+ POLICY=`eval echo '"$'"TESTPOLICY_$tcount"'"'`
+ done
+
+ return 0
+}
+
+testrun1f ()
+{
+ log_start "RUN CL Verify"
+ gpg --list-keys | grep 8A0B337A >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "You need to do 'gpg --import test/gnupg/public-key.asc' first"
+ for ff in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17; do
+ log_skip $ff $MAXTEST 'CL verify'
+ done
+ else
+ testrun_internal_CLverify
+ fi
+ log_end "RUN CL Verify"
+ return 0
+}
+
+
+
diff --git a/test/testrun_1g.sh b/test/testrun_1g.sh
new file mode 100644
index 0000000..1361c08
--- /dev/null
+++ b/test/testrun_1g.sh
@@ -0,0 +1,114 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+BUILDOPTS="--quiet $TRUST --enable-debug --enable-xml-log --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file"
+export BUILDOPTS
+
+MAXTEST=1; export MAXTEST
+
+testrun_deltadb ()
+{
+ tcount=1
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ prep_init
+ check_err $? ${tcount}; errval=$?
+
+ if [ $errval -eq 0 ]; then
+ prep_testdata
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_testpolicy 1
+ check_err $? ${tcount}; errval=$?
+ fi
+
+ rm "${BASE}/a/a/b/x"
+ rm -f file.*.*-*-*-*-*
+
+ ./samhain --create-database=./tmp_list_file
+
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ num=$( ./samhain -a -d file.*.*-*-*-*-* | grep "1970-01-01T00:00:00" >/dev/null | wc -l )
+ if [ $num -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_ok "list...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "list...";
+ log_fail ${tcount} ${MAXTEST};
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "create...";
+ log_fail ${tcount} ${MAXTEST};
+ fi
+
+ if [ $errval -eq 0 ]; then
+ ./samhain --verify-database file.*.*-*-*-*-*
+ fi
+
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ echo "o_O" > "${BASE}/a/a/b/y"
+ ./samhain --verify-database file.*.*-*-*-*-*
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "detect modify...";
+ check_err 1 ${tcount}; errval=1
+ fi
+
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+
+ [ -z "$cleanup" ] || rm -f file.*.*-*-*-*-*
+ return 0
+}
+
+testrun1g ()
+{
+ log_start "RUN CL Create DeltaDB"
+
+ testrun_deltadb
+
+ log_end "RUN CL Create DeltaDB"
+ return 0
+}
+
diff --git a/test/testrun_1h.sh b/test/testrun_1h.sh
new file mode 100644
index 0000000..30c8f99
--- /dev/null
+++ b/test/testrun_1h.sh
@@ -0,0 +1,305 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+
+# --enable-login-watch --enable-xml-log
+# --enable-debug --enable-suidcheck --with-prelude
+
+BUILDOPTS="--quiet $TRUST --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file --enable-debug"
+export BUILDOPTS
+
+BASE="${PW_DIR}/testrun_testdata"; export BASE
+TDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c"; export TDIRS
+TFILES="x y z"; export TFILES
+TFILES_PART="c/miss c/add c/change c/leave"; export TFILES_PART
+
+###########################################################
+#
+# ---- [Define tests here] ----
+#
+
+# 1 for testing new tests
+testrun1_setup=0
+
+MAXTEST=5; export MAXTEST
+
+PARTIAL_OUTFILE=".samhain_file_partial"; export PARTIAL_OUTFILE
+PARTIAL_FILTER="c/create c/miss c/change c/leave"; export PARTIAL_FILTER
+
+TEST_PART_POLICY_1="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_partial_1 () {
+ one_sec_sleep
+ rm "${BASE}/a/a/c/x" # delete
+}
+EXPECT_1="nullok"
+
+TEST_PART_POLICY_2="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_partial_2 () {
+ one_sec_sleep
+ echo "foobar" > "${BASE}/foo" # new
+}
+EXPECT_2="nullok"
+
+TEST_PART_POLICY_3="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_partial_3 () {
+ one_sec_sleep
+ rm -f "${BASE}/c/miss"
+}
+EXPECT_3=""
+
+TEST_PART_POLICY_4="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_partial_4 () {
+ one_sec_sleep
+ echo foo >"${BASE}/c/create"
+}
+EXPECT_4=""
+
+TEST_PART_POLICY_5="
+[ReadOnly]
+dir=${BASE}
+"
+mod_testdata_partial_5 () {
+ one_sec_sleep
+ echo toodledoo >"${BASE}/c/change"
+}
+EXPECT_5=""
+
+#
+# $2 == "nullok" means no mods should be detected,
+# else it is an error to detect no mods
+#
+run_check_partial_verify ()
+{
+ if [ "x$1" = "x" ]; then
+ logsev=debug
+ else
+ logsev=$1
+ fi
+ if ! test -f ${PARTIAL_OUTFILE}; then
+ [ -z "$quiet" ] && log_msg_fail "missing ${PARTIAL_OUTFILE} ...";
+ return 1
+ fi
+
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./samhain -p =err --verify-database ${PARTIAL_OUTFILE} 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ if [ "x$2" != "xnullok" ]; then
+ [ -z "$quiet" ] && log_msg_fail "check (1a)...";
+ return 1
+ fi
+ else
+ if [ "x$2" = "xnullok" ]; then
+ [ -z "$quiet" ] && log_msg_fail "check (1b)...";
+ return 1
+ fi
+ fi
+
+ LL=`wc -l test_log_valgrind | awk '{ print $1; }'`
+ if ! test x$LL = x0; then
+ [ -z "$quiet" ] && log_msg_fail "check (2)...";
+ [ -z "$quiet" ] && cat test_log_valgrind
+ return 1
+ fi
+
+ [ -z "$verbose" ] || log_msg_ok "check...";
+}
+
+run_update_partial_verify ()
+{
+ ${VALGRIND} ./samhain -t update -p none -l debug 2>>test_log_valgrind
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "update...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "update...";
+ return 1
+ fi
+}
+
+run_check_after_update_partial ()
+{
+ rm -rf $LOGFILE
+
+ run_check_partial_verify debug nullok
+}
+
+create_partial ()
+{
+ echo "${BASE}/c" > test_filter.txt
+ for ff in ${TFILES_PART}; do
+ echo "${BASE}/${ff}" >> test_filter.txt
+ done
+
+ ./samhain -o "${PARTIAL_OUTFILE}" --binary --list-filter=test_filter.txt --list-database=./.samhain_file
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "create partial DB...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "create partial DB...";
+ return 1
+ fi
+
+ if test -f "${PARTIAL_OUTFILE}"; then
+ [ -z "$verbose" ] || log_msg_ok "partial DB exists...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "partial DB exists...";
+ return 1
+ fi
+ rm -f test_filter.txt
+}
+
+prep_partial_testpolicy ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ eval echo '"$'"TEST_PART_POLICY_$1"'"' >>"${RCFILE}"
+}
+
+prep_testdata_partial ()
+{
+ prep_testdata
+ if test x$? = x0; then
+ touch "${BASE}/c/miss"
+ touch "${BASE}/c/change"
+ touch "${BASE}/c/leave"
+ else
+ return 1
+ fi
+}
+
+testrun_internal_partial_verify ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+
+ #
+ # test standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+
+ ${TOP_SRCDIR}/configure ${BUILDOPTS}
+
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE >/dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || { echo; echo "${S}Running test suite${E}"; echo; }
+
+ tcount=1
+ POLICY=`eval echo '"$'"TEST_PART_POLICY_$tcount"'"'`
+
+ until [ -z "$POLICY" ]
+ do
+ prep_init
+ check_err $? ${tcount}; errval=$?
+ if [ $errval -eq 0 ]; then
+ prep_testdata_partial
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ prep_partial_testpolicy ${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_init
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ create_partial
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ eval mod_testdata_partial_${tcount}
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ arg2=`eval echo '"$'"EXPECT_$tcount"'"'`
+ run_check_partial_verify debug $arg2
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $testrun1_setup -eq 0 ]; then
+ if [ $errval -eq 0 ]; then
+ run_update_partial_verify
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ create_partial
+ check_err $? ${tcount}; errval=$?
+ fi
+ if [ $errval -eq 0 ]; then
+ run_check_after_update_partial
+ check_err $? ${tcount}; errval=$?
+ fi
+ fi
+ #
+ if [ $errval -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok ${tcount} ${MAXTEST};
+ fi
+ #
+ let "tcount = tcount + 1" >/dev/null
+ #
+ POLICY=`eval echo '"$'"TEST_PART_POLICY_$tcount"'"'`
+ done
+
+ return 0
+}
+
+testrun1h ()
+{
+ log_start "RUN CL Partial DB Verify"
+ testrun_internal_partial_verify
+ log_end "RUN CL Partial DB Verify"
+ return 0
+}
+
+
+
diff --git a/test/testrun_2.sh b/test/testrun_2.sh
new file mode 100755
index 0000000..9a26592
--- /dev/null
+++ b/test/testrun_2.sh
@@ -0,0 +1,828 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+HTML="$PW_DIR/yule.html"; export HTML
+
+
+do_test_1 () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./yule.2 -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y2=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server #2${E}: ./yule.2 -l info -p none &";
+ echo;
+ }
+
+ ${VALGRIND} ./yule -l info -p none -e info --bind-address=127.0.0.1 \
+ --server-port=49778 >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -l none -p none -e info -t check";
+ echo;
+ }
+
+ ${VALGRIND} ./samhain.new -t check -p none -l none -e info --bind-address=127.0.0.1 >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "samhain.new -t check";
+ else
+ [ -z "$quiet" ] && log_msg_fail "samhain.new -t check";
+ kill $PROC_Y
+ kill $PROC_Y2
+ return 1
+ fi
+
+ kill $PROC_Y
+ kill $PROC_Y2
+ five_sec_sleep
+
+ # cp ${LOGFILE} triple_test
+ # cp ${LOGFILE}2 triple_test_2
+
+ egrep "START(>|\").*Yule(>|\")" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server #2 start";
+ return 1
+ fi
+ egrep "remote_host.*Checking.*/bin" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (relayed)";
+ return 1
+ fi
+ egrep "remote_host.*EXIT.*Samhain" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit (relayed)";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server #2 exit";
+ return 1
+ fi
+
+
+ egrep "START(>|\").*Yule(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "remote_host.*Checking.*/bin" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "remote_host.*EXIT.*Samhain" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ return 0
+}
+
+do_test_2 () {
+
+ ORIGINAL="UseSeparateLogs=no"
+ REPLACEMENT="UseSeparateLogs=yes"
+ ex -s $RCFILE <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+# :%s is the "ex" substitution command.
+# :wq is write-and-quit.
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+
+ rm -f $LOGFILE
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./yule -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -l none -p none -e info -t check";
+ echo;
+ }
+
+ ${VALGRIND} ./samhain.new -t check -p none -l none -e info --bind-address=127.0.0.1 >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "samhain.new -t check";
+ else
+ [ -z "$quiet" ] && log_msg_fail "samhain.new -t check";
+ kill $PROC_Y
+ return 1
+ fi
+
+ kill $PROC_Y
+ five_sec_sleep
+
+ if [ -f ${LOGFILE}.${SH_LOCALHOST} ]; then
+ remhost=${SH_LOCALHOST}
+ else
+ remhost=`echo $SH_LOCALHOST | sed 's,\..*,,'`
+ fi
+ if [ -f ${LOGFILE}.${remhost} ]; then
+ CLIENTLOG="${LOGFILE}.${remhost}"
+ else
+ tail -n 1 ${SCRIPTDIR}/test.sh >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ CLIENTLOG=`ls -1 ${LOGFILE}.* 2>/dev/null | tail -n 1`
+ else
+ CLIENTLOG=`ls -1 ${LOGFILE}.* 2>/dev/null | tail -1`
+ fi
+ fi
+
+ egrep "START(>|\").*Yule(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "remote_host.*Checking.*/bin" ${CLIENTLOG} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "remote_host.*EXIT.*Samhain" ${CLIENTLOG} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ rm -f ${LOGFILE}.${remhost}
+ return 0
+}
+
+do_test_3 () {
+
+ ORIGINAL_1="ExportSeverity=none"
+ REPLACEMENT_1="ExportSeverity=mark"
+ ORIGINAL_2="UseSeparateLogs=yes"
+ REPLACEMENT_2="UseSeparateLogs=no"
+ ORIGINAL_3="LogSeverity=none"
+ REPLACEMENT_3="LogSeverity=debug"
+ ORIGINAL_4="# SetClientTimeLimit=1800"
+ REPLACEMENT_4="SetClientTimeLimit=20"
+ # takes too much time if we leave that in
+ ORIGINAL_5="dir=1"
+ REPLACEMENT_5="#dir=1"
+ ex -s $RCFILE <<EOF
+%s/${ORIGINAL_1}/${REPLACEMENT_1}/g
+%s/${ORIGINAL_2}/${REPLACEMENT_2}/g
+%s/${ORIGINAL_3}/${REPLACEMENT_3}/g
+%s/${ORIGINAL_4}/${REPLACEMENT_4}/g
+%s/${ORIGINAL_5}/${REPLACEMENT_5}/g
+wq
+EOF
+# :%s is the "ex" substitution command.
+# :wq is write-and-quit.
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -p none -e none &";
+ echo;
+ }
+
+ rm -f $LOGFILE
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./yule -p none -e none >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -t check -p none -l none --forever --bind-address=127.0.0.1 &";
+ echo;
+ }
+
+ ${VALGRIND} ./samhain.new -t check -p none -l none --forever --bind-address=127.0.0.1 >/dev/null 2>>test_log_valgrind &
+ if test x$? = x0; then
+ PROC_S=$!
+ # echo "PID is ${PROC_S}"
+ [ -z "$verbose" ] || log_msg_ok "samhain.new -t check";
+ five_sec_sleep
+ # Redirect the shells (un-)helpful job monitoring messages.
+ # The 'disown' buildin is not portable.
+ { kill -9 ${PROC_S}; sleep 40; } >/dev/null 2>&1
+ else
+ [ -z "$quiet" ] && log_msg_fail "samhain.new -t check";
+ kill $PROC_Y
+ return 1
+ fi
+
+ if [ -t 0 ]; then
+ # enable monitor mode again if interactive
+ set -m
+ fi
+
+ kill $PROC_Y
+ five_sec_sleep
+
+ egrep "START(>|\").*Yule(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "remote_host.*File check completed.*" ${LOGFILE} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "Time limit exceeded" ${LOGFILE} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client dead detection";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ rm -f ${LOGFILE}
+ return 0
+}
+
+do_test_4 () {
+
+ # don't know what is supported on the test platform, so
+ # prepare for both (password and socket credential)
+
+ # 'id -u' is posix
+ if test -f /usr/xpg4/bin/id
+ then
+ me=`/usr/xpg4/bin/id -u`
+ else
+ me=`id -u`
+ fi
+
+ ORIGINAL_1="SetSocketAllowUid=0"
+ REPLACEMENT_1="SetSocketAllowUid=$me"
+ ex -s $RCFILE <<EOF
+%s/${ORIGINAL_1}/${REPLACEMENT_1}/g
+wq
+EOF
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+
+ rm -f $LOGFILE
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./yule -l info -p none -e none \
+ >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -l none -p none -e info -t check";
+ echo;
+ }
+
+ $MAKE yulectl >/dev/null
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "make yulectl";
+ kill $PROC_Y
+ return 1
+ fi
+
+
+ ./yulectl -v -c RELOAD foobar1 >test_log_yulectl 2>/dev/null
+
+ if [ $? -ne 0 ]; then
+ YULECTL_PASSWORD=samhain; export YULECTL_PASSWORD
+ ./yulectl -v -c RELOAD foobar1 >test_log_yulectl
+ if [ $? -ne 0 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "yulectl";
+ return 1
+ fi
+ fi
+
+ ./yulectl -v -c RELOAD foobar2 >test_yulectl_log
+
+ if [ $? -ne 0 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "yulectl";
+ return 1
+ fi
+
+ ./yulectl -v -c RELOAD foobar3 >test_log_yulectl
+
+ if [ $? -ne 0 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "yulectl";
+ return 1
+ fi
+
+ ./yulectl -v -c LISTALL dummy >test_log_yulectl
+
+ if [ $? -ne 0 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "yulectl";
+ return 1
+ fi
+
+ tmp=`cat test_log_yulectl | grep RELOAD | wc -l`
+ if [ $tmp -ne 3 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "command confirmation";
+ return 1
+ fi
+
+ ./yulectl -v -c CANCEL foobar3 >test_log_yulectl
+
+ if [ $? -ne 0 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "yulectl";
+ return 1
+ fi
+
+ ./yulectl -v -c LISTALL dummy >test_log_yulectl
+
+ if [ $? -ne 0 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "yulectl";
+ return 1
+ fi
+
+ tmp=`cat test_log_yulectl | grep RELOAD | wc -l`
+ if [ $tmp -ne 2 ]; then
+ kill ${PROC_Y}
+ [ -z "$verbose" ] || log_msg_fail "command confirmation";
+ return 1
+ fi
+
+ kill ${PROC_Y}
+ one_sec_sleep
+ one_sec_sleep
+ kill -9 ${PROC_Y} >/dev/null 2>&1
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ return 0
+}
+
+do_test_5 () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+
+( cat <<EOF
+<!-- head -->
+<html><head><title>test</title></head>
+<body>
+Current time: %T <br>
+<table>
+<!-- ehead -->
+EOF
+) >head.html
+
+( cat <<EOF
+<!-- foot -->
+</table>
+</body>
+<!-- efoot -->
+EOF
+) >foot.html
+
+( cat <<EOF
+<!-- entry -->
+<tr>
+ <td>%H</td>
+ <td>%S</td>
+ <td>%T</td>
+</tr>
+<!-- eentry -->
+EOF
+) >entry.html
+
+ ${VALGRIND} ./yule -l info -p none -e none \
+ >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ egrep '<!-- head -->' $HTML >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ # rm -f head.html; rm -f foot.html; rm -f entry.html;
+ kill $PROC_Y
+ [ -z "$verbose" ] || log_msg_fail "head.html (1)";
+ return 1
+ fi
+
+ egrep '<!-- foot -->' $HTML >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ rm -f head.html; rm -f foot.html; rm -f entry.html;
+ kill $PROC_Y
+ [ -z "$verbose" ] || log_msg_fail "foot.html (1)";
+ return 1
+ fi
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -l none -p none -e info -t check";
+ echo;
+ }
+
+ ${VALGRIND} ./samhain.new -t check -p none -l none -e info --bind-address=127.0.0.1 >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "samhain.new -t check";
+ else
+ kill $PROC_Y
+ [ -z "$quiet" ] && log_msg_fail "samhain.new -t check";
+ return 1
+ fi
+
+ cp $HTML ${HTML}.tmp
+
+ kill $PROC_Y
+ five_sec_sleep
+
+ # rm -f head.html; rm -f foot.html; rm -f entry.html;
+
+ egrep "START(>|\").*Yule(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "remote_host.*Checking.*/bin" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "remote_host.*EXIT.*Samhain" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+
+ egrep '<!-- head -->' ${HTML}.tmp >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "head.html";
+ return 1
+ fi
+ egrep '<!-- ehead -->' ${HTML}.tmp >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "end head.html";
+ return 1
+ fi
+
+ egrep '<!-- entry -->' ${HTML}.tmp >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "entry.html";
+ return 1
+ fi
+ egrep '<!-- eentry -->' ${HTML}.tmp >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "end entry.html";
+ return 1
+ fi
+
+ egrep '<!-- foot -->' ${HTML}.tmp >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "foot.html";
+ return 1
+ fi
+ egrep '<!-- efoot -->' ${HTML}.tmp >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "end foot.html";
+ return 1
+ fi
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ rm ${HTML}.tmp
+
+ return 0
+}
+
+
+testrun2_internal ()
+{
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE;
+ echo;
+ }
+ #
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet $TRUST --enable-debug --enable-network=client --enable-xml-log --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-data-file=$PW_DIR/.samhain_file --enable-encrypt=2 --enable-static
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # save binary and build server2
+ #
+ cp samhain samhain.build || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure --quiet $TRUST --enable-debug --enable-network=server --enable-xml-log --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=${RCFILE}2 --with-log-file=${LOGFILE}2 --with-pid-file=$PW_DIR/.samhain_lock2 --with-html-file=${HTML}2 --with-state-dir=$PW_DIR --enable-encrypt=2 --with-port=49778
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # save binary and build server
+ #
+ cp yule yule.2 || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure --quiet $TRUST --enable-debug --enable-network=server --enable-xml-log --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --with-html-file=$HTML --with-state-dir=$PW_DIR --enable-encrypt=2
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+
+ #####################################################################
+ #
+ #
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+
+ ./samhain.build -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ # Create a password
+
+ SHPW=`./yule -G`
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ # Set in client
+
+ ./samhain_setpwd samhain.build new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd samhain.build new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd samhain.build new $SHPW";
+ return 1
+ fi
+
+ mv samhain.build.new samhain.new || return 1
+
+ # Set in server
+
+ ./samhain_setpwd yule new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd yule new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd yule new $SHPW";
+ return 1
+ fi
+
+ mv yule.new yule || return 1
+
+ #
+
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock*
+
+ SHCLT=`./yule -P $SHPW`
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "yule -P $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "yule -P $SHPW";
+ return 1
+ fi
+
+ SHCLT1=`echo "${SHCLT}" | sed s%HOSTNAME%${SH_LOCALHOST}%`
+ AHOST=`find_hostname`
+ SHCLT2=`echo "${SHCLT}" | sed s%HOSTNAME%${AHOST}%`
+
+
+ echo $SHCLT1 >> testrc_2
+ echo $SHCLT2 >> testrc_2
+ cp testrc_2 testrc_22
+
+ do_test_1
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Client logging";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client logging";
+ fi
+
+ do_test_2
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 2 ${MAXTEST} "Client logging, separate logfiles";
+ else
+ [ -z "$quiet" ] && log_fail 2 ${MAXTEST} "Client logging, separate logfiles";
+ fi
+
+ do_test_3
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 3 ${MAXTEST} "Dead client detection";
+ else
+ [ -z "$quiet" ] && log_fail 3 ${MAXTEST} "Dead client detection";
+ fi
+
+ do_test_4
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 4 ${MAXTEST} "Server command socket";
+ else
+ [ -z "$quiet" ] && log_fail 4 ${MAXTEST} "Server command socket";
+ fi
+
+ do_test_5
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 5 ${MAXTEST} "Server status file";
+ else
+ [ -z "$quiet" ] && log_fail 5 ${MAXTEST} "Server status file";
+ fi
+
+ return $?
+}
+
+MAXTEST=5; export MAXTEST
+
+testrun2 ()
+{
+ log_start "RUN CLIENT/SERVER"
+
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+ testrun2_internal
+ #
+ log_end "RUN CLIENT/SERVER"
+
+ return 0
+}
+
diff --git a/test/testrun_2a.sh b/test/testrun_2a.sh
new file mode 100755
index 0000000..8a0c76f
--- /dev/null
+++ b/test/testrun_2a.sh
@@ -0,0 +1,302 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --enable-debug=gdb"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --enable-network=client --enable-srp --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$RCFILE --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --enable-suidcheck --enable-debug"; export CLIENT_BUILDOPTS
+
+do_test_1_a () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./yule -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -l none -p none -e info -t check --bind-address=127.0.0.1 --server-host=localhost";
+ echo;
+ }
+
+ ${VALGRIND} ./samhain.new -t check -p none -l none -e info --bind-address=127.0.0.1 --server-host=localhost >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "samhain.new -t check";
+ else
+ [ -z "$quiet" ] && log_msg_fail "samhain.new -t check";
+ kill $PROC_Y
+ return 1
+ fi
+
+ kill $PROC_Y
+ five_sec_sleep
+
+ egrep "START(>|\").*Yule(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "Checking.*/etc" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "EXIT.*Samhain" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ return 0
+}
+
+testrun2a_internal ()
+{
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE;
+ echo;
+ }
+ #
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure ${CLIENT_BUILDOPTS}
+ #
+ # Limit suid check
+ #
+ BASE="${PW_DIR}"; export BASE
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE 'DBGDEF=-DSH_SUIDTESTDIR=\"${BASE}\"' > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # save binary and build server
+ #
+ cp samhain samhain.build || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure ${SERVER_BUILDOPTS}
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+
+ #####################################################################
+ #
+ #
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ rm -f "./rc.${ALTHOST}"
+ rm -f "./file.${ALTHOST}"
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+
+ ./samhain.build -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ # Create a password
+
+ SHPW=`./yule -G`
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ # Set in client
+
+ ./samhain_setpwd samhain.build new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd samhain.build new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd samhain.build new $SHPW";
+ return 1
+ fi
+
+ mv samhain.build.new samhain.new || return 1
+
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock
+
+ SHCLT=`./yule -P $SHPW`
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "yule -P $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "yule -P $SHPW";
+ return 1
+ fi
+
+ SHCLT1=`echo "${SHCLT}" | sed s%HOSTNAME%${SH_LOCALHOST}%`
+ AHOST=`find_hostname`
+ SHCLT2=`echo "${SHCLT}" | sed s%HOSTNAME%${AHOST}%`
+
+
+ echo $SHCLT1 >> testrc_2
+ echo $SHCLT2 >> testrc_2
+
+
+ cp ./testrc_2 ./rc.${SH_LOCALHOST}
+ mv ./.samhain_file ./file.${SH_LOCALHOST}
+ chmod 644 ./rc.${SH_LOCALHOST}
+ chmod 644 ./file.${SH_LOCALHOST}
+
+ ALTHOST=`find_hostname`
+ cp ./testrc_2 "./rc.${ALTHOST}"
+ cp ./file.${SH_LOCALHOST} "./file.${ALTHOST}" 2>/dev/null
+ chmod 644 ./rc.${ALTHOST}
+ chmod 644 ./file.${ALTHOST}
+
+ echo $SHPW > ./testpw
+}
+
+MAXTEST=4; export MAXTEST
+
+testrun2a ()
+{
+ log_start "RUN FULL CLIENT/SERVER";
+ #
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+ testrun2a_internal
+ do_test_1_a
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Client download+logging";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client download+logging";
+ fi
+ ####### EXIT HERE FOR TESTING ######
+ #
+ #
+ SERVER_BUILDOPTS_ORIG="${SERVER_BUILDOPTS}"
+ CLIENT_BUILDOPTS_ORIG="${CLIENT_BUILDOPTS}"
+ #
+ SERVER_BUILDOPTS="${SERVER_BUILDOPTS_ORIG} --disable-srp"; export SERVER_BUILDOPTS
+ CLIENT_BUILDOPTS="${CLIENT_BUILDOPTS_ORIG} --disable-srp"; export CLIENT_BUILDOPTS
+ #
+ testrun2a_internal
+ do_test_1_a
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 2 ${MAXTEST} "SRP disabled";
+ else
+ [ -z "$quiet" ] && log_fail 2 ${MAXTEST} "SRP disabled";
+ fi
+ #
+ SERVER_BUILDOPTS="${SERVER_BUILDOPTS_ORIG} --disable-encrypt"; export SERVER_BUILDOPTS
+ CLIENT_BUILDOPTS="${CLIENT_BUILDOPTS_ORIG} --disable-encrypt"; export CLIENT_BUILDOPTS
+ #
+ testrun2a_internal
+ do_test_1_a
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 3 ${MAXTEST} "Encryption disabled";
+ else
+ [ -z "$quiet" ] && log_fail 3 ${MAXTEST} "Encryption disabled";
+ fi
+ #
+ SERVER_BUILDOPTS="${SERVER_BUILDOPTS_ORIG} --disable-ipv6"; export SERVER_BUILDOPTS
+ CLIENT_BUILDOPTS="${CLIENT_BUILDOPTS_ORIG} --disable-ipv6"; export CLIENT_BUILDOPTS
+ #
+ testrun2a_internal
+ do_test_1_a
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 4 ${MAXTEST} "IPv6 disabled";
+ else
+ [ -z "$quiet" ] && log_fail 4 ${MAXTEST} "IPv6 disabled";
+ fi
+ #
+ if [ -n "$cleanup" ]; then
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ ALTHOST=`find_hostname`
+ rm -f "./file.${ALTHOST}"
+ rm -f "./rc.${ALTHOST}"
+ fi
+ #
+ log_end "RUN FULL CLIENT/SERVER"
+}
diff --git a/test/testrun_2b.sh b/test/testrun_2b.sh
new file mode 100755
index 0000000..c9e6267
--- /dev/null
+++ b/test/testrun_2b.sh
@@ -0,0 +1,215 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+RCFILE_C="$PW_DIR/testrc_1.dyn"; export RCFILE_C
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --enable-micro-stealth=137 --enable-debug --enable-network=client --enable-srp --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER${RCFILE_C} --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=localhost --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock"; export CLIENT_BUILDOPTS
+
+testrun2b_internal ()
+{
+ GPG="$1"
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE; echo GPG is $GPG;
+ echo;
+ }
+
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+
+ ${TOP_SRCDIR}/configure --with-gpg=${GPG} --with-checksum=no ${CLIENT_BUILDOPTS} >/dev/null 2>&1
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ SKIP=`awk '/^__ARCHIVE_FOLLOWS__/ { print NR + 1; exit 0; }' ${SCRIPTDIR}/test.sh`
+
+ tail -n "+$SKIP" ${SCRIPTDIR}/test.sh >/dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ tail -n "+$SKIP" ${SCRIPTDIR}/test.sh | gunzip -c - 2>/dev/null | tar xf - && \
+ mv "./testrc.gpg.asc" "${RCFILE_C}"
+ else
+ tail "+$SKIP" ${SCRIPTDIR}/test.sh | gunzip -c - 2>/dev/null | tar xf - && \
+ mv "./testrc.gpg.asc" "${RCFILE_C}"
+ fi
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "extract gpg signed files...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "extract gpg signed files...";
+ return 1
+ fi
+
+ # save binary and build server
+
+ cp samhain samhain.build || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure ${SERVER_BUILDOPTS}
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+
+ #####################################################################
+ #
+ #
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+
+ ./samhain.build -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ # Create a password
+
+ SHPW=`./yule -G`
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ # Set in client
+
+ ./samhain_setpwd samhain.build new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd samhain.build new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd samhain.build new $SHPW";
+ return 1
+ fi
+
+ mv samhain.build.new samhain.new || return 1
+
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock
+
+ SHCLT=`./yule -P $SHPW`
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "yule -P $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "yule -P $SHPW";
+ return 1
+ fi
+
+ SHCLT1=`echo "${SHCLT}" | sed s%HOSTNAME%${SH_LOCALHOST}%`
+ AHOST=`find_hostname`
+ SHCLT2=`echo "${SHCLT}" | sed s%HOSTNAME%${AHOST}%`
+
+
+ echo $SHCLT1 >> testrc_2
+ echo $SHCLT2 >> testrc_2
+
+
+ cp "${RCFILE_C}" ./rc.${SH_LOCALHOST}
+ mv $PW_DIR/.samhain_file.asc ./file.${SH_LOCALHOST}
+
+ ALTHOST=`find_hostname`
+ cp "${RCFILE_C}" "./rc.${ALTHOST}"
+ cp ./file.${SH_LOCALHOST} "./file.${ALTHOST}" 2>/dev/null
+}
+
+MAXTEST=1; export MAXTEST
+
+testrun2b ()
+{
+ log_start "RUN FULL CLIENT/SERVER W/GPG";
+ #
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ #
+ GPG=`find_path gpg`
+ if [ -z "$GPG" ]; then
+ log_skip 1 $MAXTEST 'gpg not found in $PATH'
+ else
+ eval "$GPG" --list-keys 0F571F6C >/dev/null 2>/dev/null
+ if [ $? -ne 0 ]; then
+ log_skip 1 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ else
+
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+
+ testrun2b_internal "$GPG"
+
+ SAVE_VALGRIND="${VALGRIND}"; VALGRIND=''; export VALGRIND
+ do_test_1_a
+ VALGRIND="${SAVE_VALGRIND}"; export VALGRIND
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Client download+logging w/gpg";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client download+logging w/gpg";
+ fi
+
+ if [ -n "$cleanup" ]; then
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ ALTHOST=`find_hostname`
+ rm -f "./file.${ALTHOST}"
+ rm -f "./rc.${ALTHOST}"
+ fi
+ fi
+ fi
+ log_end "RUN FULL CLIENT/SERVER W/GPG"
+}
+
diff --git a/test/testrun_2c.sh b/test/testrun_2c.sh
new file mode 100755
index 0000000..4c93034
--- /dev/null
+++ b/test/testrun_2c.sh
@@ -0,0 +1,427 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+HTML="$PW_DIR/yule.html"; export HTML
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-xml-log --enable-debug --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-database=mysql"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --enable-network=client --disable-mail --disable-external-scripts --enable-login-watch --enable-xml-log --enable-db-reload --with-logserver=localhost --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock"; export CLIENT_BUILDOPTS
+
+MAXTEST=4; export MAXTEST
+
+do_test_1_c () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+
+ rm -f test_log_valgrind
+
+ ${VALGRIND} ./yule.2 -q -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y2=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server #2${E}: ./yule.2 -l info -p none &";
+ echo;
+ }
+
+ ${VALGRIND} ./yule -l info -p none -e info --bind-address=127.0.0.1 \
+ --server-port=49778 >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -l none -p none -e info -t check";
+ echo;
+ }
+
+ ${VALGRIND} ./samhain.new -t check -p none -l none -e info --bind-address=127.0.0.1 >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "samhain.new -t check";
+ else
+ [ -z "$quiet" ] && log_msg_fail "samhain.new -t check";
+ kill $PROC_Y
+ kill $PROC_Y2
+ return 1
+ fi
+
+ kill $PROC_Y
+ kill $PROC_Y2
+ five_sec_sleep
+
+ # cp ${LOGFILE} triple_test
+ # cp ${LOGFILE}2 triple_test_2
+
+ egrep "START(>|\").*Yule(>|\")" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server #2 start";
+ return 1
+ fi
+ egrep "remote_host.*Checking.*/bin" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (relayed)";
+ return 1
+ fi
+ egrep "remote_host.*EXIT.*Samhain" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit (relayed)";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" ${LOGFILE}2 >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server #2 exit";
+ return 1
+ fi
+
+
+ egrep "START(>|\").*Yule(>|\")" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "remote_host.*Checking.*/bin" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "remote_host.*EXIT.*Samhain" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+
+ [ -z "$VALGRIND" ] || {
+ tmp=`cat test_log_valgrind 2>/dev/null | wc -l`;
+ if [ $tmp -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "valgrind reports errors";
+ cat test_log_valgrind
+ return 1;
+ fi;
+ }
+
+ return 0
+}
+
+testrun_threesockets () {
+
+ GPG="$1"
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE; echo GPG is $GPG;
+ echo;
+ }
+
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+
+ ${TOP_SRCDIR}/configure --with-gpg=${GPG} --with-fp=EF6CEF54701A0AFDB86AF4C31AAD26C80F571F6C --with-checksum=no ${SERVER_BUILDOPTS} >/dev/null 2>&1
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+
+ ORIGINAL="DatabaseSeverity=none"
+ REPLACEMENT="DatabaseSeverity=warn"
+ ex -s $RCFILE <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+
+ ORIGINAL="MailSeverity=none"
+ REPLACEMENT="MailSeverity=crit"
+ ex -s $RCFILE <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+ return 0
+ }
+
+check_mysql_log () {
+ DATE="$1"
+
+ rm -f test_log_db
+ #
+ echo "SELECT * FROM log WHERE entry_status = 'NEW' and log_time > '"${DATE}"';" | mysql --password=samhain -u samhain samhain >test_log_db
+ #
+ egrep "START.*Yule" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start";
+ return 1
+ fi
+ egrep "NEW CLIENT" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect";
+ return 1
+ fi
+ egrep "Checking.*/bin" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ return 1
+ fi
+ egrep "EXIT.*Samhain" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit";
+ return 1
+ fi
+ return 0
+}
+
+testrun2c ()
+{
+ log_start "RUN FULL CLIENT/SERVER W/MYSQL"
+ #
+ if [ -z "$doall" ]; then
+ log_skip 1 $MAXTEST 'Client/server w/mysql (or use --really-all)'
+ log_skip 2 $MAXTEST 'Client/server w/mysql (or use --really-all)'
+ log_skip 3 $MAXTEST 'Client/server w/mysql (or use --really-all)'
+ log_skip 4 $MAXTEST 'Client/server w/mysql (or use --really-all)'
+ return 0
+ fi
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ MYSQL=`find_path mysql`
+ if [ -z "$MYSQL" ]; then
+ log_skip 1 $MAXTEST "mysql not found";
+ log_skip 2 $MAXTEST "mysql not found";
+ log_skip 3 $MAXTEST "mysql not found";
+ log_skip 4 $MAXTEST "mysql not found";
+ return 1
+ else
+ TEST=`echo "DESCRIBE log;" | mysql --password=samhain -u samhain samhain 2>/dev/null`
+ if [ $? -ne 0 -o -z "$TEST" ]; then
+ log_skip 1 $MAXTEST "mysql not default setup"
+ log_skip 2 $MAXTEST "mysql not default setup"
+ log_skip 3 $MAXTEST "mysql not default setup"
+ log_skip 4 $MAXTEST "mysql not default setup"
+ return 1
+ fi
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+ DATE=`date '+%Y-%m-%d %T'`
+ #
+ testrun2a_internal
+ #
+ # BUILD Server 2
+ #
+ cp ./yule ./yule.orig
+
+ ${TOP_SRCDIR}/configure --quiet $TRUST --enable-debug --enable-network=server --enable-xml-log --enable-login-watch --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=${RCFILE}2 --with-log-file=${LOGFILE}2 --with-pid-file=$PW_DIR/.samhain_lock2 --with-html-file=${HTML}2 --with-state-dir=$PW_DIR --with-port=49778 --with-database=mysql
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ cp yule yule.2 || return 1
+ #
+ cp ./yule.orig ./yule
+ #
+ SHPW=`cat ./testpw`
+
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ rm -f ./testpw
+
+ ./samhain_setpwd yule new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd yule new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd yule new $SHPW";
+ return 1
+ fi
+
+
+ $MAKE clean >/dev/null || return 1
+ mv yule.new yule || return 1
+ #
+ ORIGINAL="DatabaseSeverity=none"
+ REPLACEMENT="DatabaseSeverity=info"
+ ex -s $RCFILE <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+ #
+ do_test_1_a
+ #
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client/server w/mysql";
+ else
+ #
+ check_mysql_log "${DATE}"
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client/server w/mysql";
+ else
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Client/server w/mysql";
+ fi
+ fi
+ #
+ cp testrc_2 testrc_22
+ ORIGINAL="DatabaseSeverity=none"
+ REPLACEMENT="DatabaseSeverity=info"
+ ex -s $RCFILE <<EOF
+%s/$REPLACEMENT/$ORIGINAL/g
+wq
+EOF
+ #
+ do_test_1_c
+ #
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 2 ${MAXTEST} "Client/server (relay) w/mysql";
+ else
+ #
+ check_mysql_log "${DATE}"
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 2 ${MAXTEST} "Client/server (relay) w/mysql";
+ else
+ [ -z "$quiet" ] && log_ok 2 ${MAXTEST} "Client/server (relay) w/mysql";
+ fi
+ fi
+ #
+ #
+ if [ -f ./yule ]; then
+ ./yule -p info -l info --set-database-severity=info -D >/dev/null 2>>test_log
+ five_sec_sleep
+ netstat -pant 2>/dev/null | grep 49777 | grep yule >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 3 ${MAXTEST} "Client/server w/mysql";
+ else
+ NSOCK=`netstat -pand 2>/dev/null | grep STREAM | grep yule | wc -l`
+ if [ $NSOCK -ne 2 ]; then
+ [ -z "$quiet" ] && log_fail 3 ${MAXTEST} "Three sockets open";
+ netstat -pand 2>/dev/null | grep yule
+ else
+ [ -z "$quiet" ] && log_ok 3 ${MAXTEST} "Three sockets open";
+ fi
+ fi
+ PID=`cat .samhain_lock`
+ kill $PID
+ else
+ log_fail 3 ${MAXTEST} "Three sockets open";
+ fi
+ #
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+ #
+ GPG=`find_path gpg`
+ if [ -z "$GPG" ]; then
+ log_skip 4 $MAXTEST 'gpg not found in $PATH'
+ else
+ eval "$GPG" --list-keys 0F571F6C >/dev/null 2>/dev/null
+ if [ $? -ne 0 ]; then
+ log_skip 4 $MAXTEST 'public PGP key 0x0F571F6C not present'
+ else
+ testrun_threesockets "$GPG"
+ #
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+ #
+ if [ -f ./yule ]; then
+ ./yule -D --set-database-severity=warn >/dev/null 2>>test_log
+ five_sec_sleep
+ netstat -pant 2>/dev/null | grep 49777 | grep yule >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 4 ${MAXTEST} "Three sockets open (gpg) - 1";
+ else
+ NSOCK=`netstat -pand 2>/dev/null | grep STREAM | grep yule | wc -l`
+ if [ $NSOCK -ne 2 ]; then
+ [ -z "$quiet" ] && log_fail 4 ${MAXTEST} "Three sockets open (gpg) - 2";
+ netstat -pand 2>/dev/null | grep yule
+ else
+ [ -z "$quiet" ] && log_ok 4 ${MAXTEST} "Three sockets open (gpg)";
+ fi
+ fi
+ PID=`cat .samhain_lock`
+ kill $PID
+ else
+ log_fail 4 ${MAXTEST} "Three sockets open (gpg) - 3";
+ fi
+ fi
+ fi
+ #
+ if [ -n "$cleanup" ]; then
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ ALTHOST=`find_hostname`
+ rm -f "./file.${ALTHOST}"
+ rm -f "./rc.${ALTHOST}"
+ fi
+ #
+ log_end "RUN FULL CLIENT/SERVER W/MYSQL"
+}
+
diff --git a/test/testrun_2d.sh b/test/testrun_2d.sh
new file mode 100755
index 0000000..bfdcb1a
--- /dev/null
+++ b/test/testrun_2d.sh
@@ -0,0 +1,143 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-xml-log --enable-debug --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --with-database=postgresql"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --enable-network=client --disable-mail --disable-external-scripts --enable-login-watch --enable-xml-log --enable-db-reload --with-logserver=localhost --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock"; export CLIENT_BUILDOPTS
+
+create_pgpass () {
+touch ~/.pgpass
+chmod 600 ~/.pgpass
+cat > ~/.pgpass << EOF
+localhost:*:samhain:samhain:samhain
+EOF
+}
+
+check_psql_log () {
+ DATE="$1"
+
+ rm -f test_log_db
+ # PGPASSWORD=samhain; export PGPASSWORD
+ create_pgpass
+ psql -o test_log_db -U samhain -d samhain -c "SELECT * FROM log WHERE entry_status = 'NEW' and log_time > '${DATE}';"
+ #
+ egrep "START.*Yule" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server start (psql)";
+ return 1
+ fi
+ egrep "NEW CLIENT" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client connect (psql)";
+ return 1
+ fi
+ egrep "Checking.*/bin" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (psql)";
+ return 1
+ fi
+ egrep "EXIT.*Samhain" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client exit (psql)";
+ return 1
+ fi
+ egrep "EXIT.*Yule.*SIGTERM" test_log_db >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Server exit (psql)";
+ return 1
+ fi
+ return 0
+}
+
+MAXTEST=1; export MAXTEST
+
+testrun2d ()
+{
+ log_start "RUN FULL CLIENT/SERVER W/POSTGRESQL"
+ #
+ if [ -z "$doall" ]; then
+ log_skip 1 $MAXTEST 'Client/server w/postgresql (or use --really-all)'
+ return 0
+ fi
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ PSQL=`find_path psql`
+ if [ -z "$PSQL" ]; then
+ log_skip 1 $MAXTEST "psql not found";
+ return 1
+ else
+ # PGPASSWORD="samhain"; export PGPASSWORD
+ create_pgpass
+ TEST=`psql -U samhain -d samhain -c "SELECT * FROM log LIMIT 1;" 2>/dev/null`
+ if [ $? -ne 0 -o -z "$TEST" ]; then
+ log_skip 1 $MAXTEST "psql not default setup"
+ return 1
+ fi
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+ DATE=`date '+%Y-%m-%d %T'`
+ #
+ testrun2a_internal
+ #
+ for ff in ./rc.*; do
+ ORIGINAL="SetUdpActive=no"
+ REPLACEMENT="ReportCheckflags=yes"
+ ex -s rc.morrigan.localdomain <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+ done
+ #
+ ORIGINAL="DatabaseSeverity=none"
+ REPLACEMENT="DatabaseSeverity=info"
+ ex -s $RCFILE <<EOF
+%s/$ORIGINAL/$REPLACEMENT/g
+wq
+EOF
+ #
+ do_test_1_a
+ #
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client/server w/postgresql";
+ else
+ #
+ check_psql_log "${DATE}"
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Client/server w/postgresql";
+ else
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Client/server w/postgresql";
+ fi
+ fi
+ #
+ if [ -n "$cleanup" ]; then
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ ALTHOST=`find_hostname`
+ rm -f "./file.${ALTHOST}"
+ rm -f "./rc.${ALTHOST}"
+ fi
+ #
+ log_end "RUN FULL CLIENT/SERVER W/POSTGRESQL"
+}
+
diff --git a/test/testrun_2e.sh b/test/testrun_2e.sh
new file mode 100755
index 0000000..8ded476
--- /dev/null
+++ b/test/testrun_2e.sh
@@ -0,0 +1,299 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --enable-debug=gdb"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --enable-network=client --enable-srp --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$RCFILE --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --enable-debug"; export CLIENT_BUILDOPTS
+
+do_test_2_e () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+ rm -f test_log_valgrind
+
+ # SetSocketAllowUid=$(id -u)
+ #
+ if test -f /usr/xpg4/bin/id; then
+ MY_ID=$(/usr/xpg4/bin/id -u)
+ else
+ MY_ID=$(id -u)
+ fi
+ #
+ sed -i -e "s/SetSocketAllowUid=0/SetSocketAllowUid=${MY_ID}/g" $RCFILE
+
+ # Start server
+ #
+ ${VALGRIND} ./yule -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+ ./yulectl -c LIST >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (1)";
+ kill $PROC_Y
+ return 1
+ fi
+ NR=$( ./yulectl -c LIST | wc -l )
+ if [ $NR -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (2)";
+ kill $PROC_Y
+ return 1
+ fi
+
+ ./yulectl -c SCAN localhost.localdomain
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c SCAN";
+ kill $PROC_Y
+ return 1
+ fi
+
+ UUID=$(uuidgen)
+ ./yulectl -c DELTA:$UUID localhost.localdomain
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c DELTA:$UUID";
+ kill $PROC_Y
+ return 1
+ fi
+
+ ./yulectl -c RELOAD localhost.localdomain
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c RELOAD";
+ kill $PROC_Y
+ return 1
+ fi
+
+ ./yulectl -c LIST >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (3)";
+ kill $PROC_Y
+ return 1
+ fi
+ NR=$( ./yulectl -c LIST | wc -l )
+ if [ $NR -ne 3 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (4)";
+ kill $PROC_Y
+ return 1
+ fi
+
+ { ./yulectl -c LIST | head -n 1 | grep SCAN; } >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (5)";
+ kill $PROC_Y
+ return 1
+ fi
+ { ./yulectl -c LIST | tail -n 1 | grep RELOAD; } >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (6)";
+ kill $PROC_Y
+ return 1
+ fi
+ { ./yulectl -c LIST | tail -n 2 | head -n 1| grep "DELTA:$UUID"; } >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (7)";
+ kill $PROC_Y
+ return 1
+ fi
+
+ ./yulectl -c CANCEL localhost.localdomain
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c CANCEL";
+ kill $PROC_Y
+ return 1
+ fi
+
+ ./yulectl -c LIST >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (8)";
+ kill $PROC_Y
+ return 1
+ fi
+ NR=$( ./yulectl -c LIST | wc -l )
+ if [ $NR -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "./yulectl -c LIST (9)";
+ kill $PROC_Y
+ return 1
+ fi
+
+ kill $PROC_Y
+ return 0
+}
+
+testrun2e_internal ()
+{
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE;
+ echo;
+ }
+ #
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure ${CLIENT_BUILDOPTS}
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # save binary and build server
+ #
+ cp samhain samhain.build || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure ${SERVER_BUILDOPTS}
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+
+ #####################################################################
+ #
+ #
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ rm -f "./rc.${ALTHOST}"
+ rm -f "./file.${ALTHOST}"
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+
+ ./samhain.build -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ # Create a password
+
+ SHPW=`./yule -G`
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ # Set in client
+
+ ./samhain_setpwd samhain.build new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd samhain.build new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd samhain.build new $SHPW";
+ return 1
+ fi
+
+ mv samhain.build.new samhain.new || return 1
+
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock
+
+ SHCLT=`./yule -P $SHPW`
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "yule -P $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "yule -P $SHPW";
+ return 1
+ fi
+
+ SHCLT1=`echo "${SHCLT}" | sed s%HOSTNAME%${SH_LOCALHOST}%`
+ AHOST=`find_hostname`
+ SHCLT2=`echo "${SHCLT}" | sed s%HOSTNAME%${AHOST}%`
+
+ echo $SHCLT1 >> testrc_2
+ echo $SHCLT2 >> testrc_2
+
+ cp ./testrc_2 ./rc.${SH_LOCALHOST}
+ mv ./.samhain_file ./file.${SH_LOCALHOST}
+ chmod 644 ./rc.${SH_LOCALHOST}
+ chmod 644 ./file.${SH_LOCALHOST}
+
+ ALTHOST=`find_hostname`
+ cp ./testrc_2 "./rc.${ALTHOST}"
+ cp ./file.${SH_LOCALHOST} "./file.${ALTHOST}" 2>/dev/null
+ chmod 644 ./rc.${ALTHOST}
+ chmod 644 ./file.${ALTHOST}
+
+ echo $SHPW > ./testpw
+}
+
+MAXTEST=1; export MAXTEST
+
+testrun2e ()
+{
+ log_start "RUN SERVER W/YULECTL";
+ #
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+ testrun2e_internal
+ do_test_2_e
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Server w/yulectl";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Server w/yulectl";
+ fi
+ ####### EXIT HERE FOR TESTING ######
+ #
+ #
+ log_end "RUN SERVER W/YULECTL"
+}
diff --git a/test/testrun_2f.sh b/test/testrun_2f.sh
new file mode 100755
index 0000000..b9b4ed4
--- /dev/null
+++ b/test/testrun_2f.sh
@@ -0,0 +1,390 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --enable-debug=gdb"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --enable-network=client --enable-srp --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$RCFILE --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --enable-debug"; export CLIENT_BUILDOPTS
+
+do_test_2_f () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+ rm -f test_log_valgrind
+
+ # SetSocketAllowUid=$(id -u)
+ #
+ if test -f /usr/xpg4/bin/id; then
+ MY_ID=$(/usr/xpg4/bin/id -u)
+ else
+ MY_ID=$(id -u)
+ fi
+ #
+ sed -i -e "s/SetSocketAllowUid=0/SetSocketAllowUid=${MY_ID}/g" $RCFILE
+
+ # Start server
+ #
+ ${VALGRIND} ./yule -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -t check --foreground --forever .. &";
+ echo;
+ }
+ ${VALGRIND} ./samhain.new -t check -D -p none -l none -e info --bind-address=127.0.0.1 --server-host=localhost >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "starting samhain.new";
+ else
+ [ -z "$quiet" ] && log_msg_fail "starting samhain.new";
+ kill $PROC_Y
+ return 1
+ fi
+ five_sec_sleep
+ PROC_S=$( ps aux | grep samhain.new | grep -v grep | awk '{ print $2; }' )
+
+ for ff in 1 2; do
+ five_sec_sleep
+ done
+ egrep "File check completed" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (1)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ #
+ # >>> (1) Send SIGTTOU to force a second scan,
+ # >>> and verify that it was done
+ #
+ kill -TTOU $PROC_S
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Kill -TTOU";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ for ff in 1 2; do
+ five_sec_sleep
+ done
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "sigttou";
+
+ NR=$( egrep "POLICY" $LOGFILE | wc -l )
+ if [ $NR -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (3)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ #
+ # >>> (2) Modify the file system
+ #
+
+ UUID=$(uuidgen)
+ mkdir /tmp/testrun_samhain/$UUID
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "mkdir";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ kill -TTOU $PROC_S
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Kill -TTOU (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ for ff in 1 2; do
+ five_sec_sleep
+ done
+ NR=$( egrep "POLICY" $LOGFILE | wc -l )
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (4)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "/tmp/testrun_samhain modified";
+
+ kill $PROC_S;
+ five_sec_sleep
+
+ rm -f ./.samhain_file
+ rm -f ./file.${SH_LOCALHOST}
+ rm -f "./file.${ALTHOST}"
+
+ rm ./.samhain_log
+ rm -f ./.samhain_lock
+
+ #
+ # >>> (3) Re-init the database
+ #
+ ./samhain.new -t init -p none
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "init (2) ..";
+ kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "init (2) ..";
+
+ #
+ # >>> (4) Re-start Samhain with delay
+ #
+
+ sed --in-place -e 's/SetUdpActive=no/StartupLoadDelay=10/g' ./rc.${SH_LOCALHOST}
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "sed (1) ..";
+ kill $PROC_Y;
+ return 1
+ fi
+ sed --in-place -e 's/SetUdpActive=no/StartupLoadDelay=10/g' "./rc.${ALTHOST}"
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "sed (2) ..";
+ kill $PROC_Y;
+ return 1
+ fi
+
+ ${VALGRIND} ./samhain.new -t check -D -p none -l none -e info --bind-address=127.0.0.1 --server-host=localhost >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "starting samhain.new (2)";
+ else
+ [ -z "$quiet" ] && log_msg_fail "starting samhain.new (2)";
+ kill $PROC_Y
+ return 1
+ fi
+ five_sec_sleep
+ PROC_S=$( ps aux | grep samhain.new | grep -v grep | awk '{ print $2; }' )
+
+ #
+ # >>> (5) Copy database to server after Samhain startup
+ # >>> verifies that StartupLoadDelay works
+ #
+
+ if test -f ./.samhain_file; then
+ mv ./.samhain_file ./file.${SH_LOCALHOST}
+ chmod 644 ./file.${SH_LOCALHOST}
+
+ ALTHOST=`find_hostname`
+ cp ./file.${SH_LOCALHOST} "./file.${ALTHOST}" 2>/dev/null
+ chmod 644 ./file.${ALTHOST}
+ else
+ [ -z "$verbose" ] || log_msg_fail "baseline file ..";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ for ff in 1 2 3; do
+ five_sec_sleep
+ done
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (5)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "file check after delay";
+
+ NR=$( egrep "POLICY" $LOGFILE | wc -l )
+ if [ $NR -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (6)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ kill $PROC_S;
+ kill $PROC_Y
+ return 0
+}
+
+testrun2f_internal ()
+{
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE;
+ echo;
+ }
+ #
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure ${CLIENT_BUILDOPTS}
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # save binary and build server
+ #
+ cp samhain samhain.build || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure ${SERVER_BUILDOPTS}
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+
+ #####################################################################
+ #
+ #
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./file.${SH_LOCALHOST}
+ rm -f "./rc.${ALTHOST}"
+ rm -f "./file.${ALTHOST}"
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+
+ sed --in-place -e 's,file = /tmp,file = /tmp/testrun_samhain,g' testrc_2
+ mkdir /tmp/testrun_samhain 2>/dev/null
+
+ ./samhain.build -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ # Create a password
+
+ SHPW=`./yule -G`
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ # Set in client
+
+ ./samhain_setpwd samhain.build new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd samhain.build new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd samhain.build new $SHPW";
+ return 1
+ fi
+
+ mv samhain.build.new samhain.new || return 1
+
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock
+
+ SHCLT=`./yule -P $SHPW`
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "yule -P $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "yule -P $SHPW";
+ return 1
+ fi
+
+ SHCLT1=`echo "${SHCLT}" | sed s%HOSTNAME%${SH_LOCALHOST}%`
+ AHOST=`find_hostname`
+ SHCLT2=`echo "${SHCLT}" | sed s%HOSTNAME%${AHOST}%`
+
+ echo $SHCLT1 >> testrc_2
+ echo $SHCLT2 >> testrc_2
+
+ cp ./testrc_2 ./rc.${SH_LOCALHOST}
+ mv ./.samhain_file ./file.${SH_LOCALHOST}
+ chmod 644 ./rc.${SH_LOCALHOST}
+ chmod 644 ./file.${SH_LOCALHOST}
+
+ ALTHOST=`find_hostname`
+ cp ./testrc_2 "./rc.${ALTHOST}"
+ cp ./file.${SH_LOCALHOST} "./file.${ALTHOST}" 2>/dev/null
+ chmod 644 ./rc.${ALTHOST}
+ chmod 644 ./file.${ALTHOST}
+
+ echo $SHPW > ./testpw
+}
+
+MAXTEST=1; export MAXTEST
+
+testrun2f ()
+{
+ log_start "RUN CLIENT/SERVER CASE ONE";
+ #
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+ testrun2f_internal
+ do_test_2_f
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Case One Change Management Integration";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Case One Change Management Integration";
+ fi
+ #
+ log_end "RUN CLIENT/SERVER CASE ONE"
+}
diff --git a/test/testrun_2g.sh b/test/testrun_2g.sh
new file mode 100755
index 0000000..dadbba6
--- /dev/null
+++ b/test/testrun_2g.sh
@@ -0,0 +1,820 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2015)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+RCFILE="$PW_DIR/testrc_2"; export RCFILE
+
+SERVER_BUILDOPTS="--quiet $TRUST --enable-network=server --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$PW_DIR/testrc_2 --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-logserver=${SH_LOCALHOST} --with-log-file=$PW_DIR/.samhain_log --with-pid-file=$PW_DIR/.samhain_lock --enable-debug=gdb --enable-static"; export SERVER_BUILDOPTS
+
+CLIENT_BUILDOPTS="--quiet $TRUST --enable-network=client --enable-srp --prefix=$PW_DIR --with-tmp-dir=$PW_DIR --localstatedir=$PW_DIR --with-config-file=REQ_FROM_SERVER$RCFILE --with-data-file=REQ_FROM_SERVER$PW_DIR/.samhain_file --with-log-file=$LOGFILE --with-pid-file=$PW_DIR/.samhain_lock --enable-static"; export CLIENT_BUILDOPTS
+
+TEST_DIRS="one two three four"
+TEST_FILES="change leave rmthis"
+BASE="/tmp/testrun_samhain"
+
+TEST_LIST="./tmp_list_file"
+
+ALTHOST=`find_hostname`
+
+PROC_S=0; export PROC_S
+PROC_Y=0; export PROC_Y
+
+mod_files ()
+{
+ rm -f "${TEST_LIST}"
+ touch "${TEST_LIST}"
+ #
+ for dd in ${TEST_DIRS}; do
+ echo "changed" > "${BASE}/$dd/change"
+ rm -f "${BASE}/$dd/rmthis"
+ echo "added" > "${BASE}/$dd/addedthis"
+ echo "${BASE}/$dd" >> "${TEST_LIST}"
+ echo "${BASE}/$dd/change" >> "${TEST_LIST}"
+ echo "${BASE}/$dd/rmthis" >> "${TEST_LIST}"
+ echo "${BASE}/$dd/addedthis" >> "${TEST_LIST}"
+ done
+}
+
+do_test_2_g_yule_start () {
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Server${E}: ./yule -l info -p none &";
+ echo;
+ }
+ rm -f test_log_valgrind
+
+ # SetSocketAllowUid=$(id -u)
+ #
+ if test -f /usr/xpg4/bin/id; then
+ MY_ID=$(/usr/xpg4/bin/id -u)
+ else
+ MY_ID=$(id -u)
+ fi
+ #
+ sed -i -e "s/SetSocketAllowUid=0/SetSocketAllowUid=${MY_ID}/g" $RCFILE
+
+ # Start server
+ #
+ ${VALGRIND} ./yule -l info -p none >/dev/null 2>>test_log_valgrind &
+ PROC_Y=$!
+ five_sec_sleep
+
+
+ [ -z "$verbose" ] || {
+ echo;
+ echo "${S}Start Client${E}: ./samhain.new -t check -D .. &";
+ echo;
+ }
+ ${VALGRIND} ./samhain.new -t check -D -p none -l none -e info --bind-address=127.0.0.1 --server-host=localhost >/dev/null 2>>test_log_valgrind
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "starting samhain.new";
+ else
+ [ -z "$quiet" ] && log_msg_fail "starting samhain.new";
+ kill $PROC_Y
+ return 1
+ fi
+ five_sec_sleep
+ PROC_S=$( ps aux | grep samhain.new | grep -v grep | awk '{ print $2; }' )
+
+ for ff in 1 2; do
+ five_sec_sleep
+ done
+ egrep "File check completed" $LOGFILE >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (1)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ return 0
+}
+
+do_test_2_g_two () {
+
+ #
+ # >>> Modify files
+ #
+ mod_files
+ #
+ if ! test -f ${TEST_LIST}; then
+ [ -z "$verbose" ] || log_msg_fail "No file list created";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ #
+ #
+ # >>> Trigger a scan
+ #
+ kill -TTOU $PROC_S
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Kill -TTOU";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ for ff in 1 2 3; do
+ five_sec_sleep
+ done
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "sigttou";
+
+ NR=$( egrep "POLICY" $LOGFILE | grep ReadOnly | wc -l )
+ if [ $NR -ne 8 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (ReadOnly)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ NR=$( egrep "POLICY" $LOGFILE | grep ADDED | wc -l )
+ if [ $NR -ne 4 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (added)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ NR=$( egrep "POLICY" $LOGFILE | grep MISSING | wc -l )
+ if [ $NR -ne 4 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (removed)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ kill $PROC_S;
+ kill $PROC_Y;
+ return 0
+}
+
+do_test_2_g_one () {
+
+ #
+ # >>> (1) Modify files, create DeltaDB from file list in ${TEST_LIST}
+ #
+ mod_files
+ #
+ if ! test -f ${TEST_LIST}; then
+ [ -z "$verbose" ] || log_msg_fail "No file list created";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ #
+ ./samhain.new --outfile ./file.delta --create-database "${TEST_LIST}"
+ #
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Create DeltaDB";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ if ! test -f ./file.delta; then
+ [ -z "$verbose" ] || log_msg_fail "No DeltaDB created";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ #
+ # >>> (2) Copy to server and tag with a UUID
+ #
+ UUID=$(uuidgen)
+ mv ./file.delta file.${SH_LOCALHOST}.${UUID}
+ cp file.${SH_LOCALHOST}.${UUID} "./file.${ALTHOST}.${UUID}"
+
+ #
+ # >>> (3) Tell client to load delta database.
+ # >>> testrc_2: timestamps every 10 sec
+ #
+ grep '^SetLoopTime=10$' rc.${SH_LOCALHOST} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "SetLoopTime != 10 in rc.${SH_LOCALHOST}";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ grep '^SetLoopTime=10$' rc.${ALTHOST} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "SetLoopTime != 10 in rc.${ALTHOST}";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ ./yulectl -c "DELTA:${UUID}" ${SH_LOCALHOST}
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (1)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ ./yulectl -c "DELTA:${UUID}" ${ALTHOST}
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ NR=$( ./yulectl -c LIST | grep ${UUID} | grep -v grep | wc -l )
+ if [ $NR -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (3)";
+ [ -z "$verbose" ] || ./yulectl -c LIST
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ # Wait and verify that command has been sent
+ #
+ for tt in 1 2 3 4; do
+ five_sec_sleep
+ done
+ #
+ NR=$( ./yulectl -c LIST | grep ${UUID} | grep -v grep | wc -l )
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (4)";
+ [ -z "$verbose" ] || ./yulectl -c LISTALL
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ #
+ # >>> (4) Trigger a scan
+ #
+ kill -TTOU $PROC_S
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Kill -TTOU";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ for ff in 1 2; do
+ five_sec_sleep
+ done
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "sigttou";
+
+ NR=$( egrep "POLICY" $LOGFILE | wc -l )
+ if [ $NR -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (3)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ # --- The End ---
+
+ kill $PROC_S;
+ kill $PROC_Y
+ return 0
+}
+
+do_test_2_g_three () {
+
+ #
+ # >>> (1) Modify files, create DeltaDB from file list in ${TEST_LIST}
+ #
+ mod_files
+ #
+ if ! test -f ${TEST_LIST}; then
+ [ -z "$verbose" ] || log_msg_fail "No file list created";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ #
+ ./samhain.new --outfile ./file.delta --create-database "${TEST_LIST}"
+ #
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Create DeltaDB";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ if ! test -f ./file.delta; then
+ [ -z "$verbose" ] || log_msg_fail "No DeltaDB created";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ #
+ # >>> (2) Copy to server and tag with a UUID
+ #
+ UUID=$(uuidgen)
+ if [ x"$1" != "xnosig" ]; then
+ scripts/samhainadmin.pl -s ./test/gnupg/ -k 8A0B337A -m E ./file.delta >/dev/null
+ fi
+ if [ x"$1" == "xnodelta" ]; then
+ rm -f ./file.*
+ else
+ mv ./file.delta file.${SH_LOCALHOST}.${UUID}
+ cp file.${SH_LOCALHOST}.${UUID} "./file.${ALTHOST}.${UUID}"
+ fi
+
+ #
+ # >>> (3) Tell client to load delta database.
+ # >>> testrc_2: timestamps every 10 sec
+ #
+ grep '^SetLoopTime=10$' rc.${SH_LOCALHOST} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "SetLoopTime != 10 in rc.${SH_LOCALHOST}";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ grep '^SetLoopTime=10$' rc.${ALTHOST} >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "SetLoopTime != 10 in rc.${ALTHOST}";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ ./yulectl -c "DELTA:${UUID}" ${SH_LOCALHOST}
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (1)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ ./yulectl -c "DELTA:${UUID}" ${ALTHOST}
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ NR=$( ./yulectl -c LIST | grep ${UUID} | grep -v grep | wc -l )
+ if [ $NR -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (3)";
+ [ -z "$verbose" ] || ./yulectl -c LIST
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ # Wait and verify that command has been sent
+ #
+ for tt in 1 2 3 4; do
+ five_sec_sleep
+ done
+ #
+ NR=$( ./yulectl -c LIST | grep ${UUID} | grep -v grep | wc -l )
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "yulectl (4)";
+ [ -z "$verbose" ] || ./yulectl -c LISTALL
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ #
+ # >>> (4) Trigger a scan
+ #
+ kill -TTOU $PROC_S
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Kill -TTOU";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ for ff in 1 2; do
+ five_sec_sleep
+ done
+ if [ x"$1" != x ]; then
+ if [ x"$1" = xnodelta ]; then
+ NR=$( egrep "File download failed" $LOGFILE | wc -l )
+ else
+ NR=$( egrep "No good signature" $LOGFILE | wc -l )
+ fi
+ if [ $NR -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (expected fail)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ else
+ [ -z "$verbose" ] || log_msg_ok "Client file check (expected fail)";
+ kill $PROC_S; kill $PROC_Y;
+ return 0
+ fi
+ fi
+
+ NR=$( egrep "File check completed" $LOGFILE | wc -l )
+ if [ $NR -ne 2 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (2)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+ [ -z "$verbose" ] || log_msg_ok "sigttou";
+
+ NR=$( egrep "POLICY" $LOGFILE | wc -l )
+ if [ $NR -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "Client file check (3)";
+ kill $PROC_S; kill $PROC_Y;
+ return 1
+ fi
+
+ # --- The End ---
+
+ kill $PROC_S;
+ kill $PROC_Y
+ return 0
+}
+
+testrun2g_prepare ()
+{
+ #####################################################################
+ #
+ # Create test area and initialize database
+ #
+ rm -f ./.samhain_file
+ rm -f ./.samhain_log
+ rm -f ./.samhain_lock
+ rm -f ./rc.${SH_LOCALHOST}
+ rm -f ./rc.${ALTHOST}
+ rm -f ./file.*
+ #
+ rm -rf ${BASE}
+ #
+ mkdir ${BASE} 2>/dev/null
+ for dd in ${TEST_DIRS}; do
+ mkdir ${BASE}/$dd
+ for ff in ${TEST_FILES}; do
+ echo "foobar" > ${BASE}/$dd/$ff
+ done
+ done
+ #
+ ./samhain.build -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+}
+
+testrun2g_build ()
+{
+ [ -z "$verbose" ] || {
+ echo;
+ echo Working directory: $PW_DIR; echo MAKE is $MAKE;
+ echo;
+ }
+ #
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building client and server${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean
+ fi
+ #
+ ${TOP_SRCDIR}/configure ${CLIENT_BUILDOPTS} $1 $2 >/dev/null 2>&1
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # save binary and build server
+ #
+ cp samhain samhain.build || return 1
+ $MAKE clean >/dev/null || return 1
+
+ ${TOP_SRCDIR}/configure ${SERVER_BUILDOPTS}
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ # Create a password
+
+ SHPW=`./yule -G`
+ if test x"$SHPW" = x; then
+ [ -z "$quiet" ] && log_msg_fail "password not generated -- aborting"
+ return 1
+ fi
+
+ # Set in client
+
+ ./samhain_setpwd samhain.build new $SHPW >/dev/null
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "./samhain_setpwd samhain.build new $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "./samhain_setpwd samhain.build new $SHPW";
+ return 1
+ fi
+
+ mv samhain.build.new samhain.new || return 1
+
+ rm -f ./.samhain_log*
+ rm -f ./.samhain_lock
+
+ SHCLT=`./yule -P $SHPW`
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "yule -P $SHPW";
+ else
+ [ -z "$quiet" ] && log_msg_fail "yule -P $SHPW";
+ return 1
+ fi
+
+ SHCLT1=`echo "${SHCLT}" | sed s%HOSTNAME%${SH_LOCALHOST}%`
+ AHOST=`find_hostname`
+ SHCLT2=`echo "${SHCLT}" | sed s%HOSTNAME%${AHOST}%`
+
+ cp ${SCRIPTDIR}/testrc_2.in testrc_2
+ #
+ sed --in-place -e 's,file = /tmp,dir = 99/tmp/testrun_samhain,g' testrc_2
+ #
+ sed --in-place -e 's,SetUdpActive=no,ReportCheckflags=yes,g' testrc_2
+ #
+ echo $SHCLT1 >> testrc_2
+ echo $SHCLT2 >> testrc_2
+
+ echo $SHPW > ./testpw
+}
+
+testrun2g_signrc ()
+{
+ scripts/samhainadmin.pl -s ./test/gnupg/ -m R $1 >/dev/null
+ scripts/samhainadmin.pl -s ./test/gnupg/ -k 8A0B337A -m E $1 >/dev/null
+}
+
+testrun2g_signdb ()
+{
+ scripts/samhainadmin.pl -s ./test/gnupg/ -k 8A0B337A -m E ./.samhain_file >/dev/null
+}
+
+copy_rc_db_files ()
+{
+ cp ./testrc_2 ./rc.${SH_LOCALHOST}
+ mv ./.samhain_file ./file.${SH_LOCALHOST}
+ if [ $? -ne 0 ]; then
+ [ -z "$verbose" ] || log_msg_fail "No .samhain_file";
+ return 1
+ fi
+ chmod 644 ./rc.${SH_LOCALHOST}
+ chmod 644 ./file.${SH_LOCALHOST}
+
+ cp ./testrc_2 "./rc.${ALTHOST}"
+ cp ./file.${SH_LOCALHOST} "./file.${ALTHOST}" 2>/dev/null
+ chmod 644 ./rc.${ALTHOST}
+ chmod 644 ./file.${ALTHOST}
+}
+
+MAXTEST=6; export MAXTEST
+
+testrun2g ()
+{
+ log_start "RUN CLIENT/SERVER CASE TWO";
+ #
+ if [ x"$1" = x ]; then
+ [ -z "$quiet" ] && log_msg_fail "Missing hostname"
+ fi
+ #
+ SH_LOCALHOST=$1; export SH_LOCALHOST
+ #
+
+
+ # Test with missing delta
+ #
+ gpg --list-keys | grep 8A0B337A >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "You need to do 'gpg --import test/gnupg/public-key.asc' first"
+ log_skip 1 $MAXTEST 'Case Two w/signed files'
+ else
+ testrun2g_build "--with-gpg=/usr/bin/gpg" "--with-keyid=0x8A0B337A"
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "build..";
+ testrun2g_signrc ./testrc_2
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign rc..";
+ testrun2g_prepare
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "prepare..";
+ testrun2g_signdb
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign db..";
+ copy_rc_db_files
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "copy..";
+ do_test_2_g_yule_start
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "start yule..";
+ do_test_2_g_three nodelta
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Case Two w/missing delta";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Case Two w/missing delta";
+ fi
+ fi
+
+ # Test with unsigned delta
+ #
+ gpg --list-keys | grep 8A0B337A >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "You need to do 'gpg --import test/gnupg/public-key.asc' first"
+ log_skip 1 $MAXTEST 'Case Two w/signed files'
+ else
+ testrun2g_build "--with-gpg=/usr/bin/gpg" "--with-keyid=0x8A0B337A"
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "build..";
+ testrun2g_signrc ./testrc_2
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign rc..";
+ testrun2g_prepare
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "prepare..";
+ testrun2g_signdb
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign db..";
+ copy_rc_db_files
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "copy..";
+ do_test_2_g_yule_start
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "start yule..";
+ do_test_2_g_three nosig
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Case Two w/unsigned delta";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Case Two w/unsigned delta";
+ fi
+ fi
+
+ # Test with signed files, no sig client
+ #
+ gpg --list-keys | grep 8A0B337A >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "You need to do 'gpg --import test/gnupg/public-key.asc' first"
+ log_skip 1 $MAXTEST 'Case Two w/signed files'
+ else
+ testrun2g_build
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "build..";
+ testrun2g_signrc ./testrc_2
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign rc..";
+ testrun2g_prepare
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "prepare..";
+ testrun2g_signdb
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign db..";
+ copy_rc_db_files
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "copy..";
+ do_test_2_g_yule_start
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "start yule..";
+ do_test_2_g_three
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Case Two w/signed files+nosig client";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Case Two w/signed files+nosig client";
+ fi
+ fi
+
+ # Test with signed files
+ #
+ gpg --list-keys | grep 8A0B337A >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "You need to do 'gpg --import test/gnupg/public-key.asc' first"
+ log_skip 1 $MAXTEST 'Case Two w/signed files'
+ else
+ testrun2g_build "--with-gpg=/usr/bin/gpg" "--with-keyid=0x8A0B337A"
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "build..";
+ testrun2g_signrc ./testrc_2
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign rc..";
+ testrun2g_prepare
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "prepare..";
+ testrun2g_signdb
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "sign db..";
+ copy_rc_db_files
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "copy..";
+ do_test_2_g_yule_start
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "start yule..";
+ do_test_2_g_three
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 1 ${MAXTEST} "Case Two w/signed files";
+ else
+ [ -z "$quiet" ] && log_fail 1 ${MAXTEST} "Case Two w/signed files";
+ fi
+ fi
+
+ # Test with non-signed files
+ #
+ testrun2g_build
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "build..";
+ testrun2g_prepare
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "prepare..";
+ copy_rc_db_files
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "copy..";
+ do_test_2_g_yule_start
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "start yule..";
+ do_test_2_g_one
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 2 ${MAXTEST} "Case Two w/unsigned files";
+ else
+ [ -z "$quiet" ] && log_fail 2 ${MAXTEST} "Case Two w/unsigned files";
+ fi
+
+
+
+ #
+ testrun2g_prepare
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "prepare..";
+ copy_rc_db_files
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "copy..";
+ do_test_2_g_yule_start
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$verbose" ] || log_msg_ok "start yule..";
+ do_test_2_g_two
+ fi
+ if [ $? -eq 0 ]; then
+ [ -z "$quiet" ] && log_ok 3 ${MAXTEST} "Case Two w/o delta";
+ else
+ [ -z "$quiet" ] && log_fail 3 ${MAXTEST} "Case Two w/o delta";
+ fi
+
+
+ log_end "RUN CLIENT/SERVER CASE TWO"
+}
diff --git a/test/testtiger.txt b/test/testtiger.txt
new file mode 100644
index 0000000..17e11d0
--- /dev/null
+++ b/test/testtiger.txt
@@ -0,0 +1,13 @@
+Test results of the TIGER hash algorithm
+
+(use samhain -H string to test)
+
+string=<>, hash=<24F0130C63AC933216166E76B1BB925FF373DE2D49584E7A>
+string=<abc>, hash=<F258C1E88414AB2A527AB541FFC5B8BF935F7B951C132951>
+string=<Tiger>, hash=<9F00F599072300DD276ABB38C8EB6DEC37790C116F9D2BDF>
+string=<ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+->, hash=<87FB2A9083851CF7470D2CF810E6DF9EB586445034A5A386>
+string=<ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789>, hash=<467DB80863EBCE488DF1CD1261655DE957896565975F9197>
+string=<Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham>, hash=<0C410A042968868A1671DA5A3FD29A725EC1E457D3CDB303>
+string=<Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.>, hash=<EBF591D5AFA655CE7F22894FF87F54AC89C811B6B0DA3193>
+string=<Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.>, hash=<3D9AEB03D1BD1A6357B2774DFD6D5B24DD68151D503974FC>
+string=<ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+->, hash=<00B83EB4E53440C576AC6AAEE0A7485825FD15E70A59FFE4>
diff --git a/test/testtimesrv.sh b/test/testtimesrv.sh
new file mode 100755
index 0000000..beff051
--- /dev/null
+++ b/test/testtimesrv.sh
@@ -0,0 +1,424 @@
+#! /bin/sh
+
+#
+# Copyright Rainer Wichmann (2006)
+#
+# License Information:
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+RCFILE="$PW_DIR/testrc_1.dyn"; export RCFILE
+LOGFILE="$PW_DIR/.samhain_log"; export LOGFILE
+PIDFILE="$PW_DIR/.samhain_lock"; export PIDFILE
+
+BASE="${PW_DIR}/testrun_testdata"; export BASE
+TDIRS="a b c a/a a/b a/c a/a/a a/a/b a/a/c a/a/a/a a/a/a/b a/a/a/c"; export TDIRS
+TFILES="x y z"; export TFILES
+
+prep_testdata ()
+{
+ if test -d "$BASE"; then
+ chmod -f -R 0700 "${BASE}" || {
+ [ -z "$quiet" ] && log_msg_fail "chmod -f -R 0700 ${BASE}";
+ return 1;
+ }
+ fi
+
+ rm -rf "${BASE}" || {
+ [ -z "$quiet" ] && log_msg_fail "rm -rf ${BASE}";
+ return 1;
+ }
+
+ mkdir "${BASE}" || {
+ [ -z "$quiet" ] && log_msg_fail "mkdir ${BASE}";
+ return 1;
+ }
+
+ for ff in $TDIRS; do
+ mkdir "${BASE}/${ff}" || {
+ [ -z "$quiet" ] && log_msg_fail "mkdir ${BASE}/${ff}";
+ return 1;
+ }
+ chmod 0755 "${BASE}/${ff}"
+ for gg in $TFILES; do
+ echo "This is a test file" > "${BASE}/${ff}/${gg}"
+ chmod 0644 "${BASE}/${ff}/${gg}"
+ done
+ done
+}
+
+mkconfig_misc ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ cat >> "${RCFILE}" <<End-of-data
+[Misc]
+Daemon=no
+SetFilecheckTime=60
+TrustedUser=uucp,fax,fnet
+SetRecursionLevel=10
+SetLoopTime=30
+ReportFullDetail = no
+ChecksumTest=check
+
+End-of-data
+}
+
+mkconfig_log ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ cat >> "${RCFILE}" <<End-of-data
+[Log]
+MailSeverity=none
+LogSeverity=warn
+SyslogSeverity=none
+PrintSeverity=info
+MailSeverity=none
+#Restrict to certain classes of messages
+#LogClass=RUN
+#PreludeSeverity=err
+#ExportSeverity=none
+
+End-of-data
+}
+
+mkconfig_sev ()
+{
+ test -f "${RCFILE}" || touch "${RCFILE}"
+ cat >> "${RCFILE}" <<End-of-data
+[EventSeverity]
+SeverityUser0=crit
+SeverityUser1=crit
+SeverityReadOnly=crit
+SeverityLogFiles=crit
+SeverityGrowingLogs=crit
+SeverityIgnoreNone=crit
+SeverityAttributes=crit
+SeverityIgnoreAll=crit
+SeverityFiles=err
+SeverityDirs=err
+SeverityNames=warn
+
+End-of-data
+}
+
+prep_init ()
+{
+ rm -f ./.samhain_file
+ rm -f "${LOGFILE}"
+ rm -f ./.samhain_lock
+
+ rm -f "${RCFILE}"
+ mkconfig_sev
+ mkconfig_log
+ mkconfig_misc
+}
+
+TESTPOLICY="
+[ReadOnly]
+dir=${BASE}/c
+[Attributes]
+dir=${BASE}/a
+#dir=${BASE}/b
+"
+
+
+testtime0_int ()
+{
+ [ -z "$verbose" ] || echo Working directory: $PW_DIR
+ [ -z "$verbose" ] || { echo MAKE is $MAKE; echo; }
+ #
+ # standalone compilation
+ #
+ [ -z "$verbose" ] || { echo; echo "${S}Building standalone agent${E}"; echo; }
+ #
+ if test -r "Makefile"; then
+ $MAKE distclean >/dev/null
+ fi
+ #
+ ${TOP_SRCDIR}/configure --quiet --enable-debug --enable-xml-log --prefix=$PW_DIR --localstatedir=$PW_DIR --with-config-file=$RCFILE --with-log-file=$LOGFILE --with-pid-file=$PIDFILE --with-data-file=$PW_DIR/.samhain_file
+ #
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "configure...";
+ $MAKE > /dev/null 2>>test_log
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "make...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "make...";
+ return 1
+ fi
+ else
+ [ -z "$quiet" ] && log_msg_fail "configure...";
+ return 1
+ fi
+
+ prep_init && prep_testdata && echo "$TESTPOLICY" >>$RCFILE
+ if [ $? -ne 0 ]; then
+ [ -z "$quiet" ] && log_msg_fail "prepare...";
+ return 1
+ fi
+
+ ./samhain -t init -p none
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "init...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "init...";
+ return 1
+ fi
+
+ chmod 0555 "${BASE}/a/x"
+ chmod 0555 "${BASE}/b/x"
+
+ ./samhain -t check -p none -l info -D
+
+ count=0
+ until [ -f $PIDFILE ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ break;
+ fi
+ done
+
+ if test x$? = x0; then
+ [ -z "$verbose" ] || log_msg_ok "start daemon...";
+ else
+ [ -z "$quiet" ] && log_msg_fail "start daemon...";
+ return 1
+ fi
+
+ return 0
+}
+
+MAXTEST=14; export MAXTEST
+
+die () {
+ test -z "$stoponerr" && return 0;
+ PID=`cat $PIDFILE`
+ kill -9 $PID
+}
+
+killdaemon () {
+ if [ -f $PIDFILE ]; then
+ PID=`cat $PIDFILE`
+ kill -9 $PID
+ fi
+}
+
+check_err () {
+ if [ ${2} -ne 0 ]; then
+ die;
+ [ -z "$quiet" ] && log_fail ${1} ${MAXTEST} "${3}";
+ return 1
+ else
+ [ -z "$quiet" ] && log_ok ${1} ${MAXTEST} "${3}";
+ fi
+}
+
+daemontest_started () {
+ PID=`cat $PIDFILE`
+
+ kill -0 $PID
+ check_err ${1} $? "started"
+}
+
+daemontest_sigterm () {
+ PID=`cat $PIDFILE`
+
+ kill -15 $PID
+ count=0
+ while [ `kill -0 $PID` ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ check_err ${1} 1 "sigterm"
+ return 1
+ fi
+ done
+ check_err ${1} 0 "sigterm"
+}
+
+daemontest_sigusr2 () {
+ PID=`cat $PIDFILE`
+
+ tmp=`grep 'File check completed' $LOGFILE | wc -l`
+ kill -USR2 $PID
+ kill -TTOU $PID
+
+ count=0
+ tmp2=`grep 'SUSPEND' $LOGFILE | wc -l`
+ while [ $tmp2 -ne $2 ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ check_err ${1} 1 "sigusr2: suspend"
+ return 1
+ fi
+ tmp2=`grep 'SUSPEND' $LOGFILE | wc -l`
+ done
+
+ kill -USR2 $PID
+
+ count=0
+ tmp2=$tmp
+ while [ $tmp2 -eq $tmp ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ check_err ${1} 1 "sigusr2: wakeup"
+ return 1
+ fi
+ tmp2=`grep 'File check completed' $LOGFILE | wc -l`
+ done
+ check_err ${1} 0 "sigusr2"
+}
+
+daemontest_sigttou () {
+ PID=`cat $PIDFILE`
+
+ tmp=`grep 'File check completed' $LOGFILE | wc -l`
+ kill -TTOU $PID
+ count=0
+ tmp2=$tmp
+ while [ $tmp2 -eq $tmp ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ check_err ${1} 1 "sigttou"
+ return 1
+ fi
+ tmp2=`grep 'File check completed' $LOGFILE | wc -l`
+ done
+ check_err ${1} 0 "sigttou"
+}
+
+daemontest_sighup () {
+
+ if [ $2 -eq 1 ]; then
+ echo "dir=${BASE}/b" >>$RCFILE
+ tmp=`grep CRIT $LOGFILE | grep -v Runtime | wc -l`
+ if [ $tmp -ne 1 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count (before)";
+ return 1
+ fi
+ fi
+
+ PID=`cat $PIDFILE`
+ kill -HUP $PID
+
+ if [ $2 -eq 1 ]; then
+ kill -TTOU $PID
+ count=0
+ tmp=`grep CRIT $LOGFILE | grep -v Runtime | wc -l`
+ while [ $tmp -lt 2 ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ [ -z "$verbose" ] || log_msg_fail "policy count (after)";
+ return 1
+ fi
+ tmp=`grep CRIT $LOGFILE | grep -v Runtime | wc -l`
+ done
+ fi
+
+ count=0
+ tmp2=0
+ while [ $tmp2 -ne $2 ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ check_err ${1} 1 "sighup"
+ return 1
+ fi
+ tmp2=`grep 'Runtime configuration reloaded' $LOGFILE | wc -l`
+ done
+ check_err ${1} 0 "sighup"
+}
+
+daemontest_sigabrt () {
+ PID=`cat $PIDFILE`
+ kill -${3} $PID
+
+ count=0
+ while [ -f $LOGFILE.lock ]; do
+ one_sec_sleep
+ let "count = count + 1" >/dev/null
+ if [ $count -gt 12 ]; then
+ check_err ${1} 1 "sigabrt"
+ return 1
+ fi
+ done
+
+ kill -TTOU $PID
+
+ five_sec_sleep
+
+ if [ -f $LOGFILE.lock ]; then
+ tmp=`grep '<trail>' $LOGFILE | wc -l`
+ tst=$2; let "tst = tst + 2" >/dev/null;
+ if [ $tmp -eq $tst ]; then
+ check_err ${1} 0 "sigabrt"
+ return 0
+ fi
+ fi
+ check_err ${1} 1 "sigabrt"
+}
+
+testtime0 () {
+ log_start "DAEMON CONTROL"
+
+ testtime0_int;
+
+ tcount=1
+
+ trap 'killdaemon' 1 3 15
+
+ daemontest_started $tcount;
+
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigttou $tcount;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigttou $tcount;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigttou $tcount;
+
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigusr2 $tcount 1;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigusr2 $tcount 2;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigusr2 $tcount 3;
+
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigabrt $tcount 1 ABRT;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigabrt $tcount 2 TTIN;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigabrt $tcount 3 ABRT;
+
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sighup $tcount 1;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sighup $tcount 2;
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sighup $tcount 3;
+
+ let "tcount = tcount + 1" >/dev/null
+ daemontest_sigterm $tcount;
+
+ log_end "DAEMON CONTROL"
+}
+
+
diff --git a/yulerc.template b/yulerc.template
new file mode 100644
index 0000000..512bc0d
--- /dev/null
+++ b/yulerc.template
@@ -0,0 +1,336 @@
+#####################################################################
+#
+# Configuration file template for yule.
+#
+#####################################################################
+#
+# NOTE: This is a log server-only configuration file TEMPLATE.
+#
+# NOTE: The log server ('yule') will look for THAT configuration file
+# that has been defined at compile time with the configure option
+# ./configure --with-config-file=FILE
+# The default is "/usr/local/etc/.samhainrc" (NOT "yulerc").
+#
+#####################################################################
+#
+# -- empty lines and lines starting with '#', ';' or '//' are ignored
+# -- you can PGP clearsign this file -- samhain will check (if compiled
+# with support) or otherwise ignore the signature
+# -- CHECK mail address
+#
+# To each log facility, you can assign a threshold severity. Only
+# reports with at least the threshold severity will be logged
+# to the respective facility (even further below).
+#
+#####################################################################
+
+
+[Log]
+##
+## Switch on/OFF log facilities and set their threshold severity
+##
+## Values: debug, info, notice, warn, mark, err, crit, alert, none.
+## 'mark' is used for timestamps.
+##
+##
+## Use 'none' to SWITCH OFF a log facility
+##
+## By default, everything equal to and above the threshold is logged.
+## The specifiers '*', '!', and '=' are interpreted as
+## 'all', 'all but', and 'only', respectively (like syslogd(8) does,
+## at least on Linux). Examples:
+## MailSeverity=*
+## MailSeverity=!warn
+## MailSeverity==crit
+
+## E-mail
+##
+# MailSeverity=none
+
+## Console
+##
+PrintSeverity=none
+
+## Logfile
+##
+LogSeverity = warn
+
+## Syslog
+##
+# SyslogSeverity=none
+
+## External script or program
+##
+# ExternalSeverity = none
+
+## Logging to a database
+##
+# DatabaseSeverity = none
+
+
+# [Database]
+##
+## --- Logging to a relational database
+##
+
+## Database name
+#
+# SetDBName = samhain
+
+## Database table
+#
+# SetDBTable = log
+
+## Database user
+#
+# SetDBUser = samhain
+
+## Database password
+#
+# SetDBPassword = (default: none)
+
+## Database host
+#
+# SetDBHost = localhost
+
+## Log the server timestamp for received messages
+#
+# SetDBServerTstamp = True
+
+## Use a persistent connection
+#
+# UsePersistent = True
+
+
+
+# [External]
+##
+## Interface to call external scripts/programs for logging
+##
+
+## The absolute path to the command
+## - Each invocation of this directive will end the definition of the
+## preceding command, and start the definition of
+## an additional, new command
+#
+# OpenCommand = (no default)
+
+## Type (log or rv)
+## - log for log messages, srv for messages received by the server
+#
+# SetType = log
+
+## The command (full command line) to execute
+#
+# SetCommandLine = (no default)
+
+## The environment (KEY=value; repeat for more)
+#
+# SetEnviron = TZ=(your timezone)
+
+## The TIGER192 checksum (optional)
+#
+# SetChecksum = (no default)
+
+## User who runs the command
+#
+# SetCredentials = (default: samhain process uid)
+
+## Words not allowed in message
+#
+# SetFilterNot = (none)
+
+## Words required (ALL of them)
+#
+# SetFilterAnd = (none)
+
+## Words required (at least one)
+#
+# SetFilterOr = (none)
+
+## Deadtime between consecutive calls
+#
+# SetDeadtime = 0
+
+## Add default environment (HOME, PATH, SHELL)
+#
+# SetDefault = no
+
+
+#####################################################
+#
+# Miscellaneous configuration options
+#
+#####################################################
+
+
+[Misc]
+# whether to become a daemon process
+Daemon=yes
+
+## Interval between time stamp messages
+#
+# SetLoopTime = 60
+SetLoopTime = 600
+
+## Normally, client messages are regarded as data within a
+## server message of fixed severity. The following two
+## options cause the server to use the original severity/class
+## of client messages for logging.
+#
+# UseClientSeverity = False
+# UseClientClass = False
+
+## The maximum time between client messages (seconds)
+## This allows the server to flag clients that have exceeded
+## the timeout limits; i.e. might have died for some reason.
+#
+# SetClientTimeLimit = 86400
+
+## Use client address as known to the communication layer (might be
+## incorrect if the client is behind NAT). The default is to use
+## the client name as claimed by the client, and verify it against
+## the former (might be incorrect if the client has several
+## interfaces, and its hostname resolves to the wrong interface).
+#
+# SetClientFromAccept = False
+
+## If SetClientFromAccept is False (default), severity of a
+## failure to resolve the hostname claimed by the client
+## to the IP address of the socket peer.
+#
+# SeverityLookup = crit
+
+## The console device (can also be a file or named pipe)
+## - There are two console devices. Accordingly, you can use
+## this directive a second time to set the second console device.
+## If you have not defined the second device at compile time,
+## and you don't want to use it, then:
+## setting it to /dev/null is less effective than just leaving
+## it alone (setting to /dev/null will waste time by opening
+## /dev/null and writing to it)
+#
+# SetConsole = /dev/console
+
+## Use separate logfiles for individual clients
+#
+# UseSeparateLogs = False
+
+## Enable listening on port 514/udp for logging of remote syslog
+## messages (if optionally compiled with support for this)
+#
+# SetUDPActive = False
+
+
+## Activate the SysV IPC message queue
+#
+# MessageQueueActive = False
+
+
+## If false, skip reverse lookup when connecting to a host known
+## by name rather than IP address (i.e. trust the DNS)
+#
+# SetReverseLookup = True
+
+## If true, open a Unix domain socket to listen for commands that should
+## be passed to clients upon next connection. Only works on systems
+## that support passing of peer credentials (for authentication) via sockets.
+## Use yulectl to access the socket.
+#
+# SetUseSocket = False
+
+## The UID of the user that is allowed to pass commands to the server
+## via the Unix domain socket.
+#
+# SetSocketAllowUid = 0
+
+## --- E-Mail ---
+
+# Only highest-level (alert) reports will be mailed immediately,
+# others will be queued. Here you can define, when the queue will
+# be flushed (Note: the queue is automatically flushed after
+# completing a file check).
+#
+# SetMailTime = 86400
+
+## Maximum number of mails to queue
+#
+# SetMailNum = 10
+
+## Recipient (max. 8)
+#
+# SetMailAddress=root@localhost
+
+## Mail relay (IP address)
+#
+# SetMailRelay = NULL
+
+## Custom subject format
+#
+# MailSubject = NULL
+
+## --- end E-Mail ---
+
+# The binary. Setting the path will allow
+# samhain to check for modifications between
+# startup and exit.
+#
+# SamhainPath=/usr/local/bin/yule
+
+## The IP address of the time server
+#
+# SetTimeServer = (default: compiled-in)
+
+## Trusted Users (comma delimited list of user names)
+#
+# TrustedUser = (no default; this adds to the compiled-in list)
+
+## Custom format for message header.
+## CAREFUL if you use XML logfile format.
+##
+## %S severity
+## %T timestamp
+## %C class
+##
+## %F source file
+## %L source line
+#
+# MessageHeader="%S %T "
+
+
+## Don't log path to config/database file on startup
+#
+# HideSetup = False
+
+## The syslog facility, if you log to syslog
+#
+# SyslogFacility = LOG_AUTHPRIV
+
+
+## The message authentication method
+## - If you change this, you *must* change it
+## on client *and* server
+#
+# MACType = HMAC-TIGER
+
+
+[Clients]
+##
+## This is a sample registry entry for a client at host 'HOSTNAME'. This entry
+## is valid for the default password.
+## You are STRONGLY ADVISED to reset te password (see the README) and
+## compute your own entries using 'samhain -P <password>'
+##
+## Usually, HOSTNAME should be a fully qualified hostname,
+## no numerical address.
+## -- exception: if the client (samhain) cannot determine the
+## fully qualified hostname of its host,
+## the numerical address may be required.
+## You will know if you get a message like:
+## 'Invalid connection attempt: Not in
+## client list what.ever.it.is'
+##
+## First entry is for challenge/response, second one for SRP authentication.
+#
+# Client=HOSTNAME@00000000@C39F0EEFBC64E4A8BBF72349637CC07577F714B420B62882
+# Client=HOSTNAME@8F81BA58956F8F42@8932D08C49CA76BD843C51EDD1D6640510FA032A7A2403E572BBDA2E5C6B753991CF7E091141D20A2499C5CD3E14C1639D17482E14E1548E5246ACF4E7193D524CDDAC9C9D6A9A36C596B4ECC68BEB0C5BB7082224946FC98E3ADE214EA1343E2DA8DF4229D4D8572AD8679228928A787B6E5390D3A713102FFCC9D0B2188C92