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