/* 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 #include #include #include #include #include "samhain.h" #include "sh_error.h" #include "sh_getopt.h" #include "sh_files.h" #include "sh_utils.h" #include "sh_mail.h" #include "sh_forward.h" #include "sh_hash.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 { char * longopt; const char shortopt; 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); #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 }, #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_forward_server_port }, #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_forward_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_forward_make_client }, { N_("gen-password"), 'G', N_("Generate a random password"), HAS_ARG_NO, sh_forward_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_("full-detail"), 'a', N_("Modify -d to list full details"), HAS_ARG_NO, set_full_detail}, { N_("delimited"), '-', N_("Modify -d to list full details, comma delimited"), HAS_ARG_NO, set_list_delimited}, { N_("list-database"), 'd', N_("List database content (like ls -l)"), HAS_ARG_YES, sh_hash_list_db}, { N_("init2stdout"), '-', N_("Write database to stdout on init"), HAS_ARG_NO, sh_hash_pushdata_stdout}, #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) && defined(HAVE_LIBPRELUDE_9) /* 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 () { fputs (_("Compiled-in log facilities:"), stdout); #ifndef DEFAULT_CONSOLE printf (_(" console (/dev/console)")); #else if (0 == strcmp (DEFAULT_CONSOLE, _("NULL"))) printf (_(" console (/dev/console)")); else printf (_(" console (%s)"), DEFAULT_CONSOLE); #endif fputs (_(", syslog"), stdout); printf (_(", logfile (%s)"), DEFAULT_ERRFILE); #if defined(WITH_EXTERNAL) fputs (_(", external program"), stdout); #endif #if defined(WITH_MESSAGE_QUEUE) fputs (_(", message queue"), stdout); #endif #if defined(WITH_DATABASE) fputs (_(", database"), stdout); #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) fputs (_(", server"), stdout); #endif #if defined(SH_WITH_MAIL) fputs (_(", email"), stdout); #endif #ifdef HAVE_LIBPRELUDE #ifdef HAVE_LIBPRELUDE_8 fputs (_(", prelude (0.8)"), stdout); #else fputs (_(", prelude (0.9+)"), stdout); #endif #endif fputc ('\n', stdout); return; } static void sh_getopt_print_options () { 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_CLIENT) if (num > 0) fputc ('\n', stdout); printf (_("Server executable (port %d, user %s)"), SH_DEFAULT_PORT, DEFAULT_IDENT); ++num; #endif fputs (_(", compiled-in options:"), stdout); #if defined(HAVE_EGD_RANDOM) if (num > 0) fputc ('\n', stdout); printf (_(" use entropy gathering daemon (%s)"), EGD_SOCKET_NAME); ++num; #endif #if defined(HAVE_UNIX_RANDOM) if (num > 0) fputc ('\n', stdout); fputs (_(" use unix entropy gatherer"), stdout); ++num; #endif #if defined(HAVE_URANDOM) if (num > 0) fputc ('\n', stdout); printf (_(" use 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(SL_DEBUG) if (num > 0) fputc ('\n', stdout); fputs (_(" debug build"), 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 (_(" use time server"), stdout); ++num; #endif #if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) #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 () { #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) int num = 0; fputs (_("Compiled-in modules:"), 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 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, _("This software comes with ABSOLUTELY NO WARRANTY. ")); fprintf (stdout, _("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, _("Copyright (C) 1999-2008 Rainer Wichmann"\ " (http://la-samhna.de).\n\n")); fprintf (stdout, _("This program is free software; "\ "you can redistribute it and/or modify\n")); fprintf (stdout, _("it under the terms of the GNU General "\ "Public License as published by\n")); fprintf (stdout, _("the Free Software Foundation; either version 2 "\ "of the License, or\n")); fprintf (stdout, _("(at your option) any later version.\n\n")); fprintf (stdout, _("This program is distributed in the hope "\ "that it will be useful,\n")); fprintf (stdout, _("but WITHOUT ANY WARRANTY; "\ "without even the implied warranty of\n")); fprintf (stdout, _("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."\ " See the\n")); fprintf (stdout, _("GNU General Public License for more details.\n\n")); fprintf (stdout, _("You should have received a copy of the "\ "GNU General Public License\n")); fprintf (stdout, _("along with this program; "\ "if not, write to the Free Software\n")); fprintf (stdout, _("Foundation, Inc., 59 Temple Place - Suite 330, "\ "Boston, MA 02111-1307, USA.\n\n")); fprintf (stdout, _("This product makes use of the reference implementation "\ "of the TIGER message\n")); fprintf (stdout, _("digest algorithm. This code is copyright Eli Biham "\ "(biham@cs.technion.ac.il)\n")); fprintf (stdout, _("and Ross Anderson (rja14@cl.cam.ac.uk). It can be used "\ "freely without any\n")); fprintf (stdout, _("restrictions.\n")); #if defined(USE_SRP_PROTOCOL) && !defined(SH_STANDALONE) #if (!defined(HAVE_LIBGMP) || !defined(HAVE_GMP_H)) fprintf (stdout, _("This product makes use of the 'bignum' library by "\ "Henrik Johansson\n")); fprintf (stdout, _("(Henrik.Johansson@Nexus.Comm.SE). If you are including "\ "this library in a\n")); fprintf (stdout, _("commercial product, be sure to distribute ALL of"\ " it with the product.\n")); #endif fprintf (stdout, _("This product uses the 'Secure Remote Password' "\ "cryptographic\n")); fprintf (stdout, _("authentication system developed by Tom Wu "\ "(tjw@CS.Stanford.EDU).\n")); #endif fprintf (stdout, _("\nPlease refer to the file COPYING in the source "\ "distribution for a")); fprintf (stdout, _("\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, _("This software comes with ABSOLUTELY NO WARRANTY. ")); fprintf (stdout, _("Use at own risk.\n")); fprintf (stdout, _("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, _("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=,\t\t %s\n"), sizeof(fmt)); else sl_strlcpy(fmt, _("%c%c %s --%-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)); } } fprintf (stdout, _("\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) { dummy = (void *) dummy; SL_ENTER(_("sh_getopt_forever")); sh.flag.loop = S_TRUE; SL_RETURN(0, _("sh_getopt_forever")); } #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, _("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, _("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, _("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, _("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, _("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, _("Error: unrecognized long option\n")); (void) sh_getopt_usage(_("fail")); } } } SL_RETURN( count, _("sh_getopt_get")); }