Source File modules/ac/access_control.c

    1    | /***************************************
    2    |   $Revision: 1.20 $
    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   |
    33   | #define AC_OK RX_OK
    34   | #define AC_INVARG IP_INVARG
    35   |
    36   | #define AC_IMPL
    37   | #include <rxroutines.h>
    38   | #include <erroutines.h>
    39   | #include <access_control.h>
    40   | #include "socket.h"
    41   | #include "mysql_driver.h"
    42   | #include <constants.h>
    43   | #include <server.h>
    44   |
    45   | #define AC_DECAY_TIME 600
    46   |
    47   | /* formats for printing the access control list entries */
    48   | #define ACL_FORMAT        "%10d %10d %10d %10d %10d"
    49   | #define ACL_HEADER  "%-20s %10s %10s %10s %10s %10s\n"
    50   |
    51   | /* formats for printing the accounting entries */
    52   | #define ACC_FORMAT       "%4d    %4d    %4d    %4d    %6d    %6d    %6d"
    53   | #define ACC_HEADER "%-20s %4s    %4s    %4s    %4s    %6s    %6s    %6s\n"
    54   |
    55   |
    56   | /*++++++++++++++++++++++++++++++++++++++
    57   |   AC_to_string_header:
    58   |
    59   |   produce a header for the access stats printout
    60   |
    61   |   returns an allocated string
    62   |   ++++++++++++++++++++++++++++++++++++++*/
    63   | char *AC_to_string_header(void)
    64   | {
    65   |   char *result_buf;
    66   |
    67   |   dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
    68   |
    69   |   sprintf(result_buf, ACC_HEADER,
    70   | 	  "ip", "conn", "pass", "deny", "qry", "pub", "priv", "bonus" );
    71   |
    72   |   return result_buf;
    73   | }
    74   |
    75   | /*++++++++++++++++++++++++++++++++++++++
    76   |   AC_to_string:
    77   |
    78   |   Show an access structure
    79   |
    80   |   returns an allocated string
    81   |   ++++++++++++++++++++++++++++++++++++++*/
    82   | char *AC_to_string(GList *leafptr)
    83   | {
    84   |   char *result_buf;
    85   |   acc_st *a = leafptr->data;
    86   |
    87   |   if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
    88   |     /* XXX generic malloc handler pending ...*/
    89   |     return NULL;
    90   |   }
    91   |
    92   |   if( a == NULL ) {
    93   |     strcpy(result_buf, "DATA MISSING!");
    94   |   }
    95   |   else {
    96   |     sprintf(result_buf,  ACC_FORMAT,
    97   |             a->connections,
    98   | 	    a->addrpasses,
    99   |             a->denials,
    100  |             a->queries,
    101  |             a->public_objects,
    102  |             a->private_objects,
    103  |             a->private_bonus
    104  |             );
    105  |   }
    106  |
    107  |   return result_buf;
    108  | } /* AC_to_string() */
    109  |
    110  |
    111  | /*++++++++++++++++++++++++++++++++++++++
    112  |   AC_credit_to_string:
    113  |
    114  |  Show credit used (for logging of queries)
    115  |
    116  |  acc_st *a     - the credit structure
    117  |
    118  |  returns an allocated string
    119  |  ++++++++++++++++++++++++++++++++++++++*/
    120  | char *AC_credit_to_string(acc_st *a)
    121  | {
    122  |   char *result_buf;
    123  |
    124  |   if( wr_malloc( (void **) &result_buf, 64) != UT_OK ) {
    125  |     /* XXX generic malloc handler pending ...*/
    126  |     return NULL;
    127  |   }
    128  |
    129  |   dieif( a == NULL );
    130  |
    131  |   sprintf(result_buf,"%d+%d%s",
    132  | 	  a->private_objects,
    133  | 	  a->public_objects,
    134  | 	  a->denials ? " **DENIED**" : ""
    135  | 	  );
    136  |
    137  |   return result_buf;
    138  | } /* AC_credit_to_string */
    139  |
    140  |
    141  | /*+++++++++++++++++++++++++++++++++++++++
    142  |   AC_acl_to_string_header:
    143  |
    144  |   produce a header for the acl printout
    145  |
    146  |   returns an allocated string
    147  |   ++++++++++++++++++++++++++++++++++++++*/
    148  | char *
    149  | AC_acl_to_string_header(void)
    150  | {
    151  |   char *result_buf;
    152  |   dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
    153  |
    154  |   sprintf(result_buf, ACL_HEADER, "ip",
    155  | 	  "maxbonus", "maxdenials", "maxpublic", "ban", "trustpass" );
    156  |
    157  |   return result_buf;
    158  | }
    159  |
    160  |
    161  |
    162  | /*++++++++++++++++++++++++++++++++++++++
    163  |   AC_acl_to_string:
    164  |
    165  |   Show an access control list structure
    166  |
    167  |   returns an allocated string
    168  |   ++++++++++++++++++++++++++++++++++++++*/
    169  | char *AC_acl_to_string(GList *leafptr)
    170  | {
    171  |   char *result_buf;
    172  |   acl_st *a = leafptr->data;
    173  |
    174  |   if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
    175  |     /* XXX generic malloc handler pending ...*/
    176  |     return NULL;
    177  |   }
    178  |
    179  |   if( a != NULL ) {
    180  |     sprintf(result_buf, ACL_FORMAT,
    181  |             a->maxbonus,
    182  |             a->maxdenials,
    183  | 	    a->maxpublic,
    184  |             a->deny,
    185  |             a->trustpass
    186  |             );
    187  |   }
    188  |   else {
    189  |     strcpy(result_buf, "DATA MISSING\n");
    190  |   }
    191  |
    192  |   return result_buf;
    193  | } /* AC_acl_to_string() */
    194  |
    195  |
    196  | /*+++++++++++++++++++++++++++++++++++++++
    197  |   AC_findexless_acl_l:
    198  |
    199  |   find the exact or less specific match for the given prefix in the acl tree.
    200  |
    201  |   ip_prefix_t *prefix - prefix to look for
    202  |   acl_st *store_acl   - pointer to store the output
    203  |
    204  |   returns error code from RX or OK
    205  |
    206  |   MT-Note: assumes locked acl tree
    207  |   ++++++++++++++++++++++++++++++++++++++*/
    208  | er_ret_t
    209  | AC_findexless_acl_l(ip_prefix_t *prefix, acl_st *store_acl)
    210  | {
    211  |   GList       *datlist=NULL;
    212  |   er_ret_t    ret_err;
    213  |   rx_datref_t *datref;
    214  |
    215  |   if( (ret_err = RX_bin_search(RX_SRCH_EXLESS, 0, 0, act_acl,
    216  |                                prefix, &datlist, RX_ANS_ALL)
    217  |        ) != RX_OK   ||  g_list_length(datlist) == 0 ) {
    218  |     /* acl tree is not configured at all ! There always must be a
    219  |        catch-all record with defaults */
    220  |     die;
    221  |   }
    222  |
    223  |   datref = (rx_datref_t *)g_list_nth_data(datlist,0);
    224  |
    225  |   *store_acl = * ((acl_st *)  datref->leafptr);
    226  |
    227  |   wr_clear_list( &datlist );
    228  |
    229  |   /* XXX dbg checking tree consistency */
    230  |   {
    231  |     rx_treecheck_t errorfound;
    232  |     er_ret_t err;
    233  |     if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
    234  |       fprintf(stderr, "Nope! %d returned \n", err);
    235  |       die;
    236  |     }
    237  |   }
    238  |
    239  |   return ret_err;
    240  | }
    241  | /* AC_findexless_acl_l */
    242  |
    243  |
    244  | /*+++++++++++++++++++++++++++++++++++++++
    245  |   AC_findcreate_acl_l:
    246  |
    247  |   find or create an entry for the given prefix in the acl tree.
    248  |
    249  |   ip_prefix_t *prefix - prefix to look for
    250  |   acl_st **store_acl  - pointer to store the ptr to the acl struct
    251  |                         (initialised to the values of the parent entry
    252  | 			if just created)
    253  |
    254  |   returns error code from RX or OK
    255  |
    256  |   MT-Note: assumes locked acl tree
    257  |   ++++++++++++++++++++++++++++++++++++++*/
    258  | er_ret_t
    259  | AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
    260  | {
    261  |   GList       *datlist=NULL;
    262  |   er_ret_t    ret_err;
    263  |   acl_st      *newacl;
    264  |   acl_st acl_copy;
    265  |
    266  |   if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl,
    267  | 				    prefix, &datlist, RX_ANS_ALL)
    268  | 	    )) {
    269  |
    270  |     switch( g_list_length(datlist)) {
    271  |     case 0:
    272  |       dieif( wr_calloc((void **)&newacl, 1, sizeof(acl_st)) != UT_OK );
    273  |
    274  |       /* make the new one inherit all parameters after the old one */
    275  |
    276  |       AC_findexless_acl_l(prefix, &acl_copy);
    277  |
    278  |       *newacl = acl_copy;
    279  |
    280  |       /* link in */
    281  |       rx_bin_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
    282  |       break;
    283  |     case 1:
    284  |       {
    285  | 	/* Uh-oh, the guy is already known ! (or special, in any case) */
    286  | 	rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
    287  | 	newacl = (acl_st *) datref->leafptr;
    288  |       }
    289  |       break;
    290  |     default:
    291  |       die;
    292  |     }
    293  |   }
    294  |
    295  |   /* free search results */
    296  |   wr_clear_list( &datlist );
    297  |
    298  |   /* store */
    299  |   *store_acl = newacl;
    300  |   return ret_err;
    301  | }
    302  | /* AC_findcreate_acl_l */
    303  |
    304  |
    305  | /*+++++++++++++++++++++++++++++++++++++++
    306  |   AC_findcreate_account_l:
    307  |
    308  |   finds exact prefix in the accounting tree
    309  |   or creates area initialised to zeros + sets ptr to it.
    310  |
    311  |   rx_tree_t *tree     - the tree
    312  |   ip_prefix_t *prefix - prefix to look for
    313  |   acc_st **store_acl  - pointer to store the ptr to the account struct
    314  |
    315  |   returns error code from RX or OK
    316  |
    317  |   MT-Note: assumes locked accounting tree
    318  |   ++++++++++++++++++++++++++++++++++++++*/
    319  | er_ret_t
    320  | AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix,
    321  | 			acc_st **acc_store)
    322  | {
    323  |   GList       *datlist=NULL;
    324  |   er_ret_t    ret_err;
    325  |   acc_st      *recacc;
    326  |
    327  |   if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree,
    328  |                                prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
    329  |     switch( g_list_length(datlist) ) {
    330  |     case 0:
    331  |       /* need to create a new accounting record */
    332  |       if( (ret_err = wr_malloc( (void **)& recacc, sizeof(acc_st))) == UT_OK ) {
    333  |         /*  counters = init to zeros */
    334  |         memset( recacc, 0, sizeof(acc_st));
    335  |
    336  |         /* attach. The recacc is to be treated as a dataleaf
    337  |            (must use lower levels than RX_asc_*)
    338  |         */
    339  |         ret_err = rx_bin_node( RX_OPER_CRE, prefix,
    340  |                                act_runtime, (rx_dataleaf_t *)recacc );
    341  |       }
    342  |       break;
    343  |     case 1:
    344  |       {
    345  |         rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
    346  |
    347  |         /* OK, there is a record already */
    348  |         recacc = (acc_st *) datref->leafptr;
    349  |
    350  |       }
    351  |       break;
    352  |     default: die; /* there shouldn't be more than 1 entry per IP */
    353  |     }
    354  |   }
    355  |
    356  |   wr_clear_list( &datlist );
    357  |
    358  |   *acc_store = recacc;
    359  |
    360  |   return ret_err;
    361  | }
    362  |
    363  |
    364  | /*++++++++++++++++++++++++++++++++++++++
    365  |   AC_fetch_acc:
    366  |
    367  |   Finds the runtime accounting record for this IP,
    368  |   stores a copy of it in acc_store.
    369  |   If not found, then it is created and initialised to zeros in findcreate()
    370  |
    371  |   ip_addr_t *addr  - address
    372  |   acc_st *acc_store - pointer to store the account struct
    373  |
    374  |   MT-Note: locks/unlocks the accounting tree
    375  |   ++++++++++++++++++++++++++++++++++++++*/
    376  | er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
    377  | {
    378  |   er_ret_t ret_err;
    379  |   ip_prefix_t prefix;
    380  |   acc_st *ac_ptr;
    381  |
    382  |   prefix.ip = *addr;
    383  |   prefix.bits = IP_sizebits(addr->space);
    384  |
    385  |   TH_acquire_read_lock( &(act_runtime->rwlock) );
    386  |
    387  |   ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
    388  |   *acc_store = *ac_ptr;
    389  |
    390  |   TH_release_read_lock( &(act_runtime->rwlock) );
    391  |
    392  |   return ret_err;
    393  | }/* AC_fetch_acc() */
    394  |
    395  |
    396  | /*++++++++++++++++++++++++++++++++++++++
    397  |   AC_check_acl:
    398  |
    399  |   search for this ip or less specific record in the access control tree
    400  |
    401  |   if( bonus in combined runtime+connection accountings > max_bonus in acl)
    402  |             set denial in the acl for this ip (create if needed)
    403  |   if( combined denialcounter > max_denials in acl)
    404  |             set the permanent ban in acl; save in SQL too
    405  |   calculate credit if pointer provided
    406  |   save the access record (ip if created or found/prefix otherwise)
    407  |             at *acl_store if provided
    408  |
    409  |   ip_addr_t *addr  - address
    410  |   acc_st *acc_store - pointer to store the *credit* account struct
    411  |   acl_st *acl_store - pointer to store the acl struct
    412  |
    413  |   any of the args except address can be NULL
    414  |
    415  |   returns error code from RX or OK
    416  |
    417  |   MT-Note: locks/unlocks the accounting tree
    418  |   ++++++++++++++++++++++++++++++++++++++*/
    419  | er_ret_t AC_check_acl( ip_addr_t *addr,
    420  |                        acc_st *credit_acc,
    421  |                        acl_st *acl_store
    422  |                        )
    423  | {
    424  |   ip_prefix_t prefix;
    425  |   er_ret_t    ret_err;
    426  |   acl_st      acl_record;
    427  |   acc_st      run_acc;
    428  |
    429  |   AC_fetch_acc( addr, &run_acc );
    430  |
    431  |   prefix.ip = *addr;
    432  |   prefix.bits = IP_sizebits(addr->space);
    433  |
    434  |   /* lock the tree accordingly */
    435  |   TH_acquire_read_lock( &(act_acl->rwlock) );
    436  |
    437  |   /* find an applicable record */
    438  |   AC_findexless_acl_l(&prefix, &acl_record);
    439  |
    440  |   /* calculate the credit if pointer given */
    441  |   if( credit_acc ) {
    442  |     memset( credit_acc, 0, sizeof(acc_st));
    443  |     credit_acc->public_objects =                       /* -1 == unlimited */
    444  |       acl_record.maxpublic - run_acc.public_objects;
    445  |     credit_acc->private_objects =
    446  |       acl_record.maxbonus - run_acc.private_bonus;
    447  |   }
    448  |
    449  |   /* copy the acl record if asked for it*/
    450  |   if( acl_store ) {
    451  |     *acl_store =  acl_record;
    452  |   }
    453  |
    454  |   /* release lock */
    455  |   TH_release_read_lock( &(act_acl->rwlock) );
    456  |
    457  |
    458  |   return ret_err;
    459  | }
    460  |
    461  |
    462  |
    463  | /*++++++++++++++++++++++++++++++++++++++
    464  |   AC_acc_addup:
    465  |
    466  |   Add/subtract the values from one accounting structure to another
    467  |
    468  |   acc_st *a  - this one gets changed
    469  |   acc_st *b  - this one provides the values to change a
    470  |   int minus  - triggers subtraction if non-zero
    471  |
    472  | +++++++++++++++++++++++++++++++++++++++*/
    473  | void AC_acc_addup(acc_st *a, acc_st *b, int minus)
    474  | {
    475  |   int mul = minus ? -1 : 1;
    476  |
    477  |   /* add all counters from b to those in a */
    478  |   a->connections     +=  mul * b->connections;
    479  |   a->addrpasses      +=  mul * b->addrpasses;
    480  |
    481  |   a->denials         +=  mul * b->denials;
    482  |   a->queries         +=  mul * b->queries;
    483  |   a->public_objects  +=  mul * b->public_objects;
    484  |   a->private_objects +=  mul * b->private_objects;
    485  |   a->private_bonus   +=  mul * b->private_bonus;
    486  | }/* AC_acc_addup */
    487  |
    488  | /*++++++++++++++++++++++++++++++++++++++
    489  |   AC_commit_credit:
    490  |
    491  |   performs the commit on an accounting tree (locks them first)
    492  |   stores a copy of the accounting record at rec_store
    493  |
    494  |   rx_tree_t *tree      - the tree
    495  |   ip_prefix_t *prefix  - prefix (usually a /32)
    496  |   acc_st *acc_conn     - credit used
    497  |   acc_st *rec_store    - pointer to store the account struct
    498  |
    499  |   returns error code from AC_findcreate_account_l or OK
    500  |
    501  |   MT-Note: locks/unlocks the accounting tree
    502  | +++++++++++++++++++++++++++++++++++++++*/
    503  | er_ret_t
    504  | AC_commit_credit(rx_tree_t *tree, ip_prefix_t *prefix,
    505  | 		 acc_st *acc_conn, acc_st *rec_store )
    506  | {
    507  |   acc_st      *accountrec;
    508  |   er_ret_t    ret_err;
    509  |
    510  |
    511  |   acc_conn->private_bonus = acc_conn->private_objects;
    512  |
    513  |   TH_acquire_write_lock( &(tree->rwlock) );
    514  |
    515  |   ret_err = AC_findcreate_account_l(act_runtime, prefix, &accountrec);
    516  |
    517  |   if( NOERR(ret_err)) {
    518  |     AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
    519  |   }
    520  |
    521  |   TH_release_write_lock( &(tree->rwlock) );
    522  |
    523  |   *rec_store = *accountrec;
    524  |
    525  |   return ret_err;
    526  | }/* AC_commit_credit */
    527  |
    528  |
    529  |
    530  | /*++++++++++++++++++++++++++++++++++++++
    531  |   AC_acl_sql:
    532  |
    533  |   updates/creates a record for the given prefix in the acl table of
    534  |   the RIPADMIN database. Adds a comment.
    535  |
    536  |   ip_prefix_t *prefix  - prefix
    537  |   acl_st *newacl       - new values to store in the database
    538  |   char *newcomment     - comment to be added (must not be NULL)
    539  |
    540  |   placeholder: it may return an error code from SQ - as soon as sq
    541  |   implements common error scheme
    542  |
    543  |  ++++++++++++++++++++++++++++++++++++++*/
    544  | er_ret_t
    545  | AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
    546  | {
    547  |   SQ_connection_t *sql_connection = NULL;
    548  |   SQ_result_set_t *result;
    549  |   SQ_row_t *row;
    550  |   char *oldcomment;
    551  |   char *query;
    552  |   char querybuf[256];
    553  |
    554  |   sql_connection = SQ_get_connection(CO_get_host(),
    555  | 				     CO_get_database_port(),
    556  | 				     "RIPADMIN",
    557  | 				     CO_get_user(),
    558  | 				     CO_get_password() );
    559  |
    560  |   /* get the old entry, extend it */
    561  |   sprintf(querybuf, "SELECT comment FROM acl WHERE "
    562  | 	  "prefix = %u AND prefix_length = %d",
    563  | 	  prefix->ip.words[0],
    564  | 	  prefix->bits);
    565  |   dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
    566  |
    567  |   if( SQ_num_rows(result) == 1 ) {
    568  |     dieif( (row = SQ_row_next(result)) == NULL);
    569  |     oldcomment = SQ_get_column_string(result, row, 0);
    570  |   }
    571  |   else {
    572  |     oldcomment = "";
    573  |   }
    574  |
    575  |   SQ_free_result(result);
    576  |
    577  |   /* must hold the thing below (REPLACE..blah blah blah) + text */
    578  |   dieif( wr_malloc((void **)&query,
    579  | 		   strlen(oldcomment) + strlen(newcomment) + 256) != UT_OK );
    580  |
    581  |   /* compose new entry and insert it */
    582  |   sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
    583  | 	  "\"%s%s%s\")",
    584  | 	  prefix->ip.words[0],
    585  | 	  prefix->bits,
    586  | 	  newacl->maxbonus,
    587  | 	  newacl->maxpublic,
    588  | 	  newacl->maxdenials,
    589  | 	  newacl->deny,
    590  | 	  newacl->trustpass,
    591  | 	  oldcomment,
    592  | 	  strlen(oldcomment) > 0 ? "\n" : "",
    593  | 	  newcomment
    594  | 	  );
    595  |
    596  |   SQ_execute_query(sql_connection, query, NULL);
    597  |   SQ_close_connection(sql_connection);
    598  |
    599  |   wr_free(query);
    600  |
    601  |   return AC_OK;
    602  |
    603  | }/* AC_acl_sql */
    604  |
    605  | /*++++++++++++++++++++++++++++++++++++++
    606  |   AC_ban_set:
    607  |
    608  |   re/sets the permanent ban flag both in the acl tree in memory
    609  |   and the sql table. The "text" is appended to the comment
    610  |   in the sql record (the expected cases are
    611  |   - "automatic" in case the limit is exceeded and ban is set by s/w
    612  |   - "manual"    in case it is (un)set from the config iface
    613  |
    614  |   ip_prefix_t *prefix   - prefix
    615  |   char *text            - usually "automatic" or "manual"
    616  |   int denyflag          - new value of the denyflag (ban)
    617  |
    618  |   returns error code from AC_acl_sql or OK
    619  |   +++++++++++++++++++++++++++++++++++++++*/
    620  | er_ret_t
    621  | AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
    622  | {
    623  |   acl_st *treeacl;
    624  |   char newcomment[256];
    625  |   er_ret_t ret_err;
    626  |   time_t  clock;
    627  |   char timebuf[26];
    628  |
    629  |   time(&clock);
    630  |   ctime_r(&clock, timebuf);
    631  |
    632  |   sprintf(newcomment,"%s permanent ban set to %d at %s", text,
    633  | 	  denyflag, timebuf);
    634  |
    635  |   TH_acquire_write_lock( &(act_acl->rwlock) );
    636  |
    637  |   /* find a record in the tree */
    638  |   if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
    639  |     treeacl->deny = denyflag;
    640  |     ret_err = AC_acl_sql( prefix, treeacl, newcomment );
    641  |   }
    642  |   TH_release_write_lock( &(act_acl->rwlock) );
    643  |
    644  |   return ret_err;
    645  | }/* AC_ban_set */
    646  |
    647  |
    648  | /*++++++++++++++++++++++++++++++++++++++
    649  |   AC_asc_ban_set:
    650  |
    651  |   sets ban on text address/range. Parses the text address/range/prefix
    652  |   and then calls AC_ban_set on that prefix.
    653  |
    654  |   Precondition: if the key is a range, it must decompose into one prefix
    655  |
    656  |   returns error code from IP_smart_conv, AC_ban_set or
    657  |   AC_INVARG if range composed
    658  |   +++++++++++++++++++++++++++++++++++++++*/
    659  | er_ret_t
    660  | AC_asc_ban_set(char *addrstr, char *text, int denyflag)
    661  | {
    662  |   er_ret_t ret_err;
    663  |   GList *preflist = NULL;
    664  |   ip_keytype_t key_type;
    665  |
    666  |   if( (ret_err = IP_smart_conv(addrstr, 0, 0,
    667  | 			       &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
    668  |     return ret_err;
    669  |   }
    670  |
    671  |   /* allow only one prefix */
    672  |   /* The argument can be even a range, but must decompose into one prefix */
    673  |   if(  NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
    674  |     ret_err = AC_INVARG;
    675  |   }
    676  |
    677  |   if( NOERR(ret_err) ) {
    678  |     ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
    679  |   }
    680  |
    681  |   wr_clear_list( &preflist );
    682  |
    683  |   return ret_err;
    684  | }/* AC_asc_ban_set */
    685  |
    686  |
    687  | /*++++++++++++++++++++++++++++++++++++++
    688  |   AC_commit:
    689  |
    690  |   commits the credit into all accounting trees, (XXX: only one at the moment)
    691  |   checks the limits and sets automatic ban if limit exceeded.
    692  |
    693  |   ip_addr_t *addr  - user's address
    694  |   acc_st *acc_conn - credit used
    695  |   acl_st *acl_copy - pointer to store a copy of the acl
    696  |
    697  |   returns error code from AC_commit_credit or AC_ban_set or OK.
    698  |
    699  |   outline:
    700  |         lock runtime + minute accounting trees
    701  | 	-----------------------  XXX runtime only for the moment
    702  |            find or create entries,
    703  |            increase accounting values by the values from passed acc
    704  |            check values against acl, see if permanent ban applies
    705  |
    706  |            reset the connection acc
    707  |         unlock accounting trees
    708  |
    709  |         if permanent ban - set it! :
    710  |             lock acl
    711  |             find/create IP in memory
    712  |             set ban
    713  |             find/create IP in SQL
    714  |             copy old values (if any), set ban, append comment
    715  |             unlock acl
    716  |
    717  |  +++++++++++++++++++++++++++++++++++++++*/
    718  | er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) {
    719  |   acc_st   account;
    720  |   er_ret_t ret_err;
    721  |   ip_prefix_t prefix;
    722  |
    723  |   prefix.ip = *addr;
    724  |   prefix.bits = IP_sizebits(addr->space);
    725  |
    726  |   ret_err = AC_commit_credit(act_runtime, &prefix, acc_conn, &account);
    727  |   /* XXX add more trees here */
    728  |
    729  |   memset(acc_conn,0, sizeof(acc_st));
    730  |
    731  |   /* set permanent ban if deserved  and if not set yet */
    732  |   if( account.denials > acl_copy->maxdenials
    733  |       && acl_copy->deny == 0
    734  |       && NOERR(ret_err) ) {
    735  |
    736  |     ret_err = AC_ban_set(&prefix, "Automatic", 1);
    737  |   }
    738  |
    739  |   return ret_err;
    740  | } /* AC_commit */
    741  |
    742  |
    743  | /*++++++++++++++++++++++++++++++++++++++
    744  |   AC_decay_hook:
    745  |
    746  |   action performed on a single account node during decay (diminishing the
    747  |   bonus). Conforms to rx_walk_tree interface, therefore some of the
    748  |   arguments do not apply and are not used.
    749  |
    750  |   rx_node_t *node  - pointer to the node of the radix tree
    751  |   int level        - n/a
    752  |   int nodecounter  - n/a
    753  |   void *con        - n/a
    754  |
    755  |   returns always OK
    756  | +++++++++++++++++++++++++++++++++++++++*/
    757  | er_ret_t AC_decay_hook(rx_node_t *node, int level, int nodecounter, void *con)
    758  | {
    759  |   acc_st *a = node->leaves_ptr->data;
    760  |
    761  |   a->private_bonus *= 0.95;
    762  |
    763  |   return RX_OK;
    764  | } /* AC_decay_hook() */
    765  |
    766  |
    767  |
    768  | /*++++++++++++++++++++++++++++++++++++++
    769  |   AC_decay:
    770  |
    771  |   Every AC_DECAY_TIME goes through the accounting tree(s) and decays the
    772  |   bonus values.
    773  |
    774  |   returns always OK
    775  |
    776  |   MT-Note  This should be run as a detached thread.
    777  |   +++++++++++++++++++++++++++++++++++++++*/
    778  | er_ret_t AC_decay(void) {
    779  |   er_ret_t ret_err;
    780  |
    781  |
    782  |   while(CO_get_do_server()) {
    783  |
    784  |     TH_acquire_write_lock( &(act_runtime->rwlock) );
    785  |
    786  |     if( act_runtime->top_ptr != NULL ) {
    787  |        rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
    788  |                          RX_WALK_SKPGLU,  /* skip glue nodes */
    789  |                          255, 0, 0, NULL, &ret_err);
    790  |     }
    791  |
    792  |     /* it should also be as smart as to delete nodes that have reached
    793  |        zero, otherwise the whole of memory will be filled.
    794  |        Next release :-)
    795  |     */
    796  |
    797  |     TH_release_write_lock( &(act_runtime->rwlock) );
    798  |
    799  |     printf("AC: decaying access tree. (Every %d seconds)\n", AC_DECAY_TIME);
    800  |
    801  |     SV_sleep(LOCK_SHTDOWN, AC_DECAY_TIME);
    802  |   }
    803  |
    804  |   return ret_err;
    805  | } /* AC_decay() */
    806  |
    807  |
    808  | /*++++++++++++++++++++++++++++++++++++++
    809  |   AC_acc_load:
    810  |
    811  |   loads the acl access tree from the acl table of the RIPADMIN database.
    812  |   (takes port/host/user/password from the config module).
    813  |
    814  |   bails out if encounters problems with the database (logs to stderr).
    815  |
    816  |   returns error code from RX_bin_node or wr_malloc.
    817  |   ++++++++++++++++++++++++++++++++++++++*/
    818  | er_ret_t AC_acc_load(void)
    819  | {
    820  |   SQ_connection_t *con=NULL;
    821  |   SQ_result_set_t *result;
    822  |   SQ_row_t *row;
    823  |   er_ret_t ret_err = RX_OK;
    824  |
    825  |   if( (con = SQ_get_connection(CO_get_host(), CO_get_database_port(),
    826  |                         "RIPADMIN", CO_get_user(), CO_get_password() )
    827  |        ) == NULL ) {
    828  |     fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
    829  |     die;
    830  |   }
    831  |
    832  |   if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
    833  |       fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
    834  |       die;
    835  |   }
    836  |
    837  |   TH_acquire_write_lock( &(act_acl->rwlock) );
    838  |
    839  |   while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
    840  |     ip_prefix_t mypref;
    841  |     acl_st *newacl;
    842  |     char *col[7];
    843  |     unsigned myint;
    844  |     int i;
    845  |
    846  |     memset(&mypref, 0, sizeof(ip_prefix_t));
    847  |     mypref.ip.space = IP_V4;
    848  |
    849  |     if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
    850  |          ) == UT_OK ) {
    851  |
    852  |       for(i=0; i<7; i++) {
    853  |         if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
    854  |           die;
    855  |         }
    856  |       }
    857  |
    858  |       /* prefix ip */
    859  |       if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
    860  |
    861  |       /* prefix length */
    862  |       if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
    863  |
    864  |       /* acl contents */
    865  |       if( sscanf(col[2], "%u",  & (newacl->maxbonus)   ) < 1 ) { die; }
    866  |       if( sscanf(col[3], "%u",  & (newacl->maxpublic)   ) < 1 ) { die; }
    867  |       if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
    868  |
    869  |       /* these are chars therefore cannot read directly */
    870  |       if( sscanf(col[5], "%u", &myint              ) < 1 ) { die; }
    871  |       else {
    872  |         newacl->deny = myint;
    873  |       }
    874  |       if( sscanf(col[6], "%u", &myint  ) < 1 ) { die; }
    875  |       else {
    876  |         newacl->trustpass = myint;
    877  |       }
    878  |
    879  |       /* free space */
    880  |       for(i=0; i<6; i++) {
    881  | 	  wr_free(col[i]);
    882  |       }
    883  |
    884  |       /* now add to the tree */
    885  |       ret_err = rx_bin_node( RX_OPER_CRE, &mypref,
    886  |                              act_acl, (rx_dataleaf_t *) newacl );
    887  |     }
    888  |   } /* while row */
    889  |
    890  |   TH_release_write_lock( &(act_acl->rwlock) );
    891  |
    892  |   SQ_free_result(result);
    893  |   /* Close connection */
    894  |   SQ_close_connection(con);
    895  |
    896  |   return ret_err;
    897  | } /* AC_acc_load */
    898  |
    899  |
    900  |
    901  | /*++++++++++++++++++++++++++++++++++++++
    902  |   AC_build:
    903  |
    904  |   creates empty trees for accounting/acl.
    905  |
    906  |   returns error code from RX_tree_cre or OK.
    907  |   (XXX): just now only bails out when encounters problems.
    908  |   ++++++++++++++++++++++++++++++++++++++*/
    909  | er_ret_t AC_build(void)
    910  | {
    911  |   /* create trees */
    912  |   if (      RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
    913  | 			RX_SUB_NONE, &act_runtime) != RX_OK
    914  | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
    915  | 			RX_SUB_NONE, &act_hour) != RX_OK
    916  | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
    917  | 			RX_SUB_NONE, &act_minute) != RX_OK
    918  | 	 || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
    919  | 			RX_SUB_NONE, &act_acl) != RX_OK
    920  |          )
    921  |     die; /*can be changed to an error and handled ... some day */
    922  |
    923  |   return RX_OK;
    924  | }
    925  |
    926  | /*++++++++++++++++++++++++++++++++++++++
    927  |   AC_rxwalkhook_print:
    928  |
    929  |   action performed on a single account node
    930  |   when listing the contents of the access tree: format and print the
    931  |   data from this node.
    932  |
    933  |   Conforms to rx_walk_tree interface, therefore some of the
    934  |   arguments do not apply and are not used.
    935  |
    936  |   rx_node_t *node  - pointer to the node of the radix tree
    937  |   int level        - n/a
    938  |   int nodecounter  - n/a
    939  |   void *con        - pointer to the connection structure (prints to it)
    940  |
    941  |   returns always OK
    942  | +++++++++++++++++++++++++++++++++++++++*/
    943  | er_ret_t AC_rxwalkhook_print(rx_node_t *node,
    944  |                              int level, int nodecounter,
    945  |                              void *con)
    946  | {
    947  |   char adstr[IP_ADDRSTR_MAX];
    948  |   char line[1024];
    949  |   char *dat;
    950  |
    951  |
    952  |     if( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK ) {
    953  |       die; /* program error. */
    954  |     }
    955  |
    956  |     sprintf(line, "%-20s %s\n", adstr,
    957  |             dat=AC_to_string( node->leaves_ptr ));
    958  |     wr_free(dat);
    959  |
    960  |     SK_cd_puts((sk_conn_st *)con, line);
    961  |     return RX_OK;
    962  | } /* AC_rxwalkhook_print */
    963  |
    964  |
    965  | /*++++++++++++++++++++++++++++++++++++++
    966  |   AC_rxwalkhook_print_acl:
    967  |
    968  |   action performed on a single account node
    969  |   when listing the contents of the acl tree: format and print the
    970  |   data from this node.
    971  |
    972  |   Conforms to rx_walk_tree interface, therefore some of the
    973  |   arguments do not apply and are not used.
    974  |
    975  |   rx_node_t *node  - pointer to the node of the radix tree
    976  |   int level        - n/a
    977  |   int nodecounter  - n/a
    978  |   void *con        - pointer to the connection structure (prints to it)
    979  |
    980  |   returns always OK
    981  |   +++++++++++++++++++++++++++++++++++++++*/
    982  | er_ret_t AC_rxwalkhook_print_acl(rx_node_t *node,
    983  |                              int level, int nodecounter,
    984  |                              void *con)
    985  | {
    986  |   char prefstr[IP_PREFSTR_MAX];
    987  |   char line[1024];
    988  |   char *dat;
    989  |
    990  |
    991  |     if( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK ) {
    992  |       die; /* program error. */
    993  |     }
    994  |
    995  |     sprintf(line, "%-20s %s\n", prefstr,
    996  |             dat=AC_acl_to_string( node->leaves_ptr ));
    997  |     wr_free(dat);
    998  |
    999  |     SK_cd_puts((sk_conn_st *)con, line);
    1000 |     return RX_OK;
    1001 | }/* AC_rxwalkhook_print_acl */
    1002 |