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