/lib/snmp/src/manager/snmpm_config.erl
Erlang | 3436 lines | 2667 code | 443 blank | 326 comment | 12 complexity | fc2c18c5dd9e4923635fb9af07858fcd MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2004-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%% ------------------------------------------------------------------------- 21%% 22%% Some of the stuff stored here should really be persistent!! 23%% (e.g. snmp-engine-boot) 24%% 25%% ------------------------------------------------------------------------- 26 27-module(snmpm_config). 28 29-behaviour(gen_server). 30 31%% External exports 32%% Avoid warning for local function error/1 clashing with autoimported BIF. 33-compile({no_auto_import,[error/1]}). 34-export([start_link/1, stop/0, is_started/0]). 35-export([register_user/4, unregister_user/1, 36 which_users/0, 37 user_info/0, user_info/1, user_info/2, 38 39 register_agent/3, unregister_agent/2, 40 agent_info/0, agent_info/2, agent_info/3, 41 update_agent_info/3, update_agent_info/4, 42 which_agents/0, which_agents/1, 43 44 is_known_engine_id/2, 45 get_agent_engine_id/1, 46 get_agent_engine_max_message_size/1, 47 get_agent_version/1, 48 get_agent_mp_model/1, 49 get_agent_user_id/1, get_agent_user_id/2, 50 get_agent_user_info/2, 51 52 system_info/0, system_info/1, 53 %% update_system_info/2, 54 get_engine_id/0, get_engine_max_message_size/0, 55 56 register_usm_user/3, unregister_usm_user/2, 57 which_usm_users/0, which_usm_users/1, 58 usm_user_info/3, update_usm_user_info/4, 59 get_usm_user/2, get_usm_user_from_sec_name/2, 60 is_usm_engine_id_known/1, 61 get_engine_boots/0, get_engine_time/0, 62 set_engine_boots/1, set_engine_time/1, 63 get_usm_eboots/1, get_usm_etime/1, get_usm_eltime/1, 64 set_usm_eboots/2, set_usm_etime/2, set_usm_eltime/2, 65 reset_usm_cache/1, 66 67 68 cre_counter/2, 69 incr_counter/2, 70 increment_counter/3, increment_counter/4, 71 72 cre_stats_counter/2, 73 maybe_cre_stats_counter/2, 74 incr_stats_counter/2, 75 reset_stats_counter/1, 76 get_stats_counters/0, get_stats_counter/1, 77 78 load_mib/1, unload_mib/1, which_mibs/0, 79 make_mini_mib/0, 80 name_to_oid/1, oid_to_name/1, oid_to_type/1, 81 82 system_start_time/0, 83 84 info/0, 85 verbosity/1, 86 87 backup/1, 88 89 mk_target_name/3, 90 91 default_transport_domain/0 92 93 ]). 94 95%% Backward compatibillity exports 96-export([ 97 register_user/3, 98 unregister_agent/3, 99 update_agent_info/5, 100 is_known_engine_id/3, 101 get_agent_engine_id/2, 102 get_agent_engine_max_message_size/2, 103 get_agent_version/2, 104 get_agent_mp_model/2 105 ]). 106 107-export([ 108 order_manager_config/2, 109 check_manager_config/2, 110 check_user_config/1, 111 check_agent_config/1, 112 check_usm_user_config/1]). 113 114 115%% gen_server callbacks 116-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 117 code_change/3, terminate/2]). 118 119 120%% Includes: 121-include_lib("kernel/include/file.hrl"). 122-include("snmp_types.hrl"). 123-include("snmpm_internal.hrl"). 124-include("snmpm_usm.hrl"). 125-include("snmp_debug.hrl"). 126-include("snmp_verbosity.hrl"). 127 128 129%% Types: 130-record(user, {id, mod, data, default_agent_config}). 131 132-record(state, {backup}). 133 134 135%% Macros and Constants: 136-define(SERVER, ?MODULE). 137-define(BACKUP_DB, snmpm_config_backup). 138-define(CONFIG_DB, snmpm_config_db). 139 140-define(DEFAULT_USER, default_user). 141 142-define(DEFAULT_AGENT_PORT, 161). 143 144-define(IRB_DEFAULT, auto). 145%% -define(IRB_DEFAULT, {user, timer:seconds(15)}). 146 147-define(USER_MOD_DEFAULT, snmpm_user_default). 148-define(USER_DATA_DEFAULT, undefined). 149 150%% -define(DEF_ADDR_TAG, default_addr_tag). 151-define(DEFAULT_TARGETNAME, default_agent). 152-define(DEF_PORT_TAG, default_port_tag). 153-define(SUPPORTED_DOMAINS, [transportDomainUdpIpv4, transportDomainUdpIpv6]). 154 155-ifdef(snmp_debug). 156-define(GS_START_LINK(Opts), 157 gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], 158 [{debug,[trace]}])). 159-else. 160-define(GS_START_LINK(Opts), 161 gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], [])). 162-endif. 163 164 165 166%%%------------------------------------------------------------------- 167%%% API 168%%%------------------------------------------------------------------- 169 170default_transport_domain() -> 171 snmpUDPDomain. 172 173 174start_link(Opts) -> 175 ?d("start_link -> entry with" 176 "~n Opts: ~p", [Opts]), 177 ?GS_START_LINK(Opts). 178 179stop() -> 180 call(stop). 181 182is_started() -> 183 call(is_started, 1000). 184 185backup(BackupDir) when is_list(BackupDir) -> 186 call({backup, BackupDir}). 187 188%% Backward compatibillity 189register_user(UserId, UserMod, UserData) -> 190 register_user(UserId, UserMod, UserData, []). 191 192register_user(UserId, UserMod, UserData, DefaultAgentConfig) 193 when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> 194 case (catch verify_user_behaviour(UserMod)) of 195 ok -> 196 {ok, SystemDefaultAgentConfig} = agent_info(), 197 Config = 198 ensure_config(SystemDefaultAgentConfig, 199 DefaultAgentConfig), 200%% Config = default_agent_config(DefaultAgentConfig), 201 call({register_user, UserId, UserMod, UserData, Config}); 202 Error -> 203 Error 204 end; 205register_user(UserId, _UserMod, _UserData, DefaultAgentConfig) 206 when (UserId =/= ?DEFAULT_USER) -> 207 {error, {bad_default_agent_config, DefaultAgentConfig}}; 208register_user(UserId, _, _, _) -> 209 {error, {bad_user_id, UserId}}. 210 211%% default_agent_config(DefaultAgentConfig) -> 212%% {ok, SystemDefaultAgentConfig} = agent_info(), 213%% default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig). 214 215%% default_agent_config([], DefaultAgentConfig) -> 216%% DefaultAgentConfig; 217%% default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) -> 218%% case lists:keymember(Key, 1, DefaultAgentConfig) of 219%% true -> 220%% default_agent_config(T, DefaultAgentConfig); 221%% false -> 222%% default_agent_config(T, [Entry|DefaultAgentConfig]) 223%% end. 224 225 226verify_user_behaviour(UserMod) -> 227 case snmp_misc:verify_behaviour(snmpm_user, UserMod) of 228 ok -> 229 ok; 230 Error -> 231 %% This user may implement the old behaviour, check it 232 case snmp_misc:verify_behaviour(snmpm_user_old, UserMod) of 233 ok -> 234 ok; 235 _ -> 236 throw(Error) 237 end 238 end. 239 240 241unregister_user(UserId) when UserId =/= ?DEFAULT_USER -> 242 call({unregister_user, UserId}); 243unregister_user(BadUserId) -> 244 {error, {bad_user_id, BadUserId}}. 245 246 247which_users() -> 248 Pattern = #user{id = '$1', _ = '_'}, 249 Match = ets:match(snmpm_user_table, Pattern), 250 [UserId || [UserId] <- Match, UserId =/= ?DEFAULT_USER]. 251 252 253user_info() -> 254 UserId = ?DEFAULT_USER, 255 case user_info(UserId) of 256 {ok, Mod, Data} -> 257 {ok, UserId, Mod, Data}; 258 Error -> 259 Error 260 end. 261 262user_info(UserId) -> 263 case ets:lookup(snmpm_user_table, UserId) of 264 [#user{mod = UserMod, data = UserData}] -> 265 {ok, UserMod, UserData}; 266 _ -> 267 {error, not_found} 268 end. 269 270user_info(UserId, Item) -> 271 case (catch do_user_info(UserId, Item)) of 272 {'EXIT', _} -> 273 {error, {not_found, Item}}; 274 Val -> 275 {ok, Val} 276 end. 277 278do_user_info(UserId, module) -> 279 ets:lookup_element(snmpm_user_table, UserId, #user.mod); 280do_user_info(UserId, data) -> 281 ets:lookup_element(snmpm_user_table, UserId, #user.data); 282do_user_info(UserId, default_agent_config) -> 283 ets:lookup_element(snmpm_user_table, UserId, #user.default_agent_config); 284do_user_info(_UserId, BadItem) -> 285 error({not_found, BadItem}). 286 287 288%% A target-name constructed in this way is a string with the following: 289%% <IP-address>:<Port>-<Version> 290%% This is intended for backward compatibility and therefore has 291%% only support for IPv4 addresses and *no* other transport domain. 292mk_target_name(Domain, Addr, Config) 293 when is_atom(Domain), is_list(Config) -> 294 Version = 295 case lists:keysearch(version, 1, Config) of 296 {value, {_, V}} -> 297 V; 298 false -> 299 select_lowest_supported_version() 300 end, 301 try 302 lists:flatten( 303 io_lib:format( 304 "~s-~w", [snmp_conf:mk_addr_string({Domain, Addr}), Version])) 305 catch 306 _ -> 307 lists:flatten( 308 io_lib:format("~p-~w", [Addr, Version])) 309 end; 310mk_target_name(Ip, Port, Config) 311 when is_integer(Port), is_list(Config) -> 312 Domain = default_transport_domain(), 313 try fix_address(Domain, {Ip, Port}) of 314 Address -> 315 mk_target_name(Domain, Address, Config) 316 catch 317 _ -> 318 Version = 319 case lists:keysearch(version, 1, Config) of 320 {value, {_, V}} -> 321 V; 322 false -> 323 select_lowest_supported_version() 324 end, 325 lists:flatten( 326 io_lib:format("~p:~w-~w", [Ip, Port, Version])) 327 end. 328 329 330select_lowest_supported_version() -> 331 {ok, Versions} = system_info(versions), 332 select_lowest_supported_version([v1, v2, v3], Versions). 333 334select_lowest_supported_version([], Versions) -> 335 error({bad_versions, Versions}); 336select_lowest_supported_version([H|T], Versions) -> 337 case lists:member(H, Versions) of 338 true -> 339 H; 340 false -> 341 select_lowest_supported_version(T, Versions) 342 end. 343 344 345register_agent(UserId, _TargetName, _Config0) when (UserId =:= user_id) -> 346 {error, {bad_user_id, UserId}}; 347register_agent(UserId, TargetName, Config0) 348 when (is_list(TargetName) andalso 349 (length(TargetName) > 0) andalso 350 is_list(Config0)) -> 351 352 ?vtrace("register_agent -> entry with" 353 "~n UserId: ~p" 354 "~n TargetName: ~p" 355 "~n Config0: ~p", [UserId, TargetName, Config0]), 356 357 %% Check: 358 %% 1) That the mandatory configs are present 359 %% 2) That no illegal config, e.g. user_id (used internally), 360 %% is not present 361 %% 3) Check that there are no invalid or erroneous configs 362 %% 4) Check that the manager is capable of using the selected version 363 try 364 verify_mandatory(Config0, [engine_id, reg_type]), 365 verify_someof(Config0, [address, taddress]), 366 verify_illegal(Config0, [user_id]), 367 Config = verify_agent_config(Config0), 368 Vsns = versions(), 369 Vsn = which_version(Config), 370 verify_version(Vsn, Vsns), 371 call({register_agent, UserId, TargetName, Config}) 372 catch 373 Error -> 374 Error 375 end. 376 377versions() -> 378 case system_info(versions) of 379 {ok, Vsns} -> 380 Vsns; 381 {error, _} = ERROR -> 382 throw(ERROR) 383 end. 384 385which_version(Conf) -> 386 case lists:keysearch(version, 1, Conf) of 387 {value, {version, V}} -> 388 V; 389 false -> 390 v1 391 end. 392 393verify_version(Vsn, Vsns) -> 394 case lists:member(Vsn, Vsns) of 395 true -> 396 ok; 397 false -> 398 Reason = {version_not_supported_by_manager, Vsn, Vsns}, 399 error(Reason) 400 end. 401 402 403 404unregister_agent(UserId, TargetName) -> 405 call({unregister_agent, UserId, TargetName}). 406 407%% This is the old style agent unregistration (using Addr and Port). 408unregister_agent(UserId, Domain, Address) when is_atom(Domain) -> 409 try fix_address(Domain, Address) of 410 NAddress -> 411 do_unregister_agent(UserId, Domain, NAddress) 412 catch 413 _ -> 414 {error, not_found} 415 end; 416unregister_agent(UserId, Ip, Port) when is_integer(Port) -> 417 Domain = default_transport_domain(), 418 try fix_address(Domain, {Ip, Port}) of 419 Address -> 420 do_unregister_agent(UserId, Domain, Address) 421 catch 422 _ -> 423 {error, not_found} 424 end. 425 426do_unregister_agent(UserId, Domain, Address) -> 427 case do_agent_info(Domain, Address, target_name) of 428 {ok, TargetName} -> 429 unregister_agent(UserId, TargetName); 430 Error -> 431 Error 432 end. 433 434 435 436agent_info() -> 437 agent_info(?DEFAULT_TARGETNAME, all). 438 439agent_info(TargetName, all) -> 440 case ets:match_object(snmpm_agent_table, {{TargetName, '_'}, '_'}) of 441 [] -> 442 {error, not_found}; 443 All -> 444 {ok, [{Item, Val} || {{_, Item}, Val} <- All]} 445 end; 446%% Begin backwards compatibility 447agent_info(TargetName, address) -> 448 case agent_info({TargetName, taddress}) of 449 {ok, Val} -> 450 {Addr, _} = Val, 451 {ok, Addr}; 452 _ -> 453 %% This should be redundant since 'taddress' should exist 454 agent_info({TargetName, address}) 455 end; 456agent_info(TargetName, port) -> 457 case agent_info({TargetName, taddress}) of 458 {ok, Val} -> 459 {_, Port} = Val, 460 {ok, Port}; 461 _ -> 462 %% This should be redundant since 'taddress' should exist 463 agent_info({TargetName, port}) 464 end; 465%% End backwards compatibility 466agent_info(TargetName, Item) -> 467 agent_info({TargetName, Item}). 468 469agent_info(Key) -> 470 case ets:lookup(snmpm_agent_table, Key) of 471 [{_, Val}] -> 472 {ok, Val}; 473 [] -> 474 {error, not_found} 475 end. 476 477agent_info(Domain, Address, Item) when is_atom(Domain) -> 478 try fix_address(Domain, Address) of 479 NAddress -> 480 do_agent_info(Domain, NAddress, Item) 481 catch 482 _Thrown -> 483 %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n" 484 %% " ~p", 485 %% [Domain, Address, Item, _Thrown, erlang:get_stacktrace()]), 486 {error, not_found} 487 end; 488agent_info(Ip, Port, Item) when is_integer(Port) -> 489 %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) entry~n", 490 %% [Ip, Port, Item]), 491 Domain = default_transport_domain(), 492 try fix_address(Domain, {Ip, Port}) of 493 Address -> 494 do_agent_info(Domain, Address, Item) 495 catch 496 _Thrown -> 497 %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n" 498 %% " ~p", 499 %% [Ip, Port, Item, _Thrown, erlang:get_stacktrace()]), 500 {error, not_found} 501 end. 502 503do_agent_info(Domain, Address, target_name = Item) -> 504 %% p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n", 505 %% [Domain, Address, Item]), 506 case ets:lookup(snmpm_agent_table, {Domain, Address, Item}) of 507 [{_, Val}] -> 508 {ok, Val}; 509 [] -> 510 {error, not_found} 511 end; 512do_agent_info(Domain, Address, Item) -> 513 %% p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n", 514 %% [Domain, Address, Item]), 515 case do_agent_info(Domain, Address, target_name) of 516 {ok, TargetName} -> 517 agent_info(TargetName, Item); 518 Error -> 519 Error 520 end. 521 522 523ensure_agent_info(_, [], Info) -> 524 Info; 525ensure_agent_info(TargetName, [Item|Items], Info) -> 526 case lists:keymember(Item, 1, Info) of 527 true -> 528 ensure_agent_info(TargetName, Items, Info); 529 false -> 530 {ok, Value} = agent_info(TargetName, Item), 531 ensure_agent_info(TargetName, Items, [{Item, Value}|Info]) 532 end. 533 534 535 536which_agents() -> 537 which_agents('_'). 538 539which_agents(UserId) -> 540 Pat = {{'$1', user_id}, UserId}, 541 Agents = ets:match(snmpm_agent_table, Pat), 542 [TargetName || [TargetName] <- Agents]. 543 544 545 546update_agent_info(UserId, TargetName, Info) -> 547 call({update_agent_info, UserId, TargetName, Info}). 548 549%% <BACKWARD-COMPAT-2> 550%% This is wrapped in the interface module, so this function is 551%% only here to catch code-upgrade problems. 552update_agent_info(UserId, TargetName, Item, Val) -> 553 update_agent_info(UserId, TargetName, [{Item, Val}]). 554%% </BACKWARD-COMPAT-2> 555 556%% <BACKWARD-COMPAT-1> 557update_agent_info(UserId, Addr, Port, Item, Val) -> 558 case agent_info(Addr, Port, target_name) of 559 {ok, TargetName} -> 560 update_agent_info(UserId, TargetName, Item, Val); 561 Error -> 562 Error 563 end. 564%% </BACKWARD-COMPAT-1> 565 566is_known_engine_id(EngineID, TargetName) -> 567 case agent_info(TargetName, engine_id) of 568 {ok, EngineID} -> 569 true; 570 {ok, _OtherEngineID} -> 571 false; 572 _ -> 573 false 574 end. 575 576%% Backward compatibillity 577is_known_engine_id(EngineID, Addr, Port) -> 578 case agent_info(Addr, Port, target_name) of 579 {ok, TargetName} -> 580 is_known_engine_id(EngineID, TargetName); 581 _ -> 582 false 583 end. 584 585get_agent_engine_id(TargetName) -> 586 agent_info(TargetName, engine_id). 587 588%% Backward compatibillity 589get_agent_engine_id(Addr, Port) -> 590 agent_info(Addr, Port, engine_id). 591 592get_agent_engine_max_message_size(TargetName) -> 593 agent_info(TargetName, max_message_size). 594 595%% Backward compatibillity 596get_agent_engine_max_message_size(Addr, Port) -> 597 agent_info(Addr, Port, max_message_size). 598 599get_agent_version(TargetName) -> 600 agent_info(TargetName, version). 601 602%% Backward compatibillity 603get_agent_version(Addr, Port) -> 604 agent_info(Addr, Port, version). 605 606get_agent_mp_model(TargetName) -> 607 case agent_info(TargetName, version) of 608 {ok, v2} -> 609 {ok, v2c}; 610 {ok, V} -> 611 {ok, V}; 612 Err -> 613 Err 614 end. 615 616%% Backward compatibillity 617get_agent_mp_model(Addr, Port) -> 618 case agent_info(Addr, Port, target_name) of 619 {ok, TargetName} -> 620 get_agent_mp_model(TargetName); 621 Error -> 622 Error 623 end. 624 625get_agent_user_id(TargetName) -> 626 agent_info(TargetName, user_id). 627 628get_agent_user_id(Addr, Port) -> 629 agent_info(Addr, Port, user_id). 630 631get_agent_user_info(Addr, Port) -> 632 case agent_info(Addr, Port, target_name) of 633 {ok, Target} -> 634 case agent_info(Target, reg_type) of 635 {ok, RegType} -> 636 case agent_info(Target, user_id) of 637 {ok, UserId} -> 638 {ok, UserId, Target, RegType}; 639 {error, not_found} -> 640 {error, {user_id_not_found, Target}} 641 end; 642 {error, not_found} -> 643 {error, {reg_type_not_found, Target}} 644 end; 645 {error, not_found} -> 646 {error, {target_name_not_found, Addr, Port}} 647 end. 648 649 650 651system_info() -> 652 system_info(all). 653 654system_info(all) -> 655 lists:sort(ets:tab2list(snmpm_config_table)); 656system_info(Key) when is_atom(Key) -> 657 case ets:lookup(snmpm_config_table, Key) of 658 [{_, Val}] -> 659 {ok, Val}; 660 _ -> 661 {error, not_found} 662 end. 663 664%% update_system_info(Key, Val) -> 665%% call({update_system_info, Key, Val}). 666 667system_start_time() -> 668 system_info(system_start_time). 669 670get_engine_id() -> 671 system_info(engine_id). 672 673get_engine_max_message_size() -> 674 system_info(max_message_size). 675 676get_engine_boots() -> 677 case dets:lookup(?CONFIG_DB, snmp_engine_boots) of 678 [{_, Boots}] -> 679 {ok, Boots}; 680 _ -> 681 {error, not_found} 682 end. 683 684set_engine_boots(Boots) -> 685 case (whereis(?SERVER) =:= self()) of 686 false -> 687 call({set_engine_boots, Boots}); 688 true -> 689 dets:insert(?CONFIG_DB, {snmp_engine_boots, Boots}), 690 ok 691 end. 692 693 694get_engine_time() -> 695 case system_info(snmp_engine_base) of 696 {ok, EngineBase} -> 697 {ok, snmp_misc:now(sec) - EngineBase}; 698 Error -> 699 Error 700 end. 701 702get_usm_eboots(SnmpEngineID) -> 703 Key = {eboots, SnmpEngineID}, 704 case get_usm_cache(Key) of 705 {ok, Boots} -> 706 {ok, Boots}; 707 _ -> 708 {ok, 0} 709 end. 710 711get_usm_etime(SnmpEngineID) -> 712 Key = {etime, SnmpEngineID}, 713 case get_usm_cache(Key) of 714 {ok, Diff} -> 715 {ok, snmp_misc:now(sec) - Diff}; 716 _ -> 717 {ok, 0} 718 end. 719 720get_usm_eltime(SnmpEngineID) -> 721 Key = {eltime, SnmpEngineID}, 722 case get_usm_cache(Key) of 723 {ok, Time} -> 724 {ok, Time}; 725 _ -> 726 {ok, 0} 727 end. 728 729get_usm_cache(Key) -> 730 case ets:lookup(snmpm_usm_table, {usm_cache, Key}) of 731 [{_, Val}] -> 732 {ok, Val}; 733 _ -> 734 {error, not_found} 735 end. 736 737set_usm_eboots(SnmpEngineID, EngineBoots) -> 738 set_usm_cache({eboots, SnmpEngineID}, EngineBoots). 739 740set_usm_etime(SnmpEngineID, Diff) -> 741 set_usm_cache({etime, SnmpEngineID}, Diff). 742 743set_usm_eltime(SnmpEngineID, Time) -> 744 set_usm_cache({eltime, SnmpEngineID}, Time). 745 746set_usm_cache(Key, Val) -> 747 call({set_usm_cache, Key, Val}). 748 749reset_usm_cache(SnmpEngineID) -> 750 case (whereis(?SERVER) =:= self()) of 751 false -> 752 call({reset_usm_cache, SnmpEngineID}); 753 true -> 754 Pat = {{usm_cache, {'_', SnmpEngineID}}, '_'}, 755 ets:match_delete(snmpm_usm_table, Pat), 756 ok 757 end. 758 759set_engine_time(Time) -> 760 call({set_engine_time, Time}). 761 762register_usm_user(EngineID, Name, Config) 763 when is_list(EngineID) andalso is_list(Name) -> 764 case verify_usm_user_config(EngineID, Name, Config) of 765 {ok, User} -> 766 call({register_usm_user, User}); 767 Error -> 768 Error 769 end. 770 771unregister_usm_user(EngineID, Name) 772 when is_list(EngineID) andalso is_list(Name) -> 773 call({unregister_usm_user, EngineID, Name}). 774 775verify_usm_user_config(EngineID, Name, Config) -> 776 try 777 begin 778 verify_mandatory(Config, []), 779 verify_illegal(Config, [engine_id, name]), 780 verify_usm_user_config2(EngineID, Name, Config) 781 end 782 catch 783 throw:Error -> 784 Error 785 end. 786 787verify_usm_user_config2(EngineID, Name, Config) -> 788 SecName = verify_usm_user_get(sec_name, Name, Config), 789 Auth = verify_usm_user_get(auth, usmNoAuthProtocol, Config), 790 AuthKey = verify_usm_user_get(auth_key, [], Config), 791 Priv = verify_usm_user_get(priv, usmNoPrivProtocol, Config), 792 PrivKey = verify_usm_user_get(priv_key, [], Config), 793 User = {EngineID, Name, SecName, Auth, AuthKey, Priv, PrivKey}, 794 verify_usm_user(User). 795 796verify_usm_user_get(Item, Default, Config) -> 797 case lists:keysearch(Item, 1, Config) of 798 {value, {_, Val}} -> 799 Val; 800 false -> 801 Default 802 end. 803 804which_usm_users() -> 805 Pattern = {usm_key('$1', '$2'), '_'}, 806 Match = ets:match(snmpm_usm_table, Pattern), 807 [{EngineID, UserName} || [EngineID, UserName] <- Match]. 808 809which_usm_users(EngineID) -> 810 Pattern = {usm_key(EngineID, '$1'), '_'}, 811 Match = ets:match(snmpm_usm_table, Pattern), 812 [UserName || [UserName] <- Match]. 813 814usm_user_info(EngineID, UserName, Item) -> 815 case ets:lookup(snmpm_usm_table, usm_key(EngineID, UserName)) of 816 [] -> 817 {error, not_found}; 818 [{_Key, UsmUser}] -> 819 do_usm_user_info(UsmUser, Item) 820 end. 821 822do_usm_user_info(#usm_user{sec_name = SecName}, sec_name) -> 823 {ok, SecName}; 824do_usm_user_info(#usm_user{auth = AuthP}, auth) -> 825 {ok, AuthP}; 826do_usm_user_info(#usm_user{auth_key = AuthKey}, auth_key) -> 827 {ok, AuthKey}; 828do_usm_user_info(#usm_user{priv = PrivP}, priv) -> 829 {ok, PrivP}; 830do_usm_user_info(#usm_user{priv_key = PrivKey}, priv_key) -> 831 {ok, PrivKey}; 832do_usm_user_info(#usm_user{engine_id = EngineID}, engine_id) -> 833 {ok, EngineID}; 834do_usm_user_info(#usm_user{name = Name}, name) -> 835 {ok, Name}; 836do_usm_user_info(_, Item) -> 837 {error, {bad_iten, Item}}. 838 839update_usm_user_info(EngineID, UserName, Item, Val) 840 when (Item =/= engine_id) andalso (Item =/= name) -> 841 call({update_usm_user_info, EngineID, UserName, Item, Val}). 842 843get_usm_user(EngineID, UserName) -> 844 Key = usm_key(EngineID, UserName), 845 case ets:lookup(snmpm_usm_table, Key) of 846 [{_, User}] -> 847 {ok, User}; 848 _ -> 849 {error, not_found} 850 end. 851 852is_usm_engine_id_known(EngineID) -> 853 Pattern = {usm_key(EngineID, '$1'), '_'}, 854 case ets:match(snmpm_usm_table, Pattern) of 855 [] -> 856 false; 857 _ -> 858 true 859 end. 860 861get_usm_user_from_sec_name(EngineID, SecName) -> 862 %% Since the normal mapping between UserName and SecName is the 863 %% identity-function, we first try to use the SecName as UserName, 864 %% and check the resulting row. If it doesn't match, we'll have to 865 %% loop through the entire table. 866 Key = usm_key(EngineID, SecName), 867 case ets:lookup(snmpm_usm_table, Key) of 868 [{Key, #usm_user{sec_name = SecName} = User}] -> 869 {ok, User}; 870 _ -> 871 %% That did not work, so we have to search 872 Pattern = {usm_key(EngineID, '_'), 873 #usm_user{sec_name = SecName, _ = '_'}}, 874 case ets:match_object(snmpm_usm_table, Pattern) of 875 [{_, User}|_] -> 876 {ok, User}; 877 _ -> 878 {error, not_found} 879 end 880 end. 881 882 883%% Wrap-counters (wrapping at 2147483647 or 4294967295) 884cre_counter(Counter, Initial) -> 885 case (whereis(?SERVER) =:= self()) of 886 false -> 887 call({cre_counter, Counter, Initial}); 888 true -> 889 ets:insert(snmpm_counter_table, {Counter, Initial}), 890 Initial 891 end. 892 893incr_counter(usm_salt, Incr) -> % Backward compatibillity (upgrade) 894 incr_counter(usm_des_salt, Incr); % Backward compatibillity (upgrade) 895incr_counter(usm_des_salt, Incr) -> 896 incr_counter(usm_des_salt, Incr, 4294967295); 897incr_counter(usm_aes_salt, Incr) -> 898 incr_counter(usm_aes_salt, Incr, 36893488147419103231); 899incr_counter(Counter, Incr) -> 900 incr_counter(Counter, Incr, 2147483647). 901 902incr_counter(Counter, Incr, Wrap) -> 903 case (catch ets:update_counter(snmpm_counter_table, Counter, Incr)) of 904 {'EXIT', _} -> 905 cre_counter(Counter, Incr); 906 NewVal when NewVal =< Wrap -> 907 NewVal; 908 N -> 909 cre_counter(Counter, N - Wrap) 910 end. 911 912 913%% <ATL Sequence Number> 914increment_counter(Counter, Initial, Max) -> 915 Increment = 1, 916 increment_counter(Counter, Initial, Increment, Max). 917 918increment_counter(Counter, Initial, Increment, Max) -> 919 %% This is to make sure no one else increments our counter 920 Key = {Counter, self()}, 921 922 %% Counter data 923 Position = 2, 924 Threshold = Max, 925 SetValue = Initial, 926 UpdateOp = {Position, Increment, Threshold, SetValue}, 927 928 %% And now for the actual increment 929 Tab = snmpm_counter_table, 930 case (catch ets:update_counter(Tab, Key, UpdateOp)) of 931 {'EXIT', {badarg, _}} -> 932 %% Oups, first time 933 ets:insert(Tab, {Key, Initial}), 934 Initial; 935 Next when is_integer(Next) -> 936 Next 937 end. 938%% </ATL Sequence Number> 939 940 941maybe_cre_stats_counter(Counter, Initial) -> 942 case ets:lookup(snmpm_stats_table, Counter) of 943 [_] -> 944 ok; 945 _ -> 946 cre_stats_counter(Counter, Initial) 947 end. 948 949cre_stats_counter(Counter, Initial) -> 950 case (whereis(?SERVER) =:= self()) of 951 false -> 952 call({cre_stats_counter, Counter, Initial}); 953 true -> 954 ets:insert(snmpm_stats_table, {Counter, Initial}), 955 Initial 956 end. 957 958incr_stats_counter(Counter, Incr) -> 959 case (catch ets:update_counter(snmpm_stats_table, Counter, Incr)) of 960 {'EXIT', _} -> 961 cre_counter(Counter, Incr); 962 NewVal -> 963 NewVal 964 end. 965 966reset_stats_counter(Counter) -> 967 case (whereis(?SERVER) =:= self()) of 968 false -> 969 call({reset_stats_counter, Counter}); 970 true -> 971 ets:insert(snmpm_stats_table, {Counter, 0}) 972 end, 973 ok. 974 975get_stats_counter(Counter) -> 976 case ets:lookup(snmpm_stats_table, Counter) of 977 [{Counter, Value}] -> 978 {ok, Value}; 979 _ -> 980 {error, not_found} 981 end. 982 983get_stats_counters() -> 984 ets:tab2list(snmpm_stats_table). 985 986load_mib(Mib) when is_list(Mib) -> 987 call({load_mib, Mib}). 988 989unload_mib(Mib) when is_list(Mib) -> 990 call({unload_mib, Mib}). 991 992which_mibs() -> 993 Pattern = {{mib, '_'}, '$1', '$2'}, 994 Mibs = ets:match(snmpm_mib_table, Pattern), 995 [list_to_tuple(X) || X <- Mibs]. 996 997name_to_oid(Name) -> 998 Pat = {{mini_mib, '$1'}, Name, '_', '_'}, 999 case ets:match(snmpm_mib_table, Pat) of 1000 [] -> 1001 {error, not_found}; 1002 X -> 1003 Oids = [Oid || [Oid] <- X], 1004 {ok, Oids} 1005 end. 1006 1007oid_to_name(Oid) -> 1008 case ets:lookup(snmpm_mib_table, {mini_mib, Oid}) of 1009 [{_, Name, _, _}] -> 1010 {ok, Name}; 1011 [] -> 1012 {error, not_found} 1013 end. 1014 1015oid_to_type(Oid) -> 1016 case ets:lookup(snmpm_mib_table, {mini_mib, Oid}) of 1017 [{_, _, Type, _}] -> 1018 {ok, Type}; 1019 [] -> 1020 {error, not_found} 1021 end. 1022 1023make_mini_mib() -> 1024 Pat = {{mini_mib, '$1'}, '$2', '$3', '_'}, 1025 MiniElems = ets:match(snmpm_mib_table, Pat), 1026 lists:keysort(1, [list_to_tuple(MiniElem) || MiniElem <- MiniElems]). 1027 1028 1029info() -> 1030 call(info). 1031 1032verbosity(Verbosity) -> 1033 case ?vvalidate(Verbosity) of 1034 Verbosity -> 1035 call({verbosity, Verbosity}); 1036 _ -> 1037 {error, {invalid_verbosity, Verbosity}} 1038 end. 1039 1040 1041%%%------------------------------------------------------------------- 1042%%% Callback functions from gen_server 1043%%%------------------------------------------------------------------- 1044 1045%%-------------------------------------------------------------------- 1046%% Func: init/1 1047%% Returns: {ok, State} | 1048%% {ok, State, Timeout} | 1049%% ignore | 1050%% {stop, Reason} 1051%%-------------------------------------------------------------------- 1052init([Opts]) -> 1053% put(sname, mconf), 1054% put(verbosity, trace), 1055 ?d("init -> entry with" 1056 "~n Opts: ~p", [Opts]), 1057 case (catch do_init(Opts)) of 1058 ok -> 1059 {ok, #state{}}; 1060 {error, Reason} -> 1061 error_msg("init error: ~p", [Reason]), 1062 {stop, Reason}; 1063 {'EXIT', Reason} -> 1064 error_msg("init exit: ~p", [Reason]), 1065 {stop, Reason}; 1066 Error -> 1067 error_msg("init failed: ~p", [Error]), 1068 {stop, Error} 1069 end. 1070 1071do_init(Opts) -> 1072 process_flag(trap_exit, true), 1073 %% Mandatory = [versions, {config, [dir]}], 1074 Mandatory = [{config, [dir, db_dir]}], 1075 verify_options(Opts, Mandatory), 1076 1077 ets:new(snmpm_counter_table, [set, public, named_table, {keypos, 1}]), 1078 ets:new(snmpm_stats_table, [set, public, named_table, {keypos, 1}]), 1079 ets:new(snmpm_mib_table, [set, protected, named_table, {keypos, 1}]), 1080 ets:new(snmpm_config_table, [set, protected, named_table, {keypos, 1}]), 1081 ets:new(snmpm_agent_table, [set, protected, named_table, {keypos, 1}]), 1082 ets:new(snmpm_user_table, [set, protected, named_table, {keypos, 2}]), 1083 ets:new(snmpm_usm_table, [set, protected, named_table, {keypos, 1}]), 1084 1085 %% -- System start time -- 1086 ets:insert(snmpm_config_table, {system_start_time, snmp_misc:now(cs)}), 1087 1088 %% --- Own options (dir and db_dir mandatory) --- 1089 ConfOpts = get_opt(config, Opts, []), 1090 ConfVerb = get_opt(verbosity, ConfOpts, silence), 1091 ConfDir = get_opt(dir, ConfOpts), 1092 ConfDbDir = get_opt(db_dir, ConfOpts), 1093 ConfDbInitErr = get_opt(db_init_error, ConfOpts, terminate), 1094 ConfRep = get_opt(repair, ConfOpts, true), 1095 ConfAs = get_opt(auto_save, ConfOpts, 5000), 1096 ets:insert(snmpm_config_table, {config_verbosity, ConfVerb}), 1097 ets:insert(snmpm_config_table, {config_dir, ConfDir}), 1098 ets:insert(snmpm_config_table, {config_db_dir, ConfDbDir}), 1099 ets:insert(snmpm_config_table, {config_db_init_error, ConfDbInitErr}), 1100 ets:insert(snmpm_config_table, {config_repair, ConfRep}), 1101 ets:insert(snmpm_config_table, {config_auto_save, ConfAs}), 1102 put(sname, mconf), 1103 put(verbosity, ConfVerb), 1104 ?vlog("starting", []), 1105 1106 %% -- Create dets file used for storing persistent data -- 1107 dets_open(ConfDbDir, ConfDbInitErr, ConfRep, ConfAs), 1108 1109 %% -- Prio (optional) -- 1110 Prio = get_opt(priority, Opts, normal), 1111 ets:insert(snmpm_config_table, {prio, Prio}), 1112 try process_flag(priority, Prio) 1113 catch 1114 error:badarg -> 1115 error({invalid_priority,Prio}) 1116 end, 1117 1118 %% -- Server (optional) -- 1119 ServerOpts = get_opt(server, Opts, []), 1120 ServerVerb = get_opt(verbosity, ServerOpts, silence), 1121 ServerGct = get_opt(timeout, ServerOpts, 30000), 1122 ServerMt = get_opt(multi_threaded, ServerOpts, true), 1123 ets:insert(snmpm_config_table, {server_verbosity, ServerVerb}), 1124 ets:insert(snmpm_config_table, {server_timeout, ServerGct}), 1125 ets:insert(snmpm_config_table, {server_multi_threaded, ServerMt}), 1126 1127 %% -- Mibs (optional) -- 1128 ?vdebug("initiate mini mib", []), 1129 Mibs = get_opt(mibs, Opts, []), 1130 ets:insert(snmpm_config_table, {mibs, Mibs}), 1131 init_mini_mib(Mibs), 1132 1133 %% -- Net-if (optional) -- 1134 ?vdebug("net_if options", []), 1135 NetIfIrb = 1136 case get_opt(inform_request_behaviour, Opts, ?IRB_DEFAULT) of 1137 user -> 1138 {user, timer:seconds(15)}; 1139 Irb -> 1140 Irb 1141 end, 1142 NetIfOpts = get_opt(net_if, Opts, []), 1143 NetIfMod = get_opt(module, NetIfOpts, snmpm_net_if), 1144 NetIfVerb = get_opt(verbosity, NetIfOpts, silence), 1145 NetIfOptions = get_opt(options, NetIfOpts, []), 1146 ets:insert(snmpm_config_table, {net_if_module, NetIfMod}), 1147 ets:insert(snmpm_config_table, {net_if_verbosity, NetIfVerb}), 1148 ets:insert(snmpm_config_table, {net_if_irb, NetIfIrb}), 1149 ets:insert(snmpm_config_table, {net_if_options, NetIfOptions}), 1150 1151 %% -- Versions (optional) -- 1152 %% -- Versions (mandatory) ???????????? -- 1153 ?vdebug("versions", []), 1154 Vsns = get_opt(versions, Opts, [v1, v2, v3]), 1155 ets:insert(snmpm_config_table, {versions, Vsns}), 1156 1157 %% -- Audit trail log (optional) -- 1158 ?vdebug("audit trail log", []), 1159 case get_opt(audit_trail_log, Opts, []) of 1160 [] -> 1161 ?vtrace("no ATL", []), 1162 ets:insert(snmpm_config_table, {audit_trail_log, false}); 1163 AuditTrailLogOpts -> 1164 ?vtrace("ATL options: ~p", [AuditTrailLogOpts]), 1165 ets:insert(snmpm_config_table, {audit_trail_log, true}), 1166 LogDir = get_atl_dir(AuditTrailLogOpts), 1167 LogType = get_atl_type(AuditTrailLogOpts), 1168 LogSize = get_atl_size(AuditTrailLogOpts), 1169 LogRep = get_atl_repair(AuditTrailLogOpts), 1170 LogSeqNo = get_atl_seqno(AuditTrailLogOpts), 1171 ets:insert(snmpm_config_table, {audit_trail_log_dir, LogDir}), 1172 ets:insert(snmpm_config_table, {audit_trail_log_type, LogType}), 1173 ets:insert(snmpm_config_table, {audit_trail_log_size, LogSize}), 1174 ets:insert(snmpm_config_table, {audit_trail_log_repair, LogRep}), 1175 ets:insert(snmpm_config_table, {audit_trail_log_seqno, LogSeqNo}) 1176 end, 1177 1178 %% -- System default agent config -- 1179 ?vdebug("system default agent config", []), 1180 init_agent_default(), 1181 1182 %% -- User (optional) -- 1183 ?vdebug("default user", []), 1184 DefUserMod = get_opt(def_user_mod, Opts, ?USER_MOD_DEFAULT), 1185 DefUserData = get_opt(def_user_data, Opts, ?USER_DATA_DEFAULT), 1186 ets:insert(snmpm_config_table, {def_user_mod, DefUserMod}), 1187 ets:insert(snmpm_config_table, {def_user_data, DefUserData}), 1188 1189 {ok, SystemDefaultAgentConfig} = agent_info(), 1190 DefUser = #user{id = ?DEFAULT_USER, 1191 mod = DefUserMod, 1192 data = DefUserData, 1193 default_agent_config = SystemDefaultAgentConfig}, 1194 ok = handle_register_user(DefUser), 1195 1196 %% -- Note store -- 1197 ?vdebug("note store", []), 1198 NoteStoreOpts = get_opt(note_store, Opts, []), 1199 NoteStoreVerb = get_opt(verbosity, NoteStoreOpts, silence), 1200 NoteStoreTimeout = get_opt(timeout, NoteStoreOpts, 30000), 1201 ets:insert(snmpm_config_table, {note_store_verbosity, NoteStoreVerb}), 1202 ets:insert(snmpm_config_table, {note_store_timeout, NoteStoreTimeout}), 1203 1204 %% -- Manager SNMP config -- 1205 ?vdebug("manager snmp config", []), 1206 MgrConf = read_manager_config_file(ConfDir), 1207 init_manager_config(MgrConf), 1208 1209 %% -- User config -- 1210 ?vdebug("users config", []), 1211 Users = read_users_config_file(ConfDir), 1212 init_users_config(Users), 1213 1214 %% -- Agents config -- 1215 ?vdebug("agents config", []), 1216 Agents = read_agents_config_file(ConfDir), 1217 init_agents_config(Agents), 1218 1219 %% -- USM config -- 1220 UsmUsers = read_usm_config_file(ConfDir), 1221 init_usm_users_config(UsmUsers), 1222 1223 %% -- snmp engine init -- 1224 init_engine(), 1225 1226 ?vlog("started", []), 1227 ok. 1228 1229 1230dets_open(Dir, DbInitError, Repair, AutoSave) -> 1231 Name = ?CONFIG_DB, 1232 Filename = dets_filename(Name, Dir), 1233 case file:read_file_info(Filename) of 1234 {ok, _} -> 1235 %% File exists 1236 case do_dets_open(Name, Filename, Repair, AutoSave) of 1237 {ok, _Dets} -> 1238 ok; 1239 {error, Reason1} -> 1240 info_msg("Corrupt local database: ~p", [Filename]), 1241 case DbInitError of 1242 terminate -> 1243 error({failed_reopen_dets, Filename, Reason1}); 1244 _ -> 1245 Saved = Filename ++ ".saved", 1246 file:rename(Filename, Saved), 1247 case do_dets_open(Name, Filename, 1248 Repair, AutoSave) of 1249 {ok, _Dets} -> 1250 ok; 1251 {error, Reason2} -> 1252 error({failed_open_dets, Filename, 1253 Reason1, Reason2}) 1254 end 1255 end 1256 end; 1257 _ -> 1258 case DbInitError of 1259 create_db_and_dir -> 1260 ok = filelib:ensure_dir(Filename); 1261 _ -> 1262 ok 1263 end, 1264 case do_dets_open(Name, Filename, Repair, AutoSave) of 1265 {ok, _Dets} -> 1266 ok; 1267 {error, Reason} -> 1268 error({failed_open_dets, Filename, Reason}) 1269 end 1270 end. 1271 1272do_dets_open(Name, Filename, Repair, AutoSave) -> 1273 Opts = [{repair, Repair}, 1274 {auto_save, AutoSave}, 1275 {file, Filename}], 1276 dets:open_file(Name, Opts). 1277 1278 1279dets_filename(Name, Dir) when is_atom(Name) -> 1280 dets_filename(atom_to_list(Name), Dir); 1281dets_filename(Name, Dir) -> 1282 filename:join(dets_filename1(Dir), Name). 1283 1284dets_filename1([]) -> "."; 1285dets_filename1(Dir) -> Dir. 1286 1287 1288%% ------------------------------------------------------------------------ 1289 1290init_engine() -> 1291 case get_engine_boots() of 1292 {ok, Val} when Val < 2147483647 -> 1293 set_engine_boots(Val + 1); 1294 {ok, _} -> 1295 ok; 1296 _ -> 1297 set_engine_boots(1) 1298 end, 1299 reset_engine_base(). 1300 1301reset_engine_base() -> 1302 ets:insert(snmpm_config_table, {snmp_engine_base, snmp_misc:now(sec)}). 1303 1304 1305%% ------------------------------------------------------------------------ 1306 1307verify_options(Opts, Mandatory) -> 1308 ?d("verify_options -> entry with" 1309 "~n Opts: ~p" 1310 "~n Mandatory: ~p", [Opts, Mandatory]), 1311 verify_mandatory_options(Opts, Mandatory), 1312 verify_options(Opts). 1313 1314verify_options([]) -> 1315 ?d("verify_options -> done", []), 1316 ok; 1317verify_options([Opt|Opts]) -> 1318 ?d("verify_options -> entry with" 1319 "~n Opt: ~p", [Opt]), 1320 verify_option(Opt), 1321 verify_options(Opts). 1322 1323verify_option({prio, Prio}) -> 1324 verify_prio(Prio); 1325verify_option({mibs, Mibs}) -> 1326 verify_mibs(Mibs); 1327verify_option({inform_request_behaviour, IRB}) -> 1328 verify_irb(IRB); 1329verify_option({net_if, NetIfOpts}) -> 1330 verify_net_if_opts(NetIfOpts); 1331verify_option({server, ServerOpts}) -> 1332 verify_server_opts(ServerOpts); 1333verify_option({note_store, NoteStoreOpts}) -> 1334 verify_note_store_opts(NoteStoreOpts); 1335verify_option({config, ConfOpts0}) -> 1336 %% Make sure any db_dir option is first in the options list to make it 1337 %% easier to check if the db_init_error option specifies that a missing 1338 %% db_dir should be created. 1339 ConfOpts = case lists:keytake(db_dir, 1, ConfOpts0) of 1340 false -> ConfOpts0; 1341 {value, Result, OtherOpts} -> [Result|OtherOpts] 1342 end, 1343 verify_config_opts(ConfOpts); 1344verify_option({versions, Vsns}) -> 1345 verify_versions(Vsns); 1346verify_option({audit_trail_log, LogOpts}) -> 1347 Mandatory = [dir, size], 1348 case (catch verify_mandatory_options(LogOpts, Mandatory)) of 1349 ok -> 1350 verify_audit_trail_log_opts(LogOpts); 1351 {error, {missing_mandatory, LogOpt}} -> 1352 error({missing_mandatory, audit_trail_log, LogOpt}) 1353 end; 1354verify_option({def_user_mod, Mod}) -> 1355 verify_module(def_user_mod, Mod); 1356verify_option({def_user_data, _Data}) -> 1357 ok; 1358verify_option(Opt) -> 1359 {error, {invalid_option, Opt}}. 1360 1361verify_prio(Prio) when is_atom(Prio) -> 1362 ok; 1363verify_prio(Prio) -> 1364 error({invalid_prio, Prio}). 1365 1366verify_irb(auto) -> 1367 ok; 1368verify_irb(user) -> 1369 ok; 1370verify_irb({user, To}) when is_integer(To) andalso (To > 0) -> 1371 ok; 1372verify_irb(IRB) -> 1373 error({invalid_irb, IRB}). 1374 1375verify_mibs([]) -> 1376 ok; 1377verify_mibs([Mib|Mibs]) when is_list(Mib) -> 1378 verify_mibs(Mibs); 1379verify_mibs(Mibs) -> 1380 error({invalid_mibs, Mibs}). 1381 1382verify_config_opts([]) -> 1383 ok; 1384verify_config_opts([{verbosity, Verbosity}|Opts]) -> 1385 verify_verbosity(Verbosity), 1386 verify_config_opts(Opts); 1387verify_config_opts([{dir, Dir}|Opts]) -> 1388 verify_conf_dir(Dir), 1389 verify_config_opts(Opts); 1390verify_config_opts([{db_dir, Dir}|Opts]) -> 1391 case lists:keyfind(db_init_error, 1, Opts) of 1392 {db_init_error, create_db_and_dir} -> 1393 verify_conf_db_dir(Dir, false); 1394 _ -> 1395 verify_conf_db_dir(Dir, true) 1396 end, 1397 verify_config_opts(Opts); 1398verify_config_opts([{db_init_error, DbInitErr}|Opts]) -> 1399 verify_conf_db_init_error(DbInitErr), 1400 verify_config_opts(Opts); 1401verify_config_opts([{repair, Repair}|Opts]) -> 1402 verify_conf_repair(Repair), 1403 verify_config_opts(Opts); 1404verify_config_opts([{auto_save, AutoSave}|Opts]) -> 1405 verify_conf_auto_save(AutoSave), 1406 verify_config_opts(Opts); 1407verify_config_opts([Opt|_]) -> 1408 error({invalid_config_option, Opt}). 1409 1410verify_server_opts([]) -> 1411 ok; 1412verify_server_opts([{verbosity, Verbosity}|Opts]) -> 1413 verify_verbosity(Verbosity), 1414 verify_server_opts(Opts); 1415verify_server_opts([{timeout, Timeout}|Opts]) -> 1416 verify_server_timeout(Timeout), 1417 verify_server_opts(Opts); 1418verify_server_opts([Opt|_]) -> 1419 error({invalid_server_option, Opt}). 1420 1421verify_server_timeout(T) when is_integer(T) andalso (T > 0) -> 1422 ok; 1423verify_server_timeout(T) -> 1424 error({invalid_server_timeout, T}). 1425 1426verify_net_if_opts([]) -> 1427 ok; 1428verify_net_if_opts([{module, Mod}|Opts]) -> 1429 verify_network_interface_behaviour(Mod), 1430 verify_net_if_opts(Opts); 1431verify_net_if_opts([{verbosity, Verbosity}|Opts]) -> 1432 verify_verbosity(Verbosity), 1433 verify_net_if_opts(Opts); 1434verify_net_if_opts([{options, Options}|Opts]) when is_list(Options) -> 1435 verify_net_if_opts(Opts); 1436verify_net_if_opts([Opt|_]) -> 1437 error({invalid_net_if_option, Opt}). 1438 1439verify_network_interface_behaviour(Mod) -> 1440 case snmp_misc:verify_behaviour(snmpm_network_interface, Mod) of 1441 ok -> 1442 ok; 1443 Error -> 1444 throw(Error) 1445 end. 1446 1447 1448verify_note_store_opts([]) -> 1449 ok; 1450verify_note_store_opts([{verbosity, Verbosity}|Opts]) -> 1451 verify_verbosity(Verbosity), 1452 verify_note_store_opts(Opts); 1453verify_note_store_opts([{timeout, Timeout}|Opts]) -> 1454 verify_note_store_timeout(Timeout), 1455 verify_note_store_opts(Opts); 1456verify_note_store_opts([Opt|_]) -> 1457 error({invalid_note_store_option, Opt}). 1458 1459verify_note_store_timeout(T) when is_integer(T) andalso (T > 0) -> 1460 ok; 1461verify_note_store_timeout(T) -> 1462 error({invalid_note_store_timeout, T}). 1463 1464verify_conf_dir(Dir) -> 1465 case (catch verify_dir(Dir)) of 1466 ok -> 1467 ok; 1468 {error, Reason} -> 1469 error({invalid_conf_dir, Dir, Reason}); 1470 _ -> 1471 error({invalid_conf_dir, Dir}) 1472 end. 1473 1474verify_conf_db_dir(Dir, true) -> 1475 case (catch verify_dir(Dir)) of 1476 ok -> 1477 ok; 1478 {error, Reason} -> 1479 error({invalid_conf_db_dir, Dir, Reason}); 1480 _ -> 1481 error({invalid_conf_db_dir, Dir}) 1482 end; 1483verify_conf_db_dir(_Dir, false) -> 1484 ok. 1485 1486verify_conf_db_init_error(terminate) -> 1487 ok; 1488verify_conf_db_init_error(create) -> 1489 ok; 1490verify_conf_db_init_error(create_db_and_dir) -> 1491 ok; 1492verify_conf_db_init_error(InvalidDbInitError) -> 1493 error({invalid_conf_db_init_error, InvalidDbInitError}). 1494 1495 1496verify_conf_repair(true) -> 1497 ok; 1498verify_conf_repair(false) -> 1499 ok; 1500verify_conf_repair(force) -> 1501 ok; 1502verify_conf_repair(InvalidRepair) -> 1503 error({invalid_conf_db_repair, InvalidRepair}). 1504 1505 1506verify_conf_auto_save(infinity) -> 1507 ok; 1508verify_conf_auto_save(AutoSave) 1509 when is_integer(AutoSave) andalso (AutoSave > 0) -> 1510 ok; 1511verify_conf_auto_save(InvalidAutoSave) -> 1512 error({invalid_conf_db_auto_save, InvalidAutoSave}). 1513 1514 1515verify_versions([]) -> 1516 ok; 1517verify_versions([Vsn|Vsns]) -> 1518 verify_version(Vsn), 1519 verify_versions(Vsns); 1520verify_versions(Vsns) -> 1521 error({invalid_versions, Vsns}). 1522 1523verify_version(v1) -> 1524 ok; 1525verify_version(v2) -> 1526 ok; 1527verify_version(v3) -> 1528 ok; 1529verify_version(Vsn) -> 1530 error({invalid_version, Vsn}). 1531 1532verify_audit_trail_log_opts([]) -> 1533 ok; 1534verify_audit_trail_log_opts([{dir, Dir}|Opts]) -> 1535 verify_log_dir(Dir), 1536 verify_audit_trail_log_opts(Opts); 1537verify_audit_trail_log_opts([{type, Type}|Opts]) -> 1538 verify_log_type(Type), 1539 verify_audit_trail_log_opts(Opts); 1540verify_audit_trail_log_opts([{size, Size}|Opts]) -> 1541 verify_log_size(Size), 1542 verify_audit_trail_log_opts(Opts); 1543verify_audit_trail_log_opts([{repair, Repair}|Opts]) -> 1544 verify_log_repair(Repair), 1545 verify_audit_trail_log_opts(Opts); 1546verify_audit_trail_log_opts([{seqno, SeqNo}|Opts]) -> 1547 verify_log_seqno(SeqNo), 1548 verify_audit_trail_log_opts(Opts); 1549verify_audit_trail_log_opts([Opt|_Opts]) -> 1550 error({invalid_audit_trail_log_option, Opt}). 1551 1552verify_log_type(read) -> 1553 ok; 1554verify_log_type(write) -> 1555 ok; 1556verify_log_type(read_write) -> 1557 ok; 1558verify_log_type(Type) -> 1559 error({invalid_audit_trail_log_type, Type}). 1560 1561verify_log_dir(Dir) -> 1562 case (catch verify_dir(Dir)) of 1563 ok -> 1564 ok; 1565 {error, Reason} -> 1566 error({invalid_audit_trail_log_dir, Dir, Reason}); 1567 _ -> 1568 error({invalid_audit_trail_log_dir, Dir}) 1569 end. 1570 1571verify_log_size(Sz) when is_integer(Sz) andalso (Sz > 0) -> 1572 ok; 1573verify_log_size(infinity) -> 1574 ok; 1575verify_log_size({MaxNoBytes, MaxNoFiles}) 1576 when (is_integer(MaxNoBytes) andalso 1577 (MaxNoBytes > 0) andalso 1578 is_integer(MaxNoFiles) andalso 1579 (MaxNoFiles > 0) andalso 1580 (MaxNoFiles < 65000)) -> 1581 ok; 1582verify_log_size(Sz) -> 1583 error({invalid_audit_trail_log_size, Sz}). 1584 1585verify_log_repair(true) -> ok; 1586verify_log_repair(false) -> ok; 1587verify_log_repair(truncate) -> ok; 1588verify_log_repair(Repair) -> 1589 error({invalid_audit_trail_log_repair, Repair}). 1590 1591verify_log_seqno(true) -> ok; 1592verify_log_seqno(false) -> ok; 1593verify_log_seqno(SeqNo) -> 1594 error({invalid_audit_trail_log_seqno, SeqNo}). 1595 1596 1597verify_module(_, Mod) when is_atom(Mod) -> 1598 ok; 1599verify_module(ReasonTag, Mod) -> 1600 error({invalid_module, ReasonTag, Mod}). 1601 1602% verify_bool(_, true) -> 1603% ok; 1604% verify_bool(_, false) -> 1605% ok; 1606% verify_bool(ReasonTag, Bool) -> 1607% error({invalid_bool, ReasonTag, Bool}). 1608 1609verify_dir(Dir) when is_list(Dir) -> 1610 case file:read_file_info(Dir) of 1611 {ok, #file_info{type = directory}} -> 1612 ok; 1613 {ok, _} -> 1614 {error, not_directory}; 1615 {error, _Reason} -> 1616 {error, not_found} 1617 end; 1618verify_dir(Dir) -> 1619 {error, {invalid_log_dir, Dir}}. 1620 1621 1622verify_verbosity(Verbosity) -> 1623 case snmp_verbosity:validate(Verbosity) of 1624 Verbosity -> 1625 ok; 1626 _ -> 1627 error({invalid_verbosity, Verbosity}) 1628 end. 1629 1630 1631%% mandatory() -> [mand()] 1632%% mand() -> atom() | {atom, [atom()]} 1633verify_mandatory_options(_Opts, []) -> 1634 ok; 1635verify_mandatory_options(Opts, [Mand|Mands]) -> 1636 verify_mandatory_option(Opts, Mand), 1637 verify_mandatory_options(Opts, Mands). 1638 1639verify_mandatory_option(Opts, {Mand, MandSubOpts}) -> 1640 ?d("verify_mandatory_option -> entry with" 1641 "~n Mand: ~p" 1642 "~n MandSubObjs: ~p", [Mand, MandSubOpts]), 1643 case lists:keysearch(Mand, 1, Opts) of 1644 {value, {Mand, SubOpts}} -> 1645 verify_mandatory_options(SubOpts, MandSubOpts); 1646 false -> 1647 ?d("missing mandatory option: ~w [~p]", [Mand, MandSubOpts]), 1648 error({missing_mandatory, Mand, MandSubOpts}) 1649 end; 1650verify_mandatory_option(Opts, Mand) -> 1651 ?d("verify_mandatory_option -> entry with" 1652 "~n Mand: ~p", [Mand]), 1653 case lists:keymember(Mand, 1, Opts) of 1654 true -> 1655 ok; 1656 false -> 1657 ?d("missing mandatory option: ~w", [Mand]), 1658 error({missing_mandatory, Mand}) 1659 end. 1660 1661%% ------------------------------------------------------------------------ 1662 1663init_manager_config([]) -> 1664 ok; 1665init_manager_config([{Key, Val}|Confs]) -> 1666 ets:insert(snmpm_config_table, {Key, Val}), 1667 init_manager_config(Confs). 1668 1669 1670 1671init_agent_default() -> 1672 %% The purpose of the default_agent is only to have a place 1673 %% to store system wide default values related to agents. 1674 %% 1675 AgentDefaultConfig = 1676 [{port, ?DEFAULT_AGENT_PORT}, % Port 1677 {timeout, 10000}, % Timeout 1678 {max_message_size, 484}, % Max message (packet) size 1679 {version, v2}, % MPModel 1680 {sec_model, v2c}, % SecModel 1681 {sec_name, "initial"}, % SecName 1682 {sec_level, noAuthNoPriv}, % SecLevel 1683 {community, "all-rights"}], % Community 1684 do_update_agent_info(default_agent, AgentDefaultConfig). 1685 1686read_agents_config_file(Dir) -> 1687 Order = fun snmp_conf:no_order/2, 1688 Check = fun check_agent_config/2, 1689 try read_file(Dir, "agents.conf", Order, Check, []) 1690 catch 1691 throw:Error -> 1692 ?vlog("agent config error: ~p", [Error]), 1693 erlang:raise(throw, Error, erlang:get_stacktrace()) 1694 end. 1695 1696check_agent_config(Agent, State) -> 1697 {ok, {UserId, TargetName, Conf, Version}} = check_agent_config(Agent), 1698 {ok, Vsns} = system_info(versions), 1699 case lists:member(Version, Vsns) of 1700 true -> 1701 {{ok, {UserId, TargetName, Conf}}, State}; 1702 false -> 1703 error({version_not_supported_by_manager, Version, Vsns}) 1704 end. 1705 1706%% For backward compatibility 1707check_agent_config( 1708 {UserId, TargetName, Community, Domain, Addr, 1709 EngineId, Timeout, MaxMessageSize, 1710 Version, SecModel, SecName, SecLevel}) when is_atom(Domain) -> 1711 check_agent_config( 1712 UserId, TargetName, Community, Domain, Addr, 1713 EngineId, Timeout, MaxMessageSize, 1714 Version, SecModel, SecName, SecLevel); 1715check_agent_config( 1716 {UserId, TargetName, Community, Ip, Port, 1717 EngineId, Timeout, MaxMessageSize, 1718 Version, SecModel, SecName, SecLevel}) when is_integer(Port) -> 1719 Domain = default_transport_domain(), 1720 Addr = {Ip, Port}, 1721 check_agent_config( 1722 UserId, TargetName, Community, Domain, Addr, 1723 EngineId, Timeout, MaxMessageSize, 1724 Version, SecModel, SecName, SecLevel); 1725check_agent_config( 1726 {_UserId, _TargetName, _Community, Domain, Addr, 1727 _EngineId, _Timeout, _MaxMessageSize, 1728 _Version, _SecModel, _SecName, _SecLevel}) -> 1729 error({bad_address, {Domain, Addr}}); 1730check_agent_config( 1731 {UserId, TargetName, Community, Domain, Ip, Port, 1732 EngineId, Timeout, MaxMessageSize, 1733 Version, SecModel, SecName, SecLevel}) -> 1734 Addr = {Ip, Port}, 1735 check_agent_config( 1736 UserId, TargetName, Community, Domain, Addr, 1737 EngineId, Timeout, MaxMessageSize, 1738 Version, SecModel, SecName, SecLevel); 1739check_agent_config(Agent) -> 1740 error({bad_agent_config, Agent}). 1741 1742check_agent_config( 1743 UserId, TargetName, Comm, Domain, Addr, 1744 EngineId, Timeout, MMS, 1745 Version, SecModel, SecName, SecLevel) -> 1746 ?vdebug("check_agent_config -> entry with" 1747 "~n UserId: ~p" 1748 "~n TargetName: ~p", [UserId, TargetName]), 1749 snmp_conf:check_string(TargetName, {gt, 0}), 1750 %% Note that the order of Conf *is* important. 1751 %% Some properties may depend on others, so that 1752 %% in order to verify one property, another must 1753 %% be already verified (and present). An example 1754 %% of this is the property 'taddress', for which 1755 %% the property tdomain is needed. 1756 Conf = 1757 [{reg_type, target_name}, 1758 {tdomain, Domain}, 1759 {taddress, fix_address(Domain, Addr)}, 1760 {community, Comm}, 1761 {engine_id, EngineId}, 1762 {timeout, Timeout}, 1763 {max_message_size, MMS}, 1764 {version, Version}, 1765 {sec_model, SecModel}, 1766 {sec_name, SecName}, 1767 {sec_level, SecLevel} 1768 ], 1769 {ok, {UserId, TargetName, verify_agent_config(Conf), Version}}. 1770 1771 1772 1773init_agents_config([]) -> 1774 ok; 1775init_agents_config([Agent|Agents]) -> 1776 init_agent_config(Agent), 1777 init_agents_config(Agents). 1778 1779init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) -> 1780 error({invalid_target_name, TargetName}); 1781init_agent_config({UserId, TargetName, Config}) -> 1782 case handle_register_agent(UserId, TargetName, Config) of 1783 ok -> 1784 ok; 1785 Error -> 1786 throw(Error) 1787 end. 1788 1789 1790 1791%% Sort 'tdomain' first then 'port' to ensure both 1792%% sorts before 'taddress'. Keep the order of other items. 1793order_agent(ItemA, ItemB) -> 1794 snmp_conf:keyorder(1, ItemA, ItemB, [tdomain, port]). 1795 1796fix_agent_config(Conf) -> 1797 ?vdebug("fix_agent_config -> entry with~n~n" 1798 " Conf: ~p", [Conf]), 1799 fix_agent_config(lists:sort(fun order_agent/2, Conf), []). 1800 1801fix_agent_config([], FixedConf) -> 1802 Ret = lists:reverse(FixedConf), 1803 ?vdebug("fix_agent_config -> returns:~n" 1804 " ~p", [Ret]), 1805 Ret; 1806fix_agent_config([{taddress = Item, Address} = Entry|Conf], FixedConf) -> 1807 {value, {tdomain, TDomain}} = lists:keysearch(tdomain, 1, FixedConf), 1808 {value, {port, DefaultPort}} = lists:keysearch(port, 1, FixedConf), 1809 case snmp_conf:check_address(TDomain, Address, DefaultPort) of 1810 ok -> 1811 fix_agent_config(Conf, [Entry|FixedConf]); 1812 {ok, NAddress} -> 1813 fix_agent_config(Conf, [{Item, NAddress}|FixedConf]) 1814 end; 1815fix_agent_config([Entry|Conf], FixedConf) -> 1816 fix_agent_config(Conf, [Entry|FixedConf]). 1817 1818 1819 1820verify_agent_config(Conf) -> 1821 verify_agent_config(lists:sort(fun order_agent/2, Conf), []). 1822 1823verify_agent_config([], VerifiedConf) -> 1824 Ret = lists:reverse(VerifiedConf), 1825 ?vdebug("verify_agent_config -> returns:~n" 1826 " ~p", [Ret]), 1827 Ret; 1828verify_agent_config([{Item, _} = Entry|Conf], VerifiedConf) -> 1829 verify_illegal(VerifiedConf, [Item]), % Duplicates are hereby illegal 1830 verify_agent_config(Conf, VerifiedConf, Entry); 1831verify_agent_config([Bad|_], _VerifiedConf) -> 1832 error({bad_agent_config, Bad}). 1833 1834verify_agent_config( 1835 Conf, VerifiedConf, {taddress = Item, Address} = Entry) -> 1836 verify_illegal(VerifiedConf, [address]), 1837 {TDomain, VC} = 1838 case lists:keysearch(tdomain, 1, VerifiedConf) of 1839 {value, {tdomain,TD}} -> 1840 {TD, VerifiedConf}; 1841 _ -> 1842 %% Insert tdomain since it is missing 1843 %% Note: not default_transport_domain() since 1844 %% taddress is the new format hence the application 1845 %% should be tdomain aware and therefore addresses 1846 %% on the Domain, Addr format should be used and understood. 1847 TD = transportDomainUdpIpv4, 1848 {TD, [{tdomain, TD}|VerifiedConf]} 1849 end, 1850 case snmp_conf:check_address(TDomain, Address, 0) of 1851 ok -> 1852 verify_agent_config(Conf, [Entry|VC]); 1853 {ok, NAddress} -> 1854 verify_agent_config(Conf, [{Item, NAddress}|VC]) 1855 end; 1856verify_agent_config(Conf, VerifiedConf, {address, Address}) -> 1857 Item = taddress, 1858 verify_illegal(VerifiedConf, [Item]), 1859 {TDomain, VC} = 1860 case lists:keysearch(tdomain, 1, VerifiedConf) of 1861 {value, {tdomain, TD}} -> 1862 {TD, VerifiedConf}; 1863 _ -> 1864 %% Insert tdomain since it is missing 1865 TD = default_transport_domain(), 1866 {TD, [{tdomain, TD}|VerifiedConf]} 1867 end, 1868 case snmp_conf:check_address(TDomain, Address, 0) of 1869 ok -> 1870 verify_agent_config(Conf, [{Item, Address}|VC]); 1871 {ok, NAddress} -> 1872 verify_agent_config(Conf, [{Item, NAddress}|VC]) 1873 end; 1874verify_agent_config(Conf, VerifiedConf, {Item, Val} = Entry) -> 1875 case verify_agent_entry(Item, Val) of 1876 ok -> 1877 verify_agent_config(Conf, [Entry|VerifiedConf]); 1878 {ok, NewVal} -> 1879 verify_agent_config(Conf, [{Item, NewVal}|VerifiedConf]) 1880 end. 1881 1882verify_agent_entry(user_id, _UserId) -> 1883 ok; 1884verify_agent_entry(reg_type, RegType) -> 1885 if 1886 RegType =:= addr_port; 1887 RegType =:= target_name -> 1888 ok; 1889 true -> 1890 error({bad_reg_type, RegType}) 1891 end; 1892verify_agent_entry(tdomain, TDomain) -> 1893 snmp_conf:check_domain(TDomain); 1894verify_agent_entry(port, Port) -> 1895 snmp_conf:check_port(Port); 1896verify_agent_entry(community, Comm) -> 1897 snmp_conf:check_string(Comm); 1898verify_agent_entry(engine_id, EngineId) -> 1899 case EngineId of 1900 discovery -> 1901 ok; 1902 _ -> 1903 snmp_conf:check_string(EngineId) 1904 end; 1905verify_agent_entry(timeout, Timeout) -> 1906 snmp_conf:check_timer(Timeout); 1907verify_agent_entry(max_message_size, MMS) -> 1908 snmp_conf:check_packet_size(MMS); 1909verify_agent_entry(version, V) -> 1910 if 1911 V =:= v1; 1912 V =:= v2; 1913 V =:= v3 -> 1914 ok; 1915 true -> 1916 error({bad_version, V}) 1917 end; 1918verify_agent_entry(sec_model, Model) -> 1919 snmp_conf:check_sec_model(Model); 1920verify_agent_entry(sec_name, Name) -> 1921 try snmp_conf:check_string(Name) 1922 catch 1923 _ -> 1924 error({bad_sec_name, Name}) 1925 end; 1926verify_agent_entry(sec_level, Level) -> 1927 snmp_conf:check_sec_level(Level); 1928verify_agent_entry(Item, _) -> 1929 error({unknown_item, Item}). 1930 1931 1932 1933read_users_config_file(Dir) -> 1934 Order = fun snmp_conf:no_order/2, 1935 Check = fun (User, State) -> {check_user_config(User), State} end, 1936 try read_file(Dir, "users.conf", Order, Check, []) 1937 catch 1938 throw:Error -> 1939 ?vlog("failure reading users config file: ~n ~p", [Error]), 1940 erlang:raise(throw, Error, erlang:get_stacktrace()) 1941 end. 1942 1943check_user_config({Id, Mod, Data}) -> 1944 ?vtrace("check_user_config -> entry with" 1945 "~n Id: ~p" 1946 "~n Mod: ~p" 1947 "~n Data: ~p", [Id, Mod, Data]), 1948 check_user_config({Id, Mod, Data, []}); 1949check_user_config({Id, Mod, Data, DefaultAgentConfig} = _User) 1950 when (Id =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> 1951 ?vtrace("check_user_config -> entry with" 1952 "~n Id: ~p" 1953 "~n Mod: ~p" 1954 "~n Data: ~p" 1955 "~n DefaultAgentConfig: ~p", 1956 [Id, Mod, Data, DefaultAgentConfig]), 1957 case (catch verify_user_behaviour(Mod)) of 1958 ok -> 1959 ?vtrace("check_user_config -> user behaviour verified", []), 1960 DefAgentConf = 1961 verify_default_agent_config(DefaultAgentConfig), 1962 ?vtrace("check_user_config -> " 1963 "user agent (default) config verified", []), 1964 User2 = {Id, Mod, Data, DefAgentConf}, 1965 {ok, User2}; 1966 Error -> 1967 throw(Error) 1968 end; 1969check_user_config({Id, _Mod, _Data, DefaultAgentConfig}) 1970 when (Id =/= ?DEFAULT_USER) -> 1971 error({bad_default_agent_config, DefaultAgentConfig}); 1972check_user_config({Id, _Mod, _Data, _DefaultAgentConfig}) -> 1973 error({bad_user_id, Id}); 1974check_user_config(User) -> 1975 error({bad_user_config, User}). 1976 1977init_users_config([]) -> 1978 ok; 1979init_users_config([User|Users]) -> 1980 init_user_config(User), 1981 init_users_config(Users). 1982 1983init_user_config(User) -> 1984 case (catch verify_user(User)) of 1985 {ok, UserRec} -> 1986 case handle_register_user(UserRec) of 1987 ok -> 1988 ok; 1989 {error, Reason} -> 1990 error_msg("failed register user: " 1991 "~n~w~n~w", [User, Reason]) 1992 end; 1993 {error, Reason} -> 1994 error_msg("user config check failed: " 1995 "~n~w~n~w", [User, Reason]) 1996 end. 1997 1998verify_user({Id, UserMod, UserData}) -> 1999 verify_user({Id, UserMod, UserData, []}); 2000verify_user({Id, UserMod, UserData, DefaultAgentConfig}) 2001 when (Id =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> 2002 ?d("verify_user -> entry with" 2003 "~n Id: ~p" 2004 "~n UserMod: ~p" 2005 "~n UserData: ~p" 2006 "~n DefaultAgentConfig: ~p", 2007 [Id, UserMod, UserData, DefaultAgentConfig]), 2008 case (catch verify_user_behaviour(UserMod)) of 2009 ok -> 2010 try 2011 {ok, SystemDefaultAgentConfig} = agent_info(), 2012 Config = 2013 ensure_config( 2014 SystemDefaultAgentConfig, 2015 verify_default_agent_config(DefaultAgentConfig)), 2016%% Config = 2017%% default_agent_config( 2018%% verify_default_agent_config(DefaultAgentConfig)), 2019 {ok, #user{id = Id, 2020 mod = UserMod, 2021 data = UserData, 2022 default_agent_config = Config}} 2023 catch 2024 Error -> 2025 ?vdebug("verify_user default_agent_config -> throw" 2026 "~n Error: ~p", [Error]), 2027 error({bad_default_agent_config, Error}) 2028 end; 2029 Error -> 2030 throw(Error) 2031 end; 2032verify_user({Id, _UserMod, _UserData, DefaultAgentConfig}) 2033 when (Id =/= ?DEFAULT_USER) -> 2034 {error, {bad_default_agent_config, DefaultAgentConfig}}; 2035verify_user({Id, _, _, _}) -> 2036 {error, {bad_user_id, Id}}. 2037 2038verify_default_agent_config(Conf) -> 2039 try 2040 verify_illegal( 2041 Conf, 2042 [user_id, engine_id, address, tdomain, taddress]), 2043 verify_agent_config(Conf) 2044 catch 2045 Error -> 2046 ?vdebug("verify_default_agent_config -> throw" 2047 "~n Error: ~p", [Error]), 2048 error({bad_default_agent_config, Error}) 2049 end. 2050 2051 2052read_usm_config_file(Dir) -> 2053 Order = fun snmp_conf:no_order/2, 2054 Check = fun (User, State) -> {check_usm_user_config(User), State} end, 2055 read_file(Dir, "usm.conf", Order, Check, []). 2056 2057%% Identity-function 2058check_usm_user_config({EngineId, Name, 2059 AuthP, AuthKey, 2060 PrivP, PrivKey}) -> 2061 User = {EngineId, Name, Name, AuthP, AuthKey, PrivP, PrivKey}, 2062 verify_usm_user(User); 2063check_usm_user_config({_EngineId, _Name, _SecName, 2064 _AuthP, _AuthKey, 2065 _PrivP, _PrivKey} = User) -> 2066 verify_usm_user(User); 2067check_usm_user_config(User) -> 2068 error({bad_usm_config, User}). 2069 2070init_usm_users_config([]) -> 2071 ok; 2072init_usm_users_config([User|Users]) -> 2073 init_usm_user_config(User), 2074 init_usm_users_config(Users). 2075 2076init_usm_user_config(User) when is_record(User, usm_user) -> 2077 case handle_register_usm_user(User) of 2078 ok -> 2079 ok; 2080 Error -> 2081 throw(Error) 2082 end; 2083init_usm_user_config(BadUser) -> 2084 error({bad_usm_user, BadUser}). 2085 2086 2087verify_usm_user({EngineID, Name, SecName, AuthP, AuthKey, PrivP, PrivKey}) -> 2088 ?d("verify_usm_user -> entry with" 2089 "~n EngineID: ~p" 2090 "~n Name: ~p" 2091 "~n SecName: ~p" 2092 "~n AuthP: ~p" 2093 "~n AuthKey: ~p" 2094 "~n PrivP: ~p" 2095 "~n PrivKey: ~p", 2096 [EngineID, Name, SecName, AuthP, AuthKey, PrivP, PrivKey]), 2097 verify_usm_user_engine_id(EngineID), 2098 verify_usm_user_name(Name), 2099 verify_usm_user_sec_name(SecName), 2100 verify_usm_user(AuthP, AuthKey, PrivP, PrivKey), 2101 User = #usm_user{engine_id = EngineID, 2102 name = Name, 2103 sec_name = SecName, 2104 auth = AuthP, 2105 auth_key = AuthKey, 2106 priv = PrivP, 2107 priv_key = PrivKey}, 2108 {ok, User}. 2109 2110verify_usm_user_engine_id(EngineID) -> 2111 case (catch snmp_conf:check_string(EngineID, {gt, 0})) of 2112 ok -> 2113 ok; 2114 _ -> 2115 error({bad_usm_engine_id, EngineID}) 2116 end. 2117 2118verify_usm_user_name(Name) -> 2119 case (catch snmp_conf:check_string(Name, {gt, 0})) of 2120 ok -> 2121 ok; 2122 _ -> 2123 error({bad_usm_user_name, Name}) 2124 end. 2125 2126verify_usm_user_sec_name(Name) -> 2127 case (catch snmp_conf:check_string(Name, {gt, 0})) of 2128 ok -> 2129 ok; 2130 _ -> 2131 error({bad_usm_sec_name, Name}) 2132 end. 2133 2134verify_usm_user(AuthP, AuthKey, PrivP, PrivKey) -> 2135 verify_usm_user_auth(AuthP, AuthKey), 2136 verify_usm_user_priv(PrivP, PrivKey), 2137 ok. 2138 2139verify_usm_user_auth(usmNoAuthProtocol, AuthKey) -> 2140 case (catch snmp_conf:check_string(AuthKey, any)) of 2141 ok -> 2142 ok; 2143 _ -> 2144 error({invalid_auth_key, usmNoAuthProtocol}) 2145 end; 2146verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) 2147 when is_list(AuthKey) andalso (length(AuthKey) =:= 16) -> 2148 case is_crypto_supported(md5) of 2149 true -> 2150 case snmp_conf:all_integer(AuthKey) of 2151 true -> 2152 ok; 2153 _ -> 2154 error({invalid_auth_key, usmHMACMD5AuthProtocol}) 2155 end; 2156 false -> 2157 error({unsupported_crypto, md5}) 2158 end; 2159verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) when is_list(AuthKey) -> 2160 Len = length(AuthKey), 2161 error({invalid_auth_key, usmHMACMD5AuthProtocol, Len}); 2162verify_usm_user_auth(usmHMACMD5AuthProtocol, _AuthKey) -> 2163 error({invalid_auth_key, usmHMACMD5AuthProtocol}); 2164verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) 2165 when is_list(AuthKey) andalso (length(AuthKey) =:= 20) -> 2166 case is_crypto_supported(sha) of 2167 true -> 2168 case snmp_conf:all_integer(AuthKey) of 2169 true -> 2170 ok; 2171 _ -> 2172 error({invalid_auth_key, usmHMACSHAAuthProtocol}) 2173 end; 2174 false -> 2175 error({unsupported_crypto, sha}) 2176 end; 2177verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) when is_list(AuthKey) -> 2178 Len = length(AuthKey), 2179 error({invalid_auth_key, usmHMACSHAAuthProtocol, Len}); 2180verify_usm_user_auth(usmHMACSHAAuthProtocol, _AuthKey) -> 2181 error({invalid_auth_key, usmHMACSHAAuthProtocol}); 2182verify_usm_user_auth(AuthP, _AuthKey) -> 2183 error({invalid_auth_protocol, AuthP}). 2184 2185verify_usm_user_priv(usmNoPrivProtocol, PrivKey) -> 2186 case (catch snmp_conf:check_string(PrivKey, any)) of 2187 ok -> 2188 ok; 2189 _ -> 2190 error({invalid_priv_key, usmNoPrivProtocol}) 2191 end; 2192verify_usm_user_priv(usmDESPrivProtocol, PrivKey) 2193 when (length(PrivKey) =:= 16) -> 2194 case is_crypto_supported(des_cbc) of 2195 true -> 2196 case snmp_conf:all_integer(PrivKey) of 2197 true -> 2198 ok; 2199 _ -> 2200 error({invalid_priv_key, usmDESPrivProtocol}) 2201 end; 2202 false -> 2203 error({unsupported_crypto, des_cbc}) 2204 end; 2205verify_usm_user_priv(usmDESPrivProtocol, PrivKey) when is_list(PrivKey) -> 2206 Len = length(PrivKey), 2207 error({invalid_priv_key, usmDESPrivProtocol, Len}); 2208verify_usm_user_priv(usmDESPrivProtocol, _PrivKey) -> 2209 error({invalid_priv_key, usmDESPrivProtocol}); 2210verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) 2211 when (length(PrivKey) =:= 16) -> 2212 case is_crypto_supported(aes_cfb128) of 2213 true -> 2214 case snmp_conf:all_integer(PrivKey) of 2215 true -> 2216 ok; 2217 _ -> 2218 error({invalid_priv_key, usmAesCfb128Protocol}) 2219 end; 2220 false -> 2221 error({unsupported_crypto, aes_cfb128}) 2222 end; 2223verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) when is_list(PrivKey) -> 2224 Len = length(PrivKey), 2225 error({invalid_priv_key, usmAesCfb128Protocol, Len}); 2226verify_usm_user_priv(usmAesCfb128Protocol, _PrivKey) -> 2227 error({invalid_priv_key, usmAesCfb128Protocol}); 2228verify_usm_user_priv(PrivP, _PrivKey) -> 2229 error({invalid_priv_protocol, PrivP}). 2230 2231 2232-compile({inline, [{is_crypto_supported,1}]}). 2233is_crypto_supported(Func) -> 2234 snmp_misc:is_crypto_supported(Func). 2235 2236 2237read_manager_config_file(Dir) -> 2238 Order = fun order_manager_config/2, 2239 Check = fun check_manager_config/2, 2240 Conf = read_file(Dir, "manager.conf", Order, Check), 2241 ?d("read_manager_config_file -> ok: " 2242 "~n Conf: ~p", [Conf]), 2243 %% If the address is not specified, then we assume 2244 %% it should be the local host. 2245 %% If the address is not possible to determine 2246 %% that way, then we give up... 2247 verify_someof(Conf, [port, transports]), 2248 verify_mandatory(Conf, [engine_id, max_message_size]), 2249 default_manager_config(Conf). 2250 2251default_manager_config(Conf) -> 2252 %% Ensure valid transports entry 2253 case lists:keyfind(transports, 1, Conf) of 2254 false -> 2255 {port, Port} = lists:keyfind(port, 1, Conf), 2256 Domain = 2257 case lists:keyfind(domain, 1, Conf) of 2258 false -> 2259 default_transport_domain(); 2260 {_, D} -> 2261 D 2262 end, 2263 Family = snmp_conf:tdomain_to_family(Domain), 2264 {ok, Hostname} = inet:gethostname(), 2265 case inet:getaddr(Hostname, Family) of 2266 {ok, Address} -> 2267 lists:sort( 2268 fun order_manager_config/2, 2269 [{transports, [{Domain, {Address, Port}}]} | Conf]); 2270 {error, _Reason} -> 2271 ?d("default_manager_config -> " 2272 "failed getting ~w address for ~s:~n" 2273 " _Reason: ~p", [Family, Hostname, _Reason]), 2274 Conf 2275 end; 2276 _ -> 2277 Conf 2278 end. 2279 2280order_manager_config(EntryA, EntryB) -> 2281 snmp_conf:keyorder(1, EntryA, EntryB, [domain, port]). 2282 2283check_manager_config(Entry, undefined) -> 2284 check_manager_config(Entry, {default_transport_domain(), undefined}); 2285check_manager_config({domain, Domain}, {_, Port}) -> 2286 {snmp_conf:check_domain(Domain), {Domain, Port}}; 2287check_manager_config({port, Port}, {Domain, _}) -> 2288 {ok = snmp_conf:check_port(Port), {Domain, Port}}; 2289check_manager_config({address, _}, {_, undefined}) -> 2290 error({missing_mandatory, port}); 2291check_manager_config({address = Tag, Ip} = Entry, {Domain, Port} = State) -> 2292 {case snmp_conf:check_ip(Domain, Ip) of 2293 ok -> 2294 [Entry, 2295 {transports, [{Domain, {Ip, Port}}]}]; 2296 {ok, FixedIp} -> 2297 [{Tag, FixedIp}, 2298 {transports, [{Domain, {FixedIp, Port}}]}] 2299 end, State}; 2300check_manager_config({transports = Tag, Transports}, {_, Port} = State) 2301 when is_list(Transports) -> 2302 CheckedTransports = 2303 [case Transport of 2304 {Domain, Address} -> 2305 case 2306 case Port of 2307 undefined -> 2308 snmp_conf:check_address(Domain, Address); 2309 _ -> 2310 snmp_conf:check_address(Domain, Address, Port) 2311 end 2312 of 2313 ok -> 2314 Transport; 2315 {ok, FixedAddress} -> 2316 {Domain, FixedAddress} 2317 end; 2318 _Domain when Port =:= undefined-> 2319 error({missing_mandatory, port}); 2320 Domain -> 2321 Family = snmp_conf:tdomain_to_family(Domain), 2322 {ok, Hostname} = inet:gethostname(), 2323 case inet:getaddr(Hostname, Family) of 2324 {ok, IpAddr} -> 2325 {Domain, {IpAddr, Port}}; 2326 {error, _} -> 2327 error({bad_address, {Domain, Hostname}}) 2328 end 2329 end 2330 || Transport <- Transports], 2331 {{ok, {Tag, CheckedTransports}}, State}; 2332check_manager_config(Entry, State) -> 2333 {check_manager_config(Entry), State}. 2334 2335check_manager_config({engine_id, EngineID}) -> 2336 snmp_conf:check_string(EngineID); 2337check_manager_config({max_message_size, Max}) -> 2338 snmp_conf:check_integer(Max, {gte, 484}); 2339check_manager_config(Conf) -> 2340 error({unknown_config, Conf}). 2341 2342 2343read_file(Dir, FileName, Order, Check, Default) -> 2344 try snmp_conf:read(filename:join(Dir, FileName), Order, Check) 2345 catch 2346 {error, Reason} when element(1, Reason) =:= failed_open -> 2347 ?vlog("failed reading config from ~s: ~p", [FileName, Reason]), 2348 Default 2349 end. 2350 2351read_file(Dir, FileName, Order, Check) -> 2352 try snmp_conf:read(filename:join(Dir, FileName), Order, Check) 2353 catch 2354 throw:{error, Reason} = Error 2355 when element(1, Reason) =:= failed_open -> 2356 error_msg("failed reading config from ~s: ~p", [FileName, Reason]), 2357 erlang:raise(throw, Error, erlang:get_stacktrace()) 2358 end. 2359 2360%%-------------------------------------------------------------------- 2361%% Func: handle_call/3 2362%% Returns: {reply, Reply, State} | 2363%% {reply, Reply, State, Timeout} | 2364%% {noreply, State} | 2365%% {noreply, State, Timeout} | 2366%% {stop, Reason, Reply, State} | (terminate/2 is called) 2367%% {stop, Reason, State} (terminate/2 is called) 2368%%-------------------------------------------------------------------- 2369handle_call({register_user, UserId, UserMod, UserData, DefaultAgentConfig}, 2370 _From, State) -> 2371 ?vlog("received register_user request: " 2372 "~n UserId: ~p" 2373 "~n UserMod: ~p" 2374 "~n UserData: ~p" 2375 "~n DefaultAgentConfig: ~p", 2376 [UserId, UserMod, UserData, DefaultAgentConfig]), 2377 User = #user{id = UserId, 2378 mod = UserMod, 2379 data = UserData, 2380 default_agent_config = DefaultAgentConfig}, 2381 Reply = handle_register_user(User), 2382 {reply, Reply, State}; 2383 2384handle_call({unregister_user, UserId}, _From, State) -> 2385 ?vlog("received unregister_user request: " 2386 "~n UserId: ~p", [UserId]), 2387 Reply = handle_unregister_user(UserId), 2388 {reply, Reply, State}; 2389 2390handle_call({register_agent, UserId, TargetName, Config}, _From, State) -> 2391 ?vlog("received register_agent request: " 2392 "~n UserId: ~p" 2393 "~n TargetName: ~p" 2394 "~n Config: ~p", [UserId, TargetName, Config]), 2395 Reply = handle_register_agent(UserId, TargetName, Config), 2396 {reply, Reply, State}; 2397 2398handle_call({unregister_agent, UserId, TargetName}, _From, State) -> 2399 ?vlog("received unregister_agent request: " 2400 "~n UserId: ~p" 2401 "~n TargetName: ~p", [UserId, TargetName]), 2402 Reply = handle_unregister_agent(UserId, TargetName), 2403 {reply, Reply, State}; 2404 2405handle_call({update_agent_info, UserId, TargetName, Info}, 2406 _From, State) -> 2407 ?vlog("received update_agent_info request: " 2408 "~n UserId: ~p" 2409 "~n TargetName: ~p" 2410 "~n Info: ~p", [UserId, TargetName, Info]), 2411 Reply = handle_update_agent_info(UserId, TargetName, Info), 2412 {reply, Reply, State}; 2413 2414%% <BACKWARD-COMPAT> 2415handle_call({update_agent_info, UserId, TargetName, Item, Val}, 2416 _From, State) -> 2417 ?vlog("received update_agent_info request: " 2418 "~n UserId: ~p" 2419 "~n TargetName: ~p" 2420 "~n Item: ~p" 2421 "~n Val: ~p", [UserId, TargetName, Item, Val]), 2422 Reply = handle_update_agent_info(UserId, TargetName, Item, Val), 2423 {reply, Reply, State}; 2424%% </BACKWARD-COMPAT> 2425 2426handle_call({register_usm_user, User}, _From, State) -> 2427 ?vlog("received register_usm_user request: " 2428 "~n User: ~p", [User]), 2429 Reply = handle_register_usm_user(User), 2430 {reply, Reply, State}; 2431 2432handle_call({unregister_usm_user, EngineID, Name}, _From, State) -> 2433 ?vlog("received register_usm_user request: " 2434 "~n EngineID: ~p" 2435 "~n Name: ~p", [EngineID, Name]), 2436 Reply = handle_unregister_usm_user(EngineID, Name), 2437 {reply, Reply, State}; 2438 2439handle_call({update_usm_user_info, EngineID, UserName, Item, Val}, 2440 _From, State) -> 2441 ?vlog("received update_usm_user_info request: " 2442 "~n EngineID: ~p" 2443 "~n UserName: ~p" 2444 "~n Item: ~p" 2445 "~n Val: ~p", [EngineID, UserName, Item, Val]), 2446 Reply = handle_update_usm_user_info(EngineID, UserName, Item, Val), 2447 {reply, Reply, State}; 2448 2449handle_call({cre_counter, Counter, Initial}, _From, State) -> 2450 ?vlog("received cre_counter ~p -> ~w", [Counter, Initial]), 2451 Reply = cre_counter(Counter, Initial), 2452 {reply, Reply, State}; 2453 2454handle_call({cre_stats_counter, Counter, Initial}, _From, State) -> 2455 ?vlog("received cre_stats_counter ~p -> ~w", [Counter, Initial]), 2456 Reply = cre_stats_counter(Counter, Initial), 2457 {reply, Reply, State}; 2458 2459handle_call({reset_stats_counter, Counter}, _From, State) -> 2460 ?vlog("received reset_stats_counter ~p", [Counter]), 2461 Reply = reset_stats_counter(Counter), 2462 {reply, Reply, State}; 2463 2464handle_call({load_mib, Mib}, _From, State) -> 2465 ?vlog("received load_mib ~p", [Mib]), 2466 case handle_load_mib(Mib) of 2467 ok -> 2468 {reply, ok, State}; 2469 Error -> 2470 {reply, Error, State} 2471 end; 2472 2473 2474handle_call({unload_mib, Mib}, _From, State) -> 2475 ?vlog("received unload_mib ~p", [Mib]), 2476 case handle_unload_mib(Mib) of 2477 ok -> 2478 {reply, ok, State}; 2479 Error -> 2480 {reply, Error, State} 2481 end; 2482 2483 2484handle_call({set_engine_boots, Boots}, _From, State) -> 2485 ?vlog("received set_engine_boots ~p", [Boots]), 2486 set_engine_boots(Boots), 2487 {reply, ok, State}; 2488 2489handle_call({set_engine_time, Time}, _From, State) -> 2490 ?vlog("received set_engine_time ~p", [Time]), 2491 Base = snmp_misc:now(sec) - Time, 2492 ets:insert(snmpm_config_table, {snmp_engine_base, Base}), 2493 {reply, ok, State}; 2494 2495handle_call({set_usm_cache, Key, Val}, _From, State) -> 2496 ?vlog("received set_usm_cache: ~w -> ~p", [Key, Val]), 2497 ets:insert(snmpm_usm_table, {{usm_cache, Key}, Val}), 2498 {reply, ok, State}; 2499 2500handle_call({reset_usm_cache, EngineID}, _From, State) -> 2501 ?vlog("received reset_usm_cache: ~p", [EngineID]), 2502 reset_usm_cache(EngineID), 2503 {reply, ok, State}; 2504 2505handle_call({verbosity, Verbosity}, _From, State) -> 2506 ?vlog("received verbosity request", []), 2507 put(verbosity, Verbosity), 2508 {reply, ok, State}; 2509 2510handle_call(info, _From, State) -> 2511 ?vlog("received info request", []), 2512 Reply = get_info(), 2513 {reply, Reply, State}; 2514 2515handle_call({backup, BackupDir}, From, State) -> 2516 ?vlog("backup to ~p", [BackupDir]), 2517 Pid = self(), 2518 V = get(verbosity), 2519 case file:read_file_info(BackupDir) of 2520 {ok, #file_info{type = directory}} -> 2521 BackupServer = 2522 erlang:spawn_link( 2523 fun() -> 2524 put(sname, mcbs), 2525 put(verbosity, V), 2526 Dir = filename:join([BackupDir]), 2527 Reply = handle_backup(?CONFIG_DB, Dir), 2528 Pid ! {backup_done, Reply}, 2529 unlink(Pid) 2530 end), 2531 ?vtrace("backup server: ~p", [BackupServer]), 2532 {noreply, State#state{backup = {BackupServer, From}}}; 2533 {ok, _} -> 2534 {reply, {error, not_a_directory}, State}; 2535 Error -> 2536 {reply, Error, State} 2537 end; 2538 2539 2540%% handle_call({update_system_info, Key, Val}, _From, State) -> 2541%% ?vlog("received update_system_info: ~p -> ~p", [Key, Val]), 2542%% Reply = handle_update_system_info(Key, Val), 2543%% {reply, Reply, State}; 2544 2545 2546handle_call(is_started, _From, State) -> 2547 ?vlog("received is_started request", []), 2548 {reply, true, State}; 2549 2550 2551handle_call(stop, _From, State) -> 2552 {stop, normal, ok, State}; 2553 2554 2555handle_call(Req, _From, State) -> 2556 warning_msg("received unknown request: ~n~p", [Req]), 2557 {reply, {error, unknown_request}, State}. 2558 2559 2560%%-------------------------------------------------------------------- 2561%% Func: handle_cast/2 2562%% Returns: {noreply, State} | 2563%% {noreply, State, Timeout} | 2564%% {stop, Reason, State} (terminate/2 is called) 2565%%-------------------------------------------------------------------- 2566handle_cast(Msg, State) -> 2567 warning_msg("received unknown message: ~n~p", [Msg]), 2568 {noreply, State}. 2569 2570 2571%%-------------------------------------------------------------------- 2572%% Func: handle_info/2 2573%% Returns: {noreply, State} | 2574%% {noreply, State, Timeout} | 2575%% {stop, Reason, State} (terminate/2 is called) 2576%%-------------------------------------------------------------------- 2577handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) -> 2578 ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]), 2579 gen_server:reply(From, {error, Reason}), 2580 {noreply, S#state{backup = undefined}}; 2581 2582handle_info({'EXIT', Pid, Reason}, S) -> 2583 %% The only other processes we should be linked to are 2584 %% either the server or our supervisor, so die... 2585 {stop, {received_exit, Pid, Reason}, S}; 2586 2587handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) -> 2588 ?vlog("backup done:" 2589 "~n Reply: ~p", [Reply]), 2590 gen_server:reply(From, Reply), 2591 {noreply, S#state{backup = undefined}}; 2592 2593handle_info(Info, State) -> 2594 warning_msg("received unknown info: ~n~p", [Info]), 2595 {noreply, State}. 2596 2597 2598%%-------------------------------------------------------------------- 2599%% Func: terminate/2 2600%% Purpose: Shutdown the server 2601%% Returns: any (ignored by gen_server) 2602%%-------------------------------------------------------------------- 2603terminate(Reason, _State) -> 2604 ?vdebug("terminate: ~p",[Reason]), 2605 ok. 2606 2607%%---------------------------------------------------------------------- 2608%% Func: code_change/3 2609%% Purpose: Convert process state when code is changed 2610%% Returns: {ok, NewState} 2611%%---------------------------------------------------------------------- 2612 2613%% downgrade 2614%% 2615code_change({down, _Vsn}, S1, downgrade_to_pre_4_7) -> 2616 #state{backup = B} = S1, 2617 stop_backup_server(B), 2618 S2 = {state}, 2619 {ok, S2}; 2620 2621%% upgrade 2622%% 2623code_change(_Vsn, _S1, upgrade_from_pre_4_7) -> 2624 %% {state} = S1, 2625 S2 = #state{}, 2626 {ok, S2}; 2627 2628code_change(_Vsn, State, _Extra) -> 2629 {ok, State}. 2630 2631 2632stop_backup_server(undefined) -> 2633 ok; 2634stop_backup_server({Pid, _}) when is_pid(Pid) -> 2635 exit(Pid, kill). 2636 2637 2638 2639%%---------------------------------------------------------- 2640%% Update system info 2641%%---------------------------------------------------------- 2642 2643%% handle_update_system_info(audit_trail_log_type = Key, Val) -> 2644%% case snmpm_config:system_info(audit_trail_log) of 2645%% {ok, true} -> 2646%% Value = 2647%% case Val of 2648%% read -> 2649%% {ok, [read]}; 2650%% write -> 2651%% {ok, [write]}; 2652%% read_write -> 2653%% {ok, [read,write]}; 2654%% _ -> 2655%% {error, {bad_value, Key, Val}} 2656%% end, 2657%% case Value of 2658%% {ok, NewValue} -> 2659%% ets:insert(snmpm_config_table, {Key, NewValue}), 2660%% ok; 2661%% false -> 2662%% Value 2663%% end; 2664%% _ -> 2665%% {error, audit_trail_log_not_enabled} 2666%% end; 2667%% handle_update_system_info(BadKey, Val) -> 2668%% {error, {unsupported_update, BadKey, Val}}. 2669 2670 2671%%---------------------------------------------------------- 2672%% Backup 2673%%---------------------------------------------------------- 2674 2675handle_backup(D, BackupDir) -> 2676 %% First check that we do not wrote to the corrent db-dir... 2677 ?vtrace("handle_backup -> entry with" 2678 "~n D: ~p" 2679 "~n BackupDir: ~p", [D, BackupDir]), 2680 case dets:info(D, filename) of 2681 undefined -> 2682 ?vinfo("handle_backup -> no file to backup", []), 2683 {error, no_file}; 2684 Filename -> 2685 ?vinfo("handle_backup -> file to backup: ~n ~p", [Filename]), 2686 case filename:dirname(Filename) of 2687 BackupDir -> 2688 ?vinfo("handle_backup -> backup dir and db dir the same", 2689 []), 2690 {error, db_dir}; 2691 _ -> 2692 case file:read_file_info(BackupDir) of 2693 {ok, #file_info{type = directory}} -> 2694 ?vdebug("handle_backup -> backup dir ok", []), 2695 %% All well so far... 2696 Type = dets:info(D, type), 2697 KP = dets:info(D, keypos), 2698 dets_backup(D, 2699 filename:basename(Filename), 2700 BackupDir, Type, KP); 2701 {ok, _} -> 2702 ?vinfo("handle_backup -> backup dir not a dir", 2703 []), 2704 {error, not_a_directory}; 2705 Error -> 2706 ?vinfo("handle_backup -> Error: ~p", [Error]), 2707 Error 2708 end 2709 end 2710 end. 2711 2712dets_backup(D, Filename, BackupDir, Type, KP) -> 2713 ?vtrace("dets_backup -> entry with" 2714 "~n D: ~p" 2715 "~n Filename: ~p" 2716 "~n BackupDir: ~p", [D, Filename, BackupDir]), 2717 BackupFile = filename:join(BackupDir, Filename), 2718 ?vtrace("dets_backup -> " 2719 "~n BackupFile: ~p", [BackupFile]), 2720 Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}], 2721 case dets:open_file(?BACKUP_DB, Opts) of 2722 {ok, B} -> 2723 ?vtrace("dets_backup -> create fun", []), 2724 F = fun(Arg) -> 2725 dets_backup(Arg, start, D, B) 2726 end, 2727 dets:safe_fixtable(D, true), 2728 Res = dets:init_table(?BACKUP_DB, F, [{format, bchunk}]), 2729 dets:safe_fixtable(D, false), 2730 ?vtrace("dets_backup -> Res: ~p", [Res]), 2731 Res; 2732 Error -> 2733 ?vinfo("dets_backup -> open_file failed: " 2734 "~n ~p", [Error]), 2735 Error 2736 end. 2737 2738 2739dets_backup(close, _Cont, _D, B) -> 2740 dets:close(B), 2741 ok; 2742dets_backup(read, Cont1, D, B) -> 2743 case dets:bchunk(D, Cont1) of 2744 {Cont2, Data} -> 2745 F = fun(Arg) -> 2746 dets_backup(Arg, Cont2, D, B) 2747 end, 2748 {Data, F}; 2749 '$end_of_table' -> 2750 dets:close(B), 2751 end_of_input; 2752 Error -> 2753 Error 2754 end. 2755 2756 2757%%%------------------------------------------------------------------- 2758%%% Internal functions 2759%%%------------------------------------------------------------------- 2760 2761handle_register_user(#user{id = Id} = User) -> 2762 ?vdebug("handle_register_user -> entry with" 2763 "~n User: ~p", [User]), 2764 case ets:lookup(snmpm_user_table, Id) of 2765 [] -> 2766 ets:insert(snmpm_user_table, User), 2767 ok; 2768 _ -> 2769 {error, {already_registered, User}} 2770 end. 2771 2772handle_unregister_user(UserId) -> 2773 ?vdebug("handle_unregister_user -> entry with" 2774 "~n UserId: ~p", [UserId]), 2775 ets:delete(snmpm_user_table, UserId), 2776 ok. 2777 2778 2779handle_register_agent(UserId, TargetName, Config) -> 2780 ?vdebug("handle_register_agent -> entry with" 2781 "~n UserId: ~p" 2782 "~n TargetName: ~p" 2783 "~n Config: ~p", [UserId, TargetName, Config]), 2784 case (catch agent_info(TargetName, user_id)) of 2785 {error, _} -> 2786 ?vtrace( 2787 "handle_register_agent -> user_id not found in config", []), 2788 case ets:lookup(snmpm_user_table, UserId) of 2789 [#user{default_agent_config = DefConfig}] -> 2790 ?vtrace("handle_register_agent ->~n" 2791 " DefConfig: ~p", [DefConfig]), 2792 FixedConfig = 2793 fix_agent_config(ensure_config(DefConfig, Config)), 2794 ?vtrace("handle_register_agent ->~n" 2795 " FixedConfig: ~p", [FixedConfig]), 2796 do_handle_register_agent( 2797 TargetName, [{user_id, UserId}|FixedConfig]), 2798 %% <DIRTY-BACKWARD-COMPATIBILLITY> 2799 %% And now for some (backward compatibillity) 2800 %% dirty crossref stuff 2801 {value, {_, Domain}} = 2802 lists:keysearch(tdomain, 1, FixedConfig), 2803 {value, {_, Address}} = 2804 lists:keysearch(taddress, 1, FixedConfig), 2805 ?vtrace( 2806 "handle_register_agent -> register cross-ref fix", []), 2807 ets:insert(snmpm_agent_table, 2808 {{Domain, Address, target_name}, TargetName}), 2809 %% </DIRTY-BACKWARD-COMPATIBILLITY> 2810 2811%% %% First, insert this users default config 2812%% ?vtrace("handle_register_agent -> store default config", []), 2813%% do_handle_register_agent(TargetName, DefConfig), 2814%% %% Second, insert the config for this agent 2815%% ?vtrace("handle_register_agent -> store config", []), 2816%% do_handle_register_agent(TargetName, 2817%% [{user_id, UserId}|Config]), 2818%% %% <DIRTY-BACKWARD-COMPATIBILLITY> 2819%% %% And now for some (backward compatibillity) 2820%% %% dirty crossref stuff 2821%% ?vtrace("handle_register_agent -> lookup taddress", []), 2822%% {ok, {Addr, Port} = TAddress} = 2823%% agent_info(TargetName, taddress), 2824%% ?vtrace("handle_register_agent -> taddress: ~p", 2825%% [TAddress]), 2826%% ?vtrace("handle_register_agent -> register cross-ref fix", []), 2827%% ets:insert(snmpm_agent_table, 2828%% {{Addr, Port, target_name}, TargetName}), 2829%% %% </DIRTY-BACKWARD-COMPATIBILLITY> 2830 ok; 2831 _ -> 2832 {error, {not_found, UserId}} 2833 end; 2834 {ok, UserId} -> 2835 ?vinfo("[~w] Agent (~p) already registered" 2836 "~nwhen" 2837 "~n Agents: ~p", 2838 [UserId, TargetName, which_agents()]), 2839 {error, {already_registered, TargetName}}; 2840 {ok, OtherUserId} -> 2841 ?vinfo("[~w] Agent (~p) already registered to ~p" 2842 "~nwhen" 2843 "~n Agents: ~p", 2844 [UserId, TargetName, OtherUserId, which_agents()]), 2845 {error, {already_registered, TargetName, OtherUserId}} 2846 end. 2847 2848do_handle_register_agent(_TargetName, []) -> 2849 ok; 2850do_handle_register_agent(TargetName, [{Item, Val}|Rest]) -> 2851 ?vtrace("do_handle_register_agent -> entry with" 2852 "~n TargetName: ~p" 2853 "~n Item: ~p" 2854 "~n Val: ~p" 2855 "~n Rest: ~p", [TargetName, Item, Val, Rest]), 2856 case (catch do_update_agent_info(TargetName, Item, Val)) of 2857 ok -> 2858 do_handle_register_agent(TargetName, Rest); 2859 {error, Reason} -> 2860 ?vtrace("do_handle_register_agent -> failed updating ~p" 2861 "~n Item: ~p" 2862 "~n Reason: ~p", [Item, Reason]), 2863 ets:match_delete(snmpm_agent_table, {TargetName, '_'}), 2864 {error, Reason} 2865 end; 2866do_handle_register_agent(TargetName, BadConfig) -> 2867 error_msg("error during agent registration - bad config: ~n~p", 2868 [BadConfig]), 2869 ets:match_delete(snmpm_agent_table, {TargetName, '_'}), 2870 {error, {bad_agent_config, TargetName, BadConfig}}. 2871 2872 2873handle_unregister_agent(UserId, TargetName) -> 2874 ?vdebug("handle_unregister_agent -> entry with" 2875 "~n UserId: ~p" 2876 "~n TargetName: ~p", [UserId, TargetName]), 2877 case (catch agent_info(TargetName, user_id)) of 2878 {ok, UserId} -> 2879 {ok, EngineID} = agent_info(TargetName, engine_id), 2880 reset_usm_cache(EngineID), 2881 %% <DIRTY-BACKWARD-COMPATIBILLITY> 2882 %% And now for some (backward compatibillity) 2883 %% dirty crossref stuff 2884 {ok, Domain} = agent_info(TargetName, tdomain), 2885 {ok, Address} = agent_info(TargetName, taddress), 2886 ets:delete(snmpm_agent_table, {Domain, Address, target_name}), 2887 %% </DIRTY-BACKWARD-COMPATIBILLITY> 2888 ets:match_delete(snmpm_agent_table, {{TargetName, '_'}, '_'}), 2889 ok; 2890 {ok, OtherUserId} -> 2891 {error, {not_owner, OtherUserId}}; 2892 Error -> 2893 Error 2894 end. 2895 2896 2897handle_update_agent_info(UserId, TargetName, Info) -> 2898 ?vdebug("handle_update_agent_info -> entry with" 2899 "~n UserId: ~p" 2900 "~n TargetName: ~p" 2901 "~n Info: ~p", [UserId, TargetName, Info]), 2902 %% Verify ownership 2903 case (catch agent_info(TargetName, user_id)) of 2904 {ok, UserId} -> 2905 handle_update_agent_info(TargetName, Info); 2906 {ok, OtherUserId} -> 2907 {error, {not_owner, OtherUserId}}; 2908 Error -> 2909 Error 2910 end. 2911 2912handle_update_agent_info(TargetName, Info) -> 2913 ?vtrace("handle_update_agent_info -> entry with" 2914 "~n TargetName: ~p" 2915 "~n Info: ~p", [TargetName, Info]), 2916 %% Verify info 2917 try 2918 verify_illegal(Info, [user_id]), 2919 %% If port or domain is part of the info, then use it. 2920 %% If not, lookup what is already stored for 2921 %% this agent and use that. 2922 do_update_agent_info( 2923 TargetName, 2924 fix_agent_config( 2925 verify_agent_config( 2926 ensure_agent_info(TargetName, [port,tdomain], Info)))) 2927 catch 2928 Error -> 2929 Error; 2930 T:E -> 2931 {error, {failed_info_verification, Info, T, E}} 2932 end. 2933 2934handle_update_agent_info(UserId, TargetName, Item, Val) -> 2935 ?vdebug("handle_update_agent_info -> entry with" 2936 "~n UserId: ~p" 2937 "~n TargetName: ~p" 2938 "~n Item: ~p" 2939 "~n Val: ~p", [UserId, TargetName, Item, Val]), 2940 handle_update_agent_info(TargetName, [{Item, Val}]). 2941 2942do_update_agent_info(TargetName, Info) -> 2943 ?vtrace("do_update_agent_info -> entry with~n" 2944 " TargetName: ~p~n" 2945 " Info: ~p", [TargetName,Info]), 2946 InsertItem = 2947 fun({Item, Val}) -> 2948 ets:insert(snmpm_agent_table, {{TargetName, Item}, Val}) 2949 end, 2950 lists:foreach(InsertItem, Info). 2951 2952do_update_agent_info(TargetName, Item, Val) -> 2953 ?vtrace("do_update_agent_info -> entry with" 2954 "~n TargetName: ~p" 2955 "~n Item: ~p" 2956 "~n Val: ~p", [TargetName, Item, Val]), 2957 ets:insert(snmpm_agent_table, {{TargetName, Item}, Val}), 2958 ok. 2959 2960 2961handle_register_usm_user(#usm_user{engine_id = EngineID, 2962 name = Name} = User) -> 2963 ?vdebug("handle_register_usm_user -> entry with" 2964 "~n User: ~p", [User]), 2965 Key = usm_key(EngineID, Name), 2966 case ets:lookup(snmpm_usm_table, Key) of 2967 [] -> 2968 do_update_usm_user_info(Key, User); 2969 _ -> 2970 {error, {already_registered, EngineID, Name}} 2971 end; 2972handle_register_usm_user(BadUsmUser) -> 2973 {error, {bad_usm_user, BadUsmUser}}. 2974 2975handle_unregister_usm_user(EngineID, Name) -> 2976 ?vdebug("handle_unregister_usm_user -> entry with" 2977 "~n EngineID: ~p" 2978 "~n Name: ~p", [EngineID, Name]), 2979 Key = usm_key(EngineID, Name), 2980 ets:delete(snmpm_usm_table, Key), 2981 ok. 2982 2983 2984handle_update_usm_user_info(EngineID, Name, Item, Val) -> 2985 ?vdebug("handle_update_usm_user_info -> entry with" 2986 "~n EngineID: ~p" 2987 "~n Name: ~p" 2988 "~n Item: ~p" 2989 "~n Val: ~p", [EngineID, Name, Item, Val]), 2990 Key = usm_key(EngineID, Name), 2991 case ets:lookup(snmpm_usm_table, Key) of 2992 [] -> 2993 {error, not_found}; 2994 [{_Key, User}] -> 2995 do_update_usm_user_info(Key, User, Item, Val) 2996 end. 2997 2998do_update_usm_user_info(Key, User, sec_name, Val) -> 2999 %% case verify_usm_user_sec_name(Val) of 3000 %% ok -> 3001 %% do_update_usm_user_info(Key, User#usm_user{sec_name = Val}); 3002 %% _ -> 3003 %% {error, {invalid_usm_sec_name, Val}} 3004 %% end; 3005 ok = verify_usm_user_sec_name(Val), 3006 do_update_usm_user_info(Key, User#usm_user{sec_name = Val}); 3007do_update_usm_user_info(Key, User, auth, Val) 3008 when (Val =:= usmNoAuthProtocol) orelse 3009 (Val =:= usmHMACMD5AuthProtocol) orelse 3010 (Val =:= usmHMACSHAAuthProtocol) -> 3011 do_update_usm_user_info(Key, User#usm_user{auth = Val}); 3012do_update_usm_user_info(_Key, _User, auth, Val) -> 3013 {error, {invalid_auth_protocol, Val}}; 3014do_update_usm_user_info(Key, 3015 #usm_user{auth = usmNoAuthProtocol} = User, 3016 auth_key, Val) -> 3017 case (catch snmp_conf:check_string(Val, any)) of 3018 ok -> 3019 do_update_usm_user_info(Key, User#usm_user{auth_key = Val}); 3020 _ -> 3021 {error, {invalid_auth_key, Val}} 3022 end; 3023do_update_usm_user_info(Key, 3024 #usm_user{auth = usmHMACMD5AuthProtocol} = User, 3025 auth_key, Val) 3026 when length(Val) =:= 16 -> 3027 case is_crypto_supported(md5) of 3028 true -> 3029 do_update_usm_user_info(Key, User#usm_user{auth_key = Val}); 3030 false -> 3031 {error, {unsupported_crypto, md5}} 3032 end; 3033do_update_usm_user_info(_Key, 3034 #usm_user{auth = usmHMACMD5AuthProtocol}, 3035 auth_key, Val) when is_list(Val) -> 3036 Len = length(Val), 3037 {error, {invalid_auth_key_length, usmHMACMD5AuthProtocol, Len}}; 3038do_update_usm_user_info(_Key, 3039 #usm_user{auth = usmHMACMD5AuthProtocol}, 3040 auth_key, Val) -> 3041 {error, {invalid_auth_key, usmHMACMD5AuthProtocol, Val}}; 3042do_update_usm_user_info(Key, 3043 #usm_user{auth = usmHMACSHAAuthProtocol} = User, 3044 auth_key, Val) 3045 when length(Val) =:= 20 -> 3046 case is_crypto_supported(sha) of 3047 true -> 3048 do_update_usm_user_info(Key, User#usm_user{auth_key = Val}); 3049 false -> 3050 {error, {unsupported_crypto, sha}} 3051 end; 3052do_update_usm_user_info(_Key, 3053 #usm_user{auth = usmHMACSHAAuthProtocol}, 3054 auth_key, Val) when is_list(Val) -> 3055 Len = length(Val), 3056 {error, {invalid_auth_key_length, usmHMACSHAAuthProtocol, Len}}; 3057do_update_usm_user_info(_Key, 3058 #usm_user{auth = usmHMACSHAAuthProtocol}, 3059 auth_key, Val) -> 3060 {error, {invalid_auth_key, usmHMACSHAAuthProtocol, Val}}; 3061do_update_usm_user_info(Key, User, priv, Val) 3062 when (Val =:= usmNoPrivProtocol) orelse 3063 (Val =:= usmDESPrivProtocol) orelse 3064 (Val =:= usmAesCfb128Protocol) -> 3065 do_update_usm_user_info(Key, User#usm_user{priv = Val}); 3066do_update_usm_user_info(_Key, _User, priv, Val) -> 3067 {error, {invalid_priv_protocol, Val}}; 3068do_update_usm_user_info(Key, 3069 #usm_user{priv = usmNoPrivProtocol} = User, 3070 priv_key, Val) -> 3071 case (catch snmp_conf:check_string(Val, any)) of 3072 ok -> 3073 do_update_usm_user_info(Key, User#usm_user{priv_key = Val}); 3074 _ -> 3075 {error, {invalid_priv_key, Val}} 3076 end; 3077do_update_usm_user_info(Key, 3078 #usm_user{priv = usmDESPrivProtocol} = User, 3079 priv_key, Val) 3080 when length(Val) =:= 16 -> 3081 case is_crypto_supported(des_cbc) of 3082 true -> 3083 do_update_usm_user_info(Key, User#usm_user{priv_key = Val}); 3084 false -> 3085 {error, {unsupported_crypto, des_cbc}} 3086 end; 3087do_update_usm_user_info(Key, 3088 #usm_user{priv = usmAesCfb128Protocoll} = User, 3089 priv_key, Val) 3090 when length(Val) =:= 16 -> 3091 case is_crypto_supported(aes_cfb128) of 3092 true -> 3093 do_update_usm_user_info(Key, User#usm_user{priv_key = Val}); 3094 false -> 3095 {error, {unsupported_crypto, aes_cfb128}} 3096 end; 3097do_update_usm_user_info(_Key, 3098 #usm_user{auth = usmHMACSHAAuthProtocol}, 3099 priv_key, Val) when is_list(Val) -> 3100 Len = length(Val), 3101 {error, {invalid_priv_key_length, usmHMACSHAAuthProtocol, Len}}; 3102do_update_usm_user_info(_Key, 3103 #usm_user{auth = usmHMACSHAAuthProtocol}, 3104 priv_key, Val) -> 3105 {error, {invalid_priv_key, usmHMACSHAAuthProtocol, Val}}; 3106do_update_usm_user_info(_Key, _User, Item, Val) -> 3107 {error, {bad_item, Item, Val}}. 3108 3109do_update_usm_user_info(Key, User) -> 3110 ets:insert(snmpm_usm_table, {Key, User}), 3111 ok. 3112 3113 3114usm_key(EngineId, Name) -> 3115 {usmUserTable, EngineId, Name}. 3116 3117 3118%% --------------------------------------------------------------------- 3119 3120verify_mandatory(_, []) -> 3121 ok; 3122verify_mandatory(Conf, [Mand|Mands]) -> 3123 case lists:keymember(Mand, 1, Conf) of 3124 true -> 3125 verify_mandatory(Conf, Mands); 3126 false -> 3127 error({missing_mandatory_config, Mand}) 3128 end. 3129 3130verify_illegal(_, []) -> 3131 ok; 3132verify_illegal(Conf, [Inv|Invs]) -> 3133 case lists:member(Inv, Conf) of 3134 false -> 3135 verify_illegal(Conf, Invs); 3136 true -> 3137 error({illegal_config, Inv}) 3138 end. 3139 3140verify_someof(Conf, [Mand|Mands]) -> 3141 case lists:keymember(Mand, 1, Conf) of 3142 true -> 3143 ok; 3144 false -> 3145 case Mands of 3146 [] -> 3147 error({missing_mandatory_config, Mand}); 3148 _ -> 3149 verify_someof(Conf, Mands) 3150 end 3151 end. 3152 3153ensure_config([], Config) -> 3154 Config; 3155ensure_config([Default|Defaults], Config) -> 3156 case lists:keymember(element(1, Default), 1, Config) of 3157 true -> 3158 ensure_config(Defaults, Config); 3159 false -> 3160 ensure_config(Defaults, [Default|Config]) 3161 end. 3162 3163 3164 3165%%%------------------------------------------------------------------- 3166%%% 3167%%% Mini MIB stuff 3168%%% 3169%%%------------------------------------------------------------------- 3170 3171init_mini_mib(MibFiles) -> 3172 MiniMibs = lists:flatten([do_load_mib(MibFile) || MibFile <- MibFiles]), 3173 MiniMIB = remove_duplicates(lists:keysort(1, MiniMibs), []), 3174 init_mini_mib2(MiniMIB). 3175 3176remove_duplicates([], Res) -> 3177 Res; 3178remove_duplicates([X,X|T], Res) -> 3179 remove_duplicates([X|T], Res); 3180remove_duplicates([{Oid, Name, Type, _} = X, {Oid, Name, Type, _}|T], Res) -> 3181 remove_duplicates([X|T], Res); 3182remove_duplicates([X|T], Res) -> 3183 remove_duplicates(T, [X|Res]). 3184 3185init_mini_mib2([]) -> 3186 ok; 3187init_mini_mib2([{Oid, Name, Type, MibName}|MiniMib]) -> 3188 ?vtrace("init mini mib -> ~w: ~w [~w] from ~s", 3189 [Name, Oid, Type,MibName ]), 3190 ets:insert(snmpm_mib_table, {{mini_mib, Oid}, Name, Type, MibName}), 3191 init_mini_mib2(MiniMib). 3192 3193 3194handle_load_mib(Mib) -> 3195 [{mibs, Mibs0}] = ets:lookup(snmpm_config_table, mibs), 3196 case lists:member(Mib, Mibs0) of 3197 true -> 3198 {error, already_loaded}; 3199 false -> 3200 Mibs = [Mib|Mibs0], 3201 case (catch do_load_mib(Mib)) of 3202 MiniElems when is_list(MiniElems) -> 3203 ets:insert(snmpm_config_table, {mibs, Mibs}), 3204 update_mini_mib(MiniElems), 3205 ok; 3206 Error -> 3207 Error 3208 end 3209 end. 3210 3211update_mini_mib([]) -> 3212 ok; 3213update_mini_mib([{Oid, Name, Type, MibName}|Elems]) -> 3214 Key = {mini_mib, Oid}, 3215 case ets:lookup(snmpm_mib_table, Key) of 3216 [{Key, _Name, _Type, _AnotherMibName}] -> 3217 %% Already loaded from another mib 3218 update_mini_mib(Elems); 3219 [] -> 3220 %% Not yet loaded 3221 ?vtrace("update mini mib -> ~w: ~w [~w] from ~s", 3222 [Name, Oid, Type, MibName]), 3223 ets:insert(snmpm_mib_table, {Key, Name, Type, MibName}), 3224 update_mini_mib(Elems) 3225 end. 3226 3227 3228handle_unload_mib(Mib) -> 3229 Key = {mib, Mib}, 3230 case ets:lookup(snmpm_mib_table, Key) of 3231 [{Key, MibName, _MibFile}] -> 3232 do_unload_mib(MibName), 3233 [{mibs, Mibs0}] = ets:lookup(snmpm_config_table, mibs), 3234 Mibs = lists:delete(Mib, Mibs0), 3235 ets:insert(snmpm_config_table, {mibs, Mibs}), 3236 ets:delete(snmpm_mib_table, Key), 3237 ok; 3238 _ -> 3239 {error, not_loaded} 3240 end. 3241 3242do_unload_mib(MibName) -> 3243 Pat = {{mini_mib, '$1'}, '_', '_', MibName}, 3244 Oids = ets:match(snmpm_mib_table, Pat), 3245 F = fun([Oid]) -> ets:delete(snmpm_mib_table, {mini_mib, Oid}) end, 3246 lists:foreach(F, Oids). 3247 3248 3249do_load_mib(MibFile) -> 3250 ?vtrace("load mib ~s", [MibFile]), 3251 F1 = snmp_misc:strip_extension_from_filename(MibFile, ".bin"), 3252 ActualFileName = lists:append(F1, ".bin"), 3253 case snmp_misc:read_mib(ActualFileName) of 3254 {ok, #mib{name = Name, mes = MEs, traps = Traps}} -> 3255 %% Check that the mib was not loaded or loaded 3256 %% with a different filename: 3257 %% e.g. /tmp/MYMIB.bin and /tmp/mibs/MYMIB.bin 3258 Name1 = mib_name(Name), 3259 Pattern = {{mib, '_'}, Name1, '$1'}, 3260 case ets:match(snmpm_mib_table, Pattern) of 3261 [] -> 3262 3263 Rec = {{mib, MibFile}, Name1, ActualFileName}, 3264 ets:insert(snmpm_mib_table, Rec), 3265 init_mini_mib_elems(Name1, MEs++Traps, []); 3266 3267 %% This means that the mib has already been loaded 3268 [[ActualFileName]] -> 3269 []; 3270 3271 %% This means that the mib was loaded before, 3272 %% but under another filename 3273 [[OtherMibFile]] -> 3274 error({already_loaded, MibFile, OtherMibFile}) 3275 end; 3276 3277 {error, Reason} -> 3278 error({failed_reading_mib, MibFile, Reason}) 3279 end. 3280 3281mib_name(N) when is_list(N) -> 3282 list_to_atom(N); 3283mib_name(N) -> 3284 N. 3285 3286init_mini_mib_elems(_, [], Res) -> 3287 Res; 3288init_mini_mib_elems(MibName, 3289 [#me{aliasname = N, 3290 oid = Oid, 3291 entrytype = variable, 3292 asn1_type = #asn1_type{bertype = Type}} | T], Res) -> 3293 init_mini_mib_elems(MibName, T, [{Oid, N, Type, MibName}|Res]); 3294 3295init_mini_mib_elems(MibName, 3296 [#me{aliasname = N, 3297 oid = Oid, 3298 entrytype = table_column, 3299 asn1_type = #asn1_type{bertype = Type}}|T], Res) -> 3300 init_mini_mib_elems(MibName, T, [{Oid, N, Type, MibName}|Res]); 3301 3302init_mini_mib_elems(MibName, 3303 [#me{aliasname = N, 3304 oid = Oid, 3305 asn1_type = undefined}|T], Res) -> 3306 init_mini_mib_elems(MibName, T, [{Oid, N, undefined, MibName}|Res]); 3307 3308init_mini_mib_elems(MibName, 3309 [#notification{trapname = N, 3310 oid = Oid}|T], Res) -> 3311 init_mini_mib_elems(MibName, T, [{Oid, N, undefined, MibName}|Res]); 3312 3313init_mini_mib_elems(MibName, [_|T], Res) -> 3314 init_mini_mib_elems(MibName, T, Res). 3315 3316 3317 3318%%---------------------------------------------------------------------- 3319 3320fix_address(Domain, Address) -> 3321 case snmp_conf:check_address(Domain, Address) of 3322 ok -> 3323 Address; 3324 {ok, NAddress} -> 3325 NAddress 3326 end. 3327 3328%%---------------------------------------------------------------------- 3329 3330call(Req) -> 3331 call(Req, infinity). 3332 3333call(Req, To) -> 3334 gen_server:call(?SERVER, Req, To). 3335 3336% cast(Msg) -> 3337% gen_server:cast(snmpm_server, Msg). 3338 3339 3340%%------------------------------------------------------------------- 3341 3342get_atl_dir(Opts) -> 3343 get_opt(dir, Opts). 3344 3345get_atl_type(Opts) -> 3346 case get_opt(type, Opts, read_write) of 3347 read_write -> 3348 [read,write]; 3349 read -> 3350 [read]; 3351 write -> 3352 [write] 3353 end. 3354 3355get_atl_size(Opts) -> 3356 get_opt(size, Opts). 3357 3358get_atl_repair(Opts) -> 3359 get_opt(repair, Opts, truncate). 3360 3361get_atl_seqno(Opts) -> 3362 get_opt(seqno, Opts, false). 3363 3364 3365%%---------------------------------------------------------------------- 3366 3367get_opt(Key, Opts) -> 3368 ?d("get option ~w from ~p", [Key, Opts]), 3369 snmp_misc:get_option(Key, Opts). 3370 3371get_opt(Key, Opts, Def) -> 3372 ?d("get option ~w with default ~p from ~p", [Key, Def, Opts]), 3373 snmp_misc:get_option(Key, Opts, Def). 3374 3375 3376%%---------------------------------------------------------------------- 3377 3378get_info() -> 3379 ProcSize = proc_mem(self()), 3380 CntSz = tab_size(snmpm_counter_table), 3381 StatsSz = tab_size(snmpm_stats_table), 3382 MibSz = tab_size(snmpm_mib_table), 3383 ConfSz = tab_size(snmpm_config_table), 3384 AgentSz = tab_size(snmpm_agent_table), 3385 UserSz = tab_size(snmpm_user_table), 3386 UsmSz = tab_size(snmpm_usm_table), 3387 [{process_memory, ProcSize}, 3388 {db_memory, [{counter, CntSz}, 3389 {stats, StatsSz}, 3390 {mib, MibSz}, 3391 {config, ConfSz}, 3392 {agent, AgentSz}, 3393 {user, UserSz}, 3394 {usm, UsmSz}]}]. 3395 3396proc_mem(P) when is_pid(P) -> 3397 case (catch erlang:process_info(P, memory)) of 3398 {memory, Sz} when is_integer(Sz) -> 3399 Sz; 3400 _ -> 3401 undefined 3402 end. 3403%% proc_mem(_) -> 3404%% undefined. 3405 3406tab_size(T) -> 3407 case (catch ets:info(T, memory)) of 3408 Sz when is_integer(Sz) -> 3409 Sz; 3410 _ -> 3411 undefined 3412 end. 3413 3414 3415%%---------------------------------------------------------------------- 3416 3417error(Reason) -> 3418 throw({error, Reason}). 3419 3420 3421%%---------------------------------------------------------------------- 3422 3423info_msg(F, A) -> 3424 ?snmpm_info("Config server: " ++ F, A). 3425 3426warning_msg(F, A) -> 3427 ?snmpm_warning("Config server: " ++ F, A). 3428 3429error_msg(F, A) -> 3430 ?snmpm_error("Config server: " ++ F, A). 3431 3432%% p(F) -> 3433%% p(F, []). 3434 3435%% p(F, A) -> 3436%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).