new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / addagent / main.c
1 /* Copyright (C) 2019 OSSEC Foundation
2  * All rights reserved.
3  *
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
7  * Foundation
8  */
9
10 #include "manage_agents.h"
11 #include <stdlib.h>
12
13 /* Prototypes */
14 static void helpmsg(void) __attribute__((noreturn));
15 static void print_banner(void);
16 #ifndef WIN32
17 static void manage_shutdown(int sig) __attribute__((noreturn));
18 #endif
19
20
21 #if defined(__MINGW32__)
22 static int setenv(const char *name, const char *val, __attribute__((unused)) int overwrite)
23 {
24     int len = strlen(name) + strlen(val) + 2;
25     char *str = (char *)malloc(len);
26     if(str == NULL) {
27         merror("%s: malloc failed", ARGV0);
28         exit(errno);
29     }
30     snprintf(str, len, "%s=%s", name, val);
31     putenv(str);
32     return 0;
33 }
34 #endif
35
36 static void helpmsg()
37 {
38     print_header();
39     print_out("  %s: -[Vhlj] [-a <ip> -n <name>] [-d sec] [-e id] [-r id] [-i id] [-f file]", ARGV0);
40     print_out("    -V          Version and license message");
41     print_out("    -h          This help message");
42     print_out("    -j          Use JSON output");
43     print_out("    -l          List available agents.");
44     print_out("    -a <ip>     Add new agent");
45
46     print_out("    -e <id>     Extracts key for an agent (Manager only)");
47     print_out("    -r <id>     Remove an agent (Manager only)");
48     print_out("    -i <id>     Import authentication key (Agent only)");
49     print_out("    -n <name>   Name for new agent");
50     print_out("    -F <sec>    Remove agents with duplicated IP if disconnected since <sec> seconds");
51     print_out("    -f <file>   Bulk generate client keys from file (Manager only)");
52     print_out("                <file> contains lines in IP,NAME format");
53     print_out("                <file> should also exist within /var/ossec due to manage_agents chrooting");
54     exit(1);
55 }
56
57 static void print_banner()
58 {
59     printf("\n");
60     printf(BANNER, __ossec_name, __version);
61
62 #ifdef CLIENT
63     printf(BANNER_CLIENT);
64 #else
65     printf(BANNER_OPT);
66 #endif
67
68     return;
69 }
70
71 #ifndef WIN32
72 /* Clean shutdown on kill */
73 static void manage_shutdown(__attribute__((unused)) int sig)
74 {
75     /* Checking if restart message is necessary */
76     if (restart_necessary) {
77         printf(MUST_RESTART);
78     } else {
79         printf("\n");
80     }
81     printf(EXIT);
82
83     exit(0);
84 }
85 #endif
86
87 int main(int argc, char **argv)
88 {
89     char *user_msg;
90     int c = 0, cmdlist = 0, json_output = 0;
91     int force_antiquity;
92     char *end;
93     const char *cmdexport = NULL;
94     const char *cmdimport = NULL;
95     const char *cmdbulk = NULL;
96 #ifndef WIN32
97     const char *dir = DEFAULTDIR;
98     const char *group = GROUPGLOBAL;
99     gid_t gid;
100 #else
101     FILE *fp;
102     TCHAR path[2048];
103     DWORD last_error;
104     int ret;
105 #endif
106
107     extern int willchroot;
108     willchroot = 1;
109
110     /* Set the name */
111     OS_SetName(ARGV0);
112
113     while ((c = getopt(argc, argv, "Vhle:r:i:f:ja:n:F:")) != -1) {
114         switch (c) {
115             case 'V':
116                 print_version();
117                 break;
118             case 'h':
119                 helpmsg();
120                 break;
121             case 'e':
122 #ifdef CLIENT
123                 ErrorExit("%s: Key export only available on a master.", ARGV0);
124 #endif
125                 if (!optarg) {
126                     ErrorExit("%s: -e needs an argument.", ARGV0);
127                 }
128                 cmdexport = optarg;
129                 break;
130             case 'r':
131 #ifdef CLIENT
132                 ErrorExit("%s: Key removal only available on a master.", ARGV0);
133 #endif
134                 if (!optarg) {
135                     ErrorExit("%s: -r needs an argument.", ARGV0);
136                 }
137
138                 /* Use environment variables already available to remove_agent() */
139                 setenv("OSSEC_ACTION", "r", 1);
140                 setenv("OSSEC_AGENT_ID", optarg, 1);
141                 setenv("OSSEC_ACTION_CONFIRMED", "y", 1);
142                 break;
143             case 'i':
144 #ifndef CLIENT
145                 ErrorExit("%s: Key import only available on an agent.", ARGV0);
146 #endif
147                 if (!optarg) {
148                     ErrorExit("%s: -i needs an argument.", ARGV0);
149                 }
150                 cmdimport = optarg;
151                 break;
152             case 'f':
153 #ifdef CLIENT
154                 ErrorExit("%s: Bulk generate keys only available on a master.", ARGV0);
155 #endif
156                 if (!optarg) {
157                     ErrorExit("%s: -f needs an argument.", ARGV0);
158                 }
159                 cmdbulk = optarg;
160                 willchroot = 0;
161                 printf("Bulk load file: %s\n", cmdbulk);
162                 break;
163             case 'l':
164                 cmdlist = 1;
165                 break;
166             case 'j':
167                 json_output = 1;
168                 break;
169             case 'a':
170 #ifdef CLIENT
171                 ErrorExit("%s: Agent adding only available on a master.", ARGV0);
172 #endif
173                 if (!optarg)
174                     ErrorExit("%s: -a needs an argument.", ARGV0);
175                 setenv("OSSEC_ACTION", "a", 1);
176                 setenv("OSSEC_ACTION_CONFIRMED", "y", 1);
177                 setenv("OSSEC_AGENT_IP", optarg, 1);
178                 setenv("OSSEC_AGENT_ID", "0", 1);
179             break;
180             case 'n':
181                 if (!optarg)
182                     ErrorExit("%s: -n needs an argument.", ARGV0);
183                 setenv("OSSEC_AGENT_NAME", optarg, 1);
184                 break;
185             case 'F':
186                 if (!optarg)
187                     ErrorExit("%s: -d needs an argument.", ARGV0);
188
189                 force_antiquity = strtol(optarg, &end, 10);
190
191                 if (optarg == end || force_antiquity < 0)
192                     ErrorExit("%s: Invalid number for -d", ARGV0);
193
194                 setenv("OSSEC_REMOVE_DUPLICATED", optarg, 1);
195                 break;
196             default:
197                 helpmsg();
198                 break;
199         }
200     }
201
202     /* Get current time */
203     time1 = time(0);
204     restart_necessary = 0;
205
206     /* Before chroot */
207     srandom_init();
208
209 #ifndef WIN32
210     /* Get the group name */
211     gid = Privsep_GetGroup(group);
212     if (gid == (gid_t) - 1) {
213         ErrorExit(USER_ERROR, ARGV0, "", group);
214     }
215
216     /* Set the group */
217     if (Privsep_SetGroup(gid) < 0) {
218         ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
219     }
220
221     /* Inside chroot now */
222     if(willchroot > 0) {
223
224         /* Chroot to the default directory */
225         if (Privsep_Chroot(dir) < 0) {
226             ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
227         }
228
229         nowChroot();
230     }
231
232     /* Start signal handler */
233     StartSIG2(ARGV0, manage_shutdown);
234 #else
235     /* Get full path to the directory this executable lives in */
236     ret = GetModuleFileName(NULL, path, sizeof(path));
237
238     /* Check for errors */
239     if (!ret) {
240         ErrorExit(GMF_ERROR);
241     }
242
243     /* Get last error */
244     last_error = GetLastError();
245
246     /* Look for errors */
247     if (last_error != ERROR_SUCCESS) {
248         if (last_error == ERROR_INSUFFICIENT_BUFFER) {
249             ErrorExit(GMF_BUFF_ERROR, ret, sizeof(path));
250         } else {
251             ErrorExit(GMF_UNKN_ERROR, last_error);
252         }
253     }
254
255     /* Remove file name from path */
256     PathRemoveFileSpec(path);
257
258     /* Move to correct directory */
259     if (chdir(path)) {
260         ErrorExit(CHDIR_ERROR, ARGV0, path, errno, strerror(errno));
261     }
262
263     /* Check permissions */
264     fp = fopen(OSSECCONF, "r");
265     if (fp) {
266         fclose(fp);
267     } else {
268         ErrorExit(CONF_ERROR, OSSECCONF);
269     }
270 #endif
271
272     if (cmdlist == 1) {
273         list_agents(cmdlist);
274         exit(0);
275     } else if (cmdimport) {
276         k_import(cmdimport);
277         exit(0);
278     } else if (cmdexport) {
279         k_extract(cmdexport, json_output);
280         exit(0);
281     } else if (cmdbulk) {
282         k_bulkload(cmdbulk);
283         exit(0);
284     }
285
286     /* Little shell */
287     while (1) {
288         int leave_s = 0;
289
290         if (!json_output)
291             print_banner();
292
293
294         /* Get ACTION from the environment. If ACTION is specified,
295          * we must set leave_s = 1 to ensure that the loop will end */
296         user_msg = getenv("OSSEC_ACTION");
297         if (user_msg == NULL) {
298             user_msg = read_from_user();
299         } else {
300             leave_s = 1;
301         }
302
303         /* All the allowed actions */
304         switch (user_msg[0]) {
305             case 'A':
306             case 'a':
307 #ifdef CLIENT
308                 printf("\n ** Agent adding only available on a master ** \n\n");
309                 break;
310 #endif
311                 add_agent(json_output);
312                 break;
313             case 'e':
314             case 'E':
315 #ifdef CLIENT
316                 printf("\n ** Key export only available on a master ** \n\n");
317                 break;
318 #endif
319                 k_extract(NULL, json_output);
320                 break;
321             case 'i':
322             case 'I':
323 #ifndef CLIENT
324                 printf("\n ** Key import only available on an agent ** \n\n");
325                 break;
326 #else //CLIENT
327                 k_import(NULL);
328                 break;
329 #endif
330             case 'l':
331             case 'L':
332                 list_agents(0);
333                 break;
334             case 'r':
335             case 'R':
336 #ifdef CLIENT
337                 printf("\n ** Key removal only available on a master ** \n\n");
338                 break;
339 #endif
340                 remove_agent(json_output);
341                 break;
342             case 'q':
343             case 'Q':
344                 leave_s = 1;
345                 break;
346             case 'V':
347                 print_version();
348                 break;
349             default:
350                 printf("\n ** Invalid Action ** \n\n");
351                 break;
352         }
353
354         if (leave_s) {
355             break;
356         }
357
358         continue;
359     }
360
361     if (!json_output) {
362         if (restart_necessary) {
363             printf(MUST_RESTART);
364         } else {
365             printf("\n");
366         }
367
368         printf(EXIT);
369     }
370     printf(EXIT);
371
372     return (0);
373 }