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 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 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 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 * 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 * 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 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 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 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 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