acf91eec779925d371f97cbc520cfbd714f81899
[ossec-hids.git] / src / os_auth / main-server.c
1 /* @(#) $Id$ */
2
3 /* Copyright (C) 2010 Trend Micro Inc.
4  * All rights reserved.
5  *
6  * This program is a free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General Public
8  * License (version 2) as published by the FSF - Free Software
9  * Foundation
10  *
11  * In addition, as a special exception, the copyright holders give
12  * permission to link the code of portions of this program with the
13  * OpenSSL library under certain conditions as described in each
14  * individual source file, and distribute linked combinations
15  * including the two.
16  *
17  * You must obey the GNU General Public License in all respects
18  * for all of the code used other than OpenSSL.  If you modify
19  * file(s) with this exception, you may extend this exception to your
20  * version of the file(s), but you are not obligated to do so.  If you
21  * do not wish to do so, delete this exception statement from your
22  * version.  If you delete this exception statement from all source
23  * files in the program, then also delete it here.
24  *
25  */
26
27
28 #include "shared.h"
29 #include "auth.h"
30
31 /* TODO: Pulled this value out of the sky, may or may not be sane */
32 int POOL_SIZE = 512;
33
34 /* ossec-reportd - Runs manual reports. */
35 void report_help()
36 {
37 }
38
39 #ifndef USE_OPENSSL
40 int main()
41 {
42     printf("ERROR: Not compiled. Missing OpenSSL support.\n");
43     exit(0);
44 }
45 #else
46
47 /* Function to use with SSL on non blocking socket,
48    to know if SSL operation failed for good */
49 int ssl_error(const SSL* ssl, int ret)
50 {
51     if (ret <= 0)
52     {
53         switch (SSL_get_error(ssl, ret))
54         {
55             case SSL_ERROR_WANT_READ:
56             case SSL_ERROR_WANT_WRITE:
57                 usleep(100*1000);
58                 return (0);
59             default:
60                 merror("%s: ERROR: SSL Error (%d)", ARGV0, ret);
61                 ERR_print_errors_fp(stderr);
62                 return (1);
63         }
64     }
65
66     return (0);
67 }
68
69 void clean_exit(SSL_CTX* ctx, int sock)
70 {
71     SSL_CTX_free(ctx);
72     close(sock);
73     exit(0);
74 }
75
76 int main(int argc, char **argv)
77 {
78     FILE *fp;
79     // Bucket to keep pids in.
80     int process_pool[POOL_SIZE];
81     // Count of pids we are wait()ing on.
82     int c = 0, test_config = 0, use_ip_address = 0, pid = 0, status, i = 0, active_processes = 0;
83     int gid = 0, client_sock = 0, sock = 0, port = 1515, ret = 0;
84     char *dir  = DEFAULTDIR;
85     char *user = USER;
86     char *group = GROUPGLOBAL;
87     // TODO: implement or delete
88     char *cfg __attribute__((unused)) = DEFAULTCPATH;
89     char buf[4096 +1];
90     SSL_CTX *ctx;
91     SSL *ssl;
92     char srcip[IPSIZE +1];
93     struct sockaddr_in _nc;
94     socklen_t _ncl;
95
96
97     /* Initializing some variables */
98     memset(srcip, '\0', IPSIZE + 1);
99     memset(process_pool, 0x0, POOL_SIZE);
100
101     bio_err = 0;
102
103
104     /* Setting the name */
105     OS_SetName(ARGV0);
106     /* add an option to use the ip on the socket to tie the name to a
107        specific address */
108     while((c = getopt(argc, argv, "Vdhiu:g:D:c:m:p:")) != -1)
109     {
110         switch(c){
111             case 'V':
112                 print_version();
113                 break;
114             case 'h':
115                 report_help();
116                 break;
117             case 'd':
118                 nowDebug();
119                 break;
120             case 'i':
121                 use_ip_address = 1;
122                 break;
123             case 'u':
124                 if(!optarg)
125                     ErrorExit("%s: -u needs an argument",ARGV0);
126                 user = optarg;
127                 break;
128             case 'g':
129                 if(!optarg)
130                     ErrorExit("%s: -g needs an argument",ARGV0);
131                 group = optarg;
132                 break;
133             case 'D':
134                 if(!optarg)
135                     ErrorExit("%s: -D needs an argument",ARGV0);
136                 dir = optarg;
137                 break;
138             case 'c':
139                 if(!optarg)
140                     ErrorExit("%s: -c needs an argument",ARGV0);
141                 cfg = optarg;
142                 break;
143             case 't':
144                 test_config = 1;
145                 break;
146             case 'p':
147                if(!optarg)
148                     ErrorExit("%s: -%c needs an argument",ARGV0, c);
149                 port = atoi(optarg);
150                 if(port <= 0 || port >= 65536)
151                 {
152                     ErrorExit("%s: Invalid port: %s", ARGV0, optarg);
153                 }
154                 break;
155             default:
156                 report_help();
157                 break;
158         }
159
160     }
161
162     /* Starting daemon -- NB: need to double fork and setsid */
163     debug1(STARTED_MSG,ARGV0);
164
165     /* Check if the user/group given are valid */
166     gid = Privsep_GetGroup(group);
167     if(gid < 0)
168         ErrorExit(USER_ERROR,ARGV0,user,group);
169
170
171
172     /* Exit here if test config is set */
173     if(test_config)
174         exit(0);
175
176
177     /* Privilege separation */
178     if(Privsep_SetGroup(gid) < 0)
179         ErrorExit(SETGID_ERROR,ARGV0,group);
180
181
182     /* chrooting -- TODO: this isn't a chroot. Should also close
183        unneeded open file descriptors (like stdin/stdout)*/
184     chdir(dir);
185
186
187
188     /* Signal manipulation */
189     StartSIG(ARGV0);
190
191
192     /* Creating PID files */
193     if(CreatePID(ARGV0, getpid()) < 0)
194         ErrorExit(PID_ERROR,ARGV0);
195
196     /* Start up message */
197     verbose(STARTUP_MSG, ARGV0, (int)getpid());
198
199
200     fp = fopen(KEYSFILE_PATH,"a");
201     if(!fp)
202     {
203         merror("%s: ERROR: Unable to open %s (key file)", ARGV0, KEYSFILE_PATH);
204         exit(1);
205     }
206
207
208     /* Starting SSL */
209     ctx = os_ssl_keys(0, dir);
210     if(!ctx)
211     {
212         merror("%s: ERROR: SSL error. Exiting.", ARGV0);
213         exit(1);
214     }
215
216
217     /* Connecting via TCP */
218     sock = OS_Bindporttcp(port, NULL, 0);
219     if(sock <= 0)
220     {
221         merror("%s: Unable to bind to port %d", ARGV0, port);
222         exit(1);
223     }
224     fcntl(sock, F_SETFL, O_NONBLOCK);
225
226     debug1("%s: DEBUG: Going into listening mode.", ARGV0);
227     while(1)
228     {
229
230         // no need to completely pin the cpu, 100ms should be fast enough
231         usleep(100*1000);
232
233         // Only check process-pool if we have active processes
234         if(active_processes > 0){
235             for (i = 0; i < POOL_SIZE; i++)
236             {
237                 int rv = 0;
238                 status = 0;
239                 if (process_pool[i])
240                 {
241                     rv = waitpid(process_pool[i], &status, WNOHANG);
242                     if (rv != 0){
243                         debug1("%s: DEBUG: Process %d exited", ARGV0, process_pool[i]);
244                         process_pool[i] = 0;
245                         active_processes = active_processes - 1;
246                     }
247                 }
248             }
249         }
250         memset(&_nc, 0, sizeof(_nc));
251         _ncl = sizeof(_nc);
252
253         if((client_sock = accept(sock, (struct sockaddr *) &_nc, &_ncl)) > 0){
254             if (active_processes >= POOL_SIZE)
255             {
256                 merror("%s: Error: Max concurrency reached. Unable to fork", ARGV0);
257                 break;
258             }
259             pid = fork();
260             if(pid)
261             {
262                 active_processes = active_processes + 1;
263                 close(client_sock);
264                 for (i = 0; i < POOL_SIZE; i++)
265                 {
266                     if (! process_pool[i])
267                     {
268                         process_pool[i] = pid;
269                         break;
270                     }
271                 }
272             }
273             else
274             {
275                 strncpy(srcip, inet_ntoa(_nc.sin_addr),IPSIZE -1);
276                 char *agentname = NULL;
277                 ssl = SSL_new(ctx);
278                 SSL_set_fd(ssl, client_sock);
279
280                 do
281                 {
282                     ret = SSL_accept(ssl);
283
284                     if (ssl_error(ssl, ret))
285                         clean_exit(ctx, client_sock);
286
287                 } while (ret <= 0);
288
289                 verbose("%s: INFO: New connection from %s", ARGV0, srcip);
290
291                 do
292                 {
293                     ret = SSL_read(ssl, buf, sizeof(buf));
294
295                     if (ssl_error(ssl, ret))
296                         clean_exit(ctx, client_sock);
297
298                 } while (ret <= 0);
299
300                 int parseok = 0;
301                 if(strncmp(buf, "OSSEC A:'", 9) == 0)
302                 {
303                     char *tmpstr = buf;
304                     agentname = tmpstr + 9;
305                     tmpstr += 9;
306                     while(*tmpstr != '\0')
307                     {
308                         if(*tmpstr == '\'')
309                         {
310                             *tmpstr = '\0';
311                             verbose("%s: INFO: Received request for a new agent (%s) from: %s", ARGV0, agentname, srcip);
312                             parseok = 1;
313                             break;
314                         }
315                         tmpstr++;
316                     }
317                 }
318                 if(parseok == 0)
319                 {
320                     merror("%s: ERROR: Invalid request for new agent from: %s", ARGV0, srcip);
321                 }
322                 else
323                 {
324                     int acount = 2;
325                     char fname[2048 +1];
326                     char response[2048 +1];
327                     char *finalkey = NULL;
328                     response[2048] = '\0';
329                     fname[2048] = '\0';
330                     if(!OS_IsValidName(agentname))
331                     {
332                         merror("%s: ERROR: Invalid agent name: %s from %s", ARGV0, agentname, srcip);
333                         snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname);
334                         ret = SSL_write(ssl, response, strlen(response));
335                         snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
336                         ret = SSL_write(ssl, response, strlen(response));
337                         sleep(1);
338                         exit(0);
339                     }
340
341
342                     /* Checking for a duplicated names. */
343                     strncpy(fname, agentname, 2048);
344                     while(NameExist(fname))
345                     {
346                         snprintf(fname, 2048, "%s%d", agentname, acount);
347                         acount++;
348                         if(acount > 256)
349                         {
350                             merror("%s: ERROR: Invalid agent name %s (duplicated)", ARGV0, agentname);
351                             snprintf(response, 2048, "ERROR: Invalid agent name: %s\n\n", agentname);
352                             ret = SSL_write(ssl, response, strlen(response));
353                             snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
354                             ret = SSL_write(ssl, response, strlen(response));
355                             sleep(1);
356                             exit(0);
357                         }
358                     }
359                     agentname = fname;
360
361
362                     /* Adding the new agent. */
363                     if (use_ip_address)
364                     {
365                         finalkey = OS_AddNewAgent(agentname, srcip, NULL, NULL);
366                     }
367                     else
368                     {
369                         finalkey = OS_AddNewAgent(agentname, NULL, NULL, NULL);
370                     }
371                     if(!finalkey)
372                     {
373                         merror("%s: ERROR: Unable to add agent: %s (internal error)", ARGV0, agentname);
374                         snprintf(response, 2048, "ERROR: Internal manager error adding agent: %s\n\n", agentname);
375                         ret = SSL_write(ssl, response, strlen(response));
376                         snprintf(response, 2048, "ERROR: Unable to add agent.\n\n");
377                         ret = SSL_write(ssl, response, strlen(response));
378                         sleep(1);
379                         exit(0);
380                     }
381
382
383                     snprintf(response, 2048,"OSSEC K:'%s'\n\n", finalkey);
384                     verbose("%s: INFO: Agent key generated for %s (requested by %s)", ARGV0, agentname, srcip);
385                     ret = SSL_write(ssl, response, strlen(response));
386                     if(ret < 0)
387                     {
388                         merror("%s: ERROR: SSL write error (%d)", ARGV0, ret);
389                         merror("%s: ERROR: Agen key not saved for %s", ARGV0, agentname);
390                         ERR_print_errors_fp(stderr);
391                     }
392                     else
393                     {
394                         verbose("%s: INFO: Agent key created for %s (requested by %s)", ARGV0, agentname, srcip);
395                     }
396                 }
397
398                 clean_exit(ctx, client_sock);
399             }
400         }
401     }
402
403
404     /* Shutdown the socket */
405     clean_exit(ctx, sock);
406
407     return (0);
408 }
409
410
411 #endif
412 /* EOF */