/src/net-snmp/snmplib/vacm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Portions of this file are subject to the following copyright(s). See |
2 | | * the Net-SNMP's COPYING file for more details and other copyrights |
3 | | * that may apply: |
4 | | */ |
5 | | /* |
6 | | * Portions of this file are copyrighted by: |
7 | | * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. |
8 | | * Use is subject to license terms specified in the COPYING file |
9 | | * distributed with the Net-SNMP package. |
10 | | * |
11 | | * Portions of this file are copyrighted by: |
12 | | * Copyright (c) 2016 VMware, Inc. All rights reserved. |
13 | | * Use is subject to license terms specified in the COPYING file |
14 | | * distributed with the Net-SNMP package. |
15 | | */ |
16 | | |
17 | | /* |
18 | | * vacm.c |
19 | | * |
20 | | * SNMPv3 View-based Access Control Model |
21 | | */ |
22 | | |
23 | | #include <net-snmp/net-snmp-config.h> |
24 | | |
25 | | #ifdef HAVE_STDLIB_H |
26 | | #include <stdlib.h> |
27 | | #endif |
28 | | #ifdef HAVE_STRING_H |
29 | | #include <string.h> |
30 | | #else |
31 | | #include <strings.h> |
32 | | #endif |
33 | | #ifdef HAVE_UNISTD_H |
34 | | #include <unistd.h> |
35 | | #endif |
36 | | #include <sys/types.h> |
37 | | #include <stdio.h> |
38 | | #ifdef TIME_WITH_SYS_TIME |
39 | | # include <sys/time.h> |
40 | | # include <time.h> |
41 | | #else |
42 | | # ifdef HAVE_SYS_TIME_H |
43 | | # include <sys/time.h> |
44 | | # else |
45 | | # include <time.h> |
46 | | # endif |
47 | | #endif |
48 | | |
49 | | #ifdef HAVE_NETINET_IN_H |
50 | | #include <netinet/in.h> |
51 | | #endif |
52 | | |
53 | | #include <ctype.h> |
54 | | |
55 | | #include <net-snmp/types.h> |
56 | | #include <net-snmp/output_api.h> |
57 | | #include <net-snmp/config_api.h> |
58 | | |
59 | | #include <net-snmp/library/snmp.h> |
60 | | #include <net-snmp/library/snmp-tc.h> |
61 | | #include <net-snmp/library/snmp_api.h> |
62 | | #include <net-snmp/library/system.h> /* strlcpy() */ |
63 | | #include <net-snmp/library/tools.h> |
64 | | #include <net-snmp/library/vacm.h> |
65 | | |
66 | | static struct vacm_viewEntry *viewList = NULL, *viewScanPtr = NULL; |
67 | | static struct vacm_accessEntry *accessList = NULL, *accessScanPtr = NULL; |
68 | | static struct vacm_groupEntry *groupList = NULL, *groupScanPtr = NULL; |
69 | | |
70 | | /* |
71 | | * Macro to extend view masks with 1 bits when shorter than subtree lengths |
72 | | * REF: vacmViewTreeFamilyMask [RFC3415], snmpNotifyFilterMask [RFC3413] |
73 | | */ |
74 | | |
75 | | #define VIEW_MASK(viewPtr, idx, mask) \ |
76 | 0 | ((idx >= viewPtr->viewMaskLen) ? mask : (viewPtr->viewMask[idx] & mask)) |
77 | | |
78 | | /** |
79 | | * Initializes the VACM code. |
80 | | * Specifically: |
81 | | * - adds a set of enums mapping view numbers to human readable names |
82 | | */ |
83 | | void |
84 | | init_vacm(void) |
85 | 2.63k | { |
86 | | /* views for access via get/set/send-notifications */ |
87 | 2.63k | se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("read"), |
88 | 2.63k | VACM_VIEW_READ); |
89 | 2.63k | se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("write"), |
90 | 2.63k | VACM_VIEW_WRITE); |
91 | 2.63k | se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("notify"), |
92 | 2.63k | VACM_VIEW_NOTIFY); |
93 | | |
94 | | /* views for permissions when receiving notifications */ |
95 | 2.63k | se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("log"), |
96 | 2.63k | VACM_VIEW_LOG); |
97 | 2.63k | se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("execute"), |
98 | 2.63k | VACM_VIEW_EXECUTE); |
99 | 2.63k | se_add_pair_to_slist(VACM_VIEW_ENUM_NAME, strdup("net"), |
100 | 2.63k | VACM_VIEW_NET); |
101 | 2.63k | } |
102 | | |
103 | | void |
104 | | vacm_save(const char *token, const char *type) |
105 | 0 | { |
106 | 0 | struct vacm_viewEntry *vptr; |
107 | 0 | struct vacm_accessEntry *aptr; |
108 | 0 | struct vacm_groupEntry *gptr; |
109 | 0 | int i; |
110 | |
|
111 | 0 | for (vptr = viewList; vptr != NULL; vptr = vptr->next) { |
112 | 0 | if (vptr->viewStorageType == ST_NONVOLATILE) |
113 | 0 | vacm_save_view(vptr, token, type); |
114 | 0 | } |
115 | |
|
116 | 0 | for (aptr = accessList; aptr != NULL; aptr = aptr->next) { |
117 | 0 | if (aptr->storageType == ST_NONVOLATILE) { |
118 | | /* Store the standard views (if set) */ |
119 | 0 | if ( aptr->views[VACM_VIEW_READ ][0] || |
120 | 0 | aptr->views[VACM_VIEW_WRITE ][0] || |
121 | 0 | aptr->views[VACM_VIEW_NOTIFY][0] ) |
122 | 0 | vacm_save_access(aptr, token, type); |
123 | | /* Store any other (valid) access views */ |
124 | 0 | for ( i=VACM_VIEW_NOTIFY+1; i<VACM_MAX_VIEWS; i++ ) { |
125 | 0 | if ( aptr->views[i][0] ) |
126 | 0 | vacm_save_auth_access(aptr, token, type, i); |
127 | 0 | } |
128 | 0 | } |
129 | 0 | } |
130 | |
|
131 | 0 | for (gptr = groupList; gptr != NULL; gptr = gptr->next) { |
132 | 0 | if (gptr->storageType == ST_NONVOLATILE) |
133 | 0 | vacm_save_group(gptr, token, type); |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | | /* |
138 | | * vacm_save_view(): saves a view entry to the persistent cache |
139 | | */ |
140 | | void |
141 | | vacm_save_view(struct vacm_viewEntry *view, const char *token, |
142 | | const char *type) |
143 | 0 | { |
144 | 0 | char line[4096]; |
145 | 0 | char *cptr; |
146 | |
|
147 | 0 | memset(line, 0, sizeof(line)); |
148 | 0 | snprintf(line, sizeof(line), "%s%s %d %d %d ", token, "View", |
149 | 0 | view->viewStatus, view->viewStorageType, view->viewType); |
150 | 0 | line[ sizeof(line)-1 ] = 0; |
151 | 0 | cptr = &line[strlen(line)]; /* the NULL */ |
152 | |
|
153 | 0 | cptr = |
154 | 0 | read_config_save_octet_string(cptr, (u_char *) view->viewName + 1, |
155 | 0 | view->viewName[0]); |
156 | 0 | *cptr++ = ' '; |
157 | 0 | cptr = |
158 | 0 | read_config_save_objid(cptr, view->viewSubtree+1, |
159 | 0 | view->viewSubtreeLen-1); |
160 | 0 | *cptr++ = ' '; |
161 | 0 | cptr = read_config_save_octet_string(cptr, (u_char *) view->viewMask, |
162 | 0 | view->viewMaskLen); |
163 | |
|
164 | 0 | read_config_store(type, line); |
165 | 0 | } |
166 | | |
167 | | void |
168 | | vacm_parse_config_view(const char *token, const char *line) |
169 | 0 | { |
170 | 0 | struct vacm_viewEntry view; |
171 | 0 | struct vacm_viewEntry *vptr; |
172 | 0 | char *viewName = (char *) &view.viewName; |
173 | 0 | oid *viewSubtree = (oid *) & view.viewSubtree; |
174 | 0 | u_char *viewMask; |
175 | 0 | size_t len; |
176 | |
|
177 | 0 | view.viewStatus = atoi(line); |
178 | 0 | line = skip_token_const(line); |
179 | 0 | view.viewStorageType = atoi(line); |
180 | 0 | line = skip_token_const(line); |
181 | 0 | view.viewType = atoi(line); |
182 | 0 | line = skip_token_const(line); |
183 | 0 | len = sizeof(view.viewName); |
184 | 0 | line = |
185 | 0 | read_config_read_octet_string(line, (u_char **) & viewName, &len); |
186 | 0 | view.viewSubtreeLen = MAX_OID_LEN + 1; |
187 | 0 | line = |
188 | 0 | read_config_read_objid_const(line, (oid **) & viewSubtree, |
189 | 0 | &view.viewSubtreeLen); |
190 | |
|
191 | 0 | vptr = |
192 | 0 | vacm_createViewEntry(view.viewName, view.viewSubtree, |
193 | 0 | view.viewSubtreeLen); |
194 | 0 | if (!vptr) { |
195 | 0 | return; |
196 | 0 | } |
197 | | |
198 | 0 | vptr->viewStatus = view.viewStatus; |
199 | 0 | vptr->viewStorageType = view.viewStorageType; |
200 | 0 | vptr->viewType = view.viewType; |
201 | 0 | viewMask = vptr->viewMask; |
202 | 0 | vptr->viewMaskLen = sizeof(vptr->viewMask); |
203 | 0 | line = |
204 | 0 | read_config_read_octet_string(line, &viewMask, &vptr->viewMaskLen); |
205 | 0 | } |
206 | | |
207 | | /* |
208 | | * vacm_save_access(): saves an access entry to the persistent cache |
209 | | */ |
210 | | void |
211 | | vacm_save_access(struct vacm_accessEntry *access_entry, const char *token, |
212 | | const char *type) |
213 | 0 | { |
214 | 0 | char line[4096]; |
215 | 0 | char *cptr; |
216 | |
|
217 | 0 | memset(line, 0, sizeof(line)); |
218 | 0 | snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ", |
219 | 0 | token, "Access", access_entry->status, |
220 | 0 | access_entry->storageType, access_entry->securityModel, |
221 | 0 | access_entry->securityLevel, access_entry->contextMatch); |
222 | 0 | line[ sizeof(line)-1 ] = 0; |
223 | 0 | cptr = &line[strlen(line)]; /* the NULL */ |
224 | 0 | cptr = |
225 | 0 | read_config_save_octet_string(cptr, |
226 | 0 | (u_char *) access_entry->groupName + 1, |
227 | 0 | access_entry->groupName[0] + 1); |
228 | 0 | *cptr++ = ' '; |
229 | 0 | cptr = |
230 | 0 | read_config_save_octet_string(cptr, |
231 | 0 | (u_char *) access_entry->contextPrefix + 1, |
232 | 0 | access_entry->contextPrefix[0] + 1); |
233 | |
|
234 | 0 | *cptr++ = ' '; |
235 | 0 | cptr = read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_READ], |
236 | 0 | strlen(access_entry->views[VACM_VIEW_READ]) + 1); |
237 | 0 | *cptr++ = ' '; |
238 | 0 | cptr = |
239 | 0 | read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_WRITE], |
240 | 0 | strlen(access_entry->views[VACM_VIEW_WRITE]) + 1); |
241 | 0 | *cptr++ = ' '; |
242 | 0 | cptr = |
243 | 0 | read_config_save_octet_string(cptr, (u_char *) access_entry->views[VACM_VIEW_NOTIFY], |
244 | 0 | strlen(access_entry->views[VACM_VIEW_NOTIFY]) + 1); |
245 | |
|
246 | 0 | read_config_store(type, line); |
247 | 0 | } |
248 | | |
249 | | void |
250 | | vacm_save_auth_access(struct vacm_accessEntry *access_entry, |
251 | | const char *token, const char *type, int authtype) |
252 | 0 | { |
253 | 0 | char line[4096]; |
254 | 0 | char *cptr; |
255 | |
|
256 | 0 | memset(line, 0, sizeof(line)); |
257 | 0 | snprintf(line, sizeof(line), "%s%s %d %d %d %d %d ", |
258 | 0 | token, "AuthAccess", access_entry->status, |
259 | 0 | access_entry->storageType, access_entry->securityModel, |
260 | 0 | access_entry->securityLevel, access_entry->contextMatch); |
261 | 0 | line[ sizeof(line)-1 ] = 0; |
262 | 0 | cptr = &line[strlen(line)]; /* the NULL */ |
263 | 0 | cptr = |
264 | 0 | read_config_save_octet_string(cptr, |
265 | 0 | (u_char *) access_entry->groupName + 1, |
266 | 0 | access_entry->groupName[0] + 1); |
267 | 0 | *cptr++ = ' '; |
268 | 0 | cptr = |
269 | 0 | read_config_save_octet_string(cptr, |
270 | 0 | (u_char *) access_entry->contextPrefix + 1, |
271 | 0 | access_entry->contextPrefix[0] + 1); |
272 | |
|
273 | 0 | snprintf(cptr, sizeof(line)-(cptr-line), " %d ", authtype); |
274 | 0 | while ( *cptr ) |
275 | 0 | cptr++; |
276 | |
|
277 | 0 | *cptr++ = ' '; |
278 | 0 | cptr = read_config_save_octet_string(cptr, |
279 | 0 | (u_char *)access_entry->views[authtype], |
280 | 0 | strlen(access_entry->views[authtype]) + 1); |
281 | |
|
282 | 0 | read_config_store(type, line); |
283 | 0 | } |
284 | | |
285 | | char * |
286 | | _vacm_parse_config_access_common(struct vacm_accessEntry **aptr, |
287 | | const char *line) |
288 | 0 | { |
289 | 0 | struct vacm_accessEntry access; |
290 | 0 | char *cPrefix = (char *) &access.contextPrefix; |
291 | 0 | char *gName = (char *) &access.groupName; |
292 | 0 | size_t len; |
293 | |
|
294 | 0 | access.status = atoi(line); |
295 | 0 | line = skip_token_const(line); |
296 | 0 | access.storageType = atoi(line); |
297 | 0 | line = skip_token_const(line); |
298 | 0 | access.securityModel = atoi(line); |
299 | 0 | line = skip_token_const(line); |
300 | 0 | access.securityLevel = atoi(line); |
301 | 0 | line = skip_token_const(line); |
302 | 0 | access.contextMatch = atoi(line); |
303 | 0 | line = skip_token_const(line); |
304 | 0 | len = sizeof(access.groupName); |
305 | 0 | line = read_config_read_octet_string(line, (u_char **) &gName, &len); |
306 | 0 | len = sizeof(access.contextPrefix); |
307 | 0 | line = read_config_read_octet_string(line, (u_char **) &cPrefix, &len); |
308 | |
|
309 | 0 | *aptr = vacm_getAccessEntry(access.groupName, |
310 | 0 | access.contextPrefix, |
311 | 0 | access.securityModel, |
312 | 0 | access.securityLevel); |
313 | 0 | if (!*aptr) |
314 | 0 | *aptr = vacm_createAccessEntry(access.groupName, |
315 | 0 | access.contextPrefix, |
316 | 0 | access.securityModel, |
317 | 0 | access.securityLevel); |
318 | 0 | if (!*aptr) |
319 | 0 | return NULL; |
320 | | |
321 | 0 | (*aptr)->status = access.status; |
322 | 0 | (*aptr)->storageType = access.storageType; |
323 | 0 | (*aptr)->securityModel = access.securityModel; |
324 | 0 | (*aptr)->securityLevel = access.securityLevel; |
325 | 0 | (*aptr)->contextMatch = access.contextMatch; |
326 | 0 | return NETSNMP_REMOVE_CONST(char *, line); |
327 | 0 | } |
328 | | |
329 | | void |
330 | | vacm_parse_config_access(const char *token, const char *line) |
331 | 0 | { |
332 | 0 | struct vacm_accessEntry *aptr; |
333 | 0 | char *readView, *writeView, *notifyView; |
334 | 0 | size_t len; |
335 | |
|
336 | 0 | line = _vacm_parse_config_access_common(&aptr, line); |
337 | 0 | if (!line) |
338 | 0 | return; |
339 | | |
340 | 0 | readView = (char *) aptr->views[VACM_VIEW_READ]; |
341 | 0 | len = sizeof(aptr->views[VACM_VIEW_READ]); |
342 | 0 | line = |
343 | 0 | read_config_read_octet_string(line, (u_char **) & readView, &len); |
344 | 0 | writeView = (char *) aptr->views[VACM_VIEW_WRITE]; |
345 | 0 | len = sizeof(aptr->views[VACM_VIEW_WRITE]); |
346 | 0 | line = |
347 | 0 | read_config_read_octet_string(line, (u_char **) & writeView, &len); |
348 | 0 | notifyView = (char *) aptr->views[VACM_VIEW_NOTIFY]; |
349 | 0 | len = sizeof(aptr->views[VACM_VIEW_NOTIFY]); |
350 | 0 | line = |
351 | 0 | read_config_read_octet_string(line, (u_char **) & notifyView, |
352 | 0 | &len); |
353 | 0 | } |
354 | | |
355 | | void |
356 | | vacm_parse_config_auth_access(const char *token, const char *line) |
357 | 0 | { |
358 | 0 | struct vacm_accessEntry *aptr; |
359 | 0 | int authtype; |
360 | 0 | char *view; |
361 | 0 | size_t len; |
362 | |
|
363 | 0 | line = _vacm_parse_config_access_common(&aptr, line); |
364 | 0 | if (!line) |
365 | 0 | return; |
366 | | |
367 | 0 | authtype = atoi(line); |
368 | 0 | line = skip_token_const(line); |
369 | |
|
370 | 0 | view = (char *) aptr->views[authtype]; |
371 | 0 | len = sizeof(aptr->views[authtype]); |
372 | 0 | line = read_config_read_octet_string(line, (u_char **) & view, &len); |
373 | 0 | } |
374 | | |
375 | | /* |
376 | | * vacm_save_group(): saves a group entry to the persistent cache |
377 | | */ |
378 | | void |
379 | | vacm_save_group(struct vacm_groupEntry *group_entry, const char *token, |
380 | | const char *type) |
381 | 0 | { |
382 | 0 | char line[4096]; |
383 | 0 | char *cptr; |
384 | |
|
385 | 0 | memset(line, 0, sizeof(line)); |
386 | 0 | snprintf(line, sizeof(line), "%s%s %d %d %d ", |
387 | 0 | token, "Group", group_entry->status, |
388 | 0 | group_entry->storageType, group_entry->securityModel); |
389 | 0 | line[ sizeof(line)-1 ] = 0; |
390 | 0 | cptr = &line[strlen(line)]; /* the NULL */ |
391 | |
|
392 | 0 | cptr = |
393 | 0 | read_config_save_octet_string(cptr, |
394 | 0 | (u_char *) group_entry->securityName + 1, |
395 | 0 | group_entry->securityName[0] + 1); |
396 | 0 | *cptr++ = ' '; |
397 | 0 | cptr = read_config_save_octet_string(cptr, (u_char *) group_entry->groupName, |
398 | 0 | strlen(group_entry->groupName) + 1); |
399 | |
|
400 | 0 | read_config_store(type, line); |
401 | 0 | } |
402 | | |
403 | | void |
404 | | vacm_parse_config_group(const char *token, const char *line) |
405 | 0 | { |
406 | 0 | struct vacm_groupEntry group; |
407 | 0 | struct vacm_groupEntry *gptr; |
408 | 0 | char *securityName = (char *) &group.securityName; |
409 | 0 | char *groupName; |
410 | 0 | size_t len; |
411 | |
|
412 | 0 | group.status = atoi(line); |
413 | 0 | line = skip_token_const(line); |
414 | 0 | group.storageType = atoi(line); |
415 | 0 | line = skip_token_const(line); |
416 | 0 | group.securityModel = atoi(line); |
417 | 0 | line = skip_token_const(line); |
418 | 0 | len = sizeof(group.securityName); |
419 | 0 | line = |
420 | 0 | read_config_read_octet_string(line, (u_char **) & securityName, |
421 | 0 | &len); |
422 | |
|
423 | 0 | gptr = vacm_createGroupEntry(group.securityModel, group.securityName); |
424 | 0 | if (!gptr) |
425 | 0 | return; |
426 | | |
427 | 0 | gptr->status = group.status; |
428 | 0 | gptr->storageType = group.storageType; |
429 | 0 | groupName = (char *) gptr->groupName; |
430 | 0 | len = sizeof(group.groupName); |
431 | 0 | line = |
432 | 0 | read_config_read_octet_string(line, (u_char **) & groupName, &len); |
433 | 0 | } |
434 | | |
435 | | struct vacm_viewEntry * |
436 | | netsnmp_view_get(struct vacm_viewEntry *head, const char *viewName, |
437 | | oid * viewSubtree, size_t viewSubtreeLen, int mode) |
438 | 0 | { |
439 | 0 | struct vacm_viewEntry *vp, *vpret = NULL; |
440 | 0 | char view[VACMSTRINGLEN]; |
441 | 0 | int found, glen; |
442 | 0 | int count=0; |
443 | |
|
444 | 0 | glen = (int) strlen(viewName); |
445 | 0 | if (glen < 0 || glen > VACM_MAX_STRING) |
446 | 0 | return NULL; |
447 | 0 | view[0] = glen; |
448 | 0 | strlcpy(view + 1, viewName, sizeof(view) - 1); |
449 | 0 | for (vp = head; vp; vp = vp->next) { |
450 | 0 | if (!memcmp(view, vp->viewName, glen + 1) |
451 | 0 | && viewSubtreeLen >= (vp->viewSubtreeLen - 1)) { |
452 | 0 | int mask = 0x80; |
453 | 0 | unsigned int oidpos, maskpos = 0; |
454 | 0 | found = 1; |
455 | |
|
456 | 0 | for (oidpos = 0; |
457 | 0 | found && oidpos < vp->viewSubtreeLen - 1; |
458 | 0 | oidpos++) { |
459 | 0 | if (mode==VACM_MODE_IGNORE_MASK || (VIEW_MASK(vp, maskpos, mask) != 0)) { |
460 | 0 | if (viewSubtree[oidpos] != |
461 | 0 | vp->viewSubtree[oidpos + 1]) |
462 | 0 | found = 0; |
463 | 0 | } |
464 | 0 | if (mask == 1) { |
465 | 0 | mask = 0x80; |
466 | 0 | maskpos++; |
467 | 0 | } else |
468 | 0 | mask >>= 1; |
469 | 0 | } |
470 | |
|
471 | 0 | if (found) { |
472 | | /* |
473 | | * match successful, keep this node if its longer than |
474 | | * the previous or (equal and lexicographically greater |
475 | | * than the previous). |
476 | | */ |
477 | 0 | count++; |
478 | 0 | if (mode == VACM_MODE_CHECK_SUBTREE) { |
479 | 0 | vpret = vp; |
480 | 0 | } else if (vpret == NULL |
481 | 0 | || vp->viewSubtreeLen > vpret->viewSubtreeLen |
482 | 0 | || (vp->viewSubtreeLen == vpret->viewSubtreeLen |
483 | 0 | && snmp_oid_compare(vp->viewSubtree + 1, |
484 | 0 | vp->viewSubtreeLen - 1, |
485 | 0 | vpret->viewSubtree + 1, |
486 | 0 | vpret->viewSubtreeLen - 1) > |
487 | 0 | 0)) { |
488 | 0 | vpret = vp; |
489 | 0 | } |
490 | 0 | } |
491 | 0 | } |
492 | 0 | } |
493 | 0 | DEBUGMSGTL(("vacm:getView", ", %s\n", (vpret) ? "found" : "none")); |
494 | 0 | if (mode == VACM_MODE_CHECK_SUBTREE && count > 1) { |
495 | 0 | return NULL; |
496 | 0 | } |
497 | 0 | return vpret; |
498 | 0 | } |
499 | | |
500 | | /*******************************************************************o-o****** |
501 | | * netsnmp_view_exists |
502 | | * |
503 | | * Check to see if a view with the given name exists. |
504 | | * |
505 | | * Parameters: |
506 | | * viewName - Name of view to check |
507 | | * |
508 | | * Returns 0 if the view does not exist. Otherwise, it returns the number |
509 | | * of OID rows for the given name. |
510 | | */ |
511 | | int |
512 | | netsnmp_view_exists(struct vacm_viewEntry *head, const char *viewName) |
513 | 0 | { |
514 | 0 | struct vacm_viewEntry *vp; |
515 | 0 | char view[VACMSTRINGLEN]; |
516 | 0 | int len, count = 0; |
517 | |
|
518 | 0 | len = (int) strlen(viewName); |
519 | 0 | if (len < 0 || len > VACM_MAX_STRING) |
520 | 0 | return 0; |
521 | 0 | view[0] = len; |
522 | 0 | strcpy(view + 1, viewName); |
523 | 0 | DEBUGMSGTL(("9:vacm:view_exists", "checking %s\n", viewName)); |
524 | 0 | for (vp = head; vp; vp = vp->next) { |
525 | 0 | if (memcmp(view, vp->viewName, len + 1) == 0) |
526 | 0 | ++count; |
527 | 0 | } |
528 | |
|
529 | 0 | return count; |
530 | 0 | } |
531 | | |
532 | | /*******************************************************************o-o****** |
533 | | * vacm_checkSubtree |
534 | | * |
535 | | * Check to see if everything within a subtree is in view, not in view, |
536 | | * or possibly both. |
537 | | * |
538 | | * Parameters: |
539 | | * *viewName - Name of view to check |
540 | | * *viewSubtree - OID of subtree |
541 | | * viewSubtreeLen - length of subtree OID |
542 | | * |
543 | | * Returns: |
544 | | * VACM_SUCCESS The OID is included in the view. |
545 | | * VACM_NOTINVIEW If no entry in the view list includes the |
546 | | * provided OID, or the OID is explicitly excluded |
547 | | * from the view. |
548 | | * VACM_SUBTREE_UNKNOWN The entire subtree has both allowed and disallowed |
549 | | * portions. |
550 | | */ |
551 | | int |
552 | | netsnmp_view_subtree_check(struct vacm_viewEntry *head, const char *viewName, |
553 | | oid * viewSubtree, size_t viewSubtreeLen) |
554 | 0 | { |
555 | 0 | struct vacm_viewEntry *vp, *vpShorter = NULL, *vpLonger = NULL; |
556 | 0 | char view[VACMSTRINGLEN]; |
557 | 0 | int found, glen; |
558 | |
|
559 | 0 | glen = (int) strlen(viewName); |
560 | 0 | if (glen < 0 || glen > VACM_MAX_STRING) |
561 | 0 | return VACM_NOTINVIEW; |
562 | 0 | view[0] = glen; |
563 | 0 | strlcpy(view + 1, viewName, sizeof(view) - 1); |
564 | 0 | DEBUGMSGTL(("9:vacm:checkSubtree", "view %s\n", viewName)); |
565 | 0 | for (vp = head; vp; vp = vp->next) { |
566 | 0 | if (!memcmp(view, vp->viewName, glen + 1)) { |
567 | | /* |
568 | | * If the subtree defined in the view is shorter than or equal |
569 | | * to the subtree we are comparing, then it might envelop the |
570 | | * subtree we are comparing against. |
571 | | */ |
572 | 0 | if (viewSubtreeLen >= (vp->viewSubtreeLen - 1)) { |
573 | 0 | int mask = 0x80; |
574 | 0 | unsigned int oidpos, maskpos = 0; |
575 | 0 | found = 1; |
576 | | |
577 | | /* |
578 | | * check the mask |
579 | | */ |
580 | 0 | for (oidpos = 0; |
581 | 0 | found && oidpos < vp->viewSubtreeLen - 1; |
582 | 0 | oidpos++) { |
583 | 0 | if (VIEW_MASK(vp, maskpos, mask) != 0) { |
584 | 0 | if (viewSubtree[oidpos] != |
585 | 0 | vp->viewSubtree[oidpos + 1]) |
586 | 0 | found = 0; |
587 | 0 | } |
588 | 0 | if (mask == 1) { |
589 | 0 | mask = 0x80; |
590 | 0 | maskpos++; |
591 | 0 | } else |
592 | 0 | mask >>= 1; |
593 | 0 | } |
594 | |
|
595 | 0 | if (found) { |
596 | | /* |
597 | | * match successful, keep this node if it's longer than |
598 | | * the previous or (equal and lexicographically greater |
599 | | * than the previous). |
600 | | */ |
601 | 0 | DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName)); |
602 | | |
603 | 0 | if (vpShorter == NULL |
604 | 0 | || vp->viewSubtreeLen > vpShorter->viewSubtreeLen |
605 | 0 | || (vp->viewSubtreeLen == vpShorter->viewSubtreeLen |
606 | 0 | && snmp_oid_compare(vp->viewSubtree + 1, |
607 | 0 | vp->viewSubtreeLen - 1, |
608 | 0 | vpShorter->viewSubtree + 1, |
609 | 0 | vpShorter->viewSubtreeLen - 1) > |
610 | 0 | 0)) { |
611 | 0 | vpShorter = vp; |
612 | 0 | } |
613 | 0 | } |
614 | 0 | } |
615 | | /* |
616 | | * If the subtree defined in the view is longer than the |
617 | | * subtree we are comparing, then it might ambiguate our |
618 | | * response. |
619 | | */ |
620 | 0 | else { |
621 | 0 | int mask = 0x80; |
622 | 0 | unsigned int oidpos, maskpos = 0; |
623 | 0 | found = 1; |
624 | | |
625 | | /* |
626 | | * check the mask up to the length of the provided subtree |
627 | | */ |
628 | 0 | for (oidpos = 0; |
629 | 0 | found && oidpos < viewSubtreeLen; |
630 | 0 | oidpos++) { |
631 | 0 | if (VIEW_MASK(vp, maskpos, mask) != 0) { |
632 | 0 | if (viewSubtree[oidpos] != |
633 | 0 | vp->viewSubtree[oidpos + 1]) |
634 | 0 | found = 0; |
635 | 0 | } |
636 | 0 | if (mask == 1) { |
637 | 0 | mask = 0x80; |
638 | 0 | maskpos++; |
639 | 0 | } else |
640 | 0 | mask >>= 1; |
641 | 0 | } |
642 | |
|
643 | 0 | if (found) { |
644 | | /* |
645 | | * match successful. If we already found a match |
646 | | * with a different view type, then parts of the subtree |
647 | | * are included and others are excluded, so return UNKNOWN. |
648 | | */ |
649 | 0 | DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched?\n", vp->viewName)); |
650 | 0 | if (vpLonger != NULL |
651 | 0 | && (vpLonger->viewType != vp->viewType)) { |
652 | 0 | DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown")); |
653 | 0 | return VACM_SUBTREE_UNKNOWN; |
654 | 0 | } |
655 | 0 | else if (vpLonger == NULL) { |
656 | 0 | vpLonger = vp; |
657 | 0 | } |
658 | 0 | } |
659 | 0 | } |
660 | 0 | } |
661 | 0 | } |
662 | 0 | DEBUGMSGTL(("9:vacm:checkSubtree", " %s matched\n", viewName)); |
663 | | |
664 | | /* |
665 | | * If we found a matching view subtree with a longer OID than the provided |
666 | | * OID, check to see if its type is consistent with any matching view |
667 | | * subtree we may have found with a shorter OID than the provided OID. |
668 | | * |
669 | | * The view type of the longer OID is inconsistent with the shorter OID in |
670 | | * either of these two cases: |
671 | | * 1) No matching shorter OID was found and the view type of the longer |
672 | | * OID is INCLUDE. |
673 | | * 2) A matching shorter ID was found and its view type doesn't match |
674 | | * the view type of the longer OID. |
675 | | */ |
676 | 0 | if (vpLonger != NULL) { |
677 | 0 | if ((!vpShorter && vpLonger->viewType != SNMP_VIEW_EXCLUDED) |
678 | 0 | || (vpShorter && vpLonger->viewType != vpShorter->viewType)) { |
679 | 0 | DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "unknown")); |
680 | 0 | return VACM_SUBTREE_UNKNOWN; |
681 | 0 | } |
682 | 0 | } |
683 | | |
684 | 0 | if (vpShorter && vpShorter->viewType != SNMP_VIEW_EXCLUDED) { |
685 | 0 | DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "included")); |
686 | 0 | return VACM_SUCCESS; |
687 | 0 | } |
688 | | |
689 | 0 | DEBUGMSGTL(("vacm:checkSubtree", ", %s\n", "excluded")); |
690 | 0 | return VACM_NOTINVIEW; |
691 | 0 | } |
692 | | |
693 | | void |
694 | | vacm_scanViewInit(void) |
695 | 0 | { |
696 | 0 | viewScanPtr = viewList; |
697 | 0 | } |
698 | | |
699 | | struct vacm_viewEntry * |
700 | | vacm_scanViewNext(void) |
701 | 0 | { |
702 | 0 | struct vacm_viewEntry *returnval = viewScanPtr; |
703 | 0 | if (viewScanPtr) |
704 | 0 | viewScanPtr = viewScanPtr->next; |
705 | 0 | return returnval; |
706 | 0 | } |
707 | | |
708 | | struct vacm_viewEntry * |
709 | | netsnmp_view_create(struct vacm_viewEntry **head, const char *viewName, |
710 | | oid * viewSubtree, size_t viewSubtreeLen) |
711 | 15.8k | { |
712 | 15.8k | struct vacm_viewEntry *vp, *lp, *op = NULL; |
713 | 15.8k | int cmp, cmp2, glen; |
714 | | |
715 | 15.8k | glen = (int) strlen(viewName); |
716 | 15.8k | if (glen < 0 || glen > VACM_MAX_STRING || viewSubtreeLen > MAX_OID_LEN) |
717 | 0 | return NULL; |
718 | 15.8k | vp = calloc(1, sizeof(struct vacm_viewEntry)); |
719 | 15.8k | if (vp == NULL) |
720 | 0 | return NULL; |
721 | 15.8k | vp->reserved = calloc(1, sizeof(struct vacm_viewEntry)); |
722 | 15.8k | if (vp->reserved == NULL) { |
723 | 0 | free(vp); |
724 | 0 | return NULL; |
725 | 0 | } |
726 | | |
727 | 15.8k | vp->viewName[0] = glen; |
728 | 15.8k | strlcpy(vp->viewName + 1, viewName, sizeof(vp->viewName) - 1); |
729 | 15.8k | vp->viewSubtree[0] = viewSubtreeLen; |
730 | 15.8k | memcpy(vp->viewSubtree + 1, viewSubtree, viewSubtreeLen * sizeof(oid)); |
731 | 15.8k | vp->viewSubtreeLen = viewSubtreeLen + 1; |
732 | | |
733 | 15.8k | lp = *head; |
734 | 55.3k | while (lp) { |
735 | 39.5k | cmp = memcmp(lp->viewName, vp->viewName, glen + 1); |
736 | 39.5k | cmp2 = snmp_oid_compare(lp->viewSubtree, lp->viewSubtreeLen, |
737 | 39.5k | vp->viewSubtree, vp->viewSubtreeLen); |
738 | 39.5k | if (cmp == 0 && cmp2 > 0) |
739 | 0 | break; |
740 | 39.5k | if (cmp > 0) |
741 | 0 | break; |
742 | 39.5k | op = lp; |
743 | 39.5k | lp = lp->next; |
744 | 39.5k | } |
745 | 15.8k | vp->next = lp; |
746 | 15.8k | if (op) |
747 | 13.1k | op->next = vp; |
748 | 2.63k | else |
749 | 2.63k | *head = vp; |
750 | 15.8k | return vp; |
751 | 15.8k | } |
752 | | |
753 | | void |
754 | | netsnmp_view_destroy(struct vacm_viewEntry **head, const char *viewName, |
755 | | oid * viewSubtree, size_t viewSubtreeLen) |
756 | 0 | { |
757 | 0 | struct vacm_viewEntry *vp, *lastvp = NULL; |
758 | |
|
759 | 0 | if ((*head) && !strcmp((*head)->viewName + 1, viewName) |
760 | 0 | && (*head)->viewSubtreeLen == viewSubtreeLen |
761 | 0 | && !memcmp((char *) (*head)->viewSubtree, (char *) viewSubtree, |
762 | 0 | viewSubtreeLen * sizeof(oid))) { |
763 | 0 | vp = (*head); |
764 | 0 | (*head) = (*head)->next; |
765 | 0 | } else { |
766 | 0 | for (vp = (*head); vp; vp = vp->next) { |
767 | 0 | if (!strcmp(vp->viewName + 1, viewName) |
768 | 0 | && vp->viewSubtreeLen == viewSubtreeLen |
769 | 0 | && !memcmp((char *) vp->viewSubtree, (char *) viewSubtree, |
770 | 0 | viewSubtreeLen * sizeof(oid))) |
771 | 0 | break; |
772 | 0 | lastvp = vp; |
773 | 0 | } |
774 | 0 | if (!vp || !lastvp) |
775 | 0 | return; |
776 | 0 | lastvp->next = vp->next; |
777 | 0 | } |
778 | 0 | if (vp->reserved) |
779 | 0 | free(vp->reserved); |
780 | 0 | free(vp); |
781 | 0 | return; |
782 | 0 | } |
783 | | |
784 | | void |
785 | | netsnmp_view_clear(struct vacm_viewEntry **head) |
786 | 5.27k | { |
787 | 5.27k | struct vacm_viewEntry *vp; |
788 | 21.0k | while ((vp = (*head))) { |
789 | 15.8k | (*head) = vp->next; |
790 | 15.8k | if (vp->reserved) |
791 | 0 | free(vp->reserved); |
792 | 15.8k | free(vp); |
793 | 15.8k | } |
794 | 5.27k | } |
795 | | |
796 | | struct vacm_groupEntry * |
797 | | vacm_getGroupEntry(int securityModel, const char *securityName) |
798 | 0 | { |
799 | 0 | struct vacm_groupEntry *vp; |
800 | 0 | char secname[VACMSTRINGLEN]; |
801 | 0 | int glen; |
802 | |
|
803 | 0 | glen = (int) strlen(securityName); |
804 | 0 | if (glen < 0 || glen > VACM_MAX_STRING) |
805 | 0 | return NULL; |
806 | 0 | secname[0] = glen; |
807 | 0 | strlcpy(secname + 1, securityName, sizeof(secname) - 1); |
808 | |
|
809 | 0 | for (vp = groupList; vp; vp = vp->next) { |
810 | 0 | if ((securityModel == vp->securityModel |
811 | 0 | || vp->securityModel == SNMP_SEC_MODEL_ANY) |
812 | 0 | && !memcmp(vp->securityName, secname, glen + 1)) |
813 | 0 | return vp; |
814 | 0 | } |
815 | 0 | return NULL; |
816 | 0 | } |
817 | | |
818 | | void |
819 | | vacm_scanGroupInit(void) |
820 | 0 | { |
821 | 0 | groupScanPtr = groupList; |
822 | 0 | } |
823 | | |
824 | | struct vacm_groupEntry * |
825 | | vacm_scanGroupNext(void) |
826 | 0 | { |
827 | 0 | struct vacm_groupEntry *returnval = groupScanPtr; |
828 | 0 | if (groupScanPtr) |
829 | 0 | groupScanPtr = groupScanPtr->next; |
830 | 0 | return returnval; |
831 | 0 | } |
832 | | |
833 | | struct vacm_groupEntry * |
834 | | vacm_createGroupEntry(int securityModel, const char *securityName) |
835 | 0 | { |
836 | 0 | struct vacm_groupEntry *gp, *lg, *og; |
837 | 0 | int cmp, glen; |
838 | |
|
839 | 0 | glen = (int) strlen(securityName); |
840 | 0 | if (glen < 0 || glen > VACM_MAX_STRING) |
841 | 0 | return NULL; |
842 | 0 | gp = calloc(1, sizeof(struct vacm_groupEntry)); |
843 | 0 | if (gp == NULL) |
844 | 0 | return NULL; |
845 | 0 | gp->reserved = calloc(1, sizeof(struct vacm_groupEntry)); |
846 | 0 | if (gp->reserved == NULL) { |
847 | 0 | free(gp); |
848 | 0 | return NULL; |
849 | 0 | } |
850 | | |
851 | 0 | gp->securityModel = securityModel; |
852 | 0 | gp->securityName[0] = glen; |
853 | 0 | strlcpy(gp->securityName + 1, securityName, sizeof(gp->securityName) - 1); |
854 | |
|
855 | 0 | lg = groupList; |
856 | 0 | og = NULL; |
857 | 0 | while (lg) { |
858 | 0 | if (lg->securityModel > securityModel) |
859 | 0 | break; |
860 | 0 | if (lg->securityModel == securityModel && |
861 | 0 | (cmp = |
862 | 0 | memcmp(lg->securityName, gp->securityName, glen + 1)) > 0) |
863 | 0 | break; |
864 | | /* |
865 | | * if (lg->securityModel == securityModel && cmp == 0) abort(); |
866 | | */ |
867 | 0 | og = lg; |
868 | 0 | lg = lg->next; |
869 | 0 | } |
870 | 0 | gp->next = lg; |
871 | 0 | if (og == NULL) |
872 | 0 | groupList = gp; |
873 | 0 | else |
874 | 0 | og->next = gp; |
875 | 0 | return gp; |
876 | 0 | } |
877 | | |
878 | | void |
879 | | vacm_destroyGroupEntry(int securityModel, const char *securityName) |
880 | 0 | { |
881 | 0 | struct vacm_groupEntry *vp, *lastvp = NULL; |
882 | |
|
883 | 0 | if (groupList && groupList->securityModel == securityModel |
884 | 0 | && !strcmp(groupList->securityName + 1, securityName)) { |
885 | 0 | vp = groupList; |
886 | 0 | groupList = groupList->next; |
887 | 0 | } else { |
888 | 0 | for (vp = groupList; vp; vp = vp->next) { |
889 | 0 | if (vp->securityModel == securityModel |
890 | 0 | && !strcmp(vp->securityName + 1, securityName)) |
891 | 0 | break; |
892 | 0 | lastvp = vp; |
893 | 0 | } |
894 | 0 | if (!vp || !lastvp) |
895 | 0 | return; |
896 | 0 | lastvp->next = vp->next; |
897 | 0 | } |
898 | 0 | if (vp->reserved) |
899 | 0 | free(vp->reserved); |
900 | 0 | free(vp); |
901 | 0 | return; |
902 | 0 | } |
903 | | |
904 | | |
905 | | void |
906 | | vacm_destroyAllGroupEntries(void) |
907 | 5.27k | { |
908 | 5.27k | struct vacm_groupEntry *gp; |
909 | 5.27k | while ((gp = groupList)) { |
910 | 0 | groupList = gp->next; |
911 | 0 | if (gp->reserved) |
912 | 0 | free(gp->reserved); |
913 | 0 | free(gp); |
914 | 0 | } |
915 | 5.27k | } |
916 | | |
917 | | struct vacm_accessEntry * |
918 | | _vacm_choose_best( struct vacm_accessEntry *current, |
919 | | struct vacm_accessEntry *candidate) |
920 | 0 | { |
921 | | /* |
922 | | * RFC 3415: vacmAccessTable: |
923 | | * 2) if this set has [more than] one member, ... |
924 | | * it comes down to deciding how to weight the |
925 | | * preferences between ContextPrefixes, |
926 | | * SecurityModels, and SecurityLevels |
927 | | */ |
928 | 0 | if (( !current ) || |
929 | | /* a) if the subset of entries with securityModel |
930 | | * matching the securityModel in the message is |
931 | | * not empty, then discard the rest |
932 | | */ |
933 | 0 | ( current->securityModel == SNMP_SEC_MODEL_ANY && |
934 | 0 | candidate->securityModel != SNMP_SEC_MODEL_ANY ) || |
935 | | /* b) if the subset of entries with vacmAccessContextPrefix |
936 | | * matching the contextName in the message is |
937 | | * not empty, then discard the rest |
938 | | */ |
939 | 0 | ( current->contextMatch == CONTEXT_MATCH_PREFIX && |
940 | 0 | candidate->contextMatch == CONTEXT_MATCH_EXACT ) || |
941 | | /* c) discard all entries with ContextPrefixes shorter |
942 | | * than the longest one remaining in the set |
943 | | */ |
944 | 0 | ( current->contextMatch == CONTEXT_MATCH_PREFIX && |
945 | 0 | current->contextPrefix[0] < candidate->contextPrefix[0] ) || |
946 | | /* d) select the entry with the highest securityLevel |
947 | | */ |
948 | 0 | ( current->securityLevel < candidate->securityLevel )) { |
949 | |
|
950 | 0 | return candidate; |
951 | 0 | } |
952 | | |
953 | 0 | return current; |
954 | 0 | } |
955 | | |
956 | | struct vacm_accessEntry * |
957 | | vacm_getAccessEntry(const char *groupName, |
958 | | const char *contextPrefix, |
959 | | int securityModel, int securityLevel) |
960 | 0 | { |
961 | 0 | struct vacm_accessEntry *vp, *best=NULL; |
962 | 0 | char group[VACMSTRINGLEN]; |
963 | 0 | char context[VACMSTRINGLEN]; |
964 | 0 | int glen, clen; |
965 | |
|
966 | 0 | glen = (int) strlen(groupName); |
967 | 0 | if (glen < 0 || glen > VACM_MAX_STRING) |
968 | 0 | return NULL; |
969 | 0 | clen = (int) strlen(contextPrefix); |
970 | 0 | if (clen < 0 || clen > VACM_MAX_STRING) |
971 | 0 | return NULL; |
972 | | |
973 | 0 | group[0] = glen; |
974 | 0 | strlcpy(group + 1, groupName, sizeof(group) - 1); |
975 | 0 | context[0] = clen; |
976 | 0 | strlcpy(context + 1, contextPrefix, sizeof(context) - 1); |
977 | 0 | for (vp = accessList; vp; vp = vp->next) { |
978 | 0 | if ((securityModel == vp->securityModel |
979 | 0 | || vp->securityModel == SNMP_SEC_MODEL_ANY) |
980 | 0 | && securityLevel >= vp->securityLevel |
981 | 0 | && !memcmp(vp->groupName, group, glen + 1) |
982 | 0 | && |
983 | 0 | ((vp->contextMatch == CONTEXT_MATCH_EXACT |
984 | 0 | && clen == vp->contextPrefix[0] |
985 | 0 | && (memcmp(vp->contextPrefix, context, clen + 1) == 0)) |
986 | 0 | || (vp->contextMatch == CONTEXT_MATCH_PREFIX |
987 | 0 | && clen >= vp->contextPrefix[0] |
988 | 0 | && (memcmp(vp->contextPrefix + 1, context + 1, |
989 | 0 | vp->contextPrefix[0]) == 0)))) |
990 | 0 | best = _vacm_choose_best( best, vp ); |
991 | 0 | } |
992 | 0 | return best; |
993 | 0 | } |
994 | | |
995 | | void |
996 | | vacm_scanAccessInit(void) |
997 | 0 | { |
998 | 0 | accessScanPtr = accessList; |
999 | 0 | } |
1000 | | |
1001 | | struct vacm_accessEntry * |
1002 | | vacm_scanAccessNext(void) |
1003 | 0 | { |
1004 | 0 | struct vacm_accessEntry *returnval = accessScanPtr; |
1005 | 0 | if (accessScanPtr) |
1006 | 0 | accessScanPtr = accessScanPtr->next; |
1007 | 0 | return returnval; |
1008 | 0 | } |
1009 | | |
1010 | | struct vacm_accessEntry * |
1011 | | vacm_createAccessEntry(const char *groupName, |
1012 | | const char *contextPrefix, |
1013 | | int securityModel, int securityLevel) |
1014 | 0 | { |
1015 | 0 | struct vacm_accessEntry *vp, *lp, *op = NULL; |
1016 | 0 | int cmp, glen, clen; |
1017 | |
|
1018 | 0 | glen = (int) strlen(groupName); |
1019 | 0 | if (glen < 0 || glen > VACM_MAX_STRING) |
1020 | 0 | return NULL; |
1021 | 0 | clen = (int) strlen(contextPrefix); |
1022 | 0 | if (clen < 0 || clen > VACM_MAX_STRING) |
1023 | 0 | return NULL; |
1024 | 0 | vp = calloc(1, sizeof(struct vacm_accessEntry)); |
1025 | 0 | if (vp == NULL) |
1026 | 0 | return NULL; |
1027 | 0 | vp->reserved = calloc(1, sizeof(struct vacm_accessEntry)); |
1028 | 0 | if (vp->reserved == NULL) { |
1029 | 0 | free(vp); |
1030 | 0 | return NULL; |
1031 | 0 | } |
1032 | | |
1033 | 0 | vp->securityModel = securityModel; |
1034 | 0 | vp->securityLevel = securityLevel; |
1035 | 0 | vp->groupName[0] = glen; |
1036 | 0 | strlcpy(vp->groupName + 1, groupName, sizeof(vp->groupName) - 1); |
1037 | 0 | vp->contextPrefix[0] = clen; |
1038 | 0 | strlcpy(vp->contextPrefix + 1, contextPrefix, |
1039 | 0 | sizeof(vp->contextPrefix) - 1); |
1040 | |
|
1041 | 0 | lp = accessList; |
1042 | 0 | while (lp) { |
1043 | 0 | cmp = memcmp(lp->groupName, vp->groupName, glen + 1); |
1044 | 0 | if (cmp > 0) |
1045 | 0 | break; |
1046 | 0 | if (cmp < 0) |
1047 | 0 | goto next; |
1048 | 0 | cmp = memcmp(lp->contextPrefix, vp->contextPrefix, clen + 1); |
1049 | 0 | if (cmp > 0) |
1050 | 0 | break; |
1051 | 0 | if (cmp < 0) |
1052 | 0 | goto next; |
1053 | 0 | if (lp->securityModel > securityModel) |
1054 | 0 | break; |
1055 | 0 | if (lp->securityModel < securityModel) |
1056 | 0 | goto next; |
1057 | 0 | if (lp->securityLevel > securityLevel) |
1058 | 0 | break; |
1059 | 0 | next: |
1060 | 0 | op = lp; |
1061 | 0 | lp = lp->next; |
1062 | 0 | } |
1063 | 0 | vp->next = lp; |
1064 | 0 | if (op == NULL) |
1065 | 0 | accessList = vp; |
1066 | 0 | else |
1067 | 0 | op->next = vp; |
1068 | 0 | return vp; |
1069 | 0 | } |
1070 | | |
1071 | | void |
1072 | | vacm_destroyAccessEntry(const char *groupName, |
1073 | | const char *contextPrefix, |
1074 | | int securityModel, int securityLevel) |
1075 | 0 | { |
1076 | 0 | struct vacm_accessEntry *vp, *lastvp = NULL; |
1077 | |
|
1078 | 0 | if (accessList && accessList->securityModel == securityModel |
1079 | 0 | && accessList->securityLevel == securityLevel |
1080 | 0 | && !strcmp(accessList->groupName + 1, groupName) |
1081 | 0 | && !strcmp(accessList->contextPrefix + 1, contextPrefix)) { |
1082 | 0 | vp = accessList; |
1083 | 0 | accessList = accessList->next; |
1084 | 0 | } else { |
1085 | 0 | for (vp = accessList; vp; vp = vp->next) { |
1086 | 0 | if (vp->securityModel == securityModel |
1087 | 0 | && vp->securityLevel == securityLevel |
1088 | 0 | && !strcmp(vp->groupName + 1, groupName) |
1089 | 0 | && !strcmp(vp->contextPrefix + 1, contextPrefix)) |
1090 | 0 | break; |
1091 | 0 | lastvp = vp; |
1092 | 0 | } |
1093 | 0 | if (!vp || !lastvp) |
1094 | 0 | return; |
1095 | 0 | lastvp->next = vp->next; |
1096 | 0 | } |
1097 | 0 | if (vp->reserved) |
1098 | 0 | free(vp->reserved); |
1099 | 0 | free(vp); |
1100 | 0 | return; |
1101 | 0 | } |
1102 | | |
1103 | | void |
1104 | | vacm_destroyAllAccessEntries(void) |
1105 | 15.8k | { |
1106 | 15.8k | struct vacm_accessEntry *ap; |
1107 | 15.8k | while ((ap = accessList)) { |
1108 | 0 | accessList = ap->next; |
1109 | 0 | if (ap->reserved) |
1110 | 0 | free(ap->reserved); |
1111 | 0 | free(ap); |
1112 | 0 | } |
1113 | 15.8k | } |
1114 | | |
1115 | | int |
1116 | | store_vacm(int majorID, int minorID, void *serverarg, void *clientarg) |
1117 | 0 | { |
1118 | | /* |
1119 | | * figure out our application name |
1120 | | */ |
1121 | 0 | char *appname = (char *) clientarg; |
1122 | 0 | if (appname == NULL) { |
1123 | 0 | appname = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, |
1124 | 0 | NETSNMP_DS_LIB_APPTYPE); |
1125 | 0 | } |
1126 | | |
1127 | | /* |
1128 | | * save the VACM MIB |
1129 | | */ |
1130 | 0 | vacm_save("vacm", appname); |
1131 | 0 | return SNMPERR_SUCCESS; |
1132 | 0 | } |
1133 | | |
1134 | | /* |
1135 | | * returns 1 if vacm has *any* (non-built-in) configuration entries, |
1136 | | * regardless of whether or not there is enough to make a decision, |
1137 | | * else return 0 |
1138 | | */ |
1139 | | int |
1140 | | vacm_is_configured(void) |
1141 | 2.63k | { |
1142 | 2.63k | if (accessList == NULL && groupList == NULL) { |
1143 | 2.63k | return 0; |
1144 | 2.63k | } |
1145 | 0 | return 1; |
1146 | 2.63k | } |
1147 | | |
1148 | | /* |
1149 | | * backwards compatability |
1150 | | */ |
1151 | | struct vacm_viewEntry * |
1152 | | vacm_getViewEntry(const char *viewName, |
1153 | | oid * viewSubtree, size_t viewSubtreeLen, int mode) |
1154 | 0 | { |
1155 | 0 | return netsnmp_view_get( viewList, viewName, viewSubtree, viewSubtreeLen, |
1156 | 0 | mode); |
1157 | 0 | } |
1158 | | |
1159 | | int |
1160 | | vacm_checkSubtree(const char *viewName, |
1161 | | oid * viewSubtree, size_t viewSubtreeLen) |
1162 | 0 | { |
1163 | 0 | return netsnmp_view_subtree_check( viewList, viewName, viewSubtree, |
1164 | 0 | viewSubtreeLen); |
1165 | 0 | } |
1166 | | |
1167 | | struct vacm_viewEntry * |
1168 | | vacm_createViewEntry(const char *viewName, |
1169 | | oid * viewSubtree, size_t viewSubtreeLen) |
1170 | 15.8k | { |
1171 | 15.8k | return netsnmp_view_create( &viewList, viewName, viewSubtree, |
1172 | 15.8k | viewSubtreeLen); |
1173 | 15.8k | } |
1174 | | |
1175 | | void |
1176 | | vacm_destroyViewEntry(const char *viewName, |
1177 | | oid * viewSubtree, size_t viewSubtreeLen) |
1178 | 0 | { |
1179 | 0 | netsnmp_view_destroy( &viewList, viewName, viewSubtree, viewSubtreeLen); |
1180 | 0 | } |
1181 | | |
1182 | | void |
1183 | | vacm_destroyAllViewEntries(void) |
1184 | 5.27k | { |
1185 | 5.27k | netsnmp_view_clear( &viewList ); |
1186 | 5.27k | } |
1187 | | |
1188 | | /* |
1189 | | * vacm simple api |
1190 | | */ |
1191 | | |
1192 | | int |
1193 | | netsnmp_vacm_simple_usm_add(const char *user, int rw, int authLevel, |
1194 | | const char *view, oid *oidView, size_t oidViewLen, |
1195 | | const char *context) |
1196 | 0 | { |
1197 | 0 | struct vacm_viewEntry *vacmEntry = NULL; |
1198 | 0 | struct vacm_groupEntry *groupEntry = NULL; |
1199 | 0 | struct vacm_accessEntry *accessEntry = NULL; |
1200 | 0 | char *tmp, localContext[VACMSTRINGLEN]; |
1201 | 0 | int exact = 1; /* exact context match */ |
1202 | |
|
1203 | 0 | if (NULL == user) |
1204 | 0 | return SNMPERR_GENERR; |
1205 | | |
1206 | 0 | if (authLevel < SNMP_SEC_LEVEL_NOAUTH || |
1207 | 0 | authLevel > SNMP_SEC_LEVEL_AUTHPRIV) |
1208 | 0 | return SNMPERR_GENERR; |
1209 | | |
1210 | 0 | if (NULL != view) { |
1211 | | /* |
1212 | | * if we are given a view name, it is an error if |
1213 | | * - it exists and we have an oid |
1214 | | * - it doesn't exist and we don't have an oid |
1215 | | */ |
1216 | 0 | if (netsnmp_view_exists(viewList, view) != 0) { |
1217 | 0 | if (NULL != oidView || oidViewLen > 0) { |
1218 | 0 | DEBUGMSGTL(("vacm:simple_usm", "can't modify existing view")); |
1219 | 0 | return SNMPERR_GENERR; |
1220 | 0 | } |
1221 | 0 | } else { |
1222 | 0 | if (NULL == oidView || oidViewLen == 0) { |
1223 | 0 | DEBUGMSGTL(("vacm:simple_usm", "can't create view w/out oid")); |
1224 | 0 | return SNMPERR_GENERR; |
1225 | 0 | } |
1226 | | /** try and create view for oid */ |
1227 | 0 | vacmEntry = vacm_createViewEntry(view, oidView, oidViewLen); |
1228 | 0 | if (NULL == vacmEntry) { |
1229 | 0 | DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed")); |
1230 | 0 | return SNMPERR_GENERR; |
1231 | 0 | } |
1232 | 0 | SNMP_FREE(vacmEntry->reserved); |
1233 | 0 | } |
1234 | 0 | } else if (0 == oidViewLen || NULL == oidView) { |
1235 | 0 | view = "_all_"; /* no oid either, just use _all_ */ |
1236 | 0 | } else { |
1237 | 0 | DEBUGMSGTL(("vacm:simple_usm", "need view name for new views")); |
1238 | 0 | return SNMPERR_GENERR; |
1239 | 0 | } |
1240 | | |
1241 | | /* |
1242 | | * group |
1243 | | * grpv3user usm \"v3user\"\000prefix\000_all_\000_all_\000_all_\000\060" |
1244 | | * vacm_createGroupEntry() also automatically inserts into group list. |
1245 | | */ |
1246 | 0 | groupEntry = vacm_createGroupEntry(SNMP_SEC_MODEL_USM, user); |
1247 | 0 | if (NULL == groupEntry) { |
1248 | 0 | DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed")); |
1249 | 0 | goto bail; |
1250 | 0 | } |
1251 | 0 | snprintf(groupEntry->groupName, sizeof(groupEntry->groupName)-2, |
1252 | 0 | "grp%.28s", user); |
1253 | 0 | for (tmp=groupEntry->groupName; *tmp; tmp++) |
1254 | 0 | if (!isalnum((unsigned char)(*tmp))) |
1255 | 0 | *tmp = '_'; |
1256 | 0 | groupEntry->storageType = SNMP_STORAGE_PERMANENT; |
1257 | 0 | groupEntry->status = SNMP_ROW_ACTIVE; |
1258 | 0 | SNMP_FREE(groupEntry->reserved); |
1259 | | |
1260 | | /* |
1261 | | * access |
1262 | | * grpv3user myctx usm noauth exact _all_ none none |
1263 | | */ |
1264 | 0 | if (NULL == context) { |
1265 | 0 | localContext[0] = 0; |
1266 | 0 | context = localContext; |
1267 | 0 | } else { |
1268 | | /** check for wildcard in context */ |
1269 | 0 | int contextLen = strlen(context); |
1270 | 0 | if ('*' == context[contextLen - 1]) { |
1271 | 0 | strlcpy(localContext, context, sizeof(localContext)); |
1272 | 0 | localContext[contextLen - 1] = 0; |
1273 | 0 | context = localContext; |
1274 | 0 | exact = 2; /* not exact, have context prefix */ |
1275 | 0 | } |
1276 | 0 | } |
1277 | 0 | accessEntry = vacm_createAccessEntry(groupEntry->groupName, context, |
1278 | 0 | SNMP_SEC_MODEL_USM, authLevel); |
1279 | 0 | if (NULL == accessEntry) { |
1280 | 0 | DEBUGMSGTL(("vacm:simple_usm", "createViewEntry failed")); |
1281 | 0 | goto bail; |
1282 | 0 | } |
1283 | 0 | strlcpy(accessEntry->views[VACM_VIEW_READ], view, |
1284 | 0 | sizeof(accessEntry->views[VACM_VIEW_READ])); |
1285 | 0 | if (0 == rw) |
1286 | 0 | view = "none"; |
1287 | 0 | strlcpy(accessEntry->views[VACM_VIEW_WRITE], view, |
1288 | 0 | sizeof(accessEntry->views[VACM_VIEW_WRITE])); |
1289 | 0 | strlcpy(accessEntry->views[VACM_VIEW_NOTIFY], view, |
1290 | 0 | sizeof(accessEntry->views[VACM_VIEW_NOTIFY])); |
1291 | |
|
1292 | 0 | accessEntry->contextMatch = exact; |
1293 | 0 | accessEntry->storageType = SNMP_STORAGE_PERMANENT; |
1294 | 0 | accessEntry->status = SNMP_ROW_ACTIVE; |
1295 | 0 | SNMP_FREE(accessEntry->reserved); |
1296 | |
|
1297 | 0 | return SNMPERR_SUCCESS; |
1298 | | |
1299 | 0 | bail: |
1300 | 0 | if (NULL != groupEntry) |
1301 | 0 | vacm_destroyGroupEntry(SNMP_SEC_MODEL_USM, user); |
1302 | |
|
1303 | 0 | if (NULL != vacmEntry) |
1304 | 0 | vacm_destroyViewEntry(vacmEntry->viewName+1, vacmEntry->viewSubtree, |
1305 | 0 | vacmEntry->viewSubtreeLen); |
1306 | |
|
1307 | 0 | return SNMPERR_GENERR; |
1308 | 0 | } |
1309 | | |
1310 | | int |
1311 | | netsnmp_vacm_simple_usm_del(const char *user, int authLevel, |
1312 | | const char *view, oid *oidView, size_t oidViewLen, |
1313 | | const char *context) |
1314 | 0 | { |
1315 | 0 | char localContext[VACMSTRINGLEN]; |
1316 | 0 | char group[VACMSTRINGLEN]; |
1317 | | |
1318 | | /* |
1319 | | * only delete simple views (one OID) for which we have an OID. |
1320 | | * never delete '_all_'. |
1321 | | */ |
1322 | 0 | if ((NULL != view) && (NULL != oidView) && (oidViewLen > 0) && |
1323 | 0 | (strcmp(view, "_all_") != 0) && |
1324 | 0 | (netsnmp_view_exists(viewList, view) == 1)) { |
1325 | 0 | vacm_destroyViewEntry(view, oidView, oidViewLen); |
1326 | 0 | } |
1327 | |
|
1328 | 0 | vacm_destroyGroupEntry(SNMP_SEC_MODEL_USM, user); |
1329 | |
|
1330 | 0 | snprintf(group, sizeof(group)-2, "grp%.28s", user); |
1331 | 0 | if (NULL == context) { |
1332 | 0 | localContext[0] = 0; |
1333 | 0 | context = localContext; |
1334 | 0 | } else { |
1335 | | /** check for wildcard in context */ |
1336 | 0 | int contextLen = strlen(context); |
1337 | 0 | if ('*' == context[contextLen - 1]) { |
1338 | 0 | strlcpy(localContext, context, sizeof(localContext)); |
1339 | 0 | localContext[contextLen - 1] = 0; |
1340 | 0 | context = localContext; |
1341 | 0 | } |
1342 | 0 | } |
1343 | |
|
1344 | 0 | vacm_destroyAccessEntry(group, context, SNMP_SEC_MODEL_USM, authLevel); |
1345 | |
|
1346 | 0 | return SNMPERR_SUCCESS; |
1347 | 0 | } |