1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2004-2020. 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(SERVER_OPT_VERB_DEFAULT, silence). 151-define(SERVER_OPT_GCT_DEFAULT, 30000). 152-define(SERVER_OPT_MT_DEFAULT, true). 153-define(SERVER_OPT_CBP_DEFAULT, temporary). % permanent 154-define(SERVER_OPT_NIS_DEFAULT, none). 155 156%% -define(DEF_ADDR_TAG, default_addr_tag). 157-define(DEFAULT_TARGETNAME, default_agent). 158-define(DEF_PORT_TAG, default_port_tag). 159-define(SUPPORTED_DOMAINS, [transportDomainUdpIpv4, transportDomainUdpIpv6]). 160 161-ifdef(snmp_debug). 162-define(GS_START_LINK(Opts), 163 gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], 164 [{debug,[trace]}])). 165-else. 166-define(GS_START_LINK(Opts), 167 gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], [])). 168-endif. 169 170 171 172%%%------------------------------------------------------------------- 173%%% API 174%%%------------------------------------------------------------------- 175 176default_transport_domain() -> 177 snmpUDPDomain. 178 179 180start_link(Opts) -> 181 ?d("start_link -> entry with" 182 "~n Opts: ~p", [Opts]), 183 ?GS_START_LINK(Opts). 184 185stop() -> 186 call(stop). 187 188is_started() -> 189 call(is_started, 1000). 190 191backup(BackupDir) when is_list(BackupDir) -> 192 call({backup, BackupDir}). 193 194%% Backward compatibillity 195register_user(UserId, UserMod, UserData) -> 196 register_user(UserId, UserMod, UserData, []). 197 198register_user(UserId, UserMod, UserData, DefaultAgentConfig) 199 when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> 200 case (catch verify_user_behaviour(UserMod)) of 201 ok -> 202 {ok, SystemDefaultAgentConfig} = agent_info(), 203 Config = 204 ensure_config(SystemDefaultAgentConfig, 205 DefaultAgentConfig), 206%% Config = default_agent_config(DefaultAgentConfig), 207 call({register_user, UserId, UserMod, UserData, Config}); 208 Error -> 209 Error 210 end; 211register_user(UserId, _UserMod, _UserData, DefaultAgentConfig) 212 when (UserId =/= ?DEFAULT_USER) -> 213 {error, {bad_default_agent_config, DefaultAgentConfig}}; 214register_user(UserId, _, _, _) -> 215 {error, {bad_user_id, UserId}}. 216 217%% default_agent_config(DefaultAgentConfig) -> 218%% {ok, SystemDefaultAgentConfig} = agent_info(), 219%% default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig). 220 221%% default_agent_config([], DefaultAgentConfig) -> 222%% DefaultAgentConfig; 223%% default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) -> 224%% case lists:keymember(Key, 1, DefaultAgentConfig) of 225%% true -> 226%% default_agent_config(T, DefaultAgentConfig); 227%% false -> 228%% default_agent_config(T, [Entry|DefaultAgentConfig]) 229%% end. 230 231 232verify_user_behaviour(UserMod) -> 233 case snmp_misc:verify_behaviour(snmpm_user, UserMod) of 234 ok -> 235 ok; 236 Error -> 237 %% This user may implement the old behaviour, check it 238 case snmp_misc:verify_behaviour(snmpm_user_old, UserMod) of 239 ok -> 240 ok; 241 _ -> 242 throw(Error) 243 end 244 end. 245 246 247unregister_user(UserId) when UserId =/= ?DEFAULT_USER -> 248 call({unregister_user, UserId}); 249unregister_user(BadUserId) -> 250 {error, {bad_user_id, BadUserId}}. 251 252 253which_users() -> 254 Pattern = #user{id = '$1', _ = '_'}, 255 Match = ets:match(snmpm_user_table, Pattern), 256 [UserId || [UserId] <- Match, UserId =/= ?DEFAULT_USER]. 257 258 259user_info() -> 260 UserId = ?DEFAULT_USER, 261 case user_info(UserId) of 262 {ok, Mod, Data} -> 263 {ok, UserId, Mod, Data}; 264 Error -> 265 Error 266 end. 267 268user_info(UserId) -> 269 case ets:lookup(snmpm_user_table, UserId) of 270 [#user{mod = UserMod, data = UserData}] -> 271 {ok, UserMod, UserData}; 272 _ -> 273 {error, not_found} 274 end. 275 276user_info(UserId, Item) -> 277 case (catch do_user_info(UserId, Item)) of 278 {'EXIT', _} -> 279 {error, {not_found, Item}}; 280 Val -> 281 {ok, Val} 282 end. 283 284do_user_info(UserId, module) -> 285 ets:lookup_element(snmpm_user_table, UserId, #user.mod); 286do_user_info(UserId, data) -> 287 ets:lookup_element(snmpm_user_table, UserId, #user.data); 288do_user_info(UserId, default_agent_config) -> 289 ets:lookup_element(snmpm_user_table, UserId, #user.default_agent_config); 290do_user_info(_UserId, BadItem) -> 291 error({not_found, BadItem}). 292 293 294%% A target-name constructed in this way is a string with the following: 295%% <IP-address>:<Port>-<Version> 296%% This is intended for backward compatibility and therefore has 297%% only support for IPv4 addresses and *no* other transport domain. 298mk_target_name(Domain, Addr, Config) 299 when is_atom(Domain), is_list(Config) -> 300 Version = 301 case lists:keysearch(version, 1, Config) of 302 {value, {_, V}} -> 303 V; 304 false -> 305 select_lowest_supported_version() 306 end, 307 try 308 lists:flatten( 309 io_lib:format( 310 "~s-~w", [snmp_conf:mk_addr_string({Domain, Addr}), Version])) 311 catch 312 _ -> 313 lists:flatten( 314 io_lib:format("~p-~w", [Addr, Version])) 315 end; 316mk_target_name(Ip, Port, Config) 317 when is_integer(Port), is_list(Config) -> 318 Domain = default_transport_domain(), 319 try fix_address(Domain, {Ip, Port}) of 320 Address -> 321 mk_target_name(Domain, Address, Config) 322 catch 323 _ -> 324 Version = 325 case lists:keysearch(version, 1, Config) of 326 {value, {_, V}} -> 327 V; 328 false -> 329 select_lowest_supported_version() 330 end, 331 lists:flatten( 332 io_lib:format("~p:~w-~w", [Ip, Port, Version])) 333 end. 334 335 336select_lowest_supported_version() -> 337 {ok, Versions} = system_info(versions), 338 select_lowest_supported_version([v1, v2, v3], Versions). 339 340select_lowest_supported_version([], Versions) -> 341 error({bad_versions, Versions}); 342select_lowest_supported_version([H|T], Versions) -> 343 case lists:member(H, Versions) of 344 true -> 345 H; 346 false -> 347 select_lowest_supported_version(T, Versions) 348 end. 349 350 351register_agent(UserId, _TargetName, _Config0) when (UserId =:= user_id) -> 352 {error, {bad_user_id, UserId}}; 353register_agent(UserId, TargetName, Config0) 354 when (is_list(TargetName) andalso 355 (length(TargetName) > 0) andalso 356 is_list(Config0)) -> 357 358 ?vtrace("register_agent -> entry with" 359 "~n UserId: ~p" 360 "~n TargetName: ~p" 361 "~n Config0: ~p", [UserId, TargetName, Config0]), 362 363 %% Check: 364 %% 1) That the mandatory configs are present 365 %% 2) That no illegal config, e.g. user_id (used internally), 366 %% is not present 367 %% 3) Check that there are no invalid or erroneous configs 368 %% 4) Check that the manager is capable of using the selected version 369 try 370 verify_mandatory(Config0, [engine_id, reg_type]), 371 verify_someof(Config0, [address, taddress]), 372 verify_illegal(Config0, [user_id]), 373 Config = verify_agent_config(Config0), 374 Vsns = versions(), 375 Vsn = which_version(Config), 376 verify_version(Vsn, Vsns), 377 call({register_agent, UserId, TargetName, Config}) 378 catch 379 Error -> 380 Error 381 end. 382 383versions() -> 384 case system_info(versions) of 385 {ok, Vsns} -> 386 Vsns; 387 {error, _} = ERROR -> 388 throw(ERROR) 389 end. 390 391which_version(Conf) -> 392 case lists:keysearch(version, 1, Conf) of 393 {value, {version, V}} -> 394 V; 395 false -> 396 v1 397 end. 398 399verify_version(Vsn, Vsns) -> 400 case lists:member(Vsn, Vsns) of 401 true -> 402 ok; 403 false -> 404 Reason = {version_not_supported_by_manager, Vsn, Vsns}, 405 error(Reason) 406 end. 407 408 409 410unregister_agent(UserId, TargetName) -> 411 call({unregister_agent, UserId, TargetName}). 412 413%% This is the old style agent unregistration (using Addr and Port). 414unregister_agent(UserId, Domain, Address) when is_atom(Domain) -> 415 try fix_address(Domain, Address) of 416 NAddress -> 417 do_unregister_agent(UserId, Domain, NAddress) 418 catch 419 _ -> 420 {error, not_found} 421 end; 422unregister_agent(UserId, Ip, Port) when is_integer(Port) -> 423 Domain = default_transport_domain(), 424 try fix_address(Domain, {Ip, Port}) of 425 Address -> 426 do_unregister_agent(UserId, Domain, Address) 427 catch 428 _ -> 429 {error, not_found} 430 end. 431 432do_unregister_agent(UserId, Domain, Address) -> 433 case do_agent_info(Domain, Address, target_name) of 434 {ok, TargetName} -> 435 unregister_agent(UserId, TargetName); 436 Error -> 437 Error 438 end. 439 440 441 442agent_info() -> 443 agent_info(?DEFAULT_TARGETNAME, all). 444 445agent_info(TargetName, all) -> 446 case ets:match_object(snmpm_agent_table, {{TargetName, '_'}, '_'}) of 447 [] -> 448 {error, not_found}; 449 All -> 450 {ok, [{Item, Val} || {{_, Item}, Val} <- All]} 451 end; 452%% Begin backwards compatibility 453agent_info(TargetName, address) -> 454 case agent_info({TargetName, taddress}) of 455 {ok, Val} -> 456 {Addr, _} = Val, 457 {ok, Addr}; 458 _ -> 459 %% This should be redundant since 'taddress' should exist 460 agent_info({TargetName, address}) 461 end; 462agent_info(TargetName, port) -> 463 case agent_info({TargetName, taddress}) of 464 {ok, Val} -> 465 {_, Port} = Val, 466 {ok, Port}; 467 _ -> 468 %% This should be redundant since 'taddress' should exist 469 agent_info({TargetName, port}) 470 end; 471%% End backwards compatibility 472agent_info(TargetName, Item) -> 473 agent_info({TargetName, Item}). 474 475agent_info(Key) -> 476 case ets:lookup(snmpm_agent_table, Key) of 477 [{_, Val}] -> 478 {ok, Val}; 479 [] -> 480 {error, not_found} 481 end. 482 483agent_info(Domain, Address, Item) when is_atom(Domain) -> 484 try fix_address(Domain, Address) of 485 NAddress -> 486 do_agent_info(Domain, NAddress, Item) 487 catch 488 _C:_E:_S -> 489 {error, not_found} 490 end; 491agent_info(Ip, Port, Item) when is_integer(Port) -> 492 %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) entry~n", 493 %% [Ip, Port, Item]), 494 Domain = default_transport_domain(), 495 try fix_address(Domain, {Ip, Port}) of 496 Address -> 497 do_agent_info(Domain, Address, Item) 498 catch 499 _C:_E:_S -> 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, ?SERVER_OPT_VERB_DEFAULT), 1121 ServerGct = get_opt(timeout, ServerOpts, ?SERVER_OPT_GCT_DEFAULT), 1122 ServerMt = get_opt(multi_threaded, ServerOpts, ?SERVER_OPT_MT_DEFAULT), 1123 ServerCBP = get_opt(cbproxy, ServerOpts, ?SERVER_OPT_CBP_DEFAULT), 1124 ServerNIS = get_opt(netif_sup, ServerOpts, ?SERVER_OPT_NIS_DEFAULT), 1125 ets:insert(snmpm_config_table, {server_verbosity, ServerVerb}), 1126 ets:insert(snmpm_config_table, {server_timeout, ServerGct}), 1127 ets:insert(snmpm_config_table, {server_multi_threaded, ServerMt}), 1128 ets:insert(snmpm_config_table, {server_cbproxy, ServerCBP}), 1129 ets:insert(snmpm_config_table, {server_nis, ServerNIS}), 1130 1131 %% -- Mibs (optional) -- 1132 ?vdebug("initiate mini mib", []), 1133 Mibs = get_opt(mibs, Opts, []), 1134 ets:insert(snmpm_config_table, {mibs, Mibs}), 1135 init_mini_mib(Mibs), 1136 1137 %% -- Net-if (optional) -- 1138 ?vdebug("net-if options", []), 1139 NetIfIrb = 1140 case get_opt(inform_request_behaviour, Opts, ?IRB_DEFAULT) of 1141 user -> 1142 {user, timer:seconds(15)}; 1143 Irb -> 1144 Irb 1145 end, 1146 NetIfOpts = get_opt(net_if, Opts, []), 1147 NetIfMod = get_opt(module, NetIfOpts, snmpm_net_if), 1148 NetIfVerb = get_opt(verbosity, NetIfOpts, silence), 1149 NetIfOptions = get_opt(options, NetIfOpts, []), 1150 ets:insert(snmpm_config_table, {net_if_module, NetIfMod}), 1151 ets:insert(snmpm_config_table, {net_if_verbosity, NetIfVerb}), 1152 ets:insert(snmpm_config_table, {net_if_irb, NetIfIrb}), 1153 ets:insert(snmpm_config_table, {net_if_options, NetIfOptions}), 1154 1155 %% -- Versions (optional) -- 1156 %% -- Versions (mandatory) ???????????? -- 1157 ?vdebug("versions", []), 1158 Vsns = get_opt(versions, Opts, [v1, v2, v3]), 1159 ets:insert(snmpm_config_table, {versions, Vsns}), 1160 1161 %% -- Audit trail log (optional) -- 1162 ?vdebug("audit trail log", []), 1163 case get_opt(audit_trail_log, Opts, []) of 1164 [] -> 1165 ?vtrace("no ATL", []), 1166 ets:insert(snmpm_config_table, {audit_trail_log, false}); 1167 AuditTrailLogOpts -> 1168 ?vtrace("ATL options: ~p", [AuditTrailLogOpts]), 1169 ets:insert(snmpm_config_table, {audit_trail_log, true}), 1170 LogDir = get_atl_dir(AuditTrailLogOpts), 1171 LogType = get_atl_type(AuditTrailLogOpts), 1172 LogSize = get_atl_size(AuditTrailLogOpts), 1173 LogRep = get_atl_repair(AuditTrailLogOpts), 1174 LogSeqNo = get_atl_seqno(AuditTrailLogOpts), 1175 ets:insert(snmpm_config_table, {audit_trail_log_dir, LogDir}), 1176 ets:insert(snmpm_config_table, {audit_trail_log_type, LogType}), 1177 ets:insert(snmpm_config_table, {audit_trail_log_size, LogSize}), 1178 ets:insert(snmpm_config_table, {audit_trail_log_repair, LogRep}), 1179 ets:insert(snmpm_config_table, {audit_trail_log_seqno, LogSeqNo}) 1180 end, 1181 1182 %% -- System default agent config -- 1183 ?vdebug("system default agent config", []), 1184 init_agent_default(), 1185 1186 %% -- User (optional) -- 1187 ?vdebug("default user", []), 1188 DefUserMod = get_opt(def_user_mod, Opts, ?USER_MOD_DEFAULT), 1189 DefUserData = get_opt(def_user_data, Opts, ?USER_DATA_DEFAULT), 1190 ets:insert(snmpm_config_table, {def_user_mod, DefUserMod}), 1191 ets:insert(snmpm_config_table, {def_user_data, DefUserData}), 1192 1193 {ok, SystemDefaultAgentConfig} = agent_info(), 1194 DefUser = #user{id = ?DEFAULT_USER, 1195 mod = DefUserMod, 1196 data = DefUserData, 1197 default_agent_config = SystemDefaultAgentConfig}, 1198 ok = handle_register_user(DefUser), 1199 1200 %% -- Note store -- 1201 ?vdebug("note store", []), 1202 NoteStoreOpts = get_opt(note_store, Opts, []), 1203 NoteStoreVerb = get_opt(verbosity, NoteStoreOpts, silence), 1204 NoteStoreTimeout = get_opt(timeout, NoteStoreOpts, 30000), 1205 ets:insert(snmpm_config_table, {note_store_verbosity, NoteStoreVerb}), 1206 ets:insert(snmpm_config_table, {note_store_timeout, NoteStoreTimeout}), 1207 1208 %% -- Manager SNMP config -- 1209 ?vdebug("manager snmp config", []), 1210 MgrConf = read_manager_config_file(ConfDir), 1211 init_manager_config(MgrConf), 1212 1213 %% -- User config -- 1214 ?vdebug("users config", []), 1215 Users = read_users_config_file(ConfDir), 1216 init_users_config(Users), 1217 1218 %% -- Agents config -- 1219 ?vdebug("agents config", []), 1220 Agents = read_agents_config_file(ConfDir), 1221 init_agents_config(Agents), 1222 1223 %% -- USM config -- 1224 UsmUsers = read_usm_config_file(ConfDir), 1225 init_usm_users_config(UsmUsers), 1226 1227 %% -- snmp engine init -- 1228 init_engine(), 1229 1230 ?vlog("started", []), 1231 ok. 1232 1233 1234dets_open(Dir, DbInitError, Repair, AutoSave) -> 1235 Name = ?CONFIG_DB, 1236 Filename = dets_filename(Name, Dir), 1237 case file:read_file_info(Filename) of 1238 {ok, _} -> 1239 %% File exists 1240 case do_dets_open(Name, Filename, Repair, AutoSave) of 1241 {ok, _Dets} -> 1242 ok; 1243 {error, Reason1} -> 1244 info_msg("Corrupt local database: ~p", [Filename]), 1245 case DbInitError of 1246 terminate -> 1247 error({failed_reopen_dets, Filename, Reason1}); 1248 _ -> 1249 Saved = Filename ++ ".saved", 1250 file:rename(Filename, Saved), 1251 case do_dets_open(Name, Filename, 1252 Repair, AutoSave) of 1253 {ok, _Dets} -> 1254 ok; 1255 {error, Reason2} -> 1256 error({failed_open_dets, Filename, 1257 Reason1, Reason2}) 1258 end 1259 end 1260 end; 1261 _ -> 1262 case DbInitError of 1263 create_db_and_dir -> 1264 ok = filelib:ensure_dir(Filename); 1265 _ -> 1266 ok 1267 end, 1268 case do_dets_open(Name, Filename, Repair, AutoSave) of 1269 {ok, _Dets} -> 1270 ok; 1271 {error, Reason} -> 1272 error({failed_open_dets, Filename, Reason}) 1273 end 1274 end. 1275 1276do_dets_open(Name, Filename, Repair, AutoSave) -> 1277 Opts = [{repair, Repair}, 1278 {auto_save, AutoSave}, 1279 {file, Filename}], 1280 dets:open_file(Name, Opts). 1281 1282 1283dets_filename(Name, Dir) when is_atom(Name) -> 1284 dets_filename(atom_to_list(Name), Dir); 1285dets_filename(Name, Dir) -> 1286 filename:join(dets_filename1(Dir), Name). 1287 1288dets_filename1([]) -> "."; 1289dets_filename1(Dir) -> Dir. 1290 1291 1292%% ------------------------------------------------------------------------ 1293 1294init_engine() -> 1295 case get_engine_boots() of 1296 {ok, Val} when Val < 2147483647 -> 1297 set_engine_boots(Val + 1); 1298 {ok, _} -> 1299 ok; 1300 _ -> 1301 set_engine_boots(1) 1302 end, 1303 reset_engine_base(). 1304 1305reset_engine_base() -> 1306 ets:insert(snmpm_config_table, {snmp_engine_base, snmp_misc:now(sec)}). 1307 1308 1309%% ------------------------------------------------------------------------ 1310 1311verify_options(Opts, Mandatory) -> 1312 ?d("verify_options -> entry with" 1313 "~n Opts: ~p" 1314 "~n Mandatory: ~p", [Opts, Mandatory]), 1315 verify_mandatory_options(Opts, Mandatory), 1316 verify_options(Opts). 1317 1318verify_options([]) -> 1319 ?d("verify_options -> done", []), 1320 ok; 1321verify_options([Opt|Opts]) -> 1322 ?d("verify_options -> entry with" 1323 "~n Opt: ~p", [Opt]), 1324 verify_option(Opt), 1325 verify_options(Opts). 1326 1327verify_option({prio, Prio}) -> 1328 verify_prio(Prio); 1329verify_option({mibs, Mibs}) -> 1330 verify_mibs(Mibs); 1331verify_option({inform_request_behaviour, IRB}) -> 1332 verify_irb(IRB); 1333verify_option({net_if, NetIfOpts}) -> 1334 verify_net_if_opts(NetIfOpts); 1335verify_option({server, ServerOpts}) -> 1336 verify_server_opts(ServerOpts); 1337verify_option({note_store, NoteStoreOpts}) -> 1338 verify_note_store_opts(NoteStoreOpts); 1339verify_option({config, ConfOpts0}) -> 1340 %% Make sure any db_dir option is first in the options list to make it 1341 %% easier to check if the db_init_error option specifies that a missing 1342 %% db_dir should be created. 1343 ConfOpts = case lists:keytake(db_dir, 1, ConfOpts0) of 1344 false -> ConfOpts0; 1345 {value, Result, OtherOpts} -> [Result|OtherOpts] 1346 end, 1347 verify_config_opts(ConfOpts); 1348verify_option({versions, Vsns}) -> 1349 verify_versions(Vsns); 1350verify_option({audit_trail_log, LogOpts}) -> 1351 Mandatory = [dir, size], 1352 case (catch verify_mandatory_options(LogOpts, Mandatory)) of 1353 ok -> 1354 verify_audit_trail_log_opts(LogOpts); 1355 {error, {missing_mandatory, LogOpt}} -> 1356 error({missing_mandatory, audit_trail_log, LogOpt}) 1357 end; 1358verify_option({def_user_mod, Mod}) -> 1359 verify_module(def_user_mod, Mod); 1360verify_option({def_user_data, _Data}) -> 1361 ok; 1362verify_option(Opt) -> 1363 {error, {invalid_option, Opt}}. 1364 1365verify_prio(Prio) when is_atom(Prio) -> 1366 ok; 1367verify_prio(Prio) -> 1368 error({invalid_prio, Prio}). 1369 1370verify_irb(auto) -> 1371 ok; 1372verify_irb(user) -> 1373 ok; 1374verify_irb({user, To}) when is_integer(To) andalso (To > 0) -> 1375 ok; 1376verify_irb(IRB) -> 1377 error({invalid_irb, IRB}). 1378 1379verify_mibs([]) -> 1380 ok; 1381verify_mibs([Mib|Mibs]) when is_list(Mib) -> 1382 verify_mibs(Mibs); 1383verify_mibs(Mibs) -> 1384 error({invalid_mibs, Mibs}). 1385 1386verify_config_opts([]) -> 1387 ok; 1388verify_config_opts([{verbosity, Verbosity}|Opts]) -> 1389 verify_verbosity(Verbosity), 1390 verify_config_opts(Opts); 1391verify_config_opts([{dir, Dir}|Opts]) -> 1392 verify_conf_dir(Dir), 1393 verify_config_opts(Opts); 1394verify_config_opts([{db_dir, Dir}|Opts]) -> 1395 case lists:keyfind(db_init_error, 1, Opts) of 1396 {db_init_error, create_db_and_dir} -> 1397 verify_conf_db_dir(Dir, false); 1398 _ -> 1399 verify_conf_db_dir(Dir, true) 1400 end, 1401 verify_config_opts(Opts); 1402verify_config_opts([{db_init_error, DbInitErr}|Opts]) -> 1403 verify_conf_db_init_error(DbInitErr), 1404 verify_config_opts(Opts); 1405verify_config_opts([{repair, Repair}|Opts]) -> 1406 verify_conf_repair(Repair), 1407 verify_config_opts(Opts); 1408verify_config_opts([{auto_save, AutoSave}|Opts]) -> 1409 verify_conf_auto_save(AutoSave), 1410 verify_config_opts(Opts); 1411verify_config_opts([Opt|_]) -> 1412 error({invalid_config_option, Opt}). 1413 1414verify_server_opts([]) -> 1415 ok; 1416verify_server_opts([{verbosity, Verbosity}|Opts]) -> 1417 verify_verbosity(Verbosity), 1418 verify_server_opts(Opts); 1419verify_server_opts([{timeout, Timeout}|Opts]) -> 1420 verify_server_timeout(Timeout), 1421 verify_server_opts(Opts); 1422verify_server_opts([{multi_threaded, MT}|Opts]) when is_boolean(MT) -> 1423 verify_server_opts(Opts); 1424verify_server_opts([{cbproxy, CBP}|Opts]) -> 1425 verify_server_cbproxy(CBP), 1426 verify_server_opts(Opts); 1427verify_server_opts([{netif_sup, NIS}|Opts]) -> 1428 verify_server_nis(NIS), 1429 verify_server_opts(Opts); 1430verify_server_opts([Opt|_]) -> 1431 error({invalid_server_option, Opt}). 1432 1433verify_server_timeout(T) when is_integer(T) andalso (T > 0) -> 1434 ok; 1435verify_server_timeout(T) -> 1436 error({invalid_server_timeout, T}). 1437 1438verify_server_cbproxy(temporary) -> 1439 ok; 1440verify_server_cbproxy(permanent) -> 1441 ok; 1442verify_server_cbproxy(CBP) -> 1443 error({invalid_server_cbproxy, CBP}). 1444 1445verify_server_nis(none) -> 1446 ok; 1447verify_server_nis({PingTo, PongTo} = V) when is_integer(PingTo) andalso 1448 (PingTo > 0) andalso 1449 is_integer(PongTo) andalso 1450 (PongTo > 0) -> 1451 ok; 1452verify_server_nis(NIS) -> 1453 error({invalid_server_netif_sup, NIS}). 1454 1455 1456verify_net_if_opts([]) -> 1457 ok; 1458verify_net_if_opts([{module, Mod}|Opts]) -> 1459 verify_network_interface_behaviour(Mod), 1460 verify_net_if_opts(Opts); 1461verify_net_if_opts([{verbosity, Verbosity}|Opts]) -> 1462 verify_verbosity(Verbosity), 1463 verify_net_if_opts(Opts); 1464verify_net_if_opts([{options, Options}|Opts]) when is_list(Options) -> 1465 verify_net_if_opts(Opts); 1466verify_net_if_opts([Opt|_]) -> 1467 error({invalid_net_if_option, Opt}). 1468 1469verify_network_interface_behaviour(Mod) -> 1470 case snmp_misc:verify_behaviour(snmpm_network_interface, Mod) of 1471 ok -> 1472 ok; 1473 Error -> 1474 throw(Error) 1475 end. 1476 1477 1478verify_note_store_opts([]) -> 1479 ok; 1480verify_note_store_opts([{verbosity, Verbosity}|Opts]) -> 1481 verify_verbosity(Verbosity), 1482 verify_note_store_opts(Opts); 1483verify_note_store_opts([{timeout, Timeout}|Opts]) -> 1484 verify_note_store_timeout(Timeout), 1485 verify_note_store_opts(Opts); 1486verify_note_store_opts([Opt|_]) -> 1487 error({invalid_note_store_option, Opt}). 1488 1489verify_note_store_timeout(T) when is_integer(T) andalso (T > 0) -> 1490 ok; 1491verify_note_store_timeout(T) -> 1492 error({invalid_note_store_timeout, T}). 1493 1494verify_conf_dir(Dir) -> 1495 case (catch verify_dir(Dir)) of 1496 ok -> 1497 ok; 1498 {error, Reason} -> 1499 error({invalid_conf_dir, Dir, Reason}); 1500 _ -> 1501 error({invalid_conf_dir, Dir}) 1502 end. 1503 1504verify_conf_db_dir(Dir, true) -> 1505 case (catch verify_dir(Dir)) of 1506 ok -> 1507 ok; 1508 {error, Reason} -> 1509 error({invalid_conf_db_dir, Dir, Reason}); 1510 _ -> 1511 error({invalid_conf_db_dir, Dir}) 1512 end; 1513verify_conf_db_dir(_Dir, false) -> 1514 ok. 1515 1516verify_conf_db_init_error(terminate) -> 1517 ok; 1518verify_conf_db_init_error(create) -> 1519 ok; 1520verify_conf_db_init_error(create_db_and_dir) -> 1521 ok; 1522verify_conf_db_init_error(InvalidDbInitError) -> 1523 error({invalid_conf_db_init_error, InvalidDbInitError}). 1524 1525 1526verify_conf_repair(true) -> 1527 ok; 1528verify_conf_repair(false) -> 1529 ok; 1530verify_conf_repair(force) -> 1531 ok; 1532verify_conf_repair(InvalidRepair) -> 1533 error({invalid_conf_db_repair, InvalidRepair}). 1534 1535 1536verify_conf_auto_save(infinity) -> 1537 ok; 1538verify_conf_auto_save(AutoSave) 1539 when is_integer(AutoSave) andalso (AutoSave > 0) -> 1540 ok; 1541verify_conf_auto_save(InvalidAutoSave) -> 1542 error({invalid_conf_db_auto_save, InvalidAutoSave}). 1543 1544 1545verify_versions([]) -> 1546 ok; 1547verify_versions([Vsn|Vsns]) -> 1548 verify_version(Vsn), 1549 verify_versions(Vsns); 1550verify_versions(Vsns) -> 1551 error({invalid_versions, Vsns}). 1552 1553verify_version(v1) -> 1554 ok; 1555verify_version(v2) -> 1556 ok; 1557verify_version(v3) -> 1558 ok; 1559verify_version(Vsn) -> 1560 error({invalid_version, Vsn}). 1561 1562verify_audit_trail_log_opts([]) -> 1563 ok; 1564verify_audit_trail_log_opts([{dir, Dir}|Opts]) -> 1565 verify_log_dir(Dir), 1566 verify_audit_trail_log_opts(Opts); 1567verify_audit_trail_log_opts([{type, Type}|Opts]) -> 1568 verify_log_type(Type), 1569 verify_audit_trail_log_opts(Opts); 1570verify_audit_trail_log_opts([{size, Size}|Opts]) -> 1571 verify_log_size(Size), 1572 verify_audit_trail_log_opts(Opts); 1573verify_audit_trail_log_opts([{repair, Repair}|Opts]) -> 1574 verify_log_repair(Repair), 1575 verify_audit_trail_log_opts(Opts); 1576verify_audit_trail_log_opts([{seqno, SeqNo}|Opts]) -> 1577 verify_log_seqno(SeqNo), 1578 verify_audit_trail_log_opts(Opts); 1579verify_audit_trail_log_opts([Opt|_Opts]) -> 1580 error({invalid_audit_trail_log_option, Opt}). 1581 1582verify_log_type(read) -> 1583 ok; 1584verify_log_type(write) -> 1585 ok; 1586verify_log_type(read_write) -> 1587 ok; 1588verify_log_type(Type) -> 1589 error({invalid_audit_trail_log_type, Type}). 1590 1591verify_log_dir(Dir) -> 1592 case (catch verify_dir(Dir)) of 1593 ok -> 1594 ok; 1595 {error, Reason} -> 1596 error({invalid_audit_trail_log_dir, Dir, Reason}); 1597 _ -> 1598 error({invalid_audit_trail_log_dir, Dir}) 1599 end. 1600 1601verify_log_size(Sz) when is_integer(Sz) andalso (Sz > 0) -> 1602 ok; 1603verify_log_size(infinity) -> 1604 ok; 1605verify_log_size({MaxNoBytes, MaxNoFiles}) 1606 when (is_integer(MaxNoBytes) andalso 1607 (MaxNoBytes > 0) andalso 1608 is_integer(MaxNoFiles) andalso 1609 (MaxNoFiles > 0) andalso 1610 (MaxNoFiles < 65000)) -> 1611 ok; 1612verify_log_size(Sz) -> 1613 error({invalid_audit_trail_log_size, Sz}). 1614 1615verify_log_repair(true) -> ok; 1616verify_log_repair(false) -> ok; 1617verify_log_repair(truncate) -> ok; 1618verify_log_repair(Repair) -> 1619 error({invalid_audit_trail_log_repair, Repair}). 1620 1621verify_log_seqno(true) -> ok; 1622verify_log_seqno(false) -> ok; 1623verify_log_seqno(SeqNo) -> 1624 error({invalid_audit_trail_log_seqno, SeqNo}). 1625 1626 1627verify_module(_, Mod) when is_atom(Mod) -> 1628 ok; 1629verify_module(ReasonTag, Mod) -> 1630 error({invalid_module, ReasonTag, Mod}). 1631 1632% verify_bool(_, true) -> 1633% ok; 1634% verify_bool(_, false) -> 1635% ok; 1636% verify_bool(ReasonTag, Bool) -> 1637% error({invalid_bool, ReasonTag, Bool}). 1638 1639verify_dir(Dir) when is_list(Dir) -> 1640 case file:read_file_info(Dir) of 1641 {ok, #file_info{type = directory}} -> 1642 ok; 1643 {ok, _} -> 1644 {error, not_directory}; 1645 {error, _Reason} -> 1646 {error, not_found} 1647 end; 1648verify_dir(Dir) -> 1649 {error, {invalid_log_dir, Dir}}. 1650 1651 1652verify_verbosity(Verbosity) -> 1653 case snmp_verbosity:validate(Verbosity) of 1654 Verbosity -> 1655 ok; 1656 _ -> 1657 error({invalid_verbosity, Verbosity}) 1658 end. 1659 1660 1661%% mandatory() -> [mand()] 1662%% mand() -> atom() | {atom, [atom()]} 1663verify_mandatory_options(_Opts, []) -> 1664 ok; 1665verify_mandatory_options(Opts, [Mand|Mands]) -> 1666 verify_mandatory_option(Opts, Mand), 1667 verify_mandatory_options(Opts, Mands). 1668 1669verify_mandatory_option(Opts, {Mand, MandSubOpts}) -> 1670 ?d("verify_mandatory_option -> entry with" 1671 "~n Mand: ~p" 1672 "~n MandSubObjs: ~p", [Mand, MandSubOpts]), 1673 case lists:keysearch(Mand, 1, Opts) of 1674 {value, {Mand, SubOpts}} -> 1675 verify_mandatory_options(SubOpts, MandSubOpts); 1676 false -> 1677 ?d("missing mandatory option: ~w [~p]", [Mand, MandSubOpts]), 1678 error({missing_mandatory, Mand, MandSubOpts}) 1679 end; 1680verify_mandatory_option(Opts, Mand) -> 1681 ?d("verify_mandatory_option -> entry with" 1682 "~n Mand: ~p", [Mand]), 1683 case lists:keymember(Mand, 1, Opts) of 1684 true -> 1685 ok; 1686 false -> 1687 ?d("missing mandatory option: ~w", [Mand]), 1688 error({missing_mandatory, Mand}) 1689 end. 1690 1691%% ------------------------------------------------------------------------ 1692 1693init_manager_config([]) -> 1694 ok; 1695init_manager_config([{Key, Val}|Confs]) -> 1696 ets:insert(snmpm_config_table, {Key, Val}), 1697 init_manager_config(Confs). 1698 1699 1700 1701init_agent_default() -> 1702 %% The purpose of the default_agent is only to have a place 1703 %% to store system wide default values related to agents. 1704 %% 1705 AgentDefaultConfig = 1706 [{port, ?DEFAULT_AGENT_PORT}, % Port 1707 {timeout, 10000}, % Timeout 1708 {max_message_size, 484}, % Max message (packet) size 1709 {version, v2}, % MPModel 1710 {sec_model, v2c}, % SecModel 1711 {sec_name, "initial"}, % SecName 1712 {sec_level, noAuthNoPriv}, % SecLevel 1713 {community, "all-rights"}], % Community 1714 do_update_agent_info(default_agent, AgentDefaultConfig). 1715 1716read_agents_config_file(Dir) -> 1717 Order = fun snmp_conf:no_order/2, 1718 Check = fun check_agent_config/2, 1719 try read_file(Dir, "agents.conf", Order, Check, []) 1720 catch 1721 throw:E:S -> 1722 ?vlog("agent config error: " 1723 "~n ~p", [E]), 1724 erlang:raise(throw, E, S) 1725 end. 1726 1727check_agent_config(Agent, State) -> 1728 {ok, {UserId, TargetName, Conf, Version}} = check_agent_config(Agent), 1729 {ok, Vsns} = system_info(versions), 1730 case lists:member(Version, Vsns) of 1731 true -> 1732 {{ok, {UserId, TargetName, Conf}}, State}; 1733 false -> 1734 error({version_not_supported_by_manager, Version, Vsns}) 1735 end. 1736 1737%% For backward compatibility 1738check_agent_config( 1739 {UserId, TargetName, Community, Domain, Addr, 1740 EngineId, Timeout, MaxMessageSize, 1741 Version, SecModel, SecName, SecLevel}) when is_atom(Domain) -> 1742 check_agent_config( 1743 UserId, TargetName, Community, Domain, Addr, 1744 EngineId, Timeout, MaxMessageSize, 1745 Version, SecModel, SecName, SecLevel); 1746check_agent_config( 1747 {UserId, TargetName, Community, Ip, Port, 1748 EngineId, Timeout, MaxMessageSize, 1749 Version, SecModel, SecName, SecLevel}) when is_integer(Port) -> 1750 Domain = default_transport_domain(), 1751 Addr = {Ip, Port}, 1752 check_agent_config( 1753 UserId, TargetName, Community, Domain, Addr, 1754 EngineId, Timeout, MaxMessageSize, 1755 Version, SecModel, SecName, SecLevel); 1756check_agent_config( 1757 {_UserId, _TargetName, _Community, Domain, Addr, 1758 _EngineId, _Timeout, _MaxMessageSize, 1759 _Version, _SecModel, _SecName, _SecLevel}) -> 1760 error({bad_address, {Domain, Addr}}); 1761check_agent_config( 1762 {UserId, TargetName, Community, Domain, Ip, Port, 1763 EngineId, Timeout, MaxMessageSize, 1764 Version, SecModel, SecName, SecLevel}) -> 1765 Addr = {Ip, Port}, 1766 check_agent_config( 1767 UserId, TargetName, Community, Domain, Addr, 1768 EngineId, Timeout, MaxMessageSize, 1769 Version, SecModel, SecName, SecLevel); 1770check_agent_config(Agent) -> 1771 error({bad_agent_config, Agent}). 1772 1773check_agent_config( 1774 UserId, TargetName, Comm, Domain, Addr, 1775 EngineId, Timeout, MMS, 1776 Version, SecModel, SecName, SecLevel) -> 1777 ?vdebug("check_agent_config -> entry with" 1778 "~n UserId: ~p" 1779 "~n TargetName: ~p", [UserId, TargetName]), 1780 snmp_conf:check_string(TargetName, {gt, 0}), 1781 %% Note that the order of Conf *is* important. 1782 %% Some properties may depend on others, so that 1783 %% in order to verify one property, another must 1784 %% be already verified (and present). An example 1785 %% of this is the property 'taddress', for which 1786 %% the property tdomain is needed. 1787 Conf = 1788 [{reg_type, target_name}, 1789 {tdomain, Domain}, 1790 {taddress, fix_address(Domain, Addr)}, 1791 {community, Comm}, 1792 {engine_id, EngineId}, 1793 {timeout, Timeout}, 1794 {max_message_size, MMS}, 1795 {version, Version}, 1796 {sec_model, SecModel}, 1797 {sec_name, SecName}, 1798 {sec_level, SecLevel} 1799 ], 1800 {ok, {UserId, TargetName, verify_agent_config(Conf), Version}}. 1801 1802 1803 1804init_agents_config([]) -> 1805 ok; 1806init_agents_config([Agent|Agents]) -> 1807 init_agent_config(Agent), 1808 init_agents_config(Agents). 1809 1810init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) -> 1811 error({invalid_target_name, TargetName}); 1812init_agent_config({UserId, TargetName, Config}) -> 1813 case handle_register_agent(UserId, TargetName, Config) of 1814 ok -> 1815 ok; 1816 Error -> 1817 throw(Error) 1818 end. 1819 1820 1821 1822%% Sort 'tdomain' first then 'port' to ensure both 1823%% sorts before 'taddress'. Keep the order of other items. 1824order_agent(ItemA, ItemB) -> 1825 snmp_conf:keyorder(1, ItemA, ItemB, [tdomain, port]). 1826 1827fix_agent_config(Conf) -> 1828 ?vdebug("fix_agent_config -> entry with" 1829 "~n Conf: ~p", [Conf]), 1830 fix_agent_config(lists:sort(fun order_agent/2, Conf), []). 1831 1832fix_agent_config([], FixedConf) -> 1833 Ret = lists:reverse(FixedConf), 1834 ?vdebug("fix_agent_config -> done when (fixed config):" 1835 "~n ~p", [Ret]), 1836 Ret; 1837fix_agent_config([{taddress = Item, Address} = Entry|Conf], FixedConf) -> 1838 {value, {tdomain, TDomain}} = lists:keysearch(tdomain, 1, FixedConf), 1839 {value, {port, DefaultPort}} = lists:keysearch(port, 1, FixedConf), 1840 case snmp_conf:check_address(TDomain, Address, DefaultPort) of 1841 ok -> 1842 fix_agent_config(Conf, [Entry|FixedConf]); 1843 {ok, NAddress} -> 1844 fix_agent_config(Conf, [{Item, NAddress}|FixedConf]) 1845 end; 1846fix_agent_config([Entry|Conf], FixedConf) -> 1847 fix_agent_config(Conf, [Entry|FixedConf]). 1848 1849 1850 1851verify_agent_config(Conf) -> 1852 verify_agent_config(lists:sort(fun order_agent/2, Conf), []). 1853 1854verify_agent_config([], VerifiedConf) -> 1855 Ret = lists:reverse(VerifiedConf), 1856 ?vdebug("verify_agent_config -> returns:~n" 1857 " ~p", [Ret]), 1858 Ret; 1859verify_agent_config([{Item, _} = Entry|Conf], VerifiedConf) -> 1860 verify_illegal(VerifiedConf, [Item]), % Duplicates are hereby illegal 1861 verify_agent_config(Conf, VerifiedConf, Entry); 1862verify_agent_config([Bad|_], _VerifiedConf) -> 1863 error({bad_agent_config, Bad}). 1864 1865verify_agent_config( 1866 Conf, VerifiedConf, {taddress = Item, Address} = Entry) -> 1867 verify_illegal(VerifiedConf, [address]), 1868 {TDomain, VC} = 1869 case lists:keysearch(tdomain, 1, VerifiedConf) of 1870 {value, {tdomain,TD}} -> 1871 {TD, VerifiedConf}; 1872 _ -> 1873 %% Insert tdomain since it is missing 1874 %% Note: not default_transport_domain() since 1875 %% taddress is the new format hence the application 1876 %% should be tdomain aware and therefore addresses 1877 %% on the Domain, Addr format should be used and understood. 1878 TD = transportDomainUdpIpv4, 1879 {TD, [{tdomain, TD}|VerifiedConf]} 1880 end, 1881 case snmp_conf:check_address(TDomain, Address, 0) of 1882 ok -> 1883 verify_agent_config(Conf, [Entry|VC]); 1884 {ok, NAddress} -> 1885 verify_agent_config(Conf, [{Item, NAddress}|VC]) 1886 end; 1887verify_agent_config(Conf, VerifiedConf, {address, Address}) -> 1888 Item = taddress, 1889 verify_illegal(VerifiedConf, [Item]), 1890 {TDomain, VC} = 1891 case lists:keysearch(tdomain, 1, VerifiedConf) of 1892 {value, {tdomain, TD}} -> 1893 {TD, VerifiedConf}; 1894 _ -> 1895 %% Insert tdomain since it is missing 1896 TD = default_transport_domain(), 1897 {TD, [{tdomain, TD}|VerifiedConf]} 1898 end, 1899 case snmp_conf:check_address(TDomain, Address, 0) of 1900 ok -> 1901 verify_agent_config(Conf, [{Item, Address}|VC]); 1902 {ok, NAddress} -> 1903 verify_agent_config(Conf, [{Item, NAddress}|VC]) 1904 end; 1905verify_agent_config(Conf, VerifiedConf, {Item, Val} = Entry) -> 1906 case verify_agent_entry(Item, Val) of 1907 ok -> 1908 verify_agent_config(Conf, [Entry|VerifiedConf]); 1909 {ok, NewVal} -> 1910 verify_agent_config(Conf, [{Item, NewVal}|VerifiedConf]) 1911 end. 1912 1913verify_agent_entry(user_id, _UserId) -> 1914 ok; 1915verify_agent_entry(reg_type, RegType) -> 1916 if 1917 RegType =:= addr_port; 1918 RegType =:= target_name -> 1919 ok; 1920 true -> 1921 error({bad_reg_type, RegType}) 1922 end; 1923verify_agent_entry(tdomain, TDomain) -> 1924 snmp_conf:check_domain(TDomain); 1925verify_agent_entry(port, Port) -> 1926 snmp_conf:check_port(Port); 1927verify_agent_entry(community, Comm) -> 1928 snmp_conf:check_string(Comm); 1929verify_agent_entry(engine_id, EngineId) -> 1930 case EngineId of 1931 discovery -> 1932 ok; 1933 _ -> 1934 snmp_conf:check_string(EngineId) 1935 end; 1936verify_agent_entry(timeout, Timeout) -> 1937 snmp_conf:check_timer(Timeout); 1938verify_agent_entry(max_message_size, MMS) -> 1939 snmp_conf:check_packet_size(MMS); 1940verify_agent_entry(version, V) -> 1941 if 1942 V =:= v1; 1943 V =:= v2; 1944 V =:= v3 -> 1945 ok; 1946 true -> 1947 error({bad_version, V}) 1948 end; 1949verify_agent_entry(sec_model, Model) -> 1950 snmp_conf:check_sec_model(Model); 1951verify_agent_entry(sec_name, Name) -> 1952 try snmp_conf:check_string(Name) 1953 catch 1954 _ -> 1955 error({bad_sec_name, Name}) 1956 end; 1957verify_agent_entry(sec_level, Level) -> 1958 snmp_conf:check_sec_level(Level); 1959verify_agent_entry(Item, _) -> 1960 error({unknown_item, Item}). 1961 1962 1963 1964read_users_config_file(Dir) -> 1965 Order = fun snmp_conf:no_order/2, 1966 Check = fun (User, State) -> {check_user_config(User), State} end, 1967 try read_file(Dir, "users.conf", Order, Check, []) 1968 catch 1969 throw:E:S -> 1970 ?vlog("failure reading users config file: " 1971 "~n ~p", [E]), 1972 erlang:raise(throw, E, S) 1973 end. 1974 1975check_user_config({Id, Mod, Data}) -> 1976 ?vtrace("check_user_config -> entry with" 1977 "~n Id: ~p" 1978 "~n Mod: ~p" 1979 "~n Data: ~p", [Id, Mod, Data]), 1980 check_user_config({Id, Mod, Data, []}); 1981check_user_config({Id, Mod, Data, DefaultAgentConfig} = _User) 1982 when (Id =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> 1983 ?vtrace("check_user_config -> entry with" 1984 "~n Id: ~p" 1985 "~n Mod: ~p" 1986 "~n Data: ~p" 1987 "~n DefaultAgentConfig: ~p", 1988 [Id, Mod, Data, DefaultAgentConfig]), 1989 case (catch verify_user_behaviour(Mod)) of 1990 ok -> 1991 ?vtrace("check_user_config -> user behaviour verified", []), 1992 DefAgentConf = 1993 verify_default_agent_config(DefaultAgentConfig), 1994 ?vtrace("check_user_config -> " 1995 "user agent (default) config verified", []), 1996 User2 = {Id, Mod, Data, DefAgentConf}, 1997 {ok, User2}; 1998 Error -> 1999 throw(Error) 2000 end; 2001check_user_config({Id, _Mod, _Data, DefaultAgentConfig}) 2002 when (Id =/= ?DEFAULT_USER) -> 2003 error({bad_default_agent_config, DefaultAgentConfig}); 2004check_user_config({Id, _Mod, _Data, _DefaultAgentConfig}) -> 2005 error({bad_user_id, Id}); 2006check_user_config(User) -> 2007 error({bad_user_config, User}). 2008 2009init_users_config([]) -> 2010 ok; 2011init_users_config([User|Users]) -> 2012 init_user_config(User), 2013 init_users_config(Users). 2014 2015init_user_config(User) -> 2016 case (catch verify_user(User)) of 2017 {ok, UserRec} -> 2018 case handle_register_user(UserRec) of 2019 ok -> 2020 ok; 2021 {error, Reason} -> 2022 error_msg("failed register user: " 2023 "~n~w~n~w", [User, Reason]) 2024 end; 2025 {error, Reason} -> 2026 error_msg("user config check failed: " 2027 "~n~w~n~w", [User, Reason]) 2028 end. 2029 2030verify_user({Id, UserMod, UserData}) -> 2031 verify_user({Id, UserMod, UserData, []}); 2032verify_user({Id, UserMod, UserData, DefaultAgentConfig}) 2033 when (Id =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) -> 2034 ?d("verify_user -> entry with" 2035 "~n Id: ~p" 2036 "~n UserMod: ~p" 2037 "~n UserData: ~p" 2038 "~n DefaultAgentConfig: ~p", 2039 [Id, UserMod, UserData, DefaultAgentConfig]), 2040 case (catch verify_user_behaviour(UserMod)) of 2041 ok -> 2042 try 2043 {ok, SystemDefaultAgentConfig} = agent_info(), 2044 Config = 2045 ensure_config( 2046 SystemDefaultAgentConfig, 2047 verify_default_agent_config(DefaultAgentConfig)), 2048%% Config = 2049%% default_agent_config( 2050%% verify_default_agent_config(DefaultAgentConfig)), 2051 {ok, #user{id = Id, 2052 mod = UserMod, 2053 data = UserData, 2054 default_agent_config = Config}} 2055 catch 2056 Error -> 2057 ?vdebug("verify_user default_agent_config -> throw" 2058 "~n Error: ~p", [Error]), 2059 error({bad_default_agent_config, Error}) 2060 end; 2061 Error -> 2062 throw(Error) 2063 end; 2064verify_user({Id, _UserMod, _UserData, DefaultAgentConfig}) 2065 when (Id =/= ?DEFAULT_USER) -> 2066 {error, {bad_default_agent_config, DefaultAgentConfig}}; 2067verify_user({Id, _, _, _}) -> 2068 {error, {bad_user_id, Id}}. 2069 2070verify_default_agent_config(Conf) -> 2071 try 2072 verify_illegal( 2073 Conf, 2074 [user_id, engine_id, address, tdomain, taddress]), 2075 verify_agent_config(Conf) 2076 catch 2077 Error -> 2078 ?vdebug("verify_default_agent_config -> throw" 2079 "~n Error: ~p", [Error]), 2080 error({bad_default_agent_config, Error}) 2081 end. 2082 2083 2084read_usm_config_file(Dir) -> 2085 Order = fun snmp_conf:no_order/2, 2086 Check = fun (User, State) -> {check_usm_user_config(User), State} end, 2087 read_file(Dir, "usm.conf", Order, Check, []). 2088 2089%% Identity-function 2090check_usm_user_config({EngineId, Name, 2091 AuthP, AuthKey, 2092 PrivP, PrivKey}) -> 2093 User = {EngineId, Name, Name, AuthP, AuthKey, PrivP, PrivKey}, 2094 verify_usm_user(User); 2095check_usm_user_config({_EngineId, _Name, _SecName, 2096 _AuthP, _AuthKey, 2097 _PrivP, _PrivKey} = User) -> 2098 verify_usm_user(User); 2099check_usm_user_config(User) -> 2100 error({bad_usm_config, User}). 2101 2102init_usm_users_config([]) -> 2103 ok; 2104init_usm_users_config([User|Users]) -> 2105 init_usm_user_config(User), 2106 init_usm_users_config(Users). 2107 2108init_usm_user_config(User) when is_record(User, usm_user) -> 2109 case handle_register_usm_user(User) of 2110 ok -> 2111 ok; 2112 Error -> 2113 throw(Error) 2114 end; 2115init_usm_user_config(BadUser) -> 2116 error({bad_usm_user, BadUser}). 2117 2118 2119verify_usm_user({EngineID, Name, SecName, AuthP, AuthKey, PrivP, PrivKey}) -> 2120 ?d("verify_usm_user -> entry with" 2121 "~n EngineID: ~p" 2122 "~n Name: ~p" 2123 "~n SecName: ~p" 2124 "~n AuthP: ~p" 2125 "~n AuthKey: ~p" 2126 "~n PrivP: ~p" 2127 "~n PrivKey: ~p", 2128 [EngineID, Name, SecName, AuthP, AuthKey, PrivP, PrivKey]), 2129 verify_usm_user_engine_id(EngineID), 2130 verify_usm_user_name(Name), 2131 verify_usm_user_sec_name(SecName), 2132 verify_usm_user(AuthP, AuthKey, PrivP, PrivKey), 2133 User = #usm_user{engine_id = EngineID, 2134 name = Name, 2135 sec_name = SecName, 2136 auth = AuthP, 2137 auth_key = AuthKey, 2138 priv = PrivP, 2139 priv_key = PrivKey}, 2140 {ok, User}. 2141 2142verify_usm_user_engine_id(EngineID) -> 2143 case (catch snmp_conf:check_string(EngineID, {gt, 0})) of 2144 ok -> 2145 ok; 2146 _ -> 2147 error({bad_usm_engine_id, EngineID}) 2148 end. 2149 2150verify_usm_user_name(Name) -> 2151 case (catch snmp_conf:check_string(Name, {gt, 0})) of 2152 ok -> 2153 ok; 2154 _ -> 2155 error({bad_usm_user_name, Name}) 2156 end. 2157 2158verify_usm_user_sec_name(Name) -> 2159 case (catch snmp_conf:check_string(Name, {gt, 0})) of 2160 ok -> 2161 ok; 2162 _ -> 2163 error({bad_usm_sec_name, Name}) 2164 end. 2165 2166verify_usm_user(AuthP, AuthKey, PrivP, PrivKey) -> 2167 verify_usm_user_auth(AuthP, AuthKey), 2168 verify_usm_user_priv(PrivP, PrivKey), 2169 ok. 2170 2171verify_usm_user_auth(usmNoAuthProtocol, AuthKey) -> 2172 case (catch snmp_conf:check_string(AuthKey, any)) of 2173 ok -> 2174 ok; 2175 _ -> 2176 error({invalid_auth_key, usmNoAuthProtocol}) 2177 end; 2178verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) 2179 when is_list(AuthKey) andalso (length(AuthKey) =:= 16) -> 2180 case is_crypto_supported(md5) of 2181 true -> 2182 case snmp_conf:all_integer(AuthKey) of 2183 true -> 2184 ok; 2185 _ -> 2186 error({invalid_auth_key, usmHMACMD5AuthProtocol}) 2187 end; 2188 false -> 2189 error({unsupported_crypto, md5}) 2190 end; 2191verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) when is_list(AuthKey) -> 2192 Len = length(AuthKey), 2193 error({invalid_auth_key, usmHMACMD5AuthProtocol, Len}); 2194verify_usm_user_auth(usmHMACMD5AuthProtocol, _AuthKey) -> 2195 error({invalid_auth_key, usmHMACMD5AuthProtocol}); 2196verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) 2197 when is_list(AuthKey) andalso (length(AuthKey) =:= 20) -> 2198 case is_crypto_supported(sha) of 2199 true -> 2200 case snmp_conf:all_integer(AuthKey) of 2201 true -> 2202 ok; 2203 _ -> 2204 error({invalid_auth_key, usmHMACSHAAuthProtocol}) 2205 end; 2206 false -> 2207 error({unsupported_crypto, sha}) 2208 end; 2209verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) when is_list(AuthKey) -> 2210 Len = length(AuthKey), 2211 error({invalid_auth_key, usmHMACSHAAuthProtocol, Len}); 2212verify_usm_user_auth(usmHMACSHAAuthProtocol, _AuthKey) -> 2213 error({invalid_auth_key, usmHMACSHAAuthProtocol}); 2214verify_usm_user_auth(AuthP, _AuthKey) -> 2215 error({invalid_auth_protocol, AuthP}). 2216 2217verify_usm_user_priv(usmNoPrivProtocol, PrivKey) -> 2218 case (catch snmp_conf:check_string(PrivKey, any)) of 2219 ok -> 2220 ok; 2221 _ -> 2222 error({invalid_priv_key, usmNoPrivProtocol}) 2223 end; 2224verify_usm_user_priv(usmDESPrivProtocol, PrivKey) 2225 when (length(PrivKey) =:= 16) -> 2226 case is_crypto_supported(des_cbc) of 2227 true -> 2228 case snmp_conf:all_integer(PrivKey) of 2229 true -> 2230 ok; 2231 _ -> 2232 error({invalid_priv_key, usmDESPrivProtocol}) 2233 end; 2234 false -> 2235 error({unsupported_crypto, des_cbc}) 2236 end; 2237verify_usm_user_priv(usmDESPrivProtocol, PrivKey) when is_list(PrivKey) -> 2238 Len = length(PrivKey), 2239 error({invalid_priv_key, usmDESPrivProtocol, Len}); 2240verify_usm_user_priv(usmDESPrivProtocol, _PrivKey) -> 2241 error({invalid_priv_key, usmDESPrivProtocol}); 2242verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) 2243 when (length(PrivKey) =:= 16) -> 2244 case is_crypto_supported(aes_cfb128) of 2245 true -> 2246 case snmp_conf:all_integer(PrivKey) of 2247 true -> 2248 ok; 2249 _ -> 2250 error({invalid_priv_key, usmAesCfb128Protocol}) 2251 end; 2252 false -> 2253 error({unsupported_crypto, aes_cfb128}) 2254 end; 2255verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) when is_list(PrivKey) -> 2256 Len = length(PrivKey), 2257 error({invalid_priv_key, usmAesCfb128Protocol, Len}); 2258verify_usm_user_priv(usmAesCfb128Protocol, _PrivKey) -> 2259 error({invalid_priv_key, usmAesCfb128Protocol}); 2260verify_usm_user_priv(PrivP, _PrivKey) -> 2261 error({invalid_priv_protocol, PrivP}). 2262 2263 2264-compile({inline, [{is_crypto_supported,1}]}). 2265is_crypto_supported(Func) -> 2266 snmp_misc:is_crypto_supported(Func). 2267 2268 2269read_manager_config_file(Dir) -> 2270 Order = fun order_manager_config/2, 2271 Check = fun check_manager_config/2, 2272 Conf = read_file(Dir, "manager.conf", Order, Check), 2273 ?d("read_manager_config_file -> ok: " 2274 "~n Conf: ~p", [Conf]), 2275 %% If the address is not specified, then we assume 2276 %% it should be the local host. 2277 %% If the address is not possible to determine 2278 %% that way, then we give up... 2279 verify_someof(Conf, [port, transports]), 2280 verify_mandatory(Conf, [engine_id, max_message_size]), 2281 default_manager_config(Conf). 2282 2283default_manager_config(Conf) -> 2284 %% Ensure valid transports entry 2285 case lists:keyfind(transports, 1, Conf) of 2286 false -> 2287 {port, Port} = lists:keyfind(port, 1, Conf), 2288 Domain = 2289 case lists:keyfind(domain, 1, Conf) of 2290 false -> 2291 default_transport_domain(); 2292 {_, D} -> 2293 D 2294 end, 2295 Family = snmp_conf:tdomain_to_family(Domain), 2296 {ok, Hostname} = inet:gethostname(), 2297 case inet:getaddr(Hostname, Family) of 2298 {ok, Address} -> 2299 lists:sort( 2300 fun order_manager_config/2, 2301 [{transports, [{Domain, {Address, Port}}]} | Conf]); 2302 {error, _Reason} -> 2303 ?d("default_manager_config -> " 2304 "failed getting ~w address for ~s:~n" 2305 " _Reason: ~p", [Family, Hostname, _Reason]), 2306 Conf 2307 end; 2308 _ -> 2309 Conf 2310 end. 2311 2312order_manager_config(EntryA, EntryB) -> 2313 snmp_conf:keyorder(1, EntryA, EntryB, [domain, port]). 2314 2315check_manager_config(Entry, undefined) -> 2316 check_manager_config(Entry, {default_transport_domain(), undefined}); 2317check_manager_config({domain, Domain}, {_, Port}) -> 2318 {snmp_conf:check_domain(Domain), {Domain, Port}}; 2319check_manager_config({port, Port}, {Domain, _}) -> 2320 {ok = snmp_conf:check_port(Port), {Domain, Port}}; 2321check_manager_config({address, _}, {_, undefined}) -> 2322 error({missing_mandatory, port}); 2323check_manager_config({address = Tag, Ip} = Entry, {Domain, Port} = State) -> 2324 {case snmp_conf:check_ip(Domain, Ip) of 2325 ok -> 2326 [Entry, 2327 {transports, [{Domain, {Ip, Port}}]}]; 2328 {ok, FixedIp} -> 2329 [{Tag, FixedIp}, 2330 {transports, [{Domain, {FixedIp, Port}}]}] 2331 end, State}; 2332check_manager_config({transports = Tag, Transports}, {_, Port} = State) 2333 when is_list(Transports) -> 2334 CheckedTransports = 2335 [case Transport of 2336 {Domain, Address} -> 2337 case 2338 case Port of 2339 undefined -> 2340 snmp_conf:check_address(Domain, Address); 2341 _ -> 2342 snmp_conf:check_address(Domain, Address, Port) 2343 end 2344 of 2345 ok -> 2346 Transport; 2347 {ok, FixedAddress} -> 2348 {Domain, FixedAddress} 2349 end; 2350 _Domain when Port =:= undefined-> 2351 error({missing_mandatory, port}); 2352 Domain -> 2353 Family = snmp_conf:tdomain_to_family(Domain), 2354 {ok, Hostname} = inet:gethostname(), 2355 case inet:getaddr(Hostname, Family) of 2356 {ok, IpAddr} -> 2357 {Domain, {IpAddr, Port}}; 2358 {error, _} -> 2359 error({bad_address, {Domain, Hostname}}) 2360 end 2361 end 2362 || Transport <- Transports], 2363 {{ok, {Tag, CheckedTransports}}, State}; 2364check_manager_config(Entry, State) -> 2365 {check_manager_config(Entry), State}. 2366 2367check_manager_config({engine_id, EngineID}) -> 2368 snmp_conf:check_string(EngineID); 2369check_manager_config({max_message_size, Max}) -> 2370 snmp_conf:check_integer(Max, {gte, 484}); 2371check_manager_config(Conf) -> 2372 error({unknown_config, Conf}). 2373 2374 2375read_file(Dir, FileName, Order, Check, Default) -> 2376 try snmp_conf:read(filename:join(Dir, FileName), Order, Check) 2377 catch 2378 {error, Reason} when element(1, Reason) =:= failed_open -> 2379 ?vlog("failed reading config from ~s: ~p", [FileName, Reason]), 2380 Default 2381 end. 2382 2383read_file(Dir, FileName, Order, Check) -> 2384 try snmp_conf:read(filename:join(Dir, FileName), Order, Check) 2385 catch 2386 throw:{error, Reason} = E:S 2387 when element(1, Reason) =:= failed_open -> 2388 error_msg("failed reading config from ~s: " 2389 "~n ~p", [FileName, Reason]), 2390 erlang:raise(throw, E, S) 2391 end. 2392 2393%%-------------------------------------------------------------------- 2394%% Func: handle_call/3 2395%% Returns: {reply, Reply, State} | 2396%% {reply, Reply, State, Timeout} | 2397%% {noreply, State} | 2398%% {noreply, State, Timeout} | 2399%% {stop, Reason, Reply, State} | (terminate/2 is called) 2400%% {stop, Reason, State} (terminate/2 is called) 2401%%-------------------------------------------------------------------- 2402handle_call({register_user, UserId, UserMod, UserData, DefaultAgentConfig}, 2403 _From, State) -> 2404 ?vlog("received register_user request: " 2405 "~n UserId: ~p" 2406 "~n UserMod: ~p" 2407 "~n UserData: ~p" 2408 "~n DefaultAgentConfig: ~p", 2409 [UserId, UserMod, UserData, DefaultAgentConfig]), 2410 User = #user{id = UserId, 2411 mod = UserMod, 2412 data = UserData, 2413 default_agent_config = DefaultAgentConfig}, 2414 Reply = handle_register_user(User), 2415 {reply, Reply, State}; 2416 2417handle_call({unregister_user, UserId}, _From, State) -> 2418 ?vlog("received unregister_user request: " 2419 "~n UserId: ~p", [UserId]), 2420 Reply = handle_unregister_user(UserId), 2421 {reply, Reply, State}; 2422 2423handle_call({register_agent, UserId, TargetName, Config}, _From, State) -> 2424 ?vlog("received register_agent request: " 2425 "~n UserId: ~p" 2426 "~n TargetName: ~p" 2427 "~n Config: ~p", [UserId, TargetName, Config]), 2428 Reply = handle_register_agent(UserId, TargetName, Config), 2429 {reply, Reply, State}; 2430 2431handle_call({unregister_agent, UserId, TargetName}, _From, State) -> 2432 ?vlog("received unregister_agent request: " 2433 "~n UserId: ~p" 2434 "~n TargetName: ~p", [UserId, TargetName]), 2435 Reply = handle_unregister_agent(UserId, TargetName), 2436 {reply, Reply, State}; 2437 2438handle_call({update_agent_info, UserId, TargetName, Info}, 2439 _From, State) -> 2440 ?vlog("received update_agent_info request: " 2441 "~n UserId: ~p" 2442 "~n TargetName: ~p" 2443 "~n Info: ~p", [UserId, TargetName, Info]), 2444 Reply = handle_update_agent_info(UserId, TargetName, Info), 2445 {reply, Reply, State}; 2446 2447%% <BACKWARD-COMPAT> 2448handle_call({update_agent_info, UserId, TargetName, Item, Val}, 2449 _From, State) -> 2450 ?vlog("received update_agent_info request: " 2451 "~n UserId: ~p" 2452 "~n TargetName: ~p" 2453 "~n Item: ~p" 2454 "~n Val: ~p", [UserId, TargetName, Item, Val]), 2455 Reply = handle_update_agent_info(UserId, TargetName, Item, Val), 2456 {reply, Reply, State}; 2457%% </BACKWARD-COMPAT> 2458 2459handle_call({register_usm_user, User}, _From, State) -> 2460 ?vlog("received register_usm_user request: " 2461 "~n User: ~p", [User]), 2462 Reply = handle_register_usm_user(User), 2463 {reply, Reply, State}; 2464 2465handle_call({unregister_usm_user, EngineID, Name}, _From, State) -> 2466 ?vlog("received register_usm_user request: " 2467 "~n EngineID: ~p" 2468 "~n Name: ~p", [EngineID, Name]), 2469 Reply = handle_unregister_usm_user(EngineID, Name), 2470 {reply, Reply, State}; 2471 2472handle_call({update_usm_user_info, EngineID, UserName, Item, Val}, 2473 _From, State) -> 2474 ?vlog("received update_usm_user_info request: " 2475 "~n EngineID: ~p" 2476 "~n UserName: ~p" 2477 "~n Item: ~p" 2478 "~n Val: ~p", [EngineID, UserName, Item, Val]), 2479 Reply = handle_update_usm_user_info(EngineID, UserName, Item, Val), 2480 {reply, Reply, State}; 2481 2482handle_call({cre_counter, Counter, Initial}, _From, State) -> 2483 ?vlog("received cre_counter ~p -> ~w", [Counter, Initial]), 2484 Reply = cre_counter(Counter, Initial), 2485 {reply, Reply, State}; 2486 2487handle_call({cre_stats_counter, Counter, Initial}, _From, State) -> 2488 ?vlog("received cre_stats_counter ~p -> ~w", [Counter, Initial]), 2489 Reply = cre_stats_counter(Counter, Initial), 2490 {reply, Reply, State}; 2491 2492handle_call({reset_stats_counter, Counter}, _From, State) -> 2493 ?vlog("received reset_stats_counter ~p", [Counter]), 2494 Reply = reset_stats_counter(Counter), 2495 {reply, Reply, State}; 2496 2497handle_call({load_mib, Mib}, _From, State) -> 2498 ?vlog("received load_mib ~p", [Mib]), 2499 case handle_load_mib(Mib) of 2500 ok -> 2501 {reply, ok, State}; 2502 Error -> 2503 {reply, Error, State} 2504 end; 2505 2506 2507handle_call({unload_mib, Mib}, _From, State) -> 2508 ?vlog("received unload_mib ~p", [Mib]), 2509 case handle_unload_mib(Mib) of 2510 ok -> 2511 {reply, ok, State}; 2512 Error -> 2513 {reply, Error, State} 2514 end; 2515 2516 2517handle_call({set_engine_boots, Boots}, _From, State) -> 2518 ?vlog("received set_engine_boots ~p", [Boots]), 2519 set_engine_boots(Boots), 2520 {reply, ok, State}; 2521 2522handle_call({set_engine_time, Time}, _From, State) -> 2523 ?vlog("received set_engine_time ~p", [Time]), 2524 Base = snmp_misc:now(sec) - Time, 2525 ets:insert(snmpm_config_table, {snmp_engine_base, Base}), 2526 {reply, ok, State}; 2527 2528handle_call({set_usm_cache, Key, Val}, _From, State) -> 2529 ?vlog("received set_usm_cache: ~w -> ~p", [Key, Val]), 2530 ets:insert(snmpm_usm_table, {{usm_cache, Key}, Val}), 2531 {reply, ok, State}; 2532 2533handle_call({reset_usm_cache, EngineID}, _From, State) -> 2534 ?vlog("received reset_usm_cache: ~p", [EngineID]), 2535 reset_usm_cache(EngineID), 2536 {reply, ok, State}; 2537 2538handle_call({verbosity, Verbosity}, _From, State) -> 2539 ?vlog("received verbosity request", []), 2540 put(verbosity, Verbosity), 2541 {reply, ok, State}; 2542 2543handle_call(info, _From, State) -> 2544 ?vlog("received info request", []), 2545 Reply = get_info(), 2546 {reply, Reply, State}; 2547 2548handle_call({backup, BackupDir}, From, State) -> 2549 ?vlog("backup to ~p", [BackupDir]), 2550 Pid = self(), 2551 V = get(verbosity), 2552 case file:read_file_info(BackupDir) of 2553 {ok, #file_info{type = directory}} -> 2554 BackupServer = 2555 erlang:spawn_link( 2556 fun() -> 2557 put(sname, mcbs), 2558 put(verbosity, V), 2559 Dir = filename:join([BackupDir]), 2560 Reply = handle_backup(?CONFIG_DB, Dir), 2561 Pid ! {backup_done, Reply}, 2562 unlink(Pid) 2563 end), 2564 ?vtrace("backup server: ~p", [BackupServer]), 2565 {noreply, State#state{backup = {BackupServer, From}}}; 2566 {ok, _} -> 2567 {reply, {error, not_a_directory}, State}; 2568 Error -> 2569 {reply, Error, State} 2570 end; 2571 2572 2573%% handle_call({update_system_info, Key, Val}, _From, State) -> 2574%% ?vlog("received update_system_info: ~p -> ~p", [Key, Val]), 2575%% Reply = handle_update_system_info(Key, Val), 2576%% {reply, Reply, State}; 2577 2578 2579handle_call(is_started, _From, State) -> 2580 ?vlog("received is_started request", []), 2581 {reply, true, State}; 2582 2583 2584handle_call(stop, _From, State) -> 2585 {stop, normal, ok, State}; 2586 2587 2588handle_call(Req, _From, State) -> 2589 warning_msg("received unknown request: ~n~p", [Req]), 2590 {reply, {error, unknown_request}, State}. 2591 2592 2593%%-------------------------------------------------------------------- 2594%% Func: handle_cast/2 2595%% Returns: {noreply, State} | 2596%% {noreply, State, Timeout} | 2597%% {stop, Reason, State} (terminate/2 is called) 2598%%-------------------------------------------------------------------- 2599handle_cast(Msg, State) -> 2600 warning_msg("received unknown message: ~n~p", [Msg]), 2601 {noreply, State}. 2602 2603 2604%%-------------------------------------------------------------------- 2605%% Func: handle_info/2 2606%% Returns: {noreply, State} | 2607%% {noreply, State, Timeout} | 2608%% {stop, Reason, State} (terminate/2 is called) 2609%%-------------------------------------------------------------------- 2610handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) -> 2611 ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]), 2612 gen_server:reply(From, {error, Reason}), 2613 {noreply, S#state{backup = undefined}}; 2614 2615handle_info({'EXIT', Pid, Reason}, S) -> 2616 %% The only other processes we should be linked to are 2617 %% either the server or our supervisor, so die... 2618 {stop, {received_exit, Pid, Reason}, S}; 2619 2620handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) -> 2621 ?vlog("backup done:" 2622 "~n Reply: ~p", [Reply]), 2623 gen_server:reply(From, Reply), 2624 {noreply, S#state{backup = undefined}}; 2625 2626handle_info(Info, State) -> 2627 warning_msg("received unknown info: ~n~p", [Info]), 2628 {noreply, State}. 2629 2630 2631%%-------------------------------------------------------------------- 2632%% Func: terminate/2 2633%% Purpose: Shutdown the server 2634%% Returns: any (ignored by gen_server) 2635%%-------------------------------------------------------------------- 2636terminate(Reason, _State) -> 2637 ?vdebug("terminate: ~p",[Reason]), 2638 ok. 2639 2640%%---------------------------------------------------------------------- 2641%% Func: code_change/3 2642%% Purpose: Convert process state when code is changed 2643%% Returns: {ok, NewState} 2644%%---------------------------------------------------------------------- 2645 2646%% downgrade 2647%% 2648code_change({down, _Vsn}, S1, downgrade_to_pre_4_7) -> 2649 #state{backup = B} = S1, 2650 stop_backup_server(B), 2651 S2 = {state}, 2652 {ok, S2}; 2653 2654%% upgrade 2655%% 2656code_change(_Vsn, _S1, upgrade_from_pre_4_7) -> 2657 %% {state} = S1, 2658 S2 = #state{}, 2659 {ok, S2}; 2660 2661code_change(_Vsn, State, _Extra) -> 2662 {ok, State}. 2663 2664 2665stop_backup_server(undefined) -> 2666 ok; 2667stop_backup_server({Pid, _}) when is_pid(Pid) -> 2668 exit(Pid, kill). 2669 2670 2671 2672%%---------------------------------------------------------- 2673%% Update system info 2674%%---------------------------------------------------------- 2675 2676%% handle_update_system_info(audit_trail_log_type = Key, Val) -> 2677%% case snmpm_config:system_info(audit_trail_log) of 2678%% {ok, true} -> 2679%% Value = 2680%% case Val of 2681%% read -> 2682%% {ok, [read]}; 2683%% write -> 2684%% {ok, [write]}; 2685%% read_write -> 2686%% {ok, [read,write]}; 2687%% _ -> 2688%% {error, {bad_value, Key, Val}} 2689%% end, 2690%% case Value of 2691%% {ok, NewValue} -> 2692%% ets:insert(snmpm_config_table, {Key, NewValue}), 2693%% ok; 2694%% false -> 2695%% Value 2696%% end; 2697%% _ -> 2698%% {error, audit_trail_log_not_enabled} 2699%% end; 2700%% handle_update_system_info(BadKey, Val) -> 2701%% {error, {unsupported_update, BadKey, Val}}. 2702 2703 2704%%---------------------------------------------------------- 2705%% Backup 2706%%---------------------------------------------------------- 2707 2708handle_backup(D, BackupDir) -> 2709 %% First check that we do not wrote to the corrent db-dir... 2710 ?vtrace("handle_backup -> entry with" 2711 "~n D: ~p" 2712 "~n BackupDir: ~p", [D, BackupDir]), 2713 case dets:info(D, filename) of 2714 undefined -> 2715 ?vinfo("handle_backup -> no file to backup", []), 2716 {error, no_file}; 2717 Filename -> 2718 ?vinfo("handle_backup -> file to backup: ~n ~p", [Filename]), 2719 case filename:dirname(Filename) of 2720 BackupDir -> 2721 ?vinfo("handle_backup -> backup dir and db dir the same", 2722 []), 2723 {error, db_dir}; 2724 _ -> 2725 case file:read_file_info(BackupDir) of 2726 {ok, #file_info{type = directory}} -> 2727 ?vdebug("handle_backup -> backup dir ok", []), 2728 %% All well so far... 2729 Type = dets:info(D, type), 2730 KP = dets:info(D, keypos), 2731 dets_backup(D, 2732 filename:basename(Filename), 2733 BackupDir, Type, KP); 2734 {ok, _} -> 2735 ?vinfo("handle_backup -> backup dir not a dir", 2736 []), 2737 {error, not_a_directory}; 2738 Error -> 2739 ?vinfo("handle_backup -> Error: ~p", [Error]), 2740 Error 2741 end 2742 end 2743 end. 2744 2745dets_backup(D, Filename, BackupDir, Type, KP) -> 2746 ?vtrace("dets_backup -> entry with" 2747 "~n D: ~p" 2748 "~n Filename: ~p" 2749 "~n BackupDir: ~p", [D, Filename, BackupDir]), 2750 BackupFile = filename:join(BackupDir, Filename), 2751 ?vtrace("dets_backup -> " 2752 "~n BackupFile: ~p", [BackupFile]), 2753 Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}], 2754 case dets:open_file(?BACKUP_DB, Opts) of 2755 {ok, B} -> 2756 ?vtrace("dets_backup -> create fun", []), 2757 F = fun(Arg) -> 2758 dets_backup(Arg, start, D, B) 2759 end, 2760 dets:safe_fixtable(D, true), 2761 Res = dets:init_table(?BACKUP_DB, F, [{format, bchunk}]), 2762 dets:safe_fixtable(D, false), 2763 ?vtrace("dets_backup -> Res: ~p", [Res]), 2764 Res; 2765 Error -> 2766 ?vinfo("dets_backup -> open_file failed: " 2767 "~n ~p", [Error]), 2768 Error 2769 end. 2770 2771 2772dets_backup(close, _Cont, _D, B) -> 2773 dets:close(B), 2774 ok; 2775dets_backup(read, Cont1, D, B) -> 2776 case dets:bchunk(D, Cont1) of 2777 {error, _} = ERROR -> 2778 ERROR; 2779 '$end_of_table' -> 2780 dets:close(B), 2781 end_of_input; 2782 {Cont2, Data} -> 2783 F = fun(Arg) -> 2784 dets_backup(Arg, Cont2, D, B) 2785 end, 2786 {Data, F} 2787 end. 2788 2789 2790%%%------------------------------------------------------------------- 2791%%% Internal functions 2792%%%------------------------------------------------------------------- 2793 2794handle_register_user(#user{id = Id} = User) -> 2795 ?vdebug("handle_register_user -> entry with" 2796 "~n User: ~p", [User]), 2797 case ets:lookup(snmpm_user_table, Id) of 2798 [] -> 2799 ets:insert(snmpm_user_table, User), 2800 ok; 2801 _ -> 2802 {error, {already_registered, User}} 2803 end. 2804 2805handle_unregister_user(UserId) -> 2806 ?vdebug("handle_unregister_user -> entry with" 2807 "~n UserId: ~p", [UserId]), 2808 ets:delete(snmpm_user_table, UserId), 2809 ok. 2810 2811 2812handle_register_agent(UserId, TargetName, Config) -> 2813 ?vdebug("handle_register_agent -> entry with" 2814 "~n UserId: ~p" 2815 "~n TargetName: ~p" 2816 "~n Config: ~p", [UserId, TargetName, Config]), 2817 case (catch agent_info(TargetName, user_id)) of 2818 {error, _} -> 2819 ?vtrace( 2820 "handle_register_agent -> user_id not found in config", []), 2821 case ets:lookup(snmpm_user_table, UserId) of 2822 [#user{default_agent_config = DefConfig}] -> 2823 ?vtrace("handle_register_agent ->~n" 2824 " DefConfig: ~p", [DefConfig]), 2825 FixedConfig = 2826 fix_agent_config(ensure_config(DefConfig, Config)), 2827 ?vtrace("handle_register_agent ->~n" 2828 " FixedConfig: ~p", [FixedConfig]), 2829 do_handle_register_agent( 2830 TargetName, [{user_id, UserId}|FixedConfig]), 2831 %% <DIRTY-BACKWARD-COMPATIBILLITY> 2832 %% And now for some (backward compatibillity) 2833 %% dirty crossref stuff 2834 {value, {_, Domain}} = 2835 lists:keysearch(tdomain, 1, FixedConfig), 2836 {value, {_, Address}} = 2837 lists:keysearch(taddress, 1, FixedConfig), 2838 ?vtrace( 2839 "handle_register_agent -> register cross-ref fix", []), 2840 ets:insert(snmpm_agent_table, 2841 {{Domain, Address, target_name}, TargetName}), 2842 %% </DIRTY-BACKWARD-COMPATIBILLITY> 2843 2844%% %% First, insert this users default config 2845%% ?vtrace("handle_register_agent -> store default config", []), 2846%% do_handle_register_agent(TargetName, DefConfig), 2847%% %% Second, insert the config for this agent 2848%% ?vtrace("handle_register_agent -> store config", []), 2849%% do_handle_register_agent(TargetName, 2850%% [{user_id, UserId}|Config]), 2851%% %% <DIRTY-BACKWARD-COMPATIBILLITY> 2852%% %% And now for some (backward compatibillity) 2853%% %% dirty crossref stuff 2854%% ?vtrace("handle_register_agent -> lookup taddress", []), 2855%% {ok, {Addr, Port} = TAddress} = 2856%% agent_info(TargetName, taddress), 2857%% ?vtrace("handle_register_agent -> taddress: ~p", 2858%% [TAddress]), 2859%% ?vtrace("handle_register_agent -> register cross-ref fix", []), 2860%% ets:insert(snmpm_agent_table, 2861%% {{Addr, Port, target_name}, TargetName}), 2862%% %% </DIRTY-BACKWARD-COMPATIBILLITY> 2863 ok; 2864 _ -> 2865 {error, {not_found, UserId}} 2866 end; 2867 {ok, UserId} -> 2868 ?vinfo("[~w] Agent (~p) already registered" 2869 "~nwhen" 2870 "~n Agents: ~p", 2871 [UserId, TargetName, which_agents()]), 2872 {error, {already_registered, TargetName}}; 2873 {ok, OtherUserId} -> 2874 ?vinfo("[~w] Agent (~p) already registered to ~p" 2875 "~nwhen" 2876 "~n Agents: ~p", 2877 [UserId, TargetName, OtherUserId, which_agents()]), 2878 {error, {already_registered, TargetName, OtherUserId}} 2879 end. 2880 2881do_handle_register_agent(_TargetName, []) -> 2882 ok; 2883do_handle_register_agent(TargetName, [{Item, Val}|Rest]) -> 2884 ?vtrace("do_handle_register_agent -> entry with" 2885 "~n TargetName: ~p" 2886 "~n Item: ~p" 2887 "~n Val: ~p" 2888 "~n Rest: ~p", [TargetName, Item, Val, Rest]), 2889 case (catch do_update_agent_info(TargetName, Item, Val)) of 2890 ok -> 2891 do_handle_register_agent(TargetName, Rest); 2892 {error, Reason} -> 2893 ?vtrace("do_handle_register_agent -> failed updating ~p" 2894 "~n Item: ~p" 2895 "~n Reason: ~p", [Item, Reason]), 2896 ets:match_delete(snmpm_agent_table, {TargetName, '_'}), 2897 {error, Reason} 2898 end; 2899do_handle_register_agent(TargetName, BadConfig) -> 2900 error_msg("error during agent registration - bad config: ~n~p", 2901 [BadConfig]), 2902 ets:match_delete(snmpm_agent_table, {TargetName, '_'}), 2903 {error, {bad_agent_config, TargetName, BadConfig}}. 2904 2905 2906handle_unregister_agent(UserId, TargetName) -> 2907 ?vdebug("handle_unregister_agent -> entry with" 2908 "~n UserId: ~p" 2909 "~n TargetName: ~p", [UserId, TargetName]), 2910 case (catch agent_info(TargetName, user_id)) of 2911 {ok, UserId} -> 2912 {ok, EngineID} = agent_info(TargetName, engine_id), 2913 reset_usm_cache(EngineID), 2914 %% <DIRTY-BACKWARD-COMPATIBILLITY> 2915 %% And now for some (backward compatibillity) 2916 %% dirty crossref stuff 2917 {ok, Domain} = agent_info(TargetName, tdomain), 2918 {ok, Address} = agent_info(TargetName, taddress), 2919 ets:delete(snmpm_agent_table, {Domain, Address, target_name}), 2920 %% </DIRTY-BACKWARD-COMPATIBILLITY> 2921 ets:match_delete(snmpm_agent_table, {{TargetName, '_'}, '_'}), 2922 ok; 2923 {ok, OtherUserId} -> 2924 {error, {not_owner, OtherUserId}}; 2925 Error -> 2926 Error 2927 end. 2928 2929 2930handle_update_agent_info(UserId, TargetName, Info) -> 2931 ?vdebug("handle_update_agent_info -> entry with" 2932 "~n UserId: ~p" 2933 "~n TargetName: ~p" 2934 "~n Info: ~p", [UserId, TargetName, Info]), 2935 %% Verify ownership 2936 case (catch agent_info(TargetName, user_id)) of 2937 {ok, UserId} -> 2938 handle_update_agent_info(TargetName, Info); 2939 {ok, OtherUserId} -> 2940 {error, {not_owner, OtherUserId}}; 2941 Error -> 2942 Error 2943 end. 2944 2945handle_update_agent_info(TargetName, Info) -> 2946 ?vtrace("handle_update_agent_info -> entry with" 2947 "~n TargetName: ~p" 2948 "~n Info: ~p", [TargetName, Info]), 2949 %% Verify info 2950 try 2951 verify_illegal(Info, [user_id]), 2952 %% If port or domain is part of the info, then use it. 2953 %% If not, lookup what is already stored for 2954 %% this agent and use that. 2955 do_update_agent_info( 2956 TargetName, 2957 fix_agent_config( 2958 verify_agent_config( 2959 ensure_agent_info(TargetName, [port,tdomain], Info)))) 2960 catch 2961 Error -> 2962 Error; 2963 T:E -> 2964 {error, {failed_info_verification, Info, T, E}} 2965 end. 2966 2967handle_update_agent_info(UserId, TargetName, Item, Val) -> 2968 ?vdebug("handle_update_agent_info -> entry with" 2969 "~n UserId: ~p" 2970 "~n TargetName: ~p" 2971 "~n Item: ~p" 2972 "~n Val: ~p", [UserId, TargetName, Item, Val]), 2973 handle_update_agent_info(TargetName, [{Item, Val}]). 2974 2975do_update_agent_info(TargetName, Info) -> 2976 ?vtrace("do_update_agent_info -> entry with~n" 2977 " TargetName: ~p~n" 2978 " Info: ~p", [TargetName,Info]), 2979 InsertItem = 2980 fun({Item, Val}) -> 2981 ets:insert(snmpm_agent_table, {{TargetName, Item}, Val}) 2982 end, 2983 lists:foreach(InsertItem, Info). 2984 2985do_update_agent_info(TargetName, Item, Val) -> 2986 ?vtrace("do_update_agent_info -> entry with" 2987 "~n TargetName: ~p" 2988 "~n Item: ~p" 2989 "~n Val: ~p", [TargetName, Item, Val]), 2990 ets:insert(snmpm_agent_table, {{TargetName, Item}, Val}), 2991 ok. 2992 2993 2994handle_register_usm_user(#usm_user{engine_id = EngineID, 2995 name = Name} = User) -> 2996 ?vdebug("handle_register_usm_user -> entry with" 2997 "~n User: ~p", [User]), 2998 Key = usm_key(EngineID, Name), 2999 case ets:lookup(snmpm_usm_table, Key) of 3000 [] -> 3001 do_update_usm_user_info(Key, User); 3002 _ -> 3003 {error, {already_registered, EngineID, Name}} 3004 end; 3005handle_register_usm_user(BadUsmUser) -> 3006 {error, {bad_usm_user, BadUsmUser}}. 3007 3008handle_unregister_usm_user(EngineID, Name) -> 3009 ?vdebug("handle_unregister_usm_user -> entry with" 3010 "~n EngineID: ~p" 3011 "~n Name: ~p", [EngineID, Name]), 3012 Key = usm_key(EngineID, Name), 3013 ets:delete(snmpm_usm_table, Key), 3014 ok. 3015 3016 3017handle_update_usm_user_info(EngineID, Name, Item, Val) -> 3018 ?vdebug("handle_update_usm_user_info -> entry with" 3019 "~n EngineID: ~p" 3020 "~n Name: ~p" 3021 "~n Item: ~p" 3022 "~n Val: ~p", [EngineID, Name, Item, Val]), 3023 Key = usm_key(EngineID, Name), 3024 case ets:lookup(snmpm_usm_table, Key) of 3025 [] -> 3026 {error, not_found}; 3027 [{_Key, User}] -> 3028 do_update_usm_user_info(Key, User, Item, Val) 3029 end. 3030 3031do_update_usm_user_info(Key, User, sec_name, Val) -> 3032 %% case verify_usm_user_sec_name(Val) of 3033 %% ok -> 3034 %% do_update_usm_user_info(Key, User#usm_user{sec_name = Val}); 3035 %% _ -> 3036 %% {error, {invalid_usm_sec_name, Val}} 3037 %% end; 3038 ok = verify_usm_user_sec_name(Val), 3039 do_update_usm_user_info(Key, User#usm_user{sec_name = Val}); 3040do_update_usm_user_info(Key, User, auth, Val) 3041 when (Val =:= usmNoAuthProtocol) orelse 3042 (Val =:= usmHMACMD5AuthProtocol) orelse 3043 (Val =:= usmHMACSHAAuthProtocol) -> 3044 do_update_usm_user_info(Key, User#usm_user{auth = Val}); 3045do_update_usm_user_info(_Key, _User, auth, Val) -> 3046 {error, {invalid_auth_protocol, Val}}; 3047do_update_usm_user_info(Key, 3048 #usm_user{auth = usmNoAuthProtocol} = User, 3049 auth_key, Val) -> 3050 case (catch snmp_conf:check_string(Val, any)) of 3051 ok -> 3052 do_update_usm_user_info(Key, User#usm_user{auth_key = Val}); 3053 _ -> 3054 {error, {invalid_auth_key, Val}} 3055 end; 3056do_update_usm_user_info(Key, 3057 #usm_user{auth = usmHMACMD5AuthProtocol} = User, 3058 auth_key, Val) 3059 when length(Val) =:= 16 -> 3060 case is_crypto_supported(md5) of 3061 true -> 3062 do_update_usm_user_info(Key, User#usm_user{auth_key = Val}); 3063 false -> 3064 {error, {unsupported_crypto, md5}} 3065 end; 3066do_update_usm_user_info(_Key, 3067 #usm_user{auth = usmHMACMD5AuthProtocol}, 3068 auth_key, Val) when is_list(Val) -> 3069 Len = length(Val), 3070 {error, {invalid_auth_key_length, usmHMACMD5AuthProtocol, Len}}; 3071do_update_usm_user_info(_Key, 3072 #usm_user{auth = usmHMACMD5AuthProtocol}, 3073 auth_key, Val) -> 3074 {error, {invalid_auth_key, usmHMACMD5AuthProtocol, Val}}; 3075do_update_usm_user_info(Key, 3076 #usm_user{auth = usmHMACSHAAuthProtocol} = User, 3077 auth_key, Val) 3078 when length(Val) =:= 20 -> 3079 case is_crypto_supported(sha) of 3080 true -> 3081 do_update_usm_user_info(Key, User#usm_user{auth_key = Val}); 3082 false -> 3083 {error, {unsupported_crypto, sha}} 3084 end; 3085do_update_usm_user_info(_Key, 3086 #usm_user{auth = usmHMACSHAAuthProtocol}, 3087 auth_key, Val) when is_list(Val) -> 3088 Len = length(Val), 3089 {error, {invalid_auth_key_length, usmHMACSHAAuthProtocol, Len}}; 3090do_update_usm_user_info(_Key, 3091 #usm_user{auth = usmHMACSHAAuthProtocol}, 3092 auth_key, Val) -> 3093 {error, {invalid_auth_key, usmHMACSHAAuthProtocol, Val}}; 3094do_update_usm_user_info(Key, User, priv, Val) 3095 when (Val =:= usmNoPrivProtocol) orelse 3096 (Val =:= usmDESPrivProtocol) orelse 3097 (Val =:= usmAesCfb128Protocol) -> 3098 do_update_usm_user_info(Key, User#usm_user{priv = Val}); 3099do_update_usm_user_info(_Key, _User, priv, Val) -> 3100 {error, {invalid_priv_protocol, Val}}; 3101do_update_usm_user_info(Key, 3102 #usm_user{priv = usmNoPrivProtocol} = User, 3103 priv_key, Val) -> 3104 case (catch snmp_conf:check_string(Val, any)) of 3105 ok -> 3106 do_update_usm_user_info(Key, User#usm_user{priv_key = Val}); 3107 _ -> 3108 {error, {invalid_priv_key, Val}} 3109 end; 3110do_update_usm_user_info(Key, 3111 #usm_user{priv = usmDESPrivProtocol} = User, 3112 priv_key, Val) 3113 when length(Val) =:= 16 -> 3114 case is_crypto_supported(des_cbc) of 3115 true -> 3116 do_update_usm_user_info(Key, User#usm_user{priv_key = Val}); 3117 false -> 3118 {error, {unsupported_crypto, des_cbc}} 3119 end; 3120do_update_usm_user_info(Key, 3121 #usm_user{priv = usmAesCfb128Protocoll} = User, 3122 priv_key, Val) 3123 when length(Val) =:= 16 -> 3124 case is_crypto_supported(aes_cfb128) of 3125 true -> 3126 do_update_usm_user_info(Key, User#usm_user{priv_key = Val}); 3127 false -> 3128 {error, {unsupported_crypto, aes_cfb128}} 3129 end; 3130do_update_usm_user_info(_Key, 3131 #usm_user{auth = usmHMACSHAAuthProtocol}, 3132 priv_key, Val) when is_list(Val) -> 3133 Len = length(Val), 3134 {error, {invalid_priv_key_length, usmHMACSHAAuthProtocol, Len}}; 3135do_update_usm_user_info(_Key, 3136 #usm_user{auth = usmHMACSHAAuthProtocol}, 3137 priv_key, Val) -> 3138 {error, {invalid_priv_key, usmHMACSHAAuthProtocol, Val}}; 3139do_update_usm_user_info(_Key, _User, Item, Val) -> 3140 {error, {bad_item, Item, Val}}. 3141 3142do_update_usm_user_info(Key, User) -> 3143 ets:insert(snmpm_usm_table, {Key, User}), 3144 ok. 3145 3146 3147usm_key(EngineId, Name) -> 3148 {usmUserTable, EngineId, Name}. 3149 3150 3151%% --------------------------------------------------------------------- 3152 3153verify_mandatory(_, []) -> 3154 ok; 3155verify_mandatory(Conf, [Mand|Mands]) -> 3156 case lists:keymember(Mand, 1, Conf) of 3157 true -> 3158 verify_mandatory(Conf, Mands); 3159 false -> 3160 error({missing_mandatory_config, Mand}) 3161 end. 3162 3163verify_illegal(_, []) -> 3164 ok; 3165verify_illegal(Conf, [Inv|Invs]) -> 3166 case lists:member(Inv, Conf) of 3167 false -> 3168 verify_illegal(Conf, Invs); 3169 true -> 3170 error({illegal_config, Inv}) 3171 end. 3172 3173verify_someof(Conf, [Mand|Mands]) -> 3174 case lists:keymember(Mand, 1, Conf) of 3175 true -> 3176 ok; 3177 false -> 3178 case Mands of 3179 [] -> 3180 error({missing_mandatory_config, Mand}); 3181 _ -> 3182 verify_someof(Conf, Mands) 3183 end 3184 end. 3185 3186ensure_config([], Config) -> 3187 Config; 3188ensure_config([Default|Defaults], Config) -> 3189 case lists:keymember(element(1, Default), 1, Config) of 3190 true -> 3191 ensure_config(Defaults, Config); 3192 false -> 3193 ensure_config(Defaults, [Default|Config]) 3194 end. 3195 3196 3197 3198%%%------------------------------------------------------------------- 3199%%% 3200%%% Mini MIB stuff 3201%%% 3202%%%------------------------------------------------------------------- 3203 3204init_mini_mib(MibFiles) -> 3205 MiniMibs = lists:flatten([do_load_mib(MibFile) || MibFile <- MibFiles]), 3206 MiniMIB = remove_duplicates(lists:keysort(1, MiniMibs), []), 3207 init_mini_mib2(MiniMIB). 3208 3209remove_duplicates([], Res) -> 3210 Res; 3211remove_duplicates([X,X|T], Res) -> 3212 remove_duplicates([X|T], Res); 3213remove_duplicates([{Oid, Name, Type, _} = X, {Oid, Name, Type, _}|T], Res) -> 3214 remove_duplicates([X|T], Res); 3215remove_duplicates([X|T], Res) -> 3216 remove_duplicates(T, [X|Res]). 3217 3218init_mini_mib2([]) -> 3219 ok; 3220init_mini_mib2([{Oid, Name, Type, MibName}|MiniMib]) -> 3221 ?vtrace("init mini mib -> ~w: ~w [~w] from ~s", 3222 [Name, Oid, Type,MibName ]), 3223 ets:insert(snmpm_mib_table, {{mini_mib, Oid}, Name, Type, MibName}), 3224 init_mini_mib2(MiniMib). 3225 3226 3227handle_load_mib(Mib) -> 3228 [{mibs, Mibs0}] = ets:lookup(snmpm_config_table, mibs), 3229 case lists:member(Mib, Mibs0) of 3230 true -> 3231 {error, already_loaded}; 3232 false -> 3233 Mibs = [Mib|Mibs0], 3234 case (catch do_load_mib(Mib)) of 3235 MiniElems when is_list(MiniElems) -> 3236 ets:insert(snmpm_config_table, {mibs, Mibs}), 3237 update_mini_mib(MiniElems), 3238 ok; 3239 Error -> 3240 Error 3241 end 3242 end. 3243 3244update_mini_mib([]) -> 3245 ok; 3246update_mini_mib([{Oid, Name, Type, MibName}|Elems]) -> 3247 Key = {mini_mib, Oid}, 3248 case ets:lookup(snmpm_mib_table, Key) of 3249 [{Key, _Name, _Type, _AnotherMibName}] -> 3250 %% Already loaded from another mib 3251 update_mini_mib(Elems); 3252 [] -> 3253 %% Not yet loaded 3254 ?vtrace("update mini mib -> ~w: ~w [~w] from ~s", 3255 [Name, Oid, Type, MibName]), 3256 ets:insert(snmpm_mib_table, {Key, Name, Type, MibName}), 3257 update_mini_mib(Elems) 3258 end. 3259 3260 3261handle_unload_mib(Mib) -> 3262 Key = {mib, Mib}, 3263 case ets:lookup(snmpm_mib_table, Key) of 3264 [{Key, MibName, _MibFile}] -> 3265 do_unload_mib(MibName), 3266 [{mibs, Mibs0}] = ets:lookup(snmpm_config_table, mibs), 3267 Mibs = lists:delete(Mib, Mibs0), 3268 ets:insert(snmpm_config_table, {mibs, Mibs}), 3269 ets:delete(snmpm_mib_table, Key), 3270 ok; 3271 _ -> 3272 {error, not_loaded} 3273 end. 3274 3275do_unload_mib(MibName) -> 3276 Pat = {{mini_mib, '$1'}, '_', '_', MibName}, 3277 Oids = ets:match(snmpm_mib_table, Pat), 3278 F = fun([Oid]) -> ets:delete(snmpm_mib_table, {mini_mib, Oid}) end, 3279 lists:foreach(F, Oids). 3280 3281 3282do_load_mib(MibFile) -> 3283 ?vtrace("load mib ~s", [MibFile]), 3284 F1 = snmp_misc:strip_extension_from_filename(MibFile, ".bin"), 3285 ActualFileName = lists:append(F1, ".bin"), 3286 case snmp_misc:read_mib(ActualFileName) of 3287 {ok, #mib{name = Name, mes = MEs, traps = Traps}} -> 3288 %% Check that the mib was not loaded or loaded 3289 %% with a different filename: 3290 %% e.g. /tmp/MYMIB.bin and /tmp/mibs/MYMIB.bin 3291 Name1 = mib_name(Name), 3292 Pattern = {{mib, '_'}, Name1, '$1'}, 3293 case ets:match(snmpm_mib_table, Pattern) of 3294 [] -> 3295 3296 Rec = {{mib, MibFile}, Name1, ActualFileName}, 3297 ets:insert(snmpm_mib_table, Rec), 3298 init_mini_mib_elems(Name1, MEs++Traps, []); 3299 3300 %% This means that the mib has already been loaded 3301 [[ActualFileName]] -> 3302 []; 3303 3304 %% This means that the mib was loaded before, 3305 %% but under another filename 3306 [[OtherMibFile]] -> 3307 error({already_loaded, MibFile, OtherMibFile}) 3308 end; 3309 3310 {error, Reason} -> 3311 error({failed_reading_mib, MibFile, Reason}) 3312 end. 3313 3314mib_name(N) when is_list(N) -> 3315 list_to_atom(N); 3316mib_name(N) -> 3317 N. 3318 3319init_mini_mib_elems(_, [], Res) -> 3320 Res; 3321init_mini_mib_elems(MibName, 3322 [#me{aliasname = N, 3323 oid = Oid, 3324 entrytype = variable, 3325 asn1_type = #asn1_type{bertype = Type}} | T], Res) -> 3326 init_mini_mib_elems(MibName, T, [{Oid, N, Type, MibName}|Res]); 3327 3328init_mini_mib_elems(MibName, 3329 [#me{aliasname = N, 3330 oid = Oid, 3331 entrytype = table_column, 3332 asn1_type = #asn1_type{bertype = Type}}|T], Res) -> 3333 init_mini_mib_elems(MibName, T, [{Oid, N, Type, MibName}|Res]); 3334 3335init_mini_mib_elems(MibName, 3336 [#me{aliasname = N, 3337 oid = Oid, 3338 asn1_type = undefined}|T], Res) -> 3339 init_mini_mib_elems(MibName, T, [{Oid, N, undefined, MibName}|Res]); 3340 3341init_mini_mib_elems(MibName, 3342 [#notification{trapname = N, 3343 oid = Oid}|T], Res) -> 3344 init_mini_mib_elems(MibName, T, [{Oid, N, undefined, MibName}|Res]); 3345 3346init_mini_mib_elems(MibName, [_|T], Res) -> 3347 init_mini_mib_elems(MibName, T, Res). 3348 3349 3350 3351%%---------------------------------------------------------------------- 3352 3353fix_address(Domain, Address) -> 3354 case snmp_conf:check_address(Domain, Address) of 3355 ok -> 3356 Address; 3357 {ok, NAddress} -> 3358 NAddress 3359 end. 3360 3361%%---------------------------------------------------------------------- 3362 3363call(Req) -> 3364 call(Req, infinity). 3365 3366call(Req, To) -> 3367 gen_server:call(?SERVER, Req, To). 3368 3369% cast(Msg) -> 3370% gen_server:cast(snmpm_server, Msg). 3371 3372 3373%%------------------------------------------------------------------- 3374 3375get_atl_dir(Opts) -> 3376 get_opt(dir, Opts). 3377 3378get_atl_type(Opts) -> 3379 case get_opt(type, Opts, read_write) of 3380 read_write -> 3381 [read,write]; 3382 read -> 3383 [read]; 3384 write -> 3385 [write] 3386 end. 3387 3388get_atl_size(Opts) -> 3389 get_opt(size, Opts). 3390 3391get_atl_repair(Opts) -> 3392 get_opt(repair, Opts, truncate). 3393 3394get_atl_seqno(Opts) -> 3395 get_opt(seqno, Opts, false). 3396 3397 3398%%---------------------------------------------------------------------- 3399 3400get_opt(Key, Opts) -> 3401 ?d("get option ~w from ~p", [Key, Opts]), 3402 snmp_misc:get_option(Key, Opts). 3403 3404get_opt(Key, Opts, Def) -> 3405 ?d("get option ~w with default ~p from ~p", [Key, Def, Opts]), 3406 snmp_misc:get_option(Key, Opts, Def). 3407 3408 3409%%---------------------------------------------------------------------- 3410 3411get_info() -> 3412 ProcSize = proc_mem(self()), 3413 CntSz = tab_size(snmpm_counter_table), 3414 StatsSz = tab_size(snmpm_stats_table), 3415 MibSz = tab_size(snmpm_mib_table), 3416 ConfSz = tab_size(snmpm_config_table), 3417 AgentSz = tab_size(snmpm_agent_table), 3418 UserSz = tab_size(snmpm_user_table), 3419 UsmSz = tab_size(snmpm_usm_table), 3420 [{process_memory, ProcSize}, 3421 {db_memory, [{counter, CntSz}, 3422 {stats, StatsSz}, 3423 {mib, MibSz}, 3424 {config, ConfSz}, 3425 {agent, AgentSz}, 3426 {user, UserSz}, 3427 {usm, UsmSz}]}]. 3428 3429proc_mem(P) when is_pid(P) -> 3430 case (catch erlang:process_info(P, memory)) of 3431 {memory, Sz} when is_integer(Sz) -> 3432 Sz; 3433 _ -> 3434 undefined 3435 end. 3436%% proc_mem(_) -> 3437%% undefined. 3438 3439tab_size(T) -> 3440 case (catch ets:info(T, memory)) of 3441 Sz when is_integer(Sz) -> 3442 Sz; 3443 _ -> 3444 undefined 3445 end. 3446 3447 3448%%---------------------------------------------------------------------- 3449 3450error(Reason) -> 3451 throw({error, Reason}). 3452 3453 3454%%---------------------------------------------------------------------- 3455 3456info_msg(F, A) -> 3457 ?snmpm_info("Config server: " ++ F, A). 3458 3459warning_msg(F, A) -> 3460 ?snmpm_warning("Config server: " ++ F, A). 3461 3462error_msg(F, A) -> 3463 ?snmpm_error("Config server: " ++ F, A). 3464 3465%% p(F) -> 3466%% p(F, []). 3467 3468%% p(F, A) -> 3469%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]). 3470