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