1 /* $NetBSD: hash.c,v 1.2 1997/10/06 06:54:11 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1995 5 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __RCSID("$NetBSD: hash.c,v 1.2 1997/10/06 06:54:11 lukem Exp $"); 39 #endif 40 41 #include <sys/types.h> 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 #include "hash.h" 48 49 u_int32_t hash __P((const void *, size_t)); 50 u_int32_t hashkey __P((const char *)); 51 52 53 /* 54 * This hash function is stolen directly from the 55 * Berkeley DB package. It already exists inside libc, but 56 * it's declared static which prevents us from calling it 57 * from here. 58 */ 59 60 /* 61 * OZ's original sdbm hash 62 */ 63 u_int32_t 64 hash(keyarg, len) 65 const void *keyarg; 66 size_t len; 67 { 68 const u_char *key; 69 size_t loop; 70 u_int32_t h; 71 72 #define HASHC h = *key++ + 65599 * h 73 74 h = 0; 75 key = keyarg; 76 if (len > 0) { 77 loop = (len + 8 - 1) >> 3; 78 79 switch (len & (8 - 1)) { 80 case 0: 81 do { 82 HASHC; 83 /* FALLTHROUGH */ 84 case 7: 85 HASHC; 86 /* FALLTHROUGH */ 87 case 6: 88 HASHC; 89 /* FALLTHROUGH */ 90 case 5: 91 HASHC; 92 /* FALLTHROUGH */ 93 case 4: 94 HASHC; 95 /* FALLTHROUGH */ 96 case 3: 97 HASHC; 98 /* FALLTHROUGH */ 99 case 2: 100 HASHC; 101 /* FALLTHROUGH */ 102 case 1: 103 HASHC; 104 } while (--loop); 105 } 106 } 107 return (h); 108 } 109 110 /* 111 * Generate a hash value for a given key (character string). 112 * We mask off all but the lower 8 bits since our table array 113 * can only hold 256 elements. 114 */ 115 u_int32_t 116 hashkey(key) 117 const char *key; 118 { 119 120 if (key == NULL) 121 return (-1); 122 return(hash((void *)key, strlen(key)) & HASH_MASK); 123 } 124 125 /* Find an entry in the hash table (may be hanging off a linked list). */ 126 char * 127 lookup(table, key) 128 struct group_entry *table[]; 129 const char *key; 130 { 131 struct group_entry *cur; 132 133 cur = table[hashkey(key)]; 134 135 while (cur) { 136 if (!strcmp(cur->key, key)) 137 return(cur->data); 138 cur = cur->next; 139 } 140 141 return(NULL); 142 } 143 144 /* 145 * Store an entry in the main netgroup hash table. Here's how this 146 * works: the table can only be so big when we initialize it (TABLESIZE) 147 * but the number of netgroups in the /etc/netgroup file could easily be 148 * much larger than the table. Since our hash values are adjusted to 149 * never be greater than TABLESIZE too, this means it won't be long before 150 * we find ourselves with two keys that hash to the same value. 151 * 152 * One way to deal with this is to malloc(2) a second table and start 153 * doing indirection, but this is a pain in the butt and it's not worth 154 * going to all that trouble for a dinky little program like this. Instead, 155 * we turn each table entry into a linked list and simply link keys 156 * with the same hash value together at the same index location within 157 * the table. 158 * 159 * That's a lot of comment for such a small piece of code, isn't it. 160 */ 161 void 162 store(table, key, data) 163 struct group_entry *table[]; 164 const char *key, *data; 165 { 166 struct group_entry *new; 167 u_int32_t i; 168 169 i = hashkey(key); 170 171 new = (struct group_entry *)malloc(sizeof(struct group_entry)); 172 new->key = strdup(key); 173 new->data = strdup(data); 174 new->next = table[i]; 175 table[i] = new; 176 177 return; 178 } 179 180 /* 181 * Store a group member entry and/or update its grouplist. This is 182 * a bit more complicated than the previous function since we have to 183 * maintain not only the hash table of group members, each group member 184 * structure also has a linked list of groups hung off it. If handed 185 * a member name that we haven't encountered before, we have to do 186 * two things: add that member to the table (possibly hanging them 187 * off the end of a linked list, as above), and add a group name to 188 * the member's grouplist list. If we're handed a name that already has 189 * an entry in the table, then we just have to do one thing, which is 190 * to update its grouplist. 191 */ 192 void 193 mstore(table, key, data, domain) 194 struct member_entry *table[]; 195 const char *key, *data, *domain; 196 { 197 struct member_entry *cur, *new; 198 struct grouplist *tmp,*p; 199 u_int32_t i; 200 201 i = hashkey(key); 202 cur = table[i]; 203 204 tmp = (struct grouplist *)malloc(sizeof(struct grouplist)); 205 tmp->groupname = strdup(data); 206 tmp->next = NULL; 207 208 /* Check if all we have to do is insert a new groupname. */ 209 while (cur) { 210 if (!strcmp(cur->key, key) && !strcmp(cur->domain,domain)) { 211 p = cur->groups; 212 while(p) { 213 if (!strcmp(p->groupname,data)) 214 return; 215 p = p->next; 216 } 217 tmp->next = cur->groups; 218 cur->groups = tmp; 219 return; 220 } 221 cur = cur->next; 222 } 223 224 /* Didn't find a match -- add the whole mess to the table. */ 225 new = (struct member_entry *)malloc(sizeof(struct member_entry)); 226 new->key = strdup(key); 227 new->domain = strdup(domain); 228 new->groups = tmp; 229 new->next = table[i]; 230 table[i] = new; 231 232 return; 233 } 234