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 int willchroot;
21
22 #if defined(__MINGW32__)
setenv(const char * name,const char * val,int overwrite)23 static int setenv(const char *name, const char *val, __attribute__((unused)) int overwrite)
24 {
25 int len = strlen(name) + strlen(val) + 2;
26 char *str = (char *)malloc(len);
27 if(str == NULL) {
28 merror("%s: malloc failed", ARGV0);
29 exit(errno);
30 }
31 snprintf(str, len, "%s=%s", name, val);
32 putenv(str);
33 return 0;
34 }
35 #endif
36
helpmsg()37 static void helpmsg()
38 {
39 print_header();
40 print_out(" %s: -[Vhlj] [-a <ip> -n <name>] [-d sec] [-e id] [-r id] [-i id] [-f file]", ARGV0);
41 print_out(" -V Version and license message");
42 print_out(" -h This help message");
43 print_out(" -j Use JSON output");
44 print_out(" -l List available agents.");
45 print_out(" -a <ip> Add new agent");
46
47 print_out(" -e <id> Extracts key for an agent (Manager only)");
48 print_out(" -r <id> Remove an agent (Manager only)");
49 print_out(" -i <id> Import authentication key (Agent only)");
50 print_out(" -n <name> Name for new agent");
51 print_out(" -F <sec> Remove agents with duplicated IP if disconnected since <sec> seconds");
52 print_out(" -f <file> Bulk generate client keys from file (Manager only)");
53 print_out(" <file> contains lines in IP,NAME format");
54 print_out(" <file> should also exist within /var/ossec due to manage_agents chrooting");
55 exit(1);
56 }
57
print_banner()58 static void print_banner()
59 {
60 printf("\n");
61 printf(BANNER, __ossec_name, __version);
62
63 #ifdef CLIENT
64 printf(BANNER_CLIENT);
65 #else
66 printf(BANNER_OPT);
67 #endif
68
69 return;
70 }
71
72 #ifndef WIN32
73 /* Clean shutdown on kill */
manage_shutdown(int sig)74 static void manage_shutdown(__attribute__((unused)) int sig)
75 {
76 /* Checking if restart message is necessary */
77 if (restart_necessary) {
78 printf(MUST_RESTART);
79 } else {
80 printf("\n");
81 }
82 printf(EXIT);
83
84 exit(0);
85 }
86 #endif
87
main(int argc,char ** argv)88 int main(int argc, char **argv)
89 {
90 char *user_msg;
91 int c = 0, cmdlist = 0, json_output = 0;
92 int force_antiquity;
93 char *end;
94 const char *cmdexport = NULL;
95 const char *cmdimport = NULL;
96 const char *cmdbulk = NULL;
97 #ifndef WIN32
98 const char *dir = DEFAULTDIR;
99 const char *group = GROUPGLOBAL;
100 gid_t gid;
101 #else
102 FILE *fp;
103 TCHAR path[2048];
104 DWORD last_error;
105 int ret;
106 #endif
107
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 }
374