/** * Copyright(c) 2011 Trusted Logic. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Trusted Logic nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <stdlib.h> #include <assert.h> #include <stdio.h> #include <ctype.h> #include <string.h> #if defined(_WIN32_WCE) #include "os_wm.h" #else #include <errno.h> #endif #include "smc_properties_parser.h" #include "lib_manifest2.h" #include "lib_uuid.h" #include "s_error.h" /* --------------------------------------------------------------------------------- Defines ---------------------------------------------------------------------------------*/ #define STRUE "true" #define SFALSE "false" #if defined(_WIN32_WCE) #define GET_LAST_ERR GetLastError() #else #define GET_LAST_ERR errno #endif #if defined (LINUX) || defined (__SYMBIAN32__) || defined (ANDROID) #define STRICMP strcasecmp #elif defined(_WIN32_WCE) #define STRICMP _stricmp #else #define STRICMP stricmp #endif /* --------------------------------------------------------------------------------- Logs and Traces. ---------------------------------------------------------------------------------*/ #ifdef __SYMBIAN32__ #include "os_symbian.h" #elif NDEBUG /* Compile-out the traces */ #define TRACE_ERROR(...) #define TRACE_WARNING(...) #define TRACE_INFO(...) #else #include <stdarg.h> static void TRACE_ERROR(const char* format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "TRACE: ERROR: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } static void TRACE_WARNING(const char* format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "TRACE: WARNING: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } static void TRACE_INFO(const char* format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "TRACE: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } #endif /* NDEBUG */ /* --------------------------------------------------------------------------------- private functions. ---------------------------------------------------------------------------------*/ static NODE* static_listFindNodeElement(NODE* pList,char* pName,bool bIsCaseSensitive) { int32_t nCmp; assert(pName!=NULL); while (pList!=NULL) { if (bIsCaseSensitive) { nCmp=strcmp(pName,pList->pName); } else { nCmp=STRICMP(pName,pList->pName); } if (nCmp>0) { pList=pList->pRight; } else if (nCmp<0) { pList=pList->pLeft; } else { break; } } return pList; } static S_RESULT static_listSortedAddNode(NODE* pList,NODE* pNode) { int32_t nCmp; do { nCmp=strcmp(pNode->pName,pList->pName); if (nCmp>0) { if (pList->pRight!=NULL) { pList=pList->pRight; } else { pList->pRight=pNode; /* update linked list */ pNode->pPrevious=pList; pNode->pNext=pList->pNext; if (pList->pNext!=NULL) { pList->pNext->pPrevious=pNode; } pList->pNext=pNode; return S_SUCCESS; } } else if (nCmp<0) { if (pList->pLeft!=NULL) { pList=pList->pLeft; } else { pList->pLeft=pNode; /* update linked list */ pNode->pNext=pList; pNode->pPrevious=pList->pPrevious; if (pList->pPrevious!=NULL) { pList->pPrevious->pNext=pNode; } pList->pPrevious=pNode; return S_SUCCESS; } } } while (nCmp!=0); TRACE_ERROR("%s already exist !\n",pNode->pName); return S_ERROR_ITEM_EXISTS; } static S_RESULT SMCPropListSortedAdd(LIST* pList,NODE* pNode) { S_RESULT nResult; assert(pList!=NULL && pNode!=NULL); if (pNode->pName==NULL) { TRACE_ERROR("Trying to insert a NULL node name !\n"); return S_ERROR_BAD_PARAMETERS; } if (pList->pRoot==NULL) { pList->pRoot=pNode; pList->pFirst=pNode; return S_SUCCESS; } else { nResult=static_listSortedAddNode(pList->pRoot,pNode); /* update the first node of the linked list */ if (nResult==S_SUCCESS && pNode->pPrevious==NULL) { pList->pFirst=pNode; } } return nResult; } static NODE* SMCPropListFindElement(LIST* pList,char* pName,bool bIsCaseSensitive) { if (pList->pRoot!=NULL) { return static_listFindNodeElement(pList->pRoot,pName,bIsCaseSensitive); } return NULL; } static S_RESULT SMCPropYacc(uint8_t* pBuffer, uint32_t nBufferLength, CONF_FILE* pConfFile, SERVICE_SECTION* pService) { S_RESULT nError=S_SUCCESS; LIST *pPublicPropertyList=NULL; LIST *pPrivatePropertyList=NULL; PROPERTY* pProperty=NULL; SERVICE_SECTION* pServSection; SERVICE_SECTION* pPreviousService=NULL; uint8_t* pName; uint32_t nNameLength; uint8_t* pValue; uint32_t nValueLength; char* pNameZ = NULL; char* pValueZ = NULL; LIB_MANIFEST2_CONTEXT sParserContext; char serviceManifestName[1024]; sParserContext.pManifestName = "Configuration File"; sParserContext.pManifestContent = pBuffer; sParserContext.nManifestLength = nBufferLength; sParserContext.nType = LIB_MANIFEST2_TYPE_SOURCE_WITH_SECTIONS; if (pService!=NULL) { pPublicPropertyList=&pService->sPublicPropertyList; pPrivatePropertyList=&pService->sPrivatePropertyList; /* read inside a service compiled manifest */ sParserContext.nType = LIB_MANIFEST2_TYPE_COMPILED; sprintf(serviceManifestName, "%s(manifest)", pService->sNode.pName); sParserContext.pManifestName = serviceManifestName; } libManifest2InitContext(&sParserContext); while (true) { nError = libManifest2GetNextItem( &sParserContext, &pName, &nNameLength, &pValue, &nValueLength); if (nError == S_ERROR_ITEM_NOT_FOUND) { /* End of parsing */ nError = S_SUCCESS; break; } else if (nError != S_SUCCESS) { /* Error */ goto error; } /* Duplicate name and value in as zero-terminated strings */ /* Unclean: those strings are not going to be deallocated This is not a problem because this code is run in a tool */ pNameZ = malloc(nNameLength+1); if (pNameZ == NULL) { nError = S_ERROR_OUT_OF_MEMORY; goto error; } memcpy(pNameZ, pName, nNameLength); pNameZ[nNameLength] = 0; if (pValue == NULL) { /* It's a section */ if (STRICMP(pNameZ, SYSTEM_SECTION_NAME) == 0) { free(pNameZ); pPublicPropertyList=&pConfFile->sSystemSectionPropertyList; } else { pServSection=(SERVICE_SECTION*)SMCPropListFindElement( &pConfFile->sDriverSectionList, pNameZ, false); if (pServSection==NULL) { pServSection=(SERVICE_SECTION*)SMCPropListFindElement( &pConfFile->sPreinstalledSectionList, pNameZ, false); } if (pServSection==NULL) { pServSection=(SERVICE_SECTION*)SMCPropListFindElement( &pConfFile->sSectionList, pNameZ, false); if (pServSection==NULL) { nError=S_ERROR_ITEM_NOT_FOUND; goto error; } } free(pNameZ); pServSection->inSCF=true; if (pPreviousService!=NULL) { pPreviousService->pNextInSCF=pServSection; } else { pConfFile->pFirstSectionInSCF=pServSection; } pPreviousService=pServSection; pPublicPropertyList=&pServSection->sPublicPropertyList; pPrivatePropertyList=&pServSection->sPrivatePropertyList; } } else { /* It's a property definition */ pValueZ = malloc(nValueLength+1); if (pValueZ == NULL) { nError = S_ERROR_OUT_OF_MEMORY; goto error; } memcpy(pValueZ, pValue, nValueLength); pValueZ[nValueLength] = 0; pProperty=(PROPERTY*)malloc(sizeof(PROPERTY)); if (pProperty==NULL) { nError=S_ERROR_OUT_OF_MEMORY; goto error; } memset(pProperty, 0x00, sizeof(PROPERTY)); pProperty->sNode.pName=pNameZ; pProperty->pValue=pValueZ; if (pPrivatePropertyList==NULL) { nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty); if (nError!=S_SUCCESS) { goto error; } } else { if (strcmp(pProperty->sNode.pName,CONFIG_SERVICE_ID_PROPERTY_NAME) == 0) { if (pService!=NULL) { pService->sNode.pName=malloc(nValueLength+1); if (pService->sNode.pName==NULL) { nError=S_ERROR_OUT_OF_MEMORY; goto error; } #if defined (LINUX) || defined (__SYMBIAN32__) || defined(ANDROID) { // put each char of the value in uppercase char* p=pProperty->pValue; while(*p) { *p=toupper(*p); p++; } } #else _strupr(pProperty->pValue); #endif memcpy(pService->sNode.pName,pProperty->pValue,nValueLength+1); if (!libUUIDFromString((const uint8_t*)pProperty->pValue,&pService->sUUID)) { nError=S_ERROR_WRONG_SIGNATURE; goto error; } { S_UUID sNullUUID; memset(&sNullUUID,0,sizeof(S_UUID)); if (!memcmp(&pService->sUUID,&sNullUUID,sizeof(S_UUID))) { nError=S_ERROR_WRONG_SIGNATURE; goto error; } } } } if ((nValueLength > strlen(CONFIG_PROPERTY_NAME)) && (memcmp(pProperty->sNode.pName, CONFIG_PROPERTY_NAME, strlen(CONFIG_PROPERTY_NAME)) == 0)) { nError=SMCPropListSortedAdd(pPrivatePropertyList,(NODE*)pProperty); } else { nError=SMCPropListSortedAdd(pPublicPropertyList,(NODE*)pProperty); } if (nError!=S_SUCCESS) { goto error; } } } } error: if (nError!=S_SUCCESS) { switch (nError) { case S_ERROR_BAD_FORMAT: /* Error message already output */ break; case S_ERROR_WRONG_SIGNATURE: TRACE_ERROR("Configuration file: wrong service UUID: %s\n", pValueZ); break; case S_ERROR_OUT_OF_MEMORY: TRACE_ERROR("Out of memory\n"); break; case S_ERROR_ITEM_NOT_FOUND: TRACE_ERROR("Configuration file: service \"%s\" not found\n", pNameZ); break; } } return nError; } S_RESULT static_readFile(const char* pFilename, void** ppFile, uint32_t* pnFileLength) { S_RESULT nResult = S_SUCCESS; long nFilesize; FILE* pFile = NULL; void *pBuff = NULL; // open file and get its size... if ((pFile = fopen(pFilename, "rb")) == NULL) { TRACE_ERROR("static_readFile: fopen(%s) failed [%d]", pFilename, GET_LAST_ERR); nResult = S_ERROR_ITEM_NOT_FOUND; return nResult; } if (fseek(pFile, 0, SEEK_END) != 0) { TRACE_ERROR("static_readFile: fseek(%s) failed [%d]", pFilename, GET_LAST_ERR); nResult = S_ERROR_UNDERLYING_OS; goto error; } nFilesize = ftell(pFile); if (nFilesize < 0) { TRACE_ERROR("static_readFile: ftell(%s) failed [%d]", pFilename, GET_LAST_ERR); nResult = S_ERROR_UNDERLYING_OS; goto error; } rewind(pFile); // allocate the buffer pBuff = malloc(nFilesize + 1); if (pBuff == NULL) { TRACE_ERROR("static_readFile: out of memory"); nResult = S_ERROR_OUT_OF_MEMORY; goto error; } // read the file if (fread(pBuff, sizeof(uint8_t), (size_t)nFilesize, pFile) != (size_t)nFilesize) { TRACE_ERROR("static_readFile: fread failed [%d]", GET_LAST_ERR); nResult = S_ERROR_UNDERLYING_OS; goto error; } ((char*)pBuff)[nFilesize] = 0; *ppFile = pBuff; *pnFileLength = nFilesize; return S_SUCCESS; error: if (pBuff != NULL) free(pBuff); fclose(pFile); *ppFile = NULL; *pnFileLength = 0; return nResult; } /* --------------------------------------------------------------------------------- API functions. ---------------------------------------------------------------------------------*/ char* SMCPropGetSystemProperty(CONF_FILE* pConfFile, char* pPropertyName) { PROPERTY* pProperty; pProperty=(PROPERTY*)SMCPropListFindElement( &pConfFile->sSystemSectionPropertyList, pPropertyName, true); if (pProperty!=NULL) { return pProperty->pValue; } return NULL; } uint32_t SMCPropGetSystemPropertyAsInt(CONF_FILE* pConfFile, char* pPropertyName) { uint32_t nValue; char* pValue=SMCPropGetSystemProperty(pConfFile,pPropertyName); if (libString2GetStringAsInt(pValue, &nValue) == S_SUCCESS) { return nValue; } return 0; } S_RESULT SMCPropParseConfigFile(char* pConfigFilename,CONF_FILE* pConfFile) { S_RESULT nError=S_SUCCESS; void* pFile; uint32_t nFileLength; bool bReuseManifest; assert(pConfFile!=NULL); TRACE_INFO("Processing configuration file '%s'", pConfigFilename); if(pConfigFilename != NULL) { nError=static_readFile(pConfigFilename,&pFile,&nFileLength); if (nError!=S_SUCCESS) { goto error; } bReuseManifest = true; } else { assert(0); } nError=SMCPropYacc(pFile,nFileLength,pConfFile,NULL); if(pConfigFilename != NULL) { free(pFile); } error: return nError; }