static qeo_mgmt_client_retcode_t retrieve_url_list(qeo_mgmt_url_ctx_t ctx, qeo_mgmt_client_ssl_ctx_cb ssl_cb, void *ssl_cookie, const char* base_url){ qeo_mgmt_client_retcode_t rc = QMGMTCLIENT_EFAIL; char* data = NULL; size_t length = 0; do { rc = qeo_mgmt_curl_util_https_get(ctx->curl_ctx, base_url, QMGMTCLIENT_ACCEPT_HEADER_JSON, ssl_cb, ssl_cookie, &data, &length); if (rc != QMGMTCLIENT_OK){ //qeo_log_w("Failed to retrieve root resource."); printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>retrieve_url_list failed https_get %d\n", rc); break; } rc = parse_root_resource(ctx, data, length); if (rc != QMGMTCLIENT_OK){ printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>retrieve_url_list failed parse %d, '%s'\n", rc, data); qeo_log_w("Failed to parse root resource."); break; } } while(0); free(data); return rc; }
qeo_mgmt_client_retcode_t parse_root_resource(qeo_mgmt_url_ctx_t ctx, char* message, size_t length){ int i = 0; qeo_mgmt_client_retcode_t rc = QMGMTCLIENT_EFAIL; do { qeo_mgmt_json_hdl_t hdl = qeo_mgmt_json_util_parse_message(message, length); if (hdl == NULL){ break; } for (i = 0; i < sizeof(url_describers) / sizeof(url_describers[0]); ++i) { const char *query[ROOT_RESOURCE_URL_MAX_DEPTH + 1] = { 0 }; size_t j = 0; if (url_describers[i].service != NULL ) { query[j] = url_describers[i].service; j++; if (url_describers[i].entrypoint != NULL ) { query[j] = url_describers[i].entrypoint; j++; } } query[j++] = ROOT_RESOURCE_URL_TAG; rc = qeo_mgmt_json_util_get_string(hdl, query, j, &ctx->values[i]); if (rc != QMGMTCLIENT_OK){ qeo_log_w("Failed to retrieve url from %s->%s", (query[0] == NULL) ? "":query[0], (query[1] == NULL) ? "":query[1]); /* Be liberal, just continue */ rc = QMGMTCLIENT_OK; } } qeo_mgmt_json_util_release_handle(hdl); }while(0); return rc; }
qeo_mgmt_client_retcode_t qeo_mgmt_url_get(qeo_mgmt_url_ctx_t ctx, qeo_mgmt_client_ssl_ctx_cb ssl_cb, void *ssl_cookie, const char* base_url, qeo_mgmt_url_type_t service, const char** url){ qeo_mgmt_client_retcode_t rc = QMGMTCLIENT_EINVAL; do { if ((url == NULL) || (base_url == NULL) || (ctx == NULL) || (ctx->curl_ctx == NULL)){ break; } if (!ctx->init){ rc = retrieve_url_list(ctx, ssl_cb, ssl_cookie, base_url); if (rc != QMGMTCLIENT_OK){ printf("qeo_mgmt_url_get: retrieve_url_list failed %d\n",rc); break; } ctx->init = true; } *url = get_url(ctx, service); if (*url == NULL){ rc = QMGMTCLIENT_EBADSERVICE; qeo_log_w("URL for specified service could not be found."); break; } rc = QMGMTCLIENT_OK; } while(0); return rc; }
X509_NAME* cnhelper_create_dn(const qeo_platform_device_info *info) { X509_NAME* dn = NULL; do { dn = X509_NAME_new(); if (dn) { char devicename[MAX_CN_LENGTH]; strncpy(devicename, info->userFriendlyName, sizeof(devicename)); if (devicename[sizeof(devicename)-1] != '\0'){ strncpy(&devicename[sizeof(devicename)-4], "...", 4); qeo_log_w("Device name exceeds the maximal allowed length of <%d> characters, cutting it off to <%s>.", sizeof(devicename)-1, devicename); } //TODO: now only the friendly name is forwarded to the server, in the future this needs to be extended if (!X509_NAME_add_entry_by_NID(dn, NID_commonName, MBSTRING_ASC, (unsigned char* ) devicename, -1, -1, 0)) { X509_NAME_free(dn); dn = NULL; break; } } qeo_log_d("created DN for device"); } while (0); return dn; }
qeo_mgmt_client_retcode_t qeo_mgmt_json_util_get_string(qeo_mgmt_json_hdl_t hdl, const char **query, size_t nrquery, qeo_mgmt_client_json_value_t *value){ qeo_mgmt_client_retcode_t rc = QMGMTCLIENT_EINVAL; json_t* node = NULL; json_t* deprecation = NULL; int i = 0; const char* buf = NULL; do { if ((hdl == NULL) || (nrquery <= 0) || (query == NULL) || (*query == NULL) || (value == NULL)){ break; } value->deprecated=false; node = hdl->node; while (i < nrquery){ deprecation = json_object_get(node, QEO_MGMT_CLIENT_DEPRECATION); node = json_object_get(node, query[i]); if (node == NULL){ break; } if (deprecation != NULL){ value->deprecated=true; } i++; } if (node == NULL) { rc = QMGMTCLIENT_EFAIL; qeo_log_w("Failed to retrieve json object (%s)", query[i]); break; } if (!json_is_string(node)) { qeo_log_w("Expected string but found another json type (%d)", json_typeof(node)); break; } buf = json_string_value(node); if (buf == NULL){ break; } value->value = strdup(buf); if (value->value == NULL){ rc = QMGMTCLIENT_EMEM; break; } rc = QMGMTCLIENT_OK; } while(0); return rc; }
void qmc_clean_ongoing_thread(qeo_mgmt_client_ctx_t *ctx){ if (ctx->join_thread == true){ qeo_log_i("Waiting for worker thread to shut down"); if (pthread_join(ctx->worker_thread, NULL) != 0){ qeo_log_w("Failed to join worker thread"); } ctx->join_thread = false; } }
qeo_mgmt_client_retcode_t qeo_mgmt_curl_util_https_get_with_cb(qeo_mgmt_client_ctx_t *mg_ctx, const char* url, char *header, qeo_mgmt_client_ssl_ctx_cb ssl_cb, void *ssl_cookie, curl_write_callback data_cb, void *write_cookie) { curl_ssl_ctx_helper curlsslhelper = { ssl_cb, ssl_cookie }; qeo_mgmt_client_retcode_t ret = QMGMTCLIENT_EFAIL; const char *cafile = NULL; const char *capath = NULL; //Setting CURLOPT_CAINF and PATH is mandatory; otherwise SSL_CTX_FUNCTION will not be called. curl_opt_helper opts[] = { { CURLOPT_SSL_VERIFYHOST, (void*)2 }, /* ensure certificate matches host */ { CURLOPT_SSL_VERIFYPEER, (void*)0 }, /* ensure certificate is valid */ { CURLOPT_CAINFO, NULL }, { CURLOPT_CAPATH, NULL }, { CURLOPT_SSL_CTX_FUNCTION, (void*)qeo_mgmt_curl_sslctx_cb }, { CURLOPT_SSL_CTX_DATA, (void*)&curlsslhelper } }; bool reset = false; do { if ((mg_ctx == NULL ) || (mg_ctx->curl_ctx == NULL) || (url == NULL) || (ssl_cb == NULL) || (data_cb == NULL)){ ret = QMGMTCLIENT_EINVAL; break; } if (QEO_UTIL_OK != qeo_platform_get_cacert_path(&cafile, &capath)) { ret = QMGMTCLIENT_EFAIL; break; } /* insert values into options array */ opts[2].cookie = (void*)cafile; opts[3].cookie = (void*)capath; reset = true; if (CURLE_OK != qeo_mgmt_curl_util_set_opts(opts, sizeof(opts) / sizeof(curl_opt_helper), mg_ctx)) { ret = QMGMTCLIENT_EINVAL; break; } ret = qeo_mgmt_curl_util_http_get_with_cb(mg_ctx, url, header, data_cb, write_cookie); reset = false;/* Already done. */ } while (0); if (reset == true){ /* Make sure we reset all configuration for next calls */ curl_easy_reset(mg_ctx->curl_ctx); } if (ret != QMGMTCLIENT_OK) { qeo_log_w("Failure in https_get_%s",url); } return ret; }
/* * Intentionally made non static for unit testing. */ size_t _write_to_memory_cb( char *buffer, size_t size, size_t nmemb, void *outstream){ qmgmt_curl_data_helper *data = (qmgmt_curl_data_helper *)outstream; size_t totalsize = size * nmemb; char *buf = NULL; size_t newlength = 0; size_t result = 0; do { if (totalsize == 0){ break; } while (totalsize >= data->length - data->offset) { if (data->length >= DATA_MEMM_MAX) { qeo_log_w("Returned amount of data is too much, exceeding %d", DATA_MEMM_MAX); break; } if (data->length == 0){ newlength = DATA_MEMM_MIN; } else { newlength = data->length*2; } buf = realloc(data->data, newlength); if (buf == NULL ) { qeo_log_w("Could not allocate buffer of %d bytes", newlength); break; } data->data = buf; data->length = newlength; } if (totalsize >= data->length - data->offset) break; memcpy(data->data+data->offset, buffer, totalsize); data->offset+=totalsize; buf=data->data+data->offset; *buf = '\0';/*Make it always null terminated. */ result=totalsize; } while (0); return result; }
static const char* get_url(qeo_mgmt_url_ctx_t ctx, qeo_mgmt_url_type_t type){ int i = 0; for (i = 0; i < sizeof(url_describers)/sizeof(url_describers[0]); ++i) { if (type == url_describers[i].type){ if (ctx->values[i].deprecated == true){ qeo_log_w("You are using a deprecated service of the public server, it might no longer be available in the future."); } return ctx->values[i].value; } } return NULL; }
static qeo_util_retcode_t default_registration_params_needed(uintptr_t app_context, qeo_platform_security_context_t context){ qeo_util_retcode_t retval = QEO_UTIL_OK; char *rrf = NULL; if ((rrf = getenv("REMOTE_REGISTRATION_FILE")) != NULL){ if (remote_registration(context, rrf) != QEO_UTIL_OK){ qeo_log_w("Fallback to prompt"); return cli_otc_url(context); } } else { return cli_otc_url(context); } return retval; }
qeo_mgmt_json_hdl_t qeo_mgmt_json_util_parse_message(const char* message, size_t length){ json_error_t json_error; qeo_mgmt_json_hdl_t result = NULL; do { if (message == NULL){ break; } result = (qeo_mgmt_json_hdl_t) calloc(1, sizeof(struct qeo_mgmt_json_hdl_s)); if (result == NULL){ break; } result->node = json_loadb(message, length, JSON_REJECT_DUPLICATES, &json_error); if (result->node == NULL) { qeo_log_w("Failed to parse json message %s (%s:%d:%d)", json_error.text, json_error.source, json_error.line, json_error.column); free(result); result = NULL; break; } } while(0); return result; }
qeo_mgmt_client_retcode_t qeo_mgmt_json_util_parseGetFWDMessage(const char* data, ssize_t length, qeo_mgmt_client_forwarder_cb callback, void* cookie) { json_error_t json_error = {0}; qeo_mgmt_client_retcode_t result = QMGMTCLIENT_EBADREPLY; json_t* message = json_loadb(data, length, JSON_REJECT_DUPLICATES, &json_error); qeo_mgmt_client_forwarder_t* fwd = NULL; do { json_t* fwdArray; ssize_t fwdSize; ssize_t i; if (message == NULL) { qeo_log_w("Failed to parse json message %s (%s:%d:%d)", json_error.text, json_error.source, json_error.line, json_error.column); qeo_log_w("Data = (%s)", data); //JSON parsing error break; } if (!json_is_object(message)) { qeo_log_w("invalid message received - top level is not a JSON object"); break; } fwdArray = json_object_get(message, "forwarders"); if (fwdArray == NULL || !json_is_array(fwdArray)) { qeo_log_w("root object did not contain a field 'forwarders' of type array (%p)", fwdArray); } fwdSize = json_array_size(fwdArray); qeo_log_i("Found an array of %d forwarder(s) in message\n", fwdSize); for (i = 0; i < fwdSize; i++) { qeo_mgmt_client_retcode_t cb_result; json_t* fwdObject = json_array_get(fwdArray, i); json_t* idString; json_t* locatorArray; ssize_t nrOfLocators; ssize_t j; if (!json_is_object(fwdObject)) { qeo_log_w("unexpected content in fwdArray - object expected"); break; } idString = json_object_get(fwdObject, "id"); if (idString == NULL || !json_is_string(idString)) { qeo_log_w("forwarder object did not contain a string field called 'id' (%p)", idString); break; } locatorArray = json_object_get(fwdObject, "locators"); if (locatorArray == NULL || !json_is_array(locatorArray)) { qeo_log_w("forwarder object did not contain an array field called 'nrOfLocators' (%p)", locatorArray); break; } nrOfLocators = json_array_size(locatorArray); qeo_log_i("found forwarder with id='%s' and %d locator(s)", json_string_value(idString), nrOfLocators); fwd = malloc(sizeof(qeo_mgmt_client_forwarder_t)); if (fwd == NULL) { qeo_log_w("fwd == NULL"); result = QMGMTCLIENT_EMEM; break; } fwd->nrOfLocators = nrOfLocators; fwd->locators = calloc(nrOfLocators, sizeof(qeo_mgmt_client_locator_t)); fwd->deviceID = qeo_mgmt_util_hex_to_int(json_string_value(idString)); if (fwd->deviceID == -1){ qeo_log_w("Invalid device id inside json message"); break; } if (fwd->locators == NULL) { qeo_log_w("fwd->locators == NULL"); result = QMGMTCLIENT_EMEM; break; } for (j = 0; j < nrOfLocators; j++) { json_t* endpointObj = json_array_get(locatorArray, j); json_t* typeString = json_object_get(endpointObj,"type"); json_t* addrString = json_object_get(endpointObj,"address"); json_t* portInt = json_object_get(endpointObj,"port"); if (portInt == NULL || !json_is_integer(portInt)) { qeo_log_w("locator object did not contain a integer field called 'port' (%p)", portInt); break; } if (addrString == NULL || !json_is_string(addrString)) { qeo_log_w("locator object did not contain a string field called 'address' (%p)", addrString); break; } if (typeString == NULL || !json_is_string(typeString)) { qeo_log_w("locator object did not contain a string field called 'type' (%p)", typeString); break; } qeo_log_i("locator object %d = {type = '%s', address = '%s', port = %d}", j, json_string_value(typeString), json_string_value(addrString), (int) json_integer_value(portInt)); //valid locator fwd->locators[j].port = (int) json_integer_value(portInt); if (fwd->locators[j].port < -1 || fwd->locators[j].port > 0xffff){ qeo_log_w("Invalid port inside locator"); break; } fwd->locators[j].type = _get_locator_type(json_string_value(typeString)); fwd->locators[j].address = strdup(json_string_value(addrString)); //check value; don't forget to free! if (fwd->locators[j].address == NULL) { qeo_log_w("locator->address == NULL"); break; } } if (j != nrOfLocators){ break; } cb_result = callback(fwd, cookie); fwd = NULL; //pointer is handed over; set it to NULL so we wont free it. if (cb_result != QMGMTCLIENT_OK) {//the callback reports an error abort. result = cb_result; break; } } if (i != fwdSize){ break; } qeo_log_i("Successfully walked JSON object tree..."); result = QMGMTCLIENT_OK; } while(0); if (message) { json_decref(message); } if (fwd) { //if an error occurred, then the 'fwd' is not freed. qeo_mgmt_client_free_forwarder(fwd); } return result; }
qeo_mgmt_client_retcode_t qeo_mgmt_json_util_formatLocatorData(qeo_mgmt_client_locator_t *locators, u_int32_t nrOfLocators, char **message, size_t *length) { int i = 0; qeo_mgmt_client_retcode_t rc = QMGMTCLIENT_EFAIL; //TODO: should there be a limitation on the number of locators that can be registered? json_t* msg = NULL; json_t* array = json_array(); json_error_t json_error = {0}; do { for (i = 0; i < nrOfLocators; i++) { const char* typeString = _get_locator_string(locators[i].type); json_t *entry = NULL; if (locators[i].port < -1 || locators[i].port > 0xffff || typeString == NULL || locators[i].address == NULL) { //-1 is allowed representing the default port. rc = QMGMTCLIENT_EINVAL; break; } entry = json_pack_ex(&json_error, 0, "{sssssi}", "type", typeString, "address", locators[i].address, "port", (int)locators[i].port); if (entry == NULL ) { qeo_log_w("Failed to create json locator object %s (%s:%d:%d)", json_error.text, json_error.source, json_error.line, json_error.column); break; } if (json_array_append_new(array, entry) == -1){ rc = QMGMTCLIENT_EMEM; json_decref(entry); break; } } if (i != nrOfLocators){ break; } msg = json_pack_ex(&json_error, 0, "{so}", "locators", array); if (msg == NULL ) { qeo_log_w("Failed to create json locators list %s (%s:%d:%d)", json_error.text, json_error.source, json_error.line, json_error.column); break; } array = NULL; /* No need to free it anymore */ *message = json_dumps(msg, JSON_PRESERVE_ORDER); //data can be NULL in case of error. If not NULL data should be freed! if (*message == NULL) { rc = QMGMTCLIENT_EMEM; break; } *length = strlen(*message); rc = QMGMTCLIENT_OK; } while (0); if (msg != NULL){ json_decref(msg); } if (array != NULL){ json_decref(array); } return rc; }
static qeo_mgmt_client_retcode_t qeo_mgmt_curl_util_https_put_with_cb(qeo_mgmt_client_ctx_t *mg_ctx, const char* url, char *header, qeo_mgmt_client_ssl_ctx_cb ssl_cb, void *ssl_cookie, curl_read_callback data_cb, void *read_cookie, intptr_t length) { curl_ssl_ctx_helper curlsslhelper = { ssl_cb, ssl_cookie }; char correlation_id[CURL_UTIL_CORRELATION_ID_MAX_SIZE]; qeo_mgmt_client_retcode_t ret = QMGMTCLIENT_EFAIL; struct curl_slist *chunk = (header != NULL)?curl_slist_append(NULL, header):NULL; long http_status = 0; curl_opt_helper opts[] = { { CURLOPT_INFILESIZE, (void*) length }, /* keep this at index 0; value is update in code */ { CURLOPT_UPLOAD, (void*)1 }, { CURLOPT_READFUNCTION, (void*) data_cb }, { CURLOPT_READDATA, (void*)read_cookie}, { CURLOPT_HTTPHEADER, (void*) chunk}, { CURLOPT_SSL_VERIFYPEER, (void*)0 }, { CURLOPT_SSL_CTX_FUNCTION, (void*)qeo_mgmt_curl_sslctx_cb }, { CURLOPT_SSL_CTX_DATA, (void*)&curlsslhelper }, }; bool reset = false; do { CURL* ctx; if ((mg_ctx == NULL ) || (mg_ctx->curl_ctx == NULL) || (url == NULL) || (ssl_cb == NULL) || (data_cb == NULL)){ ret = QMGMTCLIENT_EINVAL; break; } ctx = mg_ctx->curl_ctx; reset = true; if (CURLE_OK != qeo_mgmt_curl_util_set_opts(opts, sizeof(opts) / sizeof(curl_opt_helper), mg_ctx)) { ret = QMGMTCLIENT_EINVAL; break; } ret = qeo_mgmt_curl_util_perform(ctx, url, correlation_id); if (curl_easy_getinfo(ctx, CURLINFO_RESPONSE_CODE, &http_status) == CURLE_OK) { qeo_log_d("returned status code %ld", http_status); if (http_status >= 400){ ret = qeo_mgmt_curl_util_translate_rc(CURLE_HTTP_RETURNED_ERROR); curl_util_log_http_error_description(ctx, correlation_id); break; } } } while (0); if (reset == true){ /* Make sure we reset all configuration for next calls */ curl_easy_reset(mg_ctx->curl_ctx); } if (chunk != NULL){ curl_slist_free_all(chunk); } if (ret != QMGMTCLIENT_OK) { qeo_log_w("Failure in https_put_%s",url); } return ret; }
qeo_mgmt_client_retcode_t qeo_mgmt_curl_util_http_get_with_cb(qeo_mgmt_client_ctx_t* mg_ctx, const char* url, char *header, curl_write_callback data_cb, void *write_cookie){ qeo_mgmt_client_retcode_t ret = QMGMTCLIENT_EFAIL; struct curl_slist *chunk = (header != NULL)?curl_slist_append(NULL, header):NULL; long http_status = 0; char correlation_id[CURL_UTIL_CORRELATION_ID_MAX_SIZE]; curl_opt_helper opts[] = { { CURLOPT_WRITEFUNCTION, (void*) data_cb }, { CURLOPT_WRITEDATA, (void*)write_cookie}, { CURLOPT_FAILONERROR, (void*)1 }, { CURLOPT_HTTPHEADER, (void*) chunk}}; bool reset = false; do { CURL* ctx; if ((mg_ctx == NULL) || (mg_ctx->curl_ctx == NULL) || (url == NULL) || (data_cb == NULL)){ ret = QMGMTCLIENT_EINVAL; break; } ctx = mg_ctx->curl_ctx; if ((header != NULL) && (chunk == NULL)) { ret = QMGMTCLIENT_EMEM; break; } reset = true; if (CURLE_OK != qeo_mgmt_curl_util_set_opts(opts, sizeof(opts) / sizeof(curl_opt_helper), mg_ctx)) { ret = QMGMTCLIENT_EINVAL; break; } qeo_log_i("Start fetching data from <%s>", url); ret = qeo_mgmt_curl_util_perform(ctx, url, NULL); if (ret != QMGMTCLIENT_OK) { break; } if (curl_easy_getinfo(ctx, CURLINFO_RESPONSE_CODE, &http_status) == CURLE_OK) { if (http_status >= 400){ ret = qeo_mgmt_curl_util_translate_rc(CURLE_HTTP_RETURNED_ERROR); curl_util_log_http_error_description(ctx, correlation_id); break; } } qeo_log_i("Successfully downloaded data"); } while (0); if (reset == true){ /* Make sure we reset all configuration for next calls */ curl_easy_reset(mg_ctx->curl_ctx); } if (chunk != NULL){ curl_slist_free_all(chunk); } if (ret != QMGMTCLIENT_OK) { qeo_log_w("Failure getting %s",url); } return ret; }