1 /*        $NetBSD: getservent_r.c,v 1.13 2022/03/12 17:31:39 christos Exp $     */
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *        The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
34 #if 0
35 static char sccsid[] = "@(#)getservent.c          8.1 (Berkeley) 6/4/93";
36 #else
37 __RCSID("$NetBSD: getservent_r.c,v 1.13 2022/03/12 17:31:39 christos Exp $");
38 #endif
39 #endif /* LIBC_SCCS and not lint */
40 
41 #include "namespace.h"
42 #include <cdbr.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <netdb.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 
50 #include "servent.h"
51 
52 #ifdef __weak_alias
__weak_alias(endservent_r,_endservent_r)53 __weak_alias(endservent_r,_endservent_r)
54 __weak_alias(getservent_r,_getservent_r)
55 __weak_alias(setservent_r,_setservent_r)
56 #endif
57 
58 int
59 _servent_open(struct servent_data *sd)
60 {
61           if (sd->flags & (_SV_CDB | _SV_PLAINFILE)) {
62                     sd->flags |= _SV_FIRST;
63                     return 0;
64           }
65 
66           free(sd->line);
67           sd->line = NULL;
68           free(sd->cdb_buf);
69           sd->cdb_buf = NULL;
70           sd->cdb_buf_len = 0;
71           free(sd->aliases);
72           sd->aliases = NULL;
73           sd->maxaliases = 0;
74           sd->flags |= _SV_FIRST;
75 
76           sd->cdb = cdbr_open(_PATH_SERVICES_CDB, CDBR_DEFAULT);
77           if (sd->cdb != NULL) {
78                     sd->flags |= _SV_CDB;
79                     return 0;
80           }
81 
82           sd->plainfile = fopen(_PATH_SERVICES, "re");
83           if (sd->plainfile != NULL) {
84                     sd->flags |= _SV_PLAINFILE;
85                     return 0;
86           }
87           return -1;
88 }
89 
90 void
_servent_close(struct servent_data * sd)91 _servent_close(struct servent_data *sd)
92 {
93           if (sd->flags & _SV_CDB) {
94                     cdbr_close(sd->cdb);
95                     sd->cdb = NULL;
96                     sd->flags &= ~_SV_CDB;
97           }
98 
99           if (sd->flags & _SV_PLAINFILE) {
100                     (void)fclose(sd->plainfile);
101                     sd->plainfile = NULL;
102                     sd->flags &= ~_SV_PLAINFILE;
103           }
104           sd->flags &= ~_SV_STAYOPEN;
105 }
106 
107 
108 int
_servent_getline(struct servent_data * sd)109 _servent_getline(struct servent_data *sd)
110 {
111 
112           if (sd->flags & _SV_CDB)
113                     return -1;
114 
115           if ((sd->flags & _SV_PLAINFILE) == 0)
116                     return -1;
117 
118           free(sd->line);
119           sd->line = NULL;
120 
121           if (sd->flags & _SV_FIRST) {
122                     (void)rewind((FILE *)sd->plainfile);
123                     sd->flags &= ~_SV_FIRST;
124           }
125           sd->line = fparseln(sd->plainfile, NULL, NULL, NULL,
126               FPARSELN_UNESCALL);
127           return sd->line == NULL ? -1 : 0;
128 }
129 
130 struct servent *
_servent_parseline(struct servent_data * sd,struct servent * sp)131 _servent_parseline(struct servent_data *sd, struct servent *sp)
132 {
133           size_t i = 0;
134           int oerrno;
135           char *p, *cp, **q;
136 
137           if (sd->line == NULL)
138                     return NULL;
139 
140           sp->s_name = p = sd->line;
141           p = strpbrk(p, " \t");
142           if (p == NULL)
143                     return NULL;
144           *p++ = '\0';
145           while (*p == ' ' || *p == '\t')
146                     p++;
147           cp = strpbrk(p, ",/");
148           if (cp == NULL)
149                     return NULL;
150           *cp++ = '\0';
151           sp->s_port = htons((u_short)atoi(p));
152           sp->s_proto = cp;
153           if (sd->aliases == NULL) {
154                     sd->maxaliases = 10;
155                     sd->aliases = calloc(sd->maxaliases, sizeof(*sd->aliases));
156                     if (sd->aliases == NULL) {
157                               oerrno = errno;
158                               endservent_r(sd);
159                               errno = oerrno;
160                               return NULL;
161                     }
162           }
163           sp->s_aliases = sd->aliases;
164           cp = strpbrk(cp, " \t");
165           if (cp != NULL)
166                     *cp++ = '\0';
167           while (cp && *cp) {
168                     if (*cp == ' ' || *cp == '\t') {
169                               cp++;
170                               continue;
171                     }
172                     if (i == sd->maxaliases - 2) {
173                               sd->maxaliases *= 2;
174                               q = realloc(sd->aliases, sd->maxaliases * sizeof(*q));
175                               if (q == NULL) {
176                                         oerrno = errno;
177                                         endservent_r(sd);
178                                         errno = oerrno;
179                                         return NULL;
180                               }
181                               sp->s_aliases = sd->aliases = q;
182                     }
183                     sp->s_aliases[i++] = cp;
184                     cp = strpbrk(cp, " \t");
185                     if (cp != NULL)
186                               *cp++ = '\0';
187           }
188           sp->s_aliases[i] = NULL;
189           return sp;
190 }
191 
192 void
setservent_r(int f,struct servent_data * sd)193 setservent_r(int f, struct servent_data *sd)
194 {
195           (void)_servent_open(sd);
196           sd->flags |= f ? _SV_STAYOPEN : 0;
197 }
198 
199 void
endservent_r(struct servent_data * sd)200 endservent_r(struct servent_data *sd)
201 {
202           _servent_close(sd);
203           free(sd->aliases);
204           sd->aliases = NULL;
205           sd->maxaliases = 0;
206           free(sd->line);
207           sd->line = NULL;
208           free(sd->cdb_buf);
209           sd->cdb_buf = NULL;
210           sd->cdb_buf_len = 0;
211 }
212 
213 struct servent *
getservent_r(struct servent * sp,struct servent_data * sd)214 getservent_r(struct servent *sp, struct servent_data *sd)
215 {
216 
217           if ((sd->flags & (_SV_CDB | _SV_PLAINFILE)) == 0 &&
218               _servent_open(sd) == -1)
219                     return NULL;
220 
221           if (sd->flags & _SV_CDB) {
222                     const void *data;
223                     size_t len;
224 
225                     if (sd->flags & _SV_FIRST) {
226                               sd->cdb_index = 0;
227                               sd->flags &= ~_SV_FIRST;
228                     }
229 
230                     if (cdbr_get(sd->cdb, sd->cdb_index, &data, &len))
231                               return NULL;
232                     ++sd->cdb_index;
233                     return _servent_parsedb(sd, sp, data, len);
234           }
235           if (sd->flags & _SV_PLAINFILE) {
236                     for (;;) {
237                               if (_servent_getline(sd) == -1)
238                                         return NULL;
239                               if (_servent_parseline(sd, sp) == NULL)
240                                         continue;
241                               return sp;
242                     }
243           }
244           return NULL;
245 }
246 
247 struct servent *
_servent_parsedb(struct servent_data * sd,struct servent * sp,const uint8_t * data,size_t len)248 _servent_parsedb(struct servent_data *sd, struct servent *sp,
249     const uint8_t *data, size_t len)
250 {
251           char **q;
252           size_t i;
253           int oerrno;
254 
255           if ((sd->flags & _SV_STAYOPEN) == 0) {
256                     if (len > sd->cdb_buf_len) {
257                               void *tmp = realloc(sd->cdb_buf, len);
258                               if (tmp == NULL)
259                                         goto fail;
260                               sd->cdb_buf = tmp;
261                               sd->cdb_buf_len = len;
262                     }
263                     memcpy(sd->cdb_buf, data, len);
264                     data = sd->cdb_buf;
265           }
266 
267           if (len < 2)
268                     goto fail;
269           sp->s_port = htobe16(be16dec(data));
270           data += 2;
271           len -= 2;
272 
273           if (len == 0 || len < (size_t)data[0] + 2)
274                     goto fail;
275           sp->s_proto = __UNCONST(data + 1);
276 
277           if (sp->s_proto[data[0]] != '\0')
278                     goto fail;
279 
280           len -= 2 + data[0];
281           data += 2 + data[0];
282 
283           if (len == 0)
284                     goto fail;
285           if (len < (size_t)data[0] + 2)
286                     goto fail;
287 
288           sp->s_name = __UNCONST(data + 1);
289           len -= 2 + data[0];
290           data += 2 + data[0];
291 
292           if (sd->aliases == NULL) {
293                     sd->maxaliases = 10;
294                     sd->aliases = NULL;
295                     errno = reallocarr(&sd->aliases,
296                         sd->maxaliases, sizeof(*sd->aliases));
297                     if (errno)
298                               goto fail;
299           }
300           sp->s_aliases = sd->aliases;
301           i = 0;
302           while (len) {
303                     if (len < (size_t)data[0] + 2)
304                               goto fail;
305                     if (i == sd->maxaliases - 2) {
306                               sd->maxaliases *= 2;
307                               q = sd->aliases;
308                               errno = reallocarr(&q, sd->maxaliases, sizeof(*q));
309                               if (errno)
310                                         goto fail;
311                               sp->s_aliases = sd->aliases = q;
312                     }
313                     sp->s_aliases[i++] = __UNCONST(data + 1);
314                     len -= 2 + data[0];
315                     data += 2 + data[0];
316           }
317           sp->s_aliases[i] = NULL;
318           return sp;
319 
320 fail:
321           oerrno = errno;
322           endservent_r(sd);
323           errno = oerrno;
324           return NULL;
325 }
326 
327