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 }; 619