diff --git a/0001-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch b/0001-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch new file mode 100644 index 0000000..07d6ba4 --- /dev/null +++ b/0001-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch @@ -0,0 +1,447 @@ +From 6d6644d52d8092dd4f4add859ebda06bea4b5b56 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Fri, 31 Oct 2014 11:02:33 +0000 +Subject: [PATCH] launch: libvirt: Implement drive secrets (RHBZ#1159016). + +Implement the GUESTFS_ADD_DRIVE_OPTS_SECRET argument of +guestfs_add_drive_opts. For libvirt we have to save the secret in +libvirtd first, get a UUID, and then pass the UUID back through the +domain XML. +--- + bootstrap | 1 + + generator/actions.ml | 2 +- + m4/.gitignore | 7 +- + src/launch-libvirt.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++- + 4 files changed, 275 insertions(+), 7 deletions(-) + +diff --git a/bootstrap b/bootstrap +index 402ac4e..292f454 100755 +--- a/bootstrap ++++ b/bootstrap +@@ -41,6 +41,7 @@ accept4 + areadlink + areadlinkat + arpa_inet ++base64 + byteswap + c-ctype + cloexec +diff --git a/generator/actions.ml b/generator/actions.ml +index ece3f88..83f4734 100644 +--- a/generator/actions.ml ++++ b/generator/actions.ml +@@ -1494,7 +1494,7 @@ specify the remote username you want. + =item C + + For the C protocol only, this specifies the 'secret' to use when +-connecting to the remote device. ++connecting to the remote device. It must be base64 encoded. + + If not given, then a secret matching the given username will be looked up in the + default keychain locations, or if no username is given, then no authentication +diff --git a/m4/.gitignore b/m4/.gitignore +index 605cd26..b0f8d4b 100644 +--- a/m4/.gitignore ++++ b/m4/.gitignore +@@ -5,6 +5,7 @@ + /argmatch.m4 + /arpa_inet_h.m4 + /asm-underscore.m4 ++/base64.m4 + /btowc.m4 + /byteswap.m4 + /canonicalize-lgpl.m4 +@@ -104,6 +105,7 @@ + /inttypes-pri.m4 + /ioctl.m4 + /i-ring.m4 ++/isatty.m4 + /isc-posix.m4 + /largefile.m4 + /lchown.m4 +@@ -166,6 +168,7 @@ + /printf-posix.m4 + /priv-set.m4 + /progtest.m4 ++/ptsname_r.m4 + /putenv.m4 + /quotearg.m4 + /quote.m4 +@@ -236,6 +239,7 @@ + /thread.m4 + /time_h.m4 + /timespec.m4 ++/ttyname_r.m4 + /uintmax_t.m4 + /ulonglong.m4 + /ungetc.m4 +@@ -271,6 +275,3 @@ + /xstrtol.m4 + /xvasprintf.m4 + /yield.m4 +-/isatty.m4 +-/ptsname_r.m4 +-/ttyname_r.m4 +diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c +index 7206b33..26d3202 100644 +--- a/src/launch-libvirt.c ++++ b/src/launch-libvirt.c +@@ -50,6 +50,7 @@ + #endif + + #include "glthread/lock.h" ++#include "base64.h" + + #include "guestfs.h" + #include "guestfs-internal.h" +@@ -97,6 +98,27 @@ xmlBufferDetach (xmlBufferPtr buf) + } + #endif + ++#ifdef HAVE_ATTRIBUTE_CLEANUP ++#define CLEANUP_VIRSECRETFREE __attribute__((cleanup(cleanup_virSecretFree))) ++ ++static void ++cleanup_virSecretFree (void *ptr) ++{ ++ virSecretPtr secret_obj = * (virSecretPtr *) ptr; ++ if (secret_obj) ++ virSecretFree (secret_obj); ++} ++ ++#else /* !HAVE_ATTRIBUTE_CLEANUP */ ++#define CLEANUP_VIRSECRETFREE ++#endif ++ ++/* List used to store a mapping of secret to libvirt secret UUID. */ ++struct secret { ++ char *secret; ++ char uuid[VIR_UUID_STRING_BUFLEN]; ++}; ++ + #define DOMAIN_NAME_LEN (8+16+1) /* "guestfs-" + random + \0 */ + + /* Per-handle data. */ +@@ -110,6 +132,8 @@ struct backend_libvirt_data { + char name[DOMAIN_NAME_LEN]; /* random name */ + bool is_kvm; /* false = qemu, true = kvm (from capabilities)*/ + unsigned long qemu_version; /* qemu version (from libvirt) */ ++ struct secret *secrets; /* list of secrets */ ++ size_t nr_secrets; + }; + + /* Parameters passed to construct_libvirt_xml and subfunctions. We +@@ -130,6 +154,9 @@ struct libvirt_xml_params { + }; + + static int parse_capabilities (guestfs_h *g, const char *capabilities_xml, struct backend_libvirt_data *data); ++static int add_secret (guestfs_h *g, virConnectPtr conn, struct backend_libvirt_data *data, const struct drive *drv); ++static int find_secret (guestfs_h *g, const struct backend_libvirt_data *data, const struct drive *drv, const char **type, const char **uuid); ++static int have_secret (guestfs_h *g, const struct backend_libvirt_data *data, const struct drive *drv); + static xmlChar *construct_libvirt_xml (guestfs_h *g, const struct libvirt_xml_params *params); + static void debug_appliance_permissions (guestfs_h *g); + static void debug_socket_permissions (guestfs_h *g); +@@ -224,6 +251,8 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + CLEANUP_FREE xmlChar *xml = NULL; + CLEANUP_FREE char *appliance = NULL; + struct sockaddr_un addr; ++ struct drive *drv; ++ size_t i; + int r; + uint32_t size; + CLEANUP_FREE void *buf = NULL; +@@ -458,6 +487,14 @@ launch_libvirt (guestfs_h *g, void *datav, const char *libvirt_uri) + debug (g, "cannot find group 'qemu'"); + } + ++ /* Store any secrets in libvirtd, keeping a mapping from the secret ++ * to its UUID. ++ */ ++ ITER_DRIVES (g, i, drv) { ++ if (add_secret (g, conn, data, drv) == -1) ++ goto cleanup; ++ } ++ + /* Construct the libvirt XML. */ + if (g->verbose) + guestfs___print_timestamped_message (g, "create libvirt XML"); +@@ -1272,6 +1309,8 @@ construct_libvirt_xml_disk (guestfs_h *g, + CLEANUP_FREE char *path = NULL; + int is_host_device; + CLEANUP_FREE char *format = NULL; ++ const char *type, *uuid; ++ int r; + + /* XXX We probably could support this if we thought about it some more. */ + if (drv->iface) { +@@ -1383,9 +1422,15 @@ construct_libvirt_xml_disk (guestfs_h *g, + if (drv->src.username != NULL) { + start_element ("auth") { + attribute ("username", drv->src.username); +- /* TODO: write the drive secret, after first storing it separately +- * in libvirt +- */ ++ r = find_secret (g, data, drv, &type, &uuid); ++ if (r == -1) ++ return -1; ++ if (r == 1) { ++ start_element ("secret") { ++ attribute ("type", type); ++ attribute ("uuid", uuid); ++ } end_element (); ++ } + } end_element (); + } + break; +@@ -1657,6 +1702,216 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, + } + + static int ++construct_libvirt_xml_secret (guestfs_h *g, ++ const struct backend_libvirt_data *data, ++ const struct drive *drv, ++ xmlTextWriterPtr xo) ++{ ++ start_element ("secret") { ++ attribute ("ephemeral", "yes"); ++ attribute ("private", "yes"); ++ start_element ("description") { ++ string_format ("guestfs secret associated with %s %s", ++ data->name, drv->src.u.path); ++ } end_element (); ++ } end_element (); ++ ++ return 0; ++} ++ ++/* If drv->src.secret != NULL, store the secret in libvirt, and save ++ * the UUID so we can retrieve it later. Also there is some slight ++ * variation depending on the protocol. See ++ * http://libvirt.org/formatsecret.html ++ */ ++static int ++add_secret (guestfs_h *g, virConnectPtr conn, ++ struct backend_libvirt_data *data, const struct drive *drv) ++{ ++ CLEANUP_XMLBUFFERFREE xmlBufferPtr xb = NULL; ++ xmlOutputBufferPtr ob; ++ CLEANUP_XMLFREETEXTWRITER xmlTextWriterPtr xo = NULL; ++ CLEANUP_FREE xmlChar *xml = NULL; ++ CLEANUP_VIRSECRETFREE virSecretPtr secret_obj = NULL; ++ const char *secret = drv->src.secret; ++ CLEANUP_FREE unsigned char *secret_raw = NULL; ++ size_t secret_raw_len = 0; ++ size_t i; ++ ++ if (secret == NULL) ++ return 0; ++ ++ /* If it was already stored, don't create another secret. */ ++ if (have_secret (g, data, drv)) ++ return 0; ++ ++ /* Create the XML for the secret. */ ++ xb = xmlBufferCreate (); ++ if (xb == NULL) { ++ perrorf (g, "xmlBufferCreate"); ++ return -1; ++ } ++ ob = xmlOutputBufferCreateBuffer (xb, NULL); ++ if (ob == NULL) { ++ perrorf (g, "xmlOutputBufferCreateBuffer"); ++ return -1; ++ } ++ xo = xmlNewTextWriter (ob); ++ if (xo == NULL) { ++ perrorf (g, "xmlNewTextWriter"); ++ return -1; ++ } ++ ++ if (xmlTextWriterSetIndent (xo, 1) == -1 || ++ xmlTextWriterSetIndentString (xo, BAD_CAST " ") == -1) { ++ perrorf (g, "could not set XML indent"); ++ return -1; ++ } ++ if (xmlTextWriterStartDocument (xo, NULL, NULL, NULL) == -1) { ++ perrorf (g, "xmlTextWriterStartDocument"); ++ return -1; ++ } ++ ++ if (construct_libvirt_xml_secret (g, data, drv, xo) == -1) ++ return -1; ++ ++ if (xmlTextWriterEndDocument (xo) == -1) { ++ perrorf (g, "xmlTextWriterEndDocument"); ++ return -1; ++ } ++ xml = xmlBufferDetach (xb); ++ if (xml == NULL) { ++ perrorf (g, "xmlBufferDetach"); ++ return -1; ++ } ++ ++ debug (g, "libvirt secret XML:\n%s", xml); ++ ++ /* Pass the XML to libvirt. */ ++ secret_obj = virSecretDefineXML (conn, (const char *) xml, 0); ++ if (secret_obj == NULL) { ++ libvirt_error (g, _("could not define libvirt secret")); ++ return -1; ++ } ++ ++ /* For Ceph, we have to base64 decode the secret. For others, we ++ * currently just pass the secret straight through. ++ */ ++ switch (drv->src.protocol) { ++ case drive_protocol_rbd: ++ if (!base64_decode_alloc (secret, strlen (secret), ++ (char **) &secret_raw, &secret_raw_len)) { ++ error (g, _("rbd protocol secret must be base64 encoded")); ++ return -1; ++ } ++ if (secret_raw == NULL) { ++ error (g, _("base64_decode_alloc: %m")); ++ return -1; ++ } ++ break; ++ case drive_protocol_file: ++ case drive_protocol_ftp: ++ case drive_protocol_ftps: ++ case drive_protocol_gluster: ++ case drive_protocol_http: ++ case drive_protocol_https: ++ case drive_protocol_iscsi: ++ case drive_protocol_nbd: ++ case drive_protocol_sheepdog: ++ case drive_protocol_ssh: ++ case drive_protocol_tftp: ++ secret_raw = (unsigned char *) safe_strdup (g, secret); ++ secret_raw_len = strlen (secret); ++ } ++ ++ /* Set the secret. */ ++ if (virSecretSetValue (secret_obj, secret_raw, secret_raw_len, 0) == -1) { ++ libvirt_error (g, _("could not set libvirt secret value")); ++ return -1; ++ } ++ ++ /* Get back the UUID and save it in the private data. */ ++ i = data->nr_secrets; ++ data->nr_secrets++; ++ data->secrets = ++ safe_realloc (g, data->secrets, sizeof (struct secret) * data->nr_secrets); ++ ++ data->secrets[i].secret = safe_strdup (g, secret); ++ ++ if (virSecretGetUUIDString (secret_obj, data->secrets[i].uuid) == -1) { ++ libvirt_error (g, _("could not get UUID from libvirt secret")); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++have_secret (guestfs_h *g, ++ const struct backend_libvirt_data *data, const struct drive *drv) ++{ ++ size_t i; ++ ++ if (drv->src.secret == NULL) ++ return 0; ++ ++ for (i = 0; i < data->nr_secrets; ++i) { ++ if (STREQ (data->secrets[i].secret, drv->src.secret)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Find a secret previously stored in libvirt. Returns the ++ * attributes. This function returns -1 ++ * if there was an error, 0 if there is no secret, and 1 if the ++ * secret was found and returned. ++ */ ++static int ++find_secret (guestfs_h *g, ++ const struct backend_libvirt_data *data, const struct drive *drv, ++ const char **type, const char **uuid) ++{ ++ size_t i; ++ ++ if (drv->src.secret == NULL) ++ return 0; ++ ++ for (i = 0; i < data->nr_secrets; ++i) { ++ if (STREQ (data->secrets[i].secret, drv->src.secret)) { ++ *uuid = data->secrets[i].uuid; ++ ++ *type = "volume"; ++ ++ switch (drv->src.protocol) { ++ case drive_protocol_rbd: ++ *type = "ceph"; ++ break; ++ case drive_protocol_iscsi: ++ *type = "iscsi"; ++ break; ++ case drive_protocol_file: ++ case drive_protocol_ftp: ++ case drive_protocol_ftps: ++ case drive_protocol_gluster: ++ case drive_protocol_http: ++ case drive_protocol_https: ++ case drive_protocol_nbd: ++ case drive_protocol_sheepdog: ++ case drive_protocol_ssh: ++ case drive_protocol_tftp: ++ /* set to a default value above */ ; ++ } ++ ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int + is_blk (const char *path) + { + struct stat statbuf; +@@ -1678,6 +1933,7 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) + struct backend_libvirt_data *data = datav; + virConnectPtr conn = data->conn; + virDomainPtr dom = data->dom; ++ size_t i; + int ret = 0; + int flags; + +@@ -1710,6 +1966,12 @@ shutdown_libvirt (guestfs_h *g, void *datav, int check_for_errors) + free (data->network_bridge); + data->network_bridge = NULL; + ++ for (i = 0; i < data->nr_secrets; ++i) ++ free (data->secrets[i].secret); ++ free (data->secrets); ++ data->secrets = NULL; ++ data->nr_secrets = 0; ++ + return ret; + } + +@@ -1814,6 +2076,10 @@ hot_add_drive_libvirt (guestfs_h *g, void *datav, + return -1; + } + ++ /* If the drive has an associated secret, store it in libvirt. */ ++ if (add_secret (g, conn, data, drv) == -1) ++ return -1; ++ + /* Create the XML for the new disk. */ + xml = construct_libvirt_xml_hot_add_disk (g, data, drv, drv_index); + if (xml == NULL) +-- +2.0.4 + diff --git a/add-base64-to-gnulib.patch b/add-base64-to-gnulib.patch new file mode 100644 index 0000000..1e894de --- /dev/null +++ b/add-base64-to-gnulib.patch @@ -0,0 +1,1041 @@ +diff -urN libguestfs-1.28.2.old/aclocal.m4 libguestfs-1.28.2/aclocal.m4 +--- libguestfs-1.28.2.old/aclocal.m4 2014-10-27 14:46:56.000000000 +0000 ++++ libguestfs-1.28.2/aclocal.m4 2014-10-31 22:11:26.000000000 +0000 +@@ -1367,6 +1367,7 @@ + m4_include([m4/accept4.m4]) + m4_include([m4/alloca.m4]) + m4_include([m4/arpa_inet_h.m4]) ++m4_include([m4/base64.m4]) + m4_include([m4/btowc.m4]) + m4_include([m4/byteswap.m4]) + m4_include([m4/chdir-long.m4]) +diff -urN libguestfs-1.28.2.old/gnulib/lib/base64.c libguestfs-1.28.2/gnulib/lib/base64.c +--- libguestfs-1.28.2.old/gnulib/lib/base64.c 1970-01-01 01:00:00.000000000 +0100 ++++ libguestfs-1.28.2/gnulib/lib/base64.c 2014-10-31 21:57:50.000000000 +0000 +@@ -0,0 +1,605 @@ ++/* base64.c -- Encode binary data using printable characters. ++ Copyright (C) 1999-2001, 2004-2006, 2009-2014 Free Software Foundation, Inc. ++ ++ This program 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, or (at your option) ++ any later version. ++ ++ This program 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 . */ ++ ++/* Written by Simon Josefsson. Partially adapted from GNU MailUtils ++ * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review ++ * from Paul Eggert, Bruno Haible, and Stepan Kasal. ++ * ++ * See also RFC 4648 . ++ * ++ * Be careful with error checking. Here is how you would typically ++ * use these functions: ++ * ++ * bool ok = base64_decode_alloc (in, inlen, &out, &outlen); ++ * if (!ok) ++ * FAIL: input was not valid base64 ++ * if (out == NULL) ++ * FAIL: memory allocation error ++ * OK: data in OUT/OUTLEN ++ * ++ * size_t outlen = base64_encode_alloc (in, inlen, &out); ++ * if (out == NULL && outlen == 0 && inlen != 0) ++ * FAIL: input too long ++ * if (out == NULL) ++ * FAIL: memory allocation error ++ * OK: data in OUT/OUTLEN. ++ * ++ */ ++ ++#include ++ ++/* Get prototype. */ ++#include "base64.h" ++ ++/* Get malloc. */ ++#include ++ ++/* Get UCHAR_MAX. */ ++#include ++ ++#include ++ ++/* C89 compliant way to cast 'char' to 'unsigned char'. */ ++static unsigned char ++to_uchar (char ch) ++{ ++ return ch; ++} ++ ++static const char b64c[64] = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; ++ ++/* Base64 encode IN array of size INLEN into OUT array. OUT needs ++ to be of length >= BASE64_LENGTH(INLEN), and INLEN needs to be ++ a multiple of 3. */ ++static void ++base64_encode_fast (const char *restrict in, size_t inlen, char *restrict out) ++{ ++ while (inlen) ++ { ++ *out++ = b64c[to_uchar (in[0]) >> 2]; ++ *out++ = b64c[((to_uchar (in[0]) << 4) + (to_uchar (in[1]) >> 4)) & 0x3f]; ++ *out++ = b64c[((to_uchar (in[1]) << 2) + (to_uchar (in[2]) >> 6)) & 0x3f]; ++ *out++ = b64c[to_uchar (in[2]) & 0x3f]; ++ ++ inlen -= 3; ++ in += 3; ++ } ++} ++ ++/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN. ++ If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as ++ possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero ++ terminate the output buffer. */ ++void ++base64_encode (const char *restrict in, size_t inlen, ++ char *restrict out, size_t outlen) ++{ ++ /* Note this outlen constraint can be enforced at compile time. ++ I.E. that the output buffer is exactly large enough to hold ++ the encoded inlen bytes. The inlen constraints (of corresponding ++ to outlen, and being a multiple of 3) can change at runtime ++ at the end of input. However the common case when reading ++ large inputs is to have both constraints satisfied, so we depend ++ on both in base_encode_fast(). */ ++ if (outlen % 4 == 0 && inlen == outlen / 4 * 3) ++ { ++ base64_encode_fast (in, inlen, out); ++ return; ++ } ++ ++ while (inlen && outlen) ++ { ++ *out++ = b64c[to_uchar (in[0]) >> 2]; ++ if (!--outlen) ++ break; ++ *out++ = b64c[((to_uchar (in[0]) << 4) ++ + (--inlen ? to_uchar (in[1]) >> 4 : 0)) ++ & 0x3f]; ++ if (!--outlen) ++ break; ++ *out++ = ++ (inlen ++ ? b64c[((to_uchar (in[1]) << 2) ++ + (--inlen ? to_uchar (in[2]) >> 6 : 0)) ++ & 0x3f] ++ : '='); ++ if (!--outlen) ++ break; ++ *out++ = inlen ? b64c[to_uchar (in[2]) & 0x3f] : '='; ++ if (!--outlen) ++ break; ++ if (inlen) ++ inlen--; ++ if (inlen) ++ in += 3; ++ } ++ ++ if (outlen) ++ *out = '\0'; ++} ++ ++/* Allocate a buffer and store zero terminated base64 encoded data ++ from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e., ++ the length of the encoded data, excluding the terminating zero. On ++ return, the OUT variable will hold a pointer to newly allocated ++ memory that must be deallocated by the caller. If output string ++ length would overflow, 0 is returned and OUT is set to NULL. If ++ memory allocation failed, OUT is set to NULL, and the return value ++ indicates length of the requested memory block, i.e., ++ BASE64_LENGTH(inlen) + 1. */ ++size_t ++base64_encode_alloc (const char *in, size_t inlen, char **out) ++{ ++ size_t outlen = 1 + BASE64_LENGTH (inlen); ++ ++ /* Check for overflow in outlen computation. ++ * ++ * If there is no overflow, outlen >= inlen. ++ * ++ * If the operation (inlen + 2) overflows then it yields at most +1, so ++ * outlen is 0. ++ * ++ * If the multiplication overflows, we lose at least half of the ++ * correct value, so the result is < ((inlen + 2) / 3) * 2, which is ++ * less than (inlen + 2) * 0.66667, which is less than inlen as soon as ++ * (inlen > 4). ++ */ ++ if (inlen > outlen) ++ { ++ *out = NULL; ++ return 0; ++ } ++ ++ *out = malloc (outlen); ++ if (!*out) ++ return outlen; ++ ++ base64_encode (in, inlen, *out, outlen); ++ ++ return outlen - 1; ++} ++ ++/* With this approach this file works independent of the charset used ++ (think EBCDIC). However, it does assume that the characters in the ++ Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX ++ 1003.1-2001 require that char and unsigned char are 8-bit ++ quantities, though, taking care of that problem. But this may be a ++ potential problem on non-POSIX C99 platforms. ++ ++ IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_" ++ as the formal parameter rather than "x". */ ++#define B64(_) \ ++ ((_) == 'A' ? 0 \ ++ : (_) == 'B' ? 1 \ ++ : (_) == 'C' ? 2 \ ++ : (_) == 'D' ? 3 \ ++ : (_) == 'E' ? 4 \ ++ : (_) == 'F' ? 5 \ ++ : (_) == 'G' ? 6 \ ++ : (_) == 'H' ? 7 \ ++ : (_) == 'I' ? 8 \ ++ : (_) == 'J' ? 9 \ ++ : (_) == 'K' ? 10 \ ++ : (_) == 'L' ? 11 \ ++ : (_) == 'M' ? 12 \ ++ : (_) == 'N' ? 13 \ ++ : (_) == 'O' ? 14 \ ++ : (_) == 'P' ? 15 \ ++ : (_) == 'Q' ? 16 \ ++ : (_) == 'R' ? 17 \ ++ : (_) == 'S' ? 18 \ ++ : (_) == 'T' ? 19 \ ++ : (_) == 'U' ? 20 \ ++ : (_) == 'V' ? 21 \ ++ : (_) == 'W' ? 22 \ ++ : (_) == 'X' ? 23 \ ++ : (_) == 'Y' ? 24 \ ++ : (_) == 'Z' ? 25 \ ++ : (_) == 'a' ? 26 \ ++ : (_) == 'b' ? 27 \ ++ : (_) == 'c' ? 28 \ ++ : (_) == 'd' ? 29 \ ++ : (_) == 'e' ? 30 \ ++ : (_) == 'f' ? 31 \ ++ : (_) == 'g' ? 32 \ ++ : (_) == 'h' ? 33 \ ++ : (_) == 'i' ? 34 \ ++ : (_) == 'j' ? 35 \ ++ : (_) == 'k' ? 36 \ ++ : (_) == 'l' ? 37 \ ++ : (_) == 'm' ? 38 \ ++ : (_) == 'n' ? 39 \ ++ : (_) == 'o' ? 40 \ ++ : (_) == 'p' ? 41 \ ++ : (_) == 'q' ? 42 \ ++ : (_) == 'r' ? 43 \ ++ : (_) == 's' ? 44 \ ++ : (_) == 't' ? 45 \ ++ : (_) == 'u' ? 46 \ ++ : (_) == 'v' ? 47 \ ++ : (_) == 'w' ? 48 \ ++ : (_) == 'x' ? 49 \ ++ : (_) == 'y' ? 50 \ ++ : (_) == 'z' ? 51 \ ++ : (_) == '0' ? 52 \ ++ : (_) == '1' ? 53 \ ++ : (_) == '2' ? 54 \ ++ : (_) == '3' ? 55 \ ++ : (_) == '4' ? 56 \ ++ : (_) == '5' ? 57 \ ++ : (_) == '6' ? 58 \ ++ : (_) == '7' ? 59 \ ++ : (_) == '8' ? 60 \ ++ : (_) == '9' ? 61 \ ++ : (_) == '+' ? 62 \ ++ : (_) == '/' ? 63 \ ++ : -1) ++ ++static const signed char b64[0x100] = { ++ B64 (0), B64 (1), B64 (2), B64 (3), ++ B64 (4), B64 (5), B64 (6), B64 (7), ++ B64 (8), B64 (9), B64 (10), B64 (11), ++ B64 (12), B64 (13), B64 (14), B64 (15), ++ B64 (16), B64 (17), B64 (18), B64 (19), ++ B64 (20), B64 (21), B64 (22), B64 (23), ++ B64 (24), B64 (25), B64 (26), B64 (27), ++ B64 (28), B64 (29), B64 (30), B64 (31), ++ B64 (32), B64 (33), B64 (34), B64 (35), ++ B64 (36), B64 (37), B64 (38), B64 (39), ++ B64 (40), B64 (41), B64 (42), B64 (43), ++ B64 (44), B64 (45), B64 (46), B64 (47), ++ B64 (48), B64 (49), B64 (50), B64 (51), ++ B64 (52), B64 (53), B64 (54), B64 (55), ++ B64 (56), B64 (57), B64 (58), B64 (59), ++ B64 (60), B64 (61), B64 (62), B64 (63), ++ B64 (64), B64 (65), B64 (66), B64 (67), ++ B64 (68), B64 (69), B64 (70), B64 (71), ++ B64 (72), B64 (73), B64 (74), B64 (75), ++ B64 (76), B64 (77), B64 (78), B64 (79), ++ B64 (80), B64 (81), B64 (82), B64 (83), ++ B64 (84), B64 (85), B64 (86), B64 (87), ++ B64 (88), B64 (89), B64 (90), B64 (91), ++ B64 (92), B64 (93), B64 (94), B64 (95), ++ B64 (96), B64 (97), B64 (98), B64 (99), ++ B64 (100), B64 (101), B64 (102), B64 (103), ++ B64 (104), B64 (105), B64 (106), B64 (107), ++ B64 (108), B64 (109), B64 (110), B64 (111), ++ B64 (112), B64 (113), B64 (114), B64 (115), ++ B64 (116), B64 (117), B64 (118), B64 (119), ++ B64 (120), B64 (121), B64 (122), B64 (123), ++ B64 (124), B64 (125), B64 (126), B64 (127), ++ B64 (128), B64 (129), B64 (130), B64 (131), ++ B64 (132), B64 (133), B64 (134), B64 (135), ++ B64 (136), B64 (137), B64 (138), B64 (139), ++ B64 (140), B64 (141), B64 (142), B64 (143), ++ B64 (144), B64 (145), B64 (146), B64 (147), ++ B64 (148), B64 (149), B64 (150), B64 (151), ++ B64 (152), B64 (153), B64 (154), B64 (155), ++ B64 (156), B64 (157), B64 (158), B64 (159), ++ B64 (160), B64 (161), B64 (162), B64 (163), ++ B64 (164), B64 (165), B64 (166), B64 (167), ++ B64 (168), B64 (169), B64 (170), B64 (171), ++ B64 (172), B64 (173), B64 (174), B64 (175), ++ B64 (176), B64 (177), B64 (178), B64 (179), ++ B64 (180), B64 (181), B64 (182), B64 (183), ++ B64 (184), B64 (185), B64 (186), B64 (187), ++ B64 (188), B64 (189), B64 (190), B64 (191), ++ B64 (192), B64 (193), B64 (194), B64 (195), ++ B64 (196), B64 (197), B64 (198), B64 (199), ++ B64 (200), B64 (201), B64 (202), B64 (203), ++ B64 (204), B64 (205), B64 (206), B64 (207), ++ B64 (208), B64 (209), B64 (210), B64 (211), ++ B64 (212), B64 (213), B64 (214), B64 (215), ++ B64 (216), B64 (217), B64 (218), B64 (219), ++ B64 (220), B64 (221), B64 (222), B64 (223), ++ B64 (224), B64 (225), B64 (226), B64 (227), ++ B64 (228), B64 (229), B64 (230), B64 (231), ++ B64 (232), B64 (233), B64 (234), B64 (235), ++ B64 (236), B64 (237), B64 (238), B64 (239), ++ B64 (240), B64 (241), B64 (242), B64 (243), ++ B64 (244), B64 (245), B64 (246), B64 (247), ++ B64 (248), B64 (249), B64 (250), B64 (251), ++ B64 (252), B64 (253), B64 (254), B64 (255) ++}; ++ ++#if UCHAR_MAX == 255 ++# define uchar_in_range(c) true ++#else ++# define uchar_in_range(c) ((c) <= 255) ++#endif ++ ++/* Return true if CH is a character from the Base64 alphabet, and ++ false otherwise. Note that '=' is padding and not considered to be ++ part of the alphabet. */ ++bool ++isbase64 (char ch) ++{ ++ return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)]; ++} ++ ++/* Initialize decode-context buffer, CTX. */ ++void ++base64_decode_ctx_init (struct base64_decode_context *ctx) ++{ ++ ctx->i = 0; ++} ++ ++/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and ++ none of those four is a newline, then return *IN. Otherwise, copy up to ++ 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at ++ index CTX->i and setting CTX->i to reflect the number of bytes copied, ++ and return CTX->buf. In either case, advance *IN to point to the byte ++ after the last one processed, and set *N_NON_NEWLINE to the number of ++ verified non-newline bytes accessible through the returned pointer. */ ++static char * ++get_4 (struct base64_decode_context *ctx, ++ char const *restrict *in, char const *restrict in_end, ++ size_t *n_non_newline) ++{ ++ if (ctx->i == 4) ++ ctx->i = 0; ++ ++ if (ctx->i == 0) ++ { ++ char const *t = *in; ++ if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL) ++ { ++ /* This is the common case: no newline. */ ++ *in += 4; ++ *n_non_newline = 4; ++ return (char *) t; ++ } ++ } ++ ++ { ++ /* Copy non-newline bytes into BUF. */ ++ char const *p = *in; ++ while (p < in_end) ++ { ++ char c = *p++; ++ if (c != '\n') ++ { ++ ctx->buf[ctx->i++] = c; ++ if (ctx->i == 4) ++ break; ++ } ++ } ++ ++ *in = p; ++ *n_non_newline = ctx->i; ++ return ctx->buf; ++ } ++} ++ ++#define return_false \ ++ do \ ++ { \ ++ *outp = out; \ ++ return false; \ ++ } \ ++ while (false) ++ ++/* Decode up to four bytes of base64-encoded data, IN, of length INLEN ++ into the output buffer, *OUT, of size *OUTLEN bytes. Return true if ++ decoding is successful, false otherwise. If *OUTLEN is too small, ++ as many bytes as possible are written to *OUT. On return, advance ++ *OUT to point to the byte after the last one written, and decrement ++ *OUTLEN to reflect the number of bytes remaining in *OUT. */ ++static bool ++decode_4 (char const *restrict in, size_t inlen, ++ char *restrict *outp, size_t *outleft) ++{ ++ char *out = *outp; ++ if (inlen < 2) ++ return false; ++ ++ if (!isbase64 (in[0]) || !isbase64 (in[1])) ++ return false; ++ ++ if (*outleft) ++ { ++ *out++ = ((b64[to_uchar (in[0])] << 2) ++ | (b64[to_uchar (in[1])] >> 4)); ++ --*outleft; ++ } ++ ++ if (inlen == 2) ++ return_false; ++ ++ if (in[2] == '=') ++ { ++ if (inlen != 4) ++ return_false; ++ ++ if (in[3] != '=') ++ return_false; ++ } ++ else ++ { ++ if (!isbase64 (in[2])) ++ return_false; ++ ++ if (*outleft) ++ { ++ *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0) ++ | (b64[to_uchar (in[2])] >> 2)); ++ --*outleft; ++ } ++ ++ if (inlen == 3) ++ return_false; ++ ++ if (in[3] == '=') ++ { ++ if (inlen != 4) ++ return_false; ++ } ++ else ++ { ++ if (!isbase64 (in[3])) ++ return_false; ++ ++ if (*outleft) ++ { ++ *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0) ++ | b64[to_uchar (in[3])]); ++ --*outleft; ++ } ++ } ++ } ++ ++ *outp = out; ++ return true; ++} ++ ++/* Decode base64-encoded input array IN of length INLEN to output array ++ OUT that can hold *OUTLEN bytes. The input data may be interspersed ++ with newlines. Return true if decoding was successful, i.e. if the ++ input was valid base64 data, false otherwise. If *OUTLEN is too ++ small, as many bytes as possible will be written to OUT. On return, ++ *OUTLEN holds the length of decoded bytes in OUT. Note that as soon ++ as any non-alphabet, non-newline character is encountered, decoding ++ is stopped and false is returned. If INLEN is zero, then process ++ only whatever data is stored in CTX. ++ ++ Initially, CTX must have been initialized via base64_decode_ctx_init. ++ Subsequent calls to this function must reuse whatever state is recorded ++ in that buffer. It is necessary for when a quadruple of base64 input ++ bytes spans two input buffers. ++ ++ If CTX is NULL then newlines are treated as garbage and the input ++ buffer is processed as a unit. */ ++ ++bool ++base64_decode_ctx (struct base64_decode_context *ctx, ++ const char *restrict in, size_t inlen, ++ char *restrict out, size_t *outlen) ++{ ++ size_t outleft = *outlen; ++ bool ignore_newlines = ctx != NULL; ++ bool flush_ctx = false; ++ unsigned int ctx_i = 0; ++ ++ if (ignore_newlines) ++ { ++ ctx_i = ctx->i; ++ flush_ctx = inlen == 0; ++ } ++ ++ ++ while (true) ++ { ++ size_t outleft_save = outleft; ++ if (ctx_i == 0 && !flush_ctx) ++ { ++ while (true) ++ { ++ /* Save a copy of outleft, in case we need to re-parse this ++ block of four bytes. */ ++ outleft_save = outleft; ++ if (!decode_4 (in, inlen, &out, &outleft)) ++ break; ++ ++ in += 4; ++ inlen -= 4; ++ } ++ } ++ ++ if (inlen == 0 && !flush_ctx) ++ break; ++ ++ /* Handle the common case of 72-byte wrapped lines. ++ This also handles any other multiple-of-4-byte wrapping. */ ++ if (inlen && *in == '\n' && ignore_newlines) ++ { ++ ++in; ++ --inlen; ++ continue; ++ } ++ ++ /* Restore OUT and OUTLEFT. */ ++ out -= outleft_save - outleft; ++ outleft = outleft_save; ++ ++ { ++ char const *in_end = in + inlen; ++ char const *non_nl; ++ ++ if (ignore_newlines) ++ non_nl = get_4 (ctx, &in, in_end, &inlen); ++ else ++ non_nl = in; /* Might have nl in this case. */ ++ ++ /* If the input is empty or consists solely of newlines (0 non-newlines), ++ then we're done. Likewise if there are fewer than 4 bytes when not ++ flushing context and not treating newlines as garbage. */ ++ if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines)) ++ { ++ inlen = 0; ++ break; ++ } ++ if (!decode_4 (non_nl, inlen, &out, &outleft)) ++ break; ++ ++ inlen = in_end - in; ++ } ++ } ++ ++ *outlen -= outleft; ++ ++ return inlen == 0; ++} ++ ++/* Allocate an output buffer in *OUT, and decode the base64 encoded ++ data stored in IN of size INLEN to the *OUT buffer. On return, the ++ size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL, ++ if the caller is not interested in the decoded length. *OUT may be ++ NULL to indicate an out of memory error, in which case *OUTLEN ++ contains the size of the memory block needed. The function returns ++ true on successful decoding and memory allocation errors. (Use the ++ *OUT and *OUTLEN parameters to differentiate between successful ++ decoding and memory error.) The function returns false if the ++ input was invalid, in which case *OUT is NULL and *OUTLEN is ++ undefined. */ ++bool ++base64_decode_alloc_ctx (struct base64_decode_context *ctx, ++ const char *in, size_t inlen, char **out, ++ size_t *outlen) ++{ ++ /* This may allocate a few bytes too many, depending on input, ++ but it's not worth the extra CPU time to compute the exact size. ++ The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the ++ input ends with "=" and minus another 1 if the input ends with "==". ++ Dividing before multiplying avoids the possibility of overflow. */ ++ size_t needlen = 3 * (inlen / 4) + 3; ++ ++ *out = malloc (needlen); ++ if (!*out) ++ return true; ++ ++ if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen)) ++ { ++ free (*out); ++ *out = NULL; ++ return false; ++ } ++ ++ if (outlen) ++ *outlen = needlen; ++ ++ return true; ++} +diff -urN libguestfs-1.28.2.old/gnulib/lib/base64.h libguestfs-1.28.2/gnulib/lib/base64.h +--- libguestfs-1.28.2.old/gnulib/lib/base64.h 1970-01-01 01:00:00.000000000 +0100 ++++ libguestfs-1.28.2/gnulib/lib/base64.h 2014-10-31 21:57:50.000000000 +0000 +@@ -0,0 +1,68 @@ ++/* base64.h -- Encode binary data using printable characters. ++ Copyright (C) 2004-2006, 2009-2014 Free Software Foundation, Inc. ++ Written by Simon Josefsson. ++ ++ This program 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, or (at your option) ++ any later version. ++ ++ This program 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 . */ ++ ++#ifndef BASE64_H ++# define BASE64_H ++ ++/* Get size_t. */ ++# include ++ ++/* Get bool. */ ++# include ++ ++# ifdef __cplusplus ++extern "C" { ++# endif ++ ++/* This uses that the expression (n+(k-1))/k means the smallest ++ integer >= n/k, i.e., the ceiling of n/k. */ ++# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4) ++ ++struct base64_decode_context ++{ ++ unsigned int i; ++ char buf[4]; ++}; ++ ++extern bool isbase64 (char ch) _GL_ATTRIBUTE_CONST; ++ ++extern void base64_encode (const char *restrict in, size_t inlen, ++ char *restrict out, size_t outlen); ++ ++extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out); ++ ++extern void base64_decode_ctx_init (struct base64_decode_context *ctx); ++ ++extern bool base64_decode_ctx (struct base64_decode_context *ctx, ++ const char *restrict in, size_t inlen, ++ char *restrict out, size_t *outlen); ++ ++extern bool base64_decode_alloc_ctx (struct base64_decode_context *ctx, ++ const char *in, size_t inlen, ++ char **out, size_t *outlen); ++ ++#define base64_decode(in, inlen, out, outlen) \ ++ base64_decode_ctx (NULL, in, inlen, out, outlen) ++ ++#define base64_decode_alloc(in, inlen, out, outlen) \ ++ base64_decode_alloc_ctx (NULL, in, inlen, out, outlen) ++ ++# ifdef __cplusplus ++} ++# endif ++ ++#endif /* BASE64_H */ +diff -urN libguestfs-1.28.2.old/gnulib/lib/Makefile.am libguestfs-1.28.2/gnulib/lib/Makefile.am +--- libguestfs-1.28.2.old/gnulib/lib/Makefile.am 2014-10-27 14:46:38.000000000 +0000 ++++ libguestfs-1.28.2/gnulib/lib/Makefile.am 2014-10-31 21:59:06.000000000 +0000 +@@ -21,7 +21,7 @@ + # the same distribution terms as the rest of that program. + # + # Generated by gnulib-tool. +-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gnulib/lib --m4-base=m4 --doc-base=doc --tests-base=gnulib/tests --aux-dir=build-aux --with-tests --avoid=dummy --avoid=getlogin_r-tests --no-conditional-dependencies --libtool --macro-prefix=gl accept4 areadlink areadlinkat arpa_inet byteswap c-ctype cloexec closeout connect dup3 error filevercmp fstatat fsusage fts full-read full-write futimens getaddrinfo getline gitlog-to-changelog glob gnu-make gnumakefile hash hash-pjw human iconv ignore-value lock maintainer-makefile manywarnings memmem mkdtemp mkstemps netdb netinet_in openat perror pipe2 pread ptsname_r read-file readlink select setenv sleep socket stat-time strchrnul strerror strndup symlinkat sys_select sys_wait vasprintf vc-list-files warnings xalloc xalloc-die xstrtol xstrtoll xvasprintf ++# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gnulib/lib --m4-base=m4 --doc-base=doc --tests-base=gnulib/tests --aux-dir=build-aux --with-tests --avoid=dummy --avoid=getlogin_r-tests --no-conditional-dependencies --libtool --macro-prefix=gl accept4 areadlink areadlinkat arpa_inet base64 byteswap c-ctype cloexec closeout connect dup3 error filevercmp fstatat fsusage fts full-read full-write futimens getaddrinfo getline gitlog-to-changelog glob gnu-make gnumakefile hash hash-pjw human iconv ignore-value lock maintainer-makefile manywarnings memmem mkdtemp mkstemps netdb netinet_in openat perror pipe2 pread ptsname_r read-file readlink select setenv sleep socket stat-time strchrnul strerror strndup symlinkat sys_select sys_wait vasprintf vc-list-files warnings xalloc xalloc-die xstrtol xstrtoll xvasprintf + + AUTOMAKE_OPTIONS = 1.9.6 gnits subdir-objects + +@@ -197,6 +197,12 @@ + + ## end gnulib module at-internal + ++## begin gnulib module base64 ++ ++libgnu_la_SOURCES += base64.h base64.c ++ ++## end gnulib module base64 ++ + ## begin gnulib module binary-io + + libgnu_la_SOURCES += binary-io.h binary-io.c +diff -urN libguestfs-1.28.2.old/gnulib/tests/Makefile.am libguestfs-1.28.2/gnulib/tests/Makefile.am +--- libguestfs-1.28.2.old/gnulib/tests/Makefile.am 2014-10-27 14:46:42.000000000 +0000 ++++ libguestfs-1.28.2/gnulib/tests/Makefile.am 2014-10-31 22:00:05.000000000 +0000 +@@ -120,6 +120,14 @@ + + ## end gnulib module arpa_inet-tests + ++## begin gnulib module base64-tests ++ ++TESTS += test-base64 ++check_PROGRAMS += test-base64 ++EXTRA_DIST += test-base64.c macros.h ++ ++## end gnulib module base64-tests ++ + ## begin gnulib module binary-io-tests + + TESTS += test-binary-io.sh +diff -urN libguestfs-1.28.2.old/gnulib/tests/test-base64.c libguestfs-1.28.2/gnulib/tests/test-base64.c +--- libguestfs-1.28.2.old/gnulib/tests/test-base64.c 1970-01-01 01:00:00.000000000 +0100 ++++ libguestfs-1.28.2/gnulib/tests/test-base64.c 2014-10-31 21:57:50.000000000 +0000 +@@ -0,0 +1,238 @@ ++/* Self tests for base64. ++ Copyright (C) 2004, 2008-2014 Free Software Foundation, Inc. ++ Written by Simon Josefsson. ++ ++ This program 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. ++ ++ This program 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 . */ ++ ++#include ++ ++#include "base64.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "macros.h" ++ ++int ++main (void) ++{ ++ const char *in = "abcdefghijklmnop"; ++ const char *b64in = "YWJjZGVmZw=="; ++ char out[255]; ++ size_t len; ++ bool ok; ++ char *p; ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 0, out, 0); ++ ASSERT (out[0] == '\x42'); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 1, out, 1); ++ ASSERT (memcmp (out, "YQ==", 1) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 1, out, 2); ++ ASSERT (memcmp (out, "YQ==", 2) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 1, out, 3); ++ ASSERT (memcmp (out, "YQ==", 3) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 1, out, 4); ++ ASSERT (memcmp (out, "YQ==", 4) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 1, out, 8); ++ ASSERT (memcmp (out, "YQ==", 4) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 2, out, 4); ++ ASSERT (memcmp (out, "YWI=", 4) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 3, out, 4); ++ ASSERT (memcmp (out, "YWJj", 4) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 4, out, 5); ++ ASSERT (memcmp (out, "YWJjZA==", 5) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ base64_encode (in, 4, out, 100); ++ ASSERT (memcmp (out, "YWJjZA==", 6) == 0); ++ ++ /* Decode. */ ++ ++ memset (out, 0x42, sizeof (out)); ++ len = 0; ++ ok = base64_decode (b64in, 4, out, &len); ++ ASSERT (ok); ++ ASSERT (len == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ len = 1; ++ ok = base64_decode (b64in, 4, out, &len); ++ ASSERT (ok); ++ ASSERT (len == 1); ++ ASSERT (memcmp (out, "abcdefg", 1) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ len = 2; ++ ok = base64_decode (b64in, 4, out, &len); ++ ASSERT (ok); ++ ASSERT (len == 2); ++ ASSERT (memcmp (out, "abcdefg", 2) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ len = 3; ++ ok = base64_decode (b64in, 4, out, &len); ++ ASSERT (ok); ++ ASSERT (len == 3); ++ ASSERT (memcmp (out, "abcdefg", 3) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ len = 4; ++ ok = base64_decode (b64in, 4, out, &len); ++ ASSERT (ok); ++ ASSERT (len == 3); ++ ASSERT (memcmp (out, "abcdefg", 3) == 0); ++ ++ memset (out, 0x42, sizeof (out)); ++ len = 100; ++ ok = base64_decode (b64in, strlen (b64in), out, &len); ++ ASSERT (ok); ++ ASSERT (len == 7); ++ ASSERT (memcmp (out, "abcdefg", 7) == 0); ++ ++ /* Allocating encode */ ++ ++ len = base64_encode_alloc (in, strlen (in), &p); ++ ASSERT (len == 24); ++ ASSERT (strcmp (p, "YWJjZGVmZ2hpamtsbW5vcA==") == 0); ++ free (p); ++ ++ len = base64_encode_alloc (in, SIZE_MAX - 5, &p); ++ ASSERT (len == 0); ++ ++ /* Decode context function */ ++ { ++ struct base64_decode_context ctx; ++ ++ base64_decode_ctx_init (&ctx); ++ ++ len = sizeof (out); ++ ok = base64_decode_ctx (&ctx, b64in, strlen (b64in), out, &len); ++ ASSERT (ok); ++ ASSERT (len == 7); ++ ASSERT (memcmp (out, "abcdefg", len) == 0); ++ } ++ ++ /* Allocating decode context function */ ++ ++ ok = base64_decode_alloc_ctx (NULL, b64in, strlen (b64in), &p, &len); ++ ASSERT (ok); ++ ASSERT (len == 7); ++ ASSERT (memcmp (out, "abcdefg", len) == 0); ++ free (p); ++ ++ { ++ struct base64_decode_context ctx; ++ const char *newlineb64 = "YWJjZG\nVmZ2hp\namtsbW5vcA=="; ++ ++ base64_decode_ctx_init (&ctx); ++ ++ ok = base64_decode_alloc_ctx (&ctx, newlineb64, strlen (newlineb64), &p, &len); ++ ASSERT (ok); ++ ASSERT (len == strlen (in)); ++ ASSERT (memcmp (p, in, len) == 0); ++ free (p); ++ } ++ ++ { ++ struct base64_decode_context ctx; ++ base64_decode_ctx_init (&ctx); ++ ++ ok = base64_decode_alloc_ctx (&ctx, "YW\nJjZGVmZ2hp", 13, &p, &len); ++ ASSERT (ok); ++ ASSERT (len == 9); ++ ASSERT (memcmp (p, "abcdefghi", len) == 0); ++ free (p); ++ ++ base64_decode_ctx_init (&ctx); ++ ++ ok = base64_decode_alloc_ctx (&ctx, "YW\n", 3, &p, &len); ++ ASSERT (ok); ++ ASSERT (len == 0); ++ free (p); ++ ++ ok = base64_decode_alloc_ctx (&ctx, "JjZGVmZ2", 8, &p, &len); ++ ASSERT (ok); ++ ASSERT (len == 6); ++ ASSERT (memcmp (p, "abcdef", len) == 0); ++ free (p); ++ ++ ok = base64_decode_alloc_ctx (&ctx, "hp", 2, &p, &len); ++ ASSERT (ok); ++ ASSERT (len == 3); ++ ASSERT (memcmp (p, "ghi", len) == 0); ++ free (p); ++ ++ ok = base64_decode_alloc_ctx (&ctx, "", 0, &p, &len); ++ ASSERT (ok); ++ free (p); ++ } ++ ++ { ++ struct base64_decode_context ctx; ++ const char *newlineb64 = "\n\n\n\n\n"; ++ ++ base64_decode_ctx_init (&ctx); ++ ++ ok = base64_decode_alloc_ctx (&ctx, newlineb64, strlen (newlineb64), &p, &len); ++ ASSERT (ok); ++ ASSERT (len == 0); ++ free (p); ++ } ++ ++ ok = base64_decode_alloc_ctx (NULL, " ! ", 3, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "abc\ndef", 7, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "aa", 2, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "aa=", 3, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "aax", 3, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "aa=X", 4, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "aa=X", 4, &p, &len); ++ ASSERT (!ok); ++ ++ ok = base64_decode_alloc_ctx (NULL, "aax=X", 5, &p, &len); ++ ASSERT (!ok); ++ ++ return 0; ++} +diff -urN libguestfs-1.28.2.old/m4/base64.m4 libguestfs-1.28.2/m4/base64.m4 +--- libguestfs-1.28.2.old/m4/base64.m4 1970-01-01 01:00:00.000000000 +0100 ++++ libguestfs-1.28.2/m4/base64.m4 2014-10-31 21:57:50.000000000 +0000 +@@ -0,0 +1,15 @@ ++# base64.m4 serial 4 ++dnl Copyright (C) 2004, 2006, 2009-2014 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++AC_DEFUN([gl_FUNC_BASE64], ++[ ++ gl_PREREQ_BASE64 ++]) ++ ++# Prerequisites of lib/base64.c. ++AC_DEFUN([gl_PREREQ_BASE64], [ ++ AC_REQUIRE([AC_C_RESTRICT]) ++]) +diff -urN libguestfs-1.28.2.old/m4/gnulib-comp.m4 libguestfs-1.28.2/m4/gnulib-comp.m4 +--- libguestfs-1.28.2.old/m4/gnulib-comp.m4 2014-10-27 14:46:40.000000000 +0000 ++++ libguestfs-1.28.2/m4/gnulib-comp.m4 2014-10-31 21:59:41.000000000 +0000 +@@ -57,6 +57,8 @@ + # Code from module arpa_inet: + # Code from module arpa_inet-tests: + # Code from module at-internal: ++ # Code from module base64: ++ # Code from module base64-tests: + # Code from module binary-io: + # Code from module binary-io-tests: + # Code from module bind: +@@ -502,6 +504,7 @@ + gl_HEADER_ARPA_INET + AC_PROG_MKDIR_P + AC_LIBOBJ([openat-proc]) ++ gl_FUNC_BASE64 + gl_BYTESWAP + AC_CHECK_FUNCS_ONCE([readlinkat]) + gl_UNISTD_MODULE_INDICATOR([chdir]) +@@ -1477,6 +1480,8 @@ + lib/asnprintf.c + lib/asprintf.c + lib/at-func.c ++ lib/base64.c ++ lib/base64.h + lib/basename-lgpl.c + lib/binary-io.c + lib/binary-io.h +@@ -1758,6 +1763,7 @@ + m4/accept4.m4 + m4/alloca.m4 + m4/arpa_inet_h.m4 ++ m4/base64.m4 + m4/btowc.m4 + m4/byteswap.m4 + m4/chdir-long.m4 +@@ -2008,6 +2014,7 @@ + tests/test-areadlinkat.c + tests/test-argmatch.c + tests/test-arpa_inet.c ++ tests/test-base64.c + tests/test-binary-io.c + tests/test-binary-io.sh + tests/test-bind.c diff --git a/libguestfs.spec b/libguestfs.spec index e2b1093..0d57d3a 100644 --- a/libguestfs.spec +++ b/libguestfs.spec @@ -25,13 +25,21 @@ Summary: Access and modify virtual machine disk images Name: libguestfs Epoch: 1 Version: 1.28.2 -Release: 1%{?dist} +Release: 2%{?dist} License: LGPLv2+ # Source and patches. URL: http://libguestfs.org/ Source0: http://libguestfs.org/download/1.28-stable/%{name}-%{version}.tar.gz +# Fix for https://bugzilla.redhat.com/show_bug.cgi?id=1159016 +# libvirt backend does not set RBD password +Patch1: 0001-launch-libvirt-Implement-drive-secrets-RHBZ-1159016.patch +# Unfortunately because patch1 patches gnulib configuration, we +# also need: +Patch2: add-base64-to-gnulib.patch +BuildRequires: autoconf, automake, libtool + # Basic build requirements: BuildRequires: perl(Pod::Simple) BuildRequires: perl(Pod::Man) @@ -728,6 +736,10 @@ for %{name}. %prep %setup -q +%patch1 -p1 +%patch2 -p1 +autoreconf -i + if [ "$(getenforce | tr '[A-Z]' '[a-z]')" != "disabled" ]; then # For sVirt to work, the local temporary directory we use in the # tests must be labelled the same way as /tmp. @@ -1226,6 +1238,9 @@ popd %changelog +* Fri Oct 31 2014 Richard W.M. Jones - 1:1.28.2-2 +- Fix: libvirt backend does not set RBD password (RHBZ#1159016). + * Mon Oct 27 2014 Richard W.M. Jones - 1:1.28.2-1 - New upstream version 1.28.2.