/* * Copyright (c) 2020-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "cJSON.h" #include "iproxy_client.h" #include "ipc_skeleton.h" #include "log.h" #include "pms_interface.h" #include "pms_types.h" #include "registry.h" #include "samgr_lite.h" #define PERMISSION_SERVICE "permissionms" #define PERM_FEATURE "PmsFeature" #define PERM_INNER_FEATURE "PmsInnerFeature" #define MAX_DATA_LEN 0x100 #define FIELD_PERMISSION "permissions" #define FIELD_NAME "name" #define FIELD_DESC "desc" #define FIELD_IS_GRANTED "isGranted" #define FIELD_FLAGS "flags" #define SYS_SVC_UID_MAX 99 #define SYS_APP_UID_MIN 100 #define SYS_APP_UID_MAX 999 #define PERMISSION_NUM_MAX 1000 enum FUNCID { ID_CHECK_SELF = 0, ID_QUERY, ID_CHECK = 10, ID_GRANT, ID_REVOKE, ID_GRANT_RUNTIME, ID_REVOKE_RUNTIME, ID_UPDATE_PERMS_FLAGS, }; typedef struct ClientApi { INHERIT_CLIENT_IPROXY; int (*CheckSelfPermission)(const char *permissionName); int (*QueryPermission)(const char *identifier, PermissionSaved **permissions, int *permNum); } ClientApi; typedef struct ClientEntry { INHERIT_IUNKNOWNENTRY(ClientApi); } ClientEntry; typedef struct InnerClientApi { INHERIT_CLIENT_IPROXY; int (*CheckPermission)(int uid, const char *permissionName); int (*GrantPermission)(const char *identifier, const char *permName); int (*RevokePermission)(const char *identifier, const char *permName); int (*GrantRuntimePermission)(int uid, const char *permissionName); int (*RevokeRuntimePermission)(int uid, const char *permissionName); int (*UpdatePermissionFlags)(const char *identifier, const char *permissionName, int flags); } InnerClientApi; typedef struct ClientInnerEntry { INHERIT_IUNKNOWNENTRY(InnerClientApi); } ClientInnerEntry; typedef struct RetOfQueryPerms { int resultCode; int length; PermissionSaved *permission; } RetOfQueryPerms; void *CreatClient(const char *service, const char *feature, uint32 size) { (void)service; (void)feature; uint32 len = size + sizeof(ClientEntry); if ((len < size) || (len < sizeof(ClientEntry))) { return NULL; } uint8 *client = malloc(len); if (client == NULL) { return NULL; } (void)memset_s(client, len, 0, len); ClientEntry *entry = (ClientEntry *)&client[size]; entry->ver = ((uint16)CLIENT_PROXY_VER | (uint16)DEFAULT_VERSION); entry->ref = 1; entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface; entry->iUnknown.AddRef = IUNKNOWN_AddRef; entry->iUnknown.Release = IUNKNOWN_Release; entry->iUnknown.Invoke = NULL; entry->iUnknown.CheckSelfPermission = CheckSelfPermission; entry->iUnknown.QueryPermission = QueryPermission; return client; } void DestroyClient(const char *service, const char *feature, void *iproxy) { (void)service; (void)feature; free(iproxy); } static ClientApi *GetClientApi(void) { SAMGR_RegisterFactory(PERMISSION_SERVICE, PERM_FEATURE, CreatClient, DestroyClient); ClientApi *clientApi = NULL; HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: BEGIN\n", PERMISSION_SERVICE, PERM_FEATURE); IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(PERMISSION_SERVICE, PERM_FEATURE); if (iUnknown == NULL) { HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: error is NULL\n", PERMISSION_SERVICE, PERM_FEATURE); return NULL; } (void)iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&clientApi); HILOG_INFO(HILOG_MODULE_APP, "[QueryInterface CLIENT_PROXY_VER S:%s, F:%s]\n", PERMISSION_SERVICE, PERM_FEATURE); return clientApi; } static void ReleaseClientApi(ClientApi *clientApi) { if (clientApi == NULL) { return; } int32 ref = clientApi->Release((IUnknown *)clientApi); HILOG_INFO(HILOG_MODULE_APP, "[Release api S:%s, F:%s]: ref:%d\n", PERMISSION_SERVICE, PERM_FEATURE, ref); } void *CreatInnerClient(const char *service, const char *feature, uint32 size) { (void)service; (void)feature; uint32 len = size + sizeof(ClientInnerEntry); if ((len < size) || (len < sizeof(ClientInnerEntry))) { return NULL; } uint8 *client = malloc(len); if (client == NULL) { return NULL; } (void)memset_s(client, len, 0, len); ClientInnerEntry *entry = (ClientInnerEntry *)&client[size]; entry->ver = ((uint16)CLIENT_PROXY_VER | (uint16)DEFAULT_VERSION); entry->ref = 1; entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface; entry->iUnknown.AddRef = IUNKNOWN_AddRef; entry->iUnknown.Release = IUNKNOWN_Release; entry->iUnknown.Invoke = NULL; entry->iUnknown.CheckPermission = CheckPermission; entry->iUnknown.GrantPermission = GrantPermission; entry->iUnknown.RevokePermission = RevokePermission; entry->iUnknown.GrantRuntimePermission = GrantRuntimePermission; entry->iUnknown.RevokeRuntimePermission = RevokeRuntimePermission; entry->iUnknown.UpdatePermissionFlags = UpdatePermissionFlags; return client; } void DestroyInnerClient(const char *service, const char *feature, void *iproxy) { (void)service; (void)feature; free(iproxy); } static InnerClientApi *GetInnerClientApi(void) { SAMGR_RegisterFactory(PERMISSION_SERVICE, PERM_INNER_FEATURE, CreatInnerClient, DestroyInnerClient); InnerClientApi *clientApi = NULL; HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: BEGIN\n", PERMISSION_SERVICE, PERM_INNER_FEATURE); IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(PERMISSION_SERVICE, PERM_INNER_FEATURE); if (iUnknown == NULL) { HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: error is NULL\n", PERMISSION_SERVICE, PERM_INNER_FEATURE); return NULL; } (void)iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&clientApi); HILOG_INFO(HILOG_MODULE_APP, "[QueryInterface CLIENT_PROXY_VER S:%s, F:%s]\n", PERMISSION_SERVICE, PERM_INNER_FEATURE); return clientApi; } static void ReleaseInnerClientApi(InnerClientApi *clientApi) { if (clientApi == NULL) { return; } int32 ref = clientApi->Release((IUnknown *)clientApi); HILOG_INFO(HILOG_MODULE_APP, "[Release api S:%s, F:%s]: ref:%d\n", PERMISSION_SERVICE, PERM_INNER_FEATURE, ref); } static int ParsePermissions(const char *jsonStr, PermissionSaved **perms, int *permNum) { cJSON *root = cJSON_Parse(jsonStr); if (root == NULL) { return PERM_ERRORCODE_JSONPARSE_FAIL; } cJSON *array = cJSON_GetObjectItem(root, FIELD_PERMISSION); int pSize = cJSON_GetArraySize(array); if (pSize > PERMISSION_NUM_MAX) { cJSON_Delete(root); return PERM_ERRORCODE_JSONPARSE_FAIL; } int allocSize = sizeof(PermissionSaved) * pSize; if (allocSize == 0) { cJSON_Delete(root); return PERM_ERRORCODE_SUCCESS; } *perms = (PermissionSaved *) malloc(allocSize); if (*perms == NULL) { cJSON_Delete(root); return PERM_ERRORCODE_MALLOC_FAIL; } for (int i = 0; i < pSize; i++) { cJSON *object = cJSON_GetArrayItem(array, i); cJSON *itemName = cJSON_GetObjectItem(object, FIELD_NAME); cJSON *itemDesc = cJSON_GetObjectItem(object, FIELD_DESC); cJSON *itemGranted = cJSON_GetObjectItem(object, FIELD_IS_GRANTED); if (itemName == NULL || itemDesc == NULL || itemGranted == NULL || !cJSON_IsString(itemName) || itemName->valuestring == NULL || !cJSON_IsString(itemDesc) || itemDesc->valuestring == NULL) { cJSON_Delete(root); free(*perms); *perms = NULL; return PERM_ERRORCODE_JSONPARSE_FAIL; } if (strcpy_s((*perms + i)->name, PERM_NAME_LEN, itemName->valuestring) != EOK || strcpy_s((*perms + i)->desc, PERM_DESC_LEN, itemDesc->valuestring) != EOK) { cJSON_Delete(root); free(*perms); *perms = NULL; return PERM_ERRORCODE_COPY_ERROR; } (*perms + i)->granted = (enum IsGranted) itemGranted->valueint; } *permNum = pSize; cJSON_Delete(root); return PERM_ERRORCODE_SUCCESS; } static int Notify(IOwner owner, int code, IpcIo *reply) { if ((reply == NULL) || (owner == NULL)) { HILOG_ERROR(HILOG_MODULE_APP, "Lite Ipc reply or owner is NULL"); return OHOS_FAILURE; } int32_t *ret = (int32_t *)owner; ReadInt32(reply, ret); return EC_SUCCESS; } static int DealQueryReply(IOwner owner, int code, IpcIo *reply) { if ((reply == NULL) || (owner == NULL)) { return OHOS_FAILURE; } int resultCode; ReadInt32(reply, &resultCode); RetOfQueryPerms *ret = (RetOfQueryPerms *)(owner); if (resultCode != PERM_ERRORCODE_SUCCESS) { ret->resultCode = resultCode; return resultCode; } char *jsonStr = (char *)ReadString(reply, NULL); HILOG_INFO(HILOG_MODULE_APP, "[perms: %s]", jsonStr); int retCode = ParsePermissions(jsonStr, &(ret->permission), &(ret->length)); ret->resultCode = retCode; return retCode; } int CheckSelfPermission(const char *permissionName) { uid_t callingUid = getuid(); if (callingUid <= SYS_APP_UID_MAX) { return GRANTED; } ClientApi *proxy = GetClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteString(&request, permissionName); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_CHECK_SELF, &request, &ret, Notify); ReleaseClientApi(proxy); return ret; } int CheckPermission(int uid, const char *permissionName) { uid_t callingUid = getuid(); if (callingUid <= SYS_APP_UID_MAX) { return GRANTED; } InnerClientApi *proxy = GetInnerClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteInt64(&request, uid); WriteString(&request, permissionName); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_CHECK, &request, &ret, Notify); ReleaseInnerClientApi(proxy); return ret; } int QueryPermission(const char *identifier, PermissionSaved **permissions, int *permNum) { ClientApi *proxy = GetClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } if (permissions == NULL || permNum == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteString(&request, identifier); RetOfQueryPerms ret = { .resultCode = 0, .length = 0, .permission = NULL }; proxy->Invoke((IClientProxy *)proxy, ID_QUERY, &request, &ret, DealQueryReply); *permissions = ret.permission; *permNum = ret.length; ReleaseClientApi(proxy); return ret.resultCode; } int GrantPermission(const char *identifier, const char *permName) { InnerClientApi *proxy = GetInnerClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteString(&request, identifier); WriteString(&request, permName); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_GRANT, &request, &ret, Notify); ReleaseInnerClientApi(proxy); HILOG_INFO(HILOG_MODULE_APP, "client grant[ret: %d]", ret); return ret; } int RevokePermission(const char *identifier, const char *permName) { InnerClientApi *proxy = GetInnerClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteString(&request, identifier); WriteString(&request, permName); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_REVOKE, &request, &ret, Notify); ReleaseInnerClientApi(proxy); HILOG_INFO(HILOG_MODULE_APP, "client revoke[ret: %d]", ret); return ret; } int GrantRuntimePermission(int uid, const char *permissionName) { InnerClientApi *proxy = GetInnerClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteInt64(&request, uid); WriteString(&request, permissionName); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_GRANT_RUNTIME, &request, &ret, Notify); ReleaseInnerClientApi(proxy); return ret; } int RevokeRuntimePermission(int uid, const char *permissionName) { InnerClientApi *proxy = GetInnerClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteInt64(&request, uid); WriteString(&request, permissionName); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_REVOKE_RUNTIME, &request, &ret, Notify); ReleaseInnerClientApi(proxy); return ret; } int UpdatePermissionFlags(const char *identifier, const char *permissionName, const int flags) { InnerClientApi *proxy = GetInnerClientApi(); if (proxy == NULL) { return OHOS_FAILURE; } IpcIo request; char data[MAX_DATA_LEN]; IpcIoInit(&request, data, MAX_DATA_LEN, 0); WriteString(&request, identifier); WriteString(&request, permissionName); WriteInt32(&request, flags); int32_t ret = -1; proxy->Invoke((IClientProxy *)proxy, ID_UPDATE_PERMS_FLAGS, &request, &ret, Notify); ReleaseInnerClientApi(proxy); return ret; }