blob: 19f8e33c7c8ee8844cf637a9ea5bc1323d286147 [file] [log] [blame]
xf.li86118912025-03-19 20:07:27 -07001#!/bin/sh -e
2#
3# update-ca-certificates
4#
5# Copyright (c) 2003 Fumitoshi UKAI <ukai@debian.or.jp>
6# Copyright (c) 2009 Philipp Kern <pkern@debian.org>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301,
21# USA.
22#
23
24verbose=0
25fresh=0
26default=0
27CERTSCONF=$SYSROOT/etc/ca-certificates.conf
28CERTSDIR=$SYSROOT/usr/share/ca-certificates
29LOCALCERTSDIR=$SYSROOT/usr/local/share/ca-certificates
30CERTBUNDLE=ca-certificates.crt
31ETCCERTSDIR=$SYSROOT/etc/ssl/certs
32FSROOT=../../../ # to get from $ETCCERTSDIR to the root of the file system
33HOOKSDIR=$SYSROOT/etc/ca-certificates/update.d
34
35while [ $# -gt 0 ];
36do
37 case $1 in
38 --verbose|-v)
39 verbose=1;;
40 --fresh|-f)
41 fresh=1;;
42 --default|-d)
43 default=1
44 fresh=1;;
45 --certsconf)
46 shift
47 CERTSCONF="$1";;
48 --certsdir)
49 shift
50 CERTSDIR="$1";;
51 --localcertsdir)
52 shift
53 LOCALCERTSDIR="$1";;
54 --certbundle)
55 shift
56 CERTBUNDLE="$1";;
57 --etccertsdir)
58 shift
59 ETCCERTSDIR="$1";;
60 --hooksdir)
61 shift
62 HOOKSDIR="$1";;
63 --help|-h|*)
64 echo "$0: [--verbose] [--fresh]"
65 exit;;
66 esac
67 shift
68done
69
70if [ -z "$SYSROOT" ]; then
71 local_which () {
72 if [ $# -lt 1 ]; then
73 return 1
74 fi
75
76 (
77 IFS=:
78 for entry in $PATH; do
79 if [ -x "$entry/$1" ]; then
80 echo "$entry/$1"
81 exit 0
82 fi
83 done
84 exit 1
85 )
86 }
87
88 case "$0" in
89 */*)
90 sbindir=$(cd ${0%/*} && pwd)
91 ;;
92 *)
93 sbindir=$(cd $(dirname $(local_which $0)) && pwd)
94 ;;
95 esac
96 prefix=${sbindir%/*}
97 SYSROOT=${prefix%/*}
98 if [ ! -d "$SYSROOT/usr/share/ca-certificates" ]; then
99 SYSROOT=
100 fi
101fi
102
103if [ ! -s "$CERTSCONF" ]
104then
105 fresh=1
106fi
107
108cleanup() {
109 rm -f "$TEMPBUNDLE"
110 rm -f "$ADDED"
111 rm -f "$REMOVED"
112}
113trap cleanup 0
114
115# Helper files. (Some of them are not simple arrays because we spawn
116# subshells later on.)
117TEMPBUNDLE="${ETCCERTSDIR}/${CERTBUNDLE}.new"
118ADDED="$(mktemp --tmpdir "ca-certificates.tmp.XXXXXX")"
119REMOVED="$(mktemp --tmpdir "ca-certificates.tmp.XXXXXX")"
120
121# Adds a certificate to the list of trusted ones. This includes a symlink
122# in /etc/ssl/certs to the certificate file and its inclusion into the
123# bundle.
124add() {
125 CERT="$1"
126 PEM="$ETCCERTSDIR/$(basename "$CERT" .crt | sed -e 's/ /_/g' \
127 -e 's/[()]/=/g' \
128 -e 's/,/_/g').pem"
129 DST="$(echo ${CERT} | sed -e "s|^$SYSROOT||" -e "s|^/|$FSROOT|" )"
130 if ! test -e "$PEM" || [ "$(readlink "$PEM")" != "${DST}" ]
131 then
132 ln -sf "${DST}" "$PEM"
133 echo "+$PEM" >> "$ADDED"
134 fi
135 # Add trailing newline to certificate, if it is missing (#635570)
136 sed -e '$a\' "$CERT" >> "$TEMPBUNDLE"
137}
138
139remove() {
140 CERT="$1"
141 PEM="$ETCCERTSDIR/$(basename "$CERT" .crt).pem"
142 if test -L "$PEM"
143 then
144 rm -f "$PEM"
145 echo "-$PEM" >> "$REMOVED"
146 fi
147}
148
149cd "$ETCCERTSDIR"
150if [ "$fresh" = 1 ]; then
151 echo "Clearing symlinks in $ETCCERTSDIR..."
152 find . -type l -print | while read symlink
153 do
154 case $(readlink "$symlink") in
155 $CERTSDIR*|$LOCALCERTSDIR*) rm -f $symlink;;
156 esac
157 done
158 find . -type l -print | while read symlink
159 do
160 test -f "$symlink" || rm -f "$symlink"
161 done
162 echo "done."
163fi
164
165echo "Updating certificates in $ETCCERTSDIR..."
166
167# Add default certificate authorities if requested
168if [ "$default" = 1 ]; then
169 find -L "$CERTSDIR" -type f -name '*.crt' | sort | while read crt
170 do
171 add "$crt"
172 done
173fi
174
175# Handle certificates that should be removed. This is an explicit act
176# by prefixing lines in the configuration files with exclamation marks (!).
177sed -n -e '/^$/d' -e 's/^!//p' "$CERTSCONF" | while read crt
178do
179 remove "$CERTSDIR/$crt"
180done
181
182sed -e '/^$/d' -e '/^#/d' -e '/^!/d' "$CERTSCONF" | while read crt
183do
184 if ! test -f "$CERTSDIR/$crt"
185 then
186 echo "W: $CERTSDIR/$crt not found, but listed in $CERTSCONF." >&2
187 continue
188 fi
189 add "$CERTSDIR/$crt"
190done
191
192# Now process certificate authorities installed by the local system
193# administrator.
194if [ -d "$LOCALCERTSDIR" ]
195then
196 find -L "$LOCALCERTSDIR" -type f -name '*.crt' | sort | while read crt
197 do
198 add "$crt"
199 done
200fi
201
202ADDED_CNT=$(wc -l < "$ADDED")
203REMOVED_CNT=$(wc -l < "$REMOVED")
204
205if [ "$ADDED_CNT" -gt 0 ] || [ "$REMOVED_CNT" -gt 0 ]
206then
207 # only run if set of files has changed
208 # Remove orphan symlinks found in ETCCERTSDIR to prevent `openssl rehash`
209 # from exiting with an error. See #895482, #895473.
210 find $ETCCERTSDIR -type l ! -exec test -e {} \; -print | while read orphan
211 do
212 rm -f "$orphan"
213 if [ "$verbose" = 1 ]; then
214 echo "Removed orphan symlink $orphan"
215 fi
216 done
217 if [ "$verbose" = 0 ]
218 then
219 openssl rehash . > /dev/null
220 else
221 openssl rehash -v .
222 fi
223fi
224
225# chmod and mv only if TEMPBUNDLE exists or install may fail, #996005
226if [ -f "$TEMPBUNDLE" ]
227then
228 chmod 0644 "$TEMPBUNDLE"
229 mv -f "$TEMPBUNDLE" "$CERTBUNDLE"
230 # Restore proper SELinux label after moving the file
231 [ -x /sbin/restorecon ] && /sbin/restorecon "$CERTBUNDLE" >/dev/null 2>&1
232fi
233
234echo "$ADDED_CNT added, $REMOVED_CNT removed; done."
235
236if [ -d "$HOOKSDIR" ]
237then
238
239 echo "Running hooks in $HOOKSDIR..."
240 eval run-parts --test "$HOOKSDIR" | while read hook
241 do
242 ( cat "$ADDED"
243 cat "$REMOVED" ) | "$hook" || echo "E: $hook exited with code $?."
244 done
245 echo "done."
246
247fi
248
249# vim:set et sw=2: