Lines 2721-2723
Link Here
|
2721 |
|
2721 |
|
2722 |
return -1; |
2722 |
return -1; |
2723 |
} |
2723 |
} |
|
|
2724 |
|
2725 |
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyname2_r); |
2726 |
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyaddr_r); |
2727 |
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_getaddrinfo); |
2728 |
|
2729 |
static ns_mtab methods[] = { |
2730 |
/* database, name, method, mdata */ |
2731 |
{ NSDB_HOSTS, "gethostbyaddr_r", __nss_bsdcompat_gethostbyaddr_r, NULL }, |
2732 |
{ NSDB_HOSTS, "gethostbyname2_r", __nss_bsdcompat_gethostbyname2_r, NULL }, |
2733 |
{ NSDB_HOSTS, "getaddrinfo", __nss_bsdcompat_getaddrinfo, NULL }, |
2734 |
}; |
2735 |
|
2736 |
/* |
2737 |
* The prototype for gethostbyaddr_r is: |
2738 |
* int gethostbyaddr_r(const void *addr, socklen_t len, int type, |
2739 |
* struct hostent *ret, char *buf, size_t buflen, |
2740 |
* struct hostent **result, int *h_errnop); |
2741 |
* |
2742 |
* nsdispatch calls gethostbyaddr_r as: |
2743 |
* rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS, |
2744 |
* "gethostbyaddr_r", default_src, uaddr, len, af, hp, buf, buflen, |
2745 |
* &ret_errno, h_errnop); |
2746 |
* which translates into us being (effectively) called as: |
2747 |
* rval = func(result, mdata, uaddr, len, type, ret, buf, buflen, &ret_errno, h_errnop) |
2748 |
* We turn result into a struct hostent **, set *result to NULL, and then |
2749 |
* call _nss_mdns_gethostbyaddr(). |
2750 |
*/ |
2751 |
static int |
2752 |
__nss_bsdcompat_gethostbyaddr_r(void *retval, void *mdata __unused, va_list ap) |
2753 |
{ |
2754 |
const void *addr; |
2755 |
socklen_t len; |
2756 |
int type; |
2757 |
struct hostent *ret; |
2758 |
char *buf; |
2759 |
size_t buflen; |
2760 |
struct hostent **result = (struct hostent**)retval; |
2761 |
int *ret_errno; |
2762 |
int *h_errnop; |
2763 |
enum nss_status status; |
2764 |
|
2765 |
addr = va_arg(ap, const void*); |
2766 |
len = va_arg(ap, int); |
2767 |
type = va_arg(ap, int); |
2768 |
ret = va_arg(ap, struct hostent *); |
2769 |
buf = va_arg(ap, char *); |
2770 |
buflen = va_arg(ap, size_t); |
2771 |
ret_errno = va_arg(ap, int *); |
2772 |
h_errnop = va_arg(ap, int *); |
2773 |
|
2774 |
*result = NULL; |
2775 |
status = _nss_mdns_gethostbyaddr_r(addr, len, type, ret, buf, buflen, ret_errno, h_errnop); |
2776 |
status = __nss_compat_result(status, *h_errnop); |
2777 |
if (status == NS_SUCCESS) |
2778 |
*result = ret; |
2779 |
|
2780 |
return (status); |
2781 |
} |
2782 |
|
2783 |
/* |
2784 |
* This is a lot of guesswork on my part. |
2785 |
* nsdispatch calls getaddrinfo as: |
2786 |
* |
2787 |
* _nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", |
2788 |
* default_dns_files, hostname, pai) |
2789 |
* |
2790 |
* which translates to us being (effectively) called as: |
2791 |
* rval = func(result, mdata, hostname, pai) |
2792 |
* The first argument, result, is struct addrinfo **. |
2793 |
* |
2794 |
*/ |
2795 |
|
2796 |
static struct addrinfo * |
2797 |
get_one_ai(const char *hostname, int af, const struct addrinfo *hints) |
2798 |
{ |
2799 |
nss_status lookup_status; |
2800 |
hostent hostent_buf; |
2801 |
char buf[1024] = { 0 }; |
2802 |
int err1, h_err1; |
2803 |
struct addrinfo *retval = NULL; |
2804 |
|
2805 |
memset(&hostent_buf, 0, sizeof(hostent_buf)); |
2806 |
lookup_status = mdns_gethostbyname2(hostname, |
2807 |
af, |
2808 |
&hostent_buf, |
2809 |
buf, |
2810 |
sizeof(buf), |
2811 |
&err1, |
2812 |
&h_err1); |
2813 |
lookup_status = __nss_compat_result(lookup_status, h_err1); |
2814 |
if (lookup_status == NS_SUCCESS) { |
2815 |
// Great, we found it, now what? |
2816 |
retval = calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); |
2817 |
if (retval) { |
2818 |
// Take advantage of c's scaling |
2819 |
retval->ai_addr = (struct sockaddr*)(retval + 1); |
2820 |
retval->ai_flags = hints->ai_flags; |
2821 |
retval->ai_socktype = hints->ai_socktype; |
2822 |
retval->ai_protocol = hints->ai_protocol; |
2823 |
retval->ai_family = hostent_buf.h_addrtype; |
2824 |
retval->ai_addrlen = hostent_buf.h_length; |
2825 |
retval->ai_addr->sa_len = hostent_buf.h_length; |
2826 |
retval->ai_addr->sa_family = retval->ai_family; |
2827 |
|
2828 |
if (retval->ai_family == PF_INET) { |
2829 |
struct sockaddr_in *sin = (void*)retval->ai_addr; |
2830 |
retval->ai_addrlen = sizeof(*sin); |
2831 |
memcpy(&sin->sin_addr, hostent_buf.h_addr, hostent_buf.h_length); |
2832 |
} else if (retval->ai_family == PF_INET6) { |
2833 |
struct sockaddr_in6 *sin = (void*)retval->ai_addr; |
2834 |
retval->ai_addrlen = sizeof(*sin); |
2835 |
memcpy(&sin->sin6_addr, hostent_buf.h_addr, hostent_buf.h_length); |
2836 |
} else { |
2837 |
retval->ai_addrlen = sizeof(struct sockaddr_storage); |
2838 |
memcpy(retval->ai_addr->sa_data, |
2839 |
hostent_buf.h_addr, |
2840 |
hostent_buf.h_length); |
2841 |
} |
2842 |
retval->ai_canonname = strdup(hostname); |
2843 |
#ifdef DEBUG |
2844 |
fprintf(stderr, "%s: ai_canonname = %s, ai_addrlen = %d\n", __FUNCTION__, retval->ai_canonname, (int)(retval->ai_addrlen)); |
2845 |
{ |
2846 |
char ascii[1024]; |
2847 |
void *sin_ptr; |
2848 |
|
2849 |
if (retval->ai_family == PF_INET) { |
2850 |
struct sockaddr_in *sin = (void*)retval->ai_addr; |
2851 |
sin_ptr = &sin->sin_addr; |
2852 |
} else if (retval->ai_family == PF_INET6) { |
2853 |
struct sockaddr_in6 *sin6 = (void*)retval->ai_addr; |
2854 |
sin_ptr = &sin6->sin6_addr; |
2855 |
} else { |
2856 |
sin_ptr = &retval->ai_addr; |
2857 |
} |
2858 |
if (inet_ntop(retval->ai_family, |
2859 |
sin_ptr, |
2860 |
ascii, |
2861 |
sizeof(ascii))) { |
2862 |
fprintf(stderr, "\tip = %s\n", ascii); |
2863 |
} else { |
2864 |
fprintf(stderr, "\tUnable to convert address to string\n"); |
2865 |
} |
2866 |
} |
2867 |
#endif |
2868 |
} |
2869 |
} |
2870 |
//#ifdef DEBUG |
2871 |
if (retval == NULL) |
2872 |
fprintf(stderr, "%s: returning %p, lookup_status = %d\n", __FUNCTION__, retval, lookup_status); |
2873 |
//#endif |
2874 |
return retval; |
2875 |
} |
2876 |
|
2877 |
#ifdef DEBUG |
2878 |
static void |
2879 |
PrintAddrinfo(struct addrinfo *ai) |
2880 |
{ |
2881 |
char buf[1024]; |
2882 |
void *sin_ptr; |
2883 |
if (ai == NULL) |
2884 |
return; |
2885 |
buf[0] = 0; |
2886 |
if (ai->ai_family == PF_INET) { |
2887 |
struct sockaddr_in *sin = (void*)ai->ai_addr; |
2888 |
sin_ptr = &sin->sin_addr; |
2889 |
} else if (ai->ai_family == PF_INET6) { |
2890 |
struct sockaddr_in6 *sin6 = (void*)ai->ai_addr; |
2891 |
sin_ptr = &sin6->sin6_addr; |
2892 |
} else { |
2893 |
sin_ptr = &ai->ai_addr; |
2894 |
} |
2895 |
inet_ntop(ai->ai_family, sin_ptr, buf, sizeof(buf)); |
2896 |
|
2897 |
fprintf(stderr, "struct addrinfo {\n"); |
2898 |
fprintf(stderr, "\tai_flags = %#x,\n", ai->ai_flags); |
2899 |
fprintf(stderr, "\tai_family = %d,\n", ai->ai_family); |
2900 |
fprintf(stderr, "\tai_socktype = %d,\n", ai->ai_socktype); |
2901 |
fprintf(stderr, "\tai_protocol = %d,\n", ai->ai_protocol); |
2902 |
fprintf(stderr, "\tai_addrlen = %d,\n", (int)ai->ai_addrlen); |
2903 |
fprintf(stderr, "\tai_addr = %s,\n", buf[0] ? buf : "(unknown?)"); |
2904 |
fprintf(stderr, "}\n"); |
2905 |
|
2906 |
} |
2907 |
#endif |
2908 |
|
2909 |
static int |
2910 |
__nss_bsdcompat_getaddrinfo(void *result, void *mdata __unused, va_list ap) |
2911 |
{ |
2912 |
const char *hostname; |
2913 |
const struct addrinfo *pai; |
2914 |
struct addrinfo **retval = (struct addrinfo **)result; |
2915 |
|
2916 |
hostname = va_arg(ap, const char *); |
2917 |
pai = va_arg(ap, const struct addrinfo *); |
2918 |
|
2919 |
*retval = NULL; |
2920 |
// Some quick error checking |
2921 |
if (hostname == NULL || pai == NULL) { |
2922 |
#ifdef DEBUG |
2923 |
fprintf(stderr, "%s(%d): Returning NS_UNAVAIL\n", __FUNCTION__, __LINE__); |
2924 |
#endif |
2925 |
return (NS_UNAVAIL); |
2926 |
} |
2927 |
|
2928 |
#ifdef DEBUG |
2929 |
{ |
2930 |
fprintf(stderr, |
2931 |
"%s: *retval = %p, hostname = %s, pai = { ai_flags = %#x, ai_family = %#x, ai_socktype = %#x, ai_protocol = %#x }\n", |
2932 |
__FUNCTION__, *retval, hostname, pai->ai_flags, pai->ai_family, pai->ai_socktype, pai->ai_protocol); |
2933 |
} |
2934 |
#endif |
2935 |
|
2936 |
/* |
2937 |
* We can do three kinds of searches: |
2938 |
* PF_UNSPEC: whichever kind we find |
2939 |
* PF_INET: An IPv4 address |
2940 |
* PF_INET6: An IPv6 address. |
2941 |
* We'll use mdns_gethostbyname2_r(), |
2942 |
* which will handle PF_INET or PF_INET6. |
2943 |
* Buf if we're given PF_UNSPEC we should try each in |
2944 |
* succession, I suppose? Or perhaps we're supposed to |
2945 |
* return both if we can? |
2946 |
*/ |
2947 |
switch (pai->ai_family) { |
2948 |
case PF_INET: |
2949 |
case PF_INET6: |
2950 |
*retval = get_one_ai(hostname, pai->ai_family, pai); |
2951 |
#ifdef DEBUG |
2952 |
fprintf(stderr, "Only needed one, *retval = %p\n", *retval); |
2953 |
#endif |
2954 |
break; |
2955 |
case PF_UNSPEC: |
2956 |
{ |
2957 |
// Do both! |
2958 |
struct addrinfo *ipv4, *ipv6; |
2959 |
struct addrinfo sentinel, *tmp = &sentinel; |
2960 |
memset(&sentinel, 0, sizeof(sentinel)); |
2961 |
if ((ipv6 = get_one_ai(hostname, PF_INET6, pai)) != NULL) { |
2962 |
tmp->ai_next = ipv6; |
2963 |
tmp = ipv6; |
2964 |
} |
2965 |
if ((ipv4 = get_one_ai(hostname, PF_INET, pai)) != NULL) { |
2966 |
tmp->ai_next = ipv4; |
2967 |
tmp = ipv4; |
2968 |
} |
2969 |
*retval = sentinel.ai_next; |
2970 |
} |
2971 |
break; |
2972 |
default: |
2973 |
#ifdef DEBUG |
2974 |
fprintf(stderr, "%s(%d): Returning NS_UNAVAIL\n", __FUNCTION__, __LINE__); |
2975 |
#endif |
2976 |
return (NS_UNAVAIL); |
2977 |
} |
2978 |
|
2979 |
if (*retval == NULL) { |
2980 |
#ifdef DEBUG |
2981 |
fprintf(stderr, "%s(%d): Returning NS_NOTFOUND\n", __FUNCTION__, __LINE__); |
2982 |
#endif |
2983 |
return (NS_NOTFOUND); |
2984 |
} |
2985 |
|
2986 |
#ifdef DEBUG |
2987 |
{ |
2988 |
fprintf(stderr, "%s: *retval = %p\n", __FUNCTION__, *retval); |
2989 |
} |
2990 |
struct addrinfo *tai; |
2991 |
for (tai = *retval; tai; tai = tai->ai_next) { |
2992 |
PrintAddrinfo(tai); |
2993 |
} |
2994 |
#endif |
2995 |
return (NS_SUCCESS); |
2996 |
} |
2997 |
|
2998 |
/* |
2999 |
* The prototype for gethostbyname2_r is |
3000 |
* gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer, |
3001 |
* size_t buflen, struct hostent **result, int *h_errnop) |
3002 |
* |
3003 |
* nsdispatch calls gethostbyname2_r as |
3004 |
* rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS, |
3005 |
* "gethostbyname2_r", default_src, name, af, hp, buf, buflen, |
3006 |
* &ret_errno, h_errnop); |
3007 |
* which translates into us being (effectively) called as: |
3008 |
* rval = func(result, mdata, name, af, hp, buf, buflen, &ret_errno, h_errnop) |
3009 |
* We turn result into a struct hostent **, set *result to NULL, and then |
3010 |
* call _nss_mdns_gethostbyname2_r() |
3011 |
*/ |
3012 |
static int |
3013 |
__nss_bsdcompat_gethostbyname2_r(void *retval, void *mdata __unused, |
3014 |
va_list ap) |
3015 |
{ |
3016 |
char *buf; |
3017 |
const char *name; |
3018 |
int *h_errnop; |
3019 |
struct hostent *hp; |
3020 |
struct hostent **resultp = (struct hostent **)retval; |
3021 |
int af; |
3022 |
size_t buflen; |
3023 |
int ret_errno; |
3024 |
enum nss_status status; |
3025 |
|
3026 |
name = va_arg(ap, char *); |
3027 |
af = va_arg(ap, int); |
3028 |
hp = va_arg(ap, struct hostent *); |
3029 |
buf = va_arg(ap, char *); |
3030 |
buflen = va_arg(ap, size_t); |
3031 |
ret_errno = va_arg(ap, int); |
3032 |
h_errnop = va_arg(ap, int *); |
3033 |
|
3034 |
if (hp == NULL) |
3035 |
return (NS_UNAVAIL); |
3036 |
|
3037 |
*resultp = NULL; |
3038 |
status = _nss_mdns_gethostbyname2_r(name, af, hp, buf, buflen, |
3039 |
&ret_errno, h_errnop); |
3040 |
|
3041 |
status = __nss_compat_result(status, *h_errnop); |
3042 |
if (status == NS_SUCCESS) |
3043 |
*resultp = hp; |
3044 |
return (status); |
3045 |
} |
3046 |
|
3047 |
ns_mtab * |
3048 |
nss_module_register(const char *source __unused, unsigned int *mtabsize, |
3049 |
nss_module_unregister_fn *unreg) |
3050 |
{ |
3051 |
#ifdef DEBUG |
3052 |
{ |
3053 |
fprintf(stderr, "%s(%s, %p, %p)\n", __FUNCTION__, source, mtabsize, unreg); |
3054 |
} |
3055 |
#endif |
3056 |
*mtabsize = sizeof(methods)/sizeof(methods[0]); |
3057 |
*unreg = NULL; |
3058 |
return (methods); |
3059 |
} |