summaryrefslogblamecommitdiffstats
path: root/amend/permissions.c
blob: a642d0bb281e9dbb87293f40ba4f7985a45694b3 (plain) (tree)













































































































































































































































































                                                                             
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <string.h>
#include "permissions.h"

int
initPermissionRequestList(PermissionRequestList *list)
{
    if (list != NULL) {
        list->requests = NULL;
        list->numRequests = 0;
        list->requestsAllocated = 0;
        return 0;
    }
    return -1;
}

int
addPermissionRequestToList(PermissionRequestList *list,
        const char *path, bool recursive, unsigned int permissions)
{
    if (list == NULL || list->numRequests < 0 ||
            list->requestsAllocated < list->numRequests || path == NULL)
    {
        return -1;
    }

    if (list->numRequests == list->requestsAllocated) {
        int newSize;
        PermissionRequest *newRequests;

        newSize = list->requestsAllocated * 2;
        if (newSize < 16) {
            newSize = 16;
        }
        newRequests = (PermissionRequest *)realloc(list->requests,
                newSize * sizeof(PermissionRequest));
        if (newRequests == NULL) {
            return -2;
        }
        list->requests = newRequests;
        list->requestsAllocated = newSize;
    }

    PermissionRequest *req;
    req = &list->requests[list->numRequests++];
    req->path = strdup(path);
    if (req->path == NULL) {
        list->numRequests--;
        return -3;
    }
    req->recursive = recursive;
    req->requested = permissions;
    req->allowed = 0;

    return 0;
}

void
freePermissionRequestListElements(PermissionRequestList *list)
{
    if (list != NULL && list->numRequests >= 0 &&
            list->requestsAllocated >= list->numRequests)
    {
        int i;
        for (i = 0; i < list->numRequests; i++) {
            free((void *)list->requests[i].path);
        }
        free(list->requests);
        initPermissionRequestList(list);
    }
}

/*
 * Global permission table
 */

static struct {
    Permission *permissions;
    int numPermissionEntries;
    int allocatedPermissionEntries;
    bool permissionStateInitialized;
} gPermissionState = {
#if 1
    NULL, 0, 0, false
#else
    .permissions = NULL,
    .numPermissionEntries = 0,
    .allocatedPermissionEntries = 0,
    .permissionStateInitialized = false
#endif
};

int
permissionInit()
{
    if (gPermissionState.permissionStateInitialized) {
        return -1;
    }
    gPermissionState.permissions = NULL;
    gPermissionState.numPermissionEntries = 0;
    gPermissionState.allocatedPermissionEntries = 0;
    gPermissionState.permissionStateInitialized = true;
//xxx maybe add an "namespace root gets no permissions" fallback by default
    return 0;
}

void
permissionCleanup()
{
    if (gPermissionState.permissionStateInitialized) {
        gPermissionState.permissionStateInitialized = false;
        if (gPermissionState.permissions != NULL) {
            int i;
            for (i = 0; i < gPermissionState.numPermissionEntries; i++) {
                free((void *)gPermissionState.permissions[i].path);
            }
            free(gPermissionState.permissions);
        }
    }
}

int
getPermissionCount()
{
    if (gPermissionState.permissionStateInitialized) {
        return gPermissionState.numPermissionEntries;
    }
    return -1;
}

const Permission *
getPermissionAt(int index)
{
    if (!gPermissionState.permissionStateInitialized) {
        return NULL;
    }
    if (index < 0 || index >= gPermissionState.numPermissionEntries) {
        return NULL;
    }
    return &gPermissionState.permissions[index];
}

int
getAllowedPermissions(const char *path, bool recursive,
        unsigned int *outAllowed)
{
    if (!gPermissionState.permissionStateInitialized) {
        return -2;
    }
    if (outAllowed == NULL) {
        return -1;
    }
    *outAllowed = 0;
    if (path == NULL) {
        return -1;
    }
    //TODO: implement this for real.
    recursive = false;
    *outAllowed = PERMSET_ALL;
    return 0;
}

int
countPermissionConflicts(PermissionRequestList *requests, bool updateAllowed)
{
    if (!gPermissionState.permissionStateInitialized) {
        return -2;
    }
    if (requests == NULL || requests->requests == NULL ||
            requests->numRequests < 0 ||
            requests->requestsAllocated < requests->numRequests)
    {
        return -1;
    }
    int conflicts = 0;
    int i;
    for (i = 0; i < requests->numRequests; i++) {
        PermissionRequest *req;
        unsigned int allowed;
        int ret;

        req = &requests->requests[i];
        ret = getAllowedPermissions(req->path, req->recursive, &allowed);
        if (ret < 0) {
            return ret;
        }
        if ((req->requested & ~allowed) != 0) {
            conflicts++;
        }
        if (updateAllowed) {
            req->allowed = allowed;
        }
    }
    return conflicts;
}

int
registerPermissionSet(int count, Permission *set)
{
    if (!gPermissionState.permissionStateInitialized) {
        return -2;
    }
    if (count < 0 || (count > 0 && set == NULL)) {
        return -1;
    }
    if (count == 0) {
        return 0;
    }

    if (gPermissionState.numPermissionEntries + count >=
            gPermissionState.allocatedPermissionEntries)
    {
        Permission *newList;
        int newSize;

        newSize = (gPermissionState.allocatedPermissionEntries + count) * 2;
        if (newSize < 16) {
            newSize = 16;
        }
        newList = (Permission *)realloc(gPermissionState.permissions,
                newSize * sizeof(Permission));
        if (newList == NULL) {
            return -3;
        }
        gPermissionState.permissions = newList;
        gPermissionState.allocatedPermissionEntries = newSize;
    }

    Permission *p = &gPermissionState.permissions[
                        gPermissionState.numPermissionEntries];
    int i;
    for (i = 0; i < count; i++) {
        *p = set[i];
        //TODO: cache the strlen of the path
        //TODO: normalize; strip off trailing /
        p->path = strdup(p->path);
        if (p->path == NULL) {
            /* If we can't add all of the entries, we don't
             * add any of them.
             */
            Permission *pp = &gPermissionState.permissions[
                                gPermissionState.numPermissionEntries];
            while (pp != p) {
                free((void *)pp->path);
                pp++;
            }
            return -4;
        }
        p++;
    }
    gPermissionState.numPermissionEntries += count;

    return 0;
}