From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18880 invoked by alias); 30 Mar 2004 21:30:59 -0000 Mailing-List: contact libc-hacker-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sources.redhat.com Received: (qmail 18860 invoked from network); 30 Mar 2004 21:30:58 -0000 Received: from unknown (HELO sunsite.ms.mff.cuni.cz) (195.113.15.26) by sources.redhat.com with SMTP; 30 Mar 2004 21:30:58 -0000 Received: from sunsite.ms.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8) with ESMTP id i2UJKsHS029055; Tue, 30 Mar 2004 21:20:54 +0200 Received: (from jakub@localhost) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8/Submit) id i2UJKsq3029053; Tue, 30 Mar 2004 21:20:54 +0200 Date: Wed, 31 Mar 2004 01:46:00 -0000 From: Jakub Jelinek To: Ulrich Drepper , Thorsten Kukuk Cc: Glibc hackers Subject: [PATCH] Fix NIS getservbyproto plus another performance tweak for NULL protocol Message-ID: <20040330192054.GB514@sunsite.ms.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2004-03/txt/msg00146.txt.bz2 Hi! POSIX says getservbyproto's first argument is in network byte order. Unfortunately _nss_nis_getservbyproto_r forget to ntohs it when snprintfing, so it issued a request for a wrong service with yp_match on little endian boxes. If lucky, it would not be a valid service and sequential scanning was done, if unlucky, wrong service was returned. Another thing is a performance tweak for protocol == NULL. "tcp" and "udp" are the most often used protocols, so libnss_nis.so can first try */tcp, then */udp and then fallback to the current sequential scanning. NIS doesn't comply to POSIX anyway in that it doesn't guarantee that even during sequential YPPROC_ALL scanning of services.by{,service}name original first service will be found first, so scanning for tcp and udp first doesn't make things worse in this regard. Plus there are 2 small tweaks, one is to use always services.byname map for sequential scanning (the old code did that and the comment sounded like there could be NIS servers without services.byservicename but with services.byname) and the second one is not to allocate excessive 100 chars for %d integer. 2004-03-30 Jakub Jelinek * nis/nss_nis/nis-service.c (_nss_nis_getservbyname_r): If protocol == NULL, try name/tcp and name/udp first before falling back into the sequential scanning. Use services.byname database for sequential scanning. (_nss_nis_getservbyport_r): Likewise. Just allocate sizeof (int) * 3 chars for integer. * nis/nss_nis/nis-service.c (_nss_nis_getservbyport_r): Convert proto to host by order for snprintf. --- libc/nis/nss_nis/nis-service.c.jj 2004-03-30 22:15:38.000000000 +0200 +++ libc/nis/nss_nis/nis-service.c 2004-03-30 23:03:03.899449997 +0200 @@ -268,6 +268,7 @@ _nss_nis_getservbyname_r (const char *na { enum nss_status status; char *domain; + const char *proto; if (name == NULL) { @@ -279,18 +280,21 @@ _nss_nis_getservbyname_r (const char *na return NSS_STATUS_UNAVAIL; /* If the protocol is given, we could try if our NIS server knows - about services.byservicename map. If yes, we only need one query */ - if (protocol != NULL) + about services.byservicename map. If yes, we only need one query. + If the protocol is not given, try first name/tcp, then name/udp + and then fallback to sequential scanning of services.byname map. */ + proto = protocol != NULL ? protocol : "tcp"; + do { - char key[strlen (name) + strlen (protocol) + 2]; + char key[strlen (name) + strlen (proto) + 2]; char *cp, *result; size_t keylen, len; int int_len; - /* key is: "name/protocol" */ + /* key is: "name/proto" */ cp = stpcpy (key, name); *cp++ = '/'; - stpcpy (cp, protocol); + stpcpy (cp, proto); keylen = strlen (key); status = yperr2nss (yp_match (domain, "services.byservicename", key, keylen, &result, &int_len)); @@ -329,6 +333,7 @@ _nss_nis_getservbyname_r (const char *na return NSS_STATUS_SUCCESS; } } + while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL)); struct ypall_callback ypcb; struct search_t req; @@ -343,7 +348,7 @@ _nss_nis_getservbyname_r (const char *na req.buflen = buflen; req.errnop = errnop; req.status = NSS_STATUS_NOTFOUND; - status = yperr2nss (yp_all (domain, "services.byservicename", &ypcb)); + status = yperr2nss (yp_all (domain, "services.byname", &ypcb)); if (status != NSS_STATUS_SUCCESS) return status; @@ -358,20 +363,24 @@ _nss_nis_getservbyport_r (int port, cons { enum nss_status status; char *domain; + const char *proto; if (yp_get_default_domain (&domain)) return NSS_STATUS_UNAVAIL; - /* If the protocol is given, we only need one query */ - if (protocol != NULL) + /* If the protocol is given, we only need one query. + Otherwise try first port/tcp, then port/udp and then fallback + to sequential scanning of services.byname. */ + proto = protocol != NULL ? protocol : "tcp"; + do { - char key[100 + strlen (protocol) + 2]; + char key[sizeof (int) * 3 + strlen (proto) + 2]; char *result; size_t keylen, len; int int_len; - /* key is: "port/protocol" */ - keylen = snprintf (key, sizeof (key), "%d/%s", port, protocol); + /* key is: "port/proto" */ + keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), proto); status = yperr2nss (yp_match (domain, "services.byname", key, keylen, &result, &int_len)); len = int_len; @@ -409,6 +418,7 @@ _nss_nis_getservbyport_r (int port, cons return NSS_STATUS_SUCCESS; } } + while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL)); if (port == -1) return NSS_STATUS_NOTFOUND; Jakub