1 /* Copyright (C) 2019 OSSEC Foundation
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
10 #include "addagent/manage_agents.h"
12 #include "external/cJSON/cJSON.h"
15 #define ARGV0 "agent_control"
18 static void helpmsg(void) __attribute__((noreturn));
22 printf("\nOSSEC HIDS %s: Control remote agents.\n", ARGV0);
23 printf("Available options:\n");
24 printf("\t-h This help message.\n");
25 printf("\t-l List available (active or not) agents.\n");
26 printf("\t-lc List active agents.\n");
27 printf("\t-i <id> Extracts information from an agent.\n");
28 printf("\t-R <id> Restarts agent.\n");
29 printf("\t-r -a Runs the integrity/rootkit checking on all agents now.\n");
30 printf("\t-r Runs the integrity/rootkit checking on one agent now.\n\n");
31 printf("\t-b <ip> Blocks the specified ip address.\n");
32 printf("\t-f <ar> Used with -b, specifies which response to run.\n");
33 printf("\t-L List available active responses.\n");
34 printf("\t-m Show the limit of agents that can be added.\n");
35 printf("\t-s Changes the output to CSV (comma delimited).\n");
36 printf("\t-j Changes the output to JSON .\n");
37 printf("\t-u <id> Used with -r and -b Specifies the agent to use.\n");
41 int main(int argc, char **argv)
43 const char *dir = DEFAULTDIR;
44 const char *group = GROUPGLOBAL;
45 const char *user = USER;
46 const char *agent_id = NULL;
47 const char *ip_address = NULL;
48 const char *ar = NULL;
56 int restart_syscheck = 0;
57 int restart_all_agents = 0;
64 int list_responses = 0;
66 int restart_agent = 0;
67 int show_max_agents = 0;
81 while ((c = getopt(argc, argv, "VehdlLcsjarmu:i:b:f:R:")) != -1) {
123 merror("%s: -u needs an argument", ARGV0);
130 merror("%s: -b needs an argument", ARGV0);
137 merror("%s: -e needs an argument", ARGV0);
144 merror("%s: -R needs an argument", ARGV0);
151 restart_all_agents = 1;
160 /* Prepare JSON Structure */
162 root = cJSON_CreateObject();
164 /* Get the group name */
165 gid = Privsep_GetGroup(group);
166 uid = Privsep_GetUser(user);
167 if (uid == (uid_t) - 1 || gid == (gid_t) - 1) {
168 ErrorExit(USER_ERROR, ARGV0, user, group);
172 if (Privsep_SetGroup(gid) < 0) {
173 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
176 /* Chroot to the default directory */
177 if (Privsep_Chroot(dir) < 0) {
178 ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
181 /* Inside chroot now */
185 if (Privsep_SetUser(uid) < 0) {
186 ErrorExit(SETUID_ERROR, ARGV0, user, errno, strerror(errno));
189 /* Get server hostname */
190 memset(shost, '\0', 512);
191 if (gethostname(shost, 512 - 1) != 0) {
192 strncpy(shost, "localhost", 32);
197 if (list_responses) {
199 if (!csv_output && !json_output) {
200 printf("\nOSSEC HIDS %s. Available active responses:\n", ARGV0);
203 fp = fopen(DEFAULTAR, "r");
207 while (fgets(buffer, 255, fp) != NULL) {
213 r_cmd = strchr(buffer, ' ');
227 r_timeout = strchr(r_cmd, ' ');
233 if (strcmp(r_name, "restart-ossec0") == 0) {
236 printf("\n Response name: %s, command: %s", r_name, r_cmd);
242 printf("\n No active response available.\n\n");
248 /* List available agents */
250 cJSON *agents = NULL;
252 if (!csv_output && !json_output) {
253 printf("\nOSSEC HIDS %s. List of available agents:",
255 printf("\n ID: 000, Name: %s (server), IP: 127.0.0.1, Active/Local\n",
257 } else if(json_output){
258 cJSON *first = cJSON_CreateObject();
259 agents = cJSON_CreateArray();
261 if (!(first && root && agents))
264 cJSON_AddNumberToObject(root, "error", 0);
265 cJSON_AddItemToObject(root, "response", agents);
267 cJSON_AddStringToObject(first, "id", "000");
268 cJSON_AddStringToObject(first, "name", shost);
269 cJSON_AddStringToObject(first, "ip", "127.0.0.1");
270 cJSON_AddStringToObject(first, "status", "Active");
271 cJSON_AddItemToArray(agents, first);
273 printf("000,%s (server),127.0.0.1,Active/Local,\n", shost);
276 print_agents(1, active_only, csv_output, agents);
277 // Closing JSON Object array
279 char *render = cJSON_PrintUnformatted(root);
280 printf("%s", render);
288 /* Show limit of agents */
290 if (show_max_agents) {
292 cJSON *data = cJSON_CreateObject();
294 if (!(root && data)) {
298 cJSON_AddNumberToObject(data, "max_agents", MAX_AGENTS);
299 cJSON_AddNumberToObject(root, "error", 0);
300 cJSON_AddItemToObject(root, "data", data);
302 char *render = cJSON_PrintUnformatted(root);
303 printf("%s", render);
306 } else if (csv_output) {
307 printf("%d\n", MAX_AGENTS);
309 printf("Limit of agents: %d\n", MAX_AGENTS);
315 /* Check if the provided ID is valid */
316 if (agent_id != NULL) {
317 if (strcmp(agent_id, "000") != 0) {
320 agt_id = OS_IsAllowedID(&keys, agent_id);
323 cJSON_AddNumberToObject(root, "error", 40);
324 cJSON_AddStringToObject(root, "description", "Invalid agent id");
325 printf("%s",cJSON_PrintUnformatted(root));
329 printf("\n** Invalid agent id '%s'.\n", agent_id);
339 /* Print information from an agent */
342 char final_ip[IPSIZE + 4];
343 agent_info *agt_info;
345 final_ip[(sizeof final_ip) - 1] = '\0';
346 cJSON *response = cJSON_CreateObject();
349 if (!csv_output && !json_output) {
350 printf("\nOSSEC HIDS %s. Agent information:", ARGV0);
354 agt_status = get_agent_status(keys.keyentries[agt_id]->name,
355 keys.keyentries[agt_id]->ip->ip);
357 agt_info = get_agent_info(keys.keyentries[agt_id]->name,
358 keys.keyentries[agt_id]->ip->ip);
360 /* Getting full address/prefix length from ip. */
361 snprintf(final_ip, sizeof final_ip, "%s/%u",
362 keys.keyentries[agt_id]->ip->ip,
363 keys.keyentries[agt_id]->ip->prefixlength);
365 if (!csv_output && !json_output) {
366 printf("\n Agent ID: %s\n", keys.keyentries[agt_id]->id);
367 printf(" Agent Name: %s\n", keys.keyentries[agt_id]->name);
368 printf(" IP address: %s\n", final_ip);
369 printf(" Status: %s\n\n", print_agent_status(agt_status));
370 }else if(json_output){
371 cJSON_AddStringToObject(response, "id", keys.keyentries[agt_id]->id);
372 cJSON_AddStringToObject(response, "name", keys.keyentries[agt_id]->name);
373 cJSON_AddStringToObject(response, "ip", final_ip);
374 cJSON_AddStringToObject(response, "status", print_agent_status(agt_status));
377 printf("%s,%s,%s,%s,",
378 keys.keyentries[agt_id]->id,
379 keys.keyentries[agt_id]->name,
381 print_agent_status(agt_status));
384 agt_status = get_agent_status(NULL, NULL);
385 agt_info = get_agent_info(NULL, "127.0.0.1");
387 if (!csv_output && !json_output) {
388 printf("\n Agent ID: 000 \n");
389 printf(" Agent Name: %s\n", shost);
390 printf(" IP address: 127.0.0.1\n");
391 printf(" Status: %s/Local\n\n", print_agent_status(agt_status));
392 }else if(json_output){
393 cJSON_AddStringToObject(response, "id", "000");
394 cJSON_AddStringToObject(response, "name", shost);
395 cJSON_AddStringToObject(response, "ip", "127.0.0.1");
396 cJSON_AddStringToObject(response, "status", print_agent_status(agt_status));
398 printf("000,%s,127.0.0.1,%s/Local,",
400 print_agent_status(agt_status));
404 if (!csv_output && !json_output) {
405 printf(" Operating system: %s\n", agt_info->os);
406 printf(" Client version: %s\n", agt_info->version);
407 printf(" Last keep alive: %s\n\n", agt_info->last_keepalive);
410 printf(" Syscheck last started at: %s\n", agt_info->syscheck_time);
411 printf(" Syscheck last ended at: %s\n", agt_info->syscheck_endtime);
412 printf(" Rootcheck last started at: %s\n", agt_info->rootcheck_time);
413 printf(" Rootcheck last ended at: %s\n\n", agt_info->rootcheck_endtime);
415 printf(" Syscheck last started at: %s\n", agt_info->syscheck_time);
416 printf(" Rootcheck last started at: %s\n", agt_info->rootcheck_time);
418 }else if(json_output){
419 cJSON_AddStringToObject(response, "os", agt_info->os);
420 cJSON_AddStringToObject(response, "version", agt_info->version);
421 cJSON_AddStringToObject(response, "lastKeepAlive", agt_info->last_keepalive);
422 cJSON_AddStringToObject(response, "syscheckTime", agt_info->syscheck_time);
423 cJSON_AddStringToObject(response, "syscheckEndTime", end_time ? agt_info->syscheck_endtime : "");
424 cJSON_AddStringToObject(response, "rootcheckTime", agt_info->rootcheck_time);
425 cJSON_AddStringToObject(response, "rootcheckEndTime", end_time ? agt_info->rootcheck_endtime : "");
428 printf("%s,%s,%s,%s,%s,\n",
431 agt_info->last_keepalive,
432 agt_info->syscheck_time,
433 agt_info->rootcheck_time);
436 cJSON_AddNumberToObject(root, "error", 0);
437 cJSON_AddItemToObject(root, "response", response);
438 printf("%s",cJSON_PrintUnformatted(root));
444 /* Restart syscheck everywhere */
445 if (restart_all_agents && restart_syscheck) {
446 /* Connect to remoted */
447 debug1("%s: DEBUG: Connecting to remoted...", ARGV0);
448 arq = connect_to_remoted();
451 cJSON_AddNumberToObject(root, "error", 41);
452 cJSON_AddStringToObject(root, "description", "Unable to connect to remoted");
453 printf("%s",cJSON_PrintUnformatted(root));
456 printf("\n** Unable to connect to remoted.\n");
460 debug1("%s: DEBUG: Connected...", ARGV0);
462 /* Send restart message to all agents */
463 if (send_msg_to_agent(arq, HC_SK_RESTART, NULL, NULL) == 0) {
465 cJSON_AddNumberToObject(root, "error", 0);
466 cJSON_AddStringToObject(root, "response", "Restarting Syscheck/Rootcheck on all agents");
467 printf("%s",cJSON_PrintUnformatted(root));
470 printf("\nOSSEC HIDS %s: Restarting Syscheck/Rootcheck on all agents.",ARGV0);
474 cJSON_AddNumberToObject(root, "error", 42);
475 cJSON_AddStringToObject(root, "description", "Unable to restart syscheck on all agents");
476 printf("%s",cJSON_PrintUnformatted(root));
479 printf("\n** Unable to restart syscheck on all agents.\n");
487 if (restart_syscheck && agent_id) {
488 /* Restart on the server */
489 if (strcmp(agent_id, "000") == 0) {
490 os_set_restart_syscheck();
492 cJSON_AddNumberToObject(root, "error", 0);
493 cJSON_AddStringToObject(root, "response", "Restarting Syscheck/Rootcheck locally");
494 printf("%s",cJSON_PrintUnformatted(root));
497 printf("\nOSSEC HIDS %s: Restarting Syscheck/Rootcheck ""locally.\n", ARGV0);
502 /* Connect to remoted */
503 debug1("%s: DEBUG: Connecting to remoted...", ARGV0);
504 arq = connect_to_remoted();
507 cJSON_AddNumberToObject(root, "error", 43);
508 cJSON_AddStringToObject(root, "description", "Unable to connect to remoted");
509 printf("%s",cJSON_PrintUnformatted(root));
512 printf("\n** Unable to connect to remoted.\n");
516 debug1("%s: DEBUG: Connected...", ARGV0);
518 if (send_msg_to_agent(arq, HC_SK_RESTART, agent_id, NULL) == 0) {
520 cJSON_AddNumberToObject(root, "error", 0);
521 cJSON_AddStringToObject(root, "response", "Restarting Syscheck/Rootcheck on agent");
522 printf("%s",cJSON_PrintUnformatted(root));
525 printf("\nOSSEC HIDS %s: Restarting Syscheck/Rootcheck on agent: %s\n",ARGV0, agent_id);
529 cJSON_AddNumberToObject(root, "error", 44);
530 cJSON_AddStringToObject(root, "description", "Unable to restart syscheck on agent");
531 printf("%s",cJSON_PrintUnformatted(root));
534 printf("\n** Unable to restart syscheck on agent: %s\n", agent_id);
542 if (restart_agent && agent_id) {
544 /* Connect to remoted */
545 debug1("%s: DEBUG: Connecting to remoted...", ARGV0);
546 arq = connect_to_remoted();
549 cJSON_AddNumberToObject(root, "error", 45);
550 cJSON_AddStringToObject(root, "description", "Unable to connect to remoted");
551 printf("%s",cJSON_PrintUnformatted(root));
554 printf("\n** Unable to connect to remoted.\n");
558 debug1("%s: DEBUG: Connected...", ARGV0);
560 if (send_msg_to_agent(arq, "restart-ossec0", agent_id, "null") == 0) {
563 cJSON_AddNumberToObject(root, "error", 0);
564 cJSON_AddStringToObject(root, "response", "Restarting agent");
565 printf("%s",cJSON_PrintUnformatted(root));
568 printf("\nOSSEC HIDS %s: Restarting agent: %s\n",ARGV0, agent_id);
572 cJSON_AddNumberToObject(root, "error", 46);
573 cJSON_AddStringToObject(root, "description", "Unable to restart agent");
574 printf("%s",cJSON_PrintUnformatted(root));
577 printf("\n** Unable to restart agent: %s\n", agent_id);
585 /* Run active response on the specified agent id */
586 if (ip_address && ar && agent_id) {
587 /* Connect to remoted */
588 debug1("%s: DEBUG: Connecting to remoted...", ARGV0);
589 arq = connect_to_remoted();
591 printf("\n** Unable to connect to remoted.\n");
594 debug1("%s: DEBUG: Connected...", ARGV0);
596 if (send_msg_to_agent(arq, ar, agent_id, ip_address) == 0) {
597 printf("\nOSSEC HIDS %s: Running active response '%s' on: %s\n",
598 ARGV0, ar, agent_id);
600 printf("\n** Unable to restart syscheck on agent: %s\n", agent_id);
607 printf("\n** Invalid argument combination.\n");