1 /*-
2 * Copyright (c) 2010,2018 The FreeBSD Foundation
3 *
4 * This software was developed by Shteryana Sotirova Shopova under
5 * sponsorship from the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30 #include <sys/queue.h>
31 #include <sys/types.h>
32
33 #include <errno.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <syslog.h>
40
41 #include "asn1.h"
42 #include "snmp.h"
43 #include "snmpmod.h"
44
45 #define SNMPTREE_TYPES
46 #include "usm_tree.h"
47 #include "usm_oid.h"
48
49 static struct lmodule *usm_module;
50 /* For the registration. */
51 static const struct asn_oid oid_usm = OIDX_snmpUsmMIB;
52
53 static const struct asn_oid oid_usmNoAuthProtocol = OIDX_usmNoAuthProtocol;
54 static const struct asn_oid oid_usmHMACMD5AuthProtocol = \
55 OIDX_usmHMACMD5AuthProtocol;
56 static const struct asn_oid oid_usmHMACSHAAuthProtocol = \
57 OIDX_usmHMACSHAAuthProtocol;
58
59 static const struct asn_oid oid_usmNoPrivProtocol = OIDX_usmNoPrivProtocol;
60 static const struct asn_oid oid_usmDESPrivProtocol = OIDX_usmDESPrivProtocol;
61 static const struct asn_oid oid_usmAesCfb128Protocol = OIDX_usmAesCfb128Protocol;
62
63 static const struct asn_oid oid_usmUserSecurityName = OIDX_usmUserSecurityName;
64
65 /* The registration. */
66 static uint reg_usm;
67
68 static int32_t usm_lock;
69
70 static struct usm_user * usm_get_user(const struct asn_oid *, uint);
71 static struct usm_user * usm_get_next_user(const struct asn_oid *, uint);
72 static void usm_append_userindex(struct asn_oid *, uint,
73 const struct usm_user *);
74 static int usm_user_index_decode(const struct asn_oid *, uint, uint8_t *,
75 uint32_t *, char *);
76
77 int
op_usm_stats(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub __unused,uint32_t iidx __unused,enum snmp_op op)78 op_usm_stats(struct snmp_context *ctx __unused, struct snmp_value *val,
79 uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op)
80 {
81 struct snmpd_usmstat *usmstats;
82
83 if (op == SNMP_OP_SET)
84 return (SNMP_ERR_NOT_WRITEABLE);
85
86 if ((usmstats = bsnmpd_get_usm_stats()) == NULL)
87 return (SNMP_ERR_GENERR);
88
89 if (op == SNMP_OP_GET) {
90 switch (val->var.subs[sub - 1]) {
91 case LEAF_usmStatsUnsupportedSecLevels:
92 val->v.uint32 = usmstats->unsupported_seclevels;
93 break;
94 case LEAF_usmStatsNotInTimeWindows:
95 val->v.uint32 = usmstats->not_in_time_windows;
96 break;
97 case LEAF_usmStatsUnknownUserNames:
98 val->v.uint32 = usmstats->unknown_users;
99 break;
100 case LEAF_usmStatsUnknownEngineIDs:
101 val->v.uint32 = usmstats->unknown_engine_ids;
102 break;
103 case LEAF_usmStatsWrongDigests:
104 val->v.uint32 = usmstats->wrong_digests;
105 break;
106 case LEAF_usmStatsDecryptionErrors:
107 val->v.uint32 = usmstats->decrypt_errors;
108 break;
109 default:
110 return (SNMP_ERR_NOSUCHNAME);
111 }
112 return (SNMP_ERR_NOERROR);
113 }
114 abort();
115 }
116
117 int
op_usm_lock(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)118 op_usm_lock(struct snmp_context *ctx __unused, struct snmp_value *val,
119 uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
120 {
121 if (val->var.subs[sub - 1] != LEAF_usmUserSpinLock)
122 return (SNMP_ERR_NOSUCHNAME);
123
124 switch (op) {
125 case SNMP_OP_GET:
126 if (++usm_lock == INT32_MAX)
127 usm_lock = 0;
128 val->v.integer = usm_lock;
129 break;
130 case SNMP_OP_GETNEXT:
131 abort();
132 case SNMP_OP_SET:
133 if (val->v.integer != usm_lock)
134 return (SNMP_ERR_INCONS_VALUE);
135 break;
136 case SNMP_OP_ROLLBACK:
137 /* FALLTHROUGH */
138 case SNMP_OP_COMMIT:
139 break;
140 }
141
142 return (SNMP_ERR_NOERROR);
143 }
144
145 int
op_usm_users(struct snmp_context * ctx,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)146 op_usm_users(struct snmp_context *ctx, struct snmp_value *val,
147 uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
148 {
149 uint32_t elen;
150 struct usm_user *uuser, *clone;
151 char uname[SNMP_ADM_STR32_SIZ];
152 uint8_t eid[SNMP_ENGINE_ID_SIZ];
153
154 switch (op) {
155 case SNMP_OP_GET:
156 if ((uuser = usm_get_user(&val->var, sub)) == NULL)
157 return (SNMP_ERR_NOSUCHNAME);
158 break;
159
160 case SNMP_OP_GETNEXT:
161 if ((uuser = usm_get_next_user(&val->var, sub)) == NULL)
162 return (SNMP_ERR_NOSUCHNAME);
163 usm_append_userindex(&val->var, sub, uuser);
164 break;
165
166 case SNMP_OP_SET:
167 if ((uuser = usm_get_user(&val->var, sub)) == NULL &&
168 val->var.subs[sub - 1] != LEAF_usmUserStatus &&
169 val->var.subs[sub - 1] != LEAF_usmUserCloneFrom)
170 return (SNMP_ERR_NOSUCHNAME);
171
172 /*
173 * XXX (ngie): need to investigate the MIB to determine how
174 * this is possible given some of the transitions below.
175 */
176 if (community != COMM_INITIALIZE &&
177 uuser != NULL && uuser->type == StorageType_readOnly)
178 return (SNMP_ERR_NOT_WRITEABLE);
179
180 switch (val->var.subs[sub - 1]) {
181 case LEAF_usmUserSecurityName:
182 return (SNMP_ERR_NOT_WRITEABLE);
183
184 case LEAF_usmUserCloneFrom:
185 if (uuser != NULL || usm_user_index_decode(&val->var,
186 sub, eid, &elen, uname) < 0 ||
187 !(asn_is_suboid(&oid_usmUserSecurityName, &val->v.oid)))
188 return (SNMP_ERR_WRONG_VALUE);
189 if ((clone = usm_get_user(&val->v.oid, sub)) == NULL)
190 return (SNMP_ERR_INCONS_VALUE);
191 if ((uuser = usm_new_user(eid, elen, uname)) == NULL)
192 return (SNMP_ERR_GENERR);
193 uuser->status = RowStatus_notReady;
194 if (community != COMM_INITIALIZE)
195 uuser->type = StorageType_volatile;
196 else
197 uuser->type = StorageType_readOnly;
198
199 uuser->suser.auth_proto = clone->suser.auth_proto;
200 uuser->suser.priv_proto = clone->suser.priv_proto;
201 memcpy(uuser->suser.auth_key, clone->suser.auth_key,
202 sizeof(uuser->suser.auth_key));
203 memcpy(uuser->suser.priv_key, clone->suser.priv_key,
204 sizeof(uuser->suser.priv_key));
205 ctx->scratch->int1 = RowStatus_createAndWait;
206 break;
207
208 case LEAF_usmUserAuthProtocol:
209 ctx->scratch->int1 = uuser->suser.auth_proto;
210 if (asn_compare_oid(&oid_usmNoAuthProtocol,
211 &val->v.oid) == 0)
212 uuser->suser.auth_proto = SNMP_AUTH_NOAUTH;
213 else if (asn_compare_oid(&oid_usmHMACMD5AuthProtocol,
214 &val->v.oid) == 0)
215 uuser->suser.auth_proto = SNMP_AUTH_HMAC_MD5;
216 else if (asn_compare_oid(&oid_usmHMACSHAAuthProtocol,
217 &val->v.oid) == 0)
218 uuser->suser.auth_proto = SNMP_AUTH_HMAC_SHA;
219 else
220 return (SNMP_ERR_WRONG_VALUE);
221 break;
222
223 case LEAF_usmUserAuthKeyChange:
224 case LEAF_usmUserOwnAuthKeyChange:
225 if (val->var.subs[sub - 1] ==
226 LEAF_usmUserOwnAuthKeyChange &&
227 (usm_user == NULL || strcmp(uuser->suser.sec_name,
228 usm_user->suser.sec_name) != 0))
229 return (SNMP_ERR_NO_ACCESS);
230 if (val->v.octetstring.len > SNMP_AUTH_KEY_SIZ)
231 return (SNMP_ERR_INCONS_VALUE);
232 ctx->scratch->ptr1 = malloc(SNMP_AUTH_KEY_SIZ);
233 if (ctx->scratch->ptr1 == NULL)
234 return (SNMP_ERR_GENERR);
235 memcpy(ctx->scratch->ptr1, uuser->suser.auth_key,
236 SNMP_AUTH_KEY_SIZ);
237 memcpy(uuser->suser.auth_key, val->v.octetstring.octets,
238 val->v.octetstring.len);
239 break;
240
241 case LEAF_usmUserPrivProtocol:
242 ctx->scratch->int1 = uuser->suser.priv_proto;
243 if (asn_compare_oid(&oid_usmNoPrivProtocol,
244 &val->v.oid) == 0)
245 uuser->suser.priv_proto = SNMP_PRIV_NOPRIV;
246 else if (asn_compare_oid(&oid_usmDESPrivProtocol,
247 &val->v.oid) == 0)
248 uuser->suser.priv_proto = SNMP_PRIV_DES;
249 else if (asn_compare_oid(&oid_usmAesCfb128Protocol,
250 &val->v.oid) == 0)
251 uuser->suser.priv_proto = SNMP_PRIV_AES;
252 else
253 return (SNMP_ERR_WRONG_VALUE);
254 break;
255
256 case LEAF_usmUserPrivKeyChange:
257 case LEAF_usmUserOwnPrivKeyChange:
258 if (val->var.subs[sub - 1] ==
259 LEAF_usmUserOwnPrivKeyChange &&
260 (usm_user == NULL || strcmp(uuser->suser.sec_name,
261 usm_user->suser.sec_name) != 0))
262 return (SNMP_ERR_NO_ACCESS);
263 if (val->v.octetstring.len > SNMP_PRIV_KEY_SIZ)
264 return (SNMP_ERR_INCONS_VALUE);
265 ctx->scratch->ptr1 = malloc(SNMP_PRIV_KEY_SIZ);
266 if (ctx->scratch->ptr1 == NULL)
267 return (SNMP_ERR_GENERR);
268 memcpy(ctx->scratch->ptr1, uuser->suser.priv_key,
269 sizeof(uuser->suser.priv_key));
270 memcpy(uuser->suser.priv_key, val->v.octetstring.octets,
271 val->v.octetstring.len);
272 break;
273
274 case LEAF_usmUserPublic:
275 if (val->v.octetstring.len > SNMP_ADM_STR32_SIZ)
276 return (SNMP_ERR_INCONS_VALUE);
277 if (uuser->user_public_len > 0) {
278 ctx->scratch->ptr2 =
279 malloc(uuser->user_public_len);
280 if (ctx->scratch->ptr2 == NULL)
281 return (SNMP_ERR_GENERR);
282 memcpy(ctx->scratch->ptr2, uuser->user_public,
283 uuser->user_public_len);
284 ctx->scratch->int2 = uuser->user_public_len;
285 }
286 if (val->v.octetstring.len > 0) {
287 memcpy(uuser->user_public,
288 val->v.octetstring.octets,
289 val->v.octetstring.len);
290 uuser->user_public_len = val->v.octetstring.len;
291 } else {
292 memset(uuser->user_public, 0,
293 sizeof(uuser->user_public));
294 uuser->user_public_len = 0;
295 }
296 break;
297
298 case LEAF_usmUserStorageType:
299 return (SNMP_ERR_INCONS_VALUE);
300
301 case LEAF_usmUserStatus:
302 if (uuser == NULL) {
303 if (val->v.integer != RowStatus_createAndWait ||
304 usm_user_index_decode(&val->var, sub, eid,
305 &elen, uname) < 0)
306 return (SNMP_ERR_INCONS_VALUE);
307 uuser = usm_new_user(eid, elen, uname);
308 if (uuser == NULL)
309 return (SNMP_ERR_GENERR);
310 uuser->status = RowStatus_notReady;
311 if (community != COMM_INITIALIZE)
312 uuser->type = StorageType_volatile;
313 else
314 uuser->type = StorageType_readOnly;
315 } else if (val->v.integer != RowStatus_active &&
316 val->v.integer != RowStatus_destroy)
317 return (SNMP_ERR_INCONS_VALUE);
318
319 uuser->status = val->v.integer;
320 break;
321 }
322 return (SNMP_ERR_NOERROR);
323
324 case SNMP_OP_COMMIT:
325 switch (val->var.subs[sub - 1]) {
326 case LEAF_usmUserAuthKeyChange:
327 case LEAF_usmUserOwnAuthKeyChange:
328 case LEAF_usmUserPrivKeyChange:
329 case LEAF_usmUserOwnPrivKeyChange:
330 free(ctx->scratch->ptr1);
331 break;
332 case LEAF_usmUserPublic:
333 if (ctx->scratch->ptr2 != NULL)
334 free(ctx->scratch->ptr2);
335 break;
336 case LEAF_usmUserStatus:
337 if (val->v.integer != RowStatus_destroy)
338 break;
339 if ((uuser = usm_get_user(&val->var, sub)) == NULL)
340 return (SNMP_ERR_GENERR);
341 usm_delete_user(uuser);
342 break;
343 default:
344 break;
345 }
346 return (SNMP_ERR_NOERROR);
347
348 case SNMP_OP_ROLLBACK:
349 if ((uuser = usm_get_user(&val->var, sub)) == NULL)
350 return (SNMP_ERR_GENERR);
351 switch (val->var.subs[sub - 1]) {
352 case LEAF_usmUserAuthProtocol:
353 uuser->suser.auth_proto = ctx->scratch->int1;
354 break;
355 case LEAF_usmUserAuthKeyChange:
356 case LEAF_usmUserOwnAuthKeyChange:
357 memcpy(uuser->suser.auth_key, ctx->scratch->ptr1,
358 sizeof(uuser->suser.auth_key));
359 free(ctx->scratch->ptr1);
360 break;
361 case LEAF_usmUserPrivProtocol:
362 uuser->suser.priv_proto = ctx->scratch->int1;
363 break;
364 case LEAF_usmUserPrivKeyChange:
365 case LEAF_usmUserOwnPrivKeyChange:
366 memcpy(uuser->suser.priv_key, ctx->scratch->ptr1,
367 sizeof(uuser->suser.priv_key));
368 free(ctx->scratch->ptr1);
369 break;
370 case LEAF_usmUserPublic:
371 if (ctx->scratch->ptr2 != NULL) {
372 memcpy(uuser->user_public, ctx->scratch->ptr2,
373 ctx->scratch->int2);
374 uuser->user_public_len = ctx->scratch->int2;
375 free(ctx->scratch->ptr2);
376 } else {
377 memset(uuser->user_public, 0,
378 sizeof(uuser->user_public));
379 uuser->user_public_len = 0;
380 }
381 break;
382 case LEAF_usmUserCloneFrom:
383 case LEAF_usmUserStatus:
384 if (ctx->scratch->int1 == RowStatus_createAndWait)
385 usm_delete_user(uuser);
386 break;
387 default:
388 break;
389 }
390 return (SNMP_ERR_NOERROR);
391
392 default:
393 abort();
394 }
395
396 switch (val->var.subs[sub - 1]) {
397 case LEAF_usmUserSecurityName:
398 return (string_get(val, uuser->suser.sec_name, -1));
399 case LEAF_usmUserCloneFrom:
400 memcpy(&val->v.oid, &oid_zeroDotZero, sizeof(oid_zeroDotZero));
401 break;
402 case LEAF_usmUserAuthProtocol:
403 switch (uuser->suser.auth_proto) {
404 case SNMP_AUTH_HMAC_MD5:
405 memcpy(&val->v.oid, &oid_usmHMACMD5AuthProtocol,
406 sizeof(oid_usmHMACMD5AuthProtocol));
407 break;
408 case SNMP_AUTH_HMAC_SHA:
409 memcpy(&val->v.oid, &oid_usmHMACSHAAuthProtocol,
410 sizeof(oid_usmHMACSHAAuthProtocol));
411 break;
412 default:
413 memcpy(&val->v.oid, &oid_usmNoAuthProtocol,
414 sizeof(oid_usmNoAuthProtocol));
415 break;
416 }
417 break;
418 case LEAF_usmUserAuthKeyChange:
419 case LEAF_usmUserOwnAuthKeyChange:
420 return (string_get(val, (char *)uuser->suser.auth_key, 0));
421 case LEAF_usmUserPrivProtocol:
422 switch (uuser->suser.priv_proto) {
423 case SNMP_PRIV_DES:
424 memcpy(&val->v.oid, &oid_usmDESPrivProtocol,
425 sizeof(oid_usmDESPrivProtocol));
426 break;
427 case SNMP_PRIV_AES:
428 memcpy(&val->v.oid, &oid_usmAesCfb128Protocol,
429 sizeof(oid_usmAesCfb128Protocol));
430 break;
431 default:
432 memcpy(&val->v.oid, &oid_usmNoPrivProtocol,
433 sizeof(oid_usmNoPrivProtocol));
434 break;
435 }
436 break;
437 case LEAF_usmUserPrivKeyChange:
438 case LEAF_usmUserOwnPrivKeyChange:
439 return (string_get(val, (char *)uuser->suser.priv_key, 0));
440 case LEAF_usmUserPublic:
441 return (string_get(val, uuser->user_public,
442 uuser->user_public_len));
443 case LEAF_usmUserStorageType:
444 val->v.integer = uuser->type;
445 break;
446 case LEAF_usmUserStatus:
447 val->v.integer = uuser->status;
448 break;
449 }
450
451 return (SNMP_ERR_NOERROR);
452 }
453
454 static int
usm_user_index_decode(const struct asn_oid * oid,uint sub,uint8_t * engine,uint32_t * elen,char * uname)455 usm_user_index_decode(const struct asn_oid *oid, uint sub, uint8_t *engine,
456 uint32_t *elen, char *uname)
457 {
458 uint32_t i, nlen;
459 int uname_off;
460
461 if (oid->subs[sub] > SNMP_ENGINE_ID_SIZ)
462 return (-1);
463
464 for (i = 0; i < oid->subs[sub]; i++)
465 engine[i] = oid->subs[sub + i + 1];
466 *elen = i;
467
468 uname_off = sub + oid->subs[sub] + 1;
469 if ((nlen = oid->subs[uname_off]) >= SNMP_ADM_STR32_SIZ)
470 return (-1);
471
472 for (i = 0; i < nlen; i++)
473 uname[i] = oid->subs[uname_off + i + 1];
474 uname[nlen] = '\0';
475
476 return (0);
477 }
478
479 static void
usm_append_userindex(struct asn_oid * oid,uint sub,const struct usm_user * uuser)480 usm_append_userindex(struct asn_oid *oid, uint sub,
481 const struct usm_user *uuser)
482 {
483 uint32_t i;
484
485 oid->len = sub + uuser->user_engine_len + strlen(uuser->suser.sec_name);
486 oid->len += 2;
487 oid->subs[sub] = uuser->user_engine_len;
488 for (i = 1; i < uuser->user_engine_len + 1; i++)
489 oid->subs[sub + i] = uuser->user_engine_id[i - 1];
490
491 sub += uuser->user_engine_len + 1;
492 oid->subs[sub] = strlen(uuser->suser.sec_name);
493 for (i = 1; i <= oid->subs[sub]; i++)
494 oid->subs[sub + i] = uuser->suser.sec_name[i - 1];
495 }
496
497 static struct usm_user *
usm_get_user(const struct asn_oid * oid,uint sub)498 usm_get_user(const struct asn_oid *oid, uint sub)
499 {
500 uint32_t enginelen;
501 char username[SNMP_ADM_STR32_SIZ];
502 uint8_t engineid[SNMP_ENGINE_ID_SIZ];
503
504 if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0)
505 return (NULL);
506
507 return (usm_find_user(engineid, enginelen, username));
508 }
509
510 static struct usm_user *
usm_get_next_user(const struct asn_oid * oid,uint sub)511 usm_get_next_user(const struct asn_oid *oid, uint sub)
512 {
513 uint32_t enginelen;
514 char username[SNMP_ADM_STR32_SIZ];
515 uint8_t engineid[SNMP_ENGINE_ID_SIZ];
516 struct usm_user *uuser;
517
518 if (oid->len - sub == 0)
519 return (usm_first_user());
520
521 if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0)
522 return (NULL);
523
524 if ((uuser = usm_find_user(engineid, enginelen, username)) != NULL)
525 return (usm_next_user(uuser));
526
527 return (NULL);
528 }
529
530 /*
531 * USM snmp module initialization hook.
532 * Returns 0 on success, < 0 on error.
533 */
534 static int
usm_init(struct lmodule * mod,int argc __unused,char * argv[]__unused)535 usm_init(struct lmodule * mod, int argc __unused, char *argv[] __unused)
536 {
537 usm_module = mod;
538 usm_lock = random();
539 bsnmpd_reset_usm_stats();
540 return (0);
541 }
542
543 /*
544 * USM snmp module finalization hook.
545 */
546 static int
usm_fini(void)547 usm_fini(void)
548 {
549 usm_flush_users();
550 or_unregister(reg_usm);
551
552 return (0);
553 }
554
555 /*
556 * USM snmp module start operation.
557 */
558 static void
usm_start(void)559 usm_start(void)
560 {
561 reg_usm = or_register(&oid_usm,
562 "The MIB module for managing SNMP User-Based Security Model.",
563 usm_module);
564 }
565
566 static void
usm_dump(void)567 usm_dump(void)
568 {
569 struct usm_user *uuser;
570 struct snmpd_usmstat *usmstats;
571 const char *const authstr[] = {
572 "noauth",
573 "md5",
574 "sha",
575 NULL
576 };
577 const char *const privstr[] = {
578 "nopriv",
579 "des",
580 "aes",
581 NULL
582 };
583
584 if ((usmstats = bsnmpd_get_usm_stats()) != NULL) {
585 syslog(LOG_ERR, "UnsupportedSecLevels\t\t%u",
586 usmstats->unsupported_seclevels);
587 syslog(LOG_ERR, "NotInTimeWindows\t\t%u",
588 usmstats->not_in_time_windows);
589 syslog(LOG_ERR, "UnknownUserNames\t\t%u",
590 usmstats->unknown_users);
591 syslog(LOG_ERR, "UnknownEngineIDs\t\t%u",
592 usmstats->unknown_engine_ids);
593 syslog(LOG_ERR, "WrongDigests\t\t%u",
594 usmstats->wrong_digests);
595 syslog(LOG_ERR, "DecryptionErrors\t\t%u",
596 usmstats->decrypt_errors);
597 }
598
599 syslog(LOG_ERR, "USM users");
600 for (uuser = usm_first_user(); uuser != NULL;
601 (uuser = usm_next_user(uuser)))
602 syslog(LOG_ERR, "user %s\t\t%s, %s", uuser->suser.sec_name,
603 authstr[uuser->suser.auth_proto],
604 privstr[uuser->suser.priv_proto]);
605 }
606
607 static const char usm_comment[] =
608 "This module implements SNMP User-based Security Model defined in RFC 3414.";
609
610 extern const struct snmp_module config;
611 const struct snmp_module config = {
612 .comment = usm_comment,
613 .init = usm_init,
614 .fini = usm_fini,
615 .start = usm_start,
616 .tree = usm_ctree,
617 .dump = usm_dump,
618 .tree_size = usm_CTREE_SIZE,
619 };
620