in src/utils/workflow_utils/src/workflow_utils.c [1242:1364]
ADUC_Result _workflow_parse(const JSON_Value* updateActionJson, bool validateManifest, ADUC_WorkflowHandle* handle)
{
ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 };
ADUC_Workflow* wf = NULL;
JSON_Value* updateActionJsonClone = NULL;
ADUCITF_UpdateAction updateAction = ADUCITF_UpdateAction_Undefined;
if (handle == NULL)
{
result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM;
return result;
}
*handle = NULL;
wf = malloc(sizeof(*wf));
if (wf == NULL)
{
result.ExtendedResultCode = ADUC_ERC_NOMEM;
goto done;
}
memset(wf, 0, sizeof(*wf));
updateActionJsonClone = json_value_deep_copy(updateActionJson);
updateActionJson = NULL;
// commit ownership of cloned JSON_Value to the workflow's UpdateActionObject.
wf->UpdateActionObject = json_value_get_object(updateActionJsonClone);
updateActionJsonClone = NULL;
// At this point, we have had a side-effect of committing to the
// wf->UpdateActionObject.
//
// Now, if not a cancel update action, then update the
// wf->UpdateManifestObj only after validating update manifest signature.
//
// After that, if a detached manifest exists in the manifest, then
// overwrite wf->UpdateManifestObj after downloading and verifying the
// detached manifest.
// 'cancel' action doesn't contains UpdateManifest and UpdateSignature.
// Skip this part.
workflow_parse_peek_unprotected_workflow_properties(
wf->UpdateActionObject,
&updateAction,
NULL /* outRootKeyPkgUrl_optional */,
NULL /* outWorkflowId_optional */);
if (updateAction != ADUCITF_UpdateAction_Cancel)
{
ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 };
// Skip signature validation if specified.
// Also, some (partial) action data may not contain an UpdateAction,
// e.g., Components-Update manifest that delivered as part of Bundle Updates,
// We will skip the validation for these cases.
if (updateAction != ADUCITF_UpdateAction_Undefined && validateManifest)
{
tmpResult = workflow_validate_update_manifest_signature(wf->UpdateActionObject);
if (IsAducResultCodeFailure(tmpResult.ResultCode))
{
result = tmpResult;
goto done;
}
}
tmpResult = UpdateWorkflowUpdateManifestObjFromUpdateActionObj(wf);
if (IsAducResultCodeFailure(tmpResult.ResultCode))
{
result = tmpResult;
goto done;
}
// Starting from version 4, the update manifest can contain both embedded manifest,
// or a downloadable update manifest file (files["manifest"] contains the update manifest file info)
if (!IsNullOrEmpty(json_object_get_string(
wf->UpdateManifestObject, UPDATE_MANIFEST_PROPERTY_FIELD_DETACHED_MANIFEST_FILE_ID)))
{
tmpResult = DownloadAndUseDetachedManifest(wf);
if (IsAducResultCodeFailure(tmpResult.ResultCode))
{
result = tmpResult;
goto done;
}
}
if (validateManifest)
{
int manifestVersion = workflow_get_update_manifest_version(handle_from_workflow(wf));
if (manifestVersion < SUPPORTED_UPDATE_MANIFEST_VERSION_MIN
|| manifestVersion > SUPPORTED_UPDATE_MANIFEST_VERSION_MAX)
{
Log_Error(
"Bad update manifest version: %d. (min: %d, max: %d)",
manifestVersion,
SUPPORTED_UPDATE_MANIFEST_VERSION_MIN,
SUPPORTED_UPDATE_MANIFEST_VERSION_MAX);
result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_UNSUPPORTED_UPDATE_MANIFEST_VERSION;
goto done;
}
}
}
*handle = wf;
result.ResultCode = ADUC_GeneralResult_Success;
result.ExtendedResultCode = 0;
done:
if (updateActionJsonClone != NULL)
{
json_value_free(updateActionJsonClone);
}
if (IsAducResultCodeFailure(result.ResultCode))
{
free(wf);
wf = NULL;
}
return result;
}