new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / addagent / validate.c
old mode 100755 (executable)
new mode 100644 (file)
index 60dec16..39ce6e8
@@ -1,6 +1,3 @@
-/* @(#) $Id: ./src/addagent/validate.c, 2011/09/08 dcid Exp $
- */
-
 /* Copyright (C) 2009 Trend Micro Inc.
  * All rights reserved.
  *
  * Foundation
  */
 
-
-
+#include <time.h>
 #include "manage_agents.h"
 #include "os_crypto/md5/md5_op.h"
 
-char *OS_AddNewAgent(char *name, char *ip, char *id, char *key)
+/* Global variables */
+fpos_t fp_pos;
+
+/*Number bit of int type*/
+#define INT_BIT_SIZE          (sizeof(int)*CHAR_BIT)
+/*Enable bit at a position*/
+#define SetBit(Array,pos)     ( Array[(pos/INT_BIT_SIZE)] |= (1 << (pos%INT_BIT_SIZE)) )
+/*Check state of bit at a */
+#define TestBit(Array,pos)    ( Array[(pos/INT_BIT_SIZE)] & (1 << (pos%INT_BIT_SIZE)) )
+
+int *MapIDToBitArray()
 {
-    int i = 0;
     FILE *fp;
-    int rand1;
-    os_md5 md1;
-    os_md5 md2;
-    char str1[STR_SIZE +1];
-    char str2[STR_SIZE +1];
-    char *muname = NULL;
-    char *finals = NULL;
+    char line_read[FILE_SIZE + 1];
+    line_read[FILE_SIZE] = '\0';
+    int *arrayID;
+    int max = MAX_AGENTS + AUTHD_FIRST_ID;
+    if (isChroot()) {
+        fp = fopen(AUTH_FILE, "r");
+    } else {
+        fp = fopen(KEYSFILE_PATH, "r");
+    }
 
-    char nid[9];
+    if (!fp) {
+        return (NULL);
+    }
 
+    os_calloc(MAX_AGENTS/INT_BIT_SIZE + 1, sizeof(int), arrayID);
 
-    #ifndef WIN32
-        #ifdef __OpenBSD__
-        srandomdev();
-        #else
-        srandom(time(0) + getpid() + getppid());
-        #endif
-    #else
-        srandom(time(0) + getpid());
-    #endif
+    while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
+        char *name;
 
-    rand1 = random();
+        if (line_read[0] == '#') {
+            continue;
+        }
+
+        name = strchr(line_read, ' ');
+        if (name) {
+            *name = '\0';
+            int name_num=atoi(line_read);
+            /*Enable bit at ID already allocated*/
+            if (name_num >= AUTHD_FIRST_ID && name_num < max) {
+                SetBit(arrayID, (name_num-AUTHD_FIRST_ID));
+            }
+        }
+
+    }
+    fclose(fp);
+    return arrayID;
+}
+
+char *OS_AddNewAgent(const char *name, const char *ip, const char *id)
+{
+    FILE *fp;
+    os_md5 md1;
+    os_md5 md2;
+    char str1[STR_SIZE + 1];
+    char str2[STR_SIZE + 1];
+    char *muname;
+    char *finals;
+    char nid[9] = { '\0' };
+
+    srandom_init();
     muname = getuname();
 
-    snprintf(str1, STR_SIZE, "%d%s%d%s",(int)time(0), name, rand1, muname);
+    snprintf(str1, STR_SIZE, "%d%s%d%s", (int)time(0), name, (int)random(), muname);
     snprintf(str2, STR_SIZE, "%s%s%ld", ip, id, (long int)random());
     OS_MD5_Str(str1, md1);
     OS_MD5_Str(str2, md2);
 
+    free(muname);
+
+    if (id == NULL) {
+        int *arrayID;
+        int i;
+        arrayID=(int *)MapIDToBitArray();
+        if (arrayID != NULL) {
+            /*Find first item in bit array which is not marked as allocated*/
+            for (i=0; i<MAX_AGENTS; i++) {
+                if(!TestBit(arrayID, i)) {
+                    snprintf(nid, 8, "%d", (i + AUTHD_FIRST_ID));
+                    break;
+                }
+            }
+            os_free(arrayID);
 
-    nid[8] = '\0';
-    if(id == NULL)
-    {
-        i = 1024;
-        snprintf(nid, 6, "%d", i);
-        while(IDExist(nid))
-        {
-            i++;
-            snprintf(nid, 6, "%d", i);
-            if(i >= 4000)
-            {
-                return(NULL);
+            if (i == MAX_AGENTS) {
+                return (NULL);
             }
         }
+        else {
+            return (NULL);
+        }
+
         id = nid;
     }
 
-    fp = fopen(KEYSFILE_PATH,"a");
-    if(!fp)
-    {
-        return(NULL);
+    char authentication_file[2048 + 1];
+    snprintf(authentication_file, 2048, "%s%s", DEFAULTDIR, AUTH_FILE);
+
+    fp = fopen(authentication_file, "a");
+    if (!fp) {
+        return (NULL);
     }
 
     os_calloc(2048, sizeof(char), finals);
-    if (ip == NULL){
-        snprintf(finals, 2048, "%s %s any %s%s",id, name, md1,md2);
+    if (ip == NULL) {
+        snprintf(finals, 2048, "%s %s any %s%s", id, name, md1, md2);
     } else {
-        snprintf(finals, 2048, "%s %s %s %s%s",id, name, ip, md1,md2);
+        snprintf(finals, 2048, "%s %s %s %s%s", id, name, ip, md1, md2);
     }
-    fprintf(fp, "%s\n",finals);
+    fprintf(fp, "%s\n", finals);
 
     fclose(fp);
-    return(finals);
+    return (finals);
 }
 
+int OS_RemoveAgent(const char *u_id) {
+    FILE *fp;
+    int id_exist;
+    char *full_name;
+
+    id_exist = IDExist(u_id);
 
-int OS_IsValidID(char *id)
+    if (!id_exist)
+        return 0;
+
+    fp = fopen(isChroot() ? AUTH_FILE : KEYSFILE_PATH, "r+");
+
+    if (!fp)
+        return 0;
+
+#ifndef WIN32
+    if((chmod(AUTH_FILE, 0440)) < 0) {
+        merror("addagent: ERROR: Cannot chmod %s: %s", AUTH_FILE, strerror(errno));
+    }
+#endif
+
+#ifdef REUSE_ID
+    long fp_seek;
+    size_t fp_read;
+    char *buffer;
+    char buf_discard[OS_BUFFER_SIZE];
+    struct stat fp_stat;
+
+    if (stat(AUTH_FILE, &fp_stat) < 0) {
+        fclose(fp);
+        return 0;
+    }
+
+    buffer = malloc(fp_stat.st_size);
+    if (!buffer) {
+        fclose(fp);
+        return 0;
+    }
+
+    fsetpos(fp, &fp_pos);
+    fp_seek = ftell(fp);
+    fseek(fp, 0, SEEK_SET);
+    fp_read = fread(buffer, sizeof(char), fp_seek, fp);
+    fgets(buf_discard, OS_BUFFER_SIZE - 1, fp);
+
+    if (!feof(fp))
+        fp_read += fread(buffer + fp_read, sizeof(char), fp_stat.st_size, fp);
+
+    fclose(fp);
+    fp = fopen(AUTH_FILE, "w");
+
+    if (!fp) {
+        free(buffer);
+        return 0;
+    }
+
+    fwrite(buffer, sizeof(char), fp_read, fp);
+
+#else
+    /* Remove the agent, but keep the id */
+    fsetpos(fp, &fp_pos);
+    fprintf(fp, "%s #*#*#*#*#*#*#*#*#*#*#", u_id);
+#endif
+    fclose(fp);
+
+    full_name = getFullnameById(u_id);
+    if (full_name)
+        delete_agentinfo(full_name);
+
+    /* Remove counter for ID */
+    OS_RemoveCounter(u_id);
+    return 1;
+}
+
+int OS_IsValidID(const char *id)
 {
-    int id_len = 0;
-    int i = 0;
+    size_t id_len, i;
 
     /* ID must not be null */
-    if(!id)
-      return(0);
+    if (!id) {
+        return (0);
+    }
 
     id_len = strlen(id);
 
     /* Check ID length, it should contain max. 8 characters */
-    if (id_len > 8)
-      return(0);
+    if (id_len > 8) {
+        return (0);
+    }
 
     /* Check ID if it contains only numeric characters [0-9] */
-    for(i = 0; i < id_len; i++)
-    {
-      if(!(isdigit((int)id[i])))
-        return(0);
+    for (i = 0; i < id_len; i++) {
+        if (!(isdigit((int)id[i]))) {
+            return (0);
+        }
     }
 
-    return(1);
+    return (1);
 }
 
-
-/* Get full agent name (name + ip) of ID.
- */
-char *getFullnameById(char *id)
+/* Get full agent name (name + IP) of ID */
+char *getFullnameById(const char *id)
 {
     FILE *fp;
-    char line_read[FILE_SIZE +1];
+    char line_read[FILE_SIZE + 1];
     line_read[FILE_SIZE] = '\0';
 
     /* ID must not be null */
-    if(!id)
-        return(NULL);
+    if (!id) {
+        return (NULL);
+    }
 
     fp = fopen(AUTH_FILE, "r");
-    if(!fp)
-        return(NULL);
-
+    if (!fp) {
+        return (NULL);
+    }
 
-    while(fgets(line_read, FILE_SIZE -1, fp) != NULL)
-    {
+    while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
         char *name;
         char *ip;
         char *tmp_str;
 
-        if(line_read[0] == '#')
-        {
+        if (line_read[0] == '#') {
             continue;
         }
 
         name = strchr(line_read, ' ');
-        if(name)
-        {
+        if (name) {
             *name = '\0';
             /* Didn't match */
-            if(strcmp(line_read,id) != 0)
-            {
+            if (strcmp(line_read, id) != 0) {
                 continue;
             }
 
             name++;
 
             /* Removed entry */
-            if(*name == '#')
-            {
+            if (*name == '#') {
                 continue;
             }
 
             ip = strchr(name, ' ');
-            if(ip)
-            {
+            if (ip) {
                 *ip = '\0';
                 ip++;
 
-                /* Cleaning up ip */
+                /* Clean up IP */
                 tmp_str = strchr(ip, ' ');
-                if(tmp_str)
-                {
+                if (tmp_str) {
                     char *final_str;
                     *tmp_str = '\0';
                     tmp_str = strchr(ip, '/');
-                    if(tmp_str)
+                    if (tmp_str) {
                         *tmp_str = '\0';
+                    }
 
                     /* If we reached here, we found the IP and name */
                     os_calloc(1, FILE_SIZE, final_str);
-                    snprintf(final_str, FILE_SIZE -1, "%s-%s", name, ip);
+                    snprintf(final_str, FILE_SIZE - 1, "%s-%s", name, ip);
 
                     fclose(fp);
-                    return(final_str);
+                    return (final_str);
                 }
             }
         }
     }
 
     fclose(fp);
-    return(NULL);
+    return (NULL);
 }
 
-
 /* ID Search (is valid ID) */
-int IDExist(char *id)
+int IDExist(const char *id)
 {
     FILE *fp;
-    char line_read[FILE_SIZE +1];
+    char line_read[FILE_SIZE + 1];
     line_read[FILE_SIZE] = '\0';
 
     /* ID must not be null */
-    if(!id)
-        return(0);
+    if (!id) {
+        return (0);
+    }
 
-    if(isChroot())
-      fp = fopen(AUTH_FILE, "r");
-    else
-      fp = fopen(KEYSFILE_PATH, "r");
+    if (isChroot()) {
+        fp = fopen(AUTH_FILE, "r");
+    } else {
+        fp = fopen(KEYSFILE_PATH, "r");
+    }
 
-    if(!fp)
-        return(0);
+    if (!fp) {
+        return (0);
+    }
 
     fseek(fp, 0, SEEK_SET);
     fgetpos(fp, &fp_pos);
 
-    while(fgets(line_read,FILE_SIZE -1, fp) != NULL)
-    {
+    while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
         char *name;
 
-        if(line_read[0] == '#')
-        {
+        if (line_read[0] == '#') {
             fgetpos(fp, &fp_pos);
             continue;
         }
 
         name = strchr(line_read, ' ');
-        if(name)
-        {
+        if (name) {
             *name = '\0';
             name++;
 
-            if(strcmp(line_read,id) == 0)
-            {
+            if (strcmp(line_read, id) == 0) {
                 fclose(fp);
                 return (1); /*(fp_pos);*/
             }
@@ -238,84 +347,79 @@ int IDExist(char *id)
     }
 
     fclose(fp);
-    return(0);
+    return (0);
 }
 
-
-/* Validate agent name.
- */
-int OS_IsValidName(char *u_name)
+/* Validate agent name */
+int OS_IsValidName(const char *u_name)
 {
-    int i = 0;
+    size_t i, uname_length = strlen(u_name);
 
     /* We must have something in the name */
-    if(strlen(u_name) < 2 || strlen(u_name) > 128)
-      return(0);
+    if (uname_length < 2 || uname_length > 128) {
+        return (0);
+    }
 
-    /* check if it contains any non-alphanumeric characters */
-    for(i = 0; i < strlen(u_name); i++)
-    {
-      if(!isalnum((int)u_name[i]) && (u_name[i] != '-') &&
-         (u_name[i] != '_') && (u_name[i] != '.'))
-        return(0);
+    /* Check if it contains any non-alphanumeric characters */
+    for (i = 0; i < uname_length; i++) {
+        if ( !( isalnum((int)u_name[i]) || (u_name[i] == '-') ||
+                (u_name[i] == '_') || (u_name[i] == '.') ||
+                (u_name[i] == ':') ) ) {
+            return (0);
+        }
     }
 
-    return(1);
+    return (1);
 }
 
-
-/* Is_Name (is valid name) */
-int NameExist(char *u_name)
+int NameExist(const char *u_name)
 {
     FILE *fp;
-    char line_read[FILE_SIZE +1];
+    char line_read[FILE_SIZE + 1];
     line_read[FILE_SIZE] = '\0';
 
-    if((!u_name)||
-       (*u_name == '\0')||
-       (*u_name == '\r')||
-       (*u_name == '\n'))
-        return(0);
-
-    if(isChroot())
-      fp = fopen(AUTH_FILE, "r");
-    else
-      fp = fopen(KEYSFILE_PATH, "r");
+    if ((!u_name) ||
+            (*u_name == '\0') ||
+            (*u_name == '\r') ||
+            (*u_name == '\n')) {
+        return (0);
+    }
 
-    if(!fp)
-        return(0);
+    if (isChroot()) {
+        fp = fopen(AUTH_FILE, "r");
+    } else {
+        fp = fopen(KEYSFILE_PATH, "r");
+    }
 
+    if (!fp) {
+        return (0);
+    }
 
     fseek(fp, 0, SEEK_SET);
     fgetpos(fp, &fp_pos);
 
-
-    while(fgets(line_read, FILE_SIZE-1, fp) != NULL)
-    {
+    while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
         char *name;
 
-        if(line_read[0] == '#')
+        if (line_read[0] == '#') {
             continue;
+        }
 
         name = strchr(line_read, ' ');
-        if(name)
-        {
+        if (name) {
             char *ip;
             name++;
 
-            if(*name == '#')
-            {
+            if (*name == '#') {
                 continue;
             }
 
             ip = strchr(name, ' ');
-            if(ip)
-            {
+            if (ip) {
                 *ip = '\0';
-                if(strcmp(u_name, name) == 0)
-                {
+                if (strcmp(u_name, name) == 0) {
                     fclose(fp);
-                    return(1);
+                    return (1);
                 }
             }
         }
@@ -323,130 +427,197 @@ int NameExist(char *u_name)
     }
 
     fclose(fp);
-    return(0);
+    return (0);
 }
 
+/* Returns the ID of an agent, or NULL if not found */
+char *IPExist(const char *u_ip)
+{
+    FILE *fp;
+    char *name, *ip, *pass;
+    char line_read[FILE_SIZE + 1];
+    line_read[FILE_SIZE] = '\0';
+
+    if (!(u_ip && strncmp(u_ip, "any", 3)) || strchr(u_ip, '/'))
+        return NULL;
+
+    if (isChroot())
+        fp = fopen(AUTH_FILE, "r");
+    else
+        fp = fopen(KEYSFILE_PATH, "r");
 
-/* print available agents */
-int print_agents(int print_status, int active_only, int csv_output)
+    if (!fp)
+        return NULL;
+
+    fseek(fp, 0, SEEK_SET);
+    fgetpos(fp, &fp_pos);
+
+    while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
+        if (line_read[0] == '#') {
+            continue;
+        }
+
+        name = strchr(line_read, ' ');
+        if (name) {
+            name++;
+
+            if (*name == '#') {
+                continue;
+            }
+
+            ip = strchr(name, ' ');
+            if (ip) {
+                ip++;
+
+                pass = strchr(ip, ' ');
+                if (pass) {
+                    *pass = '\0';
+                    if (strcmp(u_ip, ip) == 0) {
+                        fclose(fp);
+                        name[-1] = '\0';
+                        return strdup(line_read);
+                    }
+                }
+            }
+        }
+
+        fgetpos(fp, &fp_pos);
+    }
+
+    fclose(fp);
+    return NULL;
+}
+
+/* Returns the number of seconds since last agent connection, or -1 if error. */
+double OS_AgentAntiquity(const char *id)
+{
+    struct stat file_stat;
+    char file_name[OS_FLSIZE];
+    char *full_name = getFullnameById(id);
+
+    if (!full_name) {
+        return -1;
+    }
+
+    snprintf(file_name, OS_FLSIZE - 1, "%s/%s", AGENTINFO_DIR, full_name);
+
+    if (stat(file_name, &file_stat) < 0) {
+        if(full_name) {
+            free(full_name);
+        }
+        return -1;
+    }
+
+    free(full_name);
+
+    return difftime(time(NULL), file_stat.st_mtime);
+}
+
+/* Print available agents */
+int print_agents(int print_status, int active_only, int csv_output, cJSON *json_output)
 {
     int total = 0;
     FILE *fp;
-    char line_read[FILE_SIZE +1];
+    char line_read[FILE_SIZE + 1];
     line_read[FILE_SIZE] = '\0';
 
     fp = fopen(AUTH_FILE, "r");
-    if(!fp)
-        return(0);
+    if (!fp) {
+        return (0);
+    }
 
     fseek(fp, 0, SEEK_SET);
 
-    memset(line_read,'\0',FILE_SIZE);
+    memset(line_read, '\0', FILE_SIZE);
 
-    while(fgets(line_read, FILE_SIZE -1, fp) != NULL)
-    {
+    while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
         char *name;
 
-        if(line_read[0] == '#')
+        if (line_read[0] == '#') {
             continue;
+        }
 
         name = strchr(line_read, ' ');
-        if(name)
-        {
+        if (name) {
             char *ip;
             *name = '\0';
             name++;
 
-
-            /* Removed agent. */
-            if(*name == '#')
-            {
+            /* Removed agent */
+            if (*name == '#') {
                 continue;
             }
 
             ip = strchr(name, ' ');
-            if(ip)
-            {
+            if (ip) {
                 char *key;
                 *ip = '\0';
                 ip++;
                 key = strchr(ip, ' ');
-                if(key)
-                {
+                if (key) {
                     *key = '\0';
-                    if(!total && !print_status)
+                    if (!total && !print_status) {
                         printf(PRINT_AVAILABLE);
+                    }
                     total++;
 
-
-                    if(print_status)
-                    {
+                    if (print_status) {
                         int agt_status = get_agent_status(name, ip);
-                        if(active_only && (agt_status != GA_STATUS_ACTIVE))
-                        {
+                        if (active_only && (agt_status != GA_STATUS_ACTIVE)) {
                             continue;
                         }
 
-                        if(csv_output)
-                        {
-                            printf("%s,%s,%s,%s,\n", line_read, name, ip,
-                                                  print_agent_status(agt_status));
+                        if (csv_output) {
+                            printf("%s,%s,%s,%s,\n", line_read, name, ip, print_agent_status(agt_status));
+                        } else if (json_output) {
+                            cJSON *json_agent = cJSON_CreateObject();
+                          
+                            if (!json_agent)
+                                return 0;
+                            
+                            cJSON_AddStringToObject(json_agent, "id", line_read);
+                            cJSON_AddStringToObject(json_agent, "name", name);
+                            cJSON_AddStringToObject(json_agent, "ip", ip);
+                            cJSON_AddStringToObject(json_agent, "status", print_agent_status(agt_status));
+                            cJSON_AddItemToArray(json_output, json_agent);
+                        } else {
+                            printf(PRINT_AGENT_STATUS, line_read, name, ip, print_agent_status(agt_status));
                         }
-                        else
-                        {
-                            printf(PRINT_AGENT_STATUS, line_read, name, ip,
-                                   print_agent_status(agt_status));
-                        }
-                    }
-                    else
-                    {
+                    } else {
                         printf(PRINT_AGENT, line_read, name, ip);
                     }
                 }
-
             }
         }
     }
 
-
     /* Only print agentless for non-active only searches */
-    if(!active_only && print_status)
-    {
-        char *aip = NULL;
+    if (!active_only && print_status) {
+        const char *aip = NULL;
         DIR *dirp;
         struct dirent *dp;
 
-        if(!csv_output)
-        {
+        if (!csv_output && !json_output) {
             printf("\nList of agentless devices:\n");
         }
 
         dirp = opendir(AGENTLESS_ENTRYDIR);
-        if(dirp)
-        {
-            while ((dp = readdir(dirp)) != NULL)
-            {
-                if(strncmp(dp->d_name, ".", 1) == 0)
-                {
+        if (dirp) {
+            while ((dp = readdir(dirp)) != NULL) {
+                if (strncmp(dp->d_name, ".", 1) == 0) {
                     continue;
                 }
 
                 aip = strchr(dp->d_name, '@');
-                if(aip)
-                {
+                if (aip) {
                     aip++;
-                }
-                else
-                {
+                } else {
                     aip = "<na>";
                 }
 
-                if(csv_output)
-                {
+                if (csv_output) {
                     printf("na,%s,%s,agentless,\n", dp->d_name, aip);
-                }
-                else
-                {
+                } else {
                     printf("   ID: na, Name: %s, IP: %s, agentless\n",
                            dp->d_name, aip);
                 }
@@ -456,11 +627,22 @@ int print_agents(int print_status, int active_only, int csv_output)
     }
 
     fclose(fp);
-    if(total)
-        return(1);
+    if (total) {
+        return (1);
+    }
 
-    return(0);
+    return (0);
 }
 
+void FormatID(char *id) {
+    int number;
+    char *end;
 
-/* EOF */
+    if (id && *id) {
+        number = strtol(id, &end, 10);
+
+        if (!*end) {
+            sprintf(id, "%03d", number);
+        }
+    }
+}