diff options
Diffstat (limited to 'lib')
43 files changed, 1531 insertions, 510 deletions
diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile index 906c513fad..9e9cb18524 100644 --- a/lib/asn1/c_src/Makefile +++ b/lib/asn1/c_src/Makefile @@ -124,7 +124,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/priv/lib - $(INSTALL_DATA) $(SHARED_OBJ_FILES) $(RELSYSDIR)/priv/lib + $(INSTALL_PROGRAM) $(SHARED_OBJ_FILES) $(RELSYSDIR)/priv/lib $(INSTALL_DIR) $(RELSYSDIR)/c_src $(INSTALL_DATA) $(C_FILES) $(RELSYSDIR)/c_src diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index d01e1f1fcf..1d170790a3 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -270,7 +270,10 @@ make_del_dir(Config) when is_list(Config) -> %% Try deleting some bad directories %% Deleting the parent directory to the current, sounds dangerous, huh? %% Don't worry ;-) the parent directory should never be empty, right? - ?line {error, eexist} = ?FILE_MODULE:del_dir('..'), + case ?FILE_MODULE:del_dir('..') of + {error, eexist} -> ok; + {error, einval} -> ok %FreeBSD + end, ?line {error, enoent} = ?FILE_MODULE:del_dir(""), ?line {error, badarg} = ?FILE_MODULE:del_dir([3,2,1,{}]), diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 860aeecbf4..6badbb5090 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(prim_file_SUITE). @@ -243,7 +243,10 @@ make_del_dir(Config, Handle, Suffix) -> %% Try deleting some bad directories %% Deleting the parent directory to the current, sounds dangerous, huh? %% Don't worry ;-) the parent directory should never be empty, right? - ?line {error, eexist} = ?PRIM_FILE_call(del_dir, Handle, [".."]), + case ?PRIM_FILE_call(del_dir, Handle, [".."]) of + {error, eexist} -> ok; + {error, einval} -> ok %FreeBSD + end, ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in index 6ce9b34617..5af651d89b 100644 --- a/lib/megaco/src/flex/Makefile.in +++ b/lib/megaco/src/flex/Makefile.in @@ -280,7 +280,7 @@ release_spec: opt $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin ifeq ($(ENABLE_MEGACO_FLEX_SCANNER),true) $(INSTALL_DATA) $(FLEX_FILES) $(C_TARGETS) $(RELSYSDIR)/src/flex - $(INSTALL_DATA) $(SOLIBS) $(RELSYSDIR)/priv/lib + $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib endif diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml index 4c4b11d3c4..e528af2522 100644 --- a/lib/sasl/doc/src/notes.xml +++ b/lib/sasl/doc/src/notes.xml @@ -30,6 +30,33 @@ </header> <p>This document describes the changes made to the SASL application.</p> +<section><title>SASL 2.1.9.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>In R13B04 sys:get_status was modified to invoke + format_status/2 in the callback module if the module + exports that function. This resulted in a change to the + term returned from calling sys:get_status on the + supervisor module, since supervisor is a gen_server and + gen_server exports format_status. The sasl + release_handler_1 module had a dependency on the + pre-R13B04 term returned by sys:get_status when invoked + on a supervisor, so the R13B04 change broke that + dependency.</p> + <p>This problem has been fixed by change + release_handler_1 to handle both the pre-R13B04 and + R13B04 terms that sys:get_status can return from a + supervisor.</p> + <p> + Own Id: OTP-8619 Aux Id: seq11570 </p> + </item> + </list> + </section> + +</section> + <section><title>SASL 2.1.9.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl index e3e3caba99..9c0edf4e99 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(release_handler_1). @@ -554,7 +554,13 @@ get_supervisor_module(SupPid) -> get_supervisor_module1(SupPid) -> {status, _Pid, {module, _Mod}, [_PDict, _SysState, _Parent, _Dbg, Misc]} = sys:get_status(SupPid), - [_Name, State, _Type, _Time] = Misc, + %% supervisor Misc field changed at R13B04, handle old and new variants here + State = case Misc of + [_Name, State1, _Type, _Time] -> + State1; + [_Header, _Data, {data, [{"State", State2}]}] -> + State2 + end, %% Cannot use #supervisor_state{module = Module} = State. {ok, element(#supervisor_state.module, State)}. diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk index cad33a5d9c..d01a9bc4f1 100644 --- a/lib/sasl/vsn.mk +++ b/lib/sasl/vsn.mk @@ -1 +1 @@ -SASL_VSN = 2.1.9.1 +SASL_VSN = 2.1.9.2 diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 33e304abfa..eb7c9db6ba 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -33,6 +33,68 @@ </header> <section> + <title>SNMP Development Toolkit 4.16.2</title> + <p>Version 4.16.2 supports code replacement in runtime from/to + version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[compiler] The SMI specifies that a table row OID should be + named: { <tableIdentifier> "1" }. </p> + <p>A new option has been introduced, + <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>, + that allows for a more liberal numbering scheme</p> + <p>Own Id: OTP-8574</p> + </item> + + <item> + <p>[agent|manager] Changes to make snmp (forward) compatible with + the new version of the crypto application (released in R14). + As of R14, crypto is implemented using NIFs. Also, + the API is more strict. </p> + <p>Own Id: OTP-8594</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>Encode/decode of Counter64 values larger than + 16#7fffffffffffffff (9223372036854775807) failed. </p> + <p>Own Id: OTP-8563</p> + </item> + + <item> + <p>[compiler] Fails to compile non-contiguous BITS. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-8595</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16.2 --> + + + <section> <title>SNMP Development Toolkit 4.16.1</title> <p>Version 4.16.1 supports code replacement in runtime from/to version 4.16, 4.15, 4.14 and 4.13.5.</p> diff --git a/lib/snmp/doc/src/snmpc.xml b/lib/snmp/doc/src/snmpc.xml index 48d63d6c91..fbd0950c69 100644 --- a/lib/snmp/doc/src/snmpc.xml +++ b/lib/snmp/doc/src/snmpc.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2009</year> + <year>2004</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -13,12 +13,12 @@ compliance with the License. You should have received a copy of the Erlang Public License along with this software. If not, it can be retrieved online at http://www.erlang.org/. - + Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. - + </legalnotice> <title>snmpc</title> @@ -47,9 +47,10 @@ <type> <v>File = string()</v> <v>Options = [opt()]</v> - <v>opt() = db() | deprecated() | description() | reference() | group_check() | i() | il() | imports() | module() | module_identity() | outdir() | no_defs() | verbosity() | warnings()</v> + <v>opt() = db() | relaxed_row_name_assign_check() | deprecated() | description() | reference() | group_check() | i() | il() | imports() | module() | module_identity() | outdir() | no_defs() | verbosity() | warnings()</v> <v>db() = {db, volatile|persistent|mnesia}</v> <v>deprecated() = {deprecated, bool()}</v> + <v>relaxed_row_name_assign_check() = relaxed_row_name_assign_check</v> <v>description() = description</v> <v>reference() = reference</v> <v>group_check() = {group_check, bool()}</v> @@ -71,75 +72,104 @@ compiled file <c>BinFileName</c> is called <c><![CDATA[<File>.bin]]></c>. </p> <list type="bulleted"> - <item>The option <c>db</c> specifies which database should - be used for the default instrumentation. Default is - <c>volatile</c>. + <item> + <p>The option <c>db</c> specifies which database should + be used for the default instrumentation. </p> + <p>Default is <c>volatile</c>. </p> + </item> + <item> + <p>The option <c>deprecated</c> specifies if a deprecated + definition should be kept or not. If the option is + false the MIB compiler will ignore all deprecated + definitions. </p> + <p>Default is <c>true</c>. </p> </item> - <item>The option <c>deprecated</c> specifies if a deprecated - definition should be kept or not. If the option is - false the MIB compiler will ignore all deprecated - definitions. Default is <c>true</c>. + <item> + <p>The option <c>relaxed_row_name_assign_check</c>, if present, + specifies that the row name assign check shall not be done + strictly according to the SMI (which allows only the value 1). + With this option, all values greater than zero is allowed + (>= 1). This means that the error will be converted to a + warning. </p> + <p>By default it is not included, but if this option is present + it will be. </p> </item> - <item>The option <c>description</c> specifies if the text - of the DESCRIPTION field will be included or not. By default - it is not included, but if this option is present it will - be. + <item> + <p>The option <c>description</c> specifies if the text + of the DESCRIPTION field will be included or not. </p> + <p>By default it is not included, but if this option is + present it will be. </p> </item> - <item>The option <c>reference</c> specifies if the text - of the REFERENCE field, when found in a table definition, - will be included or not. By default - it is not included, but if this option is present it will - be. The reference text will be placed in the allocList field - of the mib-entry record (#me{}) for the table. + <item> + <p>The option <c>reference</c> specifies if the text + of the REFERENCE field, when found in a table definition, + will be included or not. </p> + <p>By default it is not included, but if this option is present + it will be. The reference text will be placed in the allocList + field of the mib-entry record (#me{}) for the table. </p> </item> - <item>The option <c>group_check</c> specifies whether the - mib compiler should check the OBJECT-GROUP macro and - the NOTIFICATION-GROUP macro for correctness or not. - Default is <c>true</c>. + <item> + <p>The option <c>group_check</c> specifies whether the + mib compiler should check the OBJECT-GROUP macro and + the NOTIFICATION-GROUP macro for correctness or not. </p> + <p>Default is <c>true</c>. </p> </item> - <item>The option <c>i</c> specifies the path to search for - imported (compiled) MIB files. The directories should be - strings with a trailing directory delimiter. Default is - <c>["./"]</c>. + <item> + <p>The option <c>i</c> specifies the path to search for + imported (compiled) MIB files. The directories should be + strings with a trailing directory delimiter. </p> + <p>Default is <c>["./"]</c>. </p> </item> - <item>The option <c>il</c> (include_lib) also specifies a - list of directories to search for imported MIBs. It - assumes that the first element in the directory name - corresponds to an OTP application. The compiler will find - the current installed version. For example, the value - ["snmp/mibs/"] will be replaced by ["snmp-3.1.1/mibs/"] - (or what the current version may be in the system). The - current directory and the <c><![CDATA[<snmp-home>/priv/mibs/]]></c> - are always listed last in the include path. + <item> + <p>The option <c>il</c> (include_lib) also specifies a + list of directories to search for imported MIBs. It + assumes that the first element in the directory name + corresponds to an OTP application. The compiler will find + the current installed version. For example, the value + ["snmp/mibs/"] will be replaced by ["snmp-3.1.1/mibs/"] + (or what the current version may be in the system). The + current directory and the + <c><![CDATA[<snmp-home>/priv/mibs/]]></c> + are always listed last in the include path. </p> </item> - <item>The option <c>imports</c>, if present, specifies that the - IMPORT statement of the MIB shall be included in the compiled mib. + <item> + <p>The option <c>imports</c>, if present, specifies that + the IMPORT statement of the MIB shall be included in the + compiled mib. </p> </item> - <item>The option <c>module</c>, if present, specifies the - name of a module which implements all instrumentation - functions for the MIB. The name of all instrumentation - functions must be the same as the corresponding managed - object it implements. + <item> + <p>The option <c>module</c>, if present, specifies the + name of a module which implements all instrumentation + functions for the MIB. </p> + <p>The name of all instrumentation + functions must be the same as the corresponding managed + object it implements. </p> </item> - <item>The option <c>module_identity</c>, if present, specifies - that the info part of the MODULE-IDENTITY statement of the MIB - shall be included in the compiled mib. + <item> + <p>The option <c>module_identity</c>, if present, specifies + that the info part of the MODULE-IDENTITY statement of the MIB + shall be included in the compiled mib. </p> </item> - <item>The option <c>no_defs</c>, if present, specifies - that if a managed object does not have an instrumentation - function, the default instrumentation function should NOT - be used, instead this is reported as an error, and the - compilation aborts. + <item> + <p>The option <c>no_defs</c>, if present, specifies + that if a managed object does not have an instrumentation + function, the default instrumentation function should NOT + be used, instead this is reported as an error, and the + compilation aborts. </p> </item> - <item>The option <c>verbosity</c> specifies the verbosity of - the SNMP mib compiler. I.e. if warning, info, log, debug - and trace messages shall be shown. Default is <c>silence</c>. - Note that if the option <c>warnings</c> is <c>true</c> and the - option <c>verbosity</c> is <c>silence</c>, warning messages will - still be shown. + <item> + <p>The option <c>verbosity</c> specifies the verbosity of + the SNMP mib compiler. I.e. if warning, info, log, debug + and trace messages shall be shown. </p> + <p>Default is <c>silence</c>. </p> + <p>Note that if the option <c>warnings</c> is <c>true</c> and the + option <c>verbosity</c> is <c>silence</c>, warning messages will + still be shown. </p> </item> - <item>The option <c>warnings</c> specifies whether warning - messages should be shown. Default is <c>true</c>. + <item> + <p>The option <c>warnings</c> specifies whether warning + messages should be shown. </p> + <p>Default is <c>true</c>. </p> </item> </list> <p>The MIB compiler understands both SMIv1 and SMIv2 MIBs. It diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl index 12a6b996ff..b94294844b 100644 --- a/lib/snmp/src/agent/snmpa_usm.erl +++ b/lib/snmp/src/agent/snmpa_usm.erl @@ -560,11 +560,15 @@ encrypt(Data, PrivProtocol, PrivKey, SecLevel) -> ?vtrace("encrypt -> 3.1.4a",[]), case (catch try_encrypt(PrivProtocol, PrivKey, Data)) of {ok, ScopedPduData, MsgPrivParams} -> - ?vtrace("encrypt -> encode tag",[]), + ?vtrace("encrypt -> encrypted - now encode tag",[]), {snmp_pdus:enc_oct_str_tag(ScopedPduData), MsgPrivParams}; {error, Reason} -> + ?vtrace("encrypt -> error: " + "~n Reason: ~p", [Reason]), error(Reason); - _Error -> + Error -> + ?vtrace("encrypt -> other: " + "~n Error: ~p", [Error]), error(encryptionError) end end. diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 204de71c2e..aa3410fea3 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -22,14 +22,25 @@ %% ----- U p g r a d e ------------------------------------------------------- [ + {"4.16.1", + [ + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, + {load_module, snmp_pdus, soft_purge, soft_purge, []} + ] + }, {"4.16", [ + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa_general_db, soft_purge, soft_purge, []}, {update, snmpm_net_if, soft, soft_purge, soft_purge, []} ] }, {"4.15", [ + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, {load_module, snmp_config, soft_purge, soft_purge, []}, {load_module, snmp_log, soft_purge, soft_purge, []}, @@ -39,12 +50,15 @@ {update, snmpa_net_if, {advanced, upgrade_from_pre_4_16}, soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, {update, snmpm_config, soft, soft_purge, soft_purge, []} ] }, {"4.14", [ + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, {load_module, snmp_config, soft_purge, soft_purge, []}, {load_module, snmp_log, soft_purge, soft_purge, []}, @@ -52,6 +66,8 @@ {update, snmpa_net_if, {advanced, upgrade_from_pre_4_16}, soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, {load_module, snmpm_user, soft_purge, soft_purge, []}, {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, @@ -64,6 +80,7 @@ }, {"4.13.5", [ + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa_mib_data, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, {load_module, snmp_config, soft_purge, soft_purge, []}, @@ -72,6 +89,8 @@ {update, snmpa_net_if, {advanced, upgrade_from_pre_4_16}, soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, {load_module, snmpm_user, soft_purge, soft_purge, []}, {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, @@ -88,14 +107,25 @@ %% ------D o w n g r a d e --------------------------------------------------- [ + {"4.16.1", + [ + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, + {load_module, snmp_pdus, soft_purge, soft_purge, []} + ] + }, {"4.16", [ + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa_general_db, soft_purge, soft_purge, []}, {update, snmpm_net_if, soft, soft_purge, soft_purge, []} ] }, {"4.15", [ + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, {load_module, snmp_config, soft_purge, soft_purge, []}, {load_module, snmp_log, soft_purge, soft_purge, []}, @@ -103,6 +133,8 @@ {update, snmpa_net_if, {advanced, downgrade_to_pre_4_16}, soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, {load_module, snmpa_general_db, soft_purge, soft_purge, []}, {update, snmpm_net_if, {advanced, downgrade_to_pre_4_16}, @@ -112,6 +144,7 @@ }, {"4.14", [ + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, {load_module, snmp_config, soft_purge, soft_purge, []}, {load_module, snmp_log, soft_purge, soft_purge, []}, @@ -119,6 +152,8 @@ {update, snmpa_net_if, {advanced, downgrade_to_pre_4_16}, soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, {load_module, snmpm_user, soft_purge, soft_purge, []}, {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, @@ -131,6 +166,7 @@ }, {"4.13.5", [ + {load_module, snmp_pdus, soft_purge, soft_purge, []}, {load_module, snmpa_mib_data, soft_purge, soft_purge, []}, {load_module, snmp_config, soft_purge, soft_purge, []}, {load_module, snmpa, soft_purge, soft_purge, [snmp_log]}, @@ -139,6 +175,8 @@ {update, snmpa_net_if, {advanced, downgrade_to_pre_4_16}, soft_purge, soft_purge, [snmpa_agent, snmp_log]}, {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmpa_usm, soft_purge, soft_purge, [snmp_usm]}, + {load_module, snmp_usm, soft_purge, soft_purge, []}, {load_module, snmpm_user, soft_purge, soft_purge, []}, {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]}, diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl index 8a1f15d4a4..a7f2cdc2bc 100644 --- a/lib/snmp/src/compile/snmpc.erl +++ b/lib/snmp/src/compile/snmpc.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(snmpc). @@ -34,6 +34,7 @@ -include("snmpc.hrl"). -include("snmpc_lib.hrl"). +-record(dldata, {deprecated, relaxed_row_name_assign_check}). look_at(Mib) -> io:format("~p ~n", [snmpc_lib:look_at(Mib)]). @@ -114,6 +115,7 @@ compile(FileName) -> %% module_identity %% {module, string()} %% no_defs +%% relaxed_row_name_assign_check %% (hidden) {verbosity, trace|debug|log|info|silence} silence %% (hidden) version %% (hidden) options @@ -201,6 +203,8 @@ get_options([imports|Opts], Formats, Args) -> get_options(Opts, ["~n imports"|Formats], Args); get_options([module_identity|Opts], Formats, Args) -> get_options(Opts, ["~n module_identity"|Formats], Args); +get_options([relaxed_row_name_assign_check|Opts], Formats, Args) -> + get_options(Opts, ["~n relaxed_row_name_assign_check"|Formats], Args); get_options([_|Opts], Formats, Args) -> get_options(Opts, Formats, Args). @@ -284,6 +288,8 @@ check_options([imports| T]) -> check_options(T); check_options([module_identity| T]) -> check_options(T); +check_options([relaxed_row_name_assign_check| T]) -> + check_options(T); check_options([{module, M} | T]) when is_atom(M) -> check_options(T); check_options([no_defs| T]) -> @@ -309,6 +315,9 @@ get_description(Options) -> get_reference(Options) -> get_bool_option(reference, Options). +get_relaxed_row_name_assign_check(Options) -> + lists:member(relaxed_row_name_assign_check, Options). + get_bool_option(Option, Options) -> case lists:member(Option, Options) of false -> @@ -406,8 +415,12 @@ compile_parsed_data(#pdata{mib_name = MibName, defs = Definitions}) -> snmpc_lib:import(Imports), update_imports(Imports), - Deprecated = get_deprecated(get(options)), - definitions_loop(Definitions, Deprecated), + Opts = get(options), + Deprecated = get_deprecated(Opts), + RelChk = get_relaxed_row_name_assign_check(Opts), + Data = #dldata{deprecated = Deprecated, + relaxed_row_name_assign_check = RelChk}, + definitions_loop(Definitions, Data), MibName. update_imports(Imports) -> @@ -436,21 +449,21 @@ update_status(Name, Status) -> %% A deprecated object definitions_loop([{#mc_object_type{name = ObjName, status = deprecated}, Line}|T], - false) -> + #dldata{deprecated = false} = Data) -> %% May be implemented but the compiler chooses not to. ?vinfo2("object_type ~w is deprecated => ignored", [ObjName], Line), update_status(ObjName, deprecated), - definitions_loop(T, false); + definitions_loop(T, Data); %% A obsolete object definitions_loop([{#mc_object_type{name = ObjName, status = obsolete}, Line}|T], - Deprecated) -> + Data) -> ?vlog2("object_type ~w is obsolete => ignored", [ObjName], Line), %% No need to implement a obsolete object update_status(ObjName, obsolete), ensure_macro_imported('OBJECT-TYPE', Line), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); %% Defining a table definitions_loop([{#mc_object_type{name = NameOfTable, @@ -475,7 +488,7 @@ definitions_loop([{#mc_object_type{name = NameOfTable, {#mc_sequence{name = SeqName, fields = FieldList}, Sline}|ColsEtc], - Deprecated) -> + Data) -> ?vlog("defloop -> " "[object_type(sequence_of),object_type(type,[1]),sequence]:" "~n NameOfTable: ~p" @@ -529,7 +542,89 @@ definitions_loop([{#mc_object_type{name = NameOfTable, TableME#me{assocList=[{table_info, TableInfo} | make_reference(Ref)]} | ColMEs]), - definitions_loop(RestObjs, Deprecated); + definitions_loop(RestObjs, Data); + +definitions_loop([{#mc_object_type{name = NameOfTable, + syntax = {{sequence_of, SeqName}, _}, + max_access = Taccess, + kind = Kind, + status = Tstatus, + description = Desc1, + units = Tunits, + reference = Ref, + name_assign = Tindex}, + Tline}, + {#mc_object_type{name = NameOfEntry, + syntax = {{type, SeqName}, TEline}, + max_access = 'not-accessible', + kind = {table_entry, IndexingInfo}, + status = Estatus, + description = Desc2, + units = Eunits, + name_assign = {NameOfTable,[Idx]} = BadOID}, + Eline}, + {#mc_sequence{name = SeqName, + fields = FieldList}, + Sline}|ColsEtc], + #dldata{relaxed_row_name_assign_check = true} = Data) + when is_integer(Idx) andalso (Idx > 1) -> + ?vlog("defloop -> " + "[object_type(sequence_of),object_type(type,[~w]),sequence]:" + "~n NameOfTable: ~p" + "~n SeqName: ~p" + "~n Taccess: ~p" + "~n Kind: ~p" + "~n Tstatus: ~p" + "~n Tindex: ~p" + "~n Tunits: ~p" + "~n Tline: ~p" + "~n NameOfEntry: ~p" + "~n TEline: ~p" + "~n IndexingInfo: ~p" + "~n Estatus: ~p" + "~n Eunits: ~p" + "~n Ref: ~p" + "~n Eline: ~p" + "~n FieldList: ~p" + "~n Sline: ~p", + [Idx, + NameOfTable,SeqName,Taccess,Kind,Tstatus, + Tindex,Tunits,Tline, + NameOfEntry,TEline,IndexingInfo,Estatus,Eunits,Ref,Eline, + FieldList,Sline]), + update_status(NameOfTable, Tstatus), + update_status(NameOfEntry, Estatus), + update_status(SeqName, undefined), + ensure_macro_imported('OBJECT-TYPE', Tline), + ?vwarning2("Bad TableEntry OID definition (~w)", + [BadOID], Eline), + test_table(NameOfTable,Taccess,Kind,Tindex,Tline), + {Tfather,Tsubindex} = Tindex, + snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex), + Description1 = make_description(Desc1), + TableME = #me{aliasname = NameOfTable, + entrytype = table, + access = 'not-accessible', + description = Description1, + units = Tunits}, + snmpc_lib:register_oid(TEline,NameOfEntry,NameOfTable,[Idx]), + Description2 = make_description(Desc2), + TableEntryME = #me{aliasname = NameOfEntry, + entrytype = table_entry, + assocList = [{table_entry_with_sequence, SeqName}], + access = 'not-accessible', + description = Description2, + units = Eunits}, + {ColMEs, RestObjs} = + define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []), + TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable, + IndexingInfo, ColMEs), + snmpc_lib:add_cdata(#cdata.mes, + [TableEntryME, + TableME#me{assocList=[{table_info, + TableInfo} | make_reference(Ref)]} | + ColMEs]), + definitions_loop(RestObjs, Data); definitions_loop([{#mc_object_type{name = NameOfTable, syntax = {{sequence_of, SeqName},_}, @@ -550,7 +645,7 @@ definitions_loop([{#mc_object_type{name = NameOfTable, name_assign = BadOID}, Eline}, {#mc_sequence{name = SeqName, fields = FieldList}, Sline}|ColsEtc], - Deprecated) -> + Data) -> ?vlog("defloop -> " "[object_type(sequence_of),object_type(type),sequence(fieldList)]:" "~n NameOfTable: ~p" @@ -605,13 +700,13 @@ definitions_loop([{#mc_object_type{name = NameOfTable, TableME#me{assocList=[{table_info, TableInfo} | make_reference(Ref)]} | ColMEs]), - definitions_loop(RestObjs, Deprecated); + definitions_loop(RestObjs, Data); definitions_loop([{#mc_new_type{name = NewTypeName, macro = Macro, syntax = OldType, display_hint = DisplayHint},Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> new_type:" "~n Macro: ~p" "~n NewTypeName: ~p" @@ -632,7 +727,7 @@ definitions_loop([{#mc_new_type{name = NewTypeName, imported = false, display_hint = DisplayHint}]) end, - definitions_loop(T, Deprecated); + definitions_loop(T, Data); %% Plain variable definitions_loop([{#mc_object_type{name = NewVarName, @@ -643,7 +738,7 @@ definitions_loop([{#mc_object_type{name = NewVarName, description = Desc1, units = Units, name_assign = {Parent,SubIndex}},Line} |T], - Deprecated) -> + Data) -> ?vlog2("defloop -> object_type (variable):" "~n NewVarName: ~p" "~n Type: ~p" @@ -672,7 +767,7 @@ definitions_loop([{#mc_object_type{name = NewVarName, VI = snmpc_lib:make_variable_info(NewME2), snmpc_lib:add_cdata(#cdata.mes, [NewME2#me{assocList = [{variable_info, VI}]}]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_module_identity{name = NewVarName, last_updated = LU, @@ -682,7 +777,7 @@ definitions_loop([{#mc_module_identity{name = NewVarName, revisions = Revs0, name_assign = {Parent, SubIndex}}, Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> module-identity: " "~n NewVarName: ~p" "~n LU: ~p" @@ -706,13 +801,13 @@ definitions_loop([{#mc_module_identity{name = NewVarName, snmpc_lib:add_cdata( #cdata.mes, [snmpc_lib:makeInternalNode2(false, NewVarName)]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_internal{name = NewVarName, macro = Macro, parent = Parent, sub_index = SubIndex},Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> internal:" "~n NewVarName: ~p" "~n Macro: ~p" @@ -724,7 +819,7 @@ definitions_loop([{#mc_internal{name = NewVarName, snmpc_lib:add_cdata( #cdata.mes, [snmpc_lib:makeInternalNode2(false, NewVarName)]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); %% A trap message definitions_loop([{#mc_trap{name = TrapName, @@ -732,7 +827,7 @@ definitions_loop([{#mc_trap{name = TrapName, vars = Variables, description = Desc1, num = SpecificCode}, Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> trap:" "~n TrapName: ~p" "~n EnterPrise: ~p" @@ -755,7 +850,7 @@ definitions_loop([{#mc_trap{name = TrapName, lists:foreach(fun(Trap2) -> snmpc_lib:check_trap(Trap2, Trap, Line) end, CDATA#cdata.traps), snmpc_lib:add_cdata(#cdata.traps, [Trap]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_object_type{name = NameOfEntry, syntax = Type, @@ -763,7 +858,7 @@ definitions_loop([{#mc_object_type{name = NameOfEntry, kind = {table_entry, Index}, status = Estatus, name_assign = SubIndex},Eline}|T], - Deprecated) -> + Data) -> ?vlog("defloop -> object_type (table_entry):" "~n NameOfEntry: ~p" "~n Type: ~p" @@ -777,7 +872,7 @@ definitions_loop([{#mc_object_type{name = NameOfEntry, update_status(NameOfEntry, Estatus), snmpc_lib:print_error("Misplaced TableEntry definition (~w)", [NameOfEntry], Eline), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_notification{name = TrapName, status = deprecated}, Line}|T], @@ -790,19 +885,19 @@ definitions_loop([{#mc_notification{name = TrapName, definitions_loop([{#mc_notification{name = TrapName, status = obsolete}, Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> notification ~w is obsolete => ignored", [TrapName], Line), update_status(TrapName, obsolete), ensure_macro_imported('NOTIFICATION-TYPE', Line), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_notification{name = TrapName, vars = Variables, status = Status, description = Desc, name_assign = {Parent, SubIndex}},Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> notification:" "~n TrapName: ~p" "~n Variables: ~p" @@ -824,13 +919,13 @@ definitions_loop([{#mc_notification{name = TrapName, oidobjects = Variables}, snmpc_lib:check_notification(Notif, Line, CDATA#cdata.traps), snmpc_lib:add_cdata(#cdata.traps, [Notif]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); -definitions_loop([{#mc_module_compliance{name = Name},Line}|T], Deprecated) -> +definitions_loop([{#mc_module_compliance{name = Name},Line}|T], Data) -> ?vlog2("defloop -> module_compliance:" "~n Name: ~p", [Name], Line), ensure_macro_imported('MODULE-COMPLIANCE', Line), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_object_group{name = Name, objects = GroupObjects, @@ -838,7 +933,7 @@ definitions_loop([{#mc_object_group{name = Name, description = Desc, reference = Ref, name_assign = {Parent,SubIndex}}, Line}|T], - Deprecated) -> + Data) -> ?vlog2("defloop -> object_group ~p:" "~n GroupObjects: ~p" "~n Status: ~p" @@ -873,7 +968,7 @@ definitions_loop([{#mc_object_group{name = Name, {objects, GroupObjects}]}, snmpc_lib:add_cdata(#cdata.mes, [NewME]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_notification_group{name = Name, objects = GroupObjects, @@ -882,7 +977,7 @@ definitions_loop([{#mc_notification_group{name = Name, reference = Ref, name_assign = {Parent,SubIndex}}, Line} - |T], Deprecated) -> + |T], Data) -> ?vlog2("defloop -> notification_group ~p:" "~n GroupObjects: ~p" "~n Status: ~p" @@ -918,13 +1013,13 @@ definitions_loop([{#mc_notification_group{name = Name, {objects, GroupObjects}]}, snmpc_lib:add_cdata(#cdata.mes, [NewME]), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_object_type{name = NameOfTable, syntax = {{sequence_of, SeqName},_}, status = Tstatus},Tline}, Entry, Seq|T], - Deprecated) -> + Data) -> ?vlog("defloop -> object_type (sequence_of): " "~n NameOfTable: ~p" "~n SeqName: ~p" @@ -956,12 +1051,12 @@ definitions_loop([{#mc_object_type{name = NameOfTable, "Invalid TableEntry '~p' (check STATUS, Sequence name, Oid)", [safe_elem(1,safe_elem(2,Entry))],Tline) end, - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_object_type{name = NameOfTable, syntax = {{sequence_of, SeqName},_}, status = Tstatus},Tline}|T], - Deprecated) -> + Data) -> ?vlog("defloop -> object_type (sequence_of):" "~n object_type: ~p" "~n sequence_of: ~p" @@ -969,24 +1064,24 @@ definitions_loop([{#mc_object_type{name = NameOfTable, update_status(NameOfTable, Tstatus), snmpc_lib:print_error("Invalid statements following table ~p.", [NameOfTable],Tline), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); definitions_loop([{#mc_sequence{name = SeqName, fields = _FieldList},Line}|T], - Deprecated) -> + Data) -> ?vwarning2("Unexpected SEQUENCE ~w => ignoring", [SeqName], Line), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); -definitions_loop([{Obj,Line}|T], Deprecated) -> +definitions_loop([{Obj,Line}|T], Data) -> ?vinfo2("defloop -> unknown error" "~n Obj: ~p", [Obj], Line), snmpc_lib:print_error("Unknown Error in MIB. " "Can't describe the error better than this: ~999p ignored." " Please send a trouble report to [email protected].", [Obj], Line), - definitions_loop(T, Deprecated); + definitions_loop(T, Data); -definitions_loop([], _Deprecated) -> +definitions_loop([], _Data) -> ?vlog("defloop -> done", []), ok. diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl index b7e84e7d6b..4e5bc69f81 100644 --- a/lib/snmp/src/compile/snmpc_lib.erl +++ b/lib/snmp/src/compile/snmpc_lib.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -125,7 +125,8 @@ test_kibbles(Kibbles,Line) -> test_kibbles2([],_,_) -> ok; -test_kibbles2([{_KibbleName,BitNo}|Ks],BitNo,Line) -> +test_kibbles2([{_KibbleName,BitNo}|Ks],ExpectBitNo,Line) + when BitNo >= ExpectBitNo -> test_kibbles2(Ks,BitNo+1,Line); test_kibbles2([{_KibbleName,BitNo}|_Ks],ExpectBitNo,Line) -> print_error("Expected kibble no ~p but got ~p.",[ExpectBitNo,BitNo],Line). diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl index 6c80fc3876..dc8900c8cd 100644 --- a/lib/snmp/src/misc/snmp_pdus.erl +++ b/lib/snmp/src/misc/snmp_pdus.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -38,7 +38,10 @@ dec_usm_security_parameters/1, strip_encrypted_scoped_pdu_data/1, octet_str_to_bits/1, bits_to_str/1, - get_encoded_length/1]). + get_encoded_length/1, + enc_value/2, dec_value/1]). + +%% -compile(export_all). %% Returns the number of octets required to encode Length. get_encoded_length(Length) -> @@ -290,12 +293,18 @@ dec_value([68 | Bytes]) -> {Value, Rest} = dec_oct_str_notag(Bytes), {{'Opaque', Value}, Rest}; dec_value([70 | Bytes]) -> + %% Counter64 is an unsigned 64 but is actually encoded as + %% a signed integer 64. {Value, Rest} = dec_integer_notag(Bytes), - if Value >= 0, Value =< 18446744073709551615 -> - {{'Counter64', Value}, Rest}; - true -> - exit({error, {bad_counter64, Value}}) - end; + Value2 = + if + (Value >= 0) andalso (Value < 16#8000000000000000) -> + Value; + (Value < 0) -> + 18446744073709551615 + Value + 1; + true -> + exit({error, {bad_counter64, Value}}) end, + {{'Counter64', Value2}, Rest}; dec_value([128,0|T]) -> {{'NULL', noSuchObject}, T}; dec_value([129,0|T]) -> @@ -633,6 +642,21 @@ enc_value(_Type, endOfMibView) -> [130,0]; enc_value('NULL', _Val) -> [5,0]; +enc_value('Counter64', Val) -> + Val2 = + if + Val > 16#ffffffffffffffff -> + exit({error, {bad_counter64, Val}}); + Val >= 16#8000000000000000 -> + (Val band 16#7fffffffffffffff) - 16#8000000000000000; + Val >= 0 -> + Val; + true -> + exit({error, {bad_counter64, Val}}) + end, + Bytes2 = enc_integer_notag(Val2), + Len2 = elength(length(Bytes2)), + lists:append([70 | Len2],Bytes2); enc_value(Type, Val) -> Bytes2 = enc_integer_notag(Val), Len2 = elength(length(Bytes2)), @@ -643,10 +667,7 @@ enc_val_tag('Counter32',Val) when (Val >= 0) andalso (Val =< 4294967295) -> enc_val_tag('Unsigned32', Val) when (Val >= 0) andalso (Val =< 4294967295) -> 66; enc_val_tag('TimeTicks', Val) when (Val >= 0) andalso (Val =< 4294967295) -> - 67; -enc_val_tag('Counter64', Val) when ((Val >= 0) andalso - (Val =< 18446744073709551615)) -> - 70. + 67. %%---------------------------------------------------------------------- diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl index 19be564a8e..3508f9e1c2 100644 --- a/lib/snmp/src/misc/snmp_usm.erl +++ b/lib/snmp/src/misc/snmp_usm.erl @@ -198,7 +198,7 @@ des_encrypt(PrivKey, Data, SaltFun) -> [A,B,C,D,E,F,G,H | PreIV] = PrivKey, DesKey = [A,B,C,D,E,F,G,H], Salt = SaltFun(), - IV = snmp_misc:str_xor(PreIV, Salt), + IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)), TailLen = (8 - (length(Data) rem 8)) rem 8, Tail = mk_tail(TailLen), EncData = crypto:des_cbc_encrypt(DesKey, IV, [Data,Tail]), @@ -213,13 +213,13 @@ des_decrypt(PrivKey, MsgPrivParams, EncData) [A,B,C,D,E,F,G,H | PreIV] = PrivKey, DesKey = [A,B,C,D,E,F,G,H], Salt = MsgPrivParams, - IV = snmp_misc:str_xor(PreIV, Salt), + IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)), %% Whatabout errors here??? E.g. not a mulitple of 8! Data = binary_to_list(crypto:des_cbc_decrypt(DesKey, IV, EncData)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), {ok, Data2}; des_decrypt(PrivKey, BadMsgPrivParams, EncData) -> - ?vtrace("des_decrypt -> entry with when bad MsgPrivParams" + ?vtrace("des_decrypt -> entry when bad MsgPrivParams" "~n PrivKey: ~p" "~n BadMsgPrivParams: ~p" "~n EncData: ~p", @@ -232,7 +232,7 @@ aes_encrypt(PrivKey, Data, SaltFun) -> Salt = SaltFun(), EngineBoots = snmp_framework_mib:get_engine_boots(), EngineTime = snmp_framework_mib:get_engine_time(), - IV = [?i32(EngineBoots), ?i32(EngineTime) | Salt], + IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]), EncData = crypto:aes_cfb_128_encrypt(AesKey, IV, Data), {ok, binary_to_list(EncData), Salt}. @@ -240,7 +240,7 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime) when length(MsgPrivParams) =:= 8 -> AesKey = PrivKey, Salt = MsgPrivParams, - IV = [?i32(EngineBoots), ?i32(EngineTime) | Salt], + IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]), %% Whatabout errors here??? E.g. not a mulitple of 8! Data = binary_to_list(crypto:aes_cfb_128_decrypt(AesKey, IV, EncData)), Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data), diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk index ff848cad1b..6a0c3e9481 100644 --- a/lib/snmp/test/modules.mk +++ b/lib/snmp/test/modules.mk @@ -1,20 +1,20 @@ #-*-makefile-*- ; force emacs to enter makefile-mode # %CopyrightBegin% -# -# Copyright Ericsson AB 2004-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 2004-2010. All Rights Reserved. +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% SUITE_MODULES = \ @@ -57,6 +57,10 @@ MODULES = \ HRL_FILES = snmp_test_lib.hrl +# These are MIBs that aure used by the compiler test-suite. +COMPILER_MIB_FILES = \ + OTP8574-MIB + MIB_FILES = \ OLD-SNMPEA-MIB.mib \ OLD-SNMPEA-MIB-v2.mib \ diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl index 9a9127a130..ad77b01362 100644 --- a/lib/snmp/test/snmp_compiler_test.erl +++ b/lib/snmp/test/snmp_compiler_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -46,7 +46,9 @@ module_identity/1, tickets/1, - otp_6150/1 + otp_6150/1, + otp_8574/1, + otp_8595/1 ]). @@ -56,6 +58,7 @@ -export([ ]). + %%---------------------------------------------------------------------- %% Macros %%---------------------------------------------------------------------- @@ -98,7 +101,9 @@ all(suite) -> tickets(suite) -> [ - otp_6150 + otp_6150, + otp_8574, + otp_8595 ]. @@ -178,6 +183,54 @@ otp_6150(Config) when is_list(Config) -> ok. +otp_8574(suite) -> + []; +otp_8574(Config) when is_list(Config) -> + put(tname,otp_8574), + p("starting with Config: ~p~n", [Config]), + + Dir = ?config(comp_dir, Config), + MibDir = ?config(mib_dir, Config), + MibFile = join(MibDir, "OTP8574-MIB.mib"), + + p("ensure compile fail without relaxed assign check"), + case snmpc:compile(MibFile, [{group_check, false}, {outdir, Dir}]) of + {error, compilation_failed} -> + p("with relaxed assign check MIB compiles with warning"), + case snmpc:compile(MibFile, [{group_check, false}, + {outdir, Dir}, + relaxed_row_name_assign_check]) of + {ok, _Mib} -> + ok; + {error, Reason} -> + p("unexpected compile failure: " + "~n Reason: ~p", [Reason]), + exit({unexpected_compile_failure, Reason}) + end; + + {ok, _} -> + p("unexpected compile success"), + exit(unexpected_compile_success) + end. + + +otp_8595(suite) -> + []; +otp_8595(Config) when is_list(Config) -> + put(tname,otp_8595), + p("starting with Config: ~p~n", [Config]), + + Dir = ?config(comp_dir, Config), + MibDir = ?config(mib_dir, Config), + MibFile = join(MibDir, "OTP8595-MIB.mib"), + ?line {ok, Mib} = + snmpc:compile(MibFile, [{outdir, Dir}, + {verbosity, trace}, + {group_check, false}]), + io:format("otp_8595 -> Mib: ~n~p~n", [Mib]), + ok. + + %%====================================================================== %% Internal functions %%====================================================================== @@ -373,6 +426,9 @@ join(A,B) -> %% p(F) -> %% p(F, []). +p(F) -> + p(F, []). + p(F, A) -> p(get(tname), F, A). diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index fcb3d7e30c..d5dc1387f7 100644 --- a/lib/snmp/test/snmp_manager_config_test.erl +++ b/lib/snmp/test/snmp_manager_config_test.erl @@ -1444,10 +1444,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> p("[test 54] write usm config file with invalid auth-key (4)"), Usm54 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"), write_usm_conf(ConfDir, [Usm54]), - %% ?line ok = crypto:start(), %% Varf�r k�r den redan? - ?line crypto:start(), %% Make sure it's started... + ?line maybe_start_crypto(), %% Make sure it's started... ?line {error, Reason54} = config_start(Opts), - ?line ok = crypto:stop(), + ?line ok = maybe_stop_crypto(), p("start failed (as expected): ~p", [Reason54]), ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason54, await_config_not_running(), @@ -1492,21 +1491,35 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> p("[test 59] write usm config file with invalid auth-key (9)"), Usm59 = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,ka]"), write_usm_conf(ConfDir, [Usm59]), - ?line ok = crypto:start(), + ?line ok = maybe_start_crypto(), ?line {error, Reason59} = config_start(Opts), - ?line ok = crypto:stop(), + ?line ok = maybe_stop_crypto(), p("start failed (as expected): ~p", [Reason59]), ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason59, await_config_not_running(), %% -- - p("[test 5A] write usm config file with valid auth-key when crypto not started (10)"), - Usm5A = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]"), - write_usm_conf(ConfDir, [Usm5A]), - ?line {error, Reason5A} = config_start(Opts), - p("start failed (as expected): ~p", [Reason5A]), - ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason5A, - await_config_not_running(), + %% <CRYPTO-MODIFICATIONS> + %% The crypto application do no longer need to be started + %% explicitly (all of it is as of R14 implemented with NIFs). + case (catch crypto:version()) of + {'EXIT', {undef, _}} -> + p("[test 5A] write usm config file with valid auth-key " + "when crypto not started (10)"), + Usm5A = setelement(4, + Usm57, + "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]"), + write_usm_conf(ConfDir, [Usm5A]), + ?line {error, Reason5A} = config_start(Opts), + p("start failed (as expected): ~p", [Reason5A]), + ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason5A, + await_config_not_running(); + _ -> + %% This function is only present in version 2.0 or greater. + %% The crypto app no longer needs to be explicitly started + ok + end, + %% </CRYPTO-MODIFICATIONS> %% -- p("[test 61] write usm config file with invalid priv-protocol (1)"), @@ -1566,9 +1579,9 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> p("[test 74] write usm config file with invalid priv-key (4)"), Usm74 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"), write_usm_conf(ConfDir, [Usm74]), - ?line ok = crypto:start(), + ?line ok = maybe_start_crypto(), ?line {error, Reason74} = config_start(Opts), - ?line ok = crypto:stop(), + ?line ok = maybe_stop_crypto(), p("start failed (as expected): ~p", [Reason74]), ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason74, await_config_not_running(), @@ -1592,15 +1605,27 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) -> await_config_not_running(), %% -- - p("[test 77] write usm config file with valid priv-key when crypto not started (7)"), - Usm77 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"), - write_usm_conf(ConfDir, [Usm77]), - ?line {error, Reason77} = config_start(Opts), - p("start failed (as expected): ~p", [Reason77]), - ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason77, - await_config_not_running(), + %% <CRYPTO-MODIFICATIONS> + %% The crypto application do no longer need to be started + %% explicitly (all of it is as of R14 implemented with NIFs). + case (catch crypto:version()) of + {'EXIT', {undef, _}} -> + p("[test 77] write usm config file with valid priv-key " + "when crypto not started (7)"), + Usm77 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"), + write_usm_conf(ConfDir, [Usm77]), + ?line {error, Reason77} = config_start(Opts), + p("start failed (as expected): ~p", [Reason77]), + ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason77, + await_config_not_running(); + _ -> + %% This function is only present in version 2.0 or greater. + %% The crypto app no longer needs to be explicitly started + ok + end, + %% </CRYPTO-MODIFICATIONS> - %% -- + %% -- p("[test 78] write usm config file with invalid usm (1)"), write_usm_conf2(ConfDir, "{\"bmkEngine\", \"swiusmcf\"}."), ?line {error, Reason81} = config_start(Opts), @@ -2676,6 +2701,27 @@ write_conf_file(Dir, File, Str) -> file:close(Fd). +maybe_start_crypto() -> + case (catch crypto:version()) of + {'EXIT', {undef, _}} -> + %% This is the version of crypto before the NIFs... + ?CRYPTO_START(); + _ -> + %% No need to start this version of crypto.. + ok + end. + +maybe_stop_crypto() -> + case (catch crypto:version()) of + {'EXIT', {undef, _}} -> + %% This is the version of crypto before the NIFs... + crypto:stop(); + _ -> + %% There is nothing to stop in this version of crypto.. + ok + end. + + %% ------ str(X) -> diff --git a/lib/snmp/test/snmp_pdus_test.erl b/lib/snmp/test/snmp_pdus_test.erl index d5add50f52..6dc5b779aa 100644 --- a/lib/snmp/test/snmp_pdus_test.erl +++ b/lib/snmp/test/snmp_pdus_test.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -37,6 +37,7 @@ all/1, tickets/1, otp7575/1, + otp8563/1, init_per_testcase/2, fin_per_testcase/2 ]). @@ -66,6 +67,7 @@ init_per_testcase(_Case, Config) when is_list(Config) -> fin_per_testcase(_Case, Config) when is_list(Config) -> Config. + %%====================================================================== %% Test case definitions %%====================================================================== @@ -76,7 +78,8 @@ all(suite) -> tickets(suite) -> [ - otp7575 + otp7575, + otp8563 ]. @@ -118,6 +121,55 @@ otp7575(Config) when is_list(Config) -> ok. +otp8563(suite) -> []; +otp8563(doc) -> ["OTP-8563"]; +otp8563(Config) when is_list(Config) -> + Val1 = 16#7fffffffffffffff, + io:format("try encode and decode ~w~n", [Val1]), + Enc1 = snmp_pdus:enc_value('Counter64', Val1), + {{'Counter64', Val1}, []} = snmp_pdus:dec_value(Enc1), + + Val2 = Val1 + 1, + io:format("try encode and decode ~w~n", [Val2]), + Enc2 = snmp_pdus:enc_value('Counter64', Val2), + {{'Counter64', Val2}, []} = snmp_pdus:dec_value(Enc2), + + Val3 = Val2 + 1, + io:format("try encode and decode ~w~n", [Val3]), + Enc3 = snmp_pdus:enc_value('Counter64', Val3), + {{'Counter64', Val3}, []} = snmp_pdus:dec_value(Enc3), + + Val4 = 16#fffffffffffffffe, + io:format("try encode and decode ~w~n", [Val4]), + Enc4 = snmp_pdus:enc_value('Counter64', Val4), + {{'Counter64', Val4}, []} = snmp_pdus:dec_value(Enc4), + + Val5 = Val4 + 1, + io:format("try encode and decode ~w~n", [Val5]), + Enc5 = snmp_pdus:enc_value('Counter64', Val5), + {{'Counter64', Val5}, []} = snmp_pdus:dec_value(Enc5), + + Val6 = 16#ffffffffffffffff + 1, + io:format("try and fail to encode ~w~n", [Val6]), + case (catch snmp_pdus:enc_value('Counter64', Val6)) of + {'EXIT', {error, {bad_counter64, Val6}}} -> + ok; + Unexpected6 -> + exit({unexpected_encode_result, Unexpected6, Val6}) + end, + + Val7 = -1, + io:format("try and fail to encode ~w~n", [Val7]), + case (catch snmp_pdus:enc_value('Counter64', Val7)) of + {'EXIT', {error, {bad_counter64, Val7}}} -> + ok; + Unexpected7 -> + exit({unexpected_encode_result, Unexpected7, Val7}) + end, + + ok. + + %%====================================================================== %% Internal functions %%====================================================================== diff --git a/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib b/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib index dd90d0ab50..2ba1a6fd67 100644 --- a/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib +++ b/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib @@ -12,18 +12,12 @@ OLD-SNMPEA-MIB DEFINITIONS ::= BEGIN ; -- MODULE-IDENTITY --- LAST-UPDATED "9709220900Z" --- ORGANIZATION "ETX/DN/S" --- CONTACT-INFO --- " Martin Bj�rklund --- --- Postal: ERICSSON SOFTWARE TECHNOLOGY AB --- ERLANG SYSTEMS --- Box 1214 --- S-164 28 KISTA, SWEDEN --- --- Tel: +46 8 719 20 89 --- E-mail: [email protected]" +-- LAST-UPDATED "1004200000Z" +-- ORGANIZATION "Erlang/OTP" +-- CONTACT-INFO "" +-- DESCRIPTION +-- "Header cleanup." +-- REVISION "1004200000Z" -- DESCRIPTION -- "This MIB module defines MIB objects for the SNMPEA -- component in OTP." diff --git a/lib/snmp/test/snmp_test_data/OTP8574-MIB.mib b/lib/snmp/test/snmp_test_data/OTP8574-MIB.mib new file mode 100644 index 0000000000..b5e5ed1848 --- /dev/null +++ b/lib/snmp/test/snmp_test_data/OTP8574-MIB.mib @@ -0,0 +1,77 @@ +OTP8574-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, enterprises, IpAddress FROM SNMPv2-SMI + RowStatus FROM SNMPv2-TC + ; + +otp8574MIB MODULE-IDENTITY + LAST-UPDATED "1004200000Z" + ORGANIZATION "Erlang/OTP" + CONTACT-INFO "www.erlang.org" + DESCRIPTION "The MIB module is used for testing a compiler feature" + ::= { otpSnmp 1 } + +ericsson OBJECT IDENTIFIER ::= { enterprises 193 } +otp OBJECT IDENTIFIER ::= { ericsson 19 } +otpApplications OBJECT IDENTIFIER ::= { otp 3 } +otpSnmp OBJECT IDENTIFIER ::= { otpApplications 3 } + +testMIBObjects OBJECT IDENTIFIER ::= { otp8574MIB 1 } + +testMIBObjectGroup OBJECT IDENTIFIER ::= { testMIBObjects 1 } + +example-Table OBJECT-TYPE + SYNTAX SEQUENCE OF ExampleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION "An example table" + ::= { testMIBObjectGroup 1 } + +example-Entry OBJECT-TYPE + SYNTAX ExampleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION "Example table entry" + INDEX { exampleIndex } + ::= { example-Table 5 } + +ExampleEntry ::= SEQUENCE { + exampleIndex INTEGER, + exampleColumn OCTET STRING, + exampleNotAccessible OCTET STRING, + exampleRowStatus RowStatus +} + +exampleIndex OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-write + STATUS current + DESCRIPTION "The index for this entry." + ::= { example-Entry 1 } + +exampleColumn OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Example table column" + ::= { example-Entry 2 } + +exampleNotAccessible OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Example table column" + ::= { example-Entry 3 } + +exampleRowStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Example table RowStatus" + ::= { example-Entry 4 } + +END diff --git a/lib/snmp/test/snmp_test_data/OTP8595-MIB.mib b/lib/snmp/test/snmp_test_data/OTP8595-MIB.mib new file mode 100644 index 0000000000..23245bce37 --- /dev/null +++ b/lib/snmp/test/snmp_test_data/OTP8595-MIB.mib @@ -0,0 +1,45 @@ +OTP8595-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, snmpModules, mib-2 + FROM SNMPv2-SMI + DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue, + TEXTUAL-CONVENTION + FROM SNMPv2-TC + MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP + FROM SNMPv2-CONF + sysLocation, sysContact + FROM SNMPv2-MIB + ; + +otp8595MIB MODULE-IDENTITY + LAST-UPDATED "1004210000Z" + ORGANIZATION "" + CONTACT-INFO + "" + DESCRIPTION + "Test mib for OTP-8595" + ::= { snmpModules 1 } + + +test OBJECT IDENTIFIER ::= { mib-2 15 } + +bits1 OBJECT-TYPE + SYNTAX BITS { + b0(0), + b1(1), + b2(2), + -- The following are extensions to the original set of + -- labels. The extensions start at an octet boundary. + -- So for bits 3 - 7, one MUST set them to zero on send + -- and one MUST ignore them on receipt. + b8(8), + b9(9) + } + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "" + ::= { test 1 } + +END diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl index e6220f9241..ef1ba0b948 100644 --- a/lib/snmp/test/snmp_test_mgr_misc.erl +++ b/lib/snmp/test/snmp_test_mgr_misc.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -101,8 +101,8 @@ init_packet(Parent, SnmpMgr, init_debug(Dbg) when is_atom(Dbg) -> put(debug,Dbg), - put(verbosity,silence); - %% put(verbosity,trace); + %% put(verbosity, silence); + put(verbosity, trace); init_debug(DbgOptions) when is_list(DbgOptions) -> case lists:keysearch(debug, 1, DbgOptions) of {value, {_, Dbg}} when is_atom(Dbg) -> diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index 50c72b33b5..2fccc733e6 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -17,11 +17,13 @@ # # %CopyrightEnd% -SNMP_VSN = 4.16.1 +SNMP_VSN = 4.16.2 PRE_VSN = APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)" -TICKETS = OTP-8480 OTP-8481 +TICKETS = OTP-8563 OTP-8574 OTP-8594 OTP-8595 + +TICKETS_4_16_1 = OTP-8480 OTP-8481 TICKETS_4_16 = \ OTP-8395 \ diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 0ae3abfa37..95cd92ee60 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -154,7 +154,7 @@ transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts} EmOptions = emulated_options(), {ok, InetValues} = inet:getopts(ListenSocket, EmOptions), ok = inet:setopts(ListenSocket, internal_inet_values()), - {CbModule,_,_} = CbInfo, + {CbModule,_,_, _} = CbInfo, case CbModule:accept(ListenSocket, Timeout) of {ok, Socket} -> ok = inet:setopts(ListenSocket, InetValues), @@ -216,7 +216,7 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) -> %% %% Description: Close a ssl connection %%-------------------------------------------------------------------- -close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _}}}, fd = new_ssl}) -> +close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}) -> CbMod:close(ListenSocket); close(#sslsocket{pid = Pid, fd = new_ssl}) -> ssl_connection:close(Pid); @@ -375,7 +375,7 @@ setopts(#sslsocket{} = Socket, Options) -> %% %% Description: Same as gen_tcp:shutdown/2 %%-------------------------------------------------------------------- -shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _}}}, fd = new_ssl}, How) -> +shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}, How) -> CbMod:shutdown(ListenSocket, How); shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) -> ssl_connection:shutdown(Pid, How). @@ -449,7 +449,7 @@ do_new_connect(Address, Port, #config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts, emulated=EmOpts,inet_ssl=SocketOpts}, Timeout) -> - {CbModule, _, _} = CbInfo, + {CbModule, _, _, _} = CbInfo, try CbModule:connect(Address, Port, SocketOpts, Timeout) of {ok, Socket} -> ssl_connection:connect(Address, Port, Socket, {SslOpts,EmOpts}, @@ -471,7 +471,7 @@ old_connect(Address, Port, Options, Timeout) -> new_listen(Port, Options0) -> try {ok, Config} = handle_options(Options0, server), - #config{cb={CbModule, _, _},inet_user=Options} = Config, + #config{cb={CbModule, _, _, _},inet_user=Options} = Config, case CbModule:listen(Port, Options) of {ok, ListenSocket} -> {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}}; @@ -546,17 +546,18 @@ handle_options(Opts0, Role) -> %% Server side option reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun), reuse_sessions = handle_option(reuse_sessions, Opts, true), + secure_renegotiate = handle_option(secure_renegotiate, Opts, false), renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT), debug = handle_option(debug, Opts, []) }, - CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed}), + CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}), SslOptions = [versions, verify, verify_fun, validate_extensions_fun, fail_if_no_peer_cert, verify_client_once, depth, certfile, keyfile, key, password, cacertfile, dhfile, ciphers, debug, reuse_session, reuse_sessions, ssl_imp, - cb_info, renegotiate_at], + cb_info, renegotiate_at, secure_renegotiate], SockOpts = lists:foldl(fun(Key, PropList) -> proplists:delete(Key, PropList) @@ -627,6 +628,10 @@ validate_option(reuse_session, Value) when is_function(Value) -> validate_option(reuse_sessions, Value) when Value == true; Value == false -> Value; + +validate_option(secure_renegotiate, Value) when Value == true; + Value == false -> + Value; validate_option(renegotiate_at, Value) when is_integer(Value) -> min(Value, ?DEFAULT_RENEGOTIATE_AT); @@ -735,24 +740,34 @@ cipher_suites(Version, Ciphers0) -> format_error({error, Reason}) -> format_error(Reason); +format_error(Reason) when is_list(Reason) -> + Reason; format_error(closed) -> - "Connection closed for the operation in question."; + "The connection is closed"; +format_error(ecacertfile) -> + "Own CA certificate file is invalid."; +format_error(ecertfile) -> + "Own certificate file is invalid."; +format_error(ekeyfile) -> + "Own private key file is invalid."; +format_error(esslaccept) -> + "Server SSL handshake procedure between client and server failed."; +format_error(esslconnect) -> + "Client SSL handshake procedure between client and server failed."; +format_error({eoptions, Options}) -> + lists:flatten(io_lib:format("Error in options list: ~p~n", [Options])); + +%%%%%%%%%%%% START OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% format_error(ebadsocket) -> "Connection not found (internal error)."; format_error(ebadstate) -> "Connection not in connect state (internal error)."; format_error(ebrokertype) -> "Wrong broker type (internal error)."; -format_error(ecacertfile) -> - "Own CA certificate file is invalid."; -format_error(ecertfile) -> - "Own certificate file is invalid."; format_error(echaintoolong) -> "The chain of certificates provided by peer is too long."; format_error(ecipher) -> "Own list of specified ciphers is invalid."; -format_error(ekeyfile) -> - "Own private key file is invalid."; format_error(ekeymismatch) -> "Own private key does not match own certificate."; format_error(enoissuercert) -> @@ -778,10 +793,6 @@ format_error(epeercertinvalid) -> "Certificate provided by peer is invalid."; format_error(eselfsignedcert) -> "Certificate provided by peer is self signed."; -format_error(esslaccept) -> - "Server SSL handshake procedure between client and server failed."; -format_error(esslconnect) -> - "Client SSL handshake procedure between client and server failed."; format_error(esslerrssl) -> "SSL protocol failure. Typically because of a fatal alert from peer."; format_error(ewantconnect) -> @@ -800,6 +811,9 @@ format_error({badcast, _Cast}) -> format_error({badinfo, _Info}) -> "Call not recognized for current mode (active or passive) and state " "of socket."; + +%%%%%%%%%%%%%%%%%% END OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + format_error(Error) -> case (catch inet:format_error(Error)) of "unkknown POSIX" ++ _ -> @@ -811,7 +825,7 @@ format_error(Error) -> end. no_format(Error) -> - io_lib:format("No format string for error: \"~p\" available.", [Error]). + lists:flatten(io_lib:format("No format string for error: \"~p\" available.", [Error])). %% Start old ssl port program if needed. ensure_old_ssl_started() -> diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index d3f9c833f1..db9a883654 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -38,10 +38,6 @@ reason_code(#alert{description = ?HANDSHAKE_FAILURE}, client) -> esslconnect; reason_code(#alert{description = ?HANDSHAKE_FAILURE}, server) -> esslaccept; -reason_code(#alert{description = ?CERTIFICATE_EXPIRED}, _) -> - epeercertexpired; -reason_code(#alert{level = ?FATAL}, _) -> - esslerrssl; reason_code(#alert{description = Description}, _) -> description_txt(Description). @@ -55,51 +51,51 @@ level_txt(?FATAL) -> "Fatal error:". description_txt(?CLOSE_NOTIFY) -> - "close_notify"; + "close notify"; description_txt(?UNEXPECTED_MESSAGE) -> - "unexpected_message"; + "unexpected message"; description_txt(?BAD_RECORD_MAC) -> - "bad_record_mac"; + "bad record mac"; description_txt(?DECRYPTION_FAILED) -> - "decryption_failed"; + "decryption failed"; description_txt(?RECORD_OVERFLOW) -> - "record_overflow"; + "record overflow"; description_txt(?DECOMPRESSION_FAILURE) -> - "decompression_failure"; + "decompression failure"; description_txt(?HANDSHAKE_FAILURE) -> - "handshake_failure"; + "handshake failure"; description_txt(?BAD_CERTIFICATE) -> - "bad_certificate"; + "bad certificate"; description_txt(?UNSUPPORTED_CERTIFICATE) -> - "unsupported_certificate"; + "unsupported certificate"; description_txt(?CERTIFICATE_REVOKED) -> - "certificate_revoked"; + "certificate revoked"; description_txt(?CERTIFICATE_EXPIRED) -> - "certificate_expired"; + "certificate expired"; description_txt(?CERTIFICATE_UNKNOWN) -> - "certificate_unknown"; + "certificate unknown"; description_txt(?ILLEGAL_PARAMETER) -> - "illegal_parameter"; + "illegal parameter"; description_txt(?UNKNOWN_CA) -> - "unknown_ca"; + "unknown ca"; description_txt(?ACCESS_DENIED) -> - "access_denied"; + "access denied"; description_txt(?DECODE_ERROR) -> - "decode_error"; + "decode error"; description_txt(?DECRYPT_ERROR) -> - "decrypt_error"; + "decrypt error"; description_txt(?EXPORT_RESTRICTION) -> - "export_restriction"; + "export restriction"; description_txt(?PROTOCOL_VERSION) -> - "protocol_version"; + "protocol version"; description_txt(?INSUFFICIENT_SECURITY) -> - "insufficient_security"; + "insufficient security"; description_txt(?INTERNAL_ERROR) -> - "internal_error"; + "internal error"; description_txt(?USER_CANCELED) -> - "user_canceled"; + "user canceled"; description_txt(?NO_RENEGOTIATION) -> - "no_renegotiation". + "no renegotiation". diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl index 4304c501b7..d282cbd780 100644 --- a/lib/ssl/src/ssl_cipher.hrl +++ b/lib/ssl/src/ssl_cipher.hrl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -250,4 +250,9 @@ -define(TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, <<?BYTE(16#00), ?BYTE(16#65)>>). -define(TLS_DHE_DSS_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#66)>>). +%% RFC 5746 - Not a real ciphersuite used to signal empty "renegotiation_info" extension +%% to avoid handshake failure from old servers that do not ignore +%% hello extension data as they should. +-define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>). + -endif. % -ifdef(ssl_cipher). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index a406e86bbf..a9ddc44edf 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -58,6 +58,7 @@ transport_cb, % atom() - callback module data_tag, % atom() - ex tcp. close_tag, % atom() - ex tcp_closed + error_tag, % atom() - ex tcp_error host, % string() | ipadress() port, % integer() socket, % socket() @@ -316,12 +317,14 @@ init([Role, Host, Port, Socket, {SSLOpts, _} = Options, %% %%-------------------------------------------------------------------- hello(start, #state{host = Host, port = Port, role = client, - ssl_options = SslOpts, - transport_cb = Transport, socket = Socket, - connection_states = ConnectionStates} + ssl_options = SslOpts, + transport_cb = Transport, socket = Socket, + connection_states = ConnectionStates, + renegotiation = {Renegotiation, _}} = State0) -> Hello = ssl_handshake:client_hello(Host, Port, - ConnectionStates, SslOpts), + ConnectionStates, SslOpts, Renegotiation), + Version = Hello#client_hello.client_version, Hashes0 = ssl_handshake:init_hashes(), {BinMsg, CS2, Hashes1} = @@ -351,55 +354,60 @@ hello(#server_hello{cipher_suite = CipherSuite, role = client, negotiated_version = ReqVersion, host = Host, port = Port, + renegotiation = {Renegotiation, _}, + ssl_options = SslOptions, session_cache = Cache, session_cache_cb = CacheCb} = State0) -> - {Version, NewId, ConnectionStates1} = - ssl_handshake:hello(Hello, ConnectionStates0), - - {KeyAlgorithm, _, _, _} = - ssl_cipher:suite_definition(CipherSuite), - - PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), - - State1 = State0#state{key_algorithm = KeyAlgorithm, - negotiated_version = Version, - connection_states = ConnectionStates1, - premaster_secret = PremasterSecret}, - - case ssl_session:is_new(OldId, NewId) of - true -> - Session = Session0#session{session_id = NewId, - cipher_suite = CipherSuite, + case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of + {Version, NewId, ConnectionStates1} -> + {KeyAlgorithm, _, _, _} = + ssl_cipher:suite_definition(CipherSuite), + + PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm), + + State1 = State0#state{key_algorithm = KeyAlgorithm, + negotiated_version = Version, + connection_states = ConnectionStates1, + premaster_secret = PremasterSecret}, + + case ssl_session:is_new(OldId, NewId) of + true -> + Session = Session0#session{session_id = NewId, + cipher_suite = CipherSuite, compression_method = Compression}, - {Record, State} = next_record(State1#state{session = Session}), - next_state(certify, Record, State); - false -> - Session = CacheCb:lookup(Cache, {{Host, Port}, NewId}), - case ssl_handshake:master_secret(Version, Session, - ConnectionStates1, client) of - {_, ConnectionStates2} -> - {Record, State} = - next_record(State1#state{ - connection_states = ConnectionStates2, - session = Session}), - next_state(abbreviated, Record, State); - #alert{} = Alert -> - handle_own_alert(Alert, Version, hello, State1), - {stop, normal, State1} - end + {Record, State} = next_record(State1#state{session = Session}), + next_state(certify, Record, State); + false -> + Session = CacheCb:lookup(Cache, {{Host, Port}, NewId}), + case ssl_handshake:master_secret(Version, Session, + ConnectionStates1, client) of + {_, ConnectionStates2} -> + {Record, State} = + next_record(State1#state{ + connection_states = ConnectionStates2, + session = Session}), + next_state(abbreviated, Record, State); + #alert{} = Alert -> + handle_own_alert(Alert, Version, hello, State1), + {stop, normal, State1} + end + end; + #alert{} = Alert -> + handle_own_alert(Alert, ReqVersion, hello, State0), + {stop, normal, State0} end; hello(Hello = #client_hello{client_version = ClientVersion}, State = #state{connection_states = ConnectionStates0, port = Port, session = Session0, - session_cache = Cache, + renegotiation = {Renegotiation, _}, + session_cache = Cache, session_cache_cb = CacheCb, ssl_options = SslOpts}) -> - case ssl_handshake:hello(Hello, {Port, SslOpts, - Session0, Cache, CacheCb, - ConnectionStates0}) of + case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb, + ConnectionStates0}, Renegotiation) of {Version, {Type, Session}, ConnectionStates} -> do_server_hello(Type, State#state{connection_states = ConnectionStates, @@ -417,29 +425,35 @@ abbreviated(#hello_request{}, State0) -> {Record, State} = next_record(State0), next_state(hello, Record, State); -abbreviated(Finished = #finished{}, +abbreviated(Finished = #finished{verify_data = Data}, #state{role = server, negotiated_version = Version, tls_handshake_hashes = Hashes, - session = #session{master_secret = MasterSecret}} = + session = #session{master_secret = MasterSecret}, + connection_states = ConnectionStates0} = State) -> case ssl_handshake:verify_connection(Version, Finished, client, MasterSecret, Hashes) of verified -> - next_state_connection(abbreviated, ack_connection(State)); + ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0), + next_state_connection(abbreviated, + ack_connection(State#state{connection_states = ConnectionStates})); #alert{} = Alert -> handle_own_alert(Alert, Version, abbreviated, State), {stop, normal, State} end; -abbreviated(Finished = #finished{}, +abbreviated(Finished = #finished{verify_data = Data}, #state{role = client, tls_handshake_hashes = Hashes0, session = #session{master_secret = MasterSecret}, - negotiated_version = Version} = State) -> + negotiated_version = Version, + connection_states = ConnectionStates0} = State) -> case ssl_handshake:verify_connection(Version, Finished, server, MasterSecret, Hashes0) of verified -> - {ConnectionStates, Hashes} = finalize_client_handshake(State), + ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0), + {ConnectionStates, Hashes} = + finalize_handshake(State#state{connection_states = ConnectionStates1}, abbreviated), next_state_connection(abbreviated, ack_connection(State#state{tls_handshake_hashes = Hashes, connection_states = @@ -653,32 +667,37 @@ cipher(#certificate_verify{signature = Signature}, {stop, normal, State0} end; -cipher(#finished{} = Finished, +cipher(#finished{verify_data = Data} = Finished, #state{negotiated_version = Version, host = Host, port = Port, role = Role, session = #session{master_secret = MasterSecret} = Session0, - tls_handshake_hashes = Hashes} = State) -> + tls_handshake_hashes = Hashes0, + connection_states = ConnectionStates0} = State) -> case ssl_handshake:verify_connection(Version, Finished, opposite_role(Role), - MasterSecret, Hashes) of + MasterSecret, Hashes0) of verified -> Session = register_session(Role, Host, Port, Session0), case Role of client -> - next_state_connection(cipher, ack_connection(State#state{session = Session})); + ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0), + next_state_connection(cipher, ack_connection(State#state{session = Session, + connection_states = ConnectionStates})); server -> - {NewConnectionStates, NewHashes} = - finalize_server_handshake(State#state{ - session = Session}), + ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0), + {ConnectionStates, Hashes} = + finalize_handshake(State#state{ + connection_states = ConnectionStates1, + session = Session}, cipher), next_state_connection(cipher, ack_connection(State#state{connection_states = - NewConnectionStates, + ConnectionStates, session = Session, tls_handshake_hashes = - NewHashes})) + Hashes})) end; #alert{} = Alert -> handle_own_alert(Alert, Version, cipher, State), @@ -695,10 +714,12 @@ connection(#hello_request{}, #state{host = Host, port = Port, negotiated_version = Version, transport_cb = Transport, connection_states = ConnectionStates0, + renegotiation = {Renegotiation, _}, tls_handshake_hashes = Hashes0} = State0) -> - + Hello = ssl_handshake:client_hello(Host, Port, - ConnectionStates0, SslOpts), + ConnectionStates0, SslOpts, Renegotiation), + {BinMsg, ConnectionStates1, Hashes1} = encode_handshake(Hello, Version, ConnectionStates0, Hashes0), Transport:send(Socket, BinMsg), @@ -913,14 +934,9 @@ handle_sync_event(peer_certificate, _, StateName, %% raw data from TCP, unpack records handle_info({Protocol, _, Data}, StateName, #state{data_tag = Protocol, - negotiated_version = Version, - tls_record_buffer = Buf0, - tls_cipher_texts = CT0} = State0) -> - case ssl_record:get_tls_records(Data, Buf0) of - {Records, Buf1} -> - CT1 = CT0 ++ Records, - {Record, State} = next_record(State0#state{tls_record_buffer = Buf1, - tls_cipher_texts = CT1}), + negotiated_version = Version} = State0) -> + case next_tls_record(Data, State0) of + {Record, State} -> next_state(StateName, Record, State); #alert{} = Alert -> handle_own_alert(Alert, Version, StateName, State0), @@ -944,14 +960,29 @@ handle_info({CloseTag, Socket}, _StateName, alert_user(Opts#socket_options.active, Pid, From, ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), Role), {stop, normal, State}; - + +handle_info({ErrorTag, Socket, econnaborted}, StateName, + #state{socket = Socket, from = User, role = Role, + error_tag = ErrorTag} = State) when StateName =/= connection -> + alert_user(User, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role), + {stop, normal, State}; + +handle_info({ErrorTag, Socket, Reason}, _, + #state{socket = Socket, from = User, + role = Role, error_tag = ErrorTag} = State) -> + Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]), + error_logger:info_report(Report), + alert_user(User, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role), + {stop, normal, State}; + handle_info({'DOWN', MonitorRef, _, _, _}, _, State = #state{user_application={MonitorRef,_Pid}}) -> {stop, normal, State}; -handle_info(A, StateName, State) -> - io:format("SSL: Bad info (state ~w): ~w\n", [StateName, A]), - {stop, bad_info, State}. +handle_info(Msg, StateName, State) -> + Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]), + error_logger:info_report(Report), + {next_state, StateName, State}. %%-------------------------------------------------------------------- %% Function: terminate(Reason, StateName, State) -> void() @@ -970,14 +1001,14 @@ terminate(_Reason, connection, #state{negotiated_version = Version, {BinAlert, _} = encode_alert(?ALERT_REC(?WARNING,?CLOSE_NOTIFY), Version, ConnectionStates), Transport:send(Socket, BinAlert), - Transport:shutdown(Socket, read_write), + workaround_transport_delivery_problems(Socket, Transport), Transport:close(Socket); terminate(_Reason, _StateName, #state{transport_cb = Transport, socket = Socket, send_queue = SendQueue, renegotiation = Renegotiate}) -> notify_senders(SendQueue), notify_renegotiater(Renegotiate), - Transport:shutdown(Socket, read_write), + workaround_transport_delivery_problems(Socket, Transport), Transport:close(Socket). %%-------------------------------------------------------------------- @@ -991,7 +1022,7 @@ code_change(_OldVsn, StateName, State, _Extra) -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_} = CbInfo, +start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_, _} = CbInfo, Timeout) -> case ssl_connection_sup:start_child([Role, Host, Port, Socket, Opts, User, CbInfo]) of @@ -1106,7 +1137,7 @@ init_diffie_hellman(DHParamFile, server) -> end. sync_send_all_state_event(FsmPid, Event) -> - sync_send_all_state_event(FsmPid, Event, ?DEFAULT_TIMEOUT). + sync_send_all_state_event(FsmPid, Event, infinity). sync_send_all_state_event(FsmPid, Event, Timeout) -> try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout) @@ -1175,32 +1206,34 @@ verify_client_cert(#state{client_certificate_requested = false} = State) -> do_server_hello(Type, #state{negotiated_version = Version, session = Session, - connection_states = ConnectionStates0} + connection_states = ConnectionStates0, + renegotiation = {Renegotiation, _}} = State0) when is_atom(Type) -> ServerHello = ssl_handshake:server_hello(Session#session.session_id, Version, - ConnectionStates0), - State = server_hello(ServerHello, State0), + ConnectionStates0, Renegotiation), + State1 = server_hello(ServerHello, State0), case Type of new -> - do_server_hello(ServerHello, State); + do_server_hello(ServerHello, State1); resumed -> + ConnectionStates1 = State1#state.connection_states, case ssl_handshake:master_secret(Version, Session, - ConnectionStates0, server) of - {_, ConnectionStates1} -> - State1 = State#state{connection_states=ConnectionStates1, - session = Session}, + ConnectionStates1, server) of + {_, ConnectionStates2} -> + State2 = State1#state{connection_states=ConnectionStates2, + session = Session}, {ConnectionStates, Hashes} = - finalize_server_handshake(State1), - Resumed0 = State1#state{connection_states = - ConnectionStates, - tls_handshake_hashes = Hashes}, - {Record, Resumed} = next_record(Resumed0), - next_state(abbreviated, Record, Resumed); + finalize_handshake(State2, abbreviated), + State3 = State2#state{connection_states = + ConnectionStates, + tls_handshake_hashes = Hashes}, + {Record, State} = next_record(State3), + next_state(abbreviated, Record, State); #alert{} = Alert -> - handle_own_alert(Alert, Version, hello, State), - {stop, normal, State} + handle_own_alert(Alert, Version, hello, State1), + {stop, normal, State1} end end; @@ -1228,7 +1261,7 @@ client_certify_and_key_exchange(#state{negotiated_version = Version} = State0) -> try do_client_certify_and_key_exchange(State0) of State1 = #state{} -> - {ConnectionStates, Hashes} = finalize_client_handshake(State1), + {ConnectionStates, Hashes} = finalize_handshake(State1, certify), State2 = State1#state{connection_states = ConnectionStates, %% Reinitialize client_certificate_requested = false, @@ -1439,45 +1472,44 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_none}} = State) -> State. -finalize_client_handshake(#state{connection_states = ConnectionStates0} - = State) -> - ConnectionStates1 = - cipher_protocol(State#state{connection_states = - ConnectionStates0}), - ConnectionStates2 = - ssl_record:activate_pending_connection_state(ConnectionStates1, +finalize_handshake(State, StateName) -> + ConnectionStates0 = cipher_protocol(State), + ConnectionStates = + ssl_record:activate_pending_connection_state(ConnectionStates0, write), - finished(State#state{connection_states = ConnectionStates2}). + finished(State#state{connection_states = ConnectionStates}, StateName). - -finalize_server_handshake(State) -> - ConnectionStates0 = cipher_protocol(State), - ConnectionStates = - ssl_record:activate_pending_connection_state(ConnectionStates0, - write), - finished(State#state{connection_states = ConnectionStates}). - -cipher_protocol(#state{connection_states = ConnectionStates, +cipher_protocol(#state{connection_states = ConnectionStates0, socket = Socket, negotiated_version = Version, transport_cb = Transport}) -> - {BinChangeCipher, NewConnectionStates} = + {BinChangeCipher, ConnectionStates} = encode_change_cipher(#change_cipher_spec{}, - Version, ConnectionStates), + Version, ConnectionStates0), Transport:send(Socket, BinChangeCipher), - NewConnectionStates. + ConnectionStates. finished(#state{role = Role, socket = Socket, negotiated_version = Version, transport_cb = Transport, session = Session, - connection_states = ConnectionStates, - tls_handshake_hashes = Hashes}) -> + connection_states = ConnectionStates0, + tls_handshake_hashes = Hashes0}, StateName) -> MasterSecret = Session#session.master_secret, - Finished = ssl_handshake:finished(Version, Role, MasterSecret, Hashes), - {BinFinished, NewConnectionStates, NewHashes} = - encode_handshake(Finished, Version, ConnectionStates, Hashes), + Finished = ssl_handshake:finished(Version, Role, MasterSecret, Hashes0), + ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName), + {BinFinished, ConnectionStates, Hashes} = + encode_handshake(Finished, Version, ConnectionStates1, Hashes0), Transport:send(Socket, BinFinished), - {NewConnectionStates, NewHashes}. + {ConnectionStates, Hashes}. + +save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, certify) -> + ssl_record:set_client_verify_data(current_write, Data, ConnectionStates); +save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, cipher) -> + ssl_record:set_server_verify_data(current_both, Data, ConnectionStates); +save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbreviated) -> + ssl_record:set_client_verify_data(current_both, Data, ConnectionStates); +save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) -> + ssl_record:set_server_verify_data(current_write, Data, ConnectionStates). handle_server_key( #server_key_exchange{params = @@ -1710,20 +1742,13 @@ format_packet_error(#socket_options{active = false, mode = Mode}, Data) -> format_packet_error(#socket_options{active = _, mode = Mode}, Data) -> {ssl_error, sslsocket(), {invalid_packet, format_reply(Mode, raw, 0, Data)}}. -format_reply(_, http, _,Data) -> Data; -format_reply(_, http_bin, _, Data) -> Data; -format_reply(_, {http, headers}, _,Data) -> Data; -format_reply(_, {http_bin, headers}, _, Data) -> Data; -format_reply(_, asn1, _,Data) -> Data; -format_reply(_, cdr, _, Data) -> Data; -format_reply(_, sunrm, _,Data) -> Data; -format_reply(_, fcgi, _, Data) -> Data; -format_reply(_, tpkt, _, Data) -> Data; -format_reply(_, line, _, Data) -> Data; format_reply(binary, _, N, Data) when N > 0 -> % Header mode header(N, Data); format_reply(binary, _, _, Data) -> Data; -format_reply(list, _, _, Data) -> binary_to_list(Data). +format_reply(list, Packet, _, Data) when is_integer(Packet); Packet == raw -> + binary_to_list(Data); +format_reply(list, _,_, Data) -> + Data. header(0, <<>>) -> <<>>; @@ -1781,7 +1806,7 @@ next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data}, Hs1 = ssl_handshake:update_hashes(Hs0, Raw), ?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs1, renegotiation = {true, peer}}); - ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_hashes=Hs0}}) -> + ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_hashes=Hs0}}) -> Hs1 = ssl_handshake:update_hashes(Hs0, Raw), ?MODULE:SName(Packet, State#state{tls_handshake_hashes=Hs1}); (_, StopState) -> StopState @@ -1802,7 +1827,6 @@ next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State {Record, State} -> next_state(StateName, Record, State) end; - next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} = _ChangeCipher, #state{connection_states = ConnectionStates0} = State0) -> @@ -1816,6 +1840,17 @@ next_state(StateName, #ssl_tls{type = _Unknown}, State0) -> {Record, State} = next_record(State0), next_state(StateName, Record, State). +next_tls_record(Data, #state{tls_record_buffer = Buf0, + tls_cipher_texts = CT0} = State0) -> + case ssl_record:get_tls_records(Data, Buf0) of + {Records, Buf1} -> + CT1 = CT0 ++ Records, + next_record(State0#state{tls_record_buffer = Buf1, + tls_cipher_texts = CT1}); + #alert{} = Alert -> + Alert + end. + next_record(#state{tls_cipher_texts = [], socket = Socket} = State) -> inet:setopts(Socket, [{active,once}]), {no_record, State}; @@ -1892,7 +1927,7 @@ invalidate_session(server, _, Port, Session) -> ssl_manager:invalidate_session(Port, Session). initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User, - {CbModule, DataTag, CloseTag}) -> + {CbModule, DataTag, CloseTag, ErrorTag}) -> ConnectionStates = ssl_record:init_connection_states(Role), SessionCacheCb = case application:get_env(ssl, session_cb) of @@ -1912,6 +1947,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User, transport_cb = CbModule, data_tag = DataTag, close_tag = CloseTag, + error_tag = ErrorTag, role = Role, host = Host, port = Port, @@ -2076,12 +2112,6 @@ handle_own_alert(Alert, Version, StateName, try %% Try to tell the other side {BinMsg, _} = encode_alert(Alert, Version, ConnectionStates), - %% Try to make sure alert will be sent before socket is closed - %% when process ends. This will help on some - %% linux platforms and knowingly not break anything on other - %% platforms. Other platforms will benefit from shutdown that is now - %% done before close. - inet:setopts(Socket, [{nodelay, true}]), Transport:send(Socket, BinMsg) catch _:_ -> %% Can crash if we are in a uninitialized state ignore @@ -2155,3 +2185,8 @@ notify_renegotiater({true, From}) when not is_atom(From) -> gen_fsm:reply(From, {error, closed}); notify_renegotiater(_) -> ok. + +workaround_transport_delivery_problems(Socket, Transport) -> + inet:setopts(Socket, [{active, false}]), + Transport:shutdown(Socket, write), + Transport:recv(Socket, 0). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 9f5ac7106a..f0413c4d31 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -31,7 +31,7 @@ -include("ssl_debug.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([master_secret/4, client_hello/4, server_hello/3, hello/2, +-export([master_secret/4, client_hello/5, server_hello/4, hello/4, hello_request/0, certify/7, certificate/3, client_certificate_verify/6, certificate_verify/6, certificate_request/2, @@ -57,7 +57,7 @@ %%-------------------------------------------------------------------- client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions, ciphers = Ciphers} - = SslOpts) -> + = SslOpts, Renegotiation) -> Fun = fun(Version) -> ssl_record:protocol_version(Version) @@ -70,22 +70,25 @@ client_hello(Host, Port, ConnectionStates, #ssl_options{versions = Versions, #client_hello{session_id = Id, client_version = Version, - cipher_suites = Ciphers, + cipher_suites = cipher_suites(Ciphers, Renegotiation), compression_methods = ssl_record:compressions(), - random = SecParams#security_parameters.client_random + random = SecParams#security_parameters.client_random, + renegotiation_info = + renegotiation_info(client, ConnectionStates, Renegotiation) }. %%-------------------------------------------------------------------- -%% Function: server_hello(Host, Port, SessionId, -%% Version, ConnectionStates) -> #server_hello{} +%% Function: server_hello(SessionId, Version, +%% ConnectionStates, Renegotiation) -> #server_hello{} %% SessionId %% Version -%% ConnectionStates +%% ConnectionStates +%% Renegotiation %% %% %% Description: Creates a server hello message. %%-------------------------------------------------------------------- -server_hello(SessionId, Version, ConnectionStates) -> +server_hello(SessionId, Version, ConnectionStates, Renegotiation) -> Pending = ssl_record:pending_connection_state(ConnectionStates, read), SecParams = Pending#connection_state.security_parameters, #server_hello{server_version = Version, @@ -93,7 +96,9 @@ server_hello(SessionId, Version, ConnectionStates) -> compression_method = SecParams#security_parameters.compression_algorithm, random = SecParams#security_parameters.server_random, - session_id = SessionId + session_id = SessionId, + renegotiation_info = + renegotiation_info(server, ConnectionStates, Renegotiation) }. %%-------------------------------------------------------------------- @@ -106,27 +111,41 @@ hello_request() -> #hello_request{}. %%-------------------------------------------------------------------- -%% Function: hello(Hello, Info) -> +%% Function: hello(Hello, Info, Renegotiation) -> %% {Version, Id, NewConnectionStates} | %% #alert{} %% %% Hello = #client_hello{} | #server_hello{} -%% Info = ConnectionStates | {Port, Session, ConnectionStates} +%% Info = ConnectionStates | {Port, #ssl_options{}, Session, +%% Cahce, CahceCb, ConnectionStates} %% ConnectionStates = #connection_states{} +%% Renegotiation = boolean() %% %% Description: Handles a recieved hello message %%-------------------------------------------------------------------- hello(#server_hello{cipher_suite = CipherSuite, server_version = Version, compression_method = Compression, random = Random, - session_id = SessionId}, ConnectionStates) -> - NewConnectionStates = - hello_pending_connection_states(client, CipherSuite, Random, - Compression, ConnectionStates), - {Version, SessionId, NewConnectionStates}; - -hello(#client_hello{client_version = ClientVersion, random = Random} = Hello, - {Port, #ssl_options{versions = Versions} = SslOpts, - Session0, Cache, CacheCb, ConnectionStates0}) -> + session_id = SessionId, renegotiation_info = Info}, + #ssl_options{secure_renegotiate = SecureRenegotation}, + ConnectionStates0, Renegotiation) -> + + case handle_renegotiation_info(client, Info, ConnectionStates0, + Renegotiation, SecureRenegotation, []) of + {ok, ConnectionStates1} -> + ConnectionStates = + hello_pending_connection_states(client, CipherSuite, Random, + Compression, ConnectionStates1), + {Version, SessionId, ConnectionStates}; + #alert{} = Alert -> + Alert + end; + +hello(#client_hello{client_version = ClientVersion, random = Random, + cipher_suites = CipherSuites, + renegotiation_info = Info} = Hello, + #ssl_options{versions = Versions, + secure_renegotiate = SecureRenegotation} = SslOpts, + {Port, Session0, Cache, CacheCb, ConnectionStates0}, Renegotiation) -> Version = select_version(ClientVersion, Versions), case ssl_record:is_acceptable_version(Version) of true -> @@ -138,13 +157,20 @@ hello(#client_hello{client_version = ClientVersion, random = Random} = Hello, no_suite -> ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY); _ -> - ConnectionStates = - hello_pending_connection_states(server, - CipherSuite, - Random, - Compression, - ConnectionStates0), - {Version, {Type, Session}, ConnectionStates} + case handle_renegotiation_info(server, Info, ConnectionStates0, + Renegotiation, SecureRenegotation, + CipherSuites) of + {ok, ConnectionStates1} -> + ConnectionStates = + hello_pending_connection_states(server, + CipherSuite, + Random, + Compression, + ConnectionStates1), + {Version, {Type, Session}, ConnectionStates}; + #alert{} = Alert -> + Alert + end end; false -> ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION) @@ -525,7 +551,109 @@ select_session(Hello, Port, Session, Version, false -> {resumed, CacheCb:lookup(Cache, {Port, SessionId})} end. - + + +cipher_suites(Suites, false) -> + [?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites]; +cipher_suites(Suites, true) -> + Suites. + +renegotiation_info(client, _, false) -> + #renegotiation_info{renegotiated_connection = undefined}; +renegotiation_info(server, ConnectionStates, false) -> + CS = ssl_record:current_connection_state(ConnectionStates, read), + case CS#connection_state.secure_renegotiation of + true -> + #renegotiation_info{renegotiated_connection = ?byte(0)}; + false -> + #renegotiation_info{renegotiated_connection = undefined} + end; +renegotiation_info(client, ConnectionStates, true) -> + CS = ssl_record:current_connection_state(ConnectionStates, read), + case CS#connection_state.secure_renegotiation of + true -> + Data = CS#connection_state.client_verify_data, + #renegotiation_info{renegotiated_connection = Data}; + false -> + #renegotiation_info{renegotiated_connection = undefined} + end; + +renegotiation_info(server, ConnectionStates, true) -> + CS = ssl_record:current_connection_state(ConnectionStates, read), + case CS#connection_state.secure_renegotiation of + true -> + CData = CS#connection_state.client_verify_data, + SData =CS#connection_state.server_verify_data, + #renegotiation_info{renegotiated_connection = <<CData/binary, SData/binary>>}; + false -> + #renegotiation_info{renegotiated_connection = undefined} + end. + +handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)}, + ConnectionStates, false, _, _) -> + {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)}; + +handle_renegotiation_info(server, undefined, ConnectionStates, _, _, CipherSuites) -> + case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of + true -> + {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)}; + false -> + {ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)} + end; + +handle_renegotiation_info(_, undefined, ConnectionStates, false, _, _) -> + {ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)}; + +handle_renegotiation_info(client, #renegotiation_info{renegotiated_connection = ClientServerVerify}, + ConnectionStates, true, _, _) -> + CS = ssl_record:current_connection_state(ConnectionStates, read), + CData = CS#connection_state.client_verify_data, + SData = CS#connection_state.server_verify_data, + case <<CData/binary, SData/binary>> == ClientServerVerify of + true -> + {ok, ConnectionStates}; + false -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE) + end; +handle_renegotiation_info(server, #renegotiation_info{renegotiated_connection = ClientVerify}, + ConnectionStates, true, _, CipherSuites) -> + + case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of + true -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE); + false -> + CS = ssl_record:current_connection_state(ConnectionStates, read), + Data = CS#connection_state.client_verify_data, + case Data == ClientVerify of + true -> + {ok, ConnectionStates}; + false -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE) + end + end; + +handle_renegotiation_info(client, undefined, ConnectionStates, true, SecureRenegotation, _) -> + handle_renegotiation_info(ConnectionStates, SecureRenegotation); + +handle_renegotiation_info(server, undefined, ConnectionStates, true, SecureRenegotation, CipherSuites) -> + case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of + true -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE); + false -> + handle_renegotiation_info(ConnectionStates, SecureRenegotation) + end. + +handle_renegotiation_info(ConnectionStates, SecureRenegotation) -> + CS = ssl_record:current_connection_state(ConnectionStates, read), + case {SecureRenegotation, CS#connection_state.secure_renegotiation} of + {_, true} -> + ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE); + {true, false} -> + ?ALERT_REC(?FATAL, ?NO_RENEGOTIATION); + {false, false} -> + {ok, ConnectionStates} + end. + %% Update pending connection states with parameters exchanged via %% hello messages %% NOTE : Role is the role of the receiver of the hello message @@ -636,31 +764,52 @@ dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), random = ssl_ssl2:client_random(ChallengeData, CDLength), session_id = 0, cipher_suites = from_3bytes(CipherSuites), - compression_methods = [?NULL] + compression_methods = [?NULL], + renegotiation_info = undefined }; dec_hs(?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID:SID_length/binary, ?UINT16(Cs_length), CipherSuites:Cs_length/binary, ?BYTE(Cm_length), Comp_methods:Cm_length/binary, - _FutureCompatData/binary>>, + Extensions/binary>>, _, _) -> + + RenegotiationInfo = proplists:get_value(renegotiation_info, dec_hello_extensions(Extensions), + undefined), #client_hello{ client_version = {Major,Minor}, random = Random, session_id = Session_ID, cipher_suites = from_2bytes(CipherSuites), - compression_methods = Comp_methods + compression_methods = Comp_methods, + renegotiation_info = RenegotiationInfo }; + dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID:SID_length/binary, - Cipher_suite:2/binary, ?BYTE(Comp_method)>>, _, _) -> + Cipher_suite:2/binary, ?BYTE(Comp_method)>>, _, _) -> #server_hello{ server_version = {Major,Minor}, random = Random, session_id = Session_ID, cipher_suite = Cipher_suite, - compression_method = Comp_method - }; + compression_method = Comp_method, + renegotiation_info = undefined}; + +dec_hs(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, + ?BYTE(SID_length), Session_ID:SID_length/binary, + Cipher_suite:2/binary, ?BYTE(Comp_method), + ?UINT16(ExtLen), Extensions:ExtLen/binary>>, _, _) -> + + RenegotiationInfo = proplists:get_value(renegotiation_info, dec_hello_extensions(Extensions, []), + undefined), + #server_hello{ + server_version = {Major,Minor}, + random = Random, + session_id = Session_ID, + cipher_suite = Cipher_suite, + compression_method = Comp_method, + renegotiation_info = RenegotiationInfo}; dec_hs(?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>, _, _) -> #certificate{asn1_certificates = certs_to_list(ASN1Certs)}; dec_hs(?SERVER_KEY_EXCHANGE, <<?UINT16(ModLen), Mod:ModLen/binary, @@ -707,6 +856,32 @@ dec_hs(?FINISHED, VerifyData, _, _) -> dec_hs(_, _, _, _) -> throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)). +dec_hello_extensions(<<>>) -> + []; +dec_hello_extensions(<<?UINT16(ExtLen), Extensions:ExtLen/binary>>) -> + dec_hello_extensions(Extensions, []); +dec_hello_extensions(_) -> + []. + +dec_hello_extensions(<<>>, Acc) -> + Acc; +dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binary, Rest/binary>>, Acc) -> + RenegotiateInfo = case Len of + 1 -> % Initial handshake + Info; % should be <<0>> will be matched in handle_renegotiation_info + _ -> + VerifyLen = Len - 1, + <<?BYTE(VerifyLen), VerifyInfo/binary>> = Info, + VerifyInfo + end, + dec_hello_extensions(Rest, [{renegotiation_info, + #renegotiation_info{renegotiated_connection = RenegotiateInfo}} | Acc]); +dec_hello_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len, Rest/binary>>, Acc) -> + dec_hello_extensions(Rest, Acc); +%% Need this clause? +dec_hello_extensions(_, Acc) -> + Acc. + encrypted_premaster_secret(Secret, RSAPublicKey) -> try PreMasterSecret = public_key:encrypt_public(Secret, RSAPublicKey, @@ -743,31 +918,36 @@ certs_from_list(ACList) -> enc_hs(#hello_request{}, _Version, _) -> {?HELLO_REQUEST, <<>>}; -enc_hs(#client_hello{ - client_version = {Major, Minor}, - random = Random, - session_id = SessionID, - cipher_suites = CipherSuites, - compression_methods = CompMethods}, _Version, _) -> +enc_hs(#client_hello{client_version = {Major, Minor}, + random = Random, + session_id = SessionID, + cipher_suites = CipherSuites, + compression_methods = CompMethods, + renegotiation_info = RenegotiationInfo}, _Version, _) -> SIDLength = byte_size(SessionID), BinCompMethods = list_to_binary(CompMethods), CmLength = byte_size(BinCompMethods), BinCipherSuites = list_to_binary(CipherSuites), CsLength = byte_size(BinCipherSuites), + Extensions = hello_extensions(RenegotiationInfo), + ExtensionsBin = enc_hello_extensions(Extensions), {?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SIDLength), SessionID/binary, ?UINT16(CsLength), BinCipherSuites/binary, - ?BYTE(CmLength), BinCompMethods/binary>>}; -enc_hs(#server_hello{ - server_version = {Major, Minor}, - random = Random, - session_id = Session_ID, - cipher_suite = Cipher_suite, - compression_method = Comp_method}, _Version, _) -> + ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>}; + +enc_hs(#server_hello{server_version = {Major, Minor}, + random = Random, + session_id = Session_ID, + cipher_suite = Cipher_suite, + compression_method = Comp_method, + renegotiation_info = RenegotiationInfo}, _Version, _) -> SID_length = byte_size(Session_ID), + Extensions = hello_extensions(RenegotiationInfo), + ExtensionsBin = enc_hello_extensions(Extensions), {?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary, ?BYTE(SID_length), Session_ID/binary, - Cipher_suite/binary, ?BYTE(Comp_method)>>}; + Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>}; enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version, _) -> ASN1Certs = certs_from_list(ASN1CertList), ACLen = erlang:iolist_size(ASN1Certs), @@ -826,6 +1006,29 @@ enc_bin_sig(BinSig) -> Size = byte_size(BinSig), <<?UINT16(Size), BinSig/binary>>. +%% Renegotiation info, only current extension +hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) -> + []; +hello_extensions(#renegotiation_info{} = Info) -> + [Info]. + +enc_hello_extensions(Extensions) -> + enc_hello_extensions(Extensions, <<>>). +enc_hello_extensions([], <<>>) -> + <<>>; +enc_hello_extensions([], Acc) -> + Size = byte_size(Acc), + <<?UINT16(Size), Acc/binary>>; + +enc_hello_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = Info} | Rest], Acc) -> + Len = byte_size(Info), + enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info/binary, Acc/binary>>); + +enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest], Acc) -> + InfoLen = byte_size(Info), + Len = InfoLen +1, + enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>). + init_hashes() -> T = {crypto:md5_init(), crypto:sha_init()}, {T, T}. diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl index 889d39f2af..74fba3786c 100644 --- a/lib/ssl/src/ssl_handshake.hrl +++ b/lib/ssl/src/ssl_handshake.hrl @@ -81,7 +81,8 @@ random, session_id, % opaque SessionID<0..32> cipher_suites, % cipher_suites<2..2^16-1> - compression_methods % compression_methods<1..2^8-1> + compression_methods, % compression_methods<1..2^8-1>, + renegotiation_info }). -record(server_hello, { @@ -89,7 +90,8 @@ random, session_id, % opaque SessionID<0..32> cipher_suite, % cipher_suites - compression_method % compression_method + compression_method, % compression_method + renegotiation_info }). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -195,6 +197,15 @@ verify_data %opaque verify_data[12] }). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Renegotiation info RFC 5746 section 3.2 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(RENEGOTIATION_EXT, 16#ff01). + +-record(renegotiation_info,{ + renegotiated_connection + }). + -endif. % -ifdef(ssl_handshake). diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 8d19abfe1e..fdc0c33750 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -75,6 +75,7 @@ %% will be reused if possible. reuse_sessions, % boolean() renegotiate_at, + secure_renegotiate, debug % }). diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl index da48f049f6..f9f915f13d 100644 --- a/lib/ssl/src/ssl_record.erl +++ b/lib/ssl/src/ssl_record.erl @@ -38,7 +38,10 @@ set_mac_secret/4, set_master_secret/2, activate_pending_connection_state/2, - set_pending_cipher_state/4]). + set_pending_cipher_state/4, + set_renegotiation_flag/2, + set_client_verify_data/3, + set_server_verify_data/3]). %% Handling of incoming data -export([get_tls_records/2]). @@ -175,6 +178,98 @@ set_master_secret(MasterSecret, master_secret = MasterSecret}}, States#connection_states{pending_read = Read1, pending_write = Write1}. +%%-------------------------------------------------------------------- +%% Function: set_renegotiation_flag(Flag, States) -> +%% #connection_states{} +%% Flag = boolean() +%% States = #connection_states{} +%% +%% Set master_secret in pending connection states +%%-------------------------------------------------------------------- +set_renegotiation_flag(Flag, #connection_states{ + current_read = CurrentRead0, + current_write = CurrentWrite0, + pending_read = PendingRead0, + pending_write = PendingWrite0} + = ConnectionStates) -> + CurrentRead = CurrentRead0#connection_state{secure_renegotiation = Flag}, + CurrentWrite = CurrentWrite0#connection_state{secure_renegotiation = Flag}, + PendingRead = PendingRead0#connection_state{secure_renegotiation = Flag}, + PendingWrite = PendingWrite0#connection_state{secure_renegotiation = Flag}, + ConnectionStates#connection_states{current_read = CurrentRead, + current_write = CurrentWrite, + pending_read = PendingRead, + pending_write = PendingWrite}. + +%%-------------------------------------------------------------------- +%% Function: set_client_verify_data(State, Data, States) -> +%% #connection_states{} +%% State = atom() +%% Data = binary() +%% States = #connection_states{} +%% +%% Set verify data in connection states. +%%-------------------------------------------------------------------- +set_client_verify_data(current_read, Data, + #connection_states{current_read = CurrentRead0, + pending_write = PendingWrite0} + = ConnectionStates) -> + CurrentRead = CurrentRead0#connection_state{client_verify_data = Data}, + PendingWrite = PendingWrite0#connection_state{client_verify_data = Data}, + ConnectionStates#connection_states{current_read = CurrentRead, + pending_write = PendingWrite}; +set_client_verify_data(current_write, Data, + #connection_states{pending_read = PendingRead0, + current_write = CurrentWrite0} + = ConnectionStates) -> + PendingRead = PendingRead0#connection_state{client_verify_data = Data}, + CurrentWrite = CurrentWrite0#connection_state{client_verify_data = Data}, + ConnectionStates#connection_states{pending_read = PendingRead, + current_write = CurrentWrite}; +set_client_verify_data(current_both, Data, + #connection_states{current_read = CurrentRead0, + current_write = CurrentWrite0} + = ConnectionStates) -> + CurrentRead = CurrentRead0#connection_state{client_verify_data = Data}, + CurrentWrite = CurrentWrite0#connection_state{client_verify_data = Data}, + ConnectionStates#connection_states{current_read = CurrentRead, + current_write = CurrentWrite}. + +%%-------------------------------------------------------------------- +%% Function: set_server_verify_data(State, Data, States) -> +%% #connection_states{} +%% State = atom() +%% Data = binary() +%% States = #connection_states{} +%% +%% Set verify data in pending connection states. +%%-------------------------------------------------------------------- +set_server_verify_data(current_write, Data, + #connection_states{pending_read = PendingRead0, + current_write = CurrentWrite0} + = ConnectionStates) -> + PendingRead = PendingRead0#connection_state{server_verify_data = Data}, + CurrentWrite = CurrentWrite0#connection_state{server_verify_data = Data}, + ConnectionStates#connection_states{pending_read = PendingRead, + current_write = CurrentWrite}; + +set_server_verify_data(current_read, Data, + #connection_states{current_read = CurrentRead0, + pending_write = PendingWrite0} + = ConnectionStates) -> + CurrentRead = CurrentRead0#connection_state{server_verify_data = Data}, + PendingWrite = PendingWrite0#connection_state{server_verify_data = Data}, + ConnectionStates#connection_states{current_read = CurrentRead, + pending_write = PendingWrite}; + +set_server_verify_data(current_both, Data, + #connection_states{current_read = CurrentRead0, + current_write = CurrentWrite0} + = ConnectionStates) -> + CurrentRead = CurrentRead0#connection_state{server_verify_data = Data}, + CurrentWrite = CurrentWrite0#connection_state{server_verify_data = Data}, + ConnectionStates#connection_states{current_read = CurrentRead, + current_write = CurrentWrite}. %%-------------------------------------------------------------------- %% Function: activate_pending_connection_state(States, Type) -> @@ -191,7 +286,9 @@ activate_pending_connection_state(States = NewCurrent = Pending#connection_state{sequence_number = 0}, SecParams = Pending#connection_state.security_parameters, ConnectionEnd = SecParams#security_parameters.connection_end, - NewPending = empty_connection_state(ConnectionEnd), + EmptyPending = empty_connection_state(ConnectionEnd), + SecureRenegotation = NewCurrent#connection_state.secure_renegotiation, + NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation}, States#connection_states{current_read = NewCurrent, pending_read = NewPending }; @@ -202,7 +299,9 @@ activate_pending_connection_state(States = NewCurrent = Pending#connection_state{sequence_number = 0}, SecParams = Pending#connection_state.security_parameters, ConnectionEnd = SecParams#security_parameters.connection_end, - NewPending = empty_connection_state(ConnectionEnd), + EmptyPending = empty_connection_state(ConnectionEnd), + SecureRenegotation = NewCurrent#connection_state.secure_renegotiation, + NewPending = EmptyPending#connection_state{secure_renegotiation = SecureRenegotation}, States#connection_states{current_write = NewCurrent, pending_write = NewPending }. diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl index 362b7039d4..5fb0070b91 100644 --- a/lib/ssl/src/ssl_record.hrl +++ b/lib/ssl/src/ssl_record.hrl @@ -60,7 +60,11 @@ compression_state, cipher_state, mac_secret, - sequence_number + sequence_number, + %% RFC 5746 + secure_renegotiation, + client_verify_data, + server_verify_data }). -define(MAX_SEQENCE_NUMBER, 18446744073709552000). %% math:pow(2, 64) - 1 = 1.8446744073709552e19 diff --git a/lib/ssl/test/ssl.cover b/lib/ssl/test/ssl.cover index 138bf96b9d..e8daa363c5 100644 --- a/lib/ssl/test/ssl.cover +++ b/lib/ssl/test/ssl.cover @@ -3,5 +3,17 @@ 'PKIX1Explicit88', 'PKIX1Implicit88', 'PKIXAttributeCertificate', - 'SSL-PKIX']}. + 'SSL-PKIX', + ssl_pem, + ssl_pkix, + ssl_base64, + ssl_broker, + ssl_broker_int, + ssl_broker_sup, + ssl_debug, + ssl_server, + ssl_prim, + inet_ssl_dist, + 'OTP-PKIX' + ]}. diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 3ee82d990b..9afcbd9113 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -171,7 +171,8 @@ all(suite) -> client_verify_none_active, client_verify_none_active_once %%, session_cache_process_list, session_cache_process_mnesia ,reuse_session, reuse_session_expired, server_does_not_want_to_reuse_session, - client_renegotiate, server_renegotiate, + client_renegotiate, server_renegotiate, client_renegotiate_reused_session, + server_renegotiate_reused_session, client_no_wrap_sequence_number, server_no_wrap_sequence_number, extended_key_usage, validate_extensions_fun ]. @@ -665,7 +666,7 @@ misc_ssl_options(Config) when is_list(Config) -> {password, []}, {reuse_session, fun(_,_,_,_) -> true end}, {debug, []}, - {cb_info, {gen_tcp, tcp, tcp_closed}}], + {cb_info, {gen_tcp, tcp, tcp_closed, tcp_error}}], Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -2112,6 +2113,76 @@ server_renegotiate(Config) when is_list(Config) -> ok. %%-------------------------------------------------------------------- +client_renegotiate_reused_session(doc) -> + ["Test ssl:renegotiate/1 on client when the ssl session will be reused."]; + +client_renegotiate_reused_session(suite) -> + []; + +client_renegotiate_reused_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = + ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_reuse_session, [Data]}}, + {options, [{reuse_sessions, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Client, ok, Server, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + process_flag(trap_exit, false), + ok. +%%-------------------------------------------------------------------- +server_renegotiate_reused_session(doc) -> + ["Test ssl:renegotiate/1 on server when the ssl session will be reused."]; + +server_renegotiate_reused_session(suite) -> + []; + +server_renegotiate_reused_session(Config) when is_list(Config) -> + process_flag(trap_exit, true), + ServerOpts = ?config(server_opts, Config), + ClientOpts = ?config(client_opts, Config), + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Data = "From erlang to erlang", + + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + renegotiate_reuse_session, [Data]}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, erlang_ssl_receive, [Data]}}, + {options, [{reuse_sessions, true} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + ok. + +%%-------------------------------------------------------------------- client_no_wrap_sequence_number(doc) -> ["Test that erlang client will renegotiate session when", "max sequence number celing is about to be reached. Although" @@ -2314,14 +2385,14 @@ renegotiate(Socket, Data) -> case Result of ok -> ok; - %% It is not an error in erlang ssl - %% if peer rejects renegotiation. - %% Connection will stay up - {error, renegotiation_rejected} -> - ok; Other -> Other end. + +renegotiate_reuse_session(Socket, Data) -> + %% Make sure session is registerd + test_server:sleep(?SLEEP), + renegotiate(Socket, Data). session_cache_process_list(doc) -> ["Test reuse of sessions (short handshake)"]; diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index 186bf52ff6..03466aec6f 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -81,11 +81,20 @@ end_per_suite(_Config) -> %% variable, but should NOT alter/remove any existing entries. %% Description: Initialization before each test case %%-------------------------------------------------------------------- -init_per_testcase(_TestCase, Config0) -> +init_per_testcase(TestCase, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), Dog = ssl_test_lib:timetrap(?TIMEOUT), - [{watchdog, Dog} | Config]. + special_init(TestCase, [{watchdog, Dog} | Config]). +special_init(TestCase, Config) + when TestCase == erlang_client_openssl_server_renegotiate; + TestCase == erlang_client_openssl_server_no_wrap_sequence_number; + TestCase == erlang_server_openssl_client_no_wrap_sequence_number -> + check_sane_openssl_renegotaite(Config); + +special_init(_, Config) -> + Config. + %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ %% Case - atom() @@ -297,12 +306,8 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) -> test_server:sleep(?SLEEP), port_command(OpensslPort, OpenSslData), - %%ssl_test_lib:check_result(Client, ok), - %% Currently allow test case to not fail - %% if server requires secure renegotiation from RFC-5746 - %% This should be removed as soon as we have implemented it. - ssl_test_lib:check_result_ignore_renegotiation_reject(Client, ok), - + ssl_test_lib:check_result(Client, ok), + %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), @@ -350,11 +355,7 @@ erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config {options, [{reuse_sessions, false}, {renegotiate_at, N} | ClientOpts]}]), - %%ssl_test_lib:check_result(Client, ok), - %% Currently allow test case to not fail - %% if server requires secure renegotiation from RFC-5746 - %% This should be removed as soon as we have implemented it. - ssl_test_lib:check_result_ignore_renegotiation_reject(Client, ok), + ssl_test_lib:check_result(Client, ok), %% Clean close down! Server needs to be closed first !! close_port(OpensslPort), @@ -1080,3 +1081,10 @@ wait_for_openssl_server() -> test_server:sleep(?SLEEP) end. +check_sane_openssl_renegotaite(Config) -> + case os:cmd("openssl version") of + "OpenSSL 0.9.8l" ++ _ -> + {skip, "Known renegotiation bug in OppenSSL"}; + _ -> + Config + end. diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk index 6db1a4b5c2..e3db7008e3 100644 --- a/lib/ssl/vsn.mk +++ b/lib/ssl/vsn.mk @@ -19,7 +19,9 @@ SSL_VSN = 3.11.1 -TICKETS = OTP-8588 +TICKETS = OTP-8588 \ + OTP-8568 \ + OTP-7049 #TICKETS_3.11 = OTP-8517 \ # OTP-7046 \ diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl index 2183da8eea..c71dad6163 100644 --- a/lib/stdlib/src/beam_lib.erl +++ b/lib/stdlib/src/beam_lib.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(beam_lib). diff --git a/lib/syntax_tools/src/erl_comment_scan.erl b/lib/syntax_tools/src/erl_comment_scan.erl index 09ce21a428..e2c6976a2b 100644 --- a/lib/syntax_tools/src/erl_comment_scan.erl +++ b/lib/syntax_tools/src/erl_comment_scan.erl @@ -273,12 +273,8 @@ join_lines([], Txt, L, Col, Ind) -> filename([C|T]) when is_integer(C), C > 0, C =< 255 -> [C | filename(T)]; -filename([H|T]) -> - filename(H) ++ filename(T); filename([]) -> []; -filename(N) when is_atom(N) -> - atom_to_list(N); filename(N) -> report_error("bad filename: `~P'.", [N, 25]), exit(error). diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl index 606441bcf1..c2c72d1ed2 100644 --- a/lib/syntax_tools/src/erl_prettypr.erl +++ b/lib/syntax_tools/src/erl_prettypr.erl @@ -384,7 +384,7 @@ lay_postcomments(Cs, D) -> beside(D, floating(break(stack_comments(Cs, true)), 1, 0)). %% Format (including padding, if `Pad' is `true', otherwise not) -%% and stack the listed comments above each other, +%% and stack the listed comments above each other. stack_comments([C | Cs], Pad) -> D = stack_comment_lines(erl_syntax:comment_text(C)), @@ -405,9 +405,7 @@ stack_comments([C | Cs], Pad) -> D1; % done _ -> above(D1, stack_comments(Cs, Pad)) - end; -stack_comments([], _) -> - empty(). + end. %% Stack lines of text above each other and prefix each string in %% the list with a single `%' character. diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl index e92e9593b6..702b399615 100644 --- a/lib/syntax_tools/src/igor.erl +++ b/lib/syntax_tools/src/igor.erl @@ -699,7 +699,7 @@ merge_files(Name, Trees, Files, Opts) -> options :: [option()] }). --spec merge_sources(atom(), erl_syntax:forms(), [option()]) -> +-spec merge_sources(atom(), [erl_syntax:forms()], [option()]) -> {erl_syntax:syntaxTree(), [stubDescriptor()]}. merge_sources(Name, Sources, Opts) -> @@ -782,12 +782,12 @@ merge_sources_1(Name, Modules, Trees, Opts) -> %% however not "safe" by default. If no modules are explicitly %% specified as static, it is assumed that *all* are static. Static0 = ordsets:from_list(proplists:append_values(static, Opts)), - case proplists:is_defined(static, Opts) of - false -> - Static = All; - true -> - Static = ordsets:add_element(Name, Static0) - end, + Static = case proplists:is_defined(static, Opts) of + false -> + All; + true -> + ordsets:add_element(Name, Static0) + end, check_module_names(Static, All, "declared 'static'"), verbose("static modules: ~p.", [Static], Opts), @@ -806,8 +806,8 @@ merge_sources_1(Name, Modules, Trees, Opts) -> verbose("safe modules: ~p.", [Safe], Opts), Preserved = (ordsets:is_element(Name, Sources) - and ordsets:is_element(Name, Export)) - or proplists:get_bool(no_banner, Opts), + andalso ordsets:is_element(Name, Export)) + orelse proplists:get_bool(no_banner, Opts), NoHeaders = proplists:get_bool(no_headers, Opts), Notes = proplists:get_value(notes, Opts, always), Rs = proplists:append_values(redirect, Opts), @@ -2924,9 +2924,7 @@ make_attribute({Name, Term}) -> [erl_syntax:abstract(Term)]). is_auto_import({F, A}) -> - erl_internal:bif(F, A); -is_auto_import(_) -> - false. + erl_internal:bif(F, A). timestamp() -> {{Yr, Mth, Dy}, {Hr, Mt, Sc}} = erlang:localtime(), diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index a84f40244d..0132587d28 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -988,7 +988,7 @@ behaviour.") (list (concat "^\\(-" erlang-atom-regexp "\\)\\(\\s-\\|\\.\\|(\\)") 1 (if (boundp 'font-lock-preprocessor-face) 'font-lock-preprocessor-face - 'font-lock-function-name-face))) + 'font-lock-constant-face))) "Font lock keyword highlighting attributes.") (defvar erlang-font-lock-keywords-quotes @@ -1019,10 +1019,12 @@ are highlighted by syntactic analysis.") (list (list (concat "?\\s-*\\(" erlang-atom-regexp "\\|" erlang-variable-regexp "\\)") - 1 'font-lock-type-face) + 1 'font-lock-constant-face) (list (concat "^\\(-\\(?:define\\|ifn?def\\)\\)\\s-*(\\s-*\\(" erlang-atom-regexp "\\|" erlang-variable-regexp "\\)") - (list 1 'font-lock-preprocessor-face t) + (if (boundp 'font-lock-preprocessor-face) + (list 1 'font-lock-preprocessor-face t) + (list 1 'font-lock-constant-face t)) (list 3 'font-lock-type-face t t)) (list "^-e\\(lse\\|ndif\\)\\>" 0 'font-lock-preprocessor-face t)) "Font lock keyword highlighting macros. diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in index 5a0b4ce8ef..8710641b57 100644 --- a/lib/wx/c_src/Makefile.in +++ b/lib/wx/c_src/Makefile.in @@ -167,7 +167,7 @@ release_spec: opt $(INSTALL_DIR) $(RELSYSDIR)/priv/$(SYS_TYPE) $(INSTALL_DATA) ../priv/erlang-logo32.png $(RELSYSDIR)/priv/ $(INSTALL_DATA) ../priv/erlang-logo64.png $(RELSYSDIR)/priv/ - $(INSTALL_DATA) $(TARGET_DIR)/$(TARGET_API)$(SO_EXT) $(RELSYSDIR)/priv/$(SYS_TYPE) + $(INSTALL_PROGRAM) $(TARGET_DIR)/$(TARGET_API)$(SO_EXT) $(RELSYSDIR)/priv/$(SYS_TYPE) release_docs_spec: |