1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (C) 1996-2009 by Andrew Church <achurch@achurch.org>
5 * Copyright (c) 2012-2021 ircd-hybrid development team
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 */
22
23 /*! \file conf_db.c
24 * \brief Includes file utilities for database handling
25 * \version $Id: conf_db.c 9858 2021-01-01 04:43:42Z michael $
26 */
27
28
29 #include "stdinc.h"
30 #include "conf.h"
31 #include "conf_db.h"
32 #include "conf_gecos.h"
33 #include "conf_resv.h"
34 #include "memory.h"
35 #include "log.h"
36 #include "send.h"
37 #include "irc_string.h"
38 #include "hostmask.h"
39
40
41 /*! \brief Return the version number on the file. Return 0 if there is no version
42 * number or the number doesn't make sense (i.e. less than 1 or greater
43 * than FILE_VERSION).
44 *
45 * \param f dbFile Struct Member
46 * \return int 0 if failure, 1 > is the version number
47 */
48 static uint32_t
get_file_version(struct dbFILE * f)49 get_file_version(struct dbFILE *f)
50 {
51 uint32_t version = 0;
52
53 if (read_uint32(&version, f) == false)
54 {
55 ilog(LOG_TYPE_IRCD, "Error reading version number on %s: %s",
56 f->filename, strerror(errno));
57 return 0;
58 }
59
60 if (version < 1)
61 {
62 ilog(LOG_TYPE_IRCD, "Invalid version number (%u) on %s",
63 version, f->filename);
64 return 0;
65 }
66
67 return version;
68 }
69
70 /*! \brief Write the current version number to the file.
71 * \param f dbFile Struct Member
72 * \param version Database version
73 * \return false on error, true on success.
74 */
75 static int
write_file_version(struct dbFILE * f,uint32_t version)76 write_file_version(struct dbFILE *f, uint32_t version)
77 {
78 if (write_uint32(version, f) == false)
79 {
80 ilog(LOG_TYPE_IRCD, "Error writing version number on %s",
81 f->filename);
82 return false;
83 }
84
85 return true;
86 }
87
88 /*! \brief Open the database for reading
89 * \param filename File to open as the database
90 * \return dbFile struct
91 */
92 static struct dbFILE *
open_db_read(const char * filename)93 open_db_read(const char *filename)
94 {
95 struct dbFILE *f = xcalloc(sizeof(*f));
96
97 strlcpy(f->filename, filename, sizeof(f->filename));
98
99 f->mode = 'r';
100 f->fp = fopen(f->filename, "rb");
101
102 if (f->fp == NULL)
103 {
104 int errno_save = errno;
105
106 if (errno != ENOENT)
107 ilog(LOG_TYPE_IRCD, "Cannot read database file %s", f->filename);
108
109 xfree(f);
110 errno = errno_save;
111 return NULL;
112 }
113
114 return f;
115 }
116
117 /*! \brief Open the database for writting
118 * \param filename File to open as the database
119 * \param version Database version
120 * \return dbFile struct
121 */
122 static struct dbFILE *
open_db_write(const char * filename,uint32_t version)123 open_db_write(const char *filename, uint32_t version)
124 {
125 struct dbFILE *f = xcalloc(sizeof(*f));
126
127 strlcpy(f->filename, filename, sizeof(f->filename));
128
129 filename = f->filename;
130 f->mode = 'w';
131
132 snprintf(f->tempname, sizeof(f->tempname), "%s.new", filename);
133
134 if (f->tempname[0] == '\0' || strcmp(f->tempname, filename) == 0)
135 {
136 ilog(LOG_TYPE_IRCD, "Opening database file %s for write: Filename too long",
137 filename);
138 xfree(f);
139 errno = ENAMETOOLONG;
140 return NULL;
141 }
142
143 remove(f->tempname);
144
145 /* Use open() to avoid people sneaking a new file in under us */
146 /*
147 * TBD: replace with C11 fopen "x" mode
148 */
149 int fd = open(f->tempname, O_WRONLY | O_CREAT | O_EXCL, 0666);
150 if (fd >= 0)
151 f->fp = fdopen(fd, "wb");
152
153 if (f->fp == NULL || write_file_version(f, version) == false)
154 {
155 int errno_save = errno;
156 static bool walloped = false;
157
158 if (walloped == false)
159 {
160 walloped = true;
161 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
162 "Cannot create temporary database file %s",
163 f->tempname);
164 }
165
166 errno = errno_save;
167 ilog(LOG_TYPE_IRCD, "Cannot create temporary database file %s",
168 f->tempname);
169
170 if (f->fp)
171 fclose(f->fp);
172
173 remove(f->tempname);
174 xfree(f);
175
176 errno = errno_save;
177 return NULL;
178 }
179
180 return f;
181 }
182
183 /*! \brief Open a database file for reading (*mode == 'r') or writing (*mode == 'w').
184 * Return the stream pointer, or NULL on error. When opening for write, the
185 * file actually opened is a temporary file, which will be renamed to the
186 * original file on close.
187 *
188 * `version' is only used when opening a file for writing, and indicates the
189 * version number to write to the file.
190 *
191 * \param filename File to open as the database
192 * \param mode Mode for writting or reading
193 * \param version Database version
194 * \return dbFile struct
195 */
196 static struct dbFILE *
open_db(const char * filename,const char * mode,uint32_t version)197 open_db(const char *filename, const char *mode, uint32_t version)
198 {
199 switch (*mode)
200 {
201 case 'r':
202 return open_db_read(filename);
203 break;
204 case 'w':
205 return open_db_write(filename, version);
206 break;
207 default:
208 errno = EINVAL;
209 return NULL;
210 }
211 }
212
213 /*! \brief Restore the database file to its condition before open_db(). This is
214 * identical to close_db() for files open for reading; however, for files
215 * open for writing, we discard the new temporary file instead of renaming
216 * it over the old file. The value of errno is preserved.
217 *
218 * \param f dbFile struct
219 */
220 static void
restore_db(struct dbFILE * f)221 restore_db(struct dbFILE *f)
222 {
223 int errno_save = errno;
224
225 if (f->fp)
226 fclose(f->fp);
227 if (f->mode == 'w' && f->tempname[0])
228 remove(f->tempname);
229
230 xfree(f);
231 errno = errno_save;
232 }
233
234 /*! \brief Close a database file. If the file was opened for write, moves the new
235 * file over the old one, and logs/wallops an error message if the rename()
236 * fails.
237 *
238 * \param f dbFile struct
239 * \return false on error, true on success.
240 */
241 static bool
close_db(struct dbFILE * f)242 close_db(struct dbFILE *f)
243 {
244 if (f->fp == NULL)
245 {
246 errno = EINVAL;
247 return false;
248 }
249
250 int res = fclose(f->fp);
251 f->fp = NULL;
252
253 if (res)
254 return false;
255
256 if (f->mode == 'w' && f->tempname[0] && strcmp(f->tempname, f->filename))
257 {
258 if (rename(f->tempname, f->filename) < 0)
259 {
260 int errno_save = errno;
261
262 sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "Unable to move new "
263 "data to database file %s; new data NOT saved.",
264 f->filename);
265 errno = errno_save;
266 ilog(LOG_TYPE_IRCD, "Unable to move new data to database file %s; new "
267 "data NOT saved.", f->filename);
268 remove(f->tempname);
269 }
270 }
271
272 xfree(f);
273 return true;
274 }
275
276 /*
277 * Read and write 2-, 4- and 8-byte quantities, and strings. All multibyte
278 * values are stored in big-endian order (most significant byte first).
279 * A string is stored with a 2-byte unsigned length (including the trailing
280 * \0) first; a length of 0 indicates that the string pointer is NULL.
281 * Written strings are truncated silently at 4294967294 bytes, and are always
282 * null-terminated.
283 */
284
285 /*! \brief Read a unsigned 8bit integer
286 *
287 * \param ret 16bit integer to read
288 * \param f dbFile struct
289 * \return false on error, true otherwise.
290 */
291 bool
read_uint16(uint16_t * ret,struct dbFILE * f)292 read_uint16(uint16_t *ret, struct dbFILE *f)
293 {
294 int c1 = fgetc(f->fp);
295 int c2 = fgetc(f->fp);
296
297 if (c1 == EOF || c2 == EOF)
298 return false;
299
300 *ret = c1 << 8 | c2;
301 return true;
302 }
303
304 /*! \brief Write a unsigned 16bit integer
305 *
306 * \param val 16bit integer to write
307 * \param f dbFile struct
308 * \return false on error, true otherwise.
309 */
310 bool
write_uint16(uint16_t val,struct dbFILE * f)311 write_uint16(uint16_t val, struct dbFILE *f)
312 {
313 if (fputc((val >> 8) & 0xFF, f->fp) == EOF ||
314 fputc((val) & 0xFF, f->fp) == EOF)
315 return false;
316
317 return true;
318 }
319
320 /*! \brief Read a unsigned 32bit integer
321 *
322 * \param ret unsigned 32bit integer to read
323 * \param f dbFile struct
324 * \return false on error, true otherwise.
325 */
326 bool
read_uint32(uint32_t * ret,struct dbFILE * f)327 read_uint32(uint32_t *ret, struct dbFILE *f)
328 {
329 int c1 = fgetc(f->fp);
330 int c2 = fgetc(f->fp);
331 int c3 = fgetc(f->fp);
332 int c4 = fgetc(f->fp);
333
334 if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
335 return false;
336
337 *ret = c1 << 24 | c2 << 16 | c3 << 8 | c4;
338 return true;
339 }
340
341
342 /*! \brief Write a unsigned 32bit integer
343 *
344 * \param val unsigned 32bit integer to write
345 * \param f dbFile struct
346 * \return false on error, true otherwise.
347 */
348 bool
write_uint32(uint32_t val,struct dbFILE * f)349 write_uint32(uint32_t val, struct dbFILE *f)
350 {
351 if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
352 return false;
353 if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
354 return false;
355 if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
356 return false;
357 if (fputc((val) & 0xFF, f->fp) == EOF)
358 return false;
359 return true;
360 }
361
362 /*! \brief Read a unsigned 64bit integer
363 *
364 * \param ret unsigned 64bit integer to read
365 * \param f dbFile struct
366 * \return false on error, true otherwise.
367 */
368 bool
read_uint64(uint64_t * ret,struct dbFILE * f)369 read_uint64(uint64_t *ret, struct dbFILE *f)
370 {
371 int64_t c1 = fgetc(f->fp);
372 int64_t c2 = fgetc(f->fp);
373 int64_t c3 = fgetc(f->fp);
374 int64_t c4 = fgetc(f->fp);
375 int64_t c5 = fgetc(f->fp);
376 int64_t c6 = fgetc(f->fp);
377 int64_t c7 = fgetc(f->fp);
378 int64_t c8 = fgetc(f->fp);
379
380 if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF ||
381 c5 == EOF || c6 == EOF || c7 == EOF || c8 == EOF)
382 return false;
383
384 *ret = c1 << 56 | c2 << 48 | c3 << 40 | c4 << 32 |
385 c5 << 24 | c6 << 16 | c7 << 8 | c8;
386 return true;
387 }
388
389
390 /*! \brief Write a unsigned 64bit integer
391 *
392 * \param val unsigned 64bit integer to write
393 * \param f dbFile struct
394 * \return false on error, true otherwise.
395 */
396 bool
write_uint64(uint64_t val,struct dbFILE * f)397 write_uint64(uint64_t val, struct dbFILE *f)
398 {
399 if (fputc((val >> 56) & 0xFF, f->fp) == EOF)
400 return false;
401 if (fputc((val >> 48) & 0xFF, f->fp) == EOF)
402 return false;
403 if (fputc((val >> 40) & 0xFF, f->fp) == EOF)
404 return false;
405 if (fputc((val >> 32) & 0xFF, f->fp) == EOF)
406 return false;
407 if (fputc((val >> 24) & 0xFF, f->fp) == EOF)
408 return false;
409 if (fputc((val >> 16) & 0xFF, f->fp) == EOF)
410 return false;
411 if (fputc((val >> 8) & 0xFF, f->fp) == EOF)
412 return false;
413 if (fputc((val) & 0xFF, f->fp) == EOF)
414 return false;
415 return true;
416 }
417
418 /*! \brief Read String
419 *
420 * \param ret string
421 * \param f dbFile struct
422 * \return false on error, true otherwise.
423 */
424 bool
read_string(char ** ret,struct dbFILE * f)425 read_string(char **ret, struct dbFILE *f)
426 {
427 uint32_t len = 0;
428
429 if (read_uint32(&len, f) == false)
430 return false;
431
432 if (len == 0)
433 {
434 *ret = NULL;
435 return true;
436 }
437
438 char *s = xcalloc(len);
439 if (len != fread(s, 1, len, f->fp))
440 {
441 xfree(s);
442 return false;
443 }
444
445 *ret = s;
446 return true;
447 }
448
449 /*! \brief Write String
450 *
451 * \param s string
452 * \param f dbFile struct
453 * \return false on error, true otherwise.
454 */
455 bool
write_string(const char * s,struct dbFILE * f)456 write_string(const char *s, struct dbFILE *f)
457 {
458 if (s == NULL)
459 return write_uint32(0, f);
460
461 uint32_t len = strlen(s);
462 if (len > 4294967294)
463 len = 4294967294;
464 if (write_uint32(len + 1, f) == false)
465 return false;
466 if (len > 0 && fwrite(s, 1, len, f->fp) != len)
467 return false;
468 if (fputc(0, f->fp) == EOF)
469 return false;
470
471 return true;
472 }
473
474 #define SAFE_READ(x) do { \
475 if ((x) == false) { \
476 break; \
477 } \
478 } while (false)
479
480 #define SAFE_WRITE(x,db) do { \
481 if ((x) == false) { \
482 restore_db(f); \
483 ilog(LOG_TYPE_IRCD, "Write error on %s", db); \
484 return; \
485 } \
486 } while (false)
487
488 void
save_kline_database(const char * filename)489 save_kline_database(const char *filename)
490 {
491 uint32_t i = 0;
492 uint32_t records = 0;
493 struct dbFILE *f = NULL;
494 dlink_node *ptr = NULL;
495
496 if ((f = open_db(filename, "w", KLINE_DB_VERSION)) == NULL)
497 return;
498
499 for (i = 0; i < ATABLE_SIZE; ++i)
500 {
501 DLINK_FOREACH(ptr, atable[i].head)
502 {
503 struct AddressRec *arec = ptr->data;
504
505 if (arec->type == CONF_KLINE && IsConfDatabase(arec->conf))
506 ++records;
507 }
508 }
509
510 SAFE_WRITE(write_uint32(records, f), filename);
511
512 for (i = 0; i < ATABLE_SIZE; ++i)
513 {
514 DLINK_FOREACH(ptr, atable[i].head)
515 {
516 struct AddressRec *arec = ptr->data;
517
518 if (arec->type == CONF_KLINE && IsConfDatabase(arec->conf))
519 {
520 SAFE_WRITE(write_string(arec->conf->user, f), filename);
521 SAFE_WRITE(write_string(arec->conf->host, f), filename);
522 SAFE_WRITE(write_string(arec->conf->reason, f), filename);
523 SAFE_WRITE(write_uint64(arec->conf->setat, f), filename);
524 SAFE_WRITE(write_uint64(arec->conf->until, f), filename);
525 }
526 }
527 }
528
529 close_db(f);
530 }
531
532 void
load_kline_database(const char * filename)533 load_kline_database(const char *filename)
534 {
535 struct dbFILE *f = NULL;
536 struct MaskItem *conf = NULL;
537 char *field_1 = NULL;
538 char *field_2 = NULL;
539 char *field_3 = NULL;
540 uint32_t i = 0;
541 uint32_t records = 0;
542 uint64_t field_4 = 0;
543 uint64_t field_5 = 0;
544
545 if ((f = open_db(filename, "r", KLINE_DB_VERSION)) == NULL)
546 return;
547
548 if (get_file_version(f) < 1)
549 {
550 close_db(f);
551 return;
552 }
553
554 read_uint32(&records, f);
555
556 for (i = 0; i < records; ++i)
557 {
558 SAFE_READ(read_string(&field_1, f));
559 SAFE_READ(read_string(&field_2, f));
560 SAFE_READ(read_string(&field_3, f));
561 SAFE_READ(read_uint64(&field_4, f));
562 SAFE_READ(read_uint64(&field_5, f));
563
564 conf = conf_make(CONF_KLINE);
565 conf->user = field_1;
566 conf->host = field_2;
567 conf->reason = field_3;
568 conf->setat = field_4;
569 conf->until = field_5;
570 SetConfDatabase(conf);
571
572 add_conf_by_address(CONF_KLINE, conf);
573 }
574
575 close_db(f);
576 }
577
578 void
save_dline_database(const char * filename)579 save_dline_database(const char *filename)
580 {
581 uint32_t i = 0;
582 uint32_t records = 0;
583 struct dbFILE *f = NULL;
584 dlink_node *ptr = NULL;
585
586 if ((f = open_db(filename, "w", KLINE_DB_VERSION)) == NULL)
587 return;
588
589 for (i = 0; i < ATABLE_SIZE; ++i)
590 {
591 DLINK_FOREACH(ptr, atable[i].head)
592 {
593 struct AddressRec *arec = ptr->data;
594
595 if (arec->type == CONF_DLINE && IsConfDatabase(arec->conf))
596 ++records;
597 }
598 }
599
600 SAFE_WRITE(write_uint32(records, f), filename);
601
602 for (i = 0; i < ATABLE_SIZE; ++i)
603 {
604 DLINK_FOREACH(ptr, atable[i].head)
605 {
606 struct AddressRec *arec = ptr->data;
607
608 if (arec->type == CONF_DLINE && IsConfDatabase(arec->conf))
609 {
610 SAFE_WRITE(write_string(arec->conf->host, f), filename);
611 SAFE_WRITE(write_string(arec->conf->reason, f), filename);
612 SAFE_WRITE(write_uint64(arec->conf->setat, f), filename);
613 SAFE_WRITE(write_uint64(arec->conf->until, f), filename);
614 }
615 }
616 }
617
618 close_db(f);
619 }
620
621 void
load_dline_database(const char * filename)622 load_dline_database(const char *filename)
623 {
624 struct dbFILE *f = NULL;
625 struct MaskItem *conf = NULL;
626 char *field_1 = NULL;
627 char *field_2 = NULL;
628 uint32_t i = 0;
629 uint32_t records = 0;
630 uint64_t field_3 = 0;
631 uint64_t field_4 = 0;
632
633 if ((f = open_db(filename, "r", KLINE_DB_VERSION)) == NULL)
634 return;
635
636 if (get_file_version(f) < 1)
637 {
638 close_db(f);
639 return;
640 }
641
642 read_uint32(&records, f);
643
644 for (i = 0; i < records; ++i)
645 {
646 SAFE_READ(read_string(&field_1, f));
647 SAFE_READ(read_string(&field_2, f));
648 SAFE_READ(read_uint64(&field_3, f));
649 SAFE_READ(read_uint64(&field_4, f));
650
651 conf = conf_make(CONF_DLINE);
652 conf->host = field_1;
653 conf->reason = field_2;
654 conf->setat = field_3;
655 conf->until = field_4;
656 SetConfDatabase(conf);
657
658 add_conf_by_address(CONF_DLINE, conf);
659 }
660
661 close_db(f);
662 }
663
664 void
save_resv_database(const char * filename)665 save_resv_database(const char *filename)
666 {
667 uint32_t records = 0;
668 struct dbFILE *f = NULL;
669 dlink_node *node = NULL;
670 const struct ResvItem *resv = NULL;
671
672 if ((f = open_db(filename, "w", KLINE_DB_VERSION)) == NULL)
673 return;
674
675 DLINK_FOREACH(node, resv_chan_get_list()->head)
676 {
677 resv = node->data;
678
679 if (resv->in_database == true)
680 ++records;
681 }
682
683 DLINK_FOREACH(node, resv_nick_get_list()->head)
684 {
685 resv = node->data;
686
687 if (resv->in_database == true)
688 ++records;
689 }
690
691 SAFE_WRITE(write_uint32(records, f), filename);
692
693 DLINK_FOREACH(node, resv_chan_get_list()->head)
694 {
695 resv = node->data;
696
697 if (resv->in_database == false)
698 continue;
699
700 SAFE_WRITE(write_string(resv->mask, f), filename);
701 SAFE_WRITE(write_string(resv->reason, f), filename);
702 SAFE_WRITE(write_uint64(resv->setat, f), filename);
703 SAFE_WRITE(write_uint64(resv->expire, f), filename);
704 }
705
706 DLINK_FOREACH(node, resv_nick_get_list()->head)
707 {
708 resv = node->data;
709
710 if (resv->in_database == false)
711 continue;
712
713 SAFE_WRITE(write_string(resv->mask, f), filename);
714 SAFE_WRITE(write_string(resv->reason, f), filename);
715 SAFE_WRITE(write_uint64(resv->setat, f), filename);
716 SAFE_WRITE(write_uint64(resv->expire, f), filename);
717 }
718
719 close_db(f);
720 }
721
722 void
load_resv_database(const char * filename)723 load_resv_database(const char *filename)
724 {
725 uint32_t i = 0;
726 uint32_t records = 0;
727 uint64_t tmp64_hold = 0, tmp64_setat = 0;
728 struct dbFILE *f = NULL;
729 char *name = NULL;
730 char *reason = NULL;
731 struct ResvItem *resv = NULL;
732
733 if ((f = open_db(filename, "r", KLINE_DB_VERSION)) == NULL)
734 return;
735
736 if (get_file_version(f) < 1)
737 {
738 close_db(f);
739 return;
740 }
741
742 read_uint32(&records, f);
743
744 for (i = 0; i < records; ++i)
745 {
746 SAFE_READ(read_string(&name, f));
747 SAFE_READ(read_string(&reason, f));
748 SAFE_READ(read_uint64(&tmp64_setat, f));
749 SAFE_READ(read_uint64(&tmp64_hold, f));
750
751 resv = resv_make(name, reason, NULL);
752 resv->setat = tmp64_setat;
753 resv->expire = tmp64_hold;
754 resv->in_database = true;
755
756 xfree(name);
757 xfree(reason);
758 }
759
760 close_db(f);
761 }
762
763 void
save_xline_database(const char * filename)764 save_xline_database(const char *filename)
765 {
766 uint32_t records = 0;
767 struct dbFILE *f = NULL;
768 dlink_node *ptr = NULL;
769 struct GecosItem *gecos = NULL;
770
771 if ((f = open_db(filename, "w", KLINE_DB_VERSION)) == NULL)
772 return;
773
774 DLINK_FOREACH(ptr, gecos_get_list()->head)
775 {
776 gecos = ptr->data;
777
778 if (gecos->in_database == true)
779 ++records;
780 }
781
782 SAFE_WRITE(write_uint32(records, f), filename);
783
784 DLINK_FOREACH(ptr, gecos_get_list()->head)
785 {
786 gecos = ptr->data;
787
788 if (gecos->in_database == false)
789 continue;
790
791 SAFE_WRITE(write_string(gecos->mask, f), filename);
792 SAFE_WRITE(write_string(gecos->reason, f), filename);
793 SAFE_WRITE(write_uint64(gecos->setat, f), filename);
794 SAFE_WRITE(write_uint64(gecos->expire, f), filename);
795 }
796
797 close_db(f);
798 }
799
800 void
load_xline_database(const char * filename)801 load_xline_database(const char *filename)
802 {
803 uint32_t i = 0;
804 uint32_t records = 0;
805 uint64_t tmp64_hold = 0, tmp64_setat = 0;
806 struct dbFILE *f = NULL;
807 char *name = NULL;
808 char *reason = NULL;
809 struct GecosItem *gecos = NULL;
810
811 if ((f = open_db(filename, "r", KLINE_DB_VERSION)) == NULL)
812 return;
813
814 if (get_file_version(f) < 1)
815 {
816 close_db(f);
817 return;
818 }
819
820 read_uint32(&records, f);
821
822 for (i = 0; i < records; ++i)
823 {
824 SAFE_READ(read_string(&name, f));
825 SAFE_READ(read_string(&reason, f));
826 SAFE_READ(read_uint64(&tmp64_setat, f));
827 SAFE_READ(read_uint64(&tmp64_hold, f));
828
829 gecos = gecos_make();
830 gecos->in_database = true;
831 gecos->mask = name;
832 gecos->reason = reason;
833 gecos->setat = tmp64_setat;
834 gecos->expire = tmp64_hold;
835 }
836
837 close_db(f);
838 }
839
840 void
save_all_databases(void * unused)841 save_all_databases(void *unused)
842 {
843 save_kline_database(ConfigGeneral.klinefile);
844 save_dline_database(ConfigGeneral.dlinefile);
845 save_xline_database(ConfigGeneral.xlinefile);
846 save_resv_database(ConfigGeneral.resvfile);
847 }
848