]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/bsnmp/snmp_usm/usm_snmp.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / bsnmp / snmp_usm / usm_snmp.c
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
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
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
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
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
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 *
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 *
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
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
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
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
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 const char usm_comment[] = \
608 "This module implements SNMP User-based Security Model defined in RFC 3414.";
609
610 const struct snmp_module config = {
611         .comment =      usm_comment,
612         .init =         usm_init,
613         .fini =         usm_fini,
614         .start =        usm_start,
615         .tree =         usm_ctree,
616         .dump =         usm_dump,
617         .tree_size =    usm_CTREE_SIZE,
618 };