1 /* Copyright (C) 1996-2001, 2002, 2003, 2004 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>
32 /* Get the declaration of the parser function. */
33 #define ENTNAME servent
35 #include <nss/nss_files/files-parse.c>
37 __libc_lock_define_initialized (static, lock
)
41 struct response_t
*next
;
47 struct response_t
*start
;
48 struct response_t
*next
;
50 typedef struct intern_t intern_t
;
52 static intern_t intern
= { NULL
, NULL
};
59 enum nss_status status
;
67 saveit (int instatus
, char *inkey
, int inkeylen
, char *inval
,
68 int invallen
, char *indata
)
70 intern_t
*intern
= (intern_t
*) indata
;
72 if (instatus
!= YP_TRUE
)
75 if (inkey
&& inkeylen
> 0 && inval
&& invallen
> 0)
77 struct response_t
*newp
= malloc (sizeof (struct response_t
)
80 return 1; /* We have no error code for out of memory */
82 if (intern
->start
== NULL
)
85 intern
->next
->next
= newp
;
89 *((char *) mempcpy (newp
->val
, inval
, invallen
)) = '\0';
96 dosearch (int instatus
, char *inkey
, int inkeylen
, char *inval
,
97 int invallen
, char *indata
)
99 struct search_t
*req
= (struct search_t
*) indata
;
101 if (instatus
!= YP_TRUE
)
104 if (inkey
&& inkeylen
> 0 && inval
&& invallen
> 0)
106 struct parser_data
*pdata
= (void *) req
->buffer
;
110 if ((size_t) (invallen
+ 1) > req
->buflen
)
112 *req
->errnop
= ERANGE
;
113 req
->status
= NSS_STATUS_TRYAGAIN
;
117 p
= strncpy (req
->buffer
, inval
, invallen
);
118 req
->buffer
[invallen
] = '\0';
122 parse_res
= _nss_files_parse_servent (p
, req
->serv
, pdata
, req
->buflen
,
126 req
->status
= NSS_STATUS_TRYAGAIN
;
133 if (req
->proto
!= NULL
&& strcmp (req
->serv
->s_proto
, req
->proto
) != 0)
136 if (req
->port
!= -1 && req
->serv
->s_port
!= req
->port
)
139 if (req
->name
!= NULL
&& strcmp (req
->serv
->s_name
, req
->name
) != 0)
142 for (cp
= req
->serv
->s_aliases
; *cp
; cp
++)
143 if (strcmp (req
->name
, *cp
) == 0)
150 req
->status
= NSS_STATUS_SUCCESS
;
157 static enum nss_status
158 internal_nis_endservent (intern_t
* intern
)
160 while (intern
->start
!= NULL
)
162 intern
->next
= intern
->start
;
163 intern
->start
= intern
->start
->next
;
167 return NSS_STATUS_SUCCESS
;
171 _nss_nis_endservent (void)
173 enum nss_status status
;
175 __libc_lock_lock (lock
);
177 status
= internal_nis_endservent (&intern
);
179 __libc_lock_unlock (lock
);
184 static enum nss_status
185 internal_nis_setservent (intern_t
*intern
)
188 struct ypall_callback ypcb
;
189 enum nss_status status
;
191 if (yp_get_default_domain (&domainname
))
192 return NSS_STATUS_UNAVAIL
;
194 (void) internal_nis_endservent (intern
);
196 ypcb
.foreach
= saveit
;
197 ypcb
.data
= (char *) intern
;
198 status
= yperr2nss (yp_all (domainname
, "services.byname", &ypcb
));
199 intern
->next
= intern
->start
;
205 _nss_nis_setservent (int stayopen
)
207 enum nss_status status
;
209 __libc_lock_lock (lock
);
211 status
= internal_nis_setservent (&intern
);
213 __libc_lock_unlock (lock
);
218 static enum nss_status
219 internal_nis_getservent_r (struct servent
*serv
, char *buffer
,
220 size_t buflen
, int *errnop
, intern_t
*data
)
222 struct parser_data
*pdata
= (void *) buffer
;
226 if (data
->start
== NULL
)
227 internal_nis_setservent (data
);
229 /* Get the next entry until we found a correct one. */
232 if (data
->next
== NULL
)
233 return NSS_STATUS_NOTFOUND
;
235 p
= strncpy (buffer
, data
->next
->val
, buflen
);
239 parse_res
= _nss_files_parse_servent (p
, serv
, pdata
, buflen
, errnop
);
241 return NSS_STATUS_TRYAGAIN
;
242 data
->next
= data
->next
->next
;
246 return NSS_STATUS_SUCCESS
;
250 _nss_nis_getservent_r (struct servent
*serv
, char *buffer
, size_t buflen
,
253 enum nss_status status
;
255 __libc_lock_lock (lock
);
257 status
= internal_nis_getservent_r (serv
, buffer
, buflen
, errnop
, &intern
);
259 __libc_lock_unlock (lock
);
265 _nss_nis_getservbyname_r (const char *name
, const char *protocol
,
266 struct servent
*serv
, char *buffer
, size_t buflen
,
269 enum nss_status status
;
275 return NSS_STATUS_UNAVAIL
;
278 if (yp_get_default_domain (&domain
))
279 return NSS_STATUS_UNAVAIL
;
281 /* If the protocol is given, we could try if our NIS server knows
282 about services.byservicename map. If yes, we only need one query. */
283 char key
[strlen (name
) + (protocol
? strlen (protocol
) : 0) + 2];
288 /* key is: "name/proto" */
289 cp
= stpcpy (key
, name
);
293 strcpy (cp
, protocol
);
295 keylen
= strlen (key
);
296 status
= yperr2nss (yp_match (domain
, "services.byservicename", key
,
297 keylen
, &result
, &int_len
));
300 /* If we found the key, it's ok and parse the result. If not,
301 fall through and parse the complete table. */
302 if (status
== NSS_STATUS_SUCCESS
)
304 struct parser_data
*pdata
= (void *) buffer
;
308 if ((size_t) (len
+ 1) > buflen
)
312 return NSS_STATUS_TRYAGAIN
;
315 p
= strncpy (buffer
, result
, len
);
320 parse_res
= _nss_files_parse_servent (p
, serv
, pdata
,
325 return NSS_STATUS_TRYAGAIN
;
327 return NSS_STATUS_NOTFOUND
;
330 return NSS_STATUS_SUCCESS
;
333 /* Check if it is safe to rely on services.byservicename. */
334 if (_nis_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE
)
337 struct ypall_callback ypcb
;
340 ypcb
.foreach
= dosearch
;
341 ypcb
.data
= (char *) &req
;
343 req
.proto
= protocol
;
349 req
.status
= NSS_STATUS_NOTFOUND
;
350 status
= yperr2nss (yp_all (domain
, "services.byname", &ypcb
));
352 if (status
!= NSS_STATUS_SUCCESS
)
359 _nss_nis_getservbyport_r (int port
, const char *protocol
,
360 struct servent
*serv
, char *buffer
,
361 size_t buflen
, int *errnop
)
363 enum nss_status status
;
366 if (yp_get_default_domain (&domain
))
367 return NSS_STATUS_UNAVAIL
;
369 /* If the protocol is given, we only need one query.
370 Otherwise try first port/tcp, then port/udp and then fallback
371 to sequential scanning of services.byname. */
372 const char *proto
= protocol
!= NULL
? protocol
: "tcp";
375 char key
[sizeof (int) * 3 + strlen (proto
) + 2];
380 /* key is: "port/proto" */
381 keylen
= snprintf (key
, sizeof (key
), "%d/%s", ntohs (port
), proto
);
382 status
= yperr2nss (yp_match (domain
, "services.byname", key
,
383 keylen
, &result
, &int_len
));
386 /* If we found the key, it's ok and parse the result. If not,
387 fall through and parse the complete table. */
388 if (status
== NSS_STATUS_SUCCESS
)
390 struct parser_data
*pdata
= (void *) buffer
;
394 if ((size_t) (len
+ 1) > buflen
)
398 return NSS_STATUS_TRYAGAIN
;
401 p
= strncpy (buffer
, result
, len
);
406 parse_res
= _nss_files_parse_servent (p
, serv
, pdata
,
411 return NSS_STATUS_TRYAGAIN
;
413 return NSS_STATUS_NOTFOUND
;
416 return NSS_STATUS_SUCCESS
;
419 while (protocol
== NULL
&& (proto
[0] == 't' ? (proto
= "udp") : NULL
));
422 return NSS_STATUS_NOTFOUND
;
424 struct ypall_callback ypcb
;
427 ypcb
.foreach
= dosearch
;
428 ypcb
.data
= (char *) &req
;
430 req
.proto
= protocol
;
436 req
.status
= NSS_STATUS_NOTFOUND
;
437 status
= yperr2nss (yp_all (domain
, "services.byname", &ypcb
));
439 if (status
!= NSS_STATUS_SUCCESS
)