Annotation of embedaddon/dhcp/server/db.c, revision 1.1.1.1

1.1       misho       1: /* db.c
                      2: 
                      3:    Persistent database management routines for DHCPD... */
                      4: 
                      5: /*
1.1.1.1 ! misho       6:  * Copyright (c) 2004-2010,2012 by Internet Systems Consortium, Inc. ("ISC")
1.1       misho       7:  * Copyright (c) 1995-2003 by Internet Software Consortium
                      8:  *
                      9:  * Permission to use, copy, modify, and distribute this software for any
                     10:  * purpose with or without fee is hereby granted, provided that the above
                     11:  * copyright notice and this permission notice appear in all copies.
                     12:  *
                     13:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
                     14:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     15:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
                     16:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     17:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     18:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
                     19:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     20:  *
                     21:  *   Internet Systems Consortium, Inc.
                     22:  *   950 Charter Street
                     23:  *   Redwood City, CA 94063
                     24:  *   <info@isc.org>
                     25:  *   https://www.isc.org/
                     26:  *
                     27:  * This software has been written for Internet Systems Consortium
                     28:  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
                     29:  * To learn more about Internet Systems Consortium, see
                     30:  * ``https://www.isc.org/''.  To learn more about Vixie Enterprises,
                     31:  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
                     32:  * ``http://www.nominum.com''.
                     33:  */
                     34: 
                     35: #include "dhcpd.h"
                     36: #include <ctype.h>
                     37: #include <errno.h>
                     38: 
1.1.1.1 ! misho      39: #define LEASE_REWRITE_PERIOD 3600
        !            40: 
1.1       misho      41: static isc_result_t write_binding_scope(FILE *db_file, struct binding *bnd,
                     42:                                        char *prepend);
                     43: 
                     44: FILE *db_file;
                     45: 
                     46: static int counting = 0;
                     47: static int count = 0;
                     48: TIME write_time;
                     49: int lease_file_is_corrupt = 0;
                     50: 
                     51: /* Write a single binding scope value in parsable format.
                     52:  */
                     53: 
                     54: static isc_result_t
                     55: write_binding_scope(FILE *db_file, struct binding *bnd, char *prepend) {
                     56:        char *s;
                     57: 
                     58:        if ((db_file == NULL) || (bnd == NULL) || (prepend == NULL))
                     59:                return ISC_R_INVALIDARG;
                     60: 
                     61:        if (bnd->value->type == binding_data) {
                     62:                if (bnd->value->value.data.data != NULL) {
                     63:                        s = quotify_buf(bnd->value->value.data.data,
                     64:                                        bnd->value->value.data.len, MDL);
                     65:                        if (s != NULL) {
                     66:                                errno = 0;
                     67:                                fprintf(db_file, "%sset %s = \"%s\";",
                     68:                                        prepend, bnd->name, s);
                     69:                                if (errno)
                     70:                                        return ISC_R_FAILURE;
                     71: 
                     72:                                dfree(s, MDL);
                     73:                        } else {
                     74:                            return ISC_R_FAILURE;
                     75:                        }
                     76:                }
                     77:        } else if (bnd->value->type == binding_numeric) {
                     78:                errno = 0;
                     79:                fprintf(db_file, "%sset %s = %%%ld;", prepend,
                     80:                        bnd->name, bnd->value->value.intval);
                     81:                if (errno)
                     82:                        return ISC_R_FAILURE;
                     83:        } else if (bnd->value->type == binding_boolean) {
                     84:                errno = 0;
                     85:                fprintf(db_file, "%sset %s = %s;", prepend, bnd->name,
                     86:                        bnd->value->value.intval ? "true" : "false");
                     87:                if (errno)
                     88:                        return ISC_R_FAILURE;
                     89:        } else if (bnd->value->type == binding_dns) {
                     90:                log_error("%s: persistent dns values not supported.",
                     91:                          bnd->name);
                     92:        } else if (bnd->value->type == binding_function) {
                     93:                log_error("%s: persistent functions not supported.",
                     94:                          bnd->name);
                     95:        } else {
                     96:                log_fatal("%s: unknown binding type %d", bnd->name,
                     97:                          bnd->value->type);
                     98:        }
                     99: 
                    100:        return ISC_R_SUCCESS;
                    101: }
                    102: 
                    103: /* Write the specified lease to the current lease database file. */
                    104: 
                    105: int write_lease (lease)
                    106:        struct lease *lease;
                    107: {
                    108:        int errors = 0;
                    109:        struct binding *b;
                    110:        char *s;
                    111:        const char *tval;
                    112: 
                    113:        /* If the lease file is corrupt, don't try to write any more leases
                    114:           until we've written a good lease file. */
                    115:        if (lease_file_is_corrupt)
                    116:                if (!new_lease_file ())
                    117:                        return 0;
                    118: 
                    119:        if (counting)
                    120:                ++count;
                    121:        errno = 0;
                    122:        fprintf (db_file, "lease %s {", piaddr (lease -> ip_addr));
                    123:        if (errno) {
                    124:                ++errors;
                    125:        }
                    126: 
                    127:        if (lease->starts &&
                    128:            ((tval = print_time(lease->starts)) == NULL ||
                    129:             fprintf(db_file, "\n  starts %s", tval) < 0))
                    130:                ++errors;
                    131: 
                    132:        if (lease->ends &&
                    133:            ((tval = print_time(lease->ends)) == NULL ||
                    134:             fprintf(db_file, "\n  ends %s", tval) < 0))
                    135:                ++errors;
                    136: 
                    137:        if (lease->tstp &&
                    138:            ((tval = print_time(lease->tstp)) == NULL ||
                    139:             fprintf(db_file, "\n  tstp %s", tval) < 0))
                    140:                ++errors;
                    141: 
                    142:        if (lease->tsfp &&
                    143:            ((tval = print_time(lease->tsfp)) == NULL ||
                    144:             fprintf(db_file, "\n  tsfp %s", tval) < 0))
                    145:                ++errors;
                    146: 
                    147:        if (lease->atsfp &&
                    148:            ((tval = print_time(lease->atsfp)) == NULL ||
                    149:             fprintf(db_file, "\n  atsfp %s", tval) < 0))
                    150:                ++errors;
                    151: 
                    152:        if (lease->cltt &&
                    153:            ((tval = print_time(lease->cltt)) == NULL ||
                    154:             fprintf(db_file, "\n  cltt %s", tval) < 0))
                    155:                ++errors;
                    156: 
                    157:        if (fprintf (db_file, "\n  binding state %s;",
                    158:                 ((lease -> binding_state > 0 &&
                    159:                   lease -> binding_state <= FTS_LAST)
                    160:                  ? binding_state_names [lease -> binding_state - 1]
                    161:                  : "abandoned")) < 0)
                    162:                 ++errors;
                    163: 
                    164:        if (lease -> binding_state != lease -> next_binding_state)
                    165:                if (fprintf (db_file, "\n  next binding state %s;",
                    166:                         ((lease -> next_binding_state > 0 &&
                    167:                           lease -> next_binding_state <= FTS_LAST)
                    168:                          ? (binding_state_names
                    169:                             [lease -> next_binding_state - 1])
                    170:                          : "abandoned")) < 0)
                    171:                         ++errors;
                    172: 
                    173:        if (lease->flags & RESERVED_LEASE)
                    174:                if (fprintf(db_file, "\n  reserved;") < 0)
                    175:                         ++errors;
                    176: 
                    177:        if (lease->flags & BOOTP_LEASE)
                    178:                if (fprintf(db_file, "\n  dynamic-bootp;") < 0)
                    179:                         ++errors;
                    180: 
                    181:        /* If this lease is billed to a class and is still valid,
                    182:           write it out. */
                    183:        if (lease -> billing_class && lease -> ends > cur_time) {
                    184:                if (!write_billing_class (lease -> billing_class)) {
                    185:                        log_error ("unable to write class %s",
                    186:                                   lease -> billing_class -> name);
                    187:                        ++errors;
                    188:                }
                    189:        }
                    190: 
                    191:        if (lease -> hardware_addr.hlen) {
                    192:                errno = 0;
                    193:                fprintf (db_file, "\n  hardware %s %s;",
                    194:                         hardware_types [lease -> hardware_addr.hbuf [0]],
                    195:                         print_hw_addr (lease -> hardware_addr.hbuf [0],
                    196:                                        lease -> hardware_addr.hlen - 1,
                    197:                                        &lease -> hardware_addr.hbuf [1]));
                    198:                if (errno)
                    199:                        ++errors;
                    200:        }
                    201:        if (lease -> uid_len) {
                    202:                s = quotify_buf (lease -> uid, lease -> uid_len, MDL);
                    203:                if (s) {
                    204:                        errno = 0;
                    205:                        fprintf (db_file, "\n  uid \"%s\";", s);
                    206:                        if (errno)
                    207:                                ++errors;
                    208:                        dfree (s, MDL);
                    209:                } else
                    210:                        ++errors;
                    211:        }
                    212: 
                    213:        if (lease->scope != NULL) {
                    214:            for (b = lease->scope->bindings; b; b = b->next) {
                    215:                if (!b->value)
                    216:                        continue;
                    217: 
                    218:                if (write_binding_scope(db_file, b, "\n  ") != ISC_R_SUCCESS)
                    219:                        ++errors;
                    220:            }
                    221:        }
                    222: 
                    223:        if (lease -> agent_options) {
                    224:            struct option_cache *oc;
                    225:            struct data_string ds;
                    226:            pair p;
                    227: 
                    228:            memset (&ds, 0, sizeof ds);
                    229:            for (p = lease -> agent_options -> first; p; p = p -> cdr) {
                    230:                oc = (struct option_cache *)p -> car;
                    231:                if (oc -> data.len) {
                    232:                errno = 0;
                    233:                fprintf (db_file, "\n  option agent.%s %s;",
                    234:                         oc -> option -> name,
                    235:                         pretty_print_option (oc -> option, oc -> data.data,
                    236:                                                oc -> data.len, 1, 1));
                    237:                if (errno)
                    238:                    ++errors;
                    239:                }
                    240:            }
                    241:        }
                    242:        if (lease -> client_hostname &&
                    243:            db_printable((unsigned char *)lease->client_hostname)) {
                    244:                s = quotify_string (lease -> client_hostname, MDL);
                    245:                if (s) {
                    246:                        errno = 0;
                    247:                        fprintf (db_file, "\n  client-hostname \"%s\";", s);
                    248:                        if (errno)
                    249:                                ++errors;
                    250:                        dfree (s, MDL);
                    251:                } else
                    252:                        ++errors;
                    253:        }
                    254:        if (lease -> on_expiry) {
                    255:                errno = 0;
                    256:                fprintf (db_file, "\n  on expiry%s {",
                    257:                         lease -> on_expiry == lease -> on_release
                    258:                         ? " or release" : "");
                    259:                write_statements (db_file, lease -> on_expiry, 4);
                    260:                /* XXX */
                    261:                fprintf (db_file, "\n  }");
                    262:                if (errno)
                    263:                        ++errors;
                    264:        }
                    265:        if (lease -> on_release && lease -> on_release != lease -> on_expiry) {
                    266:                errno = 0;
                    267:                fprintf (db_file, "\n  on release {");
                    268:                write_statements (db_file, lease -> on_release, 4);
                    269:                /* XXX */
                    270:                fprintf (db_file, "\n  }");
                    271:                if (errno)
                    272:                        ++errors;
                    273:        }
                    274: 
                    275:        errno = 0;
                    276:        fputs ("\n}\n", db_file);
                    277:        if (errno)
                    278:                ++errors;
                    279: 
                    280:        if (errors) {
                    281:                log_info ("write_lease: unable to write lease %s",
                    282:                      piaddr (lease -> ip_addr));
                    283:                lease_file_is_corrupt = 1;
                    284:         }
                    285: 
                    286:        return !errors;
                    287: }
                    288: 
                    289: int write_host (host)
                    290:        struct host_decl *host;
                    291: {
                    292:        int errors = 0;
                    293:        int i;
                    294:        struct data_string ip_addrs;
                    295: 
                    296:        /* If the lease file is corrupt, don't try to write any more leases
                    297:           until we've written a good lease file. */
                    298:        if (lease_file_is_corrupt)
                    299:                if (!new_lease_file ())
                    300:                        return 0;
                    301: 
                    302:        if (!db_printable((unsigned char *)host->name))
                    303:                return 0;
                    304: 
                    305:        if (counting)
                    306:                ++count;
                    307: 
                    308:        errno = 0;
                    309:        fprintf (db_file, "host %s {", host -> name);
                    310:        if (errno)
                    311:                ++errors;
                    312: 
                    313:        if (host -> flags & HOST_DECL_DYNAMIC) {
                    314:                errno = 0;
                    315:                fprintf (db_file, "\n  dynamic;");
                    316:                if (errno)
                    317:                        ++errors;
                    318:        }
                    319: 
                    320:        if (host -> flags & HOST_DECL_DELETED) {
                    321:                errno = 0;
                    322:                fprintf (db_file, "\n  deleted;");
                    323:                if (errno)
                    324:                        ++errors;
                    325:        } else {
                    326:                if (host -> interface.hlen) {
                    327:                        errno = 0;
                    328:                        fprintf (db_file, "\n  hardware %s %s;",
                    329:                                 hardware_types [host -> interface.hbuf [0]],
                    330:                                 print_hw_addr (host -> interface.hbuf [0],
                    331:                                                host -> interface.hlen - 1,
                    332:                                                &host -> interface.hbuf [1]));
                    333:                        if (errno)
                    334:                                ++errors;
                    335:                }
                    336:                if (host -> client_identifier.len) {
                    337:                        int i;
                    338:                        errno = 0;
                    339:                        if (db_printable_len (host -> client_identifier.data,
                    340:                                              host -> client_identifier.len)) {
                    341:                                fprintf (db_file, "\n  uid \"%.*s\";",
                    342:                                         (int)host -> client_identifier.len,
                    343:                                         host -> client_identifier.data);
                    344:                                if (errno)
                    345:                                        ++errors;
                    346:                        } else {
                    347:                                fprintf (db_file,
                    348:                                         "\n  uid %2.2x",
                    349:                                         host -> client_identifier.data [0]);
                    350:                                if (errno)
                    351:                                        ++errors;
                    352:                                for (i = 1;
                    353:                                     i < host -> client_identifier.len; i++) {
                    354:                                        errno = 0;
                    355:                                        fprintf (db_file, ":%2.2x",
                    356:                                                 host ->
                    357:                                                 client_identifier.data [i]);
                    358:                                        if (errno)
                    359:                                                ++errors;
                    360:                                }
                    361: 
                    362:                                 errno = 0;
                    363:                                fputc (';', db_file);
                    364:                                if (errno)
                    365:                                        ++errors;
                    366:                        }
                    367:                }
                    368:                
                    369:                memset (&ip_addrs, 0, sizeof ip_addrs);
                    370:                if (host -> fixed_addr &&
                    371:                    evaluate_option_cache (&ip_addrs, (struct packet *)0,
                    372:                                           (struct lease *)0,
                    373:                                           (struct client_state *)0,
                    374:                                           (struct option_state *)0,
                    375:                                           (struct option_state *)0,
                    376:                                           &global_scope,
                    377:                                           host -> fixed_addr, MDL)) {
                    378:                
                    379:                        errno = 0;
                    380:                        fprintf (db_file, "\n  fixed-address ");
                    381:                        if (errno)
                    382:                                ++errors;
                    383:                        for (i = 0; i < ip_addrs.len - 3; i += 4) {
                    384: 
                    385:                                errno = 0;
                    386:                                fprintf (db_file, "%u.%u.%u.%u%s",
                    387:                                         ip_addrs.data [i] & 0xff,
                    388:                                         ip_addrs.data [i + 1] & 0xff,
                    389:                                         ip_addrs.data [i + 2] & 0xff,
                    390:                                         ip_addrs.data [i + 3] & 0xff,
                    391:                                         i + 7 < ip_addrs.len ? "," : "");
                    392:                                if (errno)
                    393:                                        ++errors;
                    394:                        }
                    395: 
                    396:                        errno = 0;
                    397:                        fputc (';', db_file);
                    398:                        if (errno)
                    399:                                ++errors;
                    400:                }
                    401: 
                    402:                if (host -> named_group) {
                    403:                        errno = 0;
                    404:                        fprintf (db_file, "\n  group \"%s\";",
                    405:                                 host -> named_group -> name);
                    406:                        if (errno)
                    407:                                ++errors;
                    408:                }
                    409: 
                    410:                if (host -> group &&
                    411:                    (!host -> named_group ||
                    412:                     host -> group != host -> named_group -> group) &&
                    413:                    host -> group != root_group) {
                    414:                        errno = 0;
                    415:                        write_statements (db_file,
                    416:                                          host -> group -> statements, 8);
                    417:                        if (errno)
                    418:                                ++errors;
                    419:                }
                    420:        }
                    421: 
                    422:        errno = 0;
                    423:        fputs ("\n}\n", db_file);
                    424:        if (errno)
                    425:                ++errors;
                    426: 
                    427:        if (errors) {
                    428:                log_info ("write_host: unable to write host %s",
                    429:                          host -> name);
                    430:                lease_file_is_corrupt = 1;
                    431:        }
                    432: 
                    433:        return !errors;
                    434: }
                    435: 
                    436: int write_group (group)
                    437:        struct group_object *group;
                    438: {
                    439:        int errors = 0;
                    440: 
                    441:        /* If the lease file is corrupt, don't try to write any more leases
                    442:           until we've written a good lease file. */
                    443:        if (lease_file_is_corrupt)
                    444:                if (!new_lease_file ())
                    445:                        return 0;
                    446: 
                    447:        if (!db_printable((unsigned char *)group->name))
                    448:                return 0;
                    449: 
                    450:        if (counting)
                    451:                ++count;
                    452: 
                    453:        errno = 0;
                    454:        fprintf (db_file, "group %s {", group -> name);
                    455:        if (errno)
                    456:                ++errors;
                    457: 
                    458:        if (group -> flags & GROUP_OBJECT_DYNAMIC) {
                    459:                errno = 0;
                    460:                fprintf (db_file, "\n  dynamic;");
                    461:                if (errno)
                    462:                        ++errors;
                    463:        }
                    464: 
                    465:        if (group -> flags & GROUP_OBJECT_STATIC) {
                    466:                errno = 0;
                    467:                fprintf (db_file, "\n  static;");
                    468:                if (errno)
                    469:                        ++errors;
                    470:        }
                    471: 
                    472:        if (group -> flags & GROUP_OBJECT_DELETED) {
                    473:                errno = 0;
                    474:                fprintf (db_file, "\n  deleted;");
                    475:                if (errno)
                    476:                        ++errors;
                    477:        } else {
                    478:                if (group -> group) {
                    479:                        errno = 0;
                    480:                        write_statements (db_file,
                    481:                                          group -> group -> statements, 8);
                    482:                        if (errno)
                    483:                                ++errors;
                    484:                }
                    485:        }
                    486: 
                    487:        errno = 0;
                    488:        fputs ("\n}\n", db_file);
                    489:        if (errno)
                    490:                ++errors;
                    491: 
                    492:        if (errors) {
                    493:                log_info ("write_group: unable to write group %s",
                    494:                          group -> name);
                    495:                lease_file_is_corrupt = 1;
                    496:        }
                    497: 
                    498:        return !errors;
                    499: }
                    500: 
                    501: /*
                    502:  * Write an IA and the options it has.
                    503:  */
                    504: int
                    505: write_ia(const struct ia_xx *ia) {
                    506:        struct iasubopt *iasubopt;
                    507:        struct binding *bnd;
                    508:        int i;
                    509:        char addr_buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff.255.255.255.255")];
                    510:        const char *binding_state;
                    511:        const char *tval;
                    512:        char *s;
                    513:        int fprintf_ret;
                    514: 
                    515:        /* 
                    516:         * If the lease file is corrupt, don't try to write any more 
                    517:         * leases until we've written a good lease file. 
                    518:         */
                    519:        if (lease_file_is_corrupt) {
                    520:                if (!new_lease_file()) {
                    521:                        return 0;
                    522:                }
                    523:        }
                    524: 
                    525:        if (counting) {
                    526:                ++count;
                    527:        }
                    528: 
                    529:        
                    530:        s = quotify_buf(ia->iaid_duid.data, ia->iaid_duid.len, MDL);
                    531:        if (s == NULL) {
                    532:                goto error_exit;
                    533:        }
                    534:        switch (ia->ia_type) {
                    535:        case D6O_IA_NA:
                    536:                fprintf_ret = fprintf(db_file, "ia-na \"%s\" {\n", s);
                    537:                break;
                    538:        case D6O_IA_TA:
                    539:                fprintf_ret = fprintf(db_file, "ia-ta \"%s\" {\n", s);
                    540:                break;
                    541:        case D6O_IA_PD:
                    542:                fprintf_ret = fprintf(db_file, "ia-pd \"%s\" {\n", s);
                    543:                break;
                    544:        default:
                    545:                log_error("Unknown ia type %u for \"%s\" at %s:%d",
                    546:                          (unsigned)ia->ia_type, s, MDL);
                    547:                fprintf_ret = -1;
                    548:        }
                    549:        dfree(s, MDL);
                    550:        if (fprintf_ret < 0) {
                    551:                goto error_exit;
                    552:        }
                    553:        if (ia->cltt != MIN_TIME) {
                    554:                tval = print_time(ia->cltt);
                    555:                if (tval == NULL) {
                    556:                        goto error_exit;
                    557:                }
                    558:                if (fprintf(db_file, "  cltt %s\n", tval) < 0) {
                    559:                        goto error_exit;
                    560:                }
                    561:        }
                    562:        for (i=0; i<ia->num_iasubopt; i++) {
                    563:                iasubopt = ia->iasubopt[i];
                    564: 
                    565:                inet_ntop(AF_INET6, &iasubopt->addr,
                    566:                          addr_buf, sizeof(addr_buf));
                    567:                if ((ia->ia_type != D6O_IA_PD) &&
                    568:                    (fprintf(db_file, "  iaaddr %s {\n", addr_buf) < 0)) {
                    569:                        goto error_exit;
                    570:                }
                    571:                if ((ia->ia_type == D6O_IA_PD) &&
                    572:                    (fprintf(db_file, "  iaprefix %s/%d {\n",
                    573:                             addr_buf, (int)iasubopt->plen) < 0)) {
                    574:                        goto error_exit;
                    575:                }
                    576:                if ((iasubopt->state <= 0) || (iasubopt->state > FTS_LAST)) {
                    577:                        log_fatal("Unknown iasubopt state %d at %s:%d", 
                    578:                                  iasubopt->state, MDL);
                    579:                }
                    580:                binding_state = binding_state_names[iasubopt->state-1];
                    581:                if (fprintf(db_file, "    binding state %s;\n", 
                    582:                            binding_state) < 0) {
                    583:                        goto error_exit;
                    584:                }
                    585:                if (fprintf(db_file, "    preferred-life %u;\n",
                    586:                            (unsigned)iasubopt->prefer) < 0) {
                    587:                        goto error_exit;
                    588:                }
                    589:                if (fprintf(db_file, "    max-life %u;\n",
                    590:                            (unsigned)iasubopt->valid) < 0) {
                    591:                        goto error_exit;
                    592:                }
                    593: 
                    594:                /* Note that from here on out, the \n is prepended to the
                    595:                 * next write, rather than appended to the current write.
                    596:                 */
                    597:                if ((iasubopt->state == FTS_ACTIVE) ||
                    598:                    (iasubopt->state == FTS_ABANDONED) ||
                    599:                    (iasubopt->hard_lifetime_end_time != 0)) {
                    600:                        tval = print_time(iasubopt->hard_lifetime_end_time);
                    601:                } else {
                    602:                        tval = print_time(iasubopt->soft_lifetime_end_time);
                    603:                }
                    604:                if (tval == NULL) {
                    605:                        goto error_exit;
                    606:                }
                    607:                if (fprintf(db_file, "    ends %s", tval) < 0) {
                    608:                        goto error_exit;
                    609:                }
                    610: 
                    611:                /* Write out any binding scopes: note that 'ends' above does
                    612:                 * not have \n on the end!  We want that.
                    613:                 */
                    614:                if (iasubopt->scope != NULL)
                    615:                        bnd = iasubopt->scope->bindings;
                    616:                else
                    617:                        bnd = NULL;
                    618: 
                    619:                for (; bnd != NULL ; bnd = bnd->next) {
                    620:                        if (bnd->value == NULL)
                    621:                                continue;
                    622: 
                    623:                        /* We don't do a regular error_exit because the
                    624:                         * lease db is not corrupt in this case.
                    625:                         */
                    626:                        if (write_binding_scope(db_file, bnd,
                    627:                                                "\n    ") != ISC_R_SUCCESS)
                    628:                                goto error_exit;
                    629:                                
                    630:                }
                    631: 
                    632:                if (fprintf(db_file, "\n  }\n") < 0)
                    633:                         goto error_exit;
                    634:        }
                    635:        if (fprintf(db_file, "}\n\n") < 0)
                    636:                 goto error_exit;
                    637: 
                    638:        fflush(db_file);
                    639:        return 1;
                    640: 
                    641: error_exit:
                    642:        log_info("write_ia: unable to write ia");
                    643:        lease_file_is_corrupt = 1;
                    644:        return 0;
                    645: }
                    646: 
                    647: #ifdef DHCPv6
                    648: /*
                    649:  * Put a copy of the server DUID in the leases file.
                    650:  */
                    651: int
                    652: write_server_duid(void) {
                    653:        struct data_string server_duid;
                    654:        char *s;
                    655:        int fprintf_ret;
                    656: 
                    657:        /*
                    658:         * Only write the DUID if it's been set.
                    659:         */
                    660:        if (!server_duid_isset()) {
                    661:                return 1;
                    662:        }
                    663: 
                    664:        /* 
                    665:         * If the lease file is corrupt, don't try to write any more 
                    666:         * leases until we've written a good lease file. 
                    667:         */
                    668:        if (lease_file_is_corrupt) {
                    669:                if (!new_lease_file()) {
                    670:                        return 0;
                    671:                }
                    672:        }
                    673: 
                    674:        /*
                    675:         * Get a copy of our server DUID and convert to a quoted string.
                    676:         */
                    677:        memset(&server_duid, 0, sizeof(server_duid));
                    678:        copy_server_duid(&server_duid, MDL);
                    679:        s = quotify_buf(server_duid.data, server_duid.len, MDL);
                    680:        data_string_forget(&server_duid, MDL);
                    681:        if (s == NULL) {
                    682:                goto error_exit;
                    683:        }
                    684: 
                    685:        /*
                    686:         * Write to the leases file.
                    687:         */
                    688:        fprintf_ret = fprintf(db_file, "server-duid \"%s\";\n\n", s);
                    689:        dfree(s, MDL);
                    690:        if (fprintf_ret < 0) {
                    691:                goto error_exit;
                    692:        }
                    693: 
                    694:        /*
                    695:         * Check if we actually managed to write.
                    696:         */
                    697:        fflush(db_file);
                    698:        return 1;
                    699: 
                    700: error_exit:
                    701:        log_info("write_server_duid: unable to write server-duid");
                    702:        lease_file_is_corrupt = 1;
                    703:        return 0;
                    704: }
                    705: #endif /* DHCPv6 */
                    706: 
                    707: #if defined (FAILOVER_PROTOCOL)
                    708: int write_failover_state (dhcp_failover_state_t *state)
                    709: {
                    710:        int errors = 0;
                    711:        const char *tval;
                    712: 
                    713:        if (lease_file_is_corrupt)
                    714:                if (!new_lease_file ())
                    715:                        return 0;
                    716: 
                    717:        errno = 0;
                    718:        fprintf (db_file, "\nfailover peer \"%s\" state {", state -> name);
                    719:        if (errno)
                    720:                ++errors;
                    721: 
                    722:        tval = print_time(state->me.stos);
                    723:        if (tval == NULL ||
                    724:            fprintf(db_file, "\n  my state %s at %s",
                    725:                    (state->me.state == startup) ?
                    726:                    dhcp_failover_state_name_print(state->saved_state) :
                    727:                    dhcp_failover_state_name_print(state->me.state),
                    728:                    tval) < 0)
                    729:                ++errors;
                    730: 
                    731:        tval = print_time(state->partner.stos);
                    732:        if (tval == NULL ||
                    733:            fprintf(db_file, "\n  partner state %s at %s",
                    734:                    dhcp_failover_state_name_print(state->partner.state),
                    735:                    tval) < 0)
                    736:                ++errors;
                    737: 
                    738:        if (state -> i_am == secondary) {
                    739:                errno = 0;
                    740:                fprintf (db_file, "\n  mclt %ld;",
                    741:                         (unsigned long)state -> mclt);
                    742:                if (errno)
                    743:                        ++errors;
                    744:        }
                    745: 
                    746:         errno = 0;
                    747:        fprintf (db_file, "\n}\n");
                    748:        if (errno)
                    749:                ++errors;
                    750: 
                    751:        if (errors) {
                    752:                log_info ("write_failover_state: unable to write state %s",
                    753:                          state -> name);
                    754:                lease_file_is_corrupt = 1;
                    755:                return 0;
                    756:        }
                    757: 
                    758:        return 1;
                    759: 
                    760: }
                    761: #endif
                    762: 
                    763: int db_printable (s)
                    764:        const unsigned char *s;
                    765: {
                    766:        int i;
                    767:        for (i = 0; s [i]; i++)
                    768:                if (!isascii (s [i]) || !isprint (s [i])
                    769:                    || s [i] == '"' || s [i] == '\\')
                    770:                        return 0;
                    771:        return 1;
                    772: }
                    773: 
                    774: int db_printable_len (s, len)
                    775:        const unsigned char *s;
                    776:        unsigned len;
                    777: {
                    778:        int i;
                    779: 
                    780:        for (i = 0; i < len; i++)
                    781:                if (!isascii (s [i]) || !isprint (s [i]) ||
                    782:                    s [i] == '"' || s [i] == '\\')
                    783:                        return 0;
                    784:        return 1;
                    785: }
                    786: 
                    787: static int print_hash_string(FILE *fp, struct class *class)
                    788: {
                    789:        int i;
                    790: 
                    791:        for (i = 0 ; i < class->hash_string.len ; i++)
                    792:                if (!isascii(class->hash_string.data[i]) ||
                    793:                    !isprint(class->hash_string.data[i]))
                    794:                        break;
                    795: 
                    796:        if (i == class->hash_string.len) {
                    797:                if (fprintf(fp, " \"%.*s\"", (int)class->hash_string.len,
                    798:                            class->hash_string.data) <= 0) {
                    799:                        log_error("Failure writing hash string: %m");
                    800:                        return 0;
                    801:                }
                    802:        } else {
                    803:                if (fprintf(fp, " %2.2x", class->hash_string.data[0]) <= 0) {
                    804:                        log_error("Failure writing hash string: %m");
                    805:                        return 0;
                    806:                }
                    807:                for (i = 1 ; i < class->hash_string.len ; i++) {
                    808:                        if (fprintf(fp, ":%2.2x",
                    809:                                    class->hash_string.data[i]) <= 0) {
                    810:                                log_error("Failure writing hash string: %m");
                    811:                                return 0;
                    812:                        }
                    813:                }
                    814:        }
                    815: 
                    816:        return 1;
                    817: }
                    818: 
                    819: 
                    820: isc_result_t
                    821: write_named_billing_class(const void *key, unsigned len, void *object)
                    822: {
                    823:        const unsigned char *name = key;
                    824:        struct class *class = object;
                    825: 
                    826:        if (class->flags & CLASS_DECL_DYNAMIC) {
                    827:                numclasseswritten++;
                    828:                if (class->superclass == 0) {
                    829:                        if (fprintf(db_file, "class \"%s\" {\n", name) <= 0)
                    830:                                return ISC_R_IOERROR;
                    831:                } else {
                    832:                        if (fprintf(db_file, "subclass \"%s\"",
                    833:                                    class->superclass->name) <= 0)
                    834:                                return ISC_R_IOERROR;
                    835:                        if (!print_hash_string(db_file, class))
                    836:                                return ISC_R_IOERROR;
                    837:                        if (fprintf(db_file, " {\n") <= 0)
                    838:                                return ISC_R_IOERROR;
                    839:                }
                    840: 
                    841:                if ((class->flags & CLASS_DECL_DELETED) != 0) {
                    842:                        if (fprintf(db_file, "  deleted;\n") <= 0)
                    843:                                return ISC_R_IOERROR;
                    844:                } else {
                    845:                        if (fprintf(db_file, "  dynamic;\n") <= 0)
                    846:                                return ISC_R_IOERROR;
                    847:                }
                    848:        
                    849:                if (class->lease_limit > 0) {
                    850:                        if (fprintf(db_file, "  lease limit %d;\n",
                    851:                                    class->lease_limit) <= 0)
                    852:                                return ISC_R_IOERROR;
                    853:                }
                    854: 
                    855:                if (class->expr != 0) {
                    856:                        if (fprintf(db_file, "  match if ") <= 0)
                    857:                                return ISC_R_IOERROR;
                    858: 
                    859:                         errno = 0;                                       
                    860:                        write_expression(db_file, class->expr, 5, 5, 0);
                    861:                         if (errno)
                    862:                                 return ISC_R_IOERROR;
                    863: 
                    864:                        if (fprintf(db_file, ";\n") <= 0)
                    865:                                return ISC_R_IOERROR;
                    866:                }
                    867: 
                    868:                if (class->submatch != 0) {
                    869:                        if (class->spawning) {
                    870:                                if (fprintf(db_file, "  spawn ") <= 0)
                    871:                                        return ISC_R_IOERROR;
                    872:                        } else {
                    873:                                if (fprintf(db_file, "  match ") <= 0)
                    874:                                        return ISC_R_IOERROR;
                    875:                        }
                    876: 
                    877:                         errno = 0;
                    878:                        write_expression(db_file, class->submatch, 5, 5, 0);
                    879:                         if (errno)
                    880:                                 return ISC_R_IOERROR;
                    881: 
                    882:                        if (fprintf(db_file, ";\n") <= 0)
                    883:                                return ISC_R_IOERROR;
                    884:                }
                    885:        
                    886:                if (class->statements != 0) {
                    887:                         errno = 0;
                    888:                        write_statements(db_file, class->statements, 8);
                    889:                         if (errno)
                    890:                                 return ISC_R_IOERROR;
                    891:                }
                    892: 
                    893:                /* XXXJAB this isn't right, but classes read in off the
                    894:                   leases file don't get the root group assigned to them
                    895:                   (due to clone_group() call). */
                    896:                if (class->group != 0 && class->group->authoritative != 0) {
                    897:                         errno = 0;
                    898:                        write_statements(db_file, class->group->statements, 8);
                    899:                         if (errno)
                    900:                                 return ISC_R_IOERROR;
                    901:                 }
                    902: 
                    903:                if (fprintf(db_file, "}\n\n") <= 0)
                    904:                        return ISC_R_IOERROR;
                    905:        }
                    906: 
                    907:        if (class->hash != NULL) {      /* yep. recursive. god help us. */
                    908:                /* XXX - cannot check error status of this...
                    909:                 * foo_hash_foreach returns a count of operations completed.
                    910:                 */
                    911:                class_hash_foreach(class->hash, write_named_billing_class);
                    912:        }
                    913: 
                    914:        return ISC_R_SUCCESS;
                    915: }
                    916: 
                    917: void write_billing_classes ()
                    918: {
                    919:        struct collection *lp;
                    920:        struct class *cp;
                    921: 
                    922:        for (lp = collections; lp; lp = lp -> next) {
                    923:            for (cp = lp -> classes; cp; cp = cp -> nic) {
                    924:                if (cp -> spawning && cp -> hash) {
                    925:                    class_hash_foreach (cp -> hash, write_named_billing_class);
                    926:                }
                    927:            }
                    928:        }
                    929: }
                    930: 
                    931: /* Write a spawned class to the database file. */
                    932: 
                    933: int write_billing_class (class)
                    934:        struct class *class;
                    935: {
                    936:        int errors = 0;
                    937: 
                    938:        if (lease_file_is_corrupt)
                    939:                if (!new_lease_file ())
                    940:                        return 0;
                    941: 
                    942:        if (!class -> superclass) {
                    943:                errno = 0;
                    944:                fprintf (db_file, "\n  billing class \"%s\";", class -> name);
                    945:                return !errno;
                    946:        }
                    947: 
                    948:        if (fprintf(db_file, "\n  billing subclass \"%s\"",
                    949:                    class -> superclass -> name) < 0)
                    950:                ++errors;
                    951: 
                    952:        if (!print_hash_string(db_file, class))
                    953:                 ++errors;
                    954: 
                    955:        if (fprintf(db_file, ";") < 0)
                    956:                 ++errors;
                    957: 
                    958:        class -> dirty = !errors;
                    959:        if (errors)
                    960:                lease_file_is_corrupt = 1;
                    961: 
                    962:        return !errors;
                    963: }
                    964: 
                    965: /* Commit leases after a timeout. */
                    966: void commit_leases_timeout (void *foo)
                    967: {
                    968:        commit_leases ();
                    969: }
                    970: 
                    971: /* Commit any leases that have been written out... */
                    972: 
                    973: int commit_leases ()
                    974: {
                    975:        /* Commit any outstanding writes to the lease database file.
                    976:           We need to do this even if we're rewriting the file below,
                    977:           just in case the rewrite fails. */
                    978:        if (fflush (db_file) == EOF) {
                    979:                log_info ("commit_leases: unable to commit: %m");
                    980:                return 0;
                    981:        }
                    982:        if (fsync (fileno (db_file)) < 0) {
                    983:                log_info ("commit_leases: unable to commit: %m");
                    984:                return 0;
                    985:        }
                    986: 
                    987:        /* send out all deferred ACKs now */
                    988:        flush_ackqueue(NULL);
                    989: 
                    990:        /* If we haven't rewritten the lease database in over an
                    991:           hour, rewrite it now.  (The length of time should probably
                    992:           be configurable. */
1.1.1.1 ! misho     993:        if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) {
1.1       misho     994:                count = 0;
                    995:                write_time = cur_time;
                    996:                new_lease_file ();
                    997:        }
                    998:        return 1;
                    999: }
                   1000: 
1.1.1.1 ! misho    1001: /*
        !          1002:  * rewrite the lease file about once an hour
        !          1003:  * This is meant as a quick patch for ticket 24887.  It allows
        !          1004:  * us to rotate the v6 lease file without adding too many fsync()
        !          1005:  * calls.  In the future wes should revisit this area and add
        !          1006:  * something similar to the delayed ack code for v4.
        !          1007:  */
        !          1008: int commit_leases_timed()
        !          1009: {
        !          1010:        if ((count != 0) && (cur_time - write_time > LEASE_REWRITE_PERIOD)) {
        !          1011:                return (commit_leases());
        !          1012:        }
        !          1013:        return (1);
        !          1014: }
        !          1015: 
1.1       misho    1016: void db_startup (testp)
                   1017:        int testp;
                   1018: {
                   1019:        isc_result_t status;
                   1020: 
                   1021: #if defined (TRACING)
                   1022:        if (!trace_playback ()) {
                   1023: #endif
                   1024:                /* Read in the existing lease file... */
                   1025:                status = read_conf_file (path_dhcpd_db,
                   1026:                                         (struct group *)0, 0, 1);
1.1.1.1 ! misho    1027:                if (status != ISC_R_SUCCESS) {
        !          1028:                        /* XXX ignore status? */
        !          1029:                        ;
        !          1030:                }
        !          1031: 
1.1       misho    1032: #if defined (TRACING)
                   1033:        }
                   1034: #endif
                   1035: 
                   1036: #if defined (TRACING)
                   1037:        /* If we're playing back, there is no lease file, so we can't
                   1038:           append it, so we create one immediately (maybe this isn't
                   1039:           the best solution... */
                   1040:        if (trace_playback ()) {
                   1041:                new_lease_file ();
                   1042:        }
                   1043: #endif
                   1044:        if (!testp) {
                   1045:                db_file = fopen (path_dhcpd_db, "a");
                   1046:                if (!db_file)
                   1047:                        log_fatal ("Can't open %s for append.", path_dhcpd_db);
                   1048:                expire_all_pools ();
                   1049: #if defined (TRACING)
                   1050:                if (trace_playback ())
                   1051:                        write_time = cur_time;
                   1052:                else
                   1053: #endif
                   1054:                        time(&write_time);
                   1055:                new_lease_file ();
                   1056:        }
                   1057: 
                   1058: #if defined(REPORT_HASH_PERFORMANCE)
                   1059:        log_info("Host HW hash:   %s", host_hash_report(host_hw_addr_hash));
                   1060:        log_info("Host UID hash:  %s", host_hash_report(host_uid_hash));
                   1061:        log_info("Lease IP hash:  %s",
                   1062:                 lease_ip_hash_report(lease_ip_addr_hash));
                   1063:        log_info("Lease UID hash: %s", lease_id_hash_report(lease_uid_hash));
                   1064:        log_info("Lease HW hash:  %s",
                   1065:                 lease_id_hash_report(lease_hw_addr_hash));
                   1066: #endif
                   1067: }
                   1068: 
                   1069: int new_lease_file ()
                   1070: {
                   1071:        char newfname [512];
                   1072:        char backfname [512];
                   1073:        TIME t;
                   1074:        int db_fd;
                   1075:        int db_validity;
                   1076:        FILE *new_db_file;
                   1077: 
                   1078:        /* Make a temporary lease file... */
                   1079:        time(&t);
                   1080: 
                   1081:        db_validity = lease_file_is_corrupt;
                   1082: 
                   1083:        /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
                   1084:         * This should never happen since the path is a configuration
                   1085:         * variable from build-time or command-line.  But if it should,
                   1086:         * either by malice or ignorance, we panic, since the potential
                   1087:         * for havoc is high.
                   1088:         */
                   1089:        if (snprintf (newfname, sizeof newfname, "%s.%d",
                   1090:                     path_dhcpd_db, (int)t) >= sizeof newfname)
                   1091:                log_fatal("new_lease_file: lease file path too long");
                   1092: 
                   1093:        db_fd = open (newfname, O_WRONLY | O_TRUNC | O_CREAT, 0664);
                   1094:        if (db_fd < 0) {
                   1095:                log_error ("Can't create new lease file: %m");
                   1096:                return 0;
                   1097:        }
                   1098:        if ((new_db_file = fdopen(db_fd, "w")) == NULL) {
                   1099:                log_error("Can't fdopen new lease file: %m");
                   1100:                close(db_fd);
                   1101:                goto fdfail;
                   1102:        }
                   1103: 
                   1104:        /* Close previous database, if any. */
                   1105:        if (db_file)
                   1106:                fclose(db_file);
                   1107:        db_file = new_db_file;
                   1108: 
                   1109:        errno = 0;
                   1110:        fprintf (db_file, "# The format of this file is documented in the %s",
                   1111:                 "dhcpd.leases(5) manual page.\n");
                   1112:        if (errno)
                   1113:                goto fail;
                   1114: 
                   1115:        fprintf (db_file, "# This lease file was written by isc-dhcp-%s\n\n",
                   1116:                 PACKAGE_VERSION);
                   1117:        if (errno)
                   1118:                goto fail;
                   1119: 
                   1120:        /* At this point we have a new lease file that, so far, could not
                   1121:         * be described as either corrupt nor valid.
                   1122:         */
                   1123:        lease_file_is_corrupt = 0;
                   1124: 
                   1125:        /* Write out all the leases that we know of... */
                   1126:        counting = 0;
                   1127:        if (!write_leases ())
                   1128:                goto fail;
                   1129: 
                   1130: #if defined (TRACING)
                   1131:        if (!trace_playback ()) {
                   1132: #endif
                   1133:            /* %Audit% Truncated filename causes panic. %2004.06.17,Safe%
                   1134:             * This should never happen since the path is a configuration
                   1135:             * variable from build-time or command-line.  But if it should,
                   1136:             * either by malice or ignorance, we panic, since the potential
                   1137:             * for havoc is too high.
                   1138:             */
                   1139:            if (snprintf (backfname, sizeof backfname, "%s~", path_dhcpd_db)
                   1140:                        >= sizeof backfname)
                   1141:                log_fatal("new_lease_file: backup lease file path too long");
                   1142: 
                   1143:            /* Get the old database out of the way... */
                   1144:            if (unlink (backfname) < 0 && errno != ENOENT) {
                   1145:                log_error ("Can't remove old lease database backup %s: %m",
                   1146:                           backfname);
                   1147:                goto fail;
                   1148:            }
                   1149:            if (link(path_dhcpd_db, backfname) < 0) {
                   1150:                if (errno == ENOENT) {
                   1151:                        log_error("%s is missing - no lease db to backup.",
                   1152:                                  path_dhcpd_db);
                   1153:                } else {
                   1154:                        log_error("Can't backup lease database %s to %s: %m",
                   1155:                                  path_dhcpd_db, backfname);
                   1156:                        goto fail;
                   1157:                }
                   1158:            }
                   1159: #if defined (TRACING)
                   1160:        }
                   1161: #endif
                   1162:        
                   1163:        /* Move in the new file... */
                   1164:        if (rename (newfname, path_dhcpd_db) < 0) {
                   1165:                log_error ("Can't install new lease database %s to %s: %m",
                   1166:                           newfname, path_dhcpd_db);
                   1167:                goto fail;
                   1168:        }
                   1169: 
                   1170:        counting = 1;
                   1171:        return 1;
                   1172: 
                   1173:       fail:
                   1174:        lease_file_is_corrupt = db_validity;
                   1175:       fdfail:
                   1176:        unlink (newfname);
                   1177:        return 0;
                   1178: }
                   1179: 
                   1180: int group_writer (struct group_object *group)
                   1181: {
                   1182:        if (!write_group (group))
                   1183:                return 0;
                   1184:        if (!commit_leases ())
                   1185:                return 0;
                   1186:        return 1;
                   1187: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>