1 /**
2 * Copyright(c) 2011 Trusted Logic. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name Trusted Logic nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <stdlib.h>
32 #include <assert.h>
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <string.h>
36
37 #if defined(_WIN32_WCE)
38 #include "os_wm.h"
39 #else
40 #include <errno.h>
41 #endif
42
43 #include "smc_properties_parser.h"
44 #include "lib_manifest2.h"
45 #include "lib_uuid.h"
46 #include "s_error.h"
47
48 /* ---------------------------------------------------------------------------------
49 Defines
50 ---------------------------------------------------------------------------------*/
51
52 #define STRUE "true"
53 #define SFALSE "false"
54
55 #if defined(_WIN32_WCE)
56 #define GET_LAST_ERR GetLastError()
57 #else
58 #define GET_LAST_ERR errno
59 #endif
60
61 #if defined (LINUX) || defined (__SYMBIAN32__) || defined (ANDROID)
62 #define STRICMP strcasecmp
63 #elif defined(_WIN32_WCE)
64 #define STRICMP _stricmp
65 #else
66 #define STRICMP stricmp
67 #endif
68
69
70 /* ---------------------------------------------------------------------------------
71 Logs and Traces.
72 ---------------------------------------------------------------------------------*/
73 #ifdef __SYMBIAN32__
74 #include "os_symbian.h"
75 #elif NDEBUG
76 /* Compile-out the traces */
77 #define TRACE_ERROR(...)
78 #define TRACE_WARNING(...)
79 #define TRACE_INFO(...)
80 #else
81 #include <stdarg.h>
TRACE_ERROR(const char * format,...)82 static void TRACE_ERROR(const char* format, ...)
83 {
84 va_list ap;
85 va_start(ap, format);
86 fprintf(stderr, "TRACE: ERROR: ");
87 vfprintf(stderr, format, ap);
88 fprintf(stderr, "\n");
89 va_end(ap);
90 }
91
TRACE_WARNING(const char * format,...)92 static void TRACE_WARNING(const char* format, ...)
93 {
94 va_list ap;
95 va_start(ap, format);
96 fprintf(stderr, "TRACE: WARNING: ");
97 vfprintf(stderr, format, ap);
98 fprintf(stderr, "\n");
99 va_end(ap);
100 }
101
TRACE_INFO(const char * format,...)102 static void TRACE_INFO(const char* format, ...)
103 {
104 va_list ap;
105 va_start(ap, format);
106 fprintf(stderr, "TRACE: ");
107 vfprintf(stderr, format, ap);
108 fprintf(stderr, "\n");
109 va_end(ap);
110 }
111 #endif /* NDEBUG */
112
113 /* ---------------------------------------------------------------------------------
114 private functions.
115 ---------------------------------------------------------------------------------*/
116
static_listFindNodeElement(NODE * pList,char * pName,bool bIsCaseSensitive)117 static NODE* static_listFindNodeElement(NODE* pList,char* pName,bool bIsCaseSensitive)
118 {
119 int32_t nCmp;
120
121 assert(pName!=NULL);
122
123 while (pList!=NULL)
124 {
125 if (bIsCaseSensitive)
126 {
127 nCmp=strcmp(pName,pList->pName);
128 }
129 else
130 {
131 nCmp=STRICMP(pName,pList->pName);
132 }
133 if (nCmp>0)
134 {
135 pList=pList->pRight;
136 }
137 else if (nCmp<0)
138 {
139 pList=pList->pLeft;
140 }
141 else
142 {
143 break;
144 }
145 }
146 return pList;
147 }
148
149
static_listSortedAddNode(NODE * pList,NODE * pNode)150 static S_RESULT static_listSortedAddNode(NODE* pList,NODE* pNode)
151 {
152 int32_t nCmp;
153
154 do {
155 nCmp=strcmp(pNode->pName,pList->pName);
156 if (nCmp>0)
157 {
158 if (pList->pRight!=NULL)
159 {
160 pList=pList->pRight;
161 }
162 else
163 {
164 pList->pRight=pNode;
165 /* update linked list */
166 pNode->pPrevious=pList;
167 pNode->pNext=pList->pNext;
168 if (pList->pNext!=NULL)
169 {
170 pList->pNext->pPrevious=pNode;
171 }
172 pList->pNext=pNode;
173 return S_SUCCESS;
174 }
175 }
176 else if (nCmp<0)
177 {
178 if (pList->pLeft!=NULL)
179 {
180 pList=pList->pLeft;
181 }
182 else
183 {
184 pList->pLeft=pNode;
185 /* update linked list */
186 pNode->pNext=pList;
187 pNode->pPrevious=pList->pPrevious;
188 if (pList->pPrevious!=NULL)
189 {
190 pList->pPrevious->pNext=pNode;
191 }
192 pList->pPrevious=pNode;
193 return S_SUCCESS;
194 }
195 }
196 } while (nCmp!=0);
197
198 TRACE_ERROR("%s already exist !\n",pNode->pName);
199 return S_ERROR_ITEM_EXISTS;
200 }
201
202
SMCPropListSortedAdd(LIST * pList,NODE * pNode)203 static S_RESULT SMCPropListSortedAdd(LIST* pList,NODE* pNode)
204 {
205 S_RESULT nResult;
206
207 assert(pList!=NULL && pNode!=NULL);
208
209 if (pNode->pName==NULL)
210 {
211 TRACE_ERROR("Trying to insert a NULL node name !\n");
212 return S_ERROR_BAD_PARAMETERS;
213 }
214
215 if (pList->pRoot==NULL)
216 {
217 pList->pRoot=pNode;
218 pList->pFirst=pNode;
219 return S_SUCCESS;
220 }
221 else
222 {
223 nResult=static_listSortedAddNode(pList->pRoot,pNode);
224 /* update the first node of the linked list */
225 if (nResult==S_SUCCESS && pNode->pPrevious==NULL)
226 {
227 pList->pFirst=pNode;
228 }
229 }
230 return nResult;
231 }
232
233
SMCPropListFindElement(LIST * pList,char * pName,bool bIsCaseSensitive)234 static NODE* SMCPropListFindElement(LIST* pList,char* pName,bool bIsCaseSensitive)
235 {
236 if (pList->pRoot!=NULL)
237 {
238 return static_listFindNodeElement(pList->pRoot,pName,bIsCaseSensitive);
239 }
240 return NULL;
241 }
242
243
SMCPropYacc(uint8_t * pBuffer,uint32_t nBufferLength,CONF_FILE * pConfFile,SERVICE_SECTION * pService)244 static S_RESULT SMCPropYacc(uint8_t* pBuffer, uint32_t nBufferLength,
245 CONF_FILE* pConfFile, SERVICE_SECTION* pService)
246 {
247 S_RESULT nError=S_SUCCESS;
248 LIST *pPublicPropertyList=NULL;
249 LIST *pPrivatePropertyList=NULL;
250 PROPERTY* pProperty=NULL;
251 SERVICE_SECTION* pServSection;
252 SERVICE_SECTION* pPreviousService=NULL;
253
254 uint8_t* pName;
255 uint32_t nNameLength;
256 uint8_t* pValue;
257 uint32_t nValueLength;
258 char* pNameZ = NULL;
259 char* pValueZ = NULL;
260 LIB_MANIFEST2_CONTEXT sParserContext;
261 char serviceManifestName[1024];
262
263 sParserContext.pManifestName = "Configuration File";
264 sParserContext.pManifestContent = pBuffer;
265 sParserContext.nManifestLength = nBufferLength;
266 sParserContext.nType = LIB_MANIFEST2_TYPE_SOURCE_WITH_SECTIONS;
267
268 if (pService!=NULL)
269 {
270 pPublicPropertyList=&pService->sPublicPropertyList;
271 pPrivatePropertyList=&pService->sPrivatePropertyList;
272 /* read inside a service compiled manifest */
273 sParserContext.nType = LIB_MANIFEST2_TYPE_COMPILED;
274 sprintf(serviceManifestName, "%s(manifest)", pService->sNode.pName);
275 sParserContext.pManifestName = serviceManifestName;
276 }
277 libManifest2InitContext(&sParserContext);
278
279 while (true)
280 {
281 nError = libManifest2GetNextItem(
282 &sParserContext,
283 &pName,
284 &nNameLength,
285 &pValue,
286 &nValueLength);
287 if (nError == S_ERROR_ITEM_NOT_FOUND)
288 {
289 /* End of parsing */
290 nError = S_SUCCESS;
291 break;
292 }
293 else if (nError != S_SUCCESS)
294 {
295 /* Error */
296 goto error;
297 }
298
299 /* Duplicate name and value in as zero-terminated strings */
300 /* Unclean: those strings are not going to be deallocated
301 This is not a problem because this code is run in a tool
302 */
303 pNameZ = malloc(nNameLength+1);
304 if (pNameZ == NULL)
305 {
306 nError = S_ERROR_OUT_OF_MEMORY;
307 goto error;
308 }
309 memcpy(pNameZ, pName, nNameLength);
310 pNameZ[nNameLength] = 0;
311
312 if (pValue == NULL)
313 {
314 /* It's a section */
315 if (STRICMP(pNameZ, SYSTEM_SECTION_NAME) == 0)
316 {
317 free(pNameZ);
318 pPublicPropertyList=&pConfFile->sSystemSectionPropertyList;
319 }
320 else
321 {
322 pServSection=(SERVICE_SECTION*)SMCPropListFindElement(
323 &pConfFile->sDriverSectionList,
324 pNameZ,
325 false);
326 if (pServSection==NULL)
327 {
328 pServSection=(SERVICE_SECTION*)SMCPropListFindElement(
329 &pConfFile->sPreinstalledSectionList,
330 pNameZ,
331 false);
332 }
333 if (pServSection==NULL)
334 {
335 pServSection=(SERVICE_SECTION*)SMCPropListFindElement(
336 &pConfFile->sSectionList,
337 pNameZ,
338 false);
339 if (pServSection==NULL)
340 {
341 nError=S_ERROR_ITEM_NOT_FOUND;
342 goto error;
343 }
344 }
345 free(pNameZ);
346
347 pServSection->inSCF=true;
348 if (pPreviousService!=NULL)
349 {
350 pPreviousService->pNextInSCF=pServSection;
351 }
352 else
353 {
354 pConfFile->pFirstSectionInSCF=pServSection;
355 }
356 pPreviousService=pServSection;
357
358 pPublicPropertyList=&pServSection->sPublicPropertyList;
359 pPrivatePropertyList=&pServSection->sPrivatePropertyList;
360 }
361 }
362 else
363 {
364 /* It's a property definition */
365 pValueZ = malloc(nValueLength+1);
366 if (pValueZ == NULL)
367 {
368 nError = S_ERROR_OUT_OF_MEMORY;
369 goto error;
370 }
371 memcpy(pValueZ, pValue, nValueLength);
372 pValueZ[nValueLength] = 0;
373
374 pProperty=(PROPERTY*)malloc(sizeof(PROPERTY));
375 if (pProperty==NULL)
376 {
377 nError=S_ERROR_OUT_OF_MEMORY;
378 goto error;
379 }
380 memset(pProperty, 0x00, sizeof(PROPERTY));
381 pProperty->sNode.pName=pNameZ;
382
383 pProperty->pValue=pValueZ;
384
385 if (pPrivatePropertyList==NULL)
386 {
387 nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty);
388 if (nError!=S_SUCCESS)
389 {
390 goto error;
391 }
392 }
393 else
394 {
395 if (strcmp(pProperty->sNode.pName,CONFIG_SERVICE_ID_PROPERTY_NAME) == 0)
396 {
397 if (pService!=NULL)
398 {
399 pService->sNode.pName=malloc(nValueLength+1);
400 if (pService->sNode.pName==NULL)
401 {
402 nError=S_ERROR_OUT_OF_MEMORY;
403 goto error;
404 }
405 #if defined (LINUX) || defined (__SYMBIAN32__) || defined(ANDROID)
406 {
407 // put each char of the value in uppercase
408 char* p=pProperty->pValue;
409 while(*p)
410 {
411 *p=toupper(*p);
412 p++;
413 }
414 }
415 #else
416 _strupr(pProperty->pValue);
417 #endif
418 memcpy(pService->sNode.pName,pProperty->pValue,nValueLength+1);
419
420 if (!libUUIDFromString((const uint8_t*)pProperty->pValue,&pService->sUUID))
421 {
422 nError=S_ERROR_WRONG_SIGNATURE;
423 goto error;
424 }
425 {
426 S_UUID sNullUUID;
427 memset(&sNullUUID,0,sizeof(S_UUID));
428 if (!memcmp(&pService->sUUID,&sNullUUID,sizeof(S_UUID)))
429 {
430 nError=S_ERROR_WRONG_SIGNATURE;
431 goto error;
432 }
433 }
434 }
435 }
436 if ((nValueLength > strlen(CONFIG_PROPERTY_NAME)) &&
437 (memcmp(pProperty->sNode.pName, CONFIG_PROPERTY_NAME, strlen(CONFIG_PROPERTY_NAME)) == 0))
438 {
439 nError=SMCPropListSortedAdd(pPrivatePropertyList,(NODE*)pProperty);
440 }
441 else
442 {
443 nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty);
444 }
445 if (nError!=S_SUCCESS)
446 {
447 goto error;
448 }
449 }
450 }
451 }
452
453 error:
454 if (nError!=S_SUCCESS)
455 {
456 switch (nError)
457 {
458 case S_ERROR_BAD_FORMAT:
459 /* Error message already output */
460 break;
461 case S_ERROR_WRONG_SIGNATURE:
462 TRACE_ERROR("Configuration file: wrong service UUID: %s\n", pValueZ);
463 break;
464 case S_ERROR_OUT_OF_MEMORY:
465 TRACE_ERROR("Out of memory\n");
466 break;
467 case S_ERROR_ITEM_NOT_FOUND:
468 TRACE_ERROR("Configuration file: service \"%s\" not found\n", pNameZ);
469 break;
470 }
471 }
472 return nError;
473 }
474
475
static_readFile(const char * pFilename,void ** ppFile,uint32_t * pnFileLength)476 S_RESULT static_readFile(const char* pFilename, void** ppFile, uint32_t* pnFileLength)
477 {
478 S_RESULT nResult = S_SUCCESS;
479 long nFilesize;
480 FILE* pFile = NULL;
481 void *pBuff = NULL;
482
483 // open file and get its size...
484 if ((pFile = fopen(pFilename, "rb")) == NULL)
485 {
486 TRACE_ERROR("static_readFile: fopen(%s) failed [%d]", pFilename, GET_LAST_ERR);
487 nResult = S_ERROR_ITEM_NOT_FOUND;
488 return nResult;
489 }
490 if (fseek(pFile, 0, SEEK_END) != 0)
491 {
492 TRACE_ERROR("static_readFile: fseek(%s) failed [%d]", pFilename, GET_LAST_ERR);
493 nResult = S_ERROR_UNDERLYING_OS;
494 goto error;
495 }
496 nFilesize = ftell(pFile);
497 if (nFilesize < 0)
498 {
499 TRACE_ERROR("static_readFile: ftell(%s) failed [%d]", pFilename, GET_LAST_ERR);
500 nResult = S_ERROR_UNDERLYING_OS;
501 goto error;
502 }
503 rewind(pFile);
504
505 // allocate the buffer
506 pBuff = malloc(nFilesize + 1);
507 if (pBuff == NULL)
508 {
509 TRACE_ERROR("static_readFile: out of memory");
510 nResult = S_ERROR_OUT_OF_MEMORY;
511 goto error;
512 }
513
514 // read the file
515 if (fread(pBuff, sizeof(uint8_t), (size_t)nFilesize, pFile) != (size_t)nFilesize)
516 {
517 TRACE_ERROR("static_readFile: fread failed [%d]", GET_LAST_ERR);
518 nResult = S_ERROR_UNDERLYING_OS;
519 goto error;
520 }
521 ((char*)pBuff)[nFilesize] = 0;
522
523 *ppFile = pBuff;
524 *pnFileLength = nFilesize;
525 return S_SUCCESS;
526
527 error:
528 if (pBuff != NULL)
529 free(pBuff);
530 fclose(pFile);
531
532 *ppFile = NULL;
533 *pnFileLength = 0;
534 return nResult;
535 }
536
537
538
539
540
541 /* ---------------------------------------------------------------------------------
542 API functions.
543 ---------------------------------------------------------------------------------*/
544
SMCPropGetSystemProperty(CONF_FILE * pConfFile,char * pPropertyName)545 char* SMCPropGetSystemProperty(CONF_FILE* pConfFile, char* pPropertyName)
546 {
547 PROPERTY* pProperty;
548
549 pProperty=(PROPERTY*)SMCPropListFindElement(
550 &pConfFile->sSystemSectionPropertyList,
551 pPropertyName,
552 true);
553 if (pProperty!=NULL)
554 {
555 return pProperty->pValue;
556 }
557 return NULL;
558 }
559
SMCPropGetSystemPropertyAsInt(CONF_FILE * pConfFile,char * pPropertyName)560 uint32_t SMCPropGetSystemPropertyAsInt(CONF_FILE* pConfFile, char* pPropertyName)
561 {
562 uint32_t nValue;
563 char* pValue=SMCPropGetSystemProperty(pConfFile,pPropertyName);
564
565 if (libString2GetStringAsInt(pValue, &nValue) == S_SUCCESS)
566 {
567 return nValue;
568 }
569 return 0;
570 }
571
572
SMCPropParseConfigFile(char * pConfigFilename,CONF_FILE * pConfFile)573 S_RESULT SMCPropParseConfigFile(char* pConfigFilename,CONF_FILE* pConfFile)
574 {
575 S_RESULT nError=S_SUCCESS;
576 void* pFile;
577 uint32_t nFileLength;
578 bool bReuseManifest;
579
580 assert(pConfFile!=NULL);
581
582 TRACE_INFO("Processing configuration file '%s'", pConfigFilename);
583
584 if(pConfigFilename != NULL)
585 {
586 nError=static_readFile(pConfigFilename,&pFile,&nFileLength);
587 if (nError!=S_SUCCESS)
588 {
589 goto error;
590 }
591 bReuseManifest = true;
592 }
593 else
594 {
595 assert(0);
596 }
597
598 nError=SMCPropYacc(pFile,nFileLength,pConfFile,NULL);
599
600 if(pConfigFilename != NULL)
601 {
602 free(pFile);
603 }
604
605 error:
606 return nError;
607 }
608