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