]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nss_nis/nis-service.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / nis / nss_nis / nis-service.c
CommitLineData
04277e02 1/* Copyright (C) 1996-2019 Free Software Foundation, Inc.
6259ec0d 2 This file is part of the GNU C Library.
d6f6ffa1 3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
6259ec0d
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
6259ec0d
UD
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
41bdb6e2 13 Lesser General Public License for more details.
6259ec0d 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
6259ec0d
UD
18
19#include <nss.h>
20#include <netdb.h>
21#include <ctype.h>
22#include <errno.h>
23#include <string.h>
ec999b8e 24#include <libc-lock.h>
6259ec0d
UD
25#include <rpcsvc/yp.h>
26#include <rpcsvc/ypclnt.h>
27
28#include "nss-nis.h"
433f49c4 29#include <libnsl.h>
6259ec0d 30
f8b87ef0 31
5713a71e
UD
32/* Get the declaration of the parser function. */
33#define ENTNAME servent
34#define EXTERN_PARSER
35#include <nss/nss_files/files-parse.c>
f8b87ef0 36
6259ec0d
UD
37__libc_lock_define_initialized (static, lock)
38
4718026d 39static intern_t intern;
f166d865 40
3b0b6c36
UD
41struct search_t
42{
43 const char *name;
44 const char *proto;
45 int port;
46 enum nss_status status;
47 struct servent *serv;
48 char *buffer;
49 size_t buflen;
50 int *errnop;
51};
52
3b0b6c36
UD
53static int
54dosearch (int instatus, char *inkey, int inkeylen, char *inval,
55 int invallen, char *indata)
56{
57 struct search_t *req = (struct search_t *) indata;
58
a1ffb40e 59 if (__glibc_unlikely (instatus != YP_TRUE))
3b0b6c36
UD
60 return 1;
61
62 if (inkey && inkeylen > 0 && inval && invallen > 0)
63 {
a1ffb40e 64 if (__glibc_unlikely ((size_t) (invallen + 1) > req->buflen))
3b0b6c36
UD
65 {
66 *req->errnop = ERANGE;
67 req->status = NSS_STATUS_TRYAGAIN;
68 return 1;
69 }
70
ab9a9ff8 71 char *p = strncpy (req->buffer, inval, invallen);
3b0b6c36
UD
72 req->buffer[invallen] = '\0';
73 while (isspace (*p))
74 ++p;
75
ab9a9ff8
UD
76 int parse_res = _nss_files_parse_servent (p, req->serv,
77 (void *) req->buffer,
78 req->buflen, req->errnop);
3b0b6c36
UD
79 if (parse_res == -1)
80 {
81 req->status = NSS_STATUS_TRYAGAIN;
82 return 1;
83 }
84
85 if (!parse_res)
86 return 0;
87
88 if (req->proto != NULL && strcmp (req->serv->s_proto, req->proto) != 0)
89 return 0;
90
91 if (req->port != -1 && req->serv->s_port != req->port)
92 return 0;
93
94 if (req->name != NULL && strcmp (req->serv->s_name, req->name) != 0)
95 {
96 char **cp;
97 for (cp = req->serv->s_aliases; *cp; cp++)
98 if (strcmp (req->name, *cp) == 0)
99 break;
100
101 if (*cp == NULL)
102 return 0;
103 }
104
105 req->status = NSS_STATUS_SUCCESS;
106 return 1;
107 }
108
109 return 0;
110}
111
4eaa9bb4 112static void
4718026d 113internal_nis_endservent (void)
6259ec0d 114{
4718026d
UD
115 struct response_t *curr = intern.next;
116
117 while (curr != NULL)
6259ec0d 118 {
4718026d
UD
119 struct response_t *last = curr;
120 curr = curr->next;
121 free (last);
6259ec0d 122 }
f166d865 123
4718026d 124 intern.next = intern.start = NULL;
6259ec0d 125}
6675b191 126
6259ec0d 127enum nss_status
6675b191 128_nss_nis_endservent (void)
6259ec0d 129{
6259ec0d
UD
130 __libc_lock_lock (lock);
131
4eaa9bb4 132 internal_nis_endservent ();
6259ec0d
UD
133
134 __libc_lock_unlock (lock);
135
4eaa9bb4 136 return NSS_STATUS_SUCCESS;
6259ec0d
UD
137}
138
139static enum nss_status
4718026d 140internal_nis_setservent (void)
6259ec0d 141{
6675b191
UD
142 char *domainname;
143 struct ypall_callback ypcb;
144 enum nss_status status;
0d8733c4 145
6675b191
UD
146 if (yp_get_default_domain (&domainname))
147 return NSS_STATUS_UNAVAIL;
6259ec0d 148
4eaa9bb4 149 internal_nis_endservent ();
6675b191 150
e0d4e91d
UD
151 ypcb.foreach = _nis_saveit;
152 ypcb.data = (char *) &intern;
6675b191 153 status = yperr2nss (yp_all (domainname, "services.byname", &ypcb));
4718026d
UD
154
155 /* Mark the last buffer as full. */
4eaa9bb4
UD
156 if (intern.next != NULL)
157 intern.next->size = intern.offset;
4718026d
UD
158
159 intern.next = intern.start;
4eaa9bb4 160 intern.offset = 0;
6675b191
UD
161
162 return status;
163}
3b0b6c36 164
6259ec0d 165enum nss_status
6675b191 166_nss_nis_setservent (int stayopen)
6259ec0d
UD
167{
168 enum nss_status status;
169
170 __libc_lock_lock (lock);
171
4718026d 172 status = internal_nis_setservent ();
6259ec0d
UD
173
174 __libc_lock_unlock (lock);
175
176 return status;
177}
178
179static enum nss_status
180internal_nis_getservent_r (struct servent *serv, char *buffer,
4718026d 181 size_t buflen, int *errnop)
6259ec0d 182{
5713a71e 183 struct parser_data *pdata = (void *) buffer;
f166d865 184 int parse_res;
6259ec0d
UD
185 char *p;
186
4718026d
UD
187 if (intern.start == NULL)
188 internal_nis_setservent ();
0d8733c4 189
ed3691ba
UD
190 if (intern.next == NULL)
191 /* Not one entry in the map. */
192 return NSS_STATUS_NOTFOUND;
193
4718026d 194 /* Get the next entry until we found a correct one. */
6259ec0d
UD
195 do
196 {
4718026d 197 struct response_t *bucket = intern.next;
34816665 198
a1ffb40e 199 if (__glibc_unlikely (intern.offset >= bucket->size))
4718026d
UD
200 {
201 if (bucket->next == NULL)
202 return NSS_STATUS_NOTFOUND;
203
204 /* We look at all the content in the current bucket. Go on
205 to the next. */
206 bucket = intern.next = bucket->next;
207 intern.offset = 0;
208 }
209
210 for (p = &bucket->mem[intern.offset]; isspace (*p); ++p)
211 ++intern.offset;
212
213 size_t len = strlen (p) + 1;
a1ffb40e 214 if (__glibc_unlikely (len > buflen))
4718026d
UD
215 {
216 *errnop = ERANGE;
217 return NSS_STATUS_TRYAGAIN;
218 }
219
220 /* We unfortunately have to copy the data in the user-provided
221 buffer because that buffer might be around for a very long
222 time and the servent structure must remain valid. If we would
223 rely on the BUCKET memory the next 'setservent' or 'endservent'
224 call would destroy it.
225
226 The important thing is that it is a single NUL-terminated
227 string. This is what the parsing routine expects. */
228 p = memcpy (buffer, &bucket->mem[intern.offset], len);
0d8733c4 229
5713a71e 230 parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop);
a1ffb40e 231 if (__glibc_unlikely (parse_res == -1))
6259ec0d 232 return NSS_STATUS_TRYAGAIN;
4718026d
UD
233
234 intern.offset += len;
6259ec0d
UD
235 }
236 while (!parse_res);
237
238 return NSS_STATUS_SUCCESS;
239}
240
241enum nss_status
d71b808a
UD
242_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen,
243 int *errnop)
6259ec0d
UD
244{
245 enum nss_status status;
246
247 __libc_lock_lock (lock);
248
4718026d 249 status = internal_nis_getservent_r (serv, buffer, buflen, errnop);
6259ec0d
UD
250
251 __libc_lock_unlock (lock);
252
253 return status;
254}
255
256enum nss_status
51eecc4a 257_nss_nis_getservbyname_r (const char *name, const char *protocol,
d71b808a
UD
258 struct servent *serv, char *buffer, size_t buflen,
259 int *errnop)
6259ec0d 260{
e61abf83 261 if (name == NULL)
6259ec0d 262 {
ac9f45cf 263 *errnop = EINVAL;
6259ec0d
UD
264 return NSS_STATUS_UNAVAIL;
265 }
266
ab9a9ff8 267 char *domain;
a1ffb40e 268 if (__glibc_unlikely (yp_get_default_domain (&domain)))
3b0b6c36
UD
269 return NSS_STATUS_UNAVAIL;
270
b85697f6 271 /* If the protocol is given, we could try if our NIS server knows
dd047aa5 272 about services.byservicename map. If yes, we only need one query. */
b21fa963 273 size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0);
315eb1d8
AS
274 /* Limit key length to the maximum size of an RPC packet. */
275 if (keylen > UDPMSGSIZE)
276 {
277 *errnop = ERANGE;
278 return NSS_STATUS_UNAVAIL;
279 }
280
ab9a9ff8 281 char key[keylen + 1];
dd047aa5
UD
282
283 /* key is: "name/proto" */
ab9a9ff8
UD
284 char *cp = stpcpy (key, name);
285 if (protocol != NULL)
b85697f6 286 {
b85697f6 287 *cp++ = '/';
dd047aa5
UD
288 strcpy (cp, protocol);
289 }
ab9a9ff8
UD
290
291 char *result;
292 int int_len;
e7c8359e
UD
293 int status = yp_match (domain, "services.byservicename", key,
294 keylen, &result, &int_len);
ab9a9ff8 295 size_t len = int_len;
dd047aa5
UD
296
297 /* If we found the key, it's ok and parse the result. If not,
298 fall through and parse the complete table. */
a1ffb40e 299 if (__glibc_likely (status == YPERR_SUCCESS))
dd047aa5 300 {
a1ffb40e 301 if (__glibc_unlikely ((size_t) (len + 1) > buflen))
b85697f6 302 {
b85697f6 303 free (result);
dd047aa5
UD
304 *errnop = ERANGE;
305 return NSS_STATUS_TRYAGAIN;
306 }
307
ab9a9ff8 308 char *p = strncpy (buffer, result, len);
dd047aa5
UD
309 buffer[len] = '\0';
310 while (isspace (*p))
311 ++p;
312 free (result);
ab9a9ff8
UD
313
314 int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
315 buflen, errnop);
a1ffb40e 316 if (__glibc_unlikely (parse_res < 0))
dd047aa5
UD
317 {
318 if (parse_res == -1)
319 return NSS_STATUS_TRYAGAIN;
b85697f6 320 else
dd047aa5 321 return NSS_STATUS_NOTFOUND;
b85697f6 322 }
dd047aa5
UD
323 else
324 return NSS_STATUS_SUCCESS;
b85697f6
UD
325 }
326
4eb6619c 327 /* Check if it is safe to rely on services.byservicename. */
433f49c4 328 if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
e7c8359e 329 return yperr2nss (status);
4eb6619c 330
3b0b6c36
UD
331 struct ypall_callback ypcb;
332 struct search_t req;
333
334 ypcb.foreach = dosearch;
335 ypcb.data = (char *) &req;
336 req.name = name;
337 req.proto = protocol;
338 req.port = -1;
339 req.serv = serv;
340 req.buffer = buffer;
341 req.buflen = buflen;
342 req.errnop = errnop;
343 req.status = NSS_STATUS_NOTFOUND;
e7c8359e 344 status = yp_all (domain, "services.byname", &ypcb);
3b0b6c36 345
a1ffb40e 346 if (__glibc_unlikely (status != YPERR_SUCCESS))
e7c8359e 347 return yperr2nss (status);
6259ec0d 348
3b0b6c36 349 return req.status;
6259ec0d
UD
350}
351
352enum nss_status
51eecc4a
AJ
353_nss_nis_getservbyport_r (int port, const char *protocol,
354 struct servent *serv, char *buffer,
355 size_t buflen, int *errnop)
6259ec0d 356{
3b0b6c36 357 char *domain;
a1ffb40e 358 if (__glibc_unlikely (yp_get_default_domain (&domain)))
3b0b6c36 359 return NSS_STATUS_UNAVAIL;
6259ec0d 360
a70e964e
UD
361 /* If the protocol is given, we only need one query.
362 Otherwise try first port/tcp, then port/udp and then fallback
363 to sequential scanning of services.byname. */
364 const char *proto = protocol != NULL ? protocol : "tcp";
315eb1d8
AS
365 /* Limit protocol name length to the maximum size of an RPC packet. */
366 if (strlen (proto) > UDPMSGSIZE)
367 {
368 *errnop = ERANGE;
369 return NSS_STATUS_UNAVAIL;
370 }
371
a70e964e 372 do
6259ec0d 373 {
ab9a9ff8 374 /* key is: "port/proto" */
a70e964e 375 char key[sizeof (int) * 3 + strlen (proto) + 2];
ab9a9ff8
UD
376 size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port),
377 proto);
378
3b0b6c36 379 char *result;
c7e41631 380 int int_len;
e7c8359e
UD
381 int status = yp_match (domain, "services.byname", key, keylen, &result,
382 &int_len);
ab9a9ff8 383 size_t len = int_len;
b85697f6
UD
384
385 /* If we found the key, it's ok and parse the result. If not,
386 fall through and parse the complete table. */
a1ffb40e 387 if (__glibc_likely (status == YPERR_SUCCESS))
b85697f6 388 {
a1ffb40e 389 if (__glibc_unlikely ((size_t) (len + 1) > buflen))
b85697f6
UD
390 {
391 free (result);
392 *errnop = ERANGE;
393 return NSS_STATUS_TRYAGAIN;
394 }
395
ab9a9ff8 396 char *p = strncpy (buffer, result, len);
b85697f6
UD
397 buffer[len] = '\0';
398 while (isspace (*p))
399 ++p;
400 free (result);
ab9a9ff8
UD
401 int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
402 buflen, errnop);
a1ffb40e 403 if (__glibc_unlikely (parse_res < 0))
b85697f6
UD
404 {
405 if (parse_res == -1)
406 return NSS_STATUS_TRYAGAIN;
407 else
34816665 408 return NSS_STATUS_NOTFOUND;
b85697f6 409 }
ab9a9ff8
UD
410
411 return NSS_STATUS_SUCCESS;
b85697f6 412 }
6259ec0d 413 }
a70e964e 414 while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL));
6259ec0d 415
3b0b6c36
UD
416 if (port == -1)
417 return NSS_STATUS_NOTFOUND;
6259ec0d 418
3b0b6c36
UD
419 struct ypall_callback ypcb;
420 struct search_t req;
421
422 ypcb.foreach = dosearch;
423 ypcb.data = (char *) &req;
424 req.name = NULL;
425 req.proto = protocol;
426 req.port = port;
427 req.serv = serv;
428 req.buffer = buffer;
429 req.buflen = buflen;
430 req.errnop = errnop;
431 req.status = NSS_STATUS_NOTFOUND;
e7c8359e 432 int status = yp_all (domain, "services.byname", &ypcb);
6259ec0d 433
a1ffb40e 434 if (__glibc_unlikely (status != YPERR_SUCCESS))
e7c8359e 435 return yperr2nss (status);
3b0b6c36
UD
436
437 return req.status;
6259ec0d 438}