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