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