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> 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 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 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 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 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 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 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 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 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 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 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 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