diff options
Diffstat (limited to 'src/kyclogic')
-rw-r--r-- | src/kyclogic/Makefile.am | 6 | ||||
-rw-r--r-- | src/kyclogic/kyclogic-persona.conf | 4 | ||||
-rw-r--r-- | src/kyclogic/kyclogic_api.c | 9 | ||||
-rw-r--r-- | src/kyclogic/plugin_kyclogic_oauth2.c | 120 | ||||
-rw-r--r-- | src/kyclogic/plugin_kyclogic_persona.c | 374 | ||||
-rwxr-xr-x | src/kyclogic/taler-exchange-kyc-persona-converter.sh | 54 | ||||
-rw-r--r-- | src/kyclogic/taler-exchange-kyc-tester.c | 6 |
7 files changed, 307 insertions, 266 deletions
diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am index 858331f39..20430a4ea 100644 --- a/src/kyclogic/Makefile.am +++ b/src/kyclogic/Makefile.am @@ -16,7 +16,11 @@ pkgcfg_DATA = \ EXTRA_DIST = \ $(pkgcfg_DATA) \ - sample.conf + sample.conf \ + persona-sample-reply.json + +bin_SCRIPTS = \ + taler-exchange-kyc-persona-converter.sh lib_LTLIBRARIES = \ libtalerkyclogic.la diff --git a/src/kyclogic/kyclogic-persona.conf b/src/kyclogic/kyclogic-persona.conf index 7f02bf498..2d52a9ee0 100644 --- a/src/kyclogic/kyclogic-persona.conf +++ b/src/kyclogic/kyclogic-persona.conf @@ -29,6 +29,10 @@ KYC_PERSONA_SUBDOMAIN = taler # Authentication token to use. KYC_PERSONA_AUTH_TOKEN = persona_sandbox_42 +# Program that converts Persona KYC data into the +# GNU Taler format. +KYC_PERSONA_CONVERTER_HELPER = taler-exchange-kyc-persona-converter.sh + # Form to use. KYC_PERSONA_TEMPLATE_ID = itempl_Uj6Xxxxx diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c index 0ef1295ed..65f3f3ba3 100644 --- a/src/kyclogic/kyclogic_api.c +++ b/src/kyclogic/kyclogic_api.c @@ -780,10 +780,11 @@ TALER_KYCLOGIC_kyc_init (const struct GNUNET_CONFIGURATION_Handle *cfg) TALER_KYCLOGIC_kyc_done (); return GNUNET_SYSERR; } - qsort (kyc_triggers, - num_kyc_triggers, - sizeof (struct TALER_KYCLOGIC_KycTrigger *), - &sort_by_timeframe); + if (0 != num_kyc_triggers) + qsort (kyc_triggers, + num_kyc_triggers, + sizeof (struct TALER_KYCLOGIC_KycTrigger *), + &sort_by_timeframe); return GNUNET_OK; } diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c index 228525e28..c72b04b7c 100644 --- a/src/kyclogic/plugin_kyclogic_oauth2.c +++ b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -490,8 +490,6 @@ initiate_task (void *cls) struct PluginState *ps = pd->ps; char *hps; char *url; - char *redirect_uri; - char *redirect_uri_encoded; char legi_s[42]; ih->task = NULL; @@ -501,19 +499,27 @@ initiate_task (void *cls) (unsigned long long) ih->legitimization_uuid); hps = GNUNET_STRINGS_data_to_string_alloc (&ih->h_payto, sizeof (ih->h_payto)); - GNUNET_asprintf (&redirect_uri, - "%skyc-proof/%s?state=%s", - ps->exchange_base_url, - pd->section, - hps); - redirect_uri_encoded = TALER_urlencode (redirect_uri); - GNUNET_free (redirect_uri); - GNUNET_asprintf (&url, - "%s?response_type=code&client_id=%s&redirect_uri=%s", - pd->login_url, - pd->client_id, - redirect_uri_encoded); - GNUNET_free (redirect_uri_encoded); + { + char *redirect_uri_encoded; + + { + char *redirect_uri; + + GNUNET_asprintf (&redirect_uri, + "%skyc-proof/%s?state=%s", + ps->exchange_base_url, + pd->section, + hps); + redirect_uri_encoded = TALER_urlencode (redirect_uri); + GNUNET_free (redirect_uri); + } + GNUNET_asprintf (&url, + "%s?response_type=code&client_id=%s&redirect_uri=%s", + pd->login_url, + pd->client_id, + redirect_uri_encoded); + GNUNET_free (redirect_uri_encoded); + } /* FIXME-API: why do we *redirect* the client here, instead of making the HTTP request *ourselves* and forwarding the response? This prevents us @@ -583,6 +589,37 @@ oauth2_initiate_cancel (struct TALER_KYCLOGIC_InitiateHandle *ih) /** + * Cancel KYC proof. + * + * @param[in] ph handle of operation to cancel + */ +static void +oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) +{ + if (NULL != ph->task) + { + GNUNET_SCHEDULER_cancel (ph->task); + ph->task = NULL; + } + if (NULL != ph->job) + { + GNUNET_CURL_job_cancel (ph->job); + ph->job = NULL; + } + if (NULL != ph->response) + { + MHD_destroy_response (ph->response); + ph->response = NULL; + } + GNUNET_free (ph->provider_user_id); + if (NULL != ph->attributes) + json_decref (ph->attributes); + GNUNET_free (ph->post_body); + GNUNET_free (ph); +} + + +/** * Function called to asynchronously return the final * result to the callback. * @@ -602,10 +639,8 @@ return_proof_response (void *cls) ph->attributes, ph->http_status, ph->response); - GNUNET_free (ph->provider_user_id); - if (NULL != ph->attributes) - json_decref (ph->attributes); - GNUNET_free (ph); + ph->response = NULL; /*Ownership passed to 'ph->cb'!*/ + oauth2_proof_cancel (ph); } @@ -1101,7 +1136,6 @@ oauth2_proof (void *cls, 1)); { char *client_id; - char *redirect_uri; char *client_secret; char *authorization_code; char *redirect_uri_encoded; @@ -1109,13 +1143,17 @@ oauth2_proof (void *cls, hps = GNUNET_STRINGS_data_to_string_alloc (&ph->h_payto, sizeof (ph->h_payto)); - GNUNET_asprintf (&redirect_uri, - "%skyc-proof/%s?state=%s", - ps->exchange_base_url, - pd->section, - hps); - redirect_uri_encoded = TALER_urlencode (redirect_uri); - GNUNET_free (redirect_uri); + { + char *redirect_uri; + + GNUNET_asprintf (&redirect_uri, + "%skyc-proof/%s?state=%s", + ps->exchange_base_url, + pd->section, + hps); + redirect_uri_encoded = TALER_urlencode (redirect_uri); + GNUNET_free (redirect_uri); + } GNUNET_assert (NULL != redirect_uri_encoded); client_id = curl_easy_escape (ph->eh, pd->client_id, @@ -1165,34 +1203,6 @@ oauth2_proof (void *cls, /** - * Cancel KYC proof. - * - * @param[in] ph handle of operation to cancel - */ -static void -oauth2_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) -{ - if (NULL != ph->task) - { - GNUNET_SCHEDULER_cancel (ph->task); - ph->task = NULL; - } - if (NULL != ph->job) - { - GNUNET_CURL_job_cancel (ph->job); - ph->job = NULL; - } - if (NULL != ph->response) - { - MHD_destroy_response (ph->response); - ph->response = NULL; - } - GNUNET_free (ph->post_body); - GNUNET_free (ph); -} - - -/** * Function to asynchronously return the 404 not found * page for the webhook. * diff --git a/src/kyclogic/plugin_kyclogic_persona.c b/src/kyclogic/plugin_kyclogic_persona.c index 4f01ae40e..e14a50390 100644 --- a/src/kyclogic/plugin_kyclogic_persona.c +++ b/src/kyclogic/plugin_kyclogic_persona.c @@ -112,6 +112,12 @@ struct TALER_KYCLOGIC_ProviderDetails char *subdomain; /** + * Name of the program we use to convert outputs + * from Persona into our JSON inputs. + */ + char *conversion_binary; + + /** * Where to redirect the client upon completion. */ char *post_kyc_redirect_url; @@ -231,6 +237,12 @@ struct TALER_KYCLOGIC_ProofHandle char *url; /** + * Handle to an external process that converts the + * Persona response to our internal format. + */ + struct TALER_JSON_ExternalConversion *ec; + + /** * Hash of the payto:// URI we are checking the KYC for. */ struct TALER_PaytoHashP h_payto; @@ -247,6 +259,11 @@ struct TALER_KYCLOGIC_ProofHandle char *provider_user_id; /** + * Account ID from the service. + */ + char *account_id; + + /** * Inquiry ID at the provider. */ char *inquiry_id; @@ -295,6 +312,11 @@ struct TALER_KYCLOGIC_WebhookHandle char *inquiry_id; /** + * Account ID from the service. + */ + char *account_id; + + /** * URL of the cURL request. */ char *url; @@ -316,6 +338,12 @@ struct TALER_KYCLOGIC_WebhookHandle const char *template_id; /** + * Handle to an external process that converts the + * Persona response to our internal format. + */ + struct TALER_JSON_ExternalConversion *ec; + + /** * Our account ID. */ struct TALER_PaytoHashP h_payto; @@ -344,6 +372,7 @@ persona_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd) GNUNET_free (pd->auth_token); GNUNET_free (pd->template_id); GNUNET_free (pd->subdomain); + GNUNET_free (pd->conversion_binary); GNUNET_free (pd->salt); GNUNET_free (pd->section); GNUNET_free (pd->post_kyc_redirect_url); @@ -421,6 +450,18 @@ persona_load_configuration (void *cls, if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (ps->cfg, provider_section_name, + "KYC_PERSONA_CONVERTER_HELPER", + &pd->conversion_binary)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + provider_section_name, + "KYC_PERSONA_CONVERTER_HELPER"); + persona_unload_configuration (pd); + return NULL; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (ps->cfg, + provider_section_name, "KYC_PERSONA_POST_URL", &pd->post_kyc_redirect_url)) { @@ -838,8 +879,14 @@ persona_proof_cancel (struct TALER_KYCLOGIC_ProofHandle *ph) GNUNET_CURL_job_cancel (ph->job); ph->job = NULL; } + if (NULL != ph->ec) + { + TALER_JSON_external_conversion_stop (ph->ec); + ph->ec = NULL; + } GNUNET_free (ph->url); GNUNET_free (ph->provider_user_id); + GNUNET_free (ph->account_id); GNUNET_free (ph->inquiry_id); GNUNET_free (ph); } @@ -923,161 +970,6 @@ proof_reply_error (struct TALER_KYCLOGIC_ProofHandle *ph, /** - * Convert KYC attribute data from Persona response. - * - * @param attr json array with Persona attribute data - * @return KYC attribute data - */ -static json_t * -convert_attributes (const json_t *attr) -{ - const char *country_code = NULL; - const char *name_first = NULL; - const char *name_middle = NULL; - const char *name_last = NULL; - const char *address_street_1 = NULL; - const char *address_street_2 = NULL; - const char *address_city = NULL; - const char *address_postal_code = NULL; - const char *birthdate = NULL; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("country-code", - &country_code), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("name-first", - &name_first), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("name-middle", - &name_middle), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("name-last", - &name_last), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-street-1", - &address_street_1), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-street-2", - &address_street_2), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-city", - &address_city), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("address-postal-code", - &address_postal_code), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("birthdate", - &birthdate), - NULL), - GNUNET_JSON_spec_end () - }; - json_t *ret; - - if (GNUNET_OK != - GNUNET_JSON_parse (attr, - spec, - NULL, NULL)) - { - GNUNET_break (0); - json_dumpf (attr, - stderr, - JSON_INDENT (2)); - return NULL; - } - { - char *name = NULL; - char *street = NULL; - char *city = NULL; - - if ( (NULL != name_last) || - (NULL != name_first) || - (NULL != name_middle) ) - { - GNUNET_asprintf (&name, - "%s, %s %s", - (NULL != name_last) - ? name_last - : "", - (NULL != name_first) - ? name_first - : "", - (NULL != name_middle) - ? name_middle - : ""); - } - if ( (NULL != address_city) || - (NULL != address_postal_code) ) - { - GNUNET_asprintf (&city, - "%s%s%s %s", - (NULL != country_code) - ? country_code - : "", - (NULL != country_code) - ? "-" - : "", - (NULL != address_postal_code) - ? address_postal_code - : "", - (NULL != address_city) - ? address_city - : ""); - } - if ( (NULL != address_street_1) || - (NULL != address_street_2) ) - { - GNUNET_asprintf (&street, - "%s%s%s", - (NULL != address_street_1) - ? address_street_1 - : "", - ( (NULL != address_street_1) && - (NULL != address_street_2) ) - ? "\n" - : "", - (NULL != address_street_2) - ? address_street_2 - : ""); - } - ret = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_BIRTHDATE, - birthdate)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_FULL_NAME, - name)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_ADDRESS_STREET, - street)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_ADDRESS_CITY, - city)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ( - TALER_ATTRIBUTE_RESIDENCES, - country_code)) - ); - GNUNET_free (street); - GNUNET_free (city); - GNUNET_free (name); - } - return ret; -} - - -/** * Return a response for the @a ph request indicating a * protocol violation by the Persona server. * @@ -1116,6 +1008,86 @@ return_invalid_response (struct TALER_KYCLOGIC_ProofHandle *ph, /** + * Start the external conversion helper. + * + * @param pd configuration details + * @param attr attributes to give to the helper + * @param cb function to call with the result + * @param cb_cls closure for @a cb + * @return handle for the helper + */ +static struct TALER_JSON_ExternalConversion * +start_conversion (const struct TALER_KYCLOGIC_ProviderDetails *pd, + const json_t *attr, + TALER_JSON_JsonCallback cb, + void *cb_cls) +{ + return TALER_JSON_external_conversion_start ( + attr, + cb, + cb_cls, + pd->conversion_binary, + pd->conversion_binary, + "-a", + pd->auth_token, + NULL + ); +} + + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure with a `struct TALER_KYCLOGIC_ProofHandle *` + * @param status_type how did the process die + * @param code termination status code from the process + * @param attr result some JSON result, NULL if we failed to get an JSON output + */ +static void +proof_post_conversion_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *attr) +{ + struct TALER_KYCLOGIC_ProofHandle *ph = cls; + struct MHD_Response *resp; + struct GNUNET_TIME_Absolute expiration; + + ph->ec = NULL; + if ( (NULL == attr) || + (0 != code) ) + { + GNUNET_break_op (0); + return_invalid_response (ph, + MHD_HTTP_OK, + ph->inquiry_id, + "converter", + NULL); + persona_proof_cancel (ph); + return; + } + expiration = GNUNET_TIME_relative_to_absolute (ph->pd->validity); + resp = MHD_create_response_from_buffer (0, + "", + MHD_RESPMEM_PERSISTENT); + GNUNET_break (MHD_YES == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_LOCATION, + ph->pd->post_kyc_redirect_url)); + TALER_MHD_add_global_headers (resp); + ph->cb (ph->cb_cls, + TALER_KYCLOGIC_STATUS_SUCCESS, + ph->account_id, + ph->inquiry_id, + expiration, + attr, + MHD_HTTP_SEE_OTHER, + resp); + persona_proof_cancel (ph); +} + + +/** * Function called when we're done processing the * HTTP "/api/v1/inquiries/{inquiry-id}" request. * @@ -1283,46 +1255,15 @@ handle_proof_finished (void *cls, data); break; } - - { - struct MHD_Response *resp; - struct GNUNET_TIME_Absolute expiration; - json_t *attr; - - attr = convert_attributes (attributes); - if (NULL == attr) - { - GNUNET_break_op (0); - return_invalid_response (ph, - response_code, - inquiry_id, - "data-relationships-account-data-id", - data); - break; - } - expiration = GNUNET_TIME_relative_to_absolute (ph->pd->validity); - resp = MHD_create_response_from_buffer (0, - "", - MHD_RESPMEM_PERSISTENT); - GNUNET_break (MHD_YES == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_LOCATION, - ph->pd->post_kyc_redirect_url)); - TALER_MHD_add_global_headers (resp); - ph->cb (ph->cb_cls, - TALER_KYCLOGIC_STATUS_SUCCESS, - account_id, - inquiry_id, - expiration, - attr, - MHD_HTTP_SEE_OTHER, - resp); - json_decref (attr); - } + ph->account_id = GNUNET_strdup (account_id); + ph->ec = start_conversion (ph->pd, + j, + &proof_post_conversion_cb, + ph); GNUNET_JSON_parse_free (ispec); } GNUNET_JSON_parse_free (spec); - break; + return; /* continued in proof_post_conversion_cb */ } case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_NOT_FOUND: @@ -1580,6 +1521,12 @@ persona_webhook_cancel (struct TALER_KYCLOGIC_WebhookHandle *wh) GNUNET_CURL_job_cancel (wh->job); wh->job = NULL; } + if (NULL != wh->ec) + { + TALER_JSON_external_conversion_stop (wh->ec); + wh->ec = NULL; + } + GNUNET_free (wh->account_id); GNUNET_free (wh->inquiry_id); GNUNET_free (wh->url); GNUNET_free (wh); @@ -1651,6 +1598,32 @@ webhook_reply_error (struct TALER_KYCLOGIC_WebhookHandle *wh, /** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure with a `struct TALER_KYCLOGIC_WebhookHandle *` + * @param status_type how did the process die + * @param code termination status code from the process + * @param attr some JSON result, NULL if we failed to get an JSON output + */ +static void +webhook_post_conversion_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *attr) +{ + struct TALER_KYCLOGIC_WebhookHandle *wh = cls; + + wh->ec = NULL; + webhook_generic_reply (wh, + TALER_KYCLOGIC_STATUS_SUCCESS, + wh->account_id, + wh->inquiry_id, + attr, + MHD_HTTP_OK); +} + + +/** * Function called when we're done processing the * HTTP "/api/v1/inquiries/{inquiry_id}" request. * @@ -1723,7 +1696,6 @@ handle_webhook_finished (void *cls, NULL), GNUNET_JSON_spec_end () }; - json_t *attr; if (GNUNET_OK != GNUNET_JSON_parse (attributes, @@ -1807,19 +1779,15 @@ handle_webhook_finished (void *cls, MHD_HTTP_BAD_GATEWAY); break; } - - attr = convert_attributes (attributes); - webhook_generic_reply (wh, - TALER_KYCLOGIC_STATUS_SUCCESS, - account_id, - inquiry_id, - attr, - MHD_HTTP_OK); - json_decref (attr); + wh->account_id = GNUNET_strdup (account_id); + wh->ec = start_conversion (wh->pd, + j, + &webhook_post_conversion_cb, + wh); GNUNET_JSON_parse_free (ispec); } GNUNET_JSON_parse_free (spec); - break; + return; /* continued in webhook_post_conversion_cb */ } case MHD_HTTP_BAD_REQUEST: case MHD_HTTP_NOT_FOUND: diff --git a/src/kyclogic/taler-exchange-kyc-persona-converter.sh b/src/kyclogic/taler-exchange-kyc-persona-converter.sh new file mode 100755 index 000000000..a5d4d03ac --- /dev/null +++ b/src/kyclogic/taler-exchange-kyc-persona-converter.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# This file is in the public domain. +# +# This code converts (some of) the JSON output from Persona into the GNU Taler +# specific KYC attribute data (again in JSON format). We may need to download +# and inline file data in the process, for authorization pass "-a" with the +# respective bearer token. +# + +# Die if anything goes wrong. +set -eu + +# Parse command-line options +while getopts ':a:' OPTION; do + case "$OPTION" in + a) + TOKEN="$OPTARG" + ;; + ?) + echo "Unrecognized command line option" + exit 1 + ;; + esac +done + + +# First, extract everything from stdin. +J=$(jq '{"first":.data.attributes."name-first","middle":.data.attributes."name-middle","last":.data.attributes."name-last","cc":.data.attributes.fields."address-country-code".value,"birthdate":.data.attributes.birthdate,"city":.data.attributes."address-city","postcode":.data.attributes."address-postal-code","street-1":.data.attributes."address-street-1","street-2":.data.attributes."address-street-2","address-subdivision":.data.attributes."address-subdivision","identification-number":.data.attributes."identification-number","photo":.included[]|select(.type=="verification/government-id")|.attributes|select(.status=="passed")|."front-photo-url"}') + + +# Next, combine some fields into larger values. +FULLNAME=$(echo "$J" | jq -r '[.first,.middle,.last]|join(" ")') +STREET=$(echo $J | jq -r '[."street-1",."street-2"]|join(" ")') +CITY=$(echo $J | jq -r '[.postcode,.city,."address-subdivision,.cc"]|join(" ")') + +# Download and base32-encode the photo +PHOTO_URL=$(echo "$J" | jq -r '.photo') +PHOTO_FILE=$(mktemp -t tmp.XXXXXXXXXX) +if [ -z "${TOKEN:-}" ] +then + wget -q --output-document=- "$PHOTO_URL" | gnunet-base32 > ${PHOTO_FILE} +else + wget -q --output-document=- --header "Authorization: Bearer $TOKEN" "$PHOTO_URL" | gnunet-base32 > ${PHOTO_FILE} +fi + +# Combine into final result. +echo "$J" | jq \ + --arg full_name "${FULLNAME}" \ + --arg street "${STREET}" \ + --arg city "${CITY}" \ + --rawfile photo "${PHOTO_FILE}" \ + '{$full_name,$street,$city,"birthdate":.birthdate,"residences":.cc,"identification_number":."identification-number",$photo}' + +exit 0 diff --git a/src/kyclogic/taler-exchange-kyc-tester.c b/src/kyclogic/taler-exchange-kyc-tester.c index 652d498c6..c2efafd72 100644 --- a/src/kyclogic/taler-exchange-kyc-tester.c +++ b/src/kyclogic/taler-exchange-kyc-tester.c @@ -990,9 +990,9 @@ proceed_with_handler (struct TEKT_RequestContext *rc, /* Parse command-line arguments */ /* make a copy of 'url' because 'strtok_r()' will modify */ - memcpy (d, - url, - ulen); + GNUNET_memcpy (d, + url, + ulen); i = 0; args[i++] = strtok_r (d, "/", &sp); while ( (NULL != args[i - 1]) && |