/* Receive events from the server */ int receive_msg() { ssize_t recv_b; netsize_t length; int reads = 0; char buffer[OS_MAXSTR + 1]; char cleartext[OS_MAXSTR + 1]; char *tmp_msg; memset(cleartext, '\0', OS_MAXSTR + 1); memset(buffer, '\0', OS_MAXSTR + 1); /* Read until no more messages are available */ while (1) { if (agt->protocol == TCP_PROTO) { /* Only one read per call */ if (reads++) { break; } recv_b = recv(agt->sock, (char*)&length, sizeof(length), MSG_WAITALL); /* Manager disconnected */ if (recv_b <= 0) { return -1; } recv_b = recv(agt->sock, buffer, length, MSG_WAITALL); if (recv_b != length) { merror(RECV_ERROR, ARGV0); continue; } } else { recv_b = recv(agt->sock, buffer, OS_SIZE_1024, MSG_DONTWAIT); if (recv_b <= 0) { break; } } buffer[recv_b] = '\0'; tmp_msg = ReadSecMSG(&keys, buffer, cleartext, 0, recv_b - 1); if (tmp_msg == NULL) { merror(MSG_ERROR, ARGV0, agt->rip[agt->rip_id]); continue; } /* Check for commands */ if (IsValidHeader(tmp_msg)) { available_server = (int)time(NULL); #ifdef WIN32 /* Run timeout commands */ if (agt->execdq >= 0) { WinTimeoutRun(available_server); } #endif /* If it is an active response message */ if (strncmp(tmp_msg, EXECD_HEADER, strlen(EXECD_HEADER)) == 0) { tmp_msg += strlen(EXECD_HEADER); #ifndef WIN32 if (agt->execdq >= 0) { if (OS_SendUnix(agt->execdq, tmp_msg, 0) < 0) { merror("%s: Error communicating with execd", ARGV0); } } #else /* Run on Windows */ if (agt->execdq >= 0) { WinExecdRun(tmp_msg); } #endif continue; } /* Restart syscheck */ else if (strcmp(tmp_msg, HC_SK_RESTART) == 0) { os_set_restart_syscheck(); continue; } /* Ack from server */ else if (strcmp(tmp_msg, HC_ACK) == 0) { continue; } /* Close any open file pointer if it was being written to */ if (fp) { fclose(fp); fp = NULL; } /* File update message */ if (strncmp(tmp_msg, FILE_UPDATE_HEADER, strlen(FILE_UPDATE_HEADER)) == 0) { char *validate_file; tmp_msg += strlen(FILE_UPDATE_HEADER); /* Going to after the file sum */ validate_file = strchr(tmp_msg, ' '); if (!validate_file) { continue; } *validate_file = '\0'; /* Copy the file sum */ strncpy(file_sum, tmp_msg, 33); /* Set tmp_msg to the beginning of the file name */ validate_file++; tmp_msg = validate_file; if ((validate_file = strchr(tmp_msg, '\n')) != NULL) { *validate_file = '\0'; } while ((validate_file = strchr(tmp_msg, '/')) != NULL) { *validate_file = '-'; } if (tmp_msg[0] == '.') { tmp_msg[0] = '-'; } snprintf(file, OS_SIZE_1024, "%s/%s", SHAREDCFG_DIR, tmp_msg); fp = fopen(file, "w"); if (!fp) { merror(FOPEN_ERROR, ARGV0, file, errno, strerror(errno)); } } else if (strncmp(tmp_msg, FILE_CLOSE_HEADER, strlen(FILE_CLOSE_HEADER)) == 0) { /* No error */ os_md5 currently_md5; /* Close for the rename to work */ if (fp) { fclose(fp); fp = NULL; } if (file[0] == '\0') { /* Nothing to be done */ } else if (OS_MD5_File(file, currently_md5, OS_TEXT) < 0) { /* Remove file */ unlink(file); file[0] = '\0'; } else { if (strcmp(currently_md5, file_sum) != 0) { debug1("%s: ERROR: Failed md5 for: %s -- deleting.", ARGV0, file); unlink(file); } else { char *final_file; /* Rename the file to its original name */ final_file = strrchr(file, '/'); if (final_file) { if (strcmp(final_file + 1, SHAREDCFG_FILENAME) == 0) { UnmergeFiles(file, SHAREDCFG_DIR); } } else { /* Remove file */ unlink(file); } } file[0] = '\0'; } } else { merror("%s: WARN: Unknown message received from server.", ARGV0); } } else if (fp) { available_server = (int)time(NULL); fprintf(fp, "%s", tmp_msg); } else { merror("%s: WARN: Unknown message received. No action defined.", ARGV0); } } return 0; }
/** main **/ int main(int argc, char **argv) { char *dir = DEFAULTDIR; char *group = GROUPGLOBAL; char *user = USER; char *agent_id = NULL; char *ip_address = NULL; char *ar = NULL; int arq = 0; int gid = 0; int uid = 0; int c = 0, restart_syscheck = 0, restart_all_agents = 0, list_agents = 0; int info_agent = 0, agt_id = 0, active_only = 0, csv_output = 0; int list_responses = 0, end_time = 0, restart_agent = 0; char shost[512]; keystore keys; /* Setting the name */ OS_SetName(ARGV0); /* user arguments */ if(argc < 2) { helpmsg(); } while((c = getopt(argc, argv, "VehdlLcsaru:i:b:f:R:")) != -1) { switch(c){ case 'V': print_version(); break; case 'h': helpmsg(); break; case 'd': nowDebug(); break; case 'L': list_responses = 1; break; case 'e': end_time = 1; break; case 'r': restart_syscheck = 1; break; case 'l': list_agents++; break; case 's': csv_output = 1; break; case 'c': active_only++; break; case 'i': info_agent++; case 'u': if(!optarg) { merror("%s: -u needs an argument",ARGV0); helpmsg(); } agent_id = optarg; break; case 'b': if(!optarg) { merror("%s: -b needs an argument",ARGV0); helpmsg(); } ip_address = optarg; break; case 'f': if(!optarg) { merror("%s: -e needs an argument",ARGV0); helpmsg(); } ar = optarg; break; case 'R': if(!optarg) { merror("%s: -R needs an argument",ARGV0); helpmsg(); } agent_id = optarg; restart_agent = 1; case 'a': restart_all_agents = 1; break; default: helpmsg(); break; } } /* Getting the group name */ gid = Privsep_GetGroup(group); uid = Privsep_GetUser(user); if(gid < 0) { ErrorExit(USER_ERROR, ARGV0, user, group); } /* Setting the group */ if(Privsep_SetGroup(gid) < 0) { ErrorExit(SETGID_ERROR,ARGV0, group); } /* Chrooting to the default directory */ if(Privsep_Chroot(dir) < 0) { ErrorExit(CHROOT_ERROR, ARGV0, dir); } /* Inside chroot now */ nowChroot(); /* Setting the user */ if(Privsep_SetUser(uid) < 0) { ErrorExit(SETUID_ERROR, ARGV0, user); } /* Getting servers hostname */ memset(shost, '\0', 512); if(gethostname(shost, 512 -1) != 0) { strncpy(shost, "localhost", 32); return(0); } /* Listing responses. */ if(list_responses) { FILE *fp; if(!csv_output) { printf("\nOSSEC HIDS %s. Available active responses:\n", ARGV0); } fp = fopen(DEFAULTAR, "r"); if(fp) { char buffer[256]; while(fgets(buffer, 255, fp) != NULL) { char *r_name; char *r_cmd; char *r_timeout; r_name = buffer; r_cmd = strchr(buffer, ' '); if(!r_cmd) continue; *r_cmd = '\0'; r_cmd++; if(*r_cmd == '-') r_cmd++; if(*r_cmd == ' ') r_cmd++; r_timeout = strchr(r_cmd, ' '); if(!r_timeout) continue; *r_timeout = '\0'; if(strcmp(r_name, "restart-ossec0") == 0) { continue; } printf("\n Response name: %s, command: %s", r_name, r_cmd); } printf("\n\n"); fclose(fp); } else { printf("\n No active response available.\n\n"); } exit(0); } /* Listing available agents. */ if(list_agents) { if(!csv_output) { 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); } /* Checking if the provided ID is valid. */ if(agent_id != NULL) { if(strcmp(agent_id, "000") != 0) { OS_ReadKeys(&keys); agt_id = OS_IsAllowedID(&keys, agent_id); if(agt_id < 0) { printf("\n** Invalid agent id '%s'.\n", agent_id); helpmsg(); } } else { /* server. */ agt_id = -1; } } /* Printing information from an agent. */ if(info_agent) { int agt_status = 0; char final_ip[IPSIZE + 4]; agent_info *agt_info; final_ip[(sizeof final_ip) - 1] = '\0'; if(!csv_output) printf("\nOSSEC HIDS %s. Agent information:", ARGV0); if(agt_id != -1) { agt_status = get_agent_status(keys.keyentries[agt_id]->name, keys.keyentries[agt_id]->ip->ip); agt_info = get_agent_info(keys.keyentries[agt_id]->name, keys.keyentries[agt_id]->ip->ip); /* Getting full address/prefix length from ip. */ snprintf(final_ip, sizeof final_ip, "%s/%u", keys.keyentries[agt_id]->ip->ip, keys.keyentries[agt_id]->ip->prefixlength); if(!csv_output) { printf("\n Agent ID: %s\n", keys.keyentries[agt_id]->id); printf(" Agent Name: %s\n", keys.keyentries[agt_id]->name); printf(" IP address: %s\n", final_ip); printf(" Status: %s\n\n",print_agent_status(agt_status)); } else { printf("%s,%s,%s,%s,", keys.keyentries[agt_id]->id, keys.keyentries[agt_id]->name, final_ip, print_agent_status(agt_status)); } } else { agt_status = get_agent_status(NULL, NULL); agt_info = get_agent_info(NULL, "127.0.0.1"); if(!csv_output) { printf("\n Agent ID: 000 (local instance)\n"); printf(" Agent Name: %s\n", shost); printf(" IP address: 127.0.0.1\n"); printf(" Status: %s/Local\n\n",print_agent_status(agt_status)); } else { printf("000,%s,127.0.0.1,%s/Local,", shost, print_agent_status(agt_status)); } } if(!csv_output) { printf(" Operating system: %s\n", agt_info->os); printf(" Client version: %s\n", agt_info->version); printf(" Last keep alive: %s\n\n", agt_info->last_keepalive); if(end_time) { printf(" Syscheck last started at: %s\n", agt_info->syscheck_time); printf(" Syscheck last ended at: %s\n", agt_info->syscheck_endtime); printf(" Rootcheck last started at: %s\n", agt_info->rootcheck_time); printf(" Rootcheck last ended at: %s\n\n", agt_info->rootcheck_endtime); } else { printf(" Syscheck last started at: %s\n", agt_info->syscheck_time); printf(" Rootcheck last started at: %s\n", agt_info->rootcheck_time); } } else { printf("%s,%s,%s,%s,%s,\n", agt_info->os, agt_info->version, agt_info->last_keepalive, agt_info->syscheck_time, agt_info->rootcheck_time); } exit(0); } /* Restarting syscheck every where. */ if(restart_all_agents && restart_syscheck) { /* Connecting to remoted. */ debug1("%s: DEBUG: Connecting to remoted...", ARGV0); arq = connect_to_remoted(); if(arq < 0) { printf("\n** Unable to connect to remoted.\n"); exit(1); } debug1("%s: DEBUG: Connected...", ARGV0); /* Sending restart message to all agents. */ if(send_msg_to_agent(arq, HC_SK_RESTART, NULL, NULL) == 0) { printf("\nOSSEC HIDS %s: Restarting Syscheck/Rootcheck on all agents.", ARGV0); } else { printf("\n** Unable to restart syscheck on all agents.\n"); exit(1); } exit(0); } if(restart_syscheck && agent_id) { /* Restart on the server. */ if(strcmp(agent_id, "000") == 0) { os_set_restart_syscheck(); printf("\nOSSEC HIDS %s: Restarting Syscheck/Rootcheck " "locally.\n", ARGV0); exit(0); } /* Connecting to remoted. */ debug1("%s: DEBUG: Connecting to remoted...", ARGV0); arq = connect_to_remoted(); if(arq < 0) { printf("\n** Unable to connect to remoted.\n"); exit(1); } debug1("%s: DEBUG: Connected...", ARGV0); if(send_msg_to_agent(arq, HC_SK_RESTART, agent_id, NULL) == 0) { printf("\nOSSEC HIDS %s: Restarting Syscheck/Rootcheck on agent: %s\n", ARGV0, agent_id); } else { printf("\n** Unable to restart syscheck on agent: %s\n", agent_id); exit(1); } exit(0); } if(restart_agent && agent_id) { /* Connecting to remoted. */ debug1("%s: DEBUG: Connecting to remoted...", ARGV0); arq = connect_to_remoted(); if(arq < 0) { printf("\n** Unable to connect to remoted.\n"); exit(1); } debug1("%s: DEBUG: Connected...", ARGV0); if(send_msg_to_agent(arq, "restart-ossec0", agent_id, "null") == 0) { printf("\nOSSEC HIDS %s: Restarting agent: %s\n", ARGV0, agent_id); } else { printf("\n** Unable to restart agent: %s\n", agent_id); exit(1); } exit(0); } /* running active response on the specified agent id. */ if(ip_address && ar && agent_id) { /* Connecting to remoted. */ debug1("%s: DEBUG: Connecting to remoted...", ARGV0); arq = connect_to_remoted(); if(arq < 0) { printf("\n** Unable to connect to remoted.\n"); exit(1); } debug1("%s: DEBUG: Connected...", ARGV0); if(send_msg_to_agent(arq, ar, agent_id, ip_address) == 0) { printf("\nOSSEC HIDS %s: Running active response '%s' on: %s\n", ARGV0, ar, agent_id); } else { printf("\n** Unable to restart syscheck on agent: %s\n", agent_id); exit(1); } exit(0); } printf("\n** Invalid argument combination.\n"); helpmsg(); return(0); }
/* receiver_thread: * Receive events from the server. */ void *receiver_thread(void *none) { int recv_b; char file[OS_SIZE_1024 +1]; char buffer[OS_MAXSTR +1]; char cleartext[OS_MAXSTR + 1]; char *tmp_msg; char file_sum[34]; fd_set fdset; struct timeval selecttime; FILE *fp; /* Setting FP to null, before starting */ fp = NULL; memset(cleartext, '\0', OS_MAXSTR +1); memset(buffer, '\0', OS_MAXSTR +1); memset(file, '\0', OS_SIZE_1024 +1); memset(file_sum, '\0', 34); while(1) { /* sock must be set. */ if(agt->sock == -1) { sleep(5); continue; } FD_ZERO(&fdset); FD_SET(agt->sock, &fdset); /* Wait for 30 seconds. */ selecttime.tv_sec = 30; selecttime.tv_usec = 0; /* Wait with a timeout for any descriptor */ recv_b = select(0, &fdset, NULL, NULL, &selecttime); if(recv_b == -1) { merror(SELECT_ERROR, ARGV0); sleep(30); continue; } else if(recv_b == 0) { continue; } /* Read until no more messages are available */ while((recv_b = recv(agt->sock,buffer,OS_SIZE_1024, 0))>0) { /* Id of zero -- only one key allowed */ tmp_msg = ReadSecMSG(&keys, buffer, cleartext, 0, recv_b -1); if(tmp_msg == NULL) { merror(MSG_ERROR,ARGV0,agt->rip[agt->rip_id]); continue; } /* Check for commands */ if(IsValidHeader(tmp_msg)) { /* This is the only thread that modifies it */ available_server = (int)time(NULL); /* Run timeout commands. */ if(agt->execdq >= 0) WinTimeoutRun(available_server); /* If it is an active response message */ if(strncmp(tmp_msg, EXECD_HEADER, strlen(EXECD_HEADER)) == 0) { tmp_msg+=strlen(EXECD_HEADER); /* Run on windows. */ if(agt->execdq >= 0) { WinExecdRun(tmp_msg); } continue; } /* Restart syscheck. */ else if(strcmp(tmp_msg, HC_SK_RESTART) == 0) { os_set_restart_syscheck(); continue; } /* Ack from server */ else if(strcmp(tmp_msg, HC_ACK) == 0) { continue; } /* Close any open file pointer if it was being written to */ if(fp) { fclose(fp); fp = NULL; } /* File update message */ if(strncmp(tmp_msg, FILE_UPDATE_HEADER, strlen(FILE_UPDATE_HEADER)) == 0) { char *validate_file; tmp_msg+=strlen(FILE_UPDATE_HEADER); /* Going to after the file sum */ validate_file = strchr(tmp_msg, ' '); if(!validate_file) { continue; } *validate_file = '\0'; /* copying the file sum */ strncpy(file_sum, tmp_msg, 33); /* Setting tmp_msg to the beginning of the file name */ validate_file++; tmp_msg = validate_file; if((validate_file = strchr(tmp_msg, '\n')) != NULL) { *validate_file = '\0'; } while((validate_file = strchr(tmp_msg, '/')) != NULL) { *validate_file = '-'; } if(tmp_msg[0] == '.') tmp_msg[0] = '-'; snprintf(file, OS_SIZE_1024, "%s/%s", SHAREDCFG_DIR, tmp_msg); fp = fopen(file, "w"); if(!fp) { merror(FOPEN_ERROR, ARGV0, file); } } else if(strncmp(tmp_msg, FILE_CLOSE_HEADER, strlen(FILE_CLOSE_HEADER)) == 0) { /* no error */ os_md5 currently_md5; /* Making sure to close for the rename to work */ if(fp) { fclose(fp); fp = NULL; } if(file[0] == '\0') { /* nada */ } else if(OS_MD5_File(file, currently_md5) < 0) { /* Removing file */ unlink(file); file[0] = '\0'; } else { if(strcmp(currently_md5, file_sum) != 0) { debug1("%s: Failed md5 for: %s -- deleting.", ARGV0, file); unlink(file); } else { char *final_file; /* Renaming the file to its orignal name */ final_file = strrchr(file, '/'); if(final_file) { if(strcmp(final_file + 1, SHAREDCFG_FILENAME) == 0) { UnmergeFiles(file, SHAREDCFG_DIR); } } else { unlink(file); } } file[0] = '\0'; } } else { merror("%s: WARN: Unknown message received from server.", ARGV0); } } else if(fp) { available_server = (int)time(NULL); fprintf(fp, "%s", tmp_msg); } else { merror("%s: WARN: Unknown message received. No action defined.", ARGV0); } } } /* Cleaning up */ if(fp) { fclose(fp); if(file[0] != '\0') unlink(file); } return(NULL); }