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