blob: 52f21df8edb84d324d26a80b21f503643f35e0cb [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
Stephen Smalley9eb9c932014-02-19 09:16:17 -050016static inline unsigned sidtab_hash(const char * key)
Joshua Brindle13cd4c82008-08-19 15:30:36 -040017{
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
Stephen Smalley9eb9c932014-02-19 09:16:17 -050049int sidtab_insert(struct sidtab *s, const char * ctx)
Joshua Brindle13cd4c82008-08-19 15:30:36 -040050{
51 int hvalue, rc = 0;
52 struct sidtab_node *newnode;
Stephen Smalley9eb9c932014-02-19 09:16:17 -050053 char * newctx;
Joshua Brindle13cd4c82008-08-19 15:30:36 -040054
55 newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode));
56 if (!newnode) {
57 rc = -1;
58 goto out;
59 }
Stephen Smalley9eb9c932014-02-19 09:16:17 -050060 newctx = (char *) strdup(ctx);
Joshua Brindle13cd4c82008-08-19 15:30:36 -040061 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;
Eamon Walsh58866dd2009-09-02 17:41:22 -040070 newnode->sid_s.refcnt = 1; /* unused */
Joshua Brindle13cd4c82008-08-19 15:30:36 -040071 s->htable[hvalue] = newnode;
72 s->nel++;
73 out:
74 return rc;
75}
76
Joshua Brindle13cd4c82008-08-19 15:30:36 -040077int
78sidtab_context_to_sid(struct sidtab *s,
Stephen Smalley9eb9c932014-02-19 09:16:17 -050079 const char * ctx, security_id_t * sid)
Joshua Brindle13cd4c82008-08-19 15:30:36 -040080{
81 int hvalue, rc = 0;
82 struct sidtab_node *cur;
83
84 *sid = NULL;
85 hvalue = sidtab_hash(ctx);
86
87 loop:
88 cur = s->htable[hvalue];
89 while (cur != NULL && strcmp(cur->sid_s.ctx, ctx))
90 cur = cur->next;
91
92 if (cur == NULL) { /* need to make a new entry */
93 rc = sidtab_insert(s, ctx);
94 if (rc)
95 goto out;
96 goto loop; /* find the newly inserted node */
97 }
98
99 *sid = &cur->sid_s;
100 out:
101 return rc;
102}
103
104void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen)
105{
106 int i, chain_len, slots_used, max_chain_len;
107 struct sidtab_node *cur;
108
109 slots_used = 0;
110 max_chain_len = 0;
111 for (i = 0; i < SIDTAB_SIZE; i++) {
112 cur = h->htable[i];
113 if (cur) {
114 slots_used++;
115 chain_len = 0;
116 while (cur) {
117 chain_len++;
118 cur = cur->next;
119 }
120
121 if (chain_len > max_chain_len)
122 max_chain_len = chain_len;
123 }
124 }
125
126 snprintf(buf, buflen,
127 "%s: %d SID entries and %d/%d buckets used, longest "
128 "chain length %d\n", avc_prefix, h->nel, slots_used,
129 SIDTAB_SIZE, max_chain_len);
130}
131
132void sidtab_destroy(struct sidtab *s)
133{
134 int i;
135 struct sidtab_node *cur, *temp;
136
137 if (!s)
138 return;
139
140 for (i = 0; i < SIDTAB_SIZE; i++) {
141 cur = s->htable[i];
142 while (cur != NULL) {
143 temp = cur;
144 cur = cur->next;
145 freecon(temp->sid_s.ctx);
146 avc_free(temp);
147 }
148 s->htable[i] = NULL;
149 }
150 avc_free(s->htable);
151 s->htable = NULL;
152}