source: trunk/src/sh_static.c@ 19

Last change on this file since 19 was 1, checked in by katerina, 19 years ago

Initial import

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