From patchwork Tue Dec 27 15:49:25 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 709014 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tp0fy2mbPz9t0m for ; Wed, 28 Dec 2016 02:49:46 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="oWmvSJjy"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:to:subject:mime-version:content-type :content-transfer-encoding:message-id:from; q=dns; s=default; b= VYpA+oO1PbBoWxiBOkj0lcTa55l5FcaRTV/ePO6bBSVpSv+eRa77sv5cUwUqea7Q IjN1rKnpB+rRTU70NvM/Wy9Kw6nfeFYgZ7GgkKpNPS9XlkE6m6zOlcaZ9lMj9aUn otixik6rD75/eVRXS/dA1gj0qFBxDwBvUnptWmL47+E= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:date:to:subject:mime-version:content-type :content-transfer-encoding:message-id:from; s=default; bh=sJxahr KtVyzChvwKMcUe4cRhYNA=; b=oWmvSJjyc9fp0dNnYnCR4jFxGCMiqZagGVtLYE 2AyYYoceWS+KcEB+UJBWC7Gvxa5DBFXC/PDYaFCflVQhTPT9+keRhA+PEHxMT2JH lA19Ux/o5iuI9OS9tnya74JWHVP2MUTTKhq/vAH6CfjXQJNW0mRK05BCnugddxRs GBJOo= Received: (qmail 98926 invoked by alias); 27 Dec 2016 15:49:39 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 98914 invoked by uid 89); 27 Dec 2016 15:49:38 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-5.0 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=10025, herr, exports, UD:length X-HELO: mx1.redhat.com Date: Tue, 27 Dec 2016 16:49:25 +0100 To: libc-alpha@sourceware.org Subject: [PATCH COMMITTED] sunrpc: Always obtain AF_INET addresses from NSS [BZ #20964] User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Message-Id: <20161227154925.7D1F040277851@oldenburg.str.redhat.com> From: fweimer@redhat.com (Florian Weimer) The new __libc_rpc_gethostbyname function calls gethostbyname2_r with an AF_INET argument and is therefore not affected by the RES_USE_INET6 flag. Validated with the following test program, with and without RES_OPTIONS=inet6, against a NFS server. (Link with -lrpcsvc.) #include #include #include #include static void usage (char **argv) { printf ("usage:\n" " %1$s HOST getrpcport\n" " %1$s HOST callrpc\n" " %1$s HOST clnt_create\n", argv[0]); } static void dump_exports (struct exportnode *exports) { while (exports != NULL) { printf ("%s\n", exports->ex_dir); exports = exports->ex_next; } } int main (int argc, char **argv) { if (argc != 3) { usage (argv); return 1; } const char *host = argv[1]; const char *command = argv[2]; if (strcmp (command, "getrpcport") == 0) { int port = getrpcport (host, MOUNTPROG, MOUNTVERS, IPPROTO_UDP); printf ("getrpcport: %d\n", port); } else if (strcmp (command, "callrpc") == 0) { struct exportnode *exports = NULL; int ret = callrpc (host, MOUNTPROG, MOUNTVERS, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_exports, (char *)&exports); if (ret != 0) { clnt_perrno (ret); puts (""); return 1; } dump_exports (exports); } else if (strcmp (command, "clnt_create") == 0) { CLIENT *client = clnt_create (host, MOUNTPROG, MOUNTVERS, "udp"); if (client == NULL) { printf ("error: clnt_create failed\n"); return 1; } struct exportnode *exports = NULL; int ret = CLNT_CALL (client, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_exports, (char *)&exports, ((struct timeval) {15, 0})); if (ret != 0) { clnt_perrno (ret); puts (""); return 1; } dump_exports (exports); } else { usage (argv); return 1; } return 0; } 2016-12-27 Florian Weimer [BZ #20964] sunrpc: Always obtain AF_INET addresses from NSS. * include/rpc/rpc.h (__libc_rpc_gethostbyname): Declare. * sunrpc/rpc_gethostbyname.c: New file. * sunrpc/Makefile (routines): Add it. * sunrpc/clnt_gen.c (clnt_create): Use __libc_rpc_gethostbyname. * sunrpc/clnt_simp.c (callrpc): Likewise. * sunrpc/getrpcport.c (getrpcport): Likewise. diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h index 4c9ee82..60c7896 100644 --- a/include/rpc/rpc.h +++ b/include/rpc/rpc.h @@ -57,6 +57,12 @@ libc_hidden_proto (__rpc_thread_svc_pollfd) libc_hidden_proto (__rpc_thread_svc_fdset) libc_hidden_proto (__rpc_thread_createerr) +/* Perform a host name lookup for NAME and return the first IPv4 + address in *ADDR. Return 0 on success and -1 on error (and set an + RPC error). */ +int __libc_rpc_gethostbyname (const char *host, struct sockaddr_in *addr) + attribute_hidden; + #endif /* _RPC_THREAD_SAFE_ */ # endif /* !_ISOMAC */ diff --git a/sunrpc/Makefile b/sunrpc/Makefile index da6dffa..f7c593a 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -78,7 +78,8 @@ routines := auth_none authuxprot bindrsvprt clnt_raw clnt_simp \ des_crypt des_impl des_soft key_prot openchild rtime svcauth_des \ getrpcent getrpcbyname getrpcbynumber \ getrpcent_r getrpcbyname_r getrpcbynumber_r \ - clnt_unix svc_unix create_xid $(need-export-routines) + clnt_unix svc_unix create_xid $(need-export-routines) \ + rpc_gethostbyname ifneq ($(link-obsolete-rpc),yes) # We only add the RPC for compatibility to libc.so. shared-only-routines = $(routines) diff --git a/sunrpc/clnt_gen.c b/sunrpc/clnt_gen.c index df34672..8dffaa9 100644 --- a/sunrpc/clnt_gen.c +++ b/sunrpc/clnt_gen.c @@ -45,9 +45,6 @@ CLIENT * clnt_create (const char *hostname, u_long prog, u_long vers, const char *proto) { - struct hostent hostbuf, *h; - size_t hstbuflen; - char *hsttmpbuf; struct protoent protobuf, *p; size_t prtbuflen; char *prttmpbuf; @@ -56,7 +53,6 @@ clnt_create (const char *hostname, u_long prog, u_long vers, int sock; struct timeval tv; CLIENT *client; - int herr; if (strcmp (proto, "unix") == 0) { @@ -78,37 +74,8 @@ clnt_create (const char *hostname, u_long prog, u_long vers, return client; } - hstbuflen = 1024; - hsttmpbuf = __alloca (hstbuflen); - while (__gethostbyname_r (hostname, &hostbuf, hsttmpbuf, hstbuflen, - &h, &herr) != 0 - || h == NULL) - if (herr != NETDB_INTERNAL || errno != ERANGE) - { - get_rpc_createerr().cf_stat = RPC_UNKNOWNHOST; - return NULL; - } - else - { - /* Enlarge the buffer. */ - hstbuflen *= 2; - hsttmpbuf = __alloca (hstbuflen); - } - - if (h->h_addrtype != AF_INET) - { - /* - * Only support INET for now - */ - struct rpc_createerr *ce = &get_rpc_createerr (); - ce->cf_stat = RPC_SYSTEMERROR; - ce->cf_error.re_errno = EAFNOSUPPORT; - return NULL; - } - sin.sin_family = h->h_addrtype; - sin.sin_port = 0; - __bzero (sin.sin_zero, sizeof (sin.sin_zero)); - memcpy ((char *) &sin.sin_addr, h->h_addr, h->h_length); + if (__libc_rpc_gethostbyname (hostname, &sin) != 0) + return NULL; prtbuflen = 1024; prttmpbuf = __alloca (prtbuflen); diff --git a/sunrpc/clnt_simp.c b/sunrpc/clnt_simp.c index d612df0..0ecb64c 100644 --- a/sunrpc/clnt_simp.c +++ b/sunrpc/clnt_simp.c @@ -61,7 +61,6 @@ callrpc (const char *host, u_long prognum, u_long versnum, u_long procnum, struct callrpc_private_s *crp = callrpc_private; struct sockaddr_in server_addr; enum clnt_stat clnt_stat; - struct hostent hostbuf, *hp; struct timeval timeout, tottimeout; if (crp == 0) @@ -84,10 +83,6 @@ callrpc (const char *host, u_long prognum, u_long versnum, u_long procnum, } else { - size_t buflen; - char *buffer; - int herr; - crp->valid = 0; if (crp->socket != RPC_ANYSOCK) { @@ -100,25 +95,11 @@ callrpc (const char *host, u_long prognum, u_long versnum, u_long procnum, crp->client = NULL; } - buflen = 1024; - buffer = __alloca (buflen); - while (__gethostbyname_r (host, &hostbuf, buffer, buflen, - &hp, &herr) != 0 - || hp == NULL) - if (herr != NETDB_INTERNAL || errno != ERANGE) - return (int) RPC_UNKNOWNHOST; - else - { - /* Enlarge the buffer. */ - buflen *= 2; - buffer = __alloca (buflen); - } + if (__libc_rpc_gethostbyname (host, &server_addr) != 0) + return (int) get_rpc_createerr().cf_stat; timeout.tv_usec = 0; timeout.tv_sec = 5; - memcpy ((char *) &server_addr.sin_addr, hp->h_addr, hp->h_length); - server_addr.sin_family = AF_INET; - server_addr.sin_port = 0; if ((crp->client = clntudp_create (&server_addr, (u_long) prognum, (u_long) versnum, timeout, &crp->socket)) == NULL) return (int) get_rpc_createerr().cf_stat; diff --git a/sunrpc/getrpcport.c b/sunrpc/getrpcport.c index 07ee8c0..8fde0a9 100644 --- a/sunrpc/getrpcport.c +++ b/sunrpc/getrpcport.c @@ -1,3 +1,21 @@ +/* Obtain the RPC port number for an RPC service on a host. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + /* * Copyright (c) 2010, Oracle America, Inc. * @@ -43,26 +61,8 @@ int getrpcport (const char *host, u_long prognum, u_long versnum, u_int proto) { struct sockaddr_in addr; - struct hostent hostbuf, *hp; - size_t buflen; - char *buffer; - int herr; - buflen = 1024; - buffer = __alloca (buflen); - while (__gethostbyname_r (host, &hostbuf, buffer, buflen, &hp, &herr) != 0 - || hp == NULL) - if (herr != NETDB_INTERNAL || errno != ERANGE) - return 0; - else - { - /* Enlarge the buffer. */ - buflen *= 2; - buffer = __alloca (buflen); - } - - memcpy ((char *) &addr.sin_addr, hp->h_addr, hp->h_length); - addr.sin_family = AF_INET; - addr.sin_port = 0; + if (__libc_rpc_gethostbyname (host, &addr) != 0) + return 0; return pmap_getport (&addr, prognum, versnum, proto); } diff --git a/sunrpc/rpc_gethostbyname.c b/sunrpc/rpc_gethostbyname.c new file mode 100644 index 0000000..a2ee960 --- /dev/null +++ b/sunrpc/rpc_gethostbyname.c @@ -0,0 +1,73 @@ +/* IPv4-only variant of gethostbyname. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include +#include +#include + +int +__libc_rpc_gethostbyname (const char *host, struct sockaddr_in *addr) +{ + struct hostent hostbuf; + struct hostent *hp = NULL; + int herr; + struct scratch_buffer tmpbuf; + scratch_buffer_init (&tmpbuf); + + while (__gethostbyname2_r (host, AF_INET, + &hostbuf, tmpbuf.data, tmpbuf.length, &hp, + &herr) != 0 + || hp == NULL) + if (herr != NETDB_INTERNAL || errno != ERANGE) + { + struct rpc_createerr *ce = &get_rpc_createerr (); + ce->cf_stat = RPC_UNKNOWNHOST; + scratch_buffer_free (&tmpbuf); + return -1; + } + else + { + if (!scratch_buffer_grow (&tmpbuf)) + { + /* If memory allocation failed, allocating the RPC error + structure might could as well, so this could lead to a + crash. */ + struct rpc_createerr *ce = &get_rpc_createerr (); + ce->cf_stat = RPC_SYSTEMERROR; + ce->cf_error.re_errno = ENOMEM; + return -1; + } + } + + if (hp->h_addrtype != AF_INET || hp->h_length != sizeof (addr->sin_addr)) + { + struct rpc_createerr *ce = &get_rpc_createerr (); + ce->cf_stat = RPC_SYSTEMERROR; + ce->cf_error.re_errno = EAFNOSUPPORT; + scratch_buffer_free (&tmpbuf); + return -1; + } + + addr->sin_family = AF_INET; + addr->sin_port = htons (0); + memcpy (&addr->sin_addr, hp->h_addr, sizeof (addr->sin_addr)); + scratch_buffer_free (&tmpbuf); + return 0; +}