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