new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / util / syscheck_control.c
old mode 100755 (executable)
new mode 100644 (file)
index 71c705b..fdf645a
@@ -1,7 +1,4 @@
-/* @(#) $Id: ./src/util/syscheck_control.c, 2011/09/08 dcid Exp $
- */
-
-/* Copyright (C) 2009 Trend Micro Inc.
+/* Copyright (C) 2019 OSSEC Foundation
  * All right reserved.
  *
  * This program is a free software; you can redistribute it
  * Foundation
  */
 
-
 #include "addagent/manage_agents.h"
 #include "sec.h"
 
-
 #undef ARGV0
 #define ARGV0 "syscheck_control"
 
+/* Prototypes */
+static void helpmsg(void) __attribute__((noreturn));
 
-/** help **/
-void helpmsg()
+
+static void helpmsg()
 {
     printf("\nOSSEC HIDS %s: Manages the integrity checking database.\n",
            ARGV0);
     printf("Available options:\n");
     printf("\t-h          This help message.\n");
-    printf("\t-l          List available (active or not) agents.\n");
+    printf("\t-l          List available (active or inactive) agents.\n");
     printf("\t-lc         List only active agents.\n");
-    printf("\t-u <id>     Updates (clear) the database for the agent.\n");
-    printf("\t-u all      Updates (clear) the database for all agents.\n");
+    printf("\t-u <id>     Updates (clears) the database for the agent.\n");
+    printf("\t-u all      Updates (clears) the database for all agents.\n");
     printf("\t-i <id>     List modified files for the agent.\n");
     printf("\t-r -i <id>  List modified registry entries for the agent "
            "(Windows only).\n");
     printf("\t-f <file>   Prints information about a modified file.\n");
-    printf("\t-z          Used with the -f, zeroes the auto-ignore counter.\n");
-    printf("\t-d          Used with the -f, ignores that file.\n");
+    printf("\t            Must be used with -i <id>.\n");
+    printf("\t-z          Used with -f, zeroes the auto-ignore counter.\n");
+    printf("\t-d          Used with -f, ignores that file.\n");
     printf("\t-s          Changes the output to CSV (comma delimited).\n");
+    printf("\t-j          Changes the output to JSON.\n");
+    printf("\n");
+    printf("\tExamples:\n");
+    printf("\n");
+    printf("\t'Show information about /etc/passwd from agent with ID 019'\n");
+    printf("\t%s -i 019 -f /etc/passwd\n", ARGV0);
     exit(1);
 }
 
-
-/** main **/
 int main(int argc, char **argv)
 {
-    char *dir = DEFAULTDIR;
-    char *group = GROUPGLOBAL;
-    char *user = USER;
-    char *agent_id = NULL;
-    char *fname = NULL;
-
-    int gid = 0;
-    int uid = 0;
+    const char *dir = DEFAULTDIR;
+    const char *group = GROUPGLOBAL;
+    const char *user = USER;
+    const char *agent_id = NULL;
+    const char *fname = NULL;
+
+    gid_t gid;
+    uid_t uid;
     int c = 0, info_agent = 0, update_syscheck = 0,
-               list_agents = 0, zero_counter = 0,
-               registry_only = 0;
-    int active_only = 0, csv_output = 0;
+        list_agents = 0, zero_counter = 0,
+        registry_only = 0;
+    int active_only = 0, csv_output = 0, json_output = 0;
 
     char shost[512];
+    cJSON *json_root;
 
-
-
-    /* Setting the name */
+    /* Set the name */
     OS_SetName(ARGV0);
 
-
-    /* user arguments */
-    if(argc < 2)
-    {
+    /* User arguments */
+    if (argc < 2) {
         helpmsg();
     }
 
-
-    while((c = getopt(argc, argv, "VhzrDdlcsu:i:f:")) != -1)
-    {
-        switch(c){
+    while ((c = getopt(argc, argv, "VhzrDdlcsju:i:f:")) != -1) {
+        switch (c) {
             case 'V':
                 print_version();
                 break;
@@ -96,6 +93,9 @@ int main(int argc, char **argv)
             case 's':
                 csv_output = 1;
                 break;
+            case 'j':
+                json_output = 1;
+                break;
             case 'c':
                 active_only++;
                 break;
@@ -104,25 +104,22 @@ int main(int argc, char **argv)
                 break;
             case 'i':
                 info_agent++;
-                if(!optarg)
-                {
-                    merror("%s: -u needs an argument",ARGV0);
+                if (!optarg) {
+                    merror("%s: -u needs an argument", ARGV0);
                     helpmsg();
                 }
                 agent_id = optarg;
                 break;
             case 'f':
-                if(!optarg)
-                {
-                    merror("%s: -u needs an argument",ARGV0);
+                if (!optarg) {
+                    merror("%s: -u needs an argument", ARGV0);
                     helpmsg();
                 }
                 fname = optarg;
                 break;
             case 'u':
-                if(!optarg)
-                {
-                    merror("%s: -u needs an argument",ARGV0);
+                if (!optarg) {
+                    merror("%s: -u needs an argument", ARGV0);
                     helpmsg();
                 }
                 agent_id = optarg;
@@ -132,132 +129,137 @@ int main(int argc, char **argv)
                 helpmsg();
                 break;
         }
-
     }
 
-
-    /* Getting the group name */
+    /* Get the group name */
     gid = Privsep_GetGroup(group);
     uid = Privsep_GetUser(user);
-    if(gid < 0)
-    {
-           ErrorExit(USER_ERROR, ARGV0, user, group);
+    if (uid == (uid_t) - 1 || gid == (gid_t) - 1) {
+        ErrorExit(USER_ERROR, ARGV0, user, group);
     }
 
-
-    /* Setting the group */
-    if(Privsep_SetGroup(gid) < 0)
-    {
-           ErrorExit(SETGID_ERROR,ARGV0, group);
+    /* Set the group */
+    if (Privsep_SetGroup(gid) < 0) {
+        ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
     }
 
-
-    /* Chrooting to the default directory */
-    if(Privsep_Chroot(dir) < 0)
-    {
-        ErrorExit(CHROOT_ERROR, ARGV0, dir);
+    /* Chroot to the default directory */
+    if (Privsep_Chroot(dir) < 0) {
+        ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
     }
 
-
     /* Inside chroot now */
     nowChroot();
 
-
-    /* Setting the user */
-    if(Privsep_SetUser(uid) < 0)
-    {
-        ErrorExit(SETUID_ERROR, ARGV0, user);
+    /* Set the user */
+    if (Privsep_SetUser(uid) < 0) {
+        ErrorExit(SETUID_ERROR, ARGV0, user, errno, strerror(errno));
     }
 
-
-
-    /* Getting servers hostname */
+    /* Get server hostname */
     memset(shost, '\0', 512);
-    if(gethostname(shost, 512 -1) != 0)
-    {
+    if (gethostname(shost, 512 - 1) != 0) {
         strncpy(shost, "localhost", 32);
-        return(0);
+        return (0);
     }
 
-
-
-    /* Listing available agents. */
-    if(list_agents)
-    {
-        if(!csv_output)
-        {
-            printf("\nOSSEC HIDS %s. List of available agents:",
-                    ARGV0);
+    if (json_output)
+        json_root = cJSON_CreateObject();
+
+    /* List available agents */
+    if (list_agents) {
+        cJSON *json_agents = NULL;
+
+        if (json_output) {
+            cJSON *first = cJSON_CreateObject();
+            json_agents = cJSON_CreateArray();
+            cJSON_AddNumberToObject(json_root, "error", 0);
+            cJSON_AddStringToObject(first, "id", "000");
+            cJSON_AddStringToObject(first, "name", shost);
+            cJSON_AddStringToObject(first, "ip", "127.0.0.1");
+            cJSON_AddStringToObject(first, "status", "Active");
+            cJSON_AddItemToArray(json_agents, first);
+        } else if (csv_output)
+            printf("000,%s (server),127.0.0.1,Active/Local,\n", shost);
+        else {
+            printf("\nOSSEC HIDS %s. List of available agents:", ARGV0);
             printf("\n   ID: 000, Name: %s (server), IP: 127.0.0.1, "
                    "Active/Local\n", shost);
         }
-        else
-        {
-            printf("000,%s (server),127.0.0.1,Active/Local,\n", shost);
-        }
-        print_agents(1, active_only, csv_output);
-        printf("\n");
-        exit(0);
-    }
 
+        print_agents(1, active_only, csv_output, json_agents);
 
+        if (json_output) {
+            cJSON_AddItemToObject(json_root, "response", json_agents);
+            printf("%s", cJSON_PrintUnformatted(json_root));
+        } else
+            printf("\n");
 
-    /* Update syscheck database. */
-    if(update_syscheck)
-    {
-        /* Cleaning all agents (and server) db. */
-        if(strcmp(agent_id, "all") == 0)
-        {
+        exit(0);
+    }
+
+    /* Update syscheck database */
+    if (update_syscheck) {
+        /* Clean all agents (and server) db */
+        if (strcmp(agent_id, "all") == 0) {
             DIR *sys_dir;
             struct dirent *entry;
 
             sys_dir = opendir(SYSCHECK_DIR);
-            if(!sys_dir)
-            {
-                ErrorExit("%s: Unable to open: '%s'", ARGV0, SYSCHECK_DIR);
+            if (!sys_dir) {
+                if (json_output) {
+                    char buffer[1024];
+                    cJSON_AddNumberToObject(json_root, "error", 31);
+                    snprintf(buffer, 1023, "%s: Unable to open: '%s'", ARGV0, SYSCHECK_DIR);
+                    cJSON_AddStringToObject(json_root, "description", buffer);
+                    printf("%s", cJSON_PrintUnformatted(json_root));
+                    exit(1);
+                } else
+                    ErrorExit("%s: Unable to open: '%s'", ARGV0, SYSCHECK_DIR);
             }
 
-            while((entry = readdir(sys_dir)) != NULL)
-            {
+            while ((entry = readdir(sys_dir)) != NULL) {
                 FILE *fp;
-                char full_path[OS_MAXSTR +1];
+                char full_path[OS_MAXSTR + 1];
 
                 /* Do not even attempt to delete . and .. :) */
-                if((strcmp(entry->d_name,".") == 0)||
-                   (strcmp(entry->d_name,"..") == 0))
-                {
+                if ((strcmp(entry->d_name, ".") == 0) ||
+                        (strcmp(entry->d_name, "..") == 0)) {
                     continue;
                 }
 
-                snprintf(full_path, OS_MAXSTR,"%s/%s", SYSCHECK_DIR,
+                snprintf(full_path, OS_MAXSTR, "%s/%s", SYSCHECK_DIR,
                          entry->d_name);
 
                 fp = fopen(full_path, "w");
-                if(fp)
-                {
+                if (fp) {
                     fclose(fp);
                 }
-                if(entry->d_name[0] == '.')
-                {
+                if (entry->d_name[0] == '.') {
                     unlink(full_path);
                 }
             }
 
             closedir(sys_dir);
-            printf("\n** Integrity check database updated.\n\n");
+
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddStringToObject(json_root, "response", "Integrity check database updated");
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            } else
+                printf("\n** Integrity check database updated.\n\n");
+
             exit(0);
         }
 
-        else if((strcmp(agent_id, "000") == 0) ||
-                (strcmp(agent_id, "local") == 0))
-        {
+        else if ((strcmp(agent_id, "000") == 0) ||
+                 (strcmp(agent_id, "local") == 0)) {
             char final_dir[1024];
             FILE *fp;
             snprintf(final_dir, 1020, "/%s/syscheck", SYSCHECK_DIR);
 
             fp = fopen(final_dir, "w");
-            if(fp)
-            {
+            if (fp) {
                 fclose(fp);
             }
             unlink(final_dir);
@@ -267,131 +269,153 @@ int main(int argc, char **argv)
             snprintf(final_dir, 1020, "/%s/.syscheck.cpt", SYSCHECK_DIR);
 
             fp = fopen(final_dir, "w");
-            if(fp)
-            {
+            if (fp) {
                 fclose(fp);
             }
             unlink(final_dir);
 
-            printf("\n** Integrity check database updated.\n\n");
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddStringToObject(json_root, "response", "Integrity check database updated");
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            } else
+                printf("\n** Integrity check database updated.\n\n");
+
             exit(0);
         }
 
-        /* Database from remote agents. */
-        else
-        {
+        /* Database from remote agents */
+        else {
             int i;
             keystore keys;
 
             OS_ReadKeys(&keys);
 
             i = OS_IsAllowedID(&keys, agent_id);
-            if(i < 0)
-            {
-                printf("\n** Invalid agent id '%s'.\n", agent_id);
-                helpmsg();
+            if (i < 0) {
+                if (json_output) {
+                    char buffer[1024];
+                    cJSON_AddNumberToObject(json_root, "error", 33);
+                    snprintf(buffer, 1023, "Invalid agent id '%s'.", agent_id);
+                    cJSON_AddStringToObject(json_root, "description", buffer);
+                    printf("%s", cJSON_PrintUnformatted(json_root));
+                    exit(1);
+                } else {
+                    printf("\n** Invalid agent id '%s'.\n", agent_id);
+                    helpmsg();
+                }
             }
 
-            /* Deleting syscheck */
+            /* Delete syscheck */
             delete_syscheck(keys.keyentries[i]->name,
                             keys.keyentries[i]->ip->ip, 0);
 
-            printf("\n** Integrity check database updated.\n\n");
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddStringToObject(json_root, "response", "Integrity check database updated");
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            } else
+                printf("\n** Integrity check database updated.\n\n");
+
             exit(0);
         }
     }
 
-
-    /* Printing information from an agent. */
-    if(info_agent)
-    {
+    /* Print information from an agent */
+    if (info_agent) {
         int i;
-        char final_ip[128 +1];
-        char final_mask[128 +1];
+        char final_ip[IPSIZE + 4];
         keystore keys;
-
-
-        if((strcmp(agent_id, "000") == 0) ||
-           (strcmp(agent_id, "local") == 0))
-        {
-            printf("\nIntegrity checking changes for local system '%s - %s':\n",
-                    shost, "127.0.0.1");
-            if(fname)
-            {
-                printf("Detailed information for entries matching: '%s'\n",
-                       fname);
+        cJSON *json_entries = NULL;
+
+        if (json_output)
+            json_entries = cJSON_CreateArray();
+
+        if ((strcmp(agent_id, "000") == 0) ||
+                (strcmp(agent_id, "local") == 0)) {
+            if (!(csv_output || json_output)) {
+                printf("\nIntegrity checking changes for local system '%s - %s':\n",
+                       shost, "127.0.0.1");
+                if (fname) {
+                    printf("Detailed information for entries matching: '%s'\n",
+                           fname);
+                }
             }
 
-            print_syscheck(NULL,
-                           NULL, fname, 0, 0,
-                           csv_output, zero_counter);
-        }
-        else if(strchr(agent_id, '@'))
-        {
-            if(fname)
-            {
+            print_syscheck(NULL, NULL, fname, 0, 0, csv_output, json_entries, zero_counter);
+        } else if (strchr(agent_id, '@')) {
+            if (fname && ! (csv_output || json_output)) {
                 printf("Detailed information for entries matching: '%s'\n",
                        fname);
             }
             print_syscheck(agent_id, NULL, fname, registry_only, 0,
-                           csv_output, zero_counter);
-        }
-        else
-        {
+                           csv_output, json_entries, zero_counter);
+        } else {
 
             OS_ReadKeys(&keys);
 
             i = OS_IsAllowedID(&keys, agent_id);
-            if(i < 0)
-            {
-                printf("\n** Invalid agent id '%s'.\n", agent_id);
-                helpmsg();
+            if (i < 0) {
+                if (json_output) {
+                    char buffer[1024];
+                    cJSON_AddNumberToObject(json_root, "error", 32);
+                    snprintf(buffer, 1023, "Invalid agent id '%s'.", agent_id);
+                    cJSON_AddStringToObject(json_root, "description", buffer);
+                    printf("%s", cJSON_PrintUnformatted(json_root));
+                    exit(1);
+                } else {
+                    printf("\n** Invalid agent id '%s'.\n", agent_id);
+                    helpmsg();
+                }
             }
 
-            /* Getting netmask from ip. */
-            final_ip[128] = '\0';
-            final_mask[128] = '\0';
-            getNetmask(keys.keyentries[i]->ip->netmask, final_mask, 128);
-            snprintf(final_ip, 128, "%s%s",keys.keyentries[i]->ip->ip,
-                    final_mask);
-
-            if(registry_only)
-            {
-                printf("\nIntegrity changes for 'Windows Registry' of"
-                       " agent '%s (%s) - %s':\n",
-                       keys.keyentries[i]->name, keys.keyentries[i]->id,
-                       final_ip);
-            }
-            else
-            {
-                printf("\nIntegrity changes for agent "
-                       "'%s (%s) - %s':\n",
-                       keys.keyentries[i]->name, keys.keyentries[i]->id,
-                       final_ip);
-            }
+            /* Getting full address/prefix length from ip. */
+            final_ip[(sizeof final_ip) - 1] = '\0';
+            snprintf(final_ip, sizeof final_ip, "%s/%u",
+                     keys.keyentries[i]->ip->ip,
+                     keys.keyentries[i]->ip->prefixlength);
+
+            if (!(csv_output || json_output)) {
+                if (registry_only) {
+                    printf("\nIntegrity changes for 'Windows Registry' of"
+                           " agent '%s (%s) - %s':\n",
+                           keys.keyentries[i]->name, keys.keyentries[i]->id,
+                           final_ip);
+                } else {
+                    printf("\nIntegrity changes for agent "
+                           "'%s (%s) - %s':\n",
+                           keys.keyentries[i]->name, keys.keyentries[i]->id,
+                           final_ip);
+                }
 
-            if(fname)
-            {
-                printf("Detailed information for entries matching: '%s'\n",
-                       fname);
+                if (fname) {
+                    printf("Detailed information for entries matching: '%s'\n",
+                           fname);
+                }
             }
-            print_syscheck(keys.keyentries[i]->name,
-                    keys.keyentries[i]->ip->ip, fname,
-                    registry_only, 0, csv_output, zero_counter);
 
+            print_syscheck(keys.keyentries[i]->name, keys.keyentries[i]->ip->ip, fname,
+                           registry_only, 0, csv_output, json_entries, zero_counter);
+        }
+
+        if (json_output) {
+            cJSON_AddNumberToObject(json_root, "error", 0);
+            cJSON_AddItemToObject(json_root, "response", json_entries);
+            printf("%s", cJSON_PrintUnformatted(json_root));
         }
 
         exit(0);
     }
 
+    if (json_output) {
+        cJSON_AddNumberToObject(json_root, "error", 30);
+        cJSON_AddStringToObject(json_root, "description", "Invalid argument combination");
+        printf("%s", cJSON_PrintUnformatted(json_root));
+        exit(1);
+    } else {
+        printf("\n** Invalid argument combination.\n");
+        helpmsg();
+    }
 
-
-    printf("\n** Invalid argument combination.\n");
-    helpmsg();
-
-
-    return(0);
+    return (0);
 }
-
-
-/* EOF */