1 /* Copyright (C) 2010 Trend Micro Inc.
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
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
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.
25 #ifndef LIBOPENSSL_ENABLED
31 printf("ERROR: Not compiled. Missing OpenSSL support.\n");
39 #include "os_crypto/md5/md5_op.h"
41 /* TODO: Pulled this value out of the sky, may or may not be sane */
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));
50 /* Print help statement */
51 static void help_authd()
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");
75 /* Generates a random and temporary shared pass to be used by the agents. */
76 char *__generatetmppass()
86 char str1[STR_SIZE +1];
93 srandom(time(0) + getpid() + getppid());
96 srandom(time(0) + getpid());
102 rand3 = GetRandomNoise();
103 rand4 = GetRandomNoise();
105 OS_MD5_Str(rand3, md3);
106 OS_MD5_Str(rand4, md4);
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);
121 /* Function to use with SSL on non blocking socket,
122 * to know if SSL operation failed for good
124 static int ssl_error(const SSL *ssl, int ret)
127 switch (SSL_get_error(ssl, ret)) {
128 case SSL_ERROR_WANT_READ:
129 case SSL_ERROR_WANT_WRITE:
133 merror("%s: ERROR: SSL Error (%d)", ARGV0, ret);
134 ERR_print_errors_fp(stderr);
142 static void clean_exit(SSL_CTX *ctx, int sock)
150 static void cleanup();
154 int main(int argc, char **argv)
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;
163 int run_foreground = 0;
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;
176 char srcip[IPSIZE + 1];
177 struct sockaddr_storage _nc;
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 */
184 /* Initialize some variables */
185 memset(srcip, '\0', IPSIZE + 1);
186 memset(process_pool, 0x0, POOL_SIZE * sizeof(*process_pool));
189 OS_PassEmptyKeyfile();
194 while ((c = getopt(argc, argv, "Vdhtfig:D:m:p:c:v:x:k:n")) != -1) {
210 ErrorExit("%s: -g needs an argument", ARGV0);
216 ErrorExit("%s: -D needs an argument", ARGV0);
231 ErrorExit("%s: -%c needs an argument", ARGV0, c);
233 portnum = atoi(optarg);
234 if (portnum <= 0 || portnum >= 65536) {
235 ErrorExit("%s: Invalid port: %s", ARGV0, optarg);
241 ErrorExit("%s: -%c needs an argument", ARGV0, c);
247 ErrorExit("%s: -%c needs an argument", ARGV0, c);
253 ErrorExit("%s: -%c needs an argument", ARGV0, c);
255 server_cert = optarg;
259 ErrorExit("%s: -%c needs an argument", ARGV0, c);
269 /* Start daemon -- NB: need to double fork and setsid */
270 debug1(STARTED_MSG, ARGV0);
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);
278 if (!run_foreground) {
283 /* Create PID files */
284 if (CreatePID(ARGV0, getpid()) < 0) {
285 ErrorExit(PID_ERROR, ARGV0);
288 /* Exit here if test config is set */
293 /* Privilege separation */
294 if (Privsep_SetGroup(gid) < 0) {
295 ErrorExit(SETGID_ERROR, ARGV0, group, errno, strerror(errno));
298 /* chroot -- TODO: this isn't a chroot. Should also close
299 * unneeded open file descriptors (like stdin/stdout)
301 if (chdir(dir) == -1) {
302 ErrorExit(CHDIR_ERROR, ARGV0, dir, errno, strerror(errno));
305 /* Signal manipulation */
309 /* Create PID files */
310 if (CreatePID(ARGV0, getpid()) < 0) {
311 ErrorExit(PID_ERROR, ARGV0);
316 /* Start up message */
317 verbose(STARTUP_MSG, ARGV0, (int)getpid());
321 /* Checking if there is a custom password file */
322 fp = fopen(AUTHDPASS_PATH, "r");
326 char *ret = fgets(buf, 4095, fp);
328 if (ret && strlen(buf) > 2) {
330 buf[strlen(buf) - 1] = '\0';
331 authpass = strdup(buf);
338 verbose("Accepting connections. Using password specified on file: %s",AUTHDPASS_PATH);
340 /* Getting temporary pass. */
341 authpass = __generatetmppass();
342 verbose("Accepting connections. Random password chosen for agent authentication: %s", authpass);
345 verbose("Accepting connections. No password required (not recommended)");
348 /* Getting SSL cert. */
350 fp = fopen(KEYSFILE_PATH, "a");
352 merror("%s: ERROR: Unable to open %s (key file)", ARGV0, KEYSFILE_PATH);
358 ctx = os_ssl_keys(1, dir, ciphers, server_cert, server_key, ca_cert);
360 merror("%s: ERROR: SSL error. Exiting.", ARGV0);
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);
371 /* initialize select() save area */
372 fdsave = netinfo->fdset;
373 fdmax = netinfo->fdmax; /* value preset to max fd + 1 */
375 debug1("%s: DEBUG: Going into listening mode.", ARGV0);
382 if (Privsep_Chroot(dir) < 0)
383 ErrorExit(CHROOT_ERROR, ARGV0, dir, errno, strerror(errno));
389 /* No need to completely pin the cpu, 100ms should be fast enough */
392 /* Only check process-pool if we have active processes */
393 if (active_processes > 0) {
394 for (i = 0; i < POOL_SIZE; i++) {
397 if (process_pool[i]) {
398 rv = waitpid(process_pool[i], &status, WNOHANG);
400 debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]);
402 active_processes = active_processes - 1;
407 memset(&_nc, 0, sizeof(_nc));
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));
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 */
427 active_processes = active_processes + 1;
429 for (i = 0; i < POOL_SIZE; i++) {
430 if (! process_pool[i]) {
431 process_pool[i] = pid;
436 satop((struct sockaddr *) &_nc, srcip, IPSIZE);
437 char *agentname = NULL;
439 SSL_set_fd(ssl, client_sock);
442 ret = SSL_accept(ssl);
444 if (ssl_error(ssl, ret)) {
445 clean_exit(ctx, client_sock);
449 verbose("%s: INFO: New connection from %s", ARGV0, srcip);
453 ret = SSL_read(ssl, buf, sizeof(buf));
455 if (ssl_error(ssl, ret)) {
456 clean_exit(ctx, client_sock);
464 /* Checking for shared password authentication. */
466 /* Format is pretty simple: OSSEC PASS: PASS WHATEVERACTION */
467 if (strncmp(tmpstr, "OSSEC PASS: ", 12) == 0) {
468 tmpstr = tmpstr + 12;
470 if (strlen(tmpstr) > strlen(authpass) && strncmp(tmpstr, authpass, strlen(authpass)) == 0) {
471 tmpstr += strlen(authpass);
473 if (*tmpstr == ' ') {
480 merror("%s: ERROR: Invalid password provided by %s. Closing connection.", ARGV0, srcip);
487 /* Checking for action A (add agent) */
489 if (strncmp(tmpstr, "OSSEC A:'", 9) == 0) {
490 agentname = tmpstr + 9;
492 while (*tmpstr != '\0') {
493 if (*tmpstr == '\'') {
495 verbose("%s: INFO: Received request for a new agent (%s) from: %s", ARGV0, agentname, srcip);
503 merror("%s: ERROR: Invalid request for new agent from: %s", ARGV0, srcip);
506 char fname[2048 + 1];
507 char response[2048 + 1];
508 char *finalkey = NULL;
509 response[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));
521 /* Check for duplicate names */
522 strncpy(fname, agentname, 2048);
523 while (NameExist(fname)) {
524 snprintf(fname, 2048, "%s%d", agentname, acount);
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));
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));
551 /* Add the new agent */
552 if (use_ip_address) {
553 finalkey = OS_AddNewAgent(agentname, srcip, NULL);
555 finalkey = OS_AddNewAgent(agentname, NULL, NULL);
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));
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));
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);
575 verbose("%s: INFO: Agent key created for %s (requested by %s)", ARGV0, agentname, srcip);
579 clean_exit(ctx, client_sock);
582 } /* if active socket */
583 } /* for() loop on available sockets */
585 /* check for while() escape flag */
589 } /* while(1) loop for messages */
591 /* Shut down the socket */
592 clean_exit(ctx, sock);
598 static void cleanup() {
601 #endif /* LIBOPENSSL_ENABLED */