1 | /***************************************
2 | $Revision: 1.18 $
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 | /* #define AC_DECAY_TIME 3600 */
47 |
48 |
49 | #define ACL_FORMAT "%10d %10d %10d %10d %10d"
50 | #define ACL_HEADER "%-20s %10s %10s %10s %10s %10s\n"
51 |
52 |
53 | #define ACC_FORMAT "%4d %4d %4d %4d %6d %6d %6d"
54 | #define ACC_HEADER "%-20s %4s %4s %4s %4s %6s %6s %6s\n"
55 |
56 | /* AC_to_string_header() */
57 | char *AC_to_string_header(void)
58 | {
59 | char *result_buf;
60 |
61 | dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
62 |
63 | sprintf(result_buf, ACC_HEADER, "ip",
64 | "conn", "pass", "deny", "qry", "pub", "priv", "bonus" );
65 |
66 | return result_buf;
67 | }
68 |
69 | /* AC_to_string() */
70 | /*++++++++++++++++++++++++++++++++++++++
71 | Show an access structure
72 |
73 | More:
74 | +html+ <PRE>
75 | Authors:
76 | marek
77 | +html+ </PRE><DL COMPACT>
78 | +html+ <DT>Online References:
79 | +html+ </UL></DL>
80 |
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 | /* do many bad things...*/
89 | return NULL;
90 | }
91 |
92 | if( a == NULL ) {
93 | strcpy(result_buf, "DATA MISSING!");
94 | }
95 | else {
96 | sprintf(result_buf,
97 |
98 | /* "conn %4d pass %4d den %4d qrs %4d pub %5d priv %5d bonus %5d",*/
99 | ACC_FORMAT,
100 | a->connections,
101 | a->addrpasses,
102 | a->denials,
103 | a->queries,
104 | a->public_objects,
105 | a->private_objects,
106 | a->private_bonus
107 | );
108 | }
109 |
110 | return result_buf;
111 | } /* AC_to_string() */
112 |
113 |
114 | /*++++++++++++++++++++++++++++++++++++++
115 | Show credit (for logging of queries)
116 |
117 | More:
118 | +html+ <PRE>
119 | Authors:
120 | marek
121 | +html+ </PRE><DL COMPACT>
122 | +html+ <DT>Online References:
123 | +html+ </UL></DL>
124 |
125 | ++++++++++++++++++++++++++++++++++++++*/
126 | char *AC_credit_to_string(acc_st *a)
127 | {
128 | char *result_buf;
129 |
130 | if( wr_malloc( (void **) &result_buf, 64) != UT_OK ) {
131 | /* do many bad things...*/
132 | return NULL;
133 | }
134 |
135 | dieif( a == NULL );
136 |
137 | sprintf(result_buf,"%d+%d%s",
138 | a->private_objects,
139 | a->public_objects,
140 | a->denials ? " **DENIED**" : ""
141 | );
142 |
143 | return result_buf;
144 | } /* AC_credit_to_string */
145 |
146 |
147 | char *
148 | AC_acl_to_string_header(void)
149 | {
150 | char *result_buf;
151 | dieif( wr_malloc( (void **) &result_buf, 256) != UT_OK );
152 |
153 | sprintf(result_buf, ACL_HEADER, "ip",
154 | "maxbonus", "maxdenials", "maxpublic", "ban", "trustpass" );
155 |
156 | return result_buf;
157 | }
158 |
159 |
160 | /* AC_acl_to_string() */
161 | /*++++++++++++++++++++++++++++++++++++++
162 | Show an access control list structure
163 |
164 | More:
165 | +html+ <PRE>
166 | Authors:
167 | marek
168 | +html+ </PRE><DL COMPACT>
169 | +html+ <DT>Online References:
170 | +html+ </UL></DL>
171 |
172 | ++++++++++++++++++++++++++++++++++++++*/
173 | char *AC_acl_to_string(GList *leafptr)
174 | {
175 | char *result_buf;
176 | acl_st *a = leafptr->data;
177 |
178 | if( wr_malloc( (void **) &result_buf, 256) != UT_OK ) {
179 | /* do many bad things...*/
180 | return NULL;
181 | }
182 |
183 | if( a != NULL ) {
184 | sprintf(result_buf, ACL_FORMAT,
185 | a->maxbonus,
186 | a->maxdenials,
187 | a->maxpublic,
188 | a->deny,
189 | a->trustpass
190 | );
191 | }
192 | else {
193 | strcpy(result_buf, "DATA MISSING\n");
194 | }
195 |
196 | return result_buf;
197 | } /* AC_acl_to_string() */
198 |
199 | er_ret_t
200 | AC_findexless_acl_l(ip_prefix_t *prefix, acl_st *store_acl)
201 | {
202 | GList *datlist=NULL;
203 | er_ret_t ret_err;
204 | rx_datref_t *datref;
205 |
206 | if( (ret_err = RX_bin_search(RX_SRCH_EXLESS, 0, 0, act_acl,
207 | prefix, &datlist, RX_ANS_ALL)
208 | ) != RX_OK || g_list_length(datlist) == 0 ) {
209 | /* acl tree is not configured at all ! There always must be a
210 | catch-all record with defaults */
211 | die;
212 | }
213 |
214 | datref = (rx_datref_t *)g_list_nth_data(datlist,0);
215 |
216 | *store_acl = * ((acl_st *) datref->leafptr);
217 |
218 | wr_clear_list( &datlist );
219 |
220 | /* XXX checking tree consistency */
221 | {
222 | rx_treecheck_t errorfound;
223 | er_ret_t err;
224 | if( (err=RX_treecheck(act_acl, 1, &errorfound)) != RX_OK ) {
225 | fprintf(stderr, "Nope! %d returned \n", err);
226 | die;
227 | }
228 | }
229 |
230 | return ret_err;
231 | }
232 |
233 | er_ret_t
234 | AC_findcreate_acl_l(ip_prefix_t *prefix, acl_st **store_acl)
235 | {
236 | GList *datlist=NULL;
237 | er_ret_t ret_err;
238 | acl_st *newacl;
239 | acl_st acl_copy;
240 |
241 | if( NOERR(ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, act_acl,
242 | prefix, &datlist, RX_ANS_ALL)
243 | )) {
244 |
245 | switch( g_list_length(datlist)) {
246 | case 0:
247 | dieif( wr_calloc((void **)&newacl, 1, sizeof(acl_st)) != UT_OK );
248 |
249 | /* make the new one inherit all parameters after the old one */
250 |
251 | AC_findexless_acl_l(prefix, &acl_copy);
252 |
253 | *newacl = acl_copy;
254 |
255 | /* link in */
256 | RX_rt_node(RX_OPER_CRE, prefix, act_acl, (rx_dataleaf_t *)newacl);
257 | break;
258 | case 1:
259 | {
260 | /* Uh-oh, the guy is already known ! (or special, in any case) */
261 | rx_datref_t *datref = (rx_datref_t *)g_list_nth_data(datlist,0);
262 | newacl = (acl_st *) datref->leafptr;
263 | }
264 | break;
265 | default:
266 | die;
267 | }
268 | }
269 |
270 | /* free search results */
271 | wr_clear_list( &datlist );
272 |
273 | /* store */
274 | *store_acl = newacl;
275 | return ret_err;
276 | }
277 |
278 | /*
279 | finds exact prefix or creates area initialised to zeros + sets ptr to it.
280 |
281 | returns error code
282 |
283 | operates on the given tree
284 | assumes tree locked
285 | */
286 | er_ret_t
287 | AC_findcreate_account_l(rx_tree_t *tree, ip_prefix_t *prefix,
288 | acc_st **acc_store)
289 | {
290 | GList *datlist=NULL;
291 | er_ret_t ret_err;
292 | acc_st *recacc;
293 |
294 | if( (ret_err = RX_bin_search(RX_SRCH_EXACT, 0, 0, tree,
295 | prefix, &datlist, RX_ANS_ALL)) == RX_OK ) {
296 | switch( g_list_length(datlist) ) {
297 | case 0:
298 | /* need to create a new accounting record */
299 | if( (ret_err = wr_malloc( (void **)& recacc, sizeof(acc_st))) == UT_OK ) {
300 | /* counters = init to zeros */
301 | memset( recacc, 0, sizeof(acc_st));
302 |
303 | /* attach. The recacc is to be treated as a dataleaf
304 | (must use lower levels than RX_asc_*)
305 | */
306 | ret_err = RX_rt_node( RX_OPER_CRE, prefix,
307 | act_runtime, (rx_dataleaf_t *)recacc );
308 | }
309 | break;
310 | case 1:
311 | {
312 | rx_datref_t *datref = (rx_datref_t *) g_list_nth_data( datlist,0 );
313 |
314 | /* OK, there is a record already */
315 | recacc = (acc_st *) datref->leafptr;
316 |
317 | }
318 | break;
319 | default: die; /* there shouldn't be more than 1 entry per IP */
320 | }
321 | }
322 |
323 | wr_clear_list( &datlist );
324 |
325 | *acc_store = recacc;
326 |
327 | return ret_err;
328 | }
329 |
330 |
331 | /* AC_fetch_acc() */
332 | /*++++++++++++++++++++++++++++++++++++++
333 | Finds the runtime accounting record for this IP,
334 | stores a copy of it in acc_store.
335 |
336 | If not found, then it is created and initialised to zeros in findcreate()
337 |
338 | ++++++++++++++++++++++++++++++++++++++*/
339 | er_ret_t AC_fetch_acc( ip_addr_t *addr, acc_st *acc_store)
340 | {
341 | er_ret_t ret_err;
342 | ip_prefix_t prefix;
343 | acc_st *ac_ptr;
344 |
345 | prefix.ip = *addr;
346 | prefix.bits = IP_sizebits(addr->space);
347 |
348 | TH_acquire_read_lock( &(act_runtime->rwlock) );
349 |
350 | ret_err = AC_findcreate_account_l(act_runtime, &prefix, &ac_ptr);
351 | *acc_store = *ac_ptr;
352 |
353 | TH_release_read_lock( &(act_runtime->rwlock) );
354 |
355 | return ret_err;
356 | }/* AC_fetch_acc() */
357 |
358 | /* AC_check_acl() */
359 | /*++++++++++++++++++++++++++++++++++++++
360 |
361 | AC_check_acl:
362 |
363 | search for this ip or less specific record in the access control tree
364 |
365 | if( bonus in combined runtime+connection accountings > max_bonus in acl)
366 | set denial in the acl for this ip (create if needed)
367 | if( combined denialcounter > max_denials in acl)
368 | set the permanent ban in acl; save in SQL too
369 | calculate credit if pointer provided
370 | save the access record (ip if created or found/prefix otherwise)
371 | at *acl_store if provided
372 |
373 | any of the args except address can be NULL
374 |
375 | ++++++++++++++++++++++++++++++++++++++*/
376 | er_ret_t AC_check_acl( ip_addr_t *addr,
377 | acc_st *credit_acc,
378 | acl_st *acl_store
379 | )
380 | {
381 | ip_prefix_t prefix;
382 | er_ret_t ret_err;
383 | acl_st acl_record;
384 | acc_st run_acc;
385 |
386 | AC_fetch_acc( addr, &run_acc );
387 |
388 | prefix.ip = *addr;
389 | prefix.bits = IP_sizebits(addr->space);
390 |
391 | /* lock the tree accordingly */
392 | TH_acquire_read_lock( &(act_acl->rwlock) );
393 |
394 | /* find an applicable record */
395 | AC_findexless_acl_l(&prefix, &acl_record);
396 |
397 | /* calculate the credit if pointer given */
398 | if( credit_acc ) {
399 | memset( credit_acc, 0, sizeof(acc_st));
400 | credit_acc->public_objects = /* -1 == unlimited */
401 | acl_record.maxpublic - run_acc.public_objects;
402 | credit_acc->private_objects =
403 | acl_record.maxbonus - run_acc.private_bonus;
404 | }
405 |
406 | /* copy the acl record if asked for it*/
407 | if( acl_store ) {
408 | *acl_store = acl_record;
409 | }
410 |
411 | /* release lock */
412 | TH_release_read_lock( &(act_acl->rwlock) );
413 |
414 |
415 | return ret_err;
416 | }
417 |
418 | void AC_acc_addup(acc_st *a, acc_st *b, int minus)
419 | {
420 | int mul = minus ? -1 : 1;
421 |
422 | /* add all counters from b to those in a */
423 | a->connections += mul * b->connections;
424 | a->addrpasses += mul * b->addrpasses;
425 |
426 | a->denials += mul * b->denials;
427 | a->queries += mul * b->queries;
428 | a->public_objects += mul * b->public_objects;
429 | a->private_objects += mul * b->private_objects;
430 | a->private_bonus += mul * b->private_bonus;
431 | }
432 |
433 |
434 | /*
435 | performs the commit on an accounting tree (locks them first)
436 | stores a copy of the accounting record at rec_store
437 | */
438 | er_ret_t
439 | AC_commit_credit(rx_tree_t *tree, ip_prefix_t *prefix,
440 | acc_st *acc_conn, acc_st *rec_store )
441 | {
442 | acc_st *accountrec;
443 | er_ret_t ret_err;
444 |
445 |
446 | acc_conn->private_bonus = acc_conn->private_objects;
447 |
448 | TH_acquire_write_lock( &(tree->rwlock) );
449 |
450 | AC_findcreate_account_l(act_runtime, prefix, &accountrec);
451 |
452 | AC_acc_addup(accountrec, acc_conn, ACC_PLUS);
453 | /* XXX checking tree consistency */
454 |
455 | {
456 | rx_treecheck_t errorfound;
457 | er_ret_t err;
458 | if( (err=RX_treecheck(tree, 1, &errorfound)) != RX_OK ) {
459 | fprintf(stderr, "Nope! %d returned \n", err);
460 | die;
461 | }
462 | }
463 |
464 | TH_release_write_lock( &(tree->rwlock) );
465 |
466 | *rec_store = *accountrec;
467 |
468 | return ret_err;
469 | }
470 |
471 | /* insert/replace a record in the database */
472 | er_ret_t
473 | AC_acl_sql(ip_prefix_t *prefix, acl_st *newacl, char *newcomment )
474 | {
475 | SQ_connection_t *sql_connection = NULL;
476 | SQ_result_set_t *result;
477 | SQ_row_t *row;
478 | char *oldcomment;
479 | char *query;
480 | char querybuf[256];
481 |
482 | sql_connection = SQ_get_connection(CO_get_host(),
483 | CO_get_database_port(),
484 | "RIPADMIN",
485 | CO_get_user(),
486 | CO_get_password() );
487 |
488 | /* get the old entry, extend it */
489 | sprintf(querybuf, "SELECT comment FROM acl WHERE "
490 | "prefix = %u AND prefix_length = %d",
491 | prefix->ip.words[0],
492 | prefix->bits);
493 | dieif( SQ_execute_query(sql_connection, querybuf, &result) == -1 );
494 |
495 | if( SQ_num_rows(result) == 1 ) {
496 | dieif( (row = SQ_row_next(result)) == NULL);
497 | oldcomment = SQ_get_column_string(result, row, 0);
498 | }
499 | else {
500 | oldcomment = "";
501 | }
502 |
503 | SQ_free_result(result);
504 |
505 | /* must hold the thing below (replace..blah blah blah) + text */
506 | dieif( wr_malloc((void **)&query,
507 | strlen(oldcomment) + strlen(newcomment) + 256) != UT_OK );
508 |
509 | /* compose new entry and insert it */
510 | sprintf(query, "REPLACE INTO acl VALUES(%u, %d, %d, %d, %d, %d, %d,"
511 | "\"%s%s%s\")",
512 | prefix->ip.words[0],
513 | prefix->bits,
514 | newacl->maxbonus,
515 | newacl->maxpublic,
516 | newacl->maxdenials,
517 | newacl->deny,
518 | newacl->trustpass,
519 | oldcomment,
520 | strlen(oldcomment) > 0 ? "\n" : "",
521 | newcomment
522 | );
523 |
524 | SQ_execute_query(sql_connection, query, NULL);
525 | SQ_close_connection(sql_connection);
526 |
527 | wr_free(query);
528 |
529 | return AC_OK;
530 |
531 | }
532 |
533 |
534 | /* re/sets the permanent ban flag both in the acl tree in memory
535 | and the sql table. The "text" is appended to the comment
536 | in the sql record (the expected cases are
537 | - "automatic" in case the limit is exceeded and ban is set by s/w
538 | - "manual" in case it is (un)set from the config iface
539 | */
540 | er_ret_t
541 | AC_ban_set(ip_prefix_t *prefix, char *text, int denyflag)
542 | {
543 | acl_st *treeacl;
544 | char newcomment[256];
545 | er_ret_t ret_err;
546 | time_t clock;
547 | char timebuf[26];
548 |
549 | time(&clock);
550 | ctime_r(&clock, timebuf);
551 |
552 | sprintf(newcomment,"%s permanent ban set to %d at %s", text,
553 | denyflag, timebuf);
554 |
555 | TH_acquire_write_lock( &(act_acl->rwlock) );
556 |
557 | /* find a record in the tree */
558 | if( NOERR(ret_err = AC_findcreate_acl_l( prefix, &treeacl )) ) {
559 | treeacl->deny = denyflag;
560 | ret_err = AC_acl_sql( prefix, treeacl, newcomment );
561 | }
562 | TH_release_write_lock( &(act_acl->rwlock) );
563 |
564 | return ret_err;
565 | }
566 |
567 | er_ret_t
568 | AC_asc_ban_set(char *addrstr, char *text, int denyflag)
569 | {
570 | er_ret_t ret_err;
571 | GList *preflist = NULL;
572 | ip_keytype_t key_type;
573 |
574 | if( (ret_err = IP_smart_conv(addrstr, 0, 0,
575 | &preflist, IP_PLAIN, &key_type)) != IP_OK ) {
576 | return ret_err;
577 | }
578 |
579 | /* allow only one prefix */
580 | /* The argument can be even a range, but must decompose into one prefix */
581 | if( NOERR(ret_err) && g_list_length( preflist ) != 1 ) {
582 | ret_err = AC_INVARG;
583 | }
584 |
585 | if( NOERR(ret_err) ) {
586 | ret_err = AC_ban_set( (g_list_first(preflist)->data), text, denyflag);
587 | }
588 |
589 | wr_clear_list( &preflist );
590 |
591 | return ret_err;
592 | }
593 |
594 | er_ret_t AC_commit(ip_addr_t *addr, acc_st *acc_conn, acl_st *acl_copy) {
595 | /*
596 | lock runtime + minute accounting trees
597 | ----------------------- XXX runtime only for the moment
598 | find or create entries,
599 | increase accounting values by the values from passed acc
600 | check values against acl, see if permanent ban applies
601 |
602 | reset the connection acc
603 | unlock accounting trees
604 |
605 | if permanent ban - set it! :
606 | lock acl
607 | find/create IP in memory
608 | set ban
609 | find/create IP in SQL
610 | copy old values (if any), set ban, append comment
611 | unlock acl
612 | */
613 |
614 | acc_st account;
615 | er_ret_t ret_err;
616 | ip_prefix_t prefix;
617 |
618 | prefix.ip = *addr;
619 | prefix.bits = IP_sizebits(addr->space);
620 |
621 | ret_err = AC_commit_credit(act_runtime, &prefix, acc_conn, &account);
622 | /* XXX add more trees here */
623 |
624 | memset(acc_conn,0, sizeof(acc_st));
625 |
626 | /* set permanent ban if deserved and if not set yet */
627 | if( account.denials > acl_copy->maxdenials
628 | && acl_copy->deny == 0
629 | && NOERR(ret_err) ) {
630 |
631 | ret_err = AC_ban_set(&prefix, "Automatic", 1);
632 | }
633 |
634 | return ret_err;
635 | }
636 |
637 | er_ret_t AC_decay_hook(rx_node_t *node, int level, int nodecounter, void *con) {
638 | acc_st *a = node->leaves_ptr->data;
639 |
640 | a->private_bonus *= 0.95;
641 |
642 | return RX_OK;
643 | } /* AC_decay_hook() */
644 |
645 |
646 |
647 | /*
648 | This should be run as a detached thread.
649 | */
650 | er_ret_t AC_decay(void) {
651 | er_ret_t ret_err;
652 |
653 |
654 | while(CO_get_do_server()) {
655 |
656 | TH_acquire_write_lock( &(act_runtime->rwlock) );
657 |
658 | if( act_runtime->top_ptr != NULL ) {
659 | rx_walk_tree(act_runtime->top_ptr, AC_decay_hook,
660 | RX_WALK_SKPGLU, /* skip glue nodes */
661 | 255, 0, 0, NULL, &ret_err);
662 | }
663 |
664 | /* it should also be as smart as to delete nodes that have reached
665 | zero, otherwise the whole of memory will be filled.
666 | Next release :-)
667 | */
668 |
669 | TH_release_write_lock( &(act_runtime->rwlock) );
670 |
671 | printf("AC: decaying access tree. (Every %d seconds)\n", AC_DECAY_TIME);
672 |
673 | SV_sleep(LOCK_SHTDOWN, AC_DECAY_TIME);
674 | }
675 |
676 | return ret_err;
677 | } /* AC_decay() */
678 |
679 | er_ret_t AC_acc_load(void)
680 | {
681 | SQ_connection_t *con=NULL;
682 | SQ_result_set_t *result;
683 | SQ_row_t *row;
684 | er_ret_t ret_err = RX_OK;
685 |
686 | if( (con = SQ_get_connection(CO_get_host(), CO_get_database_port(),
687 | "RIPADMIN", CO_get_user(), CO_get_password() )
688 | ) == NULL ) {
689 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
690 | die;
691 | }
692 |
693 | if( SQ_execute_query(con, "SELECT * FROM acl", &result) == -1 ) {
694 | fprintf(stderr, "ERROR %d: %s\n", SQ_errno(con), SQ_error(con));
695 | die;
696 | }
697 |
698 | TH_acquire_write_lock( &(act_acl->rwlock) );
699 |
700 | while ( (row = SQ_row_next(result)) != NULL && ret_err == RX_OK) {
701 | ip_prefix_t mypref;
702 | acl_st *newacl;
703 | char *col[7];
704 | unsigned myint;
705 | int i;
706 |
707 | memset(&mypref, 0, sizeof(ip_prefix_t));
708 | mypref.ip.space = IP_V4;
709 |
710 | if( (ret_err = wr_malloc( (void **)& newacl, sizeof(acl_st))
711 | ) == UT_OK ) {
712 |
713 | for(i=0; i<7; i++) {
714 | if ( (col[i] = SQ_get_column_string(result, row, i)) == NULL) {
715 | die;
716 | }
717 | }
718 |
719 | /* prefix ip */
720 | if( sscanf(col[0], "%u", &mypref.ip.words[0] ) < 1 ) { die; }
721 |
722 | /* prefix length */
723 | if( sscanf(col[1], "%u", &mypref.bits ) < 1 ) { die; }
724 |
725 | /* acl contents */
726 | if( sscanf(col[2], "%u", & (newacl->maxbonus) ) < 1 ) { die; }
727 | if( sscanf(col[3], "%u", & (newacl->maxpublic) ) < 1 ) { die; }
728 | if( sscanf(col[4], "%hd", & (newacl->maxdenials) ) < 1 ) { die; }
729 |
730 | /* these are chars therefore cannot read directly */
731 | if( sscanf(col[5], "%u", &myint ) < 1 ) { die; }
732 | else {
733 | newacl->deny = myint;
734 | }
735 | if( sscanf(col[6], "%u", &myint ) < 1 ) { die; }
736 | else {
737 | newacl->trustpass = myint;
738 | }
739 |
740 | /* free space */
741 | for(i=0; i<6; i++) {
742 | wr_free(col[i]);
743 | }
744 |
745 |
746 | /* now add to the tree */
747 |
748 | ret_err = RX_rt_node( RX_OPER_CRE, &mypref,
749 | act_acl, (rx_dataleaf_t *) newacl );
750 | }
751 | } /* while row */
752 |
753 | TH_release_write_lock( &(act_acl->rwlock) );
754 |
755 | SQ_free_result(result);
756 | /* Close connection */
757 | SQ_close_connection(con);
758 |
759 |
760 |
761 | return ret_err;
762 | }
763 |
764 | er_ret_t AC_build(void)
765 | {
766 | /* create trees */
767 | if ( RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
768 | RX_SUB_NONE, &act_runtime) != RX_OK
769 | || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
770 | RX_SUB_NONE, &act_hour) != RX_OK
771 | || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
772 | RX_SUB_NONE, &act_minute) != RX_OK
773 | || RX_tree_cre("0.0.0.0/0", RX_FAM_IP, RX_MEM_RAMONLY,
774 | RX_SUB_NONE, &act_acl) != RX_OK
775 | )
776 | die; /*can be changed to an error and handled ... some day */
777 |
778 | return RX_OK;
779 | }
780 |
781 | er_ret_t AC_rxwalkhook_print(rx_node_t *node,
782 | int level, int nodecounter,
783 | void *con)
784 | {
785 | char adstr[IP_ADDRSTR_MAX];
786 | char line[1024];
787 | char *dat;
788 |
789 |
790 | if( IP_addr_b2a(&(node->prefix.ip), adstr, IP_ADDRSTR_MAX) != IP_OK ) {
791 | die; /* program error. */
792 | }
793 |
794 | sprintf(line, "%-20s %s\n", adstr,
795 | dat=AC_to_string( node->leaves_ptr ));
796 | wr_free(dat);
797 |
798 | SK_cd_puts((sk_conn_st *)con, line);
799 | return RX_OK;
800 | }
801 |
802 | er_ret_t AC_rxwalkhook_print_acl(rx_node_t *node,
803 | int level, int nodecounter,
804 | void *con)
805 | {
806 | char prefstr[IP_PREFSTR_MAX];
807 | char line[1024];
808 | char *dat;
809 |
810 |
811 | if( IP_pref_b2a(&(node->prefix), prefstr, IP_PREFSTR_MAX) != IP_OK ) {
812 | die; /* program error. */
813 | }
814 |
815 | sprintf(line, "%-20s %s\n", prefstr,
816 | dat=AC_acl_to_string( node->leaves_ptr ));
817 | wr_free(dat);
818 |
819 | SK_cd_puts((sk_conn_st *)con, line);
820 | return RX_OK;
821 | }
822 |