source: trunk/src/sh_static.c@ 140

Last change on this file since 140 was 134, checked in by rainer, 17 years ago

More thread-safety changes.

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