271 lines
6.8 KiB
C
271 lines
6.8 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|