source: trunk/src/sh_static.c@ 328

Last change on this file since 328 was 252, checked in by katerina, 15 years ago

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

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