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

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