summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am3
-rw-r--r--src/util/amount.c492
-rw-r--r--src/util/crypto.c16
-rw-r--r--src/util/json.c65
-rw-r--r--src/util/os_installation.c701
-rw-r--r--src/util/util.c28
6 files changed, 1116 insertions, 189 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index a15d42ad8..07c120c50 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -8,7 +8,8 @@ libtalerutil_la_SOURCES = \
amount.c \
crypto.c \
util.c \
- json.c
+ json.c \
+ os_installation.c
libtalerutil_la_LIBADD = \
-lgnunetutil \
diff --git a/src/util/amount.c b/src/util/amount.c
index 9bdc0fd93..5e7f69fd9 100644
--- a/src/util/amount.c
+++ b/src/util/amount.c
@@ -30,10 +30,6 @@
#include "taler_util.h"
#include <gcrypt.h>
-#define AMOUNT_FRAC_BASE 1000000
-
-#define AMOUNT_FRAC_LEN 6
-
/**
* Parse money amount description, in the format "A:B.C".
@@ -47,148 +43,260 @@ int
TALER_string_to_amount (const char *str,
struct TALER_Amount *denom)
{
- unsigned int i; // pos in str
- int n; // number tmp
- unsigned int c; // currency pos
- uint32_t b; // base for suffix
-
- memset (denom, 0, sizeof (struct TALER_Amount));
-
- i = n = c = 0;
-
- while (isspace(str[i]))
- i++;
-
- if (0 == str[i])
+ size_t i;
+ int n;
+ uint32_t b;
+ const char *colon;
+ const char *value;
+
+ memset (denom,
+ 0,
+ sizeof (struct TALER_Amount));
+ /* skip leading whitespace */
+ while (isspace(str[0]))
+ str++;
+ if ('\0' == str[0])
{
- printf("null before currency\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Null before currency\n");
return GNUNET_SYSERR;
}
-
- while (str[i] != ':')
+ /* parse currency */
+ colon = strchr (str, (int) ':');
+ if ( (NULL == colon) ||
+ ((colon - str) >= TALER_CURRENCY_LEN) )
{
- if (0 == str[i])
- {
- printf("null before colon");
- return GNUNET_SYSERR;
- }
- if (c > 3)
- {
- printf("currency too long\n");
- return GNUNET_SYSERR;
- }
- denom->currency[c] = str[i];
- c++;
- i++;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid currency specified before colon: `%s'",
+ str);
+ goto fail;
}
-
- // skip colon
- i++;
-
- if (0 == str[i])
+ memcpy (denom->currency,
+ str,
+ colon - str);
+ /* skip colon */
+ value = colon + 1;
+ if ('\0' == value[0])
{
- printf("null before value\n");
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Null before value\n");
+ goto fail;
}
- while (str[i] != '.')
+ /* parse value */
+ i = 0;
+ while ('.' != value[i])
{
- if (0 == str[i])
+ if ('\0' == value[i])
{
return GNUNET_OK;
}
+ if ( (str[i] < '0') || (str[i] > '9') )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid character `%c'\n",
+ str[i]);
+ goto fail;
+ }
n = str[i] - '0';
- if (n < 0 || n > 9)
+ if (denom->value * 10 + n < denom->value)
{
- printf("invalid character '%c' before comma at %u\n", (char) n, i);
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Value too large\n");
+ goto fail;
}
denom->value = (denom->value * 10) + n;
i++;
}
- // skip the dot
+ /* skip the dot */
i++;
- if (0 == str[i])
+ /* parse fraction */
+ if ('\0' == str[i])
{
- printf("null after dot");
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Null after dot");
+ goto fail;
}
-
- b = 100000;
-
- while (0 != str[i])
+ b = TALER_AMOUNT_FRAC_BASE / 10;
+ while ('\0' != str[i])
{
- n = str[i] - '0';
- if (b == 0 || n < 0 || n > 9)
+ if (0 == b)
{
- printf("error after comma");
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Fractional value too small (only %u digits supported)",
+ (unsigned int) TALER_AMOUNT_FRAC_LEN);
+ goto fail;
+ }
+ if ( (str[i] < '0') || (str[i] > '9') )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Error after comma");
+ goto fail;
}
+ n = str[i] - '0';
denom->fraction += n * b;
b /= 10;
i++;
}
-
return GNUNET_OK;
+
+ fail:
+ /* set currency to 'invalid' to prevent accidental use */
+ memset (denom->currency,
+ 0,
+ TALER_CURRENCY_LEN);
+ return GNUNET_SYSERR;
}
/**
- * FIXME
+ * Convert amount from host to network representation.
+ *
+ * @param res where to store amount in network representation
+ * @param d amount in host representation
*/
-struct TALER_AmountNBO
-TALER_amount_hton (const struct TALER_Amount d)
+void
+TALER_amount_hton (struct TALER_AmountNBO *res,
+ const struct TALER_Amount *d)
{
- struct TALER_AmountNBO dn;
- dn.value = htonl (d.value);
- dn.fraction = htonl (d.fraction);
- memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN);
+ res->value = GNUNET_htonll (d->value);
+ res->fraction = htonl (d->fraction);
+ memcpy (res->currency,
+ d->currency,
+ TALER_CURRENCY_LEN);
+}
+
- return dn;
+/**
+ * Convert amount from network to host representation.
+ *
+ * @param res where to store amount in host representation
+ * @param d amount in network representation
+ */
+void
+TALER_amount_ntoh (struct TALER_Amount *res,
+ const struct TALER_AmountNBO *dn)
+{
+ res->value = GNUNET_ntohll (dn->value);
+ res->fraction = ntohl (dn->fraction);
+ memcpy (res->currency,
+ dn->currency,
+ TALER_CURRENCY_LEN);
}
/**
- * FIXME
+ * Get the value of "zero" in a particular currency.
+ *
+ * @param cur currency description
+ * @param denom denomination to write the result to
+ * @return #GNUNET_OK if @a cur is a valid currency specification,
+ * #GNUNET_SYSERR if it is invalid.
*/
-struct TALER_Amount
-TALER_amount_ntoh (const struct TALER_AmountNBO dn)
+int
+TALER_amount_get_zero (const char *cur,
+ struct TALER_Amount *denom)
{
- struct TALER_Amount d;
- d.value = ntohl (dn.value);
- d.fraction = ntohl (dn.fraction);
- memcpy (d.currency, dn.currency, sizeof(dn.currency));
+ size_t slen;
- return d;
+ slen = strlen (cur);
+ if (slen >= TALER_CURRENCY_LEN)
+ return GNUNET_SYSERR;
+ memset (denom,
+ 0,
+ sizeof (struct TALER_Amount));
+ memcpy (denom->currency,
+ cur,
+ slen);
+ return GNUNET_OK;
}
/**
- * Compare the value/fraction of two amounts. Does not compare the currency,
- * i.e. comparing amounts with the same value and fraction but different
- * currency would return 0.
+ * Set @a a to "invalid".
+ *
+ * @param a amount to set to invalid
+ */
+static void
+invalidate (struct TALER_Amount *a)
+{
+ memset (a,
+ 0,
+ sizeof (struct TALER_Amount));
+}
+
+
+/**
+ * Test if @a a is valid
+ *
+ * @param a amount to test
+ * @return #GNUNET_YES if valid,
+ * #GNUNET_NO if invalid
+ */
+static int
+test_valid (const struct TALER_Amount *a)
+{
+ return ('\0' != a->currency[0]);
+}
+
+
+/**
+ * Test if @a a1 and @a a2 are the same currency.
+ *
+ * @param a1 amount to test
+ * @param a2 amount to test
+ * @return #GNUNET_YES if @a a1 and @a a2 are the same currency
+ * #GNUNET_NO if the currencies are different,
+ * #GNUNET_SYSERR if either amount is invalid
+ */
+int
+TALER_amount_cmp_currency (const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
+{
+ if ( (GNUNET_NO == test_valid (a1)) ||
+ (GNUNET_NO == test_valid (a2)) )
+ return GNUNET_SYSERR;
+ if (0 == strcmp (a1->currency,
+ a2->currency))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Compare the value/fraction of two amounts. Does not compare the currency.
+ * Comparing amounts of different currencies will cause the program to abort().
+ * If unsure, check with #TALER_amount_cmp_currency() first to be sure that
+ * the currencies of the two amounts are identical.
*
* @param a1 first amount
* @param a2 second amount
* @return result of the comparison
*/
int
-TALER_amount_cmp (struct TALER_Amount a1,
- struct TALER_Amount a2)
+TALER_amount_cmp (const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
{
- a1 = TALER_amount_normalize (a1);
- a2 = TALER_amount_normalize (a2);
- if (a1.value == a2.value)
+ struct TALER_Amount n1;
+ struct TALER_Amount n2;
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (a1, a2));
+ n1 = *a1;
+ n2 = *a2;
+ TALER_amount_normalize (&n1);
+ TALER_amount_normalize (&n2);
+ if (n1.value == n2.value)
{
- if (a1.fraction < a2.fraction)
+ if (n1.fraction < n2.fraction)
return -1;
- if (a1.fraction > a2.fraction)
+ if (n1.fraction > n2.fraction)
return 1;
return 0;
}
- if (a1.value < a2.value)
+ if (n1.value < n2.value)
return -1;
return 1;
}
@@ -197,108 +305,142 @@ TALER_amount_cmp (struct TALER_Amount a1,
/**
* Perform saturating subtraction of amounts.
*
+ * @param diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1
* @param a1 amount to subtract from
* @param a2 amount to subtract
- * @return (a1-a2) or 0 if a2>=a1
+ * @return #GNUNET_OK if the subtraction worked,
+ * #GNUNET_NO if @a a1 = @a a2
+ * #GNUNET_SYSERR if @a a2 > @a a1 or currencies are incompatible;
+ * @a diff is set to invalid
*/
-struct TALER_Amount
-TALER_amount_subtract (struct TALER_Amount a1,
- struct TALER_Amount a2)
+int
+TALER_amount_subtract (struct TALER_Amount *diff,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
{
- a1 = TALER_amount_normalize (a1);
- a2 = TALER_amount_normalize (a2);
+ struct TALER_Amount n1;
+ struct TALER_Amount n2;
- if (a1.value < a2.value)
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (a1, a2))
{
- a1.value = 0;
- a1.fraction = 0;
- return a1;
+ invalidate (diff);
+ return GNUNET_SYSERR;
}
+ n1 = *a1;
+ n2 = *a2;
+ TALER_amount_normalize (&n1);
+ TALER_amount_normalize (&n2);
- if (a1.fraction < a2.fraction)
+ if (n1.fraction < n2.fraction)
{
- if (0 == a1.value)
+ if (0 == n1.value)
{
- a1.fraction = 0;
- return a1;
+ invalidate (diff);
+ return GNUNET_SYSERR;
}
- a1.fraction += AMOUNT_FRAC_BASE;
- a1.value -= 1;
+ n1.fraction += TALER_AMOUNT_FRAC_BASE;
+ n1.value--;
}
-
- a1.fraction -= a2.fraction;
- a1.value -= a2.value;
-
- return a1;
+ if (n1.value < n2.value)
+ {
+ invalidate (diff);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (a1->currency,
+ diff));
+ GNUNET_assert (n1.fraction >= n2.fraction);
+ diff->fraction = n1.fraction - n2.fraction;
+ GNUNET_assert (n1.value >= n2.value);
+ diff->value = n1.value - n2.value;
+ if ( (0 == diff->fraction) &&
+ (0 == diff->value) )
+ return GNUNET_NO;
+ return GNUNET_OK;
}
/**
- * Perform saturating addition of amounts.
+ * Perform addition of amounts.
*
+ * @param sum where to store @a a1 + @a a2, set to "invalid" on overflow
* @param a1 first amount to add
* @param a2 second amount to add
- * @return sum of a1 and a2
+ * @return #GNUNET_OK if the addition worked,
+ * #GNUNET_SYSERR on overflow
*/
-struct TALER_Amount
-TALER_amount_add (struct TALER_Amount a1,
- struct TALER_Amount a2)
+int
+TALER_amount_add (struct TALER_Amount *sum,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
{
- a1 = TALER_amount_normalize (a1);
- a2 = TALER_amount_normalize (a2);
-
- a1.value += a2.value;
- a1.fraction += a2.fraction;
+ struct TALER_Amount n1;
+ struct TALER_Amount n2;
- if (0 == a1.currency[0])
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (a1, a2))
{
- memcpy (a2.currency,
- a1.currency,
- TALER_CURRENCY_LEN);
+ invalidate (sum);
+ return GNUNET_SYSERR;
}
-
- if (0 == a2.currency[0])
+ n1 = *a1;
+ n2 = *a2;
+ TALER_amount_normalize (&n1);
+ TALER_amount_normalize (&n2);
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (a1->currency,
+ sum));
+ sum->value = n1.value + n2.value;
+ if (sum->value < n1.value)
{
- memcpy (a1.currency,
- a2.currency,
- TALER_CURRENCY_LEN);
+ /* integer overflow */
+ invalidate (sum);
+ return GNUNET_SYSERR;
}
-
- if ( (0 != a1.currency[0]) &&
- (0 != memcmp (a1.currency,
- a2.currency,
- TALER_CURRENCY_LEN)) )
+ sum->fraction = n1.fraction + n2.fraction;
+ if (GNUNET_SYSERR ==
+ TALER_amount_normalize (sum))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "adding mismatching currencies\n");
- }
-
- if (a1.value < a2.value)
- {
- a1.value = UINT32_MAX;
- a2.value = UINT32_MAX;
- return a1;
+ /* integer overflow via carry from fraction */
+ invalidate (sum);
+ return GNUNET_SYSERR;
}
-
- return TALER_amount_normalize (a1);
+ return GNUNET_OK;
}
/**
* Normalize the given amount.
*
- * @param amout amount to normalize
- * @return normalized amount
+ * @param amount amount to normalize
+ * @return #GNUNET_OK if normalization worked
+ * #GNUNET_NO if value was already normalized
+ * #GNUNET_SYSERR if value was invalid or could not be normalized
*/
-struct TALER_Amount
-TALER_amount_normalize (struct TALER_Amount amount)
+int
+TALER_amount_normalize (struct TALER_Amount *amount)
{
- while (amount.value != UINT32_MAX && amount.fraction >= AMOUNT_FRAC_BASE)
+ int ret;
+
+ if (GNUNET_YES != test_valid (amount))
+ return GNUNET_SYSERR;
+ ret = GNUNET_NO;
+ while ( (amount->value != UINT64_MAX) &&
+ (amount->fraction >= TALER_AMOUNT_FRAC_BASE) )
+ {
+ amount->fraction -= TALER_AMOUNT_FRAC_BASE;
+ amount->value++;
+ ret = GNUNET_OK;
+ }
+ if (amount->fraction >= TALER_AMOUNT_FRAC_BASE)
{
- amount.fraction -= AMOUNT_FRAC_BASE;
- amount.value += 1;
+ /* failed to normalize, adding up fractions caused
+ main value to overflow! */
+ return GNUNET_SYSERR;
}
- return amount;
+ return ret;
}
@@ -309,40 +451,40 @@ TALER_amount_normalize (struct TALER_Amount amount)
* @return freshly allocated string representation
*/
char *
-TALER_amount_to_string (struct TALER_Amount amount)
+TALER_amount_to_string (const struct TALER_Amount *amount)
{
- char tail[AMOUNT_FRAC_LEN + 1] = { 0 };
- char curr[TALER_CURRENCY_LEN + 1] = { 0 };
- char *result = NULL;
- int len;
-
- memcpy (curr, amount.currency, TALER_CURRENCY_LEN);
-
- amount = TALER_amount_normalize (amount);
- if (0 != amount.fraction)
+ char *result;
+ uint32_t n;
+ char tail[TALER_AMOUNT_FRAC_LEN + 1];
+ unsigned int i;
+ struct TALER_Amount norm;
+
+ if (GNUNET_YES != test_valid (amount))
+ return NULL;
+ norm = *amount;
+ GNUNET_break (GNUNET_SYSERR !=
+ TALER_amount_normalize (&norm));
+ if (0 != (n = norm.fraction))
{
- unsigned int i;
- uint32_t n = amount.fraction;
- for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++)
+ for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
{
- tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10));
- n = (n * 10) % (AMOUNT_FRAC_BASE);
+ tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
+ n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
}
- tail[i] = 0;
- len = GNUNET_asprintf (&result,
- "%s:%lu.%s",
- curr,
- (unsigned long) amount.value,
- tail);
+ tail[i] = '\0';
+ GNUNET_asprintf (&result,
+ "%s:%llu.%s",
+ norm.currency,
+ (unsigned long long) norm.value,
+ tail);
}
else
{
- len = GNUNET_asprintf (&result,
- "%s:%lu",
- curr,
- (unsigned long) amount.value);
+ GNUNET_asprintf (&result,
+ "%s:%llu",
+ norm.currency,
+ (unsigned long long) norm.value);
}
- GNUNET_assert (len > 0);
return result;
}
diff --git a/src/util/crypto.c b/src/util/crypto.c
index 5e75d674a..ffc12fed9 100644
--- a/src/util/crypto.c
+++ b/src/util/crypto.c
@@ -52,7 +52,8 @@ fatal_error_handler (void *cls,
void
TALER_gcrypt_init ()
{
- gcry_set_fatalerror_handler (&fatal_error_handler, NULL);
+ gcry_set_fatalerror_handler (&fatal_error_handler,
+ NULL);
TALER_assert_as (gcry_check_version (NEED_LIBGCRYPT_VERSION),
"libgcrypt version mismatch");
/* Disable secure memory. */
@@ -205,11 +206,11 @@ TALER_refresh_decrypt (const struct TALER_RefreshLinkEncrypted *input,
ret = GNUNET_new (struct TALER_RefreshLinkDecrypted);
memcpy (&ret->coin_priv,
buf,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
- ret->blinding_key
+ sizeof (struct TALER_CoinSpendPrivateKey));
+ ret->blinding_key.rsa_blinding_key
= GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)],
input->blinding_key_enc_size);
- if (NULL == ret->blinding_key)
+ if (NULL == ret->blinding_key.rsa_blinding_key)
{
GNUNET_free (ret);
return NULL;
@@ -236,7 +237,7 @@ TALER_refresh_encrypt (const struct TALER_RefreshLinkDecrypted *input,
struct TALER_RefreshLinkEncrypted *ret;
derive_refresh_key (secret, &iv, &skey);
- b_buf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (input->blinding_key,
+ b_buf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (input->blinding_key.rsa_blinding_key,
&b_buf);
ret = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) +
b_buf_size);
@@ -308,14 +309,13 @@ TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info)
{
struct GNUNET_HashCode c_hash;
- /* FIXME: we had envisioned a more complex scheme... */
GNUNET_CRYPTO_hash (&coin_public_info->coin_pub,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
&c_hash);
if (GNUNET_OK !=
GNUNET_CRYPTO_rsa_verify (&c_hash,
- coin_public_info->denom_sig,
- coin_public_info->denom_pub))
+ coin_public_info->denom_sig.rsa_signature,
+ coin_public_info->denom_pub.rsa_public_key))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"coin signature is invalid\n");
diff --git a/src/util/json.c b/src/util/json.c
index a9d6dc5cc..7390eb474 100644
--- a/src/util/json.c
+++ b/src/util/json.c
@@ -48,14 +48,25 @@
* @return a json object describing the amount
*/
json_t *
-TALER_JSON_from_amount (struct TALER_Amount amount)
+TALER_JSON_from_amount (const struct TALER_Amount *amount)
{
json_t *j;
- j = json_pack ("{s: s, s:I, s:I}",
- "currency", amount.currency,
- "value", (json_int_t) amount.value,
- "fraction", (json_int_t) amount.fraction);
+ if ( (amount->value != (uint64_t) ((json_int_t) amount->value)) ||
+ (0 > ((json_int_t) amount->value)) )
+ {
+ /* Theoretically, json_int_t can be a 32-bit "long", or we might
+ have a 64-bit value which converted to a 63-bit signed long
+ long causes problems here. So we check. Note that depending
+ on the platform, the compiler may be able to statically tell
+ that at least the first check is always false. */
+ GNUNET_break (0);
+ return NULL;
+ }
+ j = json_pack ("{s:s, s:I, s:I}",
+ "currency", amount->currency,
+ "value", (json_int_t) amount->value,
+ "fraction", (json_int_t) amount->fraction);
GNUNET_assert (NULL != j);
return j;
}
@@ -151,6 +162,50 @@ TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpo
/**
+ * Convert RSA public key to JSON.
+ *
+ * @param pk public key to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+TALER_JSON_from_rsa_public_key (struct GNUNET_CRYPTO_rsa_PublicKey *pk)
+{
+ char *buf;
+ size_t buf_len;
+ json_t *ret;
+
+ buf_len = GNUNET_CRYPTO_rsa_public_key_encode (pk,
+ &buf);
+ ret = TALER_JSON_from_data (buf,
+ buf_len);
+ GNUNET_free (buf);
+ return ret;
+}
+
+
+/**
+ * Convert RSA signature to JSON.
+ *
+ * @param sig signature to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+TALER_JSON_from_rsa_signature (struct GNUNET_CRYPTO_rsa_Signature *sig)
+{
+ char *buf;
+ size_t buf_len;
+ json_t *ret;
+
+ buf_len = GNUNET_CRYPTO_rsa_signature_encode (sig,
+ &buf);
+ ret = TALER_JSON_from_data (buf,
+ buf_len);
+ GNUNET_free (buf);
+ return ret;
+}
+
+
+/**
* Convert binary data to a JSON string
* with the base32crockford encoding.
*
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
new file mode 100644
index 000000000..82dc49180
--- /dev/null
+++ b/src/util/os_installation.c
@@ -0,0 +1,701 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2006-2014 Christian Grothoff (and other contributing authors)
+
+ GNUnet 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.
+
+ GNUnet 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 GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file os_installation.c
+ * @brief get paths used by the program; based heavily on the
+ * corresponding GNUnet file, just adapted for Taler.
+ * @author Milan
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#if DARWIN
+#include <mach-o/ldsyms.h>
+#include <mach-o/dyld.h>
+#elif WINDOWS
+#include <windows.h>
+#endif
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+
+#if LINUX
+/**
+ * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_proc_maps ()
+{
+ char fn[64];
+ char line[1024];
+ char dir[1024];
+ FILE *f;
+ char *lgu;
+
+ GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
+ if (NULL == (f = FOPEN (fn, "r")))
+ return NULL;
+ while (NULL != fgets (line, sizeof (line), f))
+ {
+ if ((1 ==
+ SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
+ (NULL != (lgu = strstr (dir, "libtalerutil"))))
+ {
+ lgu[0] = '\0';
+ FCLOSE (f);
+ return GNUNET_strdup (dir);
+ }
+ }
+ FCLOSE (f);
+ return NULL;
+}
+
+
+/**
+ * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_proc_exe ()
+{
+ char fn[64];
+ char lnk[1024];
+ ssize_t size;
+
+ GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ());
+ size = readlink (fn, lnk, sizeof (lnk) - 1);
+ if (size <= 0)
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
+ return NULL;
+ }
+ GNUNET_assert (size < sizeof (lnk));
+ lnk[size] = '\0';
+ while ((lnk[size] != '/') && (size > 0))
+ size--;
+ /* test for being in lib/taler/libexec/ or lib/MULTIARCH/taler/libexec */
+ if ( (size > strlen ("/taler/libexec/")) &&
+ (0 == strcmp ("/taler/libexec/",
+ &lnk[size - strlen ("/taler/libexec/")])) )
+ size -= strlen ("taler/libexec/");
+ if ((size < 4) || (lnk[size - 4] != '/'))
+ {
+ /* not installed in "/bin/" -- binary path probably useless */
+ return NULL;
+ }
+ lnk[size] = '\0';
+ return GNUNET_strdup (lnk);
+}
+#endif
+
+
+#if WINDOWS
+static HINSTANCE dll_instance;
+
+
+/**
+ * GNUNET_util_cl_init() in common_logging.c is preferred.
+ * This function is only for thread-local storage (not used in GNUnet)
+ * and hInstance saving.
+ */
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ dll_instance = hinstDLL;
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Try to determine path with win32-specific function
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_module_filename ()
+{
+ size_t pathlen = 512;
+ DWORD real_pathlen;
+ wchar_t *idx;
+ wchar_t *modulepath = NULL;
+ char *upath;
+ uint8_t *u8_string;
+ size_t u8_string_length;
+
+ /* This braindead function won't tell us how much space it needs, so
+ * we start at 1024 and double the space up if it doesn't fit, until
+ * it fits, or we exceed the threshold.
+ */
+ do
+ {
+ pathlen = pathlen * 2;
+ modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
+ SetLastError (0);
+ real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
+ } while (real_pathlen >= pathlen && pathlen < 16*1024);
+ if (real_pathlen >= pathlen)
+ GNUNET_assert (0);
+ /* To be safe */
+ modulepath[real_pathlen] = '\0';
+
+ idx = modulepath + real_pathlen;
+ while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
+ idx--;
+ *idx = L'\0';
+
+ /* Now modulepath holds full path to the directory where libtalerutil is.
+ * This directory should look like <TALER_PREFIX>/bin or <TALER_PREFIX>.
+ */
+ if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
+ {
+ /* At least one directory component (i.e. we're not in a root directory) */
+ wchar_t *dirname = idx;
+ while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
+ dirname--;
+ *dirname = L'\0';
+ if (dirname > modulepath)
+ {
+ dirname++;
+ /* Now modulepath holds full path to the parent directory of the directory
+ * where libtalerutil is.
+ * dirname holds the name of the directory where libtalerutil is.
+ */
+ if (wcsicmp (dirname, L"bin") == 0)
+ {
+ /* pass */
+ }
+ else
+ {
+ /* Roll back our changes to modulepath */
+ dirname--;
+ *dirname = L'/';
+ }
+ }
+ }
+
+ /* modulepath is TALER_PREFIX */
+ u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
+ if (NULL == u8_string)
+ GNUNET_assert (0);
+
+ upath = GNUNET_malloc (u8_string_length + 1);
+ memcpy (upath, u8_string, u8_string_length);
+ upath[u8_string_length] = '\0';
+
+ free (u8_string);
+ GNUNET_free (modulepath);
+
+ return upath;
+}
+#endif
+
+
+#if DARWIN
+/**
+ * Signature of the '_NSGetExecutablePath" function.
+ *
+ * @param buf where to write the path
+ * @param number of bytes available in 'buf'
+ * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
+ */
+typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
+
+
+/**
+ * Try to obtain the path of our executable using '_NSGetExecutablePath'.
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_NSGetExecutablePath ()
+{
+ static char zero = '\0';
+ char *path;
+ size_t len;
+ MyNSGetExecutablePathProto func;
+
+ path = NULL;
+ if (NULL == (func =
+ (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
+ return NULL;
+ path = &zero;
+ len = 0;
+ /* get the path len, including the trailing \0 */
+ (void) func (path, &len);
+ if (0 == len)
+ return NULL;
+ path = GNUNET_malloc (len);
+ if (0 != func (path, &len))
+ {
+ GNUNET_free (path);
+ return NULL;
+ }
+ len = strlen (path);
+ while ((path[len] != '/') && (len > 0))
+ len--;
+ path[len] = '\0';
+ return path;
+}
+
+
+/**
+ * Try to obtain the path of our executable using '_dyld_image' API.
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_dyld_image ()
+{
+ const char *path;
+ char *p;
+ char *s;
+ unsigned int i;
+ int c;
+
+ c = _dyld_image_count ();
+ for (i = 0; i < c; i++)
+ {
+ if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
+ continue;
+ path = _dyld_get_image_name (i);
+ if ( (NULL == path) || (0 == strlen (path)) )
+ continue;
+ p = GNUNET_strdup (path);
+ s = p + strlen (p);
+ while ((s > p) && ('/' != *s))
+ s--;
+ s++;
+ *s = '\0';
+ return p;
+ }
+ return NULL;
+}
+#endif
+
+
+/**
+ * Return the actual path to a file found in the current
+ * PATH environment variable.
+ *
+ * @param binary the name of the file to find
+ * @return path to binary, NULL if not found
+ */
+static char *
+get_path_from_PATH (const char *binary)
+{
+ char *path;
+ char *pos;
+ char *end;
+ char *buf;
+ const char *p;
+
+ if (NULL == (p = getenv ("PATH")))
+ return NULL;
+#if WINDOWS
+ /* On W32 look in CWD first. */
+ GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
+#else
+ path = GNUNET_strdup (p); /* because we write on it */
+#endif
+ buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
+ pos = path;
+ while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
+ {
+ *end = '\0';
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
+ {
+ pos = GNUNET_strdup (pos);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return pos;
+ }
+ pos = end + 1;
+ }
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_YES == GNUNET_DISK_file_test (buf))
+ {
+ pos = GNUNET_strdup (pos);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return pos;
+ }
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return NULL;
+}
+
+
+/**
+ * Try to obtain the installation path using the "TALER_PREFIX" environment
+ * variable.
+ *
+ * @return NULL on error (environment variable not set)
+ */
+static char *
+get_path_from_TALER_PREFIX ()
+{
+ const char *p;
+
+ if (NULL != (p = getenv ("TALER_PREFIX")))
+ return GNUNET_strdup (p);
+ return NULL;
+}
+
+
+/**
+ * @brief get the path to Taler bin/ or lib/, prefering the lib/ path
+ * @author Milan
+ *
+ * @return a pointer to the executable path, or NULL on error
+ */
+static char *
+os_get_taler_path ()
+{
+ char *ret;
+
+ if (NULL != (ret = get_path_from_TALER_PREFIX ()))
+ return ret;
+#if LINUX
+ if (NULL != (ret = get_path_from_proc_maps ()))
+ return ret;
+ /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
+ if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ return ret;
+ if (NULL != (ret = get_path_from_proc_exe ()))
+ return ret;
+#endif
+#if WINDOWS
+ if (NULL != (ret = get_path_from_module_filename ()))
+ return ret;
+#endif
+#if DARWIN
+ if (NULL != (ret = get_path_from_dyld_image ()))
+ return ret;
+ if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
+ return ret;
+#endif
+ if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ return ret;
+ /* other attempts here */
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not determine installation path for %s. Set `%s' environment variable.\n"),
+ "Taler", "TALER_PREFIX");
+ return NULL;
+}
+
+
+/**
+ * @brief get the path to current app's bin/
+ * @author Milan
+ *
+ * @return a pointer to the executable path, or NULL on error
+ */
+static char *
+os_get_exec_path ()
+{
+ char *ret = NULL;
+
+#if LINUX
+ if (NULL != (ret = get_path_from_proc_exe ()))
+ return ret;
+#endif
+#if WINDOWS
+ if (NULL != (ret = get_path_from_module_filename ()))
+ return ret;
+#endif
+#if DARWIN
+ if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
+ return ret;
+#endif
+ /* other attempts here */
+ return ret;
+}
+
+
+/**
+ * @brief get the path to a specific Taler installation directory or,
+ * with #TALER_OS_IPK_SELF_PREFIX, the current running apps installation directory
+ * @author Milan
+ * @return a pointer to the dir path (to be freed by the caller)
+ */
+char *
+TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
+{
+ size_t n;
+ const char *dirname;
+ char *execpath = NULL;
+ char *tmp;
+ char *multiarch;
+ char *libdir;
+ int isbasedir;
+
+ /* if wanted, try to get the current app's bin/ */
+ if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
+ execpath = os_get_exec_path ();
+
+ /* try to get Taler's bin/ or lib/, or if previous was unsuccessful some
+ * guess for the current app */
+ if (NULL == execpath)
+ execpath = os_get_taler_path ();
+
+ if (NULL == execpath)
+ return NULL;
+
+ n = strlen (execpath);
+ if (0 == n)
+ {
+ /* should never happen, but better safe than sorry */
+ GNUNET_free (execpath);
+ return NULL;
+ }
+ /* remove filename itself */
+ while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
+ execpath[--n] = '\0';
+
+ isbasedir = 1;
+ if ((n > 6) &&
+ ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
+ (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
+ {
+ if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
+ (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
+ {
+ /* strip '/lib32' or '/lib64' */
+ execpath[n - 6] = '\0';
+ n -= 6;
+ }
+ else
+ isbasedir = 0;
+ }
+ else if ((n > 4) &&
+ ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
+ (0 == strcasecmp (&execpath[n - 4], "/lib"))))
+ {
+ /* strip '/bin' or '/lib' */
+ execpath[n - 4] = '\0';
+ n -= 4;
+ }
+ multiarch = NULL;
+ if (NULL != (libdir = strstr (execpath, "/lib/")))
+ {
+ /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
+ here we need to re-add 'multiarch' to lib and libexec paths later! */
+ multiarch = &libdir[5];
+ if (NULL == strchr (multiarch, '/'))
+ libdir[0] = '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
+ else
+ multiarch = NULL; /* maybe not, multiarch still has a '/', which is not OK */
+ }
+ /* in case this was a directory named foo-bin, remove "foo-" */
+ while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
+ execpath[--n] = '\0';
+ switch (dirkind)
+ {
+ case GNUNET_OS_IPK_PREFIX:
+ case GNUNET_OS_IPK_SELF_PREFIX:
+ dirname = DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_BINDIR:
+ dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LIBDIR:
+ if (isbasedir)
+ {
+ GNUNET_asprintf (&tmp,
+ "%s%s%s%s%s",
+ execpath,
+ DIR_SEPARATOR_STR "lib",
+ (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
+ (NULL != multiarch) ? multiarch : "",
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR);
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ tmp = NULL;
+ if (4 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if (8 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+
+ if ( (NULL != tmp) &&
+ (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ }
+ dirname = DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_DATADIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LOCALEDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_ICONDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_DOCDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
+ "gnunet" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LIBEXECDIR:
+ if (isbasedir)
+ {
+ dirname =
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s%s%s",
+ execpath,
+ DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
+ (NULL != multiarch) ? multiarch : "",
+ dirname);
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ tmp = NULL;
+ if (4 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if (8 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if ( (NULL != tmp) &&
+ (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+
+ GNUNET_free (tmp);
+ }
+ dirname =
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ break;
+ default:
+ GNUNET_free (execpath);
+ return NULL;
+ }
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ GNUNET_free (execpath);
+ return tmp;
+}
+
+
+/**
+ * Given the name of a taler-helper, taler-service or taler-daemon
+ * binary, try to prefix it with the libexec/-directory to get the
+ * full path.
+ *
+ * @param progname name of the binary
+ * @return full path to the binary, if possible, otherwise copy of 'progname'
+ */
+char *
+TALER_OS_get_libexec_binary_path (const char *progname)
+{
+ static char *cache;
+ char *libexecdir;
+ char *binary;
+
+ if ( (DIR_SEPARATOR == progname[0]) ||
+ (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
+ return GNUNET_strdup (progname);
+ if (NULL != cache)
+ libexecdir = cache;
+ else
+ libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
+ if (NULL == libexecdir)
+ return GNUNET_strdup (progname);
+ GNUNET_asprintf (&binary,
+ "%s%s",
+ libexecdir,
+ progname);
+ cache = libexecdir;
+ return binary;
+}
+
+
+
+/* end of os_installation.c */
diff --git a/src/util/util.c b/src/util/util.c
index f2ff01d0f..5c1e5eb9a 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -29,6 +29,34 @@
#include <gcrypt.h>
+/**
+ * Obtain denomination amount from configuration file.
+ *
+ * @param section section of the configuration to access
+ * @param option option of the configuration to access
+ * @param denom[OUT] set to the amount found in configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ const char *option,
+ struct TALER_Amount *denom)
+{
+ char *str;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ option,
+ &str))
+ return GNUNET_NO;
+ if (GNUNET_OK != TALER_string_to_amount (str,
+ denom))
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
/**
* Load configuration by parsing all configuration