1/* Copyright (C) 1996-2016 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#include <nss.h>
20/* The following is an ugly trick to avoid a prototype declaration for
21 _nss_nis_endgrent. */
22#define _nss_nis_endnetent _nss_nis_endnetent_XXX
23#include <netdb.h>
24#undef _nss_nis_endnetent
25#include <ctype.h>
26#include <errno.h>
27#include <stdint.h>
28#include <string.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <libc-lock.h>
32#include <rpcsvc/yp.h>
33#include <rpcsvc/ypclnt.h>
34
35#include "nss-nis.h"
36
37/* Get the declaration of the parser function. */
38#define ENTNAME netent
39#define EXTERN_PARSER
40#include <nss/nss_files/files-parse.c>
41
42__libc_lock_define_initialized (static, lock)
43
44static bool_t new_start = 1;
45static char *oldkey;
46static int oldkeylen;
47
48enum nss_status
49_nss_nis_setnetent (int stayopen)
50{
51 __libc_lock_lock (lock);
52
53 new_start = 1;
54 if (oldkey != NULL)
55 {
56 free (oldkey);
57 oldkey = NULL;
58 oldkeylen = 0;
59 }
60
61 __libc_lock_unlock (lock);
62
63 return NSS_STATUS_SUCCESS;
64}
65/* Make _nss_nis_endnetent an alias of _nss_nis_setnetent. We do this
66 even though the prototypes don't match. The argument of setnetent
67 is not used so this makes no difference. */
68strong_alias (_nss_nis_setnetent, _nss_nis_endnetent)
69
70static enum nss_status
71internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
72 int *errnop, int *herrnop)
73{
74 struct parser_data *data = (void *) buffer;
75
76 char *domain;
77 if (__glibc_unlikely (yp_get_default_domain (&domain)))
78 return NSS_STATUS_UNAVAIL;
79
80 /* Get the next entry until we found a correct one. */
81 int parse_res;
82 do
83 {
84 char *result;
85 char *outkey;
86 int len;
87 int keylen;
88 int yperr;
89
90 if (new_start)
91 yperr = yp_first (domain, "networks.byname", &outkey, &keylen, &result,
92 &len);
93 else
94 yperr = yp_next (domain, "networks.byname", oldkey, oldkeylen, &outkey,
95 &keylen, &result, &len);
96
97 if (__glibc_unlikely (yperr != YPERR_SUCCESS))
98 {
99 enum nss_status retval = yperr2nss (yperr);
100
101 if (retval == NSS_STATUS_TRYAGAIN)
102 {
103 *herrnop = NETDB_INTERNAL;
104 *errnop = errno;
105 }
106 return retval;
107 }
108
109 if (__glibc_unlikely ((size_t) (len + 1) > buflen))
110 {
111 free (result);
112 *errnop = ERANGE;
113 *herrnop = NETDB_INTERNAL;
114 return NSS_STATUS_TRYAGAIN;
115 }
116
117 char *p = strncpy (buffer, result, len);
118 buffer[len] = '\0';
119 while (isspace (*p))
120 ++p;
121 free (result);
122
123 parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
124 if (__glibc_unlikely (parse_res == -1))
125 {
126 free (outkey);
127 *herrnop = NETDB_INTERNAL;
128 *errnop = ERANGE;
129 return NSS_STATUS_TRYAGAIN;
130 }
131
132 free (oldkey);
133 oldkey = outkey;
134 oldkeylen = keylen;
135 new_start = 0;
136 }
137 while (!parse_res);
138
139 return NSS_STATUS_SUCCESS;
140}
141
142enum nss_status
143_nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
144 int *errnop, int *herrnop)
145{
146 enum nss_status status;
147
148 __libc_lock_lock (lock);
149
150 status = internal_nis_getnetent_r (net, buffer, buflen, errnop, herrnop);
151
152 __libc_lock_unlock (lock);
153
154 return status;
155}
156
157enum nss_status
158_nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
159 size_t buflen, int *errnop, int *herrnop)
160{
161 if (name == NULL)
162 {
163 *errnop = EINVAL;
164 *herrnop = NETDB_INTERNAL;
165 return NSS_STATUS_UNAVAIL;
166 }
167
168 char *domain;
169 if (__glibc_unlikely (yp_get_default_domain (&domain)))
170 return NSS_STATUS_UNAVAIL;
171
172 struct parser_data *data = (void *) buffer;
173 if (buflen < sizeof *data + 1)
174 {
175 *herrnop = NETDB_INTERNAL;
176 *errnop = ERANGE;
177 return NSS_STATUS_TRYAGAIN;
178 }
179
180 /* Convert name to lowercase. */
181 size_t namlen = strlen (name);
182 /* Limit name length to the maximum size of an RPC packet. */
183 if (namlen > UDPMSGSIZE)
184 {
185 *errnop = ERANGE;
186 return NSS_STATUS_UNAVAIL;
187 }
188
189 char name2[namlen + 1];
190 size_t i;
191
192 for (i = 0; i < namlen; ++i)
193 name2[i] = _tolower (name[i]);
194 name2[i] = '\0';
195
196 char *result;
197 int len;
198 int yperr = yp_match (domain, "networks.byname", name2, namlen, &result,
199 &len);
200
201 if (__glibc_unlikely (yperr != YPERR_SUCCESS))
202 {
203 enum nss_status retval = yperr2nss (yperr);
204
205 if (retval == NSS_STATUS_TRYAGAIN)
206 {
207 *errnop = errno;
208 *herrnop = NETDB_INTERNAL;
209 }
210 return retval;
211 }
212
213 if (__glibc_unlikely ((size_t) (len + 1) > buflen))
214 {
215 free (result);
216 *errnop = ERANGE;
217 *herrnop = NETDB_INTERNAL;
218 return NSS_STATUS_TRYAGAIN;
219 }
220
221 char *p = strncpy (buffer, result, len);
222 buffer[len] = '\0';
223 while (isspace (*p))
224 ++p;
225 free (result);
226
227 int parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
228
229 if (__glibc_unlikely (parse_res < 1))
230 {
231 *herrnop = NETDB_INTERNAL;
232 if (parse_res == -1)
233 return NSS_STATUS_TRYAGAIN;
234 else
235 return NSS_STATUS_NOTFOUND;
236 }
237 else
238 return NSS_STATUS_SUCCESS;
239}
240
241enum nss_status
242_nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net,
243 char *buffer, size_t buflen, int *errnop,
244 int *herrnop)
245{
246 char *domain;
247 if (__glibc_unlikely (yp_get_default_domain (&domain)))
248 return NSS_STATUS_UNAVAIL;
249
250 struct in_addr in = { .s_addr = htonl (addr) };
251 char *buf = inet_ntoa (in);
252 size_t blen = strlen (buf);
253
254 while (1)
255 {
256 char *result;
257 int len;
258
259 int yperr = yp_match (domain, "networks.byaddr", buf, blen, &result,
260 &len);
261
262 if (__glibc_unlikely (yperr != YPERR_SUCCESS))
263 {
264 enum nss_status retval = yperr2nss (yperr);
265
266 if (retval == NSS_STATUS_NOTFOUND)
267 {
268 if (buf[blen - 2] == '.' && buf[blen - 1] == '0')
269 {
270 /* Try again, but with trailing dot(s)
271 removed (one by one) */
272 buf[blen - 2] = '\0';
273 blen -= 2;
274 continue;
275 }
276 else
277 return NSS_STATUS_NOTFOUND;
278 }
279 else
280 {
281 if (retval == NSS_STATUS_TRYAGAIN)
282 *errnop = errno;
283 return retval;
284 }
285 }
286
287 if (__glibc_unlikely ((size_t) (len + 1) > buflen))
288 {
289 free (result);
290 *errnop = ERANGE;
291 *herrnop = NETDB_INTERNAL;
292 return NSS_STATUS_TRYAGAIN;
293 }
294
295 char *p = strncpy (buffer, result, len);
296 buffer[len] = '\0';
297 while (isspace (*p))
298 ++p;
299 free (result);
300
301 int parse_res = _nss_files_parse_netent (p, net, (void *) buffer,
302 buflen, errnop);
303
304 if (__glibc_unlikely (parse_res < 1))
305 {
306 *herrnop = NETDB_INTERNAL;
307 if (parse_res == -1)
308 return NSS_STATUS_TRYAGAIN;
309 else
310 return NSS_STATUS_NOTFOUND;
311 }
312 else
313 return NSS_STATUS_SUCCESS;
314 }
315}
316