xref: /openbsd-src/usr.sbin/snmpd/smi.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: smi.c,v 1.6 2009/12/16 22:17:53 deraadt 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 char *
83 smi_oidstring(struct ber_oid *o, char *buf, size_t len)
84 {
85 	char		 str[256];
86 	struct oid	*value, key;
87 	size_t		 i, lookup = 1;
88 
89 	bzero(buf, len);
90 	bzero(&key, sizeof(key));
91 	bcopy(o, &key.o_id, sizeof(struct ber_oid));
92 	key.o_flags |= OID_KEY;		/* do not match wildcards */
93 
94 	if (env->sc_flags & SNMPD_F_NONAMES)
95 		lookup = 0;
96 
97 	for (i = 0; i < o->bo_n; i++) {
98 		key.o_oidlen = i + 1;
99 		if (lookup &&
100 		    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL)
101 			snprintf(str, sizeof(str), "%s", value->o_name);
102 		else
103 			snprintf(str, sizeof(str), "%d", key.o_oid[i]);
104 		strlcat(buf, str, len);
105 		if (i < (o->bo_n - 1))
106 			strlcat(buf, ".", len);
107 	}
108 
109 	return (buf);
110 }
111 
112 void
113 smi_delete(struct oid *oid)
114 {
115 	struct oid	 key, *value;
116 
117 	bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid));
118 	if ((value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL &&
119 	    value == oid)
120 		RB_REMOVE(oidtree, &smi_oidtree, value);
121 
122 	if (oid->o_data != NULL)
123 		free(oid->o_data);
124 	if (oid->o_flags & OID_DYNAMIC) {
125 		free(oid->o_name);
126 		free(oid);
127 	}
128 }
129 
130 void
131 smi_insert(struct oid *oid)
132 {
133 	struct oid		 key, *value;
134 
135 	if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL)
136 		fatalx("smi_insert: invalid MIB table");
137 
138 	bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid));
139 	value = RB_FIND(oidtree, &smi_oidtree, &key);
140 	if (value != NULL)
141 		smi_delete(value);
142 
143 	RB_INSERT(oidtree, &smi_oidtree, oid);
144 }
145 
146 void
147 smi_mibtree(struct oid *oids)
148 {
149 	struct oid	*oid, *decl;
150 	size_t		 i;
151 
152 	for (i = 0; oids[i].o_oid[0] != 0; i++) {
153 		oid = &oids[i];
154 		smi_oidlen(&oid->o_id);
155 		if (oid->o_name != NULL) {
156 			if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL)
157 				fatalx("smi_mibtree: invalid MIB table");
158 			RB_INSERT(oidtree, &smi_oidtree, oid);
159 			continue;
160 		}
161 		decl = RB_FIND(oidtree, &smi_oidtree, oid);
162 		if (decl == NULL)
163 			fatalx("smi_mibtree: undeclared MIB");
164 		decl->o_flags = oid->o_flags;
165 		decl->o_get = oid->o_get;
166 		decl->o_set = oid->o_set;
167 		decl->o_table = oid->o_table;
168 		decl->o_val = oid->o_val;
169 		decl->o_data = oid->o_data;
170 	}
171 }
172 
173 int
174 smi_init(void)
175 {
176 	RB_INIT(&smi_oidtree);
177 	mib_init();
178 	return (0);
179 }
180 
181 struct oid *
182 smi_find(struct oid *oid)
183 {
184 	return (RB_FIND(oidtree, &smi_oidtree, oid));
185 }
186 
187 struct oid *
188 smi_next(struct oid *oid)
189 {
190 	return (RB_NEXT(oidtree, &smi_oidtree, oid));
191 }
192 
193 struct oid *
194 smi_foreach(struct oid *oid, u_int flags)
195 {
196 	/*
197 	 * Traverse the tree of MIBs with the option to check
198 	 * for specific OID flags.
199 	 */
200 	if (oid == NULL) {
201 		oid = RB_MIN(oidtree, &smi_oidtree);
202 		if (oid == NULL)
203 			return (NULL);
204 		if (flags == 0 || (oid->o_flags & flags))
205 			return (oid);
206 	}
207 	for (;;) {
208 		oid = RB_NEXT(oidtree, &smi_oidtree, oid);
209 		if (oid == NULL)
210 			break;
211 		if (flags == 0 || (oid->o_flags & flags))
212 			return (oid);
213 	}
214 
215 	return (oid);
216 }
217 
218 int
219 smi_oid_cmp(struct oid *a, struct oid *b)
220 {
221 	size_t	 i;
222 
223 	for (i = 0; i < MIN(a->o_oidlen, b->o_oidlen); i++)
224 		if (a->o_oid[i] != b->o_oid[i])
225 			return (a->o_oid[i] - b->o_oid[i]);
226 
227 	/*
228 	 * Return success if the matched object is a table
229 	 * (it will match any sub-elements)
230 	 */
231 	if ((b->o_flags & OID_TABLE) &&
232 	    (a->o_flags & OID_KEY) == 0 &&
233 	    (a->o_oidlen > b->o_oidlen))
234 		return (0);
235 
236 	return (a->o_oidlen - b->o_oidlen);
237 }
238 
239 RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp);
240