2.9
[glibc/nacl-glibc.git] / nis / nss_nis / nis-service.c
blob59a598f296e1d7ef68da1d618508b5e93f3ff729
1 /* Copyright (C) 1996-2004, 2006 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
20 #include <nss.h>
21 #include <netdb.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <bits/libc-lock.h>
26 #include <rpcsvc/yp.h>
27 #include <rpcsvc/ypclnt.h>
29 #include "nss-nis.h"
30 #include <libnsl.h>
33 /* Get the declaration of the parser function. */
34 #define ENTNAME servent
35 #define EXTERN_PARSER
36 #include <nss/nss_files/files-parse.c>
38 __libc_lock_define_initialized (static, lock)
40 static intern_t intern;
42 struct search_t
44 const char *name;
45 const char *proto;
46 int port;
47 enum nss_status status;
48 struct servent *serv;
49 char *buffer;
50 size_t buflen;
51 int *errnop;
54 static int
55 dosearch (int instatus, char *inkey, int inkeylen, char *inval,
56 int invallen, char *indata)
58 struct search_t *req = (struct search_t *) indata;
60 if (__builtin_expect (instatus != YP_TRUE, 0))
61 return 1;
63 if (inkey && inkeylen > 0 && inval && invallen > 0)
65 if (__builtin_expect ((size_t) (invallen + 1) > req->buflen, 0))
67 *req->errnop = ERANGE;
68 req->status = NSS_STATUS_TRYAGAIN;
69 return 1;
72 char *p = strncpy (req->buffer, inval, invallen);
73 req->buffer[invallen] = '\0';
74 while (isspace (*p))
75 ++p;
77 int parse_res = _nss_files_parse_servent (p, req->serv,
78 (void *) req->buffer,
79 req->buflen, req->errnop);
80 if (parse_res == -1)
82 req->status = NSS_STATUS_TRYAGAIN;
83 return 1;
86 if (!parse_res)
87 return 0;
89 if (req->proto != NULL && strcmp (req->serv->s_proto, req->proto) != 0)
90 return 0;
92 if (req->port != -1 && req->serv->s_port != req->port)
93 return 0;
95 if (req->name != NULL && strcmp (req->serv->s_name, req->name) != 0)
97 char **cp;
98 for (cp = req->serv->s_aliases; *cp; cp++)
99 if (strcmp (req->name, *cp) == 0)
100 break;
102 if (*cp == NULL)
103 return 0;
106 req->status = NSS_STATUS_SUCCESS;
107 return 1;
110 return 0;
113 static void
114 internal_nis_endservent (void)
116 struct response_t *curr = intern.next;
118 while (curr != NULL)
120 struct response_t *last = curr;
121 curr = curr->next;
122 free (last);
125 intern.next = intern.start = NULL;
128 enum nss_status
129 _nss_nis_endservent (void)
131 __libc_lock_lock (lock);
133 internal_nis_endservent ();
135 __libc_lock_unlock (lock);
137 return NSS_STATUS_SUCCESS;
140 static enum nss_status
141 internal_nis_setservent (void)
143 char *domainname;
144 struct ypall_callback ypcb;
145 enum nss_status status;
147 if (yp_get_default_domain (&domainname))
148 return NSS_STATUS_UNAVAIL;
150 internal_nis_endservent ();
152 ypcb.foreach = _nis_saveit;
153 ypcb.data = (char *) &intern;
154 status = yperr2nss (yp_all (domainname, "services.byname", &ypcb));
156 /* Mark the last buffer as full. */
157 if (intern.next != NULL)
158 intern.next->size = intern.offset;
160 intern.next = intern.start;
161 intern.offset = 0;
163 return status;
166 enum nss_status
167 _nss_nis_setservent (int stayopen)
169 enum nss_status status;
171 __libc_lock_lock (lock);
173 status = internal_nis_setservent ();
175 __libc_lock_unlock (lock);
177 return status;
180 static enum nss_status
181 internal_nis_getservent_r (struct servent *serv, char *buffer,
182 size_t buflen, int *errnop)
184 struct parser_data *pdata = (void *) buffer;
185 int parse_res;
186 char *p;
188 if (intern.start == NULL)
189 internal_nis_setservent ();
191 if (intern.next == NULL)
192 /* Not one entry in the map. */
193 return NSS_STATUS_NOTFOUND;
195 /* Get the next entry until we found a correct one. */
198 struct response_t *bucket = intern.next;
200 if (__builtin_expect (intern.offset >= bucket->size, 0))
202 if (bucket->next == NULL)
203 return NSS_STATUS_NOTFOUND;
205 /* We look at all the content in the current bucket. Go on
206 to the next. */
207 bucket = intern.next = bucket->next;
208 intern.offset = 0;
211 for (p = &bucket->mem[intern.offset]; isspace (*p); ++p)
212 ++intern.offset;
214 size_t len = strlen (p) + 1;
215 if (__builtin_expect (len > buflen, 0))
217 *errnop = ERANGE;
218 return NSS_STATUS_TRYAGAIN;
221 /* We unfortunately have to copy the data in the user-provided
222 buffer because that buffer might be around for a very long
223 time and the servent structure must remain valid. If we would
224 rely on the BUCKET memory the next 'setservent' or 'endservent'
225 call would destroy it.
227 The important thing is that it is a single NUL-terminated
228 string. This is what the parsing routine expects. */
229 p = memcpy (buffer, &bucket->mem[intern.offset], len);
231 parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop);
232 if (__builtin_expect (parse_res == -1, 0))
233 return NSS_STATUS_TRYAGAIN;
235 intern.offset += len;
237 while (!parse_res);
239 return NSS_STATUS_SUCCESS;
242 enum nss_status
243 _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen,
244 int *errnop)
246 enum nss_status status;
248 __libc_lock_lock (lock);
250 status = internal_nis_getservent_r (serv, buffer, buflen, errnop);
252 __libc_lock_unlock (lock);
254 return status;
257 enum nss_status
258 _nss_nis_getservbyname_r (const char *name, const char *protocol,
259 struct servent *serv, char *buffer, size_t buflen,
260 int *errnop)
262 if (name == NULL)
264 *errnop = EINVAL;
265 return NSS_STATUS_UNAVAIL;
268 char *domain;
269 if (__builtin_expect (yp_get_default_domain (&domain), 0))
270 return NSS_STATUS_UNAVAIL;
272 /* If the protocol is given, we could try if our NIS server knows
273 about services.byservicename map. If yes, we only need one query. */
274 size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0);
275 char key[keylen + 1];
277 /* key is: "name/proto" */
278 char *cp = stpcpy (key, name);
279 if (protocol != NULL)
281 *cp++ = '/';
282 strcpy (cp, protocol);
285 char *result;
286 int int_len;
287 int status = yp_match (domain, "services.byservicename", key,
288 keylen, &result, &int_len);
289 size_t len = int_len;
291 /* If we found the key, it's ok and parse the result. If not,
292 fall through and parse the complete table. */
293 if (__builtin_expect (status == YPERR_SUCCESS, 1))
295 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
297 free (result);
298 *errnop = ERANGE;
299 return NSS_STATUS_TRYAGAIN;
302 char *p = strncpy (buffer, result, len);
303 buffer[len] = '\0';
304 while (isspace (*p))
305 ++p;
306 free (result);
308 int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
309 buflen, errnop);
310 if (__builtin_expect (parse_res < 0, 0))
312 if (parse_res == -1)
313 return NSS_STATUS_TRYAGAIN;
314 else
315 return NSS_STATUS_NOTFOUND;
317 else
318 return NSS_STATUS_SUCCESS;
321 /* Check if it is safe to rely on services.byservicename. */
322 if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
323 return yperr2nss (status);
325 struct ypall_callback ypcb;
326 struct search_t req;
328 ypcb.foreach = dosearch;
329 ypcb.data = (char *) &req;
330 req.name = name;
331 req.proto = protocol;
332 req.port = -1;
333 req.serv = serv;
334 req.buffer = buffer;
335 req.buflen = buflen;
336 req.errnop = errnop;
337 req.status = NSS_STATUS_NOTFOUND;
338 status = yp_all (domain, "services.byname", &ypcb);
340 if (__builtin_expect (status != YPERR_SUCCESS, 0))
341 return yperr2nss (status);
343 return req.status;
346 enum nss_status
347 _nss_nis_getservbyport_r (int port, const char *protocol,
348 struct servent *serv, char *buffer,
349 size_t buflen, int *errnop)
351 char *domain;
352 if (__builtin_expect (yp_get_default_domain (&domain), 0))
353 return NSS_STATUS_UNAVAIL;
355 /* If the protocol is given, we only need one query.
356 Otherwise try first port/tcp, then port/udp and then fallback
357 to sequential scanning of services.byname. */
358 const char *proto = protocol != NULL ? protocol : "tcp";
361 /* key is: "port/proto" */
362 char key[sizeof (int) * 3 + strlen (proto) + 2];
363 size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port),
364 proto);
366 char *result;
367 int int_len;
368 int status = yp_match (domain, "services.byname", key, keylen, &result,
369 &int_len);
370 size_t len = int_len;
372 /* If we found the key, it's ok and parse the result. If not,
373 fall through and parse the complete table. */
374 if (__builtin_expect (status == YPERR_SUCCESS, 1))
376 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
378 free (result);
379 *errnop = ERANGE;
380 return NSS_STATUS_TRYAGAIN;
383 char *p = strncpy (buffer, result, len);
384 buffer[len] = '\0';
385 while (isspace (*p))
386 ++p;
387 free (result);
388 int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
389 buflen, errnop);
390 if (__builtin_expect (parse_res < 0, 0))
392 if (parse_res == -1)
393 return NSS_STATUS_TRYAGAIN;
394 else
395 return NSS_STATUS_NOTFOUND;
398 return NSS_STATUS_SUCCESS;
401 while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL));
403 if (port == -1)
404 return NSS_STATUS_NOTFOUND;
406 struct ypall_callback ypcb;
407 struct search_t req;
409 ypcb.foreach = dosearch;
410 ypcb.data = (char *) &req;
411 req.name = NULL;
412 req.proto = protocol;
413 req.port = port;
414 req.serv = serv;
415 req.buffer = buffer;
416 req.buflen = buflen;
417 req.errnop = errnop;
418 req.status = NSS_STATUS_NOTFOUND;
419 int status = yp_all (domain, "services.byname", &ypcb);
421 if (__builtin_expect (status != YPERR_SUCCESS, 0))
422 return yperr2nss (status);
424 return req.status;