| /** @file | |
| RedfishCrentialDxe produces the EdkIIRedfishCredentialProtocol for the consumer | |
| to get the Redfish credential Info and to restrict Redfish access from UEFI side. | |
| (C) Copyright 2020 Hewlett Packard Enterprise Development LP<BR> | |
| (C) Copyright 2024 American Megatrends International LLC<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <RedfishCredentialDxe.h> | |
| #define REDFISH_VERSION_DEFAULT_STRING L"v1" | |
| REDFISH_CREDENTIAL_PRIVATE *mCredentialPrivate = NULL; | |
| /** | |
| Callback function executed when the ExitBootServices event group is signaled. | |
| @param[in] Event Event whose notification function is being invoked. | |
| @param[out] Context Pointer to the buffer pass in. | |
| **/ | |
| VOID | |
| EFIAPI | |
| RedfishCredentialExitBootServicesEventNotify ( | |
| IN EFI_EVENT Event, | |
| OUT VOID *Context | |
| ) | |
| { | |
| LibCredentialExitBootServicesNotify ((EDKII_REDFISH_CREDENTIAL_PROTOCOL *)Context); | |
| } | |
| /** | |
| Callback function executed when the EndOfDxe event group is signaled. | |
| @param[in] Event Event whose notification function is being invoked. | |
| @param[out] Context Pointer to the buffer pass in. | |
| **/ | |
| VOID | |
| EFIAPI | |
| RedfishCredentialEndOfDxeEventNotify ( | |
| IN EFI_EVENT Event, | |
| OUT VOID *Context | |
| ) | |
| { | |
| LibCredentialEndOfDxeNotify ((EDKII_REDFISH_CREDENTIAL_PROTOCOL *)Context); | |
| // | |
| // Close event, so it will not be invoked again. | |
| // | |
| gBS->CloseEvent (Event); | |
| } | |
| EFI_STATUS | |
| ReleaseCredentialPrivate ( | |
| ); | |
| EFI_STATUS | |
| IterateThroughBootstrapAccounts ( | |
| IN REDFISH_SERVICE RedfishService | |
| ); | |
| /** | |
| Retrieve platform's Redfish authentication information. | |
| This functions returns the Redfish authentication method together with the user Id and | |
| password. | |
| - For AuthMethodNone, the UserId and Password could be used for HTTP header authentication | |
| as defined by RFC7235. | |
| - For AuthMethodRedfishSession, the UserId and Password could be used for Redfish | |
| session login as defined by Redfish API specification (DSP0266). | |
| Callers are responsible for and freeing the returned string storage. | |
| @param[in] This Pointer to EDKII_REDFISH_CREDENTIAL_PROTOCOL instance. | |
| @param[out] AuthMethod Type of Redfish authentication method. | |
| @param[out] UserId The pointer to store the returned UserId string. | |
| @param[out] Password The pointer to store the returned Password string. | |
| @retval EFI_SUCCESS Get the authentication information successfully. | |
| @retval EFI_ACCESS_DENIED SecureBoot is disabled after EndOfDxe. | |
| @retval EFI_INVALID_PARAMETER This or AuthMethod or UserId or Password is NULL. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough memory resources. | |
| @retval EFI_UNSUPPORTED Unsupported authentication method is found. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredentialGetAuthInfo ( | |
| IN EDKII_REDFISH_CREDENTIAL_PROTOCOL *This, | |
| OUT EDKII_REDFISH_AUTH_METHOD *AuthMethod, | |
| OUT CHAR8 **UserId, | |
| OUT CHAR8 **Password | |
| ) | |
| { | |
| if ((This == NULL) || (AuthMethod == NULL) || (UserId == NULL) || (Password == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return LibCredentialGetAuthInfo (This, AuthMethod, UserId, Password); | |
| } | |
| /** | |
| Notify the Redfish service provider to stop provide configuration service to this platform. | |
| This function should be called when the platfrom is about to leave the safe environment. | |
| It will notify the Redfish service provider to abort all logined session, and prohibit | |
| further login with original auth info. GetAuthInfo() will return EFI_UNSUPPORTED once this | |
| function is returned. | |
| @param[in] This Pointer to EDKII_REDFISH_CREDENTIAL_PROTOCOL instance. | |
| @param[in] ServiceStopType Reason of stopping Redfish service. | |
| @retval EFI_SUCCESS Service has been stoped successfully. | |
| @retval EFI_INVALID_PARAMETER This is NULL or given the worng ServiceStopType. | |
| @retval EFI_UNSUPPORTED Not support to stop Redfish service. | |
| @retval Others Some error happened. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredentialStopService ( | |
| IN EDKII_REDFISH_CREDENTIAL_PROTOCOL *This, | |
| IN EDKII_REDFISH_CREDENTIAL_STOP_SERVICE_TYPE ServiceStopType | |
| ) | |
| { | |
| if (This == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return LibStopRedfishService (This, ServiceStopType); | |
| } | |
| /** | |
| Retrieve platform's Redfish authentication information. | |
| This functions returns the Redfish authentication method together with the user Id and | |
| password. | |
| - For AuthMethodNone, the UserId and Password could be used for HTTP header authentication | |
| as defined by RFC7235. | |
| - For AuthMethodRedfishSession, the UserId and Password could be used for Redfish | |
| session login as defined by Redfish API specification (DSP0266). | |
| Callers are responsible for and freeing the returned string storage. | |
| @param[in] This Pointer to EDKII_REDFISH_CREDENTIAL2_PROTOCOL instance. | |
| @param[out] AuthMethod Type of Redfish authentication method. | |
| @param[out] UserId The pointer to store the returned UserId string. | |
| @param[out] Password The pointer to store the returned Password string. | |
| @retval EFI_SUCCESS Get the authentication information successfully. | |
| @retval EFI_ACCESS_DENIED SecureBoot is disabled after EndOfDxe. | |
| @retval EFI_INVALID_PARAMETER This or AuthMethod or UserId or Password is NULL. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough memory resources. | |
| @retval EFI_UNSUPPORTED Unsupported authentication method is found. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredential2GetAuthInfo ( | |
| IN EDKII_REDFISH_CREDENTIAL2_PROTOCOL *This, | |
| OUT EDKII_REDFISH_AUTH_METHOD *AuthMethod, | |
| OUT CHAR8 **UserId, | |
| OUT CHAR8 **Password | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if ((AuthMethod == NULL) || (UserId == NULL) || (Password == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| Status = mCredentialPrivate->RedfishCredentialProtocol.GetAuthInfo ( | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| AuthMethod, | |
| UserId, | |
| Password | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Failed to retrieve Redfish credential - %r\n", __func__, Status)); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Notifies the Redfish service provider to stop providing configuration service to this platform. | |
| Deletes the bootstrap account on BMC side, so it will not be used by any other driver. | |
| This function should be called when the platfrom is about to leave the safe environment. | |
| It will delete the bootstrap account sending DELETE request to BMC. | |
| It will notify the Redfish service provider to abort all logined session, and prohibit | |
| further login with original auth info. GetAuthInfo() will return EFI_UNSUPPORTED once this | |
| function is returned. | |
| @param[in] This Pointer to EDKII_REDFISH_CREDENTIAL2_PROTOCOL instance. | |
| @param[in] ServiceStopType Reason of stopping Redfish service. | |
| @retval EFI_SUCCESS Service has been stoped successfully. | |
| @retval EFI_INVALID_PARAMETER This is NULL or given the worng ServiceStopType. | |
| @retval EFI_UNSUPPORTED Not support to stop Redfish service. | |
| @retval Others Some error happened. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredential2StopService ( | |
| IN EDKII_REDFISH_CREDENTIAL2_PROTOCOL *This, | |
| IN EDKII_REDFISH_CREDENTIAL_STOP_SERVICE_TYPE ServiceStopType | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| REDFISH_SERVICE_LIST *Instance; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| if ((ServiceStopType == ServiceStopTypeExitBootService) || | |
| (ServiceStopType == ServiceStopTypeNone)) | |
| { | |
| // Check PCD and skip the action if platform library is responsible for deleting account | |
| // on exit boot service event | |
| if (FixedPcdGetBool (PcdRedfishCredentialDeleteAccount)) { | |
| if (!IsListEmpty (&mCredentialPrivate->RedfishServiceList)) { | |
| Instance = (REDFISH_SERVICE_LIST *)GetFirstNode (&mCredentialPrivate->RedfishServiceList); | |
| IterateThroughBootstrapAccounts (Instance->RedfishService); | |
| } | |
| ReleaseCredentialPrivate (); | |
| } | |
| } | |
| Status = mCredentialPrivate->RedfishCredentialProtocol.StopService ( | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| ServiceStopType | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Failed to stop service - %r\n", __func__, Status)); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Function sends DELETE request to BMC for the account defined by the target URI. | |
| @param[in] RedfishService Pointer to Redfish Service to be used | |
| for sending DELETE request to BMC. | |
| @param[in] TargetUri URI of bootstrap account to send DELETE request to. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteRedfishBootstrapAccount ( | |
| IN REDFISH_SERVICE RedfishService, | |
| IN CHAR16 *TargetUri | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| REDFISH_RESPONSE RedfishResponse; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| if ((RedfishService == NULL) || (mCredentialPrivate->AuthMethod != AuthMethodHttpBasic)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Redfish service is not available\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Remove bootstrap account at /redfish/v1/AccountService/AccountId | |
| // | |
| ZeroMem (&RedfishResponse, sizeof (REDFISH_RESPONSE)); | |
| Status = RedfishHttpDeleteResourceEx ( | |
| RedfishService, | |
| TargetUri, | |
| "{}", | |
| 2, | |
| NULL, | |
| &RedfishResponse | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: can not remove bootstrap account at BMC: %r", __func__, Status)); | |
| DumpRedfishResponse (__func__, DEBUG_ERROR, &RedfishResponse); | |
| } else { | |
| DEBUG ( | |
| (REDFISH_CREDENTIAL_DEBUG, "%a: bootstrap account: %a is removed from: %s\nURI - %s", | |
| __func__, mCredentialPrivate->AccountName, REDFISH_MANAGER_ACCOUNT_COLLECTION_URI, TargetUri) | |
| ); | |
| } | |
| RedfishHttpFreeResponse (&RedfishResponse); | |
| return Status; | |
| } | |
| /** | |
| Get the information about specific Account. | |
| Checks the User Name and if name matches delete that account | |
| @param[in] RedfishService Pointer to Redfish Service to be used | |
| for sending DELETE request to BMC. | |
| @param[in] AccountUri URI of bootstrap account to verify. | |
| **/ | |
| BOOLEAN | |
| ProcessRedfishBootstarpAccount ( | |
| IN REDFISH_SERVICE RedfishService, | |
| IN EFI_STRING AccountUri | |
| ) | |
| { | |
| EDKII_JSON_VALUE JsonUserName; | |
| EDKII_JSON_VALUE JsonValue; | |
| EFI_STATUS Status; | |
| REDFISH_RESPONSE RedfishResponse; | |
| REDFISH_REQUEST RedfishRequest; | |
| BOOLEAN Ret; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return FALSE; | |
| } | |
| if ((RedfishService == NULL) || IS_EMPTY_STRING (AccountUri) || | |
| (mCredentialPrivate->AuthMethod != AuthMethodHttpBasic)) | |
| { | |
| return FALSE; | |
| } | |
| ZeroMem (&RedfishResponse, sizeof (REDFISH_RESPONSE)); | |
| ZeroMem (&RedfishRequest, sizeof (REDFISH_REQUEST)); | |
| Status = RedfishHttpGetResource (RedfishService, AccountUri, &RedfishRequest, &RedfishResponse, FALSE); | |
| if (EFI_ERROR (Status) || (RedfishResponse.Payload == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "%a: can not get account from BMC: %r", __func__, Status)); | |
| DumpRedfishResponse (__func__, DEBUG_ERROR, &RedfishResponse); | |
| return FALSE; | |
| } | |
| Ret = FALSE; | |
| JsonValue = RedfishJsonInPayload (RedfishResponse.Payload); | |
| if (JsonValueIsObject (JsonValue)) { | |
| JsonUserName = JsonObjectGetValue (JsonValueGetObject (JsonValue), "UserName"); | |
| if (JsonValueIsString (JsonUserName) && (JsonValueGetAsciiString (JsonUserName) != NULL)) { | |
| if (AsciiStrCmp (mCredentialPrivate->AccountName, JsonValueGetAsciiString (JsonUserName)) == 0) { | |
| DeleteRedfishBootstrapAccount (RedfishService, AccountUri); | |
| Ret = TRUE; | |
| } | |
| } | |
| } | |
| RedfishHttpFreeResponse (&RedfishResponse); | |
| RedfishHttpFreeRequest (&RedfishRequest); | |
| return Ret; | |
| } | |
| /** | |
| This function returns the string of Redfish service version. | |
| @param[out] ServiceVersionStr Redfish service string. | |
| @return EFI_STATUS | |
| **/ | |
| EFI_STATUS | |
| RedfishGetServiceVersion ( | |
| OUT CHAR16 **ServiceVersionStr | |
| ) | |
| { | |
| *ServiceVersionStr = (CHAR16 *)PcdGetPtr (PcdDefaultRedfishVersion); | |
| if (*ServiceVersionStr == NULL) { | |
| *ServiceVersionStr = REDFISH_VERSION_DEFAULT_STRING; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Iterates through all account in the account collection | |
| Get the information about specific Account. | |
| Checks the User Name and if name matches delete that account | |
| @param[in] RedfishService Pointer to Redfish Service to be used | |
| for sending DELETE request to BMC. | |
| **/ | |
| EFI_STATUS | |
| IterateThroughBootstrapAccounts ( | |
| IN REDFISH_SERVICE RedfishService | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EDKII_JSON_VALUE JsonMembers; | |
| EDKII_JSON_VALUE JsonValue; | |
| EDKII_JSON_VALUE OdataId; | |
| CHAR16 TargetUri[REDFISH_URI_LENGTH]; | |
| CHAR16 *RedfishVersion; | |
| REDFISH_RESPONSE RedfishResponse; | |
| REDFISH_REQUEST RedfishRequest; | |
| UINTN MembersCount, Index; | |
| RedfishVersion = NULL; | |
| Status = EFI_NOT_FOUND; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| if ((RedfishService == NULL) || (mCredentialPrivate->AuthMethod != AuthMethodHttpBasic) || | |
| IS_EMPTY_STRING (mCredentialPrivate->AccountName)) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Carving the URI | |
| // | |
| Status = RedfishGetServiceVersion (&RedfishVersion); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: can not get Redfish version\n", __func__)); | |
| return Status; | |
| } | |
| UnicodeSPrint ( | |
| TargetUri, | |
| (sizeof (CHAR16) * REDFISH_URI_LENGTH), | |
| L"/redfish/%s/%s", | |
| RedfishVersion, | |
| REDFISH_MANAGER_ACCOUNT_COLLECTION_URI | |
| ); | |
| DEBUG ((REDFISH_CREDENTIAL_DEBUG, "%a: account collection URI: %s\n", __func__, TargetUri)); | |
| ZeroMem (&RedfishResponse, sizeof (REDFISH_RESPONSE)); | |
| ZeroMem (&RedfishRequest, sizeof (REDFISH_REQUEST)); | |
| Status = RedfishHttpGetResource (RedfishService, TargetUri, &RedfishRequest, &RedfishResponse, FALSE); | |
| if (EFI_ERROR (Status) || (RedfishResponse.Payload == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "%a: can not get accounts from BMC: %r\n", __func__, Status)); | |
| DumpRedfishResponse (__func__, DEBUG_ERROR, &RedfishResponse); | |
| return Status; | |
| } | |
| JsonValue = RedfishJsonInPayload (RedfishResponse.Payload); | |
| if (!JsonValueIsObject (JsonValue)) { | |
| Status = EFI_LOAD_ERROR; | |
| goto ON_EXIT; | |
| } | |
| JsonMembers = JsonObjectGetValue (JsonValueGetObject (JsonValue), "Members"); | |
| if (!JsonValueIsArray (JsonMembers)) { | |
| Status = EFI_LOAD_ERROR; | |
| goto ON_EXIT; | |
| } | |
| Status = EFI_NOT_FOUND; | |
| MembersCount = JsonArrayCount (JsonValueGetArray (JsonMembers)); | |
| for (Index = 0; Index < MembersCount; Index++) { | |
| JsonValue = JsonArrayGetValue (JsonValueGetArray (JsonMembers), Index); | |
| if (!JsonValueIsObject (JsonValue)) { | |
| Status = EFI_LOAD_ERROR; | |
| goto ON_EXIT; | |
| } | |
| OdataId = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.id"); | |
| if (!JsonValueIsString (OdataId) || (JsonValueGetAsciiString (OdataId) == NULL)) { | |
| Status = EFI_LOAD_ERROR; | |
| goto ON_EXIT; | |
| } | |
| UnicodeSPrint ( | |
| TargetUri, | |
| (sizeof (CHAR16) * REDFISH_URI_LENGTH), | |
| L"%a", | |
| JsonValueGetAsciiString (OdataId) | |
| ); | |
| DEBUG ((REDFISH_CREDENTIAL_DEBUG, "%a: account URI: %s\n", __func__, TargetUri)); | |
| // Verify bootstrap account User Name and delete the account if User Name matches | |
| if (ProcessRedfishBootstarpAccount (RedfishService, TargetUri)) { | |
| Status = EFI_SUCCESS; | |
| break; | |
| } | |
| } | |
| ON_EXIT: | |
| RedfishHttpFreeResponse (&RedfishResponse); | |
| RedfishHttpFreeRequest (&RedfishRequest); | |
| return Status; | |
| } | |
| /** | |
| Retrieve platform's Redfish authentication information. | |
| This functions returns the Redfish authentication method together with the user Id. | |
| For AuthMethodNone, UserId will point to NULL which means authentication | |
| is not required to access the Redfish service. | |
| Callers are responsible for freeing the returned string storage pointed by UserId. | |
| @param[out] AuthMethod Type of Redfish authentication method. | |
| @param[out] UserId The pointer to store the returned UserId string. | |
| @retval EFI_SUCCESS Get the authentication information successfully. | |
| @retval EFI_INVALID_PARAMETER AuthMethod or UserId or Password is NULL. | |
| @retval EFI_UNSUPPORTED Unsupported authentication method is found. | |
| **/ | |
| EFI_STATUS | |
| RedfishGetAuthConfig ( | |
| OUT EDKII_REDFISH_AUTH_METHOD *AuthMethod, | |
| OUT CHAR8 **UserId | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CHAR8 *Password; | |
| Password = NULL; | |
| if ((AuthMethod == NULL) || (UserId == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| Status = mCredentialPrivate->RedfishCredentialProtocol.GetAuthInfo ( | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| AuthMethod, | |
| UserId, | |
| &Password | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed to retrieve Redfish credential - %r\n", __func__, Status)); | |
| return Status; | |
| } | |
| if (Password != NULL) { | |
| ZeroMem (Password, AsciiStrSize (Password)); | |
| FreePool (Password); | |
| } | |
| return Status; | |
| } | |
| /** | |
| This function clears Redfish service internal list. | |
| @retval EFI_SUCCESS Redfish service is deleted from list successfully. | |
| @retval Others Fail to remove the entry | |
| **/ | |
| EFI_STATUS | |
| ClearRedfishServiceList ( | |
| VOID | |
| ) | |
| { | |
| REDFISH_SERVICE_LIST *Instance; | |
| REDFISH_SERVICE_LIST *NextInstance; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| if (!IsListEmpty (&mCredentialPrivate->RedfishServiceList)) { | |
| // | |
| // Free memory of REDFISH_SERVICE_LIST instance. | |
| // | |
| Instance = (REDFISH_SERVICE_LIST *)GetFirstNode (&mCredentialPrivate->RedfishServiceList); | |
| do { | |
| NextInstance = NULL; | |
| if (!IsNodeAtEnd (&mCredentialPrivate->RedfishServiceList, &Instance->NextInstance)) { | |
| NextInstance = (REDFISH_SERVICE_LIST *)GetNextNode ( | |
| &mCredentialPrivate->RedfishServiceList, | |
| &Instance->NextInstance | |
| ); | |
| } | |
| RemoveEntryList (&Instance->NextInstance); | |
| FreePool ((VOID *)Instance); | |
| Instance = NextInstance; | |
| } while (Instance != NULL); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| The function adds a new Redfish service to internal list | |
| @param[in] RedfishService Pointer to REDFISH_SERVICE to be added to the list. | |
| @retval EFI_SUCCESS Redfish service is added to list successfully. | |
| @retval EFI_OUT_OF_RESOURCES Out of resources error. | |
| **/ | |
| EFI_STATUS | |
| AddRedfishServiceToList ( | |
| IN REDFISH_SERVICE RedfishService | |
| ) | |
| { | |
| BOOLEAN ServiceFound; | |
| REDFISH_SERVICE_LIST *RedfishServiceInstance; | |
| RedfishServiceInstance = NULL; | |
| ServiceFound = FALSE; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| if (!IsListEmpty (&mCredentialPrivate->RedfishServiceList)) { | |
| RedfishServiceInstance = (REDFISH_SERVICE_LIST *)GetFirstNode (&mCredentialPrivate->RedfishServiceList); | |
| do { | |
| if (RedfishServiceInstance->RedfishService == RedfishService) { | |
| ServiceFound = TRUE; | |
| break; | |
| } | |
| if (IsNodeAtEnd (&mCredentialPrivate->RedfishServiceList, &RedfishServiceInstance->NextInstance)) { | |
| break; | |
| } | |
| RedfishServiceInstance = (REDFISH_SERVICE_LIST *)GetNextNode ( | |
| &mCredentialPrivate->RedfishServiceList, | |
| &RedfishServiceInstance->NextInstance | |
| ); | |
| } while (TRUE); | |
| } | |
| if (!ServiceFound) { | |
| RedfishServiceInstance = (REDFISH_SERVICE_LIST *)AllocateZeroPool (sizeof (REDFISH_SERVICE_LIST)); | |
| if (RedfishServiceInstance == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| RedfishServiceInstance->RedfishService = RedfishService; | |
| InsertTailList (&mCredentialPrivate->RedfishServiceList, &RedfishServiceInstance->NextInstance); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This function deletes Redfish service from internal list. | |
| @param[in] RedfishService Pointer to REDFISH_SERVICE to be delete from the list. | |
| @retval EFI_SUCCESS Redfish service is deleted from list successfully. | |
| @retval Others Fail to remove the entry | |
| **/ | |
| EFI_STATUS | |
| DeleteRedfishServiceFromList ( | |
| IN REDFISH_SERVICE RedfishService | |
| ) | |
| { | |
| REDFISH_SERVICE_LIST *RedfishServiceInstance; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| if (!IsListEmpty (&mCredentialPrivate->RedfishServiceList)) { | |
| RedfishServiceInstance = (REDFISH_SERVICE_LIST *)GetFirstNode (&mCredentialPrivate->RedfishServiceList); | |
| do { | |
| if (RedfishServiceInstance->RedfishService == RedfishService) { | |
| RemoveEntryList (&RedfishServiceInstance->NextInstance); | |
| FreePool (RedfishServiceInstance); | |
| return EFI_SUCCESS; | |
| } | |
| if (IsNodeAtEnd (&mCredentialPrivate->RedfishServiceList, &RedfishServiceInstance->NextInstance)) { | |
| break; | |
| } | |
| RedfishServiceInstance = (REDFISH_SERVICE_LIST *)GetNextNode (&mCredentialPrivate->RedfishServiceList, &RedfishServiceInstance->NextInstance); | |
| } while (TRUE); | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Register Redfish service instance so protocol knows that some module uses bootstrap account. | |
| @param[in] This Pointer to EDKII_REDFISH_CREDENTIAL_PROTOCOL instance. | |
| @param[in] RedfishService Redfish service instance to register. | |
| @retval EFI_SUCCESS This Redfish service instance has been registered successfully. | |
| @retval Others Fail to register Redfish Service | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredential2RegisterService ( | |
| IN EDKII_REDFISH_CREDENTIAL2_PROTOCOL *This, | |
| IN REDFISH_SERVICE RedfishService | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = EFI_SUCCESS; | |
| if (mCredentialPrivate == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: failed with error - %r\n", __func__, EFI_NOT_STARTED)); | |
| return EFI_NOT_STARTED; | |
| } | |
| // Check if AuthMethod has been initialized yet | |
| if (mCredentialPrivate->AuthMethod == AuthMethodMax) { | |
| Status = RedfishGetAuthConfig ( | |
| &mCredentialPrivate->AuthMethod, | |
| &mCredentialPrivate->AccountName | |
| ); | |
| } | |
| // Bootstrap account should be deleted only if Basic Authentication is used. | |
| if (!EFI_ERROR (Status) && (mCredentialPrivate->AuthMethod == AuthMethodHttpBasic)) { | |
| Status = AddRedfishServiceToList (RedfishService); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Failed to register Redfish service - %r\n", __func__, Status)); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Unregister Redfish service instance and delete the bootstrap account | |
| when all registered services unregistered. | |
| @param[in] This Pointer to EDKII_REDFISH_CREDENTIAL_PROTOCOL instance. | |
| @param[in] RedfishService Redfish service instance to unregister. | |
| @retval EFI_SUCCESS This Redfish service instance has been unregistered successfully. | |
| @retval Others Fail to unregister Redfish Service | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredential2UnregisterService ( | |
| IN EDKII_REDFISH_CREDENTIAL2_PROTOCOL *This, | |
| IN REDFISH_SERVICE RedfishService | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| // Bootstrap account should be deleted only if Basic Authentication is used. | |
| if (mCredentialPrivate->AuthMethod != AuthMethodHttpBasic) { | |
| return EFI_SUCCESS; | |
| } | |
| // Delete Redfish Service from the registered list | |
| Status = DeleteRedfishServiceFromList (RedfishService); | |
| // Check if registered list is empty | |
| if (IsListEmpty (&mCredentialPrivate->RedfishServiceList)) { | |
| // Iterate through all accounts in the account collection and delete the bootstrap account | |
| Status = IterateThroughBootstrapAccounts (RedfishService); | |
| if (!EFI_ERROR (Status)) { | |
| if (mCredentialPrivate->AccountName != NULL) { | |
| ZeroMem (mCredentialPrivate->AccountName, AsciiStrSize (mCredentialPrivate->AccountName)); | |
| FreePool (mCredentialPrivate->AccountName); | |
| mCredentialPrivate->AccountName = NULL; | |
| } | |
| mCredentialPrivate->AuthMethod = AuthMethodMax; | |
| Status = mCredentialPrivate->RedfishCredentialProtocol.StopService ( | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| ServiceStopTypeNone | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a: Failed to stop service - %r\n", __func__, Status)); | |
| } | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Main entry for this driver. | |
| @param ImageHandle Image handle this driver. | |
| @param SystemTable Pointer to SystemTable. | |
| @retval EFI_SUCCESS This function always complete successfully. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredentialDxeDriverEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| mCredentialPrivate = (REDFISH_CREDENTIAL_PRIVATE *)AllocateZeroPool (sizeof (REDFISH_CREDENTIAL_PRIVATE)); | |
| if (mCredentialPrivate == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| mCredentialPrivate->AuthMethod = AuthMethodMax; | |
| InitializeListHead (&mCredentialPrivate->RedfishServiceList); | |
| mCredentialPrivate->RedfishCredentialProtocol.GetAuthInfo = RedfishCredentialGetAuthInfo; | |
| mCredentialPrivate->RedfishCredentialProtocol.StopService = RedfishCredentialStopService; | |
| mCredentialPrivate->RedfishCredential2Protocol.Revision = REDFISH_CREDENTIAL_PROTOCOL_REVISION; | |
| mCredentialPrivate->RedfishCredential2Protocol.GetAuthInfo = RedfishCredential2GetAuthInfo; | |
| mCredentialPrivate->RedfishCredential2Protocol.StopService = RedfishCredential2StopService; | |
| mCredentialPrivate->RedfishCredential2Protocol.RegisterRedfishService = RedfishCredential2RegisterService; | |
| mCredentialPrivate->RedfishCredential2Protocol.UnregisterRedfishService = RedfishCredential2UnregisterService; | |
| // | |
| // Install the RedfishCredentialProtocol onto Handle. | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &mCredentialPrivate->Handle, | |
| &gEdkIIRedfishCredentialProtocolGuid, | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| &gEdkIIRedfishCredential2ProtocolGuid, | |
| &mCredentialPrivate->RedfishCredential2Protocol, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // After EndOfDxe, if SecureBoot is disabled, Redfish Credential Protocol should return | |
| // error code to caller to avoid the 3rd code to bypass Redfish Credential Protocol and | |
| // retrieve userid/pwd directly. So, here, we create EndOfDxe Event to check SecureBoot | |
| // status. | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| RedfishCredentialEndOfDxeEventNotify, | |
| (VOID *)&mCredentialPrivate->RedfishCredentialProtocol, | |
| &gEfiEndOfDxeEventGroupGuid, | |
| &mCredentialPrivate->EndOfDxeEvent | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto ON_ERROR; | |
| } | |
| // | |
| // After ExitBootServices, Redfish Credential Protocol should stop the service. | |
| // So, here, we create ExitBootService Event to stop service. | |
| // | |
| Status = gBS->CreateEventEx ( | |
| EVT_NOTIFY_SIGNAL, | |
| TPL_CALLBACK, | |
| RedfishCredentialExitBootServicesEventNotify, | |
| (VOID *)&mCredentialPrivate->RedfishCredentialProtocol, | |
| &gEfiEventExitBootServicesGuid, | |
| &mCredentialPrivate->ExitBootServiceEvent | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| gBS->CloseEvent (mCredentialPrivate->EndOfDxeEvent); | |
| mCredentialPrivate->EndOfDxeEvent = NULL; | |
| goto ON_ERROR; | |
| } | |
| return EFI_SUCCESS; | |
| ON_ERROR: | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| mCredentialPrivate->Handle, | |
| &gEdkIIRedfishCredentialProtocolGuid, | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| &gEdkIIRedfishCredential2ProtocolGuid, | |
| &mCredentialPrivate->RedfishCredential2Protocol, | |
| NULL | |
| ); | |
| FreePool (mCredentialPrivate); | |
| return Status; | |
| } | |
| /** | |
| Releases all resources allocated by the module. | |
| Uninstall all the protocols installed in the driver entry point. | |
| @retval EFI_SUCCESS The resources are released. | |
| @retval Others Failed to release the resources. | |
| **/ | |
| EFI_STATUS | |
| ReleaseCredentialPrivate ( | |
| ) | |
| { | |
| if (mCredentialPrivate != NULL) { | |
| if (mCredentialPrivate->AccountName != NULL) { | |
| ZeroMem (mCredentialPrivate->AccountName, AsciiStrSize (mCredentialPrivate->AccountName)); | |
| FreePool (mCredentialPrivate->AccountName); | |
| mCredentialPrivate->AccountName = NULL; | |
| } | |
| ClearRedfishServiceList (); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| This is the unload handle for Redfish Credentials module. | |
| Uninstall all the protocols installed in the driver entry point. | |
| Clear all allocated resources. | |
| @param[in] ImageHandle The drivers' driver image. | |
| @retval EFI_SUCCESS The image is unloaded. | |
| @retval Others Failed to unload the image. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RedfishCredentialDxeDriverUnload ( | |
| IN EFI_HANDLE ImageHandle | |
| ) | |
| { | |
| if (mCredentialPrivate != NULL) { | |
| gBS->UninstallMultipleProtocolInterfaces ( | |
| mCredentialPrivate->Handle, | |
| &gEdkIIRedfishCredentialProtocolGuid, | |
| &mCredentialPrivate->RedfishCredentialProtocol, | |
| &gEdkIIRedfishCredential2ProtocolGuid, | |
| &mCredentialPrivate->RedfishCredential2Protocol, | |
| NULL | |
| ); | |
| if (mCredentialPrivate->EndOfDxeEvent != NULL) { | |
| gBS->CloseEvent (mCredentialPrivate->EndOfDxeEvent); | |
| mCredentialPrivate->EndOfDxeEvent = NULL; | |
| } | |
| if (mCredentialPrivate->ExitBootServiceEvent != NULL) { | |
| gBS->CloseEvent (mCredentialPrivate->ExitBootServiceEvent); | |
| mCredentialPrivate->ExitBootServiceEvent = NULL; | |
| } | |
| ReleaseCredentialPrivate (); | |
| FreePool (mCredentialPrivate); | |
| mCredentialPrivate = NULL; | |
| } | |
| return EFI_SUCCESS; | |
| } |