new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / util / rootcheck_control.c
old mode 100755 (executable)
new mode 100644 (file)
index dc1c62f..2d0092b
@@ -1,7 +1,4 @@
-/* @(#) $Id: ./src/util/rootcheck_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"
+#include <external/cJSON/cJSON.h>
 
 
 #undef ARGV0
 #define ARGV0 "rootcheck_control"
 
+/* Prototypes */
+static void helpmsg(void) __attribute__((noreturn));
 
-/** help **/
-void helpmsg()
+
+static void helpmsg()
 {
     printf("\nOSSEC HIDS %s: Manages the policy and auditing database.\n",
            ARGV0);
@@ -35,43 +34,38 @@ void helpmsg()
     printf("\t-q          Used with -i, prints all the outstanding issues.\n");
     printf("\t-L          Used with -i, prints the last scan.\n");
     printf("\t-s          Changes the output to CSV (comma delimited).\n");
+    printf("\t-j          Changes the output to JSON.\n");
     exit(1);
 }
 
-
-/** main **/
 int main(int argc, char **argv)
 {
-    char *dir = DEFAULTDIR;
-    char *group = GROUPGLOBAL;
-    char *user = USER;
-    char *agent_id = NULL;
+    const char *dir = DEFAULTDIR;
+    const char *group = GROUPGLOBAL;
+    const char *user = USER;
+    const char *agent_id = NULL;
 
-    int gid = 0;
-    int uid = 0;
+    gid_t gid;
+    uid_t uid;
     int c = 0, info_agent = 0, update_rootcheck = 0,
-               list_agents = 0, show_last = 0,
-               resolved_only = 0;
-    int active_only = 0, csv_output = 0;
+        list_agents = 0, show_last = 0,
+        resolved_only = 0;
+    int active_only = 0, csv_output = 0, json_output = 0;
 
     char shost[512];
+    cJSON *json_root = NULL;
 
 
-
-    /* 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, "VhqrDdLlcsu:i:")) != -1)
-    {
-        switch(c){
+    while ((c = getopt(argc, argv, "VhqrDdLlcsju:i:")) != -1) {
+        switch (c) {
             case 'V':
                 print_version();
                 break;
@@ -87,6 +81,9 @@ int main(int argc, char **argv)
             case 's':
                 csv_output = 1;
                 break;
+            case 'j':
+                json_output = 1;
+                break;
             case 'c':
                 active_only++;
                 break;
@@ -101,17 +98,15 @@ 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 'u':
-                if(!optarg)
-                {
-                    merror("%s: -u needs an argument",ARGV0);
+                if (!optarg) {
+                    merror("%s: -u needs an argument", ARGV0);
                     helpmsg();
                 }
                 agent_id = optarg;
@@ -124,223 +119,250 @@ int main(int argc, char **argv)
 
     }
 
-
-    /* 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)
-        {
+    /* List available agents */
+    if (list_agents) {
+        if (!csv_output) {
             printf("\nOSSEC HIDS %s. List of available agents:",
-                    ARGV0);
+                   ARGV0);
             printf("\n   ID: 000, Name: %s (server), IP: 127.0.0.1, "
                    "Active/Local\n", shost);
-        }
-        else
-        {
+        } else {
             printf("000,%s (server),127.0.0.1,Active/Local,\n", shost);
         }
-        print_agents(1, active_only, csv_output);
+        print_agents(1, active_only, csv_output, 0);
         printf("\n");
         exit(0);
     }
 
+    /* Update rootcheck database */
+    if (update_rootcheck) {
+        char json_buffer[1024];
 
-
-    /* Update rootcheck database. */
-    if(update_rootcheck)
-    {
-        /* Cleaning all agents (and server) db. */
-        if(strcmp(agent_id, "all") == 0)
-        {
+        /* Clean all agents (and server) db */
+        if (strcmp(agent_id, "all") == 0) {
             DIR *sys_dir;
             struct dirent *entry;
 
             sys_dir = opendir(ROOTCHECK_DIR);
-            if(!sys_dir)
-            {
-                ErrorExit("%s: Unable to open: '%s'", ARGV0, ROOTCHECK_DIR);
+            if (!sys_dir) {
+                if (json_output) {
+                    cJSON_AddNumberToObject(json_root, "error", 11);
+                    snprintf(json_buffer, 1023, "%s: Unable to open: '%s'", ARGV0, ROOTCHECK_DIR);
+                    cJSON_AddStringToObject(json_root, "description", json_buffer);
+                    printf("%s", cJSON_PrintUnformatted(json_root));
+                    exit(1);
+                } else
+                    ErrorExit("%s: Unable to open: '%s'", ARGV0, ROOTCHECK_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", ROOTCHECK_DIR,
+                snprintf(full_path, OS_MAXSTR, "%s/%s", ROOTCHECK_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** Policy and auditing database updated.\n\n");
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddStringToObject(json_root, "response", "Policy and auditing database updated");
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            } else
+                printf("\n** Policy and auditing 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/rootcheck", ROOTCHECK_DIR);
 
             fp = fopen(final_dir, "w");
-            if(fp)
-            {
+            if (fp) {
                 fclose(fp);
             }
             unlink(final_dir);
-            printf("\n** Policy and auditing database updated.\n\n");
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddStringToObject(json_root, "response", "Policy and auditing database updated");
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            } else
+                printf("\n** Policy and auditing 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) {
+                    cJSON_AddNumberToObject(json_root, "error", 12);
+                    snprintf(json_buffer, 1023, "Invalid agent id '%s'.", agent_id);
+                    cJSON_AddStringToObject(json_root, "description", json_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_rootcheck(keys.keyentries[i]->name,
                              keys.keyentries[i]->ip->ip, 0);
 
-            printf("\n** Policy and auditing database updated.\n\n");
+            if (json_output) {
+                 cJSON_AddNumberToObject(json_root, "error", 0);
+                 cJSON_AddStringToObject(json_root, "response", "Policy and auditing database updated");
+                 printf("%s", cJSON_PrintUnformatted(json_root));
+            } else
+                printf("\n** Policy and auditing 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;
+        cJSON *json_events = NULL;
+        if (json_output)
+            json_events = cJSON_CreateArray();
 
+        if ((strcmp(agent_id, "000") == 0) ||
+                (strcmp(agent_id, "local") == 0)) {
+            if (!(csv_output || json_output))
 
-        if((strcmp(agent_id, "000") == 0) ||
-           (strcmp(agent_id, "local") == 0))
-        {
-            if(!csv_output)
-            printf("\nPolicy and auditing events for local system '%s - %s':\n",
-                    shost, "127.0.0.1");
+                printf("\nPolicy and auditing events for local system '%s - %s':\n",
+                       shost, "127.0.0.1");
 
-            print_rootcheck(NULL,
-                            NULL, NULL, resolved_only, csv_output, show_last);
-        }
-        else
-        {
+            print_rootcheck(NULL, NULL, NULL, resolved_only, csv_output,
+                            json_events, show_last);
 
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddItemToObject(json_root, "response", json_events);
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            }
+
+        } 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 json_buffer[1024];
+                    snprintf(json_buffer, 1023, "Invalid agent id '%s'", agent_id);
+                    cJSON_AddNumberToObject(json_root, "error", 13);
+                    cJSON_AddStringToObject(json_root, "description", json_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);
+            /* Getting full address/prefixlength 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)
-            printf("\nPolicy and auditing events for agent "
+            if (!(csv_output || json_output))
+                printf("\nPolicy and auditing events for agent "
                        "'%s (%s) - %s':\n",
                        keys.keyentries[i]->name, keys.keyentries[i]->id,
                        final_ip);
 
             print_rootcheck(keys.keyentries[i]->name,
                             keys.keyentries[i]->ip->ip, NULL,
-                            resolved_only, csv_output, show_last);
+                            resolved_only, csv_output, json_events, show_last);
+
+            if (json_output) {
+                cJSON_AddNumberToObject(json_root, "error", 0);
+                cJSON_AddItemToObject(json_root, "response", json_events);
+                printf("%s", cJSON_PrintUnformatted(json_root));
+            }
+
 
         }
 
         exit(0);
     }
 
+    if (json_output) {
+        cJSON_AddNumberToObject(json_root, "error", 10);
+        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 */