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