1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: #include <assert.h>
20: #include <atomic.h>
21: #include <errno.h>
22: #include <error.h>
23: #include <inttypes.h>
24: #include <limits.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <libintl.h>
28: #include <arpa/inet.h>
29: #include <rpcsvc/nis.h>
30: #include <sys/mman.h>
31: #include <sys/param.h>
32: #include <sys/stat.h>
33: #include <sys/uio.h>
34:
35: #include "nscd.h"
36: #include "dbg_log.h"
37:
38:
39:
40:
41: unsigned int reload_count = DEFAULT_RELOAD_LIMIT;
42:
43:
44: static void (*const readdfcts[LASTREQ]) (struct database_dyn *,
45: struct hashentry *,
46: struct datahead *) =
47: {
48: [GETPWBYNAME] = readdpwbyname,
49: [GETPWBYUID] = readdpwbyuid,
50: [GETGRBYNAME] = readdgrbyname,
51: [GETGRBYGID] = readdgrbygid,
52: [GETHOSTBYNAME] = readdhstbyname,
53: [GETHOSTBYNAMEv6] = readdhstbynamev6,
54: [GETHOSTBYADDR] = readdhstbyaddr,
55: [GETHOSTBYADDRv6] = readdhstbyaddrv6,
56: [GETAI] = readdhstai,
57: [INITGROUPS] = readdinitgroups,
58: [GETSERVBYNAME] = readdservbyname,
59: [GETSERVBYPORT] = readdservbyport
60: };
61:
62:
63:
64:
65:
66:
67:
68: struct datahead *
69: cache_search (request_type type, void *key, size_t len,
70: struct database_dyn *table, uid_t owner)
71: {
72: unsigned long int hash = __nis_hash (key, len) % table->head->module;
73:
74: unsigned long int nsearched = 0;
75: struct datahead *result = NULL;
76:
77: ref_t work = table->head->array[hash];
78: while (work != ENDREF)
79: {
80: ++nsearched;
81:
82: struct hashentry *here = (struct hashentry *) (table->data + work);
83:
84: if (type == here->type && len == here->len
85: && memcmp (key, table->data + here->key, len) == 0
86: && here->owner == owner)
87: {
88:
89: struct datahead *dh
90: = (struct datahead *) (table->data + here->packet);
91:
92:
93: if (dh->usable)
94: {
95:
96:
97:
98: if (dh->notfound)
99: ++table->head->neghit;
100: else
101: {
102: ++table->head->poshit;
103:
104: if (dh->nreloads != 0)
105: dh->nreloads = 0;
106: }
107:
108: result = dh;
109: break;
110: }
111: }
112:
113: work = here->next;
114: }
115:
116: if (nsearched > table->head->maxnsearched)
117: table->head->maxnsearched = nsearched;
118:
119: return result;
120: }
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131: int
132: cache_add (int type, const void *key, size_t len, struct datahead *packet,
133: bool first, struct database_dyn *table,
134: uid_t owner)
135: {
136: if (__builtin_expect (debug_level >= 2, 0))
137: {
138: const char *str;
139: char buf[INET6_ADDRSTRLEN + 1];
140: if (type == GETHOSTBYADDR || type == GETHOSTBYADDRv6)
141: str = inet_ntop (type == GETHOSTBYADDR ? AF_INET : AF_INET6,
142: key, buf, sizeof (buf));
143: else
144: str = key;
145:
146: dbg_log (_("add new entry \"%s\" of type %s for %s to cache%s"),
147: str, serv2str[type], dbnames[table - dbs],
148: first ? _(" (first)") : "");
149: }
150:
151: unsigned long int hash = __nis_hash (key, len) % table->head->module;
152: struct hashentry *newp;
153:
154: newp = mempool_alloc (table, sizeof (struct hashentry));
155:
156: if (newp == NULL)
157: {
158: ++table->head->addfailed;
159: return -1;
160: }
161:
162: newp->type = type;
163: newp->first = first;
164: newp->len = len;
165: newp->key = (char *) key - table->data;
166: assert (newp->key + newp->len <= table->head->first_free);
167: newp->owner = owner;
168: newp->packet = (char *) packet - table->data;
169:
170:
171: do
172: newp->next = table->head->array[hash];
173: while (atomic_compare_and_exchange_bool_acq (&table->head->array[hash],
174: (ref_t) ((char *) newp
175: - table->data),
176: (ref_t) newp->next));
177:
178:
179: if (packet->notfound)
180: ++table->head->negmiss;
181: else if (first)
182: ++table->head->posmiss;
183:
184:
185:
186: atomic_increment (&table->head->nentries);
187:
188:
189:
190: unsigned long int nentries = table->head->nentries;
191: if (nentries > table->head->maxnentries)
192: table->head->maxnentries = nentries;
193:
194: if (table->persistent)
195:
196: msync ((void *) table->head,
197: (char *) &table->head->array[hash] - (char *) table->head
198: + sizeof (ref_t), MS_ASYNC);
199:
200: return 0;
201: }
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215: void
216: prune_cache (struct database_dyn *table, time_t now, int fd)
217: {
218: size_t cnt = table->head->module;
219:
220:
221: if (cnt == 0)
222: {
223: if (fd != -1)
224: {
225:
226: int32_t resp = 0;
227: writeall (fd, &resp, sizeof (resp));
228: }
229: return;
230: }
231:
232:
233:
234:
235:
236: if (fd == -1)
237: {
238: if (pthread_mutex_trylock (&table->prunelock) != 0)
239:
240: return;
241: }
242: else
243: pthread_mutex_lock (&table->prunelock);
244:
245:
246:
247: if (table->check_file)
248: {
249: struct stat64 st;
250:
251: if (stat64 (table->filename, &st) < 0)
252: {
253: char buf[128];
254:
255:
256: dbg_log (_("cannot stat() file `%s': %s"),
257: table->filename, strerror_r (errno, buf, sizeof (buf)));
258: if (errno == ENOENT)
259: table->check_file = 0;
260: }
261: else
262: {
263: if (st.st_mtime != table->file_mtime)
264: {
265:
266: now = LONG_MAX;
267: table->file_mtime = st.st_mtime;
268: }
269: }
270: }
271:
272:
273:
274:
275:
276:
277:
278: bool mark[cnt];
279: size_t first = cnt + 1;
280: size_t last = 0;
281: char *const data = table->data;
282: bool any = false;
283:
284: if (__builtin_expect (debug_level > 2, 0))
285: dbg_log (_("pruning %s cache; time %ld"),
286: dbnames[table - dbs], (long int) now);
287:
288: do
289: {
290: ref_t run = table->head->array[--cnt];
291:
292: while (run != ENDREF)
293: {
294: struct hashentry *runp = (struct hashentry *) (data + run);
295: struct datahead *dh = (struct datahead *) (data + runp->packet);
296:
297:
298: if (__builtin_expect (debug_level > 2, 0))
299: {
300: char buf[INET6_ADDRSTRLEN];
301: const char *str;
302:
303: if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
304: {
305: inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
306: data + runp->key, buf, sizeof (buf));
307: str = buf;
308: }
309: else
310: str = data + runp->key;
311:
312: dbg_log (_("considering %s entry \"%s\", timeout %" PRIu64),
313: serv2str[runp->type], str, dh->timeout);
314: }
315:
316:
317: if (dh->timeout < now)
318: {
319:
320:
321: mark[cnt] = true;
322:
323: first = MIN (first, cnt);
324: last = MAX (last, cnt);
325:
326:
327:
328:
329: if (runp->first)
330: {
331:
332:
333:
334:
335: if ((reload_count != UINT_MAX
336: && __builtin_expect (dh->nreloads >= reload_count, 0))
337:
338: || dh->notfound
339:
340:
341: || now == LONG_MAX)
342: {
343:
344: dh->usable = false;
345:
346:
347: any = true;
348: }
349: else
350: {
351:
352:
353:
354: assert (runp->type < LASTREQ
355: && readdfcts[runp->type] != NULL);
356:
357: readdfcts[runp->type] (table, runp, dh);
358:
359:
360:
361: any |= !dh->usable;
362: }
363: }
364: }
365: else
366: assert (dh->usable);
367:
368: run = runp->next;
369: }
370: }
371: while (cnt > 0);
372:
373: if (fd != -1)
374: {
375:
376:
377: int32_t resp = 0;
378: writeall (fd, &resp, sizeof (resp));
379: }
380:
381: if (first <= last)
382: {
383: struct hashentry *head = NULL;
384:
385:
386:
387: if (__builtin_expect (pthread_rwlock_trywrlock (&table->lock) != 0, 0))
388: {
389: ++table->head->wrlockdelayed;
390: pthread_rwlock_wrlock (&table->lock);
391: }
392:
393: while (first <= last)
394: {
395: if (mark[first])
396: {
397: ref_t *old = &table->head->array[first];
398: ref_t run = table->head->array[first];
399:
400: while (run != ENDREF)
401: {
402: struct hashentry *runp = (struct hashentry *) (data + run);
403: struct datahead *dh
404: = (struct datahead *) (data + runp->packet);
405:
406: if (! dh->usable)
407: {
408:
409:
410:
411: runp->dellist = head;
412: head = runp;
413:
414:
415:
416: --table->head->nentries;
417:
418: run = *old = runp->next;
419: }
420: else
421: {
422: old = &runp->next;
423: run = runp->next;
424: }
425: }
426: }
427:
428: ++first;
429: }
430:
431:
432: pthread_rwlock_unlock (&table->lock);
433:
434:
435: if (table->persistent)
436: msync (table->head,
437: data + table->head->first_free - (char *) table->head,
438: MS_ASYNC);
439:
440:
441: if (__builtin_expect (debug_level > 0, 0))
442: {
443: struct hashentry *runp = head;
444:
445: while (runp != NULL)
446: {
447: char buf[INET6_ADDRSTRLEN];
448: const char *str;
449:
450: if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
451: {
452: inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
453: data + runp->key, buf, sizeof (buf));
454: str = buf;
455: }
456: else
457: str = data + runp->key;
458:
459: dbg_log ("remove %s entry \"%s\"", serv2str[runp->type], str);
460:
461: runp = runp->dellist;
462: }
463: }
464: }
465:
466:
467: if (any)
468: gc (table);
469:
470: pthread_mutex_unlock (&table->prunelock);
471: }