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