1 /* Copyright (C) 1997-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <hesiod.h>
20 #include <netdb.h>
21 #include <netinet/in.h>
22 #include <nss.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 NSS_DECLARE_MODULE_FUNCTIONS (hesiod)
28 
29 /* Hesiod uses a format for service entries that differs from the
30    traditional format.  We therefore declare our own parser.  */
31 
32 #define ENTNAME servent
33 
34 struct servent_data {};
35 
36 #define TRAILING_LIST_MEMBER		s_aliases
37 #define TRAILING_LIST_SEPARATOR_P	isspace
38 #include <nss/nss_files/files-parse.c>
39 #define ISSC_OR_SPACE(c)	((c) ==  ';' || isspace (c))
40 LINE_PARSER
41 ("#",
42  STRING_FIELD (result->s_name, ISSC_OR_SPACE, 1);
43  STRING_FIELD (result->s_proto, ISSC_OR_SPACE, 1);
44  INT_FIELD (result->s_port, ISSC_OR_SPACE, 10, 0, htons);
45  )
46 
47 enum nss_status
_nss_hesiod_setservent(int stayopen)48 _nss_hesiod_setservent (int stayopen)
49 {
50   return NSS_STATUS_SUCCESS;
51 }
52 
53 enum nss_status
_nss_hesiod_endservent(void)54 _nss_hesiod_endservent (void)
55 {
56   return NSS_STATUS_SUCCESS;
57 }
58 
59 static enum nss_status
lookup(const char * name,const char * type,const char * protocol,struct servent * serv,char * buffer,size_t buflen,int * errnop)60 lookup (const char *name, const char *type, const char *protocol,
61 	struct servent *serv, char *buffer, size_t buflen, int *errnop)
62 {
63   struct parser_data *data = (void *) buffer;
64   size_t linebuflen;
65   void *context;
66   char **list, **item;
67   int parse_res;
68   int found;
69   int olderr = errno;
70 
71   if (hesiod_init (&context) < 0)
72     return NSS_STATUS_UNAVAIL;
73 
74   list = hesiod_resolve (context, name, type);
75   if (list == NULL)
76     {
77       int err = errno;
78       hesiod_end (context);
79       __set_errno (olderr);
80       return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
81     }
82 
83   linebuflen = buffer + buflen - data->linebuffer;
84 
85   item = list;
86   found = 0;
87   do
88     {
89       size_t len = strlen (*item) + 1;
90 
91       if (linebuflen < len)
92 	{
93 	  hesiod_free_list (context, list);
94 	  hesiod_end (context);
95 	  *errnop = ERANGE;
96 	  return NSS_STATUS_TRYAGAIN;
97 	}
98 
99       memcpy (data->linebuffer, *item, len);
100 
101       parse_res = parse_line (buffer, serv, data, buflen, errnop);
102       if (parse_res == -1)
103 	{
104 	  hesiod_free_list (context, list);
105 	  hesiod_end (context);
106 	  return NSS_STATUS_TRYAGAIN;
107 	}
108 
109       if (parse_res > 0)
110 	found = protocol == NULL || strcasecmp (serv->s_proto, protocol) == 0;
111 
112       ++item;
113     }
114   while (*item != NULL && !found);
115 
116   hesiod_free_list (context, list);
117   hesiod_end (context);
118 
119   if (found == 0)
120     {
121       __set_errno (olderr);
122       return NSS_STATUS_NOTFOUND;
123     }
124 
125   return NSS_STATUS_SUCCESS;
126 }
127 
128 enum nss_status
_nss_hesiod_getservbyname_r(const char * name,const char * protocol,struct servent * serv,char * buffer,size_t buflen,int * errnop)129 _nss_hesiod_getservbyname_r (const char *name, const char *protocol,
130 			     struct servent *serv,
131 			     char *buffer, size_t buflen, int *errnop)
132 {
133   return lookup (name, "service", protocol, serv, buffer, buflen, errnop);
134 }
135 
136 enum nss_status
_nss_hesiod_getservbyport_r(const int port,const char * protocol,struct servent * serv,char * buffer,size_t buflen,int * errnop)137 _nss_hesiod_getservbyport_r (const int port, const char *protocol,
138 			     struct servent *serv,
139 			     char *buffer, size_t buflen, int *errnop)
140 {
141   char portstr[6];	    /* Port numbers are restricted to 16 bits. */
142 
143   snprintf (portstr, sizeof portstr, "%d", ntohs (port));
144 
145   return lookup (portstr, "port", protocol, serv, buffer, buflen, errnop);
146 }
147