1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <alloca.h>
21: #include <assert.h>
22: #include <errno.h>
23: #include <error.h>
24: #include <libintl.h>
25: #include <netdb.h>
26: #include <stdbool.h>
27: #include <stddef.h>
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <string.h>
31: #include <time.h>
32: #include <unistd.h>
33: #include <arpa/inet.h>
34: #include <arpa/nameser.h>
35: #include <sys/mman.h>
36: #include <stackinfo.h>
37:
38: #include "nscd.h"
39: #include "dbg_log.h"
40: #ifdef HAVE_SENDFILE
41: # include <kernel-features.h>
42: #endif
43:
44:
45:
46: static const hst_response_header disabled =
47: {
48: .version = NSCD_VERSION,
49: .found = -1,
50: .h_name_len = 0,
51: .h_aliases_cnt = 0,
52: .h_addrtype = -1,
53: .h_length = -1,
54: .h_addr_list_cnt = 0,
55: .error = NETDB_INTERNAL
56: };
57:
58:
59: const struct iovec hst_iov_disabled =
60: {
61: .iov_base = (void *) &disabled,
62: .iov_len = sizeof (disabled)
63: };
64:
65:
66:
67: static const hst_response_header notfound =
68: {
69: .version = NSCD_VERSION,
70: .found = 0,
71: .h_name_len = 0,
72: .h_aliases_cnt = 0,
73: .h_addrtype = -1,
74: .h_length = -1,
75: .h_addr_list_cnt = 0,
76: .error = HOST_NOT_FOUND
77: };
78:
79:
80: static void
81: cache_addhst (struct database_dyn *db, int fd, request_header *req,
82: const void *key, struct hostent *hst, uid_t owner,
83: struct hashentry *he, struct datahead *dh, int errval)
84: {
85: ssize_t total;
86: ssize_t written;
87: time_t t = time (NULL);
88:
89:
90:
91: struct dataset
92: {
93: struct datahead head;
94: hst_response_header resp;
95: char strdata[0];
96: } *dataset;
97:
98: assert (offsetof (struct dataset, resp) == offsetof (struct datahead, data));
99:
100: if (hst == NULL)
101: {
102: if (he != NULL && errval == EAGAIN)
103: {
104:
105:
106:
107: if (reload_count != UINT_MAX)
108:
109: dh->nreloads = reload_count - 1;
110:
111: written = total = 0;
112: }
113: else
114: {
115:
116:
117: written = total = sizeof (notfound);
118:
119: if (fd != -1)
120: written = TEMP_FAILURE_RETRY (send (fd, ¬found, total,
121: MSG_NOSIGNAL));
122:
123: dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
124:
125: if (dataset != NULL)
126: {
127: dataset->head.allocsize = sizeof (struct dataset) + req->key_len;
128: dataset->head.recsize = total;
129: dataset->head.notfound = true;
130: dataset->head.nreloads = 0;
131: dataset->head.usable = true;
132:
133:
134: dataset->head.timeout = t + db->negtimeout;
135:
136:
137: memcpy (&dataset->resp, ¬found, total);
138:
139:
140: memcpy (dataset->strdata, key, req->key_len);
141:
142:
143: if (db->persistent)
144: {
145:
146: uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
147: msync ((void *) pval,
148: ((uintptr_t) dataset & pagesize_m1)
149: + sizeof (struct dataset) + req->key_len, MS_ASYNC);
150: }
151:
152:
153: pthread_rwlock_rdlock (&db->lock);
154:
155: if (cache_add (req->type, &dataset->strdata, req->key_len,
156: &dataset->head, true, db, owner) < 0)
157:
158: dataset->head.usable = false;
159:
160: pthread_rwlock_unlock (&db->lock);
161:
162:
163: if (dh != NULL)
164: dh->usable = false;
165: }
166: else
167: ++db->head->addfailed;
168: }
169: }
170: else
171: {
172:
173: size_t h_name_len = strlen (hst->h_name) + 1;
174: size_t h_aliases_cnt;
175: uint32_t *h_aliases_len;
176: size_t h_addr_list_cnt;
177: int addr_list_type;
178: char *addresses;
179: char *aliases;
180: char *key_copy = NULL;
181: char *cp;
182: size_t cnt;
183:
184:
185: h_aliases_cnt = 0;
186: for (cnt = 0; hst->h_aliases[cnt] != NULL; ++cnt)
187: ++h_aliases_cnt;
188:
189: h_aliases_len = (uint32_t *) alloca (h_aliases_cnt * sizeof (uint32_t));
190: total = 0;
191: for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
192: {
193: h_aliases_len[cnt] = strlen (hst->h_aliases[cnt]) + 1;
194: total += h_aliases_len[cnt];
195: }
196:
197:
198: h_addr_list_cnt = 0;
199: while (hst->h_addr_list[h_addr_list_cnt] != NULL)
200: ++h_addr_list_cnt;
201:
202: if (h_addr_list_cnt == 0)
203:
204: return;
205:
206: total += (sizeof (struct dataset)
207: + h_name_len
208: + h_aliases_cnt * sizeof (uint32_t)
209: + h_addr_list_cnt * hst->h_length);
210: written = total;
211:
212:
213:
214:
215:
216: bool alloca_used = false;
217: dataset = NULL;
218:
219:
220:
221:
222:
223:
224: if (he == NULL && h_addr_list_cnt == 1)
225: {
226: dataset = (struct dataset *) mempool_alloc (db,
227: total + req->key_len);
228: if (dataset == NULL)
229: ++db->head->addfailed;
230: }
231:
232: if (dataset == NULL)
233: {
234:
235:
236:
237: dataset = (struct dataset *) alloca (total + req->key_len);
238:
239:
240: alloca_used = true;
241: }
242:
243: dataset->head.allocsize = total + req->key_len;
244: dataset->head.recsize = total - offsetof (struct dataset, resp);
245: dataset->head.notfound = false;
246: dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
247: dataset->head.usable = true;
248:
249:
250: dataset->head.timeout = t + db->postimeout;
251:
252: dataset->resp.version = NSCD_VERSION;
253: dataset->resp.found = 1;
254: dataset->resp.h_name_len = h_name_len;
255: dataset->resp.h_aliases_cnt = h_aliases_cnt;
256: dataset->resp.h_addrtype = hst->h_addrtype;
257: dataset->resp.h_length = hst->h_length;
258: dataset->resp.h_addr_list_cnt = h_addr_list_cnt;
259: dataset->resp.error = NETDB_SUCCESS;
260:
261: cp = dataset->strdata;
262:
263: cp = mempcpy (cp, hst->h_name, h_name_len);
264: cp = mempcpy (cp, h_aliases_len, h_aliases_cnt * sizeof (uint32_t));
265:
266:
267: addresses = cp;
268: for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
269: cp = mempcpy (cp, hst->h_addr_list[cnt], hst->h_length);
270:
271:
272: aliases = cp;
273: for (cnt = 0; cnt < h_aliases_cnt; ++cnt)
274: cp = mempcpy (cp, hst->h_aliases[cnt], h_aliases_len[cnt]);
275:
276: assert (cp
277: == dataset->strdata + total - offsetof (struct dataset,
278: strdata));
279:
280:
281:
282:
283:
284:
285: key_copy = memcpy (cp, key, req->key_len);
286:
287:
288:
289: if (he != NULL)
290: {
291: assert (fd == -1);
292:
293: if (total + req->key_len == dh->allocsize
294: && total - offsetof (struct dataset, resp) == dh->recsize
295: && memcmp (&dataset->resp, dh->data,
296: dh->allocsize - offsetof (struct dataset, resp)) == 0)
297: {
298:
299:
300:
301: assert (h_addr_list_cnt == 1);
302: dh->timeout = dataset->head.timeout;
303: ++dh->nreloads;
304: }
305: else
306: {
307: if (h_addr_list_cnt == 1)
308: {
309:
310:
311: struct dataset *newp
312: = (struct dataset *) mempool_alloc (db,
313: total + req->key_len);
314: if (newp != NULL)
315: {
316:
317: addresses = (char *) newp + (addresses
318: - (char *) dataset);
319: aliases = (char *) newp + (aliases - (char *) dataset);
320: assert (key_copy != NULL);
321: key_copy = (char *) newp + (key_copy - (char *) dataset);
322:
323: dataset = memcpy (newp, dataset, total + req->key_len);
324: alloca_used = false;
325: }
326: }
327:
328:
329: dh->usable = false;
330: }
331: }
332: else
333: {
334:
335:
336:
337: assert (fd != -1);
338:
339: #ifdef HAVE_SENDFILE
340: if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
341: {
342: assert (db->wr_fd != -1);
343: assert ((char *) &dataset->resp > (char *) db->data);
344: assert ((char *) &dataset->resp - (char *) db->head
345: + total
346: <= (sizeof (struct database_pers_head)
347: + db->head->module * sizeof (ref_t)
348: + db->head->data_size));
349: written = sendfileall (fd, db->wr_fd,
350: (char *) &dataset->resp
351: - (char *) db->head, total);
352: # ifndef __ASSUME_SENDFILE
353: if (written == -1 && errno == ENOSYS)
354: goto use_write;
355: # endif
356: }
357: else
358: # ifndef __ASSUME_SENDFILE
359: use_write:
360: # endif
361: #endif
362: written = writeall (fd, &dataset->resp, total);
363: }
364:
365:
366:
367:
368:
369:
370:
371:
372:
373: if (! alloca_used)
374: {
375:
376: if (db->persistent)
377: {
378:
379: uintptr_t pval = (uintptr_t) dataset & ~pagesize_m1;
380: msync ((void *) pval,
381: ((uintptr_t) dataset & pagesize_m1)
382: + total + req->key_len, MS_ASYNC);
383: }
384:
385: addr_list_type = (hst->h_length == NS_INADDRSZ
386: ? GETHOSTBYADDR : GETHOSTBYADDRv6);
387:
388:
389: pthread_rwlock_rdlock (&db->lock);
390:
391:
392:
393:
394:
395:
396: assert (hst->h_addr_list[1] == NULL);
397:
398:
399:
400: assert (req->type == GETHOSTBYNAME
401: || req->type == GETHOSTBYNAMEv6
402: || req->type == GETHOSTBYADDR
403: || req->type == GETHOSTBYADDRv6);
404:
405: if (cache_add (req->type, key_copy, req->key_len,
406: &dataset->head, true, db, owner) < 0)
407:
408:
409: dataset->head.usable = false;
410:
411: pthread_rwlock_unlock (&db->lock);
412: }
413: }
414:
415: if (__builtin_expect (written != total, 0) && debug_level > 0)
416: {
417: char buf[256];
418: dbg_log (_("short write in %s: %s"), __FUNCTION__,
419: strerror_r (errno, buf, sizeof (buf)));
420: }
421: }
422:
423:
424: static int
425: lookup (int type, void *key, struct hostent *resultbufp, char *buffer,
426: size_t buflen, struct hostent **hst)
427: {
428: if (type == GETHOSTBYNAME)
429: return __gethostbyname2_r (key, AF_INET, resultbufp, buffer, buflen, hst,
430: &h_errno);
431: if (type == GETHOSTBYNAMEv6)
432: return __gethostbyname2_r (key, AF_INET6, resultbufp, buffer, buflen, hst,
433: &h_errno);
434: if (type == GETHOSTBYADDR)
435: return __gethostbyaddr_r (key, NS_INADDRSZ, AF_INET, resultbufp, buffer,
436: buflen, hst, &h_errno);
437: return __gethostbyaddr_r (key, NS_IN6ADDRSZ, AF_INET6, resultbufp, buffer,
438: buflen, hst, &h_errno);
439: }
440:
441:
442: static void
443: addhstbyX (struct database_dyn *db, int fd, request_header *req,
444: void *key, uid_t uid, struct hashentry *he, struct datahead *dh)
445: {
446:
447:
448:
449:
450: int buflen = 1024;
451: char *buffer = (char *) alloca (buflen);
452: struct hostent resultbuf;
453: struct hostent *hst;
454: bool use_malloc = false;
455: int errval = 0;
456:
457: if (__builtin_expect (debug_level > 0, 0))
458: {
459: const char *str;
460: char buf[INET6_ADDRSTRLEN + 1];
461: if (req->type == GETHOSTBYNAME || req->type == GETHOSTBYNAMEv6)
462: str = key;
463: else
464: str = inet_ntop (req->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
465: key, buf, sizeof (buf));
466:
467: if (he == NULL)
468: dbg_log (_("Haven't found \"%s\" in hosts cache!"), (char *) str);
469: else
470: dbg_log (_("Reloading \"%s\" in hosts cache!"), (char *) str);
471: }
472:
473: while (lookup (req->type, key, &resultbuf, buffer, buflen, &hst) != 0
474: && h_errno == NETDB_INTERNAL
475: && (errval = errno) == ERANGE)
476: {
477: errno = 0;
478:
479: if (__builtin_expect (buflen > 32768, 0))
480: {
481: char *old_buffer = buffer;
482: buflen *= 2;
483: buffer = (char *) realloc (use_malloc ? buffer : NULL, buflen);
484: if (buffer == NULL)
485: {
486:
487:
488:
489: hst = NULL;
490: buffer = old_buffer;
491:
492:
493:
494:
495: errval = EAGAIN;
496: break;
497: }
498: use_malloc = true;
499: }
500: else
501:
502:
503: buffer = (char *) extend_alloca (buffer, buflen, 2 * buflen);
504: }
505:
506: cache_addhst (db, fd, req, key, hst, uid, he, dh,
507: h_errno == TRY_AGAIN ? errval : 0);
508:
509: if (use_malloc)
510: free (buffer);
511: }
512:
513:
514: void
515: addhstbyname (struct database_dyn *db, int fd, request_header *req,
516: void *key, uid_t uid)
517: {
518: addhstbyX (db, fd, req, key, uid, NULL, NULL);
519: }
520:
521:
522: void
523: readdhstbyname (struct database_dyn *db, struct hashentry *he,
524: struct datahead *dh)
525: {
526: request_header req =
527: {
528: .type = GETHOSTBYNAME,
529: .key_len = he->len
530: };
531:
532: addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
533: }
534:
535:
536: void
537: addhstbyaddr (struct database_dyn *db, int fd, request_header *req,
538: void *key, uid_t uid)
539: {
540: addhstbyX (db, fd, req, key, uid, NULL, NULL);
541: }
542:
543:
544: void
545: readdhstbyaddr (struct database_dyn *db, struct hashentry *he,
546: struct datahead *dh)
547: {
548: request_header req =
549: {
550: .type = GETHOSTBYADDR,
551: .key_len = he->len
552: };
553:
554: addhstbyX (db, -1, &req, db->data + he->key, he->owner, he, dh);
555: }
556:
557:
558: void
559: addhstbynamev6 (struct database_dyn *db, int fd,