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 <ctype.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/socket.h>
20
21 #include "init_log.h"
22 #include "init_param.h"
23 #include "init_utils.h"
24 #include "loop_event.h"
25 #include "param_manager.h"
26 #include "param_message.h"
27 #include "trigger_manager.h"
28 #include "securec.h"
29 #ifdef PARAM_SUPPORT_SELINUX
30 #include "selinux_parameter.h"
31 #include <policycoreutils.h>
32 #include <selinux/selinux.h>
33 #endif
34
35 static ParamService g_paramService = {};
36
OnClose(ParamTaskPtr client)37 PARAM_STATIC void OnClose(ParamTaskPtr client)
38 {
39 ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client);
40 if (client == g_paramService.watcherTask) {
41 ClearWatchTrigger(watcher, TRIGGER_PARAM_WATCH);
42 g_paramService.watcherTask = NULL;
43 } else {
44 ClearWatchTrigger(watcher, TRIGGER_PARAM_WAIT);
45 }
46 }
47
TimerCallback(const ParamTaskPtr timer,void * context)48 static void TimerCallback(const ParamTaskPtr timer, void *context)
49 {
50 UNUSED(context);
51 UNUSED(timer);
52 int ret = CheckWatchTriggerTimeout();
53 // no wait node
54 if (ret == 0 && g_paramService.timer != NULL) {
55 ParamTaskClose(g_paramService.timer);
56 g_paramService.timer = NULL;
57 }
58 }
59
CheckAndSendTrigger(uint32_t dataIndex,const char * name,const char * value)60 static void CheckAndSendTrigger(uint32_t dataIndex, const char *name, const char *value)
61 {
62 ParamNode *entry = (ParamNode *)GetTrieNode(GetWorkSpaceByName(name), dataIndex);
63 PARAM_CHECK(entry != NULL, return, "Failed to get data %s ", name);
64 uint32_t trigger = 1;
65 if ((ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_RELAXED) & PARAM_FLAGS_TRIGGED) != PARAM_FLAGS_TRIGGED) {
66 trigger = (CheckAndMarkTrigger(TRIGGER_PARAM, name) != 0) ? 1 : 0;
67 }
68 if (trigger) {
69 ATOMIC_SYNC_OR_AND_FETCH(&entry->commitId, PARAM_FLAGS_TRIGGED, MEMORY_ORDER_RELEASE);
70 // notify event to process trigger
71 PostParamTrigger(EVENT_TRIGGER_PARAM, name, value);
72 }
73
74 int wait = 1;
75 if ((ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_RELAXED) & PARAM_FLAGS_WAITED) != PARAM_FLAGS_WAITED) {
76 wait = (CheckAndMarkTrigger(TRIGGER_PARAM_WAIT, name) != 0) ? 1 : 0;
77 }
78 if (wait) {
79 ATOMIC_SYNC_OR_AND_FETCH(&entry->commitId, PARAM_FLAGS_WAITED, MEMORY_ORDER_RELEASE);
80 PostParamTrigger(EVENT_TRIGGER_PARAM_WAIT, name, value);
81 }
82 PostParamTrigger(EVENT_TRIGGER_PARAM_WATCH, name, value);
83 }
84
SendResponseMsg(ParamTaskPtr worker,const ParamMessage * msg,int result)85 static int SendResponseMsg(ParamTaskPtr worker, const ParamMessage *msg, int result)
86 {
87 ParamResponseMessage *response = NULL;
88 response = (ParamResponseMessage *)CreateParamMessage(msg->type, msg->key, sizeof(ParamResponseMessage));
89 PARAM_CHECK(response != NULL, return PARAM_CODE_ERROR, "Failed to alloc memory for response");
90 response->msg.id.msgId = msg->id.msgId;
91 response->result = result;
92 response->msg.msgSize = sizeof(ParamResponseMessage);
93 ParamTaskSendMsg(worker, (ParamMessage *)response);
94 PARAM_LOGV("Send response msg msgId %d result %d", msg->id.msgId, result);
95 return 0;
96 }
97
SendWatcherNotifyMessage(const TriggerExtInfo * extData,const char * content,uint32_t size)98 static int SendWatcherNotifyMessage(const TriggerExtInfo *extData, const char *content, uint32_t size)
99 {
100 PARAM_CHECK(content != NULL, return -1, "Invalid content");
101 PARAM_CHECK(extData != NULL && extData->stream != NULL, return -1, "Invalid extData");
102 uint32_t msgSize = sizeof(ParamMessage) + PARAM_ALIGN(strlen(content) + 1);
103 ParamMessage *msg = (ParamMessage *)CreateParamMessage(MSG_NOTIFY_PARAM, "*", msgSize);
104 PARAM_CHECK(msg != NULL, return -1, "Failed to create msg ");
105
106 uint32_t offset = 0;
107 int ret;
108 char *tmp = strstr(content, "=");
109 if (tmp != NULL) {
110 ret = strncpy_s(msg->key, sizeof(msg->key) - 1, content, tmp - content);
111 PARAM_CHECK(ret == 0, free(msg);
112 return -1, "Failed to fill value");
113 tmp++;
114 ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, tmp, strlen(tmp));
115 PARAM_CHECK(ret == 0, free(msg);
116 return -1, "Failed to fill value");
117 } else if (content != NULL && strlen(content) > 0) {
118 ret = FillParamMsgContent(msg, &offset, PARAM_VALUE, content, strlen(content));
119 PARAM_CHECK(ret == 0, free(msg);
120 return -1, "Failed to fill value");
121 }
122
123 msg->id.msgId = 0;
124 if (extData->type == TRIGGER_PARAM_WAIT) {
125 msg->id.msgId = extData->info.waitInfo.waitId;
126 } else {
127 msg->id.msgId = extData->info.watchInfo.watchId;
128 }
129 msg->msgSize = sizeof(ParamMessage) + offset;
130 PARAM_LOGV("SendWatcherNotifyMessage cmd %s, id %d msgSize %d para: %s",
131 (extData->type == TRIGGER_PARAM_WAIT) ? "wait" : "watcher",
132 msg->id.msgId, msg->msgSize, content);
133 ParamTaskSendMsg(extData->stream, msg);
134 return 0;
135 }
136
SystemSetParam(const char * name,const char * value,const ParamSecurityLabel * srcLabel)137 static int SystemSetParam(const char *name, const char *value, const ParamSecurityLabel *srcLabel)
138 {
139 PARAM_LOGV("SystemWriteParam name %s value: %s", name, value);
140 int ctrlService = 0;
141 int ret = CheckParameterSet(name, value, srcLabel, &ctrlService);
142 PARAM_CHECK(ret == 0, return ret, "Forbid to set parameter %s", name);
143
144 if ((ctrlService & PARAM_CTRL_SERVICE) != PARAM_CTRL_SERVICE) { // ctrl param
145 uint32_t dataIndex = 0;
146 ret = WriteParam(name, value, &dataIndex, 0);
147 PARAM_CHECK(ret == 0, return ret, "Failed to set param %d name %s %s", ret, name, value);
148 ret = WritePersistParam(name, value);
149 PARAM_CHECK(ret == 0, return ret, "Failed to set persist param name %s", name);
150 CheckAndSendTrigger(dataIndex, name, value);
151 }
152 return ret;
153 }
154
HandleParamSet(const ParamTaskPtr worker,const ParamMessage * msg)155 static int HandleParamSet(const ParamTaskPtr worker, const ParamMessage *msg)
156 {
157 uint32_t offset = 0;
158 ParamMsgContent *valueContent = GetNextContent(msg, &offset);
159 PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg for %s", msg->key);
160 ParamSecurityLabel srcLabel = {0};
161 struct ucred cr = {-1, -1, -1};
162 socklen_t crSize = sizeof(cr);
163 if (getsockopt(LE_GetSocketFd(worker), SOL_SOCKET, SO_PEERCRED, &cr, &crSize) < 0) {
164 PARAM_LOGE("Failed to get opt %d", errno);
165 #ifndef STARTUP_INIT_TEST
166 return SendResponseMsg(worker, msg, -1);
167 #endif
168 }
169 srcLabel.sockFd = LE_GetSocketFd(worker);
170 srcLabel.cred.uid = cr.uid;
171 srcLabel.cred.pid = cr.pid;
172 srcLabel.cred.gid = cr.gid;
173 PARAM_LOGI("Handle set param msgId %d pid %d key: %s", msg->id.msgId, cr.pid, msg->key);
174 int ret = SystemSetParam(msg->key, valueContent->content, &srcLabel);
175 return SendResponseMsg(worker, msg, ret);
176 }
177
AddWatchNode(struct tagTriggerNode_ * trigger,const struct TriggerExtInfo_ * extInfo)178 static int32_t AddWatchNode(struct tagTriggerNode_ *trigger, const struct TriggerExtInfo_ *extInfo)
179 {
180 ParamWatcher *watcher = NULL;
181 if (extInfo != NULL && extInfo->stream != NULL) {
182 watcher = (ParamWatcher *)ParamGetTaskUserData(extInfo->stream);
183 }
184 PARAM_CHECK(watcher != NULL, return -1, "Failed to get param watcher data");
185 if (extInfo->type == TRIGGER_PARAM_WAIT) {
186 WaitNode *node = (WaitNode *)trigger;
187 OH_ListInit(&node->item);
188 node->timeout = extInfo->info.waitInfo.timeout;
189 node->stream = extInfo->stream;
190 node->waitId = extInfo->info.waitInfo.waitId;
191 OH_ListAddTail(&watcher->triggerHead, &node->item);
192 } else {
193 WatchNode *node = (WatchNode *)trigger;
194 OH_ListInit(&node->item);
195 node->watchId = extInfo->info.watchInfo.watchId;
196 OH_ListAddTail(&watcher->triggerHead, &node->item);
197 }
198 return 0;
199 }
200
AddWatcherTrigger(int triggerType,const char * condition,const TriggerExtInfo * extData)201 static TriggerNode *AddWatcherTrigger(int triggerType, const char *condition, const TriggerExtInfo *extData)
202 {
203 TriggerWorkSpace *workSpace = GetTriggerWorkSpace();
204 TriggerHeader *header = (TriggerHeader *)&workSpace->triggerHead[extData->type];
205 return header->addTrigger(workSpace, condition, extData);
206 }
207
ExecuteWatchTrigger_(const struct tagTriggerNode_ * trigger,const char * content,uint32_t size)208 static int32_t ExecuteWatchTrigger_(const struct tagTriggerNode_ *trigger, const char *content, uint32_t size)
209 {
210 TriggerExtInfo extData = {};
211 extData.type = trigger->type;
212 if (trigger->type == TRIGGER_PARAM_WAIT) {
213 WaitNode *node = (WaitNode *)trigger;
214 extData.stream = node->stream;
215 extData.info.waitInfo.waitId = node->waitId;
216 extData.info.waitInfo.timeout = node->timeout;
217 } else {
218 WatchNode *node = (WatchNode *)trigger;
219 extData.stream = g_paramService.watcherTask;
220 extData.info.watchInfo.watchId = node->watchId;
221 }
222 if (content == NULL) {
223 return SendWatcherNotifyMessage(&extData, "", 0);
224 }
225 return SendWatcherNotifyMessage(&extData, content, size);
226 }
227
HandleParamWaitAdd(const ParamTaskPtr worker,const ParamMessage * msg)228 static int HandleParamWaitAdd(const ParamTaskPtr worker, const ParamMessage *msg)
229 {
230 PARAM_CHECK(msg != NULL, return -1, "Invalid message");
231 uint32_t offset = 0;
232 #ifndef STARTUP_INIT_TEST
233 uint32_t timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
234 #else
235 uint32_t timeout = 0;
236 #endif
237 ParamMsgContent *valueContent = GetNextContent(msg, &offset);
238 PARAM_CHECK(valueContent != NULL, return -1, "Invalid msg");
239 PARAM_CHECK(valueContent->contentSize <= PARAM_CONST_VALUE_LEN_MAX, return -1, "Invalid msg");
240 ParamMsgContent *timeoutContent = GetNextContent(msg, &offset);
241 if (timeoutContent != NULL) {
242 timeout = *((uint32_t *)(timeoutContent->content));
243 }
244
245 PARAM_LOGV("HandleParamWaitAdd name %s timeout %d", msg->key, timeout);
246 TriggerExtInfo extData = {};
247 extData.addNode = AddWatchNode;
248 extData.type = TRIGGER_PARAM_WAIT;
249 extData.stream = worker;
250 extData.info.waitInfo.waitId = msg->id.watcherId;
251 extData.info.waitInfo.timeout = timeout;
252 // first check match, if match send response to client
253 ParamNode *param = SystemCheckMatchParamWait(msg->key, valueContent->content);
254 if (param != NULL) {
255 SendWatcherNotifyMessage(&extData, param->data, param->valueLength);
256 return 0;
257 }
258
259 uint32_t buffSize = strlen(msg->key) + valueContent->contentSize + 1 + 1;
260 char *condition = calloc(1, buffSize);
261 PARAM_CHECK(condition != NULL, return -1, "Failed to create condition for %s", msg->key);
262 int ret = sprintf_s(condition, buffSize - 1, "%s=%s", msg->key, valueContent->content);
263 PARAM_CHECK(ret > EOK, free(condition);
264 return -1, "Failed to copy name for %s", msg->key);
265 TriggerNode *trigger = AddWatcherTrigger(TRIGGER_PARAM_WAIT, condition, &extData);
266 PARAM_CHECK(trigger != NULL, free(condition);
267 return -1, "Failed to add trigger for %s", msg->key);
268 free(condition);
269 if (g_paramService.timer == NULL) {
270 ret = ParamTimerCreate(&g_paramService.timer, TimerCallback, &g_paramService);
271 PARAM_CHECK(ret == 0, return 0, "Failed to create timer %s", msg->key);
272 ret = ParamTimerStart(g_paramService.timer, MS_UNIT, (uint64_t)-1);
273 PARAM_CHECK(ret == 0,
274 ParamTaskClose(g_paramService.timer);
275 g_paramService.timer = NULL;
276 return 0, "Failed to set timer %s", msg->key);
277 }
278 return 0;
279 }
280
HandleParamWatcherAdd(const ParamTaskPtr worker,const ParamMessage * msg)281 static int HandleParamWatcherAdd(const ParamTaskPtr worker, const ParamMessage *msg)
282 {
283 PARAM_CHECK(msg != NULL, return -1, "Invalid message");
284 PARAM_CHECK((g_paramService.watcherTask == NULL) ||
285 (g_paramService.watcherTask == worker), return -1, "Invalid watcher worker");
286 g_paramService.watcherTask = worker;
287 TriggerExtInfo extData = {};
288 extData.type = TRIGGER_PARAM_WATCH;
289 extData.addNode = AddWatchNode;
290 extData.stream = worker;
291 extData.info.watchInfo.watchId = msg->id.watcherId;
292 TriggerNode *trigger = AddWatcherTrigger(TRIGGER_PARAM_WATCH, msg->key, &extData);
293 if (trigger == NULL) {
294 PARAM_LOGE("Failed to add trigger for %s", msg->key);
295 return SendResponseMsg(worker, msg, -1);
296 }
297 PARAM_LOGV("HandleParamWatcherAdd name %s watcher: %d", msg->key, msg->id.watcherId);
298 return SendResponseMsg(worker, msg, 0);
299 }
300
HandleParamWatcherDel(const ParamTaskPtr worker,const ParamMessage * msg)301 static int HandleParamWatcherDel(const ParamTaskPtr worker, const ParamMessage *msg)
302 {
303 PARAM_CHECK(msg != NULL, return -1, "Invalid message");
304 PARAM_LOGV("HandleParamWatcherDel name %s watcher: %d", msg->key, msg->id.watcherId);
305 DelWatchTrigger(TRIGGER_PARAM_WATCH, (const void *)&msg->id.watcherId);
306 return SendResponseMsg(worker, msg, 0);
307 }
308
ProcessMessage(const ParamTaskPtr worker,const ParamMessage * msg)309 PARAM_STATIC int ProcessMessage(const ParamTaskPtr worker, const ParamMessage *msg)
310 {
311 PARAM_CHECK((msg != NULL) && (msg->msgSize >= sizeof(ParamMessage)), return -1, "Invalid msg");
312 PARAM_CHECK(worker != NULL, return -1, "Invalid worker");
313 int ret = PARAM_CODE_INVALID_PARAM;
314 switch (msg->type) {
315 case MSG_SET_PARAM:
316 ret = HandleParamSet(worker, msg);
317 break;
318 case MSG_WAIT_PARAM:
319 ret = HandleParamWaitAdd(worker, msg);
320 break;
321 case MSG_ADD_WATCHER:
322 ret = HandleParamWatcherAdd(worker, msg);
323 break;
324 case MSG_DEL_WATCHER:
325 ret = HandleParamWatcherDel(worker, msg);
326 break;
327 default:
328 break;
329 }
330 PARAM_CHECK(ret == 0, return -1, "Failed to process message ret %d", ret);
331 return 0;
332 }
333
OnIncomingConnect(LoopHandle loop,TaskHandle server)334 PARAM_STATIC int OnIncomingConnect(LoopHandle loop, TaskHandle server)
335 {
336 ParamStreamInfo info = {};
337 #ifdef STARTUP_INIT_TEST
338 info.flags = PARAM_TEST_FLAGS;
339 #endif
340 info.server = NULL;
341 info.close = OnClose;
342 info.recvMessage = ProcessMessage;
343 info.incomingConnect = NULL;
344 ParamTaskPtr client = NULL;
345 int ret = ParamStreamCreate(&client, server, &info, sizeof(ParamWatcher));
346 PARAM_CHECK(ret == 0, return -1, "Failed to create client");
347
348 ParamWatcher *watcher = (ParamWatcher *)ParamGetTaskUserData(client);
349 PARAM_CHECK(watcher != NULL, return -1, "Failed to get watcher");
350 OH_ListInit(&watcher->triggerHead);
351 watcher->stream = client;
352 #ifdef STARTUP_INIT_TEST
353 g_paramService.watcherTask = client;
354 #endif
355 return 0;
356 }
357
LoadSelinuxLabel(const char * op)358 static void LoadSelinuxLabel(const char *op)
359 {
360 // load security label
361 #ifdef PARAM_SUPPORT_SELINUX
362 ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX);
363 if (ops != NULL && ops->securityGetLabel != NULL) {
364 ops->securityGetLabel(op);
365 }
366 #endif
367 }
368
InitParamService(void)369 void InitParamService(void)
370 {
371 PARAM_LOGI("InitParamService pipe: %s.", PIPE_NAME);
372 CheckAndCreateDir(PIPE_NAME);
373 CheckAndCreateDir(PARAM_STORAGE_PATH"/");
374 // param space
375 PARAM_WORKSPACE_OPS ops = {0};
376 ops.updaterMode = InUpdaterMode();
377 // init open log
378 ops.logFunc = InitLog;
379 ops.getServiceGroupIdByPid = GetServiceGroupIdByPid;
380 #ifdef PARAM_SUPPORT_SELINUX
381 ops.setfilecon = setfilecon;
382 #endif
383 int ret = InitParamWorkSpace(0, &ops);
384 PARAM_CHECK(ret == 0, return, "Init parameter workspace fail");
385 ret = InitPersistParamWorkSpace();
386 PARAM_CHECK(ret == 0, return, "Init persist parameter workspace fail");
387 // param server
388 if (g_paramService.serverTask == NULL) {
389 ParamStreamInfo info = {};
390 info.server = PIPE_NAME;
391 info.close = NULL;
392 info.recvMessage = NULL;
393 info.incomingConnect = OnIncomingConnect;
394 ret = ParamServerCreate(&g_paramService.serverTask, &info);
395 PARAM_CHECK(ret == 0, return, "Failed to create server");
396 }
397
398 // init trigger space
399 ret = InitTriggerWorkSpace();
400 PARAM_CHECK(ret == 0, return, "Failed to init trigger");
401 RegisterTriggerExec(TRIGGER_PARAM_WAIT, ExecuteWatchTrigger_);
402 RegisterTriggerExec(TRIGGER_PARAM_WATCH, ExecuteWatchTrigger_);
403 }
404
LoadSpecialParam(void)405 void LoadSpecialParam(void)
406 {
407 // read param area size from cfg and save to dac
408 LoadParamAreaSize();
409 // read selinux label
410 LoadSelinuxLabel(NULL);
411 // from cmdline
412 LoadParamFromCmdLine();
413 // from build
414 LoadParamFromBuild();
415 }
416
StartParamService(void)417 int StartParamService(void)
418 {
419 // read selinux label
420 LoadSelinuxLabel("permission");
421 return ParamServiceStart();
422 }
423
StopParamService(void)424 void StopParamService(void)
425 {
426 PARAM_LOGI("StopParamService.");
427 ClosePersistParamWorkSpace();
428 CloseParamWorkSpace();
429 CloseTriggerWorkSpace();
430 ParamTaskClose(g_paramService.serverTask);
431 g_paramService.serverTask = NULL;
432 ParamServiceStop();
433 }
434
SystemWriteParam(const char * name,const char * value)435 int SystemWriteParam(const char *name, const char *value)
436 {
437 return SystemSetParam(name, value, GetParamSecurityLabel());
438 }
439
440 #ifdef STARTUP_INIT_TEST
GetParamService()441 ParamService *GetParamService()
442 {
443 return &g_paramService;
444 }
445 #endif
446