fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / sensor.c
1 /*
2  * (c) Copyright 2001-2002 by Steve Grubb
3  * All rights reserved.  The file named COPYRIGHT specifies the terms
4  * and conditions for redistribution.
5  */
6
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <time.h>
11
12 #include "config.h"
13 #include "pset.h"
14 #include "str.h"
15 #include "addr.h"
16 #include "msg.h"
17 #include "sconf.h"
18 #include "sensor.h"
19 #include "xconfig.h"
20 #include "xtimer.h"
21
22 /*
23  * This is the globals for the Sensor. The Sensor will add the incoming IP
24  * address to the global_no_access table for whatever the configured time is.
25  */
26 static pset_h global_no_access = NULL;        /* global no_access list   */
27 static pset_h global_no_access_time = NULL;   /* time of the infraction   */
28 static int timer_id = 0;                      /* Timer ID */
29
30 /* This function is called via a timer callback every 60 seconds */
31 static void scrub_global_access_list( void );
32
33
34 void init_sensor( void )
35 {
36    if ( global_no_access == NULL )
37       global_no_access = pset_create(10, 10);
38    if ( global_no_access_time == NULL )
39       global_no_access_time = pset_create(10, 10);
40 }
41
42 /*
43  * This function runs in the parent context and updates the global_no_access
44  * list. 
45  */
46 void process_sensor( const struct service *sp, const union xsockaddr *addr)
47 {
48    const char *func = "process_sensor";
49
50    if (SC_DENY_TIME(SVC_CONF(sp)) != 0)   /* 0 simply logs it   */
51    {
52       if ( pset_count( global_no_access ) < MAX_GLOBAL_NO_ACCESS)
53       {
54          int item_matched = addrlist_match( global_no_access, SA(addr) );
55
56          if ( item_matched == 0)
57          {   /* no match...adding to the list   */
58             char *dup_addr = new_string(xaddrname( addr ) );
59
60             if (dup_addr == NULL )
61                return ;
62
63             if (addrlist_add(global_no_access, dup_addr) == FAILED)
64                msg(LOG_ERR, func,
65                   "Failed adding %s to the global_no_access list", dup_addr);
66             else
67             {
68                time_t nowtime;
69                char time_buf[40], *tmp;
70
71                nowtime = time(NULL);
72                msg(LOG_CRIT, func,
73                    "Adding %s to the global_no_access list for %d minutes",
74                     dup_addr, SC_DENY_TIME(SVC_CONF(sp)));
75
76                if (SC_DENY_TIME(SVC_CONF(sp)) == -1)
77                     strcpy(time_buf, "-1");
78                else
79                     strx_nprint(time_buf, 38, "%ld",
80                        (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp))));
81
82                tmp = new_string(time_buf);
83                if (tmp != NULL)
84                {
85                   if (pset_add(global_no_access_time, tmp) == NULL)
86                   {
87                      msg(LOG_ERR, func,
88                          "Failed adding %s to the global_no_access_time list. "
89                          "global_no_access list is broken, xinetd needs "
90                          "restarting.", dup_addr);
91                  /* ideally, we should rollback the previous addr addition.   */
92                   }
93                }
94                if (pset_count(global_no_access) && (timer_id == 0) )
95                   timer_id = xtimer_add( scrub_global_access_list, 60 );
96             }
97             free(dup_addr);
98          }
99          else
100          {
101             /* Here again, eh?...update time stamp. */
102             char *exp_time;
103             time_t stored_time;
104
105             item_matched--; /* Is # plus 1, to even get here must be >= 1 */
106             exp_time = pset_pointer( global_no_access_time, item_matched ) ;
107             if (exp_time == NULL)
108                return ;
109
110             if ( parse_base10(exp_time, (int *)&stored_time) )
111             {  /* if never let them off, bypass */
112                if (stored_time != -1)
113                {
114                   time_t nowtime, new_time;
115
116                   nowtime = time(NULL);
117                   new_time = (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp)));                     if (difftime(new_time, (time_t)stored_time) > 0.0)
118                   {   /* new_time is longer save it   */
119                      char time_buf[40], *new_exp_time;
120
121                      strx_nprint(time_buf, 38, "%ld", (long)new_time);
122                      new_exp_time = new_string(time_buf);
123                      if ( new_exp_time )
124                      {
125                         free(exp_time);
126                         global_no_access_time->ptrs[ 
127                         (unsigned)item_matched ] = new_exp_time;
128                      }
129                   }
130                }
131             }
132          }
133       }
134       else
135          msg(LOG_ERR, func, "Maximum global_no_access count reached.");
136    }
137 }
138
139 /* They hit a real server...note, this is likely to be a child process. */
140 status_e check_sensor( const union xsockaddr *addr)
141 {
142
143    if ( (global_no_access) && pset_count( global_no_access ) )
144    {
145       if (addrlist_match( global_no_access, SA(addr)))
146          return FAILED;
147    }
148    return OK;
149 }
150    
151
152 static void scrub_global_access_list( void )
153 {
154    unsigned count;
155    const char *func = "scrub_global_no_access_list";
156
157    if ( global_no_access == NULL )
158       count = 0;
159    else
160       count = pset_count( global_no_access );
161
162    if ( count )
163    {
164       int found_one = 0;
165       unsigned u;
166       time_t nowtime = time(NULL);
167
168       for (u=0; u < count; u++)
169       {
170          char *exp_time;
171          time_t stored_time;
172          
173          exp_time = pset_pointer( global_no_access_time, u ) ;
174          stored_time = atol(exp_time);
175
176          if (stored_time == -1)   /* never let them off   */
177             continue;
178
179          if (difftime(nowtime, (time_t)stored_time) >= 0.0)
180          {
181             __pset_pointer ptr;
182
183             pset_pointer(global_no_access, u) = NULL;
184             ptr = global_no_access_time->ptrs[ u ];
185             free(ptr);
186             pset_pointer(global_no_access_time, u ) = NULL;
187             found_one = 1;
188          }
189       }
190       if (found_one)
191       {
192          pset_compact( global_no_access );
193          pset_compact( global_no_access_time );
194          msg(LOG_INFO, func, 
195             "At least 1 DENY_TIME has expired, global_no_access list updated");
196       }
197
198       /* If there's still more on the list, start another callback. */
199       count = pset_count( global_no_access );
200       if ( count )
201          timer_id = xtimer_add( scrub_global_access_list, 60 );
202       else
203       {
204          timer_id = 0;
205          msg(LOG_INFO, func, 
206                   "global_no_access list is empty.");
207       }
208    }
209 }
210
211 void destroy_global_access_list( void )
212 {
213    if ( global_no_access ) {
214       pset_apply( global_no_access, free, NULL ) ;
215       pset_destroy( global_no_access ) ;
216    }
217
218    if ( global_no_access_time ) {
219       pset_apply( global_no_access_time, free, NULL ) ;
220       pset_destroy( global_no_access_time ) ;
221    }
222 }