ref #6528
---
main/ca-certificates/APKBUILD | 60 +++--
main/ca-certificates/fix-manpage.patch | 13 ++
main/ca-certificates/update-ca-certificates | 86 --------
main/ca-certificates/update-ca.c | 327 ++++++++++++++++++++++++++++
4 files changed, 380 insertions(+), 106 deletions(-)
create mode 100644 main/ca-certificates/fix-manpage.patch
delete mode 100755 main/ca-certificates/update-ca-certificates
create mode 100644 main/ca-certificates/update-ca.c
diff --git a/main/ca-certificates/APKBUILD b/main/ca-certificates/APKBUILD
index 8f5d3fc..84e0ca6 100644
--- a/main/ca-certificates/APKBUILD
+++ b/main/ca-certificates/APKBUILD
@@ -1,30 +1,40 @@
+# Contributor: Sergei Lukin <sergej.lukin@gmail.com>
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=ca-certificates
-pkgver=20141019
-
-_date=${pkgver%_p*}
-_nmu="+nmu${pkgver#*_p}"
-[ "$_nmu" = "+nmu${pkgver}" ] && _nmu=""
-_ver=${pkgver}
-
-pkgrel=2
+pkgver=20161130
+pkgrel=0
pkgdesc="Common CA certificates PEM files"
url="http://packages.debian.org/sid/ca-certificates"
-arch="noarch"
+arch="all"
license="MPL 2.0 GPL2+"
depends="run-parts openssl lua5.2 lua5.2-posix"
makedepends="python"
subpackages="$pkgname-doc"
options="!fhs"
-triggers="ca-certificates.trigger=/usr/share/ca-certificates:/usr/local/share/ca-certificates:/etc/ssl/certs"
-source="http://ftp.no.debian.org/debian/pool/main/c/$pkgname/${pkgname}_${_ver}.tar.xz
- update-ca-certificates
+triggers="ca-certificates.trigger=/usr/share/ca-certificates:/usr/local/share/ca-certificates:/etc/ssl/certs:/etc/ca-certificates/update.d"
+source="http://ftp.no.debian.org/debian/pool/main/c/$pkgname/${pkgname}_${pkgver}.tar.xz
+ fix-manpage.patch
+ update-ca.c
"
-_builddir="$srcdir"/$pkgname-$_ver
+_builddir="$srcdir"/$pkgname
+
+prepare() {
+ cd "$_builddir"
+ for i in $source; do
+ case $i in
+ *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
+ esac
+ done
+}
+
build () {
cd "$_builddir"
make || return 1
+
+
+ ${CC:-gcc} ${CFLAGS} -o update-ca-certificates "$srcdir"/update-ca.c \
+ ${LDFLAGS} || return 1
}
package() {
@@ -35,6 +45,7 @@ package() {
"$pkgdir"/usr/local/share/ca-certificates \
"$pkgdir"/etc/ssl/certs \
|| return 1
+
make DESTDIR="$pkgdir" install || return 1
install -D -m644 sbin/update-ca-certificates.8 \
"$pkgdir"/usr/share/man/man8/update-ca-certificates.8 \
@@ -50,7 +61,7 @@ package() {
# http://bugs.alpinelinux.org/issues/2715
# http://bugs.alpinelinux.org/issues/2846
- install -m755 "$srcdir"/update-ca-certificates "$pkgdir"/usr/sbin \
+ install -m755 update-ca-certificates "$pkgdir"/usr/sbin \
|| return 1
mkdir -p "$pkgdir"/etc/apk/protected_paths.d
@@ -59,11 +70,20 @@ package() {
-etc/ssl/certs/ca-cert-*.pem
-etc/ssl/certs/[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[r0-9]*
EOF
+
+ cat > "$pkgdir"/etc/ca-certificates/update.d/c_rehash <<EOF
+#!/bin/sh
+exec /usr/bin/c_rehash /etc/ssl/certs
+EOF
+ chmod +x "$pkgdir"/etc/ca-certificates/update.d/c_rehash || return 1
}
-md5sums="f619282081c8bfc65ea64c37fa5285ed ca-certificates_20141019.tar.xz
-0c2fb9aa695d9d857fecd1c236930016 update-ca-certificates"
-sha256sums="684902d3f4e9ad27829f4af0d9d2d588afed03667997579b9c2be86fcd1eb73a ca-certificates_20141019.tar.xz
-b95a80d5881a3ffeea3f36599503a141f9c5a433bc9646d673225658ebc032a1 update-ca-certificates"
-sha512sums="5b0e8fb917f5642a5a2b4fde46a706db0c652ff3fb31a5053d9123a5b670b50c6e3cf2496915cc01c613dcbe964d6432f393c12d8a697baedfad58f9d13e568b ca-certificates_20141019.tar.xz
-ce0e6317af25a5433a4fef28db6afd0ef985089f4a6b9eb13ac1ca454de854ae3de18029fed1e385651317cb237581a38d3792c42f5f30ec12667609d689b4e1 update-ca-certificates"
+md5sums="1a0a3a1b3390dc83affed4b0c2ae1c05 ca-certificates_20161130.tar.xz
+0c3d9f5d795c7475b997e18498b7aec8 fix-manpage.patch
+d7773c690432a56911c0fa97a67bf43e update-ca.c"
+sha256sums="04bca9e142a90a834aca0311f7ced237368d71fee7bd5c9f68ef7f4611aee471 ca-certificates_20161130.tar.xz
+60b36c4881bb367891df038a0736456c2d170496de8c339026671008b1caa09b fix-manpage.patch
+b2231e7f0304d6360350f1f1aa9afad46fe4eeb0f0306a48eeb8cd74501ab26c update-ca.c"
+sha512sums="8395f27d2369d694b069e1bb250b06df05f732bd9f4a4dc8652091e9c96ad1a84003e28f59cb9e13fdfd22ca5818f495d80149692e74b2d63e34db4f6a95ee9f ca-certificates_20161130.tar.xz
+690d6bb434fb3ccce931d7ee6a167124f9c2d2e7e7a016d85f7b72a5f7f7c34db8c6133f3575e962a91981a32a88f8961776fe5fd907e57f59c03a32f2fcced3 fix-manpage.patch
+403c909ea4107d944789b8aae9c911c735ac651cf882bf8468e0f91b3179700a78cabcbec16e3ae0bed730b54d1813d5d0891c1aeae583ad80c7a20b0f425b12 update-ca.c"
diff --git a/main/ca-certificates/fix-manpage.patch b/main/ca-certificates/fix-manpage.patch
new file mode 100644
index 0000000..c4c1290
--- /dev/null
+++ b/main/ca-certificates/fix-manpage.patch
@@ -0,0 +1,13 @@
+--- ./sbin/update-ca-certificates.8.orig 2016-01-14 10:56:42.084504796 +0100
++++ ./sbin/update-ca-certificates.8 2016-01-14 10:57:21.685102125 +0100
+@@ -40,9 +40,7 @@
+ /usr/local/share/ca-certificates are also included as implicitly trusted.
+ .PP
+ Before terminating, \fBupdate-ca-certificates\fP invokes
+-\fBrun-parts\fP on /etc/ca-certificates/update.d and calls each hook with
+-a list of certificates: those added are prefixed with a +, those removed are
+-prefixed with a -.
++\fBrun-parts\fP on /etc/ca-certificates/update.d.
+ .SH OPTIONS
+ A summary of options is included below.
+ .TP
diff --git a/main/ca-certificates/update-ca-certificates b/main/ca-certificates/update-ca-certificates
deleted file mode 100755
index 1780ce5..0000000
--- a/main/ca-certificates/update-ca-certificates
@@ -1,86 +0,0 @@
-#!/usr/bin/lua5.2
-
-local CERTSDIR='/usr/share/ca-certificates/'
-local LOCALCERTSDIR='/usr/local/share/ca-certificates/'
-local ETCCERTSDIR='/etc/ssl/certs/'
-local CERTBUNDLE='ca-certificates.crt'
-local CERTSCONF='/etc/ca-certificates.conf'
-
-local posix = require 'posix'
-function string.begins(str, prefix) return str:sub(1,#prefix)==prefix end
-
-local function add(fn, out, links)
- -- Map fn to file in etc
- local pem = "ca-cert-"..fn:gsub('.*/', ''):gsub('.crt$',''):gsub('[, ]','_'):gsub('[()]','=')..".pem"
- links[pem] = fn
- -- Read the certificate for the bundle
- local f = io.open(fn, "rb")
- if f ~= nil then
- local content = f:read("*all")
- f:close()
- out:write(content)
- if content:sub(-1) ~= '\n' then out:write('\n') end
- end
-end
-
-local calinks = {}
-local cacerts = {}
-
-local fd, tmpfile = posix.mkstemp(ETCCERTSDIR..'bundleXXXXXX')
-if not fd then
- print("Failed to open temporary file for ca bundle")
- return 1
-end
-posix.close(fd)
-posix.chmod(tmpfile, "rw-r--r--")
-local bundle = io.open(tmpfile, "wb")
-
--- Handle global CA certs from config file
-for l in io.lines(CERTSCONF) do
- local firstchar = l:sub(1,1)
- if firstchar ~= "#" and firstchar ~= "!" then
- add(CERTSDIR..l, bundle, calinks)
- end
-end
-
--- Handle local CA certificates
-local certlist = posix.glob(LOCALCERTSDIR..'*.crt')
-if certlist ~= nil then
- table.sort(certlist)
- for _, fn in ipairs(certlist) do
- if posix.stat(fn, 'type') == 'regular' then
- add(fn, bundle, calinks)
- end
- end
-end
-
--- Update etc cert dir for additions and deletions
-local f, target
-for f in posix.files(ETCCERTSDIR) do
- local fn = ETCCERTSDIR..f
- if posix.stat(fn, 'type') == 'link' then
- local curtgt = posix.readlink(fn)
- local target = calinks[f]
- if target == nil then
- -- Symlink exists but is not wanted
- -- Delete it if it points to 'our' directory
- if curtgt:begins(CERTSDIR) or curtgt:begins(LOCALCERTSDIR) then
- os.remove(fn)
- end
- elseif curtgt ~= target then
- -- Symlink exists but points wrong
- posix.link(target, ETCCERTSDIR..f, true)
- else
- -- Symlink exists and is ok
- calinks[f] = nil
- end
- end
-end
-for f, target in pairs(calinks) do
- posix.link(target, ETCCERTSDIR..f, true)
-end
-
--- Update hashes and the bundle
-bundle:close()
-os.rename(tmpfile, ETCCERTSDIR..CERTBUNDLE)
-os.execute("c_rehash "..ETCCERTSDIR.." > /dev/null")
diff --git a/main/ca-certificates/update-ca.c b/main/ca-certificates/update-ca.c
new file mode 100644
index 0000000..20af994
--- /dev/null
+++ b/main/ca-certificates/update-ca.c
@@ -0,0 +1,327 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define CERTSDIR "/usr/share/ca-certificates/"
+#define LOCALCERTSDIR "/usr/local/share/ca-certificates/"
+#define ETCCERTSDIR "/etc/ssl/certs/"
+#define RUNPARTSDIR "/etc/ca-certificates/update.d/"
+#define CERTBUNDLE "ca-certificates.crt"
+#define CERTSCONF "/etc/ca-certificates.conf"
+
+static const char *last_component(const char *path)
+{
+ const char *c = strrchr(path, '/');
+ if (c) return c + 1;
+ return path;
+}
+static bool str_begins(const char* str, const char* prefix)
+{
+ return !strncmp(str, prefix, strlen(prefix));
+}
+
+struct hash_item {
+ struct hash_item *next;
+ char *key;
+ char *value;
+};
+
+struct hash {
+ struct hash_item *items[256];
+};
+
+static unsigned int hash_string(const char *str)
+{
+ unsigned long h = 5381;
+ for (; *str; str++)
+ h = (h << 5) + h + *str;
+ return h;
+}
+
+static void hash_init(struct hash *h)
+{
+ memset(h, 0, sizeof *h);
+}
+
+static struct hash_item *hash_get(struct hash *h, const char *key)
+{
+ unsigned int bucket = hash_string(key) % ARRAY_SIZE(h->items);
+ struct hash_item *item;
+
+ for (item = h->items[bucket]; item; item = item->next)
+ if (strcmp(item->key, key) == 0)
+ return item;
+ return NULL;
+}
+
+static void hash_foreach(struct hash *h, void (*cb)(struct hash_item *))
+{
+ struct hash_item *item;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(h->items); i++) {
+ for (item = h->items[i]; item; item = item->next)
+ cb(item);
+ }
+}
+
+static bool hash_add(struct hash *h, const char *key, const char *value)
+{
+ unsigned int bucket = hash_string(key) % ARRAY_SIZE(h->items);
+ size_t keylen = strlen(key), valuelen = strlen(value);
+ struct hash_item *i;
+
+ i = malloc(sizeof(struct hash_item) + keylen + 1 + valuelen + 1);
+ if (!i)
+ return false;
+
+ i->key = (char*)(i+1);
+ strcpy(i->key, key);
+ i->value = i->key + keylen + 1;
+ strcpy(i->value, value);
+
+ i->next = h->items[bucket];
+ h->items[bucket] = i;
+ return true;
+}
+
+static bool
+copyfile(const char* source, int output)
+{
+ off_t bytes = 0;
+ struct stat fileinfo = {0};
+ ssize_t result;
+ int in_fd;
+
+ if ((in_fd = open(source, O_RDONLY)) == -1)
+ return false;
+
+ if (fstat(in_fd, &fileinfo) < 0) {
+ close(in_fd);
+ return false;
+ }
+
+ result = sendfile(output, in_fd, &bytes, fileinfo.st_size);
+ close(in_fd);
+
+ return fileinfo.st_size == result;
+}
+
+typedef void (*proc_path)(const char *fullpath, struct hash *, int);
+
+static void proc_localglobaldir(const char *fullpath, struct hash *h, int tmpfile_fd)
+{
+ const char *fname = last_component(fullpath);
+ size_t flen = strlen(fname);
+ char *s, *actual_file = NULL;
+
+ /* Snip off the .crt suffix */
+ if (flen > 4 && strcmp(&fname[flen-4], ".crt") == 0)
+ flen -= 4;
+
+ if (asprintf(&actual_file, "%s%.*s%s",
+ "ca-cert-",
+ flen, fname,
+ ".pem") == -1) {
+ fprintf(stderr, "Cannot open path: %s\n", fullpath);
+ return;
+ }
+
+ for (s = actual_file; *s; s++) {
+ switch(*s) {
+ case ',':
+ case ' ':
+ *s = '_';
+ break;
+ case ')':
+ case '(':
+ *s = '=';
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!hash_add(h, actual_file, fullpath))
+ fprintf(stderr, "Warning! Cannot hash: %s\n", fullpath);
+ if (!copyfile(fullpath, tmpfile_fd))
+ fprintf(stderr, "Warning! Cannot copy to bundle: %s\n", fullpath);
+ free(actual_file);
+}
+
+static void proc_etccertsdir(const char* fullpath, struct hash* h, int tmpfile_fd)
+{
+ char linktarget[SYMLINK_MAX];
+ ssize_t linklen;
+
+ linklen = readlink(fullpath, linktarget, sizeof(linktarget)-1);
+ if (linklen < 0)
+ return;
+ linktarget[linklen] = 0;
+
+ struct hash_item *item = hash_get(h, last_component(fullpath));
+ if (!item) {
+ /* Symlink exists but is not wanted
+ * Delete it if it points to 'our' directory
+ */
+ if (str_begins(linktarget, CERTSDIR) || str_begins(linktarget, LOCALCERTSDIR))
+ unlink(fullpath);
+ } else if (strcmp(linktarget, item->value) != 0) {
+ /* Symlink exists but points wrong */
+ unlink(fullpath);
+ if (symlink(item->value, fullpath) < 0)
+ fprintf(stderr, "Warning! Cannot update symlink %s -> %s\n", item->value, fullpath);
+ item->value = 0;
+ } else {
+ /* Symlink exists and is ok */
+ item->value = 0;
+ }
+}
+
+static bool read_global_ca_list(const char* file, struct hash* d, int tmpfile_fd)
+{
+ FILE * fp = fopen(file, "r");
+ if (fp == NULL)
+ return false;
+
+ char * line = NULL;
+ size_t len = 0;
+ ssize_t read;
+
+ while ((read = getline(&line, &len, fp)) != -1) {
+ /* getline returns number of bytes in buffer, and buffer
+ * contains delimeter if it was found */
+ if (read > 0 && line[read-1] == '\n')
+ line[read-1] = 0;
+ if (str_begins(line, "#") || str_begins(line, "!"))
+ continue;
+
+ char* fullpath = 0;
+ if (asprintf(&fullpath,"%s%s", CERTSDIR, line) != -1) {
+ proc_localglobaldir(fullpath, d, tmpfile_fd);
+ free(fullpath);
+ }
+ }
+
+ fclose(fp);
+ free(line);
+ return true;
+}
+
+typedef enum {
+ FILE_LINK,
+ FILE_REGULAR
+} filetype;
+
+static bool is_filetype(const char* path, filetype file_check)
+{
+ struct stat statbuf;
+
+ if (lstat(path, &statbuf) < 0)
+ return false;
+ switch(file_check) {
+ case FILE_LINK: return S_ISLNK(statbuf.st_mode);
+ case FILE_REGULAR: return S_ISREG(statbuf.st_mode);
+ default: break;
+ }
+
+ return false;
+}
+
+static bool dir_readfiles(struct hash* d, const char* path,
+ filetype allowed_file_type,
+ proc_path path_processor,
+ int tmpfile_fd)
+{
+ DIR *dp = opendir(path);
+ if (!dp)
+ return false;
+
+ struct dirent *dirp;
+ while ((dirp = readdir(dp)) != NULL) {
+ if (str_begins(dirp->d_name, "."))
+ continue;
+
+ char* fullpath = 0;
+ if (asprintf(&fullpath, "%s%s", path, dirp->d_name) != -1) {
+ if (is_filetype(fullpath, allowed_file_type))
+ path_processor(fullpath, d, tmpfile_fd);
+
+ free(fullpath);
+ }
+ }
+
+ return closedir(dp) == 0;
+}
+
+static void update_ca_symlink(struct hash_item *item)
+{
+ if (!item->value)
+ return;
+
+ char* newpath = 0;
+ bool build_str = asprintf(&newpath, "%s%s", ETCCERTSDIR, item->key);
+ if (!build_str || symlink(item->value, newpath) == -1)
+ fprintf(stderr, "Warning! Cannot symlink %s -> %s\n",
+ item->value, newpath);
+ free(newpath);
+}
+
+int main(int a, char **v)
+{
+ struct hash _calinks, *calinks = &_calinks;
+
+ const char* bundle = "bundleXXXXXX";
+ char* tmpfile = 0;
+ if (asprintf(&tmpfile, "%s%s", ETCCERTSDIR, bundle) == -1)
+ return 1;
+
+ int fd = mkstemp(tmpfile);
+ if (fd == -1) {
+ fprintf(stderr, "Failed to open temporary file %s for ca bundle\n", tmpfile);
+ return 1;
+ }
+ fchmod(fd, 0644);
+
+ hash_init(calinks);
+
+ /* Handle global CA certs from config file */
+ read_global_ca_list(CERTSCONF, calinks, fd);
+
+ /* Handle local CA certificates */
+ dir_readfiles(calinks, LOCALCERTSDIR, FILE_REGULAR, &proc_localglobaldir, fd);
+
+ /* Update etc cert dir for additions and deletions*/
+ dir_readfiles(calinks, ETCCERTSDIR, FILE_LINK, &proc_etccertsdir, fd);
+ hash_foreach(calinks, update_ca_symlink);
+
+ /* Update hashes and the bundle */
+ if (fd != -1) {
+ close(fd);
+ char* newcertname = 0;
+ if (asprintf(&newcertname, "%s%s", ETCCERTSDIR, CERTBUNDLE) != -1) {
+ rename(tmpfile, newcertname);
+ free(newcertname);
+ }
+ }
+
+ free(tmpfile);
+
+ /* Execute run-parts */
+ static const char *run_parts_args[] = { "run-parts", RUNPARTSDIR, 0 };
+ execve("/usr/bin/run-parts", run_parts_args, NULL);
+ execve("/bin/run-parts", run_parts_args, NULL);
+ perror("run-parts");
+
+ return 1;
+}
--
2.4.11
---
Unsubscribe: alpine-aports+unsubscribe@lists.alpinelinux.org
Help: alpine-aports+help@lists.alpinelinux.org
---