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