1/* Copyright (C) 1997-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
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 <https://www.gnu.org/licenses/>. */
18
19#include <errno.h>
20#include <hesiod.h>
21#include <netdb.h>
22#include <netinet/in.h>
23#include <nss.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28NSS_DECLARE_MODULE_FUNCTIONS (hesiod)
29
30/* Hesiod uses a format for service entries that differs from the
31 traditional format. We therefore declare our own parser. */
32
33#define ENTNAME servent
34
35struct servent_data {};
36
37#define TRAILING_LIST_MEMBER s_aliases
38#define TRAILING_LIST_SEPARATOR_P isspace
39#include <nss/nss_files/files-parse.c>
40#define ISSC_OR_SPACE(c) ((c) == ';' || isspace (c))
41LINE_PARSER
42("#",
43 STRING_FIELD (result->s_name, ISSC_OR_SPACE, 1);
44 STRING_FIELD (result->s_proto, ISSC_OR_SPACE, 1);
45 INT_FIELD (result->s_port, ISSC_OR_SPACE, 10, 0, htons);
46 )
47
48enum nss_status
49_nss_hesiod_setservent (int stayopen)
50{
51 return NSS_STATUS_SUCCESS;
52}
53
54enum nss_status
55_nss_hesiod_endservent (void)
56{
57 return NSS_STATUS_SUCCESS;
58}
59
60static enum nss_status
61lookup (const char *name, const char *type, const char *protocol,
62 struct servent *serv, char *buffer, size_t buflen, int *errnop)
63{
64 struct parser_data *data = (void *) buffer;
65 size_t linebuflen;
66 void *context;
67 char **list, **item;
68 int parse_res;
69 int found;
70 int olderr = errno;
71
72 if (hesiod_init (&context) < 0)
73 return NSS_STATUS_UNAVAIL;
74
75 list = hesiod_resolve (context, name, type);
76 if (list == NULL)
77 {
78 int err = errno;
79 hesiod_end (context);
80 __set_errno (olderr);
81 return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
82 }
83
84 linebuflen = buffer + buflen - data->linebuffer;
85
86 item = list;
87 found = 0;
88 do
89 {
90 size_t len = strlen (*item) + 1;
91
92 if (linebuflen < len)
93 {
94 hesiod_free_list (context, list);
95 hesiod_end (context);
96 *errnop = ERANGE;
97 return NSS_STATUS_TRYAGAIN;
98 }
99
100 memcpy (data->linebuffer, *item, len);
101
102 parse_res = parse_line (buffer, serv, data, buflen, errnop);
103 if (parse_res == -1)
104 {
105 hesiod_free_list (context, list);
106 hesiod_end (context);
107 return NSS_STATUS_TRYAGAIN;
108 }
109
110 if (parse_res > 0)
111 found = protocol == NULL || strcasecmp (serv->s_proto, protocol) == 0;
112
113 ++item;
114 }
115 while (*item != NULL && !found);
116
117 hesiod_free_list (context, list);
118 hesiod_end (context);
119
120 if (found == 0)
121 {
122 __set_errno (olderr);
123 return NSS_STATUS_NOTFOUND;
124 }
125
126 return NSS_STATUS_SUCCESS;
127}
128
129enum nss_status
130_nss_hesiod_getservbyname_r (const char *name, const char *protocol,
131 struct servent *serv,
132 char *buffer, size_t buflen, int *errnop)
133{
134 return lookup (name, "service", protocol, serv, buffer, buflen, errnop);
135}
136
137enum nss_status
138_nss_hesiod_getservbyport_r (const int port, const char *protocol,
139 struct servent *serv,
140 char *buffer, size_t buflen, int *errnop)
141{
142 char portstr[6]; /* Port numbers are restricted to 16 bits. */
143
144 snprintf (portstr, sizeof portstr, "%d", ntohs (port));
145
146 return lookup (portstr, "port", protocol, serv, buffer, buflen, errnop);
147}
148