Imported Upstream version 2.7
[ossec-hids.git] / src / os_auth / main-server.c
diff --git a/src/os_auth/main-server.c b/src/os_auth/main-server.c
new file mode 100755 (executable)
index 0000000..cf7982a
--- /dev/null
@@ -0,0 +1,379 @@
+/* @(#) $Id$ */
+
+/* Copyright (C) 2010 Trend Micro Inc.
+ * All rights reserved.
+ *
+ * This program is a free software; you can redistribute it
+ * and/or modify it under the terms of the GNU General Public
+ * License (version 2) as published by the FSF - Free Software
+ * Foundation
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ *
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ *
+ */
+
+
+#include "shared.h"
+#include "auth.h"
+
+/* TODO: Pulled this value out of the sky, may or may not be sane */
+int POOL_SIZE = 512;
+
+/* ossec-reportd - Runs manual reports. */
+void report_help()
+{
+}
+
+#ifndef USE_OPENSSL
+int main()
+{
+    printf("ERROR: Not compiled. Missing OpenSSL support.\n");
+    exit(0);
+}
+#else
+
+
+int main(int argc, char **argv)
+{
+    FILE *fp;
+    // Bucket to keep pids in.
+    int process_pool[POOL_SIZE];
+    // Count of pids we are wait()ing on.
+    int c = 0, test_config = 0, use_ip_address = 0, pid = 0, status, i = 0, active_processes = 0;
+    int gid = 0, client_sock = 0, sock = 0, port = 1515, ret = 0;
+    char *dir  = DEFAULTDIR;
+    char *user = USER;
+    char *group = GROUPGLOBAL;
+    char *cfg = DEFAULTCPATH;
+    char buf[4096 +1];
+    SSL_CTX *ctx;
+    SSL *ssl;
+    char srcip[IPSIZE +1];
+    struct sockaddr_in _nc;
+    socklen_t _ncl;
+
+
+    /* Initializing some variables */
+    memset(srcip, '\0', IPSIZE + 1);
+    memset(process_pool, 0x0, POOL_SIZE);
+
+    bio_err = 0;
+
+
+    /* Setting the name */
+    OS_SetName(ARGV0);
+    /* add an option to use the ip on the socket to tie the name to a
+       specific address */
+    while((c = getopt(argc, argv, "Vdhiu:g:D:c:m:p:")) != -1)
+    {
+        switch(c){
+            case 'V':
+                print_version();
+                break;
+            case 'h':
+                report_help();
+                break;
+            case 'd':
+                nowDebug();
+                break;
+            case 'i':
+                use_ip_address = 1;
+                break;
+            case 'u':
+                if(!optarg)
+                    ErrorExit("%s: -u needs an argument",ARGV0);
+                user = optarg;
+                break;
+            case 'g':
+                if(!optarg)
+                    ErrorExit("%s: -g needs an argument",ARGV0);
+                group = optarg;
+                break;
+            case 'D':
+                if(!optarg)
+                    ErrorExit("%s: -D needs an argument",ARGV0);
+                dir = optarg;
+                break;
+            case 'c':
+                if(!optarg)
+                    ErrorExit("%s: -c needs an argument",ARGV0);
+                cfg = optarg;
+                break;
+            case 't':
+                test_config = 1;
+                break;
+            case 'p':
+               if(!optarg)
+                    ErrorExit("%s: -%c needs an argument",ARGV0, c);
+                port = atoi(optarg);
+                if(port <= 0 || port >= 65536)
+                {
+                    ErrorExit("%s: Invalid port: %s", ARGV0, optarg);
+                }
+                break;
+            default:
+                report_help();
+                break;
+        }
+
+    }
+
+    /* Starting daemon -- NB: need to double fork and setsid */
+    debug1(STARTED_MSG,ARGV0);
+
+    /* Check if the user/group given are valid */
+    gid = Privsep_GetGroup(group);
+    if(gid < 0)
+        ErrorExit(USER_ERROR,ARGV0,user,group);
+
+
+
+    /* Exit here if test config is set */
+    if(test_config)
+        exit(0);
+
+
+    /* Privilege separation */
+    if(Privsep_SetGroup(gid) < 0)
+        ErrorExit(SETGID_ERROR,ARGV0,group);
+
+
+    /* chrooting -- TODO: this isn't a chroot. Should also close
+       unneeded open file descriptors (like stdin/stdout)*/
+    chdir(dir);
+
+
+
+    /* Signal manipulation */
+    StartSIG(ARGV0);
+
+
+    /* Creating PID files */
+    if(CreatePID(ARGV0, getpid()) < 0)
+        ErrorExit(PID_ERROR,ARGV0);
+
+    /* Start up message */
+    verbose(STARTUP_MSG, ARGV0, (int)getpid());
+
+
+    fp = fopen(KEYSFILE_PATH,"a");
+    if(!fp)
+    {
+        merror("%s: ERROR: Unable to open %s (key file)", ARGV0, KEYSFILE_PATH);
+        exit(1);
+    }
+
+
+    /* Starting SSL */
+    ctx = os_ssl_keys(0, dir);
+    if(!ctx)
+    {
+        merror("%s: ERROR: SSL error. Exiting.", ARGV0);
+        exit(1);
+    }
+
+
+    /* Connecting via TCP */
+    sock = OS_Bindporttcp(port, NULL, 0);
+    if(sock <= 0)
+    {
+        merror("%s: Unable to bind to port %d", ARGV0, port);
+        exit(1);
+    }
+    fcntl(sock, F_SETFL, O_NONBLOCK);
+
+    debug1("%s: DEBUG: Going into listening mode.", ARGV0);
+    while(1)
+    {
+
+        // no need to completely pin the cpu
+        usleep(0);
+        for (i = 0; i < POOL_SIZE; i++)
+        {
+            int rv = 0;
+            status = 0;
+            if (process_pool[i])
+            {
+                rv = waitpid(process_pool[i], &status, WNOHANG);
+                if (rv != 0){
+                    debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]);
+                    process_pool[i] = 0;
+                    active_processes = active_processes - 1;
+                }
+            }
+        }
+        memset(&_nc, 0, sizeof(_nc));
+        _ncl = sizeof(_nc);
+
+        if((client_sock = accept(sock, (struct sockaddr *) &_nc, &_ncl)) > 0){
+            if (active_processes >= POOL_SIZE)
+            {
+                merror("%s: Error: Max concurrency reached. Unable to fork", ARGV0);
+                break;
+            }
+            pid = fork();
+            if(pid)
+            {
+                active_processes = active_processes + 1;
+                close(client_sock);
+                for (i = 0; i < POOL_SIZE; i++)
+                {
+                    if (! process_pool[i])
+                    {
+                        process_pool[i] = pid;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                strncpy(srcip, inet_ntoa(_nc.sin_addr),IPSIZE -1);
+                char *agentname = NULL;
+                ssl = SSL_new(ctx);
+                SSL_set_fd(ssl, client_sock);
+                ret = SSL_accept(ssl);
+                if(ret <= 0)
+                {
+                    merror("%s: ERROR: SSL Accept error (%d)", ARGV0, ret);
+                    ERR_print_errors_fp(stderr);
+                }
+
+                verbose("%s: INFO: New connection from %s", ARGV0, srcip);
+
+                ret = SSL_read(ssl, buf, sizeof(buf));
+                sleep(1);
+                if(ret > 0)
+                {
+                    int parseok = 0;
+                    if(strncmp(buf, "OSSEC A:'", 9) == 0)
+                    {
+                        char *tmpstr = buf;
+                        agentname = tmpstr + 9;
+                        tmpstr += 9;
+                        while(*tmpstr != '\0')
+                        {
+                            if(*tmpstr == '\'')
+                            {
+                                *tmpstr = '\0';
+                                verbose("%s: INFO: Received request for a new agent (%s) from: %s", ARGV0, agentname, srcip);
+                                parseok = 1;
+                                break;
+                            }
+                            tmpstr++;
+                        }
+                    }
+                    if(parseok == 0)
+                    {
+                        merror("%s: ERROR: Invalid request for new agent from: %s", ARGV0, srcip);
+                    }
+                    else
+                    {
+                        int acount = 2;
+                        char fname[2048 +1];
+                        char response[2048 +1];
+                        char *finalkey = NULL;
+                        response[2048] = '\0';
+                        fname[2048] = '\0';
+                        if(!OS_IsValidName(agentname))
+                        {
+                            merror("%s: ERROR: Invalid agent name: %s from %s", ARGV0, agentname, srcip);
+                            snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname);
+                            ret = SSL_write(ssl, response, strlen(response));
+                            snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
+                            ret = SSL_write(ssl, response, strlen(response));
+                            sleep(1);
+                            exit(0);
+                        }
+
+
+                        /* Checking for a duplicated names. */
+                        strncpy(fname, agentname, 2048);
+                        while(NameExist(fname))
+                        {
+                            snprintf(fname, 2048, "%s%d", agentname, acount);
+                            acount++;
+                            if(acount > 256)
+                            {
+                                merror("%s: ERROR: Invalid agent name %s (duplicated)", ARGV0, agentname);
+                                snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname);
+                                ret = SSL_write(ssl, response, strlen(response));
+                                snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
+                                ret = SSL_write(ssl, response, strlen(response));
+                                sleep(1);
+                                exit(0);
+                            }
+                        }
+                        agentname = fname;
+
+
+                        /* Adding the new agent. */
+                        if (use_ip_address)
+                        {
+                            finalkey = OS_AddNewAgent(agentname, srcip, NULL, NULL);
+                        }
+                        else
+                        {
+                            finalkey = OS_AddNewAgent(agentname, NULL, NULL, NULL);
+                        }
+                        if(!finalkey)
+                        {
+                            merror("%s: ERROR: Unable to add agent: %s (internal error)", ARGV0, agentname);
+                            snprintf(response, 2048, "ERROR: Internal manager error adding agent: %s\n\n", agentname);
+                            ret = SSL_write(ssl, response, strlen(response));
+                            snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
+                            ret = SSL_write(ssl, response, strlen(response));
+                            sleep(1);
+                            exit(0);
+                        }
+
+
+                        snprintf(response, 2048,"OSSEC K:'%s'\n\n", finalkey);
+                        verbose("%s: INFO: Agent key generated for %s (requested by %s)", ARGV0, agentname, srcip);
+                        ret = SSL_write(ssl, response, strlen(response));
+                        if(ret < 0)
+                        {
+                            merror("%s: ERROR: SSL write error (%d)", ARGV0, ret);
+                            merror("%s: ERROR: Agen key not saved for %s", ARGV0, agentname);
+                            ERR_print_errors_fp(stderr);
+                        }
+                        else
+                        {
+                            verbose("%s: INFO: Agent key created for %s (requested by %s)", ARGV0, agentname, srcip);
+                        }
+                    }
+                }
+                else
+                {
+                    merror("%s: ERROR: SSL read error (%d)", ARGV0, ret);
+                    ERR_print_errors_fp(stderr);
+                }
+                SSL_CTX_free(ctx);
+                close(client_sock);
+                exit(0);
+            }
+        }
+    }
+
+
+    /* Shutdown the socket */
+    SSL_CTX_free(ctx);
+    close(sock);
+
+    exit(0);
+}
+
+
+#endif
+/* EOF */