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