xref: /netbsd-src/external/bsd/ntp/dist/sntp/kod_management.c (revision 4391d5e9d4f291db41e3b3ba26a01b5e51364aae)
1 /*	$NetBSD: kod_management.c,v 1.3 2012/02/01 07:46:23 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 
14 int kod_init = 0, kod_db_cnt = 0;
15 const char *kod_db_file;
16 struct kod_entry **kod_db;	/* array of pointers to kod_entry */
17 
18 
19 /*
20  * Search for a KOD entry
21  */
22 int
23 search_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 
52 void
53 add_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 
92 void
93 delete_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 
117 void
118 write_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 
163 void
164 kod_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