1 /*-
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996-1999 by Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*! \file
21 * \brief
22 * Based on the Dynamic DNS reference implementation by Viraj Bais
23 * <viraj_bais@ccm.fm.intel.com>
24 */
25
26 #if !defined(lint) && !defined(SABER)
27 static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
28 #endif /* not lint */
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: stable/12/lib/libc/resolv/res_mkupdate.c 326695 2017-12-08 15:57:29Z pfg $");
31
32 #include "port_before.h"
33
34 #include <sys/param.h>
35
36 #include <netinet/in.h>
37 #include <arpa/nameser.h>
38 #include <arpa/inet.h>
39
40 #include <errno.h>
41 #include <limits.h>
42 #include <netdb.h>
43 #include <resolv.h>
44 #include <res_update.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <ctype.h>
50
51 #ifdef _LIBC
52 #include <isc/list.h>
53 #endif
54
55 #include "port_after.h"
56
57 /* Options. Leave them on. */
58 #ifndef DEBUG
59 #define DEBUG
60 #endif
61 #define MAXPORT 1024
62
63 static int getnum_str(u_char **, u_char *);
64 static int gethexnum_str(u_char **, u_char *);
65 static int getword_str(char *, int, u_char **, u_char *);
66 static int getstr_str(char *, int, u_char **, u_char *);
67
68 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
69
70 /* Forward. */
71
72 #ifdef _LIBC
73 static
74 #endif
75 int res_protocolnumber(const char *);
76 #ifdef _LIBC
77 static
78 #endif
79 int res_servicenumber(const char *);
80
81 /*%
82 * Form update packets.
83 * Returns the size of the resulting packet if no error
84 *
85 * On error,
86 * returns
87 *\li -1 if error in reading a word/number in rdata
88 * portion for update packets
89 *\li -2 if length of buffer passed is insufficient
90 *\li -3 if zone section is not the first section in
91 * the linked list, or section order has a problem
92 *\li -4 on a number overflow
93 *\li -5 unknown operation or no records
94 */
95 int
res_nmkupdate(res_state statp,ns_updrec * rrecp_in,u_char * buf,int buflen)96 res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
97 ns_updrec *rrecp_start = rrecp_in;
98 HEADER *hp;
99 u_char *cp, *sp2, *startp, *endp;
100 int n, i, soanum, multiline;
101 ns_updrec *rrecp;
102 struct in_addr ina;
103 struct in6_addr in6a;
104 char buf2[MAXDNAME];
105 u_char buf3[MAXDNAME];
106 int section, numrrs = 0, counts[ns_s_max];
107 u_int16_t rtype, rclass;
108 u_int32_t n1, rttl;
109 u_char *dnptrs[20], **dpp, **lastdnptr;
110 #ifndef _LIBC
111 int siglen;
112 #endif
113 int keylen, certlen;
114
115 /*
116 * Initialize header fields.
117 */
118 if ((buf == NULL) || (buflen < HFIXEDSZ))
119 return (-1);
120 memset(buf, 0, HFIXEDSZ);
121 hp = (HEADER *) buf;
122 statp->id = res_nrandomid(statp);
123 hp->id = htons(statp->id);
124 hp->opcode = ns_o_update;
125 hp->rcode = NOERROR;
126 cp = buf + HFIXEDSZ;
127 buflen -= HFIXEDSZ;
128 dpp = dnptrs;
129 *dpp++ = buf;
130 *dpp++ = NULL;
131 lastdnptr = dnptrs + nitems(dnptrs);
132
133 if (rrecp_start == NULL)
134 return (-5);
135 else if (rrecp_start->r_section != S_ZONE)
136 return (-3);
137
138 memset(counts, 0, sizeof counts);
139 for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
140 numrrs++;
141 section = rrecp->r_section;
142 if (section < 0 || section >= ns_s_max)
143 return (-1);
144 counts[section]++;
145 for (i = section + 1; i < ns_s_max; i++)
146 if (counts[i])
147 return (-3);
148 rtype = rrecp->r_type;
149 rclass = rrecp->r_class;
150 rttl = rrecp->r_ttl;
151 /* overload class and type */
152 if (section == S_PREREQ) {
153 rttl = 0;
154 switch (rrecp->r_opcode) {
155 case YXDOMAIN:
156 rclass = C_ANY;
157 rtype = T_ANY;
158 rrecp->r_size = 0;
159 break;
160 case NXDOMAIN:
161 rclass = C_NONE;
162 rtype = T_ANY;
163 rrecp->r_size = 0;
164 break;
165 case NXRRSET:
166 rclass = C_NONE;
167 rrecp->r_size = 0;
168 break;
169 case YXRRSET:
170 if (rrecp->r_size == 0)
171 rclass = C_ANY;
172 break;
173 default:
174 fprintf(stderr,
175 "res_mkupdate: incorrect opcode: %d\n",
176 rrecp->r_opcode);
177 fflush(stderr);
178 return (-1);
179 }
180 } else if (section == S_UPDATE) {
181 switch (rrecp->r_opcode) {
182 case DELETE:
183 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
184 break;
185 case ADD:
186 break;
187 default:
188 fprintf(stderr,
189 "res_mkupdate: incorrect opcode: %d\n",
190 rrecp->r_opcode);
191 fflush(stderr);
192 return (-1);
193 }
194 }
195
196 /*
197 * XXX appending default domain to owner name is omitted,
198 * fqdn must be provided
199 */
200 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
201 lastdnptr)) < 0)
202 return (-1);
203 cp += n;
204 ShrinkBuffer(n + 2*INT16SZ);
205 PUTSHORT(rtype, cp);
206 PUTSHORT(rclass, cp);
207 if (section == S_ZONE) {
208 if (numrrs != 1 || rrecp->r_type != T_SOA)
209 return (-3);
210 continue;
211 }
212 ShrinkBuffer(INT32SZ + INT16SZ);
213 PUTLONG(rttl, cp);
214 sp2 = cp; /*%< save pointer to length byte */
215 cp += INT16SZ;
216 if (rrecp->r_size == 0) {
217 if (section == S_UPDATE && rclass != C_ANY)
218 return (-1);
219 else {
220 PUTSHORT(0, sp2);
221 continue;
222 }
223 }
224 startp = rrecp->r_data;
225 endp = startp + rrecp->r_size - 1;
226 /* XXX this should be done centrally. */
227 switch (rrecp->r_type) {
228 case T_A:
229 if (!getword_str(buf2, sizeof buf2, &startp, endp))
230 return (-1);
231 if (!inet_aton(buf2, &ina))
232 return (-1);
233 n1 = ntohl(ina.s_addr);
234 ShrinkBuffer(INT32SZ);
235 PUTLONG(n1, cp);
236 break;
237 case T_CNAME:
238 case T_MB:
239 case T_MG:
240 case T_MR:
241 case T_NS:
242 case T_PTR:
243 case ns_t_dname:
244 if (!getword_str(buf2, sizeof buf2, &startp, endp))
245 return (-1);
246 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
247 if (n < 0)
248 return (-1);
249 cp += n;
250 ShrinkBuffer(n);
251 break;
252 case T_MINFO:
253 case T_SOA:
254 case T_RP:
255 for (i = 0; i < 2; i++) {
256 if (!getword_str(buf2, sizeof buf2, &startp,
257 endp))
258 return (-1);
259 n = dn_comp(buf2, cp, buflen,
260 dnptrs, lastdnptr);
261 if (n < 0)
262 return (-1);
263 cp += n;
264 ShrinkBuffer(n);
265 }
266 if (rrecp->r_type == T_SOA) {
267 ShrinkBuffer(5 * INT32SZ);
268 while (isspace(*startp) || !*startp)
269 startp++;
270 if (*startp == '(') {
271 multiline = 1;
272 startp++;
273 } else
274 multiline = 0;
275 /* serial, refresh, retry, expire, minimum */
276 for (i = 0; i < 5; i++) {
277 soanum = getnum_str(&startp, endp);
278 if (soanum < 0)
279 return (-1);
280 PUTLONG(soanum, cp);
281 }
282 if (multiline) {
283 while (isspace(*startp) || !*startp)
284 startp++;
285 if (*startp != ')')
286 return (-1);
287 }
288 }
289 break;
290 case T_MX:
291 case T_AFSDB:
292 case T_RT:
293 n = getnum_str(&startp, endp);
294 if (n < 0)
295 return (-1);
296 ShrinkBuffer(INT16SZ);
297 PUTSHORT(n, cp);
298 if (!getword_str(buf2, sizeof buf2, &startp, endp))
299 return (-1);
300 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
301 if (n < 0)
302 return (-1);
303 cp += n;
304 ShrinkBuffer(n);
305 break;
306 case T_SRV:
307 n = getnum_str(&startp, endp);
308 if (n < 0)
309 return (-1);
310 ShrinkBuffer(INT16SZ);
311 PUTSHORT(n, cp);
312
313 n = getnum_str(&startp, endp);
314 if (n < 0)
315 return (-1);
316 ShrinkBuffer(INT16SZ);
317 PUTSHORT(n, cp);
318
319 n = getnum_str(&startp, endp);
320 if (n < 0)
321 return (-1);
322 ShrinkBuffer(INT16SZ);
323 PUTSHORT(n, cp);
324
325 if (!getword_str(buf2, sizeof buf2, &startp, endp))
326 return (-1);
327 n = dn_comp(buf2, cp, buflen, NULL, NULL);
328 if (n < 0)
329 return (-1);
330 cp += n;
331 ShrinkBuffer(n);
332 break;
333 case T_PX:
334 n = getnum_str(&startp, endp);
335 if (n < 0)
336 return (-1);
337 PUTSHORT(n, cp);
338 ShrinkBuffer(INT16SZ);
339 for (i = 0; i < 2; i++) {
340 if (!getword_str(buf2, sizeof buf2, &startp,
341 endp))
342 return (-1);
343 n = dn_comp(buf2, cp, buflen, dnptrs,
344 lastdnptr);
345 if (n < 0)
346 return (-1);
347 cp += n;
348 ShrinkBuffer(n);
349 }
350 break;
351 case T_WKS: {
352 char bm[MAXPORT/8];
353 unsigned int maxbm = 0;
354
355 if (!getword_str(buf2, sizeof buf2, &startp, endp))
356 return (-1);
357 if (!inet_aton(buf2, &ina))
358 return (-1);
359 n1 = ntohl(ina.s_addr);
360 ShrinkBuffer(INT32SZ);
361 PUTLONG(n1, cp);
362
363 if (!getword_str(buf2, sizeof buf2, &startp, endp))
364 return (-1);
365 if ((i = res_protocolnumber(buf2)) < 0)
366 return (-1);
367 ShrinkBuffer(1);
368 *cp++ = i & 0xff;
369
370 for (i = 0; i < MAXPORT/8 ; i++)
371 bm[i] = 0;
372
373 while (getword_str(buf2, sizeof buf2, &startp, endp)) {
374 if ((n = res_servicenumber(buf2)) <= 0)
375 return (-1);
376
377 if (n < MAXPORT) {
378 bm[n/8] |= (0x80>>(n%8));
379 if ((unsigned)n > maxbm)
380 maxbm = n;
381 } else
382 return (-1);
383 }
384 maxbm = maxbm/8 + 1;
385 ShrinkBuffer(maxbm);
386 memcpy(cp, bm, maxbm);
387 cp += maxbm;
388 break;
389 }
390 case T_HINFO:
391 for (i = 0; i < 2; i++) {
392 if ((n = getstr_str(buf2, sizeof buf2,
393 &startp, endp)) < 0)
394 return (-1);
395 if (n > 255)
396 return (-1);
397 ShrinkBuffer(n+1);
398 *cp++ = n;
399 memcpy(cp, buf2, n);
400 cp += n;
401 }
402 break;
403 case T_TXT:
404 for (;;) {
405 if ((n = getstr_str(buf2, sizeof buf2,
406 &startp, endp)) < 0) {
407 if (cp != (sp2 + INT16SZ))
408 break;
409 return (-1);
410 }
411 if (n > 255)
412 return (-1);
413 ShrinkBuffer(n+1);
414 *cp++ = n;
415 memcpy(cp, buf2, n);
416 cp += n;
417 }
418 break;
419 case T_X25:
420 /* RFC1183 */
421 if ((n = getstr_str(buf2, sizeof buf2, &startp,
422 endp)) < 0)
423 return (-1);
424 if (n > 255)
425 return (-1);
426 ShrinkBuffer(n+1);
427 *cp++ = n;
428 memcpy(cp, buf2, n);
429 cp += n;
430 break;
431 case T_ISDN:
432 /* RFC1183 */
433 if ((n = getstr_str(buf2, sizeof buf2, &startp,
434 endp)) < 0)
435 return (-1);
436 if ((n > 255) || (n == 0))
437 return (-1);
438 ShrinkBuffer(n+1);
439 *cp++ = n;
440 memcpy(cp, buf2, n);
441 cp += n;
442 if ((n = getstr_str(buf2, sizeof buf2, &startp,
443 endp)) < 0)
444 n = 0;
445 if (n > 255)
446 return (-1);
447 ShrinkBuffer(n+1);
448 *cp++ = n;
449 memcpy(cp, buf2, n);
450 cp += n;
451 break;
452 case T_NSAP:
453 if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
454 ShrinkBuffer(n);
455 memcpy(cp, buf2, n);
456 cp += n;
457 } else {
458 return (-1);
459 }
460 break;
461 case T_LOC:
462 if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
463 ShrinkBuffer(n);
464 memcpy(cp, buf2, n);
465 cp += n;
466 } else
467 return (-1);
468 break;
469 case ns_t_sig:
470 #ifdef _LIBC
471 return (-1);
472 #else
473 {
474 int sig_type, success, dateerror;
475 u_int32_t exptime, timesigned;
476
477 /* type */
478 if ((n = getword_str(buf2, sizeof buf2,
479 &startp, endp)) < 0)
480 return (-1);
481 sig_type = sym_ston(__p_type_syms, buf2, &success);
482 if (!success || sig_type == ns_t_any)
483 return (-1);
484 ShrinkBuffer(INT16SZ);
485 PUTSHORT(sig_type, cp);
486 /* alg */
487 n = getnum_str(&startp, endp);
488 if (n < 0)
489 return (-1);
490 ShrinkBuffer(1);
491 *cp++ = n;
492 /* labels */
493 n = getnum_str(&startp, endp);
494 if (n <= 0 || n > 255)
495 return (-1);
496 ShrinkBuffer(1);
497 *cp++ = n;
498 /* ottl & expire */
499 if (!getword_str(buf2, sizeof buf2, &startp, endp))
500 return (-1);
501 exptime = ns_datetosecs(buf2, &dateerror);
502 if (!dateerror) {
503 ShrinkBuffer(INT32SZ);
504 PUTLONG(rttl, cp);
505 }
506 else {
507 char *ulendp;
508 u_int32_t ottl;
509
510 errno = 0;
511 ottl = strtoul(buf2, &ulendp, 10);
512 if (errno != 0 ||
513 (ulendp != NULL && *ulendp != '\0'))
514 return (-1);
515 ShrinkBuffer(INT32SZ);
516 PUTLONG(ottl, cp);
517 if (!getword_str(buf2, sizeof buf2, &startp,
518 endp))
519 return (-1);
520 exptime = ns_datetosecs(buf2, &dateerror);
521 if (dateerror)
522 return (-1);
523 }
524 /* expire */
525 ShrinkBuffer(INT32SZ);
526 PUTLONG(exptime, cp);
527 /* timesigned */
528 if (!getword_str(buf2, sizeof buf2, &startp, endp))
529 return (-1);
530 timesigned = ns_datetosecs(buf2, &dateerror);
531 if (!dateerror) {
532 ShrinkBuffer(INT32SZ);
533 PUTLONG(timesigned, cp);
534 }
535 else
536 return (-1);
537 /* footprint */
538 n = getnum_str(&startp, endp);
539 if (n < 0)
540 return (-1);
541 ShrinkBuffer(INT16SZ);
542 PUTSHORT(n, cp);
543 /* signer name */
544 if (!getword_str(buf2, sizeof buf2, &startp, endp))
545 return (-1);
546 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
547 if (n < 0)
548 return (-1);
549 cp += n;
550 ShrinkBuffer(n);
551 /* sig */
552 if ((n = getword_str(buf2, sizeof buf2,
553 &startp, endp)) < 0)
554 return (-1);
555 siglen = b64_pton(buf2, buf3, sizeof(buf3));
556 if (siglen < 0)
557 return (-1);
558 ShrinkBuffer(siglen);
559 memcpy(cp, buf3, siglen);
560 cp += siglen;
561 break;
562 }
563 #endif
564 case ns_t_key:
565 /* flags */
566 n = gethexnum_str(&startp, endp);
567 if (n < 0)
568 return (-1);
569 ShrinkBuffer(INT16SZ);
570 PUTSHORT(n, cp);
571 /* proto */
572 n = getnum_str(&startp, endp);
573 if (n < 0)
574 return (-1);
575 ShrinkBuffer(1);
576 *cp++ = n;
577 /* alg */
578 n = getnum_str(&startp, endp);
579 if (n < 0)
580 return (-1);
581 ShrinkBuffer(1);
582 *cp++ = n;
583 /* key */
584 if ((n = getword_str(buf2, sizeof buf2,
585 &startp, endp)) < 0)
586 return (-1);
587 keylen = b64_pton(buf2, buf3, sizeof(buf3));
588 if (keylen < 0)
589 return (-1);
590 ShrinkBuffer(keylen);
591 memcpy(cp, buf3, keylen);
592 cp += keylen;
593 break;
594 case ns_t_nxt:
595 {
596 int success, nxt_type;
597 u_char data[32];
598 int maxtype;
599
600 /* next name */
601 if (!getword_str(buf2, sizeof buf2, &startp, endp))
602 return (-1);
603 n = dn_comp(buf2, cp, buflen, NULL, NULL);
604 if (n < 0)
605 return (-1);
606 cp += n;
607 ShrinkBuffer(n);
608 maxtype = 0;
609 memset(data, 0, sizeof data);
610 for (;;) {
611 if (!getword_str(buf2, sizeof buf2, &startp,
612 endp))
613 break;
614 nxt_type = sym_ston(__p_type_syms, buf2,
615 &success);
616 if (!success || !ns_t_rr_p(nxt_type))
617 return (-1);
618 NS_NXT_BIT_SET(nxt_type, data);
619 if (nxt_type > maxtype)
620 maxtype = nxt_type;
621 }
622 n = maxtype/NS_NXT_BITS+1;
623 ShrinkBuffer(n);
624 memcpy(cp, data, n);
625 cp += n;
626 break;
627 }
628 case ns_t_cert:
629 /* type */
630 n = getnum_str(&startp, endp);
631 if (n < 0)
632 return (-1);
633 ShrinkBuffer(INT16SZ);
634 PUTSHORT(n, cp);
635 /* key tag */
636 n = getnum_str(&startp, endp);
637 if (n < 0)
638 return (-1);
639 ShrinkBuffer(INT16SZ);
640 PUTSHORT(n, cp);
641 /* alg */
642 n = getnum_str(&startp, endp);
643 if (n < 0)
644 return (-1);
645 ShrinkBuffer(1);
646 *cp++ = n;
647 /* cert */
648 if ((n = getword_str(buf2, sizeof buf2,
649 &startp, endp)) < 0)
650 return (-1);
651 certlen = b64_pton(buf2, buf3, sizeof(buf3));
652 if (certlen < 0)
653 return (-1);
654 ShrinkBuffer(certlen);
655 memcpy(cp, buf3, certlen);
656 cp += certlen;
657 break;
658 case ns_t_aaaa:
659 if (!getword_str(buf2, sizeof buf2, &startp, endp))
660 return (-1);
661 if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
662 return (-1);
663 ShrinkBuffer(NS_IN6ADDRSZ);
664 memcpy(cp, &in6a, NS_IN6ADDRSZ);
665 cp += NS_IN6ADDRSZ;
666 break;
667 case ns_t_naptr:
668 /* Order Preference Flags Service Replacement Regexp */
669 /* Order */
670 n = getnum_str(&startp, endp);
671 if (n < 0 || n > 65535)
672 return (-1);
673 ShrinkBuffer(INT16SZ);
674 PUTSHORT(n, cp);
675 /* Preference */
676 n = getnum_str(&startp, endp);
677 if (n < 0 || n > 65535)
678 return (-1);
679 ShrinkBuffer(INT16SZ);
680 PUTSHORT(n, cp);
681 /* Flags */
682 if ((n = getstr_str(buf2, sizeof buf2,
683 &startp, endp)) < 0) {
684 return (-1);
685 }
686 if (n > 255)
687 return (-1);
688 ShrinkBuffer(n+1);
689 *cp++ = n;
690 memcpy(cp, buf2, n);
691 cp += n;
692 /* Service Classes */
693 if ((n = getstr_str(buf2, sizeof buf2,
694 &startp, endp)) < 0) {
695 return (-1);
696 }
697 if (n > 255)
698 return (-1);
699 ShrinkBuffer(n+1);
700 *cp++ = n;
701 memcpy(cp, buf2, n);
702 cp += n;
703 /* Pattern */
704 if ((n = getstr_str(buf2, sizeof buf2,
705 &startp, endp)) < 0) {
706 return (-1);
707 }
708 if (n > 255)
709 return (-1);
710 ShrinkBuffer(n+1);
711 *cp++ = n;
712 memcpy(cp, buf2, n);
713 cp += n;
714 /* Replacement */
715 if (!getword_str(buf2, sizeof buf2, &startp, endp))
716 return (-1);
717 n = dn_comp(buf2, cp, buflen, NULL, NULL);
718 if (n < 0)
719 return (-1);
720 cp += n;
721 ShrinkBuffer(n);
722 break;
723 default:
724 return (-1);
725 } /*switch*/
726 n = (u_int16_t)((cp - sp2) - INT16SZ);
727 PUTSHORT(n, sp2);
728 } /*for*/
729
730 hp->qdcount = htons(counts[0]);
731 hp->ancount = htons(counts[1]);
732 hp->nscount = htons(counts[2]);
733 hp->arcount = htons(counts[3]);
734 return (cp - buf);
735 }
736
737 /*%
738 * Get a whitespace delimited word from a string (not file)
739 * into buf. modify the start pointer to point after the
740 * word in the string.
741 */
742 static int
getword_str(char * buf,int size,u_char ** startpp,u_char * endp)743 getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
744 char *cp;
745 int c;
746
747 for (cp = buf; *startpp <= endp; ) {
748 c = **startpp;
749 if (isspace(c) || c == '\0') {
750 if (cp != buf) /*%< trailing whitespace */
751 break;
752 else { /*%< leading whitespace */
753 (*startpp)++;
754 continue;
755 }
756 }
757 (*startpp)++;
758 if (cp >= buf+size-1)
759 break;
760 *cp++ = (u_char)c;
761 }
762 *cp = '\0';
763 return (cp != buf);
764 }
765
766 /*%
767 * get a white spae delimited string from memory. Process quoted strings
768 * and \\DDD escapes. Return length or -1 on error. Returned string may
769 * contain nulls.
770 */
771 static char digits[] = "0123456789";
772 static int
getstr_str(char * buf,int size,u_char ** startpp,u_char * endp)773 getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
774 char *cp;
775 int c, c1 = 0;
776 int inquote = 0;
777 int seen_quote = 0;
778 int escape = 0;
779 int dig = 0;
780
781 for (cp = buf; *startpp <= endp; ) {
782 if ((c = **startpp) == '\0')
783 break;
784 /* leading white space */
785 if ((cp == buf) && !seen_quote && isspace(c)) {
786 (*startpp)++;
787 continue;
788 }
789
790 switch (c) {
791 case '\\':
792 if (!escape) {
793 escape = 1;
794 dig = 0;
795 c1 = 0;
796 (*startpp)++;
797 continue;
798 }
799 goto do_escape;
800 case '"':
801 if (!escape) {
802 inquote = !inquote;
803 seen_quote = 1;
804 (*startpp)++;
805 continue;
806 }
807 /* fall through */
808 default:
809 do_escape:
810 if (escape) {
811 switch (c) {
812 case '0':
813 case '1':
814 case '2':
815 case '3':
816 case '4':
817 case '5':
818 case '6':
819 case '7':
820 case '8':
821 case '9':
822 c1 = c1 * 10 +
823 (strchr(digits, c) - digits);
824
825 if (++dig == 3) {
826 c = c1 &0xff;
827 break;
828 }
829 (*startpp)++;
830 continue;
831 }
832 escape = 0;
833 } else if (!inquote && isspace(c))
834 goto done;
835 if (cp >= buf+size-1)
836 goto done;
837 *cp++ = (u_char)c;
838 (*startpp)++;
839 }
840 }
841 done:
842 *cp = '\0';
843 return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
844 }
845
846 /*%
847 * Get a whitespace delimited base 16 number from a string (not file) into buf
848 * update the start pointer to point after the number in the string.
849 */
850 static int
gethexnum_str(u_char ** startpp,u_char * endp)851 gethexnum_str(u_char **startpp, u_char *endp) {
852 int c, n;
853 int seendigit = 0;
854 int m = 0;
855
856 if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
857 return getnum_str(startpp, endp);
858 (*startpp)+=2;
859 for (n = 0; *startpp <= endp; ) {
860 c = **startpp;
861 if (isspace(c) || c == '\0') {
862 if (seendigit) /*%< trailing whitespace */
863 break;
864 else { /*%< leading whitespace */
865 (*startpp)++;
866 continue;
867 }
868 }
869 if (c == ';') {
870 while ((*startpp <= endp) &&
871 ((c = **startpp) != '\n'))
872 (*startpp)++;
873 if (seendigit)
874 break;
875 continue;
876 }
877 if (!isxdigit(c)) {
878 if (c == ')' && seendigit) {
879 (*startpp)--;
880 break;
881 }
882 return (-1);
883 }
884 (*startpp)++;
885 if (isdigit(c))
886 n = n * 16 + (c - '0');
887 else
888 n = n * 16 + (tolower(c) - 'a' + 10);
889 seendigit = 1;
890 }
891 return (n + m);
892 }
893
894 /*%
895 * Get a whitespace delimited base 10 number from a string (not file) into buf
896 * update the start pointer to point after the number in the string.
897 */
898 static int
getnum_str(u_char ** startpp,u_char * endp)899 getnum_str(u_char **startpp, u_char *endp) {
900 int c, n;
901 int seendigit = 0;
902 int m = 0;
903
904 for (n = 0; *startpp <= endp; ) {
905 c = **startpp;
906 if (isspace(c) || c == '\0') {
907 if (seendigit) /*%< trailing whitespace */
908 break;
909 else { /*%< leading whitespace */
910 (*startpp)++;
911 continue;
912 }
913 }
914 if (c == ';') {
915 while ((*startpp <= endp) &&
916 ((c = **startpp) != '\n'))
917 (*startpp)++;
918 if (seendigit)
919 break;
920 continue;
921 }
922 if (!isdigit(c)) {
923 if (c == ')' && seendigit) {
924 (*startpp)--;
925 break;
926 }
927 return (-1);
928 }
929 (*startpp)++;
930 n = n * 10 + (c - '0');
931 seendigit = 1;
932 }
933 return (n + m);
934 }
935
936 /*%
937 * Allocate a resource record buffer & save rr info.
938 */
939 ns_updrec *
res_mkupdrec(int section,const char * dname,u_int class,u_int type,u_long ttl)940 res_mkupdrec(int section, const char *dname,
941 u_int class, u_int type, u_long ttl) {
942 ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
943
944 if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
945 if (rrecp)
946 free((char *)rrecp);
947 return (NULL);
948 }
949 INIT_LINK(rrecp, r_link);
950 INIT_LINK(rrecp, r_glink);
951 rrecp->r_class = (ns_class)class;
952 rrecp->r_type = (ns_type)type;
953 rrecp->r_ttl = ttl;
954 rrecp->r_section = (ns_sect)section;
955 return (rrecp);
956 }
957
958 /*%
959 * Free a resource record buffer created by res_mkupdrec.
960 */
961 void
res_freeupdrec(ns_updrec * rrecp)962 res_freeupdrec(ns_updrec *rrecp) {
963 /* Note: freeing r_dp is the caller's responsibility. */
964 if (rrecp->r_dname != NULL)
965 free(rrecp->r_dname);
966 free(rrecp);
967 }
968
969 struct valuelist {
970 struct valuelist * next;
971 struct valuelist * prev;
972 char * name;
973 char * proto;
974 int port;
975 };
976 static struct valuelist *servicelist, *protolist;
977
978 static void
res_buildservicelist(void)979 res_buildservicelist(void) {
980 struct servent *sp;
981 struct valuelist *slp;
982
983 #ifdef MAYBE_HESIOD
984 setservent(0);
985 #else
986 setservent(1);
987 #endif
988 while ((sp = getservent()) != NULL) {
989 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
990 if (!slp)
991 break;
992 slp->name = strdup(sp->s_name);
993 slp->proto = strdup(sp->s_proto);
994 if ((slp->name == NULL) || (slp->proto == NULL)) {
995 if (slp->name) free(slp->name);
996 if (slp->proto) free(slp->proto);
997 free(slp);
998 break;
999 }
1000 slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
1001 slp->next = servicelist;
1002 slp->prev = NULL;
1003 if (servicelist)
1004 servicelist->prev = slp;
1005 servicelist = slp;
1006 }
1007 endservent();
1008 }
1009
1010 #ifndef _LIBC
1011 void
res_destroyservicelist()1012 res_destroyservicelist() {
1013 struct valuelist *slp, *slp_next;
1014
1015 for (slp = servicelist; slp != NULL; slp = slp_next) {
1016 slp_next = slp->next;
1017 free(slp->name);
1018 free(slp->proto);
1019 free(slp);
1020 }
1021 servicelist = (struct valuelist *)0;
1022 }
1023 #endif
1024
1025 #ifdef _LIBC
1026 static
1027 #endif
1028 void
res_buildprotolist(void)1029 res_buildprotolist(void) {
1030 struct protoent *pp;
1031 struct valuelist *slp;
1032
1033 #ifdef MAYBE_HESIOD
1034 setprotoent(0);
1035 #else
1036 setprotoent(1);
1037 #endif
1038 while ((pp = getprotoent()) != NULL) {
1039 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
1040 if (!slp)
1041 break;
1042 slp->name = strdup(pp->p_name);
1043 if (slp->name == NULL) {
1044 free(slp);
1045 break;
1046 }
1047 slp->port = pp->p_proto; /*%< host byte order */
1048 slp->next = protolist;
1049 slp->prev = NULL;
1050 if (protolist)
1051 protolist->prev = slp;
1052 protolist = slp;
1053 }
1054 endprotoent();
1055 }
1056
1057 #ifndef _LIBC
1058 void
res_destroyprotolist(void)1059 res_destroyprotolist(void) {
1060 struct valuelist *plp, *plp_next;
1061
1062 for (plp = protolist; plp != NULL; plp = plp_next) {
1063 plp_next = plp->next;
1064 free(plp->name);
1065 free(plp);
1066 }
1067 protolist = (struct valuelist *)0;
1068 }
1069 #endif
1070
1071 static int
findservice(const char * s,struct valuelist ** list)1072 findservice(const char *s, struct valuelist **list) {
1073 struct valuelist *lp = *list;
1074 int n;
1075
1076 for (; lp != NULL; lp = lp->next)
1077 if (strcasecmp(lp->name, s) == 0) {
1078 if (lp != *list) {
1079 lp->prev->next = lp->next;
1080 if (lp->next)
1081 lp->next->prev = lp->prev;
1082 (*list)->prev = lp;
1083 lp->next = *list;
1084 *list = lp;
1085 }
1086 return (lp->port); /*%< host byte order */
1087 }
1088 if (sscanf(s, "%d", &n) != 1 || n <= 0)
1089 n = -1;
1090 return (n);
1091 }
1092
1093 /*%
1094 * Convert service name or (ascii) number to int.
1095 */
1096 #ifdef _LIBC
1097 static
1098 #endif
1099 int
res_servicenumber(const char * p)1100 res_servicenumber(const char *p) {
1101 if (servicelist == (struct valuelist *)0)
1102 res_buildservicelist();
1103 return (findservice(p, &servicelist));
1104 }
1105
1106 /*%
1107 * Convert protocol name or (ascii) number to int.
1108 */
1109 #ifdef _LIBC
1110 static
1111 #endif
1112 int
res_protocolnumber(const char * p)1113 res_protocolnumber(const char *p) {
1114 if (protolist == (struct valuelist *)0)
1115 res_buildprotolist();
1116 return (findservice(p, &protolist));
1117 }
1118
1119 #ifndef _LIBC
1120 static struct servent *
cgetservbyport(u_int16_t port,const char * proto)1121 cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */
1122 struct valuelist **list = &servicelist;
1123 struct valuelist *lp = *list;
1124 static struct servent serv;
1125
1126 port = ntohs(port);
1127 for (; lp != NULL; lp = lp->next) {
1128 if (port != (u_int16_t)lp->port) /*%< Host byte order. */
1129 continue;
1130 if (strcasecmp(lp->proto, proto) == 0) {
1131 if (lp != *list) {
1132 lp->prev->next = lp->next;
1133 if (lp->next)
1134 lp->next->prev = lp->prev;
1135 (*list)->prev = lp;
1136 lp->next = *list;
1137 *list = lp;
1138 }
1139 serv.s_name = lp->name;
1140 serv.s_port = htons((u_int16_t)lp->port);
1141 serv.s_proto = lp->proto;
1142 return (&serv);
1143 }
1144 }
1145 return (0);
1146 }
1147
1148 static struct protoent *
cgetprotobynumber(int proto)1149 cgetprotobynumber(int proto) { /*%< Host byte order. */
1150 struct valuelist **list = &protolist;
1151 struct valuelist *lp = *list;
1152 static struct protoent prot;
1153
1154 for (; lp != NULL; lp = lp->next)
1155 if (lp->port == proto) { /*%< Host byte order. */
1156 if (lp != *list) {
1157 lp->prev->next = lp->next;
1158 if (lp->next)
1159 lp->next->prev = lp->prev;
1160 (*list)->prev = lp;
1161 lp->next = *list;
1162 *list = lp;
1163 }
1164 prot.p_name = lp->name;
1165 prot.p_proto = lp->port; /*%< Host byte order. */
1166 return (&prot);
1167 }
1168 return (0);
1169 }
1170
1171 const char *
res_protocolname(int num)1172 res_protocolname(int num) {
1173 static char number[8];
1174 struct protoent *pp;
1175
1176 if (protolist == (struct valuelist *)0)
1177 res_buildprotolist();
1178 pp = cgetprotobynumber(num);
1179 if (pp == NULL) {
1180 (void) sprintf(number, "%d", num);
1181 return (number);
1182 }
1183 return (pp->p_name);
1184 }
1185
1186 const char *
res_servicename(u_int16_t port,const char * proto)1187 res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
1188 static char number[8];
1189 struct servent *ss;
1190
1191 if (servicelist == (struct valuelist *)0)
1192 res_buildservicelist();
1193 ss = cgetservbyport(htons(port), proto);
1194 if (ss == NULL) {
1195 (void) sprintf(number, "%d", port);
1196 return (number);
1197 }
1198 return (ss->s_name);
1199 }
1200 #endif
1201