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

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

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