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