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 "os_crypto/md5/md5_op.h"
12 #include "external/cJSON/cJSON.h"
13 #include <stdlib.h>
14
15
16 /* Prototypes */
17 static char *trimwhitespace(char *str);
18
19
trimwhitespace(char * str)20 static char *trimwhitespace(char *str)
21 {
22 char *end;
23
24 /* Trim leading space */
25 while (isspace(*str)) {
26 str++;
27 }
28
29 if (*str == 0) { /* All spaces? */
30 return str;
31 }
32
33 /* Trim trailing space */
34 end = str + strlen(str) - 1;
35 while (end > str && isspace(*end)) {
36 end--;
37 }
38
39 /* Write new null terminator */
40 *(end + 1) = 0;
41
42 return str;
43 }
44
45 /* Import a key */
k_import(const char * cmdimport)46 int k_import(const char *cmdimport)
47 {
48 FILE *fp;
49 const char *user_input;
50 char *b64_dec;
51
52 char *name;
53 char *ip;
54 char *tmp_key;
55
56 char line_read[FILE_SIZE + 1];
57
58 char auth_file_tmp[] = AUTH_FILE;
59 char *keys_file = basename_ex(auth_file_tmp);
60
61 char tmp_path[strlen(TMP_DIR) + 1 + strlen(keys_file) + 6 + 1];
62
63 snprintf(tmp_path, sizeof(tmp_path), "%s/%sXXXXXX", TMP_DIR, keys_file);
64
65 /* Parse user argument */
66 if (cmdimport) {
67 user_input = cmdimport;
68 } else {
69 printf(IMPORT_KEY);
70
71 user_input = getenv("OSSEC_AGENT_KEY");
72 if (user_input == NULL) {
73 user_input = read_from_user();
74 }
75 }
76
77 /* Quit */
78 if (strcmp(user_input, QUIT) == 0) {
79 return (0);
80 }
81
82 b64_dec = decode_base64(user_input);
83 if (b64_dec == NULL) {
84 printf(NO_KEY);
85 printf(PRESS_ENTER);
86 read_from_user();
87 return (0);
88 }
89
90 memset(line_read, '\0', FILE_SIZE + 1);
91 strncpy(line_read, b64_dec, FILE_SIZE);
92
93 name = strchr(b64_dec, ' ');
94 if (name && strlen(line_read) < FILE_SIZE) {
95 *name = '\0';
96 name++;
97 ip = strchr(name, ' ');
98 if (ip) {
99 *ip = '\0';
100 ip++;
101
102 tmp_key = strchr(ip, ' ');
103 if (!tmp_key) {
104 printf(NO_KEY);
105 free(b64_dec);
106 return (0);
107 }
108 *tmp_key = '\0';
109
110 printf("\n");
111 printf(AGENT_INFO, b64_dec, name, ip);
112
113 while (1) {
114 printf(ADD_CONFIRM);
115 fflush(stdout);
116
117 user_input = getenv("OSSEC_ACTION_CONFIRMED");
118 if (user_input == NULL) {
119 user_input = read_from_user();
120 }
121
122 if (user_input[0] == 'y' || user_input[0] == 'Y') {
123 if (mkstemp_ex(tmp_path)) {
124 ErrorExit(MKSTEMP_ERROR, ARGV0, tmp_path, errno, strerror(errno));
125 }
126
127 #ifndef WIN32
128 if (chmod(tmp_path, 0440) == -1) {
129 if (unlink(tmp_path)) {
130 verbose(DELETE_ERROR, ARGV0, tmp_path, errno, strerror(errno));
131 }
132
133 ErrorExit(CHMOD_ERROR, ARGV0, tmp_path, errno, strerror(errno));
134 }
135 #endif
136
137 fp = fopen(tmp_path, "w");
138 if (!fp) {
139 if (unlink(tmp_path)) {
140 verbose(DELETE_ERROR, ARGV0, tmp_path, errno, strerror(errno));
141 }
142
143 ErrorExit(FOPEN_ERROR, ARGV0, tmp_path, errno, strerror(errno));
144 }
145 fprintf(fp, "%s\n", line_read);
146 fclose(fp);
147
148 if (rename_ex(tmp_path, KEYS_FILE)) {
149 if (unlink(tmp_path)) {
150 verbose(DELETE_ERROR, ARGV0, tmp_path, errno, strerror(errno));
151 }
152
153 ErrorExit(RENAME_ERROR, ARGV0, tmp_path, KEYS_FILE, errno, strerror(errno));
154 }
155
156 /* Remove sender counter */
157 OS_RemoveCounter("sender");
158
159 printf(ADDED);
160 printf(PRESS_ENTER);
161 read_from_user();
162 restart_necessary = 1;
163
164 free(b64_dec);
165 return (1);
166 } else { /* if(user_input[0] == 'n' || user_input[0] == 'N') */
167 printf("%s", ADD_NOT);
168
169 free(b64_dec);
170 return (0);
171 }
172 }
173 }
174 }
175
176 printf(NO_KEY);
177 printf(PRESS_ENTER);
178 read_from_user();
179
180 free(b64_dec);
181 return (0);
182 }
183
184 /* Extract base64 for a specific agent */
k_extract(const char * cmdextract,int json_output)185 int k_extract(const char *cmdextract, int json_output)
186 {
187 FILE *fp;
188 char *user_input;
189 char *b64_enc;
190 char line_read[FILE_SIZE + 1];
191 char n_id[USER_SIZE + 1];
192 cJSON *json_root = NULL;
193
194 if (json_output)
195 json_root = cJSON_CreateObject();
196
197 if (cmdextract) {
198 user_input = strdup(cmdextract);
199 FormatID(user_input);
200
201 if (!IDExist(user_input)) {
202 if (json_output) {
203 char buffer[1024];
204 snprintf(buffer, 1023, "Invalid ID '%s' given. ID is not present", user_input);
205 cJSON_AddNumberToObject(json_root, "error", 70);
206 cJSON_AddStringToObject(json_root, "description", buffer);
207 printf("%s", cJSON_PrintUnformatted(json_root));
208 } else
209 printf(NO_ID, user_input);
210 exit(1);
211 }
212 } else {
213 if (!print_agents(0, 0, 0, 0)) {
214 printf(NO_AGENT);
215 printf(PRESS_ENTER);
216 read_from_user();
217 return (0);
218 }
219
220 while (1) {
221 printf(EXTRACT_KEY);
222 fflush(stdout);
223 user_input = read_from_user();
224
225 /* quit */
226 if (strcmp(user_input, QUIT) == 0) {
227 return (0);
228 }
229
230 FormatID(user_input);
231
232 if (IDExist(user_input)) {
233 break;
234 } else {
235 printf(NO_ID, user_input);
236 }
237
238 }
239 }
240
241 /* Try to open the auth file */
242 char authfile[257];
243 extern int willchroot;
244 if(willchroot > 0) {
245 snprintf(authfile, 256, "%s", AUTH_FILE); //XXX
246 } else {
247 const char *dir = DEFAULTDIR;
248 snprintf(authfile, 256, "%s/%s", dir, AUTH_FILE); //XXX
249 }
250
251 fp = fopen(authfile, "r");
252 if (!fp) {
253 if (json_output) {
254 char buffer[1024];
255 snprintf(buffer, 1023, "Could not open file '%s' due to [(%d)-(%s)]", AUTH_FILE, errno, strerror(errno));
256 cJSON_AddNumberToObject(json_root, "error", 71);
257 cJSON_AddStringToObject(json_root, "description", buffer);
258 printf("%s", cJSON_PrintUnformatted(json_root));
259 exit(1);
260 } else
261 ErrorExit(FOPEN_ERROR, ARGV0, AUTH_FILE, errno, strerror(errno));
262
263
264 }
265
266 if (fsetpos(fp, &fp_pos)) {
267 if (json_output) {
268 cJSON_AddNumberToObject(json_root, "error", 72);
269 cJSON_AddStringToObject(json_root, "description", "Can not set fileposition");
270 printf("%s", cJSON_PrintUnformatted(json_root));
271 } else
272 merror("%s: Can not set fileposition.", ARGV0);
273 exit(1);
274 }
275
276 memset(n_id, '\0', USER_SIZE + 1);
277 strncpy(n_id, user_input, USER_SIZE - 1);
278
279 if (fgets(line_read, FILE_SIZE, fp) == NULL) {
280 if (json_output) {
281 cJSON_AddNumberToObject(json_root, "error", 73);
282 cJSON_AddStringToObject(json_root, "description", "Unable to handle keys file");
283 printf("%s", cJSON_PrintUnformatted(json_root));
284 } else
285 printf(ERROR_KEYS);
286
287
288 exit(1);
289 }
290 chomp(line_read);
291
292 b64_enc = encode_base64(strlen(line_read), line_read);
293 if (b64_enc == NULL) {
294 if (json_output) {
295 cJSON_AddNumberToObject(json_root, "error", 74);
296 cJSON_AddStringToObject(json_root, "description", "Unable to extract agent key");
297 printf("%s", cJSON_PrintUnformatted(json_root));
298 } else
299 printf(EXTRACT_ERROR);
300 exit(1);
301 }
302
303 if (json_output) {
304 cJSON_AddNumberToObject(json_root, "error", 0);
305 cJSON_AddStringToObject(json_root, "response", b64_enc);
306 printf("%s", cJSON_PrintUnformatted(json_root));
307 } else
308 printf(EXTRACT_MSG, n_id, b64_enc);
309
310
311 if (!cmdextract) {
312 printf("\n" PRESS_ENTER);
313 read_from_user();
314 }
315
316 free(b64_enc);
317 fclose(fp);
318
319 return (0);
320 }
321
322 /* Bulk generate client keys from file */
k_bulkload(const char * cmdbulk)323 int k_bulkload(const char *cmdbulk)
324 {
325 int i = 1;
326 FILE *fp, *infp;
327 char str1[STR_SIZE + 1];
328 char str2[STR_SIZE + 1];
329
330 os_md5 md1;
331 os_md5 md2;
332 char line[FILE_SIZE + 1];
333 char name[FILE_SIZE + 1];
334 char id[FILE_SIZE + 1];
335 char ip[FILE_SIZE + 1];
336 char delims[] = ",";
337 char *token = NULL;
338
339 /* Check if we can open the input file */
340 printf("Opening: [%s]\n", cmdbulk);
341 infp = fopen(cmdbulk, "r");
342 if (!infp) {
343 perror("Failed.");
344 ErrorExit(FOPEN_ERROR, ARGV0, cmdbulk, errno, strerror(errno));
345 }
346
347 /* Check if we can open the auth_file */
348 char authfile[257];
349 if(willchroot > 0) {
350 snprintf(authfile, 256, "%s", AUTH_FILE); //XXX
351 } else {
352 const char *dir = DEFAULTDIR;
353 snprintf(authfile, 256, "%s/%s", dir, AUTH_FILE); //XXX
354 }
355
356 fp = fopen(authfile, "a");
357 if (!fp) {
358 ErrorExit(FOPEN_ERROR, ARGV0, authfile, errno, strerror(errno));
359 }
360 fclose(fp);
361
362 while (fgets(line, FILE_SIZE - 1, infp) != NULL) {
363 os_ip c_ip;
364 c_ip.ip = NULL;
365
366 if (1 >= strlen(trimwhitespace(line))) {
367 continue;
368 }
369
370 memset(ip, '\0', FILE_SIZE + 1);
371 token = strtok(line, delims);
372 strncpy(ip, trimwhitespace(token), FILE_SIZE - 1);
373
374 memset(name, '\0', FILE_SIZE + 1);
375 token = strtok(NULL, delims);
376 strncpy(name, trimwhitespace(token), FILE_SIZE - 1);
377
378 #ifndef WIN32
379 if (chmod(authfile, 0440) == -1) {
380 ErrorExit(CHMOD_ERROR, ARGV0, authfile, errno, strerror(errno));
381 }
382 #endif
383
384 /* Set time 2 */
385 time2 = time(0);
386
387 srandom_init();
388 rand1 = random();
389
390 /* Zero strings */
391 memset(str1, '\0', STR_SIZE + 1);
392 memset(str2, '\0', STR_SIZE + 1);
393
394 /* Check the name */
395 if (!OS_IsValidName(name)) {
396 printf(INVALID_NAME, name);
397 continue;
398 }
399
400 /* Search for name -- no duplicates */
401 if (NameExist(name)) {
402 printf(ADD_ERROR_NAME, name);
403 continue;
404 }
405
406 if (!OS_IsValidIP(ip, &c_ip)) {
407 printf(IP_ERROR, ip);
408 continue;
409 }
410
411 /* Default ID */
412 i = MAX_AGENTS + 32512;
413 snprintf(id, 8, "%03d", i);
414 while (!IDExist(id)) {
415 i--;
416 snprintf(id, 8, "%03d", i);
417
418 /* No key present, use id 0 */
419 if (i <= 0) {
420 i = 0;
421 break;
422 }
423 }
424 snprintf(id, 8, "%03d", i + 1);
425
426 if (!OS_IsValidID(id)) {
427 printf(INVALID_ID, id);
428 goto cleanup;
429 }
430
431 /* Search for ID KEY -- no duplicates */
432 if (IDExist(id)) {
433 printf(NO_DEFAULT, i + 1);
434 goto cleanup;
435 }
436
437 printf(AGENT_INFO, id, name, ip);
438 fflush(stdout);
439
440 time3 = time(0);
441 rand2 = random();
442
443 fp = fopen(authfile, "a");
444 if (!fp) {
445 ErrorExit(FOPEN_ERROR, ARGV0, KEYS_FILE, errno, strerror(errno));
446 }
447 #ifndef WIN32
448 if (chmod(authfile, 0440) == -1) {
449 ErrorExit(CHMOD_ERROR, ARGV0, authfile, errno, strerror(errno));
450 }
451 #endif
452
453 /* Random 1: Time took to write the agent information
454 * Random 2: Time took to choose the action
455 * Random 3: All of this + time + pid
456 * Random 4: MD5 all of this + the name, key and IP
457 * Random 5: Final key
458 */
459
460 snprintf(str1, STR_SIZE, "%d%s%d", (int)(time3 - time2), name, (int)rand1);
461 snprintf(str2, STR_SIZE, "%d%s%s%d", (int)(time2 - time1), ip, id, (int)rand2);
462
463 OS_MD5_Str(str1, md1);
464 OS_MD5_Str(str2, md2);
465
466 snprintf(str1, STR_SIZE, "%s%d%d%d", md1, (int)getpid(), (int)random(),
467 (int)time3);
468 OS_MD5_Str(str1, md1);
469
470 fprintf(fp, "%s %s %s %s%s\n", id, name, c_ip.ip, md1, md2);
471 fclose(fp);
472
473 printf(AGENT_ADD, id);
474 restart_necessary = 1;
475
476 cleanup:
477 free(c_ip.ip);
478 };
479
480 fclose(infp);
481 return (0);
482 }
483