]>
Commit | Line | Data |
---|---|---|
0ecb606c | 1 | /* Copyright (C) 1996-2004, 2006 Free Software Foundation, Inc. |
6259ec0d | 2 | This file is part of the GNU C Library. |
d6f6ffa1 | 3 | Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996. |
6259ec0d UD |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
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. | |
6259ec0d UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
6259ec0d | 14 | |
41bdb6e2 AJ |
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. */ | |
6259ec0d UD |
19 | |
20 | #include <nss.h> | |
21 | #include <netdb.h> | |
22 | #include <ctype.h> | |
23 | #include <errno.h> | |
24 | #include <string.h> | |
5107cf1d | 25 | #include <bits/libc-lock.h> |
6259ec0d UD |
26 | #include <rpcsvc/yp.h> |
27 | #include <rpcsvc/ypclnt.h> | |
28 | ||
29 | #include "nss-nis.h" | |
0ecb606c | 30 | #include <libnsl.h> |
6259ec0d | 31 | |
f8b87ef0 | 32 | |
5713a71e UD |
33 | /* Get the declaration of the parser function. */ |
34 | #define ENTNAME servent | |
35 | #define EXTERN_PARSER | |
36 | #include <nss/nss_files/files-parse.c> | |
f8b87ef0 | 37 | |
6259ec0d UD |
38 | __libc_lock_define_initialized (static, lock) |
39 | ||
0ecb606c | 40 | static intern_t intern; |
f166d865 | 41 | |
3b0b6c36 UD |
42 | struct search_t |
43 | { | |
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; | |
52 | }; | |
53 | ||
3b0b6c36 UD |
54 | static int |
55 | dosearch (int instatus, char *inkey, int inkeylen, char *inval, | |
56 | int invallen, char *indata) | |
57 | { | |
58 | struct search_t *req = (struct search_t *) indata; | |
59 | ||
0ecb606c | 60 | if (__builtin_expect (instatus != YP_TRUE, 0)) |
3b0b6c36 UD |
61 | return 1; |
62 | ||
63 | if (inkey && inkeylen > 0 && inval && invallen > 0) | |
64 | { | |
0ecb606c | 65 | if (__builtin_expect ((size_t) (invallen + 1) > req->buflen, 0)) |
3b0b6c36 UD |
66 | { |
67 | *req->errnop = ERANGE; | |
68 | req->status = NSS_STATUS_TRYAGAIN; | |
69 | return 1; | |
70 | } | |
71 | ||
0ecb606c | 72 | char *p = strncpy (req->buffer, inval, invallen); |
3b0b6c36 UD |
73 | req->buffer[invallen] = '\0'; |
74 | while (isspace (*p)) | |
75 | ++p; | |
76 | ||
0ecb606c JJ |
77 | int parse_res = _nss_files_parse_servent (p, req->serv, |
78 | (void *) req->buffer, | |
79 | req->buflen, req->errnop); | |
3b0b6c36 UD |
80 | if (parse_res == -1) |
81 | { | |
82 | req->status = NSS_STATUS_TRYAGAIN; | |
83 | return 1; | |
84 | } | |
85 | ||
86 | if (!parse_res) | |
87 | return 0; | |
88 | ||
89 | if (req->proto != NULL && strcmp (req->serv->s_proto, req->proto) != 0) | |
90 | return 0; | |
91 | ||
92 | if (req->port != -1 && req->serv->s_port != req->port) | |
93 | return 0; | |
94 | ||
95 | if (req->name != NULL && strcmp (req->serv->s_name, req->name) != 0) | |
96 | { | |
97 | char **cp; | |
98 | for (cp = req->serv->s_aliases; *cp; cp++) | |
99 | if (strcmp (req->name, *cp) == 0) | |
100 | break; | |
101 | ||
102 | if (*cp == NULL) | |
103 | return 0; | |
104 | } | |
105 | ||
106 | req->status = NSS_STATUS_SUCCESS; | |
107 | return 1; | |
108 | } | |
109 | ||
110 | return 0; | |
111 | } | |
112 | ||
0ecb606c JJ |
113 | static void |
114 | internal_nis_endservent (void) | |
6259ec0d | 115 | { |
0ecb606c JJ |
116 | struct response_t *curr = intern.next; |
117 | ||
118 | while (curr != NULL) | |
6259ec0d | 119 | { |
0ecb606c JJ |
120 | struct response_t *last = curr; |
121 | curr = curr->next; | |
122 | free (last); | |
6259ec0d | 123 | } |
f166d865 | 124 | |
0ecb606c | 125 | intern.next = intern.start = NULL; |
6259ec0d | 126 | } |
6675b191 | 127 | |
6259ec0d | 128 | enum nss_status |
6675b191 | 129 | _nss_nis_endservent (void) |
6259ec0d | 130 | { |
6259ec0d UD |
131 | __libc_lock_lock (lock); |
132 | ||
0ecb606c | 133 | internal_nis_endservent (); |
6259ec0d UD |
134 | |
135 | __libc_lock_unlock (lock); | |
136 | ||
0ecb606c | 137 | return NSS_STATUS_SUCCESS; |
6259ec0d UD |
138 | } |
139 | ||
140 | static enum nss_status | |
0ecb606c | 141 | internal_nis_setservent (void) |
6259ec0d | 142 | { |
6675b191 UD |
143 | char *domainname; |
144 | struct ypall_callback ypcb; | |
145 | enum nss_status status; | |
0d8733c4 | 146 | |
6675b191 UD |
147 | if (yp_get_default_domain (&domainname)) |
148 | return NSS_STATUS_UNAVAIL; | |
6259ec0d | 149 | |
0ecb606c | 150 | internal_nis_endservent (); |
6675b191 | 151 | |
0ecb606c JJ |
152 | ypcb.foreach = _nis_saveit; |
153 | ypcb.data = (char *) &intern; | |
6675b191 | 154 | status = yperr2nss (yp_all (domainname, "services.byname", &ypcb)); |
0ecb606c JJ |
155 | |
156 | /* Mark the last buffer as full. */ | |
157 | if (intern.next != NULL) | |
158 | intern.next->size = intern.offset; | |
159 | ||
160 | intern.next = intern.start; | |
161 | intern.offset = 0; | |
6675b191 UD |
162 | |
163 | return status; | |
164 | } | |
3b0b6c36 | 165 | |
6259ec0d | 166 | enum nss_status |
6675b191 | 167 | _nss_nis_setservent (int stayopen) |
6259ec0d UD |
168 | { |
169 | enum nss_status status; | |
170 | ||
171 | __libc_lock_lock (lock); | |
172 | ||
0ecb606c | 173 | status = internal_nis_setservent (); |
6259ec0d UD |
174 | |
175 | __libc_lock_unlock (lock); | |
176 | ||
177 | return status; | |
178 | } | |
179 | ||
180 | static enum nss_status | |
181 | internal_nis_getservent_r (struct servent *serv, char *buffer, | |
0ecb606c | 182 | size_t buflen, int *errnop) |
6259ec0d | 183 | { |
5713a71e | 184 | struct parser_data *pdata = (void *) buffer; |
f166d865 | 185 | int parse_res; |
6259ec0d UD |
186 | char *p; |
187 | ||
0ecb606c JJ |
188 | if (intern.start == NULL) |
189 | internal_nis_setservent (); | |
0d8733c4 | 190 | |
0ecb606c JJ |
191 | if (intern.next == NULL) |
192 | /* Not one entry in the map. */ | |
193 | return NSS_STATUS_NOTFOUND; | |
194 | ||
195 | /* Get the next entry until we found a correct one. */ | |
6259ec0d UD |
196 | do |
197 | { | |
0ecb606c | 198 | struct response_t *bucket = intern.next; |
34816665 | 199 | |
0ecb606c JJ |
200 | if (__builtin_expect (intern.offset >= bucket->size, 0)) |
201 | { | |
202 | if (bucket->next == NULL) | |
203 | return NSS_STATUS_NOTFOUND; | |
204 | ||
205 | /* We look at all the content in the current bucket. Go on | |
206 | to the next. */ | |
207 | bucket = intern.next = bucket->next; | |
208 | intern.offset = 0; | |
209 | } | |
210 | ||
211 | for (p = &bucket->mem[intern.offset]; isspace (*p); ++p) | |
212 | ++intern.offset; | |
213 | ||
214 | size_t len = strlen (p) + 1; | |
215 | if (__builtin_expect (len > buflen, 0)) | |
216 | { | |
217 | *errnop = ERANGE; | |
218 | return NSS_STATUS_TRYAGAIN; | |
219 | } | |
220 | ||
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. | |
226 | ||
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); | |
0d8733c4 | 230 | |
5713a71e | 231 | parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop); |
0ecb606c | 232 | if (__builtin_expect (parse_res == -1, 0)) |
6259ec0d | 233 | return NSS_STATUS_TRYAGAIN; |
0ecb606c JJ |
234 | |
235 | intern.offset += len; | |
6259ec0d UD |
236 | } |
237 | while (!parse_res); | |
238 | ||
239 | return NSS_STATUS_SUCCESS; | |
240 | } | |
241 | ||
242 | enum nss_status | |
d71b808a UD |
243 | _nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen, |
244 | int *errnop) | |
6259ec0d UD |
245 | { |
246 | enum nss_status status; | |
247 | ||
248 | __libc_lock_lock (lock); | |
249 | ||
0ecb606c | 250 | status = internal_nis_getservent_r (serv, buffer, buflen, errnop); |
6259ec0d UD |
251 | |
252 | __libc_lock_unlock (lock); | |
253 | ||
254 | return status; | |
255 | } | |
256 | ||
257 | enum nss_status | |
51eecc4a | 258 | _nss_nis_getservbyname_r (const char *name, const char *protocol, |
d71b808a UD |
259 | struct servent *serv, char *buffer, size_t buflen, |
260 | int *errnop) | |
6259ec0d | 261 | { |
e61abf83 | 262 | if (name == NULL) |
6259ec0d | 263 | { |
ac9f45cf | 264 | *errnop = EINVAL; |
6259ec0d UD |
265 | return NSS_STATUS_UNAVAIL; |
266 | } | |
267 | ||
0ecb606c JJ |
268 | char *domain; |
269 | if (__builtin_expect (yp_get_default_domain (&domain), 0)) | |
3b0b6c36 UD |
270 | return NSS_STATUS_UNAVAIL; |
271 | ||
b85697f6 | 272 | /* If the protocol is given, we could try if our NIS server knows |
dd047aa5 | 273 | about services.byservicename map. If yes, we only need one query. */ |
0ecb606c JJ |
274 | size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0); |
275 | char key[keylen + 1]; | |
dd047aa5 UD |
276 | |
277 | /* key is: "name/proto" */ | |
0ecb606c JJ |
278 | char *cp = stpcpy (key, name); |
279 | if (protocol != NULL) | |
b85697f6 | 280 | { |
b85697f6 | 281 | *cp++ = '/'; |
dd047aa5 UD |
282 | strcpy (cp, protocol); |
283 | } | |
0ecb606c JJ |
284 | |
285 | char *result; | |
286 | int int_len; | |
287 | int status = yp_match (domain, "services.byservicename", key, | |
288 | keylen, &result, &int_len); | |
289 | size_t len = int_len; | |
dd047aa5 UD |
290 | |
291 | /* If we found the key, it's ok and parse the result. If not, | |
292 | fall through and parse the complete table. */ | |
0ecb606c | 293 | if (__builtin_expect (status == YPERR_SUCCESS, 1)) |
dd047aa5 | 294 | { |
0ecb606c | 295 | if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) |
b85697f6 | 296 | { |
b85697f6 | 297 | free (result); |
dd047aa5 UD |
298 | *errnop = ERANGE; |
299 | return NSS_STATUS_TRYAGAIN; | |
300 | } | |
301 | ||
0ecb606c | 302 | char *p = strncpy (buffer, result, len); |
dd047aa5 UD |
303 | buffer[len] = '\0'; |
304 | while (isspace (*p)) | |
305 | ++p; | |
306 | free (result); | |
0ecb606c JJ |
307 | |
308 | int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, | |
309 | buflen, errnop); | |
310 | if (__builtin_expect (parse_res < 0, 0)) | |
dd047aa5 UD |
311 | { |
312 | if (parse_res == -1) | |
313 | return NSS_STATUS_TRYAGAIN; | |
b85697f6 | 314 | else |
dd047aa5 | 315 | return NSS_STATUS_NOTFOUND; |
b85697f6 | 316 | } |
dd047aa5 UD |
317 | else |
318 | return NSS_STATUS_SUCCESS; | |
b85697f6 UD |
319 | } |
320 | ||
4eb6619c | 321 | /* Check if it is safe to rely on services.byservicename. */ |
0ecb606c JJ |
322 | if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE) |
323 | return yperr2nss (status); | |
4eb6619c | 324 | |
3b0b6c36 UD |
325 | struct ypall_callback ypcb; |
326 | struct search_t req; | |
327 | ||
328 | ypcb.foreach = dosearch; | |
329 | ypcb.data = (char *) &req; | |
330 | req.name = name; | |
331 | req.proto = protocol; | |
332 | req.port = -1; | |
333 | req.serv = serv; | |
334 | req.buffer = buffer; | |
335 | req.buflen = buflen; | |
336 | req.errnop = errnop; | |
337 | req.status = NSS_STATUS_NOTFOUND; | |
0ecb606c | 338 | status = yp_all (domain, "services.byname", &ypcb); |
3b0b6c36 | 339 | |
0ecb606c JJ |
340 | if (__builtin_expect (status != YPERR_SUCCESS, 0)) |
341 | return yperr2nss (status); | |
6259ec0d | 342 | |
3b0b6c36 | 343 | return req.status; |
6259ec0d UD |
344 | } |
345 | ||
346 | enum nss_status | |
51eecc4a AJ |
347 | _nss_nis_getservbyport_r (int port, const char *protocol, |
348 | struct servent *serv, char *buffer, | |
349 | size_t buflen, int *errnop) | |
6259ec0d | 350 | { |
3b0b6c36 | 351 | char *domain; |
0ecb606c | 352 | if (__builtin_expect (yp_get_default_domain (&domain), 0)) |
3b0b6c36 | 353 | return NSS_STATUS_UNAVAIL; |
6259ec0d | 354 | |
a70e964e UD |
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"; | |
359 | do | |
6259ec0d | 360 | { |
0ecb606c | 361 | /* key is: "port/proto" */ |
a70e964e | 362 | char key[sizeof (int) * 3 + strlen (proto) + 2]; |
0ecb606c JJ |
363 | size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), |
364 | proto); | |
365 | ||
3b0b6c36 | 366 | char *result; |
c7e41631 | 367 | int int_len; |
0ecb606c JJ |
368 | int status = yp_match (domain, "services.byname", key, keylen, &result, |
369 | &int_len); | |
370 | size_t len = int_len; | |
b85697f6 UD |
371 | |
372 | /* If we found the key, it's ok and parse the result. If not, | |
373 | fall through and parse the complete table. */ | |
0ecb606c | 374 | if (__builtin_expect (status == YPERR_SUCCESS, 1)) |
b85697f6 | 375 | { |
0ecb606c | 376 | if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) |
b85697f6 UD |
377 | { |
378 | free (result); | |
379 | *errnop = ERANGE; | |
380 | return NSS_STATUS_TRYAGAIN; | |
381 | } | |
382 | ||
0ecb606c | 383 | char *p = strncpy (buffer, result, len); |
b85697f6 UD |
384 | buffer[len] = '\0'; |
385 | while (isspace (*p)) | |
386 | ++p; | |
387 | free (result); | |
0ecb606c JJ |
388 | int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer, |
389 | buflen, errnop); | |
390 | if (__builtin_expect (parse_res < 0, 0)) | |
b85697f6 UD |
391 | { |
392 | if (parse_res == -1) | |
393 | return NSS_STATUS_TRYAGAIN; | |
394 | else | |
34816665 | 395 | return NSS_STATUS_NOTFOUND; |
b85697f6 | 396 | } |
0ecb606c JJ |
397 | |
398 | return NSS_STATUS_SUCCESS; | |
b85697f6 | 399 | } |
6259ec0d | 400 | } |
a70e964e | 401 | while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL)); |
6259ec0d | 402 | |
3b0b6c36 UD |
403 | if (port == -1) |
404 | return NSS_STATUS_NOTFOUND; | |
6259ec0d | 405 | |
3b0b6c36 UD |
406 | struct ypall_callback ypcb; |
407 | struct search_t req; | |
408 | ||
409 | ypcb.foreach = dosearch; | |
410 | ypcb.data = (char *) &req; | |
411 | req.name = NULL; | |
412 | req.proto = protocol; | |
413 | req.port = port; | |
414 | req.serv = serv; | |
415 | req.buffer = buffer; | |
416 | req.buflen = buflen; | |
417 | req.errnop = errnop; | |
418 | req.status = NSS_STATUS_NOTFOUND; | |
0ecb606c | 419 | int status = yp_all (domain, "services.byname", &ypcb); |
6259ec0d | 420 | |
0ecb606c JJ |
421 | if (__builtin_expect (status != YPERR_SUCCESS, 0)) |
422 | return yperr2nss (status); | |
3b0b6c36 UD |
423 | |
424 | return req.status; | |
6259ec0d | 425 | } |