1 /*
2 * Copyright (c) 2021 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 #include "param_request.h"
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23
24 #include "init_utils.h"
25 #include "param_manager.h"
26 #include "param_message.h"
27 #include "param_security.h"
28
29 #define INVALID_SOCKET (-1)
30 #define INIT_PROCESS_PID 1
31
32 static const uint32_t RECV_BUFFER_MAX = 5 * 1024;
33
34 static atomic_uint g_requestId = ATOMIC_VAR_INIT(1);
35 static ClientWorkSpace g_clientSpace = { {}, -1, {} };
36
37 __attribute__((constructor)) static void ClientInit(void);
38 __attribute__((destructor)) static void ClientDeinit(void);
39
InitParamClient(void)40 static int InitParamClient(void)
41 {
42 if (getpid() == INIT_PROCESS_PID) {
43 PARAM_LOGI("Init process, do not init client");
44 return 0;
45 }
46 if (PARAM_TEST_FLAG(g_clientSpace.paramSpace.flags, WORKSPACE_FLAGS_INIT)) {
47 return 0;
48 }
49 PARAM_LOGV("InitParamClient");
50 pthread_mutex_init(&g_clientSpace.mutex, NULL);
51 g_clientSpace.clientFd = INVALID_SOCKET;
52 return InitParamWorkSpace(&g_clientSpace.paramSpace, 1);
53 }
54
ClientInit(void)55 void ClientInit(void)
56 {
57 PARAM_LOGV("ClientInit");
58 (void)InitParamClient();
59 }
60
ClientDeinit(void)61 void ClientDeinit(void)
62 {
63 }
64
GetClientParamSecurityOps(void)65 static ParamSecurityOps *GetClientParamSecurityOps(void)
66 {
67 return &g_clientSpace.paramSpace.paramSecurityOps;
68 }
69
FillLabelContent(const ParamMessage * request,uint32_t * start,uint32_t length)70 static int FillLabelContent(const ParamMessage *request, uint32_t *start, uint32_t length)
71 {
72 uint32_t bufferSize = request->msgSize - sizeof(ParamMessage);
73 uint32_t offset = *start;
74 PARAM_CHECK((offset + sizeof(ParamMsgContent) + length) <= bufferSize,
75 return -1, "Invalid msgSize %u offset %u", request->msgSize, offset);
76 ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
77 content->type = PARAM_LABEL;
78 content->contentSize = 0;
79 ParamSecurityOps *ops = GetClientParamSecurityOps();
80 if (length != 0 && ops != NULL && ops->securityEncodeLabel != NULL) {
81 int ret = ops->securityEncodeLabel(g_clientSpace.paramSpace.securityLabel, content->content, &length);
82 PARAM_CHECK(ret == 0, return -1, "Failed to get label length");
83 content->contentSize = length;
84 }
85 offset += sizeof(ParamMsgContent) + PARAM_ALIGN(content->contentSize);
86 *start = offset;
87 return 0;
88 }
89
ProcessRecvMsg(const ParamMessage * recvMsg)90 static int ProcessRecvMsg(const ParamMessage *recvMsg)
91 {
92 PARAM_LOGV("ProcessRecvMsg type: %u msgId: %u name %s", recvMsg->type, recvMsg->id.msgId, recvMsg->key);
93 int result = PARAM_CODE_INVALID_PARAM;
94 switch (recvMsg->type) {
95 case MSG_SET_PARAM:
96 result = ((ParamResponseMessage *)recvMsg)->result;
97 break;
98 case MSG_NOTIFY_PARAM: {
99 uint32_t offset = 0;
100 ParamMsgContent *valueContent = GetNextContent(recvMsg, &offset);
101 PARAM_CHECK(valueContent != NULL, return PARAM_CODE_TIMEOUT, "Invalid msg");
102 result = 0;
103 break;
104 }
105 default:
106 break;
107 }
108 return result;
109 }
110
StartRequest(int * fd,ParamMessage * request,int timeout)111 static int StartRequest(int *fd, ParamMessage *request, int timeout)
112 {
113 int ret = 0;
114 struct timeval time;
115 #ifndef STARTUP_INIT_TEST
116 time.tv_sec = timeout;
117 #else
118 time.tv_sec = 1;
119 #endif
120 time.tv_usec = 0;
121 do {
122 int clientFd = *fd;
123 if (clientFd == INVALID_SOCKET) {
124 clientFd = socket(AF_UNIX, SOCK_STREAM, 0);
125 PARAM_CHECK(clientFd >= 0, return PARAM_CODE_FAIL_CONNECT, "Failed to create socket");
126 ret = ConntectServer(clientFd, CLIENT_PIPE_NAME);
127 PARAM_CHECK(ret == 0, close(clientFd);
128 return PARAM_CODE_FAIL_CONNECT, "Failed to connect server");
129 setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&time, sizeof(struct timeval));
130 setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&time, sizeof(struct timeval));
131 *fd = clientFd;
132 }
133 ssize_t recvLen = 0;
134 ssize_t sendLen = send(clientFd, (char *)request, request->msgSize, 0);
135 if (sendLen > 0) {
136 recvLen = recv(clientFd, (char *)request, RECV_BUFFER_MAX, 0);
137 if (recvLen > 0) {
138 break;
139 }
140 }
141 ret = errno;
142 close(clientFd);
143 *fd = INVALID_SOCKET;
144 if (errno == EAGAIN || recvLen <= 0) {
145 ret = PARAM_CODE_TIMEOUT;
146 break;
147 }
148 PARAM_LOGE("Send or recv msg fail errno %d %zd %zd", errno, sendLen, recvLen);
149 } while (1);
150
151 if (ret == 0) { // check result
152 ret = ProcessRecvMsg(request);
153 }
154 return ret;
155 }
156
NeedCheckParamPermission(const char * name)157 static int NeedCheckParamPermission(const char *name)
158 {
159 static char *ctrlParam[] = {
160 "ohos.ctl.start",
161 "ohos.ctl.stop",
162 "ohos.startup.powerctrl"
163 };
164 for (size_t i = 0; i < ARRAY_LENGTH(ctrlParam); i++) {
165 if (strcmp(name, ctrlParam[i]) == 0) {
166 return 0;
167 }
168 }
169 ParamSecurityLabel *securityLabel = g_clientSpace.paramSpace.securityLabel;
170 if (securityLabel != NULL &&
171 ((securityLabel->flags & LABEL_CHECK_FOR_ALL_PROCESS) == LABEL_CHECK_FOR_ALL_PROCESS) &&
172 ((securityLabel->flags & LABEL_ALL_PERMISSION) != LABEL_ALL_PERMISSION)) {
173 return 1;
174 }
175 return 0;
176 }
177
SystemSetParameter(const char * name,const char * value)178 int SystemSetParameter(const char *name, const char *value)
179 {
180 InitParamClient();
181 PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid name or value");
182 int ret = CheckParamName(name, 0);
183 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
184 uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + PARAM_ALIGN(strlen(value) + 1);
185 uint32_t labelLen = 0;
186 ParamSecurityOps *ops = GetClientParamSecurityOps();
187 if (NeedCheckParamPermission(name) == 1) {
188 ret = CheckParamPermission(&g_clientSpace.paramSpace, g_clientSpace.paramSpace.securityLabel, name, DAC_WRITE);
189 PARAM_CHECK(ret == 0, return ret, "Forbit to set parameter %s", name);
190 } else if (!LABEL_IS_ALL_PERMITTED(g_clientSpace.paramSpace.securityLabel)) { // check local can check permissions
191 PARAM_CHECK(ops != NULL && ops->securityEncodeLabel != NULL, return -1, "Invalid securityEncodeLabel");
192 ret = ops->securityEncodeLabel(g_clientSpace.paramSpace.securityLabel, NULL, &labelLen);
193 PARAM_CHECK(ret == 0, return -1, "Failed to get label length");
194 }
195 msgSize += sizeof(ParamMsgContent) + labelLen;
196 msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
197
198 ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize);
199 PARAM_CHECK(request != NULL, return -1, "Failed to malloc for connect");
200 uint32_t offset = 0;
201 ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
202 PARAM_CHECK(ret == 0, free(request);
203 return -1, "Failed to fill value");
204 ret = FillLabelContent(request, &offset, labelLen);
205 PARAM_CHECK(ret == 0, free(request);
206 return -1, "Failed to fill label");
207 request->msgSize = offset + sizeof(ParamMessage);
208 request->id.msgId = atomic_fetch_add(&g_requestId, 1);
209
210 pthread_mutex_lock(&g_clientSpace.mutex);
211 ret = StartRequest(&g_clientSpace.clientFd, request, DEFAULT_PARAM_SET_TIMEOUT);
212 pthread_mutex_unlock(&g_clientSpace.mutex);
213 free(request);
214 return ret;
215 }
216
SystemWaitParameter(const char * name,const char * value,int32_t timeout)217 int SystemWaitParameter(const char *name, const char *value, int32_t timeout)
218 {
219 InitParamClient();
220 PARAM_CHECK(name != NULL, return -1, "Invalid name");
221 int ret = CheckParamName(name, 0);
222 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
223 ParamHandle handle = 0;
224 ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle);
225 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
226 PARAM_CHECK(ret == 0, return ret, "Forbid to wait parameter %s", name);
227 }
228 if (timeout <= 0) {
229 timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
230 }
231 uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + sizeof(ParamMsgContent) + sizeof(uint32_t);
232 msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
233 uint32_t offset = 0;
234 ParamMessage *request = NULL;
235 if (value != NULL && strlen(value) > 0) {
236 msgSize += PARAM_ALIGN(strlen(value) + 1);
237 request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
238 PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
239 ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
240 } else {
241 msgSize += PARAM_ALIGN(1);
242 request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
243 PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
244 ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1);
245 }
246 PARAM_CHECK(ret == 0, free(request);
247 return -1, "Failed to fill value");
248 ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
249 content->type = PARAM_WAIT_TIMEOUT;
250 content->contentSize = sizeof(uint32_t);
251 *((uint32_t *)(content->content)) = timeout;
252 offset += sizeof(ParamMsgContent) + sizeof(uint32_t);
253
254 request->msgSize = offset + sizeof(ParamMessage);
255 request->id.waitId = atomic_fetch_add(&g_requestId, 1);
256 int fd = INVALID_SOCKET;
257 ret = StartRequest(&fd, request, timeout);
258 if (fd != INVALID_SOCKET) {
259 close(fd);
260 }
261 free(request);
262 PARAM_LOGI("SystemWaitParameter %s value %s result %d ", name, value, ret);
263 return ret;
264 }
265
SystemGetParameter(const char * name,char * value,unsigned int * len)266 int SystemGetParameter(const char *name, char *value, unsigned int *len)
267 {
268 InitParamClient();
269 PARAM_CHECK(name != NULL && len != NULL, return -1, "The name or value is null");
270 ParamHandle handle = 0;
271 int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle);
272 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
273 PARAM_CHECK(ret == 0, return ret, "Forbid to get parameter %s", name);
274 }
275 return ReadParamValue(&g_clientSpace.paramSpace, handle, value, len);
276 }
277
SystemFindParameter(const char * name,ParamHandle * handle)278 int SystemFindParameter(const char *name, ParamHandle *handle)
279 {
280 InitParamClient();
281 PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null");
282 int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, handle);
283 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
284 PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
285 }
286 return ret;
287 }
288
SysCheckParamExist(const char * name)289 int SysCheckParamExist(const char *name)
290 {
291 InitParamClient();
292 PARAM_CHECK(name != NULL, return -1, "The name or handle is null");
293 ParamHandle handle;
294 int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle);
295 PARAM_LOGI("SysCheckParamExist %s result %d", name, ret);
296 if (ret == PARAM_CODE_NODE_EXIST) {
297 return 0;
298 }
299 PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
300 return ret;
301 }
302
SystemGetParameterCommitId(ParamHandle handle,uint32_t * commitId)303 int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId)
304 {
305 PARAM_CHECK(handle != 0 || commitId != NULL, return -1, "The handle is null");
306 return ReadParamCommitId(&g_clientSpace.paramSpace, handle, commitId);
307 }
308
SystemGetParameterName(ParamHandle handle,char * name,unsigned int len)309 int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len)
310 {
311 PARAM_CHECK(name != NULL && handle != 0, return -1, "The name is null");
312 return ReadParamName(&g_clientSpace.paramSpace, handle, name, len);
313 }
314
SystemGetParameterValue(ParamHandle handle,char * value,unsigned int * len)315 int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len)
316 {
317 PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null");
318 return ReadParamValue(&g_clientSpace.paramSpace, handle, value, len);
319 }
320
SystemTraversalParameter(const char * prefix,void (* traversalParameter)(ParamHandle handle,void * cookie),void * cookie)321 int SystemTraversalParameter(const char *prefix,
322 void (*traversalParameter)(ParamHandle handle, void *cookie), void *cookie)
323 {
324 InitParamClient();
325 PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null");
326 ParamHandle handle = 0;
327 // check default dac
328 const char *tmp = (prefix == NULL || strlen(prefix) == 0) ? "#" : prefix;
329 int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, tmp, DAC_READ, &handle);
330 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
331 PARAM_CHECK(ret == 0, return ret, "Forbid to traversal parameters");
332 }
333 return TraversalParam(&g_clientSpace.paramSpace, tmp, traversalParameter, cookie);
334 }
335
SystemDumpParameters(int verbose)336 void SystemDumpParameters(int verbose)
337 {
338 InitParamClient();
339 // check default dac
340 ParamHandle handle = 0;
341 int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, "#", DAC_READ, &handle);
342 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
343 PARAM_CHECK(ret == 0, return, "Forbid to dump parameters");
344 }
345 DumpParameters(&g_clientSpace.paramSpace, verbose);
346 }
347
WatchParamCheck(const char * keyprefix)348 int WatchParamCheck(const char *keyprefix)
349 {
350 InitParamClient();
351 PARAM_CHECK(keyprefix != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid keyprefix");
352 int ret = CheckParamName(keyprefix, 0);
353 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", keyprefix);
354 ParamHandle handle = 0;
355 ret = ReadParamWithCheck(&g_clientSpace.paramSpace, keyprefix, DAC_WATCH, &handle);
356 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
357 PARAM_CHECK(ret == 0, return ret, "Forbid to watch parameter %s", keyprefix);
358 }
359 return 0;
360 }
361
GetParamSecurityAuditData(const char * name,int type,ParamAuditData * auditData)362 int GetParamSecurityAuditData(const char *name, int type, ParamAuditData *auditData)
363 {
364 uint32_t labelIndex = 0;
365 FindTrieNode(&g_clientSpace.paramSpace.paramSpace, name, strlen(name), &labelIndex);
366 ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&g_clientSpace.paramSpace.paramSpace, labelIndex);
367 PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
368
369 auditData->name = name;
370 auditData->dacData.uid = node->uid;
371 auditData->dacData.gid = node->gid;
372 auditData->dacData.mode = node->mode;
373 if (node->length > 0) {
374 auditData->label = strdup(node->data);
375 }
376 return 0;
377 }
378
379 #if (defined STARTUP_INIT_TEST || defined PARAM_TEST)
GetClientParamWorkSpace(void)380 ParamWorkSpace *GetClientParamWorkSpace(void)
381 {
382 return &g_clientSpace.paramSpace;
383 }
384 #endif