1 /*
2 * Copyright (c) 2021-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 "config_policy_utils.h"
17
18 #include <ctype.h>
19 #include <securec.h>
20 #include <stdbool.h>
21 #include <unistd.h>
22
23 #include "config_policy_impl.h"
24 #ifndef __LITEOS__
25 #include "init_param.h"
26 #endif
27
28 static const size_t MIN_APPEND_LEN = 32;
29 // ':' split different x rules, example:":relPath,mode[,extra][:]"
30 // ',' split different param for x rules
31 // ":-" split for key:-value
32 // exampe:"etc/xml/config.xml,10:etc/xml/config1.xml,100,etc/carrier/${key:-value}"
33 static const char SEP_FOR_X_RULE = ':';
34 static const char SEP_FOR_X_PARAM = ',';
35 static const char *SEP_FOR_X_VALUE = ":-";
36
37 typedef struct {
38 size_t size; // allocated buffer size of p
39 size_t strLen; // strlen(p), less than size
40 char *p; // just init to NULL, by malloc
41 } StringHolder;
42
43 typedef struct {
44 int segCount; // count of char * in segs
45 char *orgStr;
46 char *segs[1];
47 } SplitedStr;
48
49 #ifdef __LITEOS_M__
50 // The data will be used always, so prealloc to avoid memory fragment
51 static char gConfigPolicy[MINI_CONFIG_POLICY_BUF_SIZE] = {0};
SetMiniConfigPolicy(const char * policy)52 void SetMiniConfigPolicy(const char *policy)
53 {
54 if (gConfigPolicy[0] != 0) {
55 return; // now only set once
56 }
57 (void)strcpy_s(gConfigPolicy, sizeof(gConfigPolicy), policy);
58 }
59
TrigSetMiniConfigPolicy()60 __WEAK void TrigSetMiniConfigPolicy()
61 {
62 return;
63 }
64 #endif
65
66 /**
67 * query function, the memory is allocated in function
68 * @return value, or NULL if not exist or strlen(value) is 0
69 * @NOTICE caller should free the returned value
70 */
71 typedef char *(*QueryFunc)(const char *key);
72 static char *ExpandStr(char *src, const char *def, QueryFunc queryFunc);
73
Min(size_t a,size_t b)74 static inline size_t Min(size_t a, size_t b)
75 {
76 return a < b ? a : b;
77 }
78
Max(size_t a,size_t b)79 static inline size_t Max(size_t a, size_t b)
80 {
81 return a > b ? a : b;
82 }
83
FreeIf(void * p)84 static void FreeIf(void *p)
85 {
86 if (p != NULL) {
87 free(p);
88 }
89 }
90
91 #ifndef __LITEOS__
CustGetSystemParam(const char * name)92 static char *CustGetSystemParam(const char *name)
93 {
94 char *value = NULL;
95 unsigned int len = 0;
96
97 if (SystemGetParameter(name, NULL, &len) != 0 || len == 0) {
98 return NULL;
99 }
100 value = (char *)calloc(len, sizeof(char));
101 if (value != NULL && SystemGetParameter(name, value, &len) == 0 && value[0]) {
102 return value;
103 }
104 FreeIf(value);
105 return NULL;
106 }
107
GetOpkeyPath(int type)108 static char *GetOpkeyPath(int type)
109 {
110 char *result = NULL;
111 const char *opKeyDir = "etc/carrier/";
112 const char *opKeyName = CUST_OPKEY0;
113 if (type == FOLLOWX_MODE_SIM_1) {
114 opKeyName = CUST_OPKEY0;
115 } else if (type == FOLLOWX_MODE_SIM_2) {
116 opKeyName = CUST_OPKEY1;
117 } else {
118 unsigned int len = 0;
119 if (SystemGetParameter(CUST_OPKEY0, NULL, &len) == 0 && len > 0) {
120 opKeyName = CUST_OPKEY0;
121 } else if (SystemGetParameter(CUST_OPKEY1, NULL, &len) == 0 && len > 0) {
122 opKeyName = CUST_OPKEY1;
123 }
124 }
125 char *opKeyValue = CustGetSystemParam(opKeyName);
126 if (opKeyValue == NULL) {
127 return NULL;
128 }
129 size_t bufSize = strlen(opKeyDir) + strlen(opKeyValue) + 1;
130 bufSize = Min(bufSize, MAX_PATH_LEN);
131 result = (char *)calloc(bufSize, sizeof(char));
132 if (result != NULL && sprintf_s(result, bufSize, "%s%s", opKeyDir, opKeyValue) > 0) {
133 FreeIf(opKeyValue);
134 return result;
135 }
136 FreeIf(opKeyValue);
137 FreeIf(result);
138 return NULL;
139 }
140 #endif // __LITEOS__
141
SplitStr(char * str,char delim)142 static SplitedStr *SplitStr(char *str, char delim)
143 {
144 int segCount = 1;
145 for (char *p = str; *p != '\0'; p++) {
146 (*p == delim) ? segCount++ : 0;
147 }
148 SplitedStr *result = (SplitedStr *)calloc(sizeof(SplitedStr) + sizeof(char *) * segCount, 1);
149 if (result == NULL) {
150 return NULL;
151 }
152 result->segCount = segCount;
153 result->orgStr = str;
154
155 char *nextDelim = NULL;
156 char delimStr[] = {delim, 0};
157 result->segs[0] = strtok_s(str, delimStr, &nextDelim);
158 for (int index = 1; index < segCount; index++) {
159 result->segs[index] = strtok_s(NULL, delimStr, &nextDelim);
160 }
161 return result;
162 }
163
FreeSplitedStr(SplitedStr * p)164 static void FreeSplitedStr(SplitedStr *p)
165 {
166 if (p != NULL) {
167 FreeIf(p->orgStr);
168 p->orgStr = NULL;
169 free(p);
170 }
171 }
172
173 #ifndef __LITEOS__
174 // get follow x rule from param variant
175 // *mode: read from contains param variant, mode is output param.
176 // return: extra path rule.
177 // followPath format ":relPath,mode[,extra][:]"
178 // example: ":etc/xml/config.xml,10:etc/xml/config1.xml,100,etc/carrier/${key:-value}"
GetFollowXRule(const char * relPath,int * mode)179 static char *GetFollowXRule(const char *relPath, int *mode)
180 {
181 char *followRule = CustGetSystemParam(CUST_FOLLOW_X_RULES);
182 if (followRule == NULL) {
183 return NULL;
184 }
185
186 size_t bufSize = strlen(relPath) + sizeof(":,") + 1;
187 bufSize = Min(bufSize, MAX_PATH_LEN);
188 char *search = (char *)calloc(bufSize, sizeof(char));
189 if (search == NULL || sprintf_s(search, bufSize, ":%s,", relPath) == -1) {
190 FreeIf(search);
191 FreeIf(followRule);
192 return NULL;
193 }
194
195 char *addPath = NULL;
196 char *item = strstr(followRule, search);
197 if (item) {
198 item++; // skip delim ':', goto ":relPath,mode[,extra][:]"
199 char *endItem = strchr(item, SEP_FOR_X_RULE);
200 char *nextItem = endItem + 1;
201 while (endItem && nextItem && *nextItem == '-') {
202 endItem = strchr(nextItem, SEP_FOR_X_RULE);
203 nextItem = endItem + 1;
204 }
205 if (endItem) {
206 *endItem = '\0';
207 }
208 char *modeStr = strchr(item, SEP_FOR_X_PARAM);
209 if (modeStr) {
210 modeStr++;
211 *mode = atoi(modeStr);
212 }
213 if (*mode == FOLLOWX_MODE_USER_DEFINE && modeStr) {
214 addPath = strchr(modeStr, SEP_FOR_X_PARAM);
215 if (addPath) {
216 addPath++; // skip ',' get extra info
217 }
218 }
219 }
220
221 char *result = (addPath && *addPath) ? strdup(addPath) : NULL;
222 FreeIf(followRule);
223 FreeIf(search);
224 return result;
225 }
226
GetFollowXPathByMode(const char * relPath,int followMode,const char * extra)227 static SplitedStr *GetFollowXPathByMode(const char *relPath, int followMode, const char *extra)
228 {
229 char *followXPath = NULL;
230 char *modePathFromCfg = NULL;
231 const char *extraPath = extra;
232 if (followMode == FOLLOWX_MODE_DEFAULT) {
233 modePathFromCfg = GetFollowXRule(relPath, &followMode);
234 if (followMode == FOLLOWX_MODE_USER_DEFINE && modePathFromCfg && *modePathFromCfg) {
235 extraPath = modePathFromCfg;
236 }
237 }
238
239 switch (followMode) {
240 case FOLLOWX_MODE_SIM_DEFAULT:
241 followXPath = GetOpkeyPath(FOLLOWX_MODE_SIM_DEFAULT);
242 break;
243 case FOLLOWX_MODE_SIM_1:
244 followXPath = GetOpkeyPath(FOLLOWX_MODE_SIM_1);
245 break;
246 case FOLLOWX_MODE_SIM_2:
247 followXPath = GetOpkeyPath(FOLLOWX_MODE_SIM_2);
248 break;
249 case FOLLOWX_MODE_USER_DEFINE:
250 followXPath = (extraPath && *extraPath) ? strdup(extraPath) : NULL;
251 break;
252 default:
253 break;
254 }
255 char *expandVal = (followXPath && *followXPath) ? ExpandStr(followXPath, "-x-", CustGetSystemParam) : NULL;
256 FreeIf(followXPath);
257 FreeIf(modePathFromCfg);
258 SplitedStr *result = expandVal ? SplitStr(expandVal, ',') : NULL;
259 return result;
260 }
261 #else
GetFollowXPathByMode(const char * relPath,int followMode,const char * extra)262 static SplitedStr *GetFollowXPathByMode(const char *relPath, int followMode, const char *extra)
263 {
264 return NULL;
265 }
266 #endif
267
TrimInplace(char * str,bool moveToStart)268 static char *TrimInplace(char *str, bool moveToStart)
269 {
270 char *src = str;
271 while (isspace(*src)) {
272 src++;
273 }
274 for (int i = strlen(src) - 1; i >= 0 && isspace(src[i]); i--) {
275 src[i] = '\0';
276 }
277
278 char *res = moveToStart ? str : src;
279 if (moveToStart && src != str) {
280 size_t len = strlen(src) + 1;
281 if (memmove_s(str, len, src, len) != EOK) {
282 return NULL;
283 }
284 }
285 return (*res != '\0') ? res : NULL;
286 }
287
EnsureHolderSpace(StringHolder * holder,size_t leastSize)288 static bool EnsureHolderSpace(StringHolder *holder, size_t leastSize)
289 {
290 if (holder->size < leastSize) {
291 size_t allocSize = Max(leastSize * 2, MIN_APPEND_LEN);
292 char *newPtr = (char *)calloc(allocSize, sizeof(char));
293 if (newPtr == NULL) {
294 allocSize = leastSize;
295 newPtr = (char *)calloc(allocSize, sizeof(char));
296 if (newPtr == NULL) {
297 return false;
298 }
299 }
300 if (holder->p != NULL && memcpy_s(newPtr, allocSize, holder->p, holder->strLen) != EOK) {
301 FreeIf(newPtr);
302 return false;
303 }
304 FreeIf(holder->p);
305 holder->p = newPtr;
306 holder->size = allocSize;
307 }
308 return true;
309 }
310
AppendStr(StringHolder * holder,const char * s)311 static bool AppendStr(StringHolder *holder, const char *s)
312 {
313 size_t leastSize = holder->strLen + strlen(s) + 1;
314 if (!EnsureHolderSpace(holder, leastSize)) {
315 return false;
316 }
317 if (strcat_s(holder->p, holder->size, s) != EOK) {
318 return false;
319 }
320 holder->strLen = leastSize - 1;
321 return true;
322 }
323
ExpandStr(char * src,const char * def,QueryFunc queryFunc)324 static char *ExpandStr(char *src, const char *def, QueryFunc queryFunc)
325 {
326 bool ok = true;
327 StringHolder sh = { 0 };
328 char *copyCur = NULL;
329 char *searchCur = NULL;
330 char *end = src + strlen(src);
331 for (copyCur = searchCur = src; ok && searchCur < end;) {
332 char *varStart = NULL;
333 char *varEnd = NULL;
334 char *find = strchr(searchCur, '$');
335 if (!find) {
336 ok = ok && AppendStr(&sh, copyCur);
337 break;
338 } else if ((varStart = strchr(find, '{')) && (varStart == find + 1) && (varEnd = strchr(find, '}')) &&
339 varEnd - varStart > 0) { // Get user defined name
340 *find = *varEnd = 0;
341 ok = ok && AppendStr(&sh, copyCur);
342 char *name = find + 2;
343 char *defVal = strstr(name, SEP_FOR_X_VALUE);
344 if (defVal) {
345 *defVal = 0; // cut for name end
346 defVal = TrimInplace(defVal + strlen(SEP_FOR_X_VALUE), false); // skip ":-", get value
347 }
348 char *value = queryFunc(name);
349 if (value || defVal || def) {
350 ok = ok && AppendStr(&sh, value ? value : (defVal ? defVal : def));
351 FreeIf(value);
352 } else {
353 errno = EINVAL;
354 ok = false;
355 break;
356 }
357 copyCur = searchCur = varEnd + 1;
358 } else {
359 searchCur = find + 1;
360 }
361 }
362 if (!ok) {
363 FreeIf(sh.p);
364 sh.p = NULL;
365 }
366 return sh.p;
367 }
368
GetCfgDirRealPolicyValue(CfgDir * res)369 static void GetCfgDirRealPolicyValue(CfgDir *res)
370 {
371 if (res == NULL) {
372 return;
373 }
374 #ifdef __LITEOS_M__
375 if (gConfigPolicy[0] == '\0') {
376 TrigSetMiniConfigPolicy();
377 }
378 if (gConfigPolicy[0] != '\0') {
379 res->realPolicyValue = strdup(gConfigPolicy);
380 }
381 #elif defined(__LITEOS__)
382 // use default, now do nothing
383 #else
384 res->realPolicyValue = CustGetSystemParam(CUST_KEY_POLICY_LAYER);
385 #endif
386 if (res->realPolicyValue != NULL && res->realPolicyValue[0]) {
387 return;
388 }
389 res->realPolicyValue = strdup(DEFAULT_LAYER);
390 }
391
FreeCfgFiles(CfgFiles * res)392 void FreeCfgFiles(CfgFiles *res)
393 {
394 if (res == NULL) {
395 return;
396 }
397 for (size_t i = 0; i < MAX_CFG_POLICY_DIRS_CNT; i++) {
398 if (res->paths[i] != NULL) {
399 free(res->paths[i]);
400 res->paths[i] = NULL;
401 }
402 }
403 free(res);
404 }
405
FreeCfgDirList(CfgDir * res)406 void FreeCfgDirList(CfgDir *res)
407 {
408 if (res == NULL) {
409 return;
410 }
411 if (res->realPolicyValue != NULL) {
412 free(res->realPolicyValue);
413 res->realPolicyValue = NULL;
414 }
415 free(res);
416 }
417
GetOneCfgFileEx(const char * pathSuffix,char * buf,unsigned int bufLength,int followMode,const char * extra)418 char *GetOneCfgFileEx(const char *pathSuffix, char *buf, unsigned int bufLength, int followMode, const char *extra)
419 {
420 if (pathSuffix == NULL || buf == NULL || bufLength < MAX_PATH_LEN) {
421 return NULL;
422 }
423 *buf = '\0';
424 CfgDir *dirs = GetCfgDirList();
425 if (dirs == NULL) {
426 return NULL;
427 }
428
429 SplitedStr *result = GetFollowXPathByMode(pathSuffix, followMode, extra);
430 for (size_t i = MAX_CFG_POLICY_DIRS_CNT; i > 0; i--) {
431 if (dirs->paths[i - 1] == NULL) {
432 continue;
433 }
434 // check follow x
435 for (int j = (result ? result->segCount : 0); j > 0; j--) {
436 if (result->segs[j - 1] &&
437 snprintf_s(buf, bufLength, bufLength - 1, "%s/%s/%s", dirs->paths[i - 1], result->segs[j - 1],
438 pathSuffix) > 0 &&
439 access(buf, F_OK) == 0) {
440 break;
441 }
442 *buf = '\0';
443 }
444 if (*buf != '\0') {
445 break;
446 }
447 if (snprintf_s(buf, bufLength, bufLength - 1, "%s/%s", dirs->paths[i - 1], pathSuffix) > 0 &&
448 access(buf, F_OK) == 0) {
449 break;
450 }
451 *buf = '\0';
452 }
453 FreeCfgDirList(dirs);
454 FreeSplitedStr(result);
455 return (*buf != '\0') ? buf : NULL;
456 }
457
GetOneCfgFile(const char * pathSuffix,char * buf,unsigned int bufLength)458 char *GetOneCfgFile(const char *pathSuffix, char *buf, unsigned int bufLength)
459 {
460 return GetOneCfgFileEx(pathSuffix, buf, bufLength, FOLLOWX_MODE_DEFAULT, NULL);
461 }
462
GetCfgFilesEx(const char * pathSuffix,int followMode,const char * extra)463 CfgFiles *GetCfgFilesEx(const char *pathSuffix, int followMode, const char *extra)
464 {
465 if (pathSuffix == NULL) {
466 return NULL;
467 }
468 char buf[MAX_PATH_LEN] = {0};
469 CfgDir *dirs = GetCfgDirList();
470 if (dirs == NULL) {
471 return NULL;
472 }
473 CfgFiles *files = (CfgFiles *)(malloc(sizeof(CfgFiles)));
474 if (files == NULL) {
475 FreeCfgDirList(dirs);
476 return NULL;
477 }
478
479 SplitedStr *result = GetFollowXPathByMode(pathSuffix, followMode, extra);
480 (void)memset_s(files, sizeof(CfgFiles), 0, sizeof(CfgFiles));
481 int index = 0;
482 for (size_t i = 0; i < MAX_CFG_POLICY_DIRS_CNT && index < MAX_CFG_POLICY_DIRS_CNT; i++) {
483 if (dirs->paths[i] == NULL) {
484 continue;
485 }
486 if (snprintf_s(buf, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s/%s", dirs->paths[i], pathSuffix) > 0 &&
487 access(buf, F_OK) == 0) {
488 files->paths[index++] = strdup(buf);
489 }
490 for (int j = 0; result && j < result->segCount; j++) {
491 if (result->segs[j] &&
492 snprintf_s(buf, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s/%s/%s", dirs->paths[i], result->segs[j],
493 pathSuffix) > 0 &&
494 access(buf, F_OK) == 0) {
495 files->paths[index++] = strdup(buf);
496 }
497 }
498 }
499 FreeCfgDirList(dirs);
500 FreeSplitedStr(result);
501 return files;
502 }
503
GetCfgFiles(const char * pathSuffix)504 CfgFiles *GetCfgFiles(const char *pathSuffix)
505 {
506 return GetCfgFilesEx(pathSuffix, FOLLOWX_MODE_DEFAULT, NULL);
507 }
508
GetCfgDirList()509 CfgDir *GetCfgDirList()
510 {
511 CfgDir *res = (CfgDir *)(malloc(sizeof(CfgDir)));
512 if (res == NULL) {
513 return NULL;
514 }
515 (void)memset_s(res, sizeof(CfgDir), 0, sizeof(CfgDir));
516 GetCfgDirRealPolicyValue(res);
517 char *next = res->realPolicyValue;
518 if (next == NULL) {
519 free(res);
520 return NULL;
521 }
522 for (size_t i = 0; i < MAX_CFG_POLICY_DIRS_CNT; i++) {
523 res->paths[i] = next;
524 next = strchr(next, ':');
525 if (next == NULL) {
526 break;
527 }
528 *next = 0;
529 next += 1;
530 }
531 return res;
532 }
533