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