1/* $NetBSD: kod_management.c,v 1.9 2020/05/25 20:47:32 christos Exp $ */ 2 3#include <config.h> 4#include <string.h> 5#include <sys/types.h> 6#include <sys/stat.h> 7 8#include "kod_management.h" 9#include "log.h" 10#include "sntp-opts.h" 11#include "ntp_stdlib.h" 12#include "ntp_worker.h" 13#include "ntp_debug.h" 14 15int kod_init = 0, kod_db_cnt = 0; 16const char *kod_db_file; 17struct kod_entry **kod_db; /* array of pointers to kod_entry */ 18 19 20/* 21 * Search for a KOD entry 22 */ 23int 24search_entry( 25 const char *hostname, 26 struct kod_entry **dst 27 ) 28{ 29 register int a, b, resc = 0; 30 31 for (a = 0; a < kod_db_cnt; a++) 32 if (!strcmp(kod_db[a]->hostname, hostname)) 33 resc++; 34 35 if (!resc) { 36 *dst = NULL; 37 return 0; 38 } 39 40 *dst = eallocarray(resc, sizeof(**dst)); 41 42 b = 0; 43 for (a = 0; a < kod_db_cnt; a++) 44 if (!strcmp(kod_db[a]->hostname, hostname)) { 45 (*dst)[b] = *kod_db[a]; 46 b++; 47 } 48 49 return resc; 50} 51 52 53void 54add_entry( 55 const char * hostname, 56 const char * type /* 4 bytes not \0 terminated */ 57 ) 58{ 59 int n; 60 struct kod_entry *pke; 61 62 pke = emalloc_zero(sizeof(*pke)); 63 pke->timestamp = time(NULL); 64 memcpy(pke->type, type, 4); 65 pke->type[sizeof(pke->type) - 1] = '\0'; 66 strlcpy(pke->hostname, hostname, sizeof(pke->hostname)); 67 68 /* 69 * insert in address ("hostname") order to find duplicates 70 */ 71 for (n = 0; n < kod_db_cnt; n++) 72 if (strcmp(kod_db[n]->hostname, pke->hostname) >= 0) 73 break; 74 75 if (n < kod_db_cnt && 76 0 == strcmp(kod_db[n]->hostname, pke->hostname)) { 77 kod_db[n]->timestamp = pke->timestamp; 78 free(pke); 79 return; 80 } 81 82 kod_db_cnt++; 83 kod_db = erealloc(kod_db, kod_db_cnt * sizeof(kod_db[0])); 84 if (n != kod_db_cnt - 1) 85 memmove(&kod_db[n + 1], &kod_db[n], 86 sizeof(kod_db[0]) * ((kod_db_cnt - 1) - n)); 87 kod_db[n] = pke; 88} 89 90 91void 92delete_entry( 93 const char * hostname, 94 const char * type 95 ) 96{ 97 int a; 98 99 for (a = 0; a < kod_db_cnt; a++) 100 if (!strcmp(kod_db[a]->hostname, hostname) 101 && !strcmp(kod_db[a]->type, type)) 102 break; 103 104 if (a == kod_db_cnt) 105 return; 106 107 free(kod_db[a]); 108 kod_db_cnt--; 109 110 if (a < kod_db_cnt) 111 memmove(&kod_db[a], &kod_db[a + 1], 112 (kod_db_cnt - a) * sizeof(kod_db[0])); 113} 114 115 116void 117atexit_write_kod_db(void) 118{ 119#ifdef WORK_FORK 120 if (worker_process) 121 return; 122#endif 123 write_kod_db(); 124} 125 126 127int 128write_kod_db(void) 129{ 130 FILE *db_s; 131 char *pch; 132 int dirmode; 133 register int a; 134 135 db_s = fopen(kod_db_file, "w"); 136 137 /* 138 * If opening fails, blindly attempt to create each directory 139 * in the path first, then retry the open. 140 */ 141 if (NULL == db_s && strlen(kod_db_file)) { 142 dirmode = S_IRUSR | S_IWUSR | S_IXUSR 143 | S_IRGRP | S_IXGRP 144 | S_IROTH | S_IXOTH; 145 pch = strchr(kod_db_file + 1, DIR_SEP); 146 while (NULL != pch) { 147 *pch = '\0'; 148 if (-1 == mkdir(kod_db_file, dirmode) 149 && errno != EEXIST) { 150 msyslog(LOG_ERR, "mkdir(%s) failed: %m", 151 kod_db_file); 152 return FALSE; 153 } 154 *pch = DIR_SEP; 155 pch = strchr(pch + 1, DIR_SEP); 156 } 157 db_s = fopen(kod_db_file, "w"); 158 } 159 160 if (NULL == db_s) { 161 msyslog(LOG_WARNING, "Can't open KOD db file %s for writing: %m", 162 kod_db_file); 163 164 return FALSE; 165 } 166 167 for (a = 0; a < kod_db_cnt; a++) { 168 fprintf(db_s, "%16.16llx %s %s\n", (unsigned long long) 169 kod_db[a]->timestamp, kod_db[a]->type, 170 kod_db[a]->hostname); 171 } 172 173 fflush(db_s); 174 fclose(db_s); 175 176 return TRUE; 177} 178 179 180void 181kod_init_kod_db( 182 const char * db_file, 183 int readonly 184 ) 185{ 186 /* 187 * Max. of 254 characters for hostname, 10 for timestamp, 4 for 188 * kisscode, 2 for spaces, 1 for \n, and 1 for \0 189 */ 190 char fbuf[254+10+4+2+1+1]; 191 FILE *db_s; 192 int a, b, sepc, len; 193 unsigned long long ull; 194 char *str_ptr; 195 char error = 0; 196 197 TRACE(2, ("Initializing KOD DB...\n")); 198 199 kod_db_file = estrdup(db_file); 200 201 db_s = fopen(db_file, "r"); 202 203 if (NULL == db_s) { 204 msyslog(LOG_WARNING, "kod_init_kod_db(): Cannot open KoD db file %s: %m", 205 db_file); 206 207 return; 208 } 209 210 if (debug) 211 printf("Starting to read KoD file %s...\n", db_file); 212 /* First let's see how many entries there are and check for right syntax */ 213 214 while (!feof(db_s) && NULL != fgets(fbuf, sizeof(fbuf), db_s)) { 215 216 /* ignore blank lines */ 217 if ('\n' == fbuf[0]) 218 continue; 219 220 sepc = 0; 221 len = strlen(fbuf); 222 for (a = 0; a < len; a++) { 223 if (' ' == fbuf[a]) 224 sepc++; 225 226 if ('\n' == fbuf[a]) { 227 if (sepc != 2) { 228 if (strcmp(db_file, "/dev/null")) 229 msyslog(LOG_DEBUG, 230 "Syntax error in KoD db file %s in line %i (missing space)", 231 db_file, 232 kod_db_cnt + 1); 233 fclose(db_s); 234 return; 235 } 236 sepc = 0; 237 kod_db_cnt++; 238 } 239 } 240 } 241 242 if (0 == kod_db_cnt) { 243 TRACE(2, ("KoD DB %s empty.\n", db_file)); 244 goto wrapup; 245 } 246 247 TRACE(2, ("KoD DB %s contains %d entries, reading...\n", db_file, kod_db_cnt)); 248 249 rewind(db_s); 250 251 /* Allocate the array of pointers to the struct kod_entry items */ 252 kod_db = eallocarray(kod_db_cnt, sizeof(kod_db[0])); 253 254 /* Read contents of file */ 255 for (b = 0; 256 !feof(db_s) && !ferror(db_s) && b < kod_db_cnt; 257 b++) { 258 259 str_ptr = fgets(fbuf, sizeof(fbuf), db_s); 260 if (NULL == str_ptr) { 261 error = 1; 262 break; 263 } 264 265 /* ignore blank lines */ 266 if ('\n' == fbuf[0]) { 267 b--; 268 continue; 269 } 270 271 /* Allocate this struct kod_entry item */ 272 kod_db[b] = emalloc(sizeof(*kod_db[0])); 273 274 if (3 != sscanf(fbuf, "%llx %4s %254s", &ull, 275 kod_db[b]->type, kod_db[b]->hostname)) { 276 277 free(kod_db[b]); 278 kod_db[b] = NULL; 279 error = 1; 280 break; 281 } 282 283 kod_db[b]->timestamp = (time_t)ull; 284 } 285 286 if (ferror(db_s) || error) { 287 kod_db_cnt = b; 288 msyslog(LOG_WARNING, "An error occured while parsing the KoD db file %s", 289 db_file); 290 fclose(db_s); 291 292 return; 293 } 294 295 wrapup: 296 fclose(db_s); 297 for (a = 0; a < kod_db_cnt; a++) 298 TRACE(2, ("KoD entry %d: %s at %llx type %s\n", a, 299 kod_db[a]->hostname, 300 (unsigned long long)kod_db[a]->timestamp, 301 kod_db[a]->type)); 302 303 if (!readonly && write_kod_db()) 304 atexit(&atexit_write_kod_db); 305} 306