9aa698e96a6db3d9596af9699cb88ab43f242483
[platform/upstream/glibc.git] / nis / nss_nis / nis-proto.c
1 /* Copyright (C) 1996-2020 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, see
17    <https://www.gnu.org/licenses/>.  */
18
19 #include <nss.h>
20 #include <netdb.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <libc-lock.h>
25 #include <rpcsvc/yp.h>
26 #include <rpcsvc/ypclnt.h>
27
28 #include "nss-nis.h"
29
30 /* Get the declaration of the parser function.  */
31 #define ENTNAME protoent
32 #define EXTERN_PARSER
33 #include <nss/nss_files/files-parse.c>
34
35 __libc_lock_define_initialized (static, lock)
36
37 struct response
38 {
39   struct response *next;
40   char val[0];
41 };
42
43 static struct response *start;
44 static struct response *next;
45
46 static int
47 saveit (int instatus, char *inkey, int inkeylen, char *inval,
48         int invallen, char *indata)
49 {
50   if (instatus != YP_TRUE)
51     return 1;
52
53   if (inkey && inkeylen > 0 && inval && invallen > 0)
54     {
55       struct response *newp = malloc (sizeof (struct response) + invallen + 1);
56       if (newp == NULL)
57         return 1; /* We have no error code for out of memory */
58
59       if (start == NULL)
60         start = newp;
61       else
62         next->next = newp;
63       next = newp;
64
65       newp->next = NULL;
66       *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
67     }
68
69   return 0;
70 }
71
72 static void
73 internal_nis_endprotoent (void)
74 {
75   while (start != NULL)
76     {
77       next = start;
78       start = start->next;
79       free (next);
80     }
81 }
82
83 static enum nss_status
84 internal_nis_setprotoent (void)
85 {
86   char *domainname;
87   struct ypall_callback ypcb;
88   enum nss_status status;
89
90   yp_get_default_domain (&domainname);
91
92   internal_nis_endprotoent ();
93
94   ypcb.foreach = saveit;
95   ypcb.data = NULL;
96   status = yperr2nss (yp_all (domainname, "protocols.bynumber", &ypcb));
97   next = start;
98
99   return status;
100 }
101
102 enum nss_status
103 _nss_nis_setprotoent (int stayopen)
104 {
105   enum nss_status status;
106
107   __libc_lock_lock (lock);
108
109   status = internal_nis_setprotoent ();
110
111   __libc_lock_unlock (lock);
112
113   return status;
114 }
115
116 enum nss_status
117 _nss_nis_endprotoent (void)
118 {
119   __libc_lock_lock (lock);
120
121   internal_nis_endprotoent ();
122   next = NULL;
123
124   __libc_lock_unlock (lock);
125
126   return NSS_STATUS_SUCCESS;
127 }
128
129 static enum nss_status
130 internal_nis_getprotoent_r (struct protoent *proto,
131                             char *buffer, size_t buflen, int *errnop)
132 {
133   struct parser_data *data = (void *) buffer;
134   int parse_res;
135
136   if (start == NULL)
137     internal_nis_setprotoent ();
138
139   /* Get the next entry until we found a correct one. */
140   do
141     {
142       char *p;
143
144       if (next == NULL)
145         return NSS_STATUS_NOTFOUND;
146
147       p = strncpy (buffer, next->val, buflen);
148
149       while (isspace (*p))
150         ++p;
151
152       parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop);
153       if (parse_res == -1)
154         return NSS_STATUS_TRYAGAIN;
155       next = next->next;
156     }
157   while (!parse_res);
158
159   return NSS_STATUS_SUCCESS;
160 }
161
162 enum nss_status
163 _nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen,
164                         int *errnop)
165 {
166   enum nss_status status;
167
168   __libc_lock_lock (lock);
169
170   status = internal_nis_getprotoent_r (proto, buffer, buflen, errnop);
171
172   __libc_lock_unlock (lock);
173
174   return status;
175 }
176
177 enum nss_status
178 _nss_nis_getprotobyname_r (const char *name, struct protoent *proto,
179                            char *buffer, size_t buflen, int *errnop)
180 {
181   if (name == NULL)
182     {
183       *errnop = EINVAL;
184       return NSS_STATUS_UNAVAIL;
185     }
186
187   char *domain;
188   if (__glibc_unlikely (yp_get_default_domain (&domain)))
189     return NSS_STATUS_UNAVAIL;
190
191   char *result;
192   int len;
193   int yperr = yp_match (domain, "protocols.byname", name, strlen (name),
194                         &result, &len);
195
196   if (__glibc_unlikely (yperr != YPERR_SUCCESS))
197     {
198       enum nss_status retval = yperr2nss (yperr);
199
200       if (retval == NSS_STATUS_TRYAGAIN)
201         *errnop = errno;
202       return retval;
203     }
204
205   if (__glibc_unlikely ((size_t) (len + 1) > buflen))
206     {
207       free (result);
208       *errnop = ERANGE;
209       return NSS_STATUS_TRYAGAIN;
210     }
211
212   char *p = strncpy (buffer, result, len);
213   buffer[len] = '\0';
214   while (isspace (*p))
215     ++p;
216   free (result);
217
218   int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen,
219                                              errnop);
220   if (__glibc_unlikely (parse_res < 1))
221     {
222       if (parse_res == -1)
223         return NSS_STATUS_TRYAGAIN;
224       else
225         return NSS_STATUS_NOTFOUND;
226     }
227   return NSS_STATUS_SUCCESS;
228 }
229
230 enum nss_status
231 _nss_nis_getprotobynumber_r (int number, struct protoent *proto,
232                              char *buffer, size_t buflen, int *errnop)
233 {
234   char *domain;
235   if (__glibc_unlikely (yp_get_default_domain (&domain)))
236     return NSS_STATUS_UNAVAIL;
237
238   char buf[32];
239   int nlen = snprintf (buf, sizeof (buf), "%d", number);
240
241   char *result;
242   int len;
243   int yperr = yp_match (domain, "protocols.bynumber", buf, nlen, &result,
244                         &len);
245
246   if (__glibc_unlikely (yperr != YPERR_SUCCESS))
247     {
248       enum nss_status retval = yperr2nss (yperr);
249
250       if (retval == NSS_STATUS_TRYAGAIN)
251         *errnop = errno;
252       return retval;
253     }
254
255   if (__glibc_unlikely ((size_t) (len + 1) > buflen))
256     {
257       free (result);
258       *errnop = ERANGE;
259       return NSS_STATUS_TRYAGAIN;
260     }
261
262   char *p = strncpy (buffer, result, len);
263   buffer[len] = '\0';
264   while (isspace (*p))
265     ++p;
266   free (result);
267
268   int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen,
269                                              errnop);
270   if (__glibc_unlikely (parse_res < 1))
271     {
272       if (parse_res == -1)
273         return NSS_STATUS_TRYAGAIN;
274       else
275         return NSS_STATUS_NOTFOUND;
276     }
277   return NSS_STATUS_SUCCESS;
278 }