d1b637c8952254e4a76fe8616c42e32e36f612c4
[ossec-hids.git] / src / os_execd / execd.c
1 /* @(#) $Id$ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All right 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
12
13
14 #include "shared.h"
15 #include "list_op.h"
16 #include "os_regex/os_regex.h"
17 #include "os_net/os_net.h"
18
19 #include "execd.h"
20
21
22
23 /* Timeout data structure */
24 typedef struct _timeout_data
25 {
26     time_t time_of_addition;
27     int time_to_block;
28     char **command;
29 }timeout_data;
30
31
32 /* Timeout list */
33 OSList *timeout_list;
34 OSListNode *timeout_node;
35             
36
37
38 /** 
39  * Shudowns execd properly.
40  */
41 void execd_shutdown()
42 {
43     /* Removing pending active responses. */
44     merror(EXEC_SHUTDOWN, ARGV0);
45     
46     timeout_node = OSList_GetFirstNode(timeout_list);
47     while(timeout_node)
48     {
49         timeout_data *list_entry;
50
51         list_entry = (timeout_data *)timeout_node->data;
52
53         ExecCmd(list_entry->command);
54
55         /* Delete currently node - already sets the pointer to next */
56         OSList_DeleteCurrentlyNode(timeout_list);
57         timeout_node = OSList_GetCurrentlyNode(timeout_list);
58     }
59
60     #ifndef WIN32
61     HandleSIG();
62     #endif
63
64 }
65
66
67 #ifndef WIN32
68
69 /** int main(int argc, char **argv) v0.1
70  */
71 int main(int argc, char **argv)
72 {
73     int c;
74     int test_config = 0,run_foreground = 0;
75     int gid = 0,m_queue = 0;
76
77     char *dir  = DEFAULTDIR;
78     char *group = GROUPGLOBAL;
79     char *cfg = DEFAULTARPATH;
80     char *xmlcfg = DEFAULTCPATH;
81
82
83     /* Setting the name */
84     OS_SetName(ARGV0);
85         
86
87     while((c = getopt(argc, argv, "Vtdhfu:g:D:c:")) != -1){
88         switch(c){
89             case 'V':
90                 print_version();
91                 break;
92             case 'h':
93                 help(ARGV0);
94                 break;
95             case 'd':
96                 nowDebug();
97                 break;
98             case 'f':
99                 run_foreground = 1;
100                 break;
101             case 'g':
102                 if(!optarg)
103                     ErrorExit("%s: -g needs an argument.",ARGV0);
104                 group = optarg;
105                 break;
106             case 'D':
107                 if(!optarg)
108                     ErrorExit("%s: -D needs an argument.",ARGV0);
109                 dir = optarg;
110             case 'c':
111                 if(!optarg)
112                     ErrorExit("%s: -c needs an argument.",ARGV0);
113                 cfg = optarg;
114                 break;
115             case 't':
116                 test_config = 1;
117                 break;    
118             default:
119                 help(ARGV0);
120                 break;
121         }
122
123     }
124
125
126
127     /* Check if the group given are valid */
128     gid = Privsep_GetGroup(group);
129     if(gid < 0)
130         ErrorExit(USER_ERROR,ARGV0,"",group);
131
132
133     /* Privilege separation */  
134     if(Privsep_SetGroup(gid) < 0)
135         ErrorExit(SETGID_ERROR,ARGV0,group);
136
137
138     /* Reading config */
139     if((c = ExecdConfig(xmlcfg)) < 0)
140     {
141         ErrorExit(CONFIG_ERROR, ARGV0, xmlcfg);
142     }
143
144
145     /* Exit if test_config */
146     if(test_config)
147         exit(0);
148         
149         
150     /* Signal manipulation */
151     StartSIG2(ARGV0, execd_shutdown);
152
153     
154     if (!run_foreground) 
155     {
156         /* Going daemon */
157         nowDaemon();
158         goDaemon();
159     } 
160
161
162     /* Active response disabled */
163     if(c == 1)
164     {
165         verbose(EXEC_DISABLED, ARGV0);
166         exit(0);
167     }
168     
169     /* Creating the PID file */
170     if(CreatePID(ARGV0, getpid()) < 0)
171         merror(PID_ERROR, ARGV0);
172
173     
174     /* Starting queue (exec queue) */
175     if((m_queue = StartMQ(EXECQUEUEPATH,READ)) < 0)
176         ErrorExit(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno));
177
178
179     /* Start up message */
180     verbose(STARTUP_MSG, ARGV0, (int)getpid());
181         
182
183     /* The real daemon Now */  
184     ExecdStart(m_queue);
185     
186     exit(0);
187 }
188
189
190 #endif
191
192
193
194 /** void FreeTimeoutEntry(timeout_data *timeout_entry) v0.1
195  * Free the timeout entry. Must be called after popping it
196  * from the timeout list
197  */
198 void FreeTimeoutEntry(void *timeout_entry_pt)
199 {
200     timeout_data *timeout_entry;
201     char **tmp_str;
202
203     timeout_entry = (timeout_data *)timeout_entry_pt;
204
205     if(!timeout_entry)
206     {
207         return;
208     }
209     
210     tmp_str = timeout_entry->command;
211
212     /* Clearing the command arguments */
213     if(tmp_str)
214     {
215         while(*tmp_str)
216         {
217             os_free(*tmp_str);
218             *tmp_str = NULL;
219             tmp_str++;
220         }
221         os_free(timeout_entry->command);
222         timeout_entry->command = NULL;
223     }
224
225     os_free(timeout_entry);
226     timeout_entry = NULL;
227
228     return;
229 }
230
231
232 #ifndef WIN32
233
234
235 /** void ExecdStart(int q) v0.2
236  * Main function on the execd. Does all the data receiving ,etc.
237  */
238 void ExecdStart(int q)
239 {
240     int i, childcount = 0;
241     time_t curr_time;
242     
243     char buffer[OS_MAXSTR + 1];
244     char *tmp_msg = NULL;
245     char *name;
246     char *command;
247     char *cmd_args[MAX_ARGS +2];
248
249
250     /* Select */
251     fd_set fdset;
252     struct timeval socket_timeout;
253
254     
255     /* Clearing the buffer */
256     memset(buffer, '\0', OS_MAXSTR +1);
257     
258     
259     /* Initializing the cmd arguments */
260     for(i = 0; i<= MAX_ARGS +1; i++)
261     {
262         cmd_args[i] = NULL;
263     }
264    
265     
266     /* Creating list for timeout */
267     timeout_list = OSList_Create(); 
268     if(!timeout_list)
269     {
270         ErrorExit(LIST_ERROR, ARGV0);
271     }
272     
273    
274     /* Main loop. */
275     while(1)
276     {
277         int timeout_value;
278         int added_before = 0;
279     
280         char **timeout_args;
281         timeout_data *timeout_entry;
282
283
284         /* Cleaning up any child. */
285         while (childcount)
286         {
287             int wp;
288             wp = waitpid((pid_t) -1, NULL, WNOHANG);
289             if (wp < 0)
290             {
291                 merror(WAITPID_ERROR, ARGV0);
292             }
293
294             /* if = 0, we still need to wait for the child process */
295             else if (wp == 0)
296             {
297                 break;
298             }
299             /* Child completed if wp > 0 */
300             else
301             {
302                 childcount--;
303             }
304         }
305
306
307         /* Getting currently time */
308         curr_time = time(0);
309
310
311         /* Checking if there is any timeouted command to execute. */
312         timeout_node = OSList_GetFirstNode(timeout_list);
313         while(timeout_node)
314         {
315             timeout_data *list_entry;
316
317             list_entry = (timeout_data *)timeout_node->data;
318             
319             /* Timeouted */
320             if((curr_time - list_entry->time_of_addition) > 
321                     list_entry->time_to_block)
322             {
323                 ExecCmd(list_entry->command);
324                 
325                 /* Deletecurrently node already sets the pointer to next */
326                 OSList_DeleteCurrentlyNode(timeout_list);
327                 timeout_node = OSList_GetCurrentlyNode(timeout_list);
328
329                 /* Clearing the memory */
330                 FreeTimeoutEntry(list_entry);
331
332                 childcount++;
333             }
334
335             else
336             {
337                 timeout_node = OSList_GetNextNode(timeout_list);
338             }
339         }
340
341         
342         /* Setting timeout to EXECD_TIMEOUT */
343         socket_timeout.tv_sec = EXECD_TIMEOUT;
344         socket_timeout.tv_usec= 0;
345
346
347
348         /* Setting FD values */
349         FD_ZERO(&fdset);
350         FD_SET(q, &fdset);
351
352         /* Adding timeout */
353         if(select(q+1, &fdset, NULL, NULL, &socket_timeout) == 0)
354         {
355             /* Timeout .. */
356             continue;
357         }
358
359
360         /* Checking for error */
361         if(!FD_ISSET(q, &fdset))
362         {
363             merror(SELECT_ERROR, ARGV0);
364             continue;
365         }
366
367
368         /* Receiving the message */
369         if(recv(q, buffer, OS_MAXSTR, 0) == -1)
370         {
371             merror(QUEUE_ERROR, ARGV0, EXECQUEUEPATH, strerror(errno));
372             continue;
373         }
374
375
376         /* Currently time */
377         curr_time = time(0);
378
379
380         /* Getting application name */
381         name = buffer;
382         
383         
384         /* Zeroing the name */
385         tmp_msg = strchr(buffer, ' ');
386         if(!tmp_msg)
387         {
388             merror(EXECD_INV_MSG, ARGV0, buffer);
389             continue;
390         }
391         *tmp_msg = '\0';
392         tmp_msg++;
393
394
395         /* Getting the command to execute (valid name) */
396         command = GetCommandbyName(name, &timeout_value);
397         if(!command)
398         {
399             ReadExecConfig();
400             command = GetCommandbyName(name, &timeout_value);
401             if(!command)
402             {
403                 merror(EXEC_INV_NAME, ARGV0, name);
404                 continue;
405             }
406         }
407
408
409         /* Command not present. */
410         if(command[0] == '\0')
411             continue;
412
413
414         /* Allocating memory for the timeout argument */
415         os_calloc(MAX_ARGS+2, sizeof(char *), timeout_args);
416         
417
418         /* Adding initial variables to the cmd_arg and to the timeout cmd */
419         cmd_args[0] = command; 
420         cmd_args[1] = ADD_ENTRY;
421         os_strdup(command, timeout_args[0]);
422         os_strdup(DELETE_ENTRY, timeout_args[1]);
423
424         cmd_args[2] = NULL;
425         timeout_args[2] = NULL;
426
427
428         /* Getting the arguments. */
429         i = 2;
430         while(i < (MAX_ARGS -1))
431         {
432             cmd_args[i] = tmp_msg;
433             cmd_args[i+1] = NULL;
434
435             tmp_msg = strchr(tmp_msg, ' ');
436             if(!tmp_msg)
437             {
438                 timeout_args[i] = strdup(cmd_args[i]);
439                 timeout_args[i+1] = NULL;
440                 break;
441             }
442             *tmp_msg = '\0';
443             tmp_msg++;
444
445             timeout_args[i] = strdup(cmd_args[i]);
446             timeout_args[i+1] = NULL;
447
448             i++;
449         }
450         
451
452         /* Check this command was already executed. */
453         timeout_node = OSList_GetFirstNode(timeout_list);
454         added_before = 0;
455
456
457         /* Checking for the username and ip argument */
458         if(!timeout_args[2] || !timeout_args[3])
459         {
460             added_before = 1;
461             merror("%s: Invalid number of arguments.", ARGV0);
462         }
463         
464         while(timeout_node)
465         {
466             timeout_data *list_entry;
467
468             list_entry = (timeout_data *)timeout_node->data;
469             if((strcmp(list_entry->command[3], timeout_args[3]) == 0) &&
470                (strcmp(list_entry->command[0], timeout_args[0]) == 0)) 
471             {
472                 /* Means we executed this command before
473                  * and we don't need to add it again.
474                  */
475                 added_before = 1;
476
477
478                 /* updating the timeout */
479                 list_entry->time_of_addition = curr_time;
480                 break;
481             }
482
483             /* Continue with the next entry in timeout list*/
484             timeout_node = OSList_GetNextNode(timeout_list);
485         }
486
487
488         /* If it wasn't added before, do it now */
489         if(!added_before)
490         {
491             /* executing command */
492             ExecCmd(cmd_args);
493
494             /* We don't need to add to the list if the timeout_value == 0 */
495             if(timeout_value)
496             {
497                 /* Creating the timeout entry */
498                 os_calloc(1, sizeof(timeout_data), timeout_entry);
499                 timeout_entry->command = timeout_args;
500                 timeout_entry->time_of_addition = curr_time;
501                 timeout_entry->time_to_block = timeout_value;
502
503
504                 /* Adding command to the timeout list */
505                 if(!OSList_AddData(timeout_list, timeout_entry))
506                 {
507                     merror(LIST_ADD_ERROR, ARGV0);
508                     FreeTimeoutEntry(timeout_entry);
509                 } 
510             }
511             
512             /* If no timeout, we still need to free it in here */
513             else
514             {
515                 char **ss_ta = timeout_args;
516                 while(*timeout_args)
517                 {
518                     os_free(*timeout_args);
519                     *timeout_args = NULL;
520                     timeout_args++;
521                 }
522                 os_free(ss_ta);
523             }
524
525             childcount++;
526         }
527         
528         /* We didn't add it to the timeout list */
529         else
530         {
531             char **ss_ta = timeout_args;
532
533             /* Clear the timeout arguments */
534             while(*timeout_args)
535             {
536                 os_free(*timeout_args);
537                 *timeout_args = NULL;
538                 timeout_args++;
539             }
540
541             os_free(ss_ta);
542         }
543
544         /* Some cleanup */
545         while(i > 0)
546         {
547             cmd_args[i] = NULL;
548             i--;
549         }
550     }
551 }
552
553
554 #endif
555
556 /* EOF */