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
25 #include <bits/libc-lock.h>
26 #include <rpcsvc/yp.h>
27 #include <rpcsvc/ypclnt.h>
33 /* Get the declaration of the parser function. */
34 #define ENTNAME servent
36 #include <nss/nss_files/files-parse.c>
38 __libc_lock_define_initialized (static, lock
)
40 static intern_t intern
;
47 enum nss_status status
;
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))
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
;
72 char *p
= strncpy (req
->buffer
, inval
, invallen
);
73 req
->buffer
[invallen
] = '\0';
77 int parse_res
= _nss_files_parse_servent (p
, req
->serv
,
79 req
->buflen
, req
->errnop
);
82 req
->status
= NSS_STATUS_TRYAGAIN
;
89 if (req
->proto
!= NULL
&& strcmp (req
->serv
->s_proto
, req
->proto
) != 0)
92 if (req
->port
!= -1 && req
->serv
->s_port
!= req
->port
)
95 if (req
->name
!= NULL
&& strcmp (req
->serv
->s_name
, req
->name
) != 0)
98 for (cp
= req
->serv
->s_aliases
; *cp
; cp
++)
99 if (strcmp (req
->name
, *cp
) == 0)
106 req
->status
= NSS_STATUS_SUCCESS
;
114 internal_nis_endservent (void)
116 struct response_t
*curr
= intern
.next
;
120 struct response_t
*last
= curr
;
125 intern
.next
= intern
.start
= NULL
;
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)
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
;
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
);
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
;
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
203 bucket
= intern
.next
= bucket
->next
;
207 for (p
= &bucket
->mem
[intern
.offset
]; isspace (*p
); ++p
)
210 size_t len
= strlen (p
) + 1;
211 if (__builtin_expect (len
> buflen
, 0))
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
;
235 return NSS_STATUS_SUCCESS
;
239 _nss_nis_getservent_r (struct servent
*serv
, char *buffer
, size_t buflen
,
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
);
254 _nss_nis_getservbyname_r (const char *name
, const char *protocol
,
255 struct servent
*serv
, char *buffer
, size_t buflen
,
261 return NSS_STATUS_UNAVAIL
;
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
)
278 strcpy (cp
, protocol
);
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))
295 return NSS_STATUS_TRYAGAIN
;
298 char *p
= strncpy (buffer
, result
, len
);
304 int parse_res
= _nss_files_parse_servent (p
, serv
, (void *) buffer
,
306 if (__builtin_expect (parse_res
< 0, 0))
309 return NSS_STATUS_TRYAGAIN
;
311 return NSS_STATUS_NOTFOUND
;
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
;
324 ypcb
.foreach
= dosearch
;
325 ypcb
.data
= (char *) &req
;
327 req
.proto
= protocol
;
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
);
343 _nss_nis_getservbyport_r (int port
, const char *protocol
,
344 struct servent
*serv
, char *buffer
,
345 size_t buflen
, int *errnop
)
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
),
364 int status
= yp_match (domain
, "services.byname", key
, keylen
, &result
,
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))
376 return NSS_STATUS_TRYAGAIN
;
379 char *p
= strncpy (buffer
, result
, len
);
384 int parse_res
= _nss_files_parse_servent (p
, serv
, (void *) buffer
,
386 if (__builtin_expect (parse_res
< 0, 0))
389 return NSS_STATUS_TRYAGAIN
;
391 return NSS_STATUS_NOTFOUND
;
394 return NSS_STATUS_SUCCESS
;
397 while (protocol
== NULL
&& (proto
[0] == 't' ? (proto
= "udp") : NULL
));
400 return NSS_STATUS_NOTFOUND
;
402 struct ypall_callback ypcb
;
405 ypcb
.foreach
= dosearch
;
406 ypcb
.data
= (char *) &req
;
408 req
.proto
= protocol
;
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
);