(saveit): Improve memory. No need to allocate multiple blocks.
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-rpc.c
1 /* Copyright (C) 1996-1998,2000,2002,2003,2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.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 <string.h>
25 #include <bits/libc-lock.h>
26 #include <rpcsvc/yp.h>
27 #include <rpcsvc/ypclnt.h>
28
29 #include "nss-nis.h"
30
31 /* Get the declaration of the parser function.  */
32 #define ENTNAME rpcent
33 #define EXTERN_PARSER
34 #include <nss/nss_files/files-parse.c>
35
36 __libc_lock_define_initialized (static, lock)
37
38 struct response_t
39 {
40   struct response_t *next;
41   char val[0];
42 };
43
44 struct intern_t
45 {
46   struct response_t *start;
47   struct response_t *next;
48 };
49 typedef struct intern_t intern_t;
50
51 static intern_t intern = {NULL, NULL};
52
53 static int
54 saveit (int instatus, char *inkey, int inkeylen, char *inval,
55         int invallen, char *indata)
56 {
57   intern_t *intern = (intern_t *)indata;
58
59   if (instatus != YP_TRUE)
60     return instatus;
61
62   if (inkey && inkeylen > 0 && inval && invallen > 0)
63     {
64       struct response_t *newp = malloc (sizeof (struct response_t)
65                                         + invallen + 1);
66       if (newp == NULL)
67         return YP_FALSE; /* We have no error code for out of memory */
68
69       if (intern->start == NULL)
70         intern->start = newp;
71       else
72         intern->next->next = newp;
73       intern->next = newp;
74
75       newp->next = NULL;
76       *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
77     }
78
79   return 0;
80 }
81
82 static void
83 internal_nis_endrpcent (intern_t *intern)
84 {
85   while (intern->start != NULL)
86     {
87       intern->next = intern->start;
88       intern->start = intern->start->next;
89       free (intern->next);
90     }
91 }
92
93 static enum nss_status
94 internal_nis_setrpcent (intern_t *intern)
95 {
96   char *domainname;
97   struct ypall_callback ypcb;
98   enum nss_status status;
99
100   if (yp_get_default_domain (&domainname))
101     return NSS_STATUS_UNAVAIL;
102
103   internal_nis_endrpcent (intern);
104
105   ypcb.foreach = saveit;
106   ypcb.data = (char *)intern;
107   status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb));
108   intern->next = intern->start;
109
110   return status;
111 }
112
113 enum nss_status
114 _nss_nis_setrpcent (int stayopen)
115 {
116   enum nss_status status;
117
118   __libc_lock_lock (lock);
119
120   status = internal_nis_setrpcent (&intern);
121
122   __libc_lock_unlock (lock);
123
124   return status;
125 }
126
127 enum nss_status
128 _nss_nis_endrpcent (void)
129 {
130   __libc_lock_lock (lock);
131
132   internal_nis_endrpcent (&intern);
133
134   __libc_lock_unlock (lock);
135
136   return NSS_STATUS_SUCCESS;
137 }
138
139 static enum nss_status
140 internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
141                           int *errnop, intern_t *data)
142 {
143   struct parser_data *pdata = (void *) buffer;
144   int parse_res;
145   char *p;
146
147   if (data->start == NULL)
148     internal_nis_setrpcent (data);
149
150   /* Get the next entry until we found a correct one. */
151   do
152     {
153       if (data->next == NULL)
154         return NSS_STATUS_NOTFOUND;
155
156       p = strncpy (buffer, data->next->val, buflen);
157       while (isspace (*p))
158         ++p;
159
160       parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop);
161       if (parse_res == -1)
162         return NSS_STATUS_TRYAGAIN;
163       data->next = data->next->next;
164     }
165   while (!parse_res);
166
167   return NSS_STATUS_SUCCESS;
168 }
169
170 enum nss_status
171 _nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
172                       int *errnop)
173 {
174   enum nss_status status;
175
176   __libc_lock_lock (lock);
177
178   status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, &intern);
179
180   __libc_lock_unlock (lock);
181
182   return status;
183 }
184
185 enum nss_status
186 _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
187                          char *buffer, size_t buflen, int *errnop)
188 {
189   intern_t data = {NULL, NULL};
190   enum nss_status status;
191   int found;
192
193   if (name == NULL)
194     {
195       *errnop = EINVAL;
196       return NSS_STATUS_UNAVAIL;
197     }
198
199   status = internal_nis_setrpcent (&data);
200   if (status != NSS_STATUS_SUCCESS)
201     return status;
202
203   found = 0;
204   while (!found &&
205          ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop,
206                                               &data)) == NSS_STATUS_SUCCESS))
207     {
208       if (strcmp (rpc->r_name, name) == 0)
209         found = 1;
210       else
211         {
212           int i = 0;
213
214           while (rpc->r_aliases[i] != NULL)
215             {
216               if (strcmp (rpc->r_aliases[i], name) == 0)
217                 {
218                   found = 1;
219                   break;
220                 }
221               else
222                 ++i;
223             }
224         }
225     }
226
227   internal_nis_endrpcent (&data);
228
229   if (!found && status == NSS_STATUS_SUCCESS)
230     return NSS_STATUS_NOTFOUND;
231   else
232     return status;
233 }
234
235 enum nss_status
236 _nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
237                            char *buffer, size_t buflen, int *errnop)
238 {
239   struct parser_data *data = (void *) buffer;
240   enum nss_status retval;
241   char *domain, *result, *p;
242   int len, nlen, parse_res;
243   char buf[32];
244
245   if (yp_get_default_domain (&domain))
246     return NSS_STATUS_UNAVAIL;
247
248   nlen = sprintf (buf, "%d", number);
249
250   retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf,
251                                  nlen, &result, &len));
252
253   if (retval != NSS_STATUS_SUCCESS)
254     {
255       if (retval == NSS_STATUS_TRYAGAIN)
256         *errnop = errno;
257       return retval;
258     }
259
260   if ((size_t) (len + 1) > buflen)
261     {
262       free (result);
263       *errnop = ERANGE;
264       return NSS_STATUS_TRYAGAIN;
265     }
266
267   p = strncpy (buffer, result, len);
268   buffer[len] = '\0';
269   while (isspace (*p))
270     ++p;
271   free (result);
272
273   parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen, errnop);
274
275   if (parse_res < 1)
276     {
277       if (parse_res == -1)
278         return NSS_STATUS_TRYAGAIN;
279       else
280         return NSS_STATUS_NOTFOUND;
281     }
282   else
283     return NSS_STATUS_SUCCESS;
284 }