Update to LGPL v2.1.
[jlayton/glibc.git] / nis / nss_nis / nis-network.c
1 /* Copyright (C) 1996-2000, 2001 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <nss.h>
21 #include <netdb.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <stdint.h>
25 #include <string.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <bits/libc-lock.h>
29 #include <rpcsvc/yp.h>
30 #include <rpcsvc/ypclnt.h>
31
32 #include "nss-nis.h"
33
34 /* Get the declaration of the parser function.  */
35 #define ENTNAME netent
36 #define EXTERN_PARSER
37 #include <nss/nss_files/files-parse.c>
38
39 __libc_lock_define_initialized (static, lock)
40
41 static bool_t new_start = 1;
42 static char *oldkey;
43 static int oldkeylen;
44
45 enum nss_status
46 _nss_nis_setnetent (int stayopen)
47 {
48   __libc_lock_lock (lock);
49
50   new_start = 1;
51   if (oldkey != NULL)
52     {
53       free (oldkey);
54       oldkey = NULL;
55       oldkeylen = 0;
56     }
57
58   __libc_lock_unlock (lock);
59
60   return NSS_STATUS_SUCCESS;
61 }
62
63 enum nss_status
64 _nss_nis_endnetent (void)
65 {
66   __libc_lock_lock (lock);
67
68   new_start = 1;
69   if (oldkey != NULL)
70     {
71       free (oldkey);
72       oldkey = NULL;
73       oldkeylen = 0;
74     }
75
76   __libc_lock_unlock (lock);
77
78   return NSS_STATUS_SUCCESS;
79 }
80
81 static enum nss_status
82 internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
83                           int *errnop, int *herrnop)
84 {
85   struct parser_data *data = (void *) buffer;
86   char *domain, *result, *outkey;
87   int len, keylen, parse_res;
88
89   if (yp_get_default_domain (&domain))
90     return NSS_STATUS_UNAVAIL;
91
92   /* Get the next entry until we found a correct one. */
93   do
94     {
95       enum nss_status retval;
96       char *p;
97
98       if (new_start)
99         retval = yperr2nss (yp_first (domain, "networks.byname",
100                                       &outkey, &keylen, &result, &len));
101       else
102         retval = yperr2nss ( yp_next (domain, "networks.byname",
103                                       oldkey, oldkeylen,
104                                       &outkey, &keylen, &result, &len));
105
106       if (retval != NSS_STATUS_SUCCESS)
107         {
108           if (retval == NSS_STATUS_NOTFOUND)
109             *errnop = ENOENT;
110           else if (retval == NSS_STATUS_TRYAGAIN)
111             {
112               *herrnop = NETDB_INTERNAL;
113               *errnop = errno;
114             }
115           return retval;
116         }
117
118       if ((size_t) (len + 1) > buflen)
119         {
120           free (result);
121           *errnop = ERANGE;
122           *herrnop = NETDB_INTERNAL;
123           return NSS_STATUS_TRYAGAIN;
124         }
125
126       p = strncpy (buffer, result, len);
127       buffer[len] = '\0';
128       while (isspace (*p))
129         ++p;
130       free (result);
131
132       parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
133       if (parse_res == -1)
134         {
135           free (outkey);
136           *herrnop = NETDB_INTERNAL;
137           *errnop = ERANGE;
138           return NSS_STATUS_TRYAGAIN;
139         }
140
141       free (oldkey);
142       oldkey = outkey;
143       oldkeylen = keylen;
144       new_start = 0;
145     }
146   while (!parse_res);
147
148   return NSS_STATUS_SUCCESS;
149 }
150
151 enum nss_status
152 _nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
153                       int *errnop, int *herrnop)
154 {
155   enum nss_status status;
156
157   __libc_lock_lock (lock);
158
159   status = internal_nis_getnetent_r (net, buffer, buflen, errnop, herrnop);
160
161   __libc_lock_unlock (lock);
162
163   return status;
164 }
165
166 enum nss_status
167 _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
168                          size_t buflen, int *errnop, int *herrnop)
169 {
170   enum nss_status retval;
171   struct parser_data *data = (void *) buffer;
172   char *domain, *result, *p;
173   int len, parse_res;
174
175   if (name == NULL)
176     {
177       *errnop = EINVAL;
178       *herrnop = NETDB_INTERNAL;
179       return NSS_STATUS_UNAVAIL;
180     }
181
182   if (yp_get_default_domain (&domain))
183     return NSS_STATUS_UNAVAIL;
184
185   if (buflen < sizeof *data + 1)
186     {
187       *herrnop = NETDB_INTERNAL;
188       *errnop = ERANGE;
189       return NSS_STATUS_TRYAGAIN;
190     }
191   else
192     {
193       /* Convert name to lowercase.  */
194       size_t namlen = strlen (name);
195       char name2[namlen + 1];
196       int i;
197
198       for (i = 0; i < namlen; ++i)
199         name2[i] = _tolower (name[i]);
200       name2[i] = '\0';
201
202       retval = yperr2nss (yp_match (domain, "networks.byname", name2,
203                                     namlen, &result, &len));
204     }
205
206
207   if (retval != NSS_STATUS_SUCCESS)
208     {
209       if (retval == NSS_STATUS_NOTFOUND)
210         *errnop = ENOENT;
211       else if (retval == NSS_STATUS_TRYAGAIN)
212         {
213           *errnop = errno;
214           *herrnop = NETDB_INTERNAL;
215         }
216       return retval;
217     }
218
219   if ((size_t) (len + 1) > buflen)
220     {
221       free (result);
222       *errnop = ERANGE;
223       *herrnop = NETDB_INTERNAL;
224       return NSS_STATUS_TRYAGAIN;
225     }
226
227   p = strncpy (buffer, result, len);
228   buffer[len] = '\0';
229   while (isspace (*p))
230     ++p;
231   free (result);
232
233   parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
234
235   if (parse_res < 1)
236     {
237       *herrnop = NETDB_INTERNAL;
238       if (parse_res == -1)
239         return NSS_STATUS_TRYAGAIN;
240       else
241         {
242           *errnop = ENOENT;
243           return NSS_STATUS_NOTFOUND;
244         }
245     }
246   else
247     return NSS_STATUS_SUCCESS;
248 }
249
250 enum nss_status
251 _nss_nis_getnetbyaddr_r (uint32_t addr, int type, struct netent *net,
252                          char *buffer, size_t buflen, int *errnop,
253                          int *herrnop)
254 {
255   struct parser_data *data = (void *) buffer;
256   char *domain;
257   char *result;
258   int len;
259   char buf[256];
260   int blen;
261   struct in_addr in;
262   char *p;
263
264   if (yp_get_default_domain (&domain))
265     return NSS_STATUS_UNAVAIL;
266
267   in = inet_makeaddr (addr, 0);
268   strcpy (buf, inet_ntoa (in));
269   blen = strlen (buf);
270
271   while (1)
272     {
273       enum nss_status retval;
274       int parse_res;
275
276       retval = yperr2nss (yp_match (domain, "networks.byaddr", buf,
277                                     strlen (buf), &result, &len));
278
279         if (retval != NSS_STATUS_SUCCESS)
280           {
281             if (retval == NSS_STATUS_NOTFOUND)
282               {
283                 if (buf[blen - 2] == '.' && buf[blen - 1] == '0')
284                   {
285                     /* Try again, but with trailing dot(s)
286                        removed (one by one) */
287                     buf[blen - 2] = '\0';
288                     blen -= 2;
289                     continue;
290                   }
291                 else
292                   {
293                     *errnop = ENOENT;
294                     return NSS_STATUS_NOTFOUND;
295                   }
296               }
297             else
298               {
299                 if (retval == NSS_STATUS_TRYAGAIN)
300                   *errnop = errno;
301                 return retval;
302               }
303           }
304
305       if ((size_t) (len + 1) > buflen)
306         {
307           free (result);
308           *errnop = ERANGE;
309           *herrnop = NETDB_INTERNAL;
310           return NSS_STATUS_TRYAGAIN;
311         }
312
313         p = strncpy (buffer, result, len);
314         buffer[len] = '\0';
315         while (isspace (*p))
316           ++p;
317         free (result);
318
319         parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
320
321         if (parse_res < 1)
322           {
323             *herrnop = NETDB_INTERNAL;
324             if (parse_res == -1)
325               return NSS_STATUS_TRYAGAIN;
326             else
327               {
328                 *errnop = ENOENT;
329                 return NSS_STATUS_NOTFOUND;
330               }
331           }
332         else
333           return NSS_STATUS_SUCCESS;
334     }
335 }