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