mirror of
git://git.gnupg.org/gnupg.git
synced 2024-06-04 22:57:47 +02:00
Compare commits
513 Commits
gnupg-2.6-
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
04ce6765f4 | ||
|
8624482160 | ||
|
ed118e2ed5 | ||
|
d2dca58338 | ||
|
42b0e9558a | ||
|
253a701ed7 | ||
|
fc3fde1bde | ||
|
34045ed9e1 | ||
|
aedeef6acf | ||
|
9adaa79ab4 | ||
|
dcb0b6fd48 | ||
|
28c705a3be | ||
|
4c1b007035 | ||
|
379fc5569d | ||
|
bdbf5cee2f | ||
|
fdc5003956 | ||
|
021c27510b | ||
|
bcc002cd45 | ||
|
d631c8198c | ||
|
2e4b1f7850 | ||
|
610a452bb5 | ||
|
cdc798db5c | ||
|
287e717b55 | ||
|
5355d08855 | ||
|
7f661aa129 | ||
|
758cd4ccfc | ||
|
6b2ebc36a9 | ||
|
0eefa08295 | ||
|
3bbfcab606 | ||
|
b36e557c5b | ||
|
e0543f97be | ||
|
0cb7f6fbb7 | ||
|
14534e72e1 | ||
|
351fc6e6fa | ||
|
473f37a53e | ||
|
467239dccb | ||
|
f415d96fac | ||
|
516b530126 | ||
|
c8a3b711f0 | ||
|
c1d62418d5 | ||
|
351f5e814b | ||
|
9128d81bb7 | ||
|
83e2dede0a | ||
|
d3b41e7611 | ||
|
02b056ef77 | ||
|
2593dcbceb | ||
|
2958e5e4cf | ||
|
a45243548e | ||
|
d1f8caafb4 | ||
|
ab703eacf7 | ||
|
dd650b2c7b | ||
|
32ec480024 | ||
|
54741685ce | ||
|
f325d3277e | ||
|
e591fd25ad | ||
|
f305e703d5 | ||
|
af98a3e5fa | ||
|
65833eefb2 | ||
|
d5c6b52e59 | ||
|
aa15272ba1 | ||
|
7728a179e0 | ||
|
f119444e64 | ||
|
ba3c873934 | ||
|
2a0a706eb2 | ||
|
967678d972 | ||
|
7d6ad28667 | ||
|
21f7ad563d | ||
|
2a71c3cf97 | ||
|
4e32ff209d | ||
|
c736052e9c | ||
|
4c20d2d273 | ||
|
35ef87d8d9 | ||
|
b48476bbef | ||
|
6f94fe01a9 | ||
|
813f8d1b8e | ||
|
61717fb0a7 | ||
|
869d1df270 | ||
|
f2fd4f1a9e | ||
|
172d53d636 | ||
|
6737e07a9b | ||
|
87025e5da6 | ||
|
84ddb24e30 | ||
|
c21237ac27 | ||
|
aee6b1131b | ||
|
04b81ec236 | ||
|
52c4b09080 | ||
|
1a37f0080b | ||
|
3a344d6236 | ||
|
f7a26aa8ad | ||
|
c5d7a332c8 | ||
|
03d53c88cc | ||
|
68d9bc9c35 | ||
|
b261478c06 | ||
|
53c6b1e858 | ||
|
ce8b25270b | ||
|
548fd7bca7 | ||
|
131dd2a351 | ||
|
0b1f7427b3 | ||
|
98e287ba6d | ||
|
97f5159495 | ||
|
6c1dd3afd1 | ||
|
4b981e415f | ||
|
fa33b18940 | ||
|
c69363e8c7 | ||
|
1fa24e2841 | ||
|
571a768ac6 | ||
|
984a0c6982 | ||
|
f9919bcc48 | ||
|
cec1fde1bc | ||
|
a0bfbdaaa2 | ||
|
fb3fe38d28 | ||
|
759adb2493 | ||
|
122803bf1a | ||
|
50e81ad38d | ||
|
f78501c545 | ||
|
c27534de95 | ||
|
14c1b73093 | ||
|
81536535f8 | ||
|
4485930f9f | ||
|
609b1ec0c6 | ||
|
cbff323b3b | ||
|
348de4a829 | ||
|
3ffcd533d4 | ||
|
09431d1762 | ||
|
1682ca9f01 | ||
|
a1ea3b13e0 | ||
|
79d0e52b2d | ||
|
00b877ecda | ||
|
37cc255e49 | ||
|
345794cfe6 | ||
|
36a3550bff | ||
|
74e4dd3668 | ||
|
233bf39323 | ||
|
c27e5be50b | ||
|
dcab895e4c | ||
|
962058f704 | ||
|
adf4db6e20 | ||
|
40227e42ea | ||
|
2372f6a403 | ||
|
a09157ccb2 | ||
|
95bc592ab5 | ||
|
3aa02027cd | ||
|
557f29d2c1 | ||
|
1e496cf2e5 | ||
|
3341017ff1 | ||
|
ad4bc3e04d | ||
|
2810b93464 | ||
|
848546b05a | ||
|
0370678536 | ||
|
04cbc3074a | ||
|
874918ab91 | ||
|
27f66148f7 | ||
|
302afcb6f6 | ||
|
5842eee805 | ||
|
e5f24218fc | ||
|
214d3ffe0f | ||
|
375c3a238a | ||
|
40b85d8e8c | ||
|
d6dedda3f2 | ||
|
300c9eeace | ||
|
03207f62e8 | ||
|
ae0a755e0d | ||
|
78eae9ffe8 | ||
|
2ed1f68b48 | ||
|
97b2837653 | ||
|
4dc09bc5e7 | ||
|
eaf6a7ab87 | ||
|
dfa60c09f5 | ||
|
af6ac2ac02 | ||
|
367ae86019 | ||
|
a43271cc08 | ||
|
c5429644e9 | ||
|
2a4180812a | ||
|
6481d410ec | ||
|
d4976e35d2 | ||
|
a227a0d54d | ||
|
154ecf17bd | ||
|
bea31c845a | ||
|
ccfbb9ebdf | ||
|
fd6c38605a | ||
|
34d19d448d | ||
|
b7c1594861 | ||
|
9408c6bf51 | ||
|
ead2982286 | ||
|
434a641d40 | ||
|
18320d692c | ||
|
ee56f71c8a | ||
|
adeb17e375 | ||
|
c8060a8f23 | ||
|
cb8eb366cb | ||
|
5402e6fb93 | ||
|
1a2c8267f5 | ||
|
daedb3c965 | ||
|
4cdfc1d0d9 | ||
|
0cb622d632 | ||
|
092154e17e | ||
|
3d60ad5c8c | ||
|
b97a36f52d | ||
|
3f12e3dacb | ||
|
5a6df94a9a | ||
|
bbad0a2644 | ||
|
e65720f286 | ||
|
8dfbad0c41 | ||
|
b7f45ee6ad | ||
|
275ced5067 | ||
|
6233a17ac9 | ||
|
4ca017e43b | ||
|
880dde8e5b | ||
|
35fd89b168 | ||
|
45f6357881 | ||
|
2cb97713e9 | ||
|
3f8cb9b339 | ||
|
4c04143d81 | ||
|
591a53d716 | ||
|
6ddaf2be9f | ||
|
7cde533ce8 | ||
|
c44f0bc91e | ||
|
2be53b214d | ||
|
2764ee309a | ||
|
431239b83d | ||
|
239c1fdc28 | ||
|
2376cdff13 | ||
|
853f36e596 | ||
|
91255c3afd | ||
|
f2904737e5 | ||
|
0b85a9ac09 | ||
|
812f988059 | ||
|
5d651fc8fd | ||
|
4dd4e9d2f1 | ||
|
93b5ba38dc | ||
|
1f04993cd0 | ||
|
b298322d36 | ||
|
2f6fec3f48 | ||
|
5488ad0517 | ||
|
8eff1d4c51 | ||
|
6b4fd3a5da | ||
|
1c5584c395 | ||
|
bd8346f7ab | ||
|
c99282fc78 | ||
|
937aeb1904 | ||
|
4e94b004a6 | ||
|
f57717bf23 | ||
|
37fa36a329 | ||
|
6b93b92111 | ||
|
1ded50dd5b | ||
|
fa677a37ce | ||
|
548d4aad5f | ||
|
a14f73a192 | ||
|
73aa6dc6e4 | ||
|
4c456bf075 | ||
|
09329d52b5 | ||
|
813bb65d95 | ||
|
cf2d3f7ba0 | ||
|
e43bd2a7a7 | ||
|
2fa916ebff | ||
|
960877b10f | ||
|
5304c9b080 | ||
|
a33ad8f9bf | ||
|
42ee841976 | ||
|
2600047470 | ||
|
def8f5f3d2 | ||
|
e6cedba119 | ||
|
6fab7b075a | ||
|
bafa7bf27f | ||
|
ec1446f944 | ||
|
3572b19fbd | ||
|
bf7b785b0e | ||
|
3a669f175f | ||
|
d6f738729f | ||
|
4db2e13e2c | ||
|
64f5f7b74e | ||
|
65607fb81d | ||
|
4257cbb06c | ||
|
e6b3d53db3 | ||
|
387ee7dcbd | ||
|
337de21f4b | ||
|
00da0e9f93 | ||
|
c2812a9bbc | ||
|
05ef8c0cc0 | ||
|
678c819027 | ||
|
95b9a31f81 | ||
|
a4fe307b55 | ||
|
164c687cb6 | ||
|
2c3c049fd8 | ||
|
97708e2ac7 | ||
|
4448bc44f0 | ||
|
7661d2fbc6 | ||
|
873b2b0da1 | ||
|
956b1e1c26 | ||
|
606933dfb4 | ||
|
a17363e992 | ||
|
5601f5db98 | ||
|
4963f13f8f | ||
|
24b3a5a579 | ||
|
9353dc811a | ||
|
0e200f2187 | ||
|
0494ec8f4d | ||
|
e783866f41 | ||
|
d17efdcd6f | ||
|
8d0819346d | ||
|
9909f622f6 | ||
|
19caa5c267 | ||
|
b4449ffabc | ||
|
c1f78634ec | ||
|
16b6b77532 | ||
|
227b3b14f4 | ||
|
98dd6f7af6 | ||
|
68b7aff9ce | ||
|
08e529fa7c | ||
|
f2ca727978 | ||
|
25c84ffd10 | ||
|
321f9c0a3f | ||
|
4206d89003 | ||
|
9a3e41c151 | ||
|
d7a1577a25 | ||
|
53bdb7440c | ||
|
52b7a60cf9 | ||
|
78afc209cc | ||
|
1da40db03e | ||
|
eda3997b43 | ||
|
a5e33618f4 | ||
|
c91f759baf | ||
|
3054016db9 | ||
|
668deeded9 | ||
|
1e120f5a8d | ||
|
fed33baed1 | ||
|
845d5e61d8 | ||
|
459bd577fc | ||
|
a8618fdccd | ||
|
26939ea222 | ||
|
2a2846959f | ||
|
bf662d0f93 | ||
|
4fc745bc43 | ||
|
7f9e05d73f | ||
|
a02f3cc4e8 | ||
|
0aa32e2429 | ||
|
34f812475e | ||
|
362a6dfb0a | ||
|
1f76cbca35 | ||
|
1be7882344 | ||
|
d90f1e5fa4 | ||
|
28364affa6 | ||
|
5e47d5edd8 | ||
|
57125d3f5a | ||
|
776876ce1c | ||
|
92de0387f0 | ||
|
76a2f18028 | ||
|
7025375e8b | ||
|
76896e2339 | ||
|
b2826924ee | ||
|
95186ae92f | ||
|
9dd8fd4ae4 | ||
|
a430f22549 | ||
|
ee27ac18ea | ||
|
32c55603df | ||
|
716e59b0b6 | ||
|
9e4d522239 | ||
|
1d73806972 | ||
|
ed4050e011 | ||
|
0821ceebfb | ||
|
5cad5f903e | ||
|
0d20b79ab7 | ||
|
fa29c86582 | ||
|
dad880155e | ||
|
1ddd69935d | ||
|
96b69c1866 | ||
|
2258bcded6 | ||
|
95d9761509 | ||
|
c68b70ce9d | ||
|
083a16ae08 | ||
|
30fc365124 | ||
|
eceba4f207 | ||
|
6e2412e74a | ||
|
6524becf28 | ||
|
ea1935252e | ||
|
521ec40aea | ||
|
ae188a3357 | ||
|
81055baf5c | ||
|
b849c930e9 | ||
|
ee9e3578ce | ||
|
5d375bb168 | ||
|
cf270b0d30 | ||
|
ea625c74f0 | ||
|
69c1d81284 | ||
|
fb046ccd93 | ||
|
23bcb78d27 | ||
|
b07b5144ff | ||
|
067bc2ed4c | ||
|
16d135c396 | ||
|
250733c0d8 | ||
|
37343db08f | ||
|
a3be97df4d | ||
|
5bc949d230 | ||
|
9f39e4da29 | ||
|
8cacfce898 | ||
|
2abea42d9c | ||
|
f2dcd158a5 | ||
|
577baf4af3 | ||
|
9ae3cfcabe | ||
|
3fb69641e8 | ||
|
2c2516f03a | ||
|
68d3a73ea7 | ||
|
dc13361524 | ||
|
2c5a93e66e | ||
|
334f5d95c8 | ||
|
2378ccf97c | ||
|
d073f26d81 | ||
|
7c04a6a284 | ||
|
7f8ea1c9be | ||
|
b83d86b988 | ||
|
7a2831bc0e | ||
|
5e94470d05 | ||
|
b5efb52d43 | ||
|
a0ff2919f7 | ||
|
5377226ec0 | ||
|
250fff0f6e | ||
|
5f694dc0be | ||
|
6049d61991 | ||
|
3672c29156 | ||
|
101433dfb4 | ||
|
c926967d85 | ||
|
25b59cf6ce | ||
|
cacb018992 | ||
|
7cfbf0dd72 | ||
|
631c23b664 | ||
|
b9b0c18320 | ||
|
72ac77c4fa | ||
|
76df934929 | ||
|
1f9a4fbc7e | ||
|
f0ecc07c4e | ||
|
87a73e8eb0 | ||
|
2756147e39 | ||
|
04d0851cca | ||
|
e9e7b5425f | ||
|
10c937ee68 | ||
|
2c7f7a5a27 | ||
|
06aeb2b45c | ||
|
28a4d0d4f5 | ||
|
be77c05532 | ||
|
40090dbbf9 | ||
|
b1ecc8353a | ||
|
701a8b30f0 | ||
|
0a63afc79a | ||
|
bf04b07327 | ||
|
3bab25d7d5 | ||
|
2178f35dff | ||
|
e9c337c0b9 | ||
|
a88aeee129 | ||
|
c58067415f | ||
|
808494b485 | ||
|
695cb04af5 | ||
|
64509134d4 | ||
|
ca3f0e66bc | ||
|
c68dd22872 | ||
|
e16fc3e19c | ||
|
3c57aee263 | ||
|
5170c366ee | ||
|
1b0ce9918c | ||
|
207c99567c | ||
|
f5656ff363 | ||
|
9433dfa5dd | ||
|
7b7fdf45e5 | ||
|
baa8883215 | ||
|
2c1d5d5cd3 | ||
|
22350d0768 | ||
|
89da4a32ab | ||
|
ef4f22b9d9 | ||
|
0fba0bbc62 | ||
|
6ed61d98a0 | ||
|
c8f6fdcd35 | ||
|
3c97dc2714 | ||
|
9e86dac84f | ||
|
550bc15b00 | ||
|
4cfa2efdc6 | ||
|
f953d67446 | ||
|
2783b786a9 | ||
|
a216e9c028 | ||
|
1d23dc9389 | ||
|
ec0c35d1b8 | ||
|
a1015bf2fc | ||
|
05f29b5c7c | ||
|
13013ec1c0 | ||
|
a048a93ed2 | ||
|
f15a643a2d | ||
|
09a96c9e1b | ||
|
9f2f7a51b2 | ||
|
e9dd47d789 | ||
|
14828c75be | ||
|
39a4373780 | ||
|
6984ddc6eb | ||
|
0f8e5f1c1d | ||
|
6a2cb8cfd7 | ||
|
000b82ade7 | ||
|
80097bc78b | ||
|
8295fb3f0b | ||
|
6657230f9e | ||
|
3a438a1cc3 | ||
|
42bea7de16 | ||
|
7e681da1b2 | ||
|
097701e698 | ||
|
faf0a97b2e | ||
|
3fbe10172f | ||
|
2f872fa68c | ||
|
48b5648554 | ||
|
5f46bcaaa0 | ||
|
cd7f286486 | ||
|
6944aefa3c | ||
|
b789ada2b0 | ||
|
d221062769 | ||
|
86cdb49097 | ||
|
5c7c6065f3 | ||
|
23bb92b755 | ||
|
a035938216 |
|
@ -1,2 +1,6 @@
|
||||||
# indent: Modernize mem2str.
|
# indent: Modernize mem2str.
|
||||||
6a80d6f9206eae2c867c45daa5cd3e7d6c6ad114
|
6a80d6f9206eae2c867c45daa5cd3e7d6c6ad114
|
||||||
|
# doc: Fix spelling errors found by lintian.
|
||||||
|
2ed1f68b48db7b5503045386de0500fddf70077e
|
||||||
|
# indent: Re-indent a function
|
||||||
|
869d1df270c0ccc3a9f792167b96d678a932b37e
|
||||||
|
|
5
AUTHORS
5
AUTHORS
|
@ -16,7 +16,7 @@ List of Copyright holders
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
Copyright (C) 1997-2019 Werner Koch
|
Copyright (C) 1997-2019 Werner Koch
|
||||||
Copyright (C) 2003-2023 g10 Code GmbH
|
Copyright (C) 2003-2024 g10 Code GmbH
|
||||||
Copyright (C) 1994-2021 Free Software Foundation, Inc.
|
Copyright (C) 1994-2021 Free Software Foundation, Inc.
|
||||||
Copyright (C) 2002 Klarälvdalens Datakonsult AB
|
Copyright (C) 2002 Klarälvdalens Datakonsult AB
|
||||||
Copyright (C) 1995-1997, 2000-2007 Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
Copyright (C) 1995-1997, 2000-2007 Ulrich Drepper <drepper@gnu.ai.mit.edu>
|
||||||
|
@ -220,6 +220,9 @@ Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||||
Kyle Butt <kylebutt@gmail.com>
|
Kyle Butt <kylebutt@gmail.com>
|
||||||
2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
|
2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
|
||||||
|
|
||||||
|
Mario Haustein <mario.haustein@hrz.tu-chemnitz.de>
|
||||||
|
2022-09-26:8149069.T7Z3S40VBb@localdomain:
|
||||||
|
|
||||||
Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
|
Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
|
||||||
2018-07-13:c397e637-f1ce-34f0-7e6a-df04a76e1c35@ssi-schaefer.com:
|
2018-07-13:c397e637-f1ce-34f0-7e6a-df04a76e1c35@ssi-schaefer.com:
|
||||||
|
|
||||||
|
|
23
Makefile.am
23
Makefile.am
|
@ -18,13 +18,13 @@
|
||||||
|
|
||||||
## Process this file with automake to produce Makefile.in
|
## Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
# To include the wixlibs for building an MSI installer in a release use
|
# We want to also build the wixlib for use by GnuPG Desktop
|
||||||
# make release WITH_MSI=1
|
WITH_MSI=1
|
||||||
|
|
||||||
# Location of the released tarball archives. This is prefixed by
|
# Location of the released tarball archives. This is prefixed by
|
||||||
# the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example:
|
# the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example:
|
||||||
# RELEASE_ARCHIVE=user@host:archive/tarballs
|
# RELEASE_ARCHIVE=user@host:archive/tarballs
|
||||||
RELEASE_ARCHIVE_SUFFIX = gnupg/v2.4
|
RELEASE_ARCHIVE_SUFFIX = gnupg/v2.5
|
||||||
# The variable RELEASE_SIGNKEY in ~/.gnupg-autogen.rc is used
|
# The variable RELEASE_SIGNKEY in ~/.gnupg-autogen.rc is used
|
||||||
# to specify the key for signing. For example:
|
# to specify the key for signing. For example:
|
||||||
# RELEASE_SIGNKEY=D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
|
# RELEASE_SIGNKEY=D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
|
||||||
|
@ -191,7 +191,7 @@ endif
|
||||||
|
|
||||||
|
|
||||||
gen_start_date = 2011-12-01T06:00:00
|
gen_start_date = 2011-12-01T06:00:00
|
||||||
.PHONY: gen-ChangeLog
|
.PHONY: gen-ChangeLog stowinstall speedo
|
||||||
gen-ChangeLog:
|
gen-ChangeLog:
|
||||||
if test -e $(top_srcdir)/.git; then \
|
if test -e $(top_srcdir)/.git; then \
|
||||||
(cd $(top_srcdir) && \
|
(cd $(top_srcdir) && \
|
||||||
|
@ -207,6 +207,11 @@ gen-ChangeLog:
|
||||||
stowinstall:
|
stowinstall:
|
||||||
$(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/gnupg
|
$(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/gnupg
|
||||||
|
|
||||||
|
|
||||||
|
speedo:
|
||||||
|
$(MAKE) -f $(top_srcdir)/build-aux/speedo.mk native SELFCHECK=0
|
||||||
|
|
||||||
|
|
||||||
TESTS_ENVIRONMENT = \
|
TESTS_ENVIRONMENT = \
|
||||||
LC_ALL=C \
|
LC_ALL=C \
|
||||||
EXEEXT=$(EXEEXT) \
|
EXEEXT=$(EXEEXT) \
|
||||||
|
@ -242,8 +247,8 @@ release:
|
||||||
mkopt=""; \
|
mkopt=""; \
|
||||||
if [ -n "$$CUSTOM_SWDB" ]; then \
|
if [ -n "$$CUSTOM_SWDB" ]; then \
|
||||||
mkopt="CUSTOM_SWB=1"; \
|
mkopt="CUSTOM_SWB=1"; \
|
||||||
x=$$(grep '^OVERRIDE_TARBALLS=' \
|
x=$$(grep '^[[:blank:]]*OVERRIDE_TARBALLS[[:blank:]]*=' \
|
||||||
$$HOME/.gnupg-autogen.rc|cut -d= -f2);\
|
$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs);\
|
||||||
if [ -f "$$x/swdb.lst" ]; then \
|
if [ -f "$$x/swdb.lst" ]; then \
|
||||||
echo "/* Copying swdb.lst from the overrides directory */"; \
|
echo "/* Copying swdb.lst from the overrides directory */"; \
|
||||||
cp "$$x/swdb.lst" . ; \
|
cp "$$x/swdb.lst" . ; \
|
||||||
|
@ -270,13 +275,15 @@ release:
|
||||||
sign-release:
|
sign-release:
|
||||||
+(set -e; \
|
+(set -e; \
|
||||||
test $$(pwd | sed 's,.*/,,') = dist || cd dist; \
|
test $$(pwd | sed 's,.*/,,') = dist || cd dist; \
|
||||||
x=$$(grep '^RELEASE_ARCHIVE=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\
|
x=$$(grep '^[[:blank:]]*RELEASE_ARCHIVE[[:blank:]]*=' \
|
||||||
|
$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs);\
|
||||||
if [ -z "$$x" ]; then \
|
if [ -z "$$x" ]; then \
|
||||||
echo "error: RELEASE_ARCHIVE missing in ~/.gnupg-autogen.rc">&2; \
|
echo "error: RELEASE_ARCHIVE missing in ~/.gnupg-autogen.rc">&2; \
|
||||||
exit 2;\
|
exit 2;\
|
||||||
fi;\
|
fi;\
|
||||||
myarchive="$$x/$(RELEASE_ARCHIVE_SUFFIX)";\
|
myarchive="$$x/$(RELEASE_ARCHIVE_SUFFIX)";\
|
||||||
x=$$(grep '^RELEASE_SIGNKEY=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\
|
x=$$(grep '^[[:blank:]]*RELEASE_SIGNKEY[[:blank:]]*=' \
|
||||||
|
$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs);\
|
||||||
if [ -z "$$x" ]; then \
|
if [ -z "$$x" ]; then \
|
||||||
echo "error: RELEASE_SIGNKEY missing in ~/.gnupg-autogen.rc">&2; \
|
echo "error: RELEASE_SIGNKEY missing in ~/.gnupg-autogen.rc">&2; \
|
||||||
exit 2;\
|
exit 2;\
|
||||||
|
|
262
NEWS
262
NEWS
|
@ -1,6 +1,252 @@
|
||||||
Noteworthy changes in version 2.5.0 (unreleased)
|
Noteworthy changes in version 2.5.0 (unreleased)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
Changes also found in 2.4.6:
|
||||||
|
|
||||||
|
* gpg: New command --quick-set-ownertrust. [rG967678d972]
|
||||||
|
|
||||||
|
* gpg: Indicate disabled keys in key listings and add list option
|
||||||
|
"show-ownertrust". [rG2a0a706eb2]
|
||||||
|
|
||||||
|
* gpg: Make sure a DECRYPTION_OKAY is never issued for a bad OCB
|
||||||
|
tag. [T7042]
|
||||||
|
|
||||||
|
* gpg: Do not allow to accidently set the RENC usage. [T7072]
|
||||||
|
|
||||||
|
* agent: Consider an empty pattern file as valid. [rGc27534de95]
|
||||||
|
|
||||||
|
* agent: Fix error handling of READKEY. [T6012]
|
||||||
|
|
||||||
|
* gpgconf: Check readability of some files with -X and change its
|
||||||
|
output format. [rG759adb2493]
|
||||||
|
|
||||||
|
|
||||||
|
Changes also found in 2.4.5:
|
||||||
|
|
||||||
|
* gpg,gpgv: New option --assert-pubkey-algo. [T6946]
|
||||||
|
|
||||||
|
* gpg: Emit status lines for errors in the compression layer.
|
||||||
|
[T6977]
|
||||||
|
|
||||||
|
* gpg: Fix invocation with --trusted-keys and --no-options. [T7025]
|
||||||
|
|
||||||
|
* gpgsm: Allow for a longer salt in PKCS#12 files. [T6757]
|
||||||
|
|
||||||
|
* gpgtar: Make --status-fd=2 work on Windows. [T6961]
|
||||||
|
|
||||||
|
* scd: Support for the ACR-122U NFC reader. [rG1682ca9f01]
|
||||||
|
|
||||||
|
* scd: Suport D-TRUST ECC cards. [T7000,T7001]
|
||||||
|
|
||||||
|
* scd: Allow auto detaching of kernel drivers; can be disabled with
|
||||||
|
the new compatibility-flag ccid-no-auto-detach. [rGa1ea3b13e0]
|
||||||
|
|
||||||
|
* scd: Allow setting a PIN length of 6 also with a reset code for
|
||||||
|
openpgp cards. [T6843]
|
||||||
|
|
||||||
|
* agent: Allow GET_PASSPHRASE in restricted mode. [rGadf4db6e20]
|
||||||
|
|
||||||
|
* dirmngr: Trust system's root CAs for checking CRL issuers.
|
||||||
|
[T6963]
|
||||||
|
|
||||||
|
* dirmngr: Fix regression in 2.4.4 in fetching keys via hkps.
|
||||||
|
[T6997]
|
||||||
|
|
||||||
|
* gpg-wks-client: Make option --mirror work properly w/o specifying
|
||||||
|
domains. [rG37cc255e49]
|
||||||
|
|
||||||
|
* g13,gpg-wks-client: Allow command style options as in "g13 mount
|
||||||
|
foo". [rGa09157ccb2]
|
||||||
|
|
||||||
|
* Allow tilde expansion for the foo-program options. [T7017]
|
||||||
|
|
||||||
|
* Make the getswdb.sh tool usable outside the GnuPG tree.
|
||||||
|
|
||||||
|
|
||||||
|
Changes also found in 2.4.4:
|
||||||
|
|
||||||
|
* gpg: Do not keep an unprotected smartcard backup key on disk. See
|
||||||
|
https://gnupg.org/blog/20240125-smartcard-backup-key.html for a
|
||||||
|
security advisory. [T6944]
|
||||||
|
|
||||||
|
* gpg: Allow to specify seconds since Epoch beyond 2038 on 32-bit
|
||||||
|
platforms. [T6736]
|
||||||
|
|
||||||
|
* gpg: Fix expiration time when Creation-Date is specified. [T5252]
|
||||||
|
|
||||||
|
* gpg: Add support for Subkey-Expire-Date. [rG96b69c1866]
|
||||||
|
|
||||||
|
* gpg: Add option --with-v5-fingerprint. [T6705]
|
||||||
|
|
||||||
|
* gpg: Add sub-option ignore-attributes to --import-options.
|
||||||
|
[rGd4976e35d2]
|
||||||
|
|
||||||
|
* gpg: Add --list-filter properties sig_expires/sig_expires_d.
|
||||||
|
[rGbf662d0f93af]
|
||||||
|
|
||||||
|
* gpg: Fix validity of re-imported keys. [T6399]
|
||||||
|
|
||||||
|
* gpg: Report BEGIN_ status before examining the input. [T6481]
|
||||||
|
|
||||||
|
* gpg: Don't try to compress a read-only keybox. [T6811]
|
||||||
|
|
||||||
|
* gpg: Choose key from inserted card over a non-inserted
|
||||||
|
card. [T6831]
|
||||||
|
|
||||||
|
* gpg: Allow to create revocations even with non-compliant algos.
|
||||||
|
[T6929]
|
||||||
|
|
||||||
|
* gpg: Fix regression in the Revoker keyword of the parameter file.
|
||||||
|
[T6923]
|
||||||
|
|
||||||
|
* gpg: Improve error message for expired default keys. [T4704]
|
||||||
|
|
||||||
|
* gpgsm: Add --always-trust feature. [T6559]
|
||||||
|
|
||||||
|
* gpgsm: Support ECC certificates in de-vs mode. [T6802]
|
||||||
|
|
||||||
|
* gpgsm: Major rewrite of the PKCS#12 parser. [T6536]
|
||||||
|
|
||||||
|
* gpgsm: No not show the pkcs#12 passphrase in debug output. [T6654]
|
||||||
|
|
||||||
|
* keyboxd: Timeout on failure to get the database lock. [T6838]
|
||||||
|
|
||||||
|
* agent: Update the key stubs only if really modified. [T6829]
|
||||||
|
|
||||||
|
* scd: Add support for certain Starcos 3.2 cards. [rG5304c9b080]
|
||||||
|
|
||||||
|
* scd: Add support for CardOS 5.4 cards. [rG812f988059]
|
||||||
|
|
||||||
|
* scd: Add support for D-Trust 4.1/4.4 cards. [rG0b85a9ac09]
|
||||||
|
|
||||||
|
* scd: Add support for Smartcafe Expert 7.0 cards. [T6919]
|
||||||
|
|
||||||
|
* scd: Add a length check for a new PIN. [T6843]
|
||||||
|
|
||||||
|
* tpm: Fix keytotpm handling in the agent. [rG9909f622f6]
|
||||||
|
|
||||||
|
* tpm: Fixes for the TPM test suite. [T6052]
|
||||||
|
|
||||||
|
* dirmngr: Avoid starting a second instance on Windows via GPGME
|
||||||
|
based launching. [T6833]
|
||||||
|
|
||||||
|
* dirmngr: New option --ignore-crl-extensions. [T6545]
|
||||||
|
|
||||||
|
* dirmngr: Support config value "none" to disable the default
|
||||||
|
keyserver. [T6708]
|
||||||
|
|
||||||
|
* dirmngr: Implement automatic proxy detection on Windows. [T5768]
|
||||||
|
|
||||||
|
* dirmngr: Fix handling of the HTTP Content-Length. [rGa5e33618f4]
|
||||||
|
|
||||||
|
* dirmngr: Add code to support proxy authentication using the
|
||||||
|
Negotiation method on Windows. [T6719]
|
||||||
|
|
||||||
|
* gpgconf: Add commands --lock and --unlock. [rG93b5ba38dc]
|
||||||
|
|
||||||
|
* gpgconf: Add keyword socketdir to gpgconf.ctl. [rG239c1fdc28]
|
||||||
|
|
||||||
|
* gpgconf: Adjust the -X command for the new VERSION file format.
|
||||||
|
[T6918]
|
||||||
|
|
||||||
|
* wkd: Use export-clean for gpg-wks-client's --mirror and --create
|
||||||
|
commands. [rG2c7f7a5a278c]
|
||||||
|
|
||||||
|
* wkd: Make --add-revocs the default in gpg-wks-client. New option
|
||||||
|
--no-add-revocs. [rG10c937ee68]
|
||||||
|
|
||||||
|
* Remove duplicated backslashes when setting the homedir. [T6833]
|
||||||
|
|
||||||
|
* Ignore attempts to remove the /dev/null device. [T6556]
|
||||||
|
|
||||||
|
* Improve advisory file lock retry strategy. [T3380]
|
||||||
|
|
||||||
|
* Improve the speedo build system for Unix. [T6710]
|
||||||
|
|
||||||
|
|
||||||
|
Changes also found in 2.4.3:
|
||||||
|
|
||||||
|
* gpg: Set default expiration date to 3 years. [T2701]
|
||||||
|
|
||||||
|
* gpg: Add --list-filter properties "key_expires" and
|
||||||
|
"key_expires_d". [T6529]
|
||||||
|
|
||||||
|
* gpg: Emit status line and proper diagnostics for write errors.
|
||||||
|
[T6528]
|
||||||
|
|
||||||
|
* gpg: Make progress work for large files on Windows. [T6534]
|
||||||
|
|
||||||
|
* gpg: New option --no-compress as alias for -z0.
|
||||||
|
|
||||||
|
* gpg: Show better error messages for blocked PINs. [T6425]
|
||||||
|
|
||||||
|
* gpgsm: Print PROGRESS status lines. Add new --input-size-hint.
|
||||||
|
[T6534]
|
||||||
|
|
||||||
|
* gpgsm: Support SENDCERT_SKI for --call-dirmngr. [rG701a8b30f0]
|
||||||
|
|
||||||
|
* gpgsm: Major rewrite of the PKCS#12 parser. [T6536]
|
||||||
|
|
||||||
|
* gpgtar: New option --no-compress.
|
||||||
|
|
||||||
|
* dirmngr: Extend the AD_QUERY command. [rG207c99567c]
|
||||||
|
|
||||||
|
* dirmngr: Disable the HTTP redirect rewriting. [T6477]
|
||||||
|
|
||||||
|
* dirmngr: New option --compatibility-flags. [rGbf04b07327]
|
||||||
|
|
||||||
|
* dirmngr: New option --ignore-crl-extensions. [T6545]
|
||||||
|
|
||||||
|
* dirmngr: Support config value "none" to disable the default
|
||||||
|
keyserver. [T6708]
|
||||||
|
|
||||||
|
* wkd: Use export-clean for gpg-wks-client's --mirror and --create
|
||||||
|
commands. [rG2c7f7a5a27]
|
||||||
|
|
||||||
|
* wkd: Make --add-revocs the default in gpg-wks-client. New option
|
||||||
|
--no-add-revocs. [rG10c937ee68]
|
||||||
|
|
||||||
|
* scd: Make signing work for Nexus cards. [rGb83d86b988]
|
||||||
|
|
||||||
|
* scd: Fix authentication with Administration Key for PIV.
|
||||||
|
[rG25b59cf6ce]
|
||||||
|
|
||||||
|
* Fix garbled time output in non-English Windows. [T6741]
|
||||||
|
|
||||||
|
|
||||||
|
Changes also found in 2.4.2:
|
||||||
|
|
||||||
|
* gpg: Print a warning if no more encryption subkeys are left over
|
||||||
|
after changing the expiration date. [rGef2c3d50fa]
|
||||||
|
|
||||||
|
* gpg: Fix searching for the ADSK key when adding an ADSK. [T6504]
|
||||||
|
|
||||||
|
* gpgsm: Speed up key listings on Windows. [rG08ff55bd44]
|
||||||
|
|
||||||
|
* gpgsm: Reduce the number of "failed to open policy file"
|
||||||
|
diagnostics. [rG68613a6a9d]
|
||||||
|
|
||||||
|
* agent: Make updating of private key files more robust and track
|
||||||
|
display S/N. [T6135]
|
||||||
|
|
||||||
|
* keyboxd: Avoid longish delays on Windows when listing keys.
|
||||||
|
[rG6944aefa3c]
|
||||||
|
|
||||||
|
* gpgtar: Emit extra status lines to help GPGME. [T6497]
|
||||||
|
|
||||||
|
* w32: Avoid using the VirtualStore. [T6403]
|
||||||
|
|
||||||
|
|
||||||
|
Release dates of 2.4 versions
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Version 2.4.5 (2024-03-07) https://dev.gnupg.org/T6960
|
||||||
|
Version 2.4.4 (2024-01-25) https://dev.gnupg.org/T6578
|
||||||
|
Version 2.4.3 (2023-07-04) https://dev.gnupg.org/T6509
|
||||||
|
Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
|
||||||
|
Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454
|
||||||
|
Version 2.4.0 (2022-12-16) https://dev.gnupg.org/T6302
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 2.4.1 (2023-04-28)
|
Noteworthy changes in version 2.4.1 (2023-04-28)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
@ -1209,7 +1455,7 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
|
||||||
Changes also found in 2.2.12:
|
Changes also found in 2.2.12:
|
||||||
|
|
||||||
* tools: New commands --install-key and --remove-key for
|
* tools: New commands --install-key and --remove-key for
|
||||||
gpg-wks-client. This allows to prepare a Web Key Directory on a
|
gpg-wks-client. This allows one to prepare a Web Key Directory on a
|
||||||
local file system for later upload to a web server.
|
local file system for later upload to a web server.
|
||||||
|
|
||||||
* gpg: New --list-option "show-only-fpr-mbox". This makes the use
|
* gpg: New --list-option "show-only-fpr-mbox". This makes the use
|
||||||
|
@ -1253,7 +1499,7 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
|
||||||
query.
|
query.
|
||||||
|
|
||||||
* gpg: Do not store the TOFU trust model in the trustdb. This
|
* gpg: Do not store the TOFU trust model in the trustdb. This
|
||||||
allows to enable or disable a TOFO model without triggering a
|
allows one to enable or disable a TOFO model without triggering a
|
||||||
trustdb rebuild. [#4134]
|
trustdb rebuild. [#4134]
|
||||||
|
|
||||||
* scd: Fix cases of "Bad PIN" after using "forcesig". [#4177]
|
* scd: Fix cases of "Bad PIN" after using "forcesig". [#4177]
|
||||||
|
@ -1595,6 +1841,8 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
|
||||||
Release dates of 2.2 versions
|
Release dates of 2.2 versions
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
Version 2.2.42 (2023-11-28) https://dev.gnupg.org/T6307
|
||||||
|
Version 2.2.41 (2022-12-09) https://dev.gnupg.org/T6280
|
||||||
Version 2.2.40 (2022-10-10) https://dev.gnupg.org/T6181
|
Version 2.2.40 (2022-10-10) https://dev.gnupg.org/T6181
|
||||||
Version 2.2.39 (2022-09-02) https://dev.gnupg.org/T6175
|
Version 2.2.39 (2022-09-02) https://dev.gnupg.org/T6175
|
||||||
Version 2.2.38 (2022-09-01) https://dev.gnupg.org/T6159
|
Version 2.2.38 (2022-09-01) https://dev.gnupg.org/T6159
|
||||||
|
@ -1670,7 +1918,7 @@ Noteworthy changes in version 2.1.23 (2017-08-09)
|
||||||
to your gpg.conf.
|
to your gpg.conf.
|
||||||
|
|
||||||
* agent: Option --no-grab is now the default. The new option --grab
|
* agent: Option --no-grab is now the default. The new option --grab
|
||||||
allows to revert this.
|
allows one to revert this.
|
||||||
|
|
||||||
* gpg: New import option "show-only".
|
* gpg: New import option "show-only".
|
||||||
|
|
||||||
|
@ -2800,7 +3048,7 @@ Noteworthy changes in version 2.1.0 (2014-11-06)
|
||||||
* gpg: Allow use of Brainpool curves.
|
* gpg: Allow use of Brainpool curves.
|
||||||
|
|
||||||
* gpg: Accepts a space separated fingerprint as user ID. This
|
* gpg: Accepts a space separated fingerprint as user ID. This
|
||||||
allows to copy and paste the fingerprint from the key listing.
|
allows one to copy and paste the fingerprint from the key listing.
|
||||||
|
|
||||||
* gpg: The hash algorithm is now printed for signature records in key
|
* gpg: The hash algorithm is now printed for signature records in key
|
||||||
listings.
|
listings.
|
||||||
|
@ -3580,7 +3828,7 @@ Noteworthy changes in version 1.9.10 (2004-07-22)
|
||||||
|
|
||||||
* Fixed a serious bug in the checking of trusted root certificates.
|
* Fixed a serious bug in the checking of trusted root certificates.
|
||||||
|
|
||||||
* New configure option --enable-agent-pnly allows to build and
|
* New configure option --enable-agent-only allows one to build and
|
||||||
install just the agent.
|
install just the agent.
|
||||||
|
|
||||||
* Fixed a problem with the log file handling.
|
* Fixed a problem with the log file handling.
|
||||||
|
@ -3975,7 +4223,7 @@ Noteworthy changes in version 1.1.92 (2002-09-11)
|
||||||
extension specified with --load-extension are checked, along
|
extension specified with --load-extension are checked, along
|
||||||
with their enclosing directories.
|
with their enclosing directories.
|
||||||
|
|
||||||
* The configure option --with-static-rnd=auto allows to build gpg
|
* The configure option --with-static-rnd=auto allows one to build gpg
|
||||||
with all available entropy gathering modules included. At
|
with all available entropy gathering modules included. At
|
||||||
runtime the best usable one will be selected from the list
|
runtime the best usable one will be selected from the list
|
||||||
linux, egd, unix. This is also the default for systems lacking
|
linux, egd, unix. This is also the default for systems lacking
|
||||||
|
@ -4358,7 +4606,7 @@ Noteworthy changes in version 1.0.2 (2000-07-12)
|
||||||
* New command --export-secret-subkeys which outputs the
|
* New command --export-secret-subkeys which outputs the
|
||||||
the _primary_ key with it's secret parts deleted. This is
|
the _primary_ key with it's secret parts deleted. This is
|
||||||
useful for automated decryption/signature creation as it
|
useful for automated decryption/signature creation as it
|
||||||
allows to keep the real secret primary key offline and
|
allows one to keep the real secret primary key offline and
|
||||||
thereby protecting the key certificates and allowing to
|
thereby protecting the key certificates and allowing to
|
||||||
create revocations for the subkeys. See the FAQ for a
|
create revocations for the subkeys. See the FAQ for a
|
||||||
procedure to install such secret keys.
|
procedure to install such secret keys.
|
||||||
|
|
57
README
57
README
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
Copyright 1997-2019 Werner Koch
|
Copyright 1997-2019 Werner Koch
|
||||||
Copyright 1998-2021 Free Software Foundation, Inc.
|
Copyright 1998-2021 Free Software Foundation, Inc.
|
||||||
Copyright 2003-2023 g10 Code GmbH
|
Copyright 2003-2024 g10 Code GmbH
|
||||||
|
|
||||||
|
|
||||||
* INTRODUCTION
|
* INTRODUCTION
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
Several other standard libraries are also required. The configure
|
Several other standard libraries are also required. The configure
|
||||||
script prints diagnostic messages if one of these libraries is not
|
script prints diagnostic messages if one of these libraries is not
|
||||||
available and a feature will not be available..
|
available and a feature will not be available.
|
||||||
|
|
||||||
You also need the Pinentry package for most functions of GnuPG;
|
You also need the Pinentry package for most functions of GnuPG;
|
||||||
however it is not a build requirement. Pinentry is available at
|
however it is not a build requirement. Pinentry is available at
|
||||||
|
@ -80,15 +80,24 @@
|
||||||
|
|
||||||
to view the directories used by GnuPG.
|
to view the directories used by GnuPG.
|
||||||
|
|
||||||
|
** Quick build method on Unix
|
||||||
|
|
||||||
To quickly build all required software without installing it, the
|
To quickly build all required software without installing it, the
|
||||||
Speedo method may be used:
|
Speedo target may be used:
|
||||||
|
|
||||||
cd build
|
make -f build-aux/speedo.mk native
|
||||||
make -f ../build-aux/speedo.mk native
|
|
||||||
|
This target downloads all required libraries and does a native build
|
||||||
|
of GnuPG to PLAY/inst/. GNU make and the patchelf tool are
|
||||||
|
required. After the build the entire software including all
|
||||||
|
libraries can be installed into an arbitrary location using for
|
||||||
|
example:
|
||||||
|
|
||||||
|
make -f build-aux/speedo.mk install SYSROOT=/usr/local/gnupg24
|
||||||
|
ldconfig -n /usr/local/gnupg24/lib
|
||||||
|
|
||||||
|
and adding /usr/local/gnupg24/bin to PATH.
|
||||||
|
|
||||||
This method downloads all required libraries and does a native build
|
|
||||||
of GnuPG to PLAY/inst/. GNU make is required and you need to set
|
|
||||||
LD_LIBRARY_PATH to $(pwd)/PLAY/inst/lib to test the binaries.
|
|
||||||
|
|
||||||
** Specific build problems on some machines:
|
** Specific build problems on some machines:
|
||||||
|
|
||||||
|
@ -144,6 +153,13 @@
|
||||||
gpg --import --import-options restore < allkeys.gpg
|
gpg --import --import-options restore < allkeys.gpg
|
||||||
gpgsm --import < allcerts.crt
|
gpgsm --import < allcerts.crt
|
||||||
|
|
||||||
|
In case the keyboxd is not able to startup due to a stale lockfile
|
||||||
|
created by another host, the command
|
||||||
|
|
||||||
|
gpgconf --unlock pubring.db
|
||||||
|
|
||||||
|
can be used to remove the lock file.
|
||||||
|
|
||||||
** Socket directory
|
** Socket directory
|
||||||
|
|
||||||
GnuPG uses Unix domain sockets to connect its components (on Windows
|
GnuPG uses Unix domain sockets to connect its components (on Windows
|
||||||
|
@ -166,11 +182,34 @@
|
||||||
fi
|
fi
|
||||||
done )
|
done )
|
||||||
|
|
||||||
|
** Conflicts with systemd socket activation
|
||||||
|
|
||||||
|
Some Linux distribution use the meanwhile deprecated --supervised
|
||||||
|
option with gpg-agent, dirmngr, and keyboxd. The idea is that the
|
||||||
|
systemd process launches the daemons as soon as gpg or gpgsm try to
|
||||||
|
access them. However, this creates a race condition with GnuPG's
|
||||||
|
own on-demand launching of these daemon. It also conflicts with the
|
||||||
|
remote use gpg-agent because the no-autostart feature on the remote
|
||||||
|
site will not work as expected.
|
||||||
|
|
||||||
|
Thus the recommendation is not to use the --supervised option. All
|
||||||
|
GnuPG components handle the startup of their daemons on their own.
|
||||||
|
|
||||||
|
The only problem is that for using GnuPG's ssh-agent protocol
|
||||||
|
support, the gpg-agent must have been started before ssh. This can
|
||||||
|
either be done with an ssh wrapper running
|
||||||
|
|
||||||
|
gpg-connect-agent updatestartuptty /bye
|
||||||
|
|
||||||
|
for each new tty or by using that command directly after login when
|
||||||
|
the anyway required SSH_AUTH_SOCK envvar is set (see the example in
|
||||||
|
the gpg-agent man page).
|
||||||
|
|
||||||
|
|
||||||
* DOCUMENTATION
|
* DOCUMENTATION
|
||||||
|
|
||||||
The complete documentation is in the texinfo manual named
|
The complete documentation is in the texinfo manual named
|
||||||
`gnupg.info'. Run "info gnupg" to read it. If you want a a
|
`gnupg.info'. Run "info gnupg" to read it. If you want a
|
||||||
printable copy of the manual, change to the "doc" directory and
|
printable copy of the manual, change to the "doc" directory and
|
||||||
enter "make pdf" For a HTML version enter "make html" and point your
|
enter "make pdf" For a HTML version enter "make html" and point your
|
||||||
browser to gnupg.html/index.html. Standard man pages for all
|
browser to gnupg.html/index.html. Standard man pages for all
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# Makefile.am - agent
|
||||||
# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
|
# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is part of GnuPG.
|
# This file is part of GnuPG.
|
||||||
|
@ -23,8 +24,8 @@ libexec_PROGRAMS = gpg-protect-tool
|
||||||
libexec_PROGRAMS += gpg-preset-passphrase
|
libexec_PROGRAMS += gpg-preset-passphrase
|
||||||
noinst_PROGRAMS = $(TESTS)
|
noinst_PROGRAMS = $(TESTS)
|
||||||
|
|
||||||
EXTRA_DIST = ChangeLog-2011 gpg-agent-w32info.rc all-tests.scm
|
EXTRA_DIST = ChangeLog-2011 all-tests.scm \
|
||||||
|
gpg-agent-w32info.rc gpg-agent.w32-manifest.in
|
||||||
|
|
||||||
AM_CPPFLAGS =
|
AM_CPPFLAGS =
|
||||||
|
|
||||||
|
@ -32,6 +33,8 @@ include $(top_srcdir)/am/cmacros.am
|
||||||
|
|
||||||
if HAVE_W32_SYSTEM
|
if HAVE_W32_SYSTEM
|
||||||
resource_objs += gpg-agent-w32info.o
|
resource_objs += gpg-agent-w32info.o
|
||||||
|
|
||||||
|
gpg-agent-w32info.o : gpg-agent.w32-manifest ../common/w32info-rc.h
|
||||||
endif
|
endif
|
||||||
|
|
||||||
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
|
||||||
|
|
|
@ -86,8 +86,8 @@ struct
|
||||||
/* Enable pinentry debugging (--debug 1024 should also be used). */
|
/* Enable pinentry debugging (--debug 1024 should also be used). */
|
||||||
int debug_pinentry;
|
int debug_pinentry;
|
||||||
|
|
||||||
/* Filename of the program to start as pinentry. */
|
/* Filename of the program to start as pinentry (malloced). */
|
||||||
const char *pinentry_program;
|
char *pinentry_program;
|
||||||
|
|
||||||
/* Filename of the program to handle daemon tasks. */
|
/* Filename of the program to handle daemon tasks. */
|
||||||
const char *daemon_program[DAEMON_MAX_TYPE];
|
const char *daemon_program[DAEMON_MAX_TYPE];
|
||||||
|
@ -121,7 +121,7 @@ struct
|
||||||
/* Flag disallowing bypassing of the warning. */
|
/* Flag disallowing bypassing of the warning. */
|
||||||
int enforce_passphrase_constraints;
|
int enforce_passphrase_constraints;
|
||||||
|
|
||||||
/* The require minmum length of a passphrase. */
|
/* The required minimum length of a passphrase. */
|
||||||
unsigned int min_passphrase_len;
|
unsigned int min_passphrase_len;
|
||||||
|
|
||||||
/* The minimum number of non-alpha characters in a passphrase. */
|
/* The minimum number of non-alpha characters in a passphrase. */
|
||||||
|
@ -225,6 +225,17 @@ typedef struct ssh_control_file_s *ssh_control_file_t;
|
||||||
/* Forward reference for local definitions in call-scd.c. */
|
/* Forward reference for local definitions in call-scd.c. */
|
||||||
struct daemon_local_s;
|
struct daemon_local_s;
|
||||||
|
|
||||||
|
/* Object to hold ephemeral secret keys. */
|
||||||
|
struct ephemeral_private_key_s
|
||||||
|
{
|
||||||
|
struct ephemeral_private_key_s *next;
|
||||||
|
unsigned char grip[KEYGRIP_LEN];
|
||||||
|
unsigned char *keybuf; /* Canon-s-exp with the private key (malloced). */
|
||||||
|
size_t keybuflen;
|
||||||
|
};
|
||||||
|
typedef struct ephemeral_private_key_s *ephemeral_private_key_t;
|
||||||
|
|
||||||
|
|
||||||
/* Collection of data per session (aka connection). */
|
/* Collection of data per session (aka connection). */
|
||||||
struct server_control_s
|
struct server_control_s
|
||||||
{
|
{
|
||||||
|
@ -246,6 +257,12 @@ struct server_control_s
|
||||||
/* Private data of the daemon (call-XXX.c). */
|
/* Private data of the daemon (call-XXX.c). */
|
||||||
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
|
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
|
||||||
|
|
||||||
|
/* Linked list with ephemeral stored private keys. */
|
||||||
|
ephemeral_private_key_t ephemeral_keys;
|
||||||
|
|
||||||
|
/* If set functions will lookup keys in the ephemeral_keys list. */
|
||||||
|
int ephemeral_mode;
|
||||||
|
|
||||||
/* Environment settings for the connection. */
|
/* Environment settings for the connection. */
|
||||||
session_env_t session_env;
|
session_env_t session_env;
|
||||||
char *lc_ctype;
|
char *lc_ctype;
|
||||||
|
@ -269,10 +286,13 @@ struct server_control_s
|
||||||
int algo;
|
int algo;
|
||||||
unsigned char value[MAX_DIGEST_LEN];
|
unsigned char value[MAX_DIGEST_LEN];
|
||||||
unsigned int raw_value: 1;
|
unsigned int raw_value: 1;
|
||||||
unsigned int is_pss: 1; /* DATA holds PSS formated data. */
|
unsigned int is_pss: 1; /* DATA holds PSS formatted data. */
|
||||||
} digest;
|
} digest;
|
||||||
|
unsigned int have_keygrip: 1;
|
||||||
|
unsigned int have_keygrip1: 1;
|
||||||
unsigned char keygrip[20];
|
unsigned char keygrip[20];
|
||||||
int have_keygrip;
|
unsigned char keygrip1[20]; /* Another keygrip for hybrid crypto. */
|
||||||
|
|
||||||
|
|
||||||
/* A flag to enable a hack to send the PKAUTH command instead of the
|
/* A flag to enable a hack to send the PKAUTH command instead of the
|
||||||
PKSIGN command to the scdaemon. */
|
PKSIGN command to the scdaemon. */
|
||||||
|
@ -411,6 +431,7 @@ void *get_agent_daemon_notify_event (void);
|
||||||
#endif
|
#endif
|
||||||
void agent_sighup_action (void);
|
void agent_sighup_action (void);
|
||||||
int map_pk_openpgp_to_gcry (int openpgp_algo);
|
int map_pk_openpgp_to_gcry (int openpgp_algo);
|
||||||
|
void agent_kick_the_loop (void);
|
||||||
|
|
||||||
/*-- command.c --*/
|
/*-- command.c --*/
|
||||||
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid,
|
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid,
|
||||||
|
@ -452,10 +473,13 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
|
||||||
/*-- findkey.c --*/
|
/*-- findkey.c --*/
|
||||||
gpg_error_t agent_modify_description (const char *in, const char *comment,
|
gpg_error_t agent_modify_description (const char *in, const char *comment,
|
||||||
const gcry_sexp_t key, char **result);
|
const gcry_sexp_t key, char **result);
|
||||||
int agent_write_private_key (const unsigned char *grip,
|
gpg_error_t agent_write_private_key (ctrl_t ctrl,
|
||||||
const void *buffer, size_t length, int force,
|
const unsigned char *grip,
|
||||||
const char *serialno, const char *keyref,
|
const void *buffer, size_t length,
|
||||||
time_t timestamp);
|
int force,
|
||||||
|
const char *serialno, const char *keyref,
|
||||||
|
const char *dispserialno,
|
||||||
|
time_t timestamp);
|
||||||
gpg_error_t agent_key_from_file (ctrl_t ctrl,
|
gpg_error_t agent_key_from_file (ctrl_t ctrl,
|
||||||
const char *cache_nonce,
|
const char *cache_nonce,
|
||||||
const char *desc_text,
|
const char *desc_text,
|
||||||
|
@ -475,7 +499,7 @@ gpg_error_t agent_ssh_key_from_file (ctrl_t ctrl,
|
||||||
gcry_sexp_t *result, int *r_order);
|
gcry_sexp_t *result, int *r_order);
|
||||||
int agent_pk_get_algo (gcry_sexp_t s_key);
|
int agent_pk_get_algo (gcry_sexp_t s_key);
|
||||||
int agent_is_tpm2_key(gcry_sexp_t s_key);
|
int agent_is_tpm2_key(gcry_sexp_t s_key);
|
||||||
int agent_key_available (const unsigned char *grip);
|
int agent_key_available (ctrl_t ctrl, const unsigned char *grip);
|
||||||
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
int *r_keytype,
|
int *r_keytype,
|
||||||
unsigned char **r_shadow_info,
|
unsigned char **r_shadow_info,
|
||||||
|
@ -483,7 +507,8 @@ gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
|
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
|
||||||
const unsigned char *grip,
|
const unsigned char *grip,
|
||||||
int force, int only_stubs);
|
int force, int only_stubs);
|
||||||
gpg_error_t agent_update_private_key (const unsigned char *grip, nvc_t pk);
|
gpg_error_t agent_update_private_key (ctrl_t ctrl,
|
||||||
|
const unsigned char *grip, nvc_t pk);
|
||||||
|
|
||||||
/*-- call-pinentry.c --*/
|
/*-- call-pinentry.c --*/
|
||||||
void initialize_module_call_pinentry (void);
|
void initialize_module_call_pinentry (void);
|
||||||
|
@ -512,7 +537,7 @@ int agent_clear_passphrase (ctrl_t ctrl,
|
||||||
/*-- cache.c --*/
|
/*-- cache.c --*/
|
||||||
void initialize_module_cache (void);
|
void initialize_module_cache (void);
|
||||||
void deinitialize_module_cache (void);
|
void deinitialize_module_cache (void);
|
||||||
void agent_cache_housekeeping (void);
|
struct timespec *agent_cache_expiration (void);
|
||||||
void agent_flush_cache (int pincache_only);
|
void agent_flush_cache (int pincache_only);
|
||||||
int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
||||||
const char *data, int ttl);
|
const char *data, int ttl);
|
||||||
|
@ -535,19 +560,37 @@ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||||
const unsigned char *ciphertext, size_t ciphertextlen,
|
const unsigned char *ciphertext, size_t ciphertextlen,
|
||||||
membuf_t *outbuf, int *r_padding);
|
membuf_t *outbuf, int *r_padding);
|
||||||
|
|
||||||
|
enum kemids
|
||||||
|
{
|
||||||
|
KEM_PQC_PGP,
|
||||||
|
KEM_PGP,
|
||||||
|
KEM_CMS
|
||||||
|
};
|
||||||
|
|
||||||
|
gpg_error_t agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
|
||||||
|
const unsigned char *ct, size_t ctlen,
|
||||||
|
const unsigned char *option, size_t optionlen,
|
||||||
|
membuf_t *outbuf);
|
||||||
|
|
||||||
/*-- genkey.c --*/
|
/*-- genkey.c --*/
|
||||||
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
|
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
|
||||||
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
|
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
|
||||||
|
|
||||||
|
#define GENKEY_FLAG_NO_PROTECTION 1
|
||||||
|
#define GENKEY_FLAG_PRESET 2
|
||||||
|
|
||||||
|
void clear_ephemeral_keys (ctrl_t ctrl);
|
||||||
|
|
||||||
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
|
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
char **failed_constraint);
|
char **failed_constraint);
|
||||||
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
||||||
char **r_passphrase);
|
char **r_passphrase);
|
||||||
int agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
int agent_genkey (ctrl_t ctrl, unsigned int flags,
|
||||||
|
const char *cache_nonce, time_t timestamp,
|
||||||
const char *keyparam, size_t keyparmlen,
|
const char *keyparam, size_t keyparmlen,
|
||||||
int no_protection, const char *override_passphrase,
|
const char *override_passphrase,
|
||||||
int preset, membuf_t *outbuf);
|
membuf_t *outbuf);
|
||||||
gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
||||||
char **passphrase_addr);
|
char **passphrase_addr);
|
||||||
|
|
||||||
|
@ -585,9 +628,10 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
|
||||||
const unsigned char *s2ksalt,
|
const unsigned char *s2ksalt,
|
||||||
unsigned int s2kcount,
|
unsigned int s2kcount,
|
||||||
unsigned char *key, size_t keylen);
|
unsigned char *key, size_t keylen);
|
||||||
gpg_error_t agent_write_shadow_key (const unsigned char *grip,
|
gpg_error_t agent_write_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
const char *serialno, const char *keyid,
|
const char *serialno, const char *keyid,
|
||||||
const unsigned char *pkbuf, int force);
|
const unsigned char *pkbuf, int force,
|
||||||
|
const char *dispserialno);
|
||||||
|
|
||||||
|
|
||||||
/*-- trustlist.c --*/
|
/*-- trustlist.c --*/
|
||||||
|
@ -661,6 +705,9 @@ gpg_error_t divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||||
const char *keyref,
|
const char *keyref,
|
||||||
const char *keydata, size_t keydatalen);
|
const char *keydata, size_t keydatalen);
|
||||||
|
|
||||||
|
gpg_error_t agent_card_ecc_kem (ctrl_t ctrl, const unsigned char *ecc_ct,
|
||||||
|
size_t ecc_point_len, unsigned char *ecc_ecdh);
|
||||||
|
|
||||||
/*-- call-daemon.c --*/
|
/*-- call-daemon.c --*/
|
||||||
gpg_error_t daemon_start (enum daemon_type type, ctrl_t ctrl);
|
gpg_error_t daemon_start (enum daemon_type type, ctrl_t ctrl);
|
||||||
assuan_context_t daemon_type_ctx (enum daemon_type type, ctrl_t ctrl);
|
assuan_context_t daemon_type_ctx (enum daemon_type type, ctrl_t ctrl);
|
||||||
|
@ -709,6 +756,7 @@ int agent_card_pkdecrypt (ctrl_t ctrl,
|
||||||
const char *desc_text,
|
const char *desc_text,
|
||||||
const unsigned char *indata, size_t indatalen,
|
const unsigned char *indata, size_t indatalen,
|
||||||
char **r_buf, size_t *r_buflen, int *r_padding);
|
char **r_buf, size_t *r_buflen, int *r_padding);
|
||||||
|
|
||||||
int agent_card_readcert (ctrl_t ctrl,
|
int agent_card_readcert (ctrl_t ctrl,
|
||||||
const char *id, char **r_buf, size_t *r_buflen);
|
const char *id, char **r_buf, size_t *r_buflen);
|
||||||
int agent_card_readkey (ctrl_t ctrl, const char *id,
|
int agent_card_readkey (ctrl_t ctrl, const char *id,
|
||||||
|
@ -730,7 +778,6 @@ void agent_card_free_keyinfo (struct card_key_info_s *l);
|
||||||
gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
|
gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
|
||||||
int cap, struct card_key_info_s **result);
|
int cap, struct card_key_info_s **result);
|
||||||
|
|
||||||
|
|
||||||
/*-- learncard.c --*/
|
/*-- learncard.c --*/
|
||||||
int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
|
int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
|
||||||
|
|
||||||
|
|
364
agent/cache.c
364
agent/cache.c
|
@ -53,8 +53,20 @@ struct secret_data_s {
|
||||||
char data[1]; /* A string. */
|
char data[1]; /* A string. */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The cache object. */
|
/* The type of cache object. */
|
||||||
typedef struct cache_item_s *ITEM;
|
typedef struct cache_item_s *ITEM;
|
||||||
|
|
||||||
|
/* The timer entry in a linked list. */
|
||||||
|
struct timer_s {
|
||||||
|
ITEM next;
|
||||||
|
int tv_sec;
|
||||||
|
int reason;
|
||||||
|
};
|
||||||
|
#define CACHE_EXPIRE_UNUSED 0
|
||||||
|
#define CACHE_EXPIRE_LAST_ACCESS 1
|
||||||
|
#define CACHE_EXPIRE_CREATION 2
|
||||||
|
|
||||||
|
/* The cache object. */
|
||||||
struct cache_item_s {
|
struct cache_item_s {
|
||||||
ITEM next;
|
ITEM next;
|
||||||
time_t created;
|
time_t created;
|
||||||
|
@ -63,12 +75,18 @@ struct cache_item_s {
|
||||||
struct secret_data_s *pw;
|
struct secret_data_s *pw;
|
||||||
cache_mode_t cache_mode;
|
cache_mode_t cache_mode;
|
||||||
int restricted; /* The value of ctrl->restricted is part of the key. */
|
int restricted; /* The value of ctrl->restricted is part of the key. */
|
||||||
|
struct timer_s t;
|
||||||
char key[1];
|
char key[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The cache himself. */
|
/* The cache himself. */
|
||||||
static ITEM thecache;
|
static ITEM thecache;
|
||||||
|
|
||||||
|
/* The timer list of expiration, in active. */
|
||||||
|
static ITEM the_timer_list;
|
||||||
|
/* Newly created entries, to be inserted into the timer list. */
|
||||||
|
static ITEM the_timer_list_new;
|
||||||
|
|
||||||
/* NULL or the last cache key stored by agent_store_cache_hit. */
|
/* NULL or the last cache key stored by agent_store_cache_hit. */
|
||||||
static char *last_stored_cache_key;
|
static char *last_stored_cache_key;
|
||||||
|
|
||||||
|
@ -193,100 +211,302 @@ new_data (const char *string, struct secret_data_s **r_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether there are items to expire. */
|
|
||||||
static void
|
static void
|
||||||
housekeeping (void)
|
insert_to_timer_list_new (ITEM entry)
|
||||||
{
|
{
|
||||||
ITEM r, rprev;
|
entry->t.next = the_timer_list_new;
|
||||||
|
the_timer_list_new = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert to the active timer list. */
|
||||||
|
static void
|
||||||
|
insert_to_timer_list (struct timespec *ts, ITEM entry)
|
||||||
|
{
|
||||||
|
ITEM e, eprev;
|
||||||
|
|
||||||
|
if (!the_timer_list || ts->tv_sec >= entry->t.tv_sec)
|
||||||
|
{
|
||||||
|
if (the_timer_list)
|
||||||
|
{
|
||||||
|
the_timer_list->t.tv_sec += ts->tv_sec - entry->t.tv_sec;
|
||||||
|
if (ts->tv_nsec >= 500000000)
|
||||||
|
the_timer_list->t.tv_sec++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts->tv_sec = entry->t.tv_sec;
|
||||||
|
ts->tv_nsec = 0;
|
||||||
|
|
||||||
|
entry->t.tv_sec = 0;
|
||||||
|
entry->t.next = the_timer_list;
|
||||||
|
the_timer_list = entry;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->t.tv_sec -= ts->tv_sec;
|
||||||
|
eprev = NULL;
|
||||||
|
for (e = the_timer_list; e; e = e->t.next)
|
||||||
|
{
|
||||||
|
if (e->t.tv_sec > entry->t.tv_sec)
|
||||||
|
break;
|
||||||
|
|
||||||
|
eprev = e;
|
||||||
|
entry->t.tv_sec -= e->t.tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->t.next = e;
|
||||||
|
if (e)
|
||||||
|
e->t.tv_sec -= entry->t.tv_sec;
|
||||||
|
|
||||||
|
if (eprev)
|
||||||
|
eprev->t.next = entry;
|
||||||
|
else
|
||||||
|
the_timer_list = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_from_timer_list (ITEM entry)
|
||||||
|
{
|
||||||
|
ITEM e, eprev;
|
||||||
|
|
||||||
|
eprev = NULL;
|
||||||
|
for (e = the_timer_list; e; e = e->t.next)
|
||||||
|
if (e != entry)
|
||||||
|
eprev = e;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (e->t.next)
|
||||||
|
e->t.next->t.tv_sec += e->t.tv_sec;
|
||||||
|
|
||||||
|
if (eprev)
|
||||||
|
eprev->t.next = e->t.next;
|
||||||
|
else
|
||||||
|
the_timer_list = e->t.next;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->t.next = NULL;
|
||||||
|
entry->t.tv_sec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_from_timer_list_new (ITEM entry)
|
||||||
|
{
|
||||||
|
ITEM e, eprev;
|
||||||
|
|
||||||
|
eprev = NULL;
|
||||||
|
for (e = the_timer_list_new; e; e = e->t.next)
|
||||||
|
if (e != entry)
|
||||||
|
eprev = e;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (eprev)
|
||||||
|
eprev->t.next = e->t.next;
|
||||||
|
else
|
||||||
|
the_timer_list_new = e->t.next;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->t.next = NULL;
|
||||||
|
entry->t.tv_sec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compute_expiration (ITEM r)
|
||||||
|
{
|
||||||
|
unsigned long maxttl;
|
||||||
time_t current = gnupg_get_time ();
|
time_t current = gnupg_get_time ();
|
||||||
|
time_t next;
|
||||||
|
|
||||||
/* First expire the actual data */
|
if (r->cache_mode == CACHE_MODE_PIN)
|
||||||
for (r=thecache; r; r = r->next)
|
return 0; /* Don't let it expire - scdaemon explicitly flushes them. */
|
||||||
|
|
||||||
|
if (!r->pw)
|
||||||
{
|
{
|
||||||
if (r->cache_mode == CACHE_MODE_PIN)
|
/* Expire an old and unused entry after 30 minutes. */
|
||||||
; /* Don't let it expire - scdaemon explicitly flushes them. */
|
r->t.tv_sec = 60*30;
|
||||||
else if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
|
r->t.reason = CACHE_EXPIRE_UNUSED;
|
||||||
{
|
return 1;
|
||||||
if (DBG_CACHE)
|
|
||||||
log_debug (" expired '%s'.%d (%ds after last access)\n",
|
|
||||||
r->key, r->restricted, r->ttl);
|
|
||||||
release_data (r->pw);
|
|
||||||
r->pw = NULL;
|
|
||||||
r->accessed = current;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second, make sure that we also remove them based on the created
|
switch (r->cache_mode)
|
||||||
* stamp so that the user has to enter it from time to time. We
|
|
||||||
* don't do this for data items which are used to storage secrets in
|
|
||||||
* meory and are not user entered passphrases etc. */
|
|
||||||
for (r=thecache; r; r = r->next)
|
|
||||||
{
|
{
|
||||||
unsigned long maxttl;
|
case CACHE_MODE_DATA:
|
||||||
|
case CACHE_MODE_PIN:
|
||||||
switch (r->cache_mode)
|
maxttl = 0; /* No MAX TTL here. */
|
||||||
{
|
break;
|
||||||
case CACHE_MODE_DATA:
|
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
|
||||||
case CACHE_MODE_PIN:
|
default: maxttl = opt.max_cache_ttl; break;
|
||||||
continue; /* No MAX TTL here. */
|
|
||||||
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
|
|
||||||
default: maxttl = opt.max_cache_ttl; break;
|
|
||||||
}
|
|
||||||
if (r->pw && r->created + maxttl < current)
|
|
||||||
{
|
|
||||||
if (DBG_CACHE)
|
|
||||||
log_debug (" expired '%s'.%d (%lus after creation)\n",
|
|
||||||
r->key, r->restricted, opt.max_cache_ttl);
|
|
||||||
release_data (r->pw);
|
|
||||||
r->pw = NULL;
|
|
||||||
r->accessed = current;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Third, make sure that we don't have too many items in the list.
|
if (maxttl)
|
||||||
* Expire old and unused entries after 30 minutes. */
|
|
||||||
for (rprev=NULL, r=thecache; r; )
|
|
||||||
{
|
{
|
||||||
if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
|
if (r->created + maxttl < current)
|
||||||
{
|
{
|
||||||
ITEM r2 = r->next;
|
r->t.tv_sec = 0;
|
||||||
if (DBG_CACHE)
|
r->t.reason = CACHE_EXPIRE_CREATION;
|
||||||
log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
|
return 1;
|
||||||
r->key, r->restricted, r->cache_mode);
|
|
||||||
xfree (r);
|
|
||||||
if (!rprev)
|
|
||||||
thecache = r2;
|
|
||||||
else
|
|
||||||
rprev->next = r2;
|
|
||||||
r = r2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rprev = r;
|
|
||||||
r = r->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next = r->created + maxttl - current;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next = 0;
|
||||||
|
|
||||||
|
if (r->ttl >= 0 && (next == 0 || r->ttl < next))
|
||||||
|
{
|
||||||
|
r->t.tv_sec = r->ttl;
|
||||||
|
r->t.reason = CACHE_EXPIRE_LAST_ACCESS;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next)
|
||||||
|
{
|
||||||
|
r->t.tv_sec = next;
|
||||||
|
r->t.reason = CACHE_EXPIRE_CREATION;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_expiration (ITEM entry, int is_new_entry)
|
||||||
|
{
|
||||||
|
if (!is_new_entry)
|
||||||
|
{
|
||||||
|
remove_from_timer_list (entry);
|
||||||
|
remove_from_timer_list_new (entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compute_expiration (entry))
|
||||||
|
{
|
||||||
|
insert_to_timer_list_new (entry);
|
||||||
|
agent_kick_the_loop ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
/* Expire the cache entry. Returns 1 when the entry should be removed
|
||||||
agent_cache_housekeeping (void)
|
* from the cache. */
|
||||||
|
static int
|
||||||
|
do_expire (ITEM e)
|
||||||
{
|
{
|
||||||
int res;
|
if (!e->pw)
|
||||||
|
/* Unused entry after 30 minutes. */
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (DBG_CACHE)
|
if (e->t.reason == CACHE_EXPIRE_LAST_ACCESS)
|
||||||
log_debug ("agent_cache_housekeeping\n");
|
{
|
||||||
|
if (DBG_CACHE)
|
||||||
|
log_debug (" expired '%s'.%d (%ds after last access)\n",
|
||||||
|
e->key, e->restricted, e->ttl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (DBG_CACHE)
|
||||||
|
log_debug (" expired '%s'.%d (%lus after creation)\n",
|
||||||
|
e->key, e->restricted, opt.max_cache_ttl);
|
||||||
|
}
|
||||||
|
|
||||||
|
release_data (e->pw);
|
||||||
|
e->pw = NULL;
|
||||||
|
e->accessed = 0;
|
||||||
|
|
||||||
|
if (compute_expiration (e))
|
||||||
|
insert_to_timer_list_new (e);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct timespec *
|
||||||
|
agent_cache_expiration (void)
|
||||||
|
{
|
||||||
|
static struct timespec abstime;
|
||||||
|
static struct timespec timeout;
|
||||||
|
struct timespec *tp;
|
||||||
|
struct timespec curtime;
|
||||||
|
int res;
|
||||||
|
int expired = 0;
|
||||||
|
ITEM e, enext;
|
||||||
|
|
||||||
res = npth_mutex_lock (&cache_lock);
|
res = npth_mutex_lock (&cache_lock);
|
||||||
if (res)
|
if (res)
|
||||||
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
|
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
|
||||||
|
|
||||||
housekeeping ();
|
npth_clock_gettime (&curtime);
|
||||||
|
if (the_timer_list)
|
||||||
|
{
|
||||||
|
if (npth_timercmp (&abstime, &curtime, <))
|
||||||
|
expired = 1;
|
||||||
|
else
|
||||||
|
npth_timersub (&abstime, &curtime, &timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expired && (e = the_timer_list) && e->t.tv_sec == 0)
|
||||||
|
{
|
||||||
|
the_timer_list = e->t.next;
|
||||||
|
e->t.next = NULL;
|
||||||
|
|
||||||
|
if (do_expire (e))
|
||||||
|
{
|
||||||
|
ITEM r, rprev;
|
||||||
|
|
||||||
|
if (DBG_CACHE)
|
||||||
|
log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
|
||||||
|
e->key, e->restricted, e->cache_mode);
|
||||||
|
|
||||||
|
rprev = NULL;
|
||||||
|
for (r = thecache; r; r = r->next)
|
||||||
|
if (r == e)
|
||||||
|
{
|
||||||
|
if (!rprev)
|
||||||
|
thecache = r->next;
|
||||||
|
else
|
||||||
|
rprev->next = r->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rprev = r;
|
||||||
|
|
||||||
|
remove_from_timer_list_new (e);
|
||||||
|
|
||||||
|
xfree (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expired || !the_timer_list)
|
||||||
|
timeout.tv_sec = timeout.tv_nsec = 0;
|
||||||
|
|
||||||
|
for (e = the_timer_list_new; e; e = enext)
|
||||||
|
{
|
||||||
|
enext = e->t.next;
|
||||||
|
e->t.next = NULL;
|
||||||
|
insert_to_timer_list (&timeout, e);
|
||||||
|
}
|
||||||
|
the_timer_list_new = NULL;
|
||||||
|
|
||||||
|
if (!the_timer_list)
|
||||||
|
tp = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (the_timer_list->t.tv_sec != 0)
|
||||||
|
{
|
||||||
|
timeout.tv_sec += the_timer_list->t.tv_sec;
|
||||||
|
the_timer_list->t.tv_sec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
npth_timeradd (&timeout, &curtime, &abstime);
|
||||||
|
tp = &timeout;
|
||||||
|
}
|
||||||
|
|
||||||
res = npth_mutex_unlock (&cache_lock);
|
res = npth_mutex_unlock (&cache_lock);
|
||||||
if (res)
|
if (res)
|
||||||
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
|
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
|
||||||
|
|
||||||
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -314,6 +534,7 @@ agent_flush_cache (int pincache_only)
|
||||||
release_data (r->pw);
|
release_data (r->pw);
|
||||||
r->pw = NULL;
|
r->pw = NULL;
|
||||||
r->accessed = 0;
|
r->accessed = 0;
|
||||||
|
update_expiration (r, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +579,6 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
||||||
if (DBG_CACHE)
|
if (DBG_CACHE)
|
||||||
log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
|
log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
|
||||||
key, restricted, cache_mode, ttl);
|
key, restricted, cache_mode, ttl);
|
||||||
housekeeping ();
|
|
||||||
|
|
||||||
if (!ttl)
|
if (!ttl)
|
||||||
{
|
{
|
||||||
|
@ -410,6 +630,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
||||||
err = new_data (data, &r->pw);
|
err = new_data (data, &r->pw);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("error replacing cache item: %s\n", gpg_strerror (err));
|
log_error ("error replacing cache item: %s\n", gpg_strerror (err));
|
||||||
|
update_expiration (r, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (data) /* Insert. */
|
else if (data) /* Insert. */
|
||||||
|
@ -431,6 +652,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
||||||
{
|
{
|
||||||
r->next = thecache;
|
r->next = thecache;
|
||||||
thecache = r;
|
thecache = r;
|
||||||
|
update_expiration (r, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -478,7 +700,6 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
|
||||||
log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
|
log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
|
||||||
key, restricted, cache_mode,
|
key, restricted, cache_mode,
|
||||||
last_stored? " (stored cache key)":"");
|
last_stored? " (stored cache key)":"");
|
||||||
housekeeping ();
|
|
||||||
|
|
||||||
for (r=thecache; r; r = r->next)
|
for (r=thecache; r; r = r->next)
|
||||||
{
|
{
|
||||||
|
@ -500,7 +721,10 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
|
||||||
* below. Note also that we don't update the accessed time
|
* below. Note also that we don't update the accessed time
|
||||||
* for data items. */
|
* for data items. */
|
||||||
if (r->cache_mode != CACHE_MODE_DATA)
|
if (r->cache_mode != CACHE_MODE_DATA)
|
||||||
r->accessed = gnupg_get_time ();
|
{
|
||||||
|
r->accessed = gnupg_get_time ();
|
||||||
|
update_expiration (r, 0);
|
||||||
|
}
|
||||||
if (DBG_CACHE)
|
if (DBG_CACHE)
|
||||||
log_debug ("... hit\n");
|
log_debug ("... hit\n");
|
||||||
if (r->pw->totallen < 32)
|
if (r->pw->totallen < 32)
|
||||||
|
|
|
@ -98,7 +98,6 @@ static npth_mutex_t start_daemon_lock;
|
||||||
struct wait_child_thread_parm_s
|
struct wait_child_thread_parm_s
|
||||||
{
|
{
|
||||||
enum daemon_type type;
|
enum daemon_type type;
|
||||||
pid_t pid;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -109,52 +108,14 @@ wait_child_thread (void *arg)
|
||||||
int err;
|
int err;
|
||||||
struct wait_child_thread_parm_s *parm = arg;
|
struct wait_child_thread_parm_s *parm = arg;
|
||||||
enum daemon_type type = parm->type;
|
enum daemon_type type = parm->type;
|
||||||
pid_t pid = parm->pid;
|
|
||||||
#ifndef HAVE_W32_SYSTEM
|
|
||||||
int wstatus;
|
|
||||||
#endif
|
|
||||||
const char *name = opt.daemon_program[type];
|
const char *name = opt.daemon_program[type];
|
||||||
struct daemon_global_s *g = &daemon_global[type];
|
struct daemon_global_s *g = &daemon_global[type];
|
||||||
struct daemon_local_s *sl;
|
struct daemon_local_s *sl;
|
||||||
|
|
||||||
xfree (parm); /* We have copied all data to the stack. */
|
xfree (parm); /* We have copied all data to the stack. */
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
assuan_pipe_wait_server_termination (g->primary_ctx, NULL, 0);
|
||||||
npth_unprotect ();
|
|
||||||
/* Note that although we use a pid_t here, it is actually a HANDLE. */
|
|
||||||
WaitForSingleObject ((HANDLE)pid, INFINITE);
|
|
||||||
npth_protect ();
|
|
||||||
log_info ("daemon %s finished\n", name);
|
log_info ("daemon %s finished\n", name);
|
||||||
#else /* !HAVE_W32_SYSTEM*/
|
|
||||||
|
|
||||||
again:
|
|
||||||
npth_unprotect ();
|
|
||||||
err = waitpid (pid, &wstatus, 0);
|
|
||||||
npth_protect ();
|
|
||||||
|
|
||||||
if (err < 0)
|
|
||||||
{
|
|
||||||
if (errno == EINTR)
|
|
||||||
goto again;
|
|
||||||
log_error ("waitpid for %s failed: %s\n", name, strerror (errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (WIFEXITED (wstatus))
|
|
||||||
log_info ("daemon %s finished (status %d)\n",
|
|
||||||
name, WEXITSTATUS (wstatus));
|
|
||||||
else if (WIFSIGNALED (wstatus))
|
|
||||||
log_info ("daemon %s killed by signal %d\n", name, WTERMSIG (wstatus));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (WIFSTOPPED (wstatus))
|
|
||||||
log_info ("daemon %s stopped by signal %d\n",
|
|
||||||
name, WSTOPSIG (wstatus));
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /*!HAVE_W32_SYSTEM*/
|
|
||||||
|
|
||||||
agent_flush_cache (1); /* Flush the PIN cache. */
|
agent_flush_cache (1); /* Flush the PIN cache. */
|
||||||
|
|
||||||
|
@ -166,8 +127,6 @@ wait_child_thread (void *arg)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1);
|
|
||||||
|
|
||||||
for (sl = g->local_list; sl; sl = sl->next_local)
|
for (sl = g->local_list; sl; sl = sl->next_local)
|
||||||
{
|
{
|
||||||
sl->invalid = 1;
|
sl->invalid = 1;
|
||||||
|
@ -471,8 +430,8 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
|
snprintf (buf, sizeof buf, "OPTION event-signal=%p",
|
||||||
(unsigned long)get_agent_daemon_notify_event ());
|
get_agent_daemon_notify_event ());
|
||||||
#else
|
#else
|
||||||
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
|
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
|
||||||
#endif
|
#endif
|
||||||
|
@ -496,7 +455,6 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
wctp->type = type;
|
wctp->type = type;
|
||||||
wctp->pid = assuan_get_pid (g->primary_ctx);
|
|
||||||
err = npth_attr_init (&tattr);
|
err = npth_attr_init (&tattr);
|
||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
|
@ -561,10 +519,9 @@ agent_daemon_dump_state (void)
|
||||||
for (i = 0; i < DAEMON_MAX_TYPE; i++) {
|
for (i = 0; i < DAEMON_MAX_TYPE; i++) {
|
||||||
struct daemon_global_s *g = &daemon_global[i];
|
struct daemon_global_s *g = &daemon_global[i];
|
||||||
|
|
||||||
log_info ("%s: name %s primary_ctx=%p pid=%ld reusable=%d\n", __func__,
|
log_info ("%s: name %s primary_ctx=%p reusable=%d\n", __func__,
|
||||||
gnupg_module_name (daemon_modules[i]),
|
gnupg_module_name (daemon_modules[i]),
|
||||||
g->primary_ctx,
|
g->primary_ctx,
|
||||||
(long)assuan_get_pid (g->primary_ctx),
|
|
||||||
g->primary_ctx_reusable);
|
g->primary_ctx_reusable);
|
||||||
if (g->socket_name)
|
if (g->socket_name)
|
||||||
log_info ("%s: socket='%s'\n", __func__, g->socket_name);
|
log_info ("%s: socket='%s'\n", __func__, g->socket_name);
|
||||||
|
|
|
@ -128,8 +128,9 @@ initialize_module_call_pinentry (void)
|
||||||
void
|
void
|
||||||
agent_query_dump_state (void)
|
agent_query_dump_state (void)
|
||||||
{
|
{
|
||||||
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
|
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%lx\n",
|
||||||
entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
|
entry_ctx, (long)assuan_get_pid (entry_ctx),
|
||||||
|
(unsigned long)popup_tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called to make sure that a popup window owned by the current
|
/* Called to make sure that a popup window owned by the current
|
||||||
|
@ -174,6 +175,7 @@ unlock_pinentry (ctrl_t ctrl, gpg_error_t rc)
|
||||||
case GPG_ERR_NO_PASSPHRASE:
|
case GPG_ERR_NO_PASSPHRASE:
|
||||||
case GPG_ERR_BAD_PASSPHRASE:
|
case GPG_ERR_BAD_PASSPHRASE:
|
||||||
case GPG_ERR_BAD_PIN:
|
case GPG_ERR_BAD_PIN:
|
||||||
|
case GPG_ERR_BAD_RESET_CODE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GPG_ERR_CORRUPTED_PROTECTION:
|
case GPG_ERR_CORRUPTED_PROTECTION:
|
||||||
|
@ -882,7 +884,7 @@ struct inq_cb_parm_s
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Return true if PIN is indentical to the last generated pin. */
|
/* Return true if PIN is identical to the last generated pin. */
|
||||||
static int
|
static int
|
||||||
is_generated_pin (struct inq_cb_parm_s *parm, const char *pin)
|
is_generated_pin (struct inq_cb_parm_s *parm, const char *pin)
|
||||||
{
|
{
|
||||||
|
@ -1287,8 +1289,6 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
|
||||||
static void *
|
static void *
|
||||||
watch_sock (void *arg)
|
watch_sock (void *arg)
|
||||||
{
|
{
|
||||||
pid_t pid = assuan_get_pid (entry_ctx);
|
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -1301,7 +1301,7 @@ watch_sock (void *arg)
|
||||||
|
|
||||||
FD_ZERO (&fdset);
|
FD_ZERO (&fdset);
|
||||||
FD_SET (FD2INT (sock), &fdset);
|
FD_SET (FD2INT (sock), &fdset);
|
||||||
err = npth_select (FD2INT (sock)+1, &fdset, NULL, NULL, &timeout);
|
err = npth_select (FD2NUM (sock)+1, &fdset, NULL, NULL, &timeout);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
|
@ -1316,17 +1316,7 @@ watch_sock (void *arg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid == (pid_t)(-1))
|
assuan_pipe_kill_server (entry_ctx);
|
||||||
; /* No pid available can't send a kill. */
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
/* Older versions of assuan set PID to 0 on Windows to indicate an
|
|
||||||
invalid value. */
|
|
||||||
else if (pid != (pid_t) INVALID_HANDLE_VALUE && pid != 0)
|
|
||||||
TerminateProcess ((HANDLE)pid, 1);
|
|
||||||
#else
|
|
||||||
else if (pid > 0)
|
|
||||||
kill (pid, SIGINT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1621,12 +1611,13 @@ agent_askpin (ctrl_t ctrl,
|
||||||
&& (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
&& (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||||
return unlock_pinentry (ctrl, rc);
|
return unlock_pinentry (ctrl, rc);
|
||||||
|
|
||||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
|
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||||
|
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN
|
||||||
|
|| gpg_err_code (rc) == GPG_ERR_BAD_RESET_CODE)
|
||||||
{
|
{
|
||||||
if (pininfo->cb_errtext)
|
if (pininfo->cb_errtext)
|
||||||
errtext = pininfo->cb_errtext;
|
errtext = pininfo->cb_errtext;
|
||||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
else
|
||||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
|
||||||
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
||||||
}
|
}
|
||||||
else if (rc)
|
else if (rc)
|
||||||
|
@ -1894,12 +1885,13 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||||
if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||||
return unlock_pinentry (ctrl, rc);
|
return unlock_pinentry (ctrl, rc);
|
||||||
|
|
||||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
|
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||||
|
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN
|
||||||
|
|| gpg_err_code (rc) == GPG_ERR_BAD_RESET_CODE)
|
||||||
{
|
{
|
||||||
if (pininfo->cb_errtext)
|
if (pininfo->cb_errtext)
|
||||||
errtext = pininfo->cb_errtext;
|
errtext = pininfo->cb_errtext;
|
||||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
else
|
||||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
|
||||||
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
||||||
}
|
}
|
||||||
else if (rc)
|
else if (rc)
|
||||||
|
@ -2121,7 +2113,6 @@ void
|
||||||
agent_popup_message_stop (ctrl_t ctrl)
|
agent_popup_message_stop (ctrl_t ctrl)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
|
|
||||||
|
@ -2134,26 +2125,10 @@ agent_popup_message_stop (ctrl_t ctrl)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = assuan_get_pid (entry_ctx);
|
if (popup_finished)
|
||||||
if (pid == (pid_t)(-1))
|
|
||||||
; /* No pid available can't send a kill. */
|
|
||||||
else if (popup_finished)
|
|
||||||
; /* Already finished and ready for joining. */
|
; /* Already finished and ready for joining. */
|
||||||
#ifdef HAVE_W32_SYSTEM
|
else
|
||||||
/* Older versions of assuan set PID to 0 on Windows to indicate an
|
assuan_pipe_kill_server (entry_ctx);
|
||||||
invalid value. */
|
|
||||||
else if (pid != (pid_t) INVALID_HANDLE_VALUE
|
|
||||||
&& pid != 0)
|
|
||||||
{
|
|
||||||
HANDLE process = (HANDLE) pid;
|
|
||||||
|
|
||||||
/* Arbitrary error code. */
|
|
||||||
TerminateProcess (process, 1);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
else if (pid > 0)
|
|
||||||
kill (pid, SIGINT);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Now wait for the thread to terminate. */
|
/* Now wait for the thread to terminate. */
|
||||||
rc = npth_join (popup_tid, NULL);
|
rc = npth_join (popup_tid, NULL);
|
||||||
|
|
|
@ -196,7 +196,8 @@ handle_pincache_get (const char *args, assuan_context_t ctx)
|
||||||
const char *key;
|
const char *key;
|
||||||
char *pin = NULL;
|
char *pin = NULL;
|
||||||
|
|
||||||
log_debug ("%s: enter '%s'\n", __func__, args);
|
if (DBG_CACHE)
|
||||||
|
log_debug ("%s: enter '%s'\n", __func__, args);
|
||||||
key = args;
|
key = args;
|
||||||
if (strlen (key) < 5)
|
if (strlen (key) < 5)
|
||||||
{
|
{
|
||||||
|
@ -210,11 +211,14 @@ handle_pincache_get (const char *args, assuan_context_t ctx)
|
||||||
if (!pin || !*pin)
|
if (!pin || !*pin)
|
||||||
{
|
{
|
||||||
xfree (pin);
|
xfree (pin);
|
||||||
|
pin = NULL;
|
||||||
err = 0; /* Not found is indicated by sending no data back. */
|
err = 0; /* Not found is indicated by sending no data back. */
|
||||||
log_debug ("%s: not cached\n", __func__);
|
if (DBG_CACHE)
|
||||||
|
log_debug ("%s: not cached\n", __func__);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
log_debug ("%s: cache returned '%s'\n", __func__, pin);
|
if (DBG_CACHE)
|
||||||
|
log_debug ("%s: cache returned '%s'\n", __func__, "[hidden]"/*pin*/);
|
||||||
err = assuan_send_data (ctx, pin, strlen (pin));
|
err = assuan_send_data (ctx, pin, strlen (pin));
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
@ -548,7 +552,8 @@ padding_info_cb (void *opaque, const char *line)
|
||||||
|
|
||||||
if ((s=has_leading_keyword (line, "PADDING")))
|
if ((s=has_leading_keyword (line, "PADDING")))
|
||||||
{
|
{
|
||||||
*r_padding = atoi (s);
|
if (r_padding)
|
||||||
|
*r_padding = atoi (s);
|
||||||
}
|
}
|
||||||
else if ((s=has_leading_keyword (line, "PINCACHE_PUT")))
|
else if ((s=has_leading_keyword (line, "PINCACHE_PUT")))
|
||||||
err = handle_pincache_put (s);
|
err = handle_pincache_put (s);
|
||||||
|
@ -560,8 +565,8 @@ padding_info_cb (void *opaque, const char *line)
|
||||||
/* Decipher INDATA using the current card. Note that the returned
|
/* Decipher INDATA using the current card. Note that the returned
|
||||||
* value is not an s-expression but the raw data as returned by
|
* value is not an s-expression but the raw data as returned by
|
||||||
* scdaemon. The padding information is stored at R_PADDING with -1
|
* scdaemon. The padding information is stored at R_PADDING with -1
|
||||||
* for not known. DESC_TEXT is an additional parameter passed to
|
* for not known, when it's not NULL. DESC_TEXT is an additional
|
||||||
* GETPIN_CB. */
|
* parameter passed to GETPIN_CB. */
|
||||||
int
|
int
|
||||||
agent_card_pkdecrypt (ctrl_t ctrl,
|
agent_card_pkdecrypt (ctrl_t ctrl,
|
||||||
const char *keyid,
|
const char *keyid,
|
||||||
|
@ -579,7 +584,8 @@ agent_card_pkdecrypt (ctrl_t ctrl,
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
*r_buf = NULL;
|
*r_buf = NULL;
|
||||||
*r_padding = -1; /* Unknown. */
|
if (r_padding)
|
||||||
|
*r_padding = -1; /* Unknown. */
|
||||||
rc = start_scd (ctrl);
|
rc = start_scd (ctrl);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -2430,11 +2430,16 @@ card_key_available (ctrl_t ctrl, const struct card_key_info_s *keyinfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
hex2bin (keyinfo->keygrip, grip, sizeof (grip));
|
hex2bin (keyinfo->keygrip, grip, sizeof (grip));
|
||||||
if ( agent_key_available (grip) )
|
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip) )
|
||||||
{
|
{
|
||||||
|
char *dispserialno;
|
||||||
|
|
||||||
/* (Shadow)-key is not available in our key storage. */
|
/* (Shadow)-key is not available in our key storage. */
|
||||||
err = agent_write_shadow_key (grip, keyinfo->serialno,
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
||||||
keyinfo->idstr, pkbuf, 0);
|
keyinfo->keygrip);
|
||||||
|
err = agent_write_shadow_key (ctrl, grip, keyinfo->serialno,
|
||||||
|
keyinfo->idstr, pkbuf, 0, dispserialno);
|
||||||
|
xfree (dispserialno);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
xfree (pkbuf);
|
xfree (pkbuf);
|
||||||
|
@ -3217,7 +3222,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
|
||||||
|
|
||||||
/* Check whether the key is already in our key storage. Don't do
|
/* Check whether the key is already in our key storage. Don't do
|
||||||
anything then besides (re-)adding it to sshcontrol. */
|
anything then besides (re-)adding it to sshcontrol. */
|
||||||
if ( !agent_key_available (key_grip_raw) )
|
if ( !agent_key_available (ctrl, key_grip_raw) )
|
||||||
goto key_exists; /* Yes, key is available. */
|
goto key_exists; /* Yes, key is available. */
|
||||||
|
|
||||||
err = ssh_key_extract_comment (key, &comment);
|
err = ssh_key_extract_comment (key, &comment);
|
||||||
|
@ -3281,8 +3286,8 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
|
||||||
|
|
||||||
/* Store this key to our key storage. We do not store a creation
|
/* Store this key to our key storage. We do not store a creation
|
||||||
* timestamp because we simply do not know. */
|
* timestamp because we simply do not know. */
|
||||||
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
|
err = agent_write_private_key (ctrl, key_grip_raw, buffer, buffer_n, 0,
|
||||||
NULL, NULL, 0);
|
NULL, NULL, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -3947,7 +3952,11 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
|
||||||
es_syshd_t syshd;
|
es_syshd_t syshd;
|
||||||
|
|
||||||
syshd.type = ES_SYSHD_SOCK;
|
syshd.type = ES_SYSHD_SOCK;
|
||||||
|
#ifdef HAVE_SOCKET
|
||||||
|
syshd.u.sock = (SOCKET)sock_client;
|
||||||
|
#else
|
||||||
syshd.u.sock = sock_client;
|
syshd.u.sock = sock_client;
|
||||||
|
#endif
|
||||||
|
|
||||||
get_client_info (sock_client, &peer_info);
|
get_client_info (sock_client, &peer_info);
|
||||||
ctrl->client_pid = peer_info.pid;
|
ctrl->client_pid = peer_info.pid;
|
||||||
|
|
201
agent/command.c
201
agent/command.c
|
@ -241,7 +241,7 @@ reset_notify (assuan_context_t ctx, char *line)
|
||||||
(void) line;
|
(void) line;
|
||||||
|
|
||||||
memset (ctrl->keygrip, 0, 20);
|
memset (ctrl->keygrip, 0, 20);
|
||||||
ctrl->have_keygrip = 0;
|
ctrl->have_keygrip = ctrl->have_keygrip1 = 0;
|
||||||
ctrl->digest.valuelen = 0;
|
ctrl->digest.valuelen = 0;
|
||||||
xfree (ctrl->digest.data);
|
xfree (ctrl->digest.data);
|
||||||
ctrl->digest.data = NULL;
|
ctrl->digest.data = NULL;
|
||||||
|
@ -251,6 +251,9 @@ reset_notify (assuan_context_t ctx, char *line)
|
||||||
|
|
||||||
clear_nonce_cache (ctrl);
|
clear_nonce_cache (ctrl);
|
||||||
|
|
||||||
|
/* Note that a RESET does not clear the ephemeral store because
|
||||||
|
* clients are used to issue a RESET on a connection. */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,34 +637,65 @@ cmd_marktrusted (assuan_context_t ctx, char *line)
|
||||||
static const char hlp_havekey[] =
|
static const char hlp_havekey[] =
|
||||||
"HAVEKEY <hexstrings_with_keygrips>\n"
|
"HAVEKEY <hexstrings_with_keygrips>\n"
|
||||||
"HAVEKEY --list[=<limit>]\n"
|
"HAVEKEY --list[=<limit>]\n"
|
||||||
|
"HAVEKEY --info <hexkeygrip>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Return success if at least one of the secret keys with the given\n"
|
"Return success if at least one of the secret keys with the given\n"
|
||||||
"keygrips is available. With --list return all available keygrips\n"
|
"keygrips is available. With --list return all available keygrips\n"
|
||||||
"as binary data; with <limit> bail out at this number of keygrips";
|
"as binary data; with <limit> bail out at this number of keygrips.\n"
|
||||||
|
"In --info mode check just one keygrip.";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_havekey (assuan_context_t ctx, char *line)
|
cmd_havekey (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
ctrl_t ctrl;
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
unsigned char grip[20];
|
unsigned char grip[20];
|
||||||
char *p;
|
char *p;
|
||||||
int list_mode; /* Less than 0 for no limit. */
|
int list_mode = 0; /* Less than 0 for no limit. */
|
||||||
|
int info_mode = 0;
|
||||||
int counter;
|
int counter;
|
||||||
char *dirname;
|
char *dirname = NULL;
|
||||||
gnupg_dir_t dir;
|
gnupg_dir_t dir = NULL;
|
||||||
gnupg_dirent_t dir_entry;
|
gnupg_dirent_t dir_entry;
|
||||||
char hexgrip[41];
|
char hexgrip[41];
|
||||||
struct card_key_info_s *keyinfo_on_cards, *l;
|
struct card_key_info_s *keyinfo_on_cards, *l;
|
||||||
|
|
||||||
if (has_option_name (line, "--list"))
|
if (has_option (line, "--info"))
|
||||||
|
info_mode = 1;
|
||||||
|
else if (has_option_name (line, "--list"))
|
||||||
{
|
{
|
||||||
if ((p = option_value (line, "--list")))
|
if ((p = option_value (line, "--list")))
|
||||||
list_mode = atoi (p);
|
list_mode = atoi (p);
|
||||||
else
|
else
|
||||||
list_mode = -1;
|
list_mode = -1;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
list_mode = 0;
|
line = skip_options (line);
|
||||||
|
|
||||||
|
if (info_mode)
|
||||||
|
{
|
||||||
|
int keytype;
|
||||||
|
const char *infostring;
|
||||||
|
|
||||||
|
err = parse_keygrip (ctx, line, grip);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = agent_key_info_from_file (ctrl, grip, &keytype, NULL, NULL);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
switch (keytype)
|
||||||
|
{
|
||||||
|
case PRIVATE_KEY_CLEAR:
|
||||||
|
case PRIVATE_KEY_OPENPGP_NONE: infostring = "clear"; break;
|
||||||
|
case PRIVATE_KEY_PROTECTED: infostring = "protected"; break;
|
||||||
|
case PRIVATE_KEY_SHADOWED: infostring = "shadowed"; break;
|
||||||
|
default: infostring = "unknown"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = agent_write_status (ctrl, "KEYFILEINFO", infostring, NULL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!list_mode)
|
if (!list_mode)
|
||||||
|
@ -672,7 +706,7 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!agent_key_available (grip))
|
if (!agent_key_available (ctrl, grip))
|
||||||
return 0; /* Found. */
|
return 0; /* Found. */
|
||||||
|
|
||||||
while (*line && *line != ' ' && *line != '\t')
|
while (*line && *line != ' ' && *line != '\t')
|
||||||
|
@ -690,7 +724,6 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
||||||
/* List mode. */
|
/* List mode. */
|
||||||
dir = NULL;
|
dir = NULL;
|
||||||
dirname = NULL;
|
dirname = NULL;
|
||||||
ctrl = assuan_get_pointer (ctx);
|
|
||||||
|
|
||||||
if (ctrl->restricted)
|
if (ctrl->restricted)
|
||||||
{
|
{
|
||||||
|
@ -763,8 +796,8 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_sigkey[] =
|
static const char hlp_sigkey[] =
|
||||||
"SIGKEY <hexstring_with_keygrip>\n"
|
"SIGKEY [--another] <hexstring_with_keygrip>\n"
|
||||||
"SETKEY <hexstring_with_keygrip>\n"
|
"SETKEY [--another] <hexstring_with_keygrip>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Set the key used for a sign or decrypt operation.";
|
"Set the key used for a sign or decrypt operation.";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
|
@ -772,11 +805,17 @@ cmd_sigkey (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
int opt_another;
|
||||||
|
|
||||||
rc = parse_keygrip (ctx, line, ctrl->keygrip);
|
opt_another = has_option (line, "--another");
|
||||||
|
line = skip_options (line);
|
||||||
|
rc = parse_keygrip (ctx, line, opt_another? ctrl->keygrip1 : ctrl->keygrip);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
ctrl->have_keygrip = 1;
|
if (opt_another)
|
||||||
|
ctrl->have_keygrip1 = 1;
|
||||||
|
else
|
||||||
|
ctrl->have_keygrip = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1010,10 +1049,14 @@ cmd_pksign (assuan_context_t ctx, char *line)
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_pkdecrypt[] =
|
static const char hlp_pkdecrypt[] =
|
||||||
"PKDECRYPT [<options>]\n"
|
"PKDECRYPT [--kem[=<kemid>] [<options>]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Perform the actual decrypt operation. Input is not\n"
|
"Perform the actual decrypt operation. Input is not\n"
|
||||||
"sensitive to eavesdropping.";
|
"sensitive to eavesdropping.\n"
|
||||||
|
"If the --kem option is used, decryption is done with the KEM,\n"
|
||||||
|
"inquiring upper-layer option, when needed. KEMID can be\n"
|
||||||
|
"specified with --kem option; Valid value is: PQC-PGP, PGP, or CMS.\n"
|
||||||
|
"Default is PQC-PGP.";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_pkdecrypt (assuan_context_t ctx, char *line)
|
cmd_pkdecrypt (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
|
@ -1022,22 +1065,52 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
|
||||||
unsigned char *value;
|
unsigned char *value;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
membuf_t outbuf;
|
membuf_t outbuf;
|
||||||
int padding;
|
int padding = -1;
|
||||||
|
unsigned char *option = NULL;
|
||||||
|
size_t optionlen = 0;
|
||||||
|
const char *p;
|
||||||
|
int kemid = -1;
|
||||||
|
|
||||||
(void)line;
|
p = has_option_name (line, "--kem");
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
kemid = KEM_PQC_PGP;
|
||||||
|
if (*p == '=')
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
if (!strcmp (p, "PQC-PGP"))
|
||||||
|
kemid = KEM_PQC_PGP;
|
||||||
|
else if (!strcmp (p, "PGP"))
|
||||||
|
kemid = KEM_PGP;
|
||||||
|
else if (!strcmp (p, "CMS"))
|
||||||
|
kemid = KEM_CMS;
|
||||||
|
else
|
||||||
|
return set_error (GPG_ERR_ASS_PARAMETER, "invalid KEM algorithm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* First inquire the data to decrypt */
|
/* First inquire the data to decrypt */
|
||||||
rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
|
rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = assuan_inquire (ctx, "CIPHERTEXT",
|
rc = assuan_inquire (ctx, "CIPHERTEXT",
|
||||||
&value, &valuelen, MAXLEN_CIPHERTEXT);
|
&value, &valuelen, MAXLEN_CIPHERTEXT);
|
||||||
|
if (!rc && kemid > KEM_PQC_PGP)
|
||||||
|
rc = assuan_inquire (ctx, "OPTION",
|
||||||
|
&option, &optionlen, MAXLEN_CIPHERTEXT);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
init_membuf (&outbuf, 512);
|
init_membuf (&outbuf, 512);
|
||||||
|
|
||||||
rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
|
if (kemid < 0)
|
||||||
value, valuelen, &outbuf, &padding);
|
rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
|
||||||
|
value, valuelen, &outbuf, &padding);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = agent_kem_decrypt (ctrl, ctrl->server_local->keydesc, kemid,
|
||||||
|
value, valuelen, option, optionlen, &outbuf);
|
||||||
|
xfree (option);
|
||||||
|
}
|
||||||
xfree (value);
|
xfree (value);
|
||||||
if (rc)
|
if (rc)
|
||||||
clear_outbuf (&outbuf);
|
clear_outbuf (&outbuf);
|
||||||
|
@ -1083,26 +1156,29 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
int rc;
|
int rc;
|
||||||
int no_protection;
|
|
||||||
unsigned char *value = NULL;
|
unsigned char *value = NULL;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
unsigned char *newpasswd = NULL;
|
unsigned char *newpasswd = NULL;
|
||||||
membuf_t outbuf;
|
membuf_t outbuf;
|
||||||
char *cache_nonce = NULL;
|
char *cache_nonce = NULL;
|
||||||
char *passwd_nonce = NULL;
|
char *passwd_nonce = NULL;
|
||||||
int opt_preset;
|
|
||||||
int opt_inq_passwd;
|
int opt_inq_passwd;
|
||||||
size_t n;
|
size_t n;
|
||||||
char *p, *pend;
|
char *p, *pend;
|
||||||
const char *s;
|
const char *s;
|
||||||
time_t opt_timestamp;
|
time_t opt_timestamp;
|
||||||
int c;
|
int c;
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
|
init_membuf (&outbuf, 512);
|
||||||
|
|
||||||
if (ctrl->restricted)
|
if (ctrl->restricted)
|
||||||
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
||||||
|
|
||||||
no_protection = has_option (line, "--no-protection");
|
if (has_option (line, "--no-protection"))
|
||||||
opt_preset = has_option (line, "--preset");
|
flags |= GENKEY_FLAG_NO_PROTECTION;
|
||||||
|
if (has_option (line, "--preset"))
|
||||||
|
flags |= GENKEY_FLAG_PRESET;
|
||||||
opt_inq_passwd = has_option (line, "--inq-passwd");
|
opt_inq_passwd = has_option (line, "--inq-passwd");
|
||||||
passwd_nonce = option_value (line, "--passwd-nonce");
|
passwd_nonce = option_value (line, "--passwd-nonce");
|
||||||
if (passwd_nonce)
|
if (passwd_nonce)
|
||||||
|
@ -1153,11 +1229,9 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
init_membuf (&outbuf, 512);
|
|
||||||
|
|
||||||
/* If requested, ask for the password to be used for the key. If
|
/* If requested, ask for the password to be used for the key. If
|
||||||
this is not used the regular Pinentry mechanism is used. */
|
this is not used the regular Pinentry mechanism is used. */
|
||||||
if (opt_inq_passwd && !no_protection)
|
if (opt_inq_passwd && !(flags & GENKEY_FLAG_NO_PROTECTION))
|
||||||
{
|
{
|
||||||
/* (N is used as a dummy) */
|
/* (N is used as a dummy) */
|
||||||
assuan_begin_confidential (ctx);
|
assuan_begin_confidential (ctx);
|
||||||
|
@ -1170,16 +1244,17 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
||||||
/* Empty password given - switch to no-protection mode. */
|
/* Empty password given - switch to no-protection mode. */
|
||||||
xfree (newpasswd);
|
xfree (newpasswd);
|
||||||
newpasswd = NULL;
|
newpasswd = NULL;
|
||||||
no_protection = 1;
|
flags |= GENKEY_FLAG_NO_PROTECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (passwd_nonce)
|
else if (passwd_nonce)
|
||||||
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
|
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
|
||||||
|
|
||||||
rc = agent_genkey (ctrl, cache_nonce, opt_timestamp,
|
|
||||||
(char*)value, valuelen, no_protection,
|
rc = agent_genkey (ctrl, flags, cache_nonce, opt_timestamp,
|
||||||
newpasswd, opt_preset, &outbuf);
|
(char*)value, valuelen,
|
||||||
|
newpasswd, &outbuf);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (newpasswd)
|
if (newpasswd)
|
||||||
|
@ -1283,7 +1358,7 @@ cmd_keyattr (assuan_context_t ctx, char *line)
|
||||||
if (!err)
|
if (!err)
|
||||||
err = nvc_set_private_key (keymeta, s_key);
|
err = nvc_set_private_key (keymeta, s_key);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = agent_update_private_key (grip, keymeta);
|
err = agent_update_private_key (ctrl, grip, keymeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
nvc_release (keymeta);
|
nvc_release (keymeta);
|
||||||
|
@ -1293,6 +1368,8 @@ cmd_keyattr (assuan_context_t ctx, char *line)
|
||||||
leave:
|
leave:
|
||||||
return leave_cmd (ctx, err);
|
return leave_cmd (ctx, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_readkey[] =
|
static const char hlp_readkey[] =
|
||||||
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
|
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
|
||||||
|
@ -1356,10 +1433,17 @@ cmd_readkey (assuan_context_t ctx, char *line)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
/* (Shadow)-key is not available in our key storage. */
|
/* (Shadow)-key is not available in our key storage. */
|
||||||
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0);
|
char *dispserialno;
|
||||||
|
char hexgrip[40+1];
|
||||||
|
|
||||||
|
bin2hex (grip, 20, hexgrip);
|
||||||
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip);
|
||||||
|
rc = agent_write_shadow_key (ctrl, grip, serialno, keyid, pkbuf, 0,
|
||||||
|
dispserialno);
|
||||||
|
xfree (dispserialno);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
@ -1374,7 +1458,9 @@ cmd_readkey (assuan_context_t ctx, char *line)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
|
rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
|
||||||
if (!rc)
|
if (rc)
|
||||||
|
goto leave;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (opt_format_ssh)
|
if (opt_format_ssh)
|
||||||
{
|
{
|
||||||
|
@ -1944,9 +2030,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
||||||
struct pin_entry_info_s *pi2 = NULL;
|
struct pin_entry_info_s *pi2 = NULL;
|
||||||
int is_generated;
|
int is_generated;
|
||||||
|
|
||||||
if (ctrl->restricted)
|
|
||||||
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
|
||||||
|
|
||||||
opt_data = has_option (line, "--data");
|
opt_data = has_option (line, "--data");
|
||||||
opt_check = has_option (line, "--check");
|
opt_check = has_option (line, "--check");
|
||||||
opt_no_ask = has_option (line, "--no-ask");
|
opt_no_ask = has_option (line, "--no-ask");
|
||||||
|
@ -1995,7 +2078,9 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
||||||
if (!desc)
|
if (!desc)
|
||||||
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
|
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
|
||||||
|
|
||||||
if (!strcmp (cacheid, "X"))
|
/* The only limitation in restricted mode is that we don't consider
|
||||||
|
* the cache. */
|
||||||
|
if (ctrl->restricted || !strcmp (cacheid, "X"))
|
||||||
cacheid = NULL;
|
cacheid = NULL;
|
||||||
if (!strcmp (errtext, "X"))
|
if (!strcmp (errtext, "X"))
|
||||||
errtext = NULL;
|
errtext = NULL;
|
||||||
|
@ -2077,7 +2162,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
||||||
entry_errtext = NULL;
|
entry_errtext = NULL;
|
||||||
is_generated = !!(pi->status & PINENTRY_STATUS_PASSWORD_GENERATED);
|
is_generated = !!(pi->status & PINENTRY_STATUS_PASSWORD_GENERATED);
|
||||||
|
|
||||||
/* We don't allow an empty passpharse in this mode. */
|
/* We don't allow an empty passphrase in this mode. */
|
||||||
if (!is_generated
|
if (!is_generated
|
||||||
&& check_passphrase_constraints (ctrl, pi->pin,
|
&& check_passphrase_constraints (ctrl, pi->pin,
|
||||||
pi->constraints_flags,
|
pi->constraints_flags,
|
||||||
|
@ -2893,7 +2978,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!force && !agent_key_available (grip))
|
if (!force && !agent_key_available (ctrl, grip))
|
||||||
err = gpg_error (GPG_ERR_EEXIST);
|
err = gpg_error (GPG_ERR_EEXIST);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2915,12 +3000,12 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
||||||
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
||||||
ctrl->s2k_count);
|
ctrl->s2k_count);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
|
err = agent_write_private_key (ctrl, grip, finalkey, finalkeylen, force,
|
||||||
NULL, NULL, opt_timestamp);
|
NULL, NULL, NULL, opt_timestamp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL,
|
err = agent_write_private_key (ctrl, grip, key, realkeylen, force,
|
||||||
opt_timestamp);
|
NULL, NULL, NULL, opt_timestamp);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
gcry_sexp_release (openpgp_sexp);
|
gcry_sexp_release (openpgp_sexp);
|
||||||
|
@ -2938,7 +3023,8 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_export_key[] =
|
static const char hlp_export_key[] =
|
||||||
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp|--mode1003] <hexkeygrip>\n"
|
"EXPORT_KEY [--cache-nonce=<nonce>] \\\n"
|
||||||
|
" [--openpgp|--mode1003] <hexkeygrip>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Export a secret key from the key store. The key will be encrypted\n"
|
"Export a secret key from the key store. The key will be encrypted\n"
|
||||||
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
|
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
|
||||||
|
@ -2946,8 +3032,8 @@ static const char hlp_export_key[] =
|
||||||
"prior to using this command. The function takes the keygrip as argument.\n"
|
"prior to using this command. The function takes the keygrip as argument.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
|
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
|
||||||
"compatible passphrase-protected form. If --mode1003 is use the secret key\n"
|
"compatible passphrase-protected form. In --mode1003 the secret key\n"
|
||||||
"is exported as s-expression as storred locally. Without those options,\n"
|
"is exported as s-expression as stored locally. Without those options,\n"
|
||||||
"the secret key material will be exported in the clear (after prompting\n"
|
"the secret key material will be exported in the clear (after prompting\n"
|
||||||
"the user to unlock it, if needed).\n";
|
"the user to unlock it, if needed).\n";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
|
@ -3004,7 +3090,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -3216,9 +3302,9 @@ cmd_keytocard (assuan_context_t ctx, char *line)
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err =gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3536,7 +3622,7 @@ cmd_keytotpm (assuan_context_t ctx, char *line)
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err =gpg_error (GPG_ERR_NO_SECKEY);
|
err =gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -3828,6 +3914,7 @@ static const char hlp_getinfo[] =
|
||||||
" getenv NAME - Return value of envvar NAME.\n"
|
" getenv NAME - Return value of envvar NAME.\n"
|
||||||
" connections - Return number of active connections.\n"
|
" connections - Return number of active connections.\n"
|
||||||
" jent_active - Returns OK if Libgcrypt's JENT is active.\n"
|
" jent_active - Returns OK if Libgcrypt's JENT is active.\n"
|
||||||
|
" ephemeral - Returns OK if the connection is in ephemeral mode.\n"
|
||||||
" restricted - Returns OK if the connection is in restricted mode.\n"
|
" restricted - Returns OK if the connection is in restricted mode.\n"
|
||||||
" cmd_has_option CMD OPT\n"
|
" cmd_has_option CMD OPT\n"
|
||||||
" - Returns OK if command CMD has option OPT.\n";
|
" - Returns OK if command CMD has option OPT.\n";
|
||||||
|
@ -3881,6 +3968,10 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
||||||
snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
|
snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
|
||||||
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (line, "ephemeral"))
|
||||||
|
{
|
||||||
|
rc = ctrl->ephemeral_mode? 0 : gpg_error (GPG_ERR_FALSE);
|
||||||
|
}
|
||||||
else if (!strcmp (line, "restricted"))
|
else if (!strcmp (line, "restricted"))
|
||||||
{
|
{
|
||||||
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
|
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
|
||||||
|
@ -4037,6 +4128,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
||||||
ctrl->server_local->allow_fully_canceled =
|
ctrl->server_local->allow_fully_canceled =
|
||||||
gnupg_compare_version (value, "2.1.0");
|
gnupg_compare_version (value, "2.1.0");
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (key, "ephemeral"))
|
||||||
|
{
|
||||||
|
ctrl->ephemeral_mode = *value? atoi (value) : 0;
|
||||||
|
}
|
||||||
else if (ctrl->restricted)
|
else if (ctrl->restricted)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||||
|
|
|
@ -969,7 +969,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (!dontcare_exist && !from_native && !agent_key_available (grip))
|
if (!dontcare_exist && !from_native && !agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_EEXIST);
|
err = gpg_error (GPG_ERR_EEXIST);
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -1147,17 +1147,19 @@ convert_from_openpgp_native (ctrl_t ctrl,
|
||||||
if (!agent_protect (*r_key, passphrase,
|
if (!agent_protect (*r_key, passphrase,
|
||||||
&protectedkey, &protectedkeylen,
|
&protectedkey, &protectedkeylen,
|
||||||
ctrl->s2k_count))
|
ctrl->s2k_count))
|
||||||
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
|
agent_write_private_key (ctrl, grip,
|
||||||
NULL, NULL, 0);
|
protectedkey,
|
||||||
|
protectedkeylen,
|
||||||
|
1, NULL, NULL, NULL, 0);
|
||||||
xfree (protectedkey);
|
xfree (protectedkey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Empty passphrase: write key without protection. */
|
/* Empty passphrase: write key without protection. */
|
||||||
agent_write_private_key (grip,
|
agent_write_private_key (ctrl, grip,
|
||||||
*r_key,
|
*r_key,
|
||||||
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
|
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
|
||||||
1, NULL, NULL, 0);
|
1, NULL, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,6 +1384,17 @@ extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
|
||||||
err = gcry_sexp_extract_param (list, NULL, format,
|
err = gcry_sexp_extract_param (list, NULL, format,
|
||||||
array+0, array+1, NULL);
|
array+0, array+1, NULL);
|
||||||
}
|
}
|
||||||
|
else if ( !strcmp (name, (algoname = "kyber512"))
|
||||||
|
|| !strcmp (name, (algoname = "kyber768"))
|
||||||
|
|| !strcmp (name, (algoname = "kyber1024")))
|
||||||
|
{
|
||||||
|
format = "/ps?";
|
||||||
|
elems = "ps?";
|
||||||
|
npkey = 1;
|
||||||
|
nskey = 2;
|
||||||
|
err = gcry_sexp_extract_param (list, NULL, format,
|
||||||
|
array+0, array+1, NULL);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||||
|
|
|
@ -90,7 +90,7 @@ has_percent0A_suffix (const char *string)
|
||||||
|
|
||||||
INFO gets displayed as part of a generic string. However if the
|
INFO gets displayed as part of a generic string. However if the
|
||||||
first character of INFO is a vertical bar all up to the next
|
first character of INFO is a vertical bar all up to the next
|
||||||
verical bar are considered flags and only everything after the
|
vertical bar are considered flags and only everything after the
|
||||||
second vertical bar gets displayed as the full prompt.
|
second vertical bar gets displayed as the full prompt.
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
@ -377,10 +377,10 @@ divert_pksign (ctrl_t ctrl, const unsigned char *grip,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Decrypt the value given asn an S-expression in CIPHER using the
|
/* Decrypt the value given as an s-expression in CIPHER using the
|
||||||
key identified by SHADOW_INFO and return the plaintext in an
|
key identified by SHADOW_INFO and return the plaintext in an
|
||||||
allocated buffer in R_BUF. The padding information is stored at
|
allocated buffer in R_BUF. The padding information is stored at
|
||||||
R_PADDING with -1 for not known. */
|
R_PADDING with -1 for not known, when it's not NULL. */
|
||||||
int
|
int
|
||||||
divert_pkdecrypt (ctrl_t ctrl,
|
divert_pkdecrypt (ctrl_t ctrl,
|
||||||
const unsigned char *grip,
|
const unsigned char *grip,
|
||||||
|
@ -399,7 +399,8 @@ divert_pkdecrypt (ctrl_t ctrl,
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
|
|
||||||
*r_padding = -1;
|
if (r_padding)
|
||||||
|
*r_padding = -1;
|
||||||
s = cipher;
|
s = cipher;
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
return gpg_error (GPG_ERR_INV_SEXP);
|
return gpg_error (GPG_ERR_INV_SEXP);
|
||||||
|
@ -485,6 +486,34 @@ divert_pkdecrypt (ctrl_t ctrl,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpg_error_t
|
||||||
|
agent_card_ecc_kem (ctrl_t ctrl, const unsigned char *ecc_ct,
|
||||||
|
size_t ecc_point_len, unsigned char *ecc_ecdh)
|
||||||
|
{
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
char *ecdh = NULL;
|
||||||
|
size_t len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = agent_card_pkdecrypt (ctrl, ctrl->keygrip, getpin_cb, ctrl, NULL,
|
||||||
|
ecc_ct, ecc_point_len, &ecdh, &len, NULL);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (len != ecc_point_len)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: ECC result length invalid (%zu != %zu)\n",
|
||||||
|
__func__, len, ecc_point_len);
|
||||||
|
return gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy (ecc_ecdh, ecdh, len);
|
||||||
|
|
||||||
|
xfree (ecdh);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
divert_writekey (ctrl_t ctrl, int force, const char *serialno,
|
||||||
|
|
|
@ -26,9 +26,10 @@ divert_tpm2_pksign (ctrl_t ctrl,
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
unsigned char *shadow_info)
|
unsigned char *shadow_info,
|
||||||
|
gcry_sexp_t s_key)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err, err1;
|
||||||
unsigned char *shdkey;
|
unsigned char *shdkey;
|
||||||
unsigned char *pkbuf;
|
unsigned char *pkbuf;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -44,16 +45,38 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
xfree (pkbuf);
|
xfree (pkbuf);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
|
log_error ("shadowing the tpm key failed: %s\n", gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = agent_delete_key (ctrl, NULL, grip, 1, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to delete unshadowed key: %s\n", gpg_strerror (err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
||||||
err = agent_write_private_key (grip, shdkey, len, 1 /*force*/,
|
err = agent_write_private_key (ctrl, grip, shdkey, len, 1 /*force*/,
|
||||||
NULL, NULL, 0);
|
NULL, NULL, NULL, 0);
|
||||||
xfree (shdkey);
|
xfree (shdkey);
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("error writing key: %s\n", gpg_strerror (err));
|
{
|
||||||
|
log_error ("error writing tpm key: %s\n", gpg_strerror (err));
|
||||||
|
|
||||||
|
len = gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||||
|
pkbuf = xtrymalloc(len);
|
||||||
|
if (!pkbuf)
|
||||||
|
return GPG_ERR_ENOMEM;
|
||||||
|
|
||||||
|
gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, pkbuf, len);
|
||||||
|
err1 = agent_write_private_key (ctrl, grip, pkbuf, len, 1 /*force*/,
|
||||||
|
NULL, NULL, NULL, 0);
|
||||||
|
xfree(pkbuf);
|
||||||
|
if (err1)
|
||||||
|
log_error ("error trying to restore private key: %s\n",
|
||||||
|
gpg_strerror (err1));
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +91,7 @@ divert_tpm2_writekey (ctrl_t ctrl, const unsigned char *grip,
|
||||||
|
|
||||||
ret = agent_tpm2d_writekey(ctrl, &shadow_info, s_skey);
|
ret = agent_tpm2d_writekey(ctrl, &shadow_info, s_skey);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = agent_write_tpm2_shadow_key (ctrl, grip, shadow_info);
|
ret = agent_write_tpm2_shadow_key (ctrl, grip, shadow_info, s_skey);
|
||||||
xfree (shadow_info);
|
xfree (shadow_info);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -83,7 +106,8 @@ divert_tpm2_pkdecrypt (ctrl_t ctrl,
|
||||||
const unsigned char *s;
|
const unsigned char *s;
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
*r_padding = -1;
|
if (r_padding)
|
||||||
|
*r_padding = -1;
|
||||||
|
|
||||||
s = cipher;
|
s = cipher;
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
|
@ -102,7 +126,8 @@ divert_tpm2_pkdecrypt (ctrl_t ctrl,
|
||||||
return gpg_error (GPG_ERR_INV_SEXP);
|
return gpg_error (GPG_ERR_INV_SEXP);
|
||||||
if (smatch (&s, n, "rsa"))
|
if (smatch (&s, n, "rsa"))
|
||||||
{
|
{
|
||||||
*r_padding = 0;
|
if (r_padding)
|
||||||
|
*r_padding = 0;
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
||||||
s++;
|
s++;
|
||||||
|
|
739
agent/findkey.c
739
agent/findkey.c
File diff suppressed because it is too large
Load Diff
174
agent/genkey.c
174
agent/genkey.c
|
@ -30,14 +30,36 @@
|
||||||
#include "../common/exechelp.h"
|
#include "../common/exechelp.h"
|
||||||
#include "../common/sysutils.h"
|
#include "../common/sysutils.h"
|
||||||
|
|
||||||
static int
|
|
||||||
store_key (gcry_sexp_t private, const char *passphrase, int force,
|
void
|
||||||
|
clear_ephemeral_keys (ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
while (ctrl->ephemeral_keys)
|
||||||
|
{
|
||||||
|
ephemeral_private_key_t next = ctrl->ephemeral_keys->next;
|
||||||
|
if (ctrl->ephemeral_keys->keybuf)
|
||||||
|
{
|
||||||
|
wipememory (ctrl->ephemeral_keys->keybuf,
|
||||||
|
ctrl->ephemeral_keys->keybuflen);
|
||||||
|
xfree (ctrl->ephemeral_keys->keybuf);
|
||||||
|
}
|
||||||
|
xfree (ctrl->ephemeral_keys);
|
||||||
|
ctrl->ephemeral_keys = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Store the key either to a file, or in ctrl->ephemeral_mode in the
|
||||||
|
* session data. */
|
||||||
|
static gpg_error_t
|
||||||
|
store_key (ctrl_t ctrl, gcry_sexp_t private,
|
||||||
|
const char *passphrase, int force,
|
||||||
unsigned long s2k_count, time_t timestamp)
|
unsigned long s2k_count, time_t timestamp)
|
||||||
{
|
{
|
||||||
int rc;
|
gpg_error_t err;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char grip[20];
|
unsigned char grip[KEYGRIP_LEN];
|
||||||
|
|
||||||
if ( !gcry_pk_get_keygrip (private, grip) )
|
if ( !gcry_pk_get_keygrip (private, grip) )
|
||||||
{
|
{
|
||||||
|
@ -49,7 +71,10 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
|
||||||
log_assert (len);
|
log_assert (len);
|
||||||
buf = gcry_malloc_secure (len);
|
buf = gcry_malloc_secure (len);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return out_of_core ();
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
|
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
|
||||||
log_assert (len);
|
log_assert (len);
|
||||||
|
|
||||||
|
@ -57,19 +82,57 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
|
||||||
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
err = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
goto leave;
|
||||||
xfree (buf);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
buf = p;
|
buf = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = agent_write_private_key (grip, buf, len, force, NULL, NULL, timestamp);
|
if (ctrl->ephemeral_mode)
|
||||||
|
{
|
||||||
|
ephemeral_private_key_t ek;
|
||||||
|
|
||||||
|
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
|
||||||
|
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
|
||||||
|
break;
|
||||||
|
if (!ek)
|
||||||
|
{
|
||||||
|
ek = xtrycalloc (1, sizeof *ek);
|
||||||
|
if (!ek)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
memcpy (ek->grip, grip, KEYGRIP_LEN);
|
||||||
|
ek->next = ctrl->ephemeral_keys;
|
||||||
|
ctrl->ephemeral_keys = ek;
|
||||||
|
}
|
||||||
|
if (ek->keybuf)
|
||||||
|
{
|
||||||
|
wipememory (ek->keybuf, ek->keybuflen);
|
||||||
|
xfree (ek->keybuf);
|
||||||
|
}
|
||||||
|
ek->keybuf = buf;
|
||||||
|
buf = NULL;
|
||||||
|
ek->keybuflen = len;
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = agent_write_private_key (ctrl, grip, buf, len, force,
|
||||||
|
NULL, NULL, NULL, timestamp);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
char hexgrip[2*KEYGRIP_LEN+1];
|
||||||
|
|
||||||
|
bin2hex (grip, KEYGRIP_LEN, hexgrip);
|
||||||
|
agent_write_status (ctrl, "KEYGRIP", hexgrip, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,7 +162,7 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
|
||||||
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
|
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
|
||||||
estream_t stream_to_check_pattern = NULL;
|
estream_t stream_to_check_pattern = NULL;
|
||||||
const char *argv[10];
|
const char *argv[10];
|
||||||
pid_t pid;
|
gnupg_process_t proc;
|
||||||
int result, i;
|
int result, i;
|
||||||
const char *pattern;
|
const char *pattern;
|
||||||
char *patternfname;
|
char *patternfname;
|
||||||
|
@ -142,11 +205,17 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
|
||||||
argv[i] = NULL;
|
argv[i] = NULL;
|
||||||
log_assert (i < sizeof argv);
|
log_assert (i < sizeof argv);
|
||||||
|
|
||||||
if (gnupg_spawn_process (pgmname, argv, NULL, 0,
|
if (gnupg_process_spawn (pgmname, argv,
|
||||||
&stream_to_check_pattern, NULL, NULL, &pid))
|
GNUPG_PROCESS_STDIN_PIPE,
|
||||||
|
NULL, &proc))
|
||||||
result = 1; /* Execute error - assume password should no be used. */
|
result = 1; /* Execute error - assume password should no be used. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
gnupg_process_get_streams (proc, 0, &stream_to_check_pattern,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
es_set_binary (stream_to_check_pattern);
|
es_set_binary (stream_to_check_pattern);
|
||||||
if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1)
|
if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1)
|
||||||
{
|
{
|
||||||
|
@ -157,11 +226,13 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
|
||||||
else
|
else
|
||||||
es_fflush (stream_to_check_pattern);
|
es_fflush (stream_to_check_pattern);
|
||||||
es_fclose (stream_to_check_pattern);
|
es_fclose (stream_to_check_pattern);
|
||||||
if (gnupg_wait_process (pgmname, pid, 1, NULL))
|
gnupg_process_wait (proc, 1);
|
||||||
|
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
|
||||||
|
if (status)
|
||||||
result = 1; /* Helper returned an error - probably a match. */
|
result = 1; /* Helper returned an error - probably a match. */
|
||||||
else
|
else
|
||||||
result = 0; /* Success; i.e. no match. */
|
result = 0; /* Success; i.e. no match. */
|
||||||
gnupg_release_process (pid);
|
gnupg_process_release (proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
xfree (patternfname);
|
xfree (patternfname);
|
||||||
|
@ -449,16 +520,19 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
||||||
|
|
||||||
|
|
||||||
/* Generate a new keypair according to the parameters given in
|
/* Generate a new keypair according to the parameters given in
|
||||||
KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
|
* KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
|
||||||
using the cache nonce. If NO_PROTECTION is true the key will not
|
* using the cache nonce. If NO_PROTECTION is true the key will not
|
||||||
be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
|
* be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
|
||||||
passphrase will be used for the new key. If TIMESTAMP is not zero
|
* passphrase will be used for the new key. If TIMESTAMP is not zero
|
||||||
it will be recorded as creation date of the key (unless extended
|
* it will be recorded as creation date of the key (unless extended
|
||||||
format is disabled) . */
|
* format is disabled). In ctrl_ephemeral_mode the key is stored in
|
||||||
|
* the session data and an identifier is returned using a status
|
||||||
|
* line. */
|
||||||
int
|
int
|
||||||
agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
agent_genkey (ctrl_t ctrl, unsigned int flags,
|
||||||
const char *keyparam, size_t keyparamlen, int no_protection,
|
const char *cache_nonce, time_t timestamp,
|
||||||
const char *override_passphrase, int preset, membuf_t *outbuf)
|
const char *keyparam, size_t keyparamlen,
|
||||||
|
const char *override_passphrase, membuf_t *outbuf)
|
||||||
{
|
{
|
||||||
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
|
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
|
||||||
char *passphrase_buffer = NULL;
|
char *passphrase_buffer = NULL;
|
||||||
|
@ -477,7 +551,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
||||||
/* Get the passphrase now, cause key generation may take a while. */
|
/* Get the passphrase now, cause key generation may take a while. */
|
||||||
if (override_passphrase)
|
if (override_passphrase)
|
||||||
passphrase = override_passphrase;
|
passphrase = override_passphrase;
|
||||||
else if (no_protection || !cache_nonce)
|
else if ((flags & GENKEY_FLAG_NO_PROTECTION) || !cache_nonce)
|
||||||
passphrase = NULL;
|
passphrase = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -485,8 +559,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
||||||
passphrase = passphrase_buffer;
|
passphrase = passphrase_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passphrase || no_protection)
|
if (passphrase || (flags & GENKEY_FLAG_NO_PROTECTION))
|
||||||
;
|
; /* No need to ask for a passphrase. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = agent_ask_new_passphrase (ctrl,
|
rc = agent_ask_new_passphrase (ctrl,
|
||||||
|
@ -531,11 +605,14 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
||||||
gcry_sexp_release (s_key); s_key = NULL;
|
gcry_sexp_release (s_key); s_key = NULL;
|
||||||
|
|
||||||
/* store the secret key */
|
/* store the secret key */
|
||||||
if (DBG_CRYPTO)
|
if (opt.verbose)
|
||||||
log_debug ("storing private key\n");
|
log_info ("storing %sprivate key\n",
|
||||||
rc = store_key (s_private, passphrase, 0, ctrl->s2k_count, timestamp);
|
ctrl->ephemeral_mode?"ephemeral ":"");
|
||||||
if (!rc)
|
rc = store_key (ctrl, s_private, passphrase, 0, ctrl->s2k_count, timestamp);
|
||||||
|
if (!rc && !ctrl->ephemeral_mode)
|
||||||
{
|
{
|
||||||
|
/* FIXME: or does it make sense to also cache passphrases in
|
||||||
|
* ephemeral mode using a dedicated cache? */
|
||||||
if (!cache_nonce)
|
if (!cache_nonce)
|
||||||
{
|
{
|
||||||
char tmpbuf[12];
|
char tmpbuf[12];
|
||||||
|
@ -543,21 +620,23 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
||||||
cache_nonce = bin2hex (tmpbuf, 12, NULL);
|
cache_nonce = bin2hex (tmpbuf, 12, NULL);
|
||||||
}
|
}
|
||||||
if (cache_nonce
|
if (cache_nonce
|
||||||
&& !no_protection
|
&& !(flags & GENKEY_FLAG_NO_PROTECTION)
|
||||||
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
|
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
|
||||||
passphrase, ctrl->cache_ttl_opt_preset))
|
passphrase, ctrl->cache_ttl_opt_preset))
|
||||||
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
|
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
|
||||||
if (preset && !no_protection)
|
if ((flags & GENKEY_FLAG_PRESET)
|
||||||
{
|
&& !(flags & GENKEY_FLAG_NO_PROTECTION))
|
||||||
unsigned char grip[20];
|
{
|
||||||
char hexgrip[40+1];
|
unsigned char grip[20];
|
||||||
if (gcry_pk_get_keygrip (s_private, grip))
|
char hexgrip[40+1];
|
||||||
{
|
if (gcry_pk_get_keygrip (s_private, grip))
|
||||||
bin2hex(grip, 20, hexgrip);
|
{
|
||||||
rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase,
|
bin2hex(grip, 20, hexgrip);
|
||||||
|
rc = agent_put_cache (ctrl, hexgrip,
|
||||||
|
CACHE_MODE_ANY, passphrase,
|
||||||
ctrl->cache_ttl_opt_preset);
|
ctrl->cache_ttl_opt_preset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xfree (passphrase_buffer);
|
xfree (passphrase_buffer);
|
||||||
passphrase_buffer = NULL;
|
passphrase_buffer = NULL;
|
||||||
|
@ -606,7 +685,8 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
||||||
if (passphrase_addr && *passphrase_addr)
|
if (passphrase_addr && *passphrase_addr)
|
||||||
{
|
{
|
||||||
/* Take an empty string as request not to protect the key. */
|
/* Take an empty string as request not to protect the key. */
|
||||||
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
|
err = store_key (ctrl, s_skey,
|
||||||
|
**passphrase_addr? *passphrase_addr:NULL, 1,
|
||||||
ctrl->s2k_count, 0);
|
ctrl->s2k_count, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -622,7 +702,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
||||||
L_("Please enter the new passphrase"),
|
L_("Please enter the new passphrase"),
|
||||||
&pass);
|
&pass);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = store_key (s_skey, pass, 1, ctrl->s2k_count, 0);
|
err = store_key (ctrl, s_skey, pass, 1, ctrl->s2k_count, 0);
|
||||||
if (!err && passphrase_addr)
|
if (!err && passphrase_addr)
|
||||||
*passphrase_addr = pass;
|
*passphrase_addr = pass;
|
||||||
else
|
else
|
||||||
|
|
|
@ -48,3 +48,5 @@
|
||||||
VALUE "Translation", 0x409, 0x4b0
|
VALUE "Translation", 0x409, 0x4b0
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
|
|
||||||
|
1 RT_MANIFEST "gpg-agent.w32-manifest"
|
||||||
|
|
|
@ -341,15 +341,13 @@ static struct debug_flags_s debug_flags [] =
|
||||||
#define MIN_PASSPHRASE_NONALPHA (1)
|
#define MIN_PASSPHRASE_NONALPHA (1)
|
||||||
#define MAX_PASSPHRASE_DAYS (0)
|
#define MAX_PASSPHRASE_DAYS (0)
|
||||||
|
|
||||||
/* The timer tick used for housekeeping stuff. Note that on Windows
|
/* CHECK_OWN_SOCKET_INTERVAL defines how often we check our own socket
|
||||||
* we use a SetWaitableTimer seems to signal earlier than about 2
|
* in standard socket mode. If that value is 0 we don't check at all.
|
||||||
* seconds. Thus we use 4 seconds on all platforms.
|
* Values is in seconds. */
|
||||||
* CHECK_OWN_SOCKET_INTERVAL defines how often we check
|
|
||||||
* our own socket in standard socket mode. If that value is 0 we
|
|
||||||
* don't check at all. All values are in seconds. */
|
|
||||||
#define TIMERTICK_INTERVAL (4)
|
|
||||||
#define CHECK_OWN_SOCKET_INTERVAL (60)
|
#define CHECK_OWN_SOCKET_INTERVAL (60)
|
||||||
|
/* CHECK_PROBLEMS_INTERVAL defines how often we check the existence of
|
||||||
|
* parent process and homedir. Value is in seconds. */
|
||||||
|
#define CHECK_PROBLEMS_INTERVAL (4)
|
||||||
|
|
||||||
/* Flag indicating that the ssh-agent subsystem has been enabled. */
|
/* Flag indicating that the ssh-agent subsystem has been enabled. */
|
||||||
static int ssh_support;
|
static int ssh_support;
|
||||||
|
@ -366,7 +364,7 @@ static int putty_support;
|
||||||
|
|
||||||
/* Path to the pipe, which handles requests from Win32-OpenSSH. */
|
/* Path to the pipe, which handles requests from Win32-OpenSSH. */
|
||||||
static const char *win32_openssh_support;
|
static const char *win32_openssh_support;
|
||||||
#define W32_DEFAILT_AGENT_PIPE_NAME "\\\\.\\pipe\\openssh-ssh-agent"
|
#define W32_DEFAULT_AGENT_PIPE_NAME "\\\\.\\pipe\\openssh-ssh-agent"
|
||||||
#endif /*HAVE_W32_SYSTEM*/
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
/* The list of open file descriptors at startup. Note that this list
|
/* The list of open file descriptors at startup. Note that this list
|
||||||
|
@ -384,9 +382,6 @@ static int startup_signal_mask_valid;
|
||||||
/* Flag to indicate that a shutdown was requested. */
|
/* Flag to indicate that a shutdown was requested. */
|
||||||
static int shutdown_pending;
|
static int shutdown_pending;
|
||||||
|
|
||||||
/* Counter for the currently running own socket checks. */
|
|
||||||
static int check_own_socket_running;
|
|
||||||
|
|
||||||
/* Flags to indicate that check_own_socket shall not be called. */
|
/* Flags to indicate that check_own_socket shall not be called. */
|
||||||
static int disable_check_own_socket;
|
static int disable_check_own_socket;
|
||||||
|
|
||||||
|
@ -396,6 +391,12 @@ static int is_supervised;
|
||||||
/* Flag indicating to start the daemon even if one already runs. */
|
/* Flag indicating to start the daemon even if one already runs. */
|
||||||
static int steal_socket;
|
static int steal_socket;
|
||||||
|
|
||||||
|
/* Flag to monitor problems. */
|
||||||
|
static int problem_detected;
|
||||||
|
#define AGENT_PROBLEM_SOCKET_TAKEOVER (1 << 0)
|
||||||
|
#define AGENT_PROBLEM_PARENT_HAS_GONE (1 << 1)
|
||||||
|
#define AGENT_PROBLEM_HOMEDIR_REMOVED (1 << 2)
|
||||||
|
|
||||||
/* Flag to inhibit socket removal in cleanup. */
|
/* Flag to inhibit socket removal in cleanup. */
|
||||||
static int inhibit_socket_removal;
|
static int inhibit_socket_removal;
|
||||||
|
|
||||||
|
@ -432,6 +433,17 @@ static assuan_sock_nonce_t socket_nonce_ssh;
|
||||||
* Let's try this as default. Change at runtime with --listen-backlog. */
|
* Let's try this as default. Change at runtime with --listen-backlog. */
|
||||||
static int listen_backlog = 64;
|
static int listen_backlog = 64;
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
/* The event to break the select call. */
|
||||||
|
static HANDLE the_event2;
|
||||||
|
#elif defined(HAVE_PSELECT_NO_EINTR)
|
||||||
|
/* An FD to break the select call. */
|
||||||
|
static int event_pipe_fd;
|
||||||
|
#else
|
||||||
|
/* PID of the main thread. */
|
||||||
|
static pid_t main_thread_pid;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Default values for options passed to the pinentry. */
|
/* Default values for options passed to the pinentry. */
|
||||||
static char *default_display;
|
static char *default_display;
|
||||||
static char *default_ttyname;
|
static char *default_ttyname;
|
||||||
|
@ -452,9 +464,14 @@ static const char *debug_level;
|
||||||
the log file after a SIGHUP if it didn't changed. Malloced. */
|
the log file after a SIGHUP if it didn't changed. Malloced. */
|
||||||
static char *current_logfile;
|
static char *current_logfile;
|
||||||
|
|
||||||
/* The handle_tick() function may test whether a parent is still
|
#ifdef HAVE_W32_SYSTEM
|
||||||
* running. We record the PID of the parent here or -1 if it should
|
#define HAVE_PARENT_PID_SUPPORT 0
|
||||||
* be watched. */
|
#else
|
||||||
|
#define HAVE_PARENT_PID_SUPPORT 1
|
||||||
|
#endif
|
||||||
|
/* The check_others_thread() function may test whether a parent is
|
||||||
|
* still running. We record the PID of the parent here or -1 if it
|
||||||
|
* should be watched. */
|
||||||
static pid_t parent_pid = (pid_t)(-1);
|
static pid_t parent_pid = (pid_t)(-1);
|
||||||
|
|
||||||
/* This flag is true if the inotify mechanism for detecting the
|
/* This flag is true if the inotify mechanism for detecting the
|
||||||
|
@ -462,11 +479,6 @@ static pid_t parent_pid = (pid_t)(-1);
|
||||||
* alternative but portable stat based check. */
|
* alternative but portable stat based check. */
|
||||||
static int have_homedir_inotify;
|
static int have_homedir_inotify;
|
||||||
|
|
||||||
/* Depending on how gpg-agent was started, the homedir inotify watch
|
|
||||||
* may not be reliable. This flag is set if we assume that inotify
|
|
||||||
* works reliable. */
|
|
||||||
static int reliable_homedir_inotify;
|
|
||||||
|
|
||||||
/* Number of active connections. */
|
/* Number of active connections. */
|
||||||
static int active_connections;
|
static int active_connections;
|
||||||
|
|
||||||
|
@ -516,13 +528,13 @@ static void agent_deinit_default_ctrl (ctrl_t ctrl);
|
||||||
static void handle_connections (gnupg_fd_t listen_fd,
|
static void handle_connections (gnupg_fd_t listen_fd,
|
||||||
gnupg_fd_t listen_fd_extra,
|
gnupg_fd_t listen_fd_extra,
|
||||||
gnupg_fd_t listen_fd_browser,
|
gnupg_fd_t listen_fd_browser,
|
||||||
gnupg_fd_t listen_fd_ssh);
|
gnupg_fd_t listen_fd_ssh,
|
||||||
static void check_own_socket (void);
|
int reliable_homedir_inotify);
|
||||||
static int check_for_running_agent (int silent);
|
static int check_for_running_agent (int silent);
|
||||||
|
#if CHECK_OWN_SOCKET_INTERVAL > 0
|
||||||
/* Pth wrapper function definitions. */
|
static void *check_own_socket_thread (void *arg);
|
||||||
ASSUAN_SYSTEM_NPTH_IMPL;
|
#endif
|
||||||
|
static void *check_others_thread (void *arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Functions.
|
Functions.
|
||||||
|
@ -864,6 +876,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||||
opt.debug = 0;
|
opt.debug = 0;
|
||||||
opt.no_grab = 1;
|
opt.no_grab = 1;
|
||||||
opt.debug_pinentry = 0;
|
opt.debug_pinentry = 0;
|
||||||
|
xfree (opt.pinentry_program);
|
||||||
opt.pinentry_program = NULL;
|
opt.pinentry_program = NULL;
|
||||||
opt.pinentry_touch_file = NULL;
|
opt.pinentry_touch_file = NULL;
|
||||||
xfree (opt.pinentry_invisible_char);
|
xfree (opt.pinentry_invisible_char);
|
||||||
|
@ -924,7 +937,10 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||||
case oNoGrab: opt.no_grab |= 1; break;
|
case oNoGrab: opt.no_grab |= 1; break;
|
||||||
case oGrab: opt.no_grab |= 2; break;
|
case oGrab: opt.no_grab |= 2; break;
|
||||||
|
|
||||||
case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
|
case oPinentryProgram:
|
||||||
|
xfree (opt.pinentry_program);
|
||||||
|
opt.pinentry_program = make_filename_try (pargs->r.ret_str, NULL);
|
||||||
|
break;
|
||||||
case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
|
case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
|
||||||
case oPinentryInvisibleChar:
|
case oPinentryInvisibleChar:
|
||||||
xfree (opt.pinentry_invisible_char);
|
xfree (opt.pinentry_invisible_char);
|
||||||
|
@ -1046,6 +1062,7 @@ thread_init_once (void)
|
||||||
* initialized and thus Libgcrypt could not set its system call
|
* initialized and thus Libgcrypt could not set its system call
|
||||||
* clamp. */
|
* clamp. */
|
||||||
gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
|
gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
|
||||||
|
assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1053,7 +1070,6 @@ static void
|
||||||
initialize_modules (void)
|
initialize_modules (void)
|
||||||
{
|
{
|
||||||
thread_init_once ();
|
thread_init_once ();
|
||||||
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
|
|
||||||
initialize_module_cache ();
|
initialize_module_cache ();
|
||||||
initialize_module_call_pinentry ();
|
initialize_module_call_pinentry ();
|
||||||
initialize_module_daemon ();
|
initialize_module_daemon ();
|
||||||
|
@ -1081,6 +1097,7 @@ main (int argc, char **argv)
|
||||||
int gpgconf_list = 0;
|
int gpgconf_list = 0;
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
struct assuan_malloc_hooks malloc_hooks;
|
struct assuan_malloc_hooks malloc_hooks;
|
||||||
|
int reliable_homedir_inotify = 1;
|
||||||
|
|
||||||
early_system_init ();
|
early_system_init ();
|
||||||
|
|
||||||
|
@ -1113,7 +1130,6 @@ main (int argc, char **argv)
|
||||||
assuan_set_malloc_hooks (&malloc_hooks);
|
assuan_set_malloc_hooks (&malloc_hooks);
|
||||||
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
|
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
|
||||||
assuan_sock_init ();
|
assuan_sock_init ();
|
||||||
assuan_sock_set_system_hooks (ASSUAN_SYSTEM_NPTH);
|
|
||||||
setup_libassuan_logging (&opt.debug, NULL);
|
setup_libassuan_logging (&opt.debug, NULL);
|
||||||
|
|
||||||
setup_libgcrypt_logging ();
|
setup_libgcrypt_logging ();
|
||||||
|
@ -1200,7 +1216,7 @@ main (int argc, char **argv)
|
||||||
* Now we are now working under our real uid
|
* Now we are now working under our real uid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The configuraton directories for use by gpgrt_argparser. */
|
/* The configuration directories for use by gpgrt_argparser. */
|
||||||
gpgrt_set_confdir (GPGRT_CONFDIR_SYS, gnupg_sysconfdir ());
|
gpgrt_set_confdir (GPGRT_CONFDIR_SYS, gnupg_sysconfdir ());
|
||||||
gpgrt_set_confdir (GPGRT_CONFDIR_USER, gnupg_homedir ());
|
gpgrt_set_confdir (GPGRT_CONFDIR_USER, gnupg_homedir ());
|
||||||
|
|
||||||
|
@ -1209,7 +1225,7 @@ main (int argc, char **argv)
|
||||||
pargs.argc = &argc;
|
pargs.argc = &argc;
|
||||||
pargs.argv = &argv;
|
pargs.argv = &argv;
|
||||||
/* We are re-using the struct, thus the reset flag. We OR the
|
/* We are re-using the struct, thus the reset flag. We OR the
|
||||||
* flags so that the internal intialized flag won't be cleared. */
|
* flags so that the internal initialized flag won't be cleared. */
|
||||||
pargs.flags |= (ARGPARSE_FLAG_RESET
|
pargs.flags |= (ARGPARSE_FLAG_RESET
|
||||||
| ARGPARSE_FLAG_KEEP
|
| ARGPARSE_FLAG_KEEP
|
||||||
| ARGPARSE_FLAG_SYS
|
| ARGPARSE_FLAG_SYS
|
||||||
|
@ -1295,7 +1311,7 @@ main (int argc, char **argv)
|
||||||
if (pargs.r_type)
|
if (pargs.r_type)
|
||||||
win32_openssh_support = pargs.r.ret_str;
|
win32_openssh_support = pargs.r.ret_str;
|
||||||
else
|
else
|
||||||
win32_openssh_support = W32_DEFAILT_AGENT_PIPE_NAME;
|
win32_openssh_support = W32_DEFAULT_AGENT_PIPE_NAME;
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1579,7 +1595,7 @@ main (int argc, char **argv)
|
||||||
|
|
||||||
log_info ("listening on: std=%d extra=%d browser=%d ssh=%d\n",
|
log_info ("listening on: std=%d extra=%d browser=%d ssh=%d\n",
|
||||||
fd, fd_extra, fd_browser, fd_ssh);
|
fd, fd_extra, fd_browser, fd_ssh);
|
||||||
handle_connections (fd, fd_extra, fd_browser, fd_ssh);
|
handle_connections (fd, fd_extra, fd_browser, fd_ssh, 1);
|
||||||
#endif /*!HAVE_W32_SYSTEM*/
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
}
|
}
|
||||||
else if (!is_daemon)
|
else if (!is_daemon)
|
||||||
|
@ -1807,14 +1823,14 @@ main (int argc, char **argv)
|
||||||
log_get_prefix (&oldflags);
|
log_get_prefix (&oldflags);
|
||||||
log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
|
log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
|
||||||
opt.running_detached = 1;
|
opt.running_detached = 1;
|
||||||
|
|
||||||
/* Unless we are running with a program given on the command
|
|
||||||
* line we can assume that the inotify things works and thus
|
|
||||||
* we can avoid the regular stat calls. */
|
|
||||||
if (!argc)
|
|
||||||
reliable_homedir_inotify = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When we are running with a program given on the command
|
||||||
|
* line, the inotify things may not work well and thus
|
||||||
|
* we cannot avoid the regular stat calls. */
|
||||||
|
if (argc)
|
||||||
|
reliable_homedir_inotify = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
|
@ -1833,7 +1849,8 @@ main (int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info ("%s %s started\n", gpgrt_strusage(11), gpgrt_strusage(13) );
|
log_info ("%s %s started\n", gpgrt_strusage(11), gpgrt_strusage(13) );
|
||||||
handle_connections (fd, fd_extra, fd_browser, fd_ssh);
|
handle_connections (fd, fd_extra, fd_browser, fd_ssh,
|
||||||
|
reliable_homedir_inotify);
|
||||||
assuan_sock_close (fd);
|
assuan_sock_close (fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1989,6 +2006,7 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
|
||||||
{
|
{
|
||||||
unregister_progress_cb ();
|
unregister_progress_cb ();
|
||||||
session_env_release (ctrl->session_env);
|
session_env_release (ctrl->session_env);
|
||||||
|
clear_ephemeral_keys (ctrl);
|
||||||
|
|
||||||
xfree (ctrl->digest.data);
|
xfree (ctrl->digest.data);
|
||||||
ctrl->digest.data = NULL;
|
ctrl->digest.data = NULL;
|
||||||
|
@ -2134,39 +2152,45 @@ get_agent_active_connection_count (void)
|
||||||
notification event. Calling it the first time creates that
|
notification event. Calling it the first time creates that
|
||||||
event. */
|
event. */
|
||||||
#if defined(HAVE_W32_SYSTEM)
|
#if defined(HAVE_W32_SYSTEM)
|
||||||
|
static void *
|
||||||
|
create_an_event (void)
|
||||||
|
{
|
||||||
|
HANDLE h, h2;
|
||||||
|
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
|
||||||
|
|
||||||
|
/* We need to use a manual reset event object due to the way our
|
||||||
|
w32-pth wait function works: If we would use an automatic
|
||||||
|
reset event we are not able to figure out which handle has
|
||||||
|
been signaled because at the time we single out the signaled
|
||||||
|
handles using WFSO the event has already been reset due to
|
||||||
|
the WFMO. */
|
||||||
|
h = CreateEvent (&sa, TRUE, FALSE, NULL);
|
||||||
|
if (!h)
|
||||||
|
log_error ("can't create an event: %s\n", w32_strerror (-1) );
|
||||||
|
else if (!DuplicateHandle (GetCurrentProcess(), h,
|
||||||
|
GetCurrentProcess(), &h2,
|
||||||
|
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
|
||||||
|
{
|
||||||
|
log_error ("setting synchronize for an event failed: %s\n",
|
||||||
|
w32_strerror (-1) );
|
||||||
|
CloseHandle (h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseHandle (h);
|
||||||
|
return h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
get_agent_daemon_notify_event (void)
|
get_agent_daemon_notify_event (void)
|
||||||
{
|
{
|
||||||
static HANDLE the_event = INVALID_HANDLE_VALUE;
|
static HANDLE the_event = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
if (the_event == INVALID_HANDLE_VALUE)
|
if (the_event == INVALID_HANDLE_VALUE)
|
||||||
{
|
the_event = create_an_event ();
|
||||||
HANDLE h, h2;
|
|
||||||
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
|
|
||||||
|
|
||||||
/* We need to use a manual reset event object due to the way our
|
|
||||||
w32-pth wait function works: If we would use an automatic
|
|
||||||
reset event we are not able to figure out which handle has
|
|
||||||
been signaled because at the time we single out the signaled
|
|
||||||
handles using WFSO the event has already been reset due to
|
|
||||||
the WFMO. */
|
|
||||||
h = CreateEvent (&sa, TRUE, FALSE, NULL);
|
|
||||||
if (!h)
|
|
||||||
log_error ("can't create scd notify event: %s\n", w32_strerror (-1) );
|
|
||||||
else if (!DuplicateHandle (GetCurrentProcess(), h,
|
|
||||||
GetCurrentProcess(), &h2,
|
|
||||||
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
|
|
||||||
{
|
|
||||||
log_error ("setting synchronize for scd notify event failed: %s\n",
|
|
||||||
w32_strerror (-1) );
|
|
||||||
CloseHandle (h);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CloseHandle (h);
|
|
||||||
the_event = h2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return the_event;
|
return the_event;
|
||||||
}
|
}
|
||||||
|
@ -2423,57 +2447,6 @@ create_directories (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* This is the worker for the ticker. It is called every few seconds
|
|
||||||
and may only do fast operations. */
|
|
||||||
static void
|
|
||||||
handle_tick (void)
|
|
||||||
{
|
|
||||||
static time_t last_minute;
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
if (!last_minute)
|
|
||||||
last_minute = time (NULL);
|
|
||||||
|
|
||||||
/* If we are running as a child of another process, check whether
|
|
||||||
the parent is still alive and shutdown if not. */
|
|
||||||
#ifndef HAVE_W32_SYSTEM
|
|
||||||
if (parent_pid != (pid_t)(-1))
|
|
||||||
{
|
|
||||||
if (kill (parent_pid, 0))
|
|
||||||
{
|
|
||||||
shutdown_pending = 2;
|
|
||||||
log_info ("parent process died - shutting down\n");
|
|
||||||
log_info ("%s %s stopped\n", gpgrt_strusage(11), gpgrt_strusage(13));
|
|
||||||
cleanup ();
|
|
||||||
agent_exit (0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /*HAVE_W32_SYSTEM*/
|
|
||||||
|
|
||||||
/* Code to be run from time to time. */
|
|
||||||
#if CHECK_OWN_SOCKET_INTERVAL > 0
|
|
||||||
if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
|
|
||||||
{
|
|
||||||
check_own_socket ();
|
|
||||||
last_minute = time (NULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Need to check for expired cache entries. */
|
|
||||||
agent_cache_housekeeping ();
|
|
||||||
|
|
||||||
/* Check whether the homedir is still available. */
|
|
||||||
if (!shutdown_pending
|
|
||||||
&& (!have_homedir_inotify || !reliable_homedir_inotify)
|
|
||||||
&& gnupg_stat (gnupg_homedir (), &statbuf) && errno == ENOENT)
|
|
||||||
{
|
|
||||||
shutdown_pending = 1;
|
|
||||||
log_info ("homedir has been removed - shutting down\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* A global function which allows us to call the reload stuff from
|
/* A global function which allows us to call the reload stuff from
|
||||||
other places too. This is only used when build for W32. */
|
other places too. This is only used when build for W32. */
|
||||||
void
|
void
|
||||||
|
@ -2532,6 +2505,11 @@ handle_signal (int signo)
|
||||||
agent_sigusr2_action ();
|
agent_sigusr2_action ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SIGCONT:
|
||||||
|
/* Do nothing, but break the syscall. */
|
||||||
|
log_debug ("SIGCONT received - breaking select\n");
|
||||||
|
break;
|
||||||
|
|
||||||
case SIGTERM:
|
case SIGTERM:
|
||||||
if (!shutdown_pending)
|
if (!shutdown_pending)
|
||||||
log_info ("SIGTERM received - shutting down ...\n");
|
log_info ("SIGTERM received - shutting down ...\n");
|
||||||
|
@ -2569,7 +2547,7 @@ check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
|
||||||
if (assuan_sock_check_nonce (ctrl->thread_startup.fd, nonce))
|
if (assuan_sock_check_nonce (ctrl->thread_startup.fd, nonce))
|
||||||
{
|
{
|
||||||
log_info (_("error reading nonce on fd %d: %s\n"),
|
log_info (_("error reading nonce on fd %d: %s\n"),
|
||||||
FD2INT(ctrl->thread_startup.fd), strerror (errno));
|
FD_DBG (ctrl->thread_startup.fd), strerror (errno));
|
||||||
assuan_sock_close (ctrl->thread_startup.fd);
|
assuan_sock_close (ctrl->thread_startup.fd);
|
||||||
xfree (ctrl);
|
xfree (ctrl);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2869,12 +2847,12 @@ do_start_connection_thread (ctrl_t ctrl)
|
||||||
agent_init_default_ctrl (ctrl);
|
agent_init_default_ctrl (ctrl);
|
||||||
if (opt.verbose > 1 && !DBG_IPC)
|
if (opt.verbose > 1 && !DBG_IPC)
|
||||||
log_info (_("handler 0x%lx for fd %d started\n"),
|
log_info (_("handler 0x%lx for fd %d started\n"),
|
||||||
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
|
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
|
||||||
|
|
||||||
start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
|
start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
|
||||||
if (opt.verbose > 1 && !DBG_IPC)
|
if (opt.verbose > 1 && !DBG_IPC)
|
||||||
log_info (_("handler 0x%lx for fd %d terminated\n"),
|
log_info (_("handler 0x%lx for fd %d terminated\n"),
|
||||||
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
|
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
|
||||||
|
|
||||||
agent_deinit_default_ctrl (ctrl);
|
agent_deinit_default_ctrl (ctrl);
|
||||||
xfree (ctrl);
|
xfree (ctrl);
|
||||||
|
@ -2949,12 +2927,12 @@ start_connection_thread_ssh (void *arg)
|
||||||
agent_init_default_ctrl (ctrl);
|
agent_init_default_ctrl (ctrl);
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info (_("ssh handler 0x%lx for fd %d started\n"),
|
log_info (_("ssh handler 0x%lx for fd %d started\n"),
|
||||||
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
|
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
|
||||||
|
|
||||||
start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
|
start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
|
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
|
||||||
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
|
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
|
||||||
|
|
||||||
agent_deinit_default_ctrl (ctrl);
|
agent_deinit_default_ctrl (ctrl);
|
||||||
xfree (ctrl);
|
xfree (ctrl);
|
||||||
|
@ -2963,13 +2941,36 @@ start_connection_thread_ssh (void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
agent_kick_the_loop (void)
|
||||||
|
{
|
||||||
|
/* Kick the select loop. */
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
int ret = SetEvent (the_event2);
|
||||||
|
if (ret == 0)
|
||||||
|
log_error ("SetEvent for agent_kick_the_loop failed: %s\n",
|
||||||
|
w32_strerror (-1));
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_PSELECT_NO_EINTR
|
||||||
|
write (event_pipe_fd, "", 1);
|
||||||
|
# else
|
||||||
|
int ret = kill (main_thread_pid, SIGCONT);
|
||||||
|
if (ret < 0)
|
||||||
|
log_error ("sending signal for agent_kick_the_loop failed: %s\n",
|
||||||
|
gpg_strerror (gpg_error_from_syserror ()));
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Connection handler loop. Wait for connection requests and spawn a
|
/* Connection handler loop. Wait for connection requests and spawn a
|
||||||
thread after accepting a connection. */
|
thread after accepting a connection. */
|
||||||
static void
|
static void
|
||||||
handle_connections (gnupg_fd_t listen_fd,
|
handle_connections (gnupg_fd_t listen_fd,
|
||||||
gnupg_fd_t listen_fd_extra,
|
gnupg_fd_t listen_fd_extra,
|
||||||
gnupg_fd_t listen_fd_browser,
|
gnupg_fd_t listen_fd_browser,
|
||||||
gnupg_fd_t listen_fd_ssh)
|
gnupg_fd_t listen_fd_ssh,
|
||||||
|
int reliable_homedir_inotify)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
npth_attr_t tattr;
|
npth_attr_t tattr;
|
||||||
|
@ -2980,12 +2981,15 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
gnupg_fd_t fd;
|
gnupg_fd_t fd;
|
||||||
int nfd;
|
int nfd;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
struct timespec abstime;
|
struct timespec *tp;
|
||||||
struct timespec curtime;
|
|
||||||
struct timespec timeout;
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
HANDLE events[2];
|
HANDLE events[3];
|
||||||
unsigned int events_set;
|
unsigned int events_set;
|
||||||
|
#else
|
||||||
|
int signo;
|
||||||
|
# ifdef HAVE_PSELECT_NO_EINTR
|
||||||
|
int pipe_fd[2];
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
int sock_inotify_fd = -1;
|
int sock_inotify_fd = -1;
|
||||||
int home_inotify_fd = -1;
|
int home_inotify_fd = -1;
|
||||||
|
@ -3013,11 +3017,24 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
npth_sigev_add (SIGUSR1);
|
npth_sigev_add (SIGUSR1);
|
||||||
npth_sigev_add (SIGUSR2);
|
npth_sigev_add (SIGUSR2);
|
||||||
npth_sigev_add (SIGINT);
|
npth_sigev_add (SIGINT);
|
||||||
|
npth_sigev_add (SIGCONT);
|
||||||
npth_sigev_add (SIGTERM);
|
npth_sigev_add (SIGTERM);
|
||||||
npth_sigev_fini ();
|
npth_sigev_fini ();
|
||||||
|
# ifdef HAVE_PSELECT_NO_EINTR
|
||||||
|
ret = gnupg_create_pipe (pipe_fd);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
log_error ("pipe creation failed: %s\n", gpg_strerror (ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event_pipe_fd = pipe_fd[1];
|
||||||
|
# else
|
||||||
|
main_thread_pid = getpid ();
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
events[0] = get_agent_daemon_notify_event ();
|
events[0] = get_agent_daemon_notify_event ();
|
||||||
events[1] = INVALID_HANDLE_VALUE;
|
events[1] = the_event2 = create_an_event ();
|
||||||
|
events[2] = INVALID_HANDLE_VALUE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (disable_check_own_socket)
|
if (disable_check_own_socket)
|
||||||
|
@ -3029,7 +3046,7 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disable_check_own_socket)
|
if (!reliable_homedir_inotify)
|
||||||
home_inotify_fd = -1;
|
home_inotify_fd = -1;
|
||||||
else if ((err = gnupg_inotify_watch_delete_self (&home_inotify_fd,
|
else if ((err = gnupg_inotify_watch_delete_self (&home_inotify_fd,
|
||||||
gnupg_homedir ())))
|
gnupg_homedir ())))
|
||||||
|
@ -3041,6 +3058,27 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
else
|
else
|
||||||
have_homedir_inotify = 1;
|
have_homedir_inotify = 1;
|
||||||
|
|
||||||
|
#if CHECK_OWN_SOCKET_INTERVAL > 0
|
||||||
|
if (!disable_check_own_socket && sock_inotify_fd == -1)
|
||||||
|
{
|
||||||
|
npth_t thread;
|
||||||
|
|
||||||
|
err = npth_create (&thread, &tattr, check_own_socket_thread, NULL);
|
||||||
|
if (err)
|
||||||
|
log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((HAVE_PARENT_PID_SUPPORT && parent_pid != (pid_t)(-1))
|
||||||
|
|| !have_homedir_inotify)
|
||||||
|
{
|
||||||
|
npth_t thread;
|
||||||
|
|
||||||
|
err = npth_create (&thread, &tattr, check_others_thread, NULL);
|
||||||
|
if (err)
|
||||||
|
log_error ("error spawning check_others_thread: %s\n", strerror (err));
|
||||||
|
}
|
||||||
|
|
||||||
/* On Windows we need to fire up a separate thread to listen for
|
/* On Windows we need to fire up a separate thread to listen for
|
||||||
requests from Putty (an SSH client), so we can replace Putty's
|
requests from Putty (an SSH client), so we can replace Putty's
|
||||||
Pageant (its ssh-agent implementation). */
|
Pageant (its ssh-agent implementation). */
|
||||||
|
@ -3070,24 +3108,24 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
|
|
||||||
FD_ZERO (&fdset);
|
FD_ZERO (&fdset);
|
||||||
FD_SET (FD2INT (listen_fd), &fdset);
|
FD_SET (FD2INT (listen_fd), &fdset);
|
||||||
nfd = FD2INT (listen_fd);
|
nfd = FD2NUM (listen_fd);
|
||||||
if (listen_fd_extra != GNUPG_INVALID_FD)
|
if (listen_fd_extra != GNUPG_INVALID_FD)
|
||||||
{
|
{
|
||||||
FD_SET ( FD2INT(listen_fd_extra), &fdset);
|
FD_SET ( FD2INT(listen_fd_extra), &fdset);
|
||||||
if (FD2INT (listen_fd_extra) > nfd)
|
if (FD2INT (listen_fd_extra) > nfd)
|
||||||
nfd = FD2INT (listen_fd_extra);
|
nfd = FD2NUM (listen_fd_extra);
|
||||||
}
|
}
|
||||||
if (listen_fd_browser != GNUPG_INVALID_FD)
|
if (listen_fd_browser != GNUPG_INVALID_FD)
|
||||||
{
|
{
|
||||||
FD_SET ( FD2INT(listen_fd_browser), &fdset);
|
FD_SET ( FD2INT(listen_fd_browser), &fdset);
|
||||||
if (FD2INT (listen_fd_browser) > nfd)
|
if (FD2INT (listen_fd_browser) > nfd)
|
||||||
nfd = FD2INT (listen_fd_browser);
|
nfd = FD2NUM (listen_fd_browser);
|
||||||
}
|
}
|
||||||
if (listen_fd_ssh != GNUPG_INVALID_FD)
|
if (listen_fd_ssh != GNUPG_INVALID_FD)
|
||||||
{
|
{
|
||||||
FD_SET ( FD2INT(listen_fd_ssh), &fdset);
|
FD_SET ( FD2INT(listen_fd_ssh), &fdset);
|
||||||
if (FD2INT (listen_fd_ssh) > nfd)
|
if (FD2INT (listen_fd_ssh) > nfd)
|
||||||
nfd = FD2INT (listen_fd_ssh);
|
nfd = FD2NUM (listen_fd_ssh);
|
||||||
}
|
}
|
||||||
if (sock_inotify_fd != -1)
|
if (sock_inotify_fd != -1)
|
||||||
{
|
{
|
||||||
|
@ -3107,15 +3145,12 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
listentbl[2].l_fd = listen_fd_browser;
|
listentbl[2].l_fd = listen_fd_browser;
|
||||||
listentbl[3].l_fd = listen_fd_ssh;
|
listentbl[3].l_fd = listen_fd_ssh;
|
||||||
|
|
||||||
npth_clock_gettime (&abstime);
|
|
||||||
abstime.tv_sec += TIMERTICK_INTERVAL;
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* Shutdown test. */
|
/* Shutdown test. */
|
||||||
if (shutdown_pending)
|
if (shutdown_pending)
|
||||||
{
|
{
|
||||||
if (active_connections == 0)
|
if (active_connections == 0 || is_supervised)
|
||||||
break; /* ready */
|
break; /* ready */
|
||||||
|
|
||||||
/* Do not accept new connections but keep on running the
|
/* Do not accept new connections but keep on running the
|
||||||
|
@ -3144,28 +3179,23 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
thus a simple assignment is fine to copy the entire set. */
|
thus a simple assignment is fine to copy the entire set. */
|
||||||
read_fdset = fdset;
|
read_fdset = fdset;
|
||||||
|
|
||||||
npth_clock_gettime (&curtime);
|
#ifdef HAVE_PSELECT_NO_EINTR
|
||||||
if (!(npth_timercmp (&curtime, &abstime, <)))
|
FD_SET (pipe_fd[0], &read_fdset);
|
||||||
{
|
if (nfd < pipe_fd[0])
|
||||||
/* Timeout. */
|
nfd = pipe_fd[0];
|
||||||
handle_tick ();
|
#endif
|
||||||
npth_clock_gettime (&abstime);
|
|
||||||
abstime.tv_sec += TIMERTICK_INTERVAL;
|
tp = agent_cache_expiration ();
|
||||||
}
|
|
||||||
npth_timersub (&abstime, &curtime, &timeout);
|
|
||||||
|
|
||||||
#ifndef HAVE_W32_SYSTEM
|
#ifndef HAVE_W32_SYSTEM
|
||||||
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
|
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, tp,
|
||||||
npth_sigev_sigmask ());
|
npth_sigev_sigmask ());
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
|
|
||||||
{
|
while (npth_sigev_get_pending (&signo))
|
||||||
int signo;
|
handle_signal (signo);
|
||||||
while (npth_sigev_get_pending (&signo))
|
|
||||||
handle_signal (signo);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
|
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, tp,
|
||||||
events, &events_set);
|
events, &events_set);
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
|
|
||||||
|
@ -3181,11 +3211,47 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
gnupg_sleep (1);
|
gnupg_sleep (1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef HAVE_W32_SYSTEM
|
||||||
|
if ((problem_detected & AGENT_PROBLEM_PARENT_HAS_GONE))
|
||||||
|
{
|
||||||
|
shutdown_pending = 2;
|
||||||
|
log_info ("parent process died - shutting down\n");
|
||||||
|
log_info ("%s %s stopped\n", gpgrt_strusage(11), gpgrt_strusage(13));
|
||||||
|
cleanup ();
|
||||||
|
agent_exit (0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((problem_detected & AGENT_PROBLEM_SOCKET_TAKEOVER))
|
||||||
|
{
|
||||||
|
/* We may not remove the socket as it is now in use by another
|
||||||
|
server. */
|
||||||
|
inhibit_socket_removal = 1;
|
||||||
|
shutdown_pending = 2;
|
||||||
|
log_info ("this process is useless - shutting down\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((problem_detected & AGENT_PROBLEM_HOMEDIR_REMOVED))
|
||||||
|
{
|
||||||
|
shutdown_pending = 1;
|
||||||
|
log_info ("homedir has been removed - shutting down\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
/* Interrupt or timeout. Will be handled when calculating the
|
/* Interrupt or timeout. Will be handled when calculating the
|
||||||
next timeout. */
|
next timeout. */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
#ifdef HAVE_PSELECT_NO_EINTR
|
||||||
|
if (FD_ISSET (pipe_fd[0], &read_fdset))
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
read (pipe_fd[0], buf, sizeof buf);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The inotify fds are set even when a shutdown is pending (see
|
/* The inotify fds are set even when a shutdown is pending (see
|
||||||
* above). So we must handle them in any case. To avoid that
|
* above). So we must handle them in any case. To avoid that
|
||||||
* they trigger a second time we close them immediately. */
|
* they trigger a second time we close them immediately. */
|
||||||
|
@ -3193,7 +3259,10 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
&& FD_ISSET (sock_inotify_fd, &read_fdset)
|
&& FD_ISSET (sock_inotify_fd, &read_fdset)
|
||||||
&& gnupg_inotify_has_name (sock_inotify_fd, GPG_AGENT_SOCK_NAME))
|
&& gnupg_inotify_has_name (sock_inotify_fd, GPG_AGENT_SOCK_NAME))
|
||||||
{
|
{
|
||||||
shutdown_pending = 1;
|
/* We may not remove the socket (if any), as it may be now
|
||||||
|
in use by another server. */
|
||||||
|
inhibit_socket_removal = 1;
|
||||||
|
shutdown_pending = 2;
|
||||||
close (sock_inotify_fd);
|
close (sock_inotify_fd);
|
||||||
sock_inotify_fd = -1;
|
sock_inotify_fd = -1;
|
||||||
log_info ("socket file has been removed - shutting down\n");
|
log_info ("socket file has been removed - shutting down\n");
|
||||||
|
@ -3222,8 +3291,8 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
plen = sizeof paddr;
|
plen = sizeof paddr;
|
||||||
fd = INT2FD (npth_accept (FD2INT(listentbl[idx].l_fd),
|
fd = assuan_sock_accept (listentbl[idx].l_fd,
|
||||||
(struct sockaddr *)&paddr, &plen));
|
(struct sockaddr *)&paddr, &plen);
|
||||||
if (fd == GNUPG_INVALID_FD)
|
if (fd == GNUPG_INVALID_FD)
|
||||||
{
|
{
|
||||||
log_error ("accept failed for %s: %s\n",
|
log_error ("accept failed for %s: %s\n",
|
||||||
|
@ -3263,13 +3332,21 @@ handle_connections (gnupg_fd_t listen_fd,
|
||||||
close (sock_inotify_fd);
|
close (sock_inotify_fd);
|
||||||
if (home_inotify_fd != -1)
|
if (home_inotify_fd != -1)
|
||||||
close (home_inotify_fd);
|
close (home_inotify_fd);
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
if (the_event2 != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle (the_event2);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_PSELECT_NO_EINTR
|
||||||
|
close (pipe_fd[0]);
|
||||||
|
close (pipe_fd[1]);
|
||||||
|
#endif
|
||||||
cleanup ();
|
cleanup ();
|
||||||
log_info (_("%s %s stopped\n"), gpgrt_strusage(11), gpgrt_strusage(13));
|
log_info (_("%s %s stopped\n"), gpgrt_strusage(11), gpgrt_strusage(13));
|
||||||
npth_attr_destroy (&tattr);
|
npth_attr_destroy (&tattr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if CHECK_OWN_SOCKET_INTERVAL > 0
|
||||||
/* Helper for check_own_socket. */
|
/* Helper for check_own_socket. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
|
check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
|
||||||
|
@ -3280,20 +3357,18 @@ check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The thread running the actual check. We need to run this in a
|
/* Check whether we are still listening on our own socket. In case
|
||||||
separate thread so that check_own_thread can be called from the
|
another gpg-agent process started after us has taken ownership of
|
||||||
timer tick. */
|
our socket, we would linger around without any real task. Thus we
|
||||||
static void *
|
better check once in a while whether we are really needed. */
|
||||||
check_own_socket_thread (void *arg)
|
static int
|
||||||
|
do_check_own_socket (const char *sockname)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
char *sockname = arg;
|
|
||||||
assuan_context_t ctx = NULL;
|
assuan_context_t ctx = NULL;
|
||||||
membuf_t mb;
|
membuf_t mb;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
||||||
check_own_socket_running++;
|
|
||||||
|
|
||||||
rc = assuan_new (&ctx);
|
rc = assuan_new (&ctx);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
@ -3331,58 +3406,78 @@ check_own_socket_thread (void *arg)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
xfree (sockname);
|
|
||||||
if (ctx)
|
if (ctx)
|
||||||
assuan_release (ctx);
|
assuan_release (ctx);
|
||||||
if (rc)
|
|
||||||
{
|
return rc;
|
||||||
/* We may not remove the socket as it is now in use by another
|
|
||||||
server. */
|
|
||||||
inhibit_socket_removal = 1;
|
|
||||||
shutdown_pending = 2;
|
|
||||||
log_info ("this process is useless - shutting down\n");
|
|
||||||
}
|
|
||||||
check_own_socket_running--;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The thread running the actual check. */
|
||||||
/* Check whether we are still listening on our own socket. In case
|
static void *
|
||||||
another gpg-agent process started after us has taken ownership of
|
check_own_socket_thread (void *arg)
|
||||||
our socket, we would linger around without any real task. Thus we
|
|
||||||
better check once in a while whether we are really needed. */
|
|
||||||
static void
|
|
||||||
check_own_socket (void)
|
|
||||||
{
|
{
|
||||||
char *sockname;
|
char *sockname;
|
||||||
npth_t thread;
|
|
||||||
npth_attr_t tattr;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (disable_check_own_socket)
|
(void)arg;
|
||||||
return;
|
|
||||||
|
|
||||||
if (check_own_socket_running || shutdown_pending)
|
|
||||||
return; /* Still running or already shutting down. */
|
|
||||||
|
|
||||||
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
|
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
|
||||||
if (!sockname)
|
if (!sockname)
|
||||||
return; /* Out of memory. */
|
return NULL; /* Out of memory. */
|
||||||
|
|
||||||
err = npth_attr_init (&tattr);
|
while (!problem_detected)
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
xfree (sockname);
|
if (shutdown_pending)
|
||||||
return;
|
goto leave;
|
||||||
|
|
||||||
|
gnupg_sleep (CHECK_OWN_SOCKET_INTERVAL);
|
||||||
|
|
||||||
|
if (do_check_own_socket (sockname))
|
||||||
|
problem_detected |= AGENT_PROBLEM_SOCKET_TAKEOVER;
|
||||||
}
|
}
|
||||||
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
|
|
||||||
err = npth_create (&thread, &tattr, check_own_socket_thread, sockname);
|
agent_kick_the_loop ();
|
||||||
if (err)
|
|
||||||
log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
|
leave:
|
||||||
npth_attr_destroy (&tattr);
|
xfree (sockname);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The thread running other checks. */
|
||||||
|
static void *
|
||||||
|
check_others_thread (void *arg)
|
||||||
|
{
|
||||||
|
const char *homedir = gnupg_homedir ();
|
||||||
|
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
while (!problem_detected)
|
||||||
|
{
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
if (shutdown_pending)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
gnupg_sleep (CHECK_PROBLEMS_INTERVAL);
|
||||||
|
|
||||||
|
/* If we are running as a child of another process, check whether
|
||||||
|
the parent is still alive and shutdown if not. */
|
||||||
|
#ifndef HAVE_W32_SYSTEM
|
||||||
|
if (parent_pid != (pid_t)(-1) && kill (parent_pid, 0))
|
||||||
|
problem_detected |= AGENT_PROBLEM_PARENT_HAS_GONE;
|
||||||
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
|
/* Check whether the homedir is still available. */
|
||||||
|
if (!have_homedir_inotify
|
||||||
|
&& gnupg_stat (homedir, &statbuf) && errno == ENOENT)
|
||||||
|
problem_detected |= AGENT_PROBLEM_HOMEDIR_REMOVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
agent_kick_the_loop ();
|
||||||
|
|
||||||
|
leave:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Figure out whether an agent is available and running. Prints an
|
/* Figure out whether an agent is available and running. Prints an
|
||||||
error if not. If SILENT is true, no messages are printed.
|
error if not. If SILENT is true, no messages are printed.
|
||||||
|
|
25
agent/gpg-agent.w32-manifest.in
Normal file
25
agent/gpg-agent.w32-manifest.in
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
<description>GNU Privacy Guard (Private Key Daemon)</description>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="GnuPG.gpg-agent"
|
||||||
|
version="@BUILD_VERSION@"
|
||||||
|
/>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/><!-- 7 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/><!-- 8 -->
|
||||||
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10 -->
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="asInvoker"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
</assembly>
|
|
@ -397,7 +397,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
|
||||||
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
|
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
|
||||||
grip[i] = xtoi_2 (p);
|
grip[i] = xtoi_2 (p);
|
||||||
|
|
||||||
if (!force && !agent_key_available (grip))
|
if (!force && !agent_key_available (ctrl, grip))
|
||||||
continue; /* The key is already available. */
|
continue; /* The key is already available. */
|
||||||
|
|
||||||
/* Unknown key - store it. */
|
/* Unknown key - store it. */
|
||||||
|
@ -408,7 +408,17 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force);
|
if (!ctrl->ephemeral_mode)
|
||||||
|
{
|
||||||
|
char *dispserialno;
|
||||||
|
|
||||||
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
||||||
|
item->hexgrip);
|
||||||
|
rc = agent_write_shadow_key (ctrl,
|
||||||
|
grip, serialno, item->id, pubkey, force,
|
||||||
|
dispserialno);
|
||||||
|
xfree (dispserialno);
|
||||||
|
}
|
||||||
xfree (pubkey);
|
xfree (pubkey);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
|
@ -27,8 +27,83 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
|
#include "../common/openpgpdefs.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Table with parameters for KEM decryption. Use get_ecc_parms to
|
||||||
|
* find an entry. */
|
||||||
|
struct ecc_params
|
||||||
|
{
|
||||||
|
const char *curve; /* Canonical name of the curve. */
|
||||||
|
size_t pubkey_len; /* Pubkey in the SEXP representation. */
|
||||||
|
size_t scalar_len;
|
||||||
|
size_t point_len;
|
||||||
|
size_t shared_len;
|
||||||
|
int hash_algo;
|
||||||
|
int kem_algo;
|
||||||
|
int scalar_reverse;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct ecc_params ecc_table[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"Curve25519",
|
||||||
|
33, 32, 32, 32,
|
||||||
|
GCRY_MD_SHA3_256, GCRY_KEM_RAW_X25519,
|
||||||
|
1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"X448",
|
||||||
|
56, 56, 56, 64,
|
||||||
|
GCRY_MD_SHA3_512, GCRY_KEM_RAW_X448,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brainpoolP256r1",
|
||||||
|
65, 32, 65, 32,
|
||||||
|
GCRY_MD_SHA3_256, GCRY_KEM_RAW_BP256,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brainpoolP384r1",
|
||||||
|
97, 48, 97, 64,
|
||||||
|
GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP384,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"brainpoolP512r1",
|
||||||
|
129, 64, 129, 64,
|
||||||
|
GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP512,
|
||||||
|
0
|
||||||
|
},
|
||||||
|
{ NULL, 0, 0, 0, 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Maximum buffer sizes required for ECC KEM. Keep this aligned to
|
||||||
|
* the ecc_table above. */
|
||||||
|
#define ECC_SCALAR_LEN_MAX 64
|
||||||
|
#define ECC_POINT_LEN_MAX (1+2*64)
|
||||||
|
#define ECC_HASH_LEN_MAX 64
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the ECC parameters for CURVE. CURVE is expected to be the
|
||||||
|
* canonical name. */
|
||||||
|
static const struct ecc_params *
|
||||||
|
get_ecc_params (const char *curve)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; ecc_table[i].curve; i++)
|
||||||
|
if (!strcmp (ecc_table[i].curve, curve))
|
||||||
|
return &ecc_table[i];
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
|
/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
|
||||||
Try to get the key from CTRL and write the decoded stuff back to
|
Try to get the key from CTRL and write the decoded stuff back to
|
||||||
OUTFP. The padding information is stored at R_PADDING with -1
|
OUTFP. The padding information is stored at R_PADDING with -1
|
||||||
|
@ -41,7 +116,6 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||||
gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL;
|
gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL;
|
||||||
unsigned char *shadow_info = NULL;
|
unsigned char *shadow_info = NULL;
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
int no_shadow_info = 0;
|
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
@ -70,17 +144,13 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||||
err = agent_key_from_file (ctrl, NULL, desc_text,
|
err = agent_key_from_file (ctrl, NULL, desc_text,
|
||||||
NULL, &shadow_info,
|
NULL, &shadow_info,
|
||||||
CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL);
|
CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL);
|
||||||
if (gpg_err_code (err) == GPG_ERR_NO_SECKEY)
|
if (err && gpg_err_code (err) != GPG_ERR_NO_SECKEY)
|
||||||
no_shadow_info = 1;
|
|
||||||
else if (err)
|
|
||||||
{
|
{
|
||||||
log_error ("failed to read the secret key\n");
|
log_error ("failed to read the secret key\n");
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
|
else if (shadow_info
|
||||||
if (shadow_info || no_shadow_info)
|
|| err /* gpg_err_code (err) == GPG_ERR_NO_SECKEY */)
|
||||||
{ /* divert operation to the smartcard */
|
{ /* divert operation to the smartcard */
|
||||||
|
|
||||||
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
|
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_INV_SEXP);
|
err = gpg_error (GPG_ERR_INV_SEXP);
|
||||||
|
@ -95,12 +165,12 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||||
&buf, &len, r_padding);
|
&buf, &len, r_padding);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
/* We restore the original error (ie. no seckey) is no card
|
/* We restore the original error (ie. no seckey) as no card
|
||||||
* has been found and we have no shadow key. This avoids a
|
* has been found and we have no shadow key. This avoids a
|
||||||
* surprising "card removed" error code. */
|
* surprising "card removed" error code. */
|
||||||
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|
||||||
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
||||||
&& no_shadow_info)
|
&& !shadow_info)
|
||||||
err = gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
else
|
else
|
||||||
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
|
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
|
||||||
|
@ -157,3 +227,597 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||||
xfree (shadow_info);
|
xfree (shadow_info);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Reverse BUFFER to change the endianness. */
|
||||||
|
static void
|
||||||
|
reverse_buffer (unsigned char *buffer, unsigned int length)
|
||||||
|
{
|
||||||
|
unsigned int tmp, i;
|
||||||
|
|
||||||
|
for (i=0; i < length/2; i++)
|
||||||
|
{
|
||||||
|
tmp = buffer[i];
|
||||||
|
buffer[i] = buffer[length-1-i];
|
||||||
|
buffer[length-1-i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
ecc_extract_pk_from_key (const struct ecc_params *ecc, gcry_sexp_t s_skey,
|
||||||
|
unsigned char *ecc_pk)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned int nbits;
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t len;
|
||||||
|
gcry_mpi_t ecc_pk_mpi = NULL;
|
||||||
|
|
||||||
|
err = gcry_sexp_extract_param (s_skey, NULL, "/q", &ecc_pk_mpi, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: extracting q and d from ECC key failed\n", __func__);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits);
|
||||||
|
len = (nbits+7)/8;
|
||||||
|
if (len != ecc->pubkey_len)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: ECC public key length invalid (%zu)\n", __func__, len);
|
||||||
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
else if (len == ecc->point_len)
|
||||||
|
memcpy (ecc_pk, p, ecc->point_len);
|
||||||
|
else if (len == ecc->point_len + 1 && p[0] == 0x40)
|
||||||
|
/* Remove the 0x40 prefix (for Curve25519) */
|
||||||
|
memcpy (ecc_pk, p+1, ecc->point_len);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (ecc_pk, ecc->pubkey_len, "ECC pubkey:");
|
||||||
|
|
||||||
|
leave:
|
||||||
|
mpi_release (ecc_pk_mpi);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
ecc_extract_sk_from_key (const struct ecc_params *ecc, gcry_sexp_t s_skey,
|
||||||
|
unsigned char *ecc_sk)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned int nbits;
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t len;
|
||||||
|
gcry_mpi_t ecc_sk_mpi = NULL;
|
||||||
|
|
||||||
|
err = gcry_sexp_extract_param (s_skey, NULL, "/d", &ecc_sk_mpi, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: extracting d from ECC key failed\n", __func__);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits);
|
||||||
|
len = (nbits+7)/8;
|
||||||
|
if (len > ecc->scalar_len)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: ECC secret key too long (%zu)\n", __func__, len);
|
||||||
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
memset (ecc_sk, 0, ecc->scalar_len - len);
|
||||||
|
memcpy (ecc_sk + ecc->scalar_len - len, p, len);
|
||||||
|
if (ecc->scalar_reverse)
|
||||||
|
reverse_buffer (ecc_sk, ecc->scalar_len);
|
||||||
|
mpi_release (ecc_sk_mpi);
|
||||||
|
ecc_sk_mpi = NULL;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (ecc_sk, ecc->scalar_len, "ECC seckey:");
|
||||||
|
|
||||||
|
leave:
|
||||||
|
mpi_release (ecc_sk_mpi);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
ecc_raw_kem (const struct ecc_params *ecc, gcry_sexp_t s_skey,
|
||||||
|
const unsigned char *ecc_ct, unsigned char *ecc_ecdh)
|
||||||
|
{
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
unsigned char ecc_sk[ECC_SCALAR_LEN_MAX];
|
||||||
|
|
||||||
|
if (ecc->scalar_len > ECC_SCALAR_LEN_MAX)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: ECC scalar length invalid (%zu)\n",
|
||||||
|
__func__, ecc->scalar_len);
|
||||||
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ecc_extract_sk_from_key (ecc, s_skey, ecc_sk);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
err = gcry_kem_decap (ecc->kem_algo, ecc_sk, ecc->scalar_len,
|
||||||
|
ecc_ct, ecc->point_len, ecc_ecdh, ecc->point_len,
|
||||||
|
NULL, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: gcry_kem_decap for ECC failed\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
wipememory (ecc_sk, sizeof ecc_sk);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
get_cardkey (ctrl_t ctrl, const char *keygrip, gcry_sexp_t *r_s_pk)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned char *pkbuf;
|
||||||
|
size_t pkbuflen;
|
||||||
|
|
||||||
|
err = agent_card_readkey (ctrl, keygrip, &pkbuf, NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
|
||||||
|
err = gcry_sexp_sscan (r_s_pk, NULL, (char*)pkbuf, pkbuflen);
|
||||||
|
if (err)
|
||||||
|
log_error ("failed to build S-Exp from received card key: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
|
||||||
|
xfree (pkbuf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
ecc_get_curve (ctrl_t ctrl, gcry_sexp_t s_skey, const char **r_curve)
|
||||||
|
{
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
gcry_sexp_t s_skey_card = NULL;
|
||||||
|
const char *curve = NULL;
|
||||||
|
gcry_sexp_t key;
|
||||||
|
|
||||||
|
*r_curve = NULL;
|
||||||
|
|
||||||
|
if (!s_skey)
|
||||||
|
{
|
||||||
|
err = get_cardkey (ctrl, ctrl->keygrip, &s_skey_card);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
key = s_skey_card;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
key = s_skey;
|
||||||
|
|
||||||
|
curve = get_ecc_curve_from_key (key);
|
||||||
|
if (!curve)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_curve = curve;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
gcry_sexp_release (s_skey_card);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given a private key in SEXP by S_SKEY0 and a cipher text by ECC_CT
|
||||||
|
* with length ECC_POINT_LEN, do ECC-KEM operation. Result is
|
||||||
|
* returned in the memory referred by ECC_SS. Shared secret length is
|
||||||
|
* returned in the memory referred by R_SHARED_LEN. CTRL is used to
|
||||||
|
* access smartcard, internally. */
|
||||||
|
static gpg_error_t
|
||||||
|
ecc_pgp_kem_decrypt (ctrl_t ctrl, gcry_sexp_t s_skey0,
|
||||||
|
unsigned char *shadow_info0,
|
||||||
|
const unsigned char *ecc_ct, size_t ecc_point_len,
|
||||||
|
unsigned char *ecc_ss, size_t *r_shared_len)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned char ecc_ecdh[ECC_POINT_LEN_MAX];
|
||||||
|
unsigned char ecc_pk[ECC_POINT_LEN_MAX];
|
||||||
|
const char *curve;
|
||||||
|
const struct ecc_params *ecc = NULL;
|
||||||
|
|
||||||
|
if (ecc_point_len > ECC_POINT_LEN_MAX)
|
||||||
|
return gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
|
||||||
|
err = ecc_get_curve (ctrl, s_skey0, &curve);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|
||||||
|
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
||||||
|
&& !s_skey0)
|
||||||
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecc = get_ecc_params (curve);
|
||||||
|
if (!ecc)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: curve '%s' not supported\n", __func__, curve);
|
||||||
|
return gpg_error (GPG_ERR_BAD_SECKEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_shared_len = ecc->shared_len;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_debug ("ECC curve: %s\n", curve);
|
||||||
|
|
||||||
|
if (ecc->point_len != ecc_point_len)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: ECC cipher text length invalid (%zu != %zu)\n",
|
||||||
|
__func__, ecc->point_len, ecc_point_len);
|
||||||
|
return gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ecc_extract_pk_from_key (ecc, s_skey0, ecc_pk);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (ecc_ct, ecc->point_len, "ECC ephem:");
|
||||||
|
|
||||||
|
if (shadow_info0 || !s_skey0)
|
||||||
|
{
|
||||||
|
if (s_skey0 && agent_is_tpm2_key (s_skey0))
|
||||||
|
{
|
||||||
|
log_error ("TPM decryption failed: %s\n", gpg_strerror (err));
|
||||||
|
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = agent_card_ecc_kem (ctrl, ecc_ct, ecc->point_len, ecc_ecdh);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("smartcard decryption failed: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = ecc_raw_kem (ecc, s_skey0, ecc_ct, ecc_ecdh);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (ecc_ecdh, ecc_point_len, "ECC ecdh:");
|
||||||
|
|
||||||
|
err = gnupg_ecc_kem_kdf (ecc_ss, ecc->shared_len, ecc->hash_algo,
|
||||||
|
ecc_ecdh, ecc->point_len, ecc_ct, ecc->point_len,
|
||||||
|
ecc_pk, ecc->point_len);
|
||||||
|
|
||||||
|
wipememory (ecc_ecdh, sizeof ecc_ecdh);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: kdf for ECC failed\n", __func__);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
log_printhex (ecc_ss, ecc->shared_len, "ECC shared:");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For composite PGP KEM (ECC+ML-KEM), decrypt CIPHERTEXT using KEM API.
|
||||||
|
First keygrip is for ECC, second keygrip is for PQC. CIPHERTEXT
|
||||||
|
should follow the format of:
|
||||||
|
|
||||||
|
(enc-val(pqc(c%d)(e%m)(k%m)(s%m)(fixed-info&)))
|
||||||
|
c: cipher identifier (symmetric)
|
||||||
|
e: ECDH ciphertext
|
||||||
|
k: ML-KEM ciphertext
|
||||||
|
s: encrypted session key
|
||||||
|
fixed-info: A buffer with the fixed info.
|
||||||
|
|
||||||
|
FIXME: For now, possible keys on smartcard are not supported.
|
||||||
|
*/
|
||||||
|
static gpg_error_t
|
||||||
|
composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
|
||||||
|
gcry_sexp_t s_cipher, membuf_t *outbuf)
|
||||||
|
{
|
||||||
|
gcry_sexp_t s_skey0 = NULL;
|
||||||
|
gcry_sexp_t s_skey1 = NULL;
|
||||||
|
unsigned char *shadow_info0 = NULL;
|
||||||
|
unsigned char *shadow_info1 = NULL;
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
|
||||||
|
unsigned int nbits;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
int algo;
|
||||||
|
gcry_mpi_t encrypted_sessionkey_mpi = NULL;
|
||||||
|
const unsigned char *encrypted_sessionkey;
|
||||||
|
size_t encrypted_sessionkey_len;
|
||||||
|
|
||||||
|
gcry_mpi_t ecc_ct_mpi = NULL;
|
||||||
|
const unsigned char *ecc_ct;
|
||||||
|
size_t ecc_ct_len;
|
||||||
|
unsigned char ecc_ss[ECC_HASH_LEN_MAX];
|
||||||
|
size_t ecc_shared_len, ecc_point_len;
|
||||||
|
|
||||||
|
enum gcry_kem_algos mlkem_kem_algo;
|
||||||
|
gcry_mpi_t mlkem_sk_mpi = NULL;
|
||||||
|
gcry_mpi_t mlkem_ct_mpi = NULL;
|
||||||
|
const unsigned char *mlkem_sk;
|
||||||
|
size_t mlkem_sk_len;
|
||||||
|
const unsigned char *mlkem_ct;
|
||||||
|
size_t mlkem_ct_len;
|
||||||
|
unsigned char mlkem_ss[GCRY_KEM_MLKEM1024_SHARED_LEN];
|
||||||
|
size_t mlkem_ss_len;
|
||||||
|
|
||||||
|
unsigned char kek[32];
|
||||||
|
size_t kek_len = 32; /* AES-256 is mandatory */
|
||||||
|
|
||||||
|
gcry_cipher_hd_t hd;
|
||||||
|
unsigned char sessionkey[256];
|
||||||
|
size_t sessionkey_len;
|
||||||
|
gcry_buffer_t fixed_info = { 0, 0, 0, NULL };
|
||||||
|
|
||||||
|
err = agent_key_from_file (ctrl, NULL, desc_text,
|
||||||
|
ctrl->keygrip, &shadow_info0,
|
||||||
|
CACHE_MODE_NORMAL, NULL, &s_skey0, NULL, NULL);
|
||||||
|
if (err && gpg_err_code (err) != GPG_ERR_NO_SECKEY)
|
||||||
|
{
|
||||||
|
log_error ("failed to read the secret key\n");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = agent_key_from_file (ctrl, NULL, desc_text,
|
||||||
|
ctrl->keygrip1, &shadow_info1,
|
||||||
|
CACHE_MODE_NORMAL, NULL, &s_skey1, NULL, NULL);
|
||||||
|
/* Here assumes no smartcard for ML-KEM, but private key in a file. */
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to read the another secret key\n");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_sexp_extract_param (s_cipher, NULL, "%dc/eks&'fixed-info'",
|
||||||
|
&algo, &ecc_ct_mpi, &mlkem_ct_mpi,
|
||||||
|
&encrypted_sessionkey_mpi, &fixed_info, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: extracting parameters failed\n", __func__);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits);
|
||||||
|
ecc_ct_len = (nbits+7)/8;
|
||||||
|
|
||||||
|
len = gcry_cipher_get_algo_keylen (algo);
|
||||||
|
encrypted_sessionkey = gcry_mpi_get_opaque (encrypted_sessionkey_mpi, &nbits);
|
||||||
|
encrypted_sessionkey_len = (nbits+7)/8;
|
||||||
|
if (len == 0 || encrypted_sessionkey_len != len + 8)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: encrypted session key length %zu"
|
||||||
|
" does not match the length for algo %d\n",
|
||||||
|
__func__, encrypted_sessionkey_len, algo);
|
||||||
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firstly, ECC part. */
|
||||||
|
ecc_point_len = ecc_ct_len;
|
||||||
|
err = ecc_pgp_kem_decrypt (ctrl, s_skey0, shadow_info0, ecc_ct, ecc_point_len,
|
||||||
|
ecc_ss, &ecc_shared_len);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Secondly, PQC part. For now, we assume ML-KEM. */
|
||||||
|
err = gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: extracting s from PQ key failed\n", __func__);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
mlkem_sk = gcry_mpi_get_opaque (mlkem_sk_mpi, &nbits);
|
||||||
|
mlkem_sk_len = (nbits+7)/8;
|
||||||
|
if (mlkem_sk_len == GCRY_KEM_MLKEM512_SECKEY_LEN)
|
||||||
|
{
|
||||||
|
mlkem_kem_algo = GCRY_KEM_MLKEM512;
|
||||||
|
mlkem_ss_len = GCRY_KEM_MLKEM512_SHARED_LEN;
|
||||||
|
mlkem_ct_len = GCRY_KEM_MLKEM512_CIPHER_LEN;
|
||||||
|
}
|
||||||
|
else if (mlkem_sk_len == GCRY_KEM_MLKEM768_SECKEY_LEN)
|
||||||
|
{
|
||||||
|
mlkem_kem_algo = GCRY_KEM_MLKEM768;
|
||||||
|
mlkem_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN;
|
||||||
|
mlkem_ct_len = GCRY_KEM_MLKEM768_CIPHER_LEN;
|
||||||
|
}
|
||||||
|
else if (mlkem_sk_len == GCRY_KEM_MLKEM1024_SECKEY_LEN)
|
||||||
|
{
|
||||||
|
mlkem_kem_algo = GCRY_KEM_MLKEM1024;
|
||||||
|
mlkem_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN;
|
||||||
|
mlkem_ct_len = GCRY_KEM_MLKEM1024_CIPHER_LEN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: PQ key length invalid (%zu)\n", __func__, mlkem_sk_len);
|
||||||
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
mlkem_ct = gcry_mpi_get_opaque (mlkem_ct_mpi, &nbits);
|
||||||
|
len = (nbits+7)/8;
|
||||||
|
if (len != mlkem_ct_len)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: PQ cipher text length invalid (%zu)\n",
|
||||||
|
__func__, mlkem_ct_len);
|
||||||
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = gcry_kem_decap (mlkem_kem_algo, mlkem_sk, mlkem_sk_len,
|
||||||
|
mlkem_ct, mlkem_ct_len, mlkem_ss, mlkem_ss_len,
|
||||||
|
NULL, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: gcry_kem_decap for PQ failed\n", __func__);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpi_release (mlkem_sk_mpi);
|
||||||
|
mlkem_sk_mpi = NULL;
|
||||||
|
|
||||||
|
/* Then, combine two shared secrets and ciphertexts into one KEK */
|
||||||
|
err = gnupg_kem_combiner (kek, kek_len,
|
||||||
|
ecc_ss, ecc_shared_len, ecc_ct, ecc_point_len,
|
||||||
|
mlkem_ss, mlkem_ss_len, mlkem_ct, mlkem_ct_len,
|
||||||
|
fixed_info.data, fixed_info.size);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("%s: KEM combiner failed\n", __func__);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpi_release (ecc_ct_mpi);
|
||||||
|
ecc_ct_mpi = NULL;
|
||||||
|
mpi_release (mlkem_ct_mpi);
|
||||||
|
mlkem_ct_mpi = NULL;
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
{
|
||||||
|
log_printhex (kek, kek_len, "KEK key: ");
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256,
|
||||||
|
GCRY_CIPHER_MODE_AESWRAP, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_error ("ecdh failed to initialize AESWRAP: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_cipher_setkey (hd, kek, kek_len);
|
||||||
|
|
||||||
|
sessionkey_len = encrypted_sessionkey_len - 8;
|
||||||
|
err = gcry_cipher_decrypt (hd, sessionkey, sessionkey_len,
|
||||||
|
encrypted_sessionkey, encrypted_sessionkey_len);
|
||||||
|
gcry_cipher_close (hd);
|
||||||
|
|
||||||
|
mpi_release (encrypted_sessionkey_mpi);
|
||||||
|
encrypted_sessionkey_mpi = NULL;
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("KEM decrypt failed: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
put_membuf_printf (outbuf,
|
||||||
|
"(5:value%u:", (unsigned int)sessionkey_len);
|
||||||
|
put_membuf (outbuf, sessionkey, sessionkey_len);
|
||||||
|
put_membuf (outbuf, ")", 2);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
wipememory (ecc_ss, sizeof ecc_ss);
|
||||||
|
wipememory (mlkem_ss, sizeof mlkem_ss);
|
||||||
|
wipememory (kek, sizeof kek);
|
||||||
|
wipememory (sessionkey, sizeof sessionkey);
|
||||||
|
|
||||||
|
mpi_release (ecc_ct_mpi);
|
||||||
|
mpi_release (mlkem_sk_mpi);
|
||||||
|
mpi_release (mlkem_ct_mpi);
|
||||||
|
mpi_release (encrypted_sessionkey_mpi);
|
||||||
|
gcry_free (fixed_info.data);
|
||||||
|
gcry_sexp_release (s_skey0);
|
||||||
|
gcry_sexp_release (s_skey1);
|
||||||
|
xfree (shadow_info0);
|
||||||
|
xfree (shadow_info1);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DECRYPT the encrypted stuff (like encrypted session key) in
|
||||||
|
CIPHERTEXT using KEM API, with KEMID. Keys (or a key) are
|
||||||
|
specified in CTRL. DESC_TEXT is used to retrieve private key.
|
||||||
|
OPTION can be specified for upper layer option for KEM. Decrypted
|
||||||
|
stuff (like session key) is written to OUTBUF.
|
||||||
|
*/
|
||||||
|
gpg_error_t
|
||||||
|
agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
|
||||||
|
const unsigned char *ciphertext, size_t ciphertextlen,
|
||||||
|
const unsigned char *option, size_t optionlen,
|
||||||
|
membuf_t *outbuf)
|
||||||
|
{
|
||||||
|
gcry_sexp_t s_cipher = NULL;
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
|
||||||
|
/* For now, only PQC-PGP is supported. */
|
||||||
|
if (kemid != KEM_PQC_PGP)
|
||||||
|
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||||
|
|
||||||
|
(void)optionlen;
|
||||||
|
if (kemid == KEM_PQC_PGP && option)
|
||||||
|
{
|
||||||
|
log_error ("PQC-PGP requires no option\n");
|
||||||
|
return gpg_error (GPG_ERR_INV_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctrl->have_keygrip)
|
||||||
|
{
|
||||||
|
log_error ("speculative decryption not yet supported\n");
|
||||||
|
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctrl->have_keygrip1)
|
||||||
|
{
|
||||||
|
log_error ("Composite KEM requires two KEYGRIPs\n");
|
||||||
|
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to convert ciphertext: %s\n", gpg_strerror (err));
|
||||||
|
return gpg_error (GPG_ERR_INV_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DBG_CRYPTO)
|
||||||
|
{
|
||||||
|
log_printhex (ctrl->keygrip, 20, "keygrip0:");
|
||||||
|
log_printhex (ctrl->keygrip1, 20, "keygrip1:");
|
||||||
|
gcry_log_debugsxp ("cipher", s_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = composite_pgp_kem_decrypt (ctrl, desc_text, s_cipher, outbuf);
|
||||||
|
|
||||||
|
gcry_sexp_release (s_cipher);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -371,9 +371,17 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyref)
|
if (keyref && !ctrl->ephemeral_mode)
|
||||||
agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, 0);
|
{
|
||||||
|
char *dispserialno;
|
||||||
|
|
||||||
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
||||||
|
hexgrip);
|
||||||
|
agent_write_shadow_key (ctrl,
|
||||||
|
ctrl->keygrip, serialno, keyref, pkbuf,
|
||||||
|
0, dispserialno);
|
||||||
|
xfree (dispserialno);
|
||||||
|
}
|
||||||
algo = get_pk_algo_from_key (s_pkey);
|
algo = get_pk_algo_from_key (s_pkey);
|
||||||
|
|
||||||
xfree (serialno);
|
xfree (serialno);
|
||||||
|
|
|
@ -755,8 +755,9 @@ release_passphrase (char *pw)
|
||||||
|
|
||||||
/* Stub function. */
|
/* Stub function. */
|
||||||
int
|
int
|
||||||
agent_key_available (const unsigned char *grip)
|
agent_key_available (ctrl_t ctrl, const unsigned char *grip)
|
||||||
{
|
{
|
||||||
|
(void)ctrl;
|
||||||
(void)grip;
|
(void)grip;
|
||||||
return -1; /* Not available. */
|
return -1; /* Not available. */
|
||||||
}
|
}
|
||||||
|
@ -813,19 +814,21 @@ agent_askpin (ctrl_t ctrl,
|
||||||
|
|
||||||
/* Replacement for the function in findkey.c. Here we write the key
|
/* Replacement for the function in findkey.c. Here we write the key
|
||||||
* to stdout. */
|
* to stdout. */
|
||||||
int
|
gpg_error_t
|
||||||
agent_write_private_key (const unsigned char *grip,
|
agent_write_private_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
const void *buffer, size_t length, int force,
|
const void *buffer, size_t length, int force,
|
||||||
const char *serialno, const char *keyref,
|
const char *serialno, const char *keyref,
|
||||||
time_t timestamp)
|
const char *dispserialno, time_t timestamp)
|
||||||
{
|
{
|
||||||
char hexgrip[40+4+1];
|
char hexgrip[40+4+1];
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
(void)force;
|
(void)force;
|
||||||
(void)serialno;
|
(void)serialno;
|
||||||
(void)keyref;
|
(void)keyref;
|
||||||
(void)timestamp;
|
(void)timestamp;
|
||||||
|
(void)dispserialno;
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
strcpy (hexgrip+40, ".key");
|
strcpy (hexgrip+40, ".key");
|
||||||
|
|
|
@ -509,7 +509,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||||
((sha1 salt no_of_iterations) 16byte_iv)
|
((sha1 salt no_of_iterations) 16byte_iv)
|
||||||
encrypted_octet_string)
|
encrypted_octet_string)
|
||||||
|
|
||||||
in canoncical format of course. We use asprintf and %n modifier
|
in canonical format of course. We use asprintf and %n modifier
|
||||||
and dummy values as placeholders. */
|
and dummy values as placeholders. */
|
||||||
{
|
{
|
||||||
char countbuf[35];
|
char countbuf[35];
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "../common/sexp-parse.h"
|
#include "../common/sexp-parse.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When it's for ECC, fixup private key part in the cannonical SEXP
|
* When it's for ECC, fixup private key part in the canonical SEXP
|
||||||
* representation in BUF. If not ECC, do nothing.
|
* representation in BUF. If not ECC, do nothing.
|
||||||
*/
|
*/
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
|
|
|
@ -38,14 +38,14 @@ struct trustitem_s
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int disabled:1; /* This entry is disabled. */
|
unsigned int disabled:1; /* This entry is disabled. */
|
||||||
int for_pgp:1; /* Set by '*' or 'P' as first flag. */
|
unsigned int for_pgp:1; /* Set by '*' or 'P' as first flag. */
|
||||||
int for_smime:1; /* Set by '*' or 'S' as first flag. */
|
unsigned int for_smime:1; /* Set by '*' or 'S' as first flag. */
|
||||||
int relax:1; /* Relax checking of root certificate
|
unsigned int relax:1; /* Relax checking of root certificate
|
||||||
constraints. */
|
constraints. */
|
||||||
int cm:1; /* Use chain model for validation. */
|
unsigned int cm:1; /* Use chain model for validation. */
|
||||||
int qual:1; /* Root CA for qualified signatures. */
|
unsigned int qual:1; /* Root CA for qualified signatures. */
|
||||||
int de_vs:1; /* Root CA for de-vs compliant PKI. */
|
unsigned int de_vs:1; /* Root CA for de-vs compliant PKI. */
|
||||||
} flags;
|
} flags;
|
||||||
unsigned char fpr[20]; /* The binary fingerprint. */
|
unsigned char fpr[20]; /* The binary fingerprint. */
|
||||||
};
|
};
|
||||||
|
@ -63,7 +63,7 @@ static const char headerblurb[] =
|
||||||
"# well as empty lines are ignored. Lines have a length limit but this\n"
|
"# well as empty lines are ignored. Lines have a length limit but this\n"
|
||||||
"# is not a serious limitation as the format of the entries is fixed and\n"
|
"# is not a serious limitation as the format of the entries is fixed and\n"
|
||||||
"# checked by gpg-agent. A non-comment line starts with optional white\n"
|
"# checked by gpg-agent. A non-comment line starts with optional white\n"
|
||||||
"# space, followed by the SHA-1 fingerpint in hex, followed by a flag\n"
|
"# space, followed by the SHA-1 fingerprint in hex, followed by a flag\n"
|
||||||
"# which may be one of 'P', 'S' or '*' and optionally followed by a list of\n"
|
"# which may be one of 'P', 'S' or '*' and optionally followed by a list of\n"
|
||||||
"# other flags. The fingerprint may be prefixed with a '!' to mark the\n"
|
"# other flags. The fingerprint may be prefixed with a '!' to mark the\n"
|
||||||
"# key as not trusted. You should give the gpg-agent a HUP or run the\n"
|
"# key as not trusted. You should give the gpg-agent a HUP or run the\n"
|
||||||
|
@ -736,7 +736,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
||||||
insert a line break. The double percent sign is actually
|
insert a line break. The double percent sign is actually
|
||||||
needed because it is also a printf format string. If you
|
needed because it is also a printf format string. If you
|
||||||
need to insert a plain % sign, you need to encode it as
|
need to insert a plain % sign, you need to encode it as
|
||||||
"%%25". The second "%s" gets replaced by a hexdecimal
|
"%%25". The second "%s" gets replaced by a hexadecimal
|
||||||
fingerprint string whereas the first one receives the name
|
fingerprint string whereas the first one receives the name
|
||||||
as stored in the certificate. */
|
as stored in the certificate. */
|
||||||
L_("Please verify that the certificate identified as:%%0A"
|
L_("Please verify that the certificate identified as:%%0A"
|
||||||
|
|
|
@ -28,15 +28,24 @@ cvtver () {
|
||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: $(basename $0) [OPTIONS]
|
Usage: $(basename $0) [OPTIONS] [packages]
|
||||||
Get the online version of the GnuPG software version database
|
Get the online version of the GnuPG software version database
|
||||||
|
and optionally download packages and verify their signatures.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
--info Print only infos about packages
|
||||||
--skip-download Assume download has already been done.
|
--skip-download Assume download has already been done.
|
||||||
--skip-verify Do not check signatures
|
--skip-verify Do not check signatures
|
||||||
--skip-selfcheck Do not check GnuPG version
|
--skip-selfcheck Do not check GnuPG version
|
||||||
|
(default if not used in the GnuPG tree)
|
||||||
--find-sha1sum Print the name of the sha1sum utility
|
--find-sha1sum Print the name of the sha1sum utility
|
||||||
--find-sha256sum Print the name of the sha256sum utility
|
--find-sha256sum Print the name of the sha256sum utility
|
||||||
--help Print this help.
|
--help Print this help.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
getswdb.sh gnupg24 gpgme libksba libassuan
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
exit $1
|
exit $1
|
||||||
}
|
}
|
||||||
|
@ -49,6 +58,9 @@ skip_verify=no
|
||||||
skip_selfcheck=no
|
skip_selfcheck=no
|
||||||
find_sha1sum=no
|
find_sha1sum=no
|
||||||
find_sha256sum=no
|
find_sha256sum=no
|
||||||
|
info_mode=no
|
||||||
|
packages=
|
||||||
|
die=no
|
||||||
while test $# -gt 0; do
|
while test $# -gt 0; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
# Set up `optarg'.
|
# Set up `optarg'.
|
||||||
|
@ -79,13 +91,20 @@ while test $# -gt 0; do
|
||||||
--find-sha256sum)
|
--find-sha256sum)
|
||||||
find_sha256sum=yes
|
find_sha256sum=yes
|
||||||
;;
|
;;
|
||||||
*)
|
--info)
|
||||||
|
info_mode=yes
|
||||||
|
;;
|
||||||
|
--*)
|
||||||
usage 1 1>&2
|
usage 1 1>&2
|
||||||
;;
|
;;
|
||||||
|
*)
|
||||||
|
packages="$packages $1"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
# Mac OSX has only a shasum and not sha1sum
|
# Mac OSX has only a shasum and not sha1sum
|
||||||
if [ ${find_sha1sum} = yes ]; then
|
if [ ${find_sha1sum} = yes ]; then
|
||||||
for i in sha1sum shasum ; do
|
for i in sha1sum shasum ; do
|
||||||
|
@ -114,16 +133,37 @@ if [ ${find_sha256sum} = yes ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ $skip_verify = no ]; then
|
||||||
|
if [ ! -f "$distsigkey" ]; then
|
||||||
|
distsigkey="/usr/local/share/gnupg/distsigkey.gpg"
|
||||||
|
if [ ! -f "$distsigkey" ]; then
|
||||||
|
distsigkey="/usr/share/gnupg/distsigkey.gpg"
|
||||||
|
if [ ! -f "$distsigkey" ]; then
|
||||||
|
echo "no keyring with release keys found!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "using release keys from $distsigkey" >&2
|
||||||
|
skip_selfcheck=yes
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Get GnuPG version from VERSION file. For a GIT checkout this means
|
# Get GnuPG version from VERSION file. For a GIT checkout this means
|
||||||
# that ./autogen.sh must have been run first. For a regular tarball
|
# that ./autogen.sh must have been run first. For a regular tarball
|
||||||
# VERSION is always available.
|
# VERSION is always available.
|
||||||
if [ ! -f "$srcdir/../VERSION" ]; then
|
if [ $skip_selfcheck = no ]; then
|
||||||
|
if [ ! -f "$srcdir/../VERSION" ]; then
|
||||||
echo "VERSION file missing - run autogen.sh first." >&2
|
echo "VERSION file missing - run autogen.sh first." >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
fi
|
||||||
|
version=$(cat "$srcdir/../VERSION")
|
||||||
|
else
|
||||||
|
version="0.0.0"
|
||||||
fi
|
fi
|
||||||
version=$(cat "$srcdir/../VERSION")
|
|
||||||
version_num=$(echo "$version" | cvtver)
|
version_num=$(echo "$version" | cvtver)
|
||||||
|
|
||||||
|
|
||||||
if [ $skip_verify = no ]; then
|
if [ $skip_verify = no ]; then
|
||||||
if ! $GPGV --version >/dev/null 2>/dev/null ; then
|
if ! $GPGV --version >/dev/null 2>/dev/null ; then
|
||||||
echo "command \"gpgv\" is not installed" >&2
|
echo "command \"gpgv\" is not installed" >&2
|
||||||
|
@ -164,10 +204,10 @@ else
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [ $skip_verify = no ]; then
|
if [ $skip_verify = no ]; then
|
||||||
if ! $GPGV --keyring "$distsigkey" swdb.lst.sig swdb.lst; then
|
if ! $GPGV --keyring "$distsigkey" swdb.lst.sig swdb.lst 2>/dev/null; then
|
||||||
echo "list of software versions is not valid!" >&2
|
echo "list of software versions is not valid!" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -188,3 +228,73 @@ if [ $skip_selfcheck = no ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Download a package and check its signature.
|
||||||
|
download_pkg () {
|
||||||
|
local url="$1"
|
||||||
|
local file="${url##*/}"
|
||||||
|
|
||||||
|
if ! $WGET -q -O - "$url" >"${file}.tmp" ; then
|
||||||
|
echo "download of $file failed." >&2
|
||||||
|
[ -f "${file}.tmp" ] && rm "${file}.tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ $skip_verify = no ]; then
|
||||||
|
if ! $WGET -q -O - "${url}.sig" >"${file}.tmpsig" ; then
|
||||||
|
echo "download of $file.sig failed." >&2
|
||||||
|
[ -f "${file}.tmpsig" ] && rm "${file}.tmpsig"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if ! $GPGV -q --keyring "$distsigkey" \
|
||||||
|
"${file}.tmpsig" "${file}.tmp" 2>/dev/null; then
|
||||||
|
echo "signature of $file is not valid!" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
mv "${file}.tmpsig" "${file}.sig"
|
||||||
|
else
|
||||||
|
[ -f "${file}.sig" ] && rm "${file}.sig"
|
||||||
|
fi
|
||||||
|
mv "${file}.tmp" "${file}"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
baseurl=$(awk '$1=="gpgorg_base" {print $2; exit 0}' swdb.lst)
|
||||||
|
for p in $packages; do
|
||||||
|
pver=$(awk '$1=="'"$p"'_ver" {print $2}' swdb.lst)
|
||||||
|
if [ -z "$pver" ]; then
|
||||||
|
echo "package '$p' not found" >&2
|
||||||
|
die=yes
|
||||||
|
else
|
||||||
|
pdir=$(awk '$1=="'"$p"'_dir" {print $2":"$3":"$4}' swdb.lst)
|
||||||
|
if [ -n "$pdir" ]; then
|
||||||
|
psuf=$(echo "$pdir" | cut -d: -f3)
|
||||||
|
pname=$(echo "$pdir" | cut -d: -f2)
|
||||||
|
pdir=$(echo "$pdir" | cut -d: -f1)
|
||||||
|
else
|
||||||
|
psuf=
|
||||||
|
pdir="$p"
|
||||||
|
pname="$p"
|
||||||
|
fi
|
||||||
|
if [ -z "$psuf" ]; then
|
||||||
|
psuf=$(awk 'BEGIN {suf="bz2"};
|
||||||
|
$1=="'"$p"'_sha1_gz" {suf="gz"; exit 0};
|
||||||
|
$1=="'"$p"'_sha1_xz" {suf"xz"; exit 0};
|
||||||
|
END {print suf}' swdb.lst)
|
||||||
|
fi
|
||||||
|
pfullname="$pname-$pver.tar.$psuf"
|
||||||
|
if [ $info_mode = yes ]; then
|
||||||
|
echo "$baseurl/$pdir/$pfullname"
|
||||||
|
else
|
||||||
|
echo "downloading $pfullname"
|
||||||
|
download_pkg "$baseurl/$pdir/$pfullname" || die=yes
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $die = yes ]; then
|
||||||
|
echo "errors found!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
|
|
@ -43,67 +43,21 @@
|
||||||
#
|
#
|
||||||
# The information required to sign the tarballs and binaries
|
# The information required to sign the tarballs and binaries
|
||||||
# are expected in the developer specific file ~/.gnupg-autogen.rc".
|
# are expected in the developer specific file ~/.gnupg-autogen.rc".
|
||||||
# Here is an example:
|
# Use "gpg-authcode-sign.sh --template" to create a template.
|
||||||
#--8<---------------cut here---------------start------------->8---
|
|
||||||
# # Location of the released tarball archives. Note that this is an
|
|
||||||
# # internal archive and before uploading this to the public server,
|
|
||||||
# # manual tests should be run and the git release tagged and pushed.
|
|
||||||
# # This is greped by the Makefile.
|
|
||||||
# RELEASE_ARCHIVE=foo@somehost:tarball-archive
|
|
||||||
#
|
|
||||||
# # The key used to sign the released sources.
|
|
||||||
# # This is greped by the Makefile.
|
|
||||||
# RELEASE_SIGNKEY=6DAA6E64A76D2840571B4902528897B826403ADA
|
|
||||||
#
|
|
||||||
# # For signing Windows binaries we need to employ a Windows machine.
|
|
||||||
# # We connect to this machine via ssh and take the connection
|
|
||||||
# # parameters via .ssh/config. For example a VM could be specified
|
|
||||||
# # like this:
|
|
||||||
# #
|
|
||||||
# # Host authenticode-signhost
|
|
||||||
# # HostName localhost
|
|
||||||
# # Port 27042
|
|
||||||
# # User gpgsign
|
|
||||||
# #
|
|
||||||
# # Depending on the used token it might be necessary to allow single
|
|
||||||
# # signon and unlock the token before running the make. The following
|
|
||||||
# # variable references this entry. This is greped by the Makefile.
|
|
||||||
# AUTHENTICODE_SIGNHOST=authenticode-signhost
|
|
||||||
#
|
|
||||||
# # The name of the signtool as used on Windows.
|
|
||||||
# # This is greped by the Makefile.
|
|
||||||
# AUTHENTICODE_TOOL="C:\Program Files (x86)\Windows Kits\10\bin\signtool.exe"
|
|
||||||
#
|
|
||||||
# # To use osslsigncode the follwing entries are required and
|
|
||||||
# # an empty string must be given for AUTHENTICODE_SIGNHOST.
|
|
||||||
# # They are greped by the Makefile.
|
|
||||||
# AUTHENTICODE_KEY=/home/foo/.gnupg/my-authenticode-key.p12
|
|
||||||
# AUTHENTICODE_CERTS=/home/foo/.gnupg/my-authenticode-certs.pem
|
|
||||||
#
|
|
||||||
# # If a smartcard is used for the Authenticode signature these
|
|
||||||
# # entries are required instead:
|
|
||||||
# AUTHENTICODE_KEY=card
|
|
||||||
# AUTHENTICODE_CERTS=/home/foo/.gnupg/my_authenticode_cert.pem
|
|
||||||
# OSSLSIGNCODE=/usr/bin/osslsigncode
|
|
||||||
# OSSLPKCS11ENGINE=/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so
|
|
||||||
# SCUTEMODULE=/usr/local/lib/scute.so
|
|
||||||
#
|
|
||||||
#--8<---------------cut here---------------end--------------->8---
|
|
||||||
|
|
||||||
|
|
||||||
# We need to know our own name.
|
# We need to know our own name.
|
||||||
SPEEDO_MK := $(realpath $(lastword $(MAKEFILE_LIST)))
|
SPEEDO_MK := $(realpath $(lastword $(MAKEFILE_LIST)))
|
||||||
|
|
||||||
.PHONY : help native native-gui w32-installer w32-source w32-wixlib
|
.PHONY : help native w32-installer w32-source w32-wixlib
|
||||||
.PHONY : git-native git-native-gui git-w32-installer git-w32-source
|
.PHONY : git-native git-w32-installer git-w32-source
|
||||||
.PHONY : this-native this-native-gui this-w32-installer this-w32-source
|
.PHONY : this-native this-w32-installer this-w32-source
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo 'usage: make -f speedo.mk TARGET'
|
@echo 'usage: make -f speedo.mk TARGET'
|
||||||
@echo ' with TARGET being one of:'
|
@echo ' with TARGET being one of:'
|
||||||
@echo ' help This help'
|
@echo ' help This help'
|
||||||
@echo ' native Native build of the GnuPG core'
|
@echo ' native Native build of the GnuPG core'
|
||||||
@echo ' native-gui Ditto but with pinentry and GPA'
|
|
||||||
@echo ' w32-installer Build a Windows installer'
|
@echo ' w32-installer Build a Windows installer'
|
||||||
@echo ' w32-source Pack a source archive'
|
@echo ' w32-source Pack a source archive'
|
||||||
@echo ' w32-release Build a Windows release'
|
@echo ' w32-release Build a Windows release'
|
||||||
|
@ -114,11 +68,12 @@ help:
|
||||||
@echo 'Prepend TARGET with "git-" to build from GIT repos.'
|
@echo 'Prepend TARGET with "git-" to build from GIT repos.'
|
||||||
@echo 'Prepend TARGET with "this-" to build from the source tarball.'
|
@echo 'Prepend TARGET with "this-" to build from the source tarball.'
|
||||||
@echo 'Use STATIC=1 to build with statically linked libraries.'
|
@echo 'Use STATIC=1 to build with statically linked libraries.'
|
||||||
@echo 'Use SELFCHECK=0 for a non-released version.'
|
@echo 'Use SELFCHECK=1 for additional check of the gnupg version.'
|
||||||
@echo 'Use CUSTOM_SWDB=1 for an already downloaded swdb.lst.'
|
@echo 'Use CUSTOM_SWDB=1 for an already downloaded swdb.lst.'
|
||||||
@echo 'Use WIXPREFIX to provide the WIX binaries for the MSI package.'
|
@echo 'Use WIXPREFIX to provide the WIX binaries for the MSI package.'
|
||||||
@echo ' Using WIX also requires wine with installed wine mono.'
|
@echo ' Using WIX also requires wine with installed wine mono.'
|
||||||
@echo ' See help-wixlib for more information'
|
@echo ' See help-wixlib for more information'
|
||||||
|
@echo 'Set W32VERSION=w64 to build a 64 bit Windows version.'
|
||||||
|
|
||||||
help-wixlib:
|
help-wixlib:
|
||||||
@echo 'The buildsystem can create a wixlib to build MSI packages.'
|
@echo 'The buildsystem can create a wixlib to build MSI packages.'
|
||||||
|
@ -148,66 +103,52 @@ help-wixlib:
|
||||||
SPEEDOMAKE := $(MAKE) -f $(SPEEDO_MK) UPD_SWDB=1
|
SPEEDOMAKE := $(MAKE) -f $(SPEEDO_MK) UPD_SWDB=1
|
||||||
|
|
||||||
native: check-tools
|
native: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=native WHAT=release WITH_GUI=0 all
|
$(SPEEDOMAKE) TARGETOS=native WHAT=release all
|
||||||
|
|
||||||
git-native: check-tools
|
git-native: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=native WHAT=git WITH_GUI=0 all
|
$(SPEEDOMAKE) TARGETOS=native WHAT=git all
|
||||||
|
|
||||||
this-native: check-tools
|
this-native: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=native WHAT=this WITH_GUI=0 all
|
$(SPEEDOMAKE) TARGETOS=native WHAT=this all
|
||||||
|
|
||||||
native-gui: check-tools
|
|
||||||
$(SPEEDOMAKE) TARGETOS=native WHAT=release WITH_GUI=1 all
|
|
||||||
|
|
||||||
git-native-gui: check-tools
|
|
||||||
$(SPEEDOMAKE) TARGETOS=native WHAT=git WITH_GUI=1 all
|
|
||||||
|
|
||||||
this-native-gui: check-tools
|
|
||||||
$(SPEEDOMAKE) TARGETOS=native WHAT=this WITH_GUI=1 all
|
|
||||||
|
|
||||||
w32-installer: check-tools
|
w32-installer: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 installer
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release installer
|
||||||
|
|
||||||
git-w32-installer: check-tools
|
git-w32-installer: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 installer
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git installer
|
||||||
|
|
||||||
this-w32-installer: check-tools
|
this-w32-installer: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 installer
|
||||||
CUSTOM_SWDB=1 installer
|
|
||||||
w32-wixlib: check-tools
|
w32-wixlib: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 wixlib
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release wixlib
|
||||||
|
|
||||||
git-w32-wixlib: check-tools
|
git-w32-wixlib: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 wixlib
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git wixlib
|
||||||
|
|
||||||
this-w32-wixlib: check-tools
|
this-w32-wixlib: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 wixlib
|
||||||
CUSTOM_SWDB=1 wixlib
|
|
||||||
|
|
||||||
w32-source: check-tools
|
w32-source: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 dist-source
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release dist-source
|
||||||
|
|
||||||
git-w32-source: check-tools
|
git-w32-source: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 dist-source
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git dist-source
|
||||||
|
|
||||||
this-w32-source: check-tools
|
this-w32-source: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 dist-source
|
||||||
CUSTOM_SWDB=1 dist-source
|
|
||||||
|
|
||||||
w32-release: check-tools
|
w32-release: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release installer-from-source
|
||||||
installer-from-source
|
|
||||||
|
|
||||||
w32-msi-release: check-tools
|
w32-msi-release: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release \
|
||||||
WITH_WIXLIB=1 installer-from-source
|
WITH_WIXLIB=1 installer-from-source
|
||||||
|
|
||||||
w32-sign-installer: check-tools
|
w32-sign-installer: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release sign-installer
|
||||||
sign-installer
|
|
||||||
|
|
||||||
w32-release-offline: check-tools
|
w32-release-offline: check-tools
|
||||||
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
|
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release \
|
||||||
CUSTOM_SWDB=1 pkgrep=${HOME}/b pkg10rep=${HOME}/b \
|
CUSTOM_SWDB=1 pkgrep=${HOME}/b pkg10rep=${HOME}/b \
|
||||||
installer-from-source
|
installer-from-source
|
||||||
|
|
||||||
|
@ -217,11 +158,11 @@ w32-release-offline: check-tools
|
||||||
# to "this" from the unpacked sources.
|
# to "this" from the unpacked sources.
|
||||||
WHAT=git
|
WHAT=git
|
||||||
|
|
||||||
# Set target to "native" or "w32"
|
# Set target to "native" or "w32".
|
||||||
TARGETOS=
|
TARGETOS=
|
||||||
|
|
||||||
# Set to 1 to build the GUI tools
|
# To build a 64 bit Windows version also change this to "w64"
|
||||||
WITH_GUI=0
|
W32VERSION=w32
|
||||||
|
|
||||||
# Set to 1 to use a pre-installed swdb.lst instead of the online version.
|
# Set to 1 to use a pre-installed swdb.lst instead of the online version.
|
||||||
CUSTOM_SWDB=0
|
CUSTOM_SWDB=0
|
||||||
|
@ -229,8 +170,8 @@ CUSTOM_SWDB=0
|
||||||
# Set to 1 to really download the swdb.
|
# Set to 1 to really download the swdb.
|
||||||
UPD_SWDB=0
|
UPD_SWDB=0
|
||||||
|
|
||||||
# Set to 0 to skip the GnuPG version self-check
|
# Set to 1 to run an additional GnuPG version check
|
||||||
SELFCHECK=1
|
SELFCHECK=0
|
||||||
|
|
||||||
# Set to 1 to build with statically linked libraries.
|
# Set to 1 to build with statically linked libraries.
|
||||||
STATIC=0
|
STATIC=0
|
||||||
|
@ -240,28 +181,26 @@ STATIC=0
|
||||||
TARBALLS=$(shell pwd)/../tarballs
|
TARBALLS=$(shell pwd)/../tarballs
|
||||||
|
|
||||||
# Number of parallel make jobs for each package
|
# Number of parallel make jobs for each package
|
||||||
MAKE_J=3
|
MAKE_J=6
|
||||||
|
|
||||||
# Name to use for the w32 installer and sources
|
# Name to use for the w32 installer and sources
|
||||||
|
|
||||||
|
|
||||||
INST_NAME=gnupg-w32
|
INST_NAME=gnupg-w32
|
||||||
|
|
||||||
# Use this to override the installaion directory for native builds.
|
# Use this to override the installation directory for native builds.
|
||||||
INSTALL_PREFIX=none
|
INSTALL_PREFIX=none
|
||||||
|
|
||||||
# Set this to the location of wixtools
|
# Set this to the location of wixtools
|
||||||
WIXPREFIX=$(shell readlink -f ~/w32root/wixtools)
|
WIXPREFIX=$(shell readlink -f ~/w32root/wixtools)
|
||||||
|
|
||||||
|
# If patchelf(1) is not available disable the command.
|
||||||
|
PATCHELF := $(shell patchelf --version 2>/dev/null >/dev/null || echo "echo please run: ")patchelf
|
||||||
|
|
||||||
# Read signing information from ~/.gnupg-autogen.rc
|
# Read signing information from ~/.gnupg-autogen.rc
|
||||||
define READ_AUTOGEN_template
|
define READ_AUTOGEN_template
|
||||||
$(1) = $$(shell grep '^$(1)=' $$$$HOME/.gnupg-autogen.rc|cut -d= -f2)
|
$(1) = $$(shell grep '^[[:blank:]]*$(1)[[:blank:]]*=' $$$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs)
|
||||||
endef
|
endef
|
||||||
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_SIGNHOST))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_TOOL))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_KEY))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_CERTS))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,OSSLSIGNCODE))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,OSSLPKCS11ENGINE))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,SCUTEMODULE))
|
|
||||||
$(eval $(call READ_AUTOGEN_template,OVERRIDE_TARBALLS))
|
$(eval $(call READ_AUTOGEN_template,OVERRIDE_TARBALLS))
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,6 +221,7 @@ AUTHENTICODE_FILES= \
|
||||||
gpgtar.exe \
|
gpgtar.exe \
|
||||||
gpgv.exe \
|
gpgv.exe \
|
||||||
gpg-card.exe \
|
gpg-card.exe \
|
||||||
|
keyboxd.exe \
|
||||||
libassuan-0.dll \
|
libassuan-0.dll \
|
||||||
libgcrypt-20.dll \
|
libgcrypt-20.dll \
|
||||||
libgpg-error-0.dll \
|
libgpg-error-0.dll \
|
||||||
|
@ -318,60 +258,16 @@ w32src := $(topsrc)/build-aux/speedo/w32
|
||||||
# Fixme: Do we need to build pkg-config for cross-building?
|
# Fixme: Do we need to build pkg-config for cross-building?
|
||||||
|
|
||||||
speedo_spkgs = \
|
speedo_spkgs = \
|
||||||
libgpg-error npth libgcrypt
|
libgpg-error npth libgcrypt \
|
||||||
|
zlib bzip2 sqlite \
|
||||||
ifeq ($(TARGETOS),w32)
|
libassuan libksba ntbtls gnupg
|
||||||
speedo_spkgs += \
|
|
||||||
zlib bzip2 sqlite
|
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
speedo_spkgs += gettext libiconv
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
speedo_spkgs += \
|
|
||||||
libassuan libksba
|
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
speedo_spkgs += \
|
|
||||||
ntbtls
|
|
||||||
endif
|
|
||||||
|
|
||||||
speedo_spkgs += \
|
|
||||||
gnupg
|
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
speedo_spkgs += \
|
|
||||||
libffi glib pkg-config
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(STATIC),0)
|
ifeq ($(STATIC),0)
|
||||||
speedo_spkgs += \
|
speedo_spkgs += gpgme
|
||||||
gpgme
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
ifeq ($(TARGETOS),w32)
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
speedo_spkgs += \
|
|
||||||
libpng \
|
|
||||||
gdk-pixbuf atk pixman cairo pango gtk+
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
|
|
||||||
speedo_spkgs += pinentry
|
speedo_spkgs += pinentry
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
speedo_spkgs += gpa gpgex
|
|
||||||
endif
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
speedo_spkgs += pinentry gpa
|
|
||||||
endif
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -381,16 +277,18 @@ endif
|
||||||
# Packages which are additionally build for 64 bit Windows. They are
|
# Packages which are additionally build for 64 bit Windows. They are
|
||||||
# only used for gpgex and thus we need to build them only if we want
|
# only used for gpgex and thus we need to build them only if we want
|
||||||
# a full installer.
|
# a full installer.
|
||||||
speedo_w64_spkgs =
|
ifeq ($(W32VERSION),w64)
|
||||||
ifeq ($(WITH_GUI),1)
|
# Keep this empty
|
||||||
speedo_w64_spkgs += libgpg-error libiconv gettext libassuan gpgex
|
speedo_w64_spkgs =
|
||||||
|
else
|
||||||
|
speedo_w64_spkgs =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Packages which use the gnupg autogen.sh build style
|
# Packages which use the gnupg autogen.sh build style
|
||||||
speedo_gnupg_style = \
|
speedo_gnupg_style = \
|
||||||
libgpg-error npth libgcrypt \
|
libgpg-error npth libgcrypt \
|
||||||
libassuan libksba ntbtls gnupg gpgme \
|
libassuan libksba ntbtls gnupg gpgme \
|
||||||
pinentry gpa gpgex
|
pinentry
|
||||||
|
|
||||||
# Packages which use only make and no build directory
|
# Packages which use only make and no build directory
|
||||||
speedo_make_only_style = \
|
speedo_make_only_style = \
|
||||||
|
@ -416,7 +314,7 @@ endif
|
||||||
# Version numbers of the released packages
|
# Version numbers of the released packages
|
||||||
gnupg_ver_this = $(shell cat $(topsrc)/VERSION)
|
gnupg_ver_this = $(shell cat $(topsrc)/VERSION)
|
||||||
|
|
||||||
gnupg_ver := $(shell awk '$$1=="gnupg24_ver" {print $$2}' swdb.lst)
|
gnupg_ver := $(shell awk '$$1=="gnupg26_ver" {print $$2}' swdb.lst)
|
||||||
|
|
||||||
libgpg_error_ver := $(shell awk '$$1=="libgpg_error_ver" {print $$2}' swdb.lst)
|
libgpg_error_ver := $(shell awk '$$1=="libgpg_error_ver" {print $$2}' swdb.lst)
|
||||||
libgpg_error_sha1:= $(shell awk '$$1=="libgpg_error_sha1" {print $$2}' swdb.lst)
|
libgpg_error_sha1:= $(shell awk '$$1=="libgpg_error_sha1" {print $$2}' swdb.lst)
|
||||||
|
@ -450,14 +348,6 @@ pinentry_ver := $(shell awk '$$1=="pinentry_ver" {print $$2}' swdb.lst)
|
||||||
pinentry_sha1 := $(shell awk '$$1=="pinentry_sha1" {print $$2}' swdb.lst)
|
pinentry_sha1 := $(shell awk '$$1=="pinentry_sha1" {print $$2}' swdb.lst)
|
||||||
pinentry_sha2 := $(shell awk '$$1=="pinentry_sha2" {print $$2}' swdb.lst)
|
pinentry_sha2 := $(shell awk '$$1=="pinentry_sha2" {print $$2}' swdb.lst)
|
||||||
|
|
||||||
gpa_ver := $(shell awk '$$1=="gpa_ver" {print $$2}' swdb.lst)
|
|
||||||
gpa_sha1 := $(shell awk '$$1=="gpa_sha1" {print $$2}' swdb.lst)
|
|
||||||
gpa_sha2 := $(shell awk '$$1=="gpa_sha2" {print $$2}' swdb.lst)
|
|
||||||
|
|
||||||
gpgex_ver := $(shell awk '$$1=="gpgex_ver" {print $$2}' swdb.lst)
|
|
||||||
gpgex_sha1 := $(shell awk '$$1=="gpgex_sha1" {print $$2}' swdb.lst)
|
|
||||||
gpgex_sha2 := $(shell awk '$$1=="gpgex_sha2" {print $$2}' swdb.lst)
|
|
||||||
|
|
||||||
zlib_ver := $(shell awk '$$1=="zlib_ver" {print $$2}' swdb.lst)
|
zlib_ver := $(shell awk '$$1=="zlib_ver" {print $$2}' swdb.lst)
|
||||||
zlib_sha1 := $(shell awk '$$1=="zlib_sha1_gz" {print $$2}' swdb.lst)
|
zlib_sha1 := $(shell awk '$$1=="zlib_sha1_gz" {print $$2}' swdb.lst)
|
||||||
zlib_sha2 := $(shell awk '$$1=="zlib_sha2_gz" {print $$2}' swdb.lst)
|
zlib_sha2 := $(shell awk '$$1=="zlib_sha2_gz" {print $$2}' swdb.lst)
|
||||||
|
@ -471,9 +361,9 @@ sqlite_sha1 := $(shell awk '$$1=="sqlite_sha1_gz" {print $$2}' swdb.lst)
|
||||||
sqlite_sha2 := $(shell awk '$$1=="sqlite_sha2_gz" {print $$2}' swdb.lst)
|
sqlite_sha2 := $(shell awk '$$1=="sqlite_sha2_gz" {print $$2}' swdb.lst)
|
||||||
|
|
||||||
|
|
||||||
$(info Information from the version database)
|
$(info Information from the version database:)
|
||||||
$(info GnuPG ..........: $(gnupg_ver) (building $(gnupg_ver_this)))
|
$(info GnuPG ..........: $(gnupg_ver) (building $(gnupg_ver_this)))
|
||||||
$(info Libgpg-error ...: $(libgpg_error_ver))
|
$(info GpgRT ..........: $(libgpg_error_ver))
|
||||||
$(info Npth ...........: $(npth_ver))
|
$(info Npth ...........: $(npth_ver))
|
||||||
$(info Libgcrypt ......: $(libgcrypt_ver))
|
$(info Libgcrypt ......: $(libgcrypt_ver))
|
||||||
$(info Libassuan ......: $(libassuan_ver))
|
$(info Libassuan ......: $(libassuan_ver))
|
||||||
|
@ -484,23 +374,28 @@ $(info SQLite .........: $(sqlite_ver))
|
||||||
$(info NtbTLS .. ......: $(ntbtls_ver))
|
$(info NtbTLS .. ......: $(ntbtls_ver))
|
||||||
$(info GPGME ..........: $(gpgme_ver))
|
$(info GPGME ..........: $(gpgme_ver))
|
||||||
$(info Pinentry .......: $(pinentry_ver))
|
$(info Pinentry .......: $(pinentry_ver))
|
||||||
$(info GPA ............: $(gpa_ver))
|
|
||||||
$(info GpgEX.... ......: $(gpgex_ver))
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$(info Information for this run:)
|
||||||
|
$(info Build type .....: $(WHAT))
|
||||||
|
$(info Target .........: $(TARGETOS))
|
||||||
|
ifeq ($(TARGETOS),w32)
|
||||||
|
ifeq ($(W32VERSION),w64)
|
||||||
|
$(info Windows version : 64 bit)
|
||||||
|
else
|
||||||
|
$(info Windows version : 32 bit)
|
||||||
|
ifneq ($(W32VERSION),w32)
|
||||||
|
$(error W32VERSION is not set to a proper value: Use only w32 or w64)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Version number for external packages
|
# Version number for external packages
|
||||||
pkg_config_ver = 0.23
|
pkg_config_ver = 0.23
|
||||||
libiconv_ver = 1.14
|
libiconv_ver = 1.14
|
||||||
gettext_ver = 0.18.2.1
|
gettext_ver = 0.18.2.1
|
||||||
libffi_ver = 3.0.13
|
|
||||||
glib_ver = 2.34.3
|
|
||||||
libpng_ver = 1.4.12
|
|
||||||
gdk_pixbuf_ver = 2.26.5
|
|
||||||
atk_ver = 1.32.0
|
|
||||||
pango_ver = 1.29.4
|
|
||||||
pixman_ver = 0.32.4
|
|
||||||
cairo_ver = 1.12.16
|
|
||||||
gtk__ver = 2.24.17
|
|
||||||
|
|
||||||
# The GIT repository. Using a local repo is much faster.
|
# The GIT repository. Using a local repo is much faster.
|
||||||
#gitrep = git://git.gnupg.org
|
#gitrep = git://git.gnupg.org
|
||||||
|
@ -551,10 +446,6 @@ else ifeq ($(WHAT),git)
|
||||||
speedo_pkg_gpgme_gitref = master
|
speedo_pkg_gpgme_gitref = master
|
||||||
speedo_pkg_pinentry_git = $(gitrep)/pinentry
|
speedo_pkg_pinentry_git = $(gitrep)/pinentry
|
||||||
speedo_pkg_pinentry_gitref = master
|
speedo_pkg_pinentry_gitref = master
|
||||||
speedo_pkg_gpa_git = $(gitrep)/gpa
|
|
||||||
speedo_pkg_gpa_gitref = master
|
|
||||||
speedo_pkg_gpgex_git = $(gitrep)/gpgex
|
|
||||||
speedo_pkg_gpgex_gitref = master
|
|
||||||
else ifeq ($(WHAT),release)
|
else ifeq ($(WHAT),release)
|
||||||
speedo_pkg_libgpg_error_tar = \
|
speedo_pkg_libgpg_error_tar = \
|
||||||
$(pkgrep)/libgpg-error/libgpg-error-$(libgpg_error_ver).tar.bz2
|
$(pkgrep)/libgpg-error/libgpg-error-$(libgpg_error_ver).tar.bz2
|
||||||
|
@ -572,10 +463,6 @@ else ifeq ($(WHAT),release)
|
||||||
$(pkgrep)/gpgme/gpgme-$(gpgme_ver).tar.bz2
|
$(pkgrep)/gpgme/gpgme-$(gpgme_ver).tar.bz2
|
||||||
speedo_pkg_pinentry_tar = \
|
speedo_pkg_pinentry_tar = \
|
||||||
$(pkgrep)/pinentry/pinentry-$(pinentry_ver).tar.bz2
|
$(pkgrep)/pinentry/pinentry-$(pinentry_ver).tar.bz2
|
||||||
speedo_pkg_gpa_tar = \
|
|
||||||
$(pkgrep)/gpa/gpa-$(gpa_ver).tar.bz2
|
|
||||||
speedo_pkg_gpgex_tar = \
|
|
||||||
$(pkg10rep)/gpgex/gpgex-$(gpgex_ver).tar.bz2
|
|
||||||
else
|
else
|
||||||
$(error invalid value for WHAT (use on of: git release this))
|
$(error invalid value for WHAT (use on of: git release this))
|
||||||
endif
|
endif
|
||||||
|
@ -586,15 +473,6 @@ speedo_pkg_bzip2_tar = $(pkgrep)/bzip2/bzip2-$(bzip2_ver).tar.gz
|
||||||
speedo_pkg_sqlite_tar = $(pkgrep)/sqlite/sqlite-autoconf-$(sqlite_ver).tar.gz
|
speedo_pkg_sqlite_tar = $(pkgrep)/sqlite/sqlite-autoconf-$(sqlite_ver).tar.gz
|
||||||
speedo_pkg_libiconv_tar = $(pkg2rep)/libiconv-$(libiconv_ver).tar.gz
|
speedo_pkg_libiconv_tar = $(pkg2rep)/libiconv-$(libiconv_ver).tar.gz
|
||||||
speedo_pkg_gettext_tar = $(pkg2rep)/gettext-$(gettext_ver).tar.gz
|
speedo_pkg_gettext_tar = $(pkg2rep)/gettext-$(gettext_ver).tar.gz
|
||||||
speedo_pkg_libffi_tar = $(pkg2rep)/libffi-$(libffi_ver).tar.gz
|
|
||||||
speedo_pkg_glib_tar = $(pkg2rep)/glib-$(glib_ver).tar.xz
|
|
||||||
speedo_pkg_libpng_tar = $(pkg2rep)/libpng-$(libpng_ver).tar.bz2
|
|
||||||
speedo_pkg_gdk_pixbuf_tar = $(pkg2rep)/gdk-pixbuf-$(gdk_pixbuf_ver).tar.xz
|
|
||||||
speedo_pkg_atk_tar = $(pkg2rep)/atk-$(atk_ver).tar.bz2
|
|
||||||
speedo_pkg_pango_tar = $(pkg2rep)/pango-$(pango_ver).tar.bz2
|
|
||||||
speedo_pkg_pixman_tar = $(pkg2rep)/pixman-$(pixman_ver).tar.gz
|
|
||||||
speedo_pkg_cairo_tar = $(pkg2rep)/cairo-$(cairo_ver).tar.xz
|
|
||||||
speedo_pkg_gtk__tar = $(pkg2rep)/gtk+-$(gtk__ver).tar.xz
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -603,8 +481,8 @@ speedo_pkg_gtk__tar = $(pkg2rep)/gtk+-$(gtk__ver).tar.xz
|
||||||
|
|
||||||
speedo_pkg_npth_configure = --enable-static
|
speedo_pkg_npth_configure = --enable-static
|
||||||
|
|
||||||
speedo_pkg_libgpg_error_configure = --enable-static --enable-install-gpg-error-config
|
speedo_pkg_libgpg_error_configure = --enable-static
|
||||||
speedo_pkg_w64_libgpg_error_configure = --enable-static --enable-install-gpg-error-config
|
speedo_pkg_w64_libgpg_error_configure = --enable-static
|
||||||
|
|
||||||
speedo_pkg_libassuan_configure = --enable-static
|
speedo_pkg_libassuan_configure = --enable-static
|
||||||
speedo_pkg_w64_libassuan_configure = --enable-static
|
speedo_pkg_w64_libassuan_configure = --enable-static
|
||||||
|
@ -637,7 +515,7 @@ speedo_pkg_gnupg_configure = \
|
||||||
else
|
else
|
||||||
speedo_pkg_gnupg_configure = --disable-g13 --enable-wks-tools
|
speedo_pkg_gnupg_configure = --disable-g13 --enable-wks-tools
|
||||||
endif
|
endif
|
||||||
speedo_pkg_gnupg_extracflags = -g
|
speedo_pkg_gnupg_extracflags =
|
||||||
|
|
||||||
# Create the version info files only for W32 so that they won't get
|
# Create the version info files only for W32 so that they won't get
|
||||||
# installed if for example INSTALL_PREFIX=/usr/local is used.
|
# installed if for example INSTALL_PREFIX=/usr/local is used.
|
||||||
|
@ -650,25 +528,13 @@ define speedo_pkg_gnupg_post_install
|
||||||
endef
|
endef
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# The LDFLAGS is needed for -lintl for glib.
|
# The LDFLAGS was needed for -lintl for glib.
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
speedo_pkg_gpgme_configure = \
|
|
||||||
--enable-static --enable-w32-glib \
|
|
||||||
--with-gpg-error-prefix=$(idir) \
|
|
||||||
LDFLAGS=-L$(idir)/lib
|
|
||||||
else
|
|
||||||
speedo_pkg_gpgme_configure = \
|
speedo_pkg_gpgme_configure = \
|
||||||
--disable-static --disable-w32-glib \
|
--disable-static --disable-w32-glib \
|
||||||
--with-gpg-error-prefix=$(idir) \
|
--with-gpg-error-prefix=$(idir) \
|
||||||
LDFLAGS=-L$(idir)/lib
|
LDFLAGS=-L$(idir)/lib
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
speedo_pkg_pinentry_configure = --disable-pinentry-gtk2
|
|
||||||
else
|
|
||||||
speedo_pkg_pinentry_configure = --enable-pinentry-gtk2
|
|
||||||
endif
|
|
||||||
speedo_pkg_pinentry_configure += \
|
speedo_pkg_pinentry_configure += \
|
||||||
--disable-pinentry-qt5 \
|
--disable-pinentry-qt5 \
|
||||||
--disable-pinentry-qt \
|
--disable-pinentry-qt \
|
||||||
|
@ -679,22 +545,6 @@ speedo_pkg_pinentry_configure += \
|
||||||
CXXFLAGS=-static-libstdc++
|
CXXFLAGS=-static-libstdc++
|
||||||
|
|
||||||
|
|
||||||
speedo_pkg_gpa_configure = \
|
|
||||||
--with-libiconv-prefix=$(idir) --with-libintl-prefix=$(idir) \
|
|
||||||
--with-gpgme-prefix=$(idir) --with-zlib=$(idir) \
|
|
||||||
--with-libassuan-prefix=$(idir) --with-gpg-error-prefix=$(idir)
|
|
||||||
|
|
||||||
speedo_pkg_gpgex_configure = \
|
|
||||||
--with-gpg-error-prefix=$(idir) \
|
|
||||||
--with-libassuan-prefix=$(idir) \
|
|
||||||
--enable-gpa-only
|
|
||||||
|
|
||||||
speedo_pkg_w64_gpgex_configure = \
|
|
||||||
--with-gpg-error-prefix=$(idir6) \
|
|
||||||
--with-libassuan-prefix=$(idir6) \
|
|
||||||
--enable-gpa-only
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# External packages
|
# External packages
|
||||||
#
|
#
|
||||||
|
@ -758,74 +608,31 @@ speedo_pkg_gettext_extracflags = -O2
|
||||||
speedo_pkg_gettext_make_dir = gettext-runtime
|
speedo_pkg_gettext_make_dir = gettext-runtime
|
||||||
|
|
||||||
|
|
||||||
speedo_pkg_glib_configure = \
|
|
||||||
--disable-modular-tests \
|
|
||||||
--with-libiconv=gnu \
|
|
||||||
CPPFLAGS=-I$(idir)/include \
|
|
||||||
LDFLAGS=-L$(idir)/lib \
|
|
||||||
CCC=$(host)-g++ \
|
|
||||||
LIBFFI_CFLAGS=-I$(idir)/lib/libffi-$(libffi_ver)/include \
|
|
||||||
LIBFFI_LIBS=\"-L$(idir)/lib -lffi\"
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
speedo_pkg_glib_extracflags = -march=i486
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
speedo_pkg_libpng_configure = \
|
|
||||||
CPPFLAGS=\"-I$(idir)/include -DPNG_BUILD_DLL\" \
|
|
||||||
LDFLAGS=\"-L$(idir)/lib\" LIBPNG_DEFINES=\"-DPNG_BUILD_DLL\"
|
|
||||||
else
|
|
||||||
speedo_pkg_libpng_configure = \
|
|
||||||
CPPFLAGS=\"-I$(idir)/include\" \
|
|
||||||
LDFLAGS=\"-L$(idir)/lib\"
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(TARGETOS),w32)
|
|
||||||
speedo_pkg_gdk_pixbuf_configure = --without-libtiff --without-libjpeg
|
|
||||||
endif
|
|
||||||
|
|
||||||
speedo_pkg_pixman_configure = \
|
|
||||||
CPPFLAGS=-I$(idir)/include \
|
|
||||||
LDFLAGS=-L$(idir)/lib
|
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
|
||||||
speedo_pkg_cairo_configure = \
|
|
||||||
--disable-qt --disable-ft --disable-fc \
|
|
||||||
--enable-win32 --enable-win32-font \
|
|
||||||
CPPFLAGS=-I$(idir)/include \
|
|
||||||
LDFLAGS=-L$(idir)/lib
|
|
||||||
else
|
|
||||||
speedo_pkg_cairo_configure = \
|
|
||||||
--disable-qt \
|
|
||||||
CPPFLAGS=-I$(idir)/include \
|
|
||||||
LDFLAGS=-L$(idir)/lib
|
|
||||||
endif
|
|
||||||
|
|
||||||
speedo_pkg_pango_configure = \
|
|
||||||
--disable-gtk-doc \
|
|
||||||
CPPFLAGS=-I$(idir)/include \
|
|
||||||
LDFLAGS=-L$(idir)/lib
|
|
||||||
|
|
||||||
speedo_pkg_gtk__configure = \
|
|
||||||
--disable-cups \
|
|
||||||
CPPFLAGS=-I$(idir)/include \
|
|
||||||
LDFLAGS=-L$(idir)/lib
|
|
||||||
|
|
||||||
|
|
||||||
# ---------
|
# ---------
|
||||||
|
|
||||||
all: all-speedo
|
all: all-speedo
|
||||||
|
|
||||||
|
install: install-speedo
|
||||||
|
|
||||||
report: report-speedo
|
report: report-speedo
|
||||||
|
|
||||||
clean: clean-speedo
|
clean: clean-speedo
|
||||||
|
|
||||||
|
|
||||||
|
ifeq ($(W32VERSION),w64)
|
||||||
|
W32CC_PREFIX = x86_64
|
||||||
|
else
|
||||||
|
W32CC_PREFIX = i686
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(TARGETOS),w32)
|
ifeq ($(TARGETOS),w32)
|
||||||
STRIP = i686-w64-mingw32-strip
|
STRIP = $(W32CC_PREFIX)-w64-mingw32-strip
|
||||||
|
W32STRIP32 = i686-w64-mingw32-strip
|
||||||
else
|
else
|
||||||
STRIP = strip
|
STRIP = strip
|
||||||
endif
|
endif
|
||||||
W32CC = i686-w64-mingw32-gcc
|
W32CC = $(W32CC_PREFIX)-w64-mingw32-gcc
|
||||||
|
W32CC32 = i686-w64-mingw32-gcc
|
||||||
|
|
||||||
-include config.mk
|
-include config.mk
|
||||||
|
|
||||||
|
@ -867,9 +674,9 @@ ifneq ($(TARGETOS),)
|
||||||
# Determine build and host system
|
# Determine build and host system
|
||||||
build := $(shell $(topsrc)/autogen.sh --silent --print-build)
|
build := $(shell $(topsrc)/autogen.sh --silent --print-build)
|
||||||
ifeq ($(TARGETOS),w32)
|
ifeq ($(TARGETOS),w32)
|
||||||
speedo_autogen_buildopt := --build-w32
|
speedo_autogen_buildopt := --build-$(W32VERSION)
|
||||||
speedo_autogen_buildopt6 := --build-w64
|
speedo_autogen_buildopt6 := --build-w64
|
||||||
host := $(shell $(topsrc)/autogen.sh --silent --print-host --build-w32)
|
host := $(shell $(topsrc)/autogen.sh --silent --print-host --build-$(W32VERSION))
|
||||||
host6:= $(shell $(topsrc)/autogen.sh --silent --print-host --build-w64)
|
host6:= $(shell $(topsrc)/autogen.sh --silent --print-host --build-w64)
|
||||||
speedo_host_build_option := --host=$(host) --build=$(build)
|
speedo_host_build_option := --host=$(host) --build=$(build)
|
||||||
speedo_host_build_option6 := --host=$(host6) --build=$(build)
|
speedo_host_build_option6 := --host=$(host6) --build=$(build)
|
||||||
|
@ -1093,7 +900,7 @@ else ifneq ($(findstring $(1),$(speedo_gnupg_style)),)
|
||||||
mkdir "$$$${pkgbdir}"; \
|
mkdir "$$$${pkgbdir}"; \
|
||||||
cd "$$$${pkgbdir}"; \
|
cd "$$$${pkgbdir}"; \
|
||||||
if [ -n "$(speedo_autogen_buildopt)" ]; then \
|
if [ -n "$(speedo_autogen_buildopt)" ]; then \
|
||||||
eval AUTOGEN_SH_SILENT=1 w32root="$(idir)" \
|
eval AUTOGEN_SH_SILENT=1 $(W32VERSION)root="$(idir)" \
|
||||||
"$$$${pkgsdir}/autogen.sh" \
|
"$$$${pkgsdir}/autogen.sh" \
|
||||||
$(speedo_autogen_buildopt) \
|
$(speedo_autogen_buildopt) \
|
||||||
$$$${pkgcfg} $$$${pkgextracflags}; \
|
$$$${pkgcfg} $$$${pkgextracflags}; \
|
||||||
|
@ -1285,6 +1092,71 @@ clean-pkg-versions:
|
||||||
@: >$(bdir)/pkg-versions.txt
|
@: >$(bdir)/pkg-versions.txt
|
||||||
|
|
||||||
all-speedo: $(stampdir)/stamp-final
|
all-speedo: $(stampdir)/stamp-final
|
||||||
|
ifneq ($(TARGETOS),w32)
|
||||||
|
@(set -e;\
|
||||||
|
cd "$(idir)"; \
|
||||||
|
echo "speedo: Making RPATH relative";\
|
||||||
|
for d in bin sbin libexec lib; do \
|
||||||
|
for f in $$(find $$d -type f); do \
|
||||||
|
if file $$f | grep ELF >/dev/null; then \
|
||||||
|
$(PATCHELF) --set-rpath '$$ORIGIN/../lib' $$f; \
|
||||||
|
fi; \
|
||||||
|
done; \
|
||||||
|
done; \
|
||||||
|
echo "sysconfdir = /etc/gnupg" >bin/gpgconf.ctl ;\
|
||||||
|
echo "rootdir = $(idir)" >>bin/gpgconf.ctl ;\
|
||||||
|
echo "speedo: /*" ;\
|
||||||
|
echo "speedo: * Now copy $(idir)/ to the final location and" ;\
|
||||||
|
echo "speedo: * adjust $(idir)/bin/gpgconf.ctl accordingly" ;\
|
||||||
|
echo "speedo: * Or run:" ;\
|
||||||
|
echo "speedo: * make -f $(topsrc)/build-aux/speedo.mk install SYSROOT=/usr/local/gnupg26" ;\
|
||||||
|
echo "speedo: * ldconfig -n /usr/local/gnupg26/lib";\
|
||||||
|
echo "speedo: */")
|
||||||
|
endif
|
||||||
|
|
||||||
|
# No dependencies for the install target; instead we test whether
|
||||||
|
# some of the to be installed files are available. This avoids
|
||||||
|
# accidental rebuilds under a wrong account.
|
||||||
|
install-speedo:
|
||||||
|
ifneq ($(TARGETOS),w32)
|
||||||
|
@(set -e; \
|
||||||
|
cd "$(idir)"; \
|
||||||
|
if [ x"$$SYSROOT" = x ]; then \
|
||||||
|
echo "speedo: ERROR: SYSROOT has not been given";\
|
||||||
|
echo "speedo: Set SYSROOT to the desired install directory";\
|
||||||
|
echo "speedo: Example:";\
|
||||||
|
echo "speedo: make -f $(topsrc)/build-aux/speedo.mk install SYSROOT=/usr/local/gnupg26";\
|
||||||
|
echo "speedo: ldconfig -n /usr/local/gnupg26/lib";\
|
||||||
|
exit 1;\
|
||||||
|
fi;\
|
||||||
|
if [ ! -d "$$SYSROOT"/bin ]; then if ! mkdir "$$SYSROOT"/bin; then \
|
||||||
|
echo "speedo: error creating target directory";\
|
||||||
|
exit 1;\
|
||||||
|
fi; fi;\
|
||||||
|
if ! touch "$$SYSROOT"/bin/gpgconf.ctl; then \
|
||||||
|
echo "speedo: Error writing $$SYSROOT/bin/gpgconf.ctl";\
|
||||||
|
echo "speedo: Please check the permissions";\
|
||||||
|
exit 1;\
|
||||||
|
fi;\
|
||||||
|
if [ ! -f bin/gpgconf.ctl ]; then \
|
||||||
|
echo "speedo: ERROR: Nothing to install";\
|
||||||
|
echo "speedo: Please run a build first";\
|
||||||
|
echo "speedo: Example:";\
|
||||||
|
echo "speedo: make -f build-aux/speedo.mk native";\
|
||||||
|
exit 1;\
|
||||||
|
fi;\
|
||||||
|
echo "speedo: Installing files to $$SYSROOT";\
|
||||||
|
find . -type f -executable \
|
||||||
|
-exec install -Dm 755 "{}" "$$SYSROOT/{}" \; ;\
|
||||||
|
find . -type f \! -executable \
|
||||||
|
-exec install -Dm 644 "{}" "$$SYSROOT/{}" \; ;\
|
||||||
|
echo "sysconfdir = /etc/gnupg" > "$$SYSROOT"/bin/gpgconf.ctl ;\
|
||||||
|
echo "rootdir = $$SYSROOT" >> "$$SYSROOT"/bin/gpgconf.ctl ;\
|
||||||
|
echo '/*' ;\
|
||||||
|
echo " * Installation to $$SYSROOT done" ;\
|
||||||
|
echo ' */' )
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
report-speedo: $(addprefix report-,$(speedo_build_list))
|
report-speedo: $(addprefix report-,$(speedo_build_list))
|
||||||
|
|
||||||
|
@ -1342,13 +1214,13 @@ $(bdir)/README.txt: $(bdir)/NEWS.tmp $(topsrc)/README $(w32src)/README.txt \
|
||||||
|
|
||||||
$(bdir)/g4wihelp.dll: $(w32src)/g4wihelp.c $(w32src)/exdll.h $(w32src)/exdll.c
|
$(bdir)/g4wihelp.dll: $(w32src)/g4wihelp.c $(w32src)/exdll.h $(w32src)/exdll.c
|
||||||
(set -e; cd $(bdir); \
|
(set -e; cd $(bdir); \
|
||||||
$(W32CC) -DUNICODE -static-libgcc -I . -O2 -c \
|
$(W32CC32) -DUNICODE -static-libgcc -I . -O2 -c \
|
||||||
-o exdll.o $(w32src)/exdll.c; \
|
-o exdll.o $(w32src)/exdll.c; \
|
||||||
$(W32CC) -DUNICODE -static-libgcc -I. -shared -O2 \
|
$(W32CC32) -DUNICODE -static-libgcc -I. -shared -O2 \
|
||||||
-o g4wihelp.dll $(w32src)/g4wihelp.c exdll.o \
|
-o g4wihelp.dll $(w32src)/g4wihelp.c exdll.o \
|
||||||
-lwinmm -lgdi32 -luserenv \
|
-lwinmm -lgdi32 -luserenv \
|
||||||
-lshell32 -loleaut32 -lshlwapi -lmsimg32; \
|
-lshell32 -loleaut32 -lshlwapi -lmsimg32; \
|
||||||
$(STRIP) g4wihelp.dll)
|
$(W32STRIP32) g4wihelp.dll)
|
||||||
|
|
||||||
w32_insthelpers: $(bdir)/g4wihelp.dll
|
w32_insthelpers: $(bdir)/g4wihelp.dll
|
||||||
|
|
||||||
|
@ -1356,9 +1228,6 @@ $(bdir)/inst-options.ini: $(w32src)/inst-options.ini
|
||||||
cat $(w32src)/inst-options.ini >$(bdir)/inst-options.ini
|
cat $(w32src)/inst-options.ini >$(bdir)/inst-options.ini
|
||||||
|
|
||||||
extra_installer_options =
|
extra_installer_options =
|
||||||
ifeq ($(WITH_GUI),1)
|
|
||||||
extra_installer_options += -DWITH_GUI=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Note that we sign only when doing the final installer.
|
# Note that we sign only when doing the final installer.
|
||||||
installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
|
installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
|
||||||
|
@ -1447,7 +1316,7 @@ wixlib: installer $(bdir)/README.txt $(w32src)/wixlib.wxs
|
||||||
)
|
)
|
||||||
|
|
||||||
define MKSWDB_commands
|
define MKSWDB_commands
|
||||||
( pref="#+macro: gnupg24_w32_$(3)" ;\
|
( pref="#+macro: gnupg26_w32_$(3)" ;\
|
||||||
echo "$${pref}ver $(INST_VERSION)_$(BUILD_DATESTR)" ;\
|
echo "$${pref}ver $(INST_VERSION)_$(BUILD_DATESTR)" ;\
|
||||||
echo "$${pref}date $(2)" ;\
|
echo "$${pref}date $(2)" ;\
|
||||||
echo "$${pref}size $$(wc -c <$(1)|awk '{print int($$1/1024)}')k";\
|
echo "$${pref}size $$(wc -c <$(1)|awk '{print int($$1/1024)}')k";\
|
||||||
|
@ -1458,35 +1327,13 @@ endef
|
||||||
|
|
||||||
# Sign the file $1 and save the result as $2
|
# Sign the file $1 and save the result as $2
|
||||||
define AUTHENTICODE_sign
|
define AUTHENTICODE_sign
|
||||||
set -e;\
|
(set -e; \
|
||||||
if [ -n "$(AUTHENTICODE_SIGNHOST)" ]; then \
|
if gpg-authcode-sign.sh --version >/dev/null; then \
|
||||||
echo "speedo: Signing via host $(AUTHENTICODE_SIGNHOST)";\
|
gpg-authcode-sign.sh "$(1)" "$(2)"; \
|
||||||
scp $(1) "$(AUTHENTICODE_SIGNHOST):a.exe" ;\
|
|
||||||
ssh "$(AUTHENTICODE_SIGNHOST)" '$(AUTHENTICODE_TOOL)' sign \
|
|
||||||
/a /n '"g10 Code GmbH"' \
|
|
||||||
/tr 'http://rfc3161timestamp.globalsign.com/advanced' /td sha256 \
|
|
||||||
/fd sha256 /du https://gnupg.org a.exe ;\
|
|
||||||
scp "$(AUTHENTICODE_SIGNHOST):a.exe" $(2);\
|
|
||||||
echo "speedo: signed file is '$(2)'" ;\
|
|
||||||
elif [ "$(AUTHENTICODE_KEY)" = card ]; then \
|
|
||||||
echo "speedo: Signing using a card: '$(1)'";\
|
|
||||||
$(OSSLSIGNCODE) sign \
|
|
||||||
-pkcs11engine $(OSSLPKCS11ENGINE) \
|
|
||||||
-pkcs11module $(SCUTEMODULE) \
|
|
||||||
-certs $(AUTHENTICODE_CERTS) \
|
|
||||||
-h sha256 -n GnuPG -i https://gnupg.org \
|
|
||||||
-ts http://rfc3161timestamp.globalsign.com/advanced \
|
|
||||||
-in $(1) -out $(2).tmp ; mv $(2).tmp $(2) ; \
|
|
||||||
elif [ -e "$(AUTHENTICODE_KEY)" ]; then \
|
|
||||||
echo "speedo: Signing using key $(AUTHENTICODE_KEY)";\
|
|
||||||
osslsigncode sign -certs $(AUTHENTICODE_CERTS) \
|
|
||||||
-pkcs12 $(AUTHENTICODE_KEY) -askpass \
|
|
||||||
-ts "http://timestamp.globalsign.com/scripts/timstamp.dll" \
|
|
||||||
-h sha256 -n GnuPG -i https://gnupg.org \
|
|
||||||
-in $(1) -out $(2) ;\
|
|
||||||
else \
|
else \
|
||||||
echo "speedo: WARNING: Binaries are not signed"; \
|
echo 2>&1 "warning: Please install gpg-authcode-sign.sh to sign files." ;\
|
||||||
fi
|
[ "$(1)" != "$(2)" ] && cp "$(1)" "$(2)" ;\
|
||||||
|
fi)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
# Help target for testing to sign a file.
|
# Help target for testing to sign a file.
|
||||||
|
@ -1543,10 +1390,8 @@ sign-installer:
|
||||||
if [ -f "$${msifile}" ]; then \
|
if [ -f "$${msifile}" ]; then \
|
||||||
$(call MKSWDB_commands,$${msifile},$${reldate},"wixlib_"); \
|
$(call MKSWDB_commands,$${msifile},$${reldate},"wixlib_"); \
|
||||||
fi; \
|
fi; \
|
||||||
echo "speedo: /*" ;\
|
echo "speedo: /* (osslsigncode verify disabled) */" ;\
|
||||||
echo "speedo: * Verification result" ;\
|
echo osslsigncode verify $${exefile} \
|
||||||
echo "speedo: */" ;\
|
|
||||||
osslsigncode verify $${exefile} \
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1556,7 +1401,7 @@ endif
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Check availibility of standard tools and prepare everything.
|
# Check availability of standard tools and prepare everything.
|
||||||
#
|
#
|
||||||
check-tools: $(stampdir)/stamp-directories
|
check-tools: $(stampdir)/stamp-directories
|
||||||
|
|
||||||
|
@ -1566,4 +1411,4 @@ check-tools: $(stampdir)/stamp-directories
|
||||||
# Mark phony targets
|
# Mark phony targets
|
||||||
#
|
#
|
||||||
.PHONY: all all-speedo report-speedo clean-stamps clean-speedo installer \
|
.PHONY: all all-speedo report-speedo clean-stamps clean-speedo installer \
|
||||||
w32_insthelpers check-tools clean-pkg-versions
|
w32_insthelpers check-tools clean-pkg-versions install-speedo install
|
||||||
|
|
|
@ -60,7 +60,7 @@ Below is the README file as distributed with the GnuPG source.
|
||||||
4. Software Versions of the Included Packages
|
4. Software Versions of the Included Packages
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
GnuPG for Windows depends on several independet developed packages
|
GnuPG for Windows depends on several independent developed packages
|
||||||
which are part of the installation. These packages along with their
|
which are part of the installation. These packages along with their
|
||||||
version numbers and the SHA-1 checksums of their compressed tarballs
|
version numbers and the SHA-1 checksums of their compressed tarballs
|
||||||
are listed here:
|
are listed here:
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
************************************************************
|
************************************************************
|
||||||
* The code for the splash screen has been taken from the Splash
|
* The code for the splash screen has been taken from the Splash
|
||||||
* plugin of the NSIS 2.04 distribution. That code comes without
|
* plugin of the NSIS 2.04 distribution. That code comes without
|
||||||
* explicit copyright notices in tyhe source files or author names, it
|
* explicit copyright notices in the source files or author names, it
|
||||||
* seems that it has been written by Justin Frankel; not sure about
|
* seems that it has been written by Justin Frankel; not sure about
|
||||||
* the year, though. [wk 2005-11-28]
|
* the year, though. [wk 2005-11-28]
|
||||||
*
|
*
|
||||||
|
|
|
@ -46,7 +46,7 @@ Unicode true
|
||||||
!define PRETTY_PACKAGE "GNU Privacy Guard"
|
!define PRETTY_PACKAGE "GNU Privacy Guard"
|
||||||
!define PRETTY_PACKAGE_SHORT "GnuPG"
|
!define PRETTY_PACKAGE_SHORT "GnuPG"
|
||||||
!define COMPANY "The GnuPG Project"
|
!define COMPANY "The GnuPG Project"
|
||||||
!define COPYRIGHT "Copyright (C) 2021 g10 Code GmbH"
|
!define COPYRIGHT "Copyright (C) 2024 g10 Code GmbH"
|
||||||
!define DESCRIPTION "GnuPG: The GNU Privacy Guard for Windows"
|
!define DESCRIPTION "GnuPG: The GNU Privacy Guard for Windows"
|
||||||
|
|
||||||
!define INSTALL_DIR "GnuPG"
|
!define INSTALL_DIR "GnuPG"
|
||||||
|
@ -63,13 +63,13 @@ Unicode true
|
||||||
GnuPG includes an advanced key management facility and is compliant \
|
GnuPG includes an advanced key management facility and is compliant \
|
||||||
with the OpenPGP Internet standard as described in RFC-4880. \
|
with the OpenPGP Internet standard as described in RFC-4880. \
|
||||||
\r\n\r\n$_CLICK \
|
\r\n\r\n$_CLICK \
|
||||||
\r\n\r\n\r\n\r\n\r\nThis is GnuPG version ${VERSION}.\r\n\
|
\r\n\r\n\r\n\r\n\r\nThis is GnuPG version ${VERSION} (64 bit).\r\n\
|
||||||
File version: ${PROD_VERSION}\r\n\
|
File version: ${PROD_VERSION}\r\n\
|
||||||
Release date: ${BUILD_ISODATE}"
|
Release date: ${BUILD_ISODATE}"
|
||||||
!define ABOUT_GERMAN \
|
!define ABOUT_GERMAN \
|
||||||
"GnuPG is die häufigst verwendete Software zur Mail- und Datenverschlüsselung.\
|
"GnuPG is die häufigst verwendete Software zur Mail- und Datenverschlüsselung.\
|
||||||
\r\n\r\n$_CLICK \
|
\r\n\r\n$_CLICK \
|
||||||
\r\n\r\n\r\n\r\n\r\nDies ist GnuPG Version ${VERSION}.\r\n\
|
\r\n\r\n\r\n\r\n\r\nDies ist GnuPG Version ${VERSION} (64 bit).\r\n\
|
||||||
Dateiversion: ${PROD_VERSION}\r\n\
|
Dateiversion: ${PROD_VERSION}\r\n\
|
||||||
Releasedatum: ${BUILD_ISODATE}"
|
Releasedatum: ${BUILD_ISODATE}"
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ OutFile "${NAME}-${VERSION}_${BUILD_DATESTR}.exe"
|
||||||
!ifndef INSTALL_DIR
|
!ifndef INSTALL_DIR
|
||||||
!define INSTALL_DIR "GnuPG"
|
!define INSTALL_DIR "GnuPG"
|
||||||
!endif
|
!endif
|
||||||
InstallDir "$PROGRAMFILES\${INSTALL_DIR}"
|
InstallDir "$PROGRAMFILES64\${INSTALL_DIR}"
|
||||||
|
|
||||||
# Add version information to the file properties.
|
# Add version information to the file properties.
|
||||||
VIProductVersion "${PROD_VERSION}"
|
VIProductVersion "${PROD_VERSION}"
|
||||||
|
@ -1067,9 +1067,7 @@ Section "-un.gnupglast"
|
||||||
nsExec::ExecToLog '"$INSTDIR\bin\launch-gpa" "--stop-server"'
|
nsExec::ExecToLog '"$INSTDIR\bin\launch-gpa" "--stop-server"'
|
||||||
no_uiserver:
|
no_uiserver:
|
||||||
ifFileExists "$INSTDIR\bin\gpgconf.exe" 0 no_gpgconf
|
ifFileExists "$INSTDIR\bin\gpgconf.exe" 0 no_gpgconf
|
||||||
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "gpg-agent"'
|
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "all"'
|
||||||
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "dirmngr"'
|
|
||||||
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "keyboxd"'
|
|
||||||
no_gpgconf:
|
no_gpgconf:
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
|
@ -1467,7 +1465,12 @@ Function .onInit
|
||||||
|
|
||||||
Call G4wRunOnce
|
Call G4wRunOnce
|
||||||
|
|
||||||
SetOutPath $TEMP
|
${IfNot} ${RunningX64}
|
||||||
|
MessageBox MB_OK "Sorry this version runs only on x64 machines"
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
SetOutPath $TEMP
|
||||||
#!ifdef SOURCES
|
#!ifdef SOURCES
|
||||||
# File /oname=gpgspltmp.bmp "${TOP_SRCDIR}/doc/logo/gnupg-logo-400px.bmp"
|
# File /oname=gpgspltmp.bmp "${TOP_SRCDIR}/doc/logo/gnupg-logo-400px.bmp"
|
||||||
# # We play the tune only for the soruce installer
|
# # We play the tune only for the soruce installer
|
||||||
|
@ -1488,7 +1491,7 @@ Function .onInit
|
||||||
|
|
||||||
Var /GLOBAL changed_dir
|
Var /GLOBAL changed_dir
|
||||||
# Check if the install directory was modified on the command line
|
# Check if the install directory was modified on the command line
|
||||||
StrCmp "$INSTDIR" "$PROGRAMFILES\${INSTALL_DIR}" unmodified 0
|
StrCmp "$INSTDIR" "$PROGRAMFILES64\${INSTALL_DIR}" unmodified 0
|
||||||
# It is modified. Save that value.
|
# It is modified. Save that value.
|
||||||
StrCpy $changed_dir "$INSTDIR"
|
StrCpy $changed_dir "$INSTDIR"
|
||||||
|
|
||||||
|
|
|
@ -61,9 +61,12 @@ and then manually edited:
|
||||||
<Component Id="cmp74961776CCC7B203F500FE261DC12F92" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4B">
|
<Component Id="cmp74961776CCC7B203F500FE261DC12F92" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4B">
|
||||||
<File Id="filB82A767EB9971018C006215A9FDE77EF" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-connect-agent.exe"/>
|
<File Id="filB82A767EB9971018C006215A9FDE77EF" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-connect-agent.exe"/>
|
||||||
</Component>
|
</Component>
|
||||||
<Component Id="cmp74961776CCC7B203F500FE261DC12F94" Directory="dirAA72FFDDFA224FB221D53750596B0144" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4C">
|
<Component Id="cmp74961776CCC7B203F500FE261DC12F94" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4C">
|
||||||
<File Id="filB82A767EB9971018C006215A9FDE77F1" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-card.exe"/>
|
<File Id="filB82A767EB9971018C006215A9FDE77F1" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-card.exe"/>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component Id="cmp74961776CCC7B203F500FE261DC12F95" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="3134BF55-46AF-4B76-A535-DC1EDDB0DBFD">
|
||||||
|
<File Id="filB82A767EB9971018C006215A9FDE77F2" KeyPath="yes" Source="$(var.SourceDir)\libexec\keyboxd.exe"/>
|
||||||
|
</Component>
|
||||||
<Component Id="cmp6C1FB70721B208E33DB24296B93AB93F" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FE29D2AA-3151-4421-B8C0-355F69F267A1">
|
<Component Id="cmp6C1FB70721B208E33DB24296B93AB93F" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FE29D2AA-3151-4421-B8C0-355F69F267A1">
|
||||||
<File Id="fil563D2C0464DCE7ECADE6E15C0FC65821" KeyPath="yes" Source="$(var.SourceDir)\libexec\gpg-preset-passphrase.exe"/>
|
<File Id="fil563D2C0464DCE7ECADE6E15C0FC65821" KeyPath="yes" Source="$(var.SourceDir)\libexec\gpg-preset-passphrase.exe"/>
|
||||||
</Component>
|
</Component>
|
||||||
|
|
|
@ -58,14 +58,14 @@ common_sources = \
|
||||||
openpgpdefs.h \
|
openpgpdefs.h \
|
||||||
gc-opt-flags.h \
|
gc-opt-flags.h \
|
||||||
sexp-parse.h \
|
sexp-parse.h \
|
||||||
tlv.c tlv.h tlv-builder.c \
|
tlv.c tlv.h tlv-builder.c tlv-parser.c \
|
||||||
init.c init.h \
|
init.c init.h \
|
||||||
sexputil.c \
|
sexputil.c \
|
||||||
sysutils.c sysutils.h \
|
sysutils.c sysutils.h \
|
||||||
homedir.c \
|
homedir.c \
|
||||||
gettime.c gettime.h \
|
gettime.c gettime.h \
|
||||||
yesno.c \
|
yesno.c \
|
||||||
b64enc.c b64dec.c zb32.c zb32.h \
|
zb32.c zb32.h \
|
||||||
convert.c \
|
convert.c \
|
||||||
percent.c \
|
percent.c \
|
||||||
mbox-util.c mbox-util.h \
|
mbox-util.c mbox-util.h \
|
||||||
|
@ -97,8 +97,8 @@ common_sources = \
|
||||||
openpgp-fpr.c \
|
openpgp-fpr.c \
|
||||||
comopt.c comopt.h \
|
comopt.c comopt.h \
|
||||||
compliance.c compliance.h \
|
compliance.c compliance.h \
|
||||||
pkscreening.c pkscreening.h
|
pkscreening.c pkscreening.h \
|
||||||
|
kem.c
|
||||||
|
|
||||||
if HAVE_W32_SYSTEM
|
if HAVE_W32_SYSTEM
|
||||||
common_sources += w32-reg.c w32-cmdline.c
|
common_sources += w32-reg.c w32-cmdline.c
|
||||||
|
@ -161,15 +161,16 @@ module_tests = t-stringhelp t-timestuff \
|
||||||
t-convert t-percent t-gettime t-sysutils t-sexputil \
|
t-convert t-percent t-gettime t-sysutils t-sexputil \
|
||||||
t-session-env t-openpgp-oid t-ssh-utils \
|
t-session-env t-openpgp-oid t-ssh-utils \
|
||||||
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
|
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
|
||||||
t-name-value t-ccparray t-recsel t-w32-cmdline
|
t-name-value t-ccparray t-recsel t-w32-cmdline t-exechelp
|
||||||
|
|
||||||
if HAVE_W32_SYSTEM
|
if HAVE_W32_SYSTEM
|
||||||
module_tests += t-w32-reg
|
module_tests += t-w32-reg
|
||||||
else
|
else
|
||||||
module_tests += t-exechelp t-exectool
|
module_tests += t-exectool
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if MAINTAINER_MODE
|
if MAINTAINER_MODE
|
||||||
module_maint_tests = t-helpfile t-b64
|
module_maint_tests = t-helpfile
|
||||||
else
|
else
|
||||||
module_maint_tests =
|
module_maint_tests =
|
||||||
endif
|
endif
|
||||||
|
@ -196,7 +197,6 @@ t_gettime_LDADD = $(t_common_ldadd)
|
||||||
t_sysutils_LDADD = $(t_common_ldadd)
|
t_sysutils_LDADD = $(t_common_ldadd)
|
||||||
t_helpfile_LDADD = $(t_common_ldadd)
|
t_helpfile_LDADD = $(t_common_ldadd)
|
||||||
t_sexputil_LDADD = $(t_common_ldadd)
|
t_sexputil_LDADD = $(t_common_ldadd)
|
||||||
t_b64_LDADD = $(t_common_ldadd)
|
|
||||||
t_exechelp_LDADD = $(t_common_ldadd)
|
t_exechelp_LDADD = $(t_common_ldadd)
|
||||||
t_exectool_LDADD = $(t_common_ldadd)
|
t_exectool_LDADD = $(t_common_ldadd)
|
||||||
t_session_env_LDADD = $(t_common_ldadd)
|
t_session_env_LDADD = $(t_common_ldadd)
|
||||||
|
|
|
@ -386,7 +386,8 @@ start_new_service (assuan_context_t *r_ctx,
|
||||||
const char *opt_lc_ctype,
|
const char *opt_lc_ctype,
|
||||||
const char *opt_lc_messages,
|
const char *opt_lc_messages,
|
||||||
session_env_t session_env,
|
session_env_t session_env,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg)
|
ctrl_t status_cb_arg)
|
||||||
{
|
{
|
||||||
|
@ -445,7 +446,7 @@ start_new_service (assuan_context_t *r_ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
|
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
|
||||||
if (err && autostart)
|
if (err && (flags & ASSHELP_FLAG_AUTOSTART))
|
||||||
{
|
{
|
||||||
char *abs_homedir;
|
char *abs_homedir;
|
||||||
lock_spawn_t lock;
|
lock_spawn_t lock;
|
||||||
|
@ -523,16 +524,11 @@ start_new_service (assuan_context_t *r_ctx,
|
||||||
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
|
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
err = gnupg_spawn_process_detached (program? program : program_name,
|
err = gnupg_process_spawn (program? program : program_name, argv,
|
||||||
argv, NULL);
|
GNUPG_PROCESS_DETACHED, NULL, NULL);
|
||||||
#else /*!W32*/
|
#else /*!W32*/
|
||||||
pid_t pid;
|
err = gnupg_process_spawn (program? program : program_name, argv,
|
||||||
|
0, NULL, NULL);
|
||||||
err = gnupg_spawn_process_fd (program? program : program_name,
|
|
||||||
argv, -1, -1, -1, &pid);
|
|
||||||
if (!err)
|
|
||||||
err = gnupg_wait_process (program? program : program_name,
|
|
||||||
pid, 1, NULL);
|
|
||||||
#endif /*!W32*/
|
#endif /*!W32*/
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("failed to start %s '%s': %s\n",
|
log_error ("failed to start %s '%s': %s\n",
|
||||||
|
@ -551,7 +547,8 @@ start_new_service (assuan_context_t *r_ctx,
|
||||||
xfree (sockname);
|
xfree (sockname);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
|
if ((flags & ASSHELP_FLAG_AUTOSTART)
|
||||||
|
|| gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
|
||||||
log_error ("can't connect to the %s: %s\n",
|
log_error ("can't connect to the %s: %s\n",
|
||||||
printed_name, gpg_strerror (err));
|
printed_name, gpg_strerror (err));
|
||||||
assuan_release (ctx);
|
assuan_release (ctx);
|
||||||
|
@ -603,55 +600,58 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||||
const char *opt_lc_ctype,
|
const char *opt_lc_ctype,
|
||||||
const char *opt_lc_messages,
|
const char *opt_lc_messages,
|
||||||
session_env_t session_env,
|
session_env_t session_env,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg)
|
ctrl_t status_cb_arg)
|
||||||
{
|
{
|
||||||
return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
|
return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
|
||||||
errsource, agent_program,
|
errsource, agent_program,
|
||||||
opt_lc_ctype, opt_lc_messages, session_env,
|
opt_lc_ctype, opt_lc_messages, session_env,
|
||||||
autostart, verbose, debug,
|
flags, verbose, debug,
|
||||||
status_cb, status_cb_arg);
|
status_cb, status_cb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Try to connect to the dirmngr via a socket. On platforms
|
/* Try to connect to the dirmngr via a socket. On platforms
|
||||||
supporting it, start it up if needed and if AUTOSTART is true.
|
supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
|
||||||
Returns a new assuan context at R_CTX or an error code. */
|
Returns a new assuan context at R_CTX or an error code. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
start_new_keyboxd (assuan_context_t *r_ctx,
|
start_new_keyboxd (assuan_context_t *r_ctx,
|
||||||
gpg_err_source_t errsource,
|
gpg_err_source_t errsource,
|
||||||
const char *keyboxd_program,
|
const char *keyboxd_program,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg)
|
ctrl_t status_cb_arg)
|
||||||
{
|
{
|
||||||
return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
|
return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
|
||||||
errsource, keyboxd_program,
|
errsource, keyboxd_program,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
autostart, verbose, debug,
|
flags, verbose, debug,
|
||||||
status_cb, status_cb_arg);
|
status_cb, status_cb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Try to connect to the dirmngr via a socket. On platforms
|
/* Try to connect to the dirmngr via a socket. On platforms
|
||||||
supporting it, start it up if needed and if AUTOSTART is true.
|
supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
|
||||||
Returns a new assuan context at R_CTX or an error code. */
|
Returns a new assuan context at R_CTX or an error code. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
start_new_dirmngr (assuan_context_t *r_ctx,
|
start_new_dirmngr (assuan_context_t *r_ctx,
|
||||||
gpg_err_source_t errsource,
|
gpg_err_source_t errsource,
|
||||||
const char *dirmngr_program,
|
const char *dirmngr_program,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg)
|
ctrl_t status_cb_arg)
|
||||||
{
|
{
|
||||||
#ifndef USE_DIRMNGR_AUTO_START
|
#ifndef USE_DIRMNGR_AUTO_START
|
||||||
autostart = 0;
|
flags &= ~ASSHELP_FLAG_AUTOSTART; /* Clear flag. */
|
||||||
#endif
|
#endif
|
||||||
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
|
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
|
||||||
errsource, dirmngr_program,
|
errsource, dirmngr_program,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
autostart, verbose, debug,
|
flags, verbose, debug,
|
||||||
status_cb, status_cb_arg);
|
status_cb, status_cb_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ get_assuan_server_version (assuan_context_t ctx, int mode, char **r_version)
|
||||||
|
|
||||||
/* Print a warning if the server's version number is less than our
|
/* Print a warning if the server's version number is less than our
|
||||||
* version number. Returns an error code on a connection problem.
|
* version number. Returns an error code on a connection problem.
|
||||||
* CTX is the Assuan context, SERVERNAME is the name of teh server,
|
* CTX is the Assuan context, SERVERNAME is the name of the server,
|
||||||
* STATUS_FUNC and STATUS_FUNC_DATA is a callback to emit status
|
* STATUS_FUNC and STATUS_FUNC_DATA is a callback to emit status
|
||||||
* messages. If PRINT_HINTS is set additional hints are printed. For
|
* messages. If PRINT_HINTS is set additional hints are printed. For
|
||||||
* MODE see get_assuan_server_version. */
|
* MODE see get_assuan_server_version. */
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/*-- asshelp.c --*/
|
/*-- asshelp.c --*/
|
||||||
|
#define ASSHELP_FLAG_AUTOSTART 1 /* Autostart the new service. */
|
||||||
|
|
||||||
|
|
||||||
void setup_libassuan_logging (unsigned int *debug_var_address,
|
void setup_libassuan_logging (unsigned int *debug_var_address,
|
||||||
int (*log_monitor)(assuan_context_t ctx,
|
int (*log_monitor)(assuan_context_t ctx,
|
||||||
|
@ -61,7 +63,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
|
||||||
const char *opt_lc_ctype,
|
const char *opt_lc_ctype,
|
||||||
const char *opt_lc_messages,
|
const char *opt_lc_messages,
|
||||||
session_env_t session_env,
|
session_env_t session_env,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg);
|
ctrl_t status_cb_arg);
|
||||||
|
|
||||||
|
@ -71,7 +74,8 @@ gpg_error_t
|
||||||
start_new_keyboxd (assuan_context_t *r_ctx,
|
start_new_keyboxd (assuan_context_t *r_ctx,
|
||||||
gpg_err_source_t errsource,
|
gpg_err_source_t errsource,
|
||||||
const char *keyboxd_program,
|
const char *keyboxd_program,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg);
|
ctrl_t status_cb_arg);
|
||||||
|
|
||||||
|
@ -81,7 +85,8 @@ gpg_error_t
|
||||||
start_new_dirmngr (assuan_context_t *r_ctx,
|
start_new_dirmngr (assuan_context_t *r_ctx,
|
||||||
gpg_err_source_t errsource,
|
gpg_err_source_t errsource,
|
||||||
const char *dirmngr_program,
|
const char *dirmngr_program,
|
||||||
int autostart, int verbose, int debug,
|
unsigned int flags,
|
||||||
|
int verbose, int debug,
|
||||||
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
gpg_error_t (*status_cb)(ctrl_t, int, ...),
|
||||||
ctrl_t status_cb_arg);
|
ctrl_t status_cb_arg);
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,9 @@ struct log_item_s
|
||||||
gpg_error_t err; /* The logged error code. */
|
gpg_error_t err; /* The logged error code. */
|
||||||
int intvalue; /* A logged integer value. */
|
int intvalue; /* A logged integer value. */
|
||||||
char *string; /* A malloced string or NULL. */
|
char *string; /* A malloced string or NULL. */
|
||||||
ksba_cert_t cert; /* A certifciate or NULL. */
|
ksba_cert_t cert; /* A certificate or NULL. */
|
||||||
int have_err:1;
|
unsigned int have_err:1;
|
||||||
int have_intvalue:1;
|
unsigned int have_intvalue:1;
|
||||||
};
|
};
|
||||||
typedef struct log_item_s *log_item_t;
|
typedef struct log_item_s *log_item_t;
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ typedef enum
|
||||||
/* The signature is a detached one. */
|
/* The signature is a detached one. */
|
||||||
|
|
||||||
AUDIT_CERT_ONLY_SIG,
|
AUDIT_CERT_ONLY_SIG,
|
||||||
/* A certifciate only signature has been detected. */
|
/* A certificate only signature has been detected. */
|
||||||
|
|
||||||
AUDIT_DATA_HASH_ALGO, /* int */
|
AUDIT_DATA_HASH_ALGO, /* int */
|
||||||
/* The hash algo given as argument is used for the data. This
|
/* The hash algo given as argument is used for the data. This
|
||||||
|
|
254
common/b64dec.c
254
common/b64dec.c
|
@ -1,254 +0,0 @@
|
||||||
/* b64dec.c - Simple Base64 decoder.
|
|
||||||
* Copyright (C) 2008, 2011 Free Software Foundation, Inc.
|
|
||||||
* Copyright (C) 2008, 2011, 2016 g10 Code GmbH
|
|
||||||
*
|
|
||||||
* This file is part of GnuPG.
|
|
||||||
*
|
|
||||||
* This file is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This file is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "i18n.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
|
|
||||||
/* The reverse base-64 list used for base-64 decoding. */
|
|
||||||
static unsigned char const asctobin[128] =
|
|
||||||
{
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
|
|
||||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
|
||||||
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
|
||||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
||||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
|
||||||
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
|
||||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
|
||||||
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
|
||||||
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
||||||
};
|
|
||||||
|
|
||||||
enum decoder_states
|
|
||||||
{
|
|
||||||
s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
|
|
||||||
s_b64_0, s_b64_1, s_b64_2, s_b64_3,
|
|
||||||
s_waitendtitle, s_waitend
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize the context for the base64 decoder. If TITLE is NULL a
|
|
||||||
plain base64 decoding is done. If it is the empty string the
|
|
||||||
decoder will skip everything until a "-----BEGIN " line has been
|
|
||||||
seen, decoding ends at a "----END " line. */
|
|
||||||
gpg_error_t
|
|
||||||
b64dec_start (struct b64state *state, const char *title)
|
|
||||||
{
|
|
||||||
memset (state, 0, sizeof *state);
|
|
||||||
if (title)
|
|
||||||
{
|
|
||||||
state->title = xtrystrdup (title);
|
|
||||||
if (!state->title)
|
|
||||||
state->lasterr = gpg_error_from_syserror ();
|
|
||||||
else
|
|
||||||
state->idx = s_init;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
state->idx = s_b64_0;
|
|
||||||
return state->lasterr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
|
|
||||||
new length of the buffer at R_NBYTES. */
|
|
||||||
gpg_error_t
|
|
||||||
b64dec_proc (struct b64state *state, void *buffer, size_t length,
|
|
||||||
size_t *r_nbytes)
|
|
||||||
{
|
|
||||||
enum decoder_states ds = state->idx;
|
|
||||||
unsigned char val = state->radbuf[0];
|
|
||||||
int pos = state->quad_count;
|
|
||||||
char *d, *s;
|
|
||||||
|
|
||||||
if (state->lasterr)
|
|
||||||
return state->lasterr;
|
|
||||||
|
|
||||||
if (state->stop_seen)
|
|
||||||
{
|
|
||||||
*r_nbytes = 0;
|
|
||||||
state->lasterr = gpg_error (GPG_ERR_EOF);
|
|
||||||
xfree (state->title);
|
|
||||||
state->title = NULL;
|
|
||||||
return state->lasterr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (s=d=buffer; length && !state->stop_seen; length--, s++)
|
|
||||||
{
|
|
||||||
again:
|
|
||||||
switch (ds)
|
|
||||||
{
|
|
||||||
case s_idle:
|
|
||||||
if (*s == '\n')
|
|
||||||
{
|
|
||||||
ds = s_lfseen;
|
|
||||||
pos = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case s_init:
|
|
||||||
ds = s_lfseen;
|
|
||||||
/* fall through */
|
|
||||||
case s_lfseen:
|
|
||||||
if (*s != "-----BEGIN "[pos])
|
|
||||||
{
|
|
||||||
ds = s_idle;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
else if (pos == 10)
|
|
||||||
{
|
|
||||||
pos = 0;
|
|
||||||
ds = s_beginseen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pos++;
|
|
||||||
break;
|
|
||||||
case s_beginseen:
|
|
||||||
if (*s != "PGP "[pos])
|
|
||||||
ds = s_begin; /* Not a PGP armor. */
|
|
||||||
else if (pos == 3)
|
|
||||||
ds = s_waitheader;
|
|
||||||
else
|
|
||||||
pos++;
|
|
||||||
break;
|
|
||||||
case s_waitheader:
|
|
||||||
if (*s == '\n')
|
|
||||||
ds = s_waitblank;
|
|
||||||
break;
|
|
||||||
case s_waitblank:
|
|
||||||
if (*s == '\n')
|
|
||||||
ds = s_b64_0; /* blank line found. */
|
|
||||||
else if (*s == ' ' || *s == '\r' || *s == '\t')
|
|
||||||
; /* Ignore spaces. */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Armor header line. Note that we don't care that our
|
|
||||||
* FSM accepts a header prefixed with spaces. */
|
|
||||||
ds = s_waitheader; /* Wait for next header. */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case s_begin:
|
|
||||||
if (*s == '\n')
|
|
||||||
ds = s_b64_0;
|
|
||||||
break;
|
|
||||||
case s_b64_0:
|
|
||||||
case s_b64_1:
|
|
||||||
case s_b64_2:
|
|
||||||
case s_b64_3:
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
|
|
||||||
if (*s == '-' && state->title)
|
|
||||||
{
|
|
||||||
/* Not a valid Base64 character: assume end
|
|
||||||
header. */
|
|
||||||
ds = s_waitend;
|
|
||||||
}
|
|
||||||
else if (*s == '=')
|
|
||||||
{
|
|
||||||
/* Pad character: stop */
|
|
||||||
if (ds == s_b64_1)
|
|
||||||
*d++ = val;
|
|
||||||
ds = state->title? s_waitendtitle : s_waitend;
|
|
||||||
}
|
|
||||||
else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
|
|
||||||
; /* Skip white spaces. */
|
|
||||||
else if ( (*s & 0x80)
|
|
||||||
|| (c = asctobin[*(unsigned char *)s]) == 255)
|
|
||||||
{
|
|
||||||
/* Skip invalid encodings. */
|
|
||||||
state->invalid_encoding = 1;
|
|
||||||
}
|
|
||||||
else if (ds == s_b64_0)
|
|
||||||
{
|
|
||||||
val = c << 2;
|
|
||||||
ds = s_b64_1;
|
|
||||||
}
|
|
||||||
else if (ds == s_b64_1)
|
|
||||||
{
|
|
||||||
val |= (c>>4)&3;
|
|
||||||
*d++ = val;
|
|
||||||
val = (c<<4)&0xf0;
|
|
||||||
ds = s_b64_2;
|
|
||||||
}
|
|
||||||
else if (ds == s_b64_2)
|
|
||||||
{
|
|
||||||
val |= (c>>2)&15;
|
|
||||||
*d++ = val;
|
|
||||||
val = (c<<6)&0xc0;
|
|
||||||
ds = s_b64_3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val |= c&0x3f;
|
|
||||||
*d++ = val;
|
|
||||||
ds = s_b64_0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case s_waitendtitle:
|
|
||||||
if (*s == '-')
|
|
||||||
ds = s_waitend;
|
|
||||||
break;
|
|
||||||
case s_waitend:
|
|
||||||
if ( *s == '\n')
|
|
||||||
state->stop_seen = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
state->idx = ds;
|
|
||||||
state->radbuf[0] = val;
|
|
||||||
state->quad_count = pos;
|
|
||||||
*r_nbytes = (d -(char*) buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function needs to be called before releasing the decoder
|
|
||||||
state. It may return an error code in case an encoding error has
|
|
||||||
been found during decoding. */
|
|
||||||
gpg_error_t
|
|
||||||
b64dec_finish (struct b64state *state)
|
|
||||||
{
|
|
||||||
xfree (state->title);
|
|
||||||
state->title = NULL;
|
|
||||||
|
|
||||||
if (state->lasterr)
|
|
||||||
return state->lasterr;
|
|
||||||
|
|
||||||
return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
|
|
||||||
}
|
|
422
common/b64enc.c
422
common/b64enc.c
|
@ -1,422 +0,0 @@
|
||||||
/* b64enc.c - Simple Base64 encoder.
|
|
||||||
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
|
|
||||||
* 2011 Free Software Foundation, Inc.
|
|
||||||
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
|
|
||||||
* 2011 g10 Code GmbH
|
|
||||||
*
|
|
||||||
* This file is part of GnuPG.
|
|
||||||
*
|
|
||||||
* This file is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This file is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "i18n.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#define B64ENC_DID_HEADER 1
|
|
||||||
#define B64ENC_DID_TRAILER 2
|
|
||||||
#define B64ENC_NO_LINEFEEDS 16
|
|
||||||
#define B64ENC_USE_PGPCRC 32
|
|
||||||
|
|
||||||
/* The base-64 character list */
|
|
||||||
static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"0123456789+/";
|
|
||||||
|
|
||||||
/* Stuff required to create the OpenPGP CRC. This crc_table has been
|
|
||||||
created using this code:
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define CRCPOLY 0x864CFB
|
|
||||||
|
|
||||||
int
|
|
||||||
main (void)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
uint32_t t;
|
|
||||||
uint32_t crc_table[256];
|
|
||||||
|
|
||||||
crc_table[0] = 0;
|
|
||||||
for (i=j=0; j < 128; j++ )
|
|
||||||
{
|
|
||||||
t = crc_table[j];
|
|
||||||
if ( (t & 0x00800000) )
|
|
||||||
{
|
|
||||||
t <<= 1;
|
|
||||||
crc_table[i++] = t ^ CRCPOLY;
|
|
||||||
crc_table[i++] = t;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
t <<= 1;
|
|
||||||
crc_table[i++] = t;
|
|
||||||
crc_table[i++] = t ^ CRCPOLY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
puts ("static const u32 crc_table[256] = {");
|
|
||||||
for (i=j=0; i < 256; i++)
|
|
||||||
{
|
|
||||||
printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
|
|
||||||
if (i != 255)
|
|
||||||
{
|
|
||||||
putchar (',');
|
|
||||||
if ( ++j > 5)
|
|
||||||
{
|
|
||||||
j = 0;
|
|
||||||
putchar ('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
puts ("\n};");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
#define CRCINIT 0xB704CE
|
|
||||||
static const u32 crc_table[256] = {
|
|
||||||
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
|
|
||||||
0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
|
|
||||||
0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
|
|
||||||
0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
|
|
||||||
0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
|
|
||||||
0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
|
|
||||||
0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
|
|
||||||
0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
|
|
||||||
0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
|
|
||||||
0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
|
|
||||||
0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
|
|
||||||
0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
|
|
||||||
0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
|
|
||||||
0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
|
|
||||||
0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
|
|
||||||
0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
|
|
||||||
0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
|
|
||||||
0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
|
|
||||||
0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
|
|
||||||
0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
|
|
||||||
0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
|
|
||||||
0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
|
|
||||||
0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
|
|
||||||
0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
|
|
||||||
0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
|
|
||||||
0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
|
|
||||||
0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
|
|
||||||
0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
|
|
||||||
0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
|
|
||||||
0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
|
|
||||||
0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
|
|
||||||
0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
|
|
||||||
0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
|
|
||||||
0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
|
|
||||||
0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
|
|
||||||
0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
|
|
||||||
0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
|
|
||||||
0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
|
|
||||||
0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
|
|
||||||
0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
|
|
||||||
0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
|
|
||||||
0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
|
|
||||||
0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
|
||||||
enc_start (struct b64state *state, FILE *fp, estream_t stream,
|
|
||||||
const char *title)
|
|
||||||
{
|
|
||||||
memset (state, 0, sizeof *state);
|
|
||||||
state->fp = fp;
|
|
||||||
state->stream = stream;
|
|
||||||
state->lasterr = 0;
|
|
||||||
if (title && !*title)
|
|
||||||
state->flags |= B64ENC_NO_LINEFEEDS;
|
|
||||||
else if (title)
|
|
||||||
{
|
|
||||||
if (!strncmp (title, "PGP ", 4))
|
|
||||||
{
|
|
||||||
state->flags |= B64ENC_USE_PGPCRC;
|
|
||||||
state->crc = CRCINIT;
|
|
||||||
}
|
|
||||||
state->title = xtrystrdup (title);
|
|
||||||
if (!state->title)
|
|
||||||
state->lasterr = gpg_error_from_syserror ();
|
|
||||||
}
|
|
||||||
return state->lasterr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
|
|
||||||
and not an empty string, this string will be used as the title for
|
|
||||||
the armor lines, with TITLE being an empty string, we don't write
|
|
||||||
the header lines and furthermore even don't write any linefeeds.
|
|
||||||
If TITLE starts with "PGP " the OpenPGP CRC checksum will be
|
|
||||||
written as well. With TITLE being NULL, we merely don't write
|
|
||||||
header but make sure that lines are not too long. Note, that we
|
|
||||||
don't write any output unless at least one byte get written using
|
|
||||||
b64enc_write. */
|
|
||||||
gpg_error_t
|
|
||||||
b64enc_start (struct b64state *state, FILE *fp, const char *title)
|
|
||||||
{
|
|
||||||
return enc_start (state, fp, NULL, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Same as b64enc_start but takes an estream. */
|
|
||||||
gpg_error_t
|
|
||||||
b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
|
|
||||||
{
|
|
||||||
return enc_start (state, NULL, fp, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
my_fputs (const char *string, struct b64state *state)
|
|
||||||
{
|
|
||||||
if (state->stream)
|
|
||||||
return es_fputs (string, state->stream);
|
|
||||||
else
|
|
||||||
return fputs (string, state->fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Write NBYTES from BUFFER to the Base 64 stream identified by
|
|
||||||
STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
|
|
||||||
stream. */
|
|
||||||
gpg_error_t
|
|
||||||
b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
|
|
||||||
{
|
|
||||||
unsigned char radbuf[4];
|
|
||||||
int idx, quad_count;
|
|
||||||
const unsigned char *p;
|
|
||||||
|
|
||||||
if (state->lasterr)
|
|
||||||
return state->lasterr;
|
|
||||||
|
|
||||||
if (!nbytes)
|
|
||||||
{
|
|
||||||
if (buffer)
|
|
||||||
if (state->stream? es_fflush (state->stream) : fflush (state->fp))
|
|
||||||
goto write_error;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(state->flags & B64ENC_DID_HEADER))
|
|
||||||
{
|
|
||||||
if (state->title)
|
|
||||||
{
|
|
||||||
if ( my_fputs ("-----BEGIN ", state) == EOF
|
|
||||||
|| my_fputs (state->title, state) == EOF
|
|
||||||
|| my_fputs ("-----\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
if ( (state->flags & B64ENC_USE_PGPCRC)
|
|
||||||
&& my_fputs ("\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->flags |= B64ENC_DID_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = state->idx;
|
|
||||||
quad_count = state->quad_count;
|
|
||||||
assert (idx < 4);
|
|
||||||
memcpy (radbuf, state->radbuf, idx);
|
|
||||||
|
|
||||||
if ( (state->flags & B64ENC_USE_PGPCRC) )
|
|
||||||
{
|
|
||||||
size_t n;
|
|
||||||
u32 crc = state->crc;
|
|
||||||
|
|
||||||
for (p=buffer, n=nbytes; n; p++, n-- )
|
|
||||||
crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
|
|
||||||
state->crc = (crc & 0x00ffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (p=buffer; nbytes; p++, nbytes--)
|
|
||||||
{
|
|
||||||
radbuf[idx++] = *p;
|
|
||||||
if (idx > 2)
|
|
||||||
{
|
|
||||||
char tmp[4];
|
|
||||||
|
|
||||||
tmp[0] = bintoasc[(*radbuf >> 2) & 077];
|
|
||||||
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
|
|
||||||
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
|
||||||
tmp[3] = bintoasc[radbuf[2]&077];
|
|
||||||
if (state->stream)
|
|
||||||
{
|
|
||||||
for (idx=0; idx < 4; idx++)
|
|
||||||
es_putc (tmp[idx], state->stream);
|
|
||||||
idx = 0;
|
|
||||||
if (es_ferror (state->stream))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (idx=0; idx < 4; idx++)
|
|
||||||
putc (tmp[idx], state->fp);
|
|
||||||
idx = 0;
|
|
||||||
if (ferror (state->fp))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
if (++quad_count >= (64/4))
|
|
||||||
{
|
|
||||||
quad_count = 0;
|
|
||||||
if (!(state->flags & B64ENC_NO_LINEFEEDS)
|
|
||||||
&& my_fputs ("\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy (state->radbuf, radbuf, idx);
|
|
||||||
state->idx = idx;
|
|
||||||
state->quad_count = quad_count;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
write_error:
|
|
||||||
state->lasterr = gpg_error_from_syserror ();
|
|
||||||
if (state->title)
|
|
||||||
{
|
|
||||||
xfree (state->title);
|
|
||||||
state->title = NULL;
|
|
||||||
}
|
|
||||||
return state->lasterr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
|
||||||
b64enc_finish (struct b64state *state)
|
|
||||||
{
|
|
||||||
gpg_error_t err = 0;
|
|
||||||
unsigned char radbuf[4];
|
|
||||||
int idx, quad_count;
|
|
||||||
char tmp[4];
|
|
||||||
|
|
||||||
if (state->lasterr)
|
|
||||||
return state->lasterr;
|
|
||||||
|
|
||||||
if (!(state->flags & B64ENC_DID_HEADER))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* Flush the base64 encoding */
|
|
||||||
idx = state->idx;
|
|
||||||
quad_count = state->quad_count;
|
|
||||||
assert (idx < 4);
|
|
||||||
memcpy (radbuf, state->radbuf, idx);
|
|
||||||
|
|
||||||
if (idx)
|
|
||||||
{
|
|
||||||
tmp[0] = bintoasc[(*radbuf>>2)&077];
|
|
||||||
if (idx == 1)
|
|
||||||
{
|
|
||||||
tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
|
|
||||||
tmp[2] = '=';
|
|
||||||
tmp[3] = '=';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
|
|
||||||
tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
|
|
||||||
tmp[3] = '=';
|
|
||||||
}
|
|
||||||
if (state->stream)
|
|
||||||
{
|
|
||||||
for (idx=0; idx < 4; idx++)
|
|
||||||
es_putc (tmp[idx], state->stream);
|
|
||||||
if (es_ferror (state->stream))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (idx=0; idx < 4; idx++)
|
|
||||||
putc (tmp[idx], state->fp);
|
|
||||||
if (ferror (state->fp))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++quad_count >= (64/4))
|
|
||||||
{
|
|
||||||
quad_count = 0;
|
|
||||||
if (!(state->flags & B64ENC_NO_LINEFEEDS)
|
|
||||||
&& my_fputs ("\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish the last line and write the trailer. */
|
|
||||||
if (quad_count
|
|
||||||
&& !(state->flags & B64ENC_NO_LINEFEEDS)
|
|
||||||
&& my_fputs ("\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
|
|
||||||
if ( (state->flags & B64ENC_USE_PGPCRC) )
|
|
||||||
{
|
|
||||||
/* Write the CRC. */
|
|
||||||
my_fputs ("=", state);
|
|
||||||
radbuf[0] = state->crc >>16;
|
|
||||||
radbuf[1] = state->crc >> 8;
|
|
||||||
radbuf[2] = state->crc;
|
|
||||||
tmp[0] = bintoasc[(*radbuf>>2)&077];
|
|
||||||
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
|
|
||||||
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
|
||||||
tmp[3] = bintoasc[radbuf[2]&077];
|
|
||||||
if (state->stream)
|
|
||||||
{
|
|
||||||
for (idx=0; idx < 4; idx++)
|
|
||||||
es_putc (tmp[idx], state->stream);
|
|
||||||
if (es_ferror (state->stream))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (idx=0; idx < 4; idx++)
|
|
||||||
putc (tmp[idx], state->fp);
|
|
||||||
if (ferror (state->fp))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
if (!(state->flags & B64ENC_NO_LINEFEEDS)
|
|
||||||
&& my_fputs ("\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->title)
|
|
||||||
{
|
|
||||||
if ( my_fputs ("-----END ", state) == EOF
|
|
||||||
|| my_fputs (state->title, state) == EOF
|
|
||||||
|| my_fputs ("-----\n", state) == EOF)
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
write_error:
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (state->title)
|
|
||||||
{
|
|
||||||
xfree (state->title);
|
|
||||||
state->title = NULL;
|
|
||||||
}
|
|
||||||
state->fp = NULL;
|
|
||||||
state->stream = NULL;
|
|
||||||
state->lasterr = err;
|
|
||||||
return err;
|
|
||||||
}
|
|
|
@ -41,8 +41,8 @@ static int initialized;
|
||||||
static int module;
|
static int module;
|
||||||
|
|
||||||
/* This value is used by DSA and RSA checks in addition to the hard
|
/* This value is used by DSA and RSA checks in addition to the hard
|
||||||
* coded length checks. It allows to increase the required key length
|
* coded length checks. It allows one to increase the required key length
|
||||||
* using a confue file. */
|
* using a config file. */
|
||||||
static unsigned int min_compliant_rsa_length;
|
static unsigned int min_compliant_rsa_length;
|
||||||
|
|
||||||
/* Return the address of a compliance cache variable for COMPLIANCE.
|
/* Return the address of a compliance cache variable for COMPLIANCE.
|
||||||
|
@ -139,7 +139,7 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|
||||||
gcry_mpi_t key[], unsigned int keylength,
|
gcry_mpi_t key[], unsigned int keylength,
|
||||||
const char *curvename)
|
const char *curvename)
|
||||||
{
|
{
|
||||||
enum { is_rsa, is_dsa, is_elg, is_ecc } algotype;
|
enum { is_rsa, is_dsa, is_elg, is_ecc, is_kem } algotype;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (! initialized)
|
if (! initialized)
|
||||||
|
@ -173,6 +173,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|
||||||
case PUBKEY_ALGO_ELGAMAL:
|
case PUBKEY_ALGO_ELGAMAL:
|
||||||
return 0; /* Signing with Elgamal is not at all supported. */
|
return 0; /* Signing with Elgamal is not at all supported. */
|
||||||
|
|
||||||
|
case PUBKEY_ALGO_KYBER:
|
||||||
|
algotype = is_kem;
|
||||||
|
break;
|
||||||
|
|
||||||
default: /* Unknown. */
|
default: /* Unknown. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -227,6 +231,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|
||||||
|| !strcmp (curvename, "brainpoolP512r1")));
|
|| !strcmp (curvename, "brainpoolP512r1")));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case is_kem:
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = 0;
|
result = 0;
|
||||||
}
|
}
|
||||||
|
@ -256,6 +264,13 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
|
||||||
if (! initialized)
|
if (! initialized)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* Map the the generic ECC algo to ECDSA if requested. */
|
||||||
|
if ((algo_flags & PK_ALGO_FLAG_ECC18)
|
||||||
|
&& algo == GCRY_PK_ECC
|
||||||
|
&& (use == PK_USE_VERIFICATION
|
||||||
|
|| use == PK_USE_SIGNING))
|
||||||
|
algo = GCRY_PK_ECDSA;
|
||||||
|
|
||||||
switch (compliance)
|
switch (compliance)
|
||||||
{
|
{
|
||||||
case CO_DE_VS:
|
case CO_DE_VS:
|
||||||
|
@ -280,7 +295,6 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
|
||||||
default:
|
default:
|
||||||
log_assert (!"reached");
|
log_assert (!"reached");
|
||||||
}
|
}
|
||||||
(void)algo_flags;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PUBKEY_ALGO_DSA:
|
case PUBKEY_ALGO_DSA:
|
||||||
|
@ -301,7 +315,7 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
|
||||||
result = (use == PK_USE_DECRYPTION);
|
result = (use == PK_USE_DECRYPTION);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PUBKEY_ALGO_ECDH:
|
case PUBKEY_ALGO_ECDH: /* Same value as GCRY_PK_ECC, i.e. 18 */
|
||||||
case GCRY_PK_ECDH:
|
case GCRY_PK_ECDH:
|
||||||
if (use == PK_USE_DECRYPTION)
|
if (use == PK_USE_DECRYPTION)
|
||||||
result = 1;
|
result = 1;
|
||||||
|
@ -549,6 +563,9 @@ gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
|
||||||
int *result;
|
int *result;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
/* #warning debug code ahead */
|
||||||
|
/* return 1; */
|
||||||
|
|
||||||
result = get_compliance_cache (compliance, 1);
|
result = get_compliance_cache (compliance, 1);
|
||||||
|
|
||||||
if (result && *result != -1)
|
if (result && *result != -1)
|
||||||
|
|
|
@ -50,6 +50,7 @@ enum pk_use_case
|
||||||
|
|
||||||
/* Flags to distinguish public key algorithm variants. */
|
/* Flags to distinguish public key algorithm variants. */
|
||||||
#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
|
#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
|
||||||
|
#define PK_ALGO_FLAG_ECC18 256 /* GCRY_PK_ECC is used in a generic way. */
|
||||||
|
|
||||||
|
|
||||||
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|
||||||
|
|
412
common/dotlock.c
412
common/dotlock.c
|
@ -291,6 +291,7 @@
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
|
# include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -393,9 +394,18 @@ struct dotlock_handle
|
||||||
unsigned int locked:1; /* Lock status. */
|
unsigned int locked:1; /* Lock status. */
|
||||||
unsigned int disable:1; /* If true, locking is disabled. */
|
unsigned int disable:1; /* If true, locking is disabled. */
|
||||||
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
|
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
|
||||||
|
unsigned int by_parent:1; /* Parent does the locking. */
|
||||||
|
unsigned int no_write:1; /* No write to the lockfile. */
|
||||||
|
|
||||||
int extra_fd; /* A place for the caller to store an FD. */
|
int extra_fd; /* A place for the caller to store an FD. */
|
||||||
|
|
||||||
|
/* An optional info callback - see dotlock_set_info_cb. */
|
||||||
|
int (*info_cb)(dotlock_t, void *,
|
||||||
|
enum dotlock_reasons reason,
|
||||||
|
const char *,...);
|
||||||
|
void *info_cb_value;
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_DOSISH_SYSTEM
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
HANDLE lockhd; /* The W32 handle of the lock file. */
|
HANDLE lockhd; /* The W32 handle of the lock file. */
|
||||||
#else /*!HAVE_DOSISH_SYSTEM */
|
#else /*!HAVE_DOSISH_SYSTEM */
|
||||||
|
@ -545,8 +555,15 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|
||||||
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
|
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
|
||||||
{
|
{
|
||||||
int e = errno;
|
int e = errno;
|
||||||
my_info_2 ("error opening lockfile '%s': %s\n",
|
if (errno != ENOENT)
|
||||||
h->lockname, strerror(errno) );
|
{
|
||||||
|
my_info_2 ("error opening lockfile '%s': %s\n",
|
||||||
|
h->lockname, strerror(errno) );
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"error opening lockfile '%s': %s\n",
|
||||||
|
h->lockname, strerror (errno) );
|
||||||
|
}
|
||||||
if (buffer != buffer_space)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
my_set_errno (e); /* Need to return ERRNO here. */
|
my_set_errno (e); /* Need to return ERRNO here. */
|
||||||
|
@ -564,6 +581,10 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|
||||||
{
|
{
|
||||||
int e = errno;
|
int e = errno;
|
||||||
my_info_1 ("error reading lockfile '%s'\n", h->lockname );
|
my_info_1 ("error reading lockfile '%s'\n", h->lockname );
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"error reading lockfile '%s': %s\n",
|
||||||
|
h->lockname, strerror (errno) );
|
||||||
close (fd);
|
close (fd);
|
||||||
if (buffer != buffer_space)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
|
@ -583,6 +604,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|
||||||
if (nread < 11)
|
if (nread < 11)
|
||||||
{
|
{
|
||||||
my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
|
my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
|
||||||
|
"invalid size of lockfile '%s'\n", h->lockname);
|
||||||
if (buffer != buffer_space)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
my_set_errno (EINVAL);
|
my_set_errno (EINVAL);
|
||||||
|
@ -594,6 +618,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|
||||||
|| !pid )
|
|| !pid )
|
||||||
{
|
{
|
||||||
my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
|
my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
|
||||||
|
"invalid pid %d in lockfile '%s'\n", pid, h->lockname);
|
||||||
if (buffer != buffer_space)
|
if (buffer != buffer_space)
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
my_set_errno (EINVAL);
|
my_set_errno (EINVAL);
|
||||||
|
@ -655,6 +682,80 @@ use_hardlinks_p (const char *tname)
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_SYSTEM
|
#ifdef HAVE_POSIX_SYSTEM
|
||||||
|
static int
|
||||||
|
dotlock_get_process_id (dotlock_t h)
|
||||||
|
{
|
||||||
|
return h->by_parent? (int)getppid(): (int)getpid();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dotlock_detect_tname (dotlock_t h)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
DIR *dir;
|
||||||
|
char *dirname;
|
||||||
|
char *basename;
|
||||||
|
struct dirent *d;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (stat (h->lockname, &sb))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
basename = make_basename (h->lockname, NULL);
|
||||||
|
dirname = make_dirname (h->lockname);
|
||||||
|
|
||||||
|
dir = opendir (dirname);
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((d = readdir (dir)))
|
||||||
|
if (sb.st_ino == d->d_ino && strcmp (d->d_name, basename))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
int len = strlen (h->tname);
|
||||||
|
int dlen = strlen (d->d_name);
|
||||||
|
const char *tname_path;
|
||||||
|
|
||||||
|
if (dlen > len)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (stpcpy (stpcpy (h->tname, dirname), DIRSEP_S), d->d_name);
|
||||||
|
h->use_o_excl = 0;
|
||||||
|
tname_path = strchr (h->tname + strlen (dirname) + 2, '.');
|
||||||
|
if (!tname_path)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
h->nodename_off = tname_path - h->tname + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
h->use_o_excl = 1;
|
||||||
|
|
||||||
|
r = closedir (dir);
|
||||||
|
if (r)
|
||||||
|
{
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (basename);
|
||||||
|
xfree (dirname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Locking core for Unix. It used a temporary file and the link
|
/* Locking core for Unix. It used a temporary file and the link
|
||||||
system call to make locking an atomic operation. */
|
system call to make locking an atomic operation. */
|
||||||
static dotlock_t
|
static dotlock_t
|
||||||
|
@ -667,8 +768,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
||||||
int dirpartlen;
|
int dirpartlen;
|
||||||
struct utsname utsbuf;
|
struct utsname utsbuf;
|
||||||
size_t tnamelen;
|
size_t tnamelen;
|
||||||
|
int pid;
|
||||||
|
|
||||||
snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
|
pid = dotlock_get_process_id (h);
|
||||||
|
snprintf (pidstr, sizeof pidstr, "%10d\n", pid);
|
||||||
|
|
||||||
/* Create a temporary file. */
|
/* Create a temporary file. */
|
||||||
if ( uname ( &utsbuf ) )
|
if ( uname ( &utsbuf ) )
|
||||||
|
@ -702,10 +805,17 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
||||||
}
|
}
|
||||||
h->nodename_len = strlen (nodename);
|
h->nodename_len = strlen (nodename);
|
||||||
|
|
||||||
|
if (h->no_write)
|
||||||
|
{
|
||||||
|
memset (h->tname, '_', tnamelen);
|
||||||
|
h->tname[tnamelen] = 0;
|
||||||
|
goto skip_write;
|
||||||
|
}
|
||||||
|
|
||||||
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
|
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
|
||||||
h->nodename_off = strlen (h->tname);
|
h->nodename_off = strlen (h->tname);
|
||||||
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
|
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
|
||||||
"%s.%d", nodename, (int)getpid ());
|
"%s.%d", nodename, pid);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -722,6 +832,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
my_error_2 (_("failed to create temporary file '%s': %s\n"),
|
my_error_2 (_("failed to create temporary file '%s': %s\n"),
|
||||||
h->tname, strerror (errno));
|
h->tname, strerror (errno));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
|
||||||
|
_("failed to create temporary file '%s': %s\n"),
|
||||||
|
h->tname, strerror (errno));
|
||||||
xfree (h->tname);
|
xfree (h->tname);
|
||||||
xfree (h);
|
xfree (h);
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
|
@ -755,11 +869,16 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
||||||
int saveerrno = errno;
|
int saveerrno = errno;
|
||||||
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
|
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
|
||||||
, h->tname, strerror (saveerrno));
|
, h->tname, strerror (saveerrno));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_CONFIG_TEST,
|
||||||
|
"can't check whether hardlinks are supported for '%s': %s\n"
|
||||||
|
, h->tname, strerror (saveerrno));
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
}
|
}
|
||||||
goto write_failed;
|
goto write_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skip_write:
|
||||||
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
|
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
|
||||||
if (!h->lockname)
|
if (!h->lockname)
|
||||||
{
|
{
|
||||||
|
@ -775,6 +894,20 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
||||||
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
|
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
|
|
||||||
|
if (h->no_write)
|
||||||
|
{
|
||||||
|
if (dotlock_detect_tname (h) < 0)
|
||||||
|
{
|
||||||
|
xfree (h->lockname);
|
||||||
|
xfree (h->tname);
|
||||||
|
xfree (h);
|
||||||
|
my_set_errno (EACCES);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->locked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
|
|
||||||
write_failed:
|
write_failed:
|
||||||
|
@ -783,6 +916,11 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
|
||||||
all_lockfiles = h->next;
|
all_lockfiles = h->next;
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
|
my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
_("error writing to '%s': %s\n"),
|
||||||
|
h->tname, strerror (errno));
|
||||||
|
|
||||||
if ( fd != -1 )
|
if ( fd != -1 )
|
||||||
close (fd);
|
close (fd);
|
||||||
unlink (h->tname);
|
unlink (h->tname);
|
||||||
|
@ -849,6 +987,10 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
|
||||||
all_lockfiles = h->next;
|
all_lockfiles = h->next;
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
|
my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
_("can't create '%s': %s\n"),
|
||||||
|
h->lockname, w32_strerror (-1));
|
||||||
xfree (h->lockname);
|
xfree (h->lockname);
|
||||||
xfree (h);
|
xfree (h);
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
|
@ -873,7 +1015,15 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
|
||||||
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
|
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
|
||||||
used.
|
used.
|
||||||
|
|
||||||
FLAGS must be 0.
|
FLAGS may include DOTLOCK_PREPARE_CREATE bit, which only allocates
|
||||||
|
the handle and requires a further call to dotlock_finish_create.
|
||||||
|
This can be used to set a callback between these calls.
|
||||||
|
|
||||||
|
FLAGS may include DOTLOCK_LOCK_BY_PARENT bit, when it's the parent
|
||||||
|
process controlling the lock. This is used by dotlock util.
|
||||||
|
|
||||||
|
FLAGS may include DOTLOCK_LOCKED bit, when it should not create the
|
||||||
|
lockfile, but to unlock. This is used by dotlock util.
|
||||||
|
|
||||||
The function returns an new handle which needs to be released using
|
The function returns an new handle which needs to be released using
|
||||||
destroy_dotlock but gets also released at the termination of the
|
destroy_dotlock but gets also released at the termination of the
|
||||||
|
@ -885,8 +1035,13 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
||||||
{
|
{
|
||||||
static int initialized;
|
static int initialized;
|
||||||
dotlock_t h;
|
dotlock_t h;
|
||||||
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
int by_parent = 0;
|
||||||
|
int no_write = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( !initialized )
|
if ( !(flags & DOTLOCK_LOCK_BY_PARENT)
|
||||||
|
&& !initialized )
|
||||||
{
|
{
|
||||||
atexit (dotlock_remove_lockfiles);
|
atexit (dotlock_remove_lockfiles);
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
|
@ -895,7 +1050,15 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
||||||
if ( !file_to_lock )
|
if ( !file_to_lock )
|
||||||
return NULL; /* Only initialization was requested. */
|
return NULL; /* Only initialization was requested. */
|
||||||
|
|
||||||
if (flags)
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
if ((flags & DOTLOCK_LOCK_BY_PARENT) || (flags & DOTLOCK_LOCKED))
|
||||||
|
{
|
||||||
|
by_parent = !!(flags & DOTLOCK_LOCK_BY_PARENT);
|
||||||
|
no_write = !!(flags & DOTLOCK_LOCKED);
|
||||||
|
flags &= ~(DOTLOCK_LOCK_BY_PARENT | DOTLOCK_LOCKED);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ((flags & ~DOTLOCK_PREPARE_CREATE))
|
||||||
{
|
{
|
||||||
my_set_errno (EINVAL);
|
my_set_errno (EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -905,6 +1068,10 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
||||||
if (!h)
|
if (!h)
|
||||||
return NULL;
|
return NULL;
|
||||||
h->extra_fd = -1;
|
h->extra_fd = -1;
|
||||||
|
#ifndef HAVE_DOSISH_SYSTEM
|
||||||
|
h->by_parent = by_parent;
|
||||||
|
h->no_write = no_write;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (never_lock)
|
if (never_lock)
|
||||||
{
|
{
|
||||||
|
@ -916,6 +1083,24 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & DOTLOCK_PREPARE_CREATE))
|
||||||
|
return h;
|
||||||
|
else
|
||||||
|
return dotlock_finish_create (h, file_to_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function may be used along with dotlock_create (file_name,
|
||||||
|
* DOTLOCK_PREPARE_CREATE) to finish the creation call. The given
|
||||||
|
* filename shall be the same as passed to dotlock_create. On success
|
||||||
|
* the same handle H is returned, on error NULL is returned and H is
|
||||||
|
* released. */
|
||||||
|
dotlock_t
|
||||||
|
dotlock_finish_create (dotlock_t h, const char *file_to_lock)
|
||||||
|
{
|
||||||
|
if (!h || !file_to_lock)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
#ifdef HAVE_DOSISH_SYSTEM
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
return dotlock_create_w32 (h, file_to_lock);
|
return dotlock_create_w32 (h, file_to_lock);
|
||||||
#else /*!HAVE_DOSISH_SYSTEM */
|
#else /*!HAVE_DOSISH_SYSTEM */
|
||||||
|
@ -942,6 +1127,24 @@ dotlock_get_fd (dotlock_t h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set a callback function for info diagnostics. The callback
|
||||||
|
* function CB is called with the handle, the opaque value OPAQUE, a
|
||||||
|
* reason code, and a format string with its arguments. The callback
|
||||||
|
* shall return 0 to continue operation or true in which case the
|
||||||
|
* current function will be terminated with an error. */
|
||||||
|
void
|
||||||
|
dotlock_set_info_cb (dotlock_t h,
|
||||||
|
int (*cb)(dotlock_t, void *,
|
||||||
|
enum dotlock_reasons reason,
|
||||||
|
const char *,...),
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
h->info_cb = cb;
|
||||||
|
h->info_cb_value = opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_SYSTEM
|
#ifdef HAVE_POSIX_SYSTEM
|
||||||
/* Unix specific code of destroy_dotlock. */
|
/* Unix specific code of destroy_dotlock. */
|
||||||
|
@ -952,7 +1155,6 @@ dotlock_destroy_unix (dotlock_t h)
|
||||||
unlink (h->lockname);
|
unlink (h->lockname);
|
||||||
if (h->tname && !h->use_o_excl)
|
if (h->tname && !h->use_o_excl)
|
||||||
unlink (h->tname);
|
unlink (h->tname);
|
||||||
xfree (h->tname);
|
|
||||||
}
|
}
|
||||||
#endif /*HAVE_POSIX_SYSTEM*/
|
#endif /*HAVE_POSIX_SYSTEM*/
|
||||||
|
|
||||||
|
@ -998,19 +1200,74 @@ dotlock_destroy (dotlock_t h)
|
||||||
UNLOCK_all_lockfiles ();
|
UNLOCK_all_lockfiles ();
|
||||||
|
|
||||||
/* Then destroy the lock. */
|
/* Then destroy the lock. */
|
||||||
if (!h->disable)
|
if (!h->disable
|
||||||
|
&& (!h->by_parent || h->no_write))
|
||||||
{
|
{
|
||||||
|
/* NOTE: under the condition of (by_parent && !no_write),
|
||||||
|
it doesn't come here. So, the lock file remains. */
|
||||||
#ifdef HAVE_DOSISH_SYSTEM
|
#ifdef HAVE_DOSISH_SYSTEM
|
||||||
dotlock_destroy_w32 (h);
|
dotlock_destroy_w32 (h);
|
||||||
#else /* !HAVE_DOSISH_SYSTEM */
|
#else /* !HAVE_DOSISH_SYSTEM */
|
||||||
dotlock_destroy_unix (h);
|
dotlock_destroy_unix (h);
|
||||||
#endif /* HAVE_DOSISH_SYSTEM */
|
#endif /* HAVE_DOSISH_SYSTEM */
|
||||||
xfree (h->lockname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_POSIX_SYSTEM
|
||||||
|
/* When DOTLOCK_LOCK_BY_PARENT and lock fails,
|
||||||
|
the temporary file created should be removed. */
|
||||||
|
if (h->by_parent && !h->no_write && !h->locked)
|
||||||
|
if (h->tname && !h->use_o_excl)
|
||||||
|
unlink (h->tname);
|
||||||
|
|
||||||
|
xfree (h->tname);
|
||||||
|
#endif
|
||||||
|
xfree (h->lockname);
|
||||||
xfree(h);
|
xfree(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if H has been taken. */
|
||||||
|
int
|
||||||
|
dotlock_is_locked (dotlock_t h)
|
||||||
|
{
|
||||||
|
return h && !!h->locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the next interval to wait. WTIME and TIMEOUT are pointers
|
||||||
|
* to the current state and are updated by this function. The
|
||||||
|
* returned value might be different from the value of WTIME. */
|
||||||
|
static int
|
||||||
|
next_wait_interval (int *wtime, long *timeout)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Wait until lock has been released. We use retry intervals of 4,
|
||||||
|
* 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 512, 1024, 2048ms, and
|
||||||
|
* so on. If wait-forever was requested we add a small random value
|
||||||
|
* to have different timeouts per process. */
|
||||||
|
if (!*wtime)
|
||||||
|
*wtime = 4;
|
||||||
|
else if (*wtime < 2048)
|
||||||
|
*wtime *= 2;
|
||||||
|
else
|
||||||
|
*wtime = 512;
|
||||||
|
|
||||||
|
result = *wtime;
|
||||||
|
if (*wtime > 8 && *timeout < 0)
|
||||||
|
result += ((unsigned int)getpid() % 37);
|
||||||
|
|
||||||
|
if (*timeout > 0)
|
||||||
|
{
|
||||||
|
if (result > *timeout)
|
||||||
|
result = *timeout;
|
||||||
|
*timeout -= result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_POSIX_SYSTEM
|
#ifdef HAVE_POSIX_SYSTEM
|
||||||
/* Unix specific code of make_dotlock. Returns 0 on success and -1 on
|
/* Unix specific code of make_dotlock. Returns 0 on success and -1 on
|
||||||
|
@ -1019,6 +1276,7 @@ static int
|
||||||
dotlock_take_unix (dotlock_t h, long timeout)
|
dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
int wtime = 0;
|
int wtime = 0;
|
||||||
|
int timedout = 0;
|
||||||
int sumtime = 0;
|
int sumtime = 0;
|
||||||
int pid;
|
int pid;
|
||||||
int lastpid = -1;
|
int lastpid = -1;
|
||||||
|
@ -1047,6 +1305,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
|
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
|
||||||
h->lockname, strerror (saveerrno));
|
h->lockname, strerror (saveerrno));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"lock not made: open(O_EXCL) of '%s' failed: %s\n",
|
||||||
|
h->lockname, strerror (saveerrno));
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1054,7 +1316,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
char pidstr[16];
|
char pidstr[16];
|
||||||
|
|
||||||
snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
|
snprintf (pidstr, sizeof pidstr, "%10d\n",
|
||||||
|
dotlock_get_process_id (h));
|
||||||
if (write (fd, pidstr, 11 ) == 11
|
if (write (fd, pidstr, 11 ) == 11
|
||||||
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
|
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
|
||||||
== h->nodename_len
|
== h->nodename_len
|
||||||
|
@ -1068,6 +1331,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
|
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
|
||||||
h->lockname, strerror (errno));
|
h->lockname, strerror (errno));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"lock not made: writing to '%s' failed: %s\n",
|
||||||
|
h->lockname, strerror (errno));
|
||||||
close (fd);
|
close (fd);
|
||||||
unlink (h->lockname);
|
unlink (h->lockname);
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
|
@ -1086,6 +1353,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
|
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
|
||||||
strerror (errno));
|
strerror (errno));
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"lock not made: Oops: stat of tmp file failed: %s\n",
|
||||||
|
strerror (errno));
|
||||||
/* In theory this might be a severe error: It is possible
|
/* In theory this might be a severe error: It is possible
|
||||||
that link succeeded but stat failed due to changed
|
that link succeeded but stat failed due to changed
|
||||||
permissions. We can't do anything about it, though. */
|
permissions. We can't do anything about it, though. */
|
||||||
|
@ -1107,16 +1378,19 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_info_0 ("cannot read lockfile\n");
|
my_info_0 ("cannot read lockfile\n");
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"cannot read lockfile\n");
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
my_info_0 ("lockfile disappeared\n");
|
my_info_0 ("lockfile disappeared\n");
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
else if ( (pid == getpid() && same_node)
|
else if ( (pid == dotlock_get_process_id (h) && same_node && !h->by_parent)
|
||||||
|| (same_node && kill (pid, 0) && errno == ESRCH) )
|
|| (same_node && kill (pid, 0) && errno == ESRCH) )
|
||||||
/* Stale lockfile is detected. */
|
|
||||||
{
|
{
|
||||||
|
/* Stale lockfile is detected. */
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
/* Check if it's unlocked during examining the lockfile. */
|
/* Check if it's unlocked during examining the lockfile. */
|
||||||
|
@ -1159,6 +1433,9 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
unlink (h->lockname);
|
unlink (h->lockname);
|
||||||
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
|
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
|
||||||
close (fd);
|
close (fd);
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_STALE_REMOVED,
|
||||||
|
_("removing stale lockfile (created by %d)\n"), pid);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1170,42 +1447,39 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||||
if (timeout)
|
if (timeout)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
int wtimereal;
|
||||||
|
|
||||||
/* Wait until lock has been released. We use increasing retry
|
if (ownerchanged)
|
||||||
intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
|
wtime = 0; /* Reset because owner changed. */
|
||||||
but reset it if the lock owner meanwhile changed. */
|
|
||||||
if (!wtime || ownerchanged)
|
|
||||||
wtime = 50;
|
|
||||||
else if (wtime < 800)
|
|
||||||
wtime *= 2;
|
|
||||||
else if (wtime == 800)
|
|
||||||
wtime = 2000;
|
|
||||||
else if (wtime < 8000)
|
|
||||||
wtime *= 2;
|
|
||||||
|
|
||||||
if (timeout > 0)
|
wtimereal = next_wait_interval (&wtime, &timeout);
|
||||||
{
|
if (!timeout)
|
||||||
if (wtime > timeout)
|
timedout = 1; /* remember. */
|
||||||
wtime = timeout;
|
|
||||||
timeout -= wtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
sumtime += wtime;
|
sumtime += wtimereal;
|
||||||
if (sumtime >= 1500)
|
if (sumtime >= 1500)
|
||||||
{
|
{
|
||||||
sumtime = 0;
|
sumtime = 0;
|
||||||
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
|
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
|
||||||
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
|
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
|
||||||
|
if (h->info_cb
|
||||||
|
&& h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
|
||||||
|
_("waiting for lock (held by %d%s) %s...\n"),
|
||||||
|
pid, maybe_dead,
|
||||||
|
maybe_deadlock(h)? _("(deadlock?) "):""))
|
||||||
|
{
|
||||||
|
my_set_errno (ECANCELED);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tv.tv_sec = wtimereal / 1000;
|
||||||
tv.tv_sec = wtime / 1000;
|
tv.tv_usec = (wtimereal % 1000) * 1000;
|
||||||
tv.tv_usec = (wtime % 1000) * 1000;
|
|
||||||
select (0, NULL, NULL, NULL, &tv);
|
select (0, NULL, NULL, NULL, &tv);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_set_errno (EACCES);
|
my_set_errno (timedout? ETIMEDOUT : EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /*HAVE_POSIX_SYSTEM*/
|
#endif /*HAVE_POSIX_SYSTEM*/
|
||||||
|
@ -1218,6 +1492,7 @@ static int
|
||||||
dotlock_take_w32 (dotlock_t h, long timeout)
|
dotlock_take_w32 (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
int wtime = 0;
|
int wtime = 0;
|
||||||
|
int timedout = 0;
|
||||||
int w32err;
|
int w32err;
|
||||||
OVERLAPPED ovl;
|
OVERLAPPED ovl;
|
||||||
|
|
||||||
|
@ -1236,38 +1511,39 @@ dotlock_take_w32 (dotlock_t h, long timeout)
|
||||||
{
|
{
|
||||||
my_error_2 (_("lock '%s' not made: %s\n"),
|
my_error_2 (_("lock '%s' not made: %s\n"),
|
||||||
h->lockname, w32_strerror (w32err));
|
h->lockname, w32_strerror (w32err));
|
||||||
my_set_errno (map_w32_to_errno (w32err));
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
_("lock '%s' not made: %s\n"),
|
||||||
|
h->lockname, w32_strerror (w32err));
|
||||||
|
_set_errno (map_w32_to_errno (w32err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout)
|
if (timeout)
|
||||||
{
|
{
|
||||||
/* Wait until lock has been released. We use retry intervals of
|
int wtimereal;
|
||||||
50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
|
|
||||||
if (!wtime)
|
|
||||||
wtime = 50;
|
|
||||||
else if (wtime < 800)
|
|
||||||
wtime *= 2;
|
|
||||||
else if (wtime == 800)
|
|
||||||
wtime = 2000;
|
|
||||||
else if (wtime < 8000)
|
|
||||||
wtime *= 2;
|
|
||||||
|
|
||||||
if (timeout > 0)
|
wtimereal = next_wait_interval (&wtime, &timeout);
|
||||||
{
|
if (!timeout)
|
||||||
if (wtime > timeout)
|
timedout = 1; /* remember. */
|
||||||
wtime = timeout;
|
|
||||||
timeout -= wtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wtime >= 800)
|
if (wtime >= 800)
|
||||||
my_info_1 (_("waiting for lock %s...\n"), h->lockname);
|
{
|
||||||
|
my_info_1 (_("waiting for lock %s...\n"), h->lockname);
|
||||||
|
if (h->info_cb
|
||||||
|
&& h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
|
||||||
|
_("waiting for lock %s...\n"), h->lockname))
|
||||||
|
{
|
||||||
|
my_set_errno (ECANCELED);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Sleep (wtime);
|
Sleep (wtimereal);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_set_errno (EACCES);
|
my_set_errno (timedout? ETIMEDOUT : EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||||
|
@ -1314,12 +1590,18 @@ dotlock_release_unix (dotlock_t h)
|
||||||
{
|
{
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_0 ("release_dotlock: lockfile error\n");
|
my_error_0 ("release_dotlock: lockfile error\n");
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"release_dotlock: lockfile error\n");
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( pid != getpid() || !same_node )
|
if ( pid != dotlock_get_process_id (h) || !same_node )
|
||||||
{
|
{
|
||||||
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
|
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_CONFLICT,
|
||||||
|
"release_dotlock: not our lock (pid=%d)\n", pid);
|
||||||
my_set_errno (EACCES);
|
my_set_errno (EACCES);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1329,6 +1611,10 @@ dotlock_release_unix (dotlock_t h)
|
||||||
saveerrno = errno;
|
saveerrno = errno;
|
||||||
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
|
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
|
||||||
h->lockname);
|
h->lockname);
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"release_dotlock: error removing lockfile '%s'\n",
|
||||||
|
h->lockname);
|
||||||
my_set_errno (saveerrno);
|
my_set_errno (saveerrno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1349,10 +1635,15 @@ dotlock_release_w32 (dotlock_t h)
|
||||||
memset (&ovl, 0, sizeof ovl);
|
memset (&ovl, 0, sizeof ovl);
|
||||||
if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
|
if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
|
||||||
{
|
{
|
||||||
int saveerrno = map_w32_to_errno (GetLastError ());
|
int ec = (int)GetLastError ();
|
||||||
|
|
||||||
my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
|
my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
|
||||||
h->lockname, w32_strerror (-1));
|
h->lockname, w32_strerror (ec));
|
||||||
my_set_errno (saveerrno);
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
|
||||||
|
"release_dotlock: error removing lockfile '%s': %s\n",
|
||||||
|
h->lockname, w32_strerror (ec));
|
||||||
|
my_set_errno (map_w32_to_errno (ec));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1383,6 +1674,9 @@ dotlock_release (dotlock_t h)
|
||||||
if ( !h->locked )
|
if ( !h->locked )
|
||||||
{
|
{
|
||||||
my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
|
my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
|
||||||
|
if (h->info_cb)
|
||||||
|
h->info_cb (h, h->info_cb_value, DOTLOCK_NOT_LOCKED,
|
||||||
|
"Oops, '%s' is not locked\n", h->lockname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,12 +97,35 @@ extern "C"
|
||||||
struct dotlock_handle;
|
struct dotlock_handle;
|
||||||
typedef struct dotlock_handle *dotlock_t;
|
typedef struct dotlock_handle *dotlock_t;
|
||||||
|
|
||||||
|
enum dotlock_reasons
|
||||||
|
{
|
||||||
|
DOTLOCK_CONFIG_TEST, /* Can't check system - function terminates. */
|
||||||
|
DOTLOCK_FILE_ERROR, /* General file error - function terminates. */
|
||||||
|
DOTLOCK_INV_FILE, /* Invalid file - function terminates. */
|
||||||
|
DOTLOCK_CONFLICT, /* Something is wrong - function terminates. */
|
||||||
|
DOTLOCK_NOT_LOCKED, /* Not locked - No action required. */
|
||||||
|
DOTLOCK_STALE_REMOVED, /* Stale lock file was removed - retrying. */
|
||||||
|
DOTLOCK_WAITING /* Waiting for the lock - may be terminated. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flags for dotlock_create. */
|
||||||
|
#define DOTLOCK_PREPARE_CREATE (1U << 5) /* Require dotlock_finish_create. */
|
||||||
|
#define DOTLOCK_LOCK_BY_PARENT (1U << 6) /* Used by dotlock util. */
|
||||||
|
#define DOTLOCK_LOCKED (1U << 7) /* Used by dotlock util. */
|
||||||
|
|
||||||
void dotlock_disable (void);
|
void dotlock_disable (void);
|
||||||
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
|
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
|
||||||
|
dotlock_t dotlock_finish_create (dotlock_t h, const char *file_to_lock);
|
||||||
void dotlock_set_fd (dotlock_t h, int fd);
|
void dotlock_set_fd (dotlock_t h, int fd);
|
||||||
int dotlock_get_fd (dotlock_t h);
|
int dotlock_get_fd (dotlock_t h);
|
||||||
|
void dotlock_set_info_cb (dotlock_t h,
|
||||||
|
int (*cb)(dotlock_t, void *,
|
||||||
|
enum dotlock_reasons reason,
|
||||||
|
const char *,...),
|
||||||
|
void *opaque);
|
||||||
void dotlock_destroy (dotlock_t h);
|
void dotlock_destroy (dotlock_t h);
|
||||||
int dotlock_take (dotlock_t h, long timeout);
|
int dotlock_take (dotlock_t h, long timeout);
|
||||||
|
int dotlock_is_locked (dotlock_t h);
|
||||||
int dotlock_release (dotlock_t h);
|
int dotlock_release (dotlock_t h);
|
||||||
void dotlock_remove_lockfiles (void);
|
void dotlock_remove_lockfiles (void);
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,15 @@
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
#else
|
#else
|
||||||
# include <errhandlingapi.h>
|
# ifdef HAVE_WINSOCK2_H
|
||||||
# include <handleapi.h>
|
# include <winsock2.h>
|
||||||
# include <libloaderapi.h>
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
# include "utf8conv.h"
|
# include "utf8conv.h"
|
||||||
# include "mischelp.h"
|
# include "mischelp.h"
|
||||||
# define RTLD_LAZY 0
|
# ifndef RTLD_LAZY
|
||||||
|
# define RTLD_LAZY 0
|
||||||
|
# endif
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
dlopen (const char *name, int flag)
|
dlopen (const char *name, int flag)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -42,7 +42,7 @@ int get_max_fds (void);
|
||||||
EXCEPT is not NULL, it is expected to be a list of file descriptors
|
EXCEPT is not NULL, it is expected to be a list of file descriptors
|
||||||
which are not to close. This list shall be sorted in ascending
|
which are not to close. This list shall be sorted in ascending
|
||||||
order with its end marked by -1. */
|
order with its end marked by -1. */
|
||||||
void close_all_fds (int first, int *except);
|
void close_all_fds (int first, const int *except);
|
||||||
|
|
||||||
|
|
||||||
/* Returns an array with all currently open file descriptors. The end
|
/* Returns an array with all currently open file descriptors. The end
|
||||||
|
@ -73,140 +73,98 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
|
||||||
void gnupg_close_pipe (int fd);
|
void gnupg_close_pipe (int fd);
|
||||||
|
|
||||||
|
|
||||||
#define GNUPG_SPAWN_NONBLOCK 16
|
/* The opaque type for a subprocess. */
|
||||||
#define GNUPG_SPAWN_RUN_ASFW 64
|
typedef struct gnupg_process *gnupg_process_t;
|
||||||
#define GNUPG_SPAWN_DETACHED 128
|
typedef struct gnupg_spawn_actions *gnupg_spawn_actions_t;
|
||||||
#define GNUPG_SPAWN_KEEP_STDIN 256
|
gpg_err_code_t gnupg_spawn_actions_new (gnupg_spawn_actions_t *r_act);
|
||||||
#define GNUPG_SPAWN_KEEP_STDOUT 512
|
void gnupg_spawn_actions_release (gnupg_spawn_actions_t act);
|
||||||
#define GNUPG_SPAWN_KEEP_STDERR 1024
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
void gnupg_spawn_actions_set_envvars (gnupg_spawn_actions_t, char *);
|
||||||
|
void gnupg_spawn_actions_set_redirect (gnupg_spawn_actions_t,
|
||||||
|
void *, void *, void *);
|
||||||
|
void gnupg_spawn_actions_set_inherit_handles (gnupg_spawn_actions_t, void **);
|
||||||
|
#else
|
||||||
|
void gnupg_spawn_actions_set_environ (gnupg_spawn_actions_t, char **);
|
||||||
|
void gnupg_spawn_actions_set_redirect (gnupg_spawn_actions_t, int, int, int);
|
||||||
|
void gnupg_spawn_actions_set_inherit_fds (gnupg_spawn_actions_t,
|
||||||
|
const int *);
|
||||||
|
void gnupg_spawn_actions_set_atfork (gnupg_spawn_actions_t,
|
||||||
|
void (*atfork)(void *), void *arg);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Fork and exec the program PGMNAME.
|
#define GNUPG_PROCESS_DETACHED (1 << 1)
|
||||||
|
|
||||||
If R_INFP is NULL connect stdin of the new process to /dev/null; if
|
/* Specify how to keep/connect standard fds. */
|
||||||
it is not NULL store the address of a pointer to a new estream
|
#define GNUPG_PROCESS_STDIN_PIPE (1 << 8)
|
||||||
there. If R_OUTFP is NULL connect stdout of the new process to
|
#define GNUPG_PROCESS_STDOUT_PIPE (1 << 9)
|
||||||
/dev/null; if it is not NULL store the address of a pointer to a
|
#define GNUPG_PROCESS_STDERR_PIPE (1 << 10)
|
||||||
new estream there. If R_ERRFP is NULL connect stderr of the new
|
#define GNUPG_PROCESS_STDINOUT_SOCKETPAIR (1 << 11)
|
||||||
process to /dev/null; if it is not NULL store the address of a
|
#define GNUPG_PROCESS_STDIN_KEEP (1 << 12)
|
||||||
pointer to a new estream there. On success the pid of the new
|
#define GNUPG_PROCESS_STDOUT_KEEP (1 << 13)
|
||||||
process is stored at PID. On error -1 is stored at PID and if
|
#define GNUPG_PROCESS_STDERR_KEEP (1 << 14)
|
||||||
R_OUTFP or R_ERRFP are not NULL, NULL is stored there.
|
#define GNUPG_PROCESS_STDFDS_SETTING ( GNUPG_PROCESS_STDIN_PIPE \
|
||||||
|
| GNUPG_PROCESS_STDOUT_PIPE | GNUPG_PROCESS_STDERR_PIPE \
|
||||||
|
| GNUPG_PROCESS_STDINOUT_SOCKETPAIR | GNUPG_PROCESS_STDIN_KEEP \
|
||||||
|
| GNUPG_PROCESS_STDOUT_KEEP | GNUPG_PROCESS_STDERR_KEEP)
|
||||||
|
|
||||||
The arguments for the process are expected in the NULL terminated
|
#define GNUPG_PROCESS_STREAM_NONBLOCK (1 << 16)
|
||||||
array ARGV. The program name itself should not be included there.
|
|
||||||
If PREEXEC is not NULL, the given function will be called right
|
|
||||||
before the exec.
|
|
||||||
|
|
||||||
IF EXCEPT is not NULL, it is expected to be an ordered list of file
|
/* Spawn PGMNAME. */
|
||||||
descriptors, terminated by an entry with the value (-1). These
|
gpg_err_code_t gnupg_process_spawn (const char *pgmname, const char *argv1[],
|
||||||
file descriptors won't be closed before spawning a new program.
|
unsigned int flags,
|
||||||
|
gnupg_spawn_actions_t act,
|
||||||
|
gnupg_process_t *r_process);
|
||||||
|
|
||||||
Returns 0 on success or an error code. Calling gnupg_wait_process
|
/* Get FDs for subprocess I/O. It is the caller which should care
|
||||||
and gnupg_release_process is required if the function succeeded.
|
FDs (closing FDs). */
|
||||||
|
gpg_err_code_t gnupg_process_get_fds (gnupg_process_t process,
|
||||||
|
unsigned int flags,
|
||||||
|
int *r_fd_in, int *r_fd_out,
|
||||||
|
int *r_fd_err);
|
||||||
|
|
||||||
FLAGS is a bit vector:
|
/* Get STREAMs for subprocess I/O. It is the caller which should care
|
||||||
|
STREAMs (closing STREAMs). */
|
||||||
|
gpg_err_code_t gnupg_process_get_streams (gnupg_process_t process,
|
||||||
|
unsigned int flags,
|
||||||
|
gpgrt_stream_t *r_fp_in,
|
||||||
|
gpgrt_stream_t *r_fp_out,
|
||||||
|
gpgrt_stream_t *r_fp_err);
|
||||||
|
|
||||||
GNUPG_SPAWN_NONBLOCK
|
enum gnupg_process_requests
|
||||||
If set the two output streams are created in non-blocking
|
{
|
||||||
mode and the input stream is switched to non-blocking mode.
|
/* Portable requests */
|
||||||
This is merely a convenience feature because the caller
|
GNUPG_PROCESS_NOP = 0,
|
||||||
could do the same with gpgrt_set_nonblock. Does not yet
|
GNUPG_PROCESS_GET_PROC_ID = 1,
|
||||||
work for Windows.
|
GNUPG_PROCESS_GET_EXIT_ID = 2,
|
||||||
|
|
||||||
GNUPG_SPAWN_DETACHED
|
/* POSIX only */
|
||||||
If set the process will be started as a background process.
|
GNUPG_PROCESS_GET_PID = 16,
|
||||||
This flag is only useful under W32 (but not W32CE) systems,
|
GNUPG_PROCESS_GET_WSTATUS = 17,
|
||||||
so that no new console is created and pops up a console
|
GNUPG_PROCESS_KILL = 18,
|
||||||
window when starting the server. Does not work on W32CE.
|
|
||||||
|
|
||||||
GNUPG_SPAWN_RUN_ASFW
|
/* Windows only */
|
||||||
On W32 (but not on W32CE) run AllowSetForegroundWindow for
|
GNUPG_PROCESS_GET_P_HANDLE = 32,
|
||||||
the child. Note that due to unknown problems this actually
|
GNUPG_PROCESS_GET_HANDLES = 33,
|
||||||
allows SetForegroundWindow for all children of this process.
|
GNUPG_PROCESS_GET_EXIT_CODE = 34,
|
||||||
|
GNUPG_PROCESS_KILL_WITH_EC = 35
|
||||||
|
};
|
||||||
|
|
||||||
GNUPG_SPAWN_KEEP_STDIN
|
/* Control of a process. */
|
||||||
GNUPG_SPAWN_KEEP_STDOUT
|
gpg_err_code_t gnupg_process_ctl (gnupg_process_t process,
|
||||||
GNUPG_SPAWN_KEEP_STDERR
|
unsigned int request, ...);
|
||||||
Do not assign /dev/null to a non-required standard file
|
|
||||||
descriptor.
|
|
||||||
|
|
||||||
*/
|
/* Wait for a single PROCESS. */
|
||||||
gpg_error_t
|
gpg_err_code_t gnupg_process_wait (gnupg_process_t process, int hang);
|
||||||
gnupg_spawn_process (const char *pgmname, const char *argv[],
|
|
||||||
int *execpt, unsigned int flags,
|
|
||||||
estream_t *r_infp,
|
|
||||||
estream_t *r_outfp,
|
|
||||||
estream_t *r_errfp,
|
|
||||||
pid_t *pid);
|
|
||||||
|
|
||||||
|
/* Terminate a PROCESS. */
|
||||||
|
gpg_err_code_t gnupg_process_terminate (gnupg_process_t process);
|
||||||
|
|
||||||
/* Simplified version of gnupg_spawn_process. This function forks and
|
/* Release PROCESS resources. */
|
||||||
then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
|
void gnupg_process_release (gnupg_process_t process);
|
||||||
and ERRFD to stderr (any of them may be -1 to connect them to
|
|
||||||
/dev/null). The arguments for the process are expected in the NULL
|
|
||||||
terminated array ARGV. The program name itself should not be
|
|
||||||
included there. Calling gnupg_wait_process and
|
|
||||||
gnupg_release_process is required. Returns 0 on success or an
|
|
||||||
error code. */
|
|
||||||
gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
|
|
||||||
const char *argv[],
|
|
||||||
int infd, int outfd, int errfd,
|
|
||||||
pid_t *pid);
|
|
||||||
|
|
||||||
|
|
||||||
/* If HANG is true, waits for the process identified by PID to exit;
|
|
||||||
if HANG is false, checks whether the process has terminated.
|
|
||||||
PGMNAME should be the same as supplied to the spawn function and is
|
|
||||||
only used for diagnostics. Return values:
|
|
||||||
|
|
||||||
0
|
|
||||||
The process exited successful. 0 is stored at R_EXITCODE.
|
|
||||||
|
|
||||||
GPG_ERR_GENERAL
|
|
||||||
The process exited without success. The exit code of process
|
|
||||||
is then stored at R_EXITCODE. An exit code of -1 indicates
|
|
||||||
that the process terminated abnormally (e.g. due to a signal).
|
|
||||||
|
|
||||||
GPG_ERR_TIMEOUT
|
|
||||||
The process is still running (returned only if HANG is false).
|
|
||||||
|
|
||||||
GPG_ERR_INV_VALUE
|
|
||||||
An invalid PID has been specified.
|
|
||||||
|
|
||||||
Other error codes may be returned as well. Unless otherwise noted,
|
|
||||||
-1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL
|
|
||||||
if the exit code is not required (in that case an error message will
|
|
||||||
be printed). Note that under Windows PID is not the process id but
|
|
||||||
the handle of the process. */
|
|
||||||
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
|
|
||||||
int *r_exitcode);
|
|
||||||
|
|
||||||
/* Like gnupg_wait_process, but for COUNT processes. */
|
|
||||||
gpg_error_t gnupg_wait_processes (const char **pgmnames, pid_t *pids,
|
|
||||||
size_t count, int hang, int *r_exitcodes);
|
|
||||||
|
|
||||||
|
|
||||||
/* Kill a process; that is send an appropriate signal to the process.
|
|
||||||
gnupg_wait_process must be called to actually remove the process
|
|
||||||
from the system. An invalid PID is ignored. */
|
|
||||||
void gnupg_kill_process (pid_t pid);
|
|
||||||
|
|
||||||
/* Release the process identified by PID. This function is actually
|
|
||||||
only required for Windows but it does not harm to always call it.
|
|
||||||
It is a nop if PID is invalid. */
|
|
||||||
void gnupg_release_process (pid_t pid);
|
|
||||||
|
|
||||||
|
|
||||||
/* Spawn a new process and immediately detach from it. The name of
|
|
||||||
the program to exec is PGMNAME and its arguments are in ARGV (the
|
|
||||||
programname is automatically passed as first argument).
|
|
||||||
Environment strings in ENVP are set. An error is returned if
|
|
||||||
pgmname is not executable; to make this work it is necessary to
|
|
||||||
provide an absolute file name. */
|
|
||||||
gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
|
|
||||||
const char *argv[],
|
|
||||||
const char *envp[] );
|
|
||||||
|
|
||||||
|
/* Wait for a multiple processes. */
|
||||||
|
gpg_err_code_t gnupg_process_wait_list (gnupg_process_t *process_list,
|
||||||
|
int count, int hang);
|
||||||
|
|
||||||
|
|
||||||
#endif /*GNUPG_COMMON_EXECHELP_H*/
|
#endif /*GNUPG_COMMON_EXECHELP_H*/
|
||||||
|
|
|
@ -38,10 +38,14 @@
|
||||||
#include <gpg-error.h>
|
#include <gpg-error.h>
|
||||||
|
|
||||||
#include <assuan.h>
|
#include <assuan.h>
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "membuf.h"
|
#include "membuf.h"
|
||||||
#include "mischelp.h"
|
#include "mischelp.h"
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
#define NEED_STRUCT_SPAWN_CB_ARG 1
|
||||||
|
#endif
|
||||||
#include "exechelp.h"
|
#include "exechelp.h"
|
||||||
#include "sysutils.h"
|
#include "sysutils.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -301,7 +305,6 @@ copy_buffer_flush (struct copy_buffer *c, estream_t sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Run the program PGMNAME with the command line arguments given in
|
/* Run the program PGMNAME with the command line arguments given in
|
||||||
* the NULL terminates array ARGV. If INPUT is not NULL it will be
|
* the NULL terminates array ARGV. If INPUT is not NULL it will be
|
||||||
* fed to stdin of the process. stderr is logged using log_info and
|
* fed to stdin of the process. stderr is logged using log_info and
|
||||||
|
@ -321,12 +324,16 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||||
void *status_cb_value)
|
void *status_cb_value)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
pid_t pid = (pid_t) -1;
|
gnupg_process_t proc = NULL;
|
||||||
estream_t infp = NULL;
|
estream_t infp = NULL;
|
||||||
estream_t extrafp = NULL;
|
estream_t extrafp = NULL;
|
||||||
estream_t outfp = NULL, errfp = NULL;
|
estream_t outfp = NULL, errfp = NULL;
|
||||||
es_poll_t fds[4];
|
es_poll_t fds[4];
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
HANDLE exceptclose[2];
|
||||||
|
#else
|
||||||
int exceptclose[2];
|
int exceptclose[2];
|
||||||
|
#endif
|
||||||
int extrapipe[2] = {-1, -1};
|
int extrapipe[2] = {-1, -1};
|
||||||
char extrafdbuf[20];
|
char extrafdbuf[20];
|
||||||
const char *argsave = NULL;
|
const char *argsave = NULL;
|
||||||
|
@ -335,7 +342,8 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||||
read_and_log_buffer_t fderrstate;
|
read_and_log_buffer_t fderrstate;
|
||||||
struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
|
struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
int dummy_exitcode;
|
gnupg_spawn_actions_t act = NULL;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
memset (fds, 0, sizeof fds);
|
memset (fds, 0, sizeof fds);
|
||||||
memset (&fderrstate, 0, sizeof fderrstate);
|
memset (&fderrstate, 0, sizeof fderrstate);
|
||||||
|
@ -389,16 +397,20 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||||
gpg_strerror (err));
|
gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
exceptclose[0] = extrapipe[0]; /* Do not close in child. */
|
/* Do not close in child. */
|
||||||
exceptclose[1] = -1;
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
exceptclose[i] = (HANDLE)_get_osfhandle (extrapipe[0]);
|
||||||
|
#else
|
||||||
|
exceptclose[i] = extrapipe[0];
|
||||||
|
#endif
|
||||||
/* Now find the argument marker and replace by the pipe's fd.
|
/* Now find the argument marker and replace by the pipe's fd.
|
||||||
Yeah, that is an ugly non-thread safe hack but it safes us to
|
Yeah, that is an ugly non-thread safe hack but it safes us to
|
||||||
create a copy of the array. */
|
create a copy of the array. */
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
snprintf (extrafdbuf, sizeof extrafdbuf, "-&%lu",
|
snprintf (extrafdbuf, sizeof extrafdbuf, "-&%lu",
|
||||||
(unsigned long)_get_osfhandle (extrapipe[0]));
|
(unsigned long)exceptclose[i]);
|
||||||
#else
|
#else
|
||||||
snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
|
snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", exceptclose[i]);
|
||||||
#endif
|
#endif
|
||||||
for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
|
for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
|
||||||
if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
|
if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
|
||||||
|
@ -407,14 +419,32 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||||
argv[argsaveidx] = extrafdbuf;
|
argv[argsaveidx] = extrafdbuf;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
exceptclose[0] = -1;
|
|
||||||
|
|
||||||
err = gnupg_spawn_process (pgmname, argv,
|
#ifdef HAVE_W32_SYSTEM
|
||||||
exceptclose, GNUPG_SPAWN_NONBLOCK,
|
exceptclose[i] = INVALID_HANDLE_VALUE;
|
||||||
input? &infp : NULL,
|
#else
|
||||||
&outfp, &errfp, &pid);
|
exceptclose[i] = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err = gnupg_spawn_actions_new (&act);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
gnupg_spawn_actions_set_inherit_handles (act, exceptclose);
|
||||||
|
#else
|
||||||
|
gnupg_spawn_actions_set_inherit_fds (act, exceptclose);
|
||||||
|
#endif
|
||||||
|
err = gnupg_process_spawn (pgmname, argv,
|
||||||
|
((input
|
||||||
|
? GNUPG_PROCESS_STDIN_PIPE
|
||||||
|
: 0)
|
||||||
|
| GNUPG_PROCESS_STDOUT_PIPE
|
||||||
|
| GNUPG_PROCESS_STDERR_PIPE), act, &proc);
|
||||||
|
gnupg_process_get_streams (proc, GNUPG_PROCESS_STREAM_NONBLOCK,
|
||||||
|
input? &infp : NULL, &outfp, &errfp);
|
||||||
if (extrapipe[0] != -1)
|
if (extrapipe[0] != -1)
|
||||||
close (extrapipe[0]);
|
close (extrapipe[0]);
|
||||||
if (argsave)
|
if (argsave)
|
||||||
|
@ -546,20 +576,26 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||||
es_fclose (outfp); outfp = NULL;
|
es_fclose (outfp); outfp = NULL;
|
||||||
es_fclose (errfp); errfp = NULL;
|
es_fclose (errfp); errfp = NULL;
|
||||||
|
|
||||||
err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
|
err = gnupg_process_wait (proc, 1);
|
||||||
pid = (pid_t)(-1);
|
if (!err)
|
||||||
|
{ /* To be compatible to old wait_process. */
|
||||||
|
int status;
|
||||||
|
|
||||||
|
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
|
||||||
|
if (status)
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (err && pid != (pid_t) -1)
|
if (err && proc)
|
||||||
gnupg_kill_process (pid);
|
gnupg_process_terminate (proc);
|
||||||
|
|
||||||
es_fclose (infp);
|
es_fclose (infp);
|
||||||
es_fclose (extrafp);
|
es_fclose (extrafp);
|
||||||
es_fclose (outfp);
|
es_fclose (outfp);
|
||||||
es_fclose (errfp);
|
es_fclose (errfp);
|
||||||
if (pid != (pid_t)(-1))
|
gnupg_process_release (proc);
|
||||||
gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
|
gnupg_spawn_actions_release (act);
|
||||||
gnupg_release_process (pid);
|
|
||||||
|
|
||||||
copy_buffer_shred (cpbuf_in);
|
copy_buffer_shred (cpbuf_in);
|
||||||
xfree (cpbuf_in);
|
xfree (cpbuf_in);
|
||||||
|
|
|
@ -94,7 +94,8 @@ start_agent (void)
|
||||||
agentargs.lc_ctype,
|
agentargs.lc_ctype,
|
||||||
agentargs.lc_messages,
|
agentargs.lc_messages,
|
||||||
agentargs.session_env,
|
agentargs.session_env,
|
||||||
1, agentargs.verbosity, 0, NULL, NULL);
|
ASSHELP_FLAG_AUTOSTART,
|
||||||
|
agentargs.verbosity, 0, NULL, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
/* Tell the agent that we support Pinentry notifications. No
|
/* Tell the agent that we support Pinentry notifications. No
|
||||||
|
|
264
common/gettime.c
264
common/gettime.c
|
@ -37,6 +37,11 @@
|
||||||
#ifdef HAVE_LANGINFO_H
|
#ifdef HAVE_LANGINFO_H
|
||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
|
#include <stdint.h> /* We use uint64_t. */
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
@ -61,6 +66,111 @@ static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
|
||||||
#define JD_DIFF 1721060L
|
#define JD_DIFF 1721060L
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
timegm() is a GNU function that might not be available everywhere.
|
||||||
|
It's basically the inverse of gmtime() - you give it a struct tm,
|
||||||
|
and get back a time_t. It differs from mktime() in that it handles
|
||||||
|
the case where the struct tm is UTC and the local environment isn't.
|
||||||
|
|
||||||
|
Note, that this replacement implementation might not be thread-safe!
|
||||||
|
|
||||||
|
Some BSDs don't handle the putenv("foo") case properly, so we use
|
||||||
|
unsetenv if the platform has it to remove environment variables.
|
||||||
|
*/
|
||||||
|
#ifndef HAVE_TIMEGM
|
||||||
|
time_t
|
||||||
|
timegm (struct tm *tm)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
uint64_t val = timegm_u64 (tm);
|
||||||
|
if (val == (uint64_t)(-1))
|
||||||
|
return (time_t)(-1);
|
||||||
|
return (time_t)val;
|
||||||
|
#else /* (Non thread safe implementation!) */
|
||||||
|
|
||||||
|
time_t answer;
|
||||||
|
char *zone;
|
||||||
|
|
||||||
|
zone=getenv("TZ");
|
||||||
|
putenv("TZ=UTC");
|
||||||
|
tzset();
|
||||||
|
answer=mktime(tm);
|
||||||
|
if(zone)
|
||||||
|
{
|
||||||
|
static char *old_zone;
|
||||||
|
|
||||||
|
if (!old_zone)
|
||||||
|
{
|
||||||
|
old_zone = malloc(3+strlen(zone)+1);
|
||||||
|
if (old_zone)
|
||||||
|
{
|
||||||
|
strcpy(old_zone,"TZ=");
|
||||||
|
strcat(old_zone,zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (old_zone)
|
||||||
|
putenv (old_zone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gnupg_unsetenv("TZ");
|
||||||
|
|
||||||
|
tzset();
|
||||||
|
return answer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif /*!HAVE_TIMEGM*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Version of the GNU timegm which returns an unsigned 64 bit integer
|
||||||
|
* instead of the usually signed time_t. On error (uint64_t)(-1) is
|
||||||
|
* returned. This function is mostly here because on 32 bit Windows
|
||||||
|
* we have an internal API to get the system time even after
|
||||||
|
* 2023-01-19. For 32 bit Unix we need to suffer from the too short
|
||||||
|
* time_t and no system function to construct the time from a tm. */
|
||||||
|
uint64_t
|
||||||
|
timegm_u64 (struct tm *tm)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
/* This one is thread safe. */
|
||||||
|
SYSTEMTIME st;
|
||||||
|
FILETIME ft;
|
||||||
|
unsigned long long cnsecs;
|
||||||
|
|
||||||
|
st.wYear = tm->tm_year + 1900;
|
||||||
|
st.wMonth = tm->tm_mon + 1;
|
||||||
|
st.wDay = tm->tm_mday;
|
||||||
|
st.wHour = tm->tm_hour;
|
||||||
|
st.wMinute = tm->tm_min;
|
||||||
|
st.wSecond = tm->tm_sec;
|
||||||
|
st.wMilliseconds = 0; /* Not available. */
|
||||||
|
st.wDayOfWeek = 0; /* Ignored. */
|
||||||
|
|
||||||
|
/* System time is UTC thus the conversion is pretty easy. */
|
||||||
|
if (!SystemTimeToFileTime (&st, &ft))
|
||||||
|
{
|
||||||
|
gpg_err_set_errno (EINVAL);
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
||||||
|
| ft.dwLowDateTime);
|
||||||
|
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
||||||
|
return (uint64_t)(cnsecs / 10000000ULL);
|
||||||
|
|
||||||
|
#else /*Unix*/
|
||||||
|
|
||||||
|
time_t t = timegm (tm);
|
||||||
|
if (t == (time_t)(-1))
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
if ((int64_t)t < 0)
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
return (uint64_t)t;
|
||||||
|
|
||||||
|
#endif /*Unix*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper for the time(3). We use this here so we can fake the time
|
/* Wrapper for the time(3). We use this here so we can fake the time
|
||||||
for tests */
|
for tests */
|
||||||
time_t
|
time_t
|
||||||
|
@ -172,6 +282,28 @@ make_timestamp (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Specialized version of atoi which returns an u32 instead of an int
|
||||||
|
* and caps the result at 2^32-2. Leading white space is skipped,
|
||||||
|
* scanning stops at at the first non-convertable byte. Note that we
|
||||||
|
* do not cap at 2^32-1 because that value is often used as error
|
||||||
|
* return. */
|
||||||
|
u32
|
||||||
|
scan_secondsstr (const char *string)
|
||||||
|
{
|
||||||
|
uint64_t value = 0;
|
||||||
|
|
||||||
|
while (*string == ' ' || *string == '\t')
|
||||||
|
string++;
|
||||||
|
for (; *string >= '0' && *string <= '9'; string++)
|
||||||
|
{
|
||||||
|
value *= 10;
|
||||||
|
value += atoi_1 (string);
|
||||||
|
if (value >= (u32)(-1))
|
||||||
|
return (u32)(-1) - 1;
|
||||||
|
}
|
||||||
|
return (u32)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Scan a date string and return a timestamp.
|
* Scan a date string and return a timestamp.
|
||||||
|
@ -208,7 +340,21 @@ scan_isodatestr( const char *string )
|
||||||
tmbuf.tm_isdst = -1;
|
tmbuf.tm_isdst = -1;
|
||||||
stamp = mktime( &tmbuf );
|
stamp = mktime( &tmbuf );
|
||||||
if( stamp == (time_t)-1 )
|
if( stamp == (time_t)-1 )
|
||||||
return 0;
|
{
|
||||||
|
/* mktime did not work. Construct an ISO timestring for noon
|
||||||
|
* of the given day instead. We keep the use of mktime for 64
|
||||||
|
* bit system to limit the risk of regressions. */
|
||||||
|
gnupg_isotime_t isobuf;
|
||||||
|
uint64_t tmp64;
|
||||||
|
|
||||||
|
snprintf (isobuf, 16, "%04d%02d%02dT120000", year, month, day);
|
||||||
|
tmp64 = isotime2epoch_u64 (isobuf);
|
||||||
|
if (tmp64 == (uint64_t)(-1))
|
||||||
|
return 0; /* Error. */
|
||||||
|
if (tmp64 >= (u32)(-1))
|
||||||
|
return 0; /* Error. */
|
||||||
|
return (u32)tmp64;
|
||||||
|
}
|
||||||
return stamp;
|
return stamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,18 +509,14 @@ string2isotime (gnupg_isotime_t atime, const char *string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Scan an ISO timestamp and return an Epoch based timestamp. The
|
/* Helper for isotime2epoch. Returns 0 on success. */
|
||||||
only supported format is "yyyymmddThhmmss[Z]" delimited by white
|
static int
|
||||||
space, nul, a colon or a comma. Returns (time_t)(-1) for an
|
isotime_make_tm (const char *string, struct tm *tmbuf)
|
||||||
invalid string. */
|
|
||||||
time_t
|
|
||||||
isotime2epoch (const char *string)
|
|
||||||
{
|
{
|
||||||
int year, month, day, hour, minu, sec;
|
int year, month, day, hour, minu, sec;
|
||||||
struct tm tmbuf;
|
|
||||||
|
|
||||||
if (!isotime_p (string))
|
if (!isotime_p (string))
|
||||||
return (time_t)(-1);
|
return -1;
|
||||||
|
|
||||||
year = atoi_4 (string);
|
year = atoi_4 (string);
|
||||||
month = atoi_2 (string + 4);
|
month = atoi_2 (string + 4);
|
||||||
|
@ -386,20 +528,48 @@ isotime2epoch (const char *string)
|
||||||
/* Basic checks. */
|
/* Basic checks. */
|
||||||
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|
||||||
|| hour > 23 || minu > 59 || sec > 61 )
|
|| hour > 23 || minu > 59 || sec > 61 )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset (tmbuf, 0, sizeof *tmbuf);
|
||||||
|
tmbuf->tm_sec = sec;
|
||||||
|
tmbuf->tm_min = minu;
|
||||||
|
tmbuf->tm_hour = hour;
|
||||||
|
tmbuf->tm_mday = day;
|
||||||
|
tmbuf->tm_mon = month-1;
|
||||||
|
tmbuf->tm_year = year - 1900;
|
||||||
|
tmbuf->tm_isdst = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Scan an ISO timestamp and return an Epoch based timestamp. The
|
||||||
|
only supported format is "yyyymmddThhmmss[Z]" delimited by white
|
||||||
|
space, nul, a colon or a comma. Returns (time_t)(-1) for an
|
||||||
|
invalid string. */
|
||||||
|
time_t
|
||||||
|
isotime2epoch (const char *string)
|
||||||
|
{
|
||||||
|
struct tm tmbuf;
|
||||||
|
|
||||||
|
if (isotime_make_tm (string, &tmbuf))
|
||||||
return (time_t)(-1);
|
return (time_t)(-1);
|
||||||
|
|
||||||
memset (&tmbuf, 0, sizeof tmbuf);
|
|
||||||
tmbuf.tm_sec = sec;
|
|
||||||
tmbuf.tm_min = minu;
|
|
||||||
tmbuf.tm_hour = hour;
|
|
||||||
tmbuf.tm_mday = day;
|
|
||||||
tmbuf.tm_mon = month-1;
|
|
||||||
tmbuf.tm_year = year - 1900;
|
|
||||||
tmbuf.tm_isdst = -1;
|
|
||||||
return timegm (&tmbuf);
|
return timegm (&tmbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
isotime2epoch_u64 (const char *string)
|
||||||
|
{
|
||||||
|
struct tm tmbuf;
|
||||||
|
|
||||||
|
if (isotime_make_tm (string, &tmbuf))
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
|
||||||
|
return timegm_u64 (&tmbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Convert an Epoch time to an iso time stamp. */
|
/* Convert an Epoch time to an iso time stamp. */
|
||||||
void
|
void
|
||||||
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
|
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
|
||||||
|
@ -453,41 +623,6 @@ isodate_human_to_tm (const char *string, struct tm *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
|
|
||||||
If you change it, then update the other one too. */
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
static time_t
|
|
||||||
_win32_timegm (struct tm *tm)
|
|
||||||
{
|
|
||||||
/* This one is thread safe. */
|
|
||||||
SYSTEMTIME st;
|
|
||||||
FILETIME ft;
|
|
||||||
unsigned long long cnsecs;
|
|
||||||
|
|
||||||
st.wYear = tm->tm_year + 1900;
|
|
||||||
st.wMonth = tm->tm_mon + 1;
|
|
||||||
st.wDay = tm->tm_mday;
|
|
||||||
st.wHour = tm->tm_hour;
|
|
||||||
st.wMinute = tm->tm_min;
|
|
||||||
st.wSecond = tm->tm_sec;
|
|
||||||
st.wMilliseconds = 0; /* Not available. */
|
|
||||||
st.wDayOfWeek = 0; /* Ignored. */
|
|
||||||
|
|
||||||
/* System time is UTC thus the conversion is pretty easy. */
|
|
||||||
if (!SystemTimeToFileTime (&st, &ft))
|
|
||||||
{
|
|
||||||
gpg_err_set_errno (EINVAL);
|
|
||||||
return (time_t)(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
|
||||||
| ft.dwLowDateTime);
|
|
||||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
|
||||||
return (time_t)(cnsecs / 10000000ULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Parse the string TIMESTAMP into a time_t. The string may either be
|
/* Parse the string TIMESTAMP into a time_t. The string may either be
|
||||||
seconds since Epoch or in the ISO 8601 format like
|
seconds since Epoch or in the ISO 8601 format like
|
||||||
"20390815T143012". Returns 0 for an empty string or seconds since
|
"20390815T143012". Returns 0 for an empty string or seconds since
|
||||||
|
@ -496,7 +631,11 @@ _win32_timegm (struct tm *tm)
|
||||||
|
|
||||||
This function is a copy of
|
This function is a copy of
|
||||||
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
|
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
|
||||||
then update the other one too. */
|
then update the other one too.
|
||||||
|
|
||||||
|
FIXME: Replace users of this function by one of the more modern
|
||||||
|
functions or change the return type to u64.
|
||||||
|
*/
|
||||||
time_t
|
time_t
|
||||||
parse_timestamp (const char *timestamp, char **endp)
|
parse_timestamp (const char *timestamp, char **endp)
|
||||||
{
|
{
|
||||||
|
@ -532,24 +671,7 @@ parse_timestamp (const char *timestamp, char **endp)
|
||||||
buf.tm_min = atoi_2 (timestamp+11);
|
buf.tm_min = atoi_2 (timestamp+11);
|
||||||
buf.tm_sec = atoi_2 (timestamp+13);
|
buf.tm_sec = atoi_2 (timestamp+13);
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
return _win32_timegm (&buf);
|
|
||||||
#else
|
|
||||||
#ifdef HAVE_TIMEGM
|
|
||||||
return timegm (&buf);
|
return timegm (&buf);
|
||||||
#else
|
|
||||||
{
|
|
||||||
time_t tim;
|
|
||||||
|
|
||||||
putenv ("TZ=UTC");
|
|
||||||
tim = mktime (&buf);
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
|
|
||||||
#endif
|
|
||||||
return tim;
|
|
||||||
}
|
|
||||||
#endif /* !HAVE_TIMEGM */
|
|
||||||
#endif /* !HAVE_W32_SYSTEM */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return (time_t)strtoul (timestamp, endp, 10);
|
return (time_t)strtoul (timestamp, endp, 10);
|
||||||
|
@ -728,7 +850,7 @@ asctimestamp (u32 stamp)
|
||||||
* 2018 has a lot of additional support but that will for sure
|
* 2018 has a lot of additional support but that will for sure
|
||||||
* break other things. We should move to ISO strings to get
|
* break other things. We should move to ISO strings to get
|
||||||
* rid of such problems. */
|
* rid of such problems. */
|
||||||
setlocale (LC_TIME, "");
|
setlocale (LC_TIME, ".UTF8");
|
||||||
done = 1;
|
done = 1;
|
||||||
/* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */
|
/* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */
|
||||||
/* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */
|
/* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
#include <time.h> /* We need time_t. */
|
#include <time.h> /* We need time_t. */
|
||||||
#include <gpg-error.h> /* We need gpg_error_t. */
|
#include <gpg-error.h> /* We need gpg_error_t. */
|
||||||
|
#include <stdint.h> /* We use uint64_t. */
|
||||||
|
|
||||||
/* A type to hold the ISO time. Note that this is the same as
|
/* A type to hold the ISO time. Note that this is the same as
|
||||||
the KSBA type ksba_isotime_t. */
|
the KSBA type ksba_isotime_t. */
|
||||||
|
@ -43,6 +43,11 @@ typedef char gnupg_isotime_t[16];
|
||||||
#define GNUPG_ISOTIME_NONE \
|
#define GNUPG_ISOTIME_NONE \
|
||||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
|
||||||
|
#ifndef HAVE_TIMEGM
|
||||||
|
time_t timegm (struct tm *tm);
|
||||||
|
#endif /*!HAVE_TIMEGM*/
|
||||||
|
uint64_t timegm_u64 (struct tm *tm);
|
||||||
|
|
||||||
time_t gnupg_get_time (void);
|
time_t gnupg_get_time (void);
|
||||||
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
|
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
|
||||||
void gnupg_get_isotime (gnupg_isotime_t timebuf);
|
void gnupg_get_isotime (gnupg_isotime_t timebuf);
|
||||||
|
@ -51,11 +56,13 @@ int gnupg_faked_time_p (void);
|
||||||
u32 make_timestamp (void);
|
u32 make_timestamp (void);
|
||||||
char *elapsed_time_string (time_t since, time_t now);
|
char *elapsed_time_string (time_t since, time_t now);
|
||||||
|
|
||||||
|
u32 scan_secondsstr (const char *string);
|
||||||
u32 scan_isodatestr (const char *string);
|
u32 scan_isodatestr (const char *string);
|
||||||
int isotime_p (const char *string);
|
int isotime_p (const char *string);
|
||||||
int isotime_human_p (const char *string, int date_only);
|
int isotime_human_p (const char *string, int date_only);
|
||||||
size_t string2isotime (gnupg_isotime_t atime, const char *string);
|
size_t string2isotime (gnupg_isotime_t atime, const char *string);
|
||||||
time_t isotime2epoch (const char *string);
|
time_t isotime2epoch (const char *string);
|
||||||
|
uint64_t isotime2epoch_u64 (const char *string);
|
||||||
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
|
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
|
||||||
int isodate_human_to_tm (const char *string, struct tm *t);
|
int isodate_human_to_tm (const char *string, struct tm *t);
|
||||||
time_t parse_timestamp (const char *timestamp, char **endp);
|
time_t parse_timestamp (const char *timestamp, char **endp);
|
||||||
|
|
675
common/homedir.c
675
common/homedir.c
|
@ -1,7 +1,7 @@
|
||||||
/* homedir.c - Setup the home directory.
|
/* homedir.c - Setup the home directory.
|
||||||
* Copyright (C) 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
|
* Copyright (C) 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2013, 2016 Werner Koch
|
* Copyright (C) 2013, 2016 Werner Koch
|
||||||
* Copyright (C) 2021 g10 Code GmbH
|
* Copyright (C) 2021, 2024 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
|
@ -77,6 +77,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Mode flags for unix_rootdir. */
|
||||||
|
enum wantdir_values {
|
||||||
|
WANTDIR_ROOT = 0,
|
||||||
|
WANTDIR_SYSCONF,
|
||||||
|
WANTDIR_SOCKET
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* The GnuPG homedir. This is only accessed by the functions
|
/* The GnuPG homedir. This is only accessed by the functions
|
||||||
* gnupg_homedir and gnupg_set_homedir. Malloced. */
|
* gnupg_homedir and gnupg_set_homedir. Malloced. */
|
||||||
static char *the_gnupg_homedir;
|
static char *the_gnupg_homedir;
|
||||||
|
@ -85,6 +93,22 @@ static char *the_gnupg_homedir;
|
||||||
static byte non_default_homedir;
|
static byte non_default_homedir;
|
||||||
|
|
||||||
|
|
||||||
|
/* An object to store information taken from a gpgconf.ctl file. This
|
||||||
|
* is parsed early at startup time and never changed later. */
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
unsigned int checked:1; /* True if we have checked for a gpgconf.ctl. */
|
||||||
|
unsigned int found:1; /* True if a gpgconf.ctl was found. */
|
||||||
|
unsigned int empty:1; /* The file is empty except for comments. */
|
||||||
|
unsigned int valid:1; /* The entries in gpgconf.ctl are valid. */
|
||||||
|
unsigned int portable:1;/* Windows portable installation. */
|
||||||
|
char *gnupg; /* The "gnupg" directory part. */
|
||||||
|
char *rootdir; /* rootdir or NULL */
|
||||||
|
char *sysconfdir; /* sysconfdir or NULL */
|
||||||
|
char *socketdir; /* socketdir or NULL */
|
||||||
|
} gpgconf_ctl;
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
/* A flag used to indicate that a control file for gpgconf has been
|
/* A flag used to indicate that a control file for gpgconf has been
|
||||||
* detected. Under Windows the presence of this file indicates a
|
* detected. Under Windows the presence of this file indicates a
|
||||||
|
@ -111,6 +135,87 @@ static byte w32_bin_is_bin;
|
||||||
static const char *w32_rootdir (void);
|
static const char *w32_rootdir (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Return the name of the gnupg dir. This is usually "gnupg". */
|
||||||
|
static const char *
|
||||||
|
my_gnupg_dirname (void)
|
||||||
|
{
|
||||||
|
if (gpgconf_ctl.valid && gpgconf_ctl.gnupg)
|
||||||
|
return gpgconf_ctl.gnupg;
|
||||||
|
return "gnupg";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the hardwired home directory which is not anymore so
|
||||||
|
* hardwired because it may now be modified using the gpgconf.ctl
|
||||||
|
* "gnupg" keyword. */
|
||||||
|
static const char *
|
||||||
|
my_fixed_default_homedir (void)
|
||||||
|
{
|
||||||
|
if (gpgconf_ctl.valid && gpgconf_ctl.gnupg)
|
||||||
|
{
|
||||||
|
static char *name;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
name = xmalloc (strlen (GNUPG_DEFAULT_HOMEDIR)
|
||||||
|
+ strlen (gpgconf_ctl.gnupg) + 1);
|
||||||
|
strcpy (name, GNUPG_DEFAULT_HOMEDIR);
|
||||||
|
p = strrchr (name, '/');
|
||||||
|
if (p)
|
||||||
|
p++;
|
||||||
|
else
|
||||||
|
p = name;
|
||||||
|
if (*p == '.')
|
||||||
|
p++; /* Keep a leading dot. */
|
||||||
|
strcpy (p, gpgconf_ctl.gnupg);
|
||||||
|
gpgrt_annotate_leaked_object (name);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return GNUPG_DEFAULT_HOMEDIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Under Windows we need to modify the standard registry key with the
|
||||||
|
* "gnupg" keyword from a gpgconf.ctl. */
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
const char *
|
||||||
|
gnupg_registry_dir (void)
|
||||||
|
{
|
||||||
|
if (gpgconf_ctl.valid && gpgconf_ctl.gnupg)
|
||||||
|
{
|
||||||
|
static char *name;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
{
|
||||||
|
name = xmalloc (strlen (GNUPG_REGISTRY_DIR)
|
||||||
|
+ strlen (gpgconf_ctl.gnupg) + 1);
|
||||||
|
strcpy (name, GNUPG_REGISTRY_DIR);
|
||||||
|
p = strrchr (name, '\\');
|
||||||
|
if (p)
|
||||||
|
p++;
|
||||||
|
else
|
||||||
|
p = name;
|
||||||
|
strcpy (p, gpgconf_ctl.gnupg);
|
||||||
|
if (!strncmp (p, "gnupg", 5))
|
||||||
|
{
|
||||||
|
/* Registry keys are case-insensitive and we use a
|
||||||
|
* capitalized version of gnupg by default. So, if the
|
||||||
|
* new value starts with "gnupg" we apply the usual
|
||||||
|
* capitalization for this first part. */
|
||||||
|
p[0] = 'G';
|
||||||
|
p[3] = 'P';
|
||||||
|
p[4] = 'G';
|
||||||
|
}
|
||||||
|
gpgrt_annotate_leaked_object (name);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
return GNUPG_REGISTRY_DIR;
|
||||||
|
}
|
||||||
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
|
|
||||||
/* This is a helper function to load and call a Windows function from
|
/* This is a helper function to load and call a Windows function from
|
||||||
|
@ -214,6 +319,10 @@ copy_dir_with_fixup (const char *newdir)
|
||||||
{
|
{
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
char *p;
|
char *p;
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
char *p0;
|
||||||
|
const char *s;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!*newdir)
|
if (!*newdir)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -245,6 +354,29 @@ copy_dir_with_fixup (const char *newdir)
|
||||||
*p-- = 0;
|
*p-- = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hack to mitigate badly doubled backslashes. */
|
||||||
|
s = result? result : newdir;
|
||||||
|
if (s[0] == '\\' && s[1] == '\\' && s[2] != '\\')
|
||||||
|
{
|
||||||
|
/* UNC (\\Servername\file) or Long UNC (\\?\Servername\file)
|
||||||
|
* Does not seem to be double quoted. */
|
||||||
|
}
|
||||||
|
else if (strstr (s, "\\\\"))
|
||||||
|
{
|
||||||
|
/* Double quotes detected. Fold them into one because that is
|
||||||
|
* what what Windows does. This way we get a unique hash
|
||||||
|
* regardless of the number of doubled backslashes. */
|
||||||
|
if (!result)
|
||||||
|
result = xstrdup (newdir);
|
||||||
|
for (p0=p=result; *p; p++)
|
||||||
|
{
|
||||||
|
*p0++ = *p;
|
||||||
|
while (*p == '\\' && p[1] == '\\')
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
*p0 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
if (newdir[strlen (newdir)-1] == '/')
|
if (newdir[strlen (newdir)-1] == '/')
|
||||||
|
@ -289,7 +421,7 @@ standard_homedir (void)
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (path)
|
if (path)
|
||||||
{
|
{
|
||||||
dir = xstrconcat (path, "\\gnupg", NULL);
|
dir = xstrconcat (path, "\\", my_gnupg_dirname (), NULL);
|
||||||
xfree (path);
|
xfree (path);
|
||||||
gpgrt_annotate_leaked_object (dir);
|
gpgrt_annotate_leaked_object (dir);
|
||||||
|
|
||||||
|
@ -300,12 +432,12 @@ standard_homedir (void)
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dir = GNUPG_DEFAULT_HOMEDIR;
|
dir = my_fixed_default_homedir ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dir;
|
return dir;
|
||||||
#else/*!HAVE_W32_SYSTEM*/
|
#else/*!HAVE_W32_SYSTEM*/
|
||||||
return GNUPG_DEFAULT_HOMEDIR;
|
return my_fixed_default_homedir ();
|
||||||
#endif /*!HAVE_W32_SYSTEM*/
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +471,7 @@ default_homedir (void)
|
||||||
* warning if the homedir has been taken from the
|
* warning if the homedir has been taken from the
|
||||||
* registry. */
|
* registry. */
|
||||||
tmp = read_w32_registry_string (NULL,
|
tmp = read_w32_registry_string (NULL,
|
||||||
GNUPG_REGISTRY_DIR,
|
gnupg_registry_dir (),
|
||||||
"HomeDir");
|
"HomeDir");
|
||||||
if (tmp && !*tmp)
|
if (tmp && !*tmp)
|
||||||
{
|
{
|
||||||
|
@ -364,7 +496,7 @@ default_homedir (void)
|
||||||
#endif /*HAVE_W32_SYSTEM*/
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
if (!dir || !*dir)
|
if (!dir || !*dir)
|
||||||
dir = GNUPG_DEFAULT_HOMEDIR;
|
dir = my_fixed_default_homedir ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -392,6 +524,234 @@ default_homedir (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if S can be inteprtated as true. This is uised for
|
||||||
|
* keywords in gpgconf.ctl. Spaces must have been trimmed. */
|
||||||
|
static int
|
||||||
|
string_is_true (const char *s)
|
||||||
|
{
|
||||||
|
return (atoi (s)
|
||||||
|
|| !ascii_strcasecmp (s, "yes")
|
||||||
|
|| !ascii_strcasecmp (s, "true")
|
||||||
|
|| !ascii_strcasecmp (s, "fact"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is used to parse the gpgconf.ctl file and set the
|
||||||
|
* information ito the gpgconf_ctl structure. This is called once
|
||||||
|
* with the full filename of gpgconf.ctl. There are two callers: One
|
||||||
|
* used on Windows and one on Unix. No error return but diagnostics
|
||||||
|
* are printed. */
|
||||||
|
static void
|
||||||
|
parse_gpgconf_ctl (const char *fname)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char *p;
|
||||||
|
char *line;
|
||||||
|
size_t linelen;
|
||||||
|
ssize_t length;
|
||||||
|
estream_t fp;
|
||||||
|
const char *name;
|
||||||
|
int anyitem = 0;
|
||||||
|
int ignoreall = 0;
|
||||||
|
char *gnupgval = NULL;
|
||||||
|
char *rootdir = NULL;
|
||||||
|
char *sysconfdir = NULL;
|
||||||
|
char *socketdir = NULL;
|
||||||
|
|
||||||
|
if (gpgconf_ctl.checked)
|
||||||
|
return; /* Just in case this is called a second time. */
|
||||||
|
gpgconf_ctl.checked = 1;
|
||||||
|
gpgconf_ctl.found = 0;
|
||||||
|
gpgconf_ctl.valid = 0;
|
||||||
|
gpgconf_ctl.empty = 0;
|
||||||
|
|
||||||
|
if (gnupg_access (fname, F_OK))
|
||||||
|
return; /* No gpgconf.ctl file. */
|
||||||
|
|
||||||
|
/* log_info ("detected '%s'\n", buffer); */
|
||||||
|
fp = es_fopen (fname, "r");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_info ("error opening '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gpgconf_ctl.found = 1;
|
||||||
|
|
||||||
|
line = NULL;
|
||||||
|
linelen = 0;
|
||||||
|
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
|
||||||
|
{
|
||||||
|
static const char *names[] =
|
||||||
|
{
|
||||||
|
"gnupg",
|
||||||
|
"rootdir",
|
||||||
|
"sysconfdir",
|
||||||
|
"socketdir",
|
||||||
|
"portable",
|
||||||
|
".enable"
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* Strip NL and CR, if present. */
|
||||||
|
while (length > 0
|
||||||
|
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
||||||
|
line[--length] = 0;
|
||||||
|
trim_spaces (line);
|
||||||
|
if (*line == '#' || !*line)
|
||||||
|
continue;
|
||||||
|
anyitem = 1;
|
||||||
|
|
||||||
|
/* Find the keyword. */
|
||||||
|
name = NULL;
|
||||||
|
p = NULL;
|
||||||
|
for (i=0; i < DIM (names); i++)
|
||||||
|
{
|
||||||
|
n = strlen (names[i]);
|
||||||
|
if (!strncmp (line, names[i], n))
|
||||||
|
{
|
||||||
|
while (line[n] == ' ' || line[n] == '\t')
|
||||||
|
n++;
|
||||||
|
if (line[n] == '=')
|
||||||
|
{
|
||||||
|
name = names[i];
|
||||||
|
p = line + n + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!name)
|
||||||
|
continue; /* Keyword not known. */
|
||||||
|
|
||||||
|
trim_spaces (p);
|
||||||
|
p = substitute_envvars (p);
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_info ("error getting %s from gpgconf.ctl: %s\n",
|
||||||
|
name, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, ".enable"))
|
||||||
|
{
|
||||||
|
if (string_is_true (p))
|
||||||
|
; /* Yes, this file shall be used. */
|
||||||
|
else
|
||||||
|
ignoreall = 1; /* No, this file shall be ignored. */
|
||||||
|
xfree (p);
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "gnupg"))
|
||||||
|
{
|
||||||
|
xfree (gnupgval);
|
||||||
|
gnupgval = p;
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "sysconfdir"))
|
||||||
|
{
|
||||||
|
xfree (sysconfdir);
|
||||||
|
sysconfdir = p;
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "socketdir"))
|
||||||
|
{
|
||||||
|
xfree (socketdir);
|
||||||
|
socketdir = p;
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "rootdir"))
|
||||||
|
{
|
||||||
|
xfree (rootdir);
|
||||||
|
rootdir = p;
|
||||||
|
}
|
||||||
|
else if (!strcmp (name, "portable"))
|
||||||
|
{
|
||||||
|
gpgconf_ctl.portable = string_is_true (p);
|
||||||
|
xfree (p);
|
||||||
|
}
|
||||||
|
else /* Unknown keyword. */
|
||||||
|
xfree (p);
|
||||||
|
}
|
||||||
|
if (es_ferror (fp))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_info ("error reading '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
ignoreall = 1; /* Force all entries to invalid. */
|
||||||
|
}
|
||||||
|
es_fclose (fp);
|
||||||
|
xfree (line);
|
||||||
|
|
||||||
|
if (ignoreall)
|
||||||
|
; /* Forced error. Note that .found is still set. */
|
||||||
|
else if (gnupgval && (!*gnupgval || strpbrk (gnupgval, "/\\")))
|
||||||
|
{
|
||||||
|
/* We don't allow a slash or backslash in the value because our
|
||||||
|
* code assumes this is a single directory name. */
|
||||||
|
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
|
||||||
|
"gnupg", gnupgval);
|
||||||
|
}
|
||||||
|
else if (rootdir && (!*rootdir || *rootdir != '/'))
|
||||||
|
{
|
||||||
|
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
|
||||||
|
"rootdir", rootdir);
|
||||||
|
}
|
||||||
|
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
|
||||||
|
{
|
||||||
|
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
|
||||||
|
"sysconfdir", sysconfdir);
|
||||||
|
}
|
||||||
|
else if (socketdir && (!*socketdir || *socketdir != '/'))
|
||||||
|
{
|
||||||
|
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
|
||||||
|
"socketdir", socketdir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (gnupgval)
|
||||||
|
{
|
||||||
|
gpgconf_ctl.gnupg = gnupgval;
|
||||||
|
gpgrt_annotate_leaked_object (gpgconf_ctl.gnupg);
|
||||||
|
/* log_info ("want gnupg '%s'\n", dir); */
|
||||||
|
}
|
||||||
|
if (rootdir)
|
||||||
|
{
|
||||||
|
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
|
||||||
|
rootdir[strlen (rootdir)-1] = 0;
|
||||||
|
gpgconf_ctl.rootdir = rootdir;
|
||||||
|
gpgrt_annotate_leaked_object (gpgconf_ctl.rootdir);
|
||||||
|
/* log_info ("want rootdir '%s'\n", dir); */
|
||||||
|
}
|
||||||
|
if (sysconfdir)
|
||||||
|
{
|
||||||
|
while (*sysconfdir && sysconfdir[strlen (sysconfdir)-1] == '/')
|
||||||
|
sysconfdir[strlen (sysconfdir)-1] = 0;
|
||||||
|
gpgconf_ctl.sysconfdir = sysconfdir;
|
||||||
|
gpgrt_annotate_leaked_object (gpgconf_ctl.sysconfdir);
|
||||||
|
/* log_info ("want sysconfdir '%s'\n", sdir); */
|
||||||
|
}
|
||||||
|
if (socketdir)
|
||||||
|
{
|
||||||
|
while (*socketdir && socketdir[strlen (socketdir)-1] == '/')
|
||||||
|
socketdir[strlen (socketdir)-1] = 0;
|
||||||
|
gpgconf_ctl.socketdir = socketdir;
|
||||||
|
gpgrt_annotate_leaked_object (gpgconf_ctl.socketdir);
|
||||||
|
/* log_info ("want socketdir '%s'\n", s2dir); */
|
||||||
|
}
|
||||||
|
gpgconf_ctl.valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpgconf_ctl.empty = !anyitem;
|
||||||
|
if (!gpgconf_ctl.valid)
|
||||||
|
{
|
||||||
|
/* Error reading some entries - clear them all. */
|
||||||
|
xfree (gnupgval);
|
||||||
|
xfree (rootdir);
|
||||||
|
xfree (sysconfdir);
|
||||||
|
xfree (socketdir);
|
||||||
|
gpgconf_ctl.gnupg = NULL;
|
||||||
|
gpgconf_ctl.rootdir = NULL;
|
||||||
|
gpgconf_ctl.sysconfdir = NULL;
|
||||||
|
gpgconf_ctl.socketdir = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
/* Check whether gpgconf is installed and if so read the gpgconf.ctl
|
/* Check whether gpgconf is installed and if so read the gpgconf.ctl
|
||||||
file. */
|
file. */
|
||||||
|
@ -404,17 +764,20 @@ check_portable_app (const char *dir)
|
||||||
if (!gnupg_access (fname, F_OK))
|
if (!gnupg_access (fname, F_OK))
|
||||||
{
|
{
|
||||||
strcpy (fname + strlen (fname) - 3, "ctl");
|
strcpy (fname + strlen (fname) - 3, "ctl");
|
||||||
if (!gnupg_access (fname, F_OK))
|
parse_gpgconf_ctl (fname);
|
||||||
|
if ((gpgconf_ctl.found && gpgconf_ctl.empty)
|
||||||
|
|| (gpgconf_ctl.valid && gpgconf_ctl.portable))
|
||||||
{
|
{
|
||||||
/* gpgconf.ctl file found. Record this fact. */
|
unsigned int flags;
|
||||||
|
|
||||||
|
/* Classic gpgconf.ctl file found. This is a portable
|
||||||
|
* application. Note that if there are any items in that
|
||||||
|
* file we don't consider this a portable application unless
|
||||||
|
* the (later added) ".portable" keyword has also been
|
||||||
|
* seen. */
|
||||||
w32_portable_app = 1;
|
w32_portable_app = 1;
|
||||||
{
|
log_get_prefix (&flags);
|
||||||
unsigned int flags;
|
log_set_prefix (NULL, (flags | GPGRT_LOG_NO_REGISTRY));
|
||||||
log_get_prefix (&flags);
|
|
||||||
log_set_prefix (NULL, (flags | GPGRT_LOG_NO_REGISTRY));
|
|
||||||
}
|
|
||||||
/* FIXME: We should read the file to detect special flags
|
|
||||||
and print a warning if we don't understand them */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
|
@ -491,27 +854,16 @@ w32_rootdir (void)
|
||||||
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
|
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
|
||||||
* entry is returned. */
|
* entry is returned. */
|
||||||
static const char *
|
static const char *
|
||||||
unix_rootdir (int want_sysconfdir)
|
unix_rootdir (enum wantdir_values wantdir)
|
||||||
{
|
{
|
||||||
static int checked;
|
if (!gpgconf_ctl.checked)
|
||||||
static char *dir; /* for the rootdir */
|
|
||||||
static char *sdir; /* for the sysconfdir */
|
|
||||||
|
|
||||||
if (!checked)
|
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
size_t bufsize = 256-1;
|
size_t bufsize = 256-1;
|
||||||
int nread;
|
int nread;
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char *line;
|
|
||||||
size_t linelen;
|
|
||||||
ssize_t length;
|
|
||||||
estream_t fp;
|
|
||||||
char *rootdir;
|
|
||||||
char *sysconfdir;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
int ignoreall = 0;
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -551,7 +903,7 @@ unix_rootdir (int want_sysconfdir)
|
||||||
if (!*buffer)
|
if (!*buffer)
|
||||||
{
|
{
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
checked = 1;
|
gpgconf_ctl.checked = 1;
|
||||||
return NULL; /* Error - assume no gpgconf.ctl. */
|
return NULL; /* Error - assume no gpgconf.ctl. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,175 +911,39 @@ unix_rootdir (int want_sysconfdir)
|
||||||
if (!p)
|
if (!p)
|
||||||
{
|
{
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
checked = 1;
|
gpgconf_ctl.checked = 1;
|
||||||
return NULL; /* Erroneous /proc - assume no gpgconf.ctl. */
|
return NULL; /* Erroneous /proc - assume no gpgconf.ctl. */
|
||||||
}
|
}
|
||||||
*p = 0; /* BUFFER has the directory. */
|
*p = 0; /* BUFFER has the directory. */
|
||||||
if ((p = strrchr (buffer, '/')))
|
if (!(p = strrchr (buffer, '/')))
|
||||||
{
|
|
||||||
/* Strip one part and expect the file below a bin dir. */
|
|
||||||
*p = 0;
|
|
||||||
p = xstrconcat (buffer, "/bin/gpgconf.ctl", NULL);
|
|
||||||
xfree (buffer);
|
|
||||||
buffer = p;
|
|
||||||
}
|
|
||||||
else /* !p */
|
|
||||||
{
|
{
|
||||||
/* Installed in the root which is not a good idea. Assume
|
/* Installed in the root which is not a good idea. Assume
|
||||||
* no gpgconf.ctl. */
|
* no gpgconf.ctl. */
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
checked = 1;
|
gpgconf_ctl.checked = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gnupg_access (buffer, F_OK))
|
/* Strip one part and expect the file below a bin dir. */
|
||||||
{
|
*p = 0;
|
||||||
/* No gpgconf.ctl file. */
|
p = xstrconcat (buffer, "/bin/gpgconf.ctl", NULL);
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
checked = 1;
|
buffer = p;
|
||||||
return NULL;
|
parse_gpgconf_ctl (buffer);
|
||||||
}
|
|
||||||
/* log_info ("detected '%s'\n", buffer); */
|
|
||||||
fp = es_fopen (buffer, "r");
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_info ("error opening '%s': %s\n", buffer, gpg_strerror (err));
|
|
||||||
xfree (buffer);
|
|
||||||
checked = 1;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
line = NULL;
|
|
||||||
linelen = 0;
|
|
||||||
rootdir = NULL;
|
|
||||||
sysconfdir = NULL;
|
|
||||||
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
|
|
||||||
{
|
|
||||||
/* Strip NL and CR, if present. */
|
|
||||||
while (length > 0
|
|
||||||
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
|
|
||||||
line[--length] = 0;
|
|
||||||
trim_spaces (line);
|
|
||||||
if (!strncmp (line, "rootdir=", 8))
|
|
||||||
{
|
|
||||||
name = "rootdir";
|
|
||||||
p = line + 8;
|
|
||||||
}
|
|
||||||
else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
|
|
||||||
{
|
|
||||||
name = "rootdir";
|
|
||||||
p = line + 9;
|
|
||||||
}
|
|
||||||
else if (!strncmp (line, "sysconfdir=", 11))
|
|
||||||
{
|
|
||||||
name = "sysconfdir";
|
|
||||||
p = line + 11;
|
|
||||||
}
|
|
||||||
else if (!strncmp (line, "sysconfdir =", 12)) /* (What a kludge) */
|
|
||||||
{
|
|
||||||
name = "sysconfdir";
|
|
||||||
p = line + 12;
|
|
||||||
}
|
|
||||||
else if (!strncmp (line, ".enable=", 8))
|
|
||||||
{
|
|
||||||
name = ".enable";
|
|
||||||
p = line + 8;
|
|
||||||
}
|
|
||||||
else if (!strncmp (line, ".enable =", 9))
|
|
||||||
{
|
|
||||||
name = ".enable";
|
|
||||||
p = line + 9;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
trim_spaces (p);
|
|
||||||
p = substitute_envvars (p);
|
|
||||||
if (!p)
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_info ("error getting %s from gpgconf.ctl: %s\n",
|
|
||||||
name, gpg_strerror (err));
|
|
||||||
}
|
|
||||||
else if (!strcmp (name, ".enable"))
|
|
||||||
{
|
|
||||||
if (atoi (p)
|
|
||||||
|| !ascii_strcasecmp (p, "yes")
|
|
||||||
|| !ascii_strcasecmp (p, "true")
|
|
||||||
|| !ascii_strcasecmp (p, "fact"))
|
|
||||||
; /* Yes, this file shall be used. */
|
|
||||||
else
|
|
||||||
ignoreall = 1; /* No, this file shall be ignored. */
|
|
||||||
xfree (p);
|
|
||||||
}
|
|
||||||
else if (!strcmp (name, "sysconfdir"))
|
|
||||||
{
|
|
||||||
xfree (sysconfdir);
|
|
||||||
sysconfdir = p;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xfree (rootdir);
|
|
||||||
rootdir = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (es_ferror (fp))
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_info ("error reading '%s': %s\n", buffer, gpg_strerror (err));
|
|
||||||
es_fclose (fp);
|
|
||||||
xfree (buffer);
|
|
||||||
xfree (line);
|
|
||||||
xfree (rootdir);
|
|
||||||
xfree (sysconfdir);
|
|
||||||
checked = 1;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
es_fclose (fp);
|
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
xfree (line);
|
|
||||||
|
|
||||||
if (ignoreall)
|
|
||||||
{
|
|
||||||
xfree (rootdir);
|
|
||||||
xfree (sysconfdir);
|
|
||||||
sdir = dir = NULL;
|
|
||||||
}
|
|
||||||
else if (!rootdir || !*rootdir || *rootdir != '/')
|
|
||||||
{
|
|
||||||
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
|
|
||||||
xfree (rootdir);
|
|
||||||
xfree (sysconfdir);
|
|
||||||
dir = NULL;
|
|
||||||
}
|
|
||||||
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
|
|
||||||
{
|
|
||||||
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
|
|
||||||
sysconfdir);
|
|
||||||
xfree (rootdir);
|
|
||||||
xfree (sysconfdir);
|
|
||||||
dir = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
|
|
||||||
rootdir[strlen (rootdir)-1] = 0;
|
|
||||||
dir = rootdir;
|
|
||||||
gpgrt_annotate_leaked_object (dir);
|
|
||||||
/* log_info ("want rootdir '%s'\n", dir); */
|
|
||||||
if (sysconfdir)
|
|
||||||
{
|
|
||||||
while (*sysconfdir && sysconfdir[strlen (sysconfdir)-1] == '/')
|
|
||||||
sysconfdir[strlen (sysconfdir)-1] = 0;
|
|
||||||
sdir = sysconfdir;
|
|
||||||
gpgrt_annotate_leaked_object (sdir);
|
|
||||||
/* log_info ("want sysconfdir '%s'\n", sdir); */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checked = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return want_sysconfdir? sdir : dir;
|
if (!gpgconf_ctl.valid)
|
||||||
|
return NULL; /* No valid entries in gpgconf.ctl */
|
||||||
|
|
||||||
|
switch (wantdir)
|
||||||
|
{
|
||||||
|
case WANTDIR_ROOT: return gpgconf_ctl.rootdir;
|
||||||
|
case WANTDIR_SYSCONF: return gpgconf_ctl.sysconfdir;
|
||||||
|
case WANTDIR_SOCKET: return gpgconf_ctl.socketdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; /* Not reached. */
|
||||||
}
|
}
|
||||||
#endif /* Unix */
|
#endif /* Unix */
|
||||||
|
|
||||||
|
@ -873,7 +1089,7 @@ gnupg_daemon_rootdir (void)
|
||||||
|
|
||||||
n = GetSystemDirectoryA (path, sizeof path);
|
n = GetSystemDirectoryA (path, sizeof path);
|
||||||
if (!n || n >= sizeof path)
|
if (!n || n >= sizeof path)
|
||||||
name = xstrdup ("/"); /* Error - use the curret top dir instead. */
|
name = xstrdup ("/"); /* Error - use the current top dir instead. */
|
||||||
else
|
else
|
||||||
name = xstrdup (path);
|
name = xstrdup (path);
|
||||||
gpgrt_annotate_leaked_object (name);
|
gpgrt_annotate_leaked_object (name);
|
||||||
|
@ -919,7 +1135,7 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
||||||
|
|
||||||
if (w32_portable_app)
|
if (w32_portable_app)
|
||||||
{
|
{
|
||||||
name = xstrconcat (w32_rootdir (), DIRSEP_S, "gnupg", NULL);
|
name = xstrconcat (w32_rootdir (), DIRSEP_S, my_gnupg_dirname (), NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -930,7 +1146,7 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (path)
|
if (path)
|
||||||
{
|
{
|
||||||
name = xstrconcat (path, "\\gnupg", NULL);
|
name = xstrconcat (path, "\\", my_gnupg_dirname (), NULL);
|
||||||
xfree (path);
|
xfree (path);
|
||||||
if (gnupg_access (name, F_OK))
|
if (gnupg_access (name, F_OK))
|
||||||
gnupg_mkdir (name, "-rwx");
|
gnupg_mkdir (name, "-rwx");
|
||||||
|
@ -1038,9 +1254,11 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char prefix[19 + 1 + 20 + 6 + 1];
|
char prefixbuffer[256];
|
||||||
|
const char *prefix;
|
||||||
const char *s;
|
const char *s;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
|
const char *gnupgname = my_gnupg_dirname ();
|
||||||
|
|
||||||
*r_info = 0;
|
*r_info = 0;
|
||||||
|
|
||||||
|
@ -1053,35 +1271,43 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
||||||
* as a background process with no (desktop) user logged in. Thus
|
* as a background process with no (desktop) user logged in. Thus
|
||||||
* we better don't do that. */
|
* we better don't do that. */
|
||||||
|
|
||||||
/* Check whether we have a /run/[gnupg/]user dir. */
|
prefix = unix_rootdir (WANTDIR_SOCKET);
|
||||||
for (i=0; bases[i]; i++)
|
if (!prefix)
|
||||||
{
|
{
|
||||||
snprintf (prefix, sizeof prefix, "%s/user/%u",
|
/* gpgconf.ctl does not specify a directory. Check whether we
|
||||||
bases[i], (unsigned int)getuid ());
|
* have the usual /run/[gnupg/]user dir. */
|
||||||
if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
|
for (i=0; bases[i]; i++)
|
||||||
break;
|
{
|
||||||
}
|
snprintf (prefixbuffer, sizeof prefixbuffer, "%s/user/%u",
|
||||||
if (!bases[i])
|
bases[i], (unsigned int)getuid ());
|
||||||
{
|
prefix = prefixbuffer;
|
||||||
*r_info |= 2; /* No /run/user directory. */
|
if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
|
||||||
goto leave;
|
break;
|
||||||
|
}
|
||||||
|
if (!bases[i])
|
||||||
|
{
|
||||||
|
*r_info |= 2; /* No /run/user directory. */
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb.st_uid != getuid ())
|
||||||
|
{
|
||||||
|
*r_info |= 4; /* Not owned by the user. */
|
||||||
|
if (!skip_checks)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen (prefix) + strlen (gnupgname) + 2 >= sizeof prefixbuffer)
|
||||||
|
{
|
||||||
|
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
strcat (prefixbuffer, "/");
|
||||||
|
strcat (prefixbuffer, gnupgname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sb.st_uid != getuid ())
|
/* Check whether the gnupg sub directory (or the specified directory)
|
||||||
{
|
* has proper permissions. */
|
||||||
*r_info |= 4; /* Not owned by the user. */
|
|
||||||
if (!skip_checks)
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen (prefix) + 7 >= sizeof prefix)
|
|
||||||
{
|
|
||||||
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
strcat (prefix, "/gnupg");
|
|
||||||
|
|
||||||
/* Check whether the gnupg sub directory has proper permissions. */
|
|
||||||
if (stat (prefix, &sb))
|
if (stat (prefix, &sb))
|
||||||
{
|
{
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
|
@ -1232,16 +1458,13 @@ gnupg_sysconfdir (void)
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
{
|
{
|
||||||
const char *s1, *s2;
|
name = xstrconcat (w32_commondir (), DIRSEP_S, "etc", DIRSEP_S,
|
||||||
s1 = w32_commondir ();
|
my_gnupg_dirname (), NULL);
|
||||||
s2 = DIRSEP_S "etc" DIRSEP_S "gnupg";
|
|
||||||
name = xmalloc (strlen (s1) + strlen (s2) + 1);
|
|
||||||
strcpy (stpcpy (name, s1), s2);
|
|
||||||
gpgrt_annotate_leaked_object (name);
|
gpgrt_annotate_leaked_object (name);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *dir = unix_rootdir (1);
|
const char *dir = unix_rootdir (WANTDIR_SYSCONF);
|
||||||
if (dir)
|
if (dir)
|
||||||
return dir;
|
return dir;
|
||||||
else
|
else
|
||||||
|
@ -1270,7 +1493,7 @@ gnupg_bindir (void)
|
||||||
else
|
else
|
||||||
return rdir;
|
return rdir;
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -1297,7 +1520,7 @@ gnupg_libexecdir (void)
|
||||||
static char *name;
|
static char *name;
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -1327,7 +1550,7 @@ gnupg_libdir (void)
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -1358,7 +1581,7 @@ gnupg_datadir (void)
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -1390,7 +1613,7 @@ gnupg_localedir (void)
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
const char *rdir;
|
const char *rdir;
|
||||||
|
|
||||||
rdir = unix_rootdir (0);
|
rdir = unix_rootdir (WANTDIR_ROOT);
|
||||||
if (rdir)
|
if (rdir)
|
||||||
{
|
{
|
||||||
if (!name)
|
if (!name)
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
# include <winsock2.h>
|
# include <winsock2.h>
|
||||||
# endif
|
# endif
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
# include <wctype.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
283
common/iobuf.c
283
common/iobuf.c
|
@ -166,7 +166,8 @@ block_filter_ctx_t;
|
||||||
/* Local prototypes. */
|
/* Local prototypes. */
|
||||||
static int underflow (iobuf_t a, int clear_pending_eof);
|
static int underflow (iobuf_t a, int clear_pending_eof);
|
||||||
static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
|
static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
|
||||||
static int translate_file_handle (int fd, int for_write);
|
static iobuf_t do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open);
|
||||||
|
|
||||||
|
|
||||||
/* Sends any pending data to the filter's FILTER function. Note: this
|
/* Sends any pending data to the filter's FILTER function. Note: this
|
||||||
works on the filter and not on the whole pipeline. That is,
|
works on the filter and not on the whole pipeline. That is,
|
||||||
|
@ -311,6 +312,13 @@ direct_open (const char *fname, const char *mode, int mode700)
|
||||||
{
|
{
|
||||||
hfile = CreateFileW (wfname, da, sm, NULL, cd,
|
hfile = CreateFileW (wfname, da, sm, NULL, cd,
|
||||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hfile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
gnupg_w32_set_errno (-1);
|
||||||
|
if (DBG_IOBUF)
|
||||||
|
log_debug ("iobuf:direct_open '%s' CreateFile failed: %s\n",
|
||||||
|
fname, gpg_strerror (gpg_error_from_syserror()));
|
||||||
|
}
|
||||||
xfree (wfname);
|
xfree (wfname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -382,7 +390,7 @@ fd_cache_close (const char *fname, gnupg_fd_t fp)
|
||||||
close (fp);
|
close (fp);
|
||||||
#endif
|
#endif
|
||||||
if (DBG_IOBUF)
|
if (DBG_IOBUF)
|
||||||
log_debug ("fd_cache_close (%d) real\n", (int)fp);
|
log_debug ("fd_cache_close (%d) real\n", FD_DBG (fp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* try to reuse a slot */
|
/* try to reuse a slot */
|
||||||
|
@ -426,8 +434,9 @@ fd_cache_open (const char *fname, const char *mode)
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff)
|
if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff)
|
||||||
{
|
{
|
||||||
log_error ("rewind file failed on handle %p: ec=%d\n",
|
int ec = (int) GetLastError ();
|
||||||
fp, (int) GetLastError ());
|
log_error ("rewind file failed on handle %p: ec=%d\n", fp, ec);
|
||||||
|
gnupg_w32_set_errno (ec);
|
||||||
fp = GNUPG_INVALID_FD;
|
fp = GNUPG_INVALID_FD;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -495,7 +504,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
|
||||||
if (ec != ERROR_BROKEN_PIPE)
|
if (ec != ERROR_BROKEN_PIPE)
|
||||||
{
|
{
|
||||||
rc = gpg_error_from_errno (ec);
|
rc = gpg_error_from_errno (ec);
|
||||||
log_error ("%s: read error: ec=%d\n", a->fname, ec);
|
log_error ("%s: read error: %s (ec=%d)\n",
|
||||||
|
a->fname, gpg_strerror (rc), ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!nread)
|
else if (!nread)
|
||||||
|
@ -563,9 +573,10 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
|
||||||
{
|
{
|
||||||
if (size && !WriteFile (f, p, nbytes, &n, NULL))
|
if (size && !WriteFile (f, p, nbytes, &n, NULL))
|
||||||
{
|
{
|
||||||
int ec = (int) GetLastError ();
|
int ec = gnupg_w32_set_errno (-1);
|
||||||
rc = gpg_error_from_errno (ec);
|
rc = gpg_error_from_syserror ();
|
||||||
log_error ("%s: write error: ec=%d\n", a->fname, ec);
|
log_error ("%s: write error: %s (ec=%d)\n",
|
||||||
|
a->fname, gpg_strerror (rc), ec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p += n;
|
p += n;
|
||||||
|
@ -624,7 +635,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
|
||||||
if (ec != ERROR_BROKEN_PIPE)
|
if (ec != ERROR_BROKEN_PIPE)
|
||||||
{
|
{
|
||||||
rc = gpg_error_from_errno (ec);
|
rc = gpg_error_from_errno (ec);
|
||||||
log_error ("%s: read error: ec=%d\n", a->fname, ec);
|
log_error ("%s: read error: %s (ec=%d)\n",
|
||||||
|
a->fname, gpg_strerror (rc), ec);
|
||||||
}
|
}
|
||||||
a->npeeked = 0;
|
a->npeeked = 0;
|
||||||
}
|
}
|
||||||
|
@ -685,7 +697,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
|
||||||
if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
|
if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
|
||||||
{
|
{
|
||||||
if (DBG_IOBUF)
|
if (DBG_IOBUF)
|
||||||
log_debug ("%s: close fd/handle %d\n", a->fname, FD2INT (f));
|
log_debug ("%s: close fd/handle %d\n", a->fname, FD_DBG (f));
|
||||||
if (!a->keep_open)
|
if (!a->keep_open)
|
||||||
fd_cache_close (a->no_cache ? NULL : a->fname, f);
|
fd_cache_close (a->no_cache ? NULL : a->fname, f);
|
||||||
}
|
}
|
||||||
|
@ -873,7 +885,8 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
|
||||||
if (n == SOCKET_ERROR)
|
if (n == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
int ec = (int) WSAGetLastError ();
|
int ec = (int) WSAGetLastError ();
|
||||||
rc = gpg_error_from_errno (ec);
|
gnupg_w32_set_errno (ec);
|
||||||
|
rc = gpg_error_from_syserror ();
|
||||||
log_error ("socket write error: ec=%d\n", ec);
|
log_error ("socket write error: ec=%d\n", ec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1398,7 +1411,7 @@ iobuf_is_pipe_filename (const char *fname)
|
||||||
{
|
{
|
||||||
if (!fname || (*fname=='-' && !fname[1]) )
|
if (!fname || (*fname=='-' && !fname[1]) )
|
||||||
return 1;
|
return 1;
|
||||||
return check_special_filename (fname, 0, 1) != -1;
|
return gnupg_check_special_filename (fname) != GNUPG_INVALID_FD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1411,7 +1424,7 @@ do_open (const char *fname, int special_filenames,
|
||||||
file_filter_ctx_t *fcx;
|
file_filter_ctx_t *fcx;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
int print_only = 0;
|
int print_only = 0;
|
||||||
int fd;
|
gnupg_fd_t fd;
|
||||||
byte desc[MAX_IOBUF_DESC];
|
byte desc[MAX_IOBUF_DESC];
|
||||||
|
|
||||||
log_assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
|
log_assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
|
||||||
|
@ -1435,9 +1448,8 @@ do_open (const char *fname, int special_filenames,
|
||||||
else if (!fname)
|
else if (!fname)
|
||||||
return NULL;
|
return NULL;
|
||||||
else if (special_filenames
|
else if (special_filenames
|
||||||
&& (fd = check_special_filename (fname, 0, 1)) != -1)
|
&& (fd = gnupg_check_special_filename (fname)) != GNUPG_INVALID_FD)
|
||||||
return iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT ? 0 : 1),
|
return do_iobuf_fdopen (fd, opentype, 0);
|
||||||
opentype);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (use == IOBUF_INPUT)
|
if (use == IOBUF_INPUT)
|
||||||
|
@ -1460,7 +1472,8 @@ do_open (const char *fname, int special_filenames,
|
||||||
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
|
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
|
||||||
if (DBG_IOBUF)
|
if (DBG_IOBUF)
|
||||||
log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
|
log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
|
||||||
a->no, a->subno, fname, iobuf_desc (a, desc), FD2INT (fcx->fp));
|
a->no, a->subno, fname, iobuf_desc (a, desc),
|
||||||
|
FD_DBG (fcx->fp));
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
@ -1485,22 +1498,19 @@ iobuf_openrw (const char *fname)
|
||||||
|
|
||||||
|
|
||||||
static iobuf_t
|
static iobuf_t
|
||||||
do_iobuf_fdopen (int fd, const char *mode, int keep_open)
|
do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open)
|
||||||
{
|
{
|
||||||
iobuf_t a;
|
iobuf_t a;
|
||||||
gnupg_fd_t fp;
|
|
||||||
file_filter_ctx_t *fcx;
|
file_filter_ctx_t *fcx;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
fp = INT2FD (fd);
|
|
||||||
|
|
||||||
a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
|
a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
|
||||||
iobuf_buffer_size);
|
iobuf_buffer_size);
|
||||||
fcx = xmalloc (sizeof *fcx + 20);
|
fcx = xmalloc (sizeof *fcx + 20);
|
||||||
fcx->fp = fp;
|
fcx->fp = fp;
|
||||||
fcx->print_only_name = 1;
|
fcx->print_only_name = 1;
|
||||||
fcx->keep_open = keep_open;
|
fcx->keep_open = keep_open;
|
||||||
sprintf (fcx->fname, "[fd %d]", fd);
|
sprintf (fcx->fname, "[fd %d]", FD_DBG (fp));
|
||||||
a->filter = file_filter;
|
a->filter = file_filter;
|
||||||
a->filter_ov = fcx;
|
a->filter_ov = fcx;
|
||||||
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
|
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
|
||||||
|
@ -1513,15 +1523,15 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
|
||||||
|
|
||||||
|
|
||||||
iobuf_t
|
iobuf_t
|
||||||
iobuf_fdopen (int fd, const char *mode)
|
iobuf_fdopen (gnupg_fd_t fp, const char *mode)
|
||||||
{
|
{
|
||||||
return do_iobuf_fdopen (fd, mode, 0);
|
return do_iobuf_fdopen (fp, mode, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
iobuf_t
|
iobuf_t
|
||||||
iobuf_fdopen_nc (int fd, const char *mode)
|
iobuf_fdopen_nc (gnupg_fd_t fp, const char *mode)
|
||||||
{
|
{
|
||||||
return do_iobuf_fdopen (fd, mode, 1);
|
return do_iobuf_fdopen (fp, mode, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1573,7 +1583,7 @@ iobuf_sockopen (int fd, const char *mode)
|
||||||
log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
|
log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
|
||||||
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
|
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
|
||||||
#else
|
#else
|
||||||
a = iobuf_fdopen (fd, mode);
|
a = do_iobuf_fdopen (fd, mode, 0);
|
||||||
#endif
|
#endif
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
@ -1660,7 +1670,7 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
|
||||||
/* Peek at a justed opened file. Use this only directly after a
|
/* Peek at a justed opened file. Use this only directly after a
|
||||||
* file has been opened for reading. Don't use it after you did
|
* file has been opened for reading. Don't use it after you did
|
||||||
* a seek. This works only if just file filter has been
|
* a seek. This works only if just file filter has been
|
||||||
* pushed. Expects a buffer wit size INTVAL at PTRVAL and returns
|
* pushed. Expects a buffer with size INTVAL at PTRVAL and returns
|
||||||
* the number of bytes put into the buffer. */
|
* the number of bytes put into the buffer. */
|
||||||
if (DBG_IOBUF)
|
if (DBG_IOBUF)
|
||||||
log_debug ("iobuf-%d.%d: ioctl '%s' peek\n",
|
log_debug ("iobuf-%d.%d: ioctl '%s' peek\n",
|
||||||
|
@ -2597,13 +2607,10 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the length of the file behind A. If there is no file, return 0. */
|
||||||
off_t
|
uint64_t
|
||||||
iobuf_get_filelength (iobuf_t a, int *overflow)
|
iobuf_get_filelength (iobuf_t a)
|
||||||
{
|
{
|
||||||
if (overflow)
|
|
||||||
*overflow = 0;
|
|
||||||
|
|
||||||
/* Hmmm: file_filter may have already been removed */
|
/* Hmmm: file_filter may have already been removed */
|
||||||
for ( ; a->chain; a = a->chain )
|
for ( ; a->chain; a = a->chain )
|
||||||
;
|
;
|
||||||
|
@ -2616,56 +2623,18 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
|
||||||
gnupg_fd_t fp = b->fp;
|
gnupg_fd_t fp = b->fp;
|
||||||
|
|
||||||
#if defined(HAVE_W32_SYSTEM)
|
#if defined(HAVE_W32_SYSTEM)
|
||||||
ulong size;
|
LARGE_INTEGER exsize;
|
||||||
static int (* __stdcall get_file_size_ex) (void *handle,
|
|
||||||
LARGE_INTEGER *r_size);
|
|
||||||
static int get_file_size_ex_initialized;
|
|
||||||
|
|
||||||
if (!get_file_size_ex_initialized)
|
if (GetFileSizeEx (fp, &exsize))
|
||||||
{
|
return exsize.QuadPart;
|
||||||
void *handle;
|
|
||||||
|
|
||||||
handle = dlopen ("kernel32.dll", RTLD_LAZY);
|
|
||||||
if (handle)
|
|
||||||
{
|
|
||||||
get_file_size_ex = dlsym (handle, "GetFileSizeEx");
|
|
||||||
if (!get_file_size_ex)
|
|
||||||
dlclose (handle);
|
|
||||||
}
|
|
||||||
get_file_size_ex_initialized = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get_file_size_ex)
|
|
||||||
{
|
|
||||||
/* This is a newer system with GetFileSizeEx; we use this
|
|
||||||
then because it seem that GetFileSize won't return a
|
|
||||||
proper error in case a file is larger than 4GB. */
|
|
||||||
LARGE_INTEGER exsize;
|
|
||||||
|
|
||||||
if (get_file_size_ex (fp, &exsize))
|
|
||||||
{
|
|
||||||
if (!exsize.u.HighPart)
|
|
||||||
return exsize.u.LowPart;
|
|
||||||
if (overflow)
|
|
||||||
*overflow = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
log_error ("GetFileSize for handle %p failed: %s\n",
|
log_error ("GetFileSize for handle %p failed: %s\n",
|
||||||
fp, w32_strerror (-1));
|
fp, w32_strerror (-1));
|
||||||
#else /*!HAVE_W32_SYSTEM*/
|
#else /*!HAVE_W32_SYSTEM*/
|
||||||
{
|
struct stat st;
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if ( !fstat (fp, &st) )
|
if ( !fstat (fp, &st) )
|
||||||
return st.st_size;
|
return st.st_size;
|
||||||
log_error("fstat() failed: %s\n", strerror(errno) );
|
log_error("fstat() failed: %s\n", strerror(errno) );
|
||||||
}
|
|
||||||
#endif /*!HAVE_W32_SYSTEM*/
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2673,20 +2642,20 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
gnupg_fd_t
|
||||||
iobuf_get_fd (iobuf_t a)
|
iobuf_get_fd (iobuf_t a)
|
||||||
{
|
{
|
||||||
for (; a->chain; a = a->chain)
|
for (; a->chain; a = a->chain)
|
||||||
;
|
;
|
||||||
|
|
||||||
if (a->filter != file_filter)
|
if (a->filter != file_filter)
|
||||||
return -1;
|
return GNUPG_INVALID_FD;
|
||||||
|
|
||||||
{
|
{
|
||||||
file_filter_ctx_t *b = a->filter_ov;
|
file_filter_ctx_t *b = a->filter_ov;
|
||||||
gnupg_fd_t fp = b->fp;
|
gnupg_fd_t fp = b->fp;
|
||||||
|
|
||||||
return FD2INT (fp);
|
return fp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2977,36 +2946,6 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
translate_file_handle (int fd, int for_write)
|
|
||||||
{
|
|
||||||
#if defined(HAVE_W32_SYSTEM)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
|
|
||||||
(void)for_write;
|
|
||||||
|
|
||||||
if (fd == 0)
|
|
||||||
x = (int) GetStdHandle (STD_INPUT_HANDLE);
|
|
||||||
else if (fd == 1)
|
|
||||||
x = (int) GetStdHandle (STD_OUTPUT_HANDLE);
|
|
||||||
else if (fd == 2)
|
|
||||||
x = (int) GetStdHandle (STD_ERROR_HANDLE);
|
|
||||||
else
|
|
||||||
x = fd;
|
|
||||||
|
|
||||||
if (x == -1)
|
|
||||||
log_debug ("GetStdHandle(%d) failed: ec=%d\n",
|
|
||||||
fd, (int) GetLastError ());
|
|
||||||
|
|
||||||
fd = x;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
(void)for_write;
|
|
||||||
#endif
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
|
iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
|
||||||
|
@ -3057,3 +2996,123 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
|
||||||
|
* packet. LEN should be at least 6. */
|
||||||
|
static int
|
||||||
|
is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
int c, ctb, pkttype;
|
||||||
|
int lenbytes;
|
||||||
|
|
||||||
|
ctb = *buf++; len--;
|
||||||
|
if (!(ctb & 0x80))
|
||||||
|
return 0; /* Invalid packet. */
|
||||||
|
|
||||||
|
if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
|
||||||
|
{
|
||||||
|
pkttype = (ctb & 0x3f);
|
||||||
|
if (!len)
|
||||||
|
return 0; /* Expected first length octet missing. */
|
||||||
|
c = *buf++; len--;
|
||||||
|
if (c < 192)
|
||||||
|
;
|
||||||
|
else if (c < 224)
|
||||||
|
{
|
||||||
|
if (!len)
|
||||||
|
return 0; /* Expected second length octet missing. */
|
||||||
|
}
|
||||||
|
else if (c == 255)
|
||||||
|
{
|
||||||
|
if (len < 4)
|
||||||
|
return 0; /* Expected length octets missing */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* Old style CTB. */
|
||||||
|
{
|
||||||
|
pkttype = (ctb>>2)&0xf;
|
||||||
|
lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
|
||||||
|
if (len < lenbytes)
|
||||||
|
return 0; /* Not enough length bytes. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pkttype == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the file is compressed, by peeking the iobuf. You need to
|
||||||
|
* pass the iobuf with INP. Returns true if the buffer seems to be
|
||||||
|
* compressed.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
is_file_compressed (iobuf_t inp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char buf[32];
|
||||||
|
int buflen;
|
||||||
|
|
||||||
|
struct magic_compress_s
|
||||||
|
{
|
||||||
|
byte len;
|
||||||
|
byte extchk;
|
||||||
|
byte magic[5];
|
||||||
|
} magic[] =
|
||||||
|
{
|
||||||
|
{ 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
|
||||||
|
{ 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
|
||||||
|
{ 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
|
||||||
|
{ 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
|
||||||
|
{ 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
|
||||||
|
{ 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!inp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for ( ; inp->chain; inp = inp->chain )
|
||||||
|
;
|
||||||
|
|
||||||
|
buflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof buf, buf);
|
||||||
|
if (buflen < 0)
|
||||||
|
{
|
||||||
|
buflen = 0;
|
||||||
|
log_debug ("peeking at input failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( buflen < 6 )
|
||||||
|
{
|
||||||
|
return 0; /* Too short to check - assume uncompressed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0; i < DIM (magic); i++ )
|
||||||
|
{
|
||||||
|
if (!memcmp( buf, magic[i].magic, magic[i].len))
|
||||||
|
{
|
||||||
|
switch (magic[i].extchk)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 1; /* Is compressed. */
|
||||||
|
case 1:
|
||||||
|
if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
|
||||||
|
return 1; /* JFIF: this likely a compressed JPEG. */
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (buflen > 8
|
||||||
|
&& buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
|
||||||
|
return 1; /* This is a PNG. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
|
||||||
|
{
|
||||||
|
return 1; /* Already compressed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* Not detected as compressed. */
|
||||||
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ struct iobuf_struct
|
||||||
byte *buf;
|
byte *buf;
|
||||||
} d;
|
} d;
|
||||||
|
|
||||||
/* A external drain buffer for reading/writting data skipping internal
|
/* A external drain buffer for reading/writing data skipping internal
|
||||||
draint buffer D.BUF. This allows zerocopy operation reducing
|
draint buffer D.BUF. This allows zerocopy operation reducing
|
||||||
processing overhead across filter stack.
|
processing overhead across filter stack.
|
||||||
|
|
||||||
|
@ -333,11 +333,11 @@ iobuf_t iobuf_openrw (const char *fname);
|
||||||
creates an input filter. Note: MODE must reflect the file
|
creates an input filter. Note: MODE must reflect the file
|
||||||
descriptors actual mode! When the filter is destroyed, the file
|
descriptors actual mode! When the filter is destroyed, the file
|
||||||
descriptor is closed. */
|
descriptor is closed. */
|
||||||
iobuf_t iobuf_fdopen (int fd, const char *mode);
|
iobuf_t iobuf_fdopen (gnupg_fd_t fd, const char *mode);
|
||||||
|
|
||||||
/* Like iobuf_fdopen, but doesn't close the file descriptor when the
|
/* Like iobuf_fdopen, but doesn't close the file descriptor when the
|
||||||
filter is destroyed. */
|
filter is destroyed. */
|
||||||
iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
|
iobuf_t iobuf_fdopen_nc (gnupg_fd_t fd, const char *mode);
|
||||||
|
|
||||||
/* Create a filter using an existing estream. If MODE contains the
|
/* Create a filter using an existing estream. If MODE contains the
|
||||||
letter 'w', creates an output filter. Otherwise, creates an input
|
letter 'w', creates an output filter. Otherwise, creates an input
|
||||||
|
@ -584,17 +584,13 @@ size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen);
|
||||||
size_t iobuf_copy (iobuf_t dest, iobuf_t source);
|
size_t iobuf_copy (iobuf_t dest, iobuf_t source);
|
||||||
|
|
||||||
/* Return the size of any underlying file. This only works with
|
/* Return the size of any underlying file. This only works with
|
||||||
file_filter based pipelines.
|
file_filter based pipelines. */
|
||||||
|
uint64_t iobuf_get_filelength (iobuf_t a);
|
||||||
On Win32, it is sometimes not possible to determine the size of
|
|
||||||
files larger than 4GB. In this case, *OVERFLOW (if not NULL) is
|
|
||||||
set to 1. Otherwise, *OVERFLOW is set to 0. */
|
|
||||||
off_t iobuf_get_filelength (iobuf_t a, int *overflow);
|
|
||||||
#define IOBUF_FILELENGTH_LIMIT 0xffffffff
|
#define IOBUF_FILELENGTH_LIMIT 0xffffffff
|
||||||
|
|
||||||
/* Return the file descriptor designating the underlying file. This
|
/* Return the file descriptor designating the underlying file. This
|
||||||
only works with file_filter based pipelines. */
|
only works with file_filter based pipelines. */
|
||||||
int iobuf_get_fd (iobuf_t a);
|
gnupg_fd_t iobuf_get_fd (iobuf_t a);
|
||||||
|
|
||||||
/* Return the real filename, if available. This only supports
|
/* Return the real filename, if available. This only supports
|
||||||
pipelines that end in file filters. Returns NULL if not
|
pipelines that end in file filters. Returns NULL if not
|
||||||
|
@ -629,6 +625,9 @@ void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len);
|
||||||
from the following filter (which may or may not return EOF). */
|
from the following filter (which may or may not return EOF). */
|
||||||
void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
|
void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
|
||||||
|
|
||||||
|
/* Check if the file is compressed, by peeking the iobuf. */
|
||||||
|
int is_file_compressed (iobuf_t inp);
|
||||||
|
|
||||||
#define iobuf_where(a) "[don't know]"
|
#define iobuf_where(a) "[don't know]"
|
||||||
|
|
||||||
/* Each time a filter is allocated (via iobuf_alloc()), a
|
/* Each time a filter is allocated (via iobuf_alloc()), a
|
||||||
|
|
220
common/kem.c
Normal file
220
common/kem.c
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
/* kem.c - KEM helper functions
|
||||||
|
* Copyright (C) 2024 g10 Code GmbH.
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute and/or modify this
|
||||||
|
* part of GnuPG under the terms of either
|
||||||
|
*
|
||||||
|
* - the GNU Lesser General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* - the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* or both in parallel, as here.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received copies of the GNU General Public License
|
||||||
|
* and the GNU Lesser General Public License along with this program;
|
||||||
|
* if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <gpg-error.h>
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#include "mischelp.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* domSeperation as per *PGP specs. */
|
||||||
|
#define KMAC_KEY "OpenPGPCompositeKeyDerivationFunction"
|
||||||
|
|
||||||
|
/* customizationString as per *PGP specs. */
|
||||||
|
#define KMAC_CUSTOM "KDF"
|
||||||
|
|
||||||
|
/* The blocksize used for Keccak by compute_kmac256. */
|
||||||
|
#define KECCAK512_BLOCKSIZE 136
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
compute_kmac256 (void *digest, size_t digestlen,
|
||||||
|
const void *key, size_t keylen,
|
||||||
|
const void *custom, size_t customlen,
|
||||||
|
gcry_buffer_t *data_iov, int data_iovlen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
gcry_buffer_t iov[20];
|
||||||
|
const unsigned char headPAD[2] = { 1, KECCAK512_BLOCKSIZE };
|
||||||
|
unsigned char headK[3];
|
||||||
|
const unsigned char pad[KECCAK512_BLOCKSIZE] = { 0 };
|
||||||
|
unsigned char right_encode_L[3];
|
||||||
|
unsigned int len;
|
||||||
|
int iovcnt;
|
||||||
|
|
||||||
|
if (data_iovlen >= DIM(iov) - 6)
|
||||||
|
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||||
|
|
||||||
|
/* Check the validity conditions of NIST SP 800-185 */
|
||||||
|
if (keylen >= 255 || customlen >= 255 || digestlen >= 255)
|
||||||
|
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||||
|
|
||||||
|
iovcnt = 0;
|
||||||
|
iov[iovcnt].data = "KMAC";
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = 4;
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
iov[iovcnt].data = (void *)custom;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = customlen;
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
iov[iovcnt].data = (void *)headPAD;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = sizeof (headPAD);
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
if (keylen < 32)
|
||||||
|
{
|
||||||
|
headK[0] = 1;
|
||||||
|
headK[1] = (keylen*8)&0xff;
|
||||||
|
iov[iovcnt].data = headK;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
headK[0] = 2;
|
||||||
|
headK[1] = (keylen*8)>>8;
|
||||||
|
headK[2] = (keylen*8)&0xff;
|
||||||
|
iov[iovcnt].data = headK;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = 3;
|
||||||
|
}
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
iov[iovcnt].data = (void *)key;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = keylen;
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
len = iov[2].len + iov[3].len + iov[4].len;
|
||||||
|
len %= KECCAK512_BLOCKSIZE;
|
||||||
|
|
||||||
|
iov[iovcnt].data = (unsigned char *)pad;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = sizeof (pad) - len;
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
memcpy (&iov[iovcnt], data_iov, data_iovlen * sizeof (gcry_buffer_t));
|
||||||
|
iovcnt += data_iovlen;
|
||||||
|
|
||||||
|
if (digestlen < 32)
|
||||||
|
{
|
||||||
|
right_encode_L[0] = (digestlen * 8) & 0xff;
|
||||||
|
right_encode_L[1] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
right_encode_L[0] = (digestlen * 8) >> 8;
|
||||||
|
right_encode_L[1] = (digestlen * 8) & 0xff;
|
||||||
|
right_encode_L[2] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov[iovcnt].data = right_encode_L;
|
||||||
|
iov[iovcnt].off = 0;
|
||||||
|
iov[iovcnt].len = 3;
|
||||||
|
iovcnt++;
|
||||||
|
|
||||||
|
err = gcry_md_hash_buffers_ext (GCRY_MD_CSHAKE256, 0,
|
||||||
|
digest, digestlen, iov, iovcnt);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compute KEK (shared secret) for ECC with HASHALGO, ECDH result,
|
||||||
|
ciphertext in ECC_CT, public key in ECC_PK. */
|
||||||
|
gpg_error_t
|
||||||
|
gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
|
||||||
|
int hashalgo, const void *ecdh, size_t ecdh_len,
|
||||||
|
const void *ecc_ct, size_t ecc_ct_len,
|
||||||
|
const void *ecc_pk, size_t ecc_pk_len)
|
||||||
|
{
|
||||||
|
gcry_buffer_t iov[3];
|
||||||
|
unsigned int dlen;
|
||||||
|
|
||||||
|
dlen = gcry_md_get_algo_dlen (hashalgo);
|
||||||
|
if (kek_len != dlen)
|
||||||
|
return gpg_error (GPG_ERR_INV_LENGTH);
|
||||||
|
|
||||||
|
memset (iov, 0, sizeof (iov));
|
||||||
|
|
||||||
|
iov[0].data = (unsigned char *)ecdh;
|
||||||
|
iov[0].len = ecdh_len;
|
||||||
|
iov[1].data = (unsigned char *)ecc_ct;
|
||||||
|
iov[1].len = ecc_ct_len;
|
||||||
|
iov[2].data = (unsigned char *)ecc_pk;
|
||||||
|
iov[2].len = ecc_pk_len;
|
||||||
|
gcry_md_hash_buffers (hashalgo, 0, kek, iov, 3);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute KEK by combining two KEMs. The caller provides a buffer
|
||||||
|
* KEK allocated with size KEK_LEN which will receive the computed
|
||||||
|
* KEK. (ECC_SS, ECC_SS_LEN) is the shared secret of the first key.
|
||||||
|
* (ECC_CT, ECC_CT_LEN) is the ciphertext of the first key.
|
||||||
|
* (MLKEM_SS, ECC_SS_LEN) is the shared secret of the second key.
|
||||||
|
* (MLKEM_CT, MLKEM_CT_LEN) is the ciphertext of the second key.
|
||||||
|
* (FIXEDINFO, FIXEDINFO_LEN) is an octet string used to bind the KEK
|
||||||
|
* to a the key; for PGP we use the concatenation of the session key's
|
||||||
|
* algorithm id and the v5 fingerprint of the key.
|
||||||
|
*/
|
||||||
|
gpg_error_t
|
||||||
|
gnupg_kem_combiner (void *kek, size_t kek_len,
|
||||||
|
const void *ecc_ss, size_t ecc_ss_len,
|
||||||
|
const void *ecc_ct, size_t ecc_ct_len,
|
||||||
|
const void *mlkem_ss, size_t mlkem_ss_len,
|
||||||
|
const void *mlkem_ct, size_t mlkem_ct_len,
|
||||||
|
const void *fixedinfo, size_t fixedinfo_len)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
gcry_buffer_t iov[6];
|
||||||
|
|
||||||
|
memset (iov, 0, sizeof (iov));
|
||||||
|
|
||||||
|
iov[0].data = "\x00\x00\x00\x01"; /* Counter */
|
||||||
|
iov[0].len = 4;
|
||||||
|
|
||||||
|
iov[1].data = (unsigned char *)ecc_ss;
|
||||||
|
iov[1].len = ecc_ss_len;
|
||||||
|
|
||||||
|
iov[2].data = (unsigned char *)ecc_ct;
|
||||||
|
iov[2].len = ecc_ct_len;
|
||||||
|
|
||||||
|
iov[3].data = (unsigned char *)mlkem_ss;
|
||||||
|
iov[3].len = mlkem_ss_len;
|
||||||
|
|
||||||
|
iov[4].data = (unsigned char *)mlkem_ct;
|
||||||
|
iov[4].len = mlkem_ct_len;
|
||||||
|
|
||||||
|
iov[5].data = (unsigned char *)fixedinfo;
|
||||||
|
iov[5].len = fixedinfo_len;
|
||||||
|
|
||||||
|
err = compute_kmac256 (kek, kek_len,
|
||||||
|
KMAC_KEY, strlen (KMAC_KEY),
|
||||||
|
KMAC_CUSTOM, strlen (KMAC_CUSTOM), iov, 6);
|
||||||
|
return err;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/* kska-io-support.c - Supporting functions for ksba reader and writer
|
/* kska-io-support.c - Supporting functions for ksba reader and writer
|
||||||
* Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch
|
* Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch
|
||||||
* Copyright (C) 2006 g10 Code GmbH
|
* Copyright (C) 2006, 2023 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -96,6 +97,15 @@ struct writer_cb_parm_s
|
||||||
|
|
||||||
char *pem_name; /* Malloced. */
|
char *pem_name; /* Malloced. */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
gnupg_ksba_progress_cb_t cb;
|
||||||
|
ctrl_t ctrl;
|
||||||
|
u32 last_time; /* last time reported */
|
||||||
|
uint64_t last; /* last amount reported */
|
||||||
|
uint64_t current; /* current amount */
|
||||||
|
uint64_t total; /* total amount */
|
||||||
|
} progress;
|
||||||
|
|
||||||
int wrote_begin;
|
int wrote_begin;
|
||||||
int did_finish;
|
int did_finish;
|
||||||
|
|
||||||
|
@ -110,6 +120,7 @@ struct writer_cb_parm_s
|
||||||
|
|
||||||
/* Context for this module's functions. */
|
/* Context for this module's functions. */
|
||||||
struct gnupg_ksba_io_s {
|
struct gnupg_ksba_io_s {
|
||||||
|
int is_writer; /* True if this context refers a writer object. */
|
||||||
union {
|
union {
|
||||||
struct reader_cb_parm_s rparm;
|
struct reader_cb_parm_s rparm;
|
||||||
struct writer_cb_parm_s wparm;
|
struct writer_cb_parm_s wparm;
|
||||||
|
@ -527,6 +538,33 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Call the progress callback if its time. We do this very 2 seconds
|
||||||
|
* or if FORCE is set. However, we also require that at least 64KiB
|
||||||
|
* have been written to avoid unnecessary progress lines for small
|
||||||
|
* files. */
|
||||||
|
static gpg_error_t
|
||||||
|
update_write_progress (struct writer_cb_parm_s *parm, size_t count, int force)
|
||||||
|
{
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
u32 timestamp;
|
||||||
|
|
||||||
|
parm->progress.current += count;
|
||||||
|
if (parm->progress.current >= (64*1024))
|
||||||
|
{
|
||||||
|
timestamp = make_timestamp ();
|
||||||
|
if (force || (timestamp - parm->progress.last_time > 1))
|
||||||
|
{
|
||||||
|
parm->progress.last = parm->progress.current;
|
||||||
|
parm->progress.last_time = timestamp;
|
||||||
|
err = parm->progress.cb (parm->progress.ctrl,
|
||||||
|
parm->progress.current,
|
||||||
|
parm->progress.total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||||
{
|
{
|
||||||
|
@ -535,6 +573,8 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||||
int i, c, idx, quad_count;
|
int i, c, idx, quad_count;
|
||||||
const unsigned char *p;
|
const unsigned char *p;
|
||||||
estream_t stream = parm->stream;
|
estream_t stream = parm->stream;
|
||||||
|
int rc;
|
||||||
|
size_t nleft;
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -557,7 +597,7 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||||
for (i=0; i < idx; i++)
|
for (i=0; i < idx; i++)
|
||||||
radbuf[i] = parm->base64.radbuf[i];
|
radbuf[i] = parm->base64.radbuf[i];
|
||||||
|
|
||||||
for (p=buffer; count; p++, count--)
|
for (p=buffer, nleft = count; nleft; p++, nleft--)
|
||||||
{
|
{
|
||||||
radbuf[idx++] = *p;
|
radbuf[idx++] = *p;
|
||||||
if (idx > 2)
|
if (idx > 2)
|
||||||
|
@ -583,7 +623,11 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||||
parm->base64.idx = idx;
|
parm->base64.idx = idx;
|
||||||
parm->base64.quad_count = quad_count;
|
parm->base64.quad_count = quad_count;
|
||||||
|
|
||||||
return es_ferror (stream)? gpg_error_from_syserror () : 0;
|
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
|
||||||
|
/* Note that we use the unencoded count for the progress. */
|
||||||
|
if (!rc && parm->progress.cb)
|
||||||
|
rc = update_write_progress (parm, count, 0);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -594,13 +638,16 @@ plain_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||||
{
|
{
|
||||||
struct writer_cb_parm_s *parm = cb_value;
|
struct writer_cb_parm_s *parm = cb_value;
|
||||||
estream_t stream = parm->stream;
|
estream_t stream = parm->stream;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
es_write (stream, buffer, count, NULL);
|
es_write (stream, buffer, count, NULL);
|
||||||
|
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
|
||||||
return es_ferror (stream)? gpg_error_from_syserror () : 0;
|
if (!rc && parm->progress.cb)
|
||||||
|
rc = update_write_progress (parm, count, 0);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -610,6 +657,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
|
||||||
unsigned char *radbuf;
|
unsigned char *radbuf;
|
||||||
int c, idx, quad_count;
|
int c, idx, quad_count;
|
||||||
estream_t stream = parm->stream;
|
estream_t stream = parm->stream;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (!parm->wrote_begin)
|
if (!parm->wrote_begin)
|
||||||
return 0; /* Nothing written or we are not called in base-64 mode. */
|
return 0; /* Nothing written or we are not called in base-64 mode. */
|
||||||
|
@ -656,7 +704,10 @@ base64_finish_write (struct writer_cb_parm_s *parm)
|
||||||
es_fputs ("-----\n", stream);
|
es_fputs ("-----\n", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
return es_ferror (stream)? gpg_error_from_syserror () : 0;
|
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
|
||||||
|
if (!rc && parm->progress.cb)
|
||||||
|
rc = update_write_progress (parm, 0, 1);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -788,6 +839,7 @@ gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags,
|
||||||
*ctx = xtrycalloc (1, sizeof **ctx);
|
*ctx = xtrycalloc (1, sizeof **ctx);
|
||||||
if (!*ctx)
|
if (!*ctx)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
(*ctx)->is_writer = 1;
|
||||||
|
|
||||||
rc = ksba_writer_new (&w);
|
rc = ksba_writer_new (&w);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -865,3 +917,37 @@ gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx)
|
||||||
xfree (ctx->u.wparm.pem_name);
|
xfree (ctx->u.wparm.pem_name);
|
||||||
xfree (ctx);
|
xfree (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set a callback to the writer object. CTRL will be bassed to the
|
||||||
|
* callback. */
|
||||||
|
void
|
||||||
|
gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx,
|
||||||
|
gnupg_ksba_progress_cb_t cb, ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
struct writer_cb_parm_s *parm;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->is_writer)
|
||||||
|
return; /* Currently only supported for writer objects. */
|
||||||
|
parm = &ctx->u.wparm;
|
||||||
|
|
||||||
|
parm->progress.cb = cb;
|
||||||
|
parm->progress.ctrl = ctrl;
|
||||||
|
parm->progress.last_time = 0;
|
||||||
|
parm->progress.last = 0;
|
||||||
|
parm->progress.current = 0;
|
||||||
|
parm->progress.total = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Update the total count for the progress thingy. */
|
||||||
|
void
|
||||||
|
gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total)
|
||||||
|
{
|
||||||
|
struct writer_cb_parm_s *parm;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->is_writer)
|
||||||
|
return; /* Currently only supported for writer objects. */
|
||||||
|
parm = &ctx->u.wparm;
|
||||||
|
parm->progress.total = total;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GNUPG_KSBA_IO_SUPPORT_H
|
#ifndef GNUPG_KSBA_IO_SUPPORT_H
|
||||||
|
@ -42,6 +43,10 @@
|
||||||
/* Context object. */
|
/* Context object. */
|
||||||
typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t;
|
typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t;
|
||||||
|
|
||||||
|
/* Progress callback type. */
|
||||||
|
typedef gpg_error_t (*gnupg_ksba_progress_cb_t)(ctrl_t ctrl,
|
||||||
|
uint64_t current,
|
||||||
|
uint64_t total);
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
|
gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
|
||||||
|
@ -57,10 +62,13 @@ gpg_error_t gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx,
|
||||||
const char *pem_name,
|
const char *pem_name,
|
||||||
estream_t stream,
|
estream_t stream,
|
||||||
ksba_writer_t *r_writer);
|
ksba_writer_t *r_writer);
|
||||||
|
|
||||||
gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx);
|
gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx);
|
||||||
void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx);
|
void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx);
|
||||||
|
|
||||||
|
void gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx,
|
||||||
|
gnupg_ksba_progress_cb_t cb, ctrl_t ctrl);
|
||||||
|
void gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,35 +57,6 @@ mem_count_chr (const void *buffer, int c, size_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This is a case-sensitive version of our memistr. I wonder why no
|
|
||||||
standard function memstr exists but I better do not use the name
|
|
||||||
memstr to avoid future conflicts. */
|
|
||||||
static const char *
|
|
||||||
my_memstr (const void *buffer, size_t buflen, const char *sub)
|
|
||||||
{
|
|
||||||
const unsigned char *buf = buffer;
|
|
||||||
const unsigned char *t = (const unsigned char *)buf;
|
|
||||||
const unsigned char *s = (const unsigned char *)sub;
|
|
||||||
size_t n = buflen;
|
|
||||||
|
|
||||||
for ( ; n ; t++, n-- )
|
|
||||||
{
|
|
||||||
if (*t == *s)
|
|
||||||
{
|
|
||||||
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
|
|
||||||
;
|
|
||||||
if (!*s)
|
|
||||||
return (const char*)buf;
|
|
||||||
t = (const unsigned char *)buf;
|
|
||||||
s = (const unsigned char *)sub ;
|
|
||||||
n = buflen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
string_has_ctrl_or_space (const char *string)
|
string_has_ctrl_or_space (const char *string)
|
||||||
{
|
{
|
||||||
|
@ -159,7 +130,7 @@ is_valid_mailbox_mem (const void *name_arg, size_t namelen)
|
||||||
|| *name == '@'
|
|| *name == '@'
|
||||||
|| name[namelen-1] == '@'
|
|| name[namelen-1] == '@'
|
||||||
|| name[namelen-1] == '.'
|
|| name[namelen-1] == '.'
|
||||||
|| my_memstr (name, namelen, ".."));
|
|| gnupg_memstr (name, namelen, ".."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,27 +36,6 @@
|
||||||
#include "iobuf.h"
|
#include "iobuf.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
/* Used by libgcrypt for logging. */
|
|
||||||
static void
|
|
||||||
my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
|
|
||||||
{
|
|
||||||
(void)dummy;
|
|
||||||
|
|
||||||
/* Map the log levels. */
|
|
||||||
switch (level)
|
|
||||||
{
|
|
||||||
case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break;
|
|
||||||
case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break;
|
|
||||||
case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break;
|
|
||||||
case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break;
|
|
||||||
case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break;
|
|
||||||
case GCRY_LOG_BUG: level = GPGRT_LOGLVL_BUG; break;
|
|
||||||
case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break;
|
|
||||||
default: level = GPGRT_LOGLVL_ERROR; break;
|
|
||||||
}
|
|
||||||
log_logv (level, fmt, arg_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This function is called by libgcrypt on a fatal error. */
|
/* This function is called by libgcrypt on a fatal error. */
|
||||||
static void
|
static void
|
||||||
|
@ -100,7 +79,6 @@ my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
|
||||||
void
|
void
|
||||||
setup_libgcrypt_logging (void)
|
setup_libgcrypt_logging (void)
|
||||||
{
|
{
|
||||||
gcry_set_log_handler (my_gcry_logger, NULL);
|
|
||||||
gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
|
gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
|
||||||
gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
|
gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
|
||||||
}
|
}
|
||||||
|
@ -415,112 +393,6 @@ decode_c_string (const char *src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
|
|
||||||
* packet. LEN should be at least 6. */
|
|
||||||
static int
|
|
||||||
is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
|
|
||||||
{
|
|
||||||
int c, ctb, pkttype;
|
|
||||||
int lenbytes;
|
|
||||||
|
|
||||||
ctb = *buf++; len--;
|
|
||||||
if (!(ctb & 0x80))
|
|
||||||
return 0; /* Invalid packet. */
|
|
||||||
|
|
||||||
if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
|
|
||||||
{
|
|
||||||
pkttype = (ctb & 0x3f);
|
|
||||||
if (!len)
|
|
||||||
return 0; /* Expected first length octet missing. */
|
|
||||||
c = *buf++; len--;
|
|
||||||
if (c < 192)
|
|
||||||
;
|
|
||||||
else if (c < 224)
|
|
||||||
{
|
|
||||||
if (!len)
|
|
||||||
return 0; /* Expected second length octet missing. */
|
|
||||||
}
|
|
||||||
else if (c == 255)
|
|
||||||
{
|
|
||||||
if (len < 4)
|
|
||||||
return 0; /* Expected length octets missing */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* Old style CTB. */
|
|
||||||
{
|
|
||||||
pkttype = (ctb>>2)&0xf;
|
|
||||||
lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
|
|
||||||
if (len < lenbytes)
|
|
||||||
return 0; /* Not enough length bytes. */
|
|
||||||
}
|
|
||||||
|
|
||||||
return (pkttype == 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the file is compressed. You need to pass the first bytes
|
|
||||||
* of the file as (BUF,BUFLEN). Returns true if the buffer seems to
|
|
||||||
* be compressed.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
is_file_compressed (const byte *buf, unsigned int buflen)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
struct magic_compress_s
|
|
||||||
{
|
|
||||||
byte len;
|
|
||||||
byte extchk;
|
|
||||||
byte magic[5];
|
|
||||||
} magic[] =
|
|
||||||
{
|
|
||||||
{ 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
|
|
||||||
{ 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
|
|
||||||
{ 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
|
|
||||||
{ 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
|
|
||||||
{ 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
|
|
||||||
{ 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( buflen < 6 )
|
|
||||||
{
|
|
||||||
return 0; /* Too short to check - assume uncompressed. */
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( i = 0; i < DIM (magic); i++ )
|
|
||||||
{
|
|
||||||
if (!memcmp( buf, magic[i].magic, magic[i].len))
|
|
||||||
{
|
|
||||||
switch (magic[i].extchk)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return 1; /* Is compressed. */
|
|
||||||
case 1:
|
|
||||||
if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
|
|
||||||
return 1; /* JFIF: this likely a compressed JPEG. */
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (buflen > 8
|
|
||||||
&& buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
|
|
||||||
return 1; /* This is a PNG. */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
|
|
||||||
{
|
|
||||||
return 1; /* Already compressed. */
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0; /* Not detected as compressed. */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Try match against each substring of multistr, delimited by | */
|
/* Try match against each substring of multistr, delimited by | */
|
||||||
int
|
int
|
||||||
match_multistr (const char *multistr,const char *match)
|
match_multistr (const char *multistr,const char *match)
|
||||||
|
@ -793,3 +665,53 @@ parse_compatibility_flags (const char *string, unsigned int *flagvar,
|
||||||
*flagvar |= result;
|
*flagvar |= result;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert STRING consisting of base64 characters into its binary
|
||||||
|
* representation and store the result in a newly allocated buffer at
|
||||||
|
* R_BUFFER with its length at R_BUFLEN. If TITLE is NULL a plain
|
||||||
|
* base64 decoding is done. If it is the empty string the decoder
|
||||||
|
* will skip everything until a "-----BEGIN " line has been seen,
|
||||||
|
* decoding then ends at a "----END " line. On failure the function
|
||||||
|
* returns an error code and sets R_BUFFER to NULL. If the decoded
|
||||||
|
* data has a length of 0 a dummy buffer will still be allocated and
|
||||||
|
* the length is set to 0. */
|
||||||
|
gpg_error_t
|
||||||
|
b64decode (const char *string, const char *title,
|
||||||
|
void **r_buffer, size_t *r_buflen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
gpgrt_b64state_t state;
|
||||||
|
size_t nbytes;
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
|
*r_buffer = NULL;
|
||||||
|
*r_buflen = 0;
|
||||||
|
|
||||||
|
buffer = xtrystrdup (string);
|
||||||
|
if (!buffer)
|
||||||
|
return gpg_error_from_syserror();
|
||||||
|
|
||||||
|
state = gpgrt_b64dec_start (title);
|
||||||
|
if (!state)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
xfree (buffer);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
err = gpgrt_b64dec_proc (state, buffer, strlen (buffer), &nbytes);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
err = gpgrt_b64dec_finish (state);
|
||||||
|
state = NULL;
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
xfree (buffer);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*r_buffer = buffer;
|
||||||
|
*r_buflen = nbytes;
|
||||||
|
}
|
||||||
|
gpgrt_b64dec_finish (state); /* Make sure it is released. */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -126,80 +126,3 @@ same_file_p (const char *name1, const char *name2)
|
||||||
}
|
}
|
||||||
return yes;
|
return yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
timegm() is a GNU function that might not be available everywhere.
|
|
||||||
It's basically the inverse of gmtime() - you give it a struct tm,
|
|
||||||
and get back a time_t. It differs from mktime() in that it handles
|
|
||||||
the case where the struct tm is UTC and the local environment isn't.
|
|
||||||
|
|
||||||
Note, that this replacement implementation might not be thread-safe!
|
|
||||||
|
|
||||||
Some BSDs don't handle the putenv("foo") case properly, so we use
|
|
||||||
unsetenv if the platform has it to remove environment variables.
|
|
||||||
*/
|
|
||||||
#ifndef HAVE_TIMEGM
|
|
||||||
time_t
|
|
||||||
timegm (struct tm *tm)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
/* This one is thread safe. */
|
|
||||||
SYSTEMTIME st;
|
|
||||||
FILETIME ft;
|
|
||||||
unsigned long long cnsecs;
|
|
||||||
|
|
||||||
st.wYear = tm->tm_year + 1900;
|
|
||||||
st.wMonth = tm->tm_mon + 1;
|
|
||||||
st.wDay = tm->tm_mday;
|
|
||||||
st.wHour = tm->tm_hour;
|
|
||||||
st.wMinute = tm->tm_min;
|
|
||||||
st.wSecond = tm->tm_sec;
|
|
||||||
st.wMilliseconds = 0; /* Not available. */
|
|
||||||
st.wDayOfWeek = 0; /* Ignored. */
|
|
||||||
|
|
||||||
/* System time is UTC thus the conversion is pretty easy. */
|
|
||||||
if (!SystemTimeToFileTime (&st, &ft))
|
|
||||||
{
|
|
||||||
gpg_err_set_errno (EINVAL);
|
|
||||||
return (time_t)(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
|
||||||
| ft.dwLowDateTime);
|
|
||||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
|
||||||
return (time_t)(cnsecs / 10000000ULL);
|
|
||||||
|
|
||||||
#else /* (Non thread safe implementation!) */
|
|
||||||
|
|
||||||
time_t answer;
|
|
||||||
char *zone;
|
|
||||||
|
|
||||||
zone=getenv("TZ");
|
|
||||||
putenv("TZ=UTC");
|
|
||||||
tzset();
|
|
||||||
answer=mktime(tm);
|
|
||||||
if(zone)
|
|
||||||
{
|
|
||||||
static char *old_zone;
|
|
||||||
|
|
||||||
if (!old_zone)
|
|
||||||
{
|
|
||||||
old_zone = malloc(3+strlen(zone)+1);
|
|
||||||
if (old_zone)
|
|
||||||
{
|
|
||||||
strcpy(old_zone,"TZ=");
|
|
||||||
strcat(old_zone,zone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (old_zone)
|
|
||||||
putenv (old_zone);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gnupg_unsetenv("TZ");
|
|
||||||
|
|
||||||
tzset();
|
|
||||||
return answer;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif /*!HAVE_TIMEGM*/
|
|
||||||
|
|
|
@ -38,12 +38,6 @@
|
||||||
int same_file_p (const char *name1, const char *name2);
|
int same_file_p (const char *name1, const char *name2);
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_TIMEGM
|
|
||||||
#include <time.h>
|
|
||||||
time_t timegm (struct tm *tm);
|
|
||||||
#endif /*!HAVE_TIMEGM*/
|
|
||||||
|
|
||||||
|
|
||||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
/* Create a directory as well as any missing parents.
|
/* Create a directory as well as any missing parents.
|
||||||
|
|
||||||
The arguments must be NULL termianted. If DIRECTORY_COMPONENTS...
|
The arguments must be NULL terminated. If DIRECTORY_COMPONENTS...
|
||||||
consists of two elements, "foo/bar" and "xyzzy", this function will
|
consists of two elements, "foo/bar" and "xyzzy", this function will
|
||||||
first try to create the directory "foo/bar" and then the directory
|
first try to create the directory "foo/bar" and then the directory
|
||||||
"foo/bar/xyzzy". On success returns 0, otherwise an error code is
|
"foo/bar/xyzzy". On success returns 0, otherwise an error code is
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct name_value_container
|
||||||
struct name_value_entry *first;
|
struct name_value_entry *first;
|
||||||
struct name_value_entry *last;
|
struct name_value_entry *last;
|
||||||
unsigned int private_key_mode:1;
|
unsigned int private_key_mode:1;
|
||||||
|
unsigned int modified:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,11 +88,15 @@ my_error (gpg_err_code_t ec)
|
||||||
|
|
||||||
/* Allocation and deallocation. */
|
/* Allocation and deallocation. */
|
||||||
|
|
||||||
/* Allocate a private key container structure. */
|
/* Allocate a name value container structure. */
|
||||||
nvc_t
|
nvc_t
|
||||||
nvc_new (void)
|
nvc_new (void)
|
||||||
{
|
{
|
||||||
return xtrycalloc (1, sizeof (struct name_value_container));
|
nvc_t nvc;
|
||||||
|
nvc = xtrycalloc (1, sizeof (struct name_value_container));
|
||||||
|
if (nvc)
|
||||||
|
nvc->modified = 1;
|
||||||
|
return nvc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,6 +147,24 @@ nvc_release (nvc_t pk)
|
||||||
xfree (pk);
|
xfree (pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the modified-flag of the container and clear it if CLEAR is
|
||||||
|
* set. That flag is set for a new container and set with each
|
||||||
|
* update. */
|
||||||
|
int
|
||||||
|
nvc_modified (nvc_t pk, int clear)
|
||||||
|
{
|
||||||
|
int modified;
|
||||||
|
|
||||||
|
if (!pk)
|
||||||
|
return 0;
|
||||||
|
modified = pk->modified;
|
||||||
|
if (clear)
|
||||||
|
pk->modified = 0;
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Dealing with names and values. */
|
/* Dealing with names and values. */
|
||||||
|
@ -427,6 +450,8 @@ _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
|
||||||
else
|
else
|
||||||
pk->first = pk->last = e;
|
pk->first = pk->last = e;
|
||||||
|
|
||||||
|
pk->modified = 1;
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
@ -476,27 +501,46 @@ nvc_set (nvc_t pk, const char *name, const char *value)
|
||||||
|
|
||||||
e = nvc_lookup (pk, name);
|
e = nvc_lookup (pk, name);
|
||||||
if (e)
|
if (e)
|
||||||
{
|
return nve_set (pk, e, value);
|
||||||
char *v;
|
|
||||||
|
|
||||||
v = xtrystrdup (value);
|
|
||||||
if (v == NULL)
|
|
||||||
return my_error_from_syserror ();
|
|
||||||
|
|
||||||
free_strlist_wipe (e->raw_value);
|
|
||||||
e->raw_value = NULL;
|
|
||||||
if (e->value)
|
|
||||||
wipememory (e->value, strlen (e->value));
|
|
||||||
xfree (e->value);
|
|
||||||
e->value = v;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return nvc_add (pk, name, value);
|
return nvc_add (pk, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Update entry E to VALUE. PK is optional; if given its modified
|
||||||
|
* flag will be updated. */
|
||||||
|
gpg_error_t
|
||||||
|
nve_set (nvc_t pk, nve_t e, const char *value)
|
||||||
|
{
|
||||||
|
char *v;
|
||||||
|
|
||||||
|
if (!e)
|
||||||
|
return GPG_ERR_INV_ARG;
|
||||||
|
|
||||||
|
if (e->value && value && !strcmp (e->value, value))
|
||||||
|
{
|
||||||
|
/* Setting same value - ignore this call and don't set the
|
||||||
|
* modified flag (if PK is given). */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = xtrystrdup (value? value:"");
|
||||||
|
if (!v)
|
||||||
|
return my_error_from_syserror ();
|
||||||
|
|
||||||
|
free_strlist_wipe (e->raw_value);
|
||||||
|
e->raw_value = NULL;
|
||||||
|
if (e->value)
|
||||||
|
wipememory (e->value, strlen (e->value));
|
||||||
|
xfree (e->value);
|
||||||
|
e->value = v;
|
||||||
|
if (pk)
|
||||||
|
pk->modified = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Delete the given entry from PK. */
|
/* Delete the given entry from PK. */
|
||||||
void
|
void
|
||||||
nvc_delete (nvc_t pk, nve_t entry)
|
nvc_delete (nvc_t pk, nve_t entry)
|
||||||
|
@ -512,6 +556,7 @@ nvc_delete (nvc_t pk, nve_t entry)
|
||||||
pk->last = entry->prev;
|
pk->last = entry->prev;
|
||||||
|
|
||||||
nve_release (entry, pk->private_key_mode);
|
nve_release (entry, pk->private_key_mode);
|
||||||
|
pk->modified = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -592,7 +637,7 @@ nve_next_value (nve_t entry, const char *name)
|
||||||
|
|
||||||
/* Return the string for the first entry in NVC with NAME. If an
|
/* Return the string for the first entry in NVC with NAME. If an
|
||||||
* entry with NAME is missing in NVC or its value is the empty string
|
* entry with NAME is missing in NVC or its value is the empty string
|
||||||
* NULL is returned. Note that the The returned string is a pointer
|
* NULL is returned. Note that the the returned string is a pointer
|
||||||
* into NVC. */
|
* into NVC. */
|
||||||
const char *
|
const char *
|
||||||
nvc_get_string (nvc_t nvc, const char *name)
|
nvc_get_string (nvc_t nvc, const char *name)
|
||||||
|
|
|
@ -50,6 +50,9 @@ nvc_t nvc_new_private_key (void);
|
||||||
/* Release a name value container structure. */
|
/* Release a name value container structure. */
|
||||||
void nvc_release (nvc_t pk);
|
void nvc_release (nvc_t pk);
|
||||||
|
|
||||||
|
/* Return the modified flag and optionally clear it. */
|
||||||
|
int nvc_modified (nvc_t pk, int clear);
|
||||||
|
|
||||||
/* Get the name. */
|
/* Get the name. */
|
||||||
char *nve_name (nve_t pke);
|
char *nve_name (nve_t pke);
|
||||||
|
|
||||||
|
@ -92,6 +95,9 @@ gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value);
|
||||||
first entry is updated. */
|
first entry is updated. */
|
||||||
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
|
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
|
||||||
|
|
||||||
|
/* Update entry E to VALUE. PK is optional. */
|
||||||
|
gpg_error_t nve_set (nvc_t pk, nve_t e, const char *value);
|
||||||
|
|
||||||
/* Delete the given entry from PK. */
|
/* Delete the given entry from PK. */
|
||||||
void nvc_delete (nvc_t pk, nve_t pke);
|
void nvc_delete (nvc_t pk, nve_t pke);
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ compute_openpgp_fpr (int keyversion, int pgpalgo, unsigned long timestamp,
|
||||||
/* log_printhex (iov[i].data, iov[i].len, "cmpfpr i=%d: ", i); */
|
/* log_printhex (iov[i].data, iov[i].len, "cmpfpr i=%d: ", i); */
|
||||||
|
|
||||||
err = gcry_md_hash_buffers (hashalgo, 0, result, iov, iovcnt);
|
err = gcry_md_hash_buffers (hashalgo, 0, result, iov, iovcnt);
|
||||||
/* log_printhex (result, 20, "fingerpint: "); */
|
/* log_printhex (result, 20, "fingerprint: "); */
|
||||||
|
|
||||||
/* Better clear the first element because it was set by us. */
|
/* Better clear the first element because it was set by us. */
|
||||||
iov[0].size = 0;
|
iov[0].size = 0;
|
||||||
|
|
|
@ -43,23 +43,34 @@ static struct {
|
||||||
const char *oidstr; /* IETF formatted OID. */
|
const char *oidstr; /* IETF formatted OID. */
|
||||||
unsigned int nbits; /* Nominal bit length of the curve. */
|
unsigned int nbits; /* Nominal bit length of the curve. */
|
||||||
const char *alias; /* NULL or alternative name of the curve. */
|
const char *alias; /* NULL or alternative name of the curve. */
|
||||||
|
const char *abbr; /* NULL or abbreviated name of the curve. */
|
||||||
int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */
|
int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */
|
||||||
|
enum gcry_kem_algos kem_algo; /* 0 or the KEM algorithm for PQC. */
|
||||||
} oidtable[] = {
|
} oidtable[] = {
|
||||||
|
|
||||||
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
|
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", NULL,
|
||||||
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
|
PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 /* only during development */},
|
||||||
{ "Curve25519", "1.3.101.110", 255, "cv25519", PUBKEY_ALGO_ECDH },
|
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", NULL,
|
||||||
{ "Ed25519", "1.3.101.112", 255, "ed25519", PUBKEY_ALGO_EDDSA },
|
PUBKEY_ALGO_EDDSA },
|
||||||
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
|
{ "Curve25519", "1.3.101.110", 255, "cv25519", NULL,
|
||||||
{ "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA },
|
PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 },
|
||||||
|
{ "Ed25519", "1.3.101.112", 255, "ed25519", NULL,
|
||||||
|
PUBKEY_ALGO_EDDSA },
|
||||||
|
{ "X448", "1.3.101.111", 448, "cv448", NULL,
|
||||||
|
PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X448 },
|
||||||
|
{ "Ed448", "1.3.101.113", 456, "ed448", NULL,
|
||||||
|
PUBKEY_ALGO_EDDSA },
|
||||||
|
|
||||||
{ "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
|
{ "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
|
||||||
{ "NIST P-384", "1.3.132.0.34", 384, "nistp384" },
|
{ "NIST P-384", "1.3.132.0.34", 384, "nistp384" },
|
||||||
{ "NIST P-521", "1.3.132.0.35", 521, "nistp521" },
|
{ "NIST P-521", "1.3.132.0.35", 521, "nistp521" },
|
||||||
|
|
||||||
{ "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256 },
|
{ "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256, NULL, "bp256",
|
||||||
{ "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384 },
|
0, GCRY_KEM_RAW_BP256 },
|
||||||
{ "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 },
|
{ "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384, NULL, "bp384",
|
||||||
|
0, GCRY_KEM_RAW_BP384 },
|
||||||
|
{ "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512, NULL, "bp512",
|
||||||
|
0, GCRY_KEM_RAW_BP512 },
|
||||||
|
|
||||||
{ "secp256k1", "1.3.132.0.10", 256 },
|
{ "secp256k1", "1.3.132.0.10", 256 },
|
||||||
|
|
||||||
|
@ -118,7 +129,7 @@ make_flagged_int (unsigned long value, char *buf, size_t buflen)
|
||||||
|
|
||||||
/* fixme: figure out the number of bits in an ulong and start with
|
/* fixme: figure out the number of bits in an ulong and start with
|
||||||
that value as shift (after making it a multiple of 7) a more
|
that value as shift (after making it a multiple of 7) a more
|
||||||
straigtforward implementation is to do it in reverse order using
|
straightforward implementation is to do it in reverse order using
|
||||||
a temporary buffer - saves a lot of compares */
|
a temporary buffer - saves a lot of compares */
|
||||||
for (more=0, shift=28; shift > 0; shift -= 7)
|
for (more=0, shift=28; shift > 0; shift -= 7)
|
||||||
{
|
{
|
||||||
|
@ -477,10 +488,20 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo)
|
||||||
|
|
||||||
|
|
||||||
/* Map an OpenPGP OID to the Libgcrypt curve name. Returns NULL for
|
/* Map an OpenPGP OID to the Libgcrypt curve name. Returns NULL for
|
||||||
* unknown curve names. Unless CANON is set we prefer an alias name
|
* unknown curve names. MODE defines which version of the curve name
|
||||||
* here which is more suitable for printing. */
|
* is returned. For example:
|
||||||
|
*
|
||||||
|
* | OID | mode=0 | mode=1 | mode=2 |
|
||||||
|
* |----------------------+-----------------+-----------------+----------|
|
||||||
|
* | 1.2.840.10045.3.1.7 | nistp256 | NIST P-256 | nistp256 |
|
||||||
|
* | 1.3.36.3.3.2.8.1.1.7 | brainpoolP256r1 | brainpoolP256r1 | bp256 |
|
||||||
|
*
|
||||||
|
* Thus mode 0 returns the name as commonly used gpg, mode 1 returns
|
||||||
|
* the canonical name, and mode 2 prefers an abbreviated name over the
|
||||||
|
* commonly used name.
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
openpgp_oid_to_curve (const char *oidstr, int canon)
|
openpgp_oid_to_curve (const char *oidstr, int mode)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -489,7 +510,15 @@ openpgp_oid_to_curve (const char *oidstr, int canon)
|
||||||
|
|
||||||
for (i=0; oidtable[i].name; i++)
|
for (i=0; oidtable[i].name; i++)
|
||||||
if (!strcmp (oidtable[i].oidstr, oidstr))
|
if (!strcmp (oidtable[i].oidstr, oidstr))
|
||||||
return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
|
{
|
||||||
|
if (mode == 2)
|
||||||
|
{
|
||||||
|
if (oidtable[i].abbr)
|
||||||
|
return oidtable[i].abbr;
|
||||||
|
mode = 0; /* No abbreviation - fallback to mode 0. */
|
||||||
|
}
|
||||||
|
return !mode && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -517,6 +546,29 @@ openpgp_oid_or_name_to_curve (const char *oidname, int canon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the KEM algorithm id for the curve with OIDNAME. */
|
||||||
|
enum gcry_kem_algos
|
||||||
|
openpgp_oid_to_kem_algo (const char *oidname)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!oidname)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i=0; oidtable[i].name; i++)
|
||||||
|
if (!strcmp (oidtable[i].oidstr, oidname))
|
||||||
|
return oidtable[i].kem_algo;
|
||||||
|
|
||||||
|
for (i=0; oidtable[i].name; i++)
|
||||||
|
if (!ascii_strcasecmp (oidtable[i].name, oidname)
|
||||||
|
|| (oidtable[i].alias
|
||||||
|
&& !ascii_strcasecmp (oidtable[i].alias, oidname)))
|
||||||
|
return oidtable[i].kem_algo;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return true if the curve with NAME is supported. */
|
/* Return true if the curve with NAME is supported. */
|
||||||
static int
|
static int
|
||||||
curve_supported_p (const char *name)
|
curve_supported_p (const char *name)
|
||||||
|
@ -574,7 +626,9 @@ openpgp_is_curve_supported (const char *name, int *r_algo,
|
||||||
{
|
{
|
||||||
if ((!ascii_strcasecmp (name, oidtable[idx].name)
|
if ((!ascii_strcasecmp (name, oidtable[idx].name)
|
||||||
|| (oidtable[idx].alias
|
|| (oidtable[idx].alias
|
||||||
&& !ascii_strcasecmp (name, (oidtable[idx].alias))))
|
&& !ascii_strcasecmp (name, (oidtable[idx].alias)))
|
||||||
|
|| (oidtable[idx].abbr
|
||||||
|
&& !ascii_strcasecmp (name, (oidtable[idx].abbr))))
|
||||||
&& curve_supported_p (oidtable[idx].name))
|
&& curve_supported_p (oidtable[idx].name))
|
||||||
{
|
{
|
||||||
if (r_algo)
|
if (r_algo)
|
||||||
|
@ -598,6 +652,7 @@ map_gcry_pk_to_openpgp (enum gcry_pk_algos algo)
|
||||||
case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA;
|
case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA;
|
||||||
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
|
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
|
||||||
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
|
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
|
||||||
|
case GCRY_PK_KEM: return PUBKEY_ALGO_KYBER;
|
||||||
default: return algo < 110 ? (pubkey_algo_t)algo : 0;
|
default: return algo < 110 ? (pubkey_algo_t)algo : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,9 @@ typedef enum
|
||||||
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
|
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
|
||||||
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
|
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
|
||||||
|
|
||||||
|
SIGSUBPKT_META_HASH = 40, /* Literal Data Meta Hash. */
|
||||||
|
SIGSUBPKT_TRUST_ALIAS = 41, /* Trust Alias. */
|
||||||
|
|
||||||
SIGSUBPKT_FLAG_CRITICAL = 128
|
SIGSUBPKT_FLAG_CRITICAL = 128
|
||||||
}
|
}
|
||||||
sigsubpkttype_t;
|
sigsubpkttype_t;
|
||||||
|
@ -168,7 +171,11 @@ typedef enum
|
||||||
PUBKEY_ALGO_ECDSA = 19, /* RFC-6637 */
|
PUBKEY_ALGO_ECDSA = 19, /* RFC-6637 */
|
||||||
PUBKEY_ALGO_ELGAMAL = 20, /* Elgamal encrypt+sign (legacy). */
|
PUBKEY_ALGO_ELGAMAL = 20, /* Elgamal encrypt+sign (legacy). */
|
||||||
/* 21 reserved by OpenPGP. */
|
/* 21 reserved by OpenPGP. */
|
||||||
PUBKEY_ALGO_EDDSA = 22, /* EdDSA (not yet assigned). */
|
PUBKEY_ALGO_EDDSA = 22, /* EdDSA. */
|
||||||
|
PUBKEY_ALGO_KYBER = 29, /* Kyber */
|
||||||
|
PUBKEY_ALGO_DIL3_25519 = 35, /* Dilithium3 + Ed25519 (aka ML-DSA-65) */
|
||||||
|
PUBKEY_ALGO_DIL5_448 = 36, /* Dilithium5 + Ed448 (aka ML-DSA-87) */
|
||||||
|
PUBKEY_ALGO_SPHINX_SHA2 = 41, /* SPHINX+-simple-SHA2 (aka SLH-DSA-SHA2) */
|
||||||
PUBKEY_ALGO_PRIVATE10 = 110
|
PUBKEY_ALGO_PRIVATE10 = 110
|
||||||
}
|
}
|
||||||
pubkey_algo_t;
|
pubkey_algo_t;
|
||||||
|
@ -203,7 +210,7 @@ compress_algo_t;
|
||||||
#define OPENPGP_MAX_NPKEY 5 /* Maximum number of public key parameters. */
|
#define OPENPGP_MAX_NPKEY 5 /* Maximum number of public key parameters. */
|
||||||
#define OPENPGP_MAX_NSKEY 7 /* Maximum number of secret key parameters. */
|
#define OPENPGP_MAX_NSKEY 7 /* Maximum number of secret key parameters. */
|
||||||
#define OPENPGP_MAX_NSIG 2 /* Maximum number of signature parameters. */
|
#define OPENPGP_MAX_NSIG 2 /* Maximum number of signature parameters. */
|
||||||
#define OPENPGP_MAX_NENC 2 /* Maximum number of encryption parameters. */
|
#define OPENPGP_MAX_NENC 4 /* Maximum number of encryption parameters. */
|
||||||
|
|
||||||
|
|
||||||
/* Decode an rfc4880 encoded S2K count. */
|
/* Decode an rfc4880 encoded S2K count. */
|
||||||
|
|
|
@ -85,37 +85,6 @@ my_error (gpg_err_code_t ec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This is a case-sensitive version of our memistr. I wonder why no
|
|
||||||
* standard function memstr exists but I better do not use the name
|
|
||||||
* memstr to avoid future conflicts.
|
|
||||||
*
|
|
||||||
* FIXME: Move this to a stringhelp.c
|
|
||||||
*/
|
|
||||||
static const char *
|
|
||||||
my_memstr (const void *buffer, size_t buflen, const char *sub)
|
|
||||||
{
|
|
||||||
const unsigned char *buf = buffer;
|
|
||||||
const unsigned char *t = (const unsigned char *)buf;
|
|
||||||
const unsigned char *s = (const unsigned char *)sub;
|
|
||||||
size_t n = buflen;
|
|
||||||
|
|
||||||
for ( ; n ; t++, n-- )
|
|
||||||
{
|
|
||||||
if (*t == *s)
|
|
||||||
{
|
|
||||||
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
|
|
||||||
;
|
|
||||||
if (!*s)
|
|
||||||
return (const char*)buf;
|
|
||||||
t = (const unsigned char *)buf;
|
|
||||||
s = (const unsigned char *)sub ;
|
|
||||||
n = buflen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return a pointer to the next logical connection operator or NULL if
|
/* Return a pointer to the next logical connection operator or NULL if
|
||||||
* none. */
|
* none. */
|
||||||
static char *
|
static char *
|
||||||
|
@ -560,7 +529,7 @@ recsel_select (recsel_expr_t selector,
|
||||||
break;
|
break;
|
||||||
case SELECT_SUB:
|
case SELECT_SUB:
|
||||||
if (se->xcase)
|
if (se->xcase)
|
||||||
result = !!my_memstr (value, valuelen, se->value);
|
result = !!gnupg_memstr (value, valuelen, se->value);
|
||||||
else
|
else
|
||||||
result = !!memistr (value, valuelen, se->value);
|
result = !!memistr (value, valuelen, se->value);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -84,9 +84,10 @@ static struct
|
||||||
modules (eg "xim"). */
|
modules (eg "xim"). */
|
||||||
{ "INSIDE_EMACS" }, /* Set by Emacs before running a
|
{ "INSIDE_EMACS" }, /* Set by Emacs before running a
|
||||||
process. */
|
process. */
|
||||||
{ "PINENTRY_USER_DATA", "pinentry-user-data"}
|
{ "PINENTRY_USER_DATA", "pinentry-user-data"},
|
||||||
/* Used for communication with
|
/* Used for communication with
|
||||||
non-standard Pinentries. */
|
non-standard Pinentries. */
|
||||||
|
{ "PINENTRY_GEOM_HINT" } /* Used to pass window information. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -314,7 +315,7 @@ session_env_putenv (session_env_t se, const char *string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Same as session_env_putenv but with name and value given as distict
|
/* Same as session_env_putenv but with name and value given as distinct
|
||||||
values. */
|
values. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
session_env_setenv (session_env_t se, const char *name, const char *value)
|
session_env_setenv (session_env_t se, const char *name, const char *value)
|
||||||
|
@ -354,7 +355,7 @@ session_env_getenv (session_env_t se, const char *name)
|
||||||
object. The returned value is valid as long as SE is valid and as
|
object. The returned value is valid as long as SE is valid and as
|
||||||
long it has not been removed or updated by a call to
|
long it has not been removed or updated by a call to
|
||||||
session_env_putenv. If the variable does not exist, the function
|
session_env_putenv. If the variable does not exist, the function
|
||||||
tries to return the value trough a call to getenv; if that returns
|
tries to return the value through a call to getenv; if that returns
|
||||||
a value, this value is recorded and used. If no value could be
|
a value, this value is recorded and used. If no value could be
|
||||||
found, returns NULL. The caller must not change the returned
|
found, returns NULL. The caller must not change the returned
|
||||||
value. */
|
value. */
|
||||||
|
|
|
@ -104,7 +104,7 @@ smatch (unsigned char const **buf, size_t buflen, const char *token)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Format VALUE for use as the length indicatior of an S-expression.
|
/* Format VALUE for use as the length indicator of an S-expression.
|
||||||
The caller needs to provide a buffer HELP_BUFFER with a length of
|
The caller needs to provide a buffer HELP_BUFFER with a length of
|
||||||
HELP_BUFLEN. The return value is a pointer into HELP_BUFFER with
|
HELP_BUFLEN. The return value is a pointer into HELP_BUFFER with
|
||||||
the formatted length string. The colon and a trailing nul are
|
the formatted length string. The colon and a trailing nul are
|
||||||
|
|
|
@ -199,7 +199,7 @@ make_canon_sexp_pad (gcry_sexp_t sexp, int secure,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the so called "keygrip" which is the SHA-1 hash of the
|
/* Return the so called "keygrip" which is the SHA-1 hash of the
|
||||||
public key parameters expressed in a way dependend on the algorithm.
|
public key parameters expressed in a way dependent on the algorithm.
|
||||||
|
|
||||||
KEY is expected to be an canonical encoded S-expression with a
|
KEY is expected to be an canonical encoded S-expression with a
|
||||||
public or private key. KEYLEN is the length of that buffer.
|
public or private key. KEYLEN is the length of that buffer.
|
||||||
|
@ -992,7 +992,7 @@ get_pk_algo_from_key (gcry_sexp_t key)
|
||||||
gcry_sexp_t list;
|
gcry_sexp_t list;
|
||||||
const char *s;
|
const char *s;
|
||||||
size_t n;
|
size_t n;
|
||||||
char algoname[6];
|
char algoname[10];
|
||||||
int algo = 0;
|
int algo = 0;
|
||||||
|
|
||||||
list = gcry_sexp_nth (key, 1);
|
list = gcry_sexp_nth (key, 1);
|
||||||
|
@ -1194,3 +1194,47 @@ cipher_mode_to_string (int mode)
|
||||||
default: return "[?]";
|
default: return "[?]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the canonical name of the ECC curve in KEY. */
|
||||||
|
const char *
|
||||||
|
get_ecc_curve_from_key (gcry_sexp_t key)
|
||||||
|
{
|
||||||
|
gcry_sexp_t list = NULL;
|
||||||
|
gcry_sexp_t l2 = NULL;
|
||||||
|
const char *curve_name = NULL;
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
/* Check that the first element is valid. */
|
||||||
|
list = gcry_sexp_find_token (key, "public-key", 0);
|
||||||
|
if (!list)
|
||||||
|
list = gcry_sexp_find_token (key, "private-key", 0);
|
||||||
|
if (!list)
|
||||||
|
list = gcry_sexp_find_token (key, "protected-private-key", 0);
|
||||||
|
if (!list)
|
||||||
|
list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
|
||||||
|
if (!list)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
l2 = gcry_sexp_cadr (list);
|
||||||
|
gcry_sexp_release (list);
|
||||||
|
list = l2;
|
||||||
|
l2 = NULL;
|
||||||
|
|
||||||
|
name = gcry_sexp_nth_string (list, 0);
|
||||||
|
if (!name)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (gcry_pk_map_name (name) != GCRY_PK_ECC)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
l2 = gcry_sexp_find_token (list, "curve", 0);
|
||||||
|
xfree (name);
|
||||||
|
name = gcry_sexp_nth_string (l2, 1);
|
||||||
|
curve_name = openpgp_oid_or_name_to_curve (name, 1);
|
||||||
|
gcry_sexp_release (l2);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (name);
|
||||||
|
gcry_sexp_release (list);
|
||||||
|
return curve_name;
|
||||||
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct b64state b64s;
|
gpgrt_b64state_t b64s;
|
||||||
estream_t stream;
|
estream_t stream;
|
||||||
char *p;
|
char *p;
|
||||||
long int len;
|
long int len;
|
||||||
|
@ -273,15 +273,15 @@ get_fingerprint (gcry_sexp_t key, int algo,
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b64enc_start_es (&b64s, stream, "");
|
b64s = gpgrt_b64enc_start (stream, "");
|
||||||
if (err)
|
if (!b64s)
|
||||||
{
|
{
|
||||||
es_fclose (stream);
|
es_fclose (stream);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b64enc_write (&b64s,
|
err = gpgrt_b64enc_write (b64s, gcry_md_read (md, algo),
|
||||||
gcry_md_read (md, algo), gcry_md_get_algo_dlen (algo));
|
gcry_md_get_algo_dlen (algo));
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
es_fclose (stream);
|
es_fclose (stream);
|
||||||
|
@ -289,7 +289,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finish, get the length, and close the stream. */
|
/* Finish, get the length, and close the stream. */
|
||||||
err = b64enc_finish (&b64s);
|
err = gpgrt_b64enc_finish (b64s);
|
||||||
len = es_ftell (stream);
|
len = es_ftell (stream);
|
||||||
es_fclose (stream);
|
es_fclose (stream);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -566,7 +566,7 @@ ssh_public_key_in_base64 (gcry_sexp_t key, estream_t stream,
|
||||||
const char *identifier = NULL;
|
const char *identifier = NULL;
|
||||||
void *blob = NULL;
|
void *blob = NULL;
|
||||||
size_t bloblen;
|
size_t bloblen;
|
||||||
struct b64state b64_state;
|
gpgrt_b64state_t b64_state;
|
||||||
|
|
||||||
algo = get_pk_algo_from_key (key);
|
algo = get_pk_algo_from_key (key);
|
||||||
if (algo == 0)
|
if (algo == 0)
|
||||||
|
@ -624,15 +624,15 @@ ssh_public_key_in_base64 (gcry_sexp_t key, estream_t stream,
|
||||||
|
|
||||||
es_fprintf (stream, "%s ", identifier);
|
es_fprintf (stream, "%s ", identifier);
|
||||||
|
|
||||||
err = b64enc_start_es (&b64_state, stream, "");
|
b64_state = gpgrt_b64enc_start (stream, "");
|
||||||
if (err)
|
if (!b64_state)
|
||||||
{
|
{
|
||||||
es_free (blob);
|
es_free (blob);
|
||||||
return err;
|
return gpg_error_from_syserror ();
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b64enc_write (&b64_state, blob, bloblen);
|
err = gpgrt_b64enc_write (b64_state, blob, bloblen);
|
||||||
b64enc_finish (&b64_state);
|
gpgrt_b64enc_finish (b64_state);
|
||||||
es_free (blob);
|
es_free (blob);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -54,6 +54,7 @@ enum
|
||||||
STATUS_NEED_PASSPHRASE,
|
STATUS_NEED_PASSPHRASE,
|
||||||
STATUS_VALIDSIG,
|
STATUS_VALIDSIG,
|
||||||
STATUS_ASSERT_SIGNER,
|
STATUS_ASSERT_SIGNER,
|
||||||
|
STATUS_ASSERT_PUBKEY_ALGO,
|
||||||
STATUS_SIG_ID,
|
STATUS_SIG_ID,
|
||||||
STATUS_ENC_TO,
|
STATUS_ENC_TO,
|
||||||
STATUS_NODATA,
|
STATUS_NODATA,
|
||||||
|
@ -152,6 +153,7 @@ enum
|
||||||
STATUS_TRUNCATED,
|
STATUS_TRUNCATED,
|
||||||
STATUS_MOUNTPOINT,
|
STATUS_MOUNTPOINT,
|
||||||
STATUS_BLOCKDEV,
|
STATUS_BLOCKDEV,
|
||||||
|
STATUS_PLAINDEV, /* The decrypted virtual device. */
|
||||||
|
|
||||||
STATUS_PINENTRY_LAUNCHED,
|
STATUS_PINENTRY_LAUNCHED,
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,35 @@ ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This is a case-sensitive version of our memistr. I wonder why no
|
||||||
|
* standard function memstr exists but we better do not use the name
|
||||||
|
* memstr to avoid future conflicts.
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
gnupg_memstr (const void *buffer, size_t buflen, const char *sub)
|
||||||
|
{
|
||||||
|
const unsigned char *buf = buffer;
|
||||||
|
const unsigned char *t = (const unsigned char *)buf;
|
||||||
|
const unsigned char *s = (const unsigned char *)sub;
|
||||||
|
size_t n = buflen;
|
||||||
|
|
||||||
|
for ( ; n ; t++, n-- )
|
||||||
|
{
|
||||||
|
if (*t == *s)
|
||||||
|
{
|
||||||
|
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
|
||||||
|
;
|
||||||
|
if (!*s)
|
||||||
|
return (const char*)buf;
|
||||||
|
t = (const unsigned char *)buf;
|
||||||
|
s = (const unsigned char *)sub ;
|
||||||
|
n = buflen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This function is similar to strncpy(). However it won't copy more
|
/* This function is similar to strncpy(). However it won't copy more
|
||||||
* than N - 1 characters and makes sure that a '\0' is appended. With
|
* than N - 1 characters and makes sure that a '\0' is appended. With
|
||||||
* N given as 0, nothing will happen. With DEST given as NULL, memory
|
* N given as 0, nothing will happen. With DEST given as NULL, memory
|
||||||
|
@ -696,7 +725,7 @@ compare_filenames (const char *a, const char *b)
|
||||||
|
|
||||||
/* Convert a base-10 number in STRING into a 64 bit unsigned int
|
/* Convert a base-10 number in STRING into a 64 bit unsigned int
|
||||||
* value. Leading white spaces are skipped but no error checking is
|
* value. Leading white spaces are skipped but no error checking is
|
||||||
* done. Thus it is similar to atoi(). */
|
* done. Thus it is similar to atoi(). See also scan_secondsstr. */
|
||||||
uint64_t
|
uint64_t
|
||||||
string_to_u64 (const char *string)
|
string_to_u64 (const char *string)
|
||||||
{
|
{
|
||||||
|
@ -1689,10 +1718,16 @@ format_text (const char *text_in, int target_cols, int max_cols)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Substitute environment variables in STRING and return a new string.
|
/* Substitute variables in STRING and return a new string. GETVAL is
|
||||||
* On error the function returns NULL. */
|
* a function which maps NAME to its value; that value is a string
|
||||||
|
* which may not change during the execution time of this function.
|
||||||
|
* If GETVAL returns NULL substitute_vars returns NULL and the caller
|
||||||
|
* may inspect ERRNO for the reason. In all other error cases this
|
||||||
|
* function also returns NULL. Caller must free the returned string. */
|
||||||
char *
|
char *
|
||||||
substitute_envvars (const char *string)
|
substitute_vars (const char *string,
|
||||||
|
const char *(*getval)(void *cookie, const char *name),
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
char *line, *p, *pend;
|
char *line, *p, *pend;
|
||||||
const char *value;
|
const char *value;
|
||||||
|
@ -1743,19 +1778,22 @@ substitute_envvars (const char *string)
|
||||||
{
|
{
|
||||||
int save = *pend;
|
int save = *pend;
|
||||||
*pend = 0;
|
*pend = 0;
|
||||||
value = getenv (p+2);
|
value = getval (cookie, p+2);
|
||||||
*pend++ = save;
|
*pend++ = save;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int save = *pend;
|
int save = *pend;
|
||||||
*pend = 0;
|
*pend = 0;
|
||||||
value = getenv (p+1);
|
value = getval (cookie, p+1);
|
||||||
*pend = save;
|
*pend = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
value = "";
|
{
|
||||||
|
xfree (result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
valuelen = strlen (value);
|
valuelen = strlen (value);
|
||||||
if (valuelen <= pend - p)
|
if (valuelen <= pend - p)
|
||||||
{
|
{
|
||||||
|
@ -1791,3 +1829,26 @@ substitute_envvars (const char *string)
|
||||||
leave:
|
leave:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for substitute_envvars. */
|
||||||
|
static const char *
|
||||||
|
subst_getenv (void *cookie, const char *name)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
(void)cookie;
|
||||||
|
|
||||||
|
s = getenv (name);
|
||||||
|
return s? s : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Substitute environment variables in STRING and return a new string.
|
||||||
|
* On error the function returns NULL. */
|
||||||
|
char *
|
||||||
|
substitute_envvars (const char *string)
|
||||||
|
{
|
||||||
|
return substitute_vars (string, subst_getenv, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
char *has_leading_keyword (const char *string, const char *keyword);
|
char *has_leading_keyword (const char *string, const char *keyword);
|
||||||
|
|
||||||
const char *memistr (const void *buf, size_t buflen, const char *sub);
|
const char *memistr (const void *buf, size_t buflen, const char *sub);
|
||||||
|
const char *gnupg_memstr (const void *buffer, size_t buflen, const char *sub);
|
||||||
char *mem2str( char *, const void *, size_t);
|
char *mem2str( char *, const void *, size_t);
|
||||||
char *trim_spaces( char *string );
|
char *trim_spaces( char *string );
|
||||||
char *ascii_trim_spaces (char *string);
|
char *ascii_trim_spaces (char *string);
|
||||||
|
@ -169,7 +170,10 @@ int compare_version_strings (const char *my_version, const char *req_version);
|
||||||
/* Format a string so that it fits within about TARGET_COLS columns. */
|
/* Format a string so that it fits within about TARGET_COLS columns. */
|
||||||
char *format_text (const char *text, int target_cols, int max_cols);
|
char *format_text (const char *text, int target_cols, int max_cols);
|
||||||
|
|
||||||
/* Substitute environmen variabales in STRING. */
|
/* Substitute variables in STRING. */
|
||||||
|
char *substitute_vars (const char *string,
|
||||||
|
const char *(*getval)(void *cookie, const char *name),
|
||||||
|
void *cookie);
|
||||||
char *substitute_envvars (const char *string);
|
char *substitute_envvars (const char *string);
|
||||||
|
|
||||||
|
|
||||||
|
|
118
common/strlist.c
118
common/strlist.c
|
@ -1,6 +1,6 @@
|
||||||
/* strlist.c - string helpers
|
/* strlist.c - string helpers
|
||||||
* Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
|
* Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2015 g10 Code GmbH
|
* Copyright (C) 2015, 2024 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
* You should have received a copies of the GNU General Public License
|
* You should have received a copies of the GNU General Public License
|
||||||
* and the GNU Lesser General Public License along with this program;
|
* and the GNU Lesser General Public License along with this program;
|
||||||
* if not, see <https://www.gnu.org/licenses/>.
|
* if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -134,27 +135,39 @@ append_to_strlist( strlist_t *list, const char *string )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Core of append_to_strlist_try which take the length of the string.
|
||||||
|
* Return the item added to the end of the list. Or NULL in case of
|
||||||
|
* an error. */
|
||||||
|
static strlist_t
|
||||||
|
do_append_to_strlist (strlist_t *list, const char *string, size_t stringlen)
|
||||||
|
{
|
||||||
|
strlist_t r, sl;
|
||||||
|
|
||||||
|
sl = xtrymalloc (sizeof *sl + stringlen);
|
||||||
|
if (!sl)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sl->flags = 0;
|
||||||
|
memcpy (sl->d, string, stringlen);
|
||||||
|
sl->d[stringlen] = 0;
|
||||||
|
sl->next = NULL;
|
||||||
|
if (!*list)
|
||||||
|
*list = sl;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (r = *list; r->next; r = r->next)
|
||||||
|
;
|
||||||
|
r->next = sl;
|
||||||
|
}
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add STRING to the LIST at the end. */
|
/* Add STRING to the LIST at the end. */
|
||||||
strlist_t
|
strlist_t
|
||||||
append_to_strlist_try (strlist_t *list, const char *string)
|
append_to_strlist_try (strlist_t *list, const char *string)
|
||||||
{
|
{
|
||||||
strlist_t r, sl;
|
return do_append_to_strlist (list, string, strlen (string));
|
||||||
|
|
||||||
sl = xtrymalloc( sizeof *sl + strlen(string));
|
|
||||||
if (sl == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
sl->flags = 0;
|
|
||||||
strcpy(sl->d, string);
|
|
||||||
sl->next = NULL;
|
|
||||||
if( !*list )
|
|
||||||
*list = sl;
|
|
||||||
else {
|
|
||||||
for( r = *list; r->next; r = r->next )
|
|
||||||
;
|
|
||||||
r->next = sl;
|
|
||||||
}
|
|
||||||
return sl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,6 +188,75 @@ append_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Tokenize STRING using the delimiters from DELIM and append each
|
||||||
|
* token to the string list LIST. On success a pinter into LIST with
|
||||||
|
* the first new token is returned. Returns NULL on error and sets
|
||||||
|
* ERRNO. Take care, an error with ENOENT set mean that no tokens
|
||||||
|
* were found in STRING. */
|
||||||
|
strlist_t
|
||||||
|
tokenize_to_strlist (strlist_t *list, const char *string, const char *delim)
|
||||||
|
{
|
||||||
|
const char *s, *se;
|
||||||
|
size_t n;
|
||||||
|
strlist_t newlist = NULL;
|
||||||
|
strlist_t tail;
|
||||||
|
|
||||||
|
s = string;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
se = strpbrk (s, delim);
|
||||||
|
if (se)
|
||||||
|
n = se - s;
|
||||||
|
else
|
||||||
|
n = strlen (s);
|
||||||
|
if (!n)
|
||||||
|
continue; /* Skip empty string. */
|
||||||
|
tail = do_append_to_strlist (&newlist, s, n);
|
||||||
|
if (!tail)
|
||||||
|
{
|
||||||
|
free_strlist (newlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
trim_spaces (tail->d);
|
||||||
|
if (!*tail->d) /* Remove new but empty item from the list. */
|
||||||
|
{
|
||||||
|
tail = strlist_prev (newlist, tail);
|
||||||
|
if (tail)
|
||||||
|
{
|
||||||
|
free_strlist (tail->next);
|
||||||
|
tail->next = NULL;
|
||||||
|
}
|
||||||
|
else if (newlist)
|
||||||
|
{
|
||||||
|
free_strlist (newlist);
|
||||||
|
newlist = NULL;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (se && (s = se + 1));
|
||||||
|
|
||||||
|
if (!newlist)
|
||||||
|
{
|
||||||
|
/* Not items found. Indicate this by returnning NULL with errno
|
||||||
|
* set to ENOENT. */
|
||||||
|
gpg_err_set_errno (ENOENT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append NEWLIST to LIST. */
|
||||||
|
if (!*list)
|
||||||
|
*list = newlist;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (tail = *list; tail->next; tail = tail->next)
|
||||||
|
;
|
||||||
|
tail->next = newlist;
|
||||||
|
}
|
||||||
|
return newlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a copy of LIST. This function terminates the process on
|
/* Return a copy of LIST. This function terminates the process on
|
||||||
memory shortage.*/
|
memory shortage.*/
|
||||||
strlist_t
|
strlist_t
|
||||||
|
|
|
@ -52,6 +52,9 @@ strlist_t append_to_strlist_try (strlist_t *list, const char *string);
|
||||||
strlist_t append_to_strlist2 (strlist_t *list, const char *string,
|
strlist_t append_to_strlist2 (strlist_t *list, const char *string,
|
||||||
int is_utf8);
|
int is_utf8);
|
||||||
|
|
||||||
|
strlist_t tokenize_to_strlist (strlist_t *list,
|
||||||
|
const char *string, const char *delim);
|
||||||
|
|
||||||
strlist_t strlist_copy (strlist_t list);
|
strlist_t strlist_copy (strlist_t list);
|
||||||
|
|
||||||
strlist_t strlist_prev (strlist_t head, strlist_t node);
|
strlist_t strlist_prev (strlist_t head, strlist_t node);
|
||||||
|
|
|
@ -113,6 +113,8 @@ static int allow_special_filenames;
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
/* State of gnupg_inhibit_set_foregound_window. */
|
/* State of gnupg_inhibit_set_foregound_window. */
|
||||||
static int inhibit_set_foregound_window;
|
static int inhibit_set_foregound_window;
|
||||||
|
/* Disable the use of _open_osfhandle. */
|
||||||
|
static int no_translate_sys2libc_fd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,6 +254,9 @@ map_w32_to_errno (DWORD w32_err)
|
||||||
case ERROR_ALREADY_EXISTS:
|
case ERROR_ALREADY_EXISTS:
|
||||||
return EEXIST;
|
return EEXIST;
|
||||||
|
|
||||||
|
case ERROR_FILE_INVALID:
|
||||||
|
return EIO;
|
||||||
|
|
||||||
/* This mapping has been taken from reactOS. */
|
/* This mapping has been taken from reactOS. */
|
||||||
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
|
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
|
||||||
case ERROR_ARENA_TRASHED: return ENOMEM;
|
case ERROR_ARENA_TRASHED: return ENOMEM;
|
||||||
|
@ -324,15 +329,17 @@ map_w32_to_errno (DWORD w32_err)
|
||||||
#endif /*HAVE_W32_SYSTEM*/
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
|
|
||||||
/* Set ERRNO from the Windows error. EC may be -1 to use the last error. */
|
/* Set ERRNO from the Windows error. EC may be -1 to use the last
|
||||||
|
* error. Returns the Windows error code. */
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
void
|
int
|
||||||
gnupg_w32_set_errno (int ec)
|
gnupg_w32_set_errno (int ec)
|
||||||
{
|
{
|
||||||
/* FIXME: Replace by gpgrt_w32_set_errno. */
|
/* FIXME: Replace by gpgrt_w32_set_errno. */
|
||||||
if (ec == -1)
|
if (ec == -1)
|
||||||
ec = GetLastError ();
|
ec = GetLastError ();
|
||||||
_set_errno (map_w32_to_errno (ec));
|
_set_errno (map_w32_to_errno (ec));
|
||||||
|
return ec;
|
||||||
}
|
}
|
||||||
#endif /*HAVE_W32_SYSTEM*/
|
#endif /*HAVE_W32_SYSTEM*/
|
||||||
|
|
||||||
|
@ -346,6 +353,16 @@ enable_special_filenames (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Disable the use use of _open_osfhandle on Windows. */
|
||||||
|
void
|
||||||
|
disable_translate_sys2libc_fd (void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
no_translate_sys2libc_fd = 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a string which is used as a kind of process ID. */
|
/* Return a string which is used as a kind of process ID. */
|
||||||
const byte *
|
const byte *
|
||||||
get_session_marker (size_t *rlen)
|
get_session_marker (size_t *rlen)
|
||||||
|
@ -532,10 +549,10 @@ gnupg_usleep (unsigned int usecs)
|
||||||
different from the libc file descriptors (like open). This function
|
different from the libc file descriptors (like open). This function
|
||||||
translates system file handles to libc file handles. FOR_WRITE
|
translates system file handles to libc file handles. FOR_WRITE
|
||||||
gives the direction of the handle. */
|
gives the direction of the handle. */
|
||||||
int
|
#if defined(HAVE_W32_SYSTEM)
|
||||||
|
static int
|
||||||
translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
|
translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_W32_SYSTEM)
|
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
if (fd == GNUPG_INVALID_FD)
|
if (fd == GNUPG_INVALID_FD)
|
||||||
|
@ -547,27 +564,87 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
|
||||||
if (x == -1)
|
if (x == -1)
|
||||||
log_error ("failed to translate osfhandle %p\n", (void *) fd);
|
log_error ("failed to translate osfhandle %p\n", (void *) fd);
|
||||||
return x;
|
return x;
|
||||||
#else /*!HAVE_W32_SYSTEM */
|
}
|
||||||
|
#endif /*!HAVE_W32_SYSTEM */
|
||||||
|
|
||||||
|
|
||||||
|
/* This is the same as translate_sys2libc_fd but takes an integer
|
||||||
|
which is assumed to be such an system handle. */
|
||||||
|
int
|
||||||
|
translate_sys2libc_fd_int (int fd, int for_write)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
if (fd <= 2 || no_translate_sys2libc_fd)
|
||||||
|
return fd; /* Do not do this for stdin, stdout, and stderr. */
|
||||||
|
|
||||||
|
return translate_sys2libc_fd ((void*)(intptr_t)fd, for_write);
|
||||||
|
#else
|
||||||
(void)for_write;
|
(void)for_write;
|
||||||
return fd;
|
return fd;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is the same as translate_sys2libc_fd but takes an integer
|
|
||||||
which is assumed to be such an system handle. On WindowsCE the
|
|
||||||
passed FD is a rendezvous ID and the function finishes the pipe
|
|
||||||
creation. */
|
|
||||||
int
|
|
||||||
translate_sys2libc_fd_int (int fd, int for_write)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
if (fd <= 2)
|
|
||||||
return fd; /* Do not do this for error, stdin, stdout, stderr. */
|
|
||||||
|
|
||||||
return translate_sys2libc_fd ((void*)fd, for_write);
|
/*
|
||||||
|
* Parse the string representation of a file reference (file handle on
|
||||||
|
* Windows or file descriptor on POSIX) in FDSTR. The string
|
||||||
|
* representation may be either of following:
|
||||||
|
|
||||||
|
* (1) 0, 1, or 2 which means stdin, stdout, and stderr, respectively.
|
||||||
|
* (2) Integer representation (by %d of printf).
|
||||||
|
* (3) Hex representation which starts as "0x".
|
||||||
|
*
|
||||||
|
* Then, fill R_SYSHD, according to the value of a file reference.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
gpg_error_t
|
||||||
|
gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
gnupg_fd_t hd;
|
||||||
|
char *endptr;
|
||||||
|
int base;
|
||||||
|
|
||||||
|
if (!strcmp (fdstr, "0"))
|
||||||
|
fd = 0;
|
||||||
|
else if (!strcmp (fdstr, "1"))
|
||||||
|
fd = 1;
|
||||||
|
else if (!strcmp (fdstr, "2"))
|
||||||
|
fd = 2;
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
r_syshd->type = ES_SYSHD_FD;
|
||||||
|
r_syshd->u.fd = fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp (fdstr, "0x", 2))
|
||||||
|
{
|
||||||
|
base = 16;
|
||||||
|
fdstr += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
base = 10;
|
||||||
|
|
||||||
|
gpg_err_set_errno (0);
|
||||||
|
#ifdef _WIN64
|
||||||
|
hd = (gnupg_fd_t)strtoll (fdstr, &endptr, base);
|
||||||
#else
|
#else
|
||||||
(void)for_write;
|
hd = (gnupg_fd_t)strtol (fdstr, &endptr, base);
|
||||||
return fd;
|
#endif
|
||||||
|
if (errno != 0 || endptr == fdstr || *endptr != '\0')
|
||||||
|
return gpg_error (GPG_ERR_INV_ARG);
|
||||||
|
|
||||||
|
r_syshd->type = ES_SYSHD_HANDLE;
|
||||||
|
r_syshd->u.handle = hd;
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
fd = atoi (fdstr);
|
||||||
|
r_syshd->type = ES_SYSHD_FD;
|
||||||
|
r_syshd->u.fd = fd;
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,13 +666,74 @@ check_special_filename (const char *fname, int for_write, int notranslate)
|
||||||
for (i=0; digitp (fname+i); i++ )
|
for (i=0; digitp (fname+i); i++ )
|
||||||
;
|
;
|
||||||
if (!fname[i])
|
if (!fname[i])
|
||||||
return notranslate? atoi (fname)
|
{
|
||||||
/**/ : translate_sys2libc_fd_int (atoi (fname), for_write);
|
if (notranslate)
|
||||||
|
return atoi (fname);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
es_syshd_t syshd;
|
||||||
|
|
||||||
|
if (gnupg_parse_fdstr (fname, &syshd))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
if (syshd.type == ES_SYSHD_FD)
|
||||||
|
return syshd.u.fd;
|
||||||
|
else
|
||||||
|
return translate_sys2libc_fd ((gnupg_fd_t)syshd.u.handle, for_write);
|
||||||
|
#else
|
||||||
|
(void)for_write;
|
||||||
|
return syshd.u.fd;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether FNAME has the form "-&nnnn", where N is a number
|
||||||
|
* representing a file. Returns GNUPG_INVALID_FD if it is not the
|
||||||
|
* case. Returns a file descriptor on POSIX, a system handle on
|
||||||
|
* Windows. */
|
||||||
|
gnupg_fd_t
|
||||||
|
gnupg_check_special_filename (const char *fname)
|
||||||
|
{
|
||||||
|
if (allow_special_filenames
|
||||||
|
&& fname && *fname == '-' && fname[1] == '&')
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fname += 2;
|
||||||
|
for (i=0; digitp (fname+i); i++ )
|
||||||
|
;
|
||||||
|
if (!fname[i])
|
||||||
|
{
|
||||||
|
es_syshd_t syshd;
|
||||||
|
|
||||||
|
if (gnupg_parse_fdstr (fname, &syshd))
|
||||||
|
return GNUPG_INVALID_FD;
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
if (syshd.type == ES_SYSHD_FD)
|
||||||
|
{
|
||||||
|
if (syshd.u.fd == 0)
|
||||||
|
return GetStdHandle (STD_INPUT_HANDLE);
|
||||||
|
else if (syshd.u.fd == 1)
|
||||||
|
return GetStdHandle (STD_OUTPUT_HANDLE);
|
||||||
|
else if (syshd.u.fd == 2)
|
||||||
|
return GetStdHandle (STD_ERROR_HANDLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return syshd.u.handle;
|
||||||
|
#else
|
||||||
|
return syshd.u.fd;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GNUPG_INVALID_FD;
|
||||||
|
}
|
||||||
|
|
||||||
/* Replacement for tmpfile(). This is required because the tmpfile
|
/* Replacement for tmpfile(). This is required because the tmpfile
|
||||||
function of Windows' runtime library is broken, insecure, ignores
|
function of Windows' runtime library is broken, insecure, ignores
|
||||||
TMPDIR and so on. In addition we create a file with an inheritable
|
TMPDIR and so on. In addition we create a file with an inheritable
|
||||||
|
@ -805,7 +943,12 @@ gnupg_remove (const char *fname)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return remove (fname);
|
/* It is common to use /dev/null for testing. We better don't
|
||||||
|
* remove that file. */
|
||||||
|
if (fname && !strcmp (fname, "/dev/null"))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return remove (fname);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,7 +1106,7 @@ modestr_to_mode (const char *modestr, mode_t oldmode)
|
||||||
int
|
int
|
||||||
gnupg_mkdir (const char *name, const char *modestr)
|
gnupg_mkdir (const char *name, const char *modestr)
|
||||||
{
|
{
|
||||||
/* Note that gpgrt_mkdir also sets ERRNO in addition to returing an
|
/* Note that gpgrt_mkdir also sets ERRNO in addition to returning an
|
||||||
* gpg-error style error code. */
|
* gpg-error style error code. */
|
||||||
return gpgrt_mkdir (name, modestr);
|
return gpgrt_mkdir (name, modestr);
|
||||||
}
|
}
|
||||||
|
@ -1148,6 +1291,19 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
|
||||||
return setenv (name, value, overwrite);
|
return setenv (name, value, overwrite);
|
||||||
#else /*!HAVE_SETENV*/
|
#else /*!HAVE_SETENV*/
|
||||||
if (! getenv (name) || overwrite)
|
if (! getenv (name) || overwrite)
|
||||||
|
#if defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
|
||||||
|
{
|
||||||
|
int e = _putenv_s (name, value);
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
gpg_err_set_errno (e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
|
@ -1165,6 +1321,7 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
|
||||||
# endif
|
# endif
|
||||||
return putenv (buf);
|
return putenv (buf);
|
||||||
}
|
}
|
||||||
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
return 0;
|
return 0;
|
||||||
#endif /*!HAVE_SETENV*/
|
#endif /*!HAVE_SETENV*/
|
||||||
}
|
}
|
||||||
|
@ -1189,6 +1346,18 @@ gnupg_unsetenv (const char *name)
|
||||||
|
|
||||||
#ifdef HAVE_UNSETENV
|
#ifdef HAVE_UNSETENV
|
||||||
return unsetenv (name);
|
return unsetenv (name);
|
||||||
|
#elif defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
|
||||||
|
{
|
||||||
|
int e = _putenv_s (name, "");
|
||||||
|
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
gpg_err_set_errno (e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#else /*!HAVE_UNSETENV*/
|
#else /*!HAVE_UNSETENV*/
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
|
@ -1819,3 +1988,22 @@ gnupg_fd_valid (int fd)
|
||||||
close (d);
|
close (d);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Open a stream from FD (a file descriptor on POSIX, a system
|
||||||
|
handle on Windows), non-closed. */
|
||||||
|
estream_t
|
||||||
|
open_stream_nc (gnupg_fd_t fd, const char *mode)
|
||||||
|
{
|
||||||
|
es_syshd_t syshd;
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
syshd.type = ES_SYSHD_HANDLE;
|
||||||
|
syshd.u.handle = fd;
|
||||||
|
#else
|
||||||
|
syshd.type = ES_SYSHD_FD;
|
||||||
|
syshd.u.fd = fd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return es_sysopen_nc (&syshd, mode);
|
||||||
|
}
|
||||||
|
|
|
@ -38,12 +38,20 @@
|
||||||
typedef void *gnupg_fd_t;
|
typedef void *gnupg_fd_t;
|
||||||
#define GNUPG_INVALID_FD ((void*)(-1))
|
#define GNUPG_INVALID_FD ((void*)(-1))
|
||||||
#define INT2FD(s) ((void *)(s))
|
#define INT2FD(s) ((void *)(s))
|
||||||
#define FD2INT(h) ((unsigned int)(h))
|
# ifdef _WIN64
|
||||||
|
# define FD2INT(h) ((intptr_t)(h))
|
||||||
|
# else
|
||||||
|
# define FD2INT(h) ((unsigned int)(h))
|
||||||
|
# endif
|
||||||
|
#define FD_DBG(h) ((int)(intptr_t)(h))
|
||||||
|
#define FD2NUM(h) ((int)(intptr_t)(h))
|
||||||
#else
|
#else
|
||||||
typedef int gnupg_fd_t;
|
typedef int gnupg_fd_t;
|
||||||
#define GNUPG_INVALID_FD (-1)
|
#define GNUPG_INVALID_FD (-1)
|
||||||
#define INT2FD(s) (s)
|
#define INT2FD(s) (s)
|
||||||
#define FD2INT(h) (h)
|
#define FD2INT(h) (h)
|
||||||
|
#define FD_DBG(h) (h)
|
||||||
|
#define FD2NUM(h) (h)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STAT
|
#ifdef HAVE_STAT
|
||||||
|
@ -67,14 +75,17 @@ void trap_unaligned (void);
|
||||||
int disable_core_dumps (void);
|
int disable_core_dumps (void);
|
||||||
int enable_core_dumps (void);
|
int enable_core_dumps (void);
|
||||||
void enable_special_filenames (void);
|
void enable_special_filenames (void);
|
||||||
|
void disable_translate_sys2libc_fd (void);
|
||||||
|
|
||||||
const unsigned char *get_session_marker (size_t *rlen);
|
const unsigned char *get_session_marker (size_t *rlen);
|
||||||
unsigned int get_uint_nonce (void);
|
unsigned int get_uint_nonce (void);
|
||||||
/*int check_permissions (const char *path,int extension,int checkonly);*/
|
/*int check_permissions (const char *path,int extension,int checkonly);*/
|
||||||
void gnupg_sleep (unsigned int seconds);
|
void gnupg_sleep (unsigned int seconds);
|
||||||
void gnupg_usleep (unsigned int usecs);
|
void gnupg_usleep (unsigned int usecs);
|
||||||
int translate_sys2libc_fd (gnupg_fd_t fd, int for_write);
|
|
||||||
int translate_sys2libc_fd_int (int fd, int for_write);
|
int translate_sys2libc_fd_int (int fd, int for_write);
|
||||||
|
gpg_error_t gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd);
|
||||||
int check_special_filename (const char *fname, int for_write, int notranslate);
|
int check_special_filename (const char *fname, int for_write, int notranslate);
|
||||||
|
gnupg_fd_t gnupg_check_special_filename (const char *fname);
|
||||||
FILE *gnupg_tmpfile (void);
|
FILE *gnupg_tmpfile (void);
|
||||||
void gnupg_reopen_std (const char *pgmname);
|
void gnupg_reopen_std (const char *pgmname);
|
||||||
void gnupg_inhibit_set_foregound_window (int yes);
|
void gnupg_inhibit_set_foregound_window (int yes);
|
||||||
|
@ -108,9 +119,10 @@ gpg_error_t gnupg_inotify_watch_delete_self (int *r_fd, const char *fname);
|
||||||
gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
|
gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
|
||||||
int gnupg_inotify_has_name (int fd, const char *name);
|
int gnupg_inotify_has_name (int fd, const char *name);
|
||||||
|
|
||||||
|
estream_t open_stream_nc (gnupg_fd_t fd, const char *mode);
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
void gnupg_w32_set_errno (int ec);
|
int gnupg_w32_set_errno (int ec);
|
||||||
void *w32_get_user_sid (void);
|
void *w32_get_user_sid (void);
|
||||||
|
|
||||||
#include "../common/w32help.h"
|
#include "../common/w32help.h"
|
||||||
|
|
181
common/t-b64.c
181
common/t-b64.c
|
@ -1,181 +0,0 @@
|
||||||
/* t-b64.c - Module tests for b64enc.c and b64dec.c
|
|
||||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* This file is part of GnuPG.
|
|
||||||
*
|
|
||||||
* GnuPG is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* GnuPG is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
As of now this is only a test program for manual tests.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#define pass() do { ; } while(0)
|
|
||||||
#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
|
|
||||||
__FILE__,__LINE__, (a)); \
|
|
||||||
errcount++; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
static int verbose;
|
|
||||||
static int errcount;
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_b64enc_pgp (const char *string)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
struct b64state state;
|
|
||||||
|
|
||||||
if (!string)
|
|
||||||
string = "a";
|
|
||||||
|
|
||||||
err = b64enc_start (&state, stdout, "PGP MESSAGE");
|
|
||||||
if (err)
|
|
||||||
fail (1);
|
|
||||||
|
|
||||||
err = b64enc_write (&state, string, strlen (string));
|
|
||||||
if (err)
|
|
||||||
fail (2);
|
|
||||||
|
|
||||||
err = b64enc_finish (&state);
|
|
||||||
if (err)
|
|
||||||
fail (3);
|
|
||||||
|
|
||||||
pass ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_b64enc_file (const char *fname)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
struct b64state state;
|
|
||||||
FILE *fp;
|
|
||||||
char buffer[50];
|
|
||||||
size_t nread;
|
|
||||||
|
|
||||||
fp = fname ? fopen (fname, "r") : stdin;
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s:%d: can't open '%s': %s\n",
|
|
||||||
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
|
|
||||||
fail (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = b64enc_start (&state, stdout, "DATA");
|
|
||||||
if (err)
|
|
||||||
fail (1);
|
|
||||||
|
|
||||||
while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
|
|
||||||
{
|
|
||||||
err = b64enc_write (&state, buffer, nread);
|
|
||||||
if (err)
|
|
||||||
fail (2);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = b64enc_finish (&state);
|
|
||||||
if (err)
|
|
||||||
fail (3);
|
|
||||||
|
|
||||||
fclose (fp);
|
|
||||||
pass ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_b64dec_file (const char *fname)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
struct b64state state;
|
|
||||||
FILE *fp;
|
|
||||||
char buffer[50];
|
|
||||||
size_t nread, nbytes;
|
|
||||||
|
|
||||||
fp = fname ? fopen (fname, "r") : stdin;
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
fprintf (stderr, "%s:%d: can't open '%s': %s\n",
|
|
||||||
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
|
|
||||||
fail (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = b64dec_start (&state, "");
|
|
||||||
if (err)
|
|
||||||
fail (1);
|
|
||||||
|
|
||||||
while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
|
|
||||||
{
|
|
||||||
err = b64dec_proc (&state, buffer, nread, &nbytes);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
if (gpg_err_code (err) == GPG_ERR_EOF)
|
|
||||||
break;
|
|
||||||
fail (2);
|
|
||||||
}
|
|
||||||
else if (nbytes)
|
|
||||||
fwrite (buffer, 1, nbytes, stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
err = b64dec_finish (&state);
|
|
||||||
if (err)
|
|
||||||
fail (3);
|
|
||||||
|
|
||||||
fclose (fp);
|
|
||||||
pass ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
int do_encode = 0;
|
|
||||||
int do_decode = 0;
|
|
||||||
|
|
||||||
if (argc)
|
|
||||||
{ argc--; argv++; }
|
|
||||||
if (argc && !strcmp (argv[0], "--verbose"))
|
|
||||||
{
|
|
||||||
verbose = 1;
|
|
||||||
argc--; argv++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc && !strcmp (argv[0], "--encode"))
|
|
||||||
{
|
|
||||||
do_encode = 1;
|
|
||||||
argc--; argv++;
|
|
||||||
}
|
|
||||||
else if (argc && !strcmp (argv[0], "--decode"))
|
|
||||||
{
|
|
||||||
do_decode = 1;
|
|
||||||
argc--; argv++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (do_encode)
|
|
||||||
test_b64enc_file (argc? *argv: NULL);
|
|
||||||
else if (do_decode)
|
|
||||||
test_b64dec_file (argc? *argv: NULL);
|
|
||||||
else
|
|
||||||
test_b64enc_pgp (argc? *argv: NULL);
|
|
||||||
|
|
||||||
return !!errcount;
|
|
||||||
}
|
|
|
@ -52,6 +52,7 @@
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
w32_strerror (int ec)
|
w32_strerror (int ec)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +175,11 @@ strconcat (const char *s1, ...)
|
||||||
|
|
||||||
#define PGM "t-dotlock"
|
#define PGM "t-dotlock"
|
||||||
|
|
||||||
|
static int opt_silent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_W32_SYSTEM
|
#ifndef HAVE_W32_SYSTEM
|
||||||
static volatile int ctrl_c_pending_flag;
|
static volatile int ctrl_c_pending_flag;
|
||||||
static void
|
static void
|
||||||
|
@ -217,6 +223,9 @@ inf (const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list arg_ptr;
|
va_list arg_ptr;
|
||||||
|
|
||||||
|
if (opt_silent)
|
||||||
|
return;
|
||||||
|
|
||||||
va_start (arg_ptr, format);
|
va_start (arg_ptr, format);
|
||||||
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
|
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
|
||||||
vfprintf (stderr, format, arg_ptr);
|
vfprintf (stderr, format, arg_ptr);
|
||||||
|
@ -225,15 +234,35 @@ inf (const char *format, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
lock_info_cb (dotlock_t h, void *opaque, enum dotlock_reasons reason,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arg_ptr;
|
||||||
|
|
||||||
|
va_start (arg_ptr, format);
|
||||||
|
fprintf (stderr, PGM "[%lu]: info_cb: reason %d, ",
|
||||||
|
(unsigned long)getpid (), (int)reason);
|
||||||
|
vfprintf (stderr, format, arg_ptr);
|
||||||
|
va_end (arg_ptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lock_and_unlock (const char *fname)
|
lock_and_unlock (const char *fname)
|
||||||
{
|
{
|
||||||
dotlock_t h;
|
dotlock_t h;
|
||||||
unsigned long usec;
|
unsigned long usec;
|
||||||
|
|
||||||
h = dotlock_create (fname, 0);
|
h = dotlock_create (fname, DOTLOCK_PREPARE_CREATE);
|
||||||
if (!h)
|
if (!h)
|
||||||
die ("error creating lock file for '%s': %s", fname, strerror (errno));
|
die ("error creating lock file for '%s': %s", fname, strerror (errno));
|
||||||
|
dotlock_set_info_cb (h, lock_info_cb, NULL);
|
||||||
|
h = dotlock_finish_create (h, fname);
|
||||||
|
if (!h)
|
||||||
|
die ("error finishing lock file creation for '%s': %s",
|
||||||
|
fname, strerror (errno));
|
||||||
inf ("lock created");
|
inf ("lock created");
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -270,6 +299,11 @@ main (int argc, char **argv)
|
||||||
ctrl_c_pending_flag = 1;
|
ctrl_c_pending_flag = 1;
|
||||||
argc--;
|
argc--;
|
||||||
}
|
}
|
||||||
|
if (argc > 1 && !strcmp (argv[1], "--silent"))
|
||||||
|
{
|
||||||
|
opt_silent = 1;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
fname = argv[argc-1];
|
fname = argv[argc-1];
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
static int verbose;
|
static int verbose;
|
||||||
|
|
||||||
|
#ifndef HAVE_W32_SYSTEM
|
||||||
static void
|
static void
|
||||||
print_open_fds (int *array)
|
print_open_fds (int *array)
|
||||||
{
|
{
|
||||||
|
@ -169,20 +169,168 @@ test_close_all_fds (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char buff12k[1024*12];
|
||||||
|
static char buff4k[1024*4];
|
||||||
|
|
||||||
|
static void
|
||||||
|
run_server (void)
|
||||||
|
{
|
||||||
|
estream_t fp;
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
unsigned int len;
|
||||||
|
int ret;
|
||||||
|
es_syshd_t syshd;
|
||||||
|
size_t n;
|
||||||
|
off_t o;
|
||||||
|
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
syshd.type = ES_SYSHD_HANDLE;
|
||||||
|
syshd.u.handle = (HANDLE)_get_osfhandle (1);
|
||||||
|
#else
|
||||||
|
syshd.type = ES_SYSHD_FD;
|
||||||
|
syshd.u.fd = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fp = es_sysopen_nc (&syshd, "w");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "es_fdopen failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the buffer by ASCII chars. */
|
||||||
|
p = buff12k;
|
||||||
|
for (i = 0; i < sizeof (buff12k); i++)
|
||||||
|
if ((i % 64) == 63)
|
||||||
|
*p++ = '\n';
|
||||||
|
else
|
||||||
|
*p++ = (i % 64) + '@';
|
||||||
|
|
||||||
|
len = sizeof (buff12k);
|
||||||
|
|
||||||
|
ret = es_write (fp, (void *)&len, sizeof (len), NULL);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "es_write (1) failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
es_fflush (fp);
|
||||||
|
|
||||||
|
o = 0;
|
||||||
|
n = len;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
size_t n0, n1;
|
||||||
|
|
||||||
|
n0 = n > 4096 ? 4096 : n;
|
||||||
|
memcpy (buff4k, buff12k + o, n0);
|
||||||
|
|
||||||
|
ret = es_write (fp, buff4k, n0, &n1);
|
||||||
|
if (ret || n0 != n1)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "es_write (2) failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
o += n0;
|
||||||
|
n -= n0;
|
||||||
|
if (n == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
es_fclose (fp);
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_pipe_stream (const char *pgmname)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
gnupg_process_t proc;
|
||||||
|
estream_t outfp;
|
||||||
|
const char *argv[2];
|
||||||
|
unsigned int len;
|
||||||
|
size_t n;
|
||||||
|
off_t o;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
argv[0] = "--server";
|
||||||
|
argv[1] = NULL;
|
||||||
|
|
||||||
|
err = gnupg_process_spawn (pgmname, argv,
|
||||||
|
(GNUPG_PROCESS_STDOUT_PIPE
|
||||||
|
|GNUPG_PROCESS_STDERR_KEEP),
|
||||||
|
NULL, &proc);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "gnupg_process_spawn failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
|
||||||
|
|
||||||
|
ret = es_read (outfp, (void *)&len, sizeof (len), NULL);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "es_read (1) failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
o = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (es_feof (outfp))
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = es_read (outfp, buff4k, sizeof (buff4k), &n);
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "es_read (2) failed\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (buff12k + o, buff4k, n);
|
||||||
|
o += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (o != sizeof (buff12k))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "received data with wrong length %d\n", (int)o);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
es_fclose (outfp);
|
||||||
|
gnupg_process_release (proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
const char *myname = "no-pgm";
|
||||||
|
|
||||||
if (argc)
|
if (argc)
|
||||||
{ argc--; argv++; }
|
{
|
||||||
|
myname = argv[0];
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
if (argc && !strcmp (argv[0], "--verbose"))
|
if (argc && !strcmp (argv[0], "--verbose"))
|
||||||
{
|
{
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
}
|
}
|
||||||
|
if (argc && !strcmp (argv[0], "--server"))
|
||||||
|
run_server ();
|
||||||
|
|
||||||
|
#ifndef HAVE_W32_SYSTEM
|
||||||
test_close_all_fds ();
|
test_close_all_fds ();
|
||||||
|
#endif
|
||||||
|
test_pipe_stream (myname);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,56 @@ static int errcount;
|
||||||
#define INVALID ((time_t)(-1))
|
#define INVALID ((time_t)(-1))
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_scan_secondsstr (void)
|
||||||
|
{
|
||||||
|
struct { const char *string; u32 expected; } array [] = {
|
||||||
|
{ "", 0 },
|
||||||
|
{ "0", 0 },
|
||||||
|
{ " 0", 0 },
|
||||||
|
{ " 0x", 0 },
|
||||||
|
{ " 1", 1 },
|
||||||
|
{ "-1", 0 },
|
||||||
|
{ " -1", 0 },
|
||||||
|
{ "2", 2 },
|
||||||
|
{ "11", 11 },
|
||||||
|
{ "011", 11 },
|
||||||
|
{ "3600 ", 3600 },
|
||||||
|
{ "65535", 65535 },
|
||||||
|
{ "65536", 65536 },
|
||||||
|
{ "65537", 65537 },
|
||||||
|
{ "4294967289", 4294967289 },
|
||||||
|
{ "4294967290", 4294967290 },
|
||||||
|
{ "4294967293", 4294967293 },
|
||||||
|
{ "4294967295", 4294967294 },
|
||||||
|
{ "4294967296", 4294967294 },
|
||||||
|
{ "4294967297", 4294967294 },
|
||||||
|
{ "4294967298", 4294967294 },
|
||||||
|
{ "4294967299", 4294967294 },
|
||||||
|
{ "4294967300", 4294967294 },
|
||||||
|
{ "5294967300", 4294967294 },
|
||||||
|
{ "9999999999", 4294967294 },
|
||||||
|
{ "99999999999",4294967294 },
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
int idx;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
for (idx=0; array[idx].string; idx++)
|
||||||
|
{
|
||||||
|
val = scan_secondsstr (array[idx].string);
|
||||||
|
if (val != array[idx].expected )
|
||||||
|
{
|
||||||
|
fail (idx);
|
||||||
|
if (verbose)
|
||||||
|
fprintf (stderr, "string '%s' exp: %ld got: %ld\n",
|
||||||
|
array[idx].string, (unsigned long)array[idx].expected,
|
||||||
|
(unsigned long)val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_isotime2epoch (void)
|
test_isotime2epoch (void)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +153,6 @@ test_isotime2epoch (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_string2isotime (void)
|
test_string2isotime (void)
|
||||||
{
|
{
|
||||||
|
@ -269,6 +318,7 @@ main (int argc, char **argv)
|
||||||
if (argc > 1 && !strcmp (argv[1], "--verbose"))
|
if (argc > 1 && !strcmp (argv[1], "--verbose"))
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
|
|
||||||
|
test_scan_secondsstr ();
|
||||||
test_isotime2epoch ();
|
test_isotime2epoch ();
|
||||||
test_string2isotime ();
|
test_string2isotime ();
|
||||||
test_isodate_human_to_tm ();
|
test_isodate_human_to_tm ();
|
||||||
|
|
|
@ -1,3 +1,36 @@
|
||||||
|
/* t-iobuf.c - Simple module test for iobuf.c
|
||||||
|
* Copyright (C) 2015 g10 Code GmbH
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of either
|
||||||
|
*
|
||||||
|
* - the GNU Lesser General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* or
|
||||||
|
*
|
||||||
|
* - the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* or both in parallel, as here.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The whole code here does not very fill into our general test frame
|
||||||
|
* work pattern. But let's keep it as it is. */
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -7,6 +40,20 @@
|
||||||
#include "iobuf.h"
|
#include "iobuf.h"
|
||||||
#include "stringhelp.h"
|
#include "stringhelp.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
xmalloc (size_t n)
|
||||||
|
{
|
||||||
|
void *p = malloc (n);
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "t-iobuf: out of core\n");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return every other byte. In particular, reads two bytes, returns
|
/* Return every other byte. In particular, reads two bytes, returns
|
||||||
the second one. */
|
the second one. */
|
||||||
static int
|
static int
|
||||||
|
@ -86,7 +133,7 @@ static struct content_filter_state *
|
||||||
content_filter_new (const char *buffer)
|
content_filter_new (const char *buffer)
|
||||||
{
|
{
|
||||||
struct content_filter_state *state
|
struct content_filter_state *state
|
||||||
= malloc (sizeof (struct content_filter_state));
|
= xmalloc (sizeof (struct content_filter_state));
|
||||||
|
|
||||||
state->pos = 0;
|
state->pos = 0;
|
||||||
state->len = strlen (buffer);
|
state->len = strlen (buffer);
|
||||||
|
@ -215,8 +262,7 @@ main (int argc, char *argv[])
|
||||||
allocate a buffer that is 5 bytes long, then no reallocation
|
allocate a buffer that is 5 bytes long, then no reallocation
|
||||||
should be required. */
|
should be required. */
|
||||||
size = 5;
|
size = 5;
|
||||||
buffer = malloc (size);
|
buffer = xmalloc (size);
|
||||||
assert (buffer);
|
|
||||||
max_len = 100;
|
max_len = 100;
|
||||||
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
|
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
|
||||||
assert (n == 4);
|
assert (n == 4);
|
||||||
|
@ -229,7 +275,7 @@ main (int argc, char *argv[])
|
||||||
requires 6 bytes of storage. We pass a buffer that is 5 bytes
|
requires 6 bytes of storage. We pass a buffer that is 5 bytes
|
||||||
large and we allow the buffer to be grown. */
|
large and we allow the buffer to be grown. */
|
||||||
size = 5;
|
size = 5;
|
||||||
buffer = malloc (size);
|
buffer = xmalloc (size);
|
||||||
max_len = 100;
|
max_len = 100;
|
||||||
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
|
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
|
||||||
assert (n == 5);
|
assert (n == 5);
|
||||||
|
@ -243,7 +289,7 @@ main (int argc, char *argv[])
|
||||||
requires 7 bytes of storage. We pass a buffer that is 5 bytes
|
requires 7 bytes of storage. We pass a buffer that is 5 bytes
|
||||||
large and we don't allow the buffer to be grown. */
|
large and we don't allow the buffer to be grown. */
|
||||||
size = 5;
|
size = 5;
|
||||||
buffer = malloc (size);
|
buffer = xmalloc (size);
|
||||||
max_len = 5;
|
max_len = 5;
|
||||||
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
|
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
|
||||||
assert (n == 4);
|
assert (n == 4);
|
||||||
|
|
|
@ -72,6 +72,194 @@ test_strlist_rev (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_tokenize_to_strlist (void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
const char *s;
|
||||||
|
const char *delim;
|
||||||
|
int error_expected;
|
||||||
|
const char *items_expected[10];
|
||||||
|
} tv[] = {
|
||||||
|
{
|
||||||
|
"", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a", ":",
|
||||||
|
0, { "a", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
":", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"::", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:b:c", ":",
|
||||||
|
0, { "a", "b", "c", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:b:", ":",
|
||||||
|
0, { "a", "b", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:b", ":",
|
||||||
|
0, { "a", "b", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aa:b:cd", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aa::b:cd", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"::b:cd", ":",
|
||||||
|
0, { "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aa: : b:cd ", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" aa: : b: cd ", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" :", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" : ", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
": ", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
": x ", ":",
|
||||||
|
0, { "x", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:bc:cde:fghi:jklmn::foo:", ":",
|
||||||
|
0, { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
",a,bc,,def,", ",",
|
||||||
|
0, { "a", "bc", "def", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" a ", " ",
|
||||||
|
0, { "a", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" ", " ",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:bc:c de:fg hi:jklmn::foo :", ":",
|
||||||
|
0, { "a", "bc", "c de", "fg hi", "jklmn", "foo", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"", " ",
|
||||||
|
1, { NULL }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const char *prefixes[3] = { "abc", "bcd", "efg" };
|
||||||
|
int tidx;
|
||||||
|
int nprefixes; /* Number of items in already in the list. */
|
||||||
|
strlist_t list = NULL;
|
||||||
|
|
||||||
|
for (nprefixes = 0; nprefixes < DIM (prefixes); nprefixes++)
|
||||||
|
for (tidx = 0; tidx < DIM(tv); tidx++)
|
||||||
|
{
|
||||||
|
int item_count_expected;
|
||||||
|
int i;
|
||||||
|
strlist_t sl, newitems;
|
||||||
|
|
||||||
|
for (item_count_expected = 0;
|
||||||
|
tv[tidx].items_expected[item_count_expected];
|
||||||
|
item_count_expected++)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* printf ("np=%d testing %d \"%s\" delim=\"%s\"\n", */
|
||||||
|
/* nprefixes, tidx, tv[tidx].s, tv[tidx].delim); */
|
||||||
|
for (i=0; i < nprefixes; i++)
|
||||||
|
append_to_strlist (&list, prefixes[i]);
|
||||||
|
|
||||||
|
newitems = tokenize_to_strlist (&list, tv[tidx].s, tv[tidx].delim);
|
||||||
|
if (!newitems)
|
||||||
|
{
|
||||||
|
if (gpg_err_code_from_syserror () == GPG_ERR_ENOENT
|
||||||
|
&& tv[tidx].error_expected)
|
||||||
|
{
|
||||||
|
/* Good. But need to check the prefixes. */
|
||||||
|
for (sl=list, i=0; i < nprefixes; i++, sl=sl->next)
|
||||||
|
{
|
||||||
|
if (!sl || strcmp (prefixes[i], sl->d))
|
||||||
|
{
|
||||||
|
printf ("For item %d prefix item %d, expected '%s'\n",
|
||||||
|
tidx, i, prefixes[i]);
|
||||||
|
fail (tidx * 1000 + 40 + i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fail (tidx * 1000);
|
||||||
|
}
|
||||||
|
else if (tv[tidx].error_expected)
|
||||||
|
{
|
||||||
|
printf ("got items");
|
||||||
|
for (sl = list; sl; sl = sl->next)
|
||||||
|
printf (" \"%s\"", sl->d);
|
||||||
|
printf ("\n");
|
||||||
|
fail (tidx * 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strlist_length (list) != nprefixes + item_count_expected)
|
||||||
|
fail (tidx * 1000);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (sl=list, i=0; i < nprefixes; i++, sl=sl->next)
|
||||||
|
{
|
||||||
|
if (!sl || strcmp (prefixes[i], sl->d))
|
||||||
|
{
|
||||||
|
printf ("For item %d prefix item %d, expected '%s'\n",
|
||||||
|
tidx, i, prefixes[i]);
|
||||||
|
fail (tidx * 1000 + 50 + i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0; i < item_count_expected; i++, sl=sl->next)
|
||||||
|
{
|
||||||
|
if (!sl)
|
||||||
|
{
|
||||||
|
printf ("No item at item index %d\n", i);
|
||||||
|
fail (tidx * 1000 + i + 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strcmp (tv[tidx].items_expected[i], sl->d))
|
||||||
|
{
|
||||||
|
printf ("For item %d, expected '%s', but got '%s'\n",
|
||||||
|
i, tv[tidx].items_expected[i], sl->d);
|
||||||
|
fail (tidx * 1000 + 10 + i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_strlist (list);
|
||||||
|
list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +267,7 @@ main (int argc, char **argv)
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
test_strlist_rev ();
|
test_strlist_rev ();
|
||||||
|
test_tokenize_to_strlist ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#ifndef GNUPG_COMMON_T_SUPPORT_H
|
#ifndef GNUPG_COMMON_T_SUPPORT_H
|
||||||
#define GNUPG_COMMON_T_SUPPORT_H 1
|
#define GNUPG_COMMON_T_SUPPORT_H 1
|
||||||
|
|
||||||
|
#ifndef LEAN_T_SUPPORT
|
||||||
|
|
||||||
#ifdef GCRYPT_VERSION
|
#ifdef GCRYPT_VERSION
|
||||||
#error The regression tests should not include with gcrypt.h
|
#error The regression tests should not include with gcrypt.h
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,11 +47,6 @@
|
||||||
# define getenv(a) (NULL)
|
# define getenv(a) (NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DIM
|
|
||||||
# define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
|
||||||
# define DIMof(type,member) DIM(((type *)0)->member)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Replacement prototypes. */
|
/* Replacement prototypes. */
|
||||||
void *gcry_xmalloc (size_t n);
|
void *gcry_xmalloc (size_t n);
|
||||||
|
@ -65,6 +62,12 @@ void gcry_free (void *a);
|
||||||
#define xstrdup(a) gcry_xstrdup ( (a) )
|
#define xstrdup(a) gcry_xstrdup ( (a) )
|
||||||
#define xfree(a) gcry_free ( (a) )
|
#define xfree(a) gcry_free ( (a) )
|
||||||
|
|
||||||
|
#endif /* LEAN_T_SUPPORT */
|
||||||
|
|
||||||
|
#ifndef DIM
|
||||||
|
# define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||||
|
# define DIMof(type,member) DIM(((type *)0)->member)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Macros to print the result of a test. */
|
/* Macros to print the result of a test. */
|
||||||
#define pass() do { ; } while(0)
|
#define pass() do { ; } while(0)
|
||||||
|
|
|
@ -95,7 +95,7 @@ ensure_space (tlv_builder_t tb)
|
||||||
* element is described by CLASS, TAG, VALUE, and VALUEEN. CLASS and
|
* element is described by CLASS, TAG, VALUE, and VALUEEN. CLASS and
|
||||||
* TAG must describe a primitive element and (VALUE,VALUELEN) specify
|
* TAG must describe a primitive element and (VALUE,VALUELEN) specify
|
||||||
* its value. The value is a pointer and its object must not be
|
* its value. The value is a pointer and its object must not be
|
||||||
* changed as long as the instance TB exists. For a TAG_NULL no vlaue
|
* changed as long as the instance TB exists. For a TAG_NULL no value
|
||||||
* is expected. Errors are not returned but recorded for later
|
* is expected. Errors are not returned but recorded for later
|
||||||
* retrieval. */
|
* retrieval. */
|
||||||
void
|
void
|
||||||
|
|
788
common/tlv-parser.c
Normal file
788
common/tlv-parser.c
Normal file
|
@ -0,0 +1,788 @@
|
||||||
|
/* tlv-parser.c - Parse BER encoded objects
|
||||||
|
* Copyright (C) 2023 g10 Code GmbH
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <gpg-error.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "tlv.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define TLV_MAX_DEPTH 25
|
||||||
|
|
||||||
|
|
||||||
|
struct bufferlist_s
|
||||||
|
{
|
||||||
|
struct bufferlist_s *next;
|
||||||
|
char *buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* An object to control the ASN.1 parsing. */
|
||||||
|
struct tlv_parser_s
|
||||||
|
{
|
||||||
|
/* The original buffer with the entire pkcs#12 object and its length. */
|
||||||
|
const unsigned char *origbuffer;
|
||||||
|
size_t origbufsize;
|
||||||
|
|
||||||
|
/* The current buffer we are working on and its length. */
|
||||||
|
const unsigned char *buffer;
|
||||||
|
size_t bufsize;
|
||||||
|
|
||||||
|
int in_ndef; /* Flag indicating that we are in a NDEF. */
|
||||||
|
int pending; /* The last tlv_next has not yet been processed. */
|
||||||
|
|
||||||
|
struct tag_info ti; /* The current tag. */
|
||||||
|
gpg_error_t lasterr; /* Last error from tlv function. */
|
||||||
|
const char *lastfunc;/* Name of last called function. */
|
||||||
|
int verbosity; /* Arg from tlv_parser_new. */
|
||||||
|
|
||||||
|
struct bufferlist_s *bufferlist; /* To keep track of malloced buffers. */
|
||||||
|
|
||||||
|
unsigned int stacklen; /* Used size of the stack. */
|
||||||
|
struct {
|
||||||
|
const unsigned char *buffer; /* Saved value of BUFFER. */
|
||||||
|
size_t bufsize; /* Saved value of BUFSIZE. */
|
||||||
|
size_t length; /* Length of the container (ti.length). */
|
||||||
|
int in_ndef; /* Saved IN_NDEF flag (ti.ndef). */
|
||||||
|
} stack[TLV_MAX_DEPTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned char *cram_octet_string (const unsigned char *input,
|
||||||
|
size_t length, size_t *r_newlength);
|
||||||
|
static int need_octet_string_cramming (const unsigned char *input,
|
||||||
|
size_t length);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_tlv_parser_dump_tag (const char *text, int lno, tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
struct tag_info *ti;
|
||||||
|
|
||||||
|
if (!tlv || tlv->verbosity < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ti = &tlv->ti;
|
||||||
|
|
||||||
|
log_debug ("p12_parse:%s:%d: @%04zu class=%d tag=%lu len=%zu nhdr=%zu %s%s\n",
|
||||||
|
text, lno,
|
||||||
|
(size_t)(tlv->buffer - tlv->origbuffer) - ti->nhdr,
|
||||||
|
ti->class, ti->tag, ti->length, ti->nhdr,
|
||||||
|
ti->is_constructed?" cons":"",
|
||||||
|
ti->ndef?" ndef":"");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_tlv_parser_dump_state (const char *text, const char *text2,
|
||||||
|
int lno, tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
if (!tlv || tlv->verbosity < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
log_debug ("p12_parse:%s%s%s:%d: @%04zu lvl=%u %s\n",
|
||||||
|
text,
|
||||||
|
text2? "/":"", text2? text2:"",
|
||||||
|
lno,
|
||||||
|
(size_t)(tlv->buffer - tlv->origbuffer),
|
||||||
|
tlv->stacklen,
|
||||||
|
tlv->in_ndef? " in-ndef":"");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse the buffer at the address BUFFER which is of SIZE and return
|
||||||
|
* the tag and the length part from the TLV triplet. Update BUFFER
|
||||||
|
* and SIZE on success. Checks that the encoded length does not
|
||||||
|
* exhaust the length of the provided buffer. */
|
||||||
|
static int
|
||||||
|
parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int tag;
|
||||||
|
|
||||||
|
err = parse_ber_header (buffer, size,
|
||||||
|
&ti->class, &tag,
|
||||||
|
&ti->is_constructed, &ti->ndef,
|
||||||
|
&ti->length, &ti->nhdr);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (tag < 0)
|
||||||
|
return gpg_error (GPG_ERR_EOVERFLOW);
|
||||||
|
ti->tag = tag;
|
||||||
|
|
||||||
|
if (ti->length > *size)
|
||||||
|
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); /* data larger than buffer. */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public version of parse_tag. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
|
||||||
|
{
|
||||||
|
return parse_tag (buffer, size, ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new TLV object. */
|
||||||
|
tlv_parser_t
|
||||||
|
tlv_parser_new (const unsigned char *buffer, size_t bufsize, int verbosity)
|
||||||
|
{
|
||||||
|
tlv_parser_t tlv;
|
||||||
|
tlv = xtrycalloc (1, sizeof *tlv);
|
||||||
|
if (tlv)
|
||||||
|
{
|
||||||
|
tlv->origbuffer = buffer;
|
||||||
|
tlv->origbufsize = bufsize;
|
||||||
|
tlv->buffer = buffer;
|
||||||
|
tlv->bufsize = bufsize;
|
||||||
|
tlv->verbosity = verbosity;
|
||||||
|
}
|
||||||
|
return tlv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function can be used to store a malloced buffer into the TLV
|
||||||
|
* object. Ownership of BUFFER is thus transferred to TLV. This
|
||||||
|
* buffer will then only be released by tlv_release. */
|
||||||
|
static gpg_error_t
|
||||||
|
register_buffer (tlv_parser_t tlv, char *buffer)
|
||||||
|
{
|
||||||
|
struct bufferlist_s *item;
|
||||||
|
|
||||||
|
item = xtrycalloc (1, sizeof *item);
|
||||||
|
if (!item)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
item->buffer = buffer;
|
||||||
|
item->next = tlv->bufferlist;
|
||||||
|
tlv->bufferlist = item;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
tlv_parser_release (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
if (!tlv)
|
||||||
|
return;
|
||||||
|
while (tlv->bufferlist)
|
||||||
|
{
|
||||||
|
struct bufferlist_s *save = tlv->bufferlist->next;
|
||||||
|
xfree (tlv->bufferlist->buffer);
|
||||||
|
xfree (tlv->bufferlist);
|
||||||
|
tlv->bufferlist = save;
|
||||||
|
}
|
||||||
|
xfree (tlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for the tlv_peek functions. */
|
||||||
|
static gpg_error_t
|
||||||
|
_tlv_peek (tlv_parser_t tlv, struct tag_info *ti)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
/* Note that we want to peek ahead of any current container but of
|
||||||
|
* course not beyond our entire buffer. */
|
||||||
|
p = tlv->buffer;
|
||||||
|
if ((p - tlv->origbuffer) > tlv->origbufsize)
|
||||||
|
return gpg_error (GPG_ERR_BUG);
|
||||||
|
n = tlv->origbufsize - (p - tlv->origbuffer);
|
||||||
|
return parse_tag (&p, &n, ti);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Look for the next tag and return true if it matches CLASS and TAG.
|
||||||
|
* Otherwise return false. No state is changed. */
|
||||||
|
int
|
||||||
|
_tlv_parser_peek (tlv_parser_t tlv, int class, int tag)
|
||||||
|
{
|
||||||
|
struct tag_info ti;
|
||||||
|
|
||||||
|
return (!_tlv_peek (tlv, &ti)
|
||||||
|
&& ti.class == class && ti.tag == tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Look for the next tag and return true if it is the Null tag.
|
||||||
|
* Otherwise return false. No state is changed. */
|
||||||
|
int
|
||||||
|
_tlv_parser_peek_null (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
struct tag_info ti;
|
||||||
|
|
||||||
|
return (!_tlv_peek (tlv, &ti)
|
||||||
|
&& ti.class == CLASS_UNIVERSAL && ti.tag == TAG_NULL
|
||||||
|
&& !ti.is_constructed && !ti.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for tlv_expect_sequence and tlv_expect_context_tag. */
|
||||||
|
static gpg_error_t
|
||||||
|
_tlv_push (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
/* Right now our pointer is at the value of the current container.
|
||||||
|
* We push that info onto the stack. */
|
||||||
|
if (tlv->stacklen >= TLV_MAX_DEPTH)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_MANY));
|
||||||
|
tlv->stack[tlv->stacklen].buffer = tlv->buffer;
|
||||||
|
tlv->stack[tlv->stacklen].bufsize = tlv->bufsize;
|
||||||
|
tlv->stack[tlv->stacklen].in_ndef = tlv->in_ndef;
|
||||||
|
tlv->stack[tlv->stacklen].length = tlv->ti.length;
|
||||||
|
tlv->stacklen++;
|
||||||
|
|
||||||
|
tlv->in_ndef = tlv->ti.ndef;
|
||||||
|
|
||||||
|
/* We set the size of the buffer to the TLV length if it is known or
|
||||||
|
* else to the size of the remaining entire buffer. */
|
||||||
|
if (tlv->in_ndef)
|
||||||
|
{
|
||||||
|
if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
|
||||||
|
tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tlv->bufsize = tlv->ti.length;
|
||||||
|
|
||||||
|
_tlv_parser_dump_state (__func__, NULL, 0, tlv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for tlv_next. */
|
||||||
|
static gpg_error_t
|
||||||
|
_tlv_pop (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
size_t lastlen;
|
||||||
|
|
||||||
|
/* We reached the end of a container, either due to the size limit
|
||||||
|
* or due to an end tag. Now we pop the last container so that we
|
||||||
|
* are positioned at the value of the last container. */
|
||||||
|
if (!tlv->stacklen)
|
||||||
|
return gpg_error (GPG_ERR_EOF);
|
||||||
|
|
||||||
|
tlv->stacklen--;
|
||||||
|
tlv->in_ndef = tlv->stack[tlv->stacklen].in_ndef;
|
||||||
|
if (tlv->in_ndef)
|
||||||
|
{
|
||||||
|
/* We keep buffer but adjust bufsize to the end of the origbuffer. */
|
||||||
|
if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
|
||||||
|
tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastlen = tlv->stack[tlv->stacklen].length;
|
||||||
|
tlv->buffer = tlv->stack[tlv->stacklen].buffer;
|
||||||
|
tlv->bufsize = tlv->stack[tlv->stacklen].bufsize;
|
||||||
|
if (lastlen > tlv->bufsize)
|
||||||
|
{
|
||||||
|
log_debug ("%s: container length larger than buffer (%zu/%zu)\n",
|
||||||
|
__func__, lastlen, tlv->bufsize);
|
||||||
|
return gpg_error (GPG_ERR_INV_BER);
|
||||||
|
}
|
||||||
|
tlv->buffer += lastlen;
|
||||||
|
tlv->bufsize -= lastlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tlv_parser_dump_state (__func__, NULL, 0, tlv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse the next tag and value. Also detect the end of a
|
||||||
|
* container. The caller should use the tlv_next macro. */
|
||||||
|
gpg_error_t
|
||||||
|
_tlv_parser_next (tlv_parser_t tlv, int lno)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
tlv->lasterr = 0;
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
|
||||||
|
if (tlv->pending)
|
||||||
|
{
|
||||||
|
tlv->pending = 0;
|
||||||
|
if (tlv->verbosity > 1)
|
||||||
|
log_debug ("%s: skipped\n", __func__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tlv->verbosity > 1)
|
||||||
|
log_debug ("%s: called\n", __func__);
|
||||||
|
/* If we are at the end of an ndef container pop the stack. */
|
||||||
|
if (!tlv->in_ndef && !tlv->bufsize)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
err = _tlv_pop (tlv);
|
||||||
|
while (!err && !tlv->in_ndef && !tlv->bufsize);
|
||||||
|
if (err)
|
||||||
|
return (tlv->lasterr = err);
|
||||||
|
if (tlv->verbosity > 1)
|
||||||
|
log_debug ("%s: container(s) closed due to size\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
|
/* Get the next tag. */
|
||||||
|
err = parse_tag (&tlv->buffer, &tlv->bufsize, &tlv->ti);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (tlv->verbosity > 1)
|
||||||
|
log_debug ("%s: reading tag returned err=%d\n", __func__, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is an end tag in an ndef container pop the stack. Also
|
||||||
|
* pop other containers which are fully consumed. */
|
||||||
|
if (tlv->in_ndef && (tlv->ti.class == CLASS_UNIVERSAL
|
||||||
|
&& !tlv->ti.tag && !tlv->ti.is_constructed))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
err = _tlv_pop (tlv);
|
||||||
|
while (!err && !tlv->in_ndef && !tlv->bufsize);
|
||||||
|
if (err)
|
||||||
|
return (tlv->lasterr = err);
|
||||||
|
if (tlv->verbosity > 1)
|
||||||
|
log_debug ("%s: container(s) closed due to end tag\n", __func__);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tlv_parser_dump_tag (__func__, lno, tlv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the current neting level of the TLV object. */
|
||||||
|
unsigned int
|
||||||
|
tlv_parser_level (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
return tlv? tlv->stacklen : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the current offset of the parser. */
|
||||||
|
size_t
|
||||||
|
tlv_parser_offset (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
return tlv? (size_t)(tlv->buffer - tlv->origbuffer) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return a string with the last function used. If TLV is NULL an
|
||||||
|
* empty string is returned. */
|
||||||
|
const char *
|
||||||
|
tlv_parser_lastfunc (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
return tlv? tlv->lastfunc:"";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
tlv_parser_lasterrstr (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
return tlv? gpg_strerror (tlv->lasterr) : "tlv parser not yet initialized";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set a flag to indicate that the last tlv_next has not yet been
|
||||||
|
* consumed. */
|
||||||
|
void
|
||||||
|
tlv_parser_set_pending (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
tlv->pending = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the length of the last read tag. If with_header is 1 the
|
||||||
|
* lengtb of the header is added to the returned length. */
|
||||||
|
size_t
|
||||||
|
tlv_parser_tag_length (tlv_parser_t tlv, int with_header)
|
||||||
|
{
|
||||||
|
if (with_header)
|
||||||
|
return tlv->ti.length + tlv->ti.nhdr;
|
||||||
|
else
|
||||||
|
return tlv->ti.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Skip over the value of the current tag. Does not yet work for ndef
|
||||||
|
* containers. */
|
||||||
|
void
|
||||||
|
tlv_parser_skip (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
log_assert (tlv->bufsize >= tlv->ti.length);
|
||||||
|
tlv->buffer += tlv->ti.length;
|
||||||
|
tlv->bufsize -= tlv->ti.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect that the current tag is a sequence and setup the context for
|
||||||
|
* processing. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_sequence (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SEQUENCE
|
||||||
|
&& tlv->ti.is_constructed))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
return _tlv_push (tlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect that the current tag is a context tag and setup the context
|
||||||
|
* for processing. The tag of the context is returned at R_TAG. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_context_tag (tlv_parser_t tlv, int *r_tag)
|
||||||
|
{
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_CONTEXT && tlv->ti.is_constructed))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
*r_tag = tlv->ti.tag;
|
||||||
|
return _tlv_push (tlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect that the current tag is a SET and setup the context for
|
||||||
|
* processing. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_set (tlv_parser_t tlv)
|
||||||
|
{
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SET
|
||||||
|
&& tlv->ti.is_constructed))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
return _tlv_push (tlv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect an object of CLASS with TAG and store its value at
|
||||||
|
* (R_DATA,R_DATALEN). Then skip over its value to the next tag.
|
||||||
|
* Note that the stored value is not allocated but points into
|
||||||
|
* TLV. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_object (tlv_parser_t tlv, int class, int tag,
|
||||||
|
unsigned char const **r_data, size_t *r_datalen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n;
|
||||||
|
int needpush = 0;
|
||||||
|
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == class && tlv->ti.tag == tag))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
p = tlv->buffer;
|
||||||
|
n = tlv->ti.length;
|
||||||
|
if (!n && tlv->ti.ndef)
|
||||||
|
{
|
||||||
|
n = tlv->bufsize;
|
||||||
|
needpush = 1;
|
||||||
|
}
|
||||||
|
else if (!tlv->ti.length)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
|
||||||
|
if (class == CLASS_CONTEXT && tag == 0 && tlv->ti.is_constructed
|
||||||
|
&& need_octet_string_cramming (p, n))
|
||||||
|
{
|
||||||
|
char *newbuffer;
|
||||||
|
|
||||||
|
newbuffer = cram_octet_string (p, n, r_datalen);
|
||||||
|
if (!newbuffer)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
|
||||||
|
err = register_buffer (tlv, newbuffer);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (newbuffer);
|
||||||
|
return (tlv->lasterr = err);
|
||||||
|
}
|
||||||
|
*r_data = newbuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*r_data = p;
|
||||||
|
*r_datalen = n;
|
||||||
|
}
|
||||||
|
if (needpush)
|
||||||
|
return _tlv_push (tlv);
|
||||||
|
|
||||||
|
if (!(tlv->bufsize >= tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
tlv->buffer += tlv->ti.length;
|
||||||
|
tlv->bufsize -= tlv->ti.length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect that the current tag is an object string and store its value
|
||||||
|
* at (R_DATA,R_DATALEN). Then skip over its value to the next tag.
|
||||||
|
* Note that the stored value are not allocated but point into TLV.
|
||||||
|
* If ENCAPSULATES is set the octet string is used as a new
|
||||||
|
* container. R_DATA and R_DATALEN are optional. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_octet_string (tlv_parser_t tlv, int encapsulates,
|
||||||
|
unsigned char const **r_data, size_t *r_datalen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OCTET_STRING
|
||||||
|
&& (!tlv->ti.is_constructed || encapsulates)))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
p = tlv->buffer;
|
||||||
|
if (!(n=tlv->ti.length) && !tlv->ti.ndef)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
|
||||||
|
if (encapsulates && tlv->ti.is_constructed
|
||||||
|
&& need_octet_string_cramming (p, n))
|
||||||
|
{
|
||||||
|
char *newbuffer;
|
||||||
|
|
||||||
|
newbuffer = cram_octet_string (p, n, r_datalen);
|
||||||
|
if (!newbuffer)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
|
||||||
|
err = register_buffer (tlv, newbuffer);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (newbuffer);
|
||||||
|
return (tlv->lasterr = err);
|
||||||
|
}
|
||||||
|
*r_data = newbuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (r_data)
|
||||||
|
*r_data = p;
|
||||||
|
if (r_datalen)
|
||||||
|
*r_datalen = tlv->ti.length;
|
||||||
|
}
|
||||||
|
if (encapsulates)
|
||||||
|
return _tlv_push (tlv);
|
||||||
|
|
||||||
|
if (!(tlv->bufsize >= tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
tlv->buffer += tlv->ti.length;
|
||||||
|
tlv->bufsize -= tlv->ti.length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect that the current tag is an integer and return its value at
|
||||||
|
* R_VALUE. Then skip over its value to the next tag. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_integer (tlv_parser_t tlv, int *r_value)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n;
|
||||||
|
int value;
|
||||||
|
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
|
||||||
|
&& !tlv->ti.is_constructed))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
p = tlv->buffer;
|
||||||
|
if (!(n=tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
|
||||||
|
/* We currently support only positive values. */
|
||||||
|
if ((*p & 0x80))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_ERANGE));
|
||||||
|
|
||||||
|
for (value = 0; n; n--)
|
||||||
|
{
|
||||||
|
value <<= 8;
|
||||||
|
value |= (*p++) & 0xff;
|
||||||
|
if (value < 0)
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_EOVERFLOW));
|
||||||
|
}
|
||||||
|
*r_value = value;
|
||||||
|
if (!(tlv->bufsize >= tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
tlv->buffer += tlv->ti.length;
|
||||||
|
tlv->bufsize -= tlv->ti.length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Variant of tlv_expect_integer which returns an MPI. If IGNORE_ZERO
|
||||||
|
* is set a value of 0 is ignored and R_VALUE not changed and the
|
||||||
|
* function returns GPG_ERR_FALSE. No check for negative encoded
|
||||||
|
* integers is done because the old code here worked the same and we
|
||||||
|
* can't foreclose invalid encoded PKCS#12 stuff - after all it is
|
||||||
|
* PKCS#12 see https://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html */
|
||||||
|
#ifdef GCRYPT_VERSION
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_mpinteger (tlv_parser_t tlv, int ignore_zero,
|
||||||
|
gcry_mpi_t *r_value)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
|
||||||
|
&& !tlv->ti.is_constructed))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
p = tlv->buffer;
|
||||||
|
if (!(n=tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
|
||||||
|
if (!(tlv->bufsize >= tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
tlv->buffer += tlv->ti.length;
|
||||||
|
tlv->bufsize -= tlv->ti.length;
|
||||||
|
if (ignore_zero && n == 1 && !*p)
|
||||||
|
return gpg_error (GPG_ERR_FALSE);
|
||||||
|
|
||||||
|
return gcry_mpi_scan (r_value, GCRYMPI_FMT_USG, p, n, NULL);
|
||||||
|
}
|
||||||
|
#endif /*GCRYPT_VERSION*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Expect that the current tag is an object id and store its value at
|
||||||
|
* (R_OID,R_OIDLEN). Then skip over its value to the next tag. Note
|
||||||
|
* that the stored value is not allocated but points into TLV. */
|
||||||
|
gpg_error_t
|
||||||
|
tlv_expect_object_id (tlv_parser_t tlv,
|
||||||
|
unsigned char const **r_oid, size_t *r_oidlen)
|
||||||
|
{
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
tlv->lastfunc = __func__;
|
||||||
|
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OBJECT_ID
|
||||||
|
&& !tlv->ti.is_constructed))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||||
|
p = tlv->buffer;
|
||||||
|
if (!(n=tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
|
||||||
|
*r_oid = p;
|
||||||
|
*r_oidlen = tlv->ti.length;
|
||||||
|
if (!(tlv->bufsize >= tlv->ti.length))
|
||||||
|
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||||
|
tlv->buffer += tlv->ti.length;
|
||||||
|
tlv->bufsize -= tlv->ti.length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given an ASN.1 chunk of a structure like:
|
||||||
|
*
|
||||||
|
* 24 NDEF: OCTET STRING -- This is not passed to us
|
||||||
|
* 04 1: OCTET STRING -- INPUT point s to here
|
||||||
|
* : 30
|
||||||
|
* 04 1: OCTET STRING
|
||||||
|
* : 80
|
||||||
|
* [...]
|
||||||
|
* 04 2: OCTET STRING
|
||||||
|
* : 00 00
|
||||||
|
* : } -- This denotes a Null tag and are the last
|
||||||
|
* -- two bytes in INPUT.
|
||||||
|
*
|
||||||
|
* The example is from Mozilla Firefox 1.0.4 which actually exports
|
||||||
|
* certs as single byte chunks of octet strings.
|
||||||
|
*
|
||||||
|
* Create a new buffer with the content of that octet string. INPUT
|
||||||
|
* is the original buffer with a LENGTH. Returns
|
||||||
|
* NULL on error or a new malloced buffer with its actual used length
|
||||||
|
* stored at R_NEWLENGTH. */
|
||||||
|
static unsigned char *
|
||||||
|
cram_octet_string (const unsigned char *input, size_t length,
|
||||||
|
size_t *r_newlength)
|
||||||
|
{
|
||||||
|
const unsigned char *s = input;
|
||||||
|
size_t n = length;
|
||||||
|
unsigned char *output, *d;
|
||||||
|
struct tag_info ti;
|
||||||
|
|
||||||
|
/* Allocate output buf. We know that it won't be longer than the
|
||||||
|
input buffer. */
|
||||||
|
d = output = xtrymalloc (length);
|
||||||
|
if (!output)
|
||||||
|
goto bailout;
|
||||||
|
|
||||||
|
while (n)
|
||||||
|
{
|
||||||
|
if (parse_tag (&s, &n, &ti))
|
||||||
|
goto bailout;
|
||||||
|
if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
|
||||||
|
&& !ti.ndef && !ti.is_constructed)
|
||||||
|
{
|
||||||
|
memcpy (d, s, ti.length);
|
||||||
|
s += ti.length;
|
||||||
|
d += ti.length;
|
||||||
|
n -= ti.length;
|
||||||
|
}
|
||||||
|
else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
|
||||||
|
break; /* Ready */
|
||||||
|
else
|
||||||
|
goto bailout;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*r_newlength = d - output;
|
||||||
|
return output;
|
||||||
|
|
||||||
|
bailout:
|
||||||
|
xfree (output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if (INPUT,LENGTH) is a structure which should be passed
|
||||||
|
* to cram_octet_string. This is basically the same loop as in
|
||||||
|
* cram_octet_string but without any actual copying. */
|
||||||
|
static int
|
||||||
|
need_octet_string_cramming (const unsigned char *input, size_t length)
|
||||||
|
{
|
||||||
|
const unsigned char *s = input;
|
||||||
|
size_t n = length;
|
||||||
|
struct tag_info ti;
|
||||||
|
|
||||||
|
if (!length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (n)
|
||||||
|
{
|
||||||
|
if (parse_tag (&s, &n, &ti))
|
||||||
|
return 0;
|
||||||
|
if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
|
||||||
|
&& !ti.ndef && !ti.is_constructed)
|
||||||
|
{
|
||||||
|
s += ti.length;
|
||||||
|
n -= ti.length;
|
||||||
|
}
|
||||||
|
else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
|
||||||
|
break; /* Ready */
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -150,13 +150,16 @@ find_tlv_unchecked (const unsigned char *buffer, size_t length,
|
||||||
|
|
||||||
|
|
||||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||||
and the length part from the TLV triplet. Update BUFFER and SIZE
|
* and the length part from the TLV triplet. Update BUFFER and SIZE
|
||||||
on success. */
|
* on success. Note that this function does not check that the value
|
||||||
|
* fits into the provided buffer; this allows one to work on the TL part
|
||||||
|
* of a TLV. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
parse_ber_header (unsigned char const **buffer, size_t *size,
|
parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||||
int *r_class, int *r_tag,
|
int *r_class, int *r_tag,
|
||||||
int *r_constructed, int *r_ndef,
|
int *r_constructed, int *r_ndef,
|
||||||
size_t *r_length, size_t *r_nhdr){
|
size_t *r_length, size_t *r_nhdr)
|
||||||
|
{
|
||||||
int c;
|
int c;
|
||||||
unsigned long tag;
|
unsigned long tag;
|
||||||
const unsigned char *buf = *buffer;
|
const unsigned char *buf = *buffer;
|
||||||
|
|
69
common/tlv.h
69
common/tlv.h
|
@ -71,10 +71,22 @@ enum tlv_tag_type {
|
||||||
TAG_BMP_STRING = 30
|
TAG_BMP_STRING = 30
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tag_info
|
||||||
|
{
|
||||||
|
int class;
|
||||||
|
int is_constructed;
|
||||||
|
unsigned long tag;
|
||||||
|
size_t length; /* length part of the TLV */
|
||||||
|
size_t nhdr;
|
||||||
|
int ndef; /* It is an indefinite length */
|
||||||
|
};
|
||||||
|
|
||||||
struct tlv_builder_s;
|
struct tlv_builder_s;
|
||||||
typedef struct tlv_builder_s *tlv_builder_t;
|
typedef struct tlv_builder_s *tlv_builder_t;
|
||||||
|
|
||||||
|
struct tlv_parser_s;
|
||||||
|
typedef struct tlv_parser_s *tlv_parser_t;
|
||||||
|
|
||||||
/*-- tlv.c --*/
|
/*-- tlv.c --*/
|
||||||
|
|
||||||
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
|
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
|
||||||
|
@ -94,7 +106,7 @@ const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
|
||||||
|
|
||||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||||
and the length part from the TLV triplet. Update BUFFER and SIZE
|
and the length part from the TLV triplet. Update BUFFER and SIZE
|
||||||
on success. */
|
on success. See also tlv_parse_tag. */
|
||||||
gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
|
gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||||
int *r_class, int *r_tag,
|
int *r_class, int *r_tag,
|
||||||
int *r_constructed,
|
int *r_constructed,
|
||||||
|
@ -129,7 +141,7 @@ void tlv_builder_add_end (tlv_builder_t tb);
|
||||||
gpg_error_t tlv_builder_finalize (tlv_builder_t tb,
|
gpg_error_t tlv_builder_finalize (tlv_builder_t tb,
|
||||||
void **r_obj, size_t *r_objlen);
|
void **r_obj, size_t *r_objlen);
|
||||||
|
|
||||||
/* Wite a TLV header to MEMBUF. */
|
/* Write a TLV header to MEMBUF. */
|
||||||
void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
|
void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
|
||||||
int constructed, size_t length);
|
int constructed, size_t length);
|
||||||
|
|
||||||
|
@ -137,6 +149,59 @@ void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
|
||||||
size_t get_tlv_length (int class, int tag, int constructed, size_t length);
|
size_t get_tlv_length (int class, int tag, int constructed, size_t length);
|
||||||
|
|
||||||
|
|
||||||
|
/*-- tlv-parser.c --*/
|
||||||
|
|
||||||
|
tlv_parser_t tlv_parser_new (const unsigned char *buffer, size_t bufsize,
|
||||||
|
int verbosity);
|
||||||
|
void tlv_parser_release (tlv_parser_t tlv);
|
||||||
|
|
||||||
|
void _tlv_parser_dump_tag (const char *text, int lno, tlv_parser_t tlv);
|
||||||
|
void _tlv_parser_dump_state (const char *text, const char *text2,
|
||||||
|
int lno, tlv_parser_t tlv);
|
||||||
|
|
||||||
|
int _tlv_parser_peek (tlv_parser_t tlv, int class, int tag);
|
||||||
|
int _tlv_parser_peek_null (tlv_parser_t tlv);
|
||||||
|
gpg_error_t _tlv_parser_next (tlv_parser_t tlv, int lno);
|
||||||
|
|
||||||
|
unsigned int tlv_parser_level (tlv_parser_t tlv);
|
||||||
|
size_t tlv_parser_offset (tlv_parser_t tlv);
|
||||||
|
const char *tlv_parser_lastfunc (tlv_parser_t tlv);
|
||||||
|
const char *tlv_parser_lasterrstr (tlv_parser_t tlv);
|
||||||
|
void tlv_parser_set_pending (tlv_parser_t tlv);
|
||||||
|
size_t tlv_parser_tag_length (tlv_parser_t tlv, int with_header);
|
||||||
|
|
||||||
|
void tlv_parser_skip (tlv_parser_t tlv);
|
||||||
|
|
||||||
|
gpg_error_t tlv_expect_sequence (tlv_parser_t tlv);
|
||||||
|
gpg_error_t tlv_expect_context_tag (tlv_parser_t tlv, int *r_tag);
|
||||||
|
gpg_error_t tlv_expect_set (tlv_parser_t tlv);
|
||||||
|
gpg_error_t tlv_expect_object (tlv_parser_t tlv, int class, int tag,
|
||||||
|
unsigned char const **r_data,
|
||||||
|
size_t *r_datalen);
|
||||||
|
gpg_error_t tlv_expect_octet_string (tlv_parser_t tlv, int encapsulates,
|
||||||
|
unsigned char const **r_data,
|
||||||
|
size_t *r_datalen);
|
||||||
|
gpg_error_t tlv_expect_integer (tlv_parser_t tlv, int *r_value);
|
||||||
|
#ifdef GCRYPT_VERSION
|
||||||
|
gpg_error_t tlv_expect_mpinteger (tlv_parser_t tlv, int ignore_zero,
|
||||||
|
gcry_mpi_t *r_value);
|
||||||
|
#endif
|
||||||
|
gpg_error_t tlv_expect_object_id (tlv_parser_t tlv,
|
||||||
|
unsigned char const **r_oid,
|
||||||
|
size_t *r_oidlen);
|
||||||
|
|
||||||
|
/* Easier to use wrapper around parse_ber_header. */
|
||||||
|
gpg_error_t tlv_parse_tag (unsigned char const **buffer,
|
||||||
|
size_t *size, struct tag_info *ti);
|
||||||
|
|
||||||
|
/* Convenience macro and macros to include the line number. */
|
||||||
|
#define tlv_parser_dump_tag(a,b) _tlv_parser_dump_tag ((a),__LINE__,(b))
|
||||||
|
#define tlv_parser_dump_state(a,b,c) \
|
||||||
|
_tlv_parser_dump_state ((a),(b),__LINE__,(c))
|
||||||
|
#define tlv_peek(a,b,c) _tlv_parser_peek ((a),(b),(c))
|
||||||
|
#define tlv_peek_null(a) _tlv_parser_peek_null ((a))
|
||||||
|
#define tlv_next(a) _tlv_parser_next ((a), __LINE__)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SCD_TLV_H */
|
#endif /* SCD_TLV_H */
|
||||||
|
|
|
@ -39,6 +39,11 @@
|
||||||
* libgpg-error version. Define them here.
|
* libgpg-error version. Define them here.
|
||||||
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
|
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
|
||||||
*/
|
*/
|
||||||
|
#if GPG_ERROR_VERSION_NUMBER < 0x012f00 /* 1.47 */
|
||||||
|
# define GPG_ERR_BAD_PUK 320
|
||||||
|
# define GPG_ERR_NO_RESET_CODE 321
|
||||||
|
# define GPG_ERR_BAD_RESET_CODE 322
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||||
# if !defined (INCLUDED_BY_MAIN_MODULE)
|
# if !defined (INCLUDED_BY_MAIN_MODULE)
|
||||||
|
@ -144,34 +149,6 @@ ssize_t read_line (FILE *fp,
|
||||||
size_t *max_length);
|
size_t *max_length);
|
||||||
|
|
||||||
|
|
||||||
/*-- b64enc.c and b64dec.c --*/
|
|
||||||
struct b64state
|
|
||||||
{
|
|
||||||
unsigned int flags;
|
|
||||||
int idx;
|
|
||||||
int quad_count;
|
|
||||||
FILE *fp;
|
|
||||||
estream_t stream;
|
|
||||||
char *title;
|
|
||||||
unsigned char radbuf[4];
|
|
||||||
u32 crc;
|
|
||||||
int stop_seen:1;
|
|
||||||
int invalid_encoding:1;
|
|
||||||
gpg_error_t lasterr;
|
|
||||||
};
|
|
||||||
|
|
||||||
gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);
|
|
||||||
gpg_error_t b64enc_start_es (struct b64state *state, estream_t fp,
|
|
||||||
const char *title);
|
|
||||||
gpg_error_t b64enc_write (struct b64state *state,
|
|
||||||
const void *buffer, size_t nbytes);
|
|
||||||
gpg_error_t b64enc_finish (struct b64state *state);
|
|
||||||
|
|
||||||
gpg_error_t b64dec_start (struct b64state *state, const char *title);
|
|
||||||
gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length,
|
|
||||||
size_t *r_nbytes);
|
|
||||||
gpg_error_t b64dec_finish (struct b64state *state);
|
|
||||||
|
|
||||||
/*-- sexputil.c */
|
/*-- sexputil.c */
|
||||||
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
|
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
|
||||||
void log_printcanon (const char *text,
|
void log_printcanon (const char *text,
|
||||||
|
@ -219,6 +196,7 @@ char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
|
||||||
const char *pubkey_algo_to_string (int algo);
|
const char *pubkey_algo_to_string (int algo);
|
||||||
const char *hash_algo_to_string (int algo);
|
const char *hash_algo_to_string (int algo);
|
||||||
const char *cipher_mode_to_string (int mode);
|
const char *cipher_mode_to_string (int mode);
|
||||||
|
const char *get_ecc_curve_from_key (gcry_sexp_t key);
|
||||||
|
|
||||||
/*-- convert.c --*/
|
/*-- convert.c --*/
|
||||||
int hex2bin (const char *string, void *buffer, size_t length);
|
int hex2bin (const char *string, void *buffer, size_t length);
|
||||||
|
@ -250,9 +228,10 @@ int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
|
||||||
int openpgp_oid_is_cv25519 (gcry_mpi_t a);
|
int openpgp_oid_is_cv25519 (gcry_mpi_t a);
|
||||||
int openpgp_oid_is_cv448 (gcry_mpi_t a);
|
int openpgp_oid_is_cv448 (gcry_mpi_t a);
|
||||||
int openpgp_oid_is_ed448 (gcry_mpi_t a);
|
int openpgp_oid_is_ed448 (gcry_mpi_t a);
|
||||||
|
enum gcry_kem_algos openpgp_oid_to_kem_algo (const char *oidname);
|
||||||
const char *openpgp_curve_to_oid (const char *name,
|
const char *openpgp_curve_to_oid (const char *name,
|
||||||
unsigned int *r_nbits, int *r_algo);
|
unsigned int *r_nbits, int *r_algo);
|
||||||
const char *openpgp_oid_to_curve (const char *oid, int canon);
|
const char *openpgp_oid_to_curve (const char *oid, int mode);
|
||||||
const char *openpgp_oid_or_name_to_curve (const char *oidname, int canon);
|
const char *openpgp_oid_or_name_to_curve (const char *oidname, int canon);
|
||||||
const char *openpgp_enum_curves (int *idxp);
|
const char *openpgp_enum_curves (int *idxp);
|
||||||
const char *openpgp_is_curve_supported (const char *name,
|
const char *openpgp_is_curve_supported (const char *name,
|
||||||
|
@ -267,6 +246,7 @@ void gnupg_set_homedir (const char *newdir);
|
||||||
void gnupg_maybe_make_homedir (const char *fname, int quiet);
|
void gnupg_maybe_make_homedir (const char *fname, int quiet);
|
||||||
const char *gnupg_homedir (void);
|
const char *gnupg_homedir (void);
|
||||||
int gnupg_default_homedir_p (void);
|
int gnupg_default_homedir_p (void);
|
||||||
|
const char *gnupg_registry_dir (void);
|
||||||
const char *gnupg_daemon_rootdir (void);
|
const char *gnupg_daemon_rootdir (void);
|
||||||
const char *gnupg_socketdir (void);
|
const char *gnupg_socketdir (void);
|
||||||
const char *gnupg_sysconfdir (void);
|
const char *gnupg_sysconfdir (void);
|
||||||
|
@ -321,6 +301,19 @@ char *gnupg_get_help_string (const char *key, int only_current_locale);
|
||||||
/*-- localename.c --*/
|
/*-- localename.c --*/
|
||||||
const char *gnupg_messages_locale_name (void);
|
const char *gnupg_messages_locale_name (void);
|
||||||
|
|
||||||
|
/*-- kem.c --*/
|
||||||
|
gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
|
||||||
|
int hashalgo, const void *ecdh, size_t ecdh_len,
|
||||||
|
const void *ecc_ct, size_t ecc_ct_len,
|
||||||
|
const void *ecc_pk, size_t ecc_pk_len);
|
||||||
|
|
||||||
|
gpg_error_t gnupg_kem_combiner (void *kek, size_t kek_len,
|
||||||
|
const void *ecc_ss, size_t ecc_ss_len,
|
||||||
|
const void *ecc_ct, size_t ecc_ct_len,
|
||||||
|
const void *mlkem_ss, size_t mlkem_ss_len,
|
||||||
|
const void *mlkem_ct, size_t mlkem_ct_len,
|
||||||
|
const void *fixedinfo, size_t fixedinfo_len);
|
||||||
|
|
||||||
/*-- miscellaneous.c --*/
|
/*-- miscellaneous.c --*/
|
||||||
|
|
||||||
/* This function is called at startup to tell libgcrypt to use our own
|
/* This function is called at startup to tell libgcrypt to use our own
|
||||||
|
@ -330,7 +323,7 @@ void setup_libgcrypt_logging (void);
|
||||||
/* Print an out of core message and die. */
|
/* Print an out of core message and die. */
|
||||||
void xoutofcore (void);
|
void xoutofcore (void);
|
||||||
|
|
||||||
/* Wrapper aroung gpgrt_reallocarray. Uses the gpgrt alloc function
|
/* Wrapper around gpgrt_reallocarray. Uses the gpgrt alloc function
|
||||||
* which redirects to the Libgcrypt versions via
|
* which redirects to the Libgcrypt versions via
|
||||||
* init_common_subsystems. Thus this can be used interchangeable with
|
* init_common_subsystems. Thus this can be used interchangeable with
|
||||||
* the other alloc functions. */
|
* the other alloc functions. */
|
||||||
|
@ -360,8 +353,6 @@ char *try_make_printable_string (const void *p, size_t n, int delim);
|
||||||
char *make_printable_string (const void *p, size_t n, int delim);
|
char *make_printable_string (const void *p, size_t n, int delim);
|
||||||
char *decode_c_string (const char *src);
|
char *decode_c_string (const char *src);
|
||||||
|
|
||||||
int is_file_compressed (const byte *buf, unsigned int buflen);
|
|
||||||
|
|
||||||
int match_multistr (const char *multistr,const char *match);
|
int match_multistr (const char *multistr,const char *match);
|
||||||
|
|
||||||
int gnupg_compare_version (const char *a, const char *b);
|
int gnupg_compare_version (const char *a, const char *b);
|
||||||
|
@ -383,11 +374,15 @@ struct compatibility_flags_s
|
||||||
int parse_compatibility_flags (const char *string, unsigned int *flagvar,
|
int parse_compatibility_flags (const char *string, unsigned int *flagvar,
|
||||||
const struct compatibility_flags_s *flags);
|
const struct compatibility_flags_s *flags);
|
||||||
|
|
||||||
|
gpg_error_t b64decode (const char *string, const char *title,
|
||||||
|
void **r_buffer, size_t *r_buflen);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-- Simple replacement functions. */
|
/*-- Simple replacement functions. */
|
||||||
|
|
||||||
/* We use the gnupg_ttyname macro to be safe not to run into conflicts
|
/* We use the gnupg_ttyname macro to be safe not to run into conflicts
|
||||||
which an extisting but broken ttyname. */
|
with an existing but broken ttyname. */
|
||||||
#if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME)
|
#if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME)
|
||||||
# define gnupg_ttyname(n) _gnupg_ttyname ((n))
|
# define gnupg_ttyname(n) _gnupg_ttyname ((n))
|
||||||
/* Systems without ttyname (W32) will merely return NULL. */
|
/* Systems without ttyname (W32) will merely return NULL. */
|
||||||
|
|
|
@ -29,4 +29,4 @@ built on @BUILD_HOSTNAME@ at @BUILD_TIMESTAMP@\0"
|
||||||
#define W32INFO_PRODUCTVERSION "@VERSION@\0"
|
#define W32INFO_PRODUCTVERSION "@VERSION@\0"
|
||||||
|
|
||||||
#define W32INFO_LEGALCOPYRIGHT "Copyright \xa9 \
|
#define W32INFO_LEGALCOPYRIGHT "Copyright \xa9 \
|
||||||
2023 g10 Code GmbH\0"
|
2024 g10 Code GmbH\0"
|
||||||
|
|
35
configure.ac
35
configure.ac
|
@ -58,22 +58,22 @@ AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg26", [swdb tag for this branch])
|
||||||
NEED_GPGRT_VERSION=1.46
|
NEED_GPGRT_VERSION=1.46
|
||||||
|
|
||||||
NEED_LIBGCRYPT_API=1
|
NEED_LIBGCRYPT_API=1
|
||||||
NEED_LIBGCRYPT_VERSION=1.9.1
|
NEED_LIBGCRYPT_VERSION=1.11.0
|
||||||
|
|
||||||
NEED_LIBASSUAN_API=2
|
NEED_LIBASSUAN_API=3
|
||||||
NEED_LIBASSUAN_VERSION=2.5.0
|
NEED_LIBASSUAN_VERSION=3.0.0
|
||||||
|
|
||||||
NEED_KSBA_API=1
|
NEED_KSBA_API=1
|
||||||
NEED_KSBA_VERSION=1.6.3
|
NEED_KSBA_VERSION=1.6.3
|
||||||
|
|
||||||
NEED_NTBTLS_API=1
|
NEED_NTBTLS_API=1
|
||||||
NEED_NTBTLS_VERSION=0.1.0
|
NEED_NTBTLS_VERSION=0.2.0
|
||||||
|
|
||||||
NEED_NPTH_API=1
|
NEED_NPTH_API=1
|
||||||
NEED_NPTH_VERSION=1.2
|
NEED_NPTH_VERSION=1.2
|
||||||
|
|
||||||
|
|
||||||
NEED_GNUTLS_VERSION=3.0
|
NEED_GNUTLS_VERSION=3.2
|
||||||
|
|
||||||
NEED_SQLITE_VERSION=3.27
|
NEED_SQLITE_VERSION=3.27
|
||||||
|
|
||||||
|
@ -525,7 +525,7 @@ AH_BOTTOM([
|
||||||
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
|
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
|
||||||
#define GNUPG_CACHE_DIR "cache.d"
|
#define GNUPG_CACHE_DIR "cache.d"
|
||||||
|
|
||||||
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2023 g10 Code GmbH"
|
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2024 g10 Code GmbH"
|
||||||
|
|
||||||
/* For some systems (DOS currently), we hardcode the path here. For
|
/* For some systems (DOS currently), we hardcode the path here. For
|
||||||
POSIX systems the values are constructed by the Makefiles, so that
|
POSIX systems the values are constructed by the Makefiles, so that
|
||||||
|
@ -1385,6 +1385,8 @@ AC_CHECK_SIZEOF(time_t,,[[
|
||||||
]])
|
]])
|
||||||
GNUPG_TIME_T_UNSIGNED
|
GNUPG_TIME_T_UNSIGNED
|
||||||
|
|
||||||
|
# Check SOCKET type for Windows.
|
||||||
|
AC_CHECK_TYPES([SOCKET], [], [], [[#include "winsock2.h"]])
|
||||||
|
|
||||||
if test "$ac_cv_sizeof_unsigned_short" = "0" \
|
if test "$ac_cv_sizeof_unsigned_short" = "0" \
|
||||||
|| test "$ac_cv_sizeof_unsigned_int" = "0" \
|
|| test "$ac_cv_sizeof_unsigned_int" = "0" \
|
||||||
|
@ -1599,7 +1601,7 @@ if test "$build_tpm2d" = "yes"; then
|
||||||
# until version 2.4.0.
|
# until version 2.4.0.
|
||||||
#
|
#
|
||||||
# Note: the missing API is fairly serious and is also easily backportable
|
# Note: the missing API is fairly serious and is also easily backportable
|
||||||
# so keep the check below as is intead of going by library version number.
|
# so keep the check below as is instead of going by library version number.
|
||||||
##
|
##
|
||||||
AC_CHECK_LIB(tss2-esys, Esys_TR_GetTpmHandle, [], [
|
AC_CHECK_LIB(tss2-esys, Esys_TR_GetTpmHandle, [], [
|
||||||
AC_MSG_WARN([Need Esys_TR_GetTpmHandle API (usually requires Intel TSS 2.4.0 or later, disabling TPM support)])
|
AC_MSG_WARN([Need Esys_TR_GetTpmHandle API (usually requires Intel TSS 2.4.0 or later, disabling TPM support)])
|
||||||
|
@ -1613,10 +1615,9 @@ if test "$build_tpm2d" = "yes"; then
|
||||||
if test "$have_libtss" != no; then
|
if test "$have_libtss" != no; then
|
||||||
AC_DEFINE(HAVE_LIBTSS, 1, [Defined if we have TPM2 support library])
|
AC_DEFINE(HAVE_LIBTSS, 1, [Defined if we have TPM2 support library])
|
||||||
# look for a TPM emulator for testing
|
# look for a TPM emulator for testing
|
||||||
AC_PATH_PROG(TPMSERVER, tpm_server,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
|
AC_PATH_PROG(TPMSERVER, tpm_server)
|
||||||
AC_PATH_PROG(SWTPM, swtpm,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
|
AC_PATH_PROG(TSSSTARTUP, tssstartup)
|
||||||
AC_PATH_PROG(SWTPM_IOCTL, swtpm_ioctl,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
|
AC_PATH_PROG(SWTPM, swtpm)
|
||||||
AC_PATH_PROG(TSSSTARTUP, tssstartup,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if test "$have_libtss" = no; then
|
if test "$have_libtss" = no; then
|
||||||
|
@ -1625,7 +1626,7 @@ fi
|
||||||
AC_SUBST(LIBTSS_LIBS)
|
AC_SUBST(LIBTSS_LIBS)
|
||||||
AC_SUBST(LIBTSS_CFLAGS)
|
AC_SUBST(LIBTSS_CFLAGS)
|
||||||
AM_CONDITIONAL(HAVE_LIBTSS, test "$have_libtss" != no)
|
AM_CONDITIONAL(HAVE_LIBTSS, test "$have_libtss" != no)
|
||||||
AM_CONDITIONAL(TEST_LIBTSS, test -n "$TPMSERVER" || test -n "$SWTPM" && test -n "$TSSSTARTUP")
|
AM_CONDITIONAL(TEST_LIBTSS, test -n "$SWTPM" -o -n "$TPMSERVER" -a -n "$TSSSTARTUP")
|
||||||
AC_SUBST(HAVE_LIBTSS)
|
AC_SUBST(HAVE_LIBTSS)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -1637,7 +1638,7 @@ if test "$GCC" = yes; then
|
||||||
mycflags=
|
mycflags=
|
||||||
mycflags_save=$CFLAGS
|
mycflags_save=$CFLAGS
|
||||||
|
|
||||||
# Check whether gcc does not emit a diagnositc for unknown -Wno-*
|
# Check whether gcc does not emit a diagnostic for unknown -Wno-*
|
||||||
# options. This is the case for gcc >= 4.6
|
# options. This is the case for gcc >= 4.6
|
||||||
AC_MSG_CHECKING([if gcc ignores unknown -Wno-* options])
|
AC_MSG_CHECKING([if gcc ignores unknown -Wno-* options])
|
||||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
@ -2102,6 +2103,14 @@ tests/tpm2dtests/Makefile
|
||||||
tests/gpgme/Makefile
|
tests/gpgme/Makefile
|
||||||
tests/pkits/Makefile
|
tests/pkits/Makefile
|
||||||
g10/gpg.w32-manifest
|
g10/gpg.w32-manifest
|
||||||
|
g10/gpgv.w32-manifest
|
||||||
|
sm/gpgsm.w32-manifest
|
||||||
|
kbx/keyboxd.w32-manifest
|
||||||
|
agent/gpg-agent.w32-manifest
|
||||||
|
scd/scdaemon.w32-manifest
|
||||||
|
dirmngr/dirmngr.w32-manifest
|
||||||
|
dirmngr/dirmngr_ldap.w32-manifest
|
||||||
|
dirmngr/dirmngr-client.w32-manifest
|
||||||
tools/gpg-connect-agent.w32-manifest
|
tools/gpg-connect-agent.w32-manifest
|
||||||
tools/gpgconf.w32-manifest
|
tools/gpgconf.w32-manifest
|
||||||
tools/gpgtar.w32-manifest
|
tools/gpgtar.w32-manifest
|
||||||
|
|
|
@ -1373,7 +1373,7 @@
|
||||||
truncated search.
|
truncated search.
|
||||||
* ldap.c (add_server_to_servers): Reactivated.
|
* ldap.c (add_server_to_servers): Reactivated.
|
||||||
(url_fetch_ldap): Call it here and try all configured servers in
|
(url_fetch_ldap): Call it here and try all configured servers in
|
||||||
case of a a failed lookup.
|
case of a failed lookup.
|
||||||
(fetch_next_cert_ldap): Detect the truncation error flag.
|
(fetch_next_cert_ldap): Detect the truncation error flag.
|
||||||
* misc.c (host_and_port_from_url, remove_percent_escapes): New.
|
* misc.c (host_and_port_from_url, remove_percent_escapes): New.
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,14 @@
|
||||||
|
|
||||||
## Process this file with automake to produce Makefile.in
|
## Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem
|
EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem \
|
||||||
|
dirmngr-w32info.rc dirmngr.w32-manifest.in \
|
||||||
|
dirmngr_ldap-w32info.rc dirmngr_ldap.w32-manifest.in \
|
||||||
|
dirmngr-client-w32info.rc dirmngr-client.w32-manifest.in
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dist_pkgdata_DATA = sks-keyservers.netCA.pem
|
dist_pkgdata_DATA = sks-keyservers.netCA.pem
|
||||||
|
|
||||||
bin_PROGRAMS = dirmngr dirmngr-client
|
bin_PROGRAMS = dirmngr dirmngr-client
|
||||||
|
@ -43,6 +50,16 @@ AM_CPPFLAGS =
|
||||||
|
|
||||||
include $(top_srcdir)/am/cmacros.am
|
include $(top_srcdir)/am/cmacros.am
|
||||||
|
|
||||||
|
if HAVE_W32_SYSTEM
|
||||||
|
dirmngr_rc_objs = dirmngr-w32info.o
|
||||||
|
dirmngr_ldap_rc_objs = dirmngr_ldap-w32info.o
|
||||||
|
dirmngr_client_rc_objs = dirmngr-client-w32info.o
|
||||||
|
|
||||||
|
dirmngr-w32info.o : dirmngr.w32-manifest ../common/w32info-rc.h
|
||||||
|
dirmngr_ldap-w32info.o : dirmngr_ldap.w32-manifest ../common/w32info-rc.h
|
||||||
|
dirmngr-client-w32info.o : dirmngr-client.w32-manifest ../common/w32info-rc.h
|
||||||
|
endif
|
||||||
|
|
||||||
AM_CFLAGS = $(USE_C99_CFLAGS) \
|
AM_CFLAGS = $(USE_C99_CFLAGS) \
|
||||||
$(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) \
|
$(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) \
|
||||||
$(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS) $(NTBTLS_CFLAGS) \
|
$(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS) $(NTBTLS_CFLAGS) \
|
||||||
|
@ -51,6 +68,7 @@ AM_CFLAGS = $(USE_C99_CFLAGS) \
|
||||||
|
|
||||||
if HAVE_W32_SYSTEM
|
if HAVE_W32_SYSTEM
|
||||||
ldap_url = ldap-url.h ldap-url.c
|
ldap_url = ldap-url.h ldap-url.c
|
||||||
|
NETLIBS += -lwinhttp -lsecurity
|
||||||
else
|
else
|
||||||
ldap_url =
|
ldap_url =
|
||||||
endif
|
endif
|
||||||
|
@ -89,12 +107,13 @@ dirmngr_LDADD = $(libcommonpth) \
|
||||||
$(DNSLIBS) $(LIBASSUAN_LIBS) \
|
$(DNSLIBS) $(LIBASSUAN_LIBS) \
|
||||||
$(KSBA_LIBS) $(NPTH_LIBS) $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
|
$(KSBA_LIBS) $(NPTH_LIBS) $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
|
||||||
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) \
|
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) \
|
||||||
$(NETLIBS)
|
$(NETLIBS) $(dirmngr_rc_objs)
|
||||||
|
|
||||||
if USE_LDAP
|
if USE_LDAP
|
||||||
dirmngr_LDADD += $(ldaplibs) $(LBER_LIBS)
|
dirmngr_LDADD += $(ldaplibs) $(LBER_LIBS)
|
||||||
endif
|
endif
|
||||||
dirmngr_LDFLAGS =
|
dirmngr_LDFLAGS =
|
||||||
|
dirmngr_DEPENDENCIES = $(dirmngr_rc_objs)
|
||||||
|
|
||||||
if USE_LDAP
|
if USE_LDAP
|
||||||
dirmngr_ldap_SOURCES = dirmngr_ldap.c ldap-misc.c ldap-misc.h $(ldap_url)
|
dirmngr_ldap_SOURCES = dirmngr_ldap.c ldap-misc.c ldap-misc.h $(ldap_url)
|
||||||
|
@ -102,14 +121,18 @@ dirmngr_ldap_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBGCRYPT_CFLAGS)
|
||||||
dirmngr_ldap_LDFLAGS =
|
dirmngr_ldap_LDFLAGS =
|
||||||
dirmngr_ldap_LDADD = $(libcommon) \
|
dirmngr_ldap_LDADD = $(libcommon) \
|
||||||
$(GPG_ERROR_LIBS) $(LIBGCRYPT_LIBS) $(LDAPLIBS) \
|
$(GPG_ERROR_LIBS) $(LIBGCRYPT_LIBS) $(LDAPLIBS) \
|
||||||
$(LBER_LIBS) $(LIBINTL) $(LIBICONV) $(NETLIBS)
|
$(LBER_LIBS) $(LIBINTL) $(LIBICONV) $(NETLIBS) \
|
||||||
|
$(dirmngr_ldap_rc_objs)
|
||||||
|
dirmngr_ldap_DEPENDENCIES = $(dirmngr_ldap_rc_objs)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
dirmngr_client_SOURCES = dirmngr-client.c
|
dirmngr_client_SOURCES = dirmngr-client.c
|
||||||
dirmngr_client_LDADD = $(libcommon) \
|
dirmngr_client_LDADD = $(libcommon) \
|
||||||
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
|
||||||
$(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV)
|
$(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV) \
|
||||||
|
$(dirmngr_client_rc_objs)
|
||||||
dirmngr_client_LDFLAGS =
|
dirmngr_client_LDFLAGS =
|
||||||
|
dirmngr_client_DEPENDENCIES = $(dirmngr_client_rc_objs)
|
||||||
|
|
||||||
|
|
||||||
t_common_src = t-support.h t-support.c
|
t_common_src = t-support.h t-support.c
|
||||||
|
|
|
@ -55,7 +55,7 @@ Noteworthy changes in version 1.0.1 (2007-08-16)
|
||||||
Noteworthy changes in version 1.0.0 (2006-11-29)
|
Noteworthy changes in version 1.0.0 (2006-11-29)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
* Bumbed the version number.
|
* Bumped the version number.
|
||||||
|
|
||||||
* Removed included gettext. We now require the system to provide a
|
* Removed included gettext. We now require the system to provide a
|
||||||
suitable installation.
|
suitable installation.
|
||||||
|
@ -174,7 +174,7 @@ Noteworthy changes in version 0.5.4 (2004-04-29)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
* New commands --ocsp-responder and --ocsp-signer to define a default
|
* New commands --ocsp-responder and --ocsp-signer to define a default
|
||||||
OCSP reponder if a certificate does not contain an assigned OCSP
|
OCSP responder if a certificate does not contain an assigned OCSP
|
||||||
responder.
|
responder.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,8 @@ static unsigned int any_cert_of_class;
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
/* We load some functions dynamically. Provide typedefs for tehse
|
#include <wincrypt.h>
|
||||||
|
/* We load some functions dynamically. Provide typedefs for these
|
||||||
* functions. */
|
* functions. */
|
||||||
typedef HCERTSTORE (WINAPI *CERTOPENSYSTEMSTORE)
|
typedef HCERTSTORE (WINAPI *CERTOPENSYSTEMSTORE)
|
||||||
(HCRYPTPROV hProv, LPCSTR szSubsystemProtocol);
|
(HCRYPTPROV hProv, LPCSTR szSubsystemProtocol);
|
||||||
|
@ -224,7 +225,7 @@ cert_compute_fpr (ksba_cert_t cert, unsigned char *digest)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Cleanup one slot. This releases all resourses but keeps the actual
|
/* Cleanup one slot. This releases all resources but keeps the actual
|
||||||
slot in the cache marked for reuse. */
|
slot in the cache marked for reuse. */
|
||||||
static void
|
static void
|
||||||
clean_cache_slot (cert_item_t ci)
|
clean_cache_slot (cert_item_t ci)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user