xcrypt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +106 -0
  3. data/ext/libxcrypt/AUTHORS +38 -0
  4. data/ext/libxcrypt/COPYING.LIB +502 -0
  5. data/ext/libxcrypt/ChangeLog +239 -0
  6. data/ext/libxcrypt/INSTALL +380 -0
  7. data/ext/libxcrypt/LICENSING +152 -0
  8. data/ext/libxcrypt/Makefile.am +704 -0
  9. data/ext/libxcrypt/Makefile.in +4110 -0
  10. data/ext/libxcrypt/NEWS +630 -0
  11. data/ext/libxcrypt/README +1 -0
  12. data/ext/libxcrypt/README.md +179 -0
  13. data/ext/libxcrypt/THANKS +13 -0
  14. data/ext/libxcrypt/TODO +1 -0
  15. data/ext/libxcrypt/TODO.md +100 -0
  16. data/ext/libxcrypt/aclocal.m4 +2617 -0
  17. data/ext/libxcrypt/autogen.sh +33 -0
  18. data/ext/libxcrypt/autom4te.cache/output.0 +19884 -0
  19. data/ext/libxcrypt/autom4te.cache/output.1 +19884 -0
  20. data/ext/libxcrypt/autom4te.cache/output.2 +19884 -0
  21. data/ext/libxcrypt/autom4te.cache/output.3 +19885 -0
  22. data/ext/libxcrypt/autom4te.cache/requests +714 -0
  23. data/ext/libxcrypt/autom4te.cache/traces.0 +4088 -0
  24. data/ext/libxcrypt/autom4te.cache/traces.1 +1060 -0
  25. data/ext/libxcrypt/autom4te.cache/traces.2 +4088 -0
  26. data/ext/libxcrypt/autom4te.cache/traces.3 +1060 -0
  27. data/ext/libxcrypt/build-aux/ci/ci-log-dependency-versions +79 -0
  28. data/ext/libxcrypt/build-aux/ci/ci-log-logfiles +22 -0
  29. data/ext/libxcrypt/build-aux/ci/clang-gcov-wrapper +2 -0
  30. data/ext/libxcrypt/build-aux/ci/configure-wrapper +10 -0
  31. data/ext/libxcrypt/build-aux/ci/summarize-coverage +24 -0
  32. data/ext/libxcrypt/build-aux/m4/ax_append_compile_flags.m4 +46 -0
  33. data/ext/libxcrypt/build-aux/m4/ax_append_flag.m4 +50 -0
  34. data/ext/libxcrypt/build-aux/m4/ax_check_compile_flag.m4 +53 -0
  35. data/ext/libxcrypt/build-aux/m4/ax_check_vscript.m4 +142 -0
  36. data/ext/libxcrypt/build-aux/m4/ax_gcc_func_attribute.m4 +246 -0
  37. data/ext/libxcrypt/build-aux/m4/ax_require_defined.m4 +37 -0
  38. data/ext/libxcrypt/build-aux/m4/ax_valgrind_check.m4 +239 -0
  39. data/ext/libxcrypt/build-aux/m4/libtool.m4 +8488 -0
  40. data/ext/libxcrypt/build-aux/m4/ltoptions.m4 +467 -0
  41. data/ext/libxcrypt/build-aux/m4/ltsugar.m4 +124 -0
  42. data/ext/libxcrypt/build-aux/m4/ltversion.m4 +24 -0
  43. data/ext/libxcrypt/build-aux/m4/lt~obsolete.m4 +99 -0
  44. data/ext/libxcrypt/build-aux/m4/pkg_compat.m4 +88 -0
  45. data/ext/libxcrypt/build-aux/m4/zw_alignment.m4 +90 -0
  46. data/ext/libxcrypt/build-aux/m4/zw_automodern.m4 +307 -0
  47. data/ext/libxcrypt/build-aux/m4/zw_detect_asan.m4 +24 -0
  48. data/ext/libxcrypt/build-aux/m4/zw_endianness.m4 +152 -0
  49. data/ext/libxcrypt/build-aux/m4/zw_ld_wrap.m4 +47 -0
  50. data/ext/libxcrypt/build-aux/m4/zw_prog_perl.m4 +40 -0
  51. data/ext/libxcrypt/build-aux/m4/zw_simple_warnings.m4 +150 -0
  52. data/ext/libxcrypt/build-aux/m4/zw_static_assert.m4 +68 -0
  53. data/ext/libxcrypt/build-aux/m4-autogen/compile +364 -0
  54. data/ext/libxcrypt/build-aux/m4-autogen/config.guess +1815 -0
  55. data/ext/libxcrypt/build-aux/m4-autogen/config.sub +2354 -0
  56. data/ext/libxcrypt/build-aux/m4-autogen/depcomp +792 -0
  57. data/ext/libxcrypt/build-aux/m4-autogen/install-sh +541 -0
  58. data/ext/libxcrypt/build-aux/m4-autogen/ltmain.sh +11524 -0
  59. data/ext/libxcrypt/build-aux/m4-autogen/missing +236 -0
  60. data/ext/libxcrypt/build-aux/m4-autogen/test-driver +160 -0
  61. data/ext/libxcrypt/build-aux/scripts/BuildCommon.pm +712 -0
  62. data/ext/libxcrypt/build-aux/scripts/check-perlcritic-config +76 -0
  63. data/ext/libxcrypt/build-aux/scripts/compute-symver-floor +116 -0
  64. data/ext/libxcrypt/build-aux/scripts/expand-selected-hashes +80 -0
  65. data/ext/libxcrypt/build-aux/scripts/gen-crypt-h +131 -0
  66. data/ext/libxcrypt/build-aux/scripts/gen-crypt-hashes-h +141 -0
  67. data/ext/libxcrypt/build-aux/scripts/gen-crypt-symbol-vers-h +150 -0
  68. data/ext/libxcrypt/build-aux/scripts/gen-libcrypt-map +67 -0
  69. data/ext/libxcrypt/build-aux/scripts/move-if-change +84 -0
  70. data/ext/libxcrypt/build-aux/scripts/skip-if-exec-format-error +78 -0
  71. data/ext/libxcrypt/codecov.yml +4 -0
  72. data/ext/libxcrypt/config.h.in +303 -0
  73. data/ext/libxcrypt/configure +19885 -0
  74. data/ext/libxcrypt/configure.ac +549 -0
  75. data/ext/libxcrypt/doc/crypt.3 +512 -0
  76. data/ext/libxcrypt/doc/crypt.5 +343 -0
  77. data/ext/libxcrypt/doc/crypt_checksalt.3 +106 -0
  78. data/ext/libxcrypt/doc/crypt_gensalt.3 +285 -0
  79. data/ext/libxcrypt/doc/crypt_gensalt_ra.3 +1 -0
  80. data/ext/libxcrypt/doc/crypt_gensalt_rn.3 +1 -0
  81. data/ext/libxcrypt/doc/crypt_preferred_method.3 +68 -0
  82. data/ext/libxcrypt/doc/crypt_r.3 +1 -0
  83. data/ext/libxcrypt/doc/crypt_ra.3 +1 -0
  84. data/ext/libxcrypt/doc/crypt_rn.3 +1 -0
  85. data/ext/libxcrypt/lib/alg-des-tables.c +3858 -0
  86. data/ext/libxcrypt/lib/alg-des.c +269 -0
  87. data/ext/libxcrypt/lib/alg-des.h +74 -0
  88. data/ext/libxcrypt/lib/alg-gost3411-2012-const.h +313 -0
  89. data/ext/libxcrypt/lib/alg-gost3411-2012-core.c +238 -0
  90. data/ext/libxcrypt/lib/alg-gost3411-2012-core.h +51 -0
  91. data/ext/libxcrypt/lib/alg-gost3411-2012-hmac.c +78 -0
  92. data/ext/libxcrypt/lib/alg-gost3411-2012-hmac.h +46 -0
  93. data/ext/libxcrypt/lib/alg-gost3411-2012-precalc.h +1426 -0
  94. data/ext/libxcrypt/lib/alg-gost3411-2012-ref.h +67 -0
  95. data/ext/libxcrypt/lib/alg-hmac-sha1.c +140 -0
  96. data/ext/libxcrypt/lib/alg-hmac-sha1.h +35 -0
  97. data/ext/libxcrypt/lib/alg-md4.c +270 -0
  98. data/ext/libxcrypt/lib/alg-md4.h +43 -0
  99. data/ext/libxcrypt/lib/alg-md5.c +291 -0
  100. data/ext/libxcrypt/lib/alg-md5.h +43 -0
  101. data/ext/libxcrypt/lib/alg-sha1.c +288 -0
  102. data/ext/libxcrypt/lib/alg-sha1.h +34 -0
  103. data/ext/libxcrypt/lib/alg-sha256.c +630 -0
  104. data/ext/libxcrypt/lib/alg-sha256.h +123 -0
  105. data/ext/libxcrypt/lib/alg-sha512.c +311 -0
  106. data/ext/libxcrypt/lib/alg-sha512.h +81 -0
  107. data/ext/libxcrypt/lib/alg-sm3-hmac.c +113 -0
  108. data/ext/libxcrypt/lib/alg-sm3-hmac.h +42 -0
  109. data/ext/libxcrypt/lib/alg-sm3.c +449 -0
  110. data/ext/libxcrypt/lib/alg-sm3.h +63 -0
  111. data/ext/libxcrypt/lib/alg-yescrypt-common.c +713 -0
  112. data/ext/libxcrypt/lib/alg-yescrypt-opt.c +1568 -0
  113. data/ext/libxcrypt/lib/alg-yescrypt-platform.c +106 -0
  114. data/ext/libxcrypt/lib/alg-yescrypt.h +360 -0
  115. data/ext/libxcrypt/lib/byteorder.h +164 -0
  116. data/ext/libxcrypt/lib/crypt-bcrypt.c +1061 -0
  117. data/ext/libxcrypt/lib/crypt-des-obsolete.c +215 -0
  118. data/ext/libxcrypt/lib/crypt-des.c +491 -0
  119. data/ext/libxcrypt/lib/crypt-gensalt-static.c +40 -0
  120. data/ext/libxcrypt/lib/crypt-gost-yescrypt.c +182 -0
  121. data/ext/libxcrypt/lib/crypt-md5.c +232 -0
  122. data/ext/libxcrypt/lib/crypt-nthash.c +134 -0
  123. data/ext/libxcrypt/lib/crypt-obsolete.h +40 -0
  124. data/ext/libxcrypt/lib/crypt-pbkdf1-sha1.c +260 -0
  125. data/ext/libxcrypt/lib/crypt-port.h +514 -0
  126. data/ext/libxcrypt/lib/crypt-scrypt.c +247 -0
  127. data/ext/libxcrypt/lib/crypt-sha256.c +308 -0
  128. data/ext/libxcrypt/lib/crypt-sha512.c +323 -0
  129. data/ext/libxcrypt/lib/crypt-sm3-yescrypt.c +189 -0
  130. data/ext/libxcrypt/lib/crypt-sm3.c +308 -0
  131. data/ext/libxcrypt/lib/crypt-static.c +44 -0
  132. data/ext/libxcrypt/lib/crypt-sunmd5.c +314 -0
  133. data/ext/libxcrypt/lib/crypt-yescrypt.c +177 -0
  134. data/ext/libxcrypt/lib/crypt.c +421 -0
  135. data/ext/libxcrypt/lib/crypt.h.in +249 -0
  136. data/ext/libxcrypt/lib/gen-des-tables.c +363 -0
  137. data/ext/libxcrypt/lib/hashes.conf +59 -0
  138. data/ext/libxcrypt/lib/libcrypt.map.in +48 -0
  139. data/ext/libxcrypt/lib/libcrypt.minver +97 -0
  140. data/ext/libxcrypt/lib/libxcrypt.pc.in +15 -0
  141. data/ext/libxcrypt/lib/util-base64.c +26 -0
  142. data/ext/libxcrypt/lib/util-gensalt-sha.c +88 -0
  143. data/ext/libxcrypt/lib/util-get-random-bytes.c +154 -0
  144. data/ext/libxcrypt/lib/util-make-failure-token.c +48 -0
  145. data/ext/libxcrypt/lib/util-xbzero.c +43 -0
  146. data/ext/libxcrypt/lib/util-xstrcpy.c +42 -0
  147. data/ext/libxcrypt/lib/xcrypt.h.in +58 -0
  148. data/ext/libxcrypt/libxcrypt.spec.rpkg +481 -0
  149. data/ext/libxcrypt/rpkg.conf +2 -0
  150. data/ext/libxcrypt/rpkg.macros +86 -0
  151. data/ext/libxcrypt/test/TestCommon.pm +326 -0
  152. data/ext/libxcrypt/test/alg-des.c +80 -0
  153. data/ext/libxcrypt/test/alg-gost3411-2012-hmac.c +90 -0
  154. data/ext/libxcrypt/test/alg-gost3411-2012.c +191 -0
  155. data/ext/libxcrypt/test/alg-hmac-sha1.c +187 -0
  156. data/ext/libxcrypt/test/alg-md4.c +111 -0
  157. data/ext/libxcrypt/test/alg-md5.c +134 -0
  158. data/ext/libxcrypt/test/alg-pbkdf-hmac-sha256.c +269 -0
  159. data/ext/libxcrypt/test/alg-sha1.c +111 -0
  160. data/ext/libxcrypt/test/alg-sha256.c +141 -0
  161. data/ext/libxcrypt/test/alg-sha512.c +170 -0
  162. data/ext/libxcrypt/test/alg-sm3-hmac.c +149 -0
  163. data/ext/libxcrypt/test/alg-sm3.c +168 -0
  164. data/ext/libxcrypt/test/alg-yescrypt.c +466 -0
  165. data/ext/libxcrypt/test/badsalt.c +726 -0
  166. data/ext/libxcrypt/test/badsetting.c +350 -0
  167. data/ext/libxcrypt/test/byteorder.c +254 -0
  168. data/ext/libxcrypt/test/checksalt.c +265 -0
  169. data/ext/libxcrypt/test/compile-strong-alias.c +43 -0
  170. data/ext/libxcrypt/test/crypt-badargs.c +392 -0
  171. data/ext/libxcrypt/test/crypt-gost-yescrypt.c +149 -0
  172. data/ext/libxcrypt/test/crypt-nested-call.c +180 -0
  173. data/ext/libxcrypt/test/crypt-sm3-yescrypt.c +149 -0
  174. data/ext/libxcrypt/test/crypt-too-long-phrase.c +157 -0
  175. data/ext/libxcrypt/test/des-cases.h +196 -0
  176. data/ext/libxcrypt/test/des-obsolete.c +206 -0
  177. data/ext/libxcrypt/test/des-obsolete_r.c +207 -0
  178. data/ext/libxcrypt/test/explicit-bzero.c +334 -0
  179. data/ext/libxcrypt/test/gensalt-bcrypt_x.c +54 -0
  180. data/ext/libxcrypt/test/gensalt-extradata.c +246 -0
  181. data/ext/libxcrypt/test/gensalt-nested-call.c +126 -0
  182. data/ext/libxcrypt/test/gensalt-nthash.c +65 -0
  183. data/ext/libxcrypt/test/gensalt.c +599 -0
  184. data/ext/libxcrypt/test/getrandom-fallbacks.c +295 -0
  185. data/ext/libxcrypt/test/getrandom-interface.c +211 -0
  186. data/ext/libxcrypt/test/ka-table-gen.py +945 -0
  187. data/ext/libxcrypt/test/ka-table.inc +5849 -0
  188. data/ext/libxcrypt/test/ka-tester.c +240 -0
  189. data/ext/libxcrypt/test/preferred-method.c +133 -0
  190. data/ext/libxcrypt/test/short-outbuf.c +119 -0
  191. data/ext/libxcrypt/test/special-char-salt.c +1160 -0
  192. data/ext/libxcrypt/test/symbols-compat.pl +137 -0
  193. data/ext/libxcrypt/test/symbols-renames.pl +107 -0
  194. data/ext/libxcrypt/test/symbols-static.pl +87 -0
  195. data/ext/xcrypt/xcrypt.c +9 -0
  196. data/lib/xcrypt/ffi.rb +76 -0
  197. data/lib/xcrypt/version.rb +5 -0
  198. data/lib/xcrypt.rb +89 -0
  199. metadata +267 -0
@@ -0,0 +1,712 @@
1
+ # Written by Zack Weinberg <zackw at panix.com> in 2017 and 2020.
2
+ # To the extent possible under law, Zack Weinberg has waived all
3
+ # copyright and related or neighboring rights to this work.
4
+ #
5
+ # See https://creativecommons.org/publicdomain/zero/1.0/ for further
6
+ # details.
7
+
8
+ package BuildCommon;
9
+
10
+ use v5.14; # implicit use strict, use feature ':5.14'
11
+ use warnings FATAL => 'all';
12
+ use utf8;
13
+ use open qw(:utf8);
14
+ no if $] >= 5.022, warnings => 'experimental::re_strict';
15
+ use if $] >= 5.022, re => 'strict';
16
+
17
+ use Cwd qw(realpath);
18
+ use File::Spec::Functions qw(
19
+ catfile
20
+ catpath
21
+ file_name_is_absolute
22
+ path
23
+ splitpath
24
+ );
25
+ use FindBin ();
26
+ use POSIX ();
27
+
28
+ our @EXPORT_OK;
29
+ use Exporter qw(import);
30
+
31
+ BEGIN {
32
+ @EXPORT_OK = qw(
33
+ enabled_set
34
+ ensure_C_locale
35
+ error
36
+ parse_hashes_conf
37
+ parse_version_map_in
38
+ popen
39
+ sh_split
40
+ sh_quote
41
+ subprocess_error
42
+ which
43
+ );
44
+ }
45
+
46
+ #
47
+ # Utilities for dealing with subprocesses.
48
+ #
49
+
50
+ # Diagnostics: report some kind of catastrophic internal error.
51
+ # Exit code 99 tells the Automake test driver to mark a test as
52
+ # 'errored' rather than 'failed'.
53
+ sub error { ## no critic (Subroutines::RequireArgUnpacking)
54
+ my $msg = join q{ }, @_;
55
+ print {*STDERR} $FindBin::Script, ': ERROR: ', $msg, "\n";
56
+ exit 99;
57
+ }
58
+
59
+ # Like 'error', but the problem was with a subprocess, detected upon
60
+ # trying to start the program named as @_.
61
+ sub invocation_error { ## no critic (Subroutines::RequireArgUnpacking)
62
+ my $err = "$!";
63
+ my $cmd = join q{ }, @_;
64
+ error("failed to invoke $cmd: $err");
65
+ }
66
+
67
+ # Like 'error', but the problem was with a subprocess, detected upon
68
+ # termination of the program named as @_; interpret both $! and $?
69
+ # appropriately.
70
+ sub subprocess_error { ## no critic (Subroutines::RequireArgUnpacking)
71
+ my $syserr = $!;
72
+ my $status = $?;
73
+ my $cmd = join q{ }, @_;
74
+ if ($syserr) {
75
+ error("system error with pipe to $cmd: $syserr");
76
+
77
+ } elsif ($status == 0) {
78
+ return;
79
+
80
+ } elsif (($status & 0xFF) == 0) {
81
+ # we wouldn't be here if the exit status was zero
82
+ error("$cmd: exit " . ($status >> 8));
83
+
84
+ } else {
85
+ my $sig = ($status & 0x7F);
86
+ # Neither Perl core nor the POSIX module exposes strsignal.
87
+ # This is the least terrible kludge I can presently find;
88
+ # it decodes the numbers to their <signal.h> constant names
89
+ # (e.g. "SIGKILL" instead of "Killed" for signal 9).
90
+ # Linear search through POSIX's hundreds of symbols is
91
+ # acceptable because this function terminates the process,
92
+ # so it can only ever be called once per run.
93
+ my $signame;
94
+ while (my ($name, $glob) = each %{'POSIX::'}) {
95
+ if ($name =~ /^SIG(?!_|RT)/ && (${$glob} // -1) == $sig) {
96
+ $signame = $name;
97
+ last;
98
+ }
99
+ }
100
+ $signame //= "signal $sig";
101
+ error("$cmd: killed by $signame");
102
+ }
103
+ }
104
+
105
+ # Split a string into words, exactly the way the Bourne shell would do
106
+ # it, with the default setting of IFS, when the string is the result
107
+ # of a variable expansion. If any of the resulting words would be
108
+ # changed by filename expansion, throw an exception, otherwise return
109
+ # a list of the words.
110
+ #
111
+ # Note: the word splitting process does *not* look for nested
112
+ # quotation, substitutions, or operators. For instance, if a
113
+ # shell variable was set with
114
+ # var='"ab cd"'
115
+ # then './a.out $var' would pass two arguments to a.out:
116
+ # '"ab' and 'cd"'.
117
+ sub sh_split {
118
+ my @words = split /[ \t\n]+/, shift;
119
+ for my $w (@words) {
120
+ die "sh_split: '$w' could be changed by filename expansion"
121
+ if $w =~ / (?<! \\) [\[?*] /ax;
122
+ }
123
+ return @words;
124
+ }
125
+
126
+ # Quote a string, or list of strings, so that they will pass
127
+ # unmolested through the shell. Avoids adding quotation whenever
128
+ # possible. Algorithm copied from Python's shlex.quote.
129
+ sub sh_quote { ## no critic (Subroutines::RequireArgUnpacking)
130
+ my @quoted;
131
+ for my $w (@_) {
132
+ if ($w =~ m{[^\w@%+=:,./-]}a) {
133
+ my $q = $w;
134
+ $q =~ s/'/'\\''/g;
135
+ $q =~ s/^/'/;
136
+ $q =~ s/$/'/;
137
+ push @quoted, $q;
138
+ } else {
139
+ push @quoted, $w;
140
+ }
141
+ }
142
+ return wantarray ? @quoted : $quoted[0];
143
+ }
144
+
145
+ # Emit a logging message for the execution of a subprocess whose
146
+ # argument vector is @_.
147
+ sub log_execution { ## no critic (Subroutines::RequireArgUnpacking)
148
+ print {*STDERR} '+ ', join(q{ }, sh_quote(@_)), "\n";
149
+ return;
150
+ }
151
+
152
+ # Run, and log execution of, a subprocess. @_ should be one of the
153
+ # open modes that creates a pipe, followed by an argument vector.
154
+ # An anonymous filehandle for the pipe is returned.
155
+ # Calls invocation_error() if open() fails.
156
+ # Does *not* call which(); do that yourself if you need it.
157
+ sub popen {
158
+ my ($mode, @args) = @_;
159
+ die "popen: inappropriate mode argument '$mode'"
160
+ unless $mode eq '-|' || $mode eq '|-';
161
+ die 'popen: no command to execute'
162
+ if scalar(@args) == 0;
163
+
164
+ log_execution(@args);
165
+ open my $fh, $mode, @args
166
+ or invocation_error($args[0]);
167
+ return $fh;
168
+ }
169
+
170
+ # Force use of the C locale for this process and all subprocesses.
171
+ # This is necessary because subprocesses' output may be locale-
172
+ # dependent. If the C.UTF-8 locale is available, it is used,
173
+ # otherwise the plain C locale. Note that we do *not*
174
+ # 'use locale' here or anywhere else!
175
+ sub ensure_C_locale {
176
+ use POSIX qw(setlocale LC_ALL);
177
+
178
+ for my $k (keys %ENV) {
179
+ if ($k eq 'LANG' || $k eq 'LANGUAGE' || $k =~ /^LC_/) {
180
+ delete $ENV{$k};
181
+ }
182
+ }
183
+ if (defined(setlocale(LC_ALL, 'C.UTF-8'))) {
184
+ $ENV{LC_ALL} = 'C.UTF-8'; ## no critic (RequireLocalizedPunctuationVars)
185
+ } elsif (defined(setlocale(LC_ALL, 'C'))) {
186
+ $ENV{LC_ALL} = 'C'; ## no critic (RequireLocalizedPunctuationVars)
187
+ } else {
188
+ error("could not set 'C' locale: $!");
189
+ }
190
+ return;
191
+ }
192
+
193
+ # Clean up $ENV{PATH}, and return the cleaned path as a list.
194
+ sub clean_PATH {
195
+ state @path;
196
+ if (!@path) {
197
+ for my $d (path()) {
198
+ # Discard all entries that are not absolute paths.
199
+ next unless file_name_is_absolute($d);
200
+ # Discard all entries that are not directories, or don't
201
+ # exist. (This is not just for tidiness; realpath()
202
+ # behaves unpredictably if called on a nonexistent
203
+ # pathname.)
204
+ next unless -d $d;
205
+ # Resolve symlinks in all remaining entries.
206
+ $d = realpath($d);
207
+ # Discard duplicates.
208
+ push @path, $d unless grep { $_ eq $d } @path;
209
+ }
210
+ error('nothing left after cleaning PATH')
211
+ unless @path;
212
+
213
+ # File::Spec knows internally whether $PATH is colon-separated
214
+ # or semicolon-separated, but it won't tell us. Assume it's
215
+ # colon-separated unless the first element of $PATH has a
216
+ # colon in it (and is therefore probably a DOS-style absolute
217
+ # path, with a drive letter).
218
+ my $newpath;
219
+ if ($path[0] =~ /:/) {
220
+ $newpath = join ';', @path;
221
+ } else {
222
+ $newpath = join ':', @path;
223
+ }
224
+ $ENV{PATH} = $newpath; ## no critic (RequireLocalizedPunctuationVars)
225
+ }
226
+ return @path;
227
+ }
228
+
229
+ # Locate a program that we need.
230
+ # $_[0] is the name of the program along with any options that are
231
+ # required to use it correctly. Split this into an argument list,
232
+ # exactly as /bin/sh would do it, and then search $PATH for the
233
+ # executable. If we find it, return a list whose first element is
234
+ # the absolute pathname of the executable, followed by any options.
235
+ # Otherwise return an empty list.
236
+ sub which {
237
+ my ($command) = @_;
238
+ my @PATH = clean_PATH();
239
+
240
+ # Split the command name from any options attached to it.
241
+ my ($cmd, @options) = sh_split($command);
242
+ my ($vol, $path, $file) = splitpath($cmd);
243
+
244
+ if ($file eq 'false') {
245
+ # Special case: the command 'false' is never considered to be
246
+ # available. Autoconf sets config variables like $CC and $NM to
247
+ # 'false' if it can't find the requested tool.
248
+ return ();
249
+
250
+ } elsif ($file ne $cmd) {
251
+ # $cmd was not a bare filename. Do not do path search, but do
252
+ # verify that $cmd exists and is executable, then convert it
253
+ # to a canonical absolute path.
254
+ #
255
+ # Note: the result of realpath() is unspecified if its
256
+ # argument does not exist, so we must test its existence
257
+ # first.
258
+ #
259
+ # Note: if $file is a symlink, we must *not* resolve that
260
+ # symlink, because that may change the name of the program,
261
+ # which in turn may change what the program does.
262
+ # For instance, suppose $CC is /usr/lib/ccache/cc, and this
263
+ # 'cc' is a symlink to /usr/bin/ccache. Resolving the symlink
264
+ # will cause ccache to be invoked as 'ccache' instead of 'cc'
265
+ # and it will error out because it's no longer being told
266
+ # it's supposed to run the compiler.
267
+ if (-f -x $cmd) {
268
+ return (catfile(realpath(catpath($vol, $path, q{})), $file),
269
+ @options);
270
+ } else {
271
+ return ();
272
+ }
273
+
274
+ } else {
275
+ for my $d (@PATH) {
276
+ my $cand = catfile($d, $cmd);
277
+ if (-f -x $cand) {
278
+ # @PATH came from clean_PATH, so all of the directories
279
+ # have already been canonicalized. If the last element
280
+ # of $cand is a symlink, we should *not* resolve it (see
281
+ # above). Therefore, we do not call realpath here.
282
+ return ($cand, @options);
283
+ }
284
+ }
285
+ return ();
286
+
287
+ }
288
+ }
289
+
290
+ #
291
+ # Code shared among scripts that work from hashes.conf
292
+ #
293
+
294
+ use Class::Struct HashSpec => [
295
+ name => '$',
296
+ prefix => '$',
297
+ nrbytes => '$',
298
+ is_strong => '$',
299
+ ];
300
+ use Class::Struct HashesConfData => [
301
+ hashes => '*%',
302
+ groups => '*%',
303
+ max_namelen => '$',
304
+ max_nrbyteslen => '$',
305
+ max_prefixlen => '$',
306
+ default_candidates => '*@',
307
+ ];
308
+
309
+ # The canonical list of flags that can appear in the fourth field
310
+ # of a hashes.conf entry. Alphabetical, except for STRONG and
311
+ # DEFAULT.
312
+ my %VALID_FLAGS = (
313
+ STRONG => 1,
314
+ DEFAULT => 1,
315
+ ALT => 1,
316
+ DEBIAN => 1,
317
+ EULER => 1,
318
+ FEDORA => 1,
319
+ FREEBSD => 1,
320
+ GLIBC => 1,
321
+ KYLIN => 1,
322
+ NETBSD => 1,
323
+ OPENBSD => 1,
324
+ OSX => 1,
325
+ OWL => 1,
326
+ SOLARIS => 1,
327
+ SUSE => 1,
328
+ );
329
+
330
+ sub parse_hashes_conf {
331
+ my $fname = shift;
332
+ my $error = 0;
333
+
334
+ my $err = sub {
335
+ my ($line, $msg) = @_;
336
+ if (!defined $msg) {
337
+ $msg = $line;
338
+ $line = $.;
339
+ }
340
+ print {*STDERR} "$fname:$line: error: $msg\n";
341
+ $error = 1;
342
+ };
343
+ my $note = sub {
344
+ my ($line, $msg) = @_;
345
+ if (!defined $msg) {
346
+ $msg = $line;
347
+ $line = $.;
348
+ }
349
+ print {*STDERR} "$fname:$line: note: $msg\n";
350
+ };
351
+
352
+ open my $fh, '<', $fname
353
+ or die "$fname: $!\n";
354
+
355
+ my %line_of;
356
+ my %hashes;
357
+ my %groups;
358
+ my $max_namelen = 0;
359
+ my $max_nrbyteslen = 0;
360
+ my $max_prefixlen = 0;
361
+ my @default_candidates;
362
+ local $_;
363
+ while (<$fh>) {
364
+ next if /^#/;
365
+ chomp;
366
+ s/\s+$//;
367
+ next if $_ eq q{};
368
+
369
+ my @fields = split;
370
+ if (scalar(@fields) != 4) {
371
+ $err->('wrong number of fields');
372
+ next;
373
+ }
374
+ my ($name, $h_prefix, $nrbytes, $flags) = @fields;
375
+ my $default_cand = 0;
376
+ my $is_strong = 0;
377
+ my @grps;
378
+
379
+ if ($name eq ':') {
380
+ $err->('method name cannot be blank');
381
+ $name = "_missing_$.";
382
+ }
383
+
384
+ # No two hashing method names can be the same.
385
+ if (exists $line_of{$name}) {
386
+ $err->("method name '$name' reused");
387
+ $note->($line_of{$name}, 'previous use was here');
388
+ } else {
389
+ $line_of{$name} = $.;
390
+ if ($max_namelen < length $name) {
391
+ $max_namelen = length $name;
392
+ }
393
+ }
394
+
395
+ $h_prefix = q{} if $h_prefix eq ':';
396
+ if ($max_prefixlen < length $h_prefix) {
397
+ $max_prefixlen = length $h_prefix;
398
+ }
399
+
400
+ if ($nrbytes !~ /^[0-9]+$/ || $nrbytes == 0) {
401
+ $err->('nrbytes must be a positive integer');
402
+ $nrbytes = 1;
403
+ }
404
+
405
+ if ($max_nrbyteslen < length $nrbytes) {
406
+ $max_nrbyteslen = length $nrbytes;
407
+ }
408
+
409
+ $flags = q{} if $flags eq ':';
410
+ for (split /,/, $flags) {
411
+ if (!exists $VALID_FLAGS{$_}) {
412
+ $err->("unrecognized flag $_");
413
+ } elsif ($_ eq 'DEFAULT') {
414
+ $default_cand = 1;
415
+ } else {
416
+ push @grps, lc;
417
+ if ($_ eq 'STRONG') {
418
+ $is_strong = 1;
419
+ }
420
+ }
421
+ }
422
+ if ($default_cand && !$is_strong) {
423
+ $err->('weak hash marked as default candidate');
424
+ }
425
+
426
+ next if $error;
427
+
428
+ my $entry = HashSpec->new(
429
+ name => $name,
430
+ prefix => $h_prefix,
431
+ nrbytes => $nrbytes,
432
+ is_strong => $is_strong,
433
+ );
434
+ $hashes{$name} = $entry;
435
+ for my $g (@grps) {
436
+ push @{$groups{$g}}, $entry;
437
+ }
438
+ if ($default_cand) {
439
+ push @default_candidates, $entry;
440
+ }
441
+ }
442
+
443
+ # No hash prefix can be a prefix of any other hash prefix, except
444
+ # for the empty prefix.
445
+ for my $p (values %hashes) {
446
+ my $pp = $p->prefix;
447
+ next if $pp eq q{};
448
+ my $mpp = qr/^\Q$pp\E/;
449
+ for my $q (values %hashes) {
450
+ next if $p->name eq $q->name;
451
+ my $pq = $q->prefix;
452
+ next if $pq eq q{};
453
+ if ($pq =~ $mpp) {
454
+ $err->(
455
+ $line_of{$q->name},
456
+ "prefix collision: '$pq' begins with '$pp'",
457
+ );
458
+ $note->(
459
+ $line_of{$p->name},
460
+ "'$pp' used for hash '" . $p->name . q{'},
461
+ );
462
+ }
463
+ }
464
+ }
465
+
466
+ die "errors while parsing '$fname'\n" if $error;
467
+ return HashesConfData->new(
468
+ hashes => \%hashes,
469
+ groups => \%groups,
470
+ max_namelen => $max_namelen,
471
+ max_nrbyteslen => $max_nrbyteslen,
472
+ max_prefixlen => $max_prefixlen,
473
+ default_candidates => \@default_candidates,
474
+ );
475
+ }
476
+
477
+ sub enabled_set {
478
+ return map { $_ => 1 }
479
+ grep { $_ ne q{} }
480
+ split /,/,
481
+ shift;
482
+ }
483
+
484
+ #
485
+ # Code shared among scripts that work from libcrypt.map.in
486
+ #
487
+
488
+ use Class::Struct VersionedSymbol => [
489
+ name => '$',
490
+ included => '$',
491
+ compat_only => '$',
492
+ versions => '*@',
493
+ ];
494
+
495
+ use Class::Struct SymbolVersionMap => [
496
+ symbols => '*@',
497
+ versions => '*@',
498
+ basemap => '$',
499
+ max_symlen => '$',
500
+ ];
501
+
502
+ # Process command-line arguments to a program that works from a
503
+ # .map.in file. These are the name of the .map.in file plus var=value
504
+ # settings for SYMVER_MIN, SYMVER_FLOOR, and COMPAT_ABI, in any order.
505
+ sub parse_symver_args {
506
+ my (@args) = @_;
507
+ my $usage_error = sub {
508
+ print {*STDERR}
509
+ "${FindBin::Script}: usage: ",
510
+ 'SYMVER_MIN=value SYMVER_FLOOR=value ',
511
+ 'COMPAT_ABI=value libcrypt.map.in',
512
+ "\n";
513
+ exit 1;
514
+ };
515
+ $usage_error->() if scalar(@args) != 4;
516
+
517
+ my $map_in;
518
+ my $SYMVER_MIN;
519
+ my $SYMVER_FLOOR;
520
+ my $COMPAT_ABI;
521
+ local $_;
522
+ for (@args) {
523
+ if (/^SYMVER_MIN=(.+)$/) {
524
+ $usage_error->() if defined $SYMVER_MIN;
525
+ $SYMVER_MIN = $1;
526
+ } elsif (/^SYMVER_FLOOR=(.+)$/) {
527
+ $usage_error->() if defined $SYMVER_FLOOR;
528
+ $SYMVER_FLOOR = $1;
529
+ } elsif (/^COMPAT_ABI=(.+)$/) {
530
+ $usage_error->() if defined $COMPAT_ABI;
531
+ $COMPAT_ABI = $1;
532
+ } else {
533
+ $usage_error->() if defined $map_in;
534
+ $map_in = $_;
535
+ }
536
+ }
537
+ return $map_in, $SYMVER_MIN, $SYMVER_FLOOR, $COMPAT_ABI;
538
+ }
539
+
540
+ # Read a .map.in file and compute the set of symbol versions to be
541
+ # included in this build of the library.
542
+ #
543
+ # All compat symbol versions that do not match COMPAT_ABI are ignored.
544
+ # All symbol versions lower than SYMVER_MIN are discarded from the output.
545
+ # All symbol versions lower than SYMVER_FLOOR are replaced with SYMVER_FLOOR.
546
+ # SYMVER_FLOOR must be greater than or equal to SYMVER_MIN.
547
+ #
548
+ # The ordering of symbol versions is entirely controlled by the %chain
549
+ # directive, which must therefore list both all of the versions
550
+ # actually used for symbols, and all of the versions that might be
551
+ # used as SYMVER_MIN or SYMVER_FLOOR.
552
+ sub parse_version_map_in { ## no critic (Subroutines::RequireArgUnpacking)
553
+ my ($map_in, $SYMVER_MIN, $SYMVER_FLOOR, $COMPAT_ABI) =
554
+ parse_symver_args(@_);
555
+
556
+ my %symbols;
557
+ my %vorder;
558
+ my $vmax = 0;
559
+ my $error;
560
+ my $max_symlen = 0;
561
+ open my $fh, '<', $map_in
562
+ or die "$map_in: $!\n";
563
+
564
+ local $_;
565
+ while (<$fh>) {
566
+ next if /^#/;
567
+ chomp;
568
+ s/\s+$//;
569
+ next if $_ eq q{};
570
+
571
+ my @vers = split;
572
+ my $sym = shift @vers;
573
+ if ($sym eq '%chain') {
574
+ for my $v (@vers) {
575
+ if (exists $vorder{$v}) {
576
+ print {*STDERR}
577
+ "$map_in:$.: error: '$v' used twice in %chain\n";
578
+ $error = 1;
579
+ next;
580
+ }
581
+ $vorder{$v} = $vmax;
582
+ $vmax++;
583
+ }
584
+ next;
585
+ }
586
+ if (exists $symbols{$sym}) {
587
+ print {*STDERR}
588
+ "$map_in:$.: error: more than one entry for '$sym'\n";
589
+ $error = 1;
590
+ next;
591
+ }
592
+ if ($max_symlen < length $sym) {
593
+ $max_symlen = length $sym;
594
+ }
595
+
596
+ # Dash in the second field means there is no default version
597
+ # for this symbol.
598
+ my $compat_only = 0;
599
+ if ($vers[0] eq '-') {
600
+ $compat_only = 1;
601
+ shift @vers;
602
+ }
603
+
604
+ my @enabled_vers;
605
+ for my $v (@vers) {
606
+ # Each $v is a symbol version name followed by zero
607
+ # or more compatibility tags, separated by colons.
608
+ # If there are no tags, the symbol version is available
609
+ # unconditionally; if there are any tags, the symbol
610
+ # version is available if COMPAT_ABI is equal to 'yes'
611
+ # or equal to one of the tags.
612
+ my @tags = split /:/, $v;
613
+ $v = shift @tags;
614
+ my $enabled = 1;
615
+ if (@tags && $COMPAT_ABI ne 'yes') {
616
+ $enabled = 0;
617
+ for my $t (@tags) {
618
+ if ($t eq $COMPAT_ABI) {
619
+ $enabled = 1;
620
+ last;
621
+ }
622
+ }
623
+ }
624
+ push @enabled_vers, $v if $enabled;
625
+ }
626
+ $symbols{$sym} = VersionedSymbol->new(
627
+ name => $sym,
628
+ included => 1,
629
+ compat_only => $compat_only,
630
+ versions => \@enabled_vers,
631
+ );
632
+ }
633
+
634
+ my $symver_min_idx;
635
+ my $symver_floor_idx;
636
+ if (!%vorder) {
637
+ print {*STDERR} "$map_in: error: missing %chain directive\n";
638
+ $error = 1;
639
+ } else {
640
+ $symver_min_idx = $vorder{$SYMVER_MIN} // -2;
641
+ $symver_floor_idx = $vorder{$SYMVER_FLOOR} // -1;
642
+ if ($symver_min_idx < 0) {
643
+ print {*STDERR}
644
+ "$map_in: error: SYMVER_MIN ($SYMVER_MIN) ",
645
+ "not found in %chain directives\n";
646
+ $error = 1;
647
+ }
648
+ if ($symver_floor_idx < 0) {
649
+ print {*STDERR}
650
+ "$map_in: error: SYMVER_FLOOR ($SYMVER_FLOOR) ",
651
+ "not found in %chain directives\n";
652
+ $error = 1;
653
+ }
654
+ if ($symver_floor_idx < $symver_min_idx) {
655
+ print {*STDERR}
656
+ "$map_in: error: SYMVER_FLOOR ($SYMVER_FLOOR) ",
657
+ "is lower than SYMVER_MIN ($SYMVER_MIN)\n";
658
+ $error = 1;
659
+ }
660
+ }
661
+ die "errors processing '$map_in'\n" if $error;
662
+
663
+ # For each symbol, remove all of its versions below SYMVER_MIN,
664
+ # and replace all of its versions below SYMVER_FLOOR with a single
665
+ # instance of SYMVER_FLOOR. If none are left, mark the symbol as
666
+ # not included. Otherwise, sort its 'versions' array in
667
+ # _descending_ order of symbol version. As we do this, keep track
668
+ # of all the symbol versions that are actually used.
669
+ my %used_versions;
670
+ for my $sym (values %symbols) {
671
+ my %pruned_versions;
672
+ for my $v (@{$sym->versions}) {
673
+ if (!exists $vorder{$v}) {
674
+ print {*STDERR}
675
+ "$map_in: error: version '$v' for symbol '",
676
+ $sym->name, "' not found in %chain\n";
677
+ $error = 1;
678
+ next;
679
+ }
680
+ if ($vorder{$v} < $symver_min_idx) {
681
+ next;
682
+ } elsif ($vorder{$v} < $symver_floor_idx) {
683
+ $pruned_versions{$SYMVER_FLOOR} = 1;
684
+ $used_versions{$SYMVER_FLOOR} = 1;
685
+ } else {
686
+ $pruned_versions{$v} = 1;
687
+ $used_versions{$v} = 1;
688
+ }
689
+ }
690
+ if (%pruned_versions) {
691
+ @{$sym->versions} =
692
+ sort { -($vorder{$a} <=> $vorder{$b}) }
693
+ keys %pruned_versions;
694
+ } else {
695
+ $sym->included(0);
696
+ @{$sym->versions} = ();
697
+ }
698
+ }
699
+
700
+ # Sort the set of used symbol versions in _ascending_ order.
701
+ my @vchain = sort { $vorder{$a} <=> $vorder{$b} } keys %used_versions;
702
+
703
+ my (undef, undef, $basemap) = splitpath($map_in);
704
+ return SymbolVersionMap->new(
705
+ symbols => [sort { $a->name cmp $b->name } values %symbols],
706
+ versions => \@vchain,
707
+ basemap => $basemap,
708
+ max_symlen => $max_symlen,
709
+ );
710
+ }
711
+
712
+ 1;