• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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