1/* 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(const char * 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, const char * ctx) 50{ 51 int hvalue, rc = 0; 52 struct sidtab_node *newnode; 53 char * newctx; 54 55 newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode)); 56 if (!newnode) { 57 rc = -1; 58 goto out; 59 } 60 newctx = (char *) 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 = 1; /* unused */ 71 s->htable[hvalue] = newnode; 72 s->nel++; 73 out: 74 return rc; 75} 76 77int 78sidtab_context_to_sid(struct sidtab *s, 79 const char * ctx, security_id_t * sid) 80{ 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} 153