194 lines
3.6 KiB
C
194 lines
3.6 KiB
C
/*
|
|
* Implementation of the userspace SID hashtable.
|
|
*
|
|
* Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil>
|
|
*/
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "selinux_internal.h"
|
|
#include <selinux/avc.h>
|
|
#include "avc_sidtab.h"
|
|
#include "avc_internal.h"
|
|
|
|
static inline unsigned sidtab_hash(security_context_t key) {
|
|
char *p, *keyp;
|
|
unsigned int size;
|
|
unsigned int val;
|
|
|
|
val = 0;
|
|
keyp = (char*)key;
|
|
size = strlen(keyp);
|
|
for (p = keyp; (unsigned int)(p - keyp) < size; p++)
|
|
val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
|
|
return val & (SIDTAB_SIZE - 1);
|
|
}
|
|
|
|
int sidtab_init(struct sidtab *s)
|
|
{
|
|
int i, rc = 0;
|
|
|
|
s->htable = (struct sidtab_node **)avc_malloc
|
|
(sizeof(struct sidtab_node *) * SIDTAB_SIZE);
|
|
|
|
if (!s->htable) {
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
for (i = 0; i < SIDTAB_SIZE; i++)
|
|
s->htable[i] = NULL;
|
|
s->nel = 0;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
sidtab_insert(struct sidtab *s, security_context_t ctx)
|
|
{
|
|
int hvalue, rc = 0;
|
|
struct sidtab_node *newnode;
|
|
security_context_t newctx;
|
|
|
|
newnode = (struct sidtab_node*)avc_malloc(sizeof(*newnode));
|
|
if (!newnode) {
|
|
rc = -1;
|
|
goto out;
|
|
}
|
|
newctx = (security_context_t)strdup(ctx);
|
|
if (!newctx) {
|
|
rc = -1;
|
|
avc_free(newnode);
|
|
goto out;
|
|
}
|
|
|
|
hvalue = sidtab_hash(newctx);
|
|
newnode->next = s->htable[hvalue];
|
|
newnode->sid_s.ctx = newctx;
|
|
newnode->sid_s.refcnt = 0; /* caller should increment */
|
|
s->htable[hvalue] = newnode;
|
|
s->nel++;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
void
|
|
sidtab_remove(struct sidtab *s, security_id_t sid)
|
|
{
|
|
int hvalue;
|
|
struct sidtab_node *cur, *prev;
|
|
|
|
hvalue = sidtab_hash(sid->ctx);
|
|
cur = s->htable[hvalue];
|
|
prev = NULL;
|
|
while (cur) {
|
|
if (sid == &cur->sid_s) {
|
|
if (prev)
|
|
prev->next = cur->next;
|
|
else
|
|
s->htable[hvalue] = cur->next;
|
|
avc_free(cur);
|
|
s->nel--;
|
|
return;
|
|
} else {
|
|
prev = cur;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
security_id_t
|
|
sidtab_claim_sid(struct sidtab *s)
|
|
{
|
|
int i;
|
|
struct sidtab_node *cur;
|
|
|
|
for (i=0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur) {
|
|
if (!cur->sid_s.refcnt)
|
|
return &cur->sid_s;
|
|
cur = cur->next;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
sidtab_context_to_sid(struct sidtab *s,
|
|
security_context_t ctx,
|
|
security_id_t *sid)
|
|
{
|
|
int hvalue, rc = 0;
|
|
struct sidtab_node *cur;
|
|
|
|
*sid = NULL;
|
|
hvalue = sidtab_hash(ctx);
|
|
|
|
loop:
|
|
cur = s->htable[hvalue];
|
|
while (cur != NULL && strcmp(cur->sid_s.ctx, ctx))
|
|
cur = cur->next;
|
|
|
|
if (cur == NULL) { /* need to make a new entry */
|
|
rc = sidtab_insert(s, ctx);
|
|
if (rc)
|
|
goto out;
|
|
goto loop; /* find the newly inserted node */
|
|
}
|
|
|
|
*sid = &cur->sid_s;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen)
|
|
{
|
|
int i, chain_len, slots_used, max_chain_len;
|
|
struct sidtab_node *cur;
|
|
|
|
slots_used = 0;
|
|
max_chain_len = 0;
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = h->htable[i];
|
|
if (cur) {
|
|
slots_used++;
|
|
chain_len = 0;
|
|
while (cur) {
|
|
chain_len++;
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (chain_len > max_chain_len)
|
|
max_chain_len = chain_len;
|
|
}
|
|
}
|
|
|
|
snprintf(buf, buflen,
|
|
"%s: %d SID entries and %d/%d buckets used, longest "
|
|
"chain length %d\n", avc_prefix, h->nel, slots_used,
|
|
SIDTAB_SIZE, max_chain_len);
|
|
}
|
|
|
|
void sidtab_destroy(struct sidtab *s)
|
|
{
|
|
int i;
|
|
struct sidtab_node *cur, *temp;
|
|
|
|
if (!s)
|
|
return;
|
|
|
|
for (i = 0; i < SIDTAB_SIZE; i++) {
|
|
cur = s->htable[i];
|
|
while (cur != NULL) {
|
|
temp = cur;
|
|
cur = cur->next;
|
|
freecon(temp->sid_s.ctx);
|
|
avc_free(temp);
|
|
}
|
|
s->htable[i] = NULL;
|
|
}
|
|
avc_free(s->htable);
|
|
s->htable = NULL;
|
|
}
|