source: trunk/src/sh_static.c@ 581

Last change on this file since 581 was 570, checked in by katerina, 3 years ago

Fixes for some compile/cppcheck warnings, version 4.4.6.

File size: 50.1 KB
Line 
1/* Copyright (C) 2003 Manuel Novoa III
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Library General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
12 *
13 * You should have received a copy of the GNU Library General Public
14 * License along with this library; if not, write to the Free
15 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18/* Nov 6, 2003 Initial version.
19 *
20 * NOTE: This implementation is quite strict about requiring all
21 * field seperators. It also does not allow leading whitespace
22 * except when processing the numeric fields. glibc is more
23 * lenient. See the various glibc difference comments below.
24 *
25 * TODO:
26 * Move to dynamic allocation of (currently staticly allocated)
27 * buffers; especially for the group-related functions since
28 * large group member lists will cause error returns.
29 *
30 */
31
32/* Jul 20, 2004 Adapted for samhain. Rainer Wichmann.
33 *
34 * Stripped all unneeded code.
35 */
36
37#include "config_xor.h"
38
39#if defined(SH_COMPILE_STATIC) && defined(__linux__)
40
41#define _GNU_SOURCE
42#include <features.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <stdint.h>
46#include <string.h>
47#include <stddef.h>
48#include <errno.h>
49#include <assert.h>
50#include <ctype.h>
51#include <pwd.h>
52#include <grp.h>
53
54#include "sh_pthread.h"
55
56extern int sl_close_fd (const char * file, int line, int fd);
57extern int sl_fclose (const char * file, int line, FILE * fp);
58
59
60#ifndef _PATH_PASSWD
61#define _PATH_PASSWD "/etc/passwd"
62#endif
63#ifndef _PATH_GROUP
64#define _PATH_GROUP "/etc/group"
65#endif
66
67#undef FIL__
68#define FIL__ _("sh_static.c")
69
70extern int sl_strlcpy(char * dst, /*@null@*/const char * src, size_t siz);
71extern int sl_strlcat(char * dst, /*@null@*/const char * src, size_t siz);
72
73
74/**********************************************************************/
75/* Sizes for staticly allocated buffers. */
76
77#define PWD_BUFFER_SIZE 256
78#define GRP_BUFFER_SIZE 3584
79#define GRP_BUFFER_SIZE_MALLOC 32768
80
81/**********************************************************************/
82/* Prototypes for internal functions. */
83
84static int __parsepwent(void *pw, char *line);
85static int __parsegrent(void *gr, char *line);
86
87static int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
88 char *__restrict line_buff,
89 size_t buflen, FILE *f);
90
91#undef GETXXKEY_R_FUNC
92#undef GETXXKEY_R_PARSER
93#undef GETXXKEY_R_ENTTYPE
94#undef GETXXKEY_R_TEST
95#undef DO_GETXXKEY_R_KEYTYPE
96#undef DO_GETXXKEY_R_PATHNAME
97#define GETXXKEY_R_FUNC sh_getpwnam_r
98#define GETXXKEY_R_PARSER __parsepwent
99#define GETXXKEY_R_ENTTYPE struct passwd
100#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->pw_name, key))
101#define DO_GETXXKEY_R_KEYTYPE const char *__restrict
102#define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
103
104int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
105 GETXXKEY_R_ENTTYPE *__restrict resultbuf,
106 char *__restrict buffer, size_t buflen,
107 GETXXKEY_R_ENTTYPE **__restrict result)
108{
109 FILE *stream;
110 int rv;
111
112 *result = NULL;
113
114 if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
115 rv = errno;
116 } else {
117 /* __STDIO_SET_USER_LOCKING(stream); */
118 do {
119 if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
120 buffer, buflen, stream))
121 ) {
122 if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
123 *result = resultbuf;
124 break;
125 }
126 } else {
127 if (rv == ENOENT) { /* end-of-file encountered. */
128 rv = 0;
129 }
130 break;
131 }
132 } while (1);
133 sl_fclose(FIL__, __LINE__, stream);
134 }
135
136 return rv;
137}
138
139#undef GETXXKEY_R_FUNC
140#undef GETXXKEY_R_PARSER
141#undef GETXXKEY_R_ENTTYPE
142#undef GETXXKEY_R_TEST
143#undef DO_GETXXKEY_R_KEYTYPE
144#undef DO_GETXXKEY_R_PATHNAME
145#define GETXXKEY_R_FUNC sh_getgrnam_r
146#define GETXXKEY_R_PARSER __parsegrent
147#define GETXXKEY_R_ENTTYPE struct group
148#define GETXXKEY_R_TEST(ENT) (!strcmp((ENT)->gr_name, key))
149#define DO_GETXXKEY_R_KEYTYPE const char *__restrict
150#define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
151
152int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
153 GETXXKEY_R_ENTTYPE *__restrict resultbuf,
154 char *__restrict buffer, size_t buflen,
155 GETXXKEY_R_ENTTYPE **__restrict result)
156{
157 FILE *stream;
158 int rv;
159
160 *result = NULL;
161
162 if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
163 rv = errno;
164 } else {
165 /* __STDIO_SET_USER_LOCKING(stream); */
166 do {
167 if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
168 buffer, buflen, stream))
169 ) {
170 if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
171 *result = resultbuf;
172 break;
173 }
174 } else {
175 if (rv == ENOENT) { /* end-of-file encountered. */
176 rv = 0;
177 }
178 break;
179 }
180 } while (1);
181 sl_fclose(FIL__, __LINE__, stream);
182 }
183
184 return rv;
185}
186
187#undef GETXXKEY_R_FUNC
188#undef GETXXKEY_R_PARSER
189#undef GETXXKEY_R_ENTTYPE
190#undef GETXXKEY_R_TEST
191#undef DO_GETXXKEY_R_KEYTYPE
192#undef DO_GETXXKEY_R_PATHNAME
193#define GETXXKEY_R_FUNC sh_getpwuid_r
194#define GETXXKEY_R_PARSER __parsepwent
195#define GETXXKEY_R_ENTTYPE struct passwd
196#define GETXXKEY_R_TEST(ENT) ((ENT)->pw_uid == key)
197#define DO_GETXXKEY_R_KEYTYPE uid_t
198#define DO_GETXXKEY_R_PATHNAME _PATH_PASSWD
199
200int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
201 GETXXKEY_R_ENTTYPE *__restrict resultbuf,
202 char *__restrict buffer, size_t buflen,
203 GETXXKEY_R_ENTTYPE **__restrict result)
204{
205 FILE *stream;
206 int rv;
207
208 *result = NULL;
209
210 if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
211 rv = errno;
212 } else {
213 /* __STDIO_SET_USER_LOCKING(stream); */
214 do {
215 if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
216 buffer, buflen, stream))
217 ) {
218 if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
219 *result = resultbuf;
220 break;
221 }
222 } else {
223 if (rv == ENOENT) { /* end-of-file encountered. */
224 rv = 0;
225 }
226 break;
227 }
228 } while (1);
229 sl_fclose(FIL__, __LINE__, stream);
230 }
231
232 return rv;
233}
234
235#undef GETXXKEY_R_FUNC
236#undef GETXXKEY_R_PARSER
237#undef GETXXKEY_R_ENTTYPE
238#undef GETXXKEY_R_TEST
239#undef DO_GETXXKEY_R_KEYTYPE
240#undef DO_GETXXKEY_R_PATHNAME
241#define GETXXKEY_R_FUNC sh_getgrgid_r
242#define GETXXKEY_R_PARSER __parsegrent
243#define GETXXKEY_R_ENTTYPE struct group
244#define GETXXKEY_R_TEST(ENT) ((ENT)->gr_gid == key)
245#define DO_GETXXKEY_R_KEYTYPE gid_t
246#define DO_GETXXKEY_R_PATHNAME _PATH_GROUP
247
248int GETXXKEY_R_FUNC(DO_GETXXKEY_R_KEYTYPE key,
249 GETXXKEY_R_ENTTYPE *__restrict resultbuf,
250 char *__restrict buffer, size_t buflen,
251 GETXXKEY_R_ENTTYPE **__restrict result)
252{
253 FILE *stream;
254 int rv;
255
256 *result = NULL;
257
258 if (!(stream = fopen(DO_GETXXKEY_R_PATHNAME, "r"))) {
259 rv = errno;
260 } else {
261 /* __STDIO_SET_USER_LOCKING(stream); */
262 do {
263 if (!(rv = __pgsreader(GETXXKEY_R_PARSER, resultbuf,
264 buffer, buflen, stream))
265 ) {
266 if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */
267 *result = resultbuf;
268 break;
269 }
270 } else {
271 if (rv == ENOENT) { /* end-of-file encountered. */
272 rv = 0;
273 }
274 break;
275 }
276 } while (1);
277 sl_fclose(FIL__, __LINE__, stream);
278 }
279
280 return rv;
281}
282
283struct passwd * sh_getpwuid(uid_t uid)
284{
285 static char buffer[PWD_BUFFER_SIZE];
286 static struct passwd resultbuf;
287 struct passwd *result;
288
289 sh_getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
290 return result;
291}
292
293struct passwd * getpwuid(uid_t uid)
294{
295 return sh_getpwuid(uid);
296}
297
298struct group * sh_getgrgid(gid_t gid)
299{
300 static char buffer[GRP_BUFFER_SIZE];
301 static struct group resultbuf;
302 struct group *result;
303
304 sh_getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
305 return result;
306}
307
308struct group * getgrgid(gid_t gid)
309{
310 return sh_getgrgid(gid);
311}
312
313struct passwd * sh_getpwnam(const char *name)
314{
315 static char buffer[PWD_BUFFER_SIZE];
316 static struct passwd resultbuf;
317 struct passwd *result;
318
319 sh_getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
320 return result;
321}
322
323struct group * sh_getgrnam(const char *name)
324{
325 static char buffer[GRP_BUFFER_SIZE];
326 static struct group resultbuf;
327 struct group *result;
328
329 sh_getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
330 return result;
331}
332
333SH_MUTEX_STATIC(pwf_lock, PTHREAD_MUTEX_INITIALIZER);
334
335
336static FILE *pwf = NULL;
337
338void sh_setpwent(void)
339{
340 SH_MUTEX_LOCK(pwf_lock);
341 if (pwf) {
342 rewind(pwf);
343 }
344 SH_MUTEX_UNLOCK(pwf_lock);
345}
346
347void sh_endpwent(void)
348{
349 SH_MUTEX_LOCK(pwf_lock);
350 if (pwf) {
351 sl_fclose(FIL__, __LINE__, pwf);
352 pwf = NULL;
353 }
354 SH_MUTEX_UNLOCK(pwf_lock);
355}
356
357
358static int sh_getpwent_r(struct passwd *__restrict resultbuf,
359 char *__restrict buffer, size_t buflen,
360 struct passwd **__restrict result)
361{
362 int rv;
363
364 SH_MUTEX_LOCK(pwf_lock);
365
366 *result = NULL; /* In case of error... */
367
368 if (!pwf) {
369 if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
370 rv = errno;
371 goto ERR;
372 }
373 /* __STDIO_SET_USER_LOCKING(pwf); */
374 }
375
376 if (!(rv = __pgsreader(__parsepwent, resultbuf,
377 buffer, buflen, pwf))) {
378 *result = resultbuf;
379 }
380
381 ERR:
382 ; /* 'label at end of compound statement' */
383 SH_MUTEX_UNLOCK(pwf_lock);
384
385 return rv;
386}
387
388SH_MUTEX_STATIC(grf_lock, PTHREAD_MUTEX_INITIALIZER);
389
390static FILE *grf = NULL;
391
392void sh_setgrent(void)
393{
394 SH_MUTEX_LOCK(grf_lock);
395 if (grf) {
396 rewind(grf);
397 }
398 SH_MUTEX_UNLOCK(grf_lock);
399}
400
401void sh_endgrent(void)
402{
403 SH_MUTEX_LOCK(grf_lock);
404 if (grf) {
405 sl_fclose(FIL__, __LINE__, grf);
406 grf = NULL;
407 }
408 SH_MUTEX_UNLOCK(grf_lock);
409}
410
411static int sh_getgrent_r(struct group *__restrict resultbuf,
412 char *__restrict buffer, size_t buflen,
413 struct group **__restrict result)
414{
415 int rv;
416
417 SH_MUTEX_LOCK(grf_lock);
418
419 *result = NULL; /* In case of error... */
420
421 if (!grf) {
422 if (!(grf = fopen(_PATH_GROUP, "r"))) {
423 rv = errno;
424 goto ERR;
425 }
426 /* __STDIO_SET_USER_LOCKING(grf); */
427 }
428
429 if (!(rv = __pgsreader(__parsegrent, resultbuf,
430 buffer, buflen, grf))) {
431 *result = resultbuf;
432 }
433
434 ERR:
435 ; /* 'label at end of compound statement' */
436 SH_MUTEX_UNLOCK(grf_lock);
437
438 return rv;
439}
440
441
442struct passwd * sh_getpwent(void)
443{
444 static char line_buff[PWD_BUFFER_SIZE];
445 static struct passwd pwd;
446 struct passwd *result;
447
448 sh_getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
449 return result;
450}
451
452
453struct group * sh_getgrent(void)
454{
455 static char line_buff[GRP_BUFFER_SIZE];
456 static struct group gr;
457 struct group *result;
458
459 sh_getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
460 return result;
461}
462
463int sh_initgroups(const char *user, gid_t gid)
464{
465 FILE *grf;
466 gid_t *group_list = NULL;
467 size_t num_groups;
468 int rv;
469 char **m;
470 struct group group;
471
472 char * buff = calloc(1,GRP_BUFFER_SIZE_MALLOC);
473
474 rv = -1;
475
476 /* We alloc space for 8 gids at a time. */
477 if (buff && ((group_list = calloc(8,sizeof(gid_t *))) != NULL)
478 && ((grf = fopen(_PATH_GROUP, "r")) != NULL)
479 ) {
480
481 /* __STDIO_SET_USER_LOCKING(grf); */
482
483 *group_list = gid;
484 num_groups = 1;
485
486 while (!__pgsreader(__parsegrent, &group, buff, GRP_BUFFER_SIZE_MALLOC, grf)) {
487 assert(group.gr_mem); /* Must have at least a NULL terminator. */
488 if (group.gr_gid != gid) {
489 for (m=group.gr_mem ; *m ; m++) {
490 if (!strcmp(*m, user)) {
491 if (!(num_groups & 7)) {
492 gid_t *tmp = NULL;
493 if (num_groups > (SIZE_MAX - 8)) {
494 rv = -1;
495 goto DO_CLOSE;
496 }
497 if ((num_groups+8) <= (SIZE_MAX / sizeof(gid_t *))) {
498 tmp = (gid_t *)
499 realloc(group_list,
500 (num_groups+8) * sizeof(gid_t *));
501 }
502 if (!tmp) {
503 rv = -1;
504 goto DO_CLOSE;
505 }
506 group_list = tmp;
507 }
508 group_list[num_groups++] = group.gr_gid;
509 break;
510 }
511 }
512 }
513 }
514
515 rv = setgroups(num_groups, group_list);
516 DO_CLOSE:
517 sl_fclose(FIL__, __LINE__, grf);
518 }
519
520 /* group_list will be NULL if initial malloc failed, which may trigger
521 * warnings from various malloc debuggers. */
522 if (group_list) free(group_list);
523 if (buff) free(buff);
524 /* cppcheck-suppress resourceLeak */
525 return rv;
526}
527
528
529/**********************************************************************/
530/* Internal uClibc functions. */
531/**********************************************************************/
532
533static const unsigned char pw_off[] = {
534 offsetof(struct passwd, pw_name), /* 0 */
535 offsetof(struct passwd, pw_passwd), /* 1 */
536 offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
537 offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
538 offsetof(struct passwd, pw_gecos), /* 4 */
539 offsetof(struct passwd, pw_dir), /* 5 */
540 offsetof(struct passwd, pw_shell) /* 6 */
541};
542
543static int __parsepwent(void *data, char *line)
544{
545 char *endptr;
546 char *p;
547 int i;
548
549 i = 0;
550 do {
551 p = ((char *) ((struct passwd *) data)) + pw_off[i];
552
553 if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
554 *((char **) p) = line;
555 if (i==6) {
556 return 0;
557 }
558 /* NOTE: glibc difference - glibc allows omission of
559 * ':' seperators after the gid field if all remaining
560 * entries are empty. We require all separators. */
561 if (!(line = strchr(line, ':'))) {
562 break;
563 }
564 } else {
565 unsigned long t = strtoul(line, &endptr, 10);
566 /* Make sure we had at least one digit, and that the
567 * failing char is the next field seperator ':'. See
568 * glibc difference note above. */
569 /* TODO: Also check for leading whitespace? */
570 if ((endptr == line) || (*endptr != ':')) {
571 break;
572 }
573 line = endptr;
574 if (i & 1) { /* i == 3 -- gid */
575 *((gid_t *) p) = t;
576 } else { /* i == 2 -- uid */
577 *((uid_t *) p) = t;
578 }
579 }
580
581 *line++ = 0;
582 ++i;
583 } while (1);
584
585 return -1;
586}
587
588static const unsigned char gr_off[] = {
589 offsetof(struct group, gr_name), /* 0 */
590 offsetof(struct group, gr_passwd), /* 1 */
591 offsetof(struct group, gr_gid) /* 2 - not a char ptr */
592};
593
594static int __parsegrent(void *data, char *line)
595{
596 char *endptr;
597 char *p;
598 int i;
599 char **members;
600 char *end_of_buf;
601
602 end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
603 i = 0;
604 do {
605 p = ((char *) ((struct group *) data)) + gr_off[i];
606
607 if (i < 2) {
608 *((char **) p) = line;
609 if (!(line = strchr(line, ':'))) {
610 break;
611 }
612 *line++ = 0;
613 ++i;
614 } else {
615 *((gid_t *) p) = strtoul(line, &endptr, 10);
616
617 /* NOTE: glibc difference - glibc allows omission of the
618 * trailing colon when there is no member list. We treat
619 * this as an error. */
620
621 /* Make sure we had at least one digit, and that the
622 * failing char is the next field seperator ':'. See
623 * glibc difference note above. */
624 if ((endptr == line) || (*endptr != ':')) {
625 break;
626 }
627
628 i = 1; /* Count terminating NULL ptr. */
629 p = endptr;
630
631 if (p[1]) { /* We have a member list to process. */
632 /* Overwrite the last ':' with a ',' before counting.
633 * This allows us to test for initial ',' and adds
634 * one ',' so that the ',' count equals the member
635 * count. */
636 *p = ',';
637 do {
638 /* NOTE: glibc difference - glibc allows and trims leading
639 * (but not trailing) space. We treat this as an error. */
640 /* NOTE: glibc difference - glibc allows consecutive and
641 * trailing commas, and ignores "empty string" users. We
642 * treat this as an error. */
643 if (*p == ',') {
644 ++i;
645 *p = 0; /* nul-terminate each member string. */
646 if (!*++p || (*p == ',') || isspace(*p)) {
647 goto ERR;
648 }
649 }
650 } while (*++p);
651 }
652
653 /* Now align (p+1), rounding up. */
654 /* Assumes sizeof(char **) is a power of 2. */
655 members = (char **)( (((intptr_t) p) + sizeof(char **))
656 & ~((intptr_t)(sizeof(char **) - 1)) );
657
658 if (((char *)(members + i)) > end_of_buf) { /* No space. */
659 break;
660 }
661
662 ((struct group *) data)->gr_mem = members;
663
664 if (--i) {
665 p = endptr; /* Pointing to char prior to first member. */
666 do {
667 *members++ = ++p;
668 if (!--i) break;
669 while (*++p) {}
670 } while (1);
671 }
672 *members = NULL;
673
674 return 0;
675 }
676 } while (1);
677
678 ERR:
679 return -1;
680}
681
682/* Reads until if EOF, or until if finds a line which fits in the buffer
683 * and for which the parser function succeeds.
684 *
685 * Returns 0 on success and ENOENT for end-of-file (glibc concession).
686 */
687
688static int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
689 char *__restrict line_buff, size_t buflen, FILE *f)
690{
691 size_t line_len; /* int -> size_t R.W. */
692 int skip;
693 int rv = ERANGE;
694
695 if (buflen < PWD_BUFFER_SIZE) {
696 errno = rv;
697 } else {
698 /* __STDIO_THREADLOCK(f); */
699
700 skip = 0;
701 do {
702 if (!fgets(line_buff, buflen, f)) {
703 if (feof(f)) {
704 rv = ENOENT;
705 }
706 break;
707 }
708
709 line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
710 if (line_buff[line_len] == '\n') {
711 line_buff[line_len] = 0;
712 } else if (line_len + 2 == buflen) { /* line too long */
713 rv = ERANGE;
714 break;
715 /*
716 ++skip;
717 continue;
718 */
719 }
720
721 if (skip) {
722 --skip;
723 continue;
724 }
725
726 /* NOTE: glibc difference - glibc strips leading whitespace from
727 * records. We do not allow leading whitespace. */
728
729 /* Skip empty lines, comment lines, and lines with leading
730 * whitespace. */
731 if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
732 if (__parserfunc == __parsegrent) { /* Do evil group hack. */
733 /* The group entry parsing function needs to know where
734 * the end of the buffer is so that it can construct the
735 * group member ptr table. */
736 ((struct group *) data)->gr_name = line_buff + buflen;
737 }
738
739 if (!__parserfunc(data, line_buff)) {
740 rv = 0;
741 break;
742 }
743 }
744 } while (1);
745
746 /* __STDIO_THREADUNLOCK(f); */
747 }
748
749 return rv;
750}
751
752/* resolv.c: DNS Resolver
753 *
754 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
755 * The Silver Hammer Group, Ltd.
756 *
757 * This library is free software; you can redistribute it and/or
758 * modify it under the terms of the GNU Library General Public
759 * License as published by the Free Software Foundation; either
760 * version 2 of the License, or (at your option) any later version.
761*/
762
763/*
764 * Portions Copyright (c) 1985, 1993
765 * The Regents of the University of California. All rights reserved.
766 *
767 * Redistribution and use in source and binary forms, with or without
768 * modification, are permitted provided that the following conditions
769 * are met:
770 * 1. Redistributions of source code must retain the above copyright
771 * notice, this list of conditions and the following disclaimer.
772 * 2. Redistributions in binary form must reproduce the above copyright
773 * notice, this list of conditions and the following disclaimer in the
774 * documentation and/or other materials provided with the distribution.
775 * 4. Neither the name of the University nor the names of its contributors
776 * may be used to endorse or promote products derived from this software
777 * without specific prior written permission.
778 *
779 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
780 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
781 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
782 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
783 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
784 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
785 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
786 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
787 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
788 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
789 * SUCH DAMAGE.
790 */
791
792/*
793 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
794 *
795 * Permission to use, copy, modify, and distribute this software for any
796 * purpose with or without fee is hereby granted, provided that the above
797 * copyright notice and this permission notice appear in all copies, and that
798 * the name of Digital Equipment Corporation not be used in advertising or
799 * publicity pertaining to distribution of the document or software without
800 * specific, written prior permission.
801 *
802 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
803 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
804 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
805 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
806 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
807 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
808 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
809 * SOFTWARE.
810 */
811
812/*
813 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
814 *
815 * Permission to use, copy, modify, and distribute this software for any
816 * purpose with or without fee is hereby granted, provided that the above
817 * copyright notice and this permission notice appear in all copies.
818 *
819 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
820 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
821 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
822 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
823 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
824 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
825 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
826 * SOFTWARE.
827 */
828
829/*
830 *
831 * 5-Oct-2000 W. Greathouse wgreathouse@smva.com
832 * Fix memory leak and memory corruption.
833 * -- Every name resolution resulted in
834 * a new parse of resolv.conf and new
835 * copy of nameservers allocated by
836 * strdup.
837 * -- Every name resolution resulted in
838 * a new read of resolv.conf without
839 * resetting index from prior read...
840 * resulting in exceeding array bounds.
841 *
842 * Limit nameservers read from resolv.conf
843 *
844 * Add "search" domains from resolv.conf
845 *
846 * Some systems will return a security
847 * signature along with query answer for
848 * dynamic DNS entries.
849 * -- skip/ignore this answer
850 *
851 * Include arpa/nameser.h for defines.
852 *
853 * General cleanup
854 *
855 * 20-Jun-2001 Michal Moskal <malekith@pld.org.pl>
856 * partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
857 * functions added), IPv6 nameservers are also supported.
858 *
859 * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
860 * more IPv6 support (IPv6 support for gethostbyaddr();
861 * address family parameter and improved IPv6 support for get_hosts_byname
862 * and read_etc_hosts; getnameinfo() port from glibc; defined
863 * defined ip6addr_any and in6addr_loopback)
864 *
865 * 2-Feb-2002 Erik Andersen <andersee@debian.org>
866 * Added gethostent(), sethostent(), and endhostent()
867 *
868 * 17-Aug-2002 Manuel Novoa III <mjn3@codepoet.org>
869 * Fixed __read_etc_hosts_r to return alias list, and modified buffer
870 * allocation accordingly. See MAX_ALIASES and ALIAS_DIM below.
871 * This fixes the segfault in the Python 2.2.1 socket test.
872 *
873 * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
874 * Fixed __decode_dotted to count the terminating null character
875 * in a host name.
876 *
877 * 02-Oct-2003 Tony J. White <tjw@tjw.org>
878 * Lifted dn_expand() and dependent ns_name_uncompress(), ns_name_unpack(),
879 * and ns_name_ntop() from glibc 2.3.2 for compatibility with ipsec-tools
880 * and openldap.
881 *
882 */
883
884#include <sys/socket.h>
885#include <netinet/in.h>
886#include <arpa/inet.h>
887
888/* sl_close_fd(FIL__, __LINE__, )
889 */
890#include <unistd.h>
891
892/* 'struct hostent'
893 */
894#include <netdb.h>
895
896/* constanst like HFIXEDSZ
897 */
898#include <arpa/nameser.h>
899
900SH_MUTEX_STATIC(resolv_lock, PTHREAD_MUTEX_INITIALIZER);
901
902#define __UCLIBC_HAS_IPV6__
903#define MAX_RECURSE 5
904#define REPLY_TIMEOUT 10
905#define MAX_RETRIES 3
906#define MAX_SERVERS 3
907#define MAX_SEARCH 4
908#define MAX_ALIASES 5
909
910/* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
911#define ALIAS_DIM (2 + MAX_ALIASES + 1)
912
913static int __nameservers;
914static char * __nameserver[MAX_SERVERS];
915static int __searchdomains;
916static char * __searchdomain[MAX_SEARCH];
917
918#undef DEBUG
919/* #define DEBUG */
920
921#ifdef DEBUG
922/* flawfinder: ignore *//* definition of debug macro */
923#define DPRINTF(X,args...) fprintf(stderr, X, ##args)
924#else
925#define DPRINTF(X,args...)
926#endif /* DEBUG */
927
928struct resolv_header {
929 int id;
930 int qr,opcode,aa,tc,rd,ra,rcode;
931 int qdcount;
932 int ancount;
933 int nscount;
934 int arcount;
935};
936
937struct resolv_question {
938 char * dotted;
939 int qtype;
940 int qclass;
941};
942
943struct resolv_answer {
944 char * dotted;
945 int atype;
946 int aclass;
947 int ttl;
948 int rdlength;
949 unsigned char * rdata;
950 int rdoffset;
951};
952
953enum etc_hosts_action {
954 GET_HOSTS_BYNAME = 0,
955 GETHOSTENT,
956 GET_HOSTS_BYADDR,
957};
958
959static int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
960{
961 if (maxlen < HFIXEDSZ)
962 return -1;
963
964 dest[0] = (h->id & 0xff00) >> 8;
965 dest[1] = (h->id & 0x00ff) >> 0;
966 dest[2] = (h->qr ? 0x80 : 0) |
967 ((h->opcode & 0x0f) << 3) |
968 (h->aa ? 0x04 : 0) |
969 (h->tc ? 0x02 : 0) |
970 (h->rd ? 0x01 : 0);
971 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
972 dest[4] = (h->qdcount & 0xff00) >> 8;
973 dest[5] = (h->qdcount & 0x00ff) >> 0;
974 dest[6] = (h->ancount & 0xff00) >> 8;
975 dest[7] = (h->ancount & 0x00ff) >> 0;
976 dest[8] = (h->nscount & 0xff00) >> 8;
977 dest[9] = (h->nscount & 0x00ff) >> 0;
978 dest[10] = (h->arcount & 0xff00) >> 8;
979 dest[11] = (h->arcount & 0x00ff) >> 0;
980
981 return HFIXEDSZ;
982}
983
984static int __decode_header(unsigned char *data, struct resolv_header *h)
985{
986 h->id = (data[0] << 8) | data[1];
987 h->qr = (data[2] & 0x80) ? 1 : 0;
988 h->opcode = (data[2] >> 3) & 0x0f;
989 h->aa = (data[2] & 0x04) ? 1 : 0;
990 h->tc = (data[2] & 0x02) ? 1 : 0;
991 h->rd = (data[2] & 0x01) ? 1 : 0;
992 h->ra = (data[3] & 0x80) ? 1 : 0;
993 h->rcode = data[3] & 0x0f;
994 h->qdcount = (data[4] << 8) | data[5];
995 h->ancount = (data[6] << 8) | data[7];
996 h->nscount = (data[8] << 8) | data[9];
997 h->arcount = (data[10] << 8) | data[11];
998
999 return HFIXEDSZ;
1000}
1001
1002static int __length_dotted(const unsigned char *data, int offset)
1003{
1004 int orig_offset = offset;
1005 int l;
1006
1007 if (!data)
1008 return -1;
1009
1010 do {
1011 l = data[offset];
1012 if (offset < INT_MAX)
1013 offset++;
1014 else
1015 return -1;
1016 if (!l)
1017 break;
1018
1019 DPRINTF("l[%d] = %d\n", offset, l);
1020
1021 if ((l & 0xc0) == (0xc0)) {
1022 if (offset < INT_MAX)
1023 offset++;
1024 else
1025 return -1;
1026 break;
1027 }
1028
1029 if (offset <= (INT_MAX - l))
1030 offset += l;
1031 else
1032 return -1;
1033
1034 } while (l);
1035
1036 DPRINTF("orig: %d now %d\n", orig_offset, offset);
1037 return offset - orig_offset;
1038}
1039
1040static int __length_question(unsigned char *message, int offset)
1041{
1042 int i;
1043
1044 i = __length_dotted(message, offset);
1045 if (i < 0)
1046 return i;
1047 if (i < (INT_MAX - 4))
1048 return i + 4;
1049 else
1050 return -1;
1051}
1052
1053/* Decode a dotted string from nameserver transport-level encoding.
1054 This routine understands compressed data. */
1055
1056static int __decode_dotted(const unsigned char *data, int offset,
1057 char *dest, int maxlen)
1058{
1059 int l;
1060 int measure = 1;
1061 int total = 0;
1062 int used = 0;
1063
1064 if (!data)
1065 return -1;
1066 if ((offset < 0) || (offset > (PACKETSZ-1)))
1067 return -1;
1068 while ((l=data[offset])) {
1069 if (offset < (PACKETSZ-1)) offset++;
1070 else return -1;
1071 if (measure)
1072 { if (total < INT_MAX) total++; else return -1; }
1073 if ((l & 0xc0) == (0xc0)) {
1074 if (measure)
1075 { if (total < INT_MAX) total++; else return -1; }
1076 /* compressed item, redirect */
1077 offset = ((l & 0x3f) << 8) | data[offset];
1078 if ((offset < 0) || (offset > (PACKETSZ-1)))
1079 return -1;
1080 measure = 0;
1081 continue;
1082 }
1083
1084 if (used >= (INT_MAX - l))
1085 return -1;
1086
1087 if ((used + l + 1) >= maxlen)
1088 return -1;
1089
1090 memcpy(dest + used, data + offset, l);
1091
1092 if (offset <= ((PACKETSZ-1) - l))
1093 offset += l;
1094 else
1095 return -1;
1096
1097 if (used <= (INT_MAX - l))
1098 used += l;
1099 else
1100 return -1;
1101 if (measure)
1102 { if (total <= (INT_MAX -l)) total += l; else return -1; }
1103
1104 if (used >= maxlen)
1105 return -1;
1106 if (data[offset] != 0)
1107 dest[used++] = '.';
1108 else
1109 dest[used++] = '\0';
1110 }
1111
1112 /* The null byte must be counted too */
1113 if (measure) {
1114 if (total < INT_MAX) total++; else return -1;
1115 }
1116
1117 DPRINTF("Total decode len = %d\n", total);
1118
1119 return total;
1120}
1121
1122static int __decode_answer(unsigned char *message, int offset,
1123 struct resolv_answer *a)
1124{
1125 char temp[256];
1126 int i = 0;
1127
1128 i = __decode_dotted(message, offset, temp, sizeof(temp));
1129 if (i < 0 || i > PACKETSZ)
1130 return -1;
1131
1132 if (offset <= ((PACKETSZ - 10) - i))
1133 message += offset + i;
1134 else
1135 return -1;
1136
1137 a->dotted = strdup(temp);
1138 a->atype = (message[0] << 8) | message[1];
1139 message += 2;
1140 a->aclass = (message[0] << 8) | message[1];
1141 message += 2;
1142 a->ttl = (message[0] << 24) |
1143 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1144 message += 4;
1145 a->rdlength = (message[0] << 8) | message[1];
1146 message += 2;
1147 a->rdata = message;
1148 a->rdoffset = offset + i + RRFIXEDSZ;
1149
1150 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1151
1152 if (RRFIXEDSZ <= (INT_MAX - i))
1153 i += RRFIXEDSZ;
1154 else
1155 return -1;
1156 if (a->rdlength <= (INT_MAX - i))
1157 return i + a->rdlength;
1158 else
1159 return -1;
1160}
1161
1162
1163/* Encode a dotted string into nameserver transport-level encoding.
1164 This routine is fairly dumb, and doesn't attempt to compress
1165 the data */
1166
1167static int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
1168{
1169 unsigned int used = 0;
1170
1171 while (dotted && *dotted) {
1172 char *c = strchr(dotted, '.');
1173 unsigned int l = c ? (unsigned int)(c - dotted) : strlen(dotted);
1174
1175 if (l >= ((unsigned int)maxlen - used - 1))
1176 return -1;
1177
1178 dest[used++] = l;
1179 memcpy(dest + used, dotted, l);
1180 used += l;
1181
1182 if (c)
1183 dotted = c + 1;
1184 else
1185 break;
1186 }
1187
1188 if (maxlen < 1)
1189 return -1;
1190
1191 dest[used++] = 0;
1192
1193 return used;
1194}
1195
1196static int __encode_question(struct resolv_question *q,
1197 unsigned char *dest, int maxlen)
1198{
1199 int i;
1200
1201 i = __encode_dotted(q->dotted, dest, maxlen);
1202 if (i < 0)
1203 return i;
1204
1205 dest += i;
1206 if (maxlen < i)
1207 return -1;
1208 maxlen -= i;
1209
1210 if (maxlen < 4)
1211 return -1;
1212
1213 dest[0] = (q->qtype & 0xff00) >> 8;
1214 dest[1] = (q->qtype & 0x00ff) >> 0;
1215 dest[2] = (q->qclass & 0xff00) >> 8;
1216 dest[3] = (q->qclass & 0x00ff) >> 0;
1217
1218 if (i <= (INT_MAX - 4))
1219 return i + 4;
1220 else
1221 return -1;
1222}
1223
1224
1225/* Just for the record, having to lock __dns_lookup() just for these two globals
1226 * is pretty lame. I think these two variables can probably be de-global-ized,
1227 * which should eliminate the need for doing locking here... Needs a closer
1228 * look anyways. */
1229static int ns=0, id=1;
1230
1231static int __dns_lookup(const char *name, int type, int nscount, char **nsip,
1232 unsigned char **outpacket, struct resolv_answer *a)
1233{
1234 int i, j, len, fd, pos, rc;
1235 struct timeval tv;
1236 fd_set fds;
1237 struct resolv_header h;
1238 struct resolv_question q;
1239 int retries = 0;
1240 unsigned char * packet = calloc(1,PACKETSZ);
1241 char *dns, *lookup = calloc(1,MAXDNAME);
1242 int variant = 0;
1243 struct sockaddr_in sa;
1244#ifdef __UCLIBC_HAS_IPV6__
1245 int v6;
1246 struct sockaddr_in6 sa6;
1247#endif
1248
1249 fd = -1;
1250
1251 if (!packet || !lookup || !nscount)
1252 goto fail;
1253
1254 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1255
1256 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1257 ns %= nscount;
1258 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1259
1260 while (retries++ < MAX_RETRIES) {
1261 if (fd != -1)
1262 sl_close_fd(FIL__, __LINE__, fd);
1263
1264 memset(packet, 0, PACKETSZ);
1265
1266 memset(&h, 0, sizeof(h));
1267
1268 /* Mess with globals while under lock */
1269 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1270 ++id;
1271 id &= 0xffff;
1272 h.id = id;
1273 dns = nsip[ns];
1274 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1275
1276 h.qdcount = 1;
1277 h.rd = 1;
1278
1279 DPRINTF("encoding header %d\n", h.rd);
1280
1281 i = __encode_header(&h, packet, PACKETSZ);
1282 if (i < 0)
1283 goto fail;
1284
1285 sl_strlcpy(lookup,name,MAXDNAME);
1286 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1287 if (variant < __searchdomains && strchr(lookup, '.') == NULL)
1288 {
1289 sl_strlcat(lookup,".", MAXDNAME);
1290 sl_strlcat(lookup,__searchdomain[variant], MAXDNAME);
1291 }
1292 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1293 DPRINTF("lookup name: %s\n", lookup);
1294 q.dotted = (char *)lookup;
1295 q.qtype = type;
1296 q.qclass = C_IN; /* CLASS_IN */
1297
1298 j = __encode_question(&q, packet+i, PACKETSZ-i);
1299 if (j < 0)
1300 goto fail;
1301
1302 len = i + j;
1303
1304 DPRINTF("On try %d, sending query to port %d of machine %s\n",
1305 retries, NAMESERVER_PORT, dns);
1306
1307#ifdef __UCLIBC_HAS_IPV6__
1308 v6 = inet_pton(AF_INET6, dns, &sa6.sin6_addr) > 0;
1309 fd = socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1310#else
1311 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1312#endif
1313 if (fd < 0) {
1314 continue;
1315 }
1316
1317 /* Connect to the UDP socket so that asyncronous errors are returned */
1318#ifdef __UCLIBC_HAS_IPV6__
1319 if (v6) {
1320 sa6.sin6_family = AF_INET6;
1321 sa6.sin6_port = htons(NAMESERVER_PORT);
1322 /* sa6.sin6_addr is already here */
1323 rc = connect(fd, (struct sockaddr *) &sa6, sizeof(sa6));
1324 } else {
1325#endif
1326 sa.sin_family = AF_INET;
1327 sa.sin_port = htons(NAMESERVER_PORT);
1328 sa.sin_addr.s_addr = inet_addr(dns);
1329 rc = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
1330#ifdef __UCLIBC_HAS_IPV6__
1331 }
1332#endif
1333 if (rc < 0) {
1334 if (errno == ENETUNREACH) {
1335 /* routing error, presume not transient */
1336 goto tryall;
1337 } else
1338 /* retry */
1339 continue;
1340 }
1341
1342 DPRINTF("Transmitting packet of length %d, id=%d, qr=%d\n",
1343 len, h.id, h.qr);
1344
1345 send(fd, packet, len, 0);
1346
1347 FD_ZERO(&fds);
1348 FD_SET(fd, &fds);
1349 tv.tv_sec = REPLY_TIMEOUT;
1350 tv.tv_usec = 0;
1351 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1352 DPRINTF("Timeout\n");
1353
1354 /* timed out, so retry send and receive,
1355 * to next nameserver on queue */
1356 goto again;
1357 }
1358
1359 i = recv(fd, packet, 512, 0);
1360 if (i < HFIXEDSZ) {
1361 /* too short ! */
1362 goto again;
1363 }
1364
1365 /* ok because we have checked that recv at least HFIXEDSZ */
1366 __decode_header(packet, &h);
1367
1368 DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
1369
1370 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1371 if ((h.id != id) || (!h.qr)) {
1372 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1373 /* unsolicited */
1374 goto again;
1375 }
1376 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1377
1378
1379 DPRINTF("Got response %s\n", "(i think)!");
1380 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1381 h.qdcount, h.ancount, h.nscount, h.arcount);
1382 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1383 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1384
1385 if ((h.rcode) || (h.ancount < 1)) {
1386 /* negative result, not present */
1387 goto again;
1388 }
1389
1390 pos = HFIXEDSZ;
1391
1392 for (j = 0; j < h.qdcount; j++) {
1393 DPRINTF("Skipping question %d at %d\n", j, pos);
1394 i = __length_question(packet, pos);
1395 DPRINTF("Length of question %d is %d\n", j, i);
1396 if (i < 0)
1397 goto again;
1398 pos += i;
1399 if (pos >= PACKETSZ)
1400 goto again;
1401 }
1402 DPRINTF("Decoding answer at pos %d\n", pos);
1403
1404 for (j=0;j<h.ancount;j++)
1405 {
1406 i = __decode_answer(packet, pos, a);
1407
1408 if (i<0) {
1409 DPRINTF("failed decode %d\n", i);
1410 goto again;
1411 }
1412 /* For all but T_SIG, accept first answer */
1413 if (a->atype != T_SIG)
1414 break;
1415
1416 DPRINTF("skipping T_SIG %d\n", i);
1417 free(a->dotted);
1418 pos += i;
1419 if (pos >= PACKETSZ)
1420 goto again;
1421 }
1422
1423 DPRINTF("Answer name = |%s|\n", a->dotted);
1424 DPRINTF("Answer type = |%d|\n", a->atype);
1425
1426 sl_close_fd(FIL__, __LINE__, fd);
1427
1428 if (outpacket)
1429 *outpacket = packet;
1430 else
1431 free(packet);
1432 free(lookup);
1433 return (0); /* success! */
1434
1435 tryall:
1436 /* if there are other nameservers, give them a go,
1437 otherwise return with error */
1438 {
1439 int sdomains;
1440
1441 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1442 sdomains=__searchdomains;
1443 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1444 variant = 0;
1445 if (retries >= nscount*(sdomains+1))
1446 goto fail;
1447 }
1448
1449 again:
1450 /* if there are searchdomains, try them or fallback as passed */
1451 {
1452 int sdomains;
1453 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1454 sdomains=__searchdomains;
1455 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1456
1457 if (variant < sdomains) {
1458 /* next search */
1459 variant++;
1460 } else {
1461 /* next server, first search */
1462 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1463 ns = (ns + 1) % nscount;
1464 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1465 variant = 0;
1466 }
1467 }
1468 }
1469
1470fail:
1471 if (fd != -1)
1472 sl_close_fd(FIL__, __LINE__, fd);
1473 if (lookup)
1474 free(lookup);
1475 if (packet)
1476 free(packet);
1477 return -1;
1478}
1479
1480static void __open_etc_hosts(FILE **fp)
1481{
1482 if ((*fp = fopen("/etc/hosts", "r")) == NULL) {
1483 *fp = fopen("/etc/config/hosts", "r");
1484 }
1485 /* cppcheck-suppress resourceLeak */
1486 return;
1487}
1488
1489static int __read_etc_hosts_r(FILE * fp, const char * name, int type,
1490 enum etc_hosts_action action,
1491 struct hostent * result_buf,
1492 char * buf, size_t buflen,
1493 struct hostent ** result,
1494 int * h_errnop)
1495{
1496 struct in_addr *in=NULL;
1497 struct in_addr **addr_list=NULL;
1498#ifdef __UCLIBC_HAS_IPV6__
1499 struct in6_addr *in6=NULL;
1500 struct in6_addr **addr_list6=NULL;
1501#endif /* __UCLIBC_HAS_IPV6__ */
1502 char *cp;
1503 char **alias;
1504 int aliases, i;
1505 int ret=HOST_NOT_FOUND;
1506
1507 if (buflen < sizeof(char *)*(ALIAS_DIM))
1508 return ERANGE;
1509 alias=(char **)buf;
1510 buf+=sizeof(char **)*(ALIAS_DIM);
1511 buflen-=sizeof(char **)*(ALIAS_DIM);
1512
1513 if (action!=GETHOSTENT) {
1514#ifdef __UCLIBC_HAS_IPV6__
1515 char *p=buf;
1516 size_t len=buflen;
1517#endif /* __UCLIBC_HAS_IPV6__ */
1518 *h_errnop=NETDB_INTERNAL;
1519 if (buflen < sizeof(*in))
1520 return ERANGE;
1521 in=(struct in_addr*)buf;
1522 buf+=sizeof(*in);
1523 buflen-=sizeof(*in);
1524
1525 if (buflen < sizeof(*addr_list)*2)
1526 return ERANGE;
1527 addr_list=(struct in_addr **)buf;
1528 buf+=sizeof(*addr_list)*2;
1529 buflen-=sizeof(*addr_list)*2;
1530
1531#ifdef __UCLIBC_HAS_IPV6__
1532 if (len < sizeof(*in6))
1533 return ERANGE;
1534 in6=(struct in6_addr*)p;
1535 p+=sizeof(*in6);
1536 len-=sizeof(*in6);
1537
1538 if (len < sizeof(*addr_list6)*2)
1539 return ERANGE;
1540 addr_list6=(struct in6_addr**)p;
1541 p+=sizeof(*addr_list6)*2;
1542 len-=sizeof(*addr_list6)*2;
1543
1544 if (len < buflen) {
1545 buflen=len;
1546 buf=p;
1547 }
1548#endif /* __UCLIBC_HAS_IPV6__ */
1549
1550 if (buflen < 80)
1551 return ERANGE;
1552
1553 __open_etc_hosts(&fp);
1554 if (fp == NULL) {
1555 result=NULL;
1556 return errno;
1557 }
1558 }
1559
1560 *h_errnop=HOST_NOT_FOUND;
1561 if (fp == NULL) {
1562 return ret;
1563 }
1564 while (fgets(buf, buflen, fp)) {
1565 if ((cp = strchr(buf, '#')))
1566 *cp = '\0';
1567 DPRINTF("Looking at: %s\n", buf);
1568 aliases = 0;
1569
1570 cp = buf;
1571 while (*cp) {
1572 while (*cp && isspace(*cp))
1573 *cp++ = '\0';
1574 if (!*cp)
1575 continue;
1576 if (aliases < (2+MAX_ALIASES))
1577 alias[aliases++] = cp;
1578 while (*cp && !isspace(*cp))
1579 cp++;
1580 }
1581 alias[aliases] = 0;
1582
1583 if (aliases < 2)
1584 continue; /* syntax error really */
1585
1586 if (action==GETHOSTENT) {
1587 /* Return whatever the next entry happens to be. */
1588 break;
1589 } else if (action==GET_HOSTS_BYADDR) {
1590 if (strcmp(name, alias[0]) != 0)
1591 continue;
1592 } else {
1593 /* GET_HOSTS_BYNAME */
1594 for (i = 1; i < aliases; i++)
1595 if (strcasecmp(name, alias[i]) == 0)
1596 break;
1597 if (i >= aliases)
1598 continue;
1599 }
1600
1601 if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
1602 DPRINTF("Found INET\n");
1603 addr_list[0] = in;
1604 addr_list[1] = 0;
1605 result_buf->h_name = alias[1];
1606 result_buf->h_addrtype = AF_INET;
1607 result_buf->h_length = sizeof(*in);
1608 result_buf->h_addr_list = (char**) addr_list;
1609 result_buf->h_aliases = alias + 2;
1610 *result=result_buf;
1611 ret=NETDB_SUCCESS;
1612#ifdef __UCLIBC_HAS_IPV6__
1613 } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
1614 DPRINTF("Found INET6\n");
1615 addr_list6[0] = in6;
1616 addr_list6[1] = 0;
1617 result_buf->h_name = alias[1];
1618 result_buf->h_addrtype = AF_INET6;
1619 result_buf->h_length = sizeof(*in6);
1620 result_buf->h_addr_list = (char**) addr_list6;
1621 result_buf->h_aliases = alias + 2;
1622 *result=result_buf;
1623 ret=NETDB_SUCCESS;
1624#endif /* __UCLIBC_HAS_IPV6__ */
1625 } else {
1626 DPRINTF("Error\n");
1627 ret=TRY_AGAIN;
1628 break; /* bad ip address */
1629 }
1630
1631 if (action!=GETHOSTENT) {
1632 sl_fclose(FIL__, __LINE__, fp);
1633 }
1634 return ret;
1635 }
1636 if (action!=GETHOSTENT) {
1637 sl_fclose(FIL__, __LINE__, fp);
1638 }
1639 return ret;
1640}
1641
1642/*
1643 * we currently read formats not quite the same as that on normal
1644 * unix systems, we can have a list of nameservers after the keyword.
1645 */
1646int __get_hosts_byname_r(const char * name, int type,
1647 struct hostent * result_buf,
1648 char * buf, size_t buflen,
1649 struct hostent ** result,
1650 int * h_errnop)
1651{
1652 return(__read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME, result_buf, buf, buflen, result, h_errnop));
1653}
1654
1655static int __open_nameservers(void)
1656{
1657 FILE *fp;
1658 int i;
1659#define RESOLV_ARGS 5
1660 char szBuffer[128], *p, *argv[RESOLV_ARGS];
1661 int argc;
1662
1663 SH_MUTEX_LOCK(resolv_lock);
1664 if (__nameservers > 0) {
1665 goto the_end;
1666 }
1667
1668 if ((fp = fopen("/etc/resolv.conf", "r")) ||
1669 (fp = fopen("/etc/config/resolv.conf", "r"))) {
1670
1671 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
1672
1673 for (p = szBuffer; *p && isspace(*p); p++)
1674 /* skip white space */;
1675 if (*p == '\0' || *p == '\n' || *p == '#') /* skip comments etc */
1676 continue;
1677 argc = 0;
1678 while (*p && argc < RESOLV_ARGS) {
1679 argv[argc++] = p;
1680 while (*p && !isspace(*p) && *p != '\n')
1681 p++;
1682 while (*p && (isspace(*p) || *p == '\n')) /* remove spaces */
1683 *p++ = '\0';
1684 }
1685
1686 if (strcmp(argv[0], "nameserver") == 0) {
1687 for (i = 1; i < argc && __nameservers < MAX_SERVERS; i++) {
1688 __nameserver[__nameservers++] = strdup(argv[i]);
1689 DPRINTF("adding nameserver %s\n", argv[i]);
1690 }
1691 }
1692
1693 /* domain and search are mutually exclusive, the last one wins */
1694 if (strcmp(argv[0],"domain")==0 || strcmp(argv[0],"search")==0) {
1695 while (__searchdomains > 0) {
1696 free(__searchdomain[--__searchdomains]);
1697 __searchdomain[__searchdomains] = NULL;
1698 }
1699 for (i=1; i < argc && __searchdomains < MAX_SEARCH; i++) {
1700 __searchdomain[__searchdomains++] = strdup(argv[i]);
1701 DPRINTF("adding search %s\n", argv[i]);
1702 }
1703 }
1704 }
1705 sl_fclose(FIL__, __LINE__, fp);
1706 } else {
1707 DPRINTF("failed to open %s\n", "resolv.conf");
1708 }
1709 DPRINTF("nameservers = %d\n", __nameservers);
1710 the_end:
1711 ; /* 'label at end of compound statement' */
1712 SH_MUTEX_UNLOCK(resolv_lock);
1713 /* cppcheck-suppress resourceLeak */
1714 return 0;
1715}
1716
1717static int sh_gethostbyname_r(const char * name,
1718 struct hostent * result_buf,
1719 char * buf, size_t buflen,
1720 struct hostent ** result,
1721 int * h_errnop)
1722{
1723 struct in_addr *in;
1724 struct in_addr **addr_list;
1725 unsigned char *packet;
1726 struct resolv_answer a;
1727 int i;
1728 int nest = 0;
1729 int __nameserversXX;
1730 char ** __nameserverXX;
1731
1732 DPRINTF("sh_gethostbyname_r: /%s/\n", name);
1733 __open_nameservers();
1734
1735 *result=NULL;
1736 if (!name)
1737 return EINVAL;
1738
1739 /* do /etc/hosts first */
1740 if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
1741 buf, buflen, result, h_errnop))==0)
1742 return i;
1743 switch (*h_errnop) {
1744 case HOST_NOT_FOUND:
1745 case NO_ADDRESS:
1746 break;
1747 case NETDB_INTERNAL:
1748 if (errno == ENOENT) {
1749 break;
1750 }
1751 /* else fall through */
1752 default:
1753 return i;
1754 }
1755
1756 DPRINTF("Nothing found in /etc/hosts\n");
1757
1758 *h_errnop = NETDB_INTERNAL;
1759 if (buflen < sizeof(*in))
1760 return ERANGE;
1761 in=(struct in_addr*)buf;
1762 buf+=sizeof(*in);
1763 buflen-=sizeof(*in);
1764
1765 if (buflen < sizeof(*addr_list)*2)
1766 return ERANGE;
1767 addr_list=(struct in_addr**)buf;
1768 buf+=sizeof(*addr_list)*2;
1769 buflen-=sizeof(*addr_list)*2;
1770
1771 addr_list[0] = in;
1772 addr_list[1] = 0;
1773
1774 if (buflen<256)
1775 return ERANGE;
1776 strncpy(buf, name, buflen-1);
1777
1778 /* First check if this is already an address */
1779 if (inet_aton(name, in)) {
1780 result_buf->h_name = buf;
1781 result_buf->h_addrtype = AF_INET;
1782 result_buf->h_length = sizeof(*in);
1783 result_buf->h_addr_list = (char **) addr_list;
1784 *result=result_buf;
1785 *h_errnop = NETDB_SUCCESS;
1786 return NETDB_SUCCESS;
1787 }
1788
1789 for (;;) {
1790
1791 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
1792 __nameserversXX=__nameservers;
1793 __nameserverXX=__nameserver;
1794 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
1795 i = __dns_lookup(buf, T_A, __nameserversXX, __nameserverXX, &packet, &a);
1796
1797 if (i < 0) {
1798 *h_errnop = HOST_NOT_FOUND;
1799 DPRINTF("__dns_lookup\n");
1800 return TRY_AGAIN;
1801 }
1802
1803 strncpy(buf, a.dotted, buflen-1);
1804 free(a.dotted);
1805
1806 if (a.atype == T_CNAME) { /* CNAME */
1807 DPRINTF("Got a CNAME in gethostbyname()\n");
1808 i = __decode_dotted(packet, a.rdoffset, buf, buflen);
1809 free(packet);
1810
1811 if (i < 0) {
1812 *h_errnop = NO_RECOVERY;
1813 DPRINTF("__decode_dotted\n");
1814 return -1;
1815 }
1816 if (++nest > MAX_RECURSE) {
1817 *h_errnop = NO_RECOVERY;
1818 DPRINTF("recursion\n");
1819 return -1;
1820 }
1821 continue;
1822 } else if (a.atype == T_A) { /* ADDRESS */
1823 memcpy(in, a.rdata, sizeof(*in));
1824 result_buf->h_name = buf;
1825 result_buf->h_addrtype = AF_INET;
1826 result_buf->h_length = sizeof(*in);
1827 result_buf->h_addr_list = (char **) addr_list;
1828 free(packet);
1829 break;
1830 } else {
1831 free(packet);
1832 *h_errnop=HOST_NOT_FOUND;
1833 DPRINTF("host_not_found\n");
1834 return TRY_AGAIN;
1835 }
1836 }
1837
1838 *result=result_buf;
1839 *h_errnop = NETDB_SUCCESS;
1840 return NETDB_SUCCESS;
1841}
1842
1843struct hostent * sh_gethostbyname(const char *name)
1844{
1845 static struct hostent h;
1846 static char buf[sizeof(struct in_addr) +
1847 sizeof(struct in_addr *)*2 +
1848 sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */];
1849 struct hostent *hp;
1850
1851 DPRINTF("sh_gethostbyname: /%s/\n", name);
1852 sh_gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
1853 return hp;
1854}
1855
1856static int __get_hosts_byaddr_r(const char * addr, int len, int type,
1857 struct hostent * result_buf,
1858 char * buf, size_t buflen,
1859 struct hostent ** result,
1860 int * h_errnop)
1861{
1862#ifndef __UCLIBC_HAS_IPV6__
1863 char ipaddr[INET_ADDRSTRLEN];
1864#else
1865 char ipaddr[INET6_ADDRSTRLEN];
1866#endif /* __UCLIBC_HAS_IPV6__ */
1867
1868 switch (type) {
1869 case AF_INET:
1870 if (len != sizeof(struct in_addr))
1871 return 0;
1872 break;
1873#ifdef __UCLIBC_HAS_IPV6__
1874 case AF_INET6:
1875 if (len != sizeof(struct in6_addr))
1876 return 0;
1877 break;
1878#endif /* __UCLIBC_HAS_IPV6__ */
1879 default:
1880 return 0;
1881 }
1882
1883 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1884
1885 return(__read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1886 result_buf, buf, buflen, result, h_errnop));
1887}
1888
1889static int sh_gethostbyaddr_r (const void *addr, socklen_t len, int type,
1890 struct hostent * result_buf,
1891 char * buf, size_t buflen,
1892 struct hostent ** result,
1893 int * h_errnop)
1894
1895{
1896 struct in_addr *in;
1897 struct in_addr **addr_list;
1898#ifdef __UCLIBC_HAS_IPV6__
1899 char *qp;
1900 size_t plen;
1901 struct in6_addr *in6;
1902 struct in6_addr **addr_list6;
1903#endif /* __UCLIBC_HAS_IPV6__ */
1904 unsigned char *packet;
1905 struct resolv_answer a;
1906 int i;
1907 int nest = 0;
1908 int __nameserversXX;
1909 char ** __nameserverXX;
1910
1911 DPRINTF("sh_gethostbyaddr_r called\n");
1912 *result=NULL;
1913 if (!addr)
1914 return EINVAL;
1915
1916 switch (type) {
1917 case AF_INET:
1918 if (len != sizeof(struct in_addr))
1919 return EINVAL;
1920 break;
1921#ifdef __UCLIBC_HAS_IPV6__
1922 case AF_INET6:
1923 if (len != sizeof(struct in6_addr))
1924 return EINVAL;
1925 break;
1926#endif /* __UCLIBC_HAS_IPV6__ */
1927 default:
1928 return EINVAL;
1929 }
1930
1931 /* do /etc/hosts first */
1932 if ((i=__get_hosts_byaddr_r(addr, len, type, result_buf,
1933 buf, buflen, result, h_errnop))==0)
1934 return i;
1935 switch (*h_errnop) {
1936 case HOST_NOT_FOUND:
1937 case NO_ADDRESS:
1938 break;
1939 default:
1940 return i;
1941 }
1942
1943 __open_nameservers();
1944
1945#ifdef __UCLIBC_HAS_IPV6__
1946 qp=buf;
1947 plen=buflen;
1948#endif /* __UCLIBC_HAS_IPV6__ */
1949
1950 *h_errnop = NETDB_INTERNAL;
1951 if (buflen < sizeof(*in))
1952 return ERANGE;
1953 in=(struct in_addr*)buf;
1954 buf+=sizeof(*in);
1955 buflen-=sizeof(*in);
1956
1957 if (buflen < sizeof(*addr_list)*2)
1958 return ERANGE;
1959 addr_list=(struct in_addr**)buf;
1960 buf+=sizeof(*addr_list)*2;
1961 buflen-=sizeof(*addr_list)*2;
1962
1963#ifdef __UCLIBC_HAS_IPV6__
1964 if (plen < sizeof(*in6))
1965 return ERANGE;
1966 in6=(struct in6_addr*)qp;
1967 qp+=sizeof(*in6);
1968 plen-=sizeof(*in6);
1969
1970 if (plen < sizeof(*addr_list6)*2)
1971 return ERANGE;
1972 addr_list6=(struct in6_addr**)qp;
1973 qp+=sizeof(*addr_list6)*2;
1974 plen-=sizeof(*addr_list6)*2;
1975
1976 if (plen < buflen) {
1977 buflen=plen;
1978 buf=qp;
1979 }
1980#endif /* __UCLIBC_HAS_IPV6__ */
1981
1982 if (buflen<256)
1983 return ERANGE;
1984
1985 if(type == AF_INET) {
1986 const unsigned char *tmp_addr = (const unsigned char *)addr;
1987
1988 memcpy(&in->s_addr, addr, len);
1989
1990 addr_list[0] = in;
1991
1992 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
1993 tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
1994#ifdef __UCLIBC_HAS_IPV6__
1995 } else {
1996 memcpy(in6->s6_addr, addr, len);
1997
1998 addr_list6[0] = in6;
1999 qp = buf;
2000
2001 for (i = len - 1; i >= 0; i--) {
2002 qp += sprintf(qp, "%x.%x.", in6->s6_addr[i] & 0xf,
2003 (in6->s6_addr[i] >> 4) & 0xf);
2004 }
2005 strcpy(qp, "ip6.int");
2006#endif /* __UCLIBC_HAS_IPV6__ */
2007 }
2008
2009 addr_list[1] = 0;
2010
2011 for (;;) {
2012
2013 SH_MUTEX_LOCK_UNSAFE(resolv_lock);
2014 __nameserversXX=__nameservers;
2015 __nameserverXX=__nameserver;
2016 SH_MUTEX_UNLOCK_UNSAFE(resolv_lock);
2017 i = __dns_lookup(buf, T_PTR, __nameserversXX, __nameserverXX, &packet, &a);
2018
2019 if (i < 0) {
2020 *h_errnop = HOST_NOT_FOUND;
2021 return TRY_AGAIN;
2022 }
2023
2024 strncpy(buf, a.dotted, buflen-1);
2025 free(a.dotted);
2026
2027 if (a.atype == T_CNAME) { /* CNAME */
2028 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2029 i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2030 free(packet);
2031
2032 if (i < 0) {
2033 *h_errnop = NO_RECOVERY;
2034 return -1;
2035 }
2036 if (++nest > MAX_RECURSE) {
2037 *h_errnop = NO_RECOVERY;
2038 return -1;
2039 }
2040 continue;
2041 } else if (a.atype == T_PTR) { /* ADDRESS */
2042 i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2043 free(packet);
2044
2045 result_buf->h_name = buf;
2046 result_buf->h_addrtype = type;
2047
2048 if(type == AF_INET) {
2049 result_buf->h_length = sizeof(*in);
2050#ifdef __UCLIBC_HAS_IPV6__
2051 } else {
2052 result_buf->h_length = sizeof(*in6);
2053#endif /* __UCLIBC_HAS_IPV6__ */
2054 }
2055
2056 result_buf->h_addr_list = (char **) addr_list;
2057 break;
2058 } else {
2059 free(packet);
2060 *h_errnop = NO_ADDRESS;
2061 return TRY_AGAIN;
2062 }
2063 }
2064
2065 *result=result_buf;
2066 *h_errnop = NETDB_SUCCESS;
2067 return NETDB_SUCCESS;
2068}
2069
2070struct hostent * sh_gethostbyaddr (const void *addr, socklen_t len, int type)
2071{
2072 static struct hostent h;
2073 static char buf[
2074#ifndef __UCLIBC_HAS_IPV6__
2075 sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2076#else
2077 sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2078#endif /* __UCLIBC_HAS_IPV6__ */
2079 sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */];
2080 struct hostent *hp;
2081
2082 DPRINTF("sh_gethostbyaddr called\n");
2083 sh_gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
2084
2085 return hp;
2086}
2087
2088/* NEED_STATIC_LIBS */
2089#else
2090
2091/* include something to avoid empty compilation unit */
2092#include <stdio.h>
2093
2094#endif
2095
Note: See TracBrowser for help on using the repository browser.