X-Original-To: alpine-aports@lists.alpinelinux.org Received: from mail-lf0-f46.google.com (mail-lf0-f46.google.com [209.85.215.46]) by lists.alpinelinux.org (Postfix) with ESMTP id 3DFD45C4AE9 for ; Fri, 27 Jan 2017 10:05:02 +0000 (GMT) Received: by mail-lf0-f46.google.com with SMTP id x1so72684669lff.0 for ; Fri, 27 Jan 2017 02:05:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=kj/Ogug6hz//GUaOQqh5XocZ2fNHiwZucnmM9DBWuL0=; b=JH60wBJUr2YTGUZm8c4zK+fJiAAn769vSI5/wxqFNVeUJghJrrpLf8vl/sAWICBakM GsAdaIE6/ruAB23vFCA48MRRGFiRJW/90ivZ4Yyt5YBTg1hKSuDFEJXeRqWn3ozC2IQ3 ToeTGXobj41XFTWpgBr6hzJTDu9O6ZpsBwQDxfM9YJn/h3jdSnt6zg47WVDzzsFPLku0 bgI7Iebp7BHS3BQ3GfaqtFG2cHjNUcodW/CY4+Key/7O5eGCQy8UwpPrfppaB7NEenBi 7NQ0NQGBKkLUp8EOg7Nm3octAbexV9J42iSXNf1X1QZC9zqe1T1XaguBEEtOIxM8AeFf oCTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=kj/Ogug6hz//GUaOQqh5XocZ2fNHiwZucnmM9DBWuL0=; b=p+8w9LFmBTcPSWGep0qWY3MG5cYtYDUFVoSXBqydynfx8NZfTmbRkY1jNi7BV8q/Mf McdaijESfQlXSxnWkkTVDayOOXsbE5FSqcTfGAsSWqNJfmU51KcijHzSxVGmZ0PeV6gx uwyqDvJf5pd1yTbA4fNYARmWFAGjymtUPYGhmU1mcWxXJPAJ28vhmczHyEa+Og4a3KFQ oywKBeWnOyhdRxAV1A8dTb1E9h4saTf3BbyeviDvZ/QSnm1icpIUwwDWRaKya2jof6Kb CwqJ5P2uVD7cSbcZ0Ax4lFCNVXU22Tn0TIS7a/S121cPrpJ07k+MxeYu+OYOGe7y81iX OqZQ== X-Gm-Message-State: AIkVDXLejUd/3Fn3CR6MdtN8BRd0dBdBi+WUUt57TZeEezKjtRHxdFMG54MORYLnPDz4zA== X-Received: by 10.46.20.21 with SMTP id u21mr2602976ljd.30.1485511500988; Fri, 27 Jan 2017 02:05:00 -0800 (PST) Received: from v3-2.util.wtbts.net ([83.145.235.199]) by smtp.gmail.com with ESMTPSA id h23sm1185142lfi.6.2017.01.27.02.04.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 27 Jan 2017 02:05:00 -0800 (PST) From: Sergei Lukin To: alpine-aports@lists.alpinelinux.org Cc: Sergei Lukin Subject: [alpine-aports] [PATCH v3.2] main/ca-certificates: security upgrade to 20161130 Date: Fri, 27 Jan 2017 10:04:54 +0000 Message-Id: <1485511494-5523-1-git-send-email-sergej.lukin@gmail.com> X-Mailer: git-send-email 2.4.11 X-Mailinglist: alpine-aports Precedence: list List-Id: Alpine Development List-Unsubscribe: List-Post: List-Help: List-Subscribe: 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 # Maintainer: Natanael Copa 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 < /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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 ---