1/*
2 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *    http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <ohos_errno.h>
17#include <pthread.h>
18#include <securec.h>
19
20#include "cJSON.h"
21#include "iproxy_client.h"
22#include "ipc_skeleton.h"
23#include "log.h"
24#include "pms_interface.h"
25#include "pms_types.h"
26#include "registry.h"
27#include "samgr_lite.h"
28
29#define PERMISSION_SERVICE "permissionms"
30#define PERM_FEATURE "PmsFeature"
31#define PERM_INNER_FEATURE "PmsInnerFeature"
32#define MAX_DATA_LEN 0x100
33#define FIELD_PERMISSION "permissions"
34#define FIELD_NAME "name"
35#define FIELD_DESC "desc"
36#define FIELD_IS_GRANTED "isGranted"
37#define FIELD_FLAGS "flags"
38#define SYS_SVC_UID_MAX 99
39#define SYS_APP_UID_MIN 100
40#define SYS_APP_UID_MAX 999
41#define PERMISSION_NUM_MAX 1000
42
43enum FUNCID {
44    ID_CHECK_SELF = 0,
45    ID_QUERY,
46    ID_CHECK = 10,
47    ID_GRANT,
48    ID_REVOKE,
49    ID_GRANT_RUNTIME,
50    ID_REVOKE_RUNTIME,
51    ID_UPDATE_PERMS_FLAGS,
52};
53
54typedef struct ClientApi {
55    INHERIT_CLIENT_IPROXY;
56    int (*CheckSelfPermission)(const char *permissionName);
57    int (*QueryPermission)(const char *identifier, PermissionSaved **permissions, int *permNum);
58} ClientApi;
59
60typedef struct ClientEntry {
61    INHERIT_IUNKNOWNENTRY(ClientApi);
62} ClientEntry;
63
64typedef struct InnerClientApi {
65    INHERIT_CLIENT_IPROXY;
66    int (*CheckPermission)(int uid, const char *permissionName);
67    int (*GrantPermission)(const char *identifier, const char *permName);
68    int (*RevokePermission)(const char *identifier, const char *permName);
69    int (*GrantRuntimePermission)(int uid, const char *permissionName);
70    int (*RevokeRuntimePermission)(int uid, const char *permissionName);
71    int (*UpdatePermissionFlags)(const char *identifier, const char *permissionName, int flags);
72} InnerClientApi;
73
74typedef struct ClientInnerEntry {
75    INHERIT_IUNKNOWNENTRY(InnerClientApi);
76} ClientInnerEntry;
77
78typedef struct RetOfQueryPerms {
79    int resultCode;
80    int length;
81    PermissionSaved *permission;
82} RetOfQueryPerms;
83
84void *CreatClient(const char *service, const char *feature, uint32 size)
85{
86    (void)service;
87    (void)feature;
88    uint32 len = size + sizeof(ClientEntry);
89    if ((len < size) || (len < sizeof(ClientEntry))) {
90        return NULL;
91    }
92    uint8 *client = malloc(len);
93    if (client == NULL) {
94        return NULL;
95    }
96    (void)memset_s(client, len, 0, len);
97    ClientEntry *entry = (ClientEntry *)&client[size];
98    entry->ver = ((uint16)CLIENT_PROXY_VER | (uint16)DEFAULT_VERSION);
99    entry->ref = 1;
100    entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface;
101    entry->iUnknown.AddRef = IUNKNOWN_AddRef;
102    entry->iUnknown.Release = IUNKNOWN_Release;
103    entry->iUnknown.Invoke = NULL;
104    entry->iUnknown.CheckSelfPermission = CheckSelfPermission;
105    entry->iUnknown.QueryPermission = QueryPermission;
106    return client;
107}
108
109void DestroyClient(const char *service, const char *feature, void *iproxy)
110{
111    (void)service;
112    (void)feature;
113    free(iproxy);
114}
115
116static ClientApi *GetClientApi(void)
117{
118    SAMGR_RegisterFactory(PERMISSION_SERVICE, PERM_FEATURE, CreatClient, DestroyClient);
119    ClientApi *clientApi = NULL;
120    HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: BEGIN\n", PERMISSION_SERVICE, PERM_FEATURE);
121    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(PERMISSION_SERVICE, PERM_FEATURE);
122    if (iUnknown == NULL) {
123        HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: error is NULL\n", PERMISSION_SERVICE, PERM_FEATURE);
124        return NULL;
125    }
126
127    (void)iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&clientApi);
128    HILOG_INFO(HILOG_MODULE_APP, "[QueryInterface CLIENT_PROXY_VER S:%s, F:%s]\n",
129               PERMISSION_SERVICE, PERM_FEATURE);
130    return clientApi;
131}
132
133static void ReleaseClientApi(ClientApi *clientApi)
134{
135    if (clientApi == NULL) {
136        return;
137    }
138    int32 ref = clientApi->Release((IUnknown *)clientApi);
139    HILOG_INFO(HILOG_MODULE_APP, "[Release api S:%s, F:%s]: ref:%d\n",
140               PERMISSION_SERVICE, PERM_FEATURE, ref);
141}
142
143void *CreatInnerClient(const char *service, const char *feature, uint32 size)
144{
145    (void)service;
146    (void)feature;
147    uint32 len = size + sizeof(ClientInnerEntry);
148    if ((len < size) || (len < sizeof(ClientInnerEntry))) {
149        return NULL;
150    }
151    uint8 *client = malloc(len);
152    if (client == NULL) {
153        return NULL;
154    }
155    (void)memset_s(client, len, 0, len);
156    ClientInnerEntry *entry = (ClientInnerEntry *)&client[size];
157    entry->ver = ((uint16)CLIENT_PROXY_VER | (uint16)DEFAULT_VERSION);
158    entry->ref = 1;
159    entry->iUnknown.QueryInterface = IUNKNOWN_QueryInterface;
160    entry->iUnknown.AddRef = IUNKNOWN_AddRef;
161    entry->iUnknown.Release = IUNKNOWN_Release;
162    entry->iUnknown.Invoke = NULL;
163    entry->iUnknown.CheckPermission = CheckPermission;
164    entry->iUnknown.GrantPermission = GrantPermission;
165    entry->iUnknown.RevokePermission = RevokePermission;
166    entry->iUnknown.GrantRuntimePermission = GrantRuntimePermission;
167    entry->iUnknown.RevokeRuntimePermission = RevokeRuntimePermission;
168    entry->iUnknown.UpdatePermissionFlags = UpdatePermissionFlags;
169    return client;
170}
171
172void DestroyInnerClient(const char *service, const char *feature, void *iproxy)
173{
174    (void)service;
175    (void)feature;
176    free(iproxy);
177}
178
179static InnerClientApi *GetInnerClientApi(void)
180{
181    SAMGR_RegisterFactory(PERMISSION_SERVICE, PERM_INNER_FEATURE, CreatInnerClient, DestroyInnerClient);
182    InnerClientApi *clientApi = NULL;
183    HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: BEGIN\n", PERMISSION_SERVICE, PERM_INNER_FEATURE);
184    IUnknown *iUnknown = SAMGR_GetInstance()->GetFeatureApi(PERMISSION_SERVICE, PERM_INNER_FEATURE);
185    if (iUnknown == NULL) {
186        HILOG_INFO(HILOG_MODULE_APP, "[GetFeatureApi S:%s F:%s]: error is NULL\n", PERMISSION_SERVICE,
187            PERM_INNER_FEATURE);
188        return NULL;
189    }
190    (void)iUnknown->QueryInterface(iUnknown, CLIENT_PROXY_VER, (void **)&clientApi);
191    HILOG_INFO(HILOG_MODULE_APP, "[QueryInterface CLIENT_PROXY_VER S:%s, F:%s]\n",
192               PERMISSION_SERVICE, PERM_INNER_FEATURE);
193    return clientApi;
194}
195
196static void ReleaseInnerClientApi(InnerClientApi *clientApi)
197{
198    if (clientApi == NULL) {
199        return;
200    }
201    int32 ref = clientApi->Release((IUnknown *)clientApi);
202    HILOG_INFO(HILOG_MODULE_APP, "[Release api S:%s, F:%s]: ref:%d\n",
203               PERMISSION_SERVICE, PERM_INNER_FEATURE, ref);
204}
205
206static int ParsePermissions(const char *jsonStr, PermissionSaved **perms, int *permNum)
207{
208    cJSON *root = cJSON_Parse(jsonStr);
209    if (root == NULL) {
210        return PERM_ERRORCODE_JSONPARSE_FAIL;
211    }
212    cJSON *array = cJSON_GetObjectItem(root, FIELD_PERMISSION);
213    int pSize = cJSON_GetArraySize(array);
214    if (pSize > PERMISSION_NUM_MAX) {
215        cJSON_Delete(root);
216        return PERM_ERRORCODE_JSONPARSE_FAIL;
217    }
218
219    int allocSize = sizeof(PermissionSaved) * pSize;
220    if (allocSize == 0) {
221        cJSON_Delete(root);
222        return PERM_ERRORCODE_SUCCESS;
223    }
224
225    *perms = (PermissionSaved *) malloc(allocSize);
226    if (*perms == NULL) {
227        cJSON_Delete(root);
228        return PERM_ERRORCODE_MALLOC_FAIL;
229    }
230    for (int i = 0; i < pSize; i++) {
231        cJSON *object = cJSON_GetArrayItem(array, i);
232        cJSON *itemName = cJSON_GetObjectItem(object, FIELD_NAME);
233        cJSON *itemDesc = cJSON_GetObjectItem(object, FIELD_DESC);
234        cJSON *itemGranted = cJSON_GetObjectItem(object, FIELD_IS_GRANTED);
235        if (itemName == NULL || itemDesc == NULL || itemGranted == NULL || !cJSON_IsString(itemName)
236            || itemName->valuestring == NULL || !cJSON_IsString(itemDesc) || itemDesc->valuestring == NULL) {
237            cJSON_Delete(root);
238            free(*perms);
239            *perms = NULL;
240            return PERM_ERRORCODE_JSONPARSE_FAIL;
241        }
242        if (strcpy_s((*perms + i)->name, PERM_NAME_LEN, itemName->valuestring) != EOK
243            || strcpy_s((*perms + i)->desc, PERM_DESC_LEN, itemDesc->valuestring) != EOK) {
244            cJSON_Delete(root);
245            free(*perms);
246            *perms = NULL;
247            return PERM_ERRORCODE_COPY_ERROR;
248        }
249        (*perms + i)->granted = (enum IsGranted) itemGranted->valueint;
250    }
251    *permNum = pSize;
252    cJSON_Delete(root);
253    return PERM_ERRORCODE_SUCCESS;
254}
255
256static int Notify(IOwner owner, int code, IpcIo *reply)
257{
258    if ((reply == NULL) || (owner == NULL)) {
259        HILOG_ERROR(HILOG_MODULE_APP, "Lite Ipc reply or owner is NULL");
260        return OHOS_FAILURE;
261    }
262
263    int32_t *ret = (int32_t *)owner;
264    ReadInt32(reply, ret);
265
266    return EC_SUCCESS;
267}
268
269static int DealQueryReply(IOwner owner, int code, IpcIo *reply)
270{
271    if ((reply == NULL) || (owner == NULL)) {
272        return OHOS_FAILURE;
273    }
274    int resultCode;
275    ReadInt32(reply, &resultCode);
276    RetOfQueryPerms *ret = (RetOfQueryPerms *)(owner);
277    if (resultCode != PERM_ERRORCODE_SUCCESS) {
278        ret->resultCode = resultCode;
279        return resultCode;
280    }
281    char *jsonStr = (char *)ReadString(reply, NULL);
282    HILOG_INFO(HILOG_MODULE_APP, "[perms: %s]", jsonStr);
283    int retCode = ParsePermissions(jsonStr, &(ret->permission), &(ret->length));
284    ret->resultCode = retCode;
285    return retCode;
286}
287
288int CheckSelfPermission(const char *permissionName)
289{
290    uid_t callingUid = getuid();
291    if (callingUid <= SYS_APP_UID_MAX) {
292        return GRANTED;
293    }
294    ClientApi *proxy = GetClientApi();
295    if (proxy == NULL) {
296        return OHOS_FAILURE;
297    }
298    IpcIo request;
299    char data[MAX_DATA_LEN];
300    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
301    WriteString(&request, permissionName);
302    int32_t ret = -1;
303    proxy->Invoke((IClientProxy *)proxy, ID_CHECK_SELF, &request, &ret, Notify);
304    ReleaseClientApi(proxy);
305    return ret;
306}
307
308int CheckPermission(int uid, const char *permissionName)
309{
310    uid_t callingUid = getuid();
311    if (callingUid <= SYS_APP_UID_MAX) {
312        return GRANTED;
313    }
314    InnerClientApi *proxy = GetInnerClientApi();
315    if (proxy == NULL) {
316        return OHOS_FAILURE;
317    }
318    IpcIo request;
319    char data[MAX_DATA_LEN];
320    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
321    WriteInt64(&request, uid);
322    WriteString(&request, permissionName);
323    int32_t ret = -1;
324    proxy->Invoke((IClientProxy *)proxy, ID_CHECK, &request, &ret, Notify);
325    ReleaseInnerClientApi(proxy);
326    return ret;
327}
328
329int QueryPermission(const char *identifier, PermissionSaved **permissions, int *permNum)
330{
331    ClientApi *proxy = GetClientApi();
332    if (proxy == NULL) {
333        return OHOS_FAILURE;
334    }
335    if (permissions == NULL || permNum == NULL) {
336        return OHOS_FAILURE;
337    }
338    IpcIo request;
339    char data[MAX_DATA_LEN];
340    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
341    WriteString(&request, identifier);
342    RetOfQueryPerms ret = {
343        .resultCode = 0,
344        .length = 0,
345        .permission = NULL
346    };
347    proxy->Invoke((IClientProxy *)proxy, ID_QUERY, &request, &ret, DealQueryReply);
348    *permissions = ret.permission;
349    *permNum = ret.length;
350    ReleaseClientApi(proxy);
351    return ret.resultCode;
352}
353
354int GrantPermission(const char *identifier, const char *permName)
355{
356    InnerClientApi *proxy = GetInnerClientApi();
357    if (proxy == NULL) {
358        return OHOS_FAILURE;
359    }
360    IpcIo request;
361    char data[MAX_DATA_LEN];
362    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
363    WriteString(&request, identifier);
364    WriteString(&request, permName);
365    int32_t ret = -1;
366    proxy->Invoke((IClientProxy *)proxy, ID_GRANT, &request, &ret, Notify);
367    ReleaseInnerClientApi(proxy);
368    HILOG_INFO(HILOG_MODULE_APP, "client grant[ret: %d]", ret);
369    return ret;
370}
371
372int RevokePermission(const char *identifier, const char *permName)
373{
374    InnerClientApi *proxy = GetInnerClientApi();
375    if (proxy == NULL) {
376        return OHOS_FAILURE;
377    }
378    IpcIo request;
379    char data[MAX_DATA_LEN];
380    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
381    WriteString(&request, identifier);
382    WriteString(&request, permName);
383    int32_t ret = -1;
384    proxy->Invoke((IClientProxy *)proxy, ID_REVOKE, &request, &ret, Notify);
385    ReleaseInnerClientApi(proxy);
386    HILOG_INFO(HILOG_MODULE_APP, "client revoke[ret: %d]", ret);
387    return ret;
388}
389
390int GrantRuntimePermission(int uid, const char *permissionName)
391{
392    InnerClientApi *proxy = GetInnerClientApi();
393    if (proxy == NULL) {
394        return OHOS_FAILURE;
395    }
396    IpcIo request;
397    char data[MAX_DATA_LEN];
398    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
399    WriteInt64(&request, uid);
400    WriteString(&request, permissionName);
401    int32_t ret = -1;
402    proxy->Invoke((IClientProxy *)proxy, ID_GRANT_RUNTIME, &request, &ret, Notify);
403    ReleaseInnerClientApi(proxy);
404    return ret;
405}
406
407int RevokeRuntimePermission(int uid, const char *permissionName)
408{
409    InnerClientApi *proxy = GetInnerClientApi();
410    if (proxy == NULL) {
411        return OHOS_FAILURE;
412    }
413    IpcIo request;
414    char data[MAX_DATA_LEN];
415    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
416    WriteInt64(&request, uid);
417    WriteString(&request, permissionName);
418    int32_t ret = -1;
419    proxy->Invoke((IClientProxy *)proxy, ID_REVOKE_RUNTIME, &request, &ret, Notify);
420    ReleaseInnerClientApi(proxy);
421    return ret;
422}
423
424int UpdatePermissionFlags(const char *identifier, const char *permissionName, const int flags)
425{
426    InnerClientApi *proxy = GetInnerClientApi();
427    if (proxy == NULL) {
428        return OHOS_FAILURE;
429    }
430    IpcIo request;
431    char data[MAX_DATA_LEN];
432    IpcIoInit(&request, data, MAX_DATA_LEN, 0);
433    WriteString(&request, identifier);
434    WriteString(&request, permissionName);
435    WriteInt32(&request, flags);
436    int32_t ret = -1;
437    proxy->Invoke((IClientProxy *)proxy, ID_UPDATE_PERMS_FLAGS, &request, &ret, Notify);
438    ReleaseInnerClientApi(proxy);
439    return ret;
440}
441
442