1    | /***************************************
2    |   $Revision: 1.47 $
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,2000,2001,2002                         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   | 
31   | /* 
32   |    test excercises:
33   | 
34   |    1. add a function to delete an entry from the acl table,
35   |       it should be called from the pc module.
36   |       
37   | */
38   | 
39   | #define AC_IMPL
40   | #include "rip.h"
41   | 
42   | #include <stdio.h>
43   | #include <glib.h>
44   | #include <string.h>
45   | #include <math.h>
46   | 
47   | #include <unistd.h>
48   | #include <stdlib.h>
49   | 
50   | extern char *suboptarg;
51   | extern int getsubopt(char **optionp, char * const *tokens, char **valuep);
52   | 
53   | /* formats for printing the access control list entries */
54   | #define ACL_FORMAT        "%10d %10d %10d %10d %10d"
55   | #define ACL_HEADER  "%-20s %10s %10s %10s %10s %10s\n"
56   | 
57   | /* formats for printing the accounting entries */
58   | #define ACC_FORMAT       "%4d %4d %4d %4d %7d %7d %7d %7.2f %7.1f %10.0f"
59   | #define ACC_HEADER "%-20s %4s %4s %4s %4s %7s %7s %7s %7s %7s %s\n"
60   | 
61   | 
62   | typedef struct {
63   | /*  double decay_factor;*/
64   |   unsigned newtotal;
65   |   GList *prunelist;
66   | } ac_decay_data_t;
67   | 
68   | ut_timer_t oldest_timestamp;
69   | 
70   | /*++++++++++++++++++++++++++++++++++++++
71   |   ac_to_string_header:
72   | 
73   |   produce a header for the access stats printout  
74   | 
75   |   returns an allocated string
76   |   ++++++++++++++++++++++++++++++++++++++*/
77   | static
78   | char *ac_to_string_header(void) 
79   | {
80   |   char *result_buf;
81   | 
82   |   result_buf = UT_malloc(256);
83   |   
84   |   sprintf(result_buf, ACC_HEADER, 
85   | 	  "ip", "conn", "pass", "deny", "qry", "refs", "priv_o", "pub_o", "priv_b","pub_b", "ts");
86   | 
87   |   return result_buf;
88   | }
89   | 
90   | /*++++++++++++++++++++++++++++++++++++++
91   |   ac_to_string:
92   | 
93   |   Show an access structure  
94   | 
95   |   returns an allocated string
96   |   ++++++++++++++++++++++++++++++++++++++*/
97   | static
98   | char *ac_to_string(GList *leafptr)
99   | {
100  |   char *result_buf;
101  |   acc_st *a = leafptr->data;
102  | 
103  |   result_buf = UT_malloc(256);
104  |   
105  |   if( a == NULL ) {
106  |     strcpy(result_buf, "DATA MISSING!");
107  |   }
108  |   else {
109  |     sprintf(result_buf,  ACC_FORMAT,
110  |             a->connections,
111  | 	    a->addrpasses,
112  |             a->denials,
113  |             a->queries,     
114  | 	    a->referrals,
115  |             a->private_objects,
116  |             a->public_objects,
117  |             a->private_bonus,
118  | 	    a->public_bonus,
119  |             UT_time_getvalue(&a->timestamp)
120  |             );
121  |   }
122  |   
123  |   return result_buf;
124  | } /* ac_to_string() */
125  | 
126  | 
127  | /*++++++++++++++++++++++++++++++++++++++
128  |   AC_credit_to_string:
129  |  
130  |  Show credit used (for logging of queries)
131  |  
132  |  acc_st *a     - the credit structure
133  |  
134  |  returns an allocated string
135  |  ++++++++++++++++++++++++++++++++++++++*/
136  | char *AC_credit_to_string(acc_st *a)
137  | {
138  |   char *result_buf;
139  |   
140  |   result_buf = UT_malloc(64);
141  |   
142  |   dieif( a == NULL );
143  |   
144  |   sprintf(result_buf,"%d+%d+%d%s",
145  | 	  a->private_objects,
146  | 	  a->public_objects,
147  | 	  a->referrals,
148  | 	  a->denials ? " **DENIED**" : ""
149  | 	  );
150  |   
151  |   return result_buf;
152  | } /* AC_credit_to_string */ 
153  | 
154  | 
155  | /*+++++++++++++++++++++++++++++++++++++++
156  |   ac_acl_to_string_header:
157  | 
158  |   produce a header for the acl printout
159  | 
160  |   returns an allocated string
161  |   ++++++++++++++++++++++++++++++++++++++*/
162  | static char *
163  | ac_acl_to_string_header(void)
164  | {
165  |   char *result_buf;
166  | 
167  |   result_buf = UT_malloc(256);
168  | 
169  |   sprintf(result_buf, ACL_HEADER, "ip",
170  | 	  /* the names must match those in AC_ar_acl, so just take
171  | 	   them from there */
172  | 	  AC_ar_acl[AC_AR_MAXPRIVATE],
173  | 	  AC_ar_acl[AC_AR_MAXPUBLIC],
174  | 	  AC_ar_acl[AC_AR_MAXDENIALS],
175  | 	  AC_ar_acl[AC_AR_DENY],
176  | 	  AC_ar_acl[AC_AR_TRUSTPASS]
177  | 	  );
178  | 
179  | 
180  |   return result_buf;
181  | }
182  | 
183  | 
184  | 
185  | /*++++++++++++++++++++++++++++++++++++++
186  |   ac_acl_to_string:
187  | 
188  |   Show an access control list structure
189  | 
190  |   returns an allocated string
191  |   ++++++++++++++++++++++++++++++++++++++*/
192  | static
193  | char *ac_acl_to_string(GList *leafptr)
194  | {
195  |   char *result_buf;
196  |   acl_st *a = leafptr->data;
197  | 
198  |   result_buf = UT_malloc(256);
199  |   
200  |   if( a != NULL ) {
201  |     sprintf(result_buf, ACL_FORMAT,
202  |             a->maxprivate,
203  | 	    a->maxpublic,  
204  | 	    a->maxdenials,
205  |             a->deny,     
206  |             a->trustpass
207  |             );
208  |   }
209  |   else {
210  |     strcpy(result_buf, "DATA MISSING\n");
211  |   }
212  |   
213  |   return result_buf;
214  | } /* ac_acl_to_string() */
215  | 
216  | 
217  | /*+++++++++++++++++++++++++++++++++++++++
218  |   ac_find_acl_l:
219  | 
220  |   find the exact or exact/less specific match for the given prefix in the acl tree.
221  | 
222  |   ip_prefix_t *prefix - prefix to look for
223  | 
224  |   acl_st *store_acl   - pointer to store the output
225  | 
226  |   returns error code from RX or OK
227  | 
228  |   MT-Note: assumes locked acl tree
229  |   ++++++++++++++++++++++++++++++++++++++*/
230  | static er_ret_t
231  | ac_find_acl_l(rx_srch_mt searchmode, ip_prefix_t *prefix, acl_st *store_acl)
232  | {
233  |   GList       *datlist=NULL;
234  |   er_ret_t    ret_err;
235  |   rx_datref_t *datref;  
236  | 
237  |   /* accept only RX_SRCH_EXLESS | RX_SRCH_EXACT modes */
238  |   dieif( searchmode != RX_SRCH_EXLESS && searchmode != RX_SRCH_EXACT);
239  | 
240  |   /* it must work */
241  |   dieif( (ret_err = RX_bin_search(searchmode, 0, 0, act_acl, 
242  |                                prefix, &datlist, RX_ANS_ALL)
243  |        ) != RX_OK );
244  |   /* In exless mode, something must be found or the acl tree is not 
245  |      configured at all ! 
246  |      There always must be a catch-all record with defaults */
247  |   dieif( searchmode == RX_SRCH_EXLESS && g_list_length(datlist) == 0 );
248  | 
249  | 
250  |   datref = (rx_datref_t *)g_list_nth_data(datlist,0);
251  | 
252  |   *store_acl = * ((acl_st *)  datref->leafptr);
253  | 
254  |   wr_clear_list( &datlist );
255  | 
256  | #if 0
257  |   /* XXX dbg checking tree consistency */
258  |   {
259  |     rx_treecheck_t errorfound;
260  |     er_ret_t err;
261  |     if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
262  |       fprintf(stderr, "Nope! %d returned \n", err);
263  |       die;
264  |     }
265  |   }  
266  | #endif
267  | 
268  |   return ret_err;
269  | }
270  | /* ac_find_acl_l */
271  | 
272  | 
273  | /*+++++++++++++++++++++++++++++++++++++++
274  |   AC_findcreate_acl_l:
275  |   
276  |   find or create an entry for the given prefix in the acl tree.
277  | 
278  |   ip_prefix_t *prefix - prefix to look for 
279  | 
280  |   acl_st **store_acl  - pointer to store the ptr to the acl struct 
281  |                         (initialised to the values of the parent entry 
282  | 			if just created)
283  | 
284  |   returns error code from RX or OK
285  | 
286  |   MT-Note: assumes locked acl tree
287  |   ++++++++++++++++++++++++++++++++++++++*/
288  | er_ret_t
289  | AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
290  | {
291  |   GList       *datlist=NULL;
292  |   er_ret_t    ret_err;
293  |   acl_st      *newacl;
294  |   acl_st acl_copy;    
295  | 
296  |   if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl, 
297  | 				    prefix, &datlist, RX_ANS_ALL)
298  | 	    )) {
299  |     
300  |     switch( g_list_length(datlist)) {
301  |     case 0:
302  |       newacl = UT_calloc(sizeof(acl_st), 1);
303  |       
304  |       /* make the new one inherit all parameters after the old one */
305  |       
306  |       ac_find_acl_l(RX_SRCH_EXLESS, prefix, &acl_copy);
307  | 
308  |       *newacl = acl_copy;
309  | 
310  |       /* link in */
311  |       rx_bin_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
312  |       break;
313  |     case 1:
314  |       {
315  | 	/* Uh-oh, the guy is already known ! (or special, in any case) */ 
316  | 	rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
317  | 	newacl = (acl_st *) datref->leafptr;
318  |       }
319  |       break;
320  |     default:
321  |       die;
322  |     }
323  |   } 
324  | 
325  |   /* free search results */
326  |   wr_clear_list( &datlist );
327  |   
328  |   /* store */
329  |   *store_acl = newacl;
330  |   return ret_err;
331  | }
332  | /* AC_findcreate_acl_l */
333  | 
334  | 
335  | /*+++++++++++++++++++++++++++++++++++++++
336  |   AC_findcreate_account_l:
337  |   
338  |   finds exact prefix in the accounting tree
339  |   or creates area initialised to zeros + sets ptr to it.
340  |   
341  |   rx_tree_t *tree     - the tree
342  | 
343  |   ip_prefix_t *prefix - prefix to look for 
344  | 
345  |   acc_st **store_acl  - pointer to store the ptr to the account struct 
346  | 
347  |   returns error code from RX or OK
348  | 
349  |   MT-Note: assumes locked accounting tree 
350  |   ++++++++++++++++++++++++++++++++++++++*/
351  | er_ret_t 
352  | AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix, 
353  | 			acc_st **acc_store)
354  | {
355  |   GList       *datlist=NULL;
356  |   er_ret_t    ret_err;
357  |   acc_st      *recacc;
358  | 
359  |   if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree, 
360  |                                prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
361  |     switch( g_list_length(datlist) ) {
362  |     case 0:
363  |       /* need to create a new accounting record */
364  |       recacc = UT_malloc(sizeof(acc_st));
365  | 
366  |       /*  counters = init to zeros */
367  |       memset( recacc, 0, sizeof(acc_st));
368  | 
369  |       recacc->changed = AC_ACC_NEW;
370  |         
371  |       /* attach. The recacc is to be treated as a dataleaf
372  |         (must use lower levels than RX_asc_*)
373  |       */
374  |       ret_err = rx_bin_node( RX_OPER_CRE, prefix, 
375  |                              act_runtime, (rx_dataleaf_t *)recacc );
376  |       if (ret_err != RX_OK) {
377  |         ER_perror(FAC_AC, AC_INTR_ERR, "rx_bin_node() returned %d", ret_err);
378  |       }
379  |       break;
380  |     case 1:
381  |       {
382  |         rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
383  |         /* OK, there is a record already */
384  |         recacc = (acc_st *) datref->leafptr;
385  |         
386  |       }
387  |       break;
388  |     default: die; /* there shouldn't be more than 1 entry per IP */
389  |     }
390  |   } else {
391  |     ER_perror(FAC_AC, AC_INTR_ERR, "RX_bin_search() returned %d", ret_err);
392  |   }
393  |     
394  |   wr_clear_list( &datlist );
395  |   
396  |   *acc_store = recacc;
397  | 
398  | #if 0
399  |   /* XXX dbg checking tree consistency */
400  |     if( act_runtime->top_ptr != NULL ) {
401  |       rx_treecheck_t errorfound;
402  |       er_ret_t err;
403  |       if( (err=RX_treecheck(act_runtime, 1, &errorfound)) != RX_OK ) {
404  | 	fprintf(stderr, "Nope! %d returned \n", errorfound);
405  | 	ER_dbg_va( FAC_AC, ASP_AC_DECAY,
406  | 		   "AC: checking access tree consistency: error %d", 
407  | 		   errorfound);
408  | 	die; /* access tree not consistent */
409  |       }
410  |     }
411  | #endif  
412  | 
413  |   return ret_err;
414  | }
415  | 
416  | 
417  | /*++++++++++++++++++++++++++++++++++++++
418  |   AC_fetch_acc:
419  | 
420  |   Finds the runtime accounting record for this IP, 
421  |   stores a copy of it in acc_store. 
422  |   If not found, then it is created and initialised to zeros in findcreate()
423  | 
424  |   ip_addr_t *addr  - address
425  | 
426  |   acc_st *acc_store - pointer to store the account struct 
427  | 
428  |   MT-Note: locks/unlocks the accounting tree
429  |   ++++++++++++++++++++++++++++++++++++++*/
430  | er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
431  | {
432  |   er_ret_t ret_err;
433  |   ip_prefix_t prefix;
434  |   acc_st *ac_ptr;
435  | 
436  |   prefix.ip = *addr;
437  |   prefix.bits = IP_sizebits(addr->space);
438  | 
439  |   TH_acquire_write_lock( &(act_runtime->rwlock) );
440  |   
441  |   ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
442  |   *acc_store = *ac_ptr;
443  | 
444  |   TH_release_write_lock( &(act_runtime->rwlock) );
445  | 
446  |   return ret_err;
447  | }/* AC_fetch_acc() */
448  | 
449  | 
450  | /*++++++++++++++++++++++++++++++++++++++  
451  |   AC_check_acl:
452  |   
453  |   search for this ip or less specific record in the access control tree
454  |   
455  |   if( bonus in combined runtime+connection accountings > max_bonus in acl)
456  |             set denial in the acl for this ip (create if needed)
457  |   if( combined denialcounter > max_denials in acl)
458  |             set the permanent ban in acl; save in SQL too
459  |   calculate credit if pointer provided
460  |   save the access record (ip if created or found/prefix otherwise) 
461  |             at *acl_store if provided
462  | 
463  |   ip_addr_t *addr  - address
464  | 
465  |   acc_st *acc_store - pointer to store the *credit* account struct 
466  | 
467  |   acl_st *acl_store - pointer to store the acl struct 
468  |   
469  |   any of the args except address can be NULL
470  | 
471  |   returns error code from RX or OK
472  | 
473  |   MT-Note: locks/unlocks the accounting tree
474  |   ++++++++++++++++++++++++++++++++++++++*/
475  | er_ret_t AC_check_acl( ip_addr_t *addr, 
476  |                        acc_st *credit_acc,
477  |                        acl_st *acl_store
478  |                        )
479  | {
480  |   ip_prefix_t prefix;
481  |   er_ret_t    ret_err = AC_OK;
482  |   acl_st      acl_record;
483  |   acc_st      run_acc;
484  | 
485  |   AC_fetch_acc( addr, &run_acc );
486  |   
487  |   prefix.ip = *addr;
488  |   prefix.bits = IP_sizebits(addr->space);
489  |   
490  |   /* lock the tree accordingly */
491  |   TH_acquire_read_lock( &(act_acl->rwlock) );  
492  |   
493  |   /* find an applicable record */
494  |   ac_find_acl_l(RX_SRCH_EXLESS, &prefix, &acl_record);
495  |   
496  |   /* calculate the credit if pointer given */
497  |   if( credit_acc ) {
498  |     memset( credit_acc, 0, sizeof(acc_st));
499  |     
500  |     /* credit = -1 if unlimited, otherwise credit = limit - bonus */
501  |     credit_acc->public_objects = 
502  |       ( acl_record.maxpublic == -1 ) 
503  |       ? -1 /* -1 == unlimited */
504  |       : (acl_record.maxpublic - run_acc.public_bonus);
505  |     
506  |     credit_acc->private_objects =
507  |       ( acl_record.maxprivate == -1 ) 
508  |       ? -1 /* -1 == unlimited */
509  |       : (acl_record.maxprivate - run_acc.private_bonus);
510  |   }
511  |   
512  |   /* copy the acl record if asked for it*/
513  |   if( acl_store ) {
514  |     *acl_store =  acl_record;
515  |   }
516  | 
517  |   /* release lock */
518  |   TH_release_read_lock( &(act_acl->rwlock) );
519  |   
520  |  
521  |   return ret_err;
522  | }
523  | 
524  | 
525  | void AC_decay_leaf_l(acc_st *leaf) {
526  |   double factor;
527  |   ut_timer_t current;
528  |   float time_diff;
529  | 
530  |   UT_timeget(&current);
531  |   time_diff = UT_timediff(&leaf->timestamp, &current);
532  |   if (UT_time_getvalue(&leaf->timestamp) > 1 && abs(time_diff) > 0.2) {
533  |     factor = exp (-0.693147180559945 * time_diff / ca_get_ac_decay_halflife);
534  |     leaf->private_bonus *= factor;
535  |     leaf->public_bonus  *= factor;
536  |   }
537  | }
538  | 
539  | /*++++++++++++++++++++++++++++++++++++++  
540  |   AC_acc_addup:
541  | 
542  |   Add/subtract the values from one accounting structure to another
543  | 
544  |   acc_st *a   this one gets changed
545  | 
546  |   acc_st *b   this one provides the values to change a
547  | 
548  |   int minus   triggers subtraction if non-zero
549  | 
550  | +++++++++++++++++++++++++++++++++++++++*/
551  | void AC_acc_addup(acc_st *a, acc_st *b, int minus)
552  | {
553  |   int mul = minus ? -1 : 1;
554  |   time_t current_time;
555  |   
556  |   current_time = time(NULL);
557  | 
558  |   AC_decay_leaf_l(a);
559  | 
560  | 
561  |   UT_timeget(&a->timestamp);
562  | 
563  |   /* add all counters from b to those in a */
564  |   a->connections     +=  mul * b->connections;   
565  |   a->addrpasses      +=  mul * b->addrpasses;  
566  |  
567  |   a->denials         +=  mul * b->denials;      
568  |   a->queries         +=  mul * b->queries;       
569  |   a->referrals       +=  mul * b->referrals;
570  |   a->public_objects  +=  mul * b->public_objects;
571  |   a->private_objects +=  mul * b->private_objects;
572  |   a->private_bonus   +=  mul * b->private_bonus;
573  |   a->public_bonus    +=  mul * b->public_bonus;
574  | 
575  | 
576  |   if (a->changed == AC_ACC_NOT_CHANGED) {
577  |     a->changed = AC_ACC_CHANGED;
578  |   }
579  | 
580  | 
581  | }/* AC_acc_addup */
582  | 
583  | /*++++++++++++++++++++++++++++++++++++++ 
584  |   commit_credit_l:
585  | 
586  |   performs the commit on an accounting tree (locks them first)
587  |   stores a copy of the accounting record at rec_store
588  | 
589  |   Assumes locked tree.
590  | 
591  |   rx_tree_t *tree      - the tree
592  | 
593  |   ip_prefix_t *prefix  - prefix (usually a /32)
594  | 
595  |   acc_st *acc_conn     - credit used
596  | 
597  |   acc_st *rec_store    - pointer to store the account struct or NULL
598  | 
599  |   returns error code from AC_findcreate_account_l or OK
600  | 
601  |   MT-Note: locks/unlocks the accounting tree
602  | +++++++++++++++++++++++++++++++++++++++*/
603  | static
604  | er_ret_t 
605  | AC_commit_credit_l(rx_tree_t *tree, ip_prefix_t *prefix, 
606  | 		 acc_st *acc_conn, acc_st *rec_store )
607  | {
608  |   acc_st      *accountrec;
609  |   er_ret_t    ret_err;
610  |   char dbg_pref[50];
611  | 
612  | 
613  |   acc_conn->private_bonus = acc_conn->private_objects;
614  |   acc_conn->public_bonus  = acc_conn->public_objects;
615  | 
616  |   
617  |   ret_err = AC_findcreate_account_l(act_runtime, prefix, &accountrec);
618  |   
619  |   if( NOERR(ret_err)) {
620  | // XXX remove debug    IP_pref_b2a(prefix, dbg_pref, 50);
621  |     AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
622  |   }
623  | 
624  |   if( rec_store ) {
625  |     *rec_store = *accountrec;
626  |   }
627  |   
628  |   return ret_err;
629  | }/* AC_commit_credit */
630  | 
631  | /*++++++++++++++++++++++++++++++++++++++  
632  |   AC_dbopen_admin:
633  | 
634  |   opens the ADMIN database and returns a pointer to the connection structure
635  |   (rationale: the opening process became a bit bloated and is done twice,
636  |   so I put it into a separate function)
637  | ++++++++++++++++++++++++++++++++++++++*/
638  | SQ_connection_t *
639  | AC_dbopen_admin(void)
640  | {
641  |   SQ_connection_t *con=NULL;
642  |   char *dbhost = ca_get_ripadminhost;
643  |   char *dbname = ca_get_ripadmintable;
644  |   char *dbuser = ca_get_ripadminuser;
645  |   char *dbpass = ca_get_ripadminpassword;
646  |   unsigned dbport = ca_get_ripadminport;
647  |   
648  |   if( (con = SQ_get_connection(dbhost, dbport, dbname, dbuser, dbpass) 
649  |        ) == NULL ) {
650  |     fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
651  |     die;
652  |   }
653  |   
654  |   UT_free(dbhost);
655  |   UT_free(dbname);
656  |   UT_free(dbuser);
657  |   UT_free(dbpass);
658  | 
659  |   return con;
660  | }
661  | 
662  | /*++++++++++++++++++++++++++++++++++++++  
663  |   AC_acl_sql:
664  | 
665  |   updates/creates a record for the given prefix in the acl table of 
666  |   the RIPADMIN database. Adds a comment.
667  | 
668  |   ip_prefix_t *prefix  - prefix
669  | 
670  |   acl_st *newacl       - new values to store in the database
671  | 
672  |   char *newcomment     - comment to be added (must not be NULL)
673  |   
674  |   placeholder: it may return an error code from SQ - as soon as sq 
675  |   implements common error scheme
676  | 
677  |  ++++++++++++++++++++++++++++++++++++++*/
678  | er_ret_t 
679  | AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
680  | {  
681  |   SQ_connection_t *sql_connection = NULL;
682  |   SQ_result_set_t *result;
683  |   SQ_row_t *row;
684  |   char *oldcomment;
685  |   char *query;
686  |   char querybuf[256];
687  | 
688  |   sql_connection = AC_dbopen_admin();
689  |   
690  |   /* get the old entry, extend it */
691  |   sprintf(querybuf, "SELECT comment FROM acl WHERE "
692  | 	  "prefix = %u AND prefix_length = %d", 
693  | 	  prefix->ip.words[0],
694  | 	  prefix->bits);
695  |   dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
696  |   
697  |   if( SQ_num_rows(result) == 1 ) {
698  |     dieif( (row = SQ_row_next(result)) == NULL);
699  |     oldcomment = SQ_get_column_string(result, row, 0);
700  |   }
701  |   else {
702  |     oldcomment = "";
703  |   }
704  | 
705  |   SQ_free_result(result);
706  |   
707  |   /* must hold the thing below (REPLACE..blah blah blah) + text */
708  |   query = UT_malloc(strlen(oldcomment) + strlen(newcomment) + 256);
709  |   
710  |   /* compose new entry and insert it */
711  |   sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
712  | 	  "\"%s%s%s\")",
713  | 	  prefix->ip.words[0],
714  | 	  prefix->bits,
715  | 	  newacl->maxprivate,
716  | 	  newacl->maxpublic,
717  | 	  newacl->maxdenials,
718  | 	  newacl->deny,
719  | 	  newacl->trustpass,
720  | 	  oldcomment, 
721  | 	  strlen(oldcomment) > 0 ? "\n" : "",
722  | 	  newcomment
723  | 	  );
724  |   
725  |   SQ_execute_query(sql_connection, query, NULL);
726  |   SQ_close_connection(sql_connection);
727  |   
728  |   UT_free(query);
729  |   
730  |   return AC_OK;
731  | 
732  | }/* AC_acl_sql */
733  | 
734  | /*++++++++++++++++++++++++++++++++++++++ 
735  |   AC_ban_set:
736  |   
737  |   re/sets the permanent ban flag both in the acl tree in memory
738  |   and the sql table. The "text" is appended to the comment 
739  |   in the sql record (the expected cases are
740  |   - "automatic" in case the limit is exceeded and ban is set by s/w
741  |   - "manual"    in case it is (un)set from the config iface
742  | 
743  |   ip_prefix_t *prefix   - prefix 
744  | 
745  |   char *text            - usually "automatic" or "manual"  
746  | 
747  |   int denyflag          - new value of the denyflag (ban)
748  |   
749  |   returns error code from AC_acl_sql or OK
750  |   +++++++++++++++++++++++++++++++++++++++*/
751  | er_ret_t
752  | AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
753  | {
754  |   acl_st *treeacl;
755  |   char newcomment[256];
756  |   er_ret_t ret_err;
757  |   time_t  clock;
758  |   char timebuf[26];
759  |   char prefstr[IP_PREFSTR_MAX];
760  |   
761  |   time(&clock);
762  |   ctime_r(&clock, timebuf);
763  | 
764  |   sprintf(newcomment,"%s permanent ban set to %d at %s", text, 
765  | 	  denyflag, timebuf);
766  | 
767  |   if( IP_pref_b2a(prefix, prefstr, IP_PREFSTR_MAX) != IP_OK ) {
768  |     die; /* program error - this is already converted so must be OK */
769  |   }
770  |   
771  |   ER_inf_va( FAC_AC, ASP_AC_I_PERMBAN, 
772  | 	     "%s permanent ban set to %d for %s", text, denyflag, prefstr );
773  |     
774  |   TH_acquire_write_lock( &(act_acl->rwlock) );  
775  | 
776  |   /* find a record in the tree */  
777  |   if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
778  |     treeacl->deny = denyflag;
779  |     ret_err = AC_acl_sql( prefix, treeacl, newcomment );
780  |   }
781  |   TH_release_write_lock( &(act_acl->rwlock) );
782  | 
783  |   return ret_err;
784  | }/* AC_ban_set */
785  | 
786  | 
787  | /*++++++++++++++++++++++++++++++++++++++ 
788  |   AC_asc_ban_set:
789  |   
790  |   This is not used, should be removed?
791  | 
792  |   sets ban on text address/range. Parses the text address/range/prefix 
793  |   and then calls AC_ban_set on that prefix. 
794  |   
795  |   Precondition: if the key is a range, it must decompose into one prefix 
796  |   
797  |   returns error code from IP_smart_conv, AC_ban_set or 
798  |   AC_INVARG if range composed
799  |   +++++++++++++++++++++++++++++++++++++++*/
800  | er_ret_t
801  | AC_asc_ban_set(char *addrstr, char *text, int denyflag)
802  | {
803  |   er_ret_t ret_err;
804  |   GList *preflist = NULL;
805  |   ip_keytype_t key_type;
806  | 
807  |   if( (ret_err = IP_smart_conv(addrstr, 0, 0,
808  | 			       &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
809  |     return ret_err;
810  |   }
811  |   
812  |   /* allow only one prefix */
813  |   /* The argument can be even a range, but must decompose into one prefix */
814  |   if(  NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
815  |     ret_err = AC_INVARG;
816  |   }
817  |   
818  |   if( NOERR(ret_err) ) {
819  |     ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
820  |   }
821  | 
822  |   wr_clear_list( &preflist );
823  |   
824  |   return ret_err;
825  | }/* AC_asc_ban_set */
826  | 
827  | /*++++++++++++++++++++++++++++++++++++++ 
828  |   AC_asc_all_set:
829  | 
830  |   take ascii prefix and find/create a new entry, inheriting all parameters
831  |   and then set them according to the array of args.
832  | 
833  | +*/
834  | er_ret_t
835  | AC_asc_all_set(ip_prefix_t *prefix, char *comment, char * array[])
836  | {
837  |   er_ret_t ret_err;
838  |   acl_st *treeacl;
839  |   int i;
840  | 
841  |   TH_acquire_write_lock( &(act_acl->rwlock) );  
842  | 
843  |   /* find/create a record in the tree */  
844  |   if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
845  |    
846  |     /* update it from the array */
847  |     for(i=0; i<AC_AR_SIZE; i++) {
848  |       if(array[i] != NULL) { /* set only those that have been specified */
849  | 	int val,k;
850  | 	
851  | 	if( (k=sscanf( array[i], "%d", &val)) < 1 ) {
852  | 	  ret_err = AC_INVARG;
853  | 	  break; /* quit the for */
854  | 	}
855  | 	
856  | 	/* otherwise, the value makes sense. Put it in the structure. */
857  | 	switch(i) {
858  | 	case AC_AR_MAXPRIVATE: treeacl->maxprivate = val; break;
859  | 	case AC_AR_MAXPUBLIC:  treeacl->maxpublic  = val; break;
860  | 	case AC_AR_MAXDENIALS: treeacl->maxdenials = val; break;
861  | 	case AC_AR_DENY:       treeacl->deny       = val; break;
862  | 	case AC_AR_TRUSTPASS:  treeacl->trustpass  = val; break;
863  | 	} /* switch */
864  |       } /* if array[i] not null */
865  |     } /* for each array element */
866  | 
867  |     if( NOERR(ret_err) ) { /* protect against AC_INVARG */
868  |       ret_err = AC_acl_sql( prefix, treeacl, comment );
869  |     }
870  |   } /* if find/create OK */
871  |   
872  |   TH_release_write_lock( &(act_acl->rwlock) );
873  |   
874  |   return ret_err;
875  | }
876  | 
877  | 
878  | /*++++++++++++++++++++++++++++++++++++++ 
879  | AC_asc_acl_command_set:
880  | 
881  |   parse a command and set acl options for an entry.
882  |   command syntax:
883  | 
884  |   <prefix> option=value,option=value,option=value...
885  | 
886  |   where <option> is defined in AC_ar_acl[] array, value is an integer
887  | 
888  |   char *command  text of the command. 
889  |                  Syntax: ip[/prefixlength] column=value,column=value...
890  |                  Column names as in acl display. Unset columns are inherited.
891  | 
892  |   char *comment  text to be added to the acl record's comment column.
893  | 
894  |   ++++++++++++++++++++++++++++++++++++++*/
895  | 
896  | er_ret_t
897  | AC_asc_acl_command_set( char *command, char *comment )
898  | {
899  |   ip_prefix_t *prefix;
900  |   char *eop, *eoc, *value;
901  |   char *array[AC_AR_SIZE];
902  |   er_ret_t ret_err = AC_OK;
903  |   GList *preflist = NULL;
904  |   ip_keytype_t key_type;
905  | 
906  |   char *copy = UT_strdup(command);
907  |   char *addrstr = copy;
908  |   eoc = strchr(copy, '\0'); /* points to the end of it */
909  |   
910  |   memset(array, 0 ,sizeof(array));
911  | 
912  |   /* first comes the prefix. Find the space after it
913  |      and break the string there.
914  |   */
915  |   if( (eop = strchr(copy,' ')) == NULL) {
916  |     ret_err = AC_INVARG;
917  |   }
918  | 
919  |   if( NOERR(ret_err) ) { 
920  |     *eop++ = 0;
921  |   
922  |     /* now eop points to the rest of the string (if any). Take options.
923  |      */
924  |     while( eop != eoc && ret_err == AC_OK) {
925  |       char *sp;
926  | 
927  |       /* give getsubopt chunks with no spaces */
928  |       if( (sp = strchr(eop, ' ')) != NULL ) {
929  | 	*sp=0;
930  |       }
931  |       
932  |       while( *eop != '\0' ) {
933  | 	int k = getsubopt(&eop, AC_ar_acl, &value);
934  | 	if( k < 0 ) {
935  | 	  ret_err = AC_INVARG;
936  | 	  break;
937  | 	}
938  | 	
939  | 	array[k] = value;
940  |       }
941  |       
942  |       if( eop != eoc ) { /*getsubopt finished but did not consume all string*/
943  | 	eop ++;            /* must have been a space. advance one */
944  |       }
945  |     }
946  |   }
947  |     
948  |   /* convert the prefix */
949  |   if(  NOERR(ret_err) ) {
950  |     ret_err = IP_smart_conv(addrstr, 0, 0, &preflist, IP_PLAIN, &key_type);
951  |     
952  |     /* allow only one prefix */
953  |     /* The argument can be even a range, but must decompose into one prefix */
954  |     if(  NOERR(ret_err) && g_list_length( preflist ) == 1 ) {
955  |       prefix = (g_list_first(preflist)->data);
956  |     }
957  |     else {
958  |       ret_err = AC_INVARG;
959  |     }
960  |   }
961  |   
962  |   /* perform changes */
963  |   if(  NOERR(ret_err) ) {
964  |     ret_err = AC_asc_all_set(prefix, comment, array);
965  |   }
966  | 
967  |   wr_clear_list( &preflist );
968  |   UT_free(copy);
969  | 
970  |   return ret_err;
971  | }/* AC_asc_acl_command_set */
972  | 
973  | 
974  | /*++++++++++++++++++++++++++++++++++++++ 
975  |   AC_asc_set_nodeny:
976  | 
977  |   reset the deny counter in the access tree to 0 (after reenabling).
978  | 
979  |   Operates on the runtime access tree. 
980  | 
981  |   char *ip      text IP (ip only, not prefix or range).
982  |   +++++++++++++++++++++++++++++++++++++++*/
983  | er_ret_t AC_asc_set_nodeny(char *ip)
984  | {
985  |   ip_prefix_t  prefix;
986  |   er_ret_t     ret_err;
987  |   acc_st *ac_ptr;
988  | 
989  |   ret_err = IP_addr_e2b( &(prefix.ip), ip );
990  |   
991  |   if( NOERR(ret_err)) {
992  |     prefix.bits = IP_sizebits(prefix.ip.space);
993  | 
994  |     TH_acquire_write_lock( &(act_runtime->rwlock) );
995  |     
996  |     ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
997  |     if( NOERR(ret_err)) {
998  |       ac_ptr->denials = 0;
999  |     }
1000 |     
1001 |     TH_release_write_lock( &(act_runtime->rwlock) );
1002 |   }
1003 | 
1004 |   return ret_err;
1005 | }
1006 | 
1007 | 
1008 | 
1009 | /*++++++++++++++++++++++++++++++++++++++ 
1010 |   AC_commit:
1011 | 
1012 |   commits the credit into all accounting trees, (XXX: only one at the moment)
1013 |   checks the limits and sets automatic ban if limit exceeded.
1014 | 
1015 |   ip_addr_t *addr  - user's address
1016 | 
1017 |   acc_st *acc_conn - credit used
1018 | 
1019 |   acl_st *acl_copy - pointer to store a copy of the acl
1020 | 
1021 |   returns error code from AC_commit_credit or AC_ban_set or OK.
1022 | 
1023 |   outline:
1024 |         lock runtime + minute accounting trees 
1025 | 	-----------------------  XXX runtime only for the moment
1026 |            find or create entries, 
1027 |            increase accounting values by the values from passed acc
1028 |            check values against acl, see if permanent ban applies
1029 | 
1030 |            reset the connection acc
1031 |         unlock accounting trees
1032 | 
1033 |         if permanent ban - set it! :
1034 |             lock acl
1035 |             find/create IP in memory
1036 |             set ban
1037 |             find/create IP in SQL
1038 |             copy old values (if any), set ban, append comment
1039 |             unlock acl
1040 | 
1041 |  +++++++++++++++++++++++++++++++++++++++*/
1042 | er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) { 
1043 |   acc_st   account;
1044 |   er_ret_t ret_err;
1045 |   ip_prefix_t prefix;
1046 |   sk_conn_st condat;
1047 | 
1048 |   prefix.ip = *addr;
1049 |   prefix.bits = IP_sizebits(addr->space);
1050 | 
1051 |   TH_acquire_write_lock( &(act_runtime->rwlock) );
1052 |   ret_err = AC_commit_credit_l(act_runtime, &prefix, acc_conn, &account);
1053 |   TH_release_write_lock( &(act_runtime->rwlock) );
1054 | 
1055 |   memset(acc_conn,0, sizeof(acc_st));
1056 | 
1057 |   /* set permanent ban if deserved  and if not set yet */
1058 |   if( account.denials > acl_copy->maxdenials 
1059 |       && acl_copy->deny == 0 
1060 |       && NOERR(ret_err) ) {
1061 |     
1062 |     ret_err = AC_ban_set(&prefix, "Automatic", 1);
1063 |   }
1064 | 
1065 |   /*
1066 |   SK_cd_make(&condat, 1, 0);
1067 |   rx_tree_print(&condat, act_runtime);
1068 |   SK_cd_free(&condat);
1069 |   */
1070 | 
1071 |   return ret_err;
1072 | } /* AC_commit */
1073 | 
1074 | 
1075 |  
1076 | /*++++++++++++++++++++++++++++++++++++++
1077 |   
1078 |  
1079 | unsigned AC_prune     deletes the entries listed in the prunelist
1080 |                     (this cannot be done from within the rx_walk_tree,
1081 | 		    because the walk would be confused).
1082 | 		    Returns number of nodes deleted.
1083 | 
1084 | GList *prunelist  list of pointers to nodes that should be deleted.
1085 |                   the prefixes actually are allocated in the node
1086 | 		  structures, so they must not be dereferenced after 
1087 | 		  they are freed here.
1088 | 
1089 |   ++++++++++++++++++++++++++++++++++++++*/
1090 | unsigned AC_prune(GList *prunelist)
1091 | {
1092 |   GList *pitem;
1093 |   char prstr[IP_PREFSTR_MAX];
1094 |   unsigned count = 0;
1095 |   acc_st accu; /* to accumulate the accounting of deleted nodes */
1096 |   ip_prefix_t globalpref;
1097 | 
1098 |   memset( &accu, 0, sizeof(accu));
1099 |   
1100 |   for( pitem = g_list_first(prunelist);
1101 |        pitem != NULL;
1102 |        pitem = g_list_next(pitem)) {
1103 |     
1104 |     rx_node_t   *nodeptr = (rx_node_t *) pitem->data;
1105 |     ip_prefix_t *prefptr = &(nodeptr->prefix);
1106 |     acc_st      *nodeacc = nodeptr->leaves_ptr->data;
1107 |     
1108 |     AC_acc_addup(&accu, nodeacc, ACC_PLUS); /* transfer the account */
1109 |     dieif( IP_pref_b2a( prefptr, prstr, IP_PREFSTR_MAX ) != IP_OK );
1110 |     ER_dbg_va( FAC_AC, ASP_AC_PRUNE_DET, "AC_prune: entry %s", prstr );
1111 |     /* delete the node. Assume there's one and only one dataleaf */
1112 |     rx_bin_node( RX_OPER_DEL, prefptr, act_runtime, (void *)nodeacc );
1113 |     count ++;
1114 |   }
1115 |   /* store the accumulated account at 0/0 */
1116 |   dieif( !NOERR (IP_pref_a2b( &globalpref, "0/0" )));
1117 |   AC_commit_credit_l(act_runtime, &globalpref, &accu, NULL);
1118 | 
1119 |   return count;
1120 | }
1121 | 
1122 | 
1123 | char AC_prunable(acc_st *leaf) {
1124 |   if(    leaf->private_bonus < 0.5  
1125 |       && leaf->public_bonus  < 0.5 
1126 |       && leaf->denials == 0          
1127 |       && leaf->addrpasses == 0 ) {
1128 |     return 1;
1129 |   }
1130 |   return 0;
1131 | }
1132 | 
1133 | /*++++++++++++++++++++++++++++++++++++++ 
1134 |   AC_decay_hook:
1135 | 
1136 |   action performed on a single account node during decay (diminishing the
1137 |   bonus). Conforms to rx_walk_tree interface, therefore some of the 
1138 |   arguments do not apply and are not used.
1139 | 
1140 |   rx_node_t *node  - pointer to the node of the radix tree
1141 | 
1142 |   int level        - not used
1143 | 
1144 |   int nodecounter  - not used
1145 | 
1146 |   void *con        - in real life: (double *) - points to the decay factor.
1147 | 
1148 |   returns always OK
1149 | +++++++++++++++++++++++++++++++++++++++*/
1150 | er_ret_t AC_decay_hook(rx_node_t *node, int level, 
1151 | 		       int nodecounter, void *con)
1152 | {
1153 |   acc_st *a = node->leaves_ptr->data;
1154 |   acc_st clone;
1155 |   ac_decay_data_t *dec_dat_p = (ac_decay_data_t *)con;
1156 | 
1157 |   clone = *a;
1158 | 
1159 |   AC_decay_leaf_l(&clone);
1160 | 
1161 |   /* XXX pending: if bonus is close to zero and the node did not hit 
1162 |      its limit, and it's not an address-passing node
1163 |      then add it to the list of nodes for deletion */
1164 | 
1165 | /*  
1166 |   ER_dbg_va( FAC_AC, ASP_AC_PRUNE_DET, 
1167 | 	     "%5.2f / %5.2f   * %5.2f  -> %5.2f / %5.2f ",
1168 | 	     bpr, bpu, factor, a->private_bonus, a->public_bonus);
1169 | */
1170 | 
1171 |   if (AC_prunable(&clone)) {
1172 |     dec_dat_p->prunelist = g_list_append(dec_dat_p->prunelist, node);
1173 |   }
1174 | 
1175 |   /* process accounting - add all queries to the total counter */
1176 |   dec_dat_p->newtotal += a->queries;
1177 | 
1178 |   /* change oldest timestamp*/
1179 |   if (UT_timediff(&clone.timestamp, &oldest_timestamp) > 0 &&
1180 |       clone.addrpasses==0 && clone.denials==0 ) {
1181 |     oldest_timestamp = clone.timestamp;
1182 |   }
1183 | 
1184 |   return RX_OK;
1185 | } /* AC_decay_hook() */
1186 | 
1187 | 
1188 | 
1189 | /*++++++++++++++++++++++++++++++++++++++
1190 |   AC_decay:
1191 |   
1192 |   Every AC_DECAY_TIME goes through the accounting tree(s) and decays the 
1193 |   bonus values.
1194 |   
1195 |   returns always OK
1196 | 
1197 |   MT-Note  This should be run as a detached thread.
1198 |   +++++++++++++++++++++++++++++++++++++++*/
1199 | er_ret_t AC_decay(void) {
1200 |   er_ret_t ret_err = AC_OK;
1201 |   ac_decay_data_t dec_dat;
1202 |   ut_timer_t begintime, endtime;
1203 |   unsigned pruned;
1204 |   float elapsed, rate, exactinterval;
1205 |   unsigned oldtotal = 0;
1206 |   unsigned increase;
1207 |   unsigned count;
1208 | 
1209 |   TA_add(0, "decay");
1210 | 
1211 |   UT_timeget( &endtime );
1212 |   
1213 |   /* XXX uses CO_get_do_server() to see when to exit the program.
1214 |      this will change */
1215 |   while(CO_get_do_server()) {
1216 |     GString *gs;
1217 | 
1218 | 
1219 |     UT_timeget( &begintime );
1220 |     exactinterval =  UT_timediff( &endtime, &begintime ); /* old endtime */
1221 | 
1222 |     
1223 |     /* those values can be changed in runtime - so recalculate 
1224 |        the decay factor vefore each pass */
1225 |     dieif( ca_get_ac_decay_halflife == 0 );
1226 | 
1227 | 
1228 |     dec_dat.prunelist = NULL;  
1229 |     /* the decay factor of 
1230 |        f(t) = exp(-a*t) 
1231 |        a = -ln(0.5) / t     
1232 |        so for T being the half-life period and v being the sampling interval
1233 |        used as the unit of time
1234 |        a = -ln(0.5) / T;
1235 |        f(t+x) = exp(-a(t+x)) = f(t)*f(x) = f(t)*exp(-ax) = 
1236 |        = f(t)*exp(ln(0.5)*v/T)
1237 |        so you multiply the previous value by exp(ln(0.5)*v/T)
1238 |     */
1239 | /*
1240 |     dec_dat.decay_factor =  
1241 |       exp ( -0.693147180559945 * exactinterval / ca_get_ac_decay_halflife) ;
1242 | */
1243 |     dec_dat.newtotal = 0;
1244 |     TH_acquire_write_lock( &(act_runtime->rwlock) );
1245 | 
1246 |     UT_timeget(&oldest_timestamp);
1247 |     if( act_runtime->top_ptr != NULL ) {
1248 |       count = rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
1249 | 			   RX_WALK_SKPGLU,  /* skip glue nodes */
1250 | 			   255, 0, 0, &dec_dat, &ret_err);
1251 |     }
1252 |     else {
1253 |       count = 0;
1254 |     }
1255 | 
1256 |     /* it should also be as smart as to delete nodes that have reached 
1257 |        zero, otherwise the whole of memory will be filled.
1258 |        Next release :-)
1259 |     */
1260 |     
1261 |     pruned = AC_prune( dec_dat.prunelist ); 
1262 | 
1263 |     /*
1264 |     gs = g_string_new("");
1265 |     AC_print_access(gs);
1266 |     printf(gs->str);
1267 |     g_list_free( dec_dat.prunelist ); 
1268 |     */
1269 | 
1270 | #if 0
1271 |     /* XXX dbg checking tree consistency */
1272 |     if( act_runtime->top_ptr != NULL ) {
1273 |       rx_treecheck_t errorfound;
1274 |       er_ret_t err;
1275 |       if( (err=RX_treecheck(act_runtime, 1, &errorfound)) != RX_OK ) {
1276 | 	fprintf(stderr, "Nope! %d returned \n", err);
1277 | 	ER_dbg_va( FAC_AC, ASP_AC_DECAY,
1278 | 		   "AC: checking access tree consistency: error %d", err);
1279 | 	die; /* access tree not consistent */
1280 |       }
1281 |     }
1282 | #endif
1283 |   
1284 |     TH_release_write_lock( &(act_runtime->rwlock) );
1285 | 
1286 |     UT_timeget(&endtime);
1287 |     
1288 |     elapsed = UT_timediff( &begintime, &endtime);
1289 |       
1290 |     ER_dbg_va( FAC_AC, ASP_AC_DECAY,
1291 | 	      "AC_decay: Pruned %d of %d nodes. Took %5.3fs. Runs every %ds.", 
1292 | 	       pruned, count, elapsed, ca_get_ac_decay_interval);  
1293 | 
1294 |     /* number/rate of queries within the last <interval> */ 
1295 |     {
1296 |       char actbuf[32];
1297 |       
1298 |       increase = dec_dat.newtotal - oldtotal;
1299 |       rate = increase / exactinterval;
1300 | 
1301 |       sprintf(actbuf, "%.2f q/s in %.1fs", rate, exactinterval);
1302 |       TA_setactivity(actbuf);
1303 |       
1304 |       oldtotal = dec_dat.newtotal;
1305 |     }
1306 |     
1307 |     SV_sleep(ca_get_ac_decay_interval);
1308 |   } /* while */
1309 | 
1310 |   TA_delete();
1311 |   
1312 |   return ret_err;
1313 | } /* AC_decay() */
1314 | 
1315 | 
1316 | /*++++++++++++++++++++++++++++++++++++++ 
1317 |   AC_acc_load:
1318 | 
1319 |   loads the acl access tree from the acl table of the RIPADMIN database.
1320 |   (takes port/host/user/password from the config module).
1321 |   
1322 |   bails out if encounters problems with the database (logs to stderr).
1323 | 
1324 |   returns error code from RX_bin_node or wr_malloc.
1325 |   ++++++++++++++++++++++++++++++++++++++*/
1326 | er_ret_t AC_acc_load(void)
1327 | {
1328 |   SQ_connection_t *con=NULL;
1329 |   SQ_result_set_t *result;
1330 |   SQ_row_t *row;
1331 |   er_ret_t ret_err = RX_OK;
1332 | 
1333 |   con = AC_dbopen_admin();
1334 | 
1335 |   if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
1336 |       fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
1337 |       die;
1338 |   }
1339 |   
1340 |   TH_acquire_write_lock( &(act_acl->rwlock) );
1341 | 
1342 |   while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
1343 |     ip_prefix_t mypref;
1344 |     acl_st *newacl;
1345 |  #define NUMELEM (7)
1346 |     char *col[NUMELEM];
1347 |     unsigned myint, i;
1348 | 
1349 |     memset(&mypref, 0, sizeof(ip_prefix_t));
1350 |     mypref.ip.space = IP_V4;
1351 |     
1352 |     newacl = UT_malloc(sizeof(acl_st));
1353 | 
1354 |     for(i=0; i<NUMELEM; i++) {
1355 |       if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
1356 |         die;
1357 |       }
1358 |     }
1359 |       
1360 |     /* prefix ip */
1361 |     if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
1362 |       
1363 |     /* prefix length */
1364 |     if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
1365 |       
1366 |     /* acl contents */
1367 |     if( sscanf(col[2], "%u",  & (newacl->maxprivate)  ) < 1 ) { die; }
1368 |     if( sscanf(col[3], "%u",  & (newacl->maxpublic)   ) < 1 ) { die; }
1369 |     if( sscanf(col[4], "%hd", & (newacl->maxdenials)  ) < 1 ) { die; }
1370 |       
1371 |     /* these are chars therefore cannot read directly */
1372 |     if( sscanf(col[5], "%u", &myint              ) < 1 ) { die; }
1373 |     else {
1374 |       newacl->deny = myint;
1375 |     }
1376 |     if( sscanf(col[6], "%u", &myint  ) < 1 ) { die; }
1377 |     else {
1378 |       newacl->trustpass = myint;
1379 |     }
1380 |       
1381 |     /* free space */
1382 |     for(i=0; i<NUMELEM; i++) {
1383 | 	UT_free(col[i]);
1384 |     }
1385 |       
1386 |     /* now add to the tree */      
1387 |     ret_err = rx_bin_node( RX_OPER_CRE, &mypref, 
1388 |                            act_acl, (rx_dataleaf_t *) newacl );
1389 |   } /* while row */
1390 | 
1391 |   TH_release_write_lock( &(act_acl->rwlock) );
1392 | 
1393 |   SQ_free_result(result);
1394 |   /* Close connection */
1395 |   SQ_close_connection(con);
1396 | 
1397 |   return ret_err;
1398 | } /* AC_acc_load */
1399 | 
1400 | 
1401 | 
1402 | /*++++++++++++++++++++++++++++++++++++++ 
1403 |   AC_build:
1404 | 
1405 |   creates empty trees for accounting/acl.
1406 |   
1407 |   returns error code from RX_tree_cre or OK.
1408 |   (XXX): just now only bails out when encounters problems.
1409 |   ++++++++++++++++++++++++++++++++++++++*/
1410 | er_ret_t AC_build(void) 
1411 | {
1412 |   /* create trees */
1413 |   if (      RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
1414 | 			RX_SUB_NONE, &act_runtime) != RX_OK
1415 | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
1416 | 			RX_SUB_NONE, &act_hour) != RX_OK
1417 | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
1418 | 			RX_SUB_NONE, &act_minute) != RX_OK
1419 | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY, 
1420 | 			RX_SUB_NONE, &act_acl) != RX_OK
1421 |          )
1422 |     die; /*can be changed to an error and handled ... some day */
1423 | 
1424 |   return RX_OK;
1425 | }
1426 | 
1427 | /*++++++++++++++++++++++++++++++++++++++ 
1428 |   ac_rxwalkhook_print:
1429 | 
1430 |   action performed on a single account node 
1431 |   when listing the contents of the access tree: format and print the
1432 |   data from this node.
1433 | 
1434 |   Conforms to rx_walk_tree interface, therefore some of the 
1435 |   arguments do not apply and are not used.
1436 |   
1437 |   rx_node_t *node  - pointer to the node of the radix tree
1438 | 
1439 |   int level        - not used
1440 | 
1441 |   int nodecounter  - not used
1442 | 
1443 |   void *con        - pointer to the target string (prints to it)
1444 |   
1445 |   returns always OK 
1446 | +++++++++++++++++++++++++++++++++++++++*/
1447 | static
1448 | er_ret_t ac_rxwalkhook_print(rx_node_t *node, 
1449 |                              int level, int nodecounter, 
1450 |                              void *outvoid)
1451 | {
1452 |   char adstr[IP_ADDRSTR_MAX];
1453 |   char *dat;
1454 |   GString *output = outvoid;
1455 |   
1456 |   dieif( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK );
1457 |   /* program error. */
1458 |   
1459 |   dat = ac_to_string( node->leaves_ptr );
1460 |   g_string_sprintfa(output, "%-20s %s\n", adstr, dat );
1461 |   UT_free(dat);
1462 |   
1463 |   return RX_OK;
1464 | } /* ac_rxwalkhook_print */
1465 | 
1466 | 
1467 | /*++++++++++++++++++++++++++++++++++++++
1468 |   This function displays the access table to the given connection.
1469 | 
1470 |   unsigned AC_print_access    Returns the number of nodes traversed
1471 | 
1472 |   GString *output             target string
1473 |   ++++++++++++++++++++++++++++++++++++++*/
1474 | unsigned AC_print_access(GString *output)
1475 | {
1476 |   int cnt = 0;
1477 |   er_ret_t err; 
1478 | 
1479 |   if( act_runtime->top_ptr != NULL ) {
1480 |     char *header = ac_to_string_header();
1481 |     
1482 |     /* print header */
1483 |     g_string_append(output, header);
1484 |     UT_free(header);
1485 |     
1486 |     cnt = rx_walk_tree(act_runtime->top_ptr, ac_rxwalkhook_print, 
1487 | 		       RX_WALK_SKPGLU,  /* print no glue nodes */
1488 | 		       255, 0, 0, output, &err);
1489 |   }
1490 |   
1491 |   return cnt;
1492 | } /* show_access() */
1493 | 
1494 | 
1495 | 
1496 | /*++++++++++++++++++++++++++++++++++++++
1497 |   ac_rxwalkhook_print_acl:
1498 |   
1499 |   action performed on a single account node 
1500 |   when listing the contents of the acl tree: format and print the
1501 |   data from this node.
1502 | 
1503 |   Conforms to rx_walk_tree interface, therefore some of the 
1504 |   arguments do not apply and are not used.
1505 |   
1506 |   rx_node_t *node  - pointer to the node of the radix tree
1507 | 
1508 |   int level        - not used
1509 | 
1510 |   int nodecounter  - not used
1511 | 
1512 |   void *con        - pointer to the target string (prints to it)
1513 | 
1514 |   returns always OK 
1515 |   +++++++++++++++++++++++++++++++++++++++*/
1516 | static
1517 | er_ret_t ac_rxwalkhook_print_acl(rx_node_t *node, 
1518 |                              int level, int nodecounter, 
1519 |                              void *outvoid)
1520 | {
1521 |   char prefstr[IP_PREFSTR_MAX];
1522 |   char *dat;
1523 |   GString *output = outvoid;
1524 |   
1525 |   dieif( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK );
1526 |   
1527 |   dat = ac_acl_to_string( node->leaves_ptr );
1528 |   g_string_sprintfa(output, "%-20s %s\n", prefstr, dat );
1529 |   UT_free(dat);
1530 |   
1531 |   return RX_OK;
1532 | }/* ac_rxwalkhook_print_acl */
1533 | 
1534 | 
1535 | /*++++++++++++++++++++++++++++++++++++++
1536 |   This function writes the acl (access control) table to the given
1537 |   Gstring (auto-expandable)
1538 | 
1539 |   unsigned AC_print_acl     Returns the number of nodes traversed
1540 | 
1541 |   GString *output           target string
1542 |   ++++++++++++++++++++++++++++++++++++++*/
1543 | unsigned AC_print_acl(GString *output)
1544 | {
1545 |   /* Administrator wishes to show access control list. */  
1546 |   int cnt = 0;
1547 |   er_ret_t err; 
1548 | 
1549 |   if( act_acl->top_ptr != NULL ) {
1550 |     char *header = ac_acl_to_string_header();
1551 |     
1552 |     /* print header */
1553 |     g_string_append(output, header);
1554 |     UT_free(header);
1555 | 
1556 |     cnt = rx_walk_tree(act_acl->top_ptr, ac_rxwalkhook_print_acl, 
1557 | 		       RX_WALK_SKPGLU,  /* print no glue nodes */
1558 | 		       255, 0, 0, output, &err);
1559 |   }
1560 | 
1561 |   return cnt;
1562 | }
1563 | 
1564 | 
1565 | /*++++++++++++++++++++++++++++++++++++++
1566 |   AC_count_object:
1567 | 
1568 |   accounts an objects in the credit accordingly to its type, 
1569 |   or sets denial if the limit is defined and the credit is exceeded.
1570 | 
1571 |   acc_st    *acc_credit     pointer to the credit structure (gets modified)
1572 | 
1573 |   acl_st    *acl            acl, contains the limits for private/public objects
1574 | 
1575 |   int private               indicates if the object type is private
1576 |   ++++++++++++++++++++++++++++++++++++++*/
1577 | void
1578 | AC_count_object( acc_st    *acc_credit, 
1579 | 		 acl_st    *acl,
1580 | 		 int private )
1581 | {
1582 |   if( private ) { 
1583 |     if( acc_credit->private_objects <= 0 && acl->maxprivate != -1 ) {
1584 |       /* must be negative - will be subtracted */
1585 |       acc_credit->denials = -1;
1586 |     } else {
1587 |       acc_credit->private_objects --;
1588 |     }
1589 |   }
1590 |   else {
1591 |     if( acc_credit->public_objects <= 0 && acl->maxpublic != -1 ) {
1592 |       acc_credit->denials = -1;
1593 |     } else {
1594 |       acc_credit->public_objects --;
1595 |     }
1596 |   }
1597 | } /* AC_count_object */
1598 | 
1599 | 
1600 | /* AC_credit_isdenied */
1601 | /*++++++++++++++++++++++++++++++++++++++
1602 |   
1603 |   checks the denied flag in credit (-1 or 1 means denied)
1604 |   
1605 |   int 
1606 |   AC_credit_isdenied     returns 1 if denied, 0 otherwise
1607 | 
1608 |   acc_st    *acc_credit    pointer to the credit structure
1609 |   ++++++++++++++++++++++++++++++++++++++*/
1610 | int 
1611 | AC_credit_isdenied(acc_st    *acc_credit)
1612 | {
1613 |   return (acc_credit->denials != 0);
1614 | } /* AC_credit_isdenied */
1615 |   
1616 | 
1617 | /* AC_get_higher_limit */
1618 | /*++++++++++++++++++++++++++++++++++++++
1619 | 
1620 |   returns the higher number of the two acl limits: maxprivate & maxpublic 
1621 |   corrected w.r.t the current credit left,
1622 |   or unlimited if any of them is 'unlimited'.
1623 | 
1624 |   int AC_get_higher_limit       returns the higher limit   
1625 | 
1626 |   acc_st    *acc_credit         current credit left
1627 |   
1628 |   acl_st    *acl                acl for that user
1629 | ++++++++++++++++++++++++++++++++++++++*/
1630 | int
1631 | AC_get_higher_limit(acc_st    *acc_credit, 
1632 | 		    acl_st    *acl)
1633 | {
1634 |   if( acl->maxprivate == -1 || acl->maxpublic == -1 ) {
1635 |     return -1;
1636 |   }
1637 |   else {
1638 |     int a = acc_credit->private_objects;
1639 |     int b = acc_credit->public_objects;
1640 | 
1641 |     return (a > b ? a : b);
1642 |   }
1643 | }/* AC_get_higher_limit */