1258945Sroberto#include <config.h> 2258945Sroberto#include <string.h> 3258945Sroberto#include <sys/types.h> 4258945Sroberto#include <sys/stat.h> 5258945Sroberto 6258945Sroberto#include "kod_management.h" 7258945Sroberto#include "log.h" 8258945Sroberto#include "sntp-opts.h" 9258945Sroberto#include "ntp_stdlib.h" 10280849Scy#include "ntp_worker.h" 11280849Scy#include "ntp_debug.h" 12258945Sroberto 13258945Srobertoint kod_init = 0, kod_db_cnt = 0; 14258945Srobertoconst char *kod_db_file; 15258945Srobertostruct kod_entry **kod_db; /* array of pointers to kod_entry */ 16258945Sroberto 17258945Sroberto 18258945Sroberto/* 19258945Sroberto * Search for a KOD entry 20258945Sroberto */ 21258945Srobertoint 22280849Scysearch_entry( 23280849Scy const char *hostname, 24280849Scy struct kod_entry **dst 25280849Scy ) 26258945Sroberto{ 27258945Sroberto register int a, b, resc = 0; 28258945Sroberto 29258945Sroberto for (a = 0; a < kod_db_cnt; a++) 30258945Sroberto if (!strcmp(kod_db[a]->hostname, hostname)) 31258945Sroberto resc++; 32258945Sroberto 33258945Sroberto if (!resc) { 34258945Sroberto *dst = NULL; 35258945Sroberto return 0; 36258945Sroberto } 37258945Sroberto 38290000Sglebius *dst = eallocarray(resc, sizeof(**dst)); 39258945Sroberto 40258945Sroberto b = 0; 41258945Sroberto for (a = 0; a < kod_db_cnt; a++) 42258945Sroberto if (!strcmp(kod_db[a]->hostname, hostname)) { 43258945Sroberto (*dst)[b] = *kod_db[a]; 44258945Sroberto b++; 45258945Sroberto } 46258945Sroberto 47258945Sroberto return resc; 48258945Sroberto} 49258945Sroberto 50258945Sroberto 51258945Srobertovoid 52258945Srobertoadd_entry( 53280849Scy const char * hostname, 54280849Scy const char * type /* 4 bytes not \0 terminated */ 55258945Sroberto ) 56258945Sroberto{ 57258945Sroberto int n; 58258945Sroberto struct kod_entry *pke; 59258945Sroberto 60280849Scy pke = emalloc_zero(sizeof(*pke)); 61258945Sroberto pke->timestamp = time(NULL); 62258945Sroberto memcpy(pke->type, type, 4); 63258945Sroberto pke->type[sizeof(pke->type) - 1] = '\0'; 64280849Scy strlcpy(pke->hostname, hostname, sizeof(pke->hostname)); 65258945Sroberto 66258945Sroberto /* 67258945Sroberto * insert in address ("hostname") order to find duplicates 68258945Sroberto */ 69258945Sroberto for (n = 0; n < kod_db_cnt; n++) 70258945Sroberto if (strcmp(kod_db[n]->hostname, pke->hostname) >= 0) 71258945Sroberto break; 72258945Sroberto 73258945Sroberto if (n < kod_db_cnt && 74258945Sroberto 0 == strcmp(kod_db[n]->hostname, pke->hostname)) { 75258945Sroberto kod_db[n]->timestamp = pke->timestamp; 76258945Sroberto free(pke); 77258945Sroberto return; 78258945Sroberto } 79258945Sroberto 80258945Sroberto kod_db_cnt++; 81258945Sroberto kod_db = erealloc(kod_db, kod_db_cnt * sizeof(kod_db[0])); 82258945Sroberto if (n != kod_db_cnt - 1) 83258945Sroberto memmove(&kod_db[n + 1], &kod_db[n], 84258945Sroberto sizeof(kod_db[0]) * ((kod_db_cnt - 1) - n)); 85258945Sroberto kod_db[n] = pke; 86258945Sroberto} 87258945Sroberto 88258945Sroberto 89258945Srobertovoid 90258945Srobertodelete_entry( 91280849Scy const char * hostname, 92280849Scy const char * type 93258945Sroberto ) 94258945Sroberto{ 95280849Scy int a; 96258945Sroberto 97258945Sroberto for (a = 0; a < kod_db_cnt; a++) 98258945Sroberto if (!strcmp(kod_db[a]->hostname, hostname) 99258945Sroberto && !strcmp(kod_db[a]->type, type)) 100258945Sroberto break; 101258945Sroberto 102258945Sroberto if (a == kod_db_cnt) 103258945Sroberto return; 104258945Sroberto 105258945Sroberto free(kod_db[a]); 106258945Sroberto kod_db_cnt--; 107258945Sroberto 108258945Sroberto if (a < kod_db_cnt) 109258945Sroberto memmove(&kod_db[a], &kod_db[a + 1], 110258945Sroberto (kod_db_cnt - a) * sizeof(kod_db[0])); 111258945Sroberto} 112258945Sroberto 113258945Sroberto 114258945Srobertovoid 115280849Scyatexit_write_kod_db(void) 116280849Scy{ 117280849Scy#ifdef WORK_FORK 118280849Scy if (worker_process) 119280849Scy return; 120280849Scy#endif 121280849Scy write_kod_db(); 122280849Scy} 123280849Scy 124280849Scy 125280849Scyint 126258945Srobertowrite_kod_db(void) 127258945Sroberto{ 128258945Sroberto FILE *db_s; 129258945Sroberto char *pch; 130258945Sroberto int dirmode; 131258945Sroberto register int a; 132258945Sroberto 133258945Sroberto db_s = fopen(kod_db_file, "w"); 134258945Sroberto 135258945Sroberto /* 136258945Sroberto * If opening fails, blindly attempt to create each directory 137258945Sroberto * in the path first, then retry the open. 138258945Sroberto */ 139258945Sroberto if (NULL == db_s && strlen(kod_db_file)) { 140258945Sroberto dirmode = S_IRUSR | S_IWUSR | S_IXUSR 141258945Sroberto | S_IRGRP | S_IXGRP 142258945Sroberto | S_IROTH | S_IXOTH; 143258945Sroberto pch = strchr(kod_db_file + 1, DIR_SEP); 144258945Sroberto while (NULL != pch) { 145258945Sroberto *pch = '\0'; 146280849Scy if (-1 == mkdir(kod_db_file, dirmode) 147280849Scy && errno != EEXIST) { 148280849Scy msyslog(LOG_ERR, "mkdir(%s) failed: %m", 149280849Scy kod_db_file); 150280849Scy return FALSE; 151280849Scy } 152258945Sroberto *pch = DIR_SEP; 153258945Sroberto pch = strchr(pch + 1, DIR_SEP); 154258945Sroberto } 155258945Sroberto db_s = fopen(kod_db_file, "w"); 156258945Sroberto } 157258945Sroberto 158258945Sroberto if (NULL == db_s) { 159280849Scy msyslog(LOG_WARNING, "Can't open KOD db file %s for writing: %m", 160258945Sroberto kod_db_file); 161258945Sroberto 162280849Scy return FALSE; 163258945Sroberto } 164258945Sroberto 165258945Sroberto for (a = 0; a < kod_db_cnt; a++) { 166258945Sroberto fprintf(db_s, "%16.16llx %s %s\n", (unsigned long long) 167258945Sroberto kod_db[a]->timestamp, kod_db[a]->type, 168258945Sroberto kod_db[a]->hostname); 169258945Sroberto } 170258945Sroberto 171258945Sroberto fflush(db_s); 172258945Sroberto fclose(db_s); 173280849Scy 174280849Scy return TRUE; 175258945Sroberto} 176258945Sroberto 177258945Sroberto 178258945Srobertovoid 179258945Srobertokod_init_kod_db( 180280849Scy const char * db_file, 181280849Scy int readonly 182258945Sroberto ) 183258945Sroberto{ 184258945Sroberto /* 185258945Sroberto * Max. of 254 characters for hostname, 10 for timestamp, 4 for 186258945Sroberto * kisscode, 2 for spaces, 1 for \n, and 1 for \0 187258945Sroberto */ 188258945Sroberto char fbuf[254+10+4+2+1+1]; 189258945Sroberto FILE *db_s; 190258945Sroberto int a, b, sepc, len; 191258945Sroberto unsigned long long ull; 192258945Sroberto char *str_ptr; 193258945Sroberto char error = 0; 194258945Sroberto 195280849Scy TRACE(2, ("Initializing KOD DB...\n")); 196258945Sroberto 197258945Sroberto kod_db_file = estrdup(db_file); 198258945Sroberto 199258945Sroberto db_s = fopen(db_file, "r"); 200258945Sroberto 201258945Sroberto if (NULL == db_s) { 202280849Scy msyslog(LOG_WARNING, "kod_init_kod_db(): Cannot open KoD db file %s: %m", 203258945Sroberto db_file); 204258945Sroberto 205258945Sroberto return; 206258945Sroberto } 207258945Sroberto 208280849Scy if (debug) 209258945Sroberto printf("Starting to read KoD file %s...\n", db_file); 210258945Sroberto /* First let's see how many entries there are and check for right syntax */ 211258945Sroberto 212258945Sroberto while (!feof(db_s) && NULL != fgets(fbuf, sizeof(fbuf), db_s)) { 213258945Sroberto 214258945Sroberto /* ignore blank lines */ 215258945Sroberto if ('\n' == fbuf[0]) 216258945Sroberto continue; 217258945Sroberto 218258945Sroberto sepc = 0; 219258945Sroberto len = strlen(fbuf); 220258945Sroberto for (a = 0; a < len; a++) { 221258945Sroberto if (' ' == fbuf[a]) 222258945Sroberto sepc++; 223258945Sroberto 224258945Sroberto if ('\n' == fbuf[a]) { 225258945Sroberto if (sepc != 2) { 226258945Sroberto if (strcmp(db_file, "/dev/null")) 227258945Sroberto msyslog(LOG_DEBUG, 228258945Sroberto "Syntax error in KoD db file %s in line %i (missing space)", 229258945Sroberto db_file, 230258945Sroberto kod_db_cnt + 1); 231258945Sroberto fclose(db_s); 232258945Sroberto return; 233258945Sroberto } 234258945Sroberto sepc = 0; 235258945Sroberto kod_db_cnt++; 236258945Sroberto } 237258945Sroberto } 238258945Sroberto } 239258945Sroberto 240258945Sroberto if (0 == kod_db_cnt) { 241280849Scy TRACE(2, ("KoD DB %s empty.\n", db_file)); 242280849Scy goto wrapup; 243258945Sroberto } 244258945Sroberto 245280849Scy TRACE(2, ("KoD DB %s contains %d entries, reading...\n", db_file, kod_db_cnt)); 246258945Sroberto 247258945Sroberto rewind(db_s); 248258945Sroberto 249290000Sglebius kod_db = eallocarray(kod_db_cnt, sizeof(kod_db[0])); 250258945Sroberto 251258945Sroberto /* Read contents of file */ 252258945Sroberto for (b = 0; 253258945Sroberto !feof(db_s) && !ferror(db_s) && b < kod_db_cnt; 254258945Sroberto b++) { 255258945Sroberto 256258945Sroberto str_ptr = fgets(fbuf, sizeof(fbuf), db_s); 257258945Sroberto if (NULL == str_ptr) { 258258945Sroberto error = 1; 259258945Sroberto break; 260258945Sroberto } 261258945Sroberto 262258945Sroberto /* ignore blank lines */ 263258945Sroberto if ('\n' == fbuf[0]) { 264258945Sroberto b--; 265258945Sroberto continue; 266258945Sroberto } 267258945Sroberto 268258945Sroberto kod_db[b] = emalloc(sizeof(*kod_db[b])); 269258945Sroberto 270258945Sroberto if (3 != sscanf(fbuf, "%llx %4s %254s", &ull, 271258945Sroberto kod_db[b]->type, kod_db[b]->hostname)) { 272258945Sroberto 273258945Sroberto free(kod_db[b]); 274258945Sroberto kod_db[b] = NULL; 275258945Sroberto error = 1; 276258945Sroberto break; 277258945Sroberto } 278258945Sroberto 279258945Sroberto kod_db[b]->timestamp = (time_t)ull; 280258945Sroberto } 281258945Sroberto 282258945Sroberto if (ferror(db_s) || error) { 283258945Sroberto kod_db_cnt = b; 284258945Sroberto msyslog(LOG_WARNING, "An error occured while parsing the KoD db file %s", 285258945Sroberto db_file); 286258945Sroberto fclose(db_s); 287258945Sroberto 288258945Sroberto return; 289258945Sroberto } 290258945Sroberto 291280849Scy wrapup: 292258945Sroberto fclose(db_s); 293258945Sroberto for (a = 0; a < kod_db_cnt; a++) 294280849Scy TRACE(2, ("KoD entry %d: %s at %llx type %s\n", a, 295280849Scy kod_db[a]->hostname, 296280849Scy (unsigned long long)kod_db[a]->timestamp, 297280849Scy kod_db[a]->type)); 298280849Scy 299280849Scy if (!readonly && write_kod_db()) 300280849Scy atexit(&atexit_write_kod_db); 301258945Sroberto} 302