|
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 |
} |