1/** Mobicore Driver Registry.
2 *
3 * Implements the MobiCore driver registry which maintains trustlets.
4 *
5 * @file
6 * @ingroup MCD_MCDIMPL_DAEMON_REG
7 * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote
18 *    products derived from this software without specific prior
19 *    written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "MobiCoreRegistry.h"
35#include <stdlib.h>
36#include <dirent.h>
37#include <stdio.h>
38#include <sys/stat.h>
39#include <assert.h>
40#include <string>
41#include <cstring>
42#include <cstddef>
43#include "mcLoadFormat.h"
44#include "mcSpid.h"
45#include "mcVersionHelper.h"
46
47#include "log.h"
48
49MC_CHECK_DATA_OBJECT_VERSION(MCLF, 2, 0);
50MC_CHECK_DATA_OBJECT_VERSION(CONTAINER, 2, 0);
51
52// Asserts expression at compile-time (to be used within a function body).
53#define ASSERT_STATIC(e) do { enum { assert_static__ = 1 / (e) }; } while (0)
54
55using namespace std;
56
57static const string MC_REGISTRY_DEFAULT_PATH = "/data/app/mcRegistry";
58static const string AUTH_TOKEN_FILE_NAME = "00000000.authtokcont";
59static const string ROOT_FILE_NAME = "00000000.rootcont";
60static const string SP_CONT_FILE_EXT = ".spcont";
61static const string TL_CONT_FILE_EXT = ".tlcont";
62static const string TL_BIN_FILE_EXT = ".tlbin";
63static const string DATA_CONT_FILE_EXT = ".datacont";
64
65static const string ENV_MC_REGISTRY_PATH = "MC_REGISTRY_PATH";
66static const string ENV_MC_REGISTRY_FALLBACK_PATH = "MC_REGISTRY_FALLBACK_PATH";
67static const string ENV_MC_AUTH_TOKEN_PATH = "MC_AUTH_TOKEN_PATH";
68
69static const string getRegistryPath();
70static const string getAuthTokenFilePath();
71static const string getRootContFilePath();
72static const string getSpDataPath(mcSpid_t spid);
73static const string getSpContFilePath(mcSpid_t spid);
74static const string getTlContFilePath(const mcUuid_t *uuid);
75static const string getTlDataPath(const mcUuid_t *uuid);
76static const string getTlDataFilePath(const mcUuid_t *uuid, mcPid_t pid);
77static const string getTlBinFilePath(const mcUuid_t *uuid);
78
79static const string uint32ToString(mcSpid_t spid);
80static const string byteArrayToString(const void *bytes, size_t elems);
81static bool doesDirExist(const char *path);
82
83//------------------------------------------------------------------------------
84mcResult_t mcRegistryStoreAuthToken(
85    const mcSoAuthTokenCont_t *so
86)
87{
88    if (NULL == so) {
89        LOG_E("mcRegistry store So.Soc failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
90        return MC_DRV_ERR_INVALID_PARAMETER;
91    }
92    if (CONT_TYPE_SOC != so->coSoc.type) {
93        LOG_E("mcRegistry store So.Soc failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
94        return MC_DRV_ERR_INVALID_PARAMETER;
95    }
96    const string &authTokenFilePath = getAuthTokenFilePath();
97    LOG_I("store AuthToken: %s", authTokenFilePath.c_str());
98
99    FILE *fs = fopen(authTokenFilePath.c_str(), "wb");
100    if (!fs) {
101        LOG_E("mcRegistry store So.Soc failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
102        return MC_DRV_ERR_INVALID_DEVICE_FILE;
103    }
104    fseek(fs, 0, SEEK_SET);
105    fwrite((char *)so, 1, sizeof(mcSoAuthTokenCont_t), fs);
106    fflush(fs);
107    fclose(fs);
108
109    return MC_DRV_OK;
110}
111
112
113//------------------------------------------------------------------------------
114mcResult_t mcRegistryReadAuthToken(
115    mcSoAuthTokenCont_t *so
116)
117{
118    if (NULL == so) {
119        LOG_E("mcRegistry read So.Soc failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
120        return MC_DRV_ERR_INVALID_PARAMETER;
121    }
122    const string &authTokenFilePath = getAuthTokenFilePath();
123    LOG_I("read AuthToken: %s", authTokenFilePath.c_str());
124
125    FILE *fs = fopen(authTokenFilePath.c_str(), "rb");
126    if (!fs) {
127        LOG_E("mcRegistry read So.Soc failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
128        return MC_DRV_ERR_INVALID_DEVICE_FILE;
129    }
130    fseek(fs, 0, SEEK_END);
131    int32_t filesize = ftell(fs);
132    if (sizeof(mcSoAuthTokenCont_t) != filesize) {
133        fclose(fs);
134        LOG_E("mcRegistry read So.Soc failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
135        return MC_DRV_ERR_OUT_OF_RESOURCES;
136    }
137    fseek(fs, 0, SEEK_SET);
138    fread((char *)so, 1, sizeof(mcSoAuthTokenCont_t), fs);
139    fclose(fs);
140
141    return MC_DRV_OK;
142}
143
144//------------------------------------------------------------------------------
145mcResult_t mcRegistryDeleteAuthToken(
146    void
147)
148{
149    remove(getAuthTokenFilePath().c_str());
150    // @TODO: is return to check ?
151    return MC_DRV_OK;
152}
153
154
155//------------------------------------------------------------------------------
156mcResult_t mcRegistryStoreRoot(
157    const mcSoRootCont_t *so
158)
159{
160    if (NULL == so) {
161        LOG_E("mcRegistry store So.Root failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
162        return MC_DRV_ERR_INVALID_PARAMETER;
163    }
164    if (CONT_TYPE_ROOT != so->cont.type) {
165        LOG_E("mcRegistry store So.Root failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
166        return MC_DRV_ERR_INVALID_PARAMETER;
167    }
168    const string &rootContFilePath = getRootContFilePath();
169    LOG_I("store Root: %s", rootContFilePath.c_str());
170
171    FILE *fs = fopen(rootContFilePath.c_str(), "wb");
172    if (!fs) {
173        LOG_E("mcRegistry store So.Root failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
174        return MC_DRV_ERR_INVALID_DEVICE_FILE;
175    }
176    fseek(fs, 0, SEEK_SET);
177    fwrite((char *)so, 1, sizeof(mcSoRootCont_t), fs);
178    fflush(fs);
179    fclose(fs);
180
181    return MC_DRV_OK;
182}
183
184
185//------------------------------------------------------------------------------
186mcResult_t mcRegistryReadRoot(
187    mcSoRootCont_t *so
188)
189{
190    if (NULL == so) {
191        LOG_E("mcRegistry read So.Root failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
192        return MC_DRV_ERR_INVALID_PARAMETER;
193    }
194    const string &rootContFilePath = getRootContFilePath();
195    LOG_I("read Root: %s", rootContFilePath.c_str());
196
197    FILE *fs = fopen(rootContFilePath.c_str(), "rb");
198    if (!fs) {
199        LOG_E("mcRegistry read So.Root failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
200        return MC_DRV_ERR_INVALID_DEVICE_FILE;
201    }
202    fseek(fs, 0, SEEK_END);
203    int32_t filesize = ftell(fs);
204    if (sizeof(mcSoRootCont_t) != filesize) {
205        fclose(fs);
206        LOG_E("mcRegistry read So.Root failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
207        return MC_DRV_ERR_OUT_OF_RESOURCES;
208    }
209    fseek(fs, 0, SEEK_SET);
210    fread((char *)so, 1, sizeof(mcSoRootCont_t), fs);
211    fclose(fs);
212
213    return MC_DRV_OK;
214}
215
216
217//------------------------------------------------------------------------------
218mcResult_t mcRegistryStoreSp(
219    mcSpid_t            spid,
220    const mcSoSpCont_t  *so
221)
222{
223    if ((0 == spid) || (NULL == so)) {
224        LOG_E("mcRegistry store So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
225        return MC_DRV_ERR_INVALID_PARAMETER;
226    }
227    if (CONT_TYPE_SP != so->cont.type) {
228        LOG_E("mcRegistry store So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
229        return MC_DRV_ERR_INVALID_PARAMETER;
230    }
231    const string &spContFilePath = getSpContFilePath(spid);
232    LOG_I("store SP: %s", spContFilePath.c_str());
233
234    FILE *fs = fopen(spContFilePath.c_str(), "wb");
235    if (!fs) {
236        LOG_E("mcRegistry store So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
237        return MC_DRV_ERR_INVALID_DEVICE_FILE;
238    }
239    fseek(fs, 0, SEEK_SET);
240    fwrite((char *)so, 1, sizeof(mcSoSpCont_t), fs);
241    fflush(fs);
242    fclose(fs);
243
244    return MC_DRV_OK;
245}
246
247
248//------------------------------------------------------------------------------
249mcResult_t mcRegistryReadSp(
250    mcSpid_t        spid,
251    mcSoSpCont_t    *so
252)
253{
254    if ((0 == spid) || (NULL == so)) {
255        LOG_E("mcRegistry read So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
256        return MC_DRV_ERR_INVALID_PARAMETER;
257    }
258    const string &spContFilePath = getSpContFilePath(spid);
259    LOG_I("read SP: %s", spContFilePath.c_str());
260
261    FILE *fs = fopen(spContFilePath.c_str(), "rb");
262    if (!fs) {
263        LOG_E("mcRegistry read So.Sp(SpId) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
264        return MC_DRV_ERR_INVALID_DEVICE_FILE;
265    }
266    fseek(fs, 0, SEEK_END);
267    int32_t filesize = ftell(fs);
268    if (sizeof(mcSoSpCont_t) != filesize) {
269        fclose(fs);
270        LOG_E("mcRegistry read So.Sp(SpId) failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
271        return MC_DRV_ERR_OUT_OF_RESOURCES;
272    }
273    fseek(fs, 0, SEEK_SET);
274    fread((char *)so, 1, sizeof(mcSoSpCont_t), fs);
275    fclose(fs);
276
277    return MC_DRV_OK;
278}
279
280
281//------------------------------------------------------------------------------
282mcResult_t mcRegistryStoreTrustletCon(
283    const mcUuid_t      *uuid,
284    const mcSoTltCont_t *so
285)
286{
287    if ((NULL == uuid) || (NULL == so)) {
288        LOG_E("mcRegistry store So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
289        return MC_DRV_ERR_INVALID_PARAMETER;
290    }
291    if (CONT_TYPE_TLCON != so->cont.type) {
292        LOG_E("mcRegistry store So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
293        return MC_DRV_ERR_INVALID_PARAMETER;
294    }
295    const string &tlContFilePath = getTlContFilePath(uuid);
296    LOG_I("store TLc: %s", tlContFilePath.c_str());
297
298    FILE *fs = fopen(tlContFilePath.c_str(), "wb");
299    if (!fs) {
300        LOG_E("mcRegistry store So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
301        return MC_DRV_ERR_INVALID_DEVICE_FILE;
302    }
303    fseek(fs, 0, SEEK_SET);
304    fwrite((char *)so, 1, sizeof(mcSoTltCont_t), fs);
305    fflush(fs);
306    fclose(fs);
307
308    return MC_DRV_OK;
309}
310
311
312//------------------------------------------------------------------------------
313mcResult_t mcRegistryReadTrustletCon(
314    const mcUuid_t  *uuid,
315    mcSoTltCont_t   *so
316)
317{
318    if ((NULL == uuid) || (NULL == so)) {
319        LOG_E("mcRegistry read So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
320        return MC_DRV_ERR_INVALID_PARAMETER;
321    }
322    const string &tlContFilePath = getTlContFilePath(uuid);
323    LOG_I("read TLc: %s", tlContFilePath.c_str());
324
325    FILE *fs = fopen(tlContFilePath.c_str(), "rb");
326    if (!fs) {
327        LOG_E("mcRegistry read So.TrustletCont(uuid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
328        return MC_DRV_ERR_INVALID_DEVICE_FILE;
329    }
330    fseek(fs, 0, SEEK_END);
331    int32_t filesize = ftell(fs);
332    if (sizeof(mcSoTltCont_t) != filesize) {
333        fclose(fs);
334        LOG_E("mcRegistry read So.TrustletCont(uuid) failed: %d. Size=%i, expected=%i", MC_DRV_ERR_OUT_OF_RESOURCES, filesize, sizeof(mcSoTltCont_t));
335        return MC_DRV_ERR_OUT_OF_RESOURCES;
336    }
337    fseek(fs, 0, SEEK_SET);
338    fread((char *)so, 1, sizeof(mcSoTltCont_t), fs);
339    fclose(fs);
340
341    return MC_DRV_OK;
342}
343
344
345//------------------------------------------------------------------------------
346mcResult_t mcRegistryStoreData(
347    const mcSoDataCont_t *so
348)
349{
350    if (NULL == so) {
351        LOG_E("mcRegistry store So.Data failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
352        return MC_DRV_ERR_INVALID_PARAMETER;
353    }
354    string pathname, filename;
355
356    switch (so->cont.type) {
357    case CONT_TYPE_SPDATA:
358        LOG_E("SPDATA not supported");
359        return MC_DRV_ERR_INVALID_PARAMETER;
360        break;
361    case CONT_TYPE_TLDATA:
362        pathname = getTlDataPath(&so->cont.uuid);
363        filename = getTlDataFilePath(&so->cont.uuid, so->cont.pid);
364        break;
365    default:
366        LOG_E("mcRegistry store So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
367        return MC_DRV_ERR_INVALID_PARAMETER;
368    }
369    mkdir(pathname.c_str(), 0777);
370
371    LOG_I("store DT: %s", filename.c_str());
372
373    FILE *fs = fopen(filename.c_str(), "wb");
374    if (!fs) {
375        LOG_E("mcRegistry store So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
376        return MC_DRV_ERR_INVALID_DEVICE_FILE;
377    }
378    fseek(fs, 0, SEEK_SET);
379    fwrite((char *)so, 1, MC_SO_SIZE(so->soHeader.plainLen, so->soHeader.encryptedLen), fs);
380    fflush(fs);
381    fclose(fs);
382
383    return MC_DRV_OK;
384}
385
386
387//------------------------------------------------------------------------------
388mcResult_t mcRegistryReadData(
389    uint32_t        context,
390    const mcCid_t   *cid,
391    mcPid_t         pid,
392    mcSoDataCont_t  *so,
393    uint32_t        maxLen
394)
395{
396    if ((NULL == cid) || (NULL == so)) {
397        LOG_E("mcRegistry read So.Data failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
398        return MC_DRV_ERR_INVALID_PARAMETER;
399    }
400    string filename;
401    switch (context) {
402    case 0:
403        LOG_E("SPDATA not supported");
404        return MC_DRV_ERR_INVALID_PARAMETER;
405        break;
406    case 1:
407        filename = getTlDataFilePath(&so->cont.uuid, so->cont.pid);
408        break;
409    default:
410        LOG_E("mcRegistry read So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
411        return MC_DRV_ERR_INVALID_PARAMETER;
412    }
413    LOG_I("read DT: %s", filename.c_str());
414
415    FILE *fs = fopen(filename.c_str(), "rb");
416    if (!fs) {
417        LOG_E("mcRegistry read So.Data(cid/pid) failed: %d", MC_DRV_ERR_INVALID_DEVICE_FILE);
418        return MC_DRV_ERR_INVALID_DEVICE_FILE;
419    }
420    fseek(fs, 0, SEEK_END);
421    uint32_t filesize = ftell(fs);
422    if (maxLen < filesize) {
423        fclose(fs);
424        LOG_E("mcRegistry read So.Data(cid/pid) failed: %d", MC_DRV_ERR_OUT_OF_RESOURCES);
425        return MC_DRV_ERR_OUT_OF_RESOURCES;
426    }
427    fseek(fs, 0, SEEK_SET);
428    char *p = (char *) so;
429    fread(p, 1, sizeof(mcSoHeader_t), fs);
430    p += sizeof(mcSoHeader_t);
431    fread(p, 1, MC_SO_SIZE(so->soHeader.plainLen, so->soHeader.encryptedLen) - sizeof(mcSoHeader_t), fs);
432    fclose(fs);
433
434    return MC_DRV_OK;
435}
436
437
438//------------------------------------------------------------------------------
439mcResult_t mcRegistryCleanupTrustlet(
440    const mcUuid_t *uuid
441)
442{
443    DIR            *dp;
444    struct dirent  *de;
445    int             e;
446
447    if (NULL == uuid) {
448        LOG_E("mcRegistry cleanupTrustlet(uuid) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
449        return MC_DRV_ERR_INVALID_PARAMETER;
450    }
451    string pathname = getTlDataPath(uuid);
452    if (NULL != (dp = opendir(pathname.c_str()))) {
453        while (NULL != (de = readdir(dp))) {
454            if (de->d_name[0] != '.') {
455                string dname = pathname + "/" + string (de->d_name);
456                LOG_I("delete DT: %s", dname.c_str());
457                if (0 != (e = remove(dname.c_str()))) {
458                    LOG_E("remove UUID-data %s failed! error: %d", dname.c_str(), e);
459                    return MC_DRV_ERR_UNKNOWN;
460                }
461            }
462        }
463        LOG_I("delete dir: %s", pathname.c_str());
464        if (0 != (e = rmdir(pathname.c_str()))) {
465            LOG_E("remove UUID-dir failed! errno: %d", e);
466            return MC_DRV_ERR_UNKNOWN;
467        }
468    }
469    string tlBinFilePath = getTlBinFilePath(uuid);
470    LOG_I("delete Tlb: %s", tlBinFilePath.c_str());
471    if (0 != (e = remove(tlBinFilePath.c_str()))) {
472        LOG_E("remove Tlb failed! errno: %d", e);
473//        return MC_DRV_ERR_UNKNOWN;     // a trustlet-binary must not be present ! (registered but not usable)
474    }
475    string tlContFilePath = getTlContFilePath(uuid);
476    LOG_I("delete Tlc: %s", tlContFilePath.c_str());
477    if (0 != (e = remove(tlContFilePath.c_str()))) {
478        LOG_E("remove Tlc failed! errno: %d", e);
479        return MC_DRV_ERR_UNKNOWN;
480    }
481    return MC_DRV_OK;
482}
483
484
485//------------------------------------------------------------------------------
486mcResult_t mcRegistryCleanupSp(
487    mcSpid_t spid
488)
489{
490    mcResult_t      ret;
491    mcSoSpCont_t    data;
492    uint32_t        i;
493    DIR            *dp;
494    struct dirent  *de;
495    int             e;
496
497    if (0 == spid) {
498        LOG_E("mcRegistry cleanupSP(SpId) failed: %d", MC_DRV_ERR_INVALID_PARAMETER);
499        return MC_DRV_ERR_INVALID_PARAMETER;
500    }
501    ret = mcRegistryReadSp(spid, &data);
502    if (MC_DRV_OK != ret) {
503        LOG_E("read SP->UUID aborted! Return code: %d", ret);
504        return ret;
505    }
506    for (i = 0; (i < MC_CONT_CHILDREN_COUNT) && (ret == MC_DRV_OK); i++) {
507        if (0 != strncmp((const char *) & (data.cont.children[i]), (const char *)&MC_UUID_FREE, sizeof(mcUuid_t))) {
508            ret = mcRegistryCleanupTrustlet(&(data.cont.children[i]));
509        }
510    }
511    if (MC_DRV_OK != ret) {
512        LOG_E("delete SP->UUID failed! Return code: %d", ret);
513        return ret;
514    }
515    string pathname = getSpDataPath(spid);
516
517    if (NULL != (dp = opendir(pathname.c_str()))) {
518        while (NULL != (de = readdir(dp))) {
519            if (de->d_name[0] != '.') {
520                string dname = pathname + "/" + string (de->d_name);
521                LOG_I("delete DT: %s", dname.c_str());
522                if (0 != (e = remove(dname.c_str()))) {
523                    LOG_E("remove SPID-data %s failed! error: %d", dname.c_str(), e);
524                    return MC_DRV_ERR_UNKNOWN;
525                }
526            }
527        }
528        LOG_I("delete dir: %s", pathname.c_str());
529        if (0 != (e = rmdir(pathname.c_str()))) {
530            LOG_E("remove SPID-dir failed! error: %d", e);
531            return MC_DRV_ERR_UNKNOWN;
532        }
533    }
534    string spContFilePath = getSpContFilePath(spid);
535    LOG_I("delete Sp: %s", spContFilePath.c_str());
536    if (0 != (e = remove(spContFilePath.c_str()))) {
537        LOG_E("remove SP failed! error: %d", e);
538        return MC_DRV_ERR_UNKNOWN;
539    }
540    return MC_DRV_OK;
541}
542
543
544//------------------------------------------------------------------------------
545mcResult_t mcRegistryCleanupRoot(void)
546{
547    mcResult_t ret;
548    mcSoRootCont_t data;
549    uint32_t i;
550    int e;
551
552    ret = mcRegistryReadRoot(&data);
553    if (MC_DRV_OK != ret) {
554        LOG_E("read Root aborted! Return code: %d", ret);
555        return ret;
556    }
557    for (i = 0; (i < MC_CONT_CHILDREN_COUNT) && (ret == MC_DRV_OK); i++) {
558        mcSpid_t spid = data.cont.children[i];
559        if (spid != MC_SPID_FREE) {
560            ret = mcRegistryCleanupSp(spid);
561            if (MC_DRV_OK != ret) {
562                LOG_E("Cleanup SP failed! Return code: %d", ret);
563                return ret;
564            }
565        }
566    }
567
568    string rootContFilePath = getRootContFilePath();
569    LOG_I("Delete root: %s", rootContFilePath.c_str());
570    if (0 != (e = remove(rootContFilePath.c_str()))) {
571        LOG_E("Delete root failed! error: %d", e);
572        return MC_DRV_ERR_UNKNOWN;
573    }
574    return MC_DRV_OK;
575}
576
577
578//------------------------------------------------------------------------------
579regObject_t *mcRegistryGetServiceBlob(
580    const mcUuid_t *uuid
581)
582{
583    regObject_t *regobj = NULL;
584
585    // Ensure that a UUID is provided.
586    if (NULL == uuid) {
587        LOG_E("No UUID given");
588        return NULL;
589    }
590
591    // Open service blob file.
592    string tlBinFilePath = getTlBinFilePath(uuid);
593    LOG_I(" Loading %s", tlBinFilePath.c_str());
594
595    FILE *fs = fopen(tlBinFilePath.c_str(), "rb");
596    if (!fs) {
597        LOG_E("Cannot open %s", tlBinFilePath.c_str());
598        return NULL;
599    }
600
601    // Determine and check service blob size.
602    fseek(fs, 0, SEEK_END);
603    int32_t tlSize = ftell(fs);
604    fseek(fs, 0, SEEK_SET);
605    if (MAX_TL_SIZE < tlSize) {
606        LOG_E("mcRegistryGetServiceBlob() failed: service blob too big: %d", tlSize);
607        return NULL;
608    }
609
610    // Check TL magic value.
611    fseek(fs, offsetof(mclfIntro_t, magic), SEEK_SET);
612    uint32_t magic;
613    fread((char *)&magic, 1, sizeof(magic), fs);
614    if (magic != MC_SERVICE_HEADER_MAGIC_BE) {
615        fclose(fs);
616        LOG_E("mcRegistryGetServiceBlob() failed: wrong header magic value: %d", magic);
617        return NULL;
618    }
619
620    // Check header version.
621    fseek(fs, offsetof(mclfIntro_t, version), SEEK_SET);
622    uint32_t version;
623    fread((char *)&version, 1, sizeof(version), fs);
624
625    char *msg;
626    if (!checkVersionOkDataObjectMCLF(version, &msg)) {
627        fclose(fs);
628        LOG_E("%s", msg);
629        return NULL;
630    }
631
632    // Get service type.
633    fseek(fs, offsetof(mclfHeaderV2_t, serviceType), SEEK_SET);
634    serviceType_t serviceType;
635    fread((char *)&serviceType, 1, sizeof(serviceType), fs);
636    fseek(fs, 0, SEEK_SET);
637
638#ifndef NDEBUG
639    {
640        const char *service_types[] = {
641            "illegal", "Driver", "Trustlet", "System Trustlet"
642        };
643        int serviceType_safe = serviceType > SERVICE_TYPE_SYSTEM_TRUSTLET ? SERVICE_TYPE_ILLEGAL : serviceType;
644        LOG_I(" Service is a %s (service type %d)", service_types[serviceType_safe], serviceType);
645    }
646#endif
647
648    // If loadable driver or system trustlet.
649    if (SERVICE_TYPE_DRIVER == serviceType || SERVICE_TYPE_SYSTEM_TRUSTLET == serviceType) {
650        // Take trustlet blob 'as is'.
651        if (NULL == (regobj = (regObject_t *) (malloc(sizeof(regObject_t) + tlSize)))) {
652            fclose(fs);
653            LOG_E("mcRegistryGetServiceBlob() failed: Out of memory");
654            return NULL;
655        }
656        regobj->len = tlSize;
657        fread((char *)regobj->value, 1, tlSize, fs);
658        fclose(fs);
659        // If user trustlet.
660    } else if (SERVICE_TYPE_SP_TRUSTLET == serviceType) {
661        // Take trustlet blob and append root, sp, and tl container.
662        size_t regObjValueSize = tlSize + sizeof(mcSoContainerPath_t);
663
664        // Prepare registry object.
665        if (NULL == (regobj = (regObject_t *) malloc(sizeof(regObject_t) + regObjValueSize))) {
666            fclose(fs);
667            LOG_E("mcRegistryGetServiceBlob() failed: Out of memory");
668            return NULL;
669        }
670        regobj->len = regObjValueSize;
671
672        // Read and fill in trustlet blob at beginning.
673        fread((char *)regobj->value, 1, tlSize, fs);
674        fclose(fs);
675
676        // Goto end of allocated space and fill in tl container, sp container,
677        // and root container from back to front. Final registry object value
678        // looks like this:
679        //
680        //    +---------------------------+-----------+---------+---------+
681        //    | TL-Header TL-Code TL-Data | Root Cont | SP Cont | TL Cont |
682        //    +---------------------------+-----------+-------------------+
683        //    /------ Trustlet BLOB ------/
684        //
685        //    /------------------ regobj->header.len ---------------------/
686
687        uint8_t *p = regobj->value + regobj->len;
688        mcResult_t ret;
689        do {
690            char *msg;
691
692            // Fill in TL container.
693            p -= sizeof(mcSoTltCont_t);
694            mcSoTltCont_t *soTlt = (mcSoTltCont_t *)p;
695            if (MC_DRV_OK != (ret = mcRegistryReadTrustletCon(uuid, soTlt))) {
696                break;
697            }
698            mcTltCont_t *tltCont = &soTlt->cont;
699            if (!checkVersionOkDataObjectCONTAINER(tltCont->version, &msg)) {
700                LOG_E("Tlt container %s", msg);
701                ret = MC_DRV_ERR_CONTAINER_VERSION;
702                break;
703            }
704
705            // Fill in SP container.
706            mcSpid_t spid = tltCont->parent;
707            p -= sizeof(mcSoSpCont_t);
708            mcSoSpCont_t *soSp = (mcSoSpCont_t *)p;
709            if (MC_DRV_OK != (ret = mcRegistryReadSp(spid, soSp))) {
710                break;
711            }
712            mcSpCont_t *spCont = &soSp->cont;
713            if (!checkVersionOkDataObjectCONTAINER(spCont->version, &msg)) {
714                LOG_E("SP container %s", msg);
715                ret = MC_DRV_ERR_CONTAINER_VERSION;
716                break;
717            }
718
719            // Fill in root container.
720            p -= sizeof(mcSoRootCont_t);
721            mcSoRootCont_t *soRoot = (mcSoRootCont_t *)p;
722            if (MC_DRV_OK != (ret = mcRegistryReadRoot(soRoot))) {
723                break;
724            }
725            mcRootCont_t *rootCont = &soRoot->cont;
726            if (!checkVersionOkDataObjectCONTAINER(rootCont->version, &msg)) {
727                LOG_E("Root container %s", msg);
728                ret = MC_DRV_ERR_CONTAINER_VERSION;
729                break;
730            }
731
732            // Ensure order of elements in registry object value.
733            assert(p - tlSize - sizeof(regObject_t) == (uint8_t *)regobj);
734        } while (false);
735
736        if (MC_DRV_OK != ret) {
737            LOG_E("mcRegistryGetServiceBlob() failed: Error code: %d", ret);
738            free(regobj);
739            return NULL;
740        }
741        // Any other service type.
742    } else {
743        fclose(fs);
744        LOG_E("mcRegistryGetServiceBlob() failed: Unsupported service type %u", serviceType);
745    }
746
747    return regobj;
748}
749
750//------------------------------------------------------------------------------
751regObject_t *mcRegistryGetDriverBlob(
752    const char *driverFilename
753)
754{
755    regObject_t *regobj = NULL;
756
757    // Open service blob file.
758    FILE *fs = fopen(driverFilename, "rb");
759    if (!fs) {
760        LOG_E("mcRegistryGetDriverBlob() failed: cannot open %s", driverFilename);
761        return NULL;
762    }
763
764    // Determine and check service blob size.
765    fseek(fs, 0, SEEK_END);
766    int32_t tlSize = ftell(fs);
767    fseek(fs, 0, SEEK_SET);
768    if (MAX_TL_SIZE < tlSize) {
769        LOG_E("mcRegistryGetDriverBlob() failed: service blob too big: %d", tlSize);
770        fclose(fs);
771        return NULL;
772    }
773
774    // Check TL magic value.
775    fseek(fs, offsetof(mclfIntro_t, magic), SEEK_SET);
776    uint32_t magic;
777    fread((char *)&magic, 1, sizeof(magic), fs);
778    if (magic != MC_SERVICE_HEADER_MAGIC_BE) {
779        LOG_E("mcRegistryGetDriverBlob() failed: wrong header magic value: %d", magic);
780        fclose(fs);
781        return NULL;
782    }
783
784    // Check header version.
785    fseek(fs, offsetof(mclfIntro_t, version), SEEK_SET);
786    uint32_t version;
787    fread((char *)&version, 1, sizeof(version), fs);
788
789    char *msg;
790    if (!checkVersionOkDataObjectMCLF(version, &msg)) {
791        LOG_E("%s", msg);
792        fclose(fs);
793        return NULL;
794    }
795
796    // Get service type.
797    fseek(fs, offsetof(mclfHeaderV2_t, serviceType), SEEK_SET);
798    serviceType_t serviceType;
799    fread((char *)&serviceType, 1, sizeof(serviceType), fs);
800    fseek(fs, 0, SEEK_SET);
801
802    LOG_I("mcRegistryGetDriverBlob() Service is of type: %d", serviceType);
803
804    // If loadable driver or system trustlet.
805    if (SERVICE_TYPE_DRIVER == serviceType) {
806        // Take trustlet blob 'as is'.
807        if (NULL == (regobj = (regObject_t *) (malloc(sizeof(regObject_t) + tlSize)))) {
808            LOG_E("mcRegistryGetDriverBlob() failed: Out of memory");
809            fclose(fs);
810            return NULL;
811        }
812        regobj->len = tlSize;
813        fread((char *)regobj->value, 1, tlSize, fs);
814        // Otherwise we are not interested
815    } else {
816        LOG_E("mcRegistryGetServiceBlob() failed: Unsupported service type %u", serviceType);
817    }
818
819    fclose(fs);
820
821    return regobj;
822}
823
824//------------------------------------------------------------------------------
825static const string getRegistryPath()
826{
827    const char *path;
828    string registryPath;
829
830    // First, attempt to use regular registry environment variable.
831    path = getenv(ENV_MC_REGISTRY_PATH.c_str());
832    if (doesDirExist(path)) {
833        LOG_I("getRegistryPath(): Using MC_REGISTRY_PATH %s", path);
834        registryPath = path;
835    } else {
836        // Second, attempt to use fallback registry environment variable.
837        path = getenv(ENV_MC_REGISTRY_FALLBACK_PATH.c_str());
838        if (doesDirExist(path)) {
839            LOG_I("getRegistryPath(): Using MC_REGISTRY_FALLBACK_PATH %s", path);
840            registryPath = path;
841        }
842    }
843
844    // As a last resort, use the default registry path.
845    if (registryPath.length() == 0) {
846        registryPath = MC_REGISTRY_DEFAULT_PATH;
847        LOG_I(" Using default registry path %s", registryPath.c_str());
848    }
849
850    assert(registryPath.length() != 0);
851
852    return registryPath;
853}
854
855//------------------------------------------------------------------------------
856static const string getAuthTokenFilePath()
857{
858    const char *path;
859    string authTokenPath;
860
861    // First, attempt to use regular auth token path environment variable.
862    path = getenv(ENV_MC_AUTH_TOKEN_PATH.c_str());
863    if (doesDirExist(path)) {
864        LOG_I("getAuthTokenFilePath(): Using MC_AUTH_TOKEN_PATH %s", path);
865        authTokenPath = path;
866    } else {
867        authTokenPath = getRegistryPath();
868        LOG_I("getAuthTokenFilePath(): Using path %s", authTokenPath.c_str());
869    }
870
871    return authTokenPath + "/" + AUTH_TOKEN_FILE_NAME;
872}
873
874//------------------------------------------------------------------------------
875static const string getRootContFilePath()
876{
877    return getRegistryPath() + "/" + ROOT_FILE_NAME;
878}
879
880//------------------------------------------------------------------------------
881static const string getSpDataPath(mcSpid_t spid)
882{
883    return getRegistryPath() + "/" + uint32ToString(spid);
884}
885
886//------------------------------------------------------------------------------
887static const string getSpContFilePath(mcSpid_t spid)
888{
889    return getRegistryPath() + "/" + uint32ToString(spid) + SP_CONT_FILE_EXT;
890}
891
892//------------------------------------------------------------------------------
893static const string getTlContFilePath(const mcUuid_t *uuid)
894{
895    return getRegistryPath() + "/" + byteArrayToString(uuid, sizeof(*uuid)) + TL_CONT_FILE_EXT;
896}
897
898//------------------------------------------------------------------------------
899static const string getTlDataPath(const mcUuid_t *uuid)
900{
901    return getRegistryPath() + "/" + byteArrayToString(uuid, sizeof(*uuid));
902}
903
904//------------------------------------------------------------------------------
905static const string getTlDataFilePath(const mcUuid_t *uuid, mcPid_t pid)
906{
907    return getTlDataPath(uuid) + "/" + uint32ToString(pid.data) + DATA_CONT_FILE_EXT;
908}
909
910//------------------------------------------------------------------------------
911static const string getTlBinFilePath(const mcUuid_t *uuid)
912{
913    return getRegistryPath() + "/" + byteArrayToString(uuid, sizeof(*uuid)) + TL_BIN_FILE_EXT;
914}
915
916//------------------------------------------------------------------------------
917static const string byteArrayToString(const void *bytes, size_t elems)
918{
919    char hx[elems * 2 + 1];
920
921    for (size_t i = 0; i < elems; i++) {
922        sprintf(&hx[i * 2], "%02x", ((uint8_t *)bytes)[i]);
923    }
924    return string(hx);
925}
926
927//------------------------------------------------------------------------------
928static const string uint32ToString(
929    uint32_t value
930)
931{
932    char hx[sizeof(uint32_t) * 2 + 1];
933    uint32_t i;
934
935    for (i = 0; i < (2 * sizeof(value)); i++) {
936        hx[i] = (value >> (28 - (i * 4))) & 0x0F;
937        if (hx[i] > 9) {
938            hx[i] = (hx[i] - 9) | 0x40;
939        } else {
940            hx[i] |= 0x30;
941        }
942    }
943    hx[i] = '\0';
944    return string(hx);
945}
946
947//------------------------------------------------------------------------------
948static bool doesDirExist(const char *path)
949{
950    struct stat ss;
951    if (path != NULL && stat(path, &ss) == 0 && S_ISDIR(ss.st_mode)) {
952        return true;
953    }
954    return false;
955}
956
957
958/** @} */
959