1 /*
2 networks.c - NSS lookup functions for networks database
3
4 Copyright (C) 2006 West Consulting
5 Copyright (C) 2006-2015 Arthur de Jong
6 Copyright (C) 2010 Symas Corporation
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 #include "config.h"
25
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31
32 #include "prototypes.h"
33 #include "common.h"
34 #include "compat/attrs.h"
35
36 /* Redefine some ERROR_OUT macros as we also want to set h_errnop. */
37
38 #undef ERROR_OUT_OPENERROR
39 #define ERROR_OUT_OPENERROR \
40 *errnop = ENOENT; \
41 *h_errnop = HOST_NOT_FOUND; \
42 return (errno == EAGAIN) ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
43
44 #undef ERROR_OUT_READERROR
45 #define ERROR_OUT_READERROR(fp) \
46 (void)tio_close(fp); \
47 fp = NULL; \
48 *errnop = ENOENT; \
49 *h_errnop = NO_RECOVERY; \
50 return NSS_STATUS_UNAVAIL;
51
52 #undef ERROR_OUT_BUFERROR
53 #define ERROR_OUT_BUFERROR(fp) \
54 *errnop = ERANGE; \
55 *h_errnop = NETDB_INTERNAL; \
56 return NSS_STATUS_TRYAGAIN;
57
58 #undef ERROR_OUT_WRITEERROR
59 #define ERROR_OUT_WRITEERROR(fp) \
60 ERROR_OUT_READERROR(fp)
61
62 /* read a single network entry from the stream, ignoring entries
63 that are not AF_INET (IPv4), result is stored in result */
read_netent(TFILE * fp,struct netent * result,char * buffer,size_t buflen,int * errnop,int * h_errnop)64 static nss_status_t read_netent(TFILE *fp, struct netent *result,
65 char *buffer, size_t buflen, int *errnop,
66 int *h_errnop)
67 {
68 int32_t tmpint32, tmp2int32, tmp3int32;
69 int32_t numaddr;
70 int readaf;
71 size_t bufptr = 0;
72 nss_status_t retv = NSS_STATUS_NOTFOUND;
73 memset(result, 0, sizeof(struct netent));
74 /* read the network entry */
75 READ_BUF_STRING(fp, result->n_name);
76 READ_BUF_STRINGLIST(fp, result->n_aliases);
77 result->n_addrtype = AF_INET;
78 /* read number of addresses to follow */
79 READ_INT32(fp, numaddr);
80 /* go through the address list and filter on af */
81 while (--numaddr >= 0)
82 {
83 /* read address family and size */
84 READ_INT32(fp, readaf);
85 READ_INT32(fp, tmp2int32); /* address length */
86 if ((readaf == AF_INET) && (tmp2int32 == 4))
87 {
88 /* read address and translate to host byte order */
89 READ_INT32(fp, result->n_net);
90 /* signal that we've read a proper entry */
91 retv = NSS_STATUS_SUCCESS;
92 /* don't return here to not upset the stream */
93 }
94 else
95 {
96 /* skip unsupported address families */
97 SKIP(fp, tmpint32);
98 }
99 }
100 return retv;
101 }
102
103 /* write an address value */
104 /* version 2.10 of glibc changed the address from network to host order
105 (changelog entry 2009-07-01) */
106 #define WRITE_ADDRESS(fp, addr) \
107 WRITE_INT32(fp, AF_INET); \
108 WRITE_INT32(fp, 4); \
109 WRITE_INT32(fp, addr);
110
111 #ifdef NSS_FLAVOUR_GLIBC
112
113 /* get a network entry by name */
NSS_NAME(getnetbyname_r)114 nss_status_t NSS_NAME(getnetbyname_r)(const char *name,
115 struct netent *result, char *buffer,
116 size_t buflen, int *errnop,
117 int *h_errnop)
118 {
119 NSS_GETONE(NSLCD_ACTION_NETWORK_BYNAME,
120 WRITE_STRING(fp, name),
121 read_netent(fp, result, buffer, buflen, errnop, h_errnop));
122 }
123
124 /* Note: the af parameter is ignored and is assumed to be AF_INET */
125 /* TODO: implement handling of af parameter */
NSS_NAME(getnetbyaddr_r)126 nss_status_t NSS_NAME(getnetbyaddr_r)(uint32_t addr, int UNUSED(af),
127 struct netent *result, char *buffer,
128 size_t buflen, int *errnop,
129 int *h_errnop)
130 {
131 NSS_GETONE(NSLCD_ACTION_NETWORK_BYADDR,
132 WRITE_ADDRESS(fp, addr),
133 read_netent(fp, result, buffer, buflen, errnop, h_errnop));
134 }
135
136 /* thread-local file pointer to an ongoing request */
137 static TLS TFILE *netentfp;
138
139 /* start a request to read all networks */
NSS_NAME(setnetent)140 nss_status_t NSS_NAME(setnetent)(int UNUSED(stayopen))
141 {
142 NSS_SETENT(netentfp);
143 }
144
145 /* get a single network entry from the stream */
NSS_NAME(getnetent_r)146 nss_status_t NSS_NAME(getnetent_r)(struct netent *result,
147 char *buffer, size_t buflen, int *errnop,
148 int *h_errnop)
149 {
150 NSS_GETENT(netentfp, NSLCD_ACTION_NETWORK_ALL,
151 read_netent(netentfp, result, buffer, buflen, errnop, h_errnop));
152 }
153
154 /* close the stream opened by setnetent() above */
NSS_NAME(endnetent)155 nss_status_t NSS_NAME(endnetent)(void)
156 {
157 NSS_ENDENT(netentfp);
158 }
159
160 #endif /* NSS_FLAVOUR_GLIBC */
161
162 #ifdef NSS_FLAVOUR_SOLARIS
163
164 #ifdef HAVE_STRUCT_NSS_XBYY_ARGS_RETURNLEN
netent2str(struct netent * result,char * buffer,size_t buflen)165 static char *netent2str(struct netent *result, char *buffer, size_t buflen)
166 {
167 int i, res;
168 struct in_addr priv_in_addr;
169 priv_in_addr.s_addr = htonl(result->n_net);
170 res = snprintf(buffer, buflen, "%s %s", result->n_name, inet_ntoa(priv_in_addr));
171 if ((res < 0) || (res >= (int)buflen))
172 return NULL;
173 if (result->n_aliases)
174 for (i = 0; result->n_aliases[i]; i++)
175 {
176 strlcat(buffer, " ", buflen);
177 strlcat(buffer, result->n_aliases[i], buflen);
178 }
179 if (strlen(buffer) >= buflen - 1)
180 return NULL;
181 return buffer;
182 }
183 #endif /* HAVE_STRUCT_NSS_XBYY_ARGS_RETURNLEN */
184
read_result(TFILE * fp,nss_XbyY_args_t * args)185 static nss_status_t read_result(TFILE *fp, nss_XbyY_args_t *args)
186 {
187 READ_RESULT(netent, &args->erange, &args->h_errno);
188 }
189
190 /* more of a dirty hack */
191 #define h_errnop (&(NSS_ARGS(args)->h_errno))
192
networks_getnetbyname(nss_backend_t UNUSED (* be),void * args)193 static nss_status_t networks_getnetbyname(nss_backend_t UNUSED(*be), void *args)
194 {
195 NSS_GETONE(NSLCD_ACTION_NETWORK_BYNAME,
196 WRITE_STRING(fp, NSS_ARGS(args)->key.name),
197 read_result(fp, args));
198 }
199
networks_getnetbyaddr(nss_backend_t UNUSED (* be),void * args)200 static nss_status_t networks_getnetbyaddr(nss_backend_t UNUSED(*be), void *args)
201 {
202 NSS_GETONE(NSLCD_ACTION_NETWORK_BYADDR,
203 WRITE_ADDRESS(fp, NSS_ARGS(args)->key.netaddr.net),
204 read_result(fp, args));
205 }
206
networks_setnetent(nss_backend_t * be,void UNUSED (* args))207 static nss_status_t networks_setnetent(nss_backend_t *be, void UNUSED(*args))
208 {
209 NSS_SETENT(LDAP_BE(be)->fp);
210 }
211
networks_getnetent(nss_backend_t * be,void * args)212 static nss_status_t networks_getnetent(nss_backend_t *be, void *args)
213 {
214 NSS_GETENT(LDAP_BE(be)->fp, NSLCD_ACTION_NETWORK_ALL,
215 read_result(LDAP_BE(be)->fp, args));
216 }
217
networks_endnetent(nss_backend_t * be,void UNUSED (* args))218 static nss_status_t networks_endnetent(nss_backend_t *be, void UNUSED(*args))
219 {
220 NSS_ENDENT(LDAP_BE(be)->fp);
221 }
222
223 static nss_backend_op_t networks_ops[] = {
224 nss_ldap_destructor,
225 networks_endnetent,
226 networks_setnetent,
227 networks_getnetent,
228 networks_getnetbyname,
229 networks_getnetbyaddr
230 };
231
NSS_NAME(networks_constr)232 nss_backend_t *NSS_NAME(networks_constr)(const char UNUSED(*db_name),
233 const char UNUSED(*src_name),
234 const char UNUSED(*cfg_args))
235 {
236 return nss_ldap_constructor(networks_ops, sizeof(networks_ops));
237 }
238
239 #endif /* NSS_FLAVOUR_SOLARIS */
240