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