1/* Copyright (C) 1996-2016 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
4
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.
9
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.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#include <nss.h>
20#include <netdb.h>
21#include <ctype.h>
22#include <errno.h>
23#include <string.h>
24#include <libc-lock.h>
25#include <rpcsvc/yp.h>
26#include <rpcsvc/ypclnt.h>
27
28#include "nss-nis.h"
29
30/* Get the declaration of the parser function. */
31#define ENTNAME rpcent
32#define EXTERN_PARSER
33#include <nss/nss_files/files-parse.c>
34
35__libc_lock_define_initialized (static, lock)
36
37static intern_t intern;
38
39
40static void
41internal_nis_endrpcent (intern_t *intern)
42{
43 struct response_t *curr = intern->next;
44
45 while (curr != NULL)
46 {
47 struct response_t *last = curr;
48 curr = curr->next;
49 free (last);
50 }
51
52 intern->next = intern->start = NULL;
53}
54
55static enum nss_status
56internal_nis_setrpcent (intern_t *intern)
57{
58 char *domainname;
59 struct ypall_callback ypcb;
60 enum nss_status status;
61
62 if (yp_get_default_domain (&domainname))
63 return NSS_STATUS_UNAVAIL;
64
65 internal_nis_endrpcent (intern);
66
67 ypcb.foreach = _nis_saveit;
68 ypcb.data = (char *) intern;
69 status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb));
70
71 /* Mark the last buffer as full. */
72 if (intern->next != NULL)
73 intern->next->size = intern->offset;
74
75 intern->next = intern->start;
76 intern->offset = 0;
77
78 return status;
79}
80
81enum nss_status
82_nss_nis_setrpcent (int stayopen)
83{
84 enum nss_status status;
85
86 __libc_lock_lock (lock);
87
88 status = internal_nis_setrpcent (&intern);
89
90 __libc_lock_unlock (lock);
91
92 return status;
93}
94
95enum nss_status
96_nss_nis_endrpcent (void)
97{
98 __libc_lock_lock (lock);
99
100 internal_nis_endrpcent (&intern);
101
102 __libc_lock_unlock (lock);
103
104 return NSS_STATUS_SUCCESS;
105}
106
107static enum nss_status
108internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
109 int *errnop, intern_t *intern)
110{
111 struct parser_data *pdata = (void *) buffer;
112 int parse_res;
113 char *p;
114
115 if (intern->start == NULL)
116 internal_nis_setrpcent (intern);
117
118 if (intern->next == NULL)
119 /* Not one entry in the map. */
120 return NSS_STATUS_NOTFOUND;
121
122 /* Get the next entry until we found a correct one. */
123 do
124 {
125 struct response_t *bucket = intern->next;
126
127 if (__glibc_unlikely (intern->offset >= bucket->size))
128 {
129 if (bucket->next == NULL)
130 return NSS_STATUS_NOTFOUND;
131
132 /* We look at all the content in the current bucket. Go on
133 to the next. */
134 bucket = intern->next = bucket->next;
135 intern->offset = 0;
136 }
137
138 for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
139 ++intern->offset;
140
141 size_t len = strlen (p) + 1;
142 if (__glibc_unlikely (len > buflen))
143 {
144 *errnop = ERANGE;
145 return NSS_STATUS_TRYAGAIN;
146 }
147
148 /* We unfortunately have to copy the data in the user-provided
149 buffer because that buffer might be around for a very long
150 time and the servent structure must remain valid. If we would
151 rely on the BUCKET memory the next 'setservent' or 'endservent'
152 call would destroy it.
153
154 The important thing is that it is a single NUL-terminated
155 string. This is what the parsing routine expects. */
156 p = memcpy (buffer, &bucket->mem[intern->offset], len);
157
158 parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop);
159 if (__glibc_unlikely (parse_res == -1))
160 return NSS_STATUS_TRYAGAIN;
161
162 intern->offset += len;
163 }
164 while (!parse_res);
165
166 return NSS_STATUS_SUCCESS;
167}
168
169enum nss_status
170_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
171 int *errnop)
172{
173 enum nss_status status;
174
175 __libc_lock_lock (lock);
176
177 status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, &intern);
178
179 __libc_lock_unlock (lock);
180
181 return status;
182}
183
184enum nss_status
185_nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
186 char *buffer, size_t buflen, int *errnop)
187{
188 if (name == NULL)
189 {
190 *errnop = EINVAL;
191 return NSS_STATUS_UNAVAIL;
192 }
193
194 intern_t data = { NULL, NULL, 0 };
195 enum nss_status status = internal_nis_setrpcent (&data);
196 if (__glibc_unlikely (status != NSS_STATUS_SUCCESS))
197 return status;
198
199 int found = 0;
200 while (!found &&
201 ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop,
202 &data)) == NSS_STATUS_SUCCESS))
203 {
204 if (strcmp (rpc->r_name, name) == 0)
205 found = 1;
206 else
207 {
208 int i = 0;
209
210 while (rpc->r_aliases[i] != NULL)
211 {
212 if (strcmp (rpc->r_aliases[i], name) == 0)
213 {
214 found = 1;
215 break;
216 }
217 else
218 ++i;
219 }
220 }
221 }
222
223 internal_nis_endrpcent (&data);
224
225 if (__glibc_unlikely (!found && status == NSS_STATUS_SUCCESS))
226 return NSS_STATUS_NOTFOUND;
227
228 return status;
229}
230
231enum nss_status
232_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
233 char *buffer, size_t buflen, int *errnop)
234{
235 char *domain;
236 if (__glibc_unlikely (yp_get_default_domain (&domain)))
237 return NSS_STATUS_UNAVAIL;
238
239 char buf[32];
240 int nlen = snprintf (buf, sizeof (buf), "%d", number);
241
242 char *result;
243 int len;
244 int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len);
245
246 if (__glibc_unlikely (yperr != YPERR_SUCCESS))
247 {
248 enum nss_status retval = yperr2nss (yperr);
249
250 if (retval == NSS_STATUS_TRYAGAIN)
251 *errnop = errno;
252 return retval;
253 }
254
255 if (__glibc_unlikely ((size_t) (len + 1) > buflen))
256 {
257 free (result);
258 *errnop = ERANGE;
259 return NSS_STATUS_TRYAGAIN;
260 }
261
262 char *p = strncpy (buffer, result, len);
263 buffer[len] = '\0';
264 while (isspace (*p))
265 ++p;
266 free (result);
267
268 int parse_res = _nss_files_parse_rpcent (p, rpc, (void *) buffer, buflen,
269 errnop);
270 if (__glibc_unlikely (parse_res < 1))
271 {
272 if (parse_res == -1)
273 return NSS_STATUS_TRYAGAIN;
274 else
275 return NSS_STATUS_NOTFOUND;
276 }
277 else
278 return NSS_STATUS_SUCCESS;
279}
280