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