]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nss_nis/nis-service.c
2.5-18.1
[thirdparty/glibc.git] / nis / nss_nis / nis-service.c
CommitLineData
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 40static intern_t intern;
f166d865 41
3b0b6c36
UD
42struct 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
54static int
55dosearch (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
113static void
114internal_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 128enum 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
140static enum nss_status
0ecb606c 141internal_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 166enum 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
180static enum nss_status
181internal_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
242enum 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
257enum 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
346enum 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}