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