source: trunk/src/sh_static.c@ 222

Last change on this file since 222 was 170, checked in by katerina, 17 years ago

Plenty of compiler warnings fixed, SQL query length fixed, doc update.

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