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 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
207 bucket
= intern
.next
= bucket
->next
;
211 for (p
= &bucket
->mem
[intern
.offset
]; isspace (*p
); ++p
)
214 size_t len
= strlen (p
) + 1;
215 if (__builtin_expect (len
> buflen
, 0))
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
;
239 return NSS_STATUS_SUCCESS
;
243 _nss_nis_getservent_r (struct servent
*serv
, char *buffer
, size_t buflen
,
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
);
258 _nss_nis_getservbyname_r (const char *name
, const char *protocol
,
259 struct servent
*serv
, char *buffer
, size_t buflen
,
265 return NSS_STATUS_UNAVAIL
;
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
)
282 strcpy (cp
, protocol
);
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))
299 return NSS_STATUS_TRYAGAIN
;
302 char *p
= strncpy (buffer
, result
, len
);
308 int parse_res
= _nss_files_parse_servent (p
, serv
, (void *) buffer
,
310 if (__builtin_expect (parse_res
< 0, 0))
313 return NSS_STATUS_TRYAGAIN
;
315 return NSS_STATUS_NOTFOUND
;
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
;
328 ypcb
.foreach
= dosearch
;
329 ypcb
.data
= (char *) &req
;
331 req
.proto
= protocol
;
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
);
347 _nss_nis_getservbyport_r (int port
, const char *protocol
,
348 struct servent
*serv
, char *buffer
,
349 size_t buflen
, int *errnop
)
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
),
368 int status
= yp_match (domain
, "services.byname", key
, keylen
, &result
,
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))
380 return NSS_STATUS_TRYAGAIN
;
383 char *p
= strncpy (buffer
, result
, len
);
388 int parse_res
= _nss_files_parse_servent (p
, serv
, (void *) buffer
,
390 if (__builtin_expect (parse_res
< 0, 0))
393 return NSS_STATUS_TRYAGAIN
;
395 return NSS_STATUS_NOTFOUND
;
398 return NSS_STATUS_SUCCESS
;
401 while (protocol
== NULL
&& (proto
[0] == 't' ? (proto
= "udp") : NULL
));
404 return NSS_STATUS_NOTFOUND
;
406 struct ypall_callback ypcb
;
409 ypcb
.foreach
= dosearch
;
410 ypcb
.data
= (char *) &req
;
412 req
.proto
= protocol
;
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
);