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