Updated to fedora-glibc-20060511T1325
[glibc.git] / nis / nss_nis / nis-service.c
blobc0e064d9a4eb0f1124a95fe9fe40ff2681d379b6
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 /* Get the next entry until we found a correct one. */
194 struct response_t *bucket = intern.next;
196 if (__builtin_expect (intern.offset >= bucket->size, 0))
198 if (bucket->next == NULL)
199 return NSS_STATUS_NOTFOUND;
201 /* We look at all the content in the current bucket. Go on
202 to the next. */
203 bucket = intern.next = bucket->next;
204 intern.offset = 0;
207 for (p = &bucket->mem[intern.offset]; isspace (*p); ++p)
208 ++intern.offset;
210 size_t len = strlen (p) + 1;
211 if (__builtin_expect (len > buflen, 0))
213 *errnop = ERANGE;
214 return NSS_STATUS_TRYAGAIN;
217 /* We unfortunately have to copy the data in the user-provided
218 buffer because that buffer might be around for a very long
219 time and the servent structure must remain valid. If we would
220 rely on the BUCKET memory the next 'setservent' or 'endservent'
221 call would destroy it.
223 The important thing is that it is a single NUL-terminated
224 string. This is what the parsing routine expects. */
225 p = memcpy (buffer, &bucket->mem[intern.offset], len);
227 parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop);
228 if (__builtin_expect (parse_res == -1, 0))
229 return NSS_STATUS_TRYAGAIN;
231 intern.offset += len;
233 while (!parse_res);
235 return NSS_STATUS_SUCCESS;
238 enum nss_status
239 _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen,
240 int *errnop)
242 enum nss_status status;
244 __libc_lock_lock (lock);
246 status = internal_nis_getservent_r (serv, buffer, buflen, errnop);
248 __libc_lock_unlock (lock);
250 return status;
253 enum nss_status
254 _nss_nis_getservbyname_r (const char *name, const char *protocol,
255 struct servent *serv, char *buffer, size_t buflen,
256 int *errnop)
258 if (name == NULL)
260 *errnop = EINVAL;
261 return NSS_STATUS_UNAVAIL;
264 char *domain;
265 if (__builtin_expect (yp_get_default_domain (&domain), 0))
266 return NSS_STATUS_UNAVAIL;
268 /* If the protocol is given, we could try if our NIS server knows
269 about services.byservicename map. If yes, we only need one query. */
270 size_t keylen = strlen (name) + 1 + (protocol ? strlen (protocol) : 0);
271 char key[keylen + 1];
273 /* key is: "name/proto" */
274 char *cp = stpcpy (key, name);
275 if (protocol != NULL)
277 *cp++ = '/';
278 strcpy (cp, protocol);
281 char *result;
282 int int_len;
283 int status = yp_match (domain, "services.byservicename", key,
284 keylen, &result, &int_len);
285 size_t len = int_len;
287 /* If we found the key, it's ok and parse the result. If not,
288 fall through and parse the complete table. */
289 if (__builtin_expect (status == YPERR_SUCCESS, 1))
291 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
293 free (result);
294 *errnop = ERANGE;
295 return NSS_STATUS_TRYAGAIN;
298 char *p = strncpy (buffer, result, len);
299 buffer[len] = '\0';
300 while (isspace (*p))
301 ++p;
302 free (result);
304 int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
305 buflen, errnop);
306 if (__builtin_expect (parse_res < 0, 0))
308 if (parse_res == -1)
309 return NSS_STATUS_TRYAGAIN;
310 else
311 return NSS_STATUS_NOTFOUND;
313 else
314 return NSS_STATUS_SUCCESS;
317 /* Check if it is safe to rely on services.byservicename. */
318 if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
319 return yperr2nss (status);
321 struct ypall_callback ypcb;
322 struct search_t req;
324 ypcb.foreach = dosearch;
325 ypcb.data = (char *) &req;
326 req.name = name;
327 req.proto = protocol;
328 req.port = -1;
329 req.serv = serv;
330 req.buffer = buffer;
331 req.buflen = buflen;
332 req.errnop = errnop;
333 req.status = NSS_STATUS_NOTFOUND;
334 status = yp_all (domain, "services.byname", &ypcb);
336 if (__builtin_expect (status != YPERR_SUCCESS, 0))
337 return yperr2nss (status);
339 return req.status;
342 enum nss_status
343 _nss_nis_getservbyport_r (int port, const char *protocol,
344 struct servent *serv, char *buffer,
345 size_t buflen, int *errnop)
347 char *domain;
348 if (__builtin_expect (yp_get_default_domain (&domain), 0))
349 return NSS_STATUS_UNAVAIL;
351 /* If the protocol is given, we only need one query.
352 Otherwise try first port/tcp, then port/udp and then fallback
353 to sequential scanning of services.byname. */
354 const char *proto = protocol != NULL ? protocol : "tcp";
357 /* key is: "port/proto" */
358 char key[sizeof (int) * 3 + strlen (proto) + 2];
359 size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port),
360 proto);
362 char *result;
363 int int_len;
364 int status = yp_match (domain, "services.byname", key, keylen, &result,
365 &int_len);
366 size_t len = int_len;
368 /* If we found the key, it's ok and parse the result. If not,
369 fall through and parse the complete table. */
370 if (__builtin_expect (status == YPERR_SUCCESS, 1))
372 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
374 free (result);
375 *errnop = ERANGE;
376 return NSS_STATUS_TRYAGAIN;
379 char *p = strncpy (buffer, result, len);
380 buffer[len] = '\0';
381 while (isspace (*p))
382 ++p;
383 free (result);
384 int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
385 buflen, errnop);
386 if (__builtin_expect (parse_res < 0, 0))
388 if (parse_res == -1)
389 return NSS_STATUS_TRYAGAIN;
390 else
391 return NSS_STATUS_NOTFOUND;
394 return NSS_STATUS_SUCCESS;
397 while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL));
399 if (port == -1)
400 return NSS_STATUS_NOTFOUND;
402 struct ypall_callback ypcb;
403 struct search_t req;
405 ypcb.foreach = dosearch;
406 ypcb.data = (char *) &req;
407 req.name = NULL;
408 req.proto = protocol;
409 req.port = port;
410 req.serv = serv;
411 req.buffer = buffer;
412 req.buflen = buflen;
413 req.errnop = errnop;
414 req.status = NSS_STATUS_NOTFOUND;
415 int status = yp_all (domain, "services.byname", &ypcb);
417 if (__builtin_expect (status != YPERR_SUCCESS, 0))
418 return yperr2nss (status);
420 return req.status;