Home | History | Annotate | Download | only in src
      1 /*
      2  * Implementation of the userspace SID hashtable.
      3  *
      4  * Author : Eamon Walsh, <ewalsh (at) 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 
     16 static 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 
     31 int 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 
     49 int 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 
     77 int
     78 sidtab_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 
    104 void 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:  %u 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 
    132 void 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