xref: /openbsd-src/usr.sbin/snmpd/smi.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: smi.c,v 1.7 2012/02/01 18:44:06 camield Exp $	*/
2 
3 /*
4  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/param.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <sys/tree.h>
26 #include <sys/sysctl.h>
27 
28 #include <net/if.h>
29 #include <net/if_dl.h>
30 #include <net/if_arp.h>
31 #include <net/if_media.h>
32 #include <net/route.h>
33 #include <netinet/in.h>
34 #include <netinet/if_ether.h>
35 #include <arpa/inet.h>
36 
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <event.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <pwd.h>
45 
46 #include "snmpd.h"
47 #include "mib.h"
48 
49 extern struct snmpd *env;
50 
51 RB_HEAD(oidtree, oid);
52 RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp);
53 struct oidtree smi_oidtree;
54 
55 u_long
56 smi_getticks(void)
57 {
58 	struct timeval	 now, run;
59 	u_long		 ticks;
60 
61 	gettimeofday(&now, NULL);
62 	if (timercmp(&now, &env->sc_starttime, <=))
63 		return (0);
64 	timersub(&now, &env->sc_starttime, &run);
65 	ticks = run.tv_sec * 100;
66 	if (run.tv_usec)
67 		ticks += run.tv_usec / 10000;
68 
69 	return (ticks);
70 }
71 
72 void
73 smi_oidlen(struct ber_oid *o)
74 {
75 	size_t	 i;
76 
77 	for (i = 0; i < BER_MAX_OID_LEN && o->bo_id[i] != 0; i++)
78 		;
79 	o->bo_n = i;
80 }
81 
82 void
83 smi_scalar_oidlen(struct ber_oid *o)
84 {
85 	smi_oidlen(o);
86 
87 	/* Append .0. */
88 	if (o->bo_n < BER_MAX_OID_LEN)
89 		o->bo_n++;
90 }
91 
92 char *
93 smi_oidstring(struct ber_oid *o, char *buf, size_t len)
94 {
95 	char		 str[256];
96 	struct oid	*value, key;
97 	size_t		 i, lookup = 1;
98 
99 	bzero(buf, len);
100 	bzero(&key, sizeof(key));
101 	bcopy(o, &key.o_id, sizeof(struct ber_oid));
102 	key.o_flags |= OID_KEY;		/* do not match wildcards */
103 
104 	if (env->sc_flags & SNMPD_F_NONAMES)
105 		lookup = 0;
106 
107 	for (i = 0; i < o->bo_n; i++) {
108 		key.o_oidlen = i + 1;
109 		if (lookup &&
110 		    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL)
111 			snprintf(str, sizeof(str), "%s", value->o_name);
112 		else
113 			snprintf(str, sizeof(str), "%d", key.o_oid[i]);
114 		strlcat(buf, str, len);
115 		if (i < (o->bo_n - 1))
116 			strlcat(buf, ".", len);
117 	}
118 
119 	return (buf);
120 }
121 
122 void
123 smi_delete(struct oid *oid)
124 {
125 	struct oid	 key, *value;
126 
127 	bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid));
128 	if ((value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL &&
129 	    value == oid)
130 		RB_REMOVE(oidtree, &smi_oidtree, value);
131 
132 	if (oid->o_data != NULL)
133 		free(oid->o_data);
134 	if (oid->o_flags & OID_DYNAMIC) {
135 		free(oid->o_name);
136 		free(oid);
137 	}
138 }
139 
140 void
141 smi_insert(struct oid *oid)
142 {
143 	struct oid		 key, *value;
144 
145 	if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL)
146 		fatalx("smi_insert: invalid MIB table");
147 
148 	bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid));
149 	value = RB_FIND(oidtree, &smi_oidtree, &key);
150 	if (value != NULL)
151 		smi_delete(value);
152 
153 	RB_INSERT(oidtree, &smi_oidtree, oid);
154 }
155 
156 void
157 smi_mibtree(struct oid *oids)
158 {
159 	struct oid	*oid, *decl;
160 	size_t		 i;
161 
162 	for (i = 0; oids[i].o_oid[0] != 0; i++) {
163 		oid = &oids[i];
164 		smi_oidlen(&oid->o_id);
165 		if (oid->o_name != NULL) {
166 			if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL)
167 				fatalx("smi_mibtree: invalid MIB table");
168 			RB_INSERT(oidtree, &smi_oidtree, oid);
169 			continue;
170 		}
171 		decl = RB_FIND(oidtree, &smi_oidtree, oid);
172 		if (decl == NULL)
173 			fatalx("smi_mibtree: undeclared MIB");
174 		decl->o_flags = oid->o_flags;
175 		decl->o_get = oid->o_get;
176 		decl->o_set = oid->o_set;
177 		decl->o_table = oid->o_table;
178 		decl->o_val = oid->o_val;
179 		decl->o_data = oid->o_data;
180 	}
181 }
182 
183 int
184 smi_init(void)
185 {
186 	RB_INIT(&smi_oidtree);
187 	mib_init();
188 	return (0);
189 }
190 
191 struct oid *
192 smi_find(struct oid *oid)
193 {
194 	return (RB_FIND(oidtree, &smi_oidtree, oid));
195 }
196 
197 struct oid *
198 smi_next(struct oid *oid)
199 {
200 	return (RB_NEXT(oidtree, &smi_oidtree, oid));
201 }
202 
203 struct oid *
204 smi_foreach(struct oid *oid, u_int flags)
205 {
206 	/*
207 	 * Traverse the tree of MIBs with the option to check
208 	 * for specific OID flags.
209 	 */
210 	if (oid == NULL) {
211 		oid = RB_MIN(oidtree, &smi_oidtree);
212 		if (oid == NULL)
213 			return (NULL);
214 		if (flags == 0 || (oid->o_flags & flags))
215 			return (oid);
216 	}
217 	for (;;) {
218 		oid = RB_NEXT(oidtree, &smi_oidtree, oid);
219 		if (oid == NULL)
220 			break;
221 		if (flags == 0 || (oid->o_flags & flags))
222 			return (oid);
223 	}
224 
225 	return (oid);
226 }
227 
228 int
229 smi_oid_cmp(struct oid *a, struct oid *b)
230 {
231 	size_t	 i;
232 
233 	for (i = 0; i < MIN(a->o_oidlen, b->o_oidlen); i++)
234 		if (a->o_oid[i] != b->o_oid[i])
235 			return (a->o_oid[i] - b->o_oid[i]);
236 
237 	/*
238 	 * Return success if the matched object is a table
239 	 * (it will match any sub-elements)
240 	 */
241 	if ((b->o_flags & OID_TABLE) &&
242 	    (a->o_flags & OID_KEY) == 0 &&
243 	    (a->o_oidlen > b->o_oidlen))
244 		return (0);
245 
246 	return (a->o_oidlen - b->o_oidlen);
247 }
248 
249 RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp);
250