1 /* Copyright (C) 2010 Trend Micro Inc.
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 * In addition, as a special exception, the copyright holders give
10 * permission to link the code of portions of this program with the
11 * OpenSSL library under certain conditions as described in each
12 * individual source file, and distribute linked combinations
13 * including the two.
14 *
15 * You must obey the GNU General Public License in all respects
16 * for all of the code used other than OpenSSL. If you modify
17 * file(s) with this exception, you may extend this exception to your
18 * version of the file(s), but you are not obligated to do so. If you
19 * do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source
21 * files in the program, then also delete it here.
22 *
23 */
24
25 #ifndef LIBOPENSSL_ENABLED
26
27 #include <stdlib.h>
28 #include <stdio.h>
main()29 int main()
30 {
31 printf("ERROR: Not compiled. Missing OpenSSL support.\n");
32 exit(0);
33 }
34
35 #else
36
37 #include <sys/wait.h>
38 #include "auth.h"
39 #include "os_crypto/md5/md5_op.h"
40
41 /* TODO: Pulled this value out of the sky, may or may not be sane */
42 #define POOL_SIZE 512
43
44 /* Prototypes */
45 static void help_authd(void) __attribute((noreturn));
46 static int ssl_error(const SSL *ssl, int ret);
47 static void clean_exit(SSL_CTX *ctx, int sock) __attribute__((noreturn));
48
49
50 /* Print help statement */
help_authd()51 static void help_authd()
52 {
53 print_header();
54 print_out(" %s: -[Vhdti] [-g group] [-D dir] [-p port] [-c ciphers] [-v path] [-x path] [-k path]", ARGV0);
55 print_out(" -V Version and license message");
56 print_out(" -h This help message");
57 print_out(" -d Execute in debug mode. This parameter");
58 print_out(" can be specified multiple times");
59 print_out(" to increase the debug level.");
60 print_out(" -t Test configuration");
61 print_out(" -f Run in foreground.");
62 print_out(" -i Use client's source IP address");
63 print_out(" -g <group> Group to run as (default: %s)", GROUPGLOBAL);
64 print_out(" -D <dir> Directory to chroot into (default: %s)", DEFAULTDIR);
65 print_out(" -p <port> Manager port (default: %s)", DEFAULT_PORT);
66 print_out(" -n Disable shared password authentication (not recommended).\n");
67 print_out(" -c SSL cipher list (default: %s)", DEFAULT_CIPHERS);
68 print_out(" -v <path> Full path to CA certificate used to verify clients");
69 print_out(" -x <path> Full path to server certificate");
70 print_out(" -k <path> Full path to server key");
71 print_out(" ");
72 exit(1);
73 }
74
75 /* Generates a random and temporary shared pass to be used by the agents. */
__generatetmppass()76 char *__generatetmppass()
77 {
78 int rand1;
79 int rand2;
80 char *rand3;
81 char *rand4;
82 os_md5 md1;
83 os_md5 md3;
84 os_md5 md4;
85 char *fstring = NULL;
86 char str1[STR_SIZE +1];
87 char *muname = NULL;
88
89 #ifndef WIN32
90 #ifdef __OpenBSD__
91 srandomdev();
92 #else
93 srandom(time(0) + getpid() + getppid());
94 #endif
95 #else
96 srandom(time(0) + getpid());
97 #endif
98
99 rand1 = random();
100 rand2 = random();
101
102 rand3 = GetRandomNoise();
103 rand4 = GetRandomNoise();
104
105 OS_MD5_Str(rand3, md3);
106 OS_MD5_Str(rand4, md4);
107
108 muname = getuname();
109
110 snprintf(str1, STR_SIZE, "%d%d%s%d%s%s",(int)time(0), rand1, muname, rand2, md3, md4);
111 OS_MD5_Str(str1, md1);
112 fstring = strdup(md1);
113 free(rand3);
114 free(rand4);
115 if(muname) {
116 free(muname);
117 }
118 return(fstring);
119 }
120
121 /* Function to use with SSL on non blocking socket,
122 * to know if SSL operation failed for good
123 */
ssl_error(const SSL * ssl,int ret)124 static int ssl_error(const SSL *ssl, int ret)
125 {
126 if (ret <= 0) {
127 switch (SSL_get_error(ssl, ret)) {
128 case SSL_ERROR_WANT_READ:
129 case SSL_ERROR_WANT_WRITE:
130 usleep(100 * 1000);
131 return (0);
132 default:
133 merror("%s: ERROR: SSL Error (%d)", ARGV0, ret);
134 ERR_print_errors_fp(stderr);
135 return (1);
136 }
137 }
138
139 return (0);
140 }
141
clean_exit(SSL_CTX * ctx,int sock)142 static void clean_exit(SSL_CTX *ctx, int sock)
143 {
144 SSL_CTX_free(ctx);
145 close(sock);
146 exit(0);
147 }
148
149 /* Exit handler */
150 static void cleanup();
151
152
153
main(int argc,char ** argv)154 int main(int argc, char **argv)
155 {
156 FILE *fp;
157 char *authpass = NULL;
158 /* Bucket to keep pids in */
159 int process_pool[POOL_SIZE];
160 /* Count of pids we are wait()ing on */
161 int c = 0, test_config = 0, use_ip_address = 0, pid = 0, status, i = 0, active_processes = 0;
162 int use_pass = 1;
163 int run_foreground = 0;
164 gid_t gid;
165 int client_sock = 0, sock = 0, portnum, ret = 0;
166 char *port = DEFAULT_PORT;
167 char *ciphers = DEFAULT_CIPHERS;
168 const char *dir = DEFAULTDIR;
169 const char *group = GROUPGLOBAL;
170 const char *server_cert = NULL;
171 const char *server_key = NULL;
172 const char *ca_cert = NULL;
173 char buf[4096 + 1];
174 SSL_CTX *ctx;
175 SSL *ssl;
176 char srcip[IPSIZE + 1];
177 struct sockaddr_storage _nc;
178 socklen_t _ncl;
179 fd_set fdsave, fdwork; /* select() work areas */
180 int fdmax; /* max socket number + 1 */
181 OSNetInfo *netinfo; /* bound network sockets */
182 int esc = 0; /* while() escape flag */
183
184 /* Initialize some variables */
185 memset(srcip, '\0', IPSIZE + 1);
186 memset(process_pool, 0x0, POOL_SIZE * sizeof(*process_pool));
187 bio_err = 0;
188
189 OS_PassEmptyKeyfile();
190
191 /* Set the name */
192 OS_SetName(ARGV0);
193
194 while ((c = getopt(argc, argv, "Vdhtfig:D:m:p:c:v:x:k:n")) != -1) {
195 switch (c) {
196 case 'V':
197 print_version();
198 break;
199 case 'h':
200 help_authd();
201 break;
202 case 'd':
203 nowDebug();
204 break;
205 case 'i':
206 use_ip_address = 1;
207 break;
208 case 'g':
209 if (!optarg) {
210 ErrorExit("%s: -g needs an argument", ARGV0);
211 }
212 group = optarg;
213 break;
214 case 'D':
215 if (!optarg) {
216 ErrorExit("%s: -D needs an argument", ARGV0);
217 }
218 dir = optarg;
219 break;
220 case 't':
221 test_config = 1;
222 break;
223 case 'f':
224 run_foreground = 1;
225 break;
226 case 'n':
227 use_pass = 0;
228 break;
229 case 'p':
230 if (!optarg) {
231 ErrorExit("%s: -%c needs an argument", ARGV0, c);
232 }
233 portnum = atoi(optarg);
234 if (portnum <= 0 || portnum >= 65536) {
235 ErrorExit("%s: Invalid port: %s", ARGV0, optarg);
236 }
237 port = optarg;
238 break;
239 case 'c':
240 if (!optarg) {
241 ErrorExit("%s: -%c needs an argument", ARGV0, c);
242 }
243 ciphers = optarg;
244 break;
245 case 'v':
246 if (!optarg) {
247 ErrorExit("%s: -%c needs an argument", ARGV0, c);
248 }
249 ca_cert = optarg;
250 break;
251 case 'x':
252 if (!optarg) {
253 ErrorExit("%s: -%c needs an argument", ARGV0, c);
254 }
255 server_cert = optarg;
256 break;
257 case 'k':
258 if (!optarg) {
259 ErrorExit("%s: -%c needs an argument", ARGV0, c);
260 }
261 server_key = optarg;
262 break;
263 default:
264 help_authd();
265 break;
266 }
267 }
268
269 /* Start daemon -- NB: need to double fork and setsid */
270 debug1(STARTED_MSG, ARGV0);
271
272 /* Check if the user/group given are valid */
273 gid = Privsep_GetGroup(group);
274 if (gid == (gid_t) - 1) {
275 ErrorExit(USER_ERROR, ARGV0, "", group);
276 }
277
278 if (!run_foreground) {
279 nowDaemon();
280 goDaemon();
281 }
282
283 /* Create PID files */
284 if (CreatePID(ARGV0, getpid()) < 0) {
285 ErrorExit(PID_ERROR, ARGV0);
286 }
287
288 /* Exit here if test config is set */
289 if (test_config) {
290 exit(0);
291 }
292
293 /* Privilege separation */
294 if (Privsep_SetGroup(gid) < 0) {
295 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
296 }
297
298 /* chroot -- TODO: this isn't a chroot. Should also close
299 * unneeded open file descriptors (like stdin/stdout)
300 */
301 if (chdir(dir) == -1) {
302 ErrorExit(CHDIR_ERROR, ARGV0, dir, errno, strerror(errno));
303 }
304
305 /* Signal manipulation */
306 StartSIG(ARGV0);
307
308
309 /* Create PID files */
310 if (CreatePID(ARGV0, getpid()) < 0) {
311 ErrorExit(PID_ERROR, ARGV0);
312 }
313
314 atexit(cleanup);
315
316 /* Start up message */
317 verbose(STARTUP_MSG, ARGV0, (int)getpid());
318
319 if (use_pass) {
320
321 /* Checking if there is a custom password file */
322 fp = fopen(AUTHDPASS_PATH, "r");
323 buf[0] = '\0';
324 if (fp) {
325 buf[4096] = '\0';
326 char *ret = fgets(buf, 4095, fp);
327
328 if (ret && strlen(buf) > 2) {
329 /* Remove newline */
330 buf[strlen(buf) - 1] = '\0';
331 authpass = strdup(buf);
332 }
333
334 fclose(fp);
335 }
336
337 if (buf[0] != '\0')
338 verbose("Accepting connections. Using password specified on file: %s",AUTHDPASS_PATH);
339 else {
340 /* Getting temporary pass. */
341 authpass = __generatetmppass();
342 verbose("Accepting connections. Random password chosen for agent authentication: %s", authpass);
343 }
344 } else {
345 verbose("Accepting connections. No password required (not recommended)");
346 }
347
348 /* Getting SSL cert. */
349
350 fp = fopen(KEYSFILE_PATH, "a");
351 if (!fp) {
352 merror("%s: ERROR: Unable to open %s (key file)", ARGV0, KEYSFILE_PATH);
353 exit(1);
354 }
355 fclose(fp);
356
357 /* Start SSL */
358 ctx = os_ssl_keys(1, dir, ciphers, server_cert, server_key, ca_cert);
359 if (!ctx) {
360 merror("%s: ERROR: SSL error. Exiting.", ARGV0);
361 exit(1);
362 }
363
364 /* Connect via TCP */
365 netinfo = OS_Bindporttcp(port, NULL);
366 if (netinfo->status < 0) {
367 merror("%s: Unable to bind to port %s", ARGV0, port);
368 exit(1);
369 }
370
371 /* initialize select() save area */
372 fdsave = netinfo->fdset;
373 fdmax = netinfo->fdmax; /* value preset to max fd + 1 */
374
375 debug1("%s: DEBUG: Going into listening mode.", ARGV0);
376
377 /* Setup random */
378 srandom_init();
379
380 /* Chroot */
381 /*
382 if (Privsep_Chroot(dir) < 0)
383 ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
384
385 nowChroot();
386 */
387
388 while (1) {
389 /* No need to completely pin the cpu, 100ms should be fast enough */
390 usleep(100 * 1000);
391
392 /* Only check process-pool if we have active processes */
393 if (active_processes > 0) {
394 for (i = 0; i < POOL_SIZE; i++) {
395 int rv = 0;
396 status = 0;
397 if (process_pool[i]) {
398 rv = waitpid(process_pool[i], &status, WNOHANG);
399 if (rv != 0) {
400 debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]);
401 process_pool[i] = 0;
402 active_processes = active_processes - 1;
403 }
404 }
405 }
406 }
407 memset(&_nc, 0, sizeof(_nc));
408 _ncl = sizeof(_nc);
409
410 fdwork = fdsave;
411 if (select (fdmax, &fdwork, NULL, NULL, NULL) < 0) {
412 ErrorExit("ERROR: Call to os_auth select() failed, errno %d - %s",
413 errno, strerror (errno));
414 }
415
416 /* read through socket list for active socket */
417 for (sock = 0; sock <= fdmax; sock++) {
418 if (FD_ISSET (sock, &fdwork)) {
419 if ((client_sock = accept(sock, (struct sockaddr *) &_nc, &_ncl)) > 0) {
420 if (active_processes >= POOL_SIZE) {
421 merror("%s: Error: Max concurrency reached. Unable to fork", ARGV0);
422 esc = 1; /* exit while(1) loop */
423 break;
424 }
425 pid = fork();
426 if (pid) {
427 active_processes = active_processes + 1;
428 close(client_sock);
429 for (i = 0; i < POOL_SIZE; i++) {
430 if (! process_pool[i]) {
431 process_pool[i] = pid;
432 break;
433 }
434 }
435 } else {
436 satop((struct sockaddr *) &_nc, srcip, IPSIZE);
437 char *agentname = NULL;
438 ssl = SSL_new(ctx);
439 SSL_set_fd(ssl, client_sock);
440
441 do {
442 ret = SSL_accept(ssl);
443
444 if (ssl_error(ssl, ret)) {
445 clean_exit(ctx, client_sock);
446 }
447
448 } while (ret <= 0);
449 verbose("%s: INFO: New connection from %s", ARGV0, srcip);
450 buf[0] = '\0';
451
452 do {
453 ret = SSL_read(ssl, buf, sizeof(buf));
454
455 if (ssl_error(ssl, ret)) {
456 clean_exit(ctx, client_sock);
457 }
458
459 } while (ret <= 0);
460
461 int parseok = 0;
462 char *tmpstr = buf;
463
464 /* Checking for shared password authentication. */
465 if(authpass) {
466 /* Format is pretty simple: OSSEC PASS: PASS WHATEVERACTION */
467 if (strncmp(tmpstr, "OSSEC PASS: ", 12) == 0) {
468 tmpstr = tmpstr + 12;
469
470 if (strlen(tmpstr) > strlen(authpass) && strncmp(tmpstr, authpass, strlen(authpass)) == 0) {
471 tmpstr += strlen(authpass);
472
473 if (*tmpstr == ' ') {
474 tmpstr++;
475 parseok = 1;
476 }
477 }
478 }
479 if (parseok == 0) {
480 merror("%s: ERROR: Invalid password provided by %s. Closing connection.", ARGV0, srcip);
481 SSL_CTX_free(ctx);
482 close(client_sock);
483 exit(0);
484 }
485 }
486
487 /* Checking for action A (add agent) */
488 parseok = 0;
489 if (strncmp(tmpstr, "OSSEC A:'", 9) == 0) {
490 agentname = tmpstr + 9;
491 tmpstr += 9;
492 while (*tmpstr != '\0') {
493 if (*tmpstr == '\'') {
494 *tmpstr = '\0';
495 verbose("%s: INFO: Received request for a new agent (%s) from: %s", ARGV0, agentname, srcip);
496 parseok = 1;
497 break;
498 }
499 tmpstr++;
500 }
501 }
502 if (parseok == 0) {
503 merror("%s: ERROR: Invalid request for new agent from: %s", ARGV0, srcip);
504 } else {
505 int acount = 2;
506 char fname[2048 + 1];
507 char response[2048 + 1];
508 char *finalkey = NULL;
509 response[2048] = '\0';
510 fname[2048] = '\0';
511 if (!OS_IsValidName(agentname)) {
512 merror("%s: ERROR: Invalid agent name: %s from %s", ARGV0, agentname, srcip);
513 snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname);
514 SSL_write(ssl, response, strlen(response));
515 snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
516 SSL_write(ssl, response, strlen(response));
517 sleep(1);
518 exit(0);
519 }
520
521 /* Check for duplicate names */
522 strncpy(fname, agentname, 2048);
523 while (NameExist(fname)) {
524 snprintf(fname, 2048, "%s%d", agentname, acount);
525 acount++;
526 if (acount > 256) {
527 merror("%s: ERROR: Invalid agent name %s (duplicated)", ARGV0, agentname);
528 snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname);
529 SSL_write(ssl, response, strlen(response));
530 snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
531 SSL_write(ssl, response, strlen(response));
532 sleep(1);
533 exit(0);
534 }
535 }
536 agentname = fname;
537
538 /* Check for duplicate IP addresses */
539 char *check_ip_address = NULL;
540 check_ip_address = IPExist(srcip);
541 if(check_ip_address) {
542 merror("%s: ERROR: Invalid IP address %s (duplicated)", ARGV0, check_ip_address);
543 snprintf(response, 2048, "ERROR: Invalid IP address: %s\n\n", check_ip_address);
544 SSL_write(ssl, response, strlen(response));
545 snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
546 SSL_write(ssl, response, strlen(response));
547 sleep(1);
548 exit(0);
549 }
550
551 /* Add the new agent */
552 if (use_ip_address) {
553 finalkey = OS_AddNewAgent(agentname, srcip, NULL);
554 } else {
555 finalkey = OS_AddNewAgent(agentname, NULL, NULL);
556 }
557 if (!finalkey) {
558 merror("%s: ERROR: Unable to add agent: %s (internal error)", ARGV0, agentname);
559 snprintf(response, 2048, "ERROR: Internal manager error adding agent: %s\n\n", agentname);
560 SSL_write(ssl, response, strlen(response));
561 snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
562 SSL_write(ssl, response, strlen(response));
563 sleep(1);
564 exit(0);
565 }
566
567 snprintf(response, 2048, "OSSEC K:'%s'\n\n", finalkey);
568 verbose("%s: INFO: Agent key generated for %s (requested by %s)", ARGV0, agentname, srcip);
569 ret = SSL_write(ssl, response, strlen(response));
570 if (ret < 0) {
571 merror("%s: ERROR: SSL write error (%d)", ARGV0, ret);
572 merror("%s: ERROR: Agen key not saved for %s", ARGV0, agentname);
573 ERR_print_errors_fp(stderr);
574 } else {
575 verbose("%s: INFO: Agent key created for %s (requested by %s)", ARGV0, agentname, srcip);
576 }
577 }
578
579 clean_exit(ctx, client_sock);
580 }
581 }
582 } /* if active socket */
583 } /* for() loop on available sockets */
584
585 /* check for while() escape flag */
586 if (esc == 1)
587 break;
588
589 } /* while(1) loop for messages */
590
591 /* Shut down the socket */
592 clean_exit(ctx, sock);
593
594 return (0);
595 }
596
597 /* Exit handler */
cleanup()598 static void cleanup() {
599 DeletePID(ARGV0);
600 }
601 #endif /* LIBOPENSSL_ENABLED */
602