1 #include <net-snmp/net-snmp-config.h>
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <net-snmp/net-snmp-includes.h>
7 #include <net-snmp/library/snmp_transport.h>
8 
9 static char**
create_word_array_helper(const char * cptr,size_t idx,char * tmp,size_t tmplen)10 create_word_array_helper(const char* cptr, size_t idx, char* tmp, size_t tmplen)
11 {
12     char* item;
13     char** res;
14     cptr = copy_nword_const(cptr, tmp, tmplen);
15     item = strdup(tmp);
16     if (cptr)
17         res = create_word_array_helper(cptr, idx + 1, tmp, tmplen);
18     else {
19         res = (char**)malloc(sizeof(char*) * (idx + 2));
20         res[idx + 1] = NULL;
21     }
22     res[idx] = item;
23     return res;
24 }
25 
26 static char**
create_word_array(const char * cptr)27 create_word_array(const char* cptr)
28 {
29     size_t tmplen = strlen(cptr);
30     char* tmp = (char*)malloc(tmplen + 1);
31     char** res = create_word_array_helper(cptr, 0, tmp, tmplen + 1);
32     free(tmp);
33     return res;
34 }
35 
36 static void
destroy_word_array(char ** arr)37 destroy_word_array(char** arr)
38 {
39     if (arr) {
40         char** run = arr;
41         while(*run) {
42             free(*run);
43             ++run;
44         }
45         free(arr);
46     }
47 }
48 
49 struct netsnmp_lookup_domain {
50     char* application;
51     char** userDomain;
52     char** domain;
53     struct netsnmp_lookup_domain* next;
54 };
55 
56 static struct netsnmp_lookup_domain* domains = NULL;
57 
58 int
netsnmp_register_default_domain(const char * application,const char * domain)59 netsnmp_register_default_domain(const char* application, const char* domain)
60 {
61     struct netsnmp_lookup_domain *run = domains, *prev = NULL;
62     int res = 0;
63 
64     while (run != NULL && strcmp(run->application, application) < 0) {
65 	prev = run;
66 	run = run->next;
67     }
68     if (run && strcmp(run->application, application) == 0) {
69       if (run->domain != NULL) {
70           destroy_word_array(run->domain);
71 	  run->domain = NULL;
72 	  res = 1;
73       }
74     } else {
75 	run = SNMP_MALLOC_STRUCT(netsnmp_lookup_domain);
76 	run->application = strdup(application);
77 	run->userDomain = NULL;
78 	if (prev) {
79 	    run->next = prev->next;
80 	    prev->next = run;
81 	} else {
82 	    run->next = domains;
83 	    domains = run;
84 	}
85     }
86     if (domain) {
87         run->domain = create_word_array(domain);
88     } else if (run->userDomain == NULL) {
89 	if (prev)
90 	    prev->next = run->next;
91 	else
92 	    domains = run->next;
93 	free(run->application);
94 	free(run);
95     }
96     return res;
97 }
98 
99 void
netsnmp_clear_default_domain(void)100 netsnmp_clear_default_domain(void)
101 {
102     while (domains) {
103 	struct netsnmp_lookup_domain *tmp = domains;
104 	domains = domains->next;
105 	free(tmp->application);
106         destroy_word_array(tmp->userDomain);
107         destroy_word_array(tmp->domain);
108 	free(tmp);
109     }
110 }
111 
112 static void
netsnmp_register_user_domain(const char * token,char * cptr)113 netsnmp_register_user_domain(const char* token, char* cptr)
114 {
115     struct netsnmp_lookup_domain *run = domains, *prev = NULL;
116     size_t len = strlen(cptr) + 1;
117     char* application = (char*)malloc(len);
118     char** domain;
119 
120     {
121         char* cp = copy_nword(cptr, application, len);
122         if (cp == NULL) {
123             netsnmp_config_error("No domain(s) in registration of "
124                                  "defDomain \"%s\"", application);
125             free(application);
126             return;
127         }
128         domain = create_word_array(cp);
129     }
130 
131     while (run != NULL && strcmp(run->application, application) < 0) {
132 	prev = run;
133 	run = run->next;
134     }
135     if (run && strcmp(run->application, application) == 0) {
136 	if (run->userDomain != NULL) {
137 	    config_perror("Default transport already registered for this "
138 			  "application");
139             destroy_word_array(domain);
140             free(application);
141 	    return;
142 	}
143     } else {
144 	run = SNMP_MALLOC_STRUCT(netsnmp_lookup_domain);
145 	run->application = strdup(application);
146 	run->domain = NULL;
147 	if (prev) {
148 	    run->next = prev->next;
149 	    prev->next = run;
150 	} else {
151 	    run->next = domains;
152 	    domains = run;
153 	}
154     }
155     run->userDomain = domain;
156     free(application);
157 }
158 
159 static void
netsnmp_clear_user_domain(void)160 netsnmp_clear_user_domain(void)
161 {
162     struct netsnmp_lookup_domain *run = domains, *prev = NULL;
163 
164     while (run) {
165 	if (run->userDomain != NULL) {
166             destroy_word_array(run->userDomain);
167 	    run->userDomain = NULL;
168 	}
169 	if (run->domain == NULL) {
170 	    struct netsnmp_lookup_domain *tmp = run;
171 	    if (prev)
172 		run = prev->next = run->next;
173 	    else
174 		run = domains = run->next;
175 	    free(tmp->application);
176 	    free(tmp);
177 	} else {
178 	    prev = run;
179 	    run = run->next;
180 	}
181     }
182 }
183 
184 const char* const *
netsnmp_lookup_default_domains(const char * application)185 netsnmp_lookup_default_domains(const char* application)
186 {
187     const char * const * res;
188 
189     if (application == NULL)
190 	res = NULL;
191     else {
192         struct netsnmp_lookup_domain *run = domains;
193 
194 	while (run && strcmp(run->application, application) < 0)
195 	    run = run->next;
196 	if (run && strcmp(run->application, application) == 0)
197 	    if (run->userDomain)
198                 res = (const char * const *)run->userDomain;
199 	    else
200                 res = (const char * const *)run->domain;
201 	else
202 	    res = NULL;
203     }
204     DEBUGMSGTL(("defaults",
205                 "netsnmp_lookup_default_domain(\"%s\") ->",
206                 application ? application : "[NIL]"));
207     if (res) {
208         const char * const * r = res;
209         while(*r) {
210             DEBUGMSG(("defaults", " \"%s\"", *r));
211             ++r;
212         }
213         DEBUGMSG(("defaults", "\n"));
214     } else
215         DEBUGMSG(("defaults", " \"[NIL]\"\n"));
216     return res;
217 }
218 
219 const char*
netsnmp_lookup_default_domain(const char * application)220 netsnmp_lookup_default_domain(const char* application)
221 {
222     const char * const * res = netsnmp_lookup_default_domains(application);
223     return (res ? *res : NULL);
224 }
225 
226 struct netsnmp_lookup_target {
227     char* application;
228     char* domain;
229     char* userTarget;
230     char* target;
231     struct netsnmp_lookup_target* next;
232 };
233 
234 static struct netsnmp_lookup_target* targets = NULL;
235 
236 /**
237  * Add an (application, domain, target) triplet to the targets list if target
238  * != NULL. Remove an entry if target == NULL and the userTarget pointer for
239  * the entry found is also NULL. Keep at most one target per (application,
240  * domain) pair.
241  *
242  * @return 1 if an entry for (application, domain) was already present in the
243  *   targets list or 0 if such an entry was not yet present in the targets list.
244  */
245 int
netsnmp_register_default_target(const char * application,const char * domain,const char * target)246 netsnmp_register_default_target(const char* application, const char* domain,
247 				const char* target)
248 {
249     struct netsnmp_lookup_target *run = targets, *prev = NULL;
250     int i = 0, res = 0;
251     while (run && ((i = strcmp(run->application, application)) < 0 ||
252 		   (i == 0 && strcmp(run->domain, domain) < 0))) {
253 	prev = run;
254 	run = run->next;
255     }
256     if (run && i == 0 && strcmp(run->domain, domain) == 0) {
257       if (run->target != NULL) {
258 	    free(run->target);
259 	    run->target = NULL;
260 	    res = 1;
261       }
262     } else {
263 	run = SNMP_MALLOC_STRUCT(netsnmp_lookup_target);
264 	run->application = strdup(application);
265 	run->domain = strdup(domain);
266 	run->userTarget = NULL;
267 	if (prev) {
268 	    run->next = prev->next;
269 	    prev->next = run;
270 	} else {
271 	    run->next = targets;
272 	    targets = run;
273 	}
274     }
275     if (target) {
276 	run->target = strdup(target);
277     } else if (run->userTarget == NULL) {
278 	if (prev)
279 	    prev->next = run->next;
280 	else
281 	    targets = run->next;
282 	free(run->domain);
283 	free(run->application);
284 	free(run);
285     }
286     return res;
287 }
288 
289 /**
290  * Clear the targets list.
291  */
292 void
netsnmp_clear_default_target(void)293 netsnmp_clear_default_target(void)
294 {
295     while (targets) {
296 	struct netsnmp_lookup_target *tmp = targets;
297 	targets = targets->next;
298 	free(tmp->application);
299 	free(tmp->domain);
300 	free(tmp->userTarget);
301 	free(tmp->target);
302 	free(tmp);
303     }
304 }
305 
306 static void
netsnmp_register_user_target(const char * token,char * cptr)307 netsnmp_register_user_target(const char* token, char* cptr)
308 {
309     struct netsnmp_lookup_target *run = targets, *prev = NULL;
310     size_t len = strlen(cptr) + 1;
311     char* application = (char*)malloc(len);
312     char* domain = (char*)malloc(len);
313     char* target = (char*)malloc(len);
314     int i = 0;
315 
316     {
317 	char* cp = copy_nword(cptr, application, len);
318         if (cp == NULL) {
319             netsnmp_config_error("No domain and target in registration of "
320                                  "defTarget \"%s\"", application);
321             goto done;
322         }
323 	cp = copy_nword(cp, domain, len);
324         if (cp == NULL) {
325             netsnmp_config_error("No target in registration of "
326                                  "defTarget \"%s\" \"%s\"",
327                                  application, domain);
328             goto done;
329         }
330 	cp = copy_nword(cp, target, len);
331 	if (cp)
332 	    config_pwarn("Trailing junk found");
333     }
334 
335     while (run && ((i = strcmp(run->application, application)) < 0 ||
336 		   (i == 0 && strcmp(run->domain, domain) < 0))) {
337 	prev = run;
338 	run = run->next;
339     }
340     if (run && i == 0 && strcmp(run->domain, domain) == 0) {
341 	if (run->userTarget != NULL) {
342 	    config_perror("Default target already registered for this "
343 			  "application-domain combination");
344 	    goto done;
345 	}
346     } else {
347 	run = SNMP_MALLOC_STRUCT(netsnmp_lookup_target);
348 	run->application = strdup(application);
349 	run->domain = strdup(domain);
350 	run->target = NULL;
351 	if (prev) {
352 	    run->next = prev->next;
353 	    prev->next = run;
354 	} else {
355 	    run->next = targets;
356 	    targets = run;
357 	}
358     }
359     run->userTarget = strdup(target);
360  done:
361     free(target);
362     free(domain);
363     free(application);
364 }
365 
366 static void
netsnmp_clear_user_target(void)367 netsnmp_clear_user_target(void)
368 {
369     struct netsnmp_lookup_target *run = targets, *prev = NULL;
370 
371     while (run) {
372 	if (run->userTarget != NULL) {
373 	    free(run->userTarget);
374 	    run->userTarget = NULL;
375 	}
376 	if (run->target == NULL) {
377 	    struct netsnmp_lookup_target *tmp = run;
378 	    if (prev)
379 		run = prev->next = run->next;
380 	    else
381 		run = targets = run->next;
382 	    free(tmp->application);
383 	    free(tmp->domain);
384 	    free(tmp);
385 	} else {
386 	    prev = run;
387 	    run = run->next;
388 	}
389     }
390 }
391 
392 const char*
netsnmp_lookup_default_target(const char * application,const char * domain)393 netsnmp_lookup_default_target(const char* application, const char* domain)
394 {
395     int i = 0;
396     struct netsnmp_lookup_target *run = targets;
397     const char *res;
398 
399     if (application == NULL || domain == NULL)
400 	res = NULL;
401     else {
402 	while (run && ((i = strcmp(run->application, application)) < 0 ||
403 		       (i == 0 && strcmp(run->domain, domain) < 0)))
404 	    run = run->next;
405 	if (run && i == 0 && strcmp(run->domain, domain) == 0)
406 	    if (run->userTarget != NULL)
407 		res = run->userTarget;
408 	    else
409 		res = run->target;
410 	else
411 	    res = NULL;
412     }
413     DEBUGMSGTL(("defaults",
414 		"netsnmp_lookup_default_target(\"%s\", \"%s\") -> \"%s\"\n",
415 		application ? application : "[NIL]",
416 		domain ? domain : "[NIL]",
417 		res ? res : "[NIL]"));
418     return res;
419 }
420 
421 void
netsnmp_register_service_handlers(void)422 netsnmp_register_service_handlers(void)
423 {
424     register_config_handler("snmp:", "defDomain",
425 			    netsnmp_register_user_domain,
426 			    netsnmp_clear_user_domain,
427 			    "application domain");
428     register_config_handler("snmp:", "defTarget",
429 			    netsnmp_register_user_target,
430 			    netsnmp_clear_user_target,
431 			    "application domain target");
432 }
433