## modules/ac/access_control.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. ac_to_string_header
2. ac_to_string
3. AC_credit_to_string
4. ac_acl_to_string_header
5. ac_acl_to_string
6. ac_find_acl_l
7. AC_findcreate_acl_l
8. AC_findcreate_account_l
9. AC_fetch_acc
10. AC_check_acl
11. AC_acc_addup
12. AC_commit_credit_l
13. AC_dbopen_admin
14. AC_acl_sql
15. AC_ban_set
16. AC_asc_ban_set
17. AC_asc_all_set
18. AC_asc_acl_command_set
19. AC_asc_set_nodeny
20. AC_commit
21. AC_prune
22. AC_decay_hook
23. AC_decay
24. AC_acc_load
25. AC_build
26. ac_rxwalkhook_print
27. AC_print_access
28. ac_rxwalkhook_print_acl
29. AC_print_acl
30. AC_count_object
31. AC_credit_isdenied
32. AC_get_higher_limit

       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)
         /* [<][>][^][v][top][bottom][index][help] */
      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)
         /* [<][>][^][v][top][bottom][index][help] */
      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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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 )
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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[])
         /* [<][>][^][v][top][bottom][index][help] */
     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 )
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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,
         /* [<][>][^][v][top][bottom][index][help] */
    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) {
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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,
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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,
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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,
         /* [<][>][^][v][top][bottom][index][help] */
    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)
         /* [<][>][^][v][top][bottom][index][help] */
    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,
         /* [<][>][^][v][top][bottom][index][help] */
    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 */

/* [<][>][^][v][top][bottom][index][help] */