xref: /netbsd-src/usr.sbin/ypserv/revnetgroup/hash.c (revision d3d3aa621a23f4e4debf860217b2785d6947315c)
1*d3d3aa62Slukem /*	$NetBSD: hash.c,v 1.5 2009/04/19 06:06:40 lukem Exp $ */
27307c9a9Slukem 
342f1aa04Slukem /*
442f1aa04Slukem  * Copyright (c) 1995
542f1aa04Slukem  *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
642f1aa04Slukem  *
742f1aa04Slukem  * Redistribution and use in source and binary forms, with or without
842f1aa04Slukem  * modification, are permitted provided that the following conditions
942f1aa04Slukem  * are met:
1042f1aa04Slukem  * 1. Redistributions of source code must retain the above copyright
1142f1aa04Slukem  *    notice, this list of conditions and the following disclaimer.
1242f1aa04Slukem  * 2. Redistributions in binary form must reproduce the above copyright
1342f1aa04Slukem  *    notice, this list of conditions and the following disclaimer in the
1442f1aa04Slukem  *    documentation and/or other materials provided with the distribution.
1542f1aa04Slukem  * 3. All advertising materials mentioning features or use of this software
1642f1aa04Slukem  *    must display the following acknowledgement:
1742f1aa04Slukem  *	This product includes software developed by Bill Paul.
1842f1aa04Slukem  * 4. Neither the name of the author nor the names of any co-contributors
1942f1aa04Slukem  *    may be used to endorse or promote products derived from this software
2042f1aa04Slukem  *    without specific prior written permission.
2142f1aa04Slukem  *
2242f1aa04Slukem  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2342f1aa04Slukem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2442f1aa04Slukem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2542f1aa04Slukem  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
2642f1aa04Slukem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2742f1aa04Slukem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2842f1aa04Slukem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2942f1aa04Slukem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3042f1aa04Slukem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3142f1aa04Slukem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3242f1aa04Slukem  * SUCH DAMAGE.
3342f1aa04Slukem  *
3442f1aa04Slukem  */
3542f1aa04Slukem 
367307c9a9Slukem #include <sys/cdefs.h>
377307c9a9Slukem #ifndef lint
38*d3d3aa62Slukem __RCSID("$NetBSD: hash.c,v 1.5 2009/04/19 06:06:40 lukem Exp $");
397307c9a9Slukem #endif
407307c9a9Slukem 
417307c9a9Slukem #include <sys/types.h>
427307c9a9Slukem 
4342f1aa04Slukem #include <stdio.h>
4442f1aa04Slukem #include <stdlib.h>
4542f1aa04Slukem #include <string.h>
467307c9a9Slukem 
4742f1aa04Slukem #include "hash.h"
4842f1aa04Slukem 
493a0b8f6eSwiz u_int32_t	hash(const void *, size_t);
503a0b8f6eSwiz u_int32_t	hashkey(const char *);
517307c9a9Slukem 
5242f1aa04Slukem 
5342f1aa04Slukem /*
5442f1aa04Slukem  * This hash function is stolen directly from the
5542f1aa04Slukem  * Berkeley DB package. It already exists inside libc, but
5642f1aa04Slukem  * it's declared static which prevents us from calling it
5742f1aa04Slukem  * from here.
5842f1aa04Slukem  */
597307c9a9Slukem 
6042f1aa04Slukem /*
6142f1aa04Slukem  * OZ's original sdbm hash
6242f1aa04Slukem  */
6342f1aa04Slukem u_int32_t
hash(const void * keyarg,size_t len)643a0b8f6eSwiz hash(const void *keyarg, size_t len)
6542f1aa04Slukem {
667307c9a9Slukem 	const u_char *key;
677307c9a9Slukem 	size_t loop;
687307c9a9Slukem 	u_int32_t h;
6942f1aa04Slukem 
7042f1aa04Slukem #define HASHC   h = *key++ + 65599 * h
7142f1aa04Slukem 
7242f1aa04Slukem 	h = 0;
7342f1aa04Slukem 	key = keyarg;
7442f1aa04Slukem 	if (len > 0) {
7542f1aa04Slukem 		loop = (len + 8 - 1) >> 3;
7642f1aa04Slukem 
7742f1aa04Slukem 		switch (len & (8 - 1)) {
7842f1aa04Slukem 		case 0:
7942f1aa04Slukem 			do {
8042f1aa04Slukem 				HASHC;
8142f1aa04Slukem 				/* FALLTHROUGH */
8242f1aa04Slukem 		case 7:
8342f1aa04Slukem 				HASHC;
8442f1aa04Slukem 				/* FALLTHROUGH */
8542f1aa04Slukem 		case 6:
8642f1aa04Slukem 				HASHC;
8742f1aa04Slukem 				/* FALLTHROUGH */
8842f1aa04Slukem 		case 5:
8942f1aa04Slukem 				HASHC;
9042f1aa04Slukem 				/* FALLTHROUGH */
9142f1aa04Slukem 		case 4:
9242f1aa04Slukem 				HASHC;
9342f1aa04Slukem 				/* FALLTHROUGH */
9442f1aa04Slukem 		case 3:
9542f1aa04Slukem 				HASHC;
9642f1aa04Slukem 				/* FALLTHROUGH */
9742f1aa04Slukem 		case 2:
9842f1aa04Slukem 				HASHC;
9942f1aa04Slukem 				/* FALLTHROUGH */
10042f1aa04Slukem 		case 1:
10142f1aa04Slukem 				HASHC;
10242f1aa04Slukem 			} while (--loop);
10342f1aa04Slukem 		}
10442f1aa04Slukem 	}
10542f1aa04Slukem 	return (h);
10642f1aa04Slukem }
10742f1aa04Slukem 
10842f1aa04Slukem /*
10942f1aa04Slukem  * Generate a hash value for a given key (character string).
11042f1aa04Slukem  * We mask off all but the lower 8 bits since our table array
11142f1aa04Slukem  * can only hold 256 elements.
11242f1aa04Slukem  */
1137307c9a9Slukem u_int32_t
hashkey(const char * key)1143a0b8f6eSwiz hashkey(const char *key)
11542f1aa04Slukem {
11642f1aa04Slukem 
11742f1aa04Slukem 	if (key == NULL)
11842f1aa04Slukem 		return (-1);
119*d3d3aa62Slukem 	return(hash((const void *)key, strlen(key)) & HASH_MASK);
12042f1aa04Slukem }
12142f1aa04Slukem 
12242f1aa04Slukem /* Find an entry in the hash table (may be hanging off a linked list). */
1237307c9a9Slukem char *
lookup(struct group_entry ** table,const char * key)1243a0b8f6eSwiz lookup(struct group_entry **table, const char *key)
12542f1aa04Slukem {
12642f1aa04Slukem 	struct group_entry *cur;
12742f1aa04Slukem 
12842f1aa04Slukem 	cur = table[hashkey(key)];
12942f1aa04Slukem 
13042f1aa04Slukem 	while (cur) {
13142f1aa04Slukem 		if (!strcmp(cur->key, key))
13242f1aa04Slukem 			return(cur->data);
13342f1aa04Slukem 		cur = cur->next;
13442f1aa04Slukem 	}
13542f1aa04Slukem 
13642f1aa04Slukem 	return(NULL);
13742f1aa04Slukem }
13842f1aa04Slukem 
13942f1aa04Slukem /*
14042f1aa04Slukem  * Store an entry in the main netgroup hash table. Here's how this
14142f1aa04Slukem  * works: the table can only be so big when we initialize it (TABLESIZE)
14242f1aa04Slukem  * but the number of netgroups in the /etc/netgroup file could easily be
14342f1aa04Slukem  * much larger than the table. Since our hash values are adjusted to
14442f1aa04Slukem  * never be greater than TABLESIZE too, this means it won't be long before
14542f1aa04Slukem  * we find ourselves with two keys that hash to the same value.
14642f1aa04Slukem  *
14742f1aa04Slukem  * One way to deal with this is to malloc(2) a second table and start
14842f1aa04Slukem  * doing indirection, but this is a pain in the butt and it's not worth
14942f1aa04Slukem  * going to all that trouble for a dinky little program like this. Instead,
15042f1aa04Slukem  * we turn each table entry into a linked list and simply link keys
15142f1aa04Slukem  * with the same hash value together at the same index location within
15242f1aa04Slukem  * the table.
15342f1aa04Slukem  *
15442f1aa04Slukem  * That's a lot of comment for such a small piece of code, isn't it.
15542f1aa04Slukem  */
1567307c9a9Slukem void
store(struct group_entry * table[],const char * key,const char * data)1573a0b8f6eSwiz store(struct group_entry *table[], const char *key, const char *data)
15842f1aa04Slukem {
15942f1aa04Slukem 	struct group_entry *new;
16042f1aa04Slukem 	u_int32_t i;
16142f1aa04Slukem 
16242f1aa04Slukem 	i = hashkey(key);
16342f1aa04Slukem 
16442f1aa04Slukem 	new = (struct group_entry *)malloc(sizeof(struct group_entry));
16542f1aa04Slukem 	new->key = strdup(key);
16642f1aa04Slukem 	new->data = strdup(data);
16742f1aa04Slukem 	new->next = table[i];
16842f1aa04Slukem 	table[i] = new;
16942f1aa04Slukem 
17042f1aa04Slukem 	return;
17142f1aa04Slukem }
17242f1aa04Slukem 
17342f1aa04Slukem /*
17442f1aa04Slukem  * Store a group member entry and/or update its grouplist. This is
17542f1aa04Slukem  * a bit more complicated than the previous function since we have to
17642f1aa04Slukem  * maintain not only the hash table of group members, each group member
17742f1aa04Slukem  * structure also has a linked list of groups hung off it. If handed
17842f1aa04Slukem  * a member name that we haven't encountered before, we have to do
17942f1aa04Slukem  * two things: add that member to the table (possibly hanging them
18042f1aa04Slukem  * off the end of a linked list, as above), and add a group name to
18142f1aa04Slukem  * the member's grouplist list. If we're handed a name that already has
18242f1aa04Slukem  * an entry in the table, then we just have to do one thing, which is
18342f1aa04Slukem  * to update its grouplist.
18442f1aa04Slukem  */
1857307c9a9Slukem void
mstore(struct member_entry * table[],const char * key,const char * data,const char * domain)1863a0b8f6eSwiz mstore(struct member_entry *table[], const char *key, const char *data,
1873a0b8f6eSwiz        const char *domain)
18842f1aa04Slukem {
18942f1aa04Slukem 	struct member_entry *cur, *new;
19042f1aa04Slukem 	struct grouplist *tmp,*p;
19142f1aa04Slukem 	u_int32_t i;
19242f1aa04Slukem 
19342f1aa04Slukem 	i = hashkey(key);
19442f1aa04Slukem 	cur = table[i];
19542f1aa04Slukem 
19642f1aa04Slukem 	tmp = (struct grouplist *)malloc(sizeof(struct grouplist));
19742f1aa04Slukem 	tmp->groupname = strdup(data);
19842f1aa04Slukem 	tmp->next = NULL;
19942f1aa04Slukem 
20042f1aa04Slukem 	/* Check if all we have to do is insert a new groupname. */
20142f1aa04Slukem 	while (cur) {
20242f1aa04Slukem 		if (!strcmp(cur->key, key) && !strcmp(cur->domain,domain)) {
20342f1aa04Slukem 		  	p = cur->groups;
20442f1aa04Slukem 			while(p) {
205d6638342Sbouyer 				if (!strcmp(p->groupname,data)) {
206d6638342Sbouyer 					/* group already there */
207d6638342Sbouyer 					free(tmp);
20842f1aa04Slukem 					return;
209d6638342Sbouyer 				}
21042f1aa04Slukem 				p = p->next;
21142f1aa04Slukem 			}
21242f1aa04Slukem 			tmp->next = cur->groups;
21342f1aa04Slukem 			cur->groups = tmp;
21442f1aa04Slukem 			return;
21542f1aa04Slukem 		}
21642f1aa04Slukem 		cur = cur->next;
21742f1aa04Slukem 	}
21842f1aa04Slukem 
21942f1aa04Slukem 	/* Didn't find a match -- add the whole mess to the table. */
22042f1aa04Slukem 	new = (struct member_entry *)malloc(sizeof(struct member_entry));
22142f1aa04Slukem 	new->key = strdup(key);
22242f1aa04Slukem 	new->domain = strdup(domain);
22342f1aa04Slukem 	new->groups = tmp;
22442f1aa04Slukem 	new->next = table[i];
22542f1aa04Slukem 	table[i] = new;
22642f1aa04Slukem 
22742f1aa04Slukem 	return;
22842f1aa04Slukem }
229