PageRenderTime 9ms CodeModel.GetById 3ms app.highlight 106ms RepoModel.GetById 1ms app.codeStats 1ms

/lib/snmp/src/manager/snmpm_config.erl

https://github.com/bsmr-erlang/otp
Erlang | 3436 lines | 2667 code | 443 blank | 326 comment | 12 complexity | fc2c18c5dd9e4923635fb9af07858fcd MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1%% 
   2%% %CopyrightBegin%
   3%%
   4%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
   5%%
   6%% Licensed under the Apache License, Version 2.0 (the "License");
   7%% you may not use this file except in compliance with the License.
   8%% You may obtain a copy of the License at
   9%%
  10%%     http://www.apache.org/licenses/LICENSE-2.0
  11%%
  12%% Unless required by applicable law or agreed to in writing, software
  13%% distributed under the License is distributed on an "AS IS" BASIS,
  14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15%% See the License for the specific language governing permissions and
  16%% limitations under the License.
  17%%
  18%% %CopyrightEnd%
  19%% 
  20%% -------------------------------------------------------------------------
  21%%
  22%% Some of the stuff stored here should really be persistent!!
  23%% (e.g. snmp-engine-boot)
  24%%
  25%% -------------------------------------------------------------------------
  26
  27-module(snmpm_config).
  28
  29-behaviour(gen_server).
  30
  31%% External exports
  32%% Avoid warning for local function error/1 clashing with autoimported BIF.
  33-compile({no_auto_import,[error/1]}).
  34-export([start_link/1, stop/0, is_started/0]).
  35-export([register_user/4, unregister_user/1, 
  36	 which_users/0, 
  37	 user_info/0, user_info/1, user_info/2, 
  38
  39	 register_agent/3, unregister_agent/2, 
  40	 agent_info/0, agent_info/2, agent_info/3, 
  41	 update_agent_info/3, update_agent_info/4, 
  42	 which_agents/0, which_agents/1, 
  43
  44	 is_known_engine_id/2, 
  45	 get_agent_engine_id/1, 
  46	 get_agent_engine_max_message_size/1, 
  47	 get_agent_version/1, 
  48	 get_agent_mp_model/1, 
  49	 get_agent_user_id/1, get_agent_user_id/2, 
  50	 get_agent_user_info/2, 
  51	 
  52	 system_info/0, system_info/1, 
  53	 %% update_system_info/2, 
  54	 get_engine_id/0, get_engine_max_message_size/0,
  55
  56	 register_usm_user/3, unregister_usm_user/2, 
  57	 which_usm_users/0, which_usm_users/1, 
  58	 usm_user_info/3, update_usm_user_info/4, 
  59	 get_usm_user/2, get_usm_user_from_sec_name/2, 
  60	 is_usm_engine_id_known/1,
  61	 get_engine_boots/0, get_engine_time/0, 
  62	 set_engine_boots/1, set_engine_time/1, 
  63	 get_usm_eboots/1, get_usm_etime/1, get_usm_eltime/1, 
  64	 set_usm_eboots/2, set_usm_etime/2, set_usm_eltime/2, 
  65	 reset_usm_cache/1, 
  66	 
  67
  68	 cre_counter/2,
  69	 incr_counter/2,
  70	 increment_counter/3, increment_counter/4, 
  71
  72	 cre_stats_counter/2,
  73	 maybe_cre_stats_counter/2,
  74	 incr_stats_counter/2,
  75	 reset_stats_counter/1,
  76	 get_stats_counters/0, get_stats_counter/1,
  77
  78	 load_mib/1, unload_mib/1, which_mibs/0, 
  79	 make_mini_mib/0,
  80	 name_to_oid/1, oid_to_name/1, oid_to_type/1, 
  81
  82	 system_start_time/0,
  83
  84	 info/0, 
  85	 verbosity/1,
  86
  87	 backup/1,
  88
  89	 mk_target_name/3,
  90	 
  91	 default_transport_domain/0
  92
  93	]).
  94
  95%% Backward compatibillity exports
  96-export([
  97	 register_user/3,
  98	 unregister_agent/3, 
  99	 update_agent_info/5,
 100	 is_known_engine_id/3, 
 101	 get_agent_engine_id/2, 
 102	 get_agent_engine_max_message_size/2, 
 103	 get_agent_version/2, 
 104	 get_agent_mp_model/2
 105	]).
 106
 107-export([
 108	 order_manager_config/2,
 109	 check_manager_config/2,
 110	 check_user_config/1,
 111	 check_agent_config/1,
 112	 check_usm_user_config/1]).
 113
 114
 115%% gen_server callbacks
 116-export([init/1, handle_call/3, handle_cast/2, handle_info/2, 
 117	 code_change/3, terminate/2]).
 118
 119
 120%% Includes:
 121-include_lib("kernel/include/file.hrl").
 122-include("snmp_types.hrl").
 123-include("snmpm_internal.hrl").
 124-include("snmpm_usm.hrl").
 125-include("snmp_debug.hrl").
 126-include("snmp_verbosity.hrl").
 127
 128
 129%% Types:
 130-record(user, {id, mod, data, default_agent_config}).
 131
 132-record(state, {backup}).
 133
 134
 135%% Macros and Constants:
 136-define(SERVER,             ?MODULE).
 137-define(BACKUP_DB,          snmpm_config_backup).
 138-define(CONFIG_DB,          snmpm_config_db).
 139
 140-define(DEFAULT_USER,       default_user).
 141
 142-define(DEFAULT_AGENT_PORT, 161).
 143
 144-define(IRB_DEFAULT,        auto).
 145%% -define(IRB_DEFAULT,        {user, timer:seconds(15)}).
 146
 147-define(USER_MOD_DEFAULT,   snmpm_user_default).
 148-define(USER_DATA_DEFAULT,  undefined).
 149
 150%% -define(DEF_ADDR_TAG, default_addr_tag).
 151-define(DEFAULT_TARGETNAME, default_agent).
 152-define(DEF_PORT_TAG,       default_port_tag).
 153-define(SUPPORTED_DOMAINS,  [transportDomainUdpIpv4, transportDomainUdpIpv6]).
 154
 155-ifdef(snmp_debug).
 156-define(GS_START_LINK(Opts),
 157	gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], 
 158			      [{debug,[trace]}])).
 159-else.
 160-define(GS_START_LINK(Opts),
 161	gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], [])).
 162-endif.
 163
 164
 165
 166%%%-------------------------------------------------------------------
 167%%% API
 168%%%-------------------------------------------------------------------
 169
 170default_transport_domain() ->
 171    snmpUDPDomain.
 172
 173
 174start_link(Opts) -> 
 175    ?d("start_link -> entry with"
 176       "~n   Opts: ~p", [Opts]),
 177    ?GS_START_LINK(Opts).
 178
 179stop() ->
 180    call(stop).
 181
 182is_started() ->
 183    call(is_started, 1000).
 184
 185backup(BackupDir) when is_list(BackupDir) ->
 186    call({backup, BackupDir}).
 187
 188%% Backward compatibillity
 189register_user(UserId, UserMod, UserData) ->
 190    register_user(UserId, UserMod, UserData, []).
 191
 192register_user(UserId, UserMod, UserData, DefaultAgentConfig) 
 193  when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) ->
 194    case (catch verify_user_behaviour(UserMod)) of
 195	ok ->
 196	    {ok, SystemDefaultAgentConfig} = agent_info(),
 197	    Config =
 198		ensure_config(SystemDefaultAgentConfig,
 199			      DefaultAgentConfig),
 200%%	    Config = default_agent_config(DefaultAgentConfig),
 201	    call({register_user, UserId, UserMod, UserData, Config});
 202	Error ->
 203	    Error
 204    end;
 205register_user(UserId, _UserMod, _UserData, DefaultAgentConfig) 
 206  when (UserId =/= ?DEFAULT_USER) ->
 207    {error, {bad_default_agent_config, DefaultAgentConfig}};
 208register_user(UserId, _, _, _) ->
 209    {error, {bad_user_id, UserId}}.
 210
 211%% default_agent_config(DefaultAgentConfig) ->
 212%%     {ok, SystemDefaultAgentConfig} = agent_info(),
 213%%     default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig).
 214
 215%% default_agent_config([], DefaultAgentConfig) ->
 216%%     DefaultAgentConfig;
 217%% default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) ->
 218%%     case lists:keymember(Key, 1, DefaultAgentConfig) of
 219%% 	true ->
 220%% 	    default_agent_config(T, DefaultAgentConfig);
 221%% 	false ->
 222%% 	    default_agent_config(T, [Entry|DefaultAgentConfig])
 223%%     end.
 224
 225
 226verify_user_behaviour(UserMod) ->
 227    case snmp_misc:verify_behaviour(snmpm_user, UserMod) of
 228	ok ->
 229	    ok;
 230	Error ->
 231	    %% This user may implement the old behaviour, check it
 232	    case snmp_misc:verify_behaviour(snmpm_user_old, UserMod) of
 233		ok ->
 234		    ok;
 235		_ ->
 236		    throw(Error)
 237	    end
 238    end.
 239
 240
 241unregister_user(UserId) when UserId =/= ?DEFAULT_USER ->
 242    call({unregister_user, UserId});
 243unregister_user(BadUserId) ->
 244    {error, {bad_user_id, BadUserId}}.
 245
 246
 247which_users() ->
 248    Pattern = #user{id = '$1', _ = '_'},
 249    Match   = ets:match(snmpm_user_table, Pattern),
 250    [UserId || [UserId] <- Match, UserId =/= ?DEFAULT_USER].
 251
 252
 253user_info() ->
 254    UserId = ?DEFAULT_USER,
 255    case user_info(UserId) of
 256	{ok, Mod, Data} ->
 257	    {ok, UserId, Mod, Data};
 258	Error ->
 259	    Error
 260    end.
 261
 262user_info(UserId) ->
 263    case ets:lookup(snmpm_user_table, UserId) of
 264	[#user{mod = UserMod, data = UserData}] ->
 265	    {ok, UserMod, UserData};
 266	_ ->
 267	    {error, not_found}
 268    end.
 269
 270user_info(UserId, Item) ->
 271    case (catch do_user_info(UserId, Item)) of
 272	{'EXIT', _} ->
 273	    {error, {not_found, Item}};
 274	Val ->
 275	    {ok, Val}
 276    end.
 277
 278do_user_info(UserId, module) ->
 279    ets:lookup_element(snmpm_user_table, UserId, #user.mod);
 280do_user_info(UserId, data) ->
 281    ets:lookup_element(snmpm_user_table, UserId, #user.data);
 282do_user_info(UserId, default_agent_config) ->
 283    ets:lookup_element(snmpm_user_table, UserId, #user.default_agent_config);
 284do_user_info(_UserId, BadItem) ->
 285    error({not_found, BadItem}).
 286
 287
 288%% A target-name constructed in this way is a string with the following: 
 289%% <IP-address>:<Port>-<Version>
 290%% This is intended for backward compatibility and therefore has
 291%% only support for IPv4 addresses and *no* other transport domain.
 292mk_target_name(Domain, Addr, Config)
 293  when is_atom(Domain), is_list(Config) ->
 294    Version = 
 295	case lists:keysearch(version, 1, Config) of
 296	    {value, {_, V}} ->
 297		V;
 298	    false ->
 299		select_lowest_supported_version()
 300	end,
 301    try
 302	lists:flatten(
 303	  io_lib:format(
 304	    "~s-~w", [snmp_conf:mk_addr_string({Domain, Addr}), Version]))
 305    catch
 306	_ ->
 307	    lists:flatten(
 308	      io_lib:format("~p-~w", [Addr, Version]))
 309    end;
 310mk_target_name(Ip, Port, Config)
 311  when is_integer(Port), is_list(Config) ->
 312    Domain = default_transport_domain(),
 313    try fix_address(Domain, {Ip, Port}) of
 314	Address ->
 315	    mk_target_name(Domain, Address, Config)
 316    catch
 317	_ ->
 318	    Version =
 319		case lists:keysearch(version, 1, Config) of
 320		    {value, {_, V}} ->
 321			V;
 322		    false ->
 323			select_lowest_supported_version()
 324		end,
 325	    lists:flatten(
 326	      io_lib:format("~p:~w-~w", [Ip, Port, Version]))
 327    end.
 328
 329
 330select_lowest_supported_version() ->
 331    {ok, Versions} = system_info(versions),
 332    select_lowest_supported_version([v1, v2, v3], Versions).
 333
 334select_lowest_supported_version([], Versions) ->
 335    error({bad_versions, Versions});
 336select_lowest_supported_version([H|T], Versions) ->
 337    case lists:member(H, Versions) of
 338	true ->
 339	    H;
 340	false ->
 341	    select_lowest_supported_version(T, Versions)
 342    end.
 343
 344
 345register_agent(UserId, _TargetName, _Config0) when (UserId =:= user_id) ->
 346    {error, {bad_user_id, UserId}};
 347register_agent(UserId, TargetName, Config0) 
 348  when (is_list(TargetName) andalso 
 349	(length(TargetName) > 0) andalso 
 350	is_list(Config0)) ->
 351
 352    ?vtrace("register_agent -> entry with"
 353	    "~n   UserId:     ~p"
 354	    "~n   TargetName: ~p"
 355	    "~n   Config0:    ~p", [UserId, TargetName, Config0]),
 356
 357    %% Check: 
 358    %%   1) That the mandatory configs are present
 359    %%   2) That no illegal config, e.g. user_id (used internally), 
 360    %%      is not present
 361    %%   3) Check that there are no invalid or erroneous configs
 362    %%   4) Check that the manager is capable of using the selected version
 363    try
 364	verify_mandatory(Config0, [engine_id, reg_type]),
 365	verify_someof(Config0, [address, taddress]),
 366	verify_illegal(Config0, [user_id]),
 367	Config = verify_agent_config(Config0),
 368	Vsns = versions(),
 369	Vsn = which_version(Config),
 370	verify_version(Vsn, Vsns),
 371	call({register_agent, UserId, TargetName, Config})
 372    catch
 373	Error ->
 374	    Error
 375    end.
 376
 377versions() ->
 378    case system_info(versions) of
 379	{ok, Vsns} ->
 380	    Vsns;
 381	{error, _} = ERROR ->
 382	    throw(ERROR)
 383    end.
 384
 385which_version(Conf) ->
 386    case lists:keysearch(version, 1, Conf) of
 387	{value, {version, V}} ->
 388	    V;
 389	false ->
 390	    v1
 391    end.
 392
 393verify_version(Vsn, Vsns) ->
 394    case lists:member(Vsn, Vsns) of
 395	true ->
 396	    ok;
 397	false ->
 398	    Reason = {version_not_supported_by_manager, Vsn, Vsns}, 
 399	    error(Reason)
 400    end.
 401
 402
 403
 404unregister_agent(UserId, TargetName) ->
 405    call({unregister_agent, UserId, TargetName}).
 406
 407%% This is the old style agent unregistration (using Addr and Port).
 408unregister_agent(UserId, Domain, Address) when is_atom(Domain) ->
 409    try fix_address(Domain, Address) of
 410	NAddress ->
 411	    do_unregister_agent(UserId, Domain, NAddress)
 412    catch
 413	_ ->
 414	    {error, not_found}
 415    end;
 416unregister_agent(UserId, Ip, Port) when is_integer(Port) ->
 417    Domain = default_transport_domain(),
 418    try fix_address(Domain, {Ip, Port}) of
 419	Address ->
 420	    do_unregister_agent(UserId, Domain, Address)
 421    catch
 422	_ ->
 423	    {error, not_found}
 424    end.
 425
 426do_unregister_agent(UserId, Domain, Address) ->
 427    case do_agent_info(Domain, Address, target_name) of
 428	{ok, TargetName} ->
 429	    unregister_agent(UserId, TargetName);
 430	Error ->
 431	    Error
 432    end.
 433
 434
 435
 436agent_info() ->
 437    agent_info(?DEFAULT_TARGETNAME, all).
 438
 439agent_info(TargetName, all) ->
 440    case ets:match_object(snmpm_agent_table, {{TargetName, '_'}, '_'}) of
 441	[] ->
 442	    {error, not_found};
 443	All ->
 444	    {ok, [{Item, Val} || {{_, Item}, Val} <- All]}
 445    end;
 446%% Begin backwards compatibility
 447agent_info(TargetName, address) ->
 448    case agent_info({TargetName, taddress}) of
 449	{ok, Val} ->
 450	    {Addr, _} = Val,
 451	    {ok, Addr};
 452	_ ->
 453	    %% This should be redundant since 'taddress' should exist
 454	    agent_info({TargetName, address})
 455    end;
 456agent_info(TargetName, port) ->
 457    case agent_info({TargetName, taddress}) of
 458	{ok, Val} ->
 459	    {_, Port} = Val,
 460	    {ok, Port};
 461	_ ->
 462	    %% This should be redundant since 'taddress' should exist
 463	    agent_info({TargetName, port})
 464    end;
 465%% End backwards compatibility
 466agent_info(TargetName, Item) ->
 467    agent_info({TargetName, Item}).
 468
 469agent_info(Key) ->
 470    case ets:lookup(snmpm_agent_table, Key) of
 471	[{_, Val}] ->
 472	    {ok, Val};
 473	[] ->
 474	    {error, not_found}
 475    end.
 476
 477agent_info(Domain, Address, Item) when is_atom(Domain) ->
 478    try fix_address(Domain, Address) of
 479	NAddress ->
 480	    do_agent_info(Domain, NAddress, Item)
 481    catch
 482	_Thrown ->
 483	    %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n"
 484	    %%   "    ~p",
 485	    %%   [Domain, Address, Item, _Thrown, erlang:get_stacktrace()]),
 486	    {error, not_found}
 487    end;
 488agent_info(Ip, Port, Item) when is_integer(Port) ->
 489    %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) entry~n",
 490    %%   [Ip, Port, Item]),
 491    Domain = default_transport_domain(),
 492    try fix_address(Domain, {Ip, Port}) of
 493	Address ->
 494	    do_agent_info(Domain, Address, Item)
 495    catch
 496	_Thrown ->
 497	    %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n"
 498	    %%   "    ~p",
 499	    %%   [Ip, Port, Item, _Thrown, erlang:get_stacktrace()]),
 500	    {error, not_found}
 501    end.
 502
 503do_agent_info(Domain, Address, target_name = Item) ->
 504    %% p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n",
 505    %%   [Domain, Address, Item]),
 506    case ets:lookup(snmpm_agent_table, {Domain, Address, Item}) of
 507	[{_, Val}] ->
 508	    {ok, Val};
 509	[] ->
 510	    {error, not_found}
 511    end;
 512do_agent_info(Domain, Address, Item) ->
 513    %% p(?MODULE_STRING":do_agent_info(~p, ~p, ~p) entry~n",
 514    %%   [Domain, Address, Item]),
 515    case do_agent_info(Domain, Address, target_name) of
 516	{ok, TargetName} ->
 517	    agent_info(TargetName, Item);
 518	Error ->
 519	    Error
 520    end.
 521
 522
 523ensure_agent_info(_, [], Info) ->
 524    Info;
 525ensure_agent_info(TargetName, [Item|Items], Info) ->
 526    case lists:keymember(Item, 1, Info) of
 527	true ->
 528	    ensure_agent_info(TargetName, Items, Info);
 529	false ->
 530	    {ok, Value} = agent_info(TargetName, Item),
 531	    ensure_agent_info(TargetName, Items, [{Item, Value}|Info])
 532    end.
 533
 534
 535
 536which_agents() ->
 537    which_agents('_').
 538
 539which_agents(UserId) ->
 540    Pat = {{'$1', user_id}, UserId},
 541    Agents = ets:match(snmpm_agent_table, Pat),
 542    [TargetName || [TargetName] <- Agents].
 543
 544
 545
 546update_agent_info(UserId, TargetName, Info) ->
 547    call({update_agent_info, UserId, TargetName, Info}).
 548
 549%% <BACKWARD-COMPAT-2>
 550%% This is wrapped in the interface module, so this function is
 551%% only here to catch code-upgrade problems.
 552update_agent_info(UserId, TargetName, Item, Val) ->
 553    update_agent_info(UserId, TargetName, [{Item, Val}]).
 554%% </BACKWARD-COMPAT-2>
 555
 556%% <BACKWARD-COMPAT-1>
 557update_agent_info(UserId, Addr, Port, Item, Val)  ->
 558    case agent_info(Addr, Port, target_name) of
 559	{ok, TargetName} ->
 560	    update_agent_info(UserId, TargetName, Item, Val);
 561	Error ->
 562	    Error
 563    end.
 564%% </BACKWARD-COMPAT-1>
 565
 566is_known_engine_id(EngineID, TargetName) ->
 567    case agent_info(TargetName, engine_id) of
 568	{ok, EngineID} ->
 569	    true;
 570	{ok, _OtherEngineID} ->
 571	    false;
 572	_ ->
 573	    false
 574    end.
 575    
 576%% Backward compatibillity
 577is_known_engine_id(EngineID, Addr, Port) ->
 578    case agent_info(Addr, Port, target_name) of
 579	{ok, TargetName} ->
 580	    is_known_engine_id(EngineID, TargetName);
 581	_ ->
 582	    false
 583    end.
 584
 585get_agent_engine_id(TargetName) ->
 586    agent_info(TargetName, engine_id).
 587
 588%% Backward compatibillity
 589get_agent_engine_id(Addr, Port) ->
 590    agent_info(Addr, Port, engine_id).
 591
 592get_agent_engine_max_message_size(TargetName) ->
 593    agent_info(TargetName, max_message_size).
 594
 595%% Backward compatibillity
 596get_agent_engine_max_message_size(Addr, Port) ->
 597    agent_info(Addr, Port, max_message_size).
 598
 599get_agent_version(TargetName) ->
 600    agent_info(TargetName, version). 
 601
 602%% Backward compatibillity
 603get_agent_version(Addr, Port) ->
 604    agent_info(Addr, Port, version). 
 605
 606get_agent_mp_model(TargetName) ->
 607    case agent_info(TargetName, version) of
 608	{ok, v2} ->
 609	    {ok, v2c};
 610	{ok, V} ->
 611	    {ok, V};
 612	Err ->
 613	    Err
 614    end.
 615
 616%% Backward compatibillity
 617get_agent_mp_model(Addr, Port) ->
 618    case agent_info(Addr, Port, target_name) of
 619	{ok, TargetName} ->
 620	    get_agent_mp_model(TargetName);
 621	Error ->
 622	    Error
 623    end.
 624
 625get_agent_user_id(TargetName) ->
 626    agent_info(TargetName, user_id).
 627
 628get_agent_user_id(Addr, Port) ->
 629    agent_info(Addr, Port, user_id).
 630
 631get_agent_user_info(Addr, Port) ->
 632    case agent_info(Addr, Port, target_name) of
 633	{ok, Target} ->
 634	    case agent_info(Target, reg_type) of
 635		{ok, RegType} ->
 636		    case agent_info(Target, user_id) of
 637			{ok, UserId} ->
 638			    {ok, UserId, Target, RegType};
 639			{error, not_found} ->
 640			    {error, {user_id_not_found, Target}}
 641		    end;
 642		{error, not_found} ->
 643		    {error, {reg_type_not_found, Target}}
 644	    end;
 645	{error, not_found} ->
 646	    {error, {target_name_not_found, Addr, Port}}
 647    end.
 648	    
 649
 650
 651system_info() ->
 652    system_info(all).
 653
 654system_info(all) ->
 655    lists:sort(ets:tab2list(snmpm_config_table));
 656system_info(Key) when is_atom(Key) ->
 657    case ets:lookup(snmpm_config_table, Key) of
 658	[{_, Val}] ->
 659	    {ok, Val};
 660	_ ->
 661	    {error, not_found}
 662    end.
 663
 664%% update_system_info(Key, Val) ->
 665%%     call({update_system_info, Key, Val}).
 666
 667system_start_time() ->
 668    system_info(system_start_time).
 669
 670get_engine_id() ->
 671    system_info(engine_id).
 672
 673get_engine_max_message_size() ->
 674    system_info(max_message_size).
 675
 676get_engine_boots() ->
 677    case dets:lookup(?CONFIG_DB, snmp_engine_boots) of
 678	[{_, Boots}] ->
 679	    {ok, Boots};
 680	_ ->
 681	    {error, not_found}
 682    end.
 683
 684set_engine_boots(Boots) ->
 685    case (whereis(?SERVER) =:= self()) of
 686	false ->
 687	    call({set_engine_boots, Boots});
 688	true ->
 689	    dets:insert(?CONFIG_DB, {snmp_engine_boots, Boots}),
 690	    ok
 691    end.
 692    
 693
 694get_engine_time() ->
 695    case system_info(snmp_engine_base) of
 696	{ok, EngineBase} ->
 697	    {ok, snmp_misc:now(sec) - EngineBase};
 698	Error ->
 699	    Error
 700    end.
 701
 702get_usm_eboots(SnmpEngineID) ->
 703    Key = {eboots, SnmpEngineID},
 704    case get_usm_cache(Key) of
 705	{ok, Boots} ->
 706	    {ok, Boots};
 707	_ ->
 708	    {ok, 0}
 709    end.
 710
 711get_usm_etime(SnmpEngineID) ->
 712    Key = {etime, SnmpEngineID},
 713    case get_usm_cache(Key) of
 714	{ok, Diff} ->
 715	    {ok, snmp_misc:now(sec) - Diff};
 716	_ ->
 717	    {ok, 0}
 718    end.
 719
 720get_usm_eltime(SnmpEngineID) ->
 721    Key = {eltime, SnmpEngineID},
 722    case get_usm_cache(Key) of
 723	{ok, Time} ->
 724	    {ok, Time};
 725	_ ->
 726	    {ok, 0}
 727    end.
 728
 729get_usm_cache(Key) ->
 730    case ets:lookup(snmpm_usm_table, {usm_cache, Key}) of
 731	[{_, Val}] ->
 732	    {ok, Val};
 733	_ ->
 734	    {error, not_found}
 735    end.
 736    
 737set_usm_eboots(SnmpEngineID, EngineBoots) ->
 738    set_usm_cache({eboots, SnmpEngineID}, EngineBoots).
 739
 740set_usm_etime(SnmpEngineID, Diff) ->
 741    set_usm_cache({etime, SnmpEngineID}, Diff).
 742
 743set_usm_eltime(SnmpEngineID, Time) ->
 744    set_usm_cache({eltime, SnmpEngineID}, Time).
 745
 746set_usm_cache(Key, Val) ->
 747    call({set_usm_cache, Key, Val}).
 748
 749reset_usm_cache(SnmpEngineID) ->
 750    case (whereis(?SERVER) =:= self()) of
 751	false ->
 752	    call({reset_usm_cache, SnmpEngineID});
 753	true ->
 754	    Pat = {{usm_cache, {'_', SnmpEngineID}}, '_'},
 755	    ets:match_delete(snmpm_usm_table, Pat),
 756	    ok
 757    end.
 758
 759set_engine_time(Time) ->
 760    call({set_engine_time, Time}).
 761
 762register_usm_user(EngineID, Name, Config) 
 763  when is_list(EngineID) andalso is_list(Name) ->
 764    case verify_usm_user_config(EngineID, Name, Config) of
 765	{ok, User} ->
 766	    call({register_usm_user, User});
 767	Error ->
 768	    Error
 769    end.
 770
 771unregister_usm_user(EngineID, Name) 
 772  when is_list(EngineID) andalso is_list(Name) ->
 773    call({unregister_usm_user, EngineID, Name}).
 774
 775verify_usm_user_config(EngineID, Name, Config) ->
 776    try
 777	begin
 778	    verify_mandatory(Config, []), 
 779	    verify_illegal(Config, [engine_id, name]),
 780	    verify_usm_user_config2(EngineID, Name, Config)
 781	end
 782    catch 
 783	throw:Error ->
 784	    Error
 785    end.
 786
 787verify_usm_user_config2(EngineID, Name, Config) ->
 788    SecName = verify_usm_user_get(sec_name, Name,              Config),
 789    Auth    = verify_usm_user_get(auth,     usmNoAuthProtocol, Config),
 790    AuthKey = verify_usm_user_get(auth_key, [],                Config),
 791    Priv    = verify_usm_user_get(priv,     usmNoPrivProtocol, Config),
 792    PrivKey = verify_usm_user_get(priv_key, [],                Config),
 793    User = {EngineID, Name, SecName, Auth, AuthKey, Priv, PrivKey},
 794    verify_usm_user(User).
 795	
 796verify_usm_user_get(Item, Default, Config) ->	
 797    case lists:keysearch(Item, 1, Config) of
 798	{value, {_, Val}} ->
 799	    Val;
 800	false ->
 801	    Default
 802    end.
 803
 804which_usm_users() ->
 805    Pattern = {usm_key('$1', '$2'), '_'},
 806    Match   = ets:match(snmpm_usm_table, Pattern),
 807    [{EngineID, UserName} || [EngineID, UserName] <- Match].
 808
 809which_usm_users(EngineID) ->
 810    Pattern = {usm_key(EngineID, '$1'), '_'},
 811    Match   = ets:match(snmpm_usm_table, Pattern),
 812    [UserName || [UserName] <- Match].
 813
 814usm_user_info(EngineID, UserName, Item) ->
 815    case ets:lookup(snmpm_usm_table, usm_key(EngineID, UserName)) of
 816	[] ->
 817	    {error, not_found};
 818	[{_Key, UsmUser}] ->
 819	    do_usm_user_info(UsmUser, Item)
 820    end.
 821
 822do_usm_user_info(#usm_user{sec_name = SecName}, sec_name) ->
 823    {ok, SecName};
 824do_usm_user_info(#usm_user{auth = AuthP}, auth) ->
 825    {ok, AuthP};
 826do_usm_user_info(#usm_user{auth_key = AuthKey}, auth_key) ->
 827    {ok, AuthKey};
 828do_usm_user_info(#usm_user{priv = PrivP}, priv) ->
 829    {ok, PrivP};
 830do_usm_user_info(#usm_user{priv_key = PrivKey}, priv_key) ->
 831    {ok, PrivKey};
 832do_usm_user_info(#usm_user{engine_id = EngineID}, engine_id) ->
 833    {ok, EngineID};
 834do_usm_user_info(#usm_user{name = Name}, name) ->
 835    {ok, Name};
 836do_usm_user_info(_, Item) ->
 837    {error, {bad_iten, Item}}.
 838
 839update_usm_user_info(EngineID, UserName, Item, Val) 
 840  when (Item =/= engine_id) andalso (Item =/= name) ->
 841    call({update_usm_user_info, EngineID, UserName, Item, Val}).
 842
 843get_usm_user(EngineID, UserName) ->
 844    Key = usm_key(EngineID, UserName),
 845    case ets:lookup(snmpm_usm_table, Key) of
 846	[{_, User}] ->
 847	    {ok, User};
 848	_ ->
 849	    {error, not_found}
 850    end.
 851
 852is_usm_engine_id_known(EngineID) ->
 853    Pattern = {usm_key(EngineID, '$1'), '_'},
 854    case ets:match(snmpm_usm_table, Pattern) of
 855	[] ->
 856	    false;
 857	_ ->
 858	    true
 859    end.
 860
 861get_usm_user_from_sec_name(EngineID, SecName) ->
 862    %% Since the normal mapping between UserName and SecName is the
 863    %% identity-function, we first try to use the SecName as UserName,
 864    %% and check the resulting row.  If it doesn't match, we'll have to
 865    %% loop through the entire table.
 866    Key = usm_key(EngineID, SecName),
 867    case ets:lookup(snmpm_usm_table, Key) of
 868	[{Key, #usm_user{sec_name = SecName} = User}] ->
 869	    {ok, User};
 870	_ ->
 871	    %% That did not work, so we have to search
 872	    Pattern = {usm_key(EngineID, '_'), 
 873		       #usm_user{sec_name = SecName, _ = '_'}},
 874	    case ets:match_object(snmpm_usm_table, Pattern) of
 875		[{_, User}|_] ->
 876		    {ok, User};
 877		_ ->
 878		    {error, not_found}
 879	    end
 880    end.
 881
 882
 883%% Wrap-counters (wrapping at 2147483647 or 4294967295)
 884cre_counter(Counter, Initial) ->
 885    case (whereis(?SERVER) =:= self()) of
 886	false ->
 887	    call({cre_counter, Counter, Initial});
 888	true ->
 889	    ets:insert(snmpm_counter_table, {Counter, Initial}),
 890	    Initial
 891    end.
 892
 893incr_counter(usm_salt, Incr) ->        % Backward compatibillity (upgrade)
 894    incr_counter(usm_des_salt, Incr);  % Backward compatibillity (upgrade)
 895incr_counter(usm_des_salt, Incr) ->
 896    incr_counter(usm_des_salt, Incr, 4294967295);
 897incr_counter(usm_aes_salt, Incr) ->
 898    incr_counter(usm_aes_salt, Incr, 36893488147419103231);
 899incr_counter(Counter, Incr) ->
 900    incr_counter(Counter, Incr, 2147483647).
 901
 902incr_counter(Counter, Incr, Wrap) ->
 903    case (catch ets:update_counter(snmpm_counter_table, Counter, Incr)) of
 904	{'EXIT', _} ->
 905	    cre_counter(Counter, Incr);
 906	NewVal when NewVal =< Wrap ->
 907	    NewVal;
 908	N ->
 909	    cre_counter(Counter, N - Wrap)
 910    end.
 911
 912
 913%% <ATL Sequence Number>
 914increment_counter(Counter, Initial, Max) ->
 915    Increment = 1, 
 916    increment_counter(Counter, Initial, Increment, Max).
 917
 918increment_counter(Counter, Initial, Increment, Max) ->
 919    %% This is to make sure no one else increments our counter
 920    Key = {Counter, self()},
 921
 922    %% Counter data
 923    Position  = 2,
 924    Threshold = Max,
 925    SetValue  = Initial,
 926    UpdateOp  = {Position, Increment, Threshold, SetValue},
 927
 928    %% And now for the actual increment
 929    Tab = snmpm_counter_table, 
 930    case (catch ets:update_counter(Tab, Key, UpdateOp)) of
 931        {'EXIT', {badarg, _}} ->
 932            %% Oups, first time
 933            ets:insert(Tab, {Key, Initial}),
 934            Initial;
 935        Next when is_integer(Next) ->
 936            Next
 937    end.
 938%% </ATL Sequence Number>
 939
 940
 941maybe_cre_stats_counter(Counter, Initial) ->
 942    case ets:lookup(snmpm_stats_table, Counter) of
 943	[_] ->
 944	    ok;
 945	_ ->
 946	    cre_stats_counter(Counter, Initial)
 947    end.
 948			      
 949cre_stats_counter(Counter, Initial) ->
 950    case (whereis(?SERVER) =:= self()) of
 951	false ->
 952	    call({cre_stats_counter, Counter, Initial});
 953	true ->
 954	    ets:insert(snmpm_stats_table, {Counter, Initial}),
 955	    Initial
 956    end.
 957
 958incr_stats_counter(Counter, Incr) ->
 959    case (catch ets:update_counter(snmpm_stats_table, Counter, Incr)) of
 960	{'EXIT', _} ->
 961	    cre_counter(Counter, Incr);
 962	NewVal ->
 963	    NewVal
 964    end.
 965
 966reset_stats_counter(Counter) ->
 967    case (whereis(?SERVER) =:= self()) of
 968	false ->
 969	    call({reset_stats_counter, Counter});
 970	true ->
 971	    ets:insert(snmpm_stats_table, {Counter, 0})
 972    end,
 973    ok.
 974    
 975get_stats_counter(Counter) ->
 976    case ets:lookup(snmpm_stats_table, Counter) of
 977	[{Counter, Value}] ->
 978	    {ok, Value};
 979	_ ->
 980	    {error, not_found}
 981    end.
 982    
 983get_stats_counters() ->
 984    ets:tab2list(snmpm_stats_table).
 985    
 986load_mib(Mib) when is_list(Mib) ->
 987    call({load_mib, Mib}).
 988
 989unload_mib(Mib) when is_list(Mib) ->
 990    call({unload_mib, Mib}).
 991
 992which_mibs() ->
 993    Pattern = {{mib, '_'}, '$1', '$2'},
 994    Mibs = ets:match(snmpm_mib_table, Pattern),
 995    [list_to_tuple(X) || X <- Mibs].
 996
 997name_to_oid(Name) ->
 998    Pat = {{mini_mib, '$1'}, Name, '_', '_'},
 999    case ets:match(snmpm_mib_table, Pat) of
1000	[] ->
1001	    {error, not_found};
1002	X ->
1003	    Oids = [Oid || [Oid] <- X],
1004	    {ok, Oids}
1005    end.
1006
1007oid_to_name(Oid) ->
1008    case ets:lookup(snmpm_mib_table, {mini_mib, Oid}) of
1009	[{_, Name, _, _}] ->
1010	    {ok, Name};
1011	[] ->
1012	    {error, not_found}
1013    end.
1014
1015oid_to_type(Oid) ->
1016    case ets:lookup(snmpm_mib_table, {mini_mib, Oid}) of
1017	[{_, _, Type, _}] ->
1018	    {ok, Type};
1019	[] ->
1020	    {error, not_found}
1021    end.
1022
1023make_mini_mib() ->
1024    Pat = {{mini_mib, '$1'}, '$2', '$3', '_'},
1025    MiniElems = ets:match(snmpm_mib_table, Pat),
1026    lists:keysort(1, [list_to_tuple(MiniElem) || MiniElem <- MiniElems]).
1027
1028
1029info() ->
1030    call(info).
1031
1032verbosity(Verbosity) ->
1033    case ?vvalidate(Verbosity) of
1034	Verbosity ->
1035	    call({verbosity, Verbosity});
1036	_ ->
1037	    {error, {invalid_verbosity, Verbosity}}
1038    end.
1039
1040
1041%%%-------------------------------------------------------------------
1042%%% Callback functions from gen_server
1043%%%-------------------------------------------------------------------
1044
1045%%--------------------------------------------------------------------
1046%% Func: init/1
1047%% Returns: {ok, State}          |
1048%%          {ok, State, Timeout} |
1049%%          ignore               |
1050%%          {stop, Reason}
1051%%--------------------------------------------------------------------
1052init([Opts]) ->
1053%     put(sname, mconf),
1054%     put(verbosity, trace),
1055    ?d("init -> entry with"
1056       "~n   Opts: ~p", [Opts]),
1057    case (catch do_init(Opts)) of
1058	ok ->
1059	    {ok, #state{}};
1060	{error, Reason} ->
1061	    error_msg("init error: ~p", [Reason]),
1062	    {stop, Reason};
1063	{'EXIT', Reason} ->
1064	    error_msg("init exit: ~p", [Reason]),
1065	    {stop, Reason};
1066	Error ->
1067	    error_msg("init failed: ~p", [Error]),
1068	    {stop, Error}
1069    end.
1070
1071do_init(Opts) ->
1072    process_flag(trap_exit, true),
1073    %% Mandatory = [versions, {config, [dir]}],
1074    Mandatory = [{config, [dir, db_dir]}],
1075    verify_options(Opts, Mandatory),
1076
1077    ets:new(snmpm_counter_table, [set, public,    named_table, {keypos, 1}]),
1078    ets:new(snmpm_stats_table,   [set, public,    named_table, {keypos, 1}]),
1079    ets:new(snmpm_mib_table,     [set, protected, named_table, {keypos, 1}]),
1080    ets:new(snmpm_config_table,  [set, protected, named_table, {keypos, 1}]),
1081    ets:new(snmpm_agent_table,   [set, protected, named_table, {keypos, 1}]),
1082    ets:new(snmpm_user_table,    [set, protected, named_table, {keypos, 2}]),
1083    ets:new(snmpm_usm_table,     [set, protected, named_table, {keypos, 1}]),
1084
1085    %% -- System start time --
1086    ets:insert(snmpm_config_table, {system_start_time, snmp_misc:now(cs)}),
1087    
1088    %% --- Own options (dir and db_dir mandatory) ---
1089    ConfOpts      = get_opt(config,        Opts,     []),
1090    ConfVerb      = get_opt(verbosity,     ConfOpts, silence),
1091    ConfDir       = get_opt(dir,           ConfOpts),
1092    ConfDbDir     = get_opt(db_dir,        ConfOpts),
1093    ConfDbInitErr = get_opt(db_init_error, ConfOpts, terminate),
1094    ConfRep       = get_opt(repair,        ConfOpts, true),
1095    ConfAs        = get_opt(auto_save,     ConfOpts, 5000),
1096    ets:insert(snmpm_config_table, {config_verbosity,     ConfVerb}),
1097    ets:insert(snmpm_config_table, {config_dir,           ConfDir}),
1098    ets:insert(snmpm_config_table, {config_db_dir,        ConfDbDir}),
1099    ets:insert(snmpm_config_table, {config_db_init_error, ConfDbInitErr}),
1100    ets:insert(snmpm_config_table, {config_repair,        ConfRep}),
1101    ets:insert(snmpm_config_table, {config_auto_save,     ConfAs}),
1102    put(sname, mconf),
1103    put(verbosity, ConfVerb),
1104    ?vlog("starting", []),
1105
1106    %% -- Create dets file used for storing persistent data --
1107    dets_open(ConfDbDir, ConfDbInitErr, ConfRep, ConfAs),
1108    
1109    %% -- Prio (optional) --
1110    Prio = get_opt(priority, Opts, normal),
1111    ets:insert(snmpm_config_table, {prio, Prio}),
1112    try process_flag(priority, Prio)
1113    catch
1114	error:badarg ->
1115	    error({invalid_priority,Prio})
1116    end,
1117
1118    %% -- Server (optional) --
1119    ServerOpts = get_opt(server,         Opts,      []),
1120    ServerVerb = get_opt(verbosity,      ServerOpts, silence),
1121    ServerGct  = get_opt(timeout,        ServerOpts, 30000),
1122    ServerMt   = get_opt(multi_threaded, ServerOpts, true),
1123    ets:insert(snmpm_config_table, {server_verbosity,      ServerVerb}),
1124    ets:insert(snmpm_config_table, {server_timeout,        ServerGct}),
1125    ets:insert(snmpm_config_table, {server_multi_threaded, ServerMt}),
1126   
1127    %% -- Mibs (optional) --
1128    ?vdebug("initiate mini mib", []),
1129    Mibs = get_opt(mibs, Opts, []),
1130    ets:insert(snmpm_config_table, {mibs, Mibs}),
1131    init_mini_mib(Mibs),
1132
1133    %% -- Net-if (optional) --
1134    ?vdebug("net_if options", []),
1135    NetIfIrb     = 
1136	case get_opt(inform_request_behaviour, Opts, ?IRB_DEFAULT) of
1137	    user ->
1138		{user, timer:seconds(15)};
1139	    Irb ->
1140		Irb
1141	end,
1142    NetIfOpts    = get_opt(net_if,                    Opts,      []),
1143    NetIfMod     = get_opt(module,                    NetIfOpts, snmpm_net_if),
1144    NetIfVerb    = get_opt(verbosity,                 NetIfOpts, silence),
1145    NetIfOptions = get_opt(options,                   NetIfOpts, []),
1146    ets:insert(snmpm_config_table, {net_if_module,    NetIfMod}),
1147    ets:insert(snmpm_config_table, {net_if_verbosity, NetIfVerb}),
1148    ets:insert(snmpm_config_table, {net_if_irb,       NetIfIrb}),
1149    ets:insert(snmpm_config_table, {net_if_options,   NetIfOptions}),
1150
1151    %% -- Versions (optional) --
1152    %% -- Versions (mandatory) ???????????? --
1153    ?vdebug("versions", []),
1154    Vsns = get_opt(versions, Opts, [v1, v2, v3]),
1155    ets:insert(snmpm_config_table, {versions, Vsns}),
1156
1157    %% -- Audit trail log (optional) --
1158    ?vdebug("audit trail log", []),
1159    case get_opt(audit_trail_log, Opts, []) of
1160	[] ->
1161	    ?vtrace("no ATL", []),
1162	    ets:insert(snmpm_config_table, {audit_trail_log, false});
1163	AuditTrailLogOpts ->
1164	    ?vtrace("ATL options: ~p", [AuditTrailLogOpts]),
1165	    ets:insert(snmpm_config_table, {audit_trail_log, true}),
1166	    LogDir   = get_atl_dir(AuditTrailLogOpts),
1167	    LogType  = get_atl_type(AuditTrailLogOpts),
1168	    LogSize  = get_atl_size(AuditTrailLogOpts),
1169	    LogRep   = get_atl_repair(AuditTrailLogOpts),
1170	    LogSeqNo = get_atl_seqno(AuditTrailLogOpts),
1171	    ets:insert(snmpm_config_table, {audit_trail_log_dir,    LogDir}),
1172	    ets:insert(snmpm_config_table, {audit_trail_log_type,   LogType}),
1173	    ets:insert(snmpm_config_table, {audit_trail_log_size,   LogSize}),
1174	    ets:insert(snmpm_config_table, {audit_trail_log_repair, LogRep}),
1175	    ets:insert(snmpm_config_table, {audit_trail_log_seqno,  LogSeqNo})
1176    end,
1177
1178    %% -- System default agent config --
1179    ?vdebug("system default agent config", []),
1180    init_agent_default(),
1181
1182    %% -- User (optional) --
1183    ?vdebug("default user", []),
1184    DefUserMod  = get_opt(def_user_mod,  Opts, ?USER_MOD_DEFAULT),
1185    DefUserData = get_opt(def_user_data, Opts, ?USER_DATA_DEFAULT),
1186    ets:insert(snmpm_config_table, {def_user_mod,  DefUserMod}),
1187    ets:insert(snmpm_config_table, {def_user_data, DefUserData}),
1188    
1189    {ok, SystemDefaultAgentConfig}       = agent_info(),
1190    DefUser = #user{id                   = ?DEFAULT_USER, 
1191		    mod                  = DefUserMod, 
1192		    data                 = DefUserData,
1193		    default_agent_config = SystemDefaultAgentConfig},
1194    ok = handle_register_user(DefUser),
1195    
1196    %% -- Note store --
1197    ?vdebug("note store", []),
1198    NoteStoreOpts    = get_opt(note_store, Opts, []),
1199    NoteStoreVerb    = get_opt(verbosity,  NoteStoreOpts, silence),
1200    NoteStoreTimeout = get_opt(timeout,    NoteStoreOpts, 30000),
1201    ets:insert(snmpm_config_table, {note_store_verbosity, NoteStoreVerb}),
1202    ets:insert(snmpm_config_table, {note_store_timeout,   NoteStoreTimeout}),
1203    
1204    %% -- Manager SNMP config --
1205    ?vdebug("manager snmp config", []),
1206    MgrConf = read_manager_config_file(ConfDir),
1207    init_manager_config(MgrConf),
1208
1209    %% -- User config --
1210    ?vdebug("users config", []),
1211    Users = read_users_config_file(ConfDir),
1212    init_users_config(Users),
1213
1214    %% -- Agents config --
1215    ?vdebug("agents config", []),
1216    Agents = read_agents_config_file(ConfDir),
1217    init_agents_config(Agents),
1218
1219    %% -- USM config --
1220    UsmUsers = read_usm_config_file(ConfDir),
1221    init_usm_users_config(UsmUsers),
1222
1223    %% -- snmp engine init --
1224    init_engine(),
1225
1226    ?vlog("started", []),
1227    ok.
1228
1229
1230dets_open(Dir, DbInitError, Repair, AutoSave) ->
1231    Name     = ?CONFIG_DB, 
1232    Filename = dets_filename(Name, Dir),
1233    case file:read_file_info(Filename) of
1234	{ok, _} ->
1235	    %% File exists
1236	    case do_dets_open(Name, Filename, Repair, AutoSave) of
1237		{ok, _Dets} ->
1238		    ok;
1239		{error, Reason1} ->
1240                    info_msg("Corrupt local database: ~p", [Filename]),
1241		    case DbInitError of
1242			terminate ->
1243			    error({failed_reopen_dets, Filename, Reason1});
1244			_ ->
1245			    Saved = Filename ++ ".saved",
1246			    file:rename(Filename, Saved),
1247			    case do_dets_open(Name, Filename, 
1248					      Repair, AutoSave) of
1249				{ok, _Dets} ->
1250				    ok;
1251				{error, Reason2} ->
1252				    error({failed_open_dets, Filename, 
1253					   Reason1, Reason2})
1254			    end
1255		    end
1256	    end;
1257	_ ->
1258	    case DbInitError of
1259		create_db_and_dir ->
1260		    ok = filelib:ensure_dir(Filename);
1261		_ ->
1262		    ok
1263	    end,
1264	    case do_dets_open(Name, Filename, Repair, AutoSave) of
1265		{ok, _Dets} ->
1266		    ok;
1267		{error, Reason} ->
1268		    error({failed_open_dets, Filename, Reason})
1269	    end
1270    end.
1271		
1272do_dets_open(Name, Filename, Repair, AutoSave) ->
1273    Opts = [{repair,    Repair}, 
1274	    {auto_save, AutoSave}, 
1275	    {file,      Filename}],
1276    dets:open_file(Name, Opts).
1277
1278
1279dets_filename(Name, Dir) when is_atom(Name) ->
1280    dets_filename(atom_to_list(Name), Dir);
1281dets_filename(Name, Dir) ->
1282    filename:join(dets_filename1(Dir), Name).
1283
1284dets_filename1([])  -> ".";
1285dets_filename1(Dir) -> Dir.
1286
1287
1288%% ------------------------------------------------------------------------
1289
1290init_engine() ->
1291    case get_engine_boots() of
1292	{ok, Val} when Val < 2147483647 ->
1293	    set_engine_boots(Val + 1);
1294	{ok, _} ->
1295	    ok;
1296	_ ->
1297	    set_engine_boots(1)
1298    end,
1299    reset_engine_base().
1300
1301reset_engine_base() ->
1302    ets:insert(snmpm_config_table, {snmp_engine_base, snmp_misc:now(sec)}).
1303
1304
1305%% ------------------------------------------------------------------------
1306
1307verify_options(Opts, Mandatory) ->
1308    ?d("verify_options -> entry with"
1309       "~n   Opts:      ~p"
1310       "~n   Mandatory: ~p", [Opts, Mandatory]),
1311    verify_mandatory_options(Opts, Mandatory),
1312    verify_options(Opts).
1313
1314verify_options([]) ->
1315    ?d("verify_options -> done", []),
1316    ok;
1317verify_options([Opt|Opts]) ->
1318    ?d("verify_options -> entry with"
1319       "~n   Opt: ~p", [Opt]),
1320    verify_option(Opt),
1321    verify_options(Opts).
1322
1323verify_option({prio, Prio}) ->
1324    verify_prio(Prio);
1325verify_option({mibs, Mibs}) ->
1326    verify_mibs(Mibs);
1327verify_option({inform_request_behaviour, IRB}) ->
1328    verify_irb(IRB);
1329verify_option({net_if, NetIfOpts}) ->
1330    verify_net_if_opts(NetIfOpts);
1331verify_option({server, ServerOpts}) ->
1332    verify_server_opts(ServerOpts);
1333verify_option({note_store, NoteStoreOpts}) ->
1334    verify_note_store_opts(NoteStoreOpts);
1335verify_option({config, ConfOpts0}) ->
1336    %% Make sure any db_dir option is first in the options list to make it
1337    %% easier to check if the db_init_error option specifies that a missing
1338    %% db_dir should be created.
1339    ConfOpts = case lists:keytake(db_dir, 1, ConfOpts0) of
1340                   false -> ConfOpts0;
1341                   {value, Result, OtherOpts} -> [Result|OtherOpts]
1342               end,
1343    verify_config_opts(ConfOpts);
1344verify_option({versions, Vsns}) ->
1345    verify_versions(Vsns);
1346verify_option({audit_trail_log, LogOpts}) ->
1347    Mandatory = [dir, size],
1348    case (catch verify_mandatory_options(LogOpts, Mandatory)) of
1349	ok ->
1350	    verify_audit_trail_log_opts(LogOpts);
1351	{error, {missing_mandatory, LogOpt}} ->
1352	    error({missing_mandatory, audit_trail_log, LogOpt})
1353    end;
1354verify_option({def_user_mod, Mod}) ->
1355    verify_module(def_user_mod, Mod);
1356verify_option({def_user_data, _Data}) ->
1357    ok;
1358verify_option(Opt) ->
1359    {error, {invalid_option, Opt}}.
1360
1361verify_prio(Prio) when is_atom(Prio) ->
1362    ok;
1363verify_prio(Prio) ->
1364    error({invalid_prio, Prio}).
1365
1366verify_irb(auto) ->
1367    ok;
1368verify_irb(user) ->
1369    ok;
1370verify_irb({user, To}) when is_integer(To) andalso (To > 0) ->
1371    ok;
1372verify_irb(IRB) ->
1373    error({invalid_irb, IRB}).
1374
1375verify_mibs([]) ->
1376    ok;
1377verify_mibs([Mib|Mibs]) when is_list(Mib) ->
1378    verify_mibs(Mibs);
1379verify_mibs(Mibs) ->
1380    error({invalid_mibs, Mibs}).
1381
1382verify_config_opts([]) ->
1383    ok;
1384verify_config_opts([{verbosity, Verbosity}|Opts]) ->
1385    verify_verbosity(Verbosity),
1386    verify_config_opts(Opts);
1387verify_config_opts([{dir, Dir}|Opts]) ->
1388    verify_conf_dir(Dir),
1389    verify_config_opts(Opts);
1390verify_config_opts([{db_dir, Dir}|Opts]) ->
1391    case lists:keyfind(db_init_error, 1, Opts) of
1392        {db_init_error, create_db_and_dir} ->
1393            verify_conf_db_dir(Dir, false);
1394        _ ->
1395            verify_conf_db_dir(Dir, true)
1396    end,
1397    verify_config_opts(Opts);
1398verify_config_opts([{db_init_error, DbInitErr}|Opts]) ->
1399    verify_conf_db_init_error(DbInitErr),
1400    verify_config_opts(Opts);
1401verify_config_opts([{repair, Repair}|Opts]) ->
1402    verify_conf_repair(Repair),
1403    verify_config_opts(Opts);
1404verify_config_opts([{auto_save, AutoSave}|Opts]) ->
1405    verify_conf_auto_save(AutoSave),
1406    verify_config_opts(Opts);
1407verify_config_opts([Opt|_]) ->
1408    error({invalid_config_option, Opt}).
1409
1410verify_server_opts([]) ->
1411    ok;
1412verify_server_opts([{verbosity, Verbosity}|Opts]) ->
1413    verify_verbosity(Verbosity),
1414    verify_server_opts(Opts);
1415verify_server_opts([{timeout, Timeout}|Opts]) ->
1416    verify_server_timeout(Timeout),
1417    verify_server_opts(Opts);
1418verify_server_opts([Opt|_]) ->
1419    error({invalid_server_option, Opt}).
1420
1421verify_server_timeout(T) when is_integer(T) andalso (T > 0) ->
1422    ok;
1423verify_server_timeout(T) ->
1424    error({invalid_server_timeout, T}).
1425
1426verify_net_if_opts([]) ->
1427    ok;
1428verify_net_if_opts([{module, Mod}|Opts]) ->
1429    verify_network_interface_behaviour(Mod),
1430    verify_net_if_opts(Opts);
1431verify_net_if_opts([{verbosity, Verbosity}|Opts]) ->
1432    verify_verbosity(Verbosity),
1433    verify_net_if_opts(Opts);
1434verify_net_if_opts([{options, Options}|Opts]) when is_list(Options) ->
1435    verify_net_if_opts(Opts);
1436verify_net_if_opts([Opt|_]) ->
1437    error({invalid_net_if_option, Opt}).
1438
1439verify_network_interface_behaviour(Mod) ->
1440    case snmp_misc:verify_behaviour(snmpm_network_interface, Mod) of
1441	ok ->
1442	    ok;
1443	Error ->
1444	    throw(Error)
1445    end.
1446    
1447    
1448verify_note_store_opts([]) ->
1449    ok;
1450verify_note_store_opts([{verbosity, Verbosity}|Opts]) ->
1451    verify_verbosity(Verbosity),
1452    verify_note_store_opts(Opts);
1453verify_note_store_opts([{timeout, Timeout}|Opts]) ->
1454    verify_note_store_timeout(Timeout),
1455    verify_note_store_opts(Opts);
1456verify_note_store_opts([Opt|_]) ->
1457    error({invalid_note_store_option, Opt}).
1458
1459verify_note_store_timeout(T) when is_integer(T) andalso (T > 0) ->
1460    ok;
1461verify_note_store_timeout(T) ->
1462    error({invalid_note_store_timeout, T}).
1463
1464verify_conf_dir(Dir) ->
1465    case (catch verify_dir(Dir)) of
1466	ok ->
1467	    ok;
1468	{error, Reason} ->
1469	    error({invalid_conf_dir, Dir, Reason});
1470	_ ->
1471	    error({invalid_conf_dir, Dir})
1472    end.
1473
1474verify_conf_db_dir(Dir, true) ->
1475    case (catch verify_dir(Dir)) of
1476	ok ->
1477	    ok;
1478	{error, Reason} ->
1479	    error({invalid_conf_db_dir, Dir, Reason});
1480	_ ->
1481	    error({invalid_conf_db_dir, Dir})
1482    end;
1483verify_conf_db_dir(_Dir, false) ->
1484    ok.
1485
1486verify_conf_db_init_error(terminate) ->
1487    ok;
1488verify_conf_db_init_error(create) ->
1489    ok;
1490verify_conf_db_init_error(create_db_and_dir) ->
1491    ok;
1492verify_conf_db_init_error(InvalidDbInitError) ->
1493    error({invalid_conf_db_init_error, InvalidDbInitError}).
1494
1495
1496verify_conf_repair(true) ->
1497    ok;
1498verify_conf_repair(false) ->
1499    ok;
1500verify_conf_repair(force) ->
1501    ok;
1502verify_conf_repair(InvalidRepair) ->
1503    error({invalid_conf_db_repair, InvalidRepair}).
1504
1505
1506verify_conf_auto_save(infinity) ->
1507    ok;
1508verify_conf_auto_save(AutoSave) 
1509  when is_integer(AutoSave) andalso (AutoSave > 0) ->
1510    ok;
1511verify_conf_auto_save(InvalidAutoSave) ->
1512    error({invalid_conf_db_auto_save, InvalidAutoSave}).
1513
1514
1515verify_versions([]) ->
1516    ok;
1517verify_versions([Vsn|Vsns]) ->
1518    verify_version(Vsn),
1519    verify_versions(Vsns);
1520verify_versions(Vsns) ->
1521    error({invalid_versions, Vsns}).
1522
1523verify_version(v1) ->
1524    ok;
1525verify_version(v2) ->
1526    ok;
1527verify_version(v3) ->
1528    ok;
1529verify_version(Vsn) ->
1530    error({invalid_version, Vsn}).
1531
1532verify_audit_trail_log_opts([]) ->
1533    ok;
1534verify_audit_trail_log_opts([{dir, Dir}|Opts]) ->
1535    verify_log_dir(Dir),
1536    verify_audit_trail_log_opts(Opts);
1537verify_audit_trail_log_opts([{type, Type}|Opts]) ->
1538    verify_log_type(Type),
1539    verify_audit_trail_log_opts(Opts);
1540verify_audit_trail_log_opts([{size, Size}|Opts]) ->
1541    verify_log_size(Size),
1542    verify_audit_trail_log_opts(Opts);
1543verify_audit_trail_log_opts([{repair, Repair}|Opts]) ->
1544    verify_log_repair(Repair),
1545    verify_audit_trail_log_opts(Opts);
1546verify_audit_trail_log_opts([{seqno, SeqNo}|Opts]) ->
1547    verify_log_seqno(SeqNo),
1548    verify_audit_trail_log_opts(Opts);
1549verify_audit_trail_log_opts([Opt|_Opts]) ->
1550    error({invalid_audit_trail_log_option, Opt}).
1551
1552verify_log_type(read) ->
1553    ok;
1554verify_log_type(write) ->
1555    ok;
1556verify_log_type(read_write) ->
1557    ok;
1558verify_log_type(Type) ->
1559    error({invalid_audit_trail_log_type, Type}).
1560
1561verify_log_dir(Dir) ->
1562    case (catch verify_dir(Dir)) of
1563	ok ->
1564	    ok;
1565	{error, Reason} ->
1566	    error({invalid_audit_trail_log_dir, Dir, Reason});
1567	_ ->
1568	    error({invalid_audit_trail_log_dir, Dir})
1569    end.
1570
1571verify_log_size(Sz) when is_integer(Sz) andalso (Sz > 0) ->
1572    ok;
1573verify_log_size(infinity) ->
1574    ok;
1575verify_log_size({MaxNoBytes, MaxNoFiles}) 
1576  when (is_integer(MaxNoBytes) andalso 
1577	(MaxNoBytes > 0) andalso 
1578	is_integer(MaxNoFiles) andalso 
1579	(MaxNoFiles > 0) andalso 
1580	(MaxNoFiles < 65000)) ->
1581    ok;
1582verify_log_size(Sz) ->
1583    error({invalid_audit_trail_log_size, Sz}).
1584
1585verify_log_repair(true) -> ok;
1586verify_log_repair(false) -> ok;
1587verify_log_repair(truncate) -> ok;
1588verify_log_repair(Repair) ->
1589    error({invalid_audit_trail_log_repair, Repair}).
1590
1591verify_log_seqno(true) -> ok;
1592verify_log_seqno(false) -> ok;
1593verify_log_seqno(SeqNo) ->
1594    error({invalid_audit_trail_log_seqno, SeqNo}).
1595
1596
1597verify_module(_, Mod) when is_atom(Mod) ->
1598    ok;
1599verify_module(ReasonTag, Mod) ->
1600    error({invalid_module, ReasonTag, Mod}).
1601
1602% verify_bool(_, true) ->
1603%     ok;
1604% verify_bool(_, false) ->
1605%     ok;
1606% verify_bool(ReasonTag, Bool) ->
1607%     error({invalid_bool, ReasonTag, Bool}).
1608
1609verify_dir(Dir) when is_list(Dir) ->
1610    case file:read_file_info(Dir) of
1611	{ok, #file_info{type = directory}} ->
1612	    ok;
1613	{ok, _} ->
1614	    {error, not_directory};
1615	{error, _Reason} ->
1616	    {error, not_found}
1617    end;
1618verify_dir(Dir) ->
1619    {error, {invalid_log_dir, Dir}}.
1620
1621
1622verify_verbosity(Verbosity) ->
1623    case snmp_verbosity:validate(Verbosity) of
1624	Verbosity ->
1625	    ok;
1626	_ ->
1627	    error({invalid_verbosity, Verbosity})
1628    end.
1629
1630    
1631%% mandatory() -> [mand()]
1632%% mand() -> atom() | {atom, [atom()]}
1633verify_mandatory_options(_Opts, []) ->
1634    ok;
1635verify_mandatory_options(Opts, [Mand|Mands]) ->
1636    verify_mandatory_option(Opts, Mand),
1637    verify_mandatory_options(Opts, Mands).
1638
1639verify_mandatory_option(Opts, {Mand, MandSubOpts}) ->
1640    ?d("verify_mandatory_option -> entry with"
1641       "~n   Mand:        ~p"
1642       "~n   MandSubObjs: ~p", [Mand, MandSubOpts]),
1643    case lists:keysearch(Mand, 1, Opts) of
1644	{value, {Mand, SubOpts}} ->
1645	    verify_mandatory_options(SubOpts, MandSubOpts);
1646	false ->
1647	    ?d("missing mandatory option: ~w [~p]", [Mand, MandSubOpts]),
1648	    error({missing_mandatory, Mand, MandSubOpts})
1649    end;
1650verify_mandatory_option(Opts, Mand) ->
1651    ?d("verify_mandatory_option -> entry with"
1652       "~n   Mand:        ~p", [Mand]),
1653    case lists:keymember(Mand, 1, Opts) of
1654	true ->
1655	    ok;
1656	false ->
1657	    ?d("missing mandatory option: ~w", [Mand]),
1658	    error({missing_mandatory, Mand})
1659    end.
1660
1661%% ------------------------------------------------------------------------
1662
1663init_manager_config([]) ->
1664    ok;
1665init_manager_config([{Key, Val}|Confs]) ->
1666    ets:insert(snmpm_config_table, {Key, Val}),
1667    init_manager_config(Confs).
1668
1669
1670
1671init_agent_default() ->
1672    %% The purpose of the default_agent is only to have a place
1673    %% to store system wide default values related to agents.
1674    %% 
1675    AgentDefaultConfig =
1676	[{port, ?DEFAULT_AGENT_PORT}, % Port
1677	 {timeout, 10000},            % Timeout
1678	 {max_message_size, 484},     % Max message (packet) size
1679	 {version, v2},               % MPModel
1680	 {sec_model, v2c},            % SecModel
1681	 {sec_name, "initial"},       % SecName
1682	 {sec_level, noAuthNoPriv},   % SecLevel
1683	 {community, "all-rights"}],  % Community
1684    do_update_agent_info(default_agent, AgentDefaultConfig).
1685
1686read_agents_config_file(Dir) ->
1687    Order = fun snmp_conf:no_order/2,
1688    Check = fun check_agent_config/2,
1689    try read_file(Dir, "agents.conf", Order, Check, [])
1690    catch
1691	throw:Error ->
1692	    ?vlog("agent config error: ~p", [Error]),
1693	    erlang:raise(throw, Error, erlang:get_stacktrace())
1694    end.
1695
1696check_agent_config(Agent, State) ->
1697    {ok, {UserId, TargetName, Conf, Version}} = check_agent_config(Agent),
1698    {ok, Vsns} = system_info(versions),
1699    case lists:member(Version, Vsns) of
1700	true ->
1701	    {{ok, {UserId, TargetName, Conf}}, State};
1702	false ->
1703	    error({version_not_supported_by_manager, Version, Vsns})
1704    end.
1705
1706%% For backward compatibility
1707check_agent_config(
1708  {UserId, TargetName, Community, Domain, Addr,
1709   EngineId, Timeout, MaxMessageSize,
1710   Version, SecModel, SecName, SecLevel}) when is_atom(Domain) ->
1711    check_agent_config(
1712      UserId, TargetName, Community, Domain, Addr,
1713      EngineId, Timeout, MaxMessageSize,
1714      Version, SecModel, SecName, SecLevel);
1715check_agent_config(
1716  {UserId, TargetName, Community, Ip, Port,
1717   EngineId, Timeout, MaxMessageSize,
1718   Version, SecModel, SecName, SecLevel}) when is_integer(Port) ->
1719    Domain = default_transport_domain(),
1720    Addr = {Ip, Port},
1721    check_agent_config(
1722      UserId, TargetName, Community, Domain, Addr,
1723      EngineId, Timeout, MaxMessageSize,
1724      Version, SecModel, SecName, SecLevel);
1725check_agent_config(
1726  {_UserId, _TargetName, _Community, Domain, Addr,
1727   _EngineId, _Timeout, _MaxMessageSize,
1728   _Version, _SecModel, _SecName, _SecLevel}) ->
1729    error({bad_address, {Domain, Addr}});
1730check_agent_config(
1731  {UserId, TargetName, Community, Domain, Ip, Port,
1732   EngineId, Timeout, MaxMessageSize,
1733   Version, SecModel, SecName, SecLevel}) ->
1734    Addr = {Ip, Port},
1735    check_agent_config(
1736      UserId, TargetName, Community, Domain, Addr,
1737      EngineId, Timeout, MaxMessageSize,
1738      Version, SecModel, SecName, SecLevel);
1739check_agent_config(Agent) ->
1740    error({bad_agent_config, Agent}).
1741
1742check_agent_config(
1743  UserId, TargetName, Comm, Domain, Addr,
1744  EngineId, Timeout, MMS,
1745  Version, SecModel, SecName, SecLevel) ->
1746    ?vdebug("check_agent_config -> entry with"
1747	    "~n   UserId:     ~p"
1748	    "~n   TargetName: ~p", [UserId, TargetName]),
1749    snmp_conf:check_string(TargetName, {gt, 0}),
1750    %% Note that the order of Conf *is* important.
1751    %% Some properties may depend on others, so that
1752    %% in order to verify one property, another must
1753    %% be already verified (and present). An example 
1754    %% of this is the property 'taddress', for which
1755    %% the property tdomain is needed.
1756    Conf =
1757	[{reg_type,         target_name},
1758	 {tdomain,        

Large files files are truncated, but you can click here to view the full file