1    | /***************************************
2    |   $Revision: 1.20 $
3    | 
4    |   Access control module (ac) - access control for the query part
5    | 
6    |   Status: NOT REVIEWED, TESTED
7    |   
8    |   Design and implementation by: Marek Bukowy
9    |   
10   |   ******************/ /******************
11   |   Copyright (c) 1999                              RIPE NCC
12   |  
13   |   All Rights Reserved
14   |   
15   |   Permission to use, copy, modify, and distribute this software and its
16   |   documentation for any purpose and without fee is hereby granted,
17   |   provided that the above copyright notice appear in all copies and that
18   |   both that copyright notice and this permission notice appear in
19   |   supporting documentation, and that the name of the author not be
20   |   used in advertising or publicity pertaining to distribution of the
21   |   software without specific, written prior permission.
22   |   
23   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
25   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
26   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
27   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
28   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29   |   ***************************************/
30   | #include <stdio.h>
31   | #include <glib.h>
32   | 
33   | #define AC_OK RX_OK
34   | #define AC_INVARG IP_INVARG
35   | 
36   | #define AC_IMPL
37   | #include <rxroutines.h>
38   | #include <erroutines.h>
39   | #include <access_control.h>
40   | #include "socket.h"
41   | #include "mysql_driver.h"
42   | #include <constants.h>
43   | #include <server.h>
44   | 
45   | #define AC_DECAY_TIME 600
46   | 
47   | /* formats for printing the access control list entries */
48   | #define ACL_FORMAT        "%10d %10d %10d %10d %10d"
49   | #define ACL_HEADER  "%-20s %10s %10s %10s %10s %10s\n"
50   | 
51   | /* formats for printing the accounting entries */
52   | #define ACC_FORMAT       "%4d    %4d    %4d    %4d    %6d    %6d    %6d"
53   | #define ACC_HEADER "%-20s %4s    %4s    %4s    %4s    %6s    %6s    %6s\n"
54   | 
55   | 
56   | /*++++++++++++++++++++++++++++++++++++++
57   |   AC_to_string_header:
58   | 
59   |   produce a header for the access stats printout  
60   | 
61   |   returns an allocated string
62   |   ++++++++++++++++++++++++++++++++++++++*/
63   | char *AC_to_string_header(void) 
64   | {
65   |   char *result_buf;
66   | 
67   |   dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
68   |   
69   |   sprintf(result_buf, ACC_HEADER, 
70   | 	  "ip", "conn", "pass", "deny", "qry", "pub", "priv", "bonus" );
71   | 
72   |   return result_buf;
73   | }
74   | 
75   | /*++++++++++++++++++++++++++++++++++++++
76   |   AC_to_string:
77   | 
78   |   Show an access structure  
79   | 
80   |   returns an allocated string
81   |   ++++++++++++++++++++++++++++++++++++++*/
82   | char *AC_to_string(GList *leafptr)
83   | {
84   |   char *result_buf;
85   |   acc_st *a = leafptr->data;
86   | 
87   |   if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
88   |     /* XXX generic malloc handler pending ...*/
89   |     return NULL;
90   |   }
91   |   
92   |   if( a == NULL ) {
93   |     strcpy(result_buf, "DATA MISSING!");
94   |   }
95   |   else {
96   |     sprintf(result_buf,  ACC_FORMAT,
97   |             a->connections,
98   | 	    a->addrpasses,
99   |             a->denials,
100  |             a->queries,     
101  |             a->public_objects,
102  |             a->private_objects,
103  |             a->private_bonus
104  |             );
105  |   }
106  |   
107  |   return result_buf;
108  | } /* AC_to_string() */
109  | 
110  | 
111  | /*++++++++++++++++++++++++++++++++++++++
112  |   AC_credit_to_string:
113  |  
114  |  Show credit used (for logging of queries)
115  |  
116  |  acc_st *a     - the credit structure
117  |  
118  |  returns an allocated string
119  |  ++++++++++++++++++++++++++++++++++++++*/
120  | char *AC_credit_to_string(acc_st *a)
121  | {
122  |   char *result_buf;
123  |   
124  |   if( wr_malloc( (void **) &result_buf, 64) != UT_OK ) {
125  |     /* XXX generic malloc handler pending ...*/
126  |     return NULL;
127  |   }
128  |   
129  |   dieif( a == NULL );
130  |   
131  |   sprintf(result_buf,"%d+%d%s",
132  | 	  a->private_objects,
133  | 	  a->public_objects,
134  | 	  a->denials ? " **DENIED**" : ""
135  | 	  );
136  |   
137  |   return result_buf;
138  | } /* AC_credit_to_string */ 
139  | 
140  | 
141  | /*+++++++++++++++++++++++++++++++++++++++
142  |   AC_acl_to_string_header:
143  | 
144  |   produce a header for the acl printout
145  | 
146  |   returns an allocated string
147  |   ++++++++++++++++++++++++++++++++++++++*/
148  | char *
149  | AC_acl_to_string_header(void)
150  | {
151  |   char *result_buf;
152  |   dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
153  | 
154  |   sprintf(result_buf, ACL_HEADER, "ip",
155  | 	  "maxbonus", "maxdenials", "maxpublic", "ban", "trustpass" );
156  | 
157  |   return result_buf;
158  | }
159  | 
160  | 
161  | 
162  | /*++++++++++++++++++++++++++++++++++++++
163  |   AC_acl_to_string:
164  | 
165  |   Show an access control list structure
166  | 
167  |   returns an allocated string
168  |   ++++++++++++++++++++++++++++++++++++++*/
169  | char *AC_acl_to_string(GList *leafptr)
170  | {
171  |   char *result_buf;
172  |   acl_st *a = leafptr->data;
173  | 
174  |   if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
175  |     /* XXX generic malloc handler pending ...*/
176  |     return NULL;
177  |   }
178  |   
179  |   if( a != NULL ) {
180  |     sprintf(result_buf, ACL_FORMAT,
181  |             a->maxbonus,
182  |             a->maxdenials,
183  | 	    a->maxpublic,
184  |             a->deny,     
185  |             a->trustpass
186  |             );
187  |   }
188  |   else {
189  |     strcpy(result_buf, "DATA MISSING\n");
190  |   }
191  |   
192  |   return result_buf;
193  | } /* AC_acl_to_string() */
194  | 
195  | 
196  | /*+++++++++++++++++++++++++++++++++++++++
197  |   AC_findexless_acl_l:
198  | 
199  |   find the exact or less specific match for the given prefix in the acl tree.
200  | 
201  |   ip_prefix_t *prefix - prefix to look for
202  |   acl_st *store_acl   - pointer to store the output
203  | 
204  |   returns error code from RX or OK
205  | 
206  |   MT-Note: assumes locked acl tree
207  |   ++++++++++++++++++++++++++++++++++++++*/
208  | er_ret_t
209  | AC_findexless_acl_l(ip_prefix_t *prefix, acl_st *store_acl)
210  | {
211  |   GList       *datlist=NULL;
212  |   er_ret_t    ret_err;
213  |   rx_datref_t *datref;  
214  | 
215  |   if( (ret_err = RX_bin_search(RX_SRCH_EXLESS, 0, 0, act_acl, 
216  |                                prefix, &datlist, RX_ANS_ALL)
217  |        ) != RX_OK   ||  g_list_length(datlist) == 0 ) {
218  |     /* acl tree is not configured at all ! There always must be a
219  |        catch-all record with defaults */
220  |     die;
221  |   }
222  | 
223  |   datref = (rx_datref_t *)g_list_nth_data(datlist,0);
224  | 
225  |   *store_acl = * ((acl_st *)  datref->leafptr);
226  | 
227  |   wr_clear_list( &datlist );
228  | 
229  |   /* XXX dbg checking tree consistency */
230  |   {
231  |     rx_treecheck_t errorfound;
232  |     er_ret_t err;
233  |     if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
234  |       fprintf(stderr, "Nope! %d returned \n", err);
235  |       die;
236  |     }
237  |   }  
238  | 
239  |   return ret_err;
240  | }
241  | /* AC_findexless_acl_l */
242  | 
243  | 
244  | /*+++++++++++++++++++++++++++++++++++++++
245  |   AC_findcreate_acl_l:
246  |   
247  |   find or create an entry for the given prefix in the acl tree.
248  | 
249  |   ip_prefix_t *prefix - prefix to look for 
250  |   acl_st **store_acl  - pointer to store the ptr to the acl struct 
251  |                         (initialised to the values of the parent entry 
252  | 			if just created)
253  | 
254  |   returns error code from RX or OK
255  | 
256  |   MT-Note: assumes locked acl tree
257  |   ++++++++++++++++++++++++++++++++++++++*/
258  | er_ret_t
259  | AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
260  | {
261  |   GList       *datlist=NULL;
262  |   er_ret_t    ret_err;
263  |   acl_st      *newacl;
264  |   acl_st acl_copy;    
265  | 
266  |   if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl, 
267  | 				    prefix, &datlist, RX_ANS_ALL)
268  | 	    )) {
269  |     
270  |     switch( g_list_length(datlist)) {
271  |     case 0:
272  |       dieif( wr_calloc((void **)&newacl, 1, sizeof(acl_st)) != UT_OK );
273  |       
274  |       /* make the new one inherit all parameters after the old one */
275  |       
276  |       AC_findexless_acl_l(prefix, &acl_copy);
277  | 
278  |       *newacl = acl_copy;
279  |       
280  |       /* link in */
281  |       rx_bin_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
282  |       break;
283  |     case 1:
284  |       {
285  | 	/* Uh-oh, the guy is already known ! (or special, in any case) */ 
286  | 	rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
287  | 	newacl = (acl_st *) datref->leafptr;
288  |       }
289  |       break;
290  |     default:
291  |       die;
292  |     }
293  |   } 
294  | 
295  |   /* free search results */
296  |   wr_clear_list( &datlist );
297  |   
298  |   /* store */
299  |   *store_acl = newacl;
300  |   return ret_err;
301  | }
302  | /* AC_findcreate_acl_l */
303  | 
304  | 
305  | /*+++++++++++++++++++++++++++++++++++++++
306  |   AC_findcreate_account_l:
307  |   
308  |   finds exact prefix in the accounting tree
309  |   or creates area initialised to zeros + sets ptr to it.
310  |   
311  |   rx_tree_t *tree     - the tree
312  |   ip_prefix_t *prefix - prefix to look for 
313  |   acc_st **store_acl  - pointer to store the ptr to the account struct 
314  | 
315  |   returns error code from RX or OK
316  | 
317  |   MT-Note: assumes locked accounting tree 
318  |   ++++++++++++++++++++++++++++++++++++++*/
319  | er_ret_t 
320  | AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix, 
321  | 			acc_st **acc_store)
322  | {
323  |   GList       *datlist=NULL;
324  |   er_ret_t    ret_err;
325  |   acc_st      *recacc;
326  | 
327  |   if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree, 
328  |                                prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
329  |     switch( g_list_length(datlist) ) {
330  |     case 0:
331  |       /* need to create a new accounting record */
332  |       if( (ret_err = wr_malloc( (void **)& recacc, sizeof(acc_st))) == UT_OK ) {
333  |         /*  counters = init to zeros */
334  |         memset( recacc, 0, sizeof(acc_st));
335  |         
336  |         /* attach. The recacc is to be treated as a dataleaf
337  |            (must use lower levels than RX_asc_*)
338  |         */
339  |         ret_err = rx_bin_node( RX_OPER_CRE, prefix, 
340  |                                act_runtime, (rx_dataleaf_t *)recacc );
341  |       }
342  |       break;
343  |     case 1:
344  |       {
345  |         rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
346  |         
347  |         /* OK, there is a record already */
348  |         recacc = (acc_st *) datref->leafptr;
349  |         
350  |       }
351  |       break;
352  |     default: die; /* there shouldn't be more than 1 entry per IP */
353  |     }
354  |   }
355  |     
356  |   wr_clear_list( &datlist );
357  |   
358  |   *acc_store = recacc;
359  |   
360  |   return ret_err;
361  | }
362  | 
363  | 
364  | /*++++++++++++++++++++++++++++++++++++++
365  |   AC_fetch_acc:
366  | 
367  |   Finds the runtime accounting record for this IP, 
368  |   stores a copy of it in acc_store. 
369  |   If not found, then it is created and initialised to zeros in findcreate()
370  | 
371  |   ip_addr_t *addr  - address
372  |   acc_st *acc_store - pointer to store the account struct 
373  | 
374  |   MT-Note: locks/unlocks the accounting tree
375  |   ++++++++++++++++++++++++++++++++++++++*/
376  | er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
377  | {
378  |   er_ret_t ret_err;
379  |   ip_prefix_t prefix;
380  |   acc_st *ac_ptr;
381  | 
382  |   prefix.ip = *addr;
383  |   prefix.bits = IP_sizebits(addr->space);
384  | 
385  |   TH_acquire_read_lock( &(act_runtime->rwlock) );
386  |   
387  |   ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
388  |   *acc_store = *ac_ptr;
389  | 
390  |   TH_release_read_lock( &(act_runtime->rwlock) );
391  | 
392  |   return ret_err;
393  | }/* AC_fetch_acc() */
394  | 
395  | 
396  | /*++++++++++++++++++++++++++++++++++++++  
397  |   AC_check_acl:
398  |   
399  |   search for this ip or less specific record in the access control tree
400  |   
401  |   if( bonus in combined runtime+connection accountings > max_bonus in acl)
402  |             set denial in the acl for this ip (create if needed)
403  |   if( combined denialcounter > max_denials in acl)
404  |             set the permanent ban in acl; save in SQL too
405  |   calculate credit if pointer provided
406  |   save the access record (ip if created or found/prefix otherwise) 
407  |             at *acl_store if provided
408  | 
409  |   ip_addr_t *addr  - address
410  |   acc_st *acc_store - pointer to store the *credit* account struct 
411  |   acl_st *acl_store - pointer to store the acl struct 
412  |   
413  |   any of the args except address can be NULL
414  | 
415  |   returns error code from RX or OK
416  | 
417  |   MT-Note: locks/unlocks the accounting tree
418  |   ++++++++++++++++++++++++++++++++++++++*/
419  | er_ret_t AC_check_acl( ip_addr_t *addr, 
420  |                        acc_st *credit_acc,
421  |                        acl_st *acl_store
422  |                        )
423  | {
424  |   ip_prefix_t prefix;
425  |   er_ret_t    ret_err;
426  |   acl_st      acl_record;
427  |   acc_st      run_acc;
428  | 
429  |   AC_fetch_acc( addr, &run_acc );
430  |   
431  |   prefix.ip = *addr;
432  |   prefix.bits = IP_sizebits(addr->space);
433  |   
434  |   /* lock the tree accordingly */
435  |   TH_acquire_read_lock( &(act_acl->rwlock) );  
436  |   
437  |   /* find an applicable record */
438  |   AC_findexless_acl_l(&prefix, &acl_record);
439  |   
440  |   /* calculate the credit if pointer given */
441  |   if( credit_acc ) {
442  |     memset( credit_acc, 0, sizeof(acc_st));
443  |     credit_acc->public_objects =                       /* -1 == unlimited */
444  |       acl_record.maxpublic - run_acc.public_objects;
445  |     credit_acc->private_objects =
446  |       acl_record.maxbonus - run_acc.private_bonus;
447  |   }
448  | 
449  |   /* copy the acl record if asked for it*/
450  |   if( acl_store ) {
451  |     *acl_store =  acl_record;
452  |   }
453  | 
454  |   /* release lock */
455  |   TH_release_read_lock( &(act_acl->rwlock) );
456  |   
457  |  
458  |   return ret_err;
459  | }
460  | 
461  | 
462  | 
463  | /*++++++++++++++++++++++++++++++++++++++  
464  |   AC_acc_addup:
465  | 
466  |   Add/subtract the values from one accounting structure to another
467  | 
468  |   acc_st *a  - this one gets changed
469  |   acc_st *b  - this one provides the values to change a
470  |   int minus  - triggers subtraction if non-zero
471  | 
472  | +++++++++++++++++++++++++++++++++++++++*/
473  | void AC_acc_addup(acc_st *a, acc_st *b, int minus)
474  | {
475  |   int mul = minus ? -1 : 1;
476  |   
477  |   /* add all counters from b to those in a */
478  |   a->connections     +=  mul * b->connections;   
479  |   a->addrpasses      +=  mul * b->addrpasses;  
480  |  
481  |   a->denials         +=  mul * b->denials;      
482  |   a->queries         +=  mul * b->queries;       
483  |   a->public_objects  +=  mul * b->public_objects;
484  |   a->private_objects +=  mul * b->private_objects;
485  |   a->private_bonus   +=  mul * b->private_bonus;
486  | }/* AC_acc_addup */
487  | 
488  | /*++++++++++++++++++++++++++++++++++++++ 
489  |   AC_commit_credit:
490  | 
491  |   performs the commit on an accounting tree (locks them first)
492  |   stores a copy of the accounting record at rec_store
493  | 
494  |   rx_tree_t *tree      - the tree
495  |   ip_prefix_t *prefix  - prefix (usually a /32)
496  |   acc_st *acc_conn     - credit used
497  |   acc_st *rec_store    - pointer to store the account struct 
498  | 
499  |   returns error code from AC_findcreate_account_l or OK
500  | 
501  |   MT-Note: locks/unlocks the accounting tree
502  | +++++++++++++++++++++++++++++++++++++++*/
503  | er_ret_t 
504  | AC_commit_credit(rx_tree_t *tree, ip_prefix_t *prefix, 
505  | 		 acc_st *acc_conn, acc_st *rec_store )
506  | {
507  |   acc_st      *accountrec;
508  |   er_ret_t    ret_err;
509  | 
510  | 
511  |   acc_conn->private_bonus = acc_conn->private_objects;
512  | 
513  |   TH_acquire_write_lock( &(tree->rwlock) );
514  | 
515  |   ret_err = AC_findcreate_account_l(act_runtime, prefix, &accountrec);
516  |   
517  |   if( NOERR(ret_err)) {
518  |     AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
519  |   }
520  | 
521  |   TH_release_write_lock( &(tree->rwlock) );
522  |  
523  |   *rec_store = *accountrec;
524  |   
525  |   return ret_err;
526  | }/* AC_commit_credit */
527  | 
528  | 
529  | 
530  | /*++++++++++++++++++++++++++++++++++++++  
531  |   AC_acl_sql:
532  | 
533  |   updates/creates a record for the given prefix in the acl table of 
534  |   the RIPADMIN database. Adds a comment.
535  | 
536  |   ip_prefix_t *prefix  - prefix
537  |   acl_st *newacl       - new values to store in the database
538  |   char *newcomment     - comment to be added (must not be NULL)
539  |   
540  |   placeholder: it may return an error code from SQ - as soon as sq 
541  |   implements common error scheme
542  | 
543  |  ++++++++++++++++++++++++++++++++++++++*/
544  | er_ret_t 
545  | AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
546  | {  
547  |   SQ_connection_t *sql_connection = NULL;
548  |   SQ_result_set_t *result;
549  |   SQ_row_t *row;
550  |   char *oldcomment;
551  |   char *query;
552  |   char querybuf[256];
553  |   
554  |   sql_connection = SQ_get_connection(CO_get_host(),
555  | 				     CO_get_database_port(),
556  | 				     "RIPADMIN",
557  | 				     CO_get_user(), 
558  | 				     CO_get_password() );
559  |   
560  |   /* get the old entry, extend it */
561  |   sprintf(querybuf, "SELECT comment FROM acl WHERE "
562  | 	  "prefix = %u AND prefix_length = %d", 
563  | 	  prefix->ip.words[0],
564  | 	  prefix->bits);
565  |   dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
566  |   
567  |   if( SQ_num_rows(result) == 1 ) {
568  |     dieif( (row = SQ_row_next(result)) == NULL);
569  |     oldcomment = SQ_get_column_string(result, row, 0);
570  |   }
571  |   else {
572  |     oldcomment = "";
573  |   }
574  | 
575  |   SQ_free_result(result);
576  |   
577  |   /* must hold the thing below (REPLACE..blah blah blah) + text */
578  |   dieif( wr_malloc((void **)&query, 
579  | 		   strlen(oldcomment) + strlen(newcomment) + 256) != UT_OK );
580  |   
581  |   /* compose new entry and insert it */
582  |   sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
583  | 	  "\"%s%s%s\")",
584  | 	  prefix->ip.words[0],
585  | 	  prefix->bits,
586  | 	  newacl->maxbonus,
587  | 	  newacl->maxpublic,
588  | 	  newacl->maxdenials,
589  | 	  newacl->deny,
590  | 	  newacl->trustpass,
591  | 	  oldcomment, 
592  | 	  strlen(oldcomment) > 0 ? "\n" : "",
593  | 	  newcomment
594  | 	  );
595  |   
596  |   SQ_execute_query(sql_connection, query, NULL);
597  |   SQ_close_connection(sql_connection);
598  |   
599  |   wr_free(query);
600  |   
601  |   return AC_OK;
602  | 
603  | }/* AC_acl_sql */
604  | 
605  | /*++++++++++++++++++++++++++++++++++++++ 
606  |   AC_ban_set:
607  |   
608  |   re/sets the permanent ban flag both in the acl tree in memory
609  |   and the sql table. The "text" is appended to the comment 
610  |   in the sql record (the expected cases are
611  |   - "automatic" in case the limit is exceeded and ban is set by s/w
612  |   - "manual"    in case it is (un)set from the config iface
613  | 
614  |   ip_prefix_t *prefix   - prefix 
615  |   char *text            - usually "automatic" or "manual"  
616  |   int denyflag          - new value of the denyflag (ban)
617  |   
618  |   returns error code from AC_acl_sql or OK
619  |   +++++++++++++++++++++++++++++++++++++++*/
620  | er_ret_t
621  | AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
622  | {
623  |   acl_st *treeacl;
624  |   char newcomment[256];
625  |   er_ret_t ret_err;
626  |   time_t  clock;
627  |   char timebuf[26];
628  |   
629  |   time(&clock);
630  |   ctime_r(&clock, timebuf);
631  | 
632  |   sprintf(newcomment,"%s permanent ban set to %d at %s", text, 
633  | 	  denyflag, timebuf);
634  |     
635  |   TH_acquire_write_lock( &(act_acl->rwlock) );  
636  | 
637  |   /* find a record in the tree */  
638  |   if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
639  |     treeacl->deny = denyflag;
640  |     ret_err = AC_acl_sql( prefix, treeacl, newcomment );
641  |   }
642  |   TH_release_write_lock( &(act_acl->rwlock) );
643  | 
644  |   return ret_err;
645  | }/* AC_ban_set */
646  | 
647  | 
648  | /*++++++++++++++++++++++++++++++++++++++ 
649  |   AC_asc_ban_set:
650  |   
651  |   sets ban on text address/range. Parses the text address/range/prefix 
652  |   and then calls AC_ban_set on that prefix. 
653  |   
654  |   Precondition: if the key is a range, it must decompose into one prefix 
655  |   
656  |   returns error code from IP_smart_conv, AC_ban_set or 
657  |   AC_INVARG if range composed
658  |   +++++++++++++++++++++++++++++++++++++++*/
659  | er_ret_t
660  | AC_asc_ban_set(char *addrstr, char *text, int denyflag)
661  | {
662  |   er_ret_t ret_err;
663  |   GList *preflist = NULL;
664  |   ip_keytype_t key_type;
665  | 
666  |   if( (ret_err = IP_smart_conv(addrstr, 0, 0,
667  | 			       &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
668  |     return ret_err;
669  |   }
670  |   
671  |   /* allow only one prefix */
672  |   /* The argument can be even a range, but must decompose into one prefix */
673  |   if(  NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
674  |     ret_err = AC_INVARG;
675  |   }
676  |   
677  |   if( NOERR(ret_err) ) {
678  |     ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
679  |   }
680  | 
681  |   wr_clear_list( &preflist );
682  |   
683  |   return ret_err;
684  | }/* AC_asc_ban_set */
685  | 
686  | 
687  | /*++++++++++++++++++++++++++++++++++++++ 
688  |   AC_commit:
689  | 
690  |   commits the credit into all accounting trees, (XXX: only one at the moment)
691  |   checks the limits and sets automatic ban if limit exceeded.
692  | 
693  |   ip_addr_t *addr  - user's address
694  |   acc_st *acc_conn - credit used
695  |   acl_st *acl_copy - pointer to store a copy of the acl
696  | 
697  |   returns error code from AC_commit_credit or AC_ban_set or OK.
698  | 
699  |   outline:
700  |         lock runtime + minute accounting trees 
701  | 	-----------------------  XXX runtime only for the moment
702  |            find or create entries, 
703  |            increase accounting values by the values from passed acc
704  |            check values against acl, see if permanent ban applies
705  | 
706  |            reset the connection acc
707  |         unlock accounting trees
708  | 
709  |         if permanent ban - set it! :
710  |             lock acl
711  |             find/create IP in memory
712  |             set ban
713  |             find/create IP in SQL
714  |             copy old values (if any), set ban, append comment
715  |             unlock acl
716  | 
717  |  +++++++++++++++++++++++++++++++++++++++*/
718  | er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) { 
719  |   acc_st   account;
720  |   er_ret_t ret_err;
721  |   ip_prefix_t prefix;
722  | 
723  |   prefix.ip = *addr;
724  |   prefix.bits = IP_sizebits(addr->space);
725  |   
726  |   ret_err = AC_commit_credit(act_runtime, &prefix, acc_conn, &account);
727  |   /* XXX add more trees here */
728  |   
729  |   memset(acc_conn,0, sizeof(acc_st));
730  | 
731  |   /* set permanent ban if deserved  and if not set yet */
732  |   if( account.denials > acl_copy->maxdenials 
733  |       && acl_copy->deny == 0 
734  |       && NOERR(ret_err) ) {
735  |     
736  |     ret_err = AC_ban_set(&prefix, "Automatic", 1);
737  |   }
738  | 
739  |   return ret_err;
740  | } /* AC_commit */
741  | 
742  | 
743  | /*++++++++++++++++++++++++++++++++++++++ 
744  |   AC_decay_hook:
745  | 
746  |   action performed on a single account node during decay (diminishing the
747  |   bonus). Conforms to rx_walk_tree interface, therefore some of the 
748  |   arguments do not apply and are not used.
749  | 
750  |   rx_node_t *node  - pointer to the node of the radix tree
751  |   int level        - n/a
752  |   int nodecounter  - n/a
753  |   void *con        - n/a
754  | 
755  |   returns always OK
756  | +++++++++++++++++++++++++++++++++++++++*/
757  | er_ret_t AC_decay_hook(rx_node_t *node, int level, int nodecounter, void *con)
758  | {
759  |   acc_st *a = node->leaves_ptr->data;
760  |   
761  |   a->private_bonus *= 0.95;
762  | 
763  |   return RX_OK;
764  | } /* AC_decay_hook() */
765  | 
766  | 
767  | 
768  | /*++++++++++++++++++++++++++++++++++++++
769  |   AC_decay:
770  |   
771  |   Every AC_DECAY_TIME goes through the accounting tree(s) and decays the 
772  |   bonus values.
773  |   
774  |   returns always OK
775  | 
776  |   MT-Note  This should be run as a detached thread.
777  |   +++++++++++++++++++++++++++++++++++++++*/
778  | er_ret_t AC_decay(void) {
779  |   er_ret_t ret_err;
780  | 
781  |   
782  |   while(CO_get_do_server()) {
783  | 
784  |     TH_acquire_write_lock( &(act_runtime->rwlock) );
785  | 
786  |     if( act_runtime->top_ptr != NULL ) {
787  |        rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
788  |                          RX_WALK_SKPGLU,  /* skip glue nodes */
789  |                          255, 0, 0, NULL, &ret_err);
790  |     }
791  | 
792  |     /* it should also be as smart as to delete nodes that have reached 
793  |        zero, otherwise the whole of memory will be filled.
794  |        Next release :-)
795  |     */
796  | 
797  |     TH_release_write_lock( &(act_runtime->rwlock) );
798  | 
799  |     printf("AC: decaying access tree. (Every %d seconds)\n", AC_DECAY_TIME);
800  | 
801  |     SV_sleep(LOCK_SHTDOWN, AC_DECAY_TIME);
802  |   }
803  | 
804  |   return ret_err;
805  | } /* AC_decay() */
806  | 
807  | 
808  | /*++++++++++++++++++++++++++++++++++++++ 
809  |   AC_acc_load:
810  | 
811  |   loads the acl access tree from the acl table of the RIPADMIN database.
812  |   (takes port/host/user/password from the config module).
813  |   
814  |   bails out if encounters problems with the database (logs to stderr).
815  | 
816  |   returns error code from RX_bin_node or wr_malloc.
817  |   ++++++++++++++++++++++++++++++++++++++*/
818  | er_ret_t AC_acc_load(void)
819  | {
820  |   SQ_connection_t *con=NULL;
821  |   SQ_result_set_t *result;
822  |   SQ_row_t *row;
823  |   er_ret_t ret_err = RX_OK;
824  | 
825  |   if( (con = SQ_get_connection(CO_get_host(), CO_get_database_port(), 
826  |                         "RIPADMIN", CO_get_user(), CO_get_password() )
827  |        ) == NULL ) {
828  |     fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
829  |     die;
830  |   }
831  |   
832  |   if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
833  |       fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
834  |       die;
835  |   }
836  |   
837  |   TH_acquire_write_lock( &(act_acl->rwlock) );
838  | 
839  |   while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
840  |     ip_prefix_t mypref;
841  |     acl_st *newacl;
842  |     char *col[7];
843  |     unsigned myint;
844  |     int i;
845  | 
846  |     memset(&mypref, 0, sizeof(ip_prefix_t));
847  |     mypref.ip.space = IP_V4;
848  |     
849  |     if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
850  |          ) == UT_OK ) {
851  | 
852  |       for(i=0; i<7; i++) {
853  |         if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
854  |           die;
855  |         }
856  |       }
857  |       
858  |       /* prefix ip */
859  |       if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
860  |       
861  |       /* prefix length */
862  |       if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
863  |       
864  |       /* acl contents */
865  |       if( sscanf(col[2], "%u",  & (newacl->maxbonus)   ) < 1 ) { die; }
866  |       if( sscanf(col[3], "%u",  & (newacl->maxpublic)   ) < 1 ) { die; }
867  |       if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
868  |       
869  |       /* these are chars therefore cannot read directly */
870  |       if( sscanf(col[5], "%u", &myint              ) < 1 ) { die; }
871  |       else {
872  |         newacl->deny = myint;
873  |       }
874  |       if( sscanf(col[6], "%u", &myint  ) < 1 ) { die; }
875  |       else {
876  |         newacl->trustpass = myint;
877  |       }
878  |       
879  |       /* free space */
880  |       for(i=0; i<6; i++) {
881  | 	  wr_free(col[i]);
882  |       }
883  |       
884  |       /* now add to the tree */      
885  |       ret_err = rx_bin_node( RX_OPER_CRE, &mypref, 
886  |                              act_acl, (rx_dataleaf_t *) newacl );
887  |     }
888  |   } /* while row */
889  | 
890  |   TH_release_write_lock( &(act_acl->rwlock) );
891  | 
892  |   SQ_free_result(result);
893  |   /* Close connection */
894  |   SQ_close_connection(con);
895  | 
896  |   return ret_err;
897  | } /* AC_acc_load */
898  | 
899  | 
900  | 
901  | /*++++++++++++++++++++++++++++++++++++++ 
902  |   AC_build:
903  | 
904  |   creates empty trees for accounting/acl.
905  |   
906  |   returns error code from RX_tree_cre or OK.
907  |   (XXX): just now only bails out when encounters problems.
908  |   ++++++++++++++++++++++++++++++++++++++*/
909  | er_ret_t AC_build(void) 
910  | {
911  |   /* create trees */
912  |   if (      RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
913  | 			RX_SUB_NONE, &act_runtime) != RX_OK
914  | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
915  | 			RX_SUB_NONE, &act_hour) != RX_OK
916  | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
917  | 			RX_SUB_NONE, &act_minute) != RX_OK
918  | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
919  | 			RX_SUB_NONE, &act_acl) != RX_OK
920  |          )
921  |     die; /*can be changed to an error and handled ... some day */
922  | 
923  |   return RX_OK;
924  | }
925  | 
926  | /*++++++++++++++++++++++++++++++++++++++ 
927  |   AC_rxwalkhook_print:
928  | 
929  |   action performed on a single account node 
930  |   when listing the contents of the access tree: format and print the
931  |   data from this node.
932  | 
933  |   Conforms to rx_walk_tree interface, therefore some of the 
934  |   arguments do not apply and are not used.
935  |   
936  |   rx_node_t *node  - pointer to the node of the radix tree
937  |   int level        - n/a
938  |   int nodecounter  - n/a
939  |   void *con        - pointer to the connection structure (prints to it)
940  |   
941  |   returns always OK 
942  | +++++++++++++++++++++++++++++++++++++++*/
943  | er_ret_t AC_rxwalkhook_print(rx_node_t *node, 
944  |                              int level, int nodecounter, 
945  |                              void *con)
946  | {
947  |   char adstr[IP_ADDRSTR_MAX];
948  |   char line[1024];
949  |   char *dat;
950  |   
951  |   
952  |     if( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK ) {
953  |       die; /* program error. */
954  |     }
955  |     
956  |     sprintf(line, "%-20s %s\n", adstr, 
957  |             dat=AC_to_string( node->leaves_ptr ));
958  |     wr_free(dat);
959  |     
960  |     SK_cd_puts((sk_conn_st *)con, line);
961  |     return RX_OK;
962  | } /* AC_rxwalkhook_print */
963  | 
964  | 
965  | /*++++++++++++++++++++++++++++++++++++++
966  |   AC_rxwalkhook_print_acl:
967  |   
968  |   action performed on a single account node 
969  |   when listing the contents of the acl tree: format and print the
970  |   data from this node.
971  | 
972  |   Conforms to rx_walk_tree interface, therefore some of the 
973  |   arguments do not apply and are not used.
974  |   
975  |   rx_node_t *node  - pointer to the node of the radix tree
976  |   int level        - n/a
977  |   int nodecounter  - n/a
978  |   void *con        - pointer to the connection structure (prints to it)
979  | 
980  |   returns always OK 
981  |   +++++++++++++++++++++++++++++++++++++++*/
982  | er_ret_t AC_rxwalkhook_print_acl(rx_node_t *node, 
983  |                              int level, int nodecounter, 
984  |                              void *con)
985  | {
986  |   char prefstr[IP_PREFSTR_MAX];
987  |   char line[1024];
988  |   char *dat;
989  |   
990  |   
991  |     if( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK ) {
992  |       die; /* program error. */
993  |     }
994  |     
995  |     sprintf(line, "%-20s %s\n", prefstr, 
996  |             dat=AC_acl_to_string( node->leaves_ptr ));
997  |     wr_free(dat);
998  |     
999  |     SK_cd_puts((sk_conn_st *)con, line);
1000 |     return RX_OK;
1001 | }/* AC_rxwalkhook_print_acl */
1002 |