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