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