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