Deleted Added
full compact
getservent.c (157779) getservent.c (158115)
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 21 unchanged lines hidden (view full) ---

30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93";
36#endif /* LIBC_SCCS and not lint */
37#include <sys/cdefs.h>
1/*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 21 unchanged lines hidden (view full) ---

30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93";
36#endif /* LIBC_SCCS and not lint */
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/lib/libc/net/getservent.c 157779 2006-04-15 16:20:27Z ume $");
38__FBSDID("$FreeBSD: head/lib/libc/net/getservent.c 158115 2006-04-28 12:03:38Z ume $");
39
40#include <sys/param.h>
41#include <sys/types.h>
42#include <sys/socket.h>
43#include <arpa/inet.h>
44#include <errno.h>
45#include <limits.h>
46#include <netdb.h>
39
40#include <sys/param.h>
41#include <sys/types.h>
42#include <sys/socket.h>
43#include <arpa/inet.h>
44#include <errno.h>
45#include <limits.h>
46#include <netdb.h>
47#include <nsswitch.h>
47#include <stdio.h>
48#include <string.h>
49#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <stdlib.h>
51#include <unistd.h>
50#ifdef YP
51#include <rpc/rpc.h>
52#include <rpcsvc/yp_prot.h>
53#include <rpcsvc/ypclnt.h>
54#endif
55#include "namespace.h"
56#include "reentrant.h"
57#include "un-namespace.h"
58#include "netdb_private.h"
52#ifdef YP
53#include <rpc/rpc.h>
54#include <rpcsvc/yp_prot.h>
55#include <rpcsvc/ypclnt.h>
56#endif
57#include "namespace.h"
58#include "reentrant.h"
59#include "un-namespace.h"
60#include "netdb_private.h"
61#ifdef NS_CACHING
62#include "nscache.h"
63#endif
64#include "nss_tls.h"
59
65
60NETDB_THREAD_ALLOC(servent_data)
61NETDB_THREAD_ALLOC(servdata)
66enum constants
67{
68 SETSERVENT = 1,
69 ENDSERVENT = 2,
70 SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
71 SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
72};
62
73
63static void
64servent_data_clear(struct servent_data *sed)
74struct servent_mdata
65{
75{
66 if (sed->fp) {
67 fclose(sed->fp);
68 sed->fp = NULL;
69 }
76 enum nss_lookup_type how;
77 int compat_mode;
78};
79
80static const ns_src defaultsrc[] = {
81 { NSSRC_COMPAT, NS_SUCCESS },
82 { NULL, 0 }
83};
84
85static int servent_unpack(char *, struct servent *, char **, size_t, int *);
86
87/* files backend declarations */
88struct files_state
89{
90 FILE *fp;
91 int stayopen;
92
93 int compat_mode_active;
94};
95static void files_endstate(void *);
96NSS_TLS_HANDLING(files);
97
98static int files_servent(void *, void *, va_list);
99static int files_setservent(void *, void *, va_list);
100
70#ifdef YP
101#ifdef YP
71 free(sed->yp_key);
72 sed->yp_key = NULL;
102/* nis backend declarations */
103static int nis_servent(void *, void *, va_list);
104static int nis_setservent(void *, void *, va_list);
105
106struct nis_state
107{
108 int yp_stepping;
109 char yp_domain[MAXHOSTNAMELEN];
110 char *yp_key;
111 int yp_keylen;
112};
113static void nis_endstate(void *);
114NSS_TLS_HANDLING(nis);
115
116static int nis_servent(void *, void *, va_list);
117static int nis_setservent(void *, void *, va_list);
73#endif
118#endif
74}
75
119
76static void
77servent_data_free(void *ptr)
120/* compat backend declarations */
121static int compat_setservent(void *, void *, va_list);
122
123/* get** wrappers for get**_r functions declarations */
124struct servent_state {
125 struct servent serv;
126 char *buffer;
127 size_t bufsize;
128};
129static void servent_endstate(void *);
130NSS_TLS_HANDLING(servent);
131
132struct key {
133 const char *proto;
134 union {
135 const char *name;
136 int port;
137 };
138};
139
140static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
141 struct servent **);
142static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
143 struct servent **);
144static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
145 struct servent **);
146static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
147 size_t, struct servent **), struct key);
148
149#ifdef NS_CACHING
150static int serv_id_func(char *, size_t *, va_list, void *);
151static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
152static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
153#endif
154
155static int
156servent_unpack(char *p, struct servent *serv, char **aliases,
157 size_t aliases_size, int *errnop)
78{
158{
79 struct servent_data *sed = ptr;
159 char *cp, **q, *endp;
160 long l;
80
161
81 servent_data_clear(sed);
82 free(sed);
162 if (*p == '#')
163 return -1;
164
165 memset(serv, 0, sizeof(struct servent));
166
167 cp = strpbrk(p, "#\n");
168 if (cp != NULL)
169 *cp = '\0';
170 serv->s_name = p;
171
172 p = strpbrk(p, " \t");
173 if (p == NULL)
174 return -1;
175 *p++ = '\0';
176 while (*p == ' ' || *p == '\t')
177 p++;
178 cp = strpbrk(p, ",/");
179 if (cp == NULL)
180 return -1;
181
182 *cp++ = '\0';
183 l = strtol(p, &endp, 10);
184 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
185 return -1;
186 serv->s_port = htons((in_port_t)l);
187 serv->s_proto = cp;
188
189 q = serv->s_aliases = aliases;
190 cp = strpbrk(cp, " \t");
191 if (cp != NULL)
192 *cp++ = '\0';
193 while (cp && *cp) {
194 if (*cp == ' ' || *cp == '\t') {
195 cp++;
196 continue;
197 }
198 if (q < &aliases[aliases_size - 1]) {
199 *q++ = cp;
200 } else {
201 *q = NULL;
202 *errnop = ERANGE;
203 return -1;
204 }
205 cp = strpbrk(cp, " \t");
206 if (cp != NULL)
207 *cp++ = '\0';
208 }
209 *q = NULL;
210
211 return 0;
83}
84
212}
213
85static void
86servdata_free(void *ptr)
214/* files backend implementation */
215static void
216files_endstate(void *p)
87{
217{
88 free(ptr);
218 FILE * f;
219
220 if (p == NULL)
221 return;
222
223 f = ((struct files_state *)p)->fp;
224 if (f != NULL)
225 fclose(f);
226
227 free(p);
89}
90
228}
229
91int
92__copy_servent(struct servent *se, struct servent *sptr, char *buf,
93 size_t buflen)
230/*
231 * compat structures. compat and files sources functionalities are almost
232 * equal, so they all are managed by files_servent function
233 */
234static int
235files_servent(void *retval, void *mdata, va_list ap)
94{
236{
95 char *cp;
96 int i, n;
97 int numptr, len;
237 static const ns_src compat_src[] = {
238#ifdef YP
239 { NSSRC_NIS, NS_SUCCESS },
240#endif
241 { NULL, 0 }
242 };
243 ns_dtab compat_dtab[] = {
244#ifdef YP
245 { NSSRC_NIS, nis_servent,
246 (void *)((struct servent_mdata *)mdata)->how },
247#endif
248 { NULL, NULL, NULL }
249 };
98
250
99 /* Find out the amount of space required to store the answer. */
100 numptr = 1; /* NULL ptr */
101 len = (char *)ALIGN(buf) - buf;
102 for (i = 0; se->s_aliases[i]; i++, numptr++) {
103 len += strlen(se->s_aliases[i]) + 1;
251 struct files_state *st;
252 int rv;
253 int stayopen;
254
255 struct servent_mdata *serv_mdata;
256 char *name;
257 char *proto;
258 int port;
259
260 struct servent *serv;
261 char *buffer;
262 size_t bufsize;
263 int *errnop;
264
265 char **aliases;
266 int aliases_size;
267 size_t linesize;
268 char *line;
269 char **cp;
270
271 name = NULL;
272 proto = NULL;
273 serv_mdata = (struct servent_mdata *)mdata;
274 switch (serv_mdata->how) {
275 case nss_lt_name:
276 name = va_arg(ap, char *);
277 proto = va_arg(ap, char *);
278 break;
279 case nss_lt_id:
280 port = va_arg(ap, int);
281 proto = va_arg(ap, char *);
282 break;
283 case nss_lt_all:
284 break;
285 default:
286 return NS_NOTFOUND;
287 };
288
289 serv = va_arg(ap, struct servent *);
290 buffer = va_arg(ap, char *);
291 bufsize = va_arg(ap, size_t);
292 errnop = va_arg(ap,int *);
293
294 *errnop = files_getstate(&st);
295 if (*errnop != 0)
296 return (NS_UNAVAIL);
297
298 if (st->fp == NULL)
299 st->compat_mode_active = 0;
300
301 if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "r")) == NULL) {
302 *errnop = errno;
303 return (NS_UNAVAIL);
104 }
304 }
105 len += strlen(se->s_name) + 1;
106 len += strlen(se->s_proto) + 1;
107 len += numptr * sizeof(char*);
108
305
109 if (len > (int)buflen) {
110 errno = ERANGE;
111 return (-1);
306 if (serv_mdata->how == nss_lt_all)
307 stayopen = 1;
308 else {
309 rewind(st->fp);
310 stayopen = st->stayopen;
112 }
113
311 }
312
114 /* copy port value */
115 sptr->s_port = se->s_port;
313 rv = NS_NOTFOUND;
314 do {
315 if (!st->compat_mode_active) {
316 if ((line = fgetln(st->fp, &linesize)) == NULL) {
317 *errnop = errno;
318 rv = NS_RETURN;
319 break;
320 }
116
321
117 cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
322 if (*line=='+') {
323 if (serv_mdata->compat_mode != 0)
324 st->compat_mode_active = 1;
325 } else {
326 if (bufsize <= linesize + _ALIGNBYTES +
327 sizeof(char *)) {
328 *errnop = ERANGE;
329 rv = NS_RETURN;
330 break;
331 }
332 aliases = (char **)_ALIGN(&buffer[linesize+1]);
333 aliases_size = (buffer + bufsize -
334 (char *)aliases) / sizeof(char *);
335 if (aliases_size < 1) {
336 *errnop = ERANGE;
337 rv = NS_RETURN;
338 break;
339 }
118
340
119 /* copy official name */
120 n = strlen(se->s_name) + 1;
121 strcpy(cp, se->s_name);
122 sptr->s_name = cp;
123 cp += n;
341 memcpy(buffer, line, linesize);
342 buffer[linesize] = '\0';
343 }
344 }
124
345
125 /* copy aliases */
126 sptr->s_aliases = (char **)ALIGN(buf);
127 for (i = 0 ; se->s_aliases[i]; i++) {
128 n = strlen(se->s_aliases[i]) + 1;
129 strcpy(cp, se->s_aliases[i]);
130 sptr->s_aliases[i] = cp;
131 cp += n;
346 if (st->compat_mode_active != 0) {
347 switch (serv_mdata->how) {
348 case nss_lt_name:
349 rv = nsdispatch(retval, compat_dtab,
350 NSDB_SERVICES_COMPAT, "getservbyname_r",
351 compat_src, name, proto, serv, buffer,
352 bufsize, errnop);
353 break;
354 case nss_lt_id:
355 rv = nsdispatch(retval, compat_dtab,
356 NSDB_SERVICES_COMPAT, "getservbyport_r",
357 compat_src, port, proto, serv, buffer,
358 bufsize, errnop);
359 break;
360 case nss_lt_all:
361 rv = nsdispatch(retval, compat_dtab,
362 NSDB_SERVICES_COMPAT, "getservent_r",
363 compat_src, serv, buffer, bufsize, errnop);
364 break;
365 }
366
367 if (!(rv & NS_TERMINATE) ||
368 serv_mdata->how != nss_lt_all)
369 st->compat_mode_active = 0;
370
371 continue;
372 }
373
374 rv = servent_unpack(buffer, serv, aliases, aliases_size,
375 errnop);
376 if (rv !=0 ) {
377 if (*errnop == 0) {
378 rv = NS_NOTFOUND;
379 continue;
380 }
381 else {
382 rv = NS_RETURN;
383 break;
384 }
385 }
386
387 rv = NS_NOTFOUND;
388 switch (serv_mdata->how) {
389 case nss_lt_name:
390 if (strcmp(name, serv->s_name) == 0)
391 goto gotname;
392 for (cp = serv->s_aliases; *cp; cp++)
393 if (strcmp(name, *cp) == 0)
394 goto gotname;
395
396 continue;
397 gotname:
398 if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
399 rv = NS_SUCCESS;
400 break;
401 case nss_lt_id:
402 if (port != serv->s_port)
403 continue;
404
405 if (proto == 0 || strcmp(serv->s_proto, proto) == 0)
406 rv = NS_SUCCESS;
407 break;
408 case nss_lt_all:
409 rv = NS_SUCCESS;
410 break;
411 }
412
413 } while (!(rv & NS_TERMINATE));
414
415 if (!stayopen && st->fp != NULL) {
416 fclose(st->fp);
417 st->fp = NULL;
132 }
418 }
133 sptr->s_aliases[i] = NULL;
134
419
135 /* copy proto */
136 n = strlen(se->s_proto) + 1;
137 strcpy(cp, se->s_proto);
138 sptr->s_proto = cp;
139 cp += n;
420 if ((rv == NS_SUCCESS) && (retval != NULL))
421 *(struct servent **)retval=serv;
140
422
141 return (0);
423 return (rv);
142}
143
424}
425
426static int
427files_setservent(void *retval, void *mdata, va_list ap)
428{
429 struct files_state *st;
430 int rv;
431 int f;
432
433 rv = files_getstate(&st);
434 if (rv != 0)
435 return (NS_UNAVAIL);
436
437 switch ((enum constants)mdata) {
438 case SETSERVENT:
439 f = va_arg(ap,int);
440 if (st->fp == NULL)
441 st->fp = fopen(_PATH_SERVICES, "r");
442 else
443 rewind(st->fp);
444 st->stayopen |= f;
445 break;
446 case ENDSERVENT:
447 if (st->fp != NULL) {
448 fclose(st->fp);
449 st->fp = NULL;
450 }
451 st->stayopen = 0;
452 break;
453 default:
454 break;
455 };
456
457 st->compat_mode_active = 0;
458 return (NS_UNAVAIL);
459}
460
461/* nis backend implementation */
144#ifdef YP
462#ifdef YP
463static void
464nis_endstate(void *p)
465{
466 if (p == NULL)
467 return;
468
469 free(((struct nis_state *)p)->yp_key);
470 free(p);
471}
472
145static int
473static int
146_getservbyport_yp(struct servent_data *sed)
474nis_servent(void *retval, void *mdata, va_list ap)
147{
475{
148 char *result;
149 int resultlen;
476 char *resultbuf, *lastkey;
477 int resultbuflen;
150 char buf[YPMAXRECORD + 2];
478 char buf[YPMAXRECORD + 2];
479
480 struct nis_state *st;
151 int rv;
152
481 int rv;
482
153 snprintf(buf, sizeof(buf), "%d/%s", ntohs(sed->yp_port),
154 sed->yp_proto);
483 enum nss_lookup_type how;
484 char *name;
485 char *proto;
486 int port;
155
487
156 sed->yp_port = 0;
157 sed->yp_proto = NULL;
488 struct servent *serv;
489 char *buffer;
490 size_t bufsize;
491 int *errnop;
158
492
159 if (!sed->yp_domain) {
160 if (yp_get_default_domain(&sed->yp_domain))
161 return (0);
493 char **aliases;
494 int aliases_size;
495
496 name = NULL;
497 proto = NULL;
498 how = (enum nss_lookup_type)mdata;
499 switch (how) {
500 case nss_lt_name:
501 name = va_arg(ap, char *);
502 proto = va_arg(ap, char *);
503 break;
504 case nss_lt_id:
505 port = va_arg(ap, int);
506 proto = va_arg(ap, char *);
507 break;
508 case nss_lt_all:
509 break;
510 default:
511 return NS_NOTFOUND;
512 };
513
514 serv = va_arg(ap, struct servent *);
515 buffer = va_arg(ap, char *);
516 bufsize = va_arg(ap, size_t);
517 errnop = va_arg(ap, int *);
518
519 *errnop = nis_getstate(&st);
520 if (*errnop != 0)
521 return (NS_UNAVAIL);
522
523 if (st->yp_domain[0] == '\0') {
524 if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
525 *errnop = errno;
526 return (NS_UNAVAIL);
527 }
162 }
163
528 }
529
164 /*
165 * We have to be a little flexible here. Ideally you're supposed
166 * to have both a services.byname and a services.byport map, but
167 * some systems have only services.byname. FreeBSD cheats a little
168 * by putting the services.byport information in the same map as
169 * services.byname so that either case will work. We allow for both
170 * possibilities here: if there is no services.byport map, we try
171 * services.byname instead.
172 */
173 if ((rv = yp_match(sed->yp_domain, "services.byport", buf, strlen(buf),
174 &result, &resultlen))) {
175 if (rv == YPERR_MAP) {
176 if (yp_match(sed->yp_domain, "services.byname", buf,
177 strlen(buf), &result, &resultlen))
178 return(0);
530 do {
531 switch (how) {
532 case nss_lt_name:
533 snprintf(buf, sizeof(buf), "%s/%s", name, proto);
534 if (yp_match(st->yp_domain, "services.byname", buf,
535 strlen(buf), &resultbuf, &resultbuflen)) {
536 rv = NS_NOTFOUND;
537 goto fin;
538 }
539 break;
540 case nss_lt_id:
541 snprintf(buf, sizeof(buf), "%d/%s", ntohs(port),
542 proto);
543
544 /*
545 * We have to be a little flexible
546 * here. Ideally you're supposed to have both
547 * a services.byname and a services.byport
548 * map, but some systems have only
549 * services.byname. FreeBSD cheats a little by
550 * putting the services.byport information in
551 * the same map as services.byname so that
552 * either case will work. We allow for both
553 * possibilities here: if there is no
554 * services.byport map, we try services.byname
555 * instead.
556 */
557 rv = yp_match(st->yp_domain, "services.byport", buf,
558 strlen(buf), &resultbuf, &resultbuflen);
559 if (rv) {
560 if (rv == YPERR_MAP) {
561 if (yp_match(st->yp_domain,
562 "services.byname", buf,
563 strlen(buf), &resultbuf,
564 &resultbuflen)) {
565 rv = NS_NOTFOUND;
566 goto fin;
567 }
568 } else {
569 rv = NS_NOTFOUND;
570 goto fin;
571 }
572 }
573
574 break;
575 case nss_lt_all:
576 if (!st->yp_stepping) {
577 free(st->yp_key);
578 rv = yp_first(st->yp_domain, "services.byname",
579 &st->yp_key, &st->yp_keylen, &resultbuf,
580 &resultbuflen);
581 if (rv) {
582 rv = NS_NOTFOUND;
583 goto fin;
584 }
585 st->yp_stepping = 1;
586 } else {
587 lastkey = st->yp_key;
588 rv = yp_next(st->yp_domain, "services.byname",
589 st->yp_key, st->yp_keylen, &st->yp_key,
590 &st->yp_keylen, &resultbuf, &resultbuflen);
591 free(lastkey);
592 if (rv) {
593 st->yp_stepping = 0;
594 rv = NS_NOTFOUND;
595 goto fin;
596 }
597 }
598 break;
599 };
600
601 /* we need a room for additional \n symbol */
602 if (bufsize <=
603 resultbuflen + 1 + _ALIGNBYTES + sizeof(char *)) {
604 *errnop = ERANGE;
605 rv = NS_RETURN;
606 break;
607 }
608
609 aliases = (char **)_ALIGN(&buffer[resultbuflen + 2]);
610 aliases_size =
611 (buffer + bufsize - (char *)aliases) / sizeof(char *);
612 if (aliases_size < 1) {
613 *errnop = ERANGE;
614 rv = NS_RETURN;
615 break;
616 }
617
618 /*
619 * servent_unpack expects lines terminated with \n --
620 * make it happy
621 */
622 memcpy(buffer, resultbuf, resultbuflen);
623 buffer[resultbuflen] = '\n';
624 buffer[resultbuflen + 1] = '\0';
625
626 if (servent_unpack(buffer, serv, aliases, aliases_size,
627 errnop) != 0) {
628 if (*errnop == 0)
629 rv = NS_NOTFOUND;
630 else
631 rv = NS_RETURN;
179 } else
632 } else
180 return(0);
181 }
633 rv = NS_SUCCESS;
634 free(resultbuf);
182
635
183 /* getservent() expects lines terminated with \n -- make it happy */
184 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result);
636 } while (!(rv & NS_TERMINATE) && how == nss_lt_all);
185
637
186 free(result);
187 return(1);
638fin:
639 if (rv == NS_SUCCESS && retval != NULL)
640 *(struct servent **)retval = serv;
641
642 return (rv);
188}
189
190static int
643}
644
645static int
191_getservbyname_yp(struct servent_data *sed)
646nis_setservent(void *result, void *mdata, va_list ap)
192{
647{
193 char *result;
194 int resultlen;
195 char buf[YPMAXRECORD + 2];
648 struct nis_state *st;
649 int rv;
196
650
197 if(!sed->yp_domain) {
198 if(yp_get_default_domain(&sed->yp_domain))
199 return (0);
200 }
651 rv = nis_getstate(&st);
652 if (rv != 0)
653 return (NS_UNAVAIL);
201
654
202 snprintf(buf, sizeof(buf), "%s/%s", sed->yp_name, sed->yp_proto);
655 switch ((enum constants)mdata) {
656 case SETSERVENT:
657 case ENDSERVENT:
658 free(st->yp_key);
659 st->yp_key = NULL;
660 st->yp_stepping = 0;
661 break;
662 default:
663 break;
664 };
203
665
204 sed->yp_name = 0;
205 sed->yp_proto = NULL;
666 return (NS_UNAVAIL);
667}
668#endif
206
669
207 if (yp_match(sed->yp_domain, "services.byname", buf, strlen(buf),
208 &result, &resultlen)) {
209 return(0);
210 }
670/* compat backend implementation */
671static int
672compat_setservent(void *retval, void *mdata, va_list ap)
673{
674 static const ns_src compat_src[] = {
675#ifdef YP
676 { NSSRC_NIS, NS_SUCCESS },
677#endif
678 { NULL, 0 }
679 };
680 ns_dtab compat_dtab[] = {
681#ifdef YP
682 { NSSRC_NIS, nis_setservent, mdata },
683#endif
684 { NULL, NULL, NULL }
685 };
686 int f;
211
687
212 /* getservent() expects lines terminated with \n -- make it happy */
213 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result);
688 (void)files_setservent(retval, mdata, ap);
214
689
215 free(result);
216 return(1);
690 switch ((enum constants)mdata) {
691 case SETSERVENT:
692 f = va_arg(ap,int);
693 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
694 "setservent", compat_src, f);
695 break;
696 case ENDSERVENT:
697 (void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
698 "endservent", compat_src);
699 break;
700 default:
701 break;
702 }
703
704 return (NS_UNAVAIL);
217}
218
705}
706
707#ifdef NS_CACHING
219static int
708static int
220_getservent_yp(struct servent_data *sed)
709serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
221{
710{
222 char *lastkey, *result;
223 int resultlen;
224 int rv;
711 char *name;
712 char *proto;
713 int port;
225
714
226 if (!sed->yp_domain) {
227 if (yp_get_default_domain(&sed->yp_domain))
228 return (0);
229 }
715 size_t desired_size, size, size2;
716 enum nss_lookup_type lookup_type;
717 int res = NS_UNAVAIL;
230
718
231 if (!sed->yp_stepping) {
232 free(sed->yp_key);
233 rv = yp_first(sed->yp_domain, "services.byname", &sed->yp_key,
234 &sed->yp_keylen, &result, &resultlen);
235 if (rv) {
236 sed->yp_stepping = 0;
237 return(0);
719 lookup_type = (enum nss_lookup_type)cache_mdata;
720 switch (lookup_type) {
721 case nss_lt_name:
722 name = va_arg(ap, char *);
723 proto = va_arg(ap, char *);
724
725 size = strlen(name);
726 desired_size = sizeof(enum nss_lookup_type) + size + 1;
727 if (proto != NULL) {
728 size2 = strlen(proto);
729 desired_size += size2 + 1;
730 } else
731 size2 = 0;
732
733 if (desired_size > *buffer_size) {
734 res = NS_RETURN;
735 goto fin;
238 }
736 }
239 sed->yp_stepping = 1;
240 } else {
241 lastkey = sed->yp_key;
242 rv = yp_next(sed->yp_domain, "services.byname", sed->yp_key,
243 sed->yp_keylen, &sed->yp_key, &sed->yp_keylen, &result,
244 &resultlen);
245 free(lastkey);
246 if (rv) {
247 sed->yp_stepping = 0;
248 return (0);
737
738 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
739 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
740
741 if (proto != NULL)
742 memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
743 proto, size2 + 1);
744
745 res = NS_SUCCESS;
746 break;
747 case nss_lt_id:
748 port = va_arg(ap, int);
749 proto = va_arg(ap, char *);
750
751 desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
752 if (proto != NULL) {
753 size = strlen(proto);
754 desired_size += size + 1;
755 } else
756 size = 0;
757
758 if (desired_size > *buffer_size) {
759 res = NS_RETURN;
760 goto fin;
249 }
761 }
762
763 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
764 memcpy(buffer + sizeof(enum nss_lookup_type), &port,
765 sizeof(int));
766
767 if (proto != NULL)
768 memcpy(buffer + sizeof(enum nss_lookup_type) +
769 sizeof(int), proto, size + 1);
770
771 res = NS_SUCCESS;
772 break;
773 default:
774 /* should be unreachable */
775 return (NS_UNAVAIL);
250 }
251
776 }
777
252 /* getservent() expects lines terminated with \n -- make it happy */
253 snprintf(sed->line, sizeof sed->line, "%.*s\n", resultlen, result);
778fin:
779 *buffer_size = desired_size;
780 return (res);
781}
254
782
255 free(result);
783int
784serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
785 void *cache_mdata)
786{
787 char *name;
788 char *proto;
789 int port;
790 struct servent *serv;
791 char *orig_buf;
792 size_t orig_buf_size;
256
793
257 return(1);
794 struct servent new_serv;
795 size_t desired_size;
796 char **alias;
797 char *p;
798 size_t size;
799 size_t aliases_size;
800
801 switch ((enum nss_lookup_type)cache_mdata) {
802 case nss_lt_name:
803 name = va_arg(ap, char *);
804 proto = va_arg(ap, char *);
805 break;
806 case nss_lt_id:
807 port = va_arg(ap, int);
808 proto = va_arg(ap, char *);
809 break;
810 case nss_lt_all:
811 break;
812 default:
813 /* should be unreachable */
814 return (NS_UNAVAIL);
815 }
816
817 serv = va_arg(ap, struct servent *);
818 orig_buf = va_arg(ap, char *);
819 orig_buf_size = va_arg(ap, size_t);
820
821 desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
822 if (serv->s_name != NULL)
823 desired_size += strlen(serv->s_name) + 1;
824 if (serv->s_proto != NULL)
825 desired_size += strlen(serv->s_proto) + 1;
826
827 aliases_size = 0;
828 if (serv->s_aliases != NULL) {
829 for (alias = serv->s_aliases; *alias; ++alias) {
830 desired_size += strlen(*alias) + 1;
831 ++aliases_size;
832 }
833
834 desired_size += _ALIGNBYTES +
835 sizeof(char *) * (aliases_size + 1);
836 }
837
838 if (*buffer_size < desired_size) {
839 /* this assignment is here for future use */
840 *buffer_size = desired_size;
841 return (NS_RETURN);
842 }
843
844 memcpy(&new_serv, serv, sizeof(struct servent));
845 memset(buffer, 0, desired_size);
846
847 *buffer_size = desired_size;
848 p = buffer + sizeof(struct servent) + sizeof(char *);
849 memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
850 p = (char *)_ALIGN(p);
851
852 if (new_serv.s_name != NULL) {
853 size = strlen(new_serv.s_name);
854 memcpy(p, new_serv.s_name, size);
855 new_serv.s_name = p;
856 p += size + 1;
857 }
858
859 if (new_serv.s_proto != NULL) {
860 size = strlen(new_serv.s_proto);
861 memcpy(p, new_serv.s_proto, size);
862 new_serv.s_proto = p;
863 p += size + 1;
864 }
865
866 if (new_serv.s_aliases != NULL) {
867 p = (char *)_ALIGN(p);
868 memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
869 new_serv.s_aliases = (char **)p;
870 p += sizeof(char *) * (aliases_size + 1);
871
872 for (alias = new_serv.s_aliases; *alias; ++alias) {
873 size = strlen(*alias);
874 memcpy(p, *alias, size);
875 *alias = p;
876 p += size + 1;
877 }
878 }
879
880 memcpy(buffer, &new_serv, sizeof(struct servent));
881 return (NS_SUCCESS);
258}
882}
259#endif
260
883
261void
262__setservent_p(int f, struct servent_data *sed)
884int
885serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
886 void *cache_mdata)
263{
887{
264 if (sed->fp == NULL)
265 sed->fp = fopen(_PATH_SERVICES, "r");
266 else
267 rewind(sed->fp);
268 sed->stayopen |= f;
888 char *name;
889 char *proto;
890 int port;
891 struct servent *serv;
892 char *orig_buf;
893 char *p;
894 char **alias;
895 size_t orig_buf_size;
896 int *ret_errno;
897
898 switch ((enum nss_lookup_type)cache_mdata) {
899 case nss_lt_name:
900 name = va_arg(ap, char *);
901 proto = va_arg(ap, char *);
902 break;
903 case nss_lt_id:
904 port = va_arg(ap, int);
905 proto = va_arg(ap, char *);
906 break;
907 case nss_lt_all:
908 break;
909 default:
910 /* should be unreachable */
911 return (NS_UNAVAIL);
912 }
913
914 serv = va_arg(ap, struct servent *);
915 orig_buf = va_arg(ap, char *);
916 orig_buf_size = va_arg(ap, size_t);
917 ret_errno = va_arg(ap, int *);
918
919 if (orig_buf_size <
920 buffer_size - sizeof(struct servent) - sizeof(char *)) {
921 *ret_errno = ERANGE;
922 return (NS_RETURN);
923 }
924
925 memcpy(serv, buffer, sizeof(struct servent));
926 memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
927
928 orig_buf = (char *)_ALIGN(orig_buf);
929 memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
930 (_ALIGN(p) - (size_t)p),
931 buffer_size - sizeof(struct servent) - sizeof(char *) -
932 (_ALIGN(p) - (size_t)p));
933 p = (char *)_ALIGN(p);
934
935 NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
936 NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
937 if (serv->s_aliases != NULL) {
938 NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
939
940 for (alias = serv->s_aliases; *alias; ++alias)
941 NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
942 }
943
944 if (retval != NULL)
945 *((struct servent **)retval) = serv;
946 return (NS_SUCCESS);
269}
270
947}
948
271void
272__endservent_p(struct servent_data *sed)
949NSS_MP_CACHE_HANDLING(services);
950#endif /* NS_CACHING */
951
952/* get**_r functions implementation */
953int
954getservbyname_r(const char *name, const char *proto, struct servent *serv,
955 char *buffer, size_t bufsize, struct servent **result)
273{
956{
274 servent_data_clear(sed);
275 sed->stayopen = 0;
957 static const struct servent_mdata mdata = { nss_lt_name, 0 };
958 static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
959#ifdef NS_CACHING
960 static const nss_cache_info cache_info =
961 NS_COMMON_CACHE_INFO_INITIALIZER(
962 services, (void *)nss_lt_name,
963 serv_id_func, serv_marshal_func, serv_unmarshal_func);
964#endif /* NS_CACHING */
965 static const ns_dtab dtab[] = {
966 { NSSRC_FILES, files_servent, (void *)&mdata },
276#ifdef YP
967#ifdef YP
277 sed->yp_stepping = 0;
278 sed->yp_domain = NULL;
968 { NSSRC_NIS, nis_servent, (void *)nss_lt_name },
279#endif
969#endif
970 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
971#ifdef NS_CACHING
972 NS_CACHE_CB(&cache_info)
973#endif
974 { NULL, NULL, NULL }
975 };
976 int rv, ret_errno;
977
978 ret_errno = 0;
979 *result = NULL;
980 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
981 defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
982
983 if (rv == NS_SUCCESS)
984 return (0);
985 else
986 return (ret_errno);
280}
281
282int
987}
988
989int
283__getservent_p(struct servent *se, struct servent_data *sed)
990getservbyport_r(int port, const char *proto, struct servent *serv,
991 char *buffer, size_t bufsize, struct servent **result)
284{
992{
285 char *p;
286 char *cp, **q, *endp;
287 long l;
288
289#ifdef YP
290 if (sed->yp_stepping && _getservent_yp(sed)) {
291 p = sed->line;
292 goto unpack;
293 }
294tryagain:
993 static const struct servent_mdata mdata = { nss_lt_id, 0 };
994 static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
995#ifdef NS_CACHING
996 static const nss_cache_info cache_info =
997 NS_COMMON_CACHE_INFO_INITIALIZER(
998 services, (void *)nss_lt_id,
999 serv_id_func, serv_marshal_func, serv_unmarshal_func);
295#endif
1000#endif
296 if (sed->fp == NULL && (sed->fp = fopen(_PATH_SERVICES, "r")) == NULL)
297 return (-1);
298again:
299 if ((p = fgets(sed->line, sizeof sed->line, sed->fp)) == NULL)
300 return (-1);
1001 static const ns_dtab dtab[] = {
1002 { NSSRC_FILES, files_servent, (void *)&mdata },
301#ifdef YP
1003#ifdef YP
302 if (*p == '+' && _yp_check(NULL)) {
303 if (sed->yp_name != NULL) {
304 if (!_getservbyname_yp(sed))
305 goto tryagain;
306 }
307 else if (sed->yp_port != 0) {
308 if (!_getservbyport_yp(sed))
309 goto tryagain;
310 }
311 else if (!_getservent_yp(sed))
312 goto tryagain;
313 }
314unpack:
1004 { NSSRC_NIS, nis_servent, (void *)nss_lt_id },
315#endif
1005#endif
316 if (*p == '#')
317 goto again;
318 cp = strpbrk(p, "#\n");
319 if (cp != NULL)
320 *cp = '\0';
321 se->s_name = p;
322 p = strpbrk(p, " \t");
323 if (p == NULL)
324 goto again;
325 *p++ = '\0';
326 while (*p == ' ' || *p == '\t')
327 p++;
328 cp = strpbrk(p, ",/");
329 if (cp == NULL)
330 goto again;
331 *cp++ = '\0';
332 l = strtol(p, &endp, 10);
333 if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
334 goto again;
335 se->s_port = htons((in_port_t)l);
336 se->s_proto = cp;
337 q = se->s_aliases = sed->aliases;
338 cp = strpbrk(cp, " \t");
339 if (cp != NULL)
340 *cp++ = '\0';
341 while (cp && *cp) {
342 if (*cp == ' ' || *cp == '\t') {
343 cp++;
344 continue;
345 }
346 if (q < &sed->aliases[_MAXALIASES - 1])
347 *q++ = cp;
348 cp = strpbrk(cp, " \t");
349 if (cp != NULL)
350 *cp++ = '\0';
351 }
352 *q = NULL;
353 return (0);
1006 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1007#ifdef NS_CACHING
1008 NS_CACHE_CB(&cache_info)
1009#endif
1010 { NULL, NULL, NULL }
1011 };
1012 int rv, ret_errno;
1013
1014 ret_errno = 0;
1015 *result = NULL;
1016 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
1017 defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
1018
1019 if (rv == NS_SUCCESS)
1020 return (0);
1021 else
1022 return (ret_errno);
354}
355
356int
1023}
1024
1025int
357getservent_r(struct servent *sptr, char *buffer, size_t buflen,
1026getservent_r(struct servent *serv, char *buffer, size_t bufsize,
358 struct servent **result)
359{
1027 struct servent **result)
1028{
360 struct servent se;
361 struct servent_data *sed;
1029 static const struct servent_mdata mdata = { nss_lt_all, 0 };
1030 static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
1031#ifdef NS_CACHING
1032 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1033 services, (void *)nss_lt_all,
1034 serv_marshal_func, serv_unmarshal_func);
1035#endif
1036 static const ns_dtab dtab[] = {
1037 { NSSRC_FILES, files_servent, (void *)&mdata },
1038#ifdef YP
1039 { NSSRC_NIS, nis_servent, (void *)nss_lt_all },
1040#endif
1041 { NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1042#ifdef NS_CACHING
1043 NS_CACHE_CB(&cache_info)
1044#endif
1045 { NULL, NULL, NULL }
1046 };
1047 int rv, ret_errno;
362
1048
363 if ((sed = __servent_data_init()) == NULL)
364 return (-1);
1049 ret_errno = 0;
1050 *result = NULL;
1051 rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
1052 defaultsrc, serv, buffer, bufsize, &ret_errno);
365
1053
366 if (__getservent_p(&se, sed) != 0)
367 return (-1);
368 if (__copy_servent(&se, sptr, buffer, buflen) != 0)
369 return (-1);
370 *result = sptr;
371 return (0);
1054 if (rv == NS_SUCCESS)
1055 return (0);
1056 else
1057 return (ret_errno);
372}
373
374void
1058}
1059
1060void
375setservent(int f)
1061setservent(int stayopen)
376{
1062{
377 struct servent_data *sed;
1063#ifdef NS_CACHING
1064 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1065 services, (void *)nss_lt_all,
1066 NULL, NULL);
1067#endif
1068 static const ns_dtab dtab[] = {
1069 { NSSRC_FILES, files_setservent, (void *)SETSERVENT },
1070#ifdef YP
1071 { NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
1072#endif
1073 { NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
1074#ifdef NS_CACHING
1075 NS_CACHE_CB(&cache_info)
1076#endif
1077 { NULL, NULL, NULL }
1078 };
378
1079
379 if ((sed = __servent_data_init()) == NULL)
380 return;
381 __setservent_p(f, sed);
1080 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
1081 stayopen);
382}
383
384void
1082}
1083
1084void
385endservent(void)
1085endservent()
386{
1086{
387 struct servent_data *sed;
1087#ifdef NS_CACHING
1088 static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1089 services, (void *)nss_lt_all,
1090 NULL, NULL);
1091#endif
1092 static const ns_dtab dtab[] = {
1093 { NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
1094#ifdef YP
1095 { NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
1096#endif
1097 { NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
1098#ifdef NS_CACHING
1099 NS_CACHE_CB(&cache_info)
1100#endif
1101 { NULL, NULL, NULL }
1102 };
388
1103
389 if ((sed = __servent_data_init()) == NULL)
1104 (void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
1105}
1106
1107/* get** wrappers for get**_r functions implementation */
1108static void
1109servent_endstate(void *p)
1110{
1111 if (p == NULL)
390 return;
1112 return;
391 __endservent_p(sed);
1113
1114 free(((struct servent_state *)p)->buffer);
1115 free(p);
392}
393
1116}
1117
1118static int
1119wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
1120 size_t bufsize, struct servent **res)
1121{
1122 return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
1123 res));
1124}
1125
1126static int
1127wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
1128 size_t bufsize, struct servent **res)
1129{
1130 return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
1131 res));
1132}
1133
1134static int
1135wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
1136 size_t bufsize, struct servent **res)
1137{
1138 return (getservent_r(serv, buffer, bufsize, res));
1139}
1140
1141static struct servent *
1142getserv(int (*fn)(struct key, struct servent *, char *, size_t,
1143 struct servent **), struct key key)
1144{
1145 int rv;
1146 struct servent *res;
1147 struct servent_state * st;
1148
1149 rv = servent_getstate(&st);
1150 if (rv != 0) {
1151 errno = rv;
1152 return NULL;
1153 }
1154
1155 if (st->buffer == NULL) {
1156 st->buffer = malloc(SERVENT_STORAGE_INITIAL);
1157 if (st->buffer == NULL)
1158 return (NULL);
1159 st->bufsize = SERVENT_STORAGE_INITIAL;
1160 }
1161 do {
1162 rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
1163 if (res == NULL && rv == ERANGE) {
1164 free(st->buffer);
1165 if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
1166 st->buffer = NULL;
1167 errno = ERANGE;
1168 return (NULL);
1169 }
1170 st->bufsize <<= 1;
1171 st->buffer = malloc(st->bufsize);
1172 if (st->buffer == NULL)
1173 return (NULL);
1174 }
1175 } while (res == NULL && rv == ERANGE);
1176 if (rv != 0)
1177 errno = rv;
1178
1179 return (res);
1180}
1181
394struct servent *
1182struct servent *
395getservent(void)
1183getservbyname(const char *name, const char *proto)
396{
1184{
397 struct servdata *sd;
398 struct servent *rval;
1185 struct key key;
399
1186
400 if ((sd = __servdata_init()) == NULL)
401 return (NULL);
402 if (getservent_r(&sd->serv, sd->data, sizeof(sd->data), &rval) != 0)
403 return (NULL);
404 return (rval);
1187 key.name = name;
1188 key.proto = proto;
1189
1190 return (getserv(wrap_getservbyname_r, key));
405}
1191}
1192
1193struct servent *
1194getservbyport(int port, const char *proto)
1195{
1196 struct key key;
1197
1198 key.port = port;
1199 key.proto = proto;
1200
1201 return (getserv(wrap_getservbyport_r, key));
1202}
1203
1204struct servent *
1205getservent()
1206{
1207 struct key key;
1208
1209 key.proto = NULL;
1210 key.port = 0;
1211
1212 return (getserv(wrap_getservent_r, key));
1213}