Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/net/getprotoent.c
39530 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
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/param.h>
33
#include <sys/socket.h>
34
#include <errno.h>
35
#include <limits.h>
36
#include <netdb.h>
37
#include <nsswitch.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include "namespace.h"
42
#include "reentrant.h"
43
#include "un-namespace.h"
44
#include "netdb_private.h"
45
#ifdef NS_CACHING
46
#include "nscache.h"
47
#endif
48
#include "nss_tls.h"
49
50
static const ns_src defaultsrc[] = {
51
{ NSSRC_FILES, NS_SUCCESS },
52
{ NULL, 0 }
53
};
54
55
NETDB_THREAD_ALLOC(protoent_data)
56
NETDB_THREAD_ALLOC(protodata)
57
58
static void
59
protoent_data_clear(struct protoent_data *ped)
60
{
61
if (ped->fp) {
62
fclose(ped->fp);
63
ped->fp = NULL;
64
}
65
}
66
67
static void
68
protoent_data_free(void *ptr)
69
{
70
struct protoent_data *ped = ptr;
71
72
protoent_data_clear(ped);
73
free(ped);
74
}
75
76
static void
77
protodata_free(void *ptr)
78
{
79
free(ptr);
80
}
81
82
#ifdef NS_CACHING
83
int
84
__proto_id_func(char *buffer, size_t *buffer_size, va_list ap,
85
void *cache_mdata)
86
{
87
char *name;
88
int proto;
89
90
size_t desired_size, size;
91
enum nss_lookup_type lookup_type;
92
int res = NS_UNAVAIL;
93
94
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
95
switch (lookup_type) {
96
case nss_lt_name:
97
name = va_arg(ap, char *);
98
99
size = strlen(name);
100
desired_size = sizeof(enum nss_lookup_type) + size + 1;
101
if (desired_size > *buffer_size) {
102
res = NS_RETURN;
103
goto fin;
104
}
105
106
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
107
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
108
109
res = NS_SUCCESS;
110
break;
111
case nss_lt_id:
112
proto = va_arg(ap, int);
113
114
desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
115
if (desired_size > *buffer_size) {
116
res = NS_RETURN;
117
goto fin;
118
}
119
120
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
121
memcpy(buffer + sizeof(enum nss_lookup_type), &proto,
122
sizeof(int));
123
124
res = NS_SUCCESS;
125
break;
126
default:
127
/* should be unreachable */
128
return (NS_UNAVAIL);
129
}
130
131
fin:
132
*buffer_size = desired_size;
133
return (res);
134
}
135
136
137
int
138
__proto_marshal_func(char *buffer, size_t *buffer_size, void *retval,
139
va_list ap, void *cache_mdata)
140
{
141
char *name __unused;
142
int num __unused;
143
struct protoent *proto;
144
char *orig_buf __unused;
145
size_t orig_buf_size __unused;
146
147
struct protoent new_proto;
148
size_t desired_size, size, aliases_size;
149
char *p;
150
char **alias;
151
152
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
153
case nss_lt_name:
154
name = va_arg(ap, char *);
155
break;
156
case nss_lt_id:
157
num = va_arg(ap, int);
158
break;
159
case nss_lt_all:
160
break;
161
default:
162
/* should be unreachable */
163
return (NS_UNAVAIL);
164
}
165
166
proto = va_arg(ap, struct protoent *);
167
orig_buf = va_arg(ap, char *);
168
orig_buf_size = va_arg(ap, size_t);
169
170
desired_size = _ALIGNBYTES + sizeof(struct protoent) + sizeof(char *);
171
if (proto->p_name != NULL)
172
desired_size += strlen(proto->p_name) + 1;
173
174
if (proto->p_aliases != NULL) {
175
aliases_size = 0;
176
for (alias = proto->p_aliases; *alias; ++alias) {
177
desired_size += strlen(*alias) + 1;
178
++aliases_size;
179
}
180
181
desired_size += _ALIGNBYTES + (aliases_size + 1) *
182
sizeof(char *);
183
}
184
185
if (*buffer_size < desired_size) {
186
/* this assignment is here for future use */
187
*buffer_size = desired_size;
188
return (NS_RETURN);
189
}
190
191
memcpy(&new_proto, proto, sizeof(struct protoent));
192
193
*buffer_size = desired_size;
194
memset(buffer, 0, desired_size);
195
p = buffer + sizeof(struct protoent) + sizeof(char *);
196
memcpy(buffer + sizeof(struct protoent), &p, sizeof(char *));
197
p = (char *)_ALIGN(p);
198
199
if (new_proto.p_name != NULL) {
200
size = strlen(new_proto.p_name);
201
memcpy(p, new_proto.p_name, size);
202
new_proto.p_name = p;
203
p += size + 1;
204
}
205
206
if (new_proto.p_aliases != NULL) {
207
p = (char *)_ALIGN(p);
208
memcpy(p, new_proto.p_aliases, sizeof(char *) * aliases_size);
209
new_proto.p_aliases = (char **)p;
210
p += sizeof(char *) * (aliases_size + 1);
211
212
for (alias = new_proto.p_aliases; *alias; ++alias) {
213
size = strlen(*alias);
214
memcpy(p, *alias, size);
215
*alias = p;
216
p += size + 1;
217
}
218
}
219
220
memcpy(buffer, &new_proto, sizeof(struct protoent));
221
return (NS_SUCCESS);
222
}
223
224
int
225
__proto_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
226
va_list ap, void *cache_mdata)
227
{
228
char *name __unused;
229
int num __unused;
230
struct protoent *proto;
231
char *orig_buf;
232
size_t orig_buf_size;
233
int *ret_errno;
234
235
char *p;
236
char **alias;
237
238
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
239
case nss_lt_name:
240
name = va_arg(ap, char *);
241
break;
242
case nss_lt_id:
243
num = va_arg(ap, int);
244
break;
245
case nss_lt_all:
246
break;
247
default:
248
/* should be unreachable */
249
return (NS_UNAVAIL);
250
}
251
252
proto = va_arg(ap, struct protoent *);
253
orig_buf = va_arg(ap, char *);
254
orig_buf_size = va_arg(ap, size_t);
255
ret_errno = va_arg(ap, int *);
256
257
if (orig_buf_size <
258
buffer_size - sizeof(struct protoent) - sizeof(char *)) {
259
*ret_errno = ERANGE;
260
return (NS_RETURN);
261
}
262
263
memcpy(proto, buffer, sizeof(struct protoent));
264
memcpy(&p, buffer + sizeof(struct protoent), sizeof(char *));
265
266
orig_buf = (char *)_ALIGN(orig_buf);
267
memcpy(orig_buf, buffer + sizeof(struct protoent) + sizeof(char *) +
268
_ALIGN(p) - (size_t)p,
269
buffer_size - sizeof(struct protoent) - sizeof(char *) -
270
_ALIGN(p) + (size_t)p);
271
p = (char *)_ALIGN(p);
272
273
NS_APPLY_OFFSET(proto->p_name, orig_buf, p, char *);
274
if (proto->p_aliases != NULL) {
275
NS_APPLY_OFFSET(proto->p_aliases, orig_buf, p, char **);
276
277
for (alias = proto->p_aliases; *alias; ++alias)
278
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
279
}
280
281
if (retval != NULL)
282
*((struct protoent **)retval) = proto;
283
284
return (NS_SUCCESS);
285
}
286
287
NSS_MP_CACHE_HANDLING(protocols);
288
#endif /* NS_CACHING */
289
290
int
291
__copy_protoent(struct protoent *pe, struct protoent *pptr, char *buf,
292
size_t buflen)
293
{
294
char *cp;
295
int i, n;
296
int numptr, len;
297
298
/* Find out the amount of space required to store the answer. */
299
numptr = 1; /* NULL ptr */
300
len = (char *)ALIGN(buf) - buf;
301
for (i = 0; pe->p_aliases[i]; i++, numptr++) {
302
len += strlen(pe->p_aliases[i]) + 1;
303
}
304
len += strlen(pe->p_name) + 1;
305
len += numptr * sizeof(char*);
306
307
if (len > (int)buflen) {
308
errno = ERANGE;
309
return (-1);
310
}
311
312
/* copy protocol value*/
313
pptr->p_proto = pe->p_proto;
314
315
cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
316
317
/* copy official name */
318
n = strlen(pe->p_name) + 1;
319
strcpy(cp, pe->p_name);
320
pptr->p_name = cp;
321
cp += n;
322
323
/* copy aliases */
324
pptr->p_aliases = (char **)ALIGN(buf);
325
for (i = 0 ; pe->p_aliases[i]; i++) {
326
n = strlen(pe->p_aliases[i]) + 1;
327
strcpy(cp, pe->p_aliases[i]);
328
pptr->p_aliases[i] = cp;
329
cp += n;
330
}
331
pptr->p_aliases[i] = NULL;
332
333
return (0);
334
}
335
336
void
337
__setprotoent_p(int f, struct protoent_data *ped)
338
{
339
if (ped->fp == NULL)
340
ped->fp = fopen(_PATH_PROTOCOLS, "re");
341
else
342
rewind(ped->fp);
343
ped->stayopen |= f;
344
}
345
346
void
347
__endprotoent_p(struct protoent_data *ped)
348
{
349
if (ped->fp) {
350
fclose(ped->fp);
351
ped->fp = NULL;
352
}
353
ped->stayopen = 0;
354
}
355
356
int
357
__getprotoent_p(struct protoent *pe, struct protoent_data *ped)
358
{
359
char *p;
360
char *cp, **q, *endp;
361
long l;
362
363
if (ped->fp == NULL && (ped->fp = fopen(_PATH_PROTOCOLS, "re")) == NULL)
364
return (-1);
365
again:
366
if ((p = fgets(ped->line, sizeof ped->line, ped->fp)) == NULL)
367
return (-1);
368
if (*p == '#')
369
goto again;
370
cp = strpbrk(p, "#\n");
371
if (cp != NULL)
372
*cp = '\0';
373
pe->p_name = p;
374
cp = strpbrk(p, " \t");
375
if (cp == NULL)
376
goto again;
377
*cp++ = '\0';
378
while (*cp == ' ' || *cp == '\t')
379
cp++;
380
p = strpbrk(cp, " \t");
381
if (p != NULL)
382
*p++ = '\0';
383
l = strtol(cp, &endp, 10);
384
if (endp == cp || *endp != '\0' || l < 0 || l > USHRT_MAX)
385
goto again;
386
pe->p_proto = l;
387
q = pe->p_aliases = ped->aliases;
388
if (p != NULL) {
389
cp = p;
390
while (cp && *cp) {
391
if (*cp == ' ' || *cp == '\t') {
392
cp++;
393
continue;
394
}
395
if (q < &ped->aliases[_MAXALIASES - 1])
396
*q++ = cp;
397
cp = strpbrk(cp, " \t");
398
if (cp != NULL)
399
*cp++ = '\0';
400
}
401
}
402
*q = NULL;
403
return (0);
404
}
405
406
static int
407
files_getprotoent_r(void *retval, void *mdata, va_list ap)
408
{
409
struct protoent pe;
410
struct protoent_data *ped;
411
412
struct protoent *pptr;
413
char *buffer;
414
size_t buflen;
415
int *errnop;
416
417
pptr = va_arg(ap, struct protoent *);
418
buffer = va_arg(ap, char *);
419
buflen = va_arg(ap, size_t);
420
errnop = va_arg(ap, int *);
421
422
if ((ped = __protoent_data_init()) == NULL) {
423
*errnop = errno;
424
return (NS_NOTFOUND);
425
}
426
427
if (__getprotoent_p(&pe, ped) != 0) {
428
*errnop = errno;
429
return (NS_NOTFOUND);
430
}
431
432
if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
433
*errnop = errno;
434
return (NS_RETURN);
435
}
436
437
*((struct protoent **)retval) = pptr;
438
return (NS_SUCCESS);
439
}
440
441
static int
442
files_setprotoent(void *retval, void *mdata, va_list ap)
443
{
444
struct protoent_data *ped;
445
int f;
446
447
f = va_arg(ap, int);
448
if ((ped = __protoent_data_init()) == NULL)
449
return (NS_UNAVAIL);
450
451
__setprotoent_p(f, ped);
452
return (NS_UNAVAIL);
453
}
454
455
static int
456
files_endprotoent(void *retval, void *mdata, va_list ap)
457
{
458
struct protoent_data *ped;
459
460
if ((ped = __protoent_data_init()) == NULL)
461
return (NS_UNAVAIL);
462
463
__endprotoent_p(ped);
464
return (NS_UNAVAIL);
465
}
466
467
int
468
getprotoent_r(struct protoent *pptr, char *buffer, size_t buflen,
469
struct protoent **result)
470
{
471
#ifdef NS_CACHING
472
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
473
protocols, (void *)nss_lt_all,
474
__proto_marshal_func, __proto_unmarshal_func);
475
#endif
476
static const ns_dtab dtab[] = {
477
{ NSSRC_FILES, files_getprotoent_r, (void *)nss_lt_all },
478
#ifdef NS_CACHING
479
NS_CACHE_CB(&cache_info)
480
#endif
481
{ NULL, NULL, NULL }
482
};
483
int rv, ret_errno;
484
485
ret_errno = 0;
486
*result = NULL;
487
rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotoent_r",
488
defaultsrc, pptr, buffer, buflen, &ret_errno);
489
490
if (rv != NS_SUCCESS) {
491
errno = ret_errno;
492
return (ret_errno);
493
}
494
return (0);
495
}
496
497
void
498
setprotoent(int stayopen)
499
{
500
#ifdef NS_CACHING
501
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
502
protocols, (void *)nss_lt_all,
503
NULL, NULL);
504
#endif
505
506
static const ns_dtab dtab[] = {
507
{ NSSRC_FILES, files_setprotoent, NULL },
508
#ifdef NS_CACHING
509
NS_CACHE_CB(&cache_info)
510
#endif
511
{ NULL, NULL, NULL }
512
};
513
514
(void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "setprotoent", defaultsrc,
515
stayopen);
516
}
517
518
void
519
endprotoent(void)
520
{
521
#ifdef NS_CACHING
522
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
523
protocols, (void *)nss_lt_all,
524
NULL, NULL);
525
#endif
526
527
static const ns_dtab dtab[] = {
528
{ NSSRC_FILES, files_endprotoent, NULL },
529
#ifdef NS_CACHING
530
NS_CACHE_CB(&cache_info)
531
#endif
532
{ NULL, NULL, NULL }
533
};
534
535
(void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "endprotoent", defaultsrc);
536
}
537
538
struct protoent *
539
getprotoent(void)
540
{
541
struct protodata *pd;
542
struct protoent *rval;
543
544
if ((pd = __protodata_init()) == NULL)
545
return (NULL);
546
if (getprotoent_r(&pd->proto, pd->data, sizeof(pd->data), &rval) != 0)
547
return (NULL);
548
return (rval);
549
}
550
551