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