blob: dab5c4ea125ab90633d74e74ace5f256dcfcf1b5 [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001/*
2 * Implementation of the userspace SID hashtable.
3 *
4 * Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil>
5 */
6#include <errno.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdint.h>
10#include <string.h>
11#include "selinux_internal.h"
12#include <selinux/avc.h>
13#include "avc_sidtab.h"
14#include "avc_internal.h"
15
16static inline unsigned sidtab_hash(security_context_t key)
17{
18 char *p, *keyp;
19 unsigned int size;
20 unsigned int val;
21
22 val = 0;
23 keyp = (char *)key;
24 size = strlen(keyp);
25 for (p = keyp; (unsigned int)(p - keyp) < size; p++)
26 val =
27 (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
28 return val & (SIDTAB_SIZE - 1);
29}
30
31int sidtab_init(struct sidtab *s)
32{
33 int i, rc = 0;
34
35 s->htable = (struct sidtab_node **)avc_malloc
36 (sizeof(struct sidtab_node *) * SIDTAB_SIZE);
37
38 if (!s->htable) {
39 rc = -1;
40 goto out;
41 }
42 for (i = 0; i < SIDTAB_SIZE; i++)
43 s->htable[i] = NULL;
44 s->nel = 0;
45 out:
46 return rc;
47}
48
49int sidtab_insert(struct sidtab *s, security_context_t ctx)
50{
51 int hvalue, rc = 0;
52 struct sidtab_node *newnode;
53 security_context_t newctx;
54
55 newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode));
56 if (!newnode) {
57 rc = -1;
58 goto out;
59 }
60 newctx = (security_context_t) strdup(ctx);
61 if (!newctx) {
62 rc = -1;
63 avc_free(newnode);
64 goto out;
65 }
66
67 hvalue = sidtab_hash(newctx);
68 newnode->next = s->htable[hvalue];
69 newnode->sid_s.ctx = newctx;
70 newnode->sid_s.refcnt = 0; /* caller should increment */
71 s->htable[hvalue] = newnode;
72 s->nel++;
73 out:
74 return rc;
75}
76
77void sidtab_remove(struct sidtab *s, security_id_t sid)
78{
79 int hvalue;
80 struct sidtab_node *cur, *prev;
81
82 hvalue = sidtab_hash(sid->ctx);
83 cur = s->htable[hvalue];
84 prev = NULL;
85 while (cur) {
86 if (sid == &cur->sid_s) {
87 if (prev)
88 prev->next = cur->next;
89 else
90 s->htable[hvalue] = cur->next;
91 avc_free(cur);
92 s->nel--;
93 return;
94 } else {
95 prev = cur;
96 cur = cur->next;
97 }
98 }
99}
100
101security_id_t sidtab_claim_sid(struct sidtab *s)
102{
103 int i;
104 struct sidtab_node *cur;
105
106 for (i = 0; i < SIDTAB_SIZE; i++) {
107 cur = s->htable[i];
108 while (cur) {
109 if (!cur->sid_s.refcnt)
110 return &cur->sid_s;
111 cur = cur->next;
112 }
113 }
114 return NULL;
115}
116
117int
118sidtab_context_to_sid(struct sidtab *s,
119 security_context_t ctx, security_id_t * sid)
120{
121 int hvalue, rc = 0;
122 struct sidtab_node *cur;
123
124 *sid = NULL;
125 hvalue = sidtab_hash(ctx);
126
127 loop:
128 cur = s->htable[hvalue];
129 while (cur != NULL && strcmp(cur->sid_s.ctx, ctx))
130 cur = cur->next;
131
132 if (cur == NULL) { /* need to make a new entry */
133 rc = sidtab_insert(s, ctx);
134 if (rc)
135 goto out;
136 goto loop; /* find the newly inserted node */
137 }
138
139 *sid = &cur->sid_s;
140 out:
141 return rc;
142}
143
144void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen)
145{
146 int i, chain_len, slots_used, max_chain_len;
147 struct sidtab_node *cur;
148
149 slots_used = 0;
150 max_chain_len = 0;
151 for (i = 0; i < SIDTAB_SIZE; i++) {
152 cur = h->htable[i];
153 if (cur) {
154 slots_used++;
155 chain_len = 0;
156 while (cur) {
157 chain_len++;
158 cur = cur->next;
159 }
160
161 if (chain_len > max_chain_len)
162 max_chain_len = chain_len;
163 }
164 }
165
166 snprintf(buf, buflen,
167 "%s: %d SID entries and %d/%d buckets used, longest "
168 "chain length %d\n", avc_prefix, h->nel, slots_used,
169 SIDTAB_SIZE, max_chain_len);
170}
171
172void sidtab_destroy(struct sidtab *s)
173{
174 int i;
175 struct sidtab_node *cur, *temp;
176
177 if (!s)
178 return;
179
180 for (i = 0; i < SIDTAB_SIZE; i++) {
181 cur = s->htable[i];
182 while (cur != NULL) {
183 temp = cur;
184 cur = cur->next;
185 freecon(temp->sid_s.ctx);
186 avc_free(temp);
187 }
188 s->htable[i] = NULL;
189 }
190 avc_free(s->htable);
191 s->htable = NULL;
192}