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