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