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 "s_error.h"
46
47/* ---------------------------------------------------------------------------------
48   Defines
49   ---------------------------------------------------------------------------------*/
50
51#define STRUE                             "true"
52#define SFALSE                            "false"
53
54#if defined(_WIN32_WCE)
55#define GET_LAST_ERR GetLastError()
56#else
57#define GET_LAST_ERR  errno
58#endif
59
60#if defined (LINUX) || defined (__SYMBIAN32__) || defined (__ANDROID32__)
61#define STRICMP strcasecmp
62#elif defined(_WIN32_WCE)
63#define STRICMP _stricmp
64#else
65#define STRICMP stricmp
66#endif
67
68
69/* ---------------------------------------------------------------------------------
70   Logs and Traces.
71   ---------------------------------------------------------------------------------*/
72#ifdef __SYMBIAN32__
73#include "os_symbian.h"
74#elif NDEBUG
75/* Compile-out the traces */
76#define TRACE_ERROR(...)
77#define TRACE_WARNING(...)
78#define TRACE_INFO(...)
79#else
80#include <stdarg.h>
81static void TRACE_ERROR(const char* format, ...)
82{
83   va_list ap;
84   va_start(ap, format);
85   fprintf(stderr, "TRACE: ERROR: ");
86   vfprintf(stderr, format, ap);
87   fprintf(stderr, "\n");
88   va_end(ap);
89}
90
91static void TRACE_WARNING(const char* format, ...)
92{
93   va_list ap;
94   va_start(ap, format);
95   fprintf(stderr, "TRACE: WARNING: ");
96   vfprintf(stderr, format, ap);
97   fprintf(stderr, "\n");
98   va_end(ap);
99}
100
101static void TRACE_INFO(const char* format, ...)
102{
103   va_list ap;
104   va_start(ap, format);
105   fprintf(stderr, "TRACE: ");
106   vfprintf(stderr, format, ap);
107   fprintf(stderr, "\n");
108   va_end(ap);
109}
110#endif /* NDEBUG */
111
112/* ---------------------------------------------------------------------------------
113   private functions.
114   ---------------------------------------------------------------------------------*/
115
116static NODE* static_listFindNodeElement(NODE* pList,char* pName,bool bIsCaseSensitive)
117{
118   int32_t nCmp;
119
120   assert(pName!=NULL);
121
122   while (pList!=NULL)
123   {
124      if (bIsCaseSensitive)
125      {
126         nCmp=strcmp(pName,pList->pName);
127      }
128      else
129      {
130         nCmp=STRICMP(pName,pList->pName);
131      }
132      if (nCmp>0)
133      {
134         pList=pList->pRight;
135      }
136      else if (nCmp<0)
137      {
138         pList=pList->pLeft;
139      }
140      else
141      {
142         break;
143      }
144   }
145   return pList;
146}
147
148
149static S_RESULT static_listSortedAddNode(NODE* pList,NODE* pNode)
150{
151   int32_t nCmp;
152
153   do {
154      nCmp=strcmp(pNode->pName,pList->pName);
155      if (nCmp>0)
156      {
157         if (pList->pRight!=NULL)
158         {
159            pList=pList->pRight;
160         }
161         else
162         {
163            pList->pRight=pNode;
164            /* update linked list */
165            pNode->pPrevious=pList;
166            pNode->pNext=pList->pNext;
167            if (pList->pNext!=NULL)
168            {
169               pList->pNext->pPrevious=pNode;
170            }
171            pList->pNext=pNode;
172            return S_SUCCESS;
173         }
174      }
175      else if (nCmp<0)
176      {
177         if (pList->pLeft!=NULL)
178         {
179            pList=pList->pLeft;
180         }
181         else
182         {
183            pList->pLeft=pNode;
184            /* update linked list */
185            pNode->pNext=pList;
186            pNode->pPrevious=pList->pPrevious;
187            if (pList->pPrevious!=NULL)
188            {
189               pList->pPrevious->pNext=pNode;
190            }
191            pList->pPrevious=pNode;
192            return S_SUCCESS;
193         }
194      }
195   } while (nCmp!=0);
196
197   TRACE_ERROR("%s already exist !\n",pNode->pName);
198   return S_ERROR_ITEM_EXISTS;
199}
200
201
202static S_RESULT SMCPropListSortedAdd(LIST* pList,NODE* pNode)
203{
204   S_RESULT nResult;
205
206   assert(pList!=NULL && pNode!=NULL);
207
208   if (pNode->pName==NULL)
209   {
210	   TRACE_ERROR("Trying to insert a NULL node name !\n");
211      return S_ERROR_BAD_PARAMETERS;
212   }
213
214   if (pList->pRoot==NULL)
215   {
216      pList->pRoot=pNode;
217      pList->pFirst=pNode;
218      return S_SUCCESS;
219   }
220   else
221   {
222      nResult=static_listSortedAddNode(pList->pRoot,pNode);
223      /* update the first node of the linked list */
224      if (nResult==S_SUCCESS && pNode->pPrevious==NULL)
225      {
226         pList->pFirst=pNode;
227      }
228   }
229   return nResult;
230}
231
232
233static NODE* SMCPropListFindElement(LIST* pList,char* pName,bool bIsCaseSensitive)
234{
235   if (pList->pRoot!=NULL)
236   {
237      return static_listFindNodeElement(pList->pRoot,pName,bIsCaseSensitive);
238   }
239   return NULL;
240}
241
242
243static S_RESULT SMCPropYacc(uint8_t* pBuffer, uint32_t nBufferLength,
244                     CONF_FILE* pConfFile)
245{
246   S_RESULT nError=S_SUCCESS;
247   LIST *pPublicPropertyList=NULL;
248   LIST *pPrivatePropertyList=NULL;
249   PROPERTY* pProperty=NULL;
250   SERVICE_SECTION* pServSection;
251   SERVICE_SECTION* pPreviousService=NULL;
252
253   uint8_t* pName;
254   uint32_t nNameLength;
255   uint8_t* pValue;
256   uint32_t nValueLength;
257   char* pNameZ = NULL;
258   char* pValueZ = NULL;
259   LIB_MANIFEST2_CONTEXT sParserContext;
260   char serviceManifestName[1024];
261
262   sParserContext.pManifestName = "Configuration File";
263   sParserContext.pManifestContent = pBuffer;
264   sParserContext.nManifestLength = nBufferLength;
265   sParserContext.nType = LIB_MANIFEST2_TYPE_SOURCE_WITH_SECTIONS;
266
267   libManifest2InitContext(&sParserContext);
268
269   while (true)
270   {
271      nError = libManifest2GetNextItem(
272         &sParserContext,
273         &pName,
274         &nNameLength,
275         &pValue,
276         &nValueLength);
277      if (nError == S_ERROR_ITEM_NOT_FOUND)
278      {
279         /* End of parsing */
280         nError = S_SUCCESS;
281         break;
282      }
283      else if (nError != S_SUCCESS)
284      {
285         /* Error */
286         goto error;
287      }
288
289      /* Duplicate name and value in as zero-terminated strings */
290      /* Unclean: those strings are not going to be deallocated
291         This is not a problem because this code is run in a tool
292      */
293      pNameZ = malloc(nNameLength+1);
294      if (pNameZ == NULL)
295      {
296         nError = S_ERROR_OUT_OF_MEMORY;
297         goto error;
298      }
299      memcpy(pNameZ, pName, nNameLength);
300      pNameZ[nNameLength] = 0;
301
302      if (pValue == NULL)
303      {
304         /* It's a section */
305         if (STRICMP(pNameZ, SYSTEM_SECTION_NAME) == 0)
306         {
307            free(pNameZ);
308            pPublicPropertyList=&pConfFile->sSystemSectionPropertyList;
309         }
310         else
311         {
312            pServSection=(SERVICE_SECTION*)SMCPropListFindElement(
313               &pConfFile->sDriverSectionList,
314               pNameZ,
315               false);
316            if (pServSection==NULL)
317            {
318               pServSection=(SERVICE_SECTION*)SMCPropListFindElement(
319                     &pConfFile->sPreinstalledSectionList,
320                     pNameZ,
321                     false);
322            }
323            if (pServSection==NULL)
324            {
325               pServSection=(SERVICE_SECTION*)SMCPropListFindElement(
326                  &pConfFile->sSectionList,
327                  pNameZ,
328                  false);
329               if (pServSection==NULL)
330               {
331                  nError=S_ERROR_ITEM_NOT_FOUND;
332                  goto error;
333               }
334            }
335            free(pNameZ);
336
337            pServSection->inSCF=true;
338            if (pPreviousService!=NULL)
339            {
340               pPreviousService->pNextInSCF=pServSection;
341            }
342            else
343            {
344               pConfFile->pFirstSectionInSCF=pServSection;
345            }
346            pPreviousService=pServSection;
347
348            pPublicPropertyList=&pServSection->sPublicPropertyList;
349            pPrivatePropertyList=&pServSection->sPrivatePropertyList;
350         }
351      }
352      else
353      {
354         /* It's a property definition */
355         pValueZ = malloc(nValueLength+1);
356         if (pValueZ == NULL)
357         {
358            nError = S_ERROR_OUT_OF_MEMORY;
359            goto error;
360         }
361         memcpy(pValueZ, pValue, nValueLength);
362         pValueZ[nValueLength] = 0;
363
364         pProperty=(PROPERTY*)malloc(sizeof(PROPERTY));
365         if (pProperty==NULL)
366         {
367            nError=S_ERROR_OUT_OF_MEMORY;
368            goto error;
369         }
370         memset(pProperty, 0x00, sizeof(PROPERTY));
371         pProperty->sNode.pName=pNameZ;
372
373         pProperty->pValue=pValueZ;
374
375         if (pPrivatePropertyList==NULL)
376         {
377            nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty);
378            if (nError!=S_SUCCESS)
379            {
380               goto error;
381            }
382         }
383         else
384         {
385            if ((nValueLength > strlen(CONFIG_PROPERTY_NAME)) &&
386                (memcmp(pProperty->sNode.pName, CONFIG_PROPERTY_NAME, strlen(CONFIG_PROPERTY_NAME)) == 0))
387            {
388               nError=SMCPropListSortedAdd(pPrivatePropertyList,(NODE*)pProperty);
389            }
390            else
391            {
392               nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty);
393            }
394            if (nError!=S_SUCCESS)
395            {
396               goto error;
397            }
398         }
399      }
400   }
401
402error:
403   if (nError!=S_SUCCESS)
404   {
405      switch (nError)
406      {
407      case S_ERROR_BAD_FORMAT:
408         /* Error message already output */
409         break;
410      case S_ERROR_WRONG_SIGNATURE:
411         TRACE_ERROR("Configuration file: wrong service UUID: %s\n", pValueZ);
412         break;
413      case S_ERROR_OUT_OF_MEMORY:
414	  TRACE_ERROR("Out of memory\n");
415         break;
416      case S_ERROR_ITEM_NOT_FOUND:
417	  TRACE_ERROR("Configuration file: service \"%s\" not found\n", pNameZ);
418         break;
419      }
420   }
421   return nError;
422}
423
424
425S_RESULT static_readFile(const char* pFilename, void** ppFile, uint32_t* pnFileLength)
426{
427   S_RESULT nResult = S_SUCCESS;
428   long nFilesize;
429   FILE* pFile = NULL;
430   void *pBuff = NULL;
431
432   // open file and get its size...
433   if ((pFile = fopen(pFilename, "rb")) == NULL)
434   {
435      TRACE_ERROR("static_readFile: fopen(%s) failed [%d]", pFilename, GET_LAST_ERR);
436	   nResult = S_ERROR_ITEM_NOT_FOUND;
437	   return nResult;
438   }
439   if (fseek(pFile, 0, SEEK_END) != 0)
440   {
441      TRACE_ERROR("static_readFile: fseek(%s) failed [%d]", pFilename, GET_LAST_ERR);
442	   nResult = S_ERROR_UNDERLYING_OS;
443	   goto error;
444   }
445   nFilesize = ftell(pFile);
446   if (nFilesize < 0)
447   {
448      TRACE_ERROR("static_readFile: ftell(%s) failed [%d]", pFilename, GET_LAST_ERR);
449	   nResult = S_ERROR_UNDERLYING_OS;
450	   goto error;
451   }
452   rewind(pFile);
453
454   // allocate the buffer
455   pBuff = malloc(nFilesize + 1);
456   if (pBuff == NULL)
457   {
458      TRACE_ERROR("static_readFile: out of memory");
459      nResult = S_ERROR_OUT_OF_MEMORY;
460      goto error;
461   }
462
463   // read the file
464   if (fread(pBuff, sizeof(uint8_t), (size_t)nFilesize, pFile) != (size_t)nFilesize)
465   {
466      TRACE_ERROR("static_readFile: fread failed [%d]", GET_LAST_ERR);
467      nResult = S_ERROR_UNDERLYING_OS;
468      goto error;
469   }
470   ((char*)pBuff)[nFilesize] = 0;
471
472   *ppFile = pBuff;
473   *pnFileLength = nFilesize;
474   return S_SUCCESS;
475
476error:
477   if (pBuff != NULL)
478      free(pBuff);
479   fclose(pFile);
480
481   *ppFile = NULL;
482   *pnFileLength = 0;
483   return nResult;
484}
485
486
487
488
489
490/* ---------------------------------------------------------------------------------
491   API functions.
492   ---------------------------------------------------------------------------------*/
493
494char* SMCPropGetSystemProperty(CONF_FILE* pConfFile, char* pPropertyName)
495{
496   PROPERTY* pProperty;
497
498   pProperty=(PROPERTY*)SMCPropListFindElement(
499      &pConfFile->sSystemSectionPropertyList,
500      pPropertyName,
501      true);
502   if (pProperty!=NULL)
503   {
504      return pProperty->pValue;
505   }
506   return NULL;
507}
508
509uint32_t SMCPropGetSystemPropertyAsInt(CONF_FILE* pConfFile, char* pPropertyName)
510{
511   uint32_t nValue;
512   char* pValue=SMCPropGetSystemProperty(pConfFile,pPropertyName);
513
514   if (libString2GetStringAsInt(pValue, &nValue) == S_SUCCESS)
515   {
516      return nValue;
517   }
518   return 0;
519}
520
521
522S_RESULT SMCPropParseConfigFile(char* pConfigFilename,CONF_FILE* pConfFile)
523{
524   S_RESULT nError=S_SUCCESS;
525   void* pFile;
526   uint32_t nFileLength;
527   bool bReuseManifest;
528
529   assert(pConfFile!=NULL);
530
531   TRACE_INFO("Processing configuration file '%s'", pConfigFilename);
532
533   if(pConfigFilename != NULL)
534   {
535      nError=static_readFile(pConfigFilename,&pFile,&nFileLength);
536      if (nError!=S_SUCCESS)
537      {
538         goto error;
539      }
540      bReuseManifest = true;
541   }
542   else
543   {
544      assert(0);
545   }
546
547   nError=SMCPropYacc(pFile,nFileLength,pConfFile);
548
549   if(pConfigFilename != NULL)
550   {
551      free(pFile);
552   }
553
554error:
555   return nError;
556}
557