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
search_entry(const char * hostname,struct kod_entry ** dst)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
add_entry(const char * hostname,const char * type)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
delete_entry(const char * hostname,const char * type)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
atexit_write_kod_db(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
write_kod_db(void)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
kod_init_kod_db(const char * db_file,int readonly)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