## 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_findexless_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
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_commit
20. AC_decay_hook
21. AC_decay
22. AC_acc_load
23. AC_build
24. AC_rxwalkhook_print
25. AC_rxwalkhook_print_acl
26. AC_count_object
27. AC_credit_isdenied
28. AC_get_higher_limit

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

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