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