]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
BIND 8 resolver, gutted and fileted.
authorTed Lemon <source@isc.org>
Wed, 2 Feb 2000 07:28:15 +0000 (07:28 +0000)
committerTed Lemon <source@isc.org>
Wed, 2 Feb 2000 07:28:15 +0000 (07:28 +0000)
25 files changed:
minires/Makefile.dist [new file with mode: 0644]
minires/base64.c [new file with mode: 0644]
minires/dst_api.c [new file with mode: 0644]
minires/dst_internal.h [new file with mode: 0644]
minires/hmac_link.c [new file with mode: 0644]
minires/md5.h [new file with mode: 0644]
minires/md5_dgst.c [new file with mode: 0644]
minires/md5_locl.h [new file with mode: 0644]
minires/ns_date.c [new file with mode: 0644]
minires/ns_name.c [new file with mode: 0644]
minires/ns_parse.c [new file with mode: 0644]
minires/ns_samedomain.c [new file with mode: 0644]
minires/ns_sign.c [new file with mode: 0644]
minires/ns_verify.c [new file with mode: 0644]
minires/prandom.c [new file with mode: 0644]
minires/res_comp.c [new file with mode: 0644]
minires/res_findzonecut.c [new file with mode: 0644]
minires/res_init.c [new file with mode: 0644]
minires/res_mkquery.c [new file with mode: 0644]
minires/res_mkupdate.c [new file with mode: 0644]
minires/res_query.c [new file with mode: 0644]
minires/res_send.c [new file with mode: 0644]
minires/res_sendsigned.c [new file with mode: 0644]
minires/res_update.c [new file with mode: 0644]
minires/support.c [new file with mode: 0644]

diff --git a/minires/Makefile.dist b/minires/Makefile.dist
new file mode 100644 (file)
index 0000000..62177f3
--- /dev/null
@@ -0,0 +1,61 @@
+# Makefile.dist
+#
+# Copyright (c) 1996-2000 Internet Software Consortium.
+# Use is subject to license terms which appear in the file named
+# ISC-LICENSE that should have accompanied this file when you
+# received it.   If a file named ISC-LICENSE did not accompany this
+# file, or you are not sure the one you have is correct, you may
+# obtain an applicable copy of the license at:
+#
+#             http://www.isc.org/isc-license-1.0.html. 
+#
+# This file is part of the ISC DHCP distribution.   The documentation
+# associated with this file is listed in the file DOCUMENTATION,
+# included in the top-level directory of this release.
+#
+# Support and other services are available for ISC products - see
+# http://www.isc.org for more information.
+#
+
+CATMANPAGES = dhcpctl.cat3
+SEDMANPAGES = dhcpctl.man3
+SRC    = res_mkupdate.c res_init.c res_update.c res_send.c res_comp.c \
+        res_sendsigned.c res_findzonecut.c res_query.c res_mkquery.c \
+        ns_date.c ns_parse.c ns_sign.c ns_name.c ns_samedomain.c ns_verify.c \
+        dst_api.c hmac_link.c md5_dgst.c prandom.c support.c base64.c
+OBJ    = res_mkupdate.o res_init.o res_update.o res_send.o res_comp.o \
+        res_sendsigned.o res_findzonecut.o res_query.o res_mkquery.o \
+        ns_date.o ns_parse.o ns_sign.o ns_name.o ns_samedomain.o ns_verify.o \
+        dst_api.o hmac_link.o md5_dgst.o prandom.o support.o base64.o
+
+DEBUG  = -g
+INCLUDES = $(BINDINC) -I../includes
+CFLAGS = $(DEBUG) $(PREDEFINES) $(INCLUDES) $(COPTS) -DHMAC_MD5
+
+all:   libres.a
+
+libres.a:      $(OBJ)
+       rm -f res.a
+       ar cruv libres.a $(OBJ)
+       $(RANLIB) libres.a
+
+depend:
+       makedepend $(INCLUDES) $(PREDEFINES) $(SRCS)
+
+clean:
+       -rm -f $(OBJ) test.o test cltest.o cltest
+
+realclean: clean
+       -rm -f libdhcpctl.a *~ $(CATMANPAGES) $(SEDMANPAGES)
+
+distclean: realclean
+       -rm -f Makefile
+
+dhcpctl.cat3:  dhcpctl.man3
+       nroff -man dhcpctl.man3 >dhcpctl.cat3
+
+dhcpctl.man3:  dhcpctl.3
+       sed -e "s#ETCDIR#$(ETC)#g" -e "s#DBDIR#$(VARDB)#g" \
+               -e "s#RUNDIR#$(VARRUN)#g" < dhcpctl.3 >dhcpctl.man3
+
+# Dependencies (semi-automatically-generated)
diff --git a/minires/base64.c b/minires/base64.c
new file mode 100644 (file)
index 0000000..0d4b71a
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$Id: base64.c,v 1.1 2000/02/02 07:28:14 mellon Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/socket.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+   The following encoding technique is taken from RFC 1521 by Borenstein
+   and Freed.  It is reproduced here in a slightly edited form for
+   convenience.
+
+   A 65-character subset of US-ASCII is used, enabling 6 bits to be
+   represented per printable character. (The extra 65th character, "=",
+   is used to signify a special processing function.)
+
+   The encoding process represents 24-bit groups of input bits as output
+   strings of 4 encoded characters. Proceeding from left to right, a
+   24-bit input group is formed by concatenating 3 8-bit input groups.
+   These 24 bits are then treated as 4 concatenated 6-bit groups, each
+   of which is translated into a single digit in the base64 alphabet.
+
+   Each 6-bit group is used as an index into an array of 64 printable
+   characters. The character referenced by the index is placed in the
+   output string.
+
+                         Table 1: The Base64 Alphabet
+
+      Value Encoding  Value Encoding  Value Encoding  Value Encoding
+          0 A            17 R            34 i            51 z
+          1 B            18 S            35 j            52 0
+          2 C            19 T            36 k            53 1
+          3 D            20 U            37 l            54 2
+          4 E            21 V            38 m            55 3
+          5 F            22 W            39 n            56 4
+          6 G            23 X            40 o            57 5
+          7 H            24 Y            41 p            58 6
+          8 I            25 Z            42 q            59 7
+          9 J            26 a            43 r            60 8
+         10 K            27 b            44 s            61 9
+         11 L            28 c            45 t            62 +
+         12 M            29 d            46 u            63 /
+         13 N            30 e            47 v
+         14 O            31 f            48 w         (pad) =
+         15 P            32 g            49 x
+         16 Q            33 h            50 y
+
+   Special processing is performed if fewer than 24 bits are available
+   at the end of the data being encoded.  A full encoding quantum is
+   always completed at the end of a quantity.  When fewer than 24 input
+   bits are available in an input group, zero bits are added (on the
+   right) to form an integral number of 6-bit groups.  Padding at the
+   end of the data is performed using the '=' character.
+
+   Since all base64 input is an integral number of octets, only the
+         -------------------------------------------------                       
+   following cases can arise:
+   
+       (1) the final quantum of encoding input is an integral
+           multiple of 24 bits; here, the final unit of encoded
+          output will be an integral multiple of 4 characters
+          with no "=" padding,
+       (2) the final quantum of encoding input is exactly 8 bits;
+           here, the final unit of encoded output will be two
+          characters followed by two "=" padding characters, or
+       (3) the final quantum of encoding input is exactly 16 bits;
+           here, the final unit of encoded output will be three
+          characters followed by one "=" padding character.
+   */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+       size_t datalength = 0;
+       u_char input[3];
+       u_char output[4];
+       size_t i;
+
+       while (2 < srclength) {
+               input[0] = *src++;
+               input[1] = *src++;
+               input[2] = *src++;
+               srclength -= 3;
+
+               output[0] = input[0] >> 2;
+               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+               output[3] = input[2] & 0x3f;
+               Assert(output[0] < 64);
+               Assert(output[1] < 64);
+               Assert(output[2] < 64);
+               Assert(output[3] < 64);
+
+               if (datalength + 4 > targsize)
+                       return (-1);
+               target[datalength++] = Base64[output[0]];
+               target[datalength++] = Base64[output[1]];
+               target[datalength++] = Base64[output[2]];
+               target[datalength++] = Base64[output[3]];
+       }
+    
+       /* Now we worry about padding. */
+       if (0 != srclength) {
+               /* Get what's left. */
+               input[0] = input[1] = input[2] = '\0';
+               for (i = 0; i < srclength; i++)
+                       input[i] = *src++;
+       
+               output[0] = input[0] >> 2;
+               output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+               output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+               Assert(output[0] < 64);
+               Assert(output[1] < 64);
+               Assert(output[2] < 64);
+
+               if (datalength + 4 > targsize)
+                       return (-1);
+               target[datalength++] = Base64[output[0]];
+               target[datalength++] = Base64[output[1]];
+               if (srclength == 1)
+                       target[datalength++] = Pad64;
+               else
+                       target[datalength++] = Base64[output[2]];
+               target[datalength++] = Pad64;
+       }
+       if (datalength >= targsize)
+               return (-1);
+       target[datalength] = '\0';      /* Returned value doesn't count \0. */
+       return (datalength);
+}
+
+/* skips all whitespace anywhere.
+   converts characters, four at a time, starting at (or after)
+   src from base - 64 numbers into three 8 bit bytes in the target area.
+   it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+       char const *src;
+       u_char *target;
+       size_t targsize;
+{
+       int tarindex, state, ch;
+       char *pos;
+
+       state = 0;
+       tarindex = 0;
+
+       while ((ch = *src++) != '\0') {
+               if (isspace(ch))        /* Skip whitespace anywhere. */
+                       continue;
+
+               if (ch == Pad64)
+                       break;
+
+               pos = strchr(Base64, ch);
+               if (pos == 0)           /* A non-base64 character. */
+                       return (-1);
+
+               switch (state) {
+               case 0:
+                       if (target) {
+                               if ((size_t)tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] = (pos - Base64) << 2;
+                       }
+                       state = 1;
+                       break;
+               case 1:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 4;
+                               target[tarindex+1]  = ((pos - Base64) & 0x0f)
+                                                       << 4 ;
+                       }
+                       tarindex++;
+                       state = 2;
+                       break;
+               case 2:
+                       if (target) {
+                               if ((size_t)tarindex + 1 >= targsize)
+                                       return (-1);
+                               target[tarindex]   |=  (pos - Base64) >> 2;
+                               target[tarindex+1]  = ((pos - Base64) & 0x03)
+                                                       << 6;
+                       }
+                       tarindex++;
+                       state = 3;
+                       break;
+               case 3:
+                       if (target) {
+                               if ((size_t)tarindex >= targsize)
+                                       return (-1);
+                               target[tarindex] |= (pos - Base64);
+                       }
+                       tarindex++;
+                       state = 0;
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       /*
+        * We are done decoding Base-64 chars.  Let's see if we ended
+        * on a byte boundary, and/or with erroneous trailing characters.
+        */
+
+       if (ch == Pad64) {              /* We got a pad char. */
+               ch = *src++;            /* Skip it, get next. */
+               switch (state) {
+               case 0:         /* Invalid = in first position */
+               case 1:         /* Invalid = in second position */
+                       return (-1);
+
+               case 2:         /* Valid, means one byte of info */
+                       /* Skip any number of spaces. */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!isspace(ch))
+                                       break;
+                       /* Make sure there is another trailing = sign. */
+                       if (ch != Pad64)
+                               return (-1);
+                       ch = *src++;            /* Skip the = */
+                       /* Fall through to "single trailing =" case. */
+                       /* FALLTHROUGH */
+
+               case 3:         /* Valid, means two bytes of info */
+                       /*
+                        * We know this char is an =.  Is there anything but
+                        * whitespace after it?
+                        */
+                       for ((void)NULL; ch != '\0'; ch = *src++)
+                               if (!isspace(ch))
+                                       return (-1);
+
+                       /*
+                        * Now make sure for cases 2 and 3 that the "extra"
+                        * bits that slopped past the last full byte were
+                        * zeros.  If we don't check them, they become a
+                        * subliminal channel.
+                        */
+                       if (target && target[tarindex] != 0)
+                               return (-1);
+               }
+       } else {
+               /*
+                * We ended by seeing the end of the string.  Make sure we
+                * have no partial bytes lying around.
+                */
+               if (state != 0)
+                       return (-1);
+       }
+
+       return (tarindex);
+}
diff --git a/minires/dst_api.c b/minires/dst_api.c
new file mode 100644 (file)
index 0000000..0d1e4f7
--- /dev/null
@@ -0,0 +1,1078 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /tmp/cvstest/DHCP/minires/Attic/dst_api.c,v 1.1 2000/02/02 07:28:14 mellon Exp $";
+#endif
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+/*
+ * This file contains the interface between the DST API and the crypto API.
+ * This is the only file that needs to be changed if the crypto system is
+ * changed.  Exported functions are:
+ * void dst_init()      Initialize the toolkit
+ * int  dst_check_algorithm()   Function to determines if alg is suppored.
+ * int  dst_compare_keys()      Function to compare two keys for equality.
+ * int  dst_sign_data()         Incremental signing routine.
+ * int  dst_verify_data()       Incremental verify routine.
+ * int  dst_generate_key()      Function to generate new KEY
+ * DST_KEY *dst_read_key()      Function to retrieve private/public KEY.
+ * void dst_write_key()         Function to write out a key.
+ * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST
+ *                             KEY structure.
+ * int dst_key_to_dnskey()     Function to return a public key in DNS 
+ *                             format binary
+ * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY
+ * int *dst_key_to_buffer()    Writes out DST_KEY key matterial in buffer
+ * void dst_free_key()         Releases all memory referenced by key structure
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+#include "dst_internal.h"
+
+/* static variables */
+static int done_init = 0;
+dst_func *dst_t_func[DST_MAX_ALGS];
+const char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n";
+const char *dst_path = "";
+
+/* internal I/O functions */
+static DST_KEY *dst_s_read_public_key(const char *in_name, 
+                                     const unsigned in_id, int in_alg);
+static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key,
+                                      unsigned in_id, int in_alg);
+static int dst_s_write_public_key(const DST_KEY *key);
+static int dst_s_write_private_key(const DST_KEY *key);
+
+/* internal function to set up data structure */
+static DST_KEY *dst_s_get_key_struct(const char *name, const int alg,
+                                    const u_int32_t flags, const int protocol,
+                                    const int bits);
+
+/*
+ *  dst_init
+ *     This function initializes the Digital Signature Toolkit.
+ *     Right now, it just checks the DSTKEYPATH environment variable.
+ *  Parameters
+ *     none
+ *  Returns
+ *     none
+ */
+void
+dst_init()
+{
+       char *s;
+       unsigned len;
+
+       if (done_init != 0)
+               return;
+       done_init = 1;
+
+       s = getenv("DSTKEYPATH");
+       len = 0;
+       if (s) {
+               struct stat statbuf;
+
+               len = strlen(s);
+               if (len > PATH_MAX) {
+                       EREPORT(("%s is longer than %d characters, ignoring\n",
+                                s, PATH_MAX));
+               } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+                       EREPORT(("%s is not a valid directory\n", s));
+               } else {
+                       char *dp = (char *) malloc(len + 2);
+                       int l;
+                       memcpy(dp, s, len + 1);
+                       l = strlen (dp);
+                       if (dp[l - 1] != '/') {
+                               dp[l + 1] = 0;
+                               dp[l] = '/';
+                       }
+                       dst_path = dp;
+               }
+       }
+       memset(dst_t_func, 0, sizeof(dst_t_func));
+       /* first one is selected */
+#if 0
+       dst_bsafe_init();
+       dst_rsaref_init(); 
+#endif
+       dst_hmac_md5_init();
+#if 0
+       dst_eay_dss_init();
+       dst_cylink_init();
+#endif
+}
+
+/*
+ *  dst_check_algorithm
+ *     This function determines if the crypto system for the specified
+ *     algorithm is present.
+ *  Parameters
+ *     alg     1       KEY_RSA
+ *             3       KEY_DSA
+ *           157     KEY_HMAC_MD5
+ *                   future algorithms TBD and registered with IANA.
+ *  Returns
+ *     1 - The algorithm is available.
+ *     0 - The algorithm is not available.
+ */
+int
+dst_check_algorithm(const int alg)
+{
+       return (dst_t_func[alg] != NULL);
+}
+
+/* 
+ * dst_s_get_key_struct 
+ *     This function allocates key structure and fills in some of the 
+ *     fields of the structure. 
+ * Parameters: 
+ *     name:     the name of the key 
+ *     alg:      the algorithm number 
+ *     flags:    the dns flags of the key
+ *     protocol: the dns protocol of the key
+ *     bits:     the size of the key
+ * Returns:
+ *       NULL if error
+ *       valid pointer otherwise
+ */
+static DST_KEY *
+dst_s_get_key_struct(const char *name, const int alg, const u_int32_t flags,
+                    const int protocol, const int bits)
+{
+       DST_KEY *new_key = NULL; 
+
+       if (dst_check_algorithm(alg)) /* make sure alg is available */
+               new_key = (DST_KEY *) malloc(sizeof(*new_key));
+       if (new_key == NULL)
+               return (NULL);
+
+       memset(new_key, 0, sizeof(*new_key));
+       new_key->dk_key_name = strdup(name);
+       new_key->dk_alg = alg;
+       new_key->dk_flags = flags;
+       new_key->dk_proto = protocol;
+       new_key->dk_KEY_struct = NULL;
+       new_key->dk_key_size = bits;
+       new_key->dk_func = dst_t_func[alg];
+       return (new_key);
+}
+
+/*
+ *  dst_compare_keys
+ *     Compares two keys for equality.
+ *  Parameters
+ *     key1, key2      Two keys to be compared.
+ *  Returns
+ *     0              The keys are equal.
+ *     non-zero        The keys are not equal.
+ */
+
+int
+dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+       if (key1 == key2)
+               return (0);
+       if (key1 == NULL || key2 == NULL)
+               return (4);
+       if (key1->dk_alg != key2->dk_alg)
+               return (1);
+       if (key1->dk_key_size != key2->dk_key_size)
+               return (2);
+       if (key1->dk_id != key2->dk_id)
+               return (3);
+       return (key1->dk_func->compare(key1, key2));
+}
+
+
+/*
+ * dst_sign_data
+ *     An incremental signing function.  Data is signed in steps.
+ *     First the context must be initialized (SIG_MODE_INIT).
+ *     Then data is hashed (SIG_MODE_UPDATE).  Finally the signature
+ *     itself is created (SIG_MODE_FINAL).  This function can be called
+ *     once with INIT, UPDATE and FINAL modes all set, or it can be
+
+ *     called separately with a different mode set for each step.  The
+ *     UPDATE step can be repeated.
+ * Parameters
+ *     mode    A bit mask used to specify operation(s) to be performed.
+ *               SIG_MODE_INIT    1   Initialize digest
+ *               SIG_MODE_UPDATE        2   Add data to digest
+ *               SIG_MODE_FINAL          4   Generate signature
+ *                                           from signature
+ *               SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL
+ *     data    Data to be signed.
+ *     len     The length in bytes of data to be signed.
+ *     in_key  Contains a private key to sign with.
+ *               KEY structures should be handled (created, converted,
+ *               compared, stored, freed) by the DST.
+ *     signature
+ *           The location to which the signature will be written.
+ *     sig_len Length of the signature field in bytes.
+ * Return
+ *      0      Successfull INIT or Update operation
+ *     >0      success FINAL (sign) operation
+ *     <0      failure
+ */
+
+int
+dst_sign_data(const int mode, DST_KEY *in_key, void **context, 
+             const u_char *data, const unsigned len,
+             u_char *signature, const unsigned sig_len)
+{
+       DUMP(data, mode, len, "dst_sign_data()");
+
+       if (mode & SIG_MODE_FINAL &&
+           (in_key->dk_KEY_struct == NULL || signature == NULL))
+               return (MISSING_KEY_OR_SIGNATURE);
+
+       if (in_key->dk_func && in_key->dk_func->sign)
+               return (in_key->dk_func->sign(mode, in_key, context, data, len,
+                                             signature, sig_len));
+       return (UNKNOWN_KEYALG);
+}
+
+
+/*
+ *  dst_verify_data
+ *     An incremental verify function.  Data is verified in steps.
+ *     First the context must be initialized (SIG_MODE_INIT).
+ *     Then data is hashed (SIG_MODE_UPDATE).  Finally the signature
+ *     is verified (SIG_MODE_FINAL).  This function can be called
+ *     once with INIT, UPDATE and FINAL modes all set, or it can be
+ *     called separately with a different mode set for each step.  The
+ *     UPDATE step can be repeated.
+ *  Parameters
+ *     mode    Operations to perform this time.
+ *                   SIG_MODE_INIT       1   Initialize digest
+ *                   SIG_MODE_UPDATE     2   add data to digest
+ *                   SIG_MODE_FINAL      4   verify signature
+ *                   SIG_MODE_ALL
+ *                       (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL)
+ *     data    Data to pass through the hash function.
+ *     len      Length of the data in bytes.
+ *     in_key      Key for verification.
+ *     signature   Location of signature.
+ *     sig_len     Length of the signature in bytes.
+ *  Returns
+ *     0          Verify success
+ *     Non-Zero    Verify Failure
+ */
+
+int
+dst_verify_data(const int mode, DST_KEY *in_key, void **context, 
+               const u_char *data, const unsigned len,
+               const u_char *signature, const unsigned sig_len)
+{
+       DUMP(data, mode, len, "dst_verify_data()");
+       if (mode & SIG_MODE_FINAL &&
+           (in_key->dk_KEY_struct == NULL || signature == NULL))
+               return (MISSING_KEY_OR_SIGNATURE);
+
+       if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL)
+               return (UNSUPPORTED_KEYALG);
+       return (in_key->dk_func->verify(mode, in_key, context, data, len,
+                                       signature, sig_len));
+}
+
+
+/*
+ *  dst_read_private_key
+ *     Access a private key.  First the list of private keys that have
+ *     already been read in is searched, then the key accessed on disk.
+ *     If the private key can be found, it is returned.  If the key cannot
+ *     be found, a null pointer is returned.  The options specify required
+ *     key characteristics.  If the private key requested does not have
+ *     these characteristics, it will not be read.
+ *  Parameters
+ *     in_keyname  The private key name.
+ *     in_id       The id of the private key.
+ *     options     DST_FORCE_READ  Read from disk - don't use a previously
+ *                                   read key.
+ *               DST_CAN_SIGN    The key must be useable for signing.
+ *               DST_NO_AUTHEN   The key must be useable for authentication.
+ *               DST_STANDARD    Return any key 
+ *  Returns
+ *     NULL    If there is no key found in the current directory or
+ *                   this key has not been loaded before.
+ *     !NULL       Success - KEY structure returned.
+ */
+
+DST_KEY *
+dst_read_key(const char *in_keyname, const unsigned in_id, 
+            const int in_alg, const int type)
+{
+       char keyname[PATH_MAX];
+       DST_KEY *dg_key = NULL, *pubkey = NULL;
+
+       if (!dst_check_algorithm(in_alg)) { /* make sure alg is available */
+               EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n",
+                        in_alg));
+               return (NULL);
+       }
+       if ((type && (DST_PUBLIC | DST_PRIVATE)) == 0) 
+               return (NULL);
+       if (in_keyname == NULL) {
+               EREPORT(("dst_read_private_key(): Null key name passed in\n"));
+               return (NULL);
+       } else
+               strcpy(keyname, in_keyname);
+
+       /* before I read in the public key, check if it is allowed to sign */
+       if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL)
+               return (NULL);
+
+       if (type == DST_PUBLIC) 
+               return pubkey; 
+
+       if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg,
+                                           pubkey->dk_flags, pubkey->dk_proto,
+                                           0)))
+               return (dg_key);
+       /* Fill in private key and some fields in the general key structure */
+       if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id,
+                                       pubkey->dk_alg) == 0)
+               dg_key = dst_free_key(dg_key);
+
+       pubkey = dst_free_key(pubkey);
+       return (dg_key);
+}
+
+int 
+dst_write_key(const DST_KEY *key, const int type)
+{
+       int pub = 0, priv = 0;
+
+       if (key == NULL) 
+               return (0);
+       if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */
+               EREPORT(("dst_write_key(): Algorithm %d not suppored\n", 
+                        key->dk_alg));
+               return (UNSUPPORTED_KEYALG);
+       }
+       if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0)
+               return (0);
+
+       if (type & DST_PUBLIC) 
+               if ((pub = dst_s_write_public_key(key)) < 0)
+                       return (pub);
+       if (type & DST_PRIVATE)
+               if ((priv = dst_s_write_private_key(key)) < 0)
+                       return (priv);
+       return (priv+pub);
+}
+
+/*
+ *  dst_write_private_key
+ *     Write a private key to disk.  The filename will be of the form:
+ *     K<key->dk_name>+<key->dk_alg>+<key->dk_id>.<private key suffix>.
+ *     If there is already a file with this name, an error is returned.
+ *
+ *  Parameters
+ *     key     A DST managed key structure that contains
+ *           all information needed about a key.
+ *  Return
+ *     >= 0    Correct behavior.  Returns length of encoded key value
+ *               written to disk.
+ *     <  0    error.
+ */
+
+static int
+dst_s_write_private_key(const DST_KEY *key)
+{
+       u_char encoded_block[RAW_KEY_SIZE];
+       char file[PATH_MAX];
+       unsigned len;
+       FILE *fp;
+
+       /* First encode the key into the portable key format */
+       if (key == NULL)
+               return (-1);
+       if (key->dk_KEY_struct == NULL)
+               return (0);     /* null key has no private key */
+
+       if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) {
+               EREPORT(("dst_write_private_key(): Unsupported operation %d\n",
+                        key->dk_alg));
+               return (-5);
+       } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block,
+                                            sizeof(encoded_block))) <= 0) {
+               EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len));
+               return (-8);
+       }
+       /* Now I can create the file I want to use */
+       dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg,
+                            PRIVATE_KEY, PATH_MAX);
+
+       /* Do not overwrite an existing file */
+       if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
+               int nn;
+               if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+                       EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+                                file, out_len, nn, errno));
+                       return (-5);
+               }
+               fclose(fp);
+       } else {
+               EREPORT(("dst_write_private_key(): Can not create file %s\n"
+                        ,file));
+               return (-6);
+       }
+       memset(encoded_block, 0, len);
+       return (len);
+}
+
+/*
+*
+ *  dst_read_public_key
+ *     Read a public key from disk and store in a DST key structure.
+ *  Parameters
+ *     in_name  K<in_name><in_id>.<public key suffix> is the
+ *                   filename of the key file to be read.
+ *  Returns
+ *     NULL        If the key does not exist or no name is supplied.
+ *     NON-NULL        Initalized key structure if the key exists.
+ */
+
+static DST_KEY *
+dst_s_read_public_key(const char *in_name, const unsigned in_id, int in_alg)
+{
+       unsigned flags, len;
+       int proto, alg, dlen;
+       int c;
+       char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace;
+       u_char deckey[RAW_KEY_SIZE];
+       FILE *fp;
+
+       if (in_name == NULL) {
+               EREPORT(("dst_read_public_key(): No key name given\n"));
+               return (NULL);
+       }
+       if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY,
+                                PATH_MAX) == -1) {
+               EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n",
+                        in_name, in_id, PUBLIC_KEY));
+               return (NULL);
+       }
+       /*
+        * Open the file and read it's formatted contents up to key
+        * File format:
+        *    domain.name [ttl] [IN] KEY  <flags> <protocol> <algorithm> <key>
+        * flags, proto, alg stored as decimal (or hex numbers FIXME).
+        * (FIXME: handle parentheses for line continuation.)
+        */
+       if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
+               EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+                        name));
+               return (NULL);
+       }
+       /* Skip domain name, which ends at first blank */
+       while ((c = getc(fp)) != EOF)
+               if (isspace(c))
+                       break;
+       /* Skip blank to get to next field */
+       while ((c = getc(fp)) != EOF)
+               if (!isspace(c))
+                       break;
+
+       /* Skip optional TTL -- if initial digit, skip whole word. */
+       if (isdigit(c)) {
+               while ((c = getc(fp)) != EOF)
+                       if (isspace(c))
+                               break;
+               while ((c = getc(fp)) != EOF)
+                       if (!isspace(c))
+                               break;
+       }
+       /* Skip optional "IN" */
+       if (c == 'I' || c == 'i') {
+               while ((c = getc(fp)) != EOF)
+                       if (isspace(c))
+                               break;
+               while ((c = getc(fp)) != EOF)
+                       if (!isspace(c))
+                               break;
+       }
+       /* Locate and skip "KEY" */
+       if (c != 'K' && c != 'k') {
+               EREPORT(("\"KEY\" doesn't appear in file: %s", name));
+               return NULL;
+       }
+       while ((c = getc(fp)) != EOF)
+               if (isspace(c))
+                       break;
+       while ((c = getc(fp)) != EOF)
+               if (!isspace(c))
+                       break;
+       ungetc(c, fp);          /* return the charcter to the input field */
+       /* Handle hex!! FIXME.  */
+
+       if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) {
+               EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n"
+                        ,name));
+               return (NULL);
+       }
+       /* read in the key string */
+       fgets(enckey, sizeof(enckey), fp);
+
+       /* If we aren't at end-of-file, something is wrong.  */
+       while ((c = getc(fp)) != EOF)
+               if (!isspace(c))
+                       break;
+       if (!feof(fp)) {
+               EREPORT(("Key too long in file: %s", name));
+               return NULL;
+       }
+       fclose(fp);
+
+       if ((len = strlen(enckey)) <= 0)
+               return (NULL);
+
+       /* discard \n */
+       enckey[--len] = '\0';
+
+       /* remove leading spaces */
+       for (notspace = (char *) enckey; isspace(*notspace); len--)
+               notspace++;
+
+       dlen = b64_pton(notspace, deckey, sizeof(deckey));
+       if (dlen < 0) {
+               EREPORT(("dst_read_public_key: bad return from b64_pton = %d",
+                        dlen));
+               return (NULL);
+       }
+       /* store key and info in a key structure that is returned */
+/*     return dst_store_public_key(in_name, alg, proto, 666, flags, deckey,
+                                   dlen);*/
+       return dst_buffer_to_key(in_name, alg,
+                                flags, proto, deckey, (unsigned)dlen);
+}
+
+
+/*
+ *  dst_write_public_key
+ *     Write a key to disk in DNS format.
+ *  Parameters
+ *     key     Pointer to a DST key structure.
+ *  Returns
+ *     0       Failure
+ *     1       Success
+ */
+
+static int
+dst_s_write_public_key(const DST_KEY *key)
+{
+       FILE *fp;
+       char filename[PATH_MAX];
+       u_char out_key[RAW_KEY_SIZE];
+       char enc_key[RAW_KEY_SIZE];
+       int len = 0;
+
+       memset(out_key, 0, sizeof(out_key));
+       if (key == NULL) {
+               EREPORT(("dst_write_public_key(): No key specified \n"));
+               return (0);
+       } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0)
+               return (0);
+
+       /* Make the filename */
+       if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id,
+                                key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) {
+               EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n",
+                        key->dk_key_name, key->dk_id, PUBLIC_KEY));
+               return (0);
+       }
+       /* create public key file */
+       if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) {
+               EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+                        filename, errno));
+               return (0);
+       }
+       /*write out key first base64 the key data */
+       if (key->dk_flags & DST_EXTEND_FLAG)
+               b64_ntop(&out_key[6],
+                        (unsigned)(len - 6), enc_key, sizeof(enc_key));
+       else
+               b64_ntop(&out_key[4],
+                        (unsigned)(len - 4), enc_key, sizeof(enc_key));
+       fprintf(fp, "%s IN KEY %d %d %d %s\n",
+               key->dk_key_name,
+               key->dk_flags, key->dk_proto, key->dk_alg, enc_key);
+       fclose(fp);
+       return (1);
+}
+
+
+/*
+ *  dst_dnskey_to_public_key
+ *     This function converts the contents of a DNS KEY RR into a DST
+ *     key structure.
+ *  Paramters
+ *     len      Length of the RDATA of the KEY RR RDATA
+ *     rdata    A pointer to the the KEY RR RDATA.
+ *     in_name     Key name to be stored in key structure.
+ *  Returns
+ *     NULL        Failure
+ *     NON-NULL        Success.  Pointer to key structure.
+ *                     Caller's responsibility to free() it.
+ */
+
+DST_KEY *
+dst_dnskey_to_key(const char *in_name,
+                 const u_char *rdata, const unsigned len)
+{
+       DST_KEY *key_st;
+       int alg ;
+       int start = DST_KEY_START;
+
+       if (rdata == NULL || len <= DST_KEY_ALG) /* no data */
+               return (NULL);
+       alg = (u_int8_t) rdata[DST_KEY_ALG];
+       if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+               EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n",
+                        alg));
+               return (NULL);
+       }
+       if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL)
+               return (NULL);
+
+       if (in_name == NULL)
+               return (NULL);
+       key_st->dk_flags = dst_s_get_int16(rdata);
+       key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT];
+       if (key_st->dk_flags & DST_EXTEND_FLAG) {
+               u_int32_t ext_flags;
+               ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]);
+               key_st->dk_flags = key_st->dk_flags | (ext_flags << 16);
+               start += 2;
+       }
+       /*
+        * now point to the begining of the data representing the encoding
+        * of the key
+        */
+       if (key_st->dk_func && key_st->dk_func->from_dns_key) {
+               if (key_st->dk_func->from_dns_key(key_st, &rdata[start],
+                                                 len - start) > 0)
+                       return (key_st);
+       } else
+               EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n",
+                        alg));
+
+       SAFE_FREE(key_st);
+       return (key_st);
+}
+
+
+/*
+ *  dst_public_key_to_dnskey
+ *     Function to encode a public key into DNS KEY wire format 
+ *  Parameters
+ *     key          Key structure to encode.
+ *     out_storage     Location to write the encoded key to.
+ *     out_len  Size of the output array.
+ *  Returns
+ *     <0      Failure
+ *     >=0     Number of bytes written to out_storage
+ */
+
+int
+dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage,
+                        const unsigned out_len)
+{
+       u_int16_t val;
+       int loc = 0;
+       int enc_len = 0;
+       if (key == NULL)
+               return (-1);
+
+       if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */
+               EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n",
+                        key->dk_alg));
+               return (UNSUPPORTED_KEYALG);
+       }
+       memset(out_storage, 0, out_len);
+       val = (u_int16_t)(key->dk_flags & 0xffff);
+       putUShort(out_storage, val);
+       loc += 2;
+
+       out_storage[loc++] = (u_char) key->dk_proto;
+       out_storage[loc++] = (u_char) key->dk_alg;
+
+       if (key->dk_flags > 0xffff) {   /* Extended flags */
+               val = (u_int16_t)((key->dk_flags >> 16) & 0xffff);
+               putUShort(&out_storage[loc], val);
+               loc += 2;
+       }
+       if (key->dk_KEY_struct == NULL)
+               return (loc);
+       if (key->dk_func && key->dk_func->to_dns_key) {
+               enc_len = key->dk_func->to_dns_key(key,
+                                                (u_char *) &out_storage[loc],
+                                                  out_len - loc);
+               if (enc_len > 0)
+                       return (enc_len + loc);
+               else
+                       return (-1);
+       } else
+               EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n",
+                        key->dk_alg));
+       return (-1);
+}
+
+
+/*
+ *  dst_buffer_to_key
+ *     Function to encode a string of raw data into a DST key
+ *  Parameters
+ *     alg             The algorithm (HMAC only)
+ *     key             A pointer to the data
+ *     keylen          The length of the data
+ *  Returns
+ *     NULL        an error occurred
+ *     NON-NULL        the DST key
+ */
+DST_KEY *
+dst_buffer_to_key(const char *key_name,                /* name of the key */
+                 const int alg,                /* algorithm */
+                 const unsigned flags,         /* dns flags */
+                 const int protocol,           /* dns protocol */
+                 const u_char *key_buf,        /* key in dns wire fmt */
+                 const unsigned key_len)               /* size of key */
+{
+       
+       DST_KEY *dkey = NULL; 
+
+       if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+               EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg));
+               return (NULL);
+       }
+
+       dkey = dst_s_get_key_struct(key_name, alg, flags,  protocol, -1);
+
+       if (dkey == NULL)
+               return (NULL);
+       if (dkey->dk_func != NULL &&
+           dkey->dk_func->from_dns_key != NULL) {
+               if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) {
+                       EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n"));
+                       return (dst_free_key(dkey));
+               }
+               return (dkey);
+       }
+       return (NULL);
+}
+
+int 
+dst_key_to_buffer(DST_KEY *key, u_char *out_buff, unsigned buf_len)
+{
+       int len;
+  /* this function will extrac the secret of HMAC into a buffer */
+       if(key == NULL) 
+               return (0);
+       if(key->dk_func != NULL && key->dk_func != NULL) {
+               len = key->dk_func->to_dns_key(key, out_buff, buf_len);
+               if (len < 0)
+                       return (0);
+               return (len);
+       }
+       return (0);
+}
+
+
+/*
+ * dst_s_read_private_key_file
+ *     Function reads in private key from a file.
+ *     Fills out the KEY structure.
+ * Parameters
+ *     name    Name of the key to be read.
+ *     pk_key  Structure that the key is returned in.
+ *     in_id   Key identifier (tag)
+ * Return
+ *     1 if everthing works
+ *     0 if there is any problem
+ */
+
+static int
+dst_s_read_private_key_file(char *name, DST_KEY *pk_key, unsigned in_id,
+                           int in_alg)
+{
+       int cnt, alg, len, major, minor, file_major, file_minor;
+       int id;
+       char filename[PATH_MAX];
+       u_char in_buff[RAW_KEY_SIZE], *p;
+       FILE *fp;
+
+       if (name == NULL || pk_key == NULL) {
+               EREPORT(("dst_read_private_key_file(): No key name given\n"));
+               return (0);
+       }
+       /* Make the filename */
+       if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY,
+                                PATH_MAX) == -1) {
+               EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n",
+                        name, in_id, PRIVATE_KEY));
+               return (0);
+       }
+       /* first check if we can find the key file */
+       if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
+               EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+                        filename, dst_path[0] ? dst_path :
+                        (char *) getcwd(NULL, PATH_MAX - 1)));
+               return (0);
+       }
+       /* now read the header info from the file */
+       if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) {
+               fclose(fp);
+               EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n",
+                        filename));
+               return (0);
+       }
+       /* decrypt key */
+       fclose(fp);
+       if (memcmp(in_buff, "Private-key-format: v", 20) != 0)
+               goto fail;
+       len = cnt;
+       p = in_buff;
+
+       if (!dst_s_verify_str((const char **) &p, "Private-key-format: v")) {
+               EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name));
+               goto fail;
+       }
+       /* read in file format */
+       sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+       sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor);
+       if (file_major < 1) {
+               EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n",
+                        file_major, file_minor, name));
+               goto fail;
+       } else if (file_major > major || file_minor > minor)
+               EREPORT((
+                               "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n",
+                               name, file_major, file_minor));
+
+       while (*p++ != '\n') ;  /* skip to end of line */
+
+       if (!dst_s_verify_str((const char **) &p, "Algorithm: "))
+               goto fail;
+
+       if (sscanf((char *)p, "%d", &alg) != 1)
+               goto fail;
+       while (*p++ != '\n') ;  /* skip to end of line */
+
+       if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name))
+               SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name));
+       pk_key->dk_key_name = (char *) strdup(name);
+
+       /* allocate and fill in key structure */
+       if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL)
+               goto fail;
+
+       id = pk_key->dk_func->from_file_fmt(pk_key, (char *)p,
+                                           (unsigned)(&in_buff[len] - p));
+       if (id < 0)
+               goto fail;
+
+       /* Make sure the actual key tag matches the input tag used in the filename
+        */
+       if (id != in_id) {
+               EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id));
+               goto fail;
+       }
+       pk_key->dk_id = (u_int16_t) id;
+       pk_key->dk_alg = alg;
+       memset(in_buff, 0, (unsigned)cnt);
+       return (1);
+
+ fail:
+       memset(in_buff, 0, (unsigned)cnt);
+       return (0);
+}
+
+
+/*
+ *  dst_generate_key
+ *     Generate and store a public/private keypair.
+ *     Keys will be stored in formatted files.
+ *  Parameters
+ *     name    Name of the new key.  Used to create key files
+ *               K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private.
+ *     bits    Size of the new key in bits.
+ *     exp     What exponent to use:
+ *               0        use exponent 3
+ *               non-zero    use Fermant4
+ *     flags   The default value of the DNS Key flags.
+ *               The DNS Key RR Flag field is defined in RFC 2065,
+ *               section 3.3.  The field has 16 bits.
+ *     protocol
+ *           Default value of the DNS Key protocol field.
+ *               The DNS Key protocol field is defined in RFC 2065,
+ *               section 3.4.  The field has 8 bits.
+ *     alg     What algorithm to use.  Currently defined:
+ *               KEY_RSA       1
+ *               KEY_DSA       3
+ *               KEY_HMAC    157
+ *     out_id The key tag is returned.
+ *
+ *  Return
+ *     NULL            Failure
+ *     non-NULL        the generated key pair
+ *                     Caller frees the result, and its dk_name pointer.
+ */
+DST_KEY *
+dst_generate_key(const char *name, const int bits, const int exp,
+                const unsigned flags, const int protocol, const int alg)
+{
+       DST_KEY *new_key = NULL;
+       int res;
+       if (name == NULL)
+               return (NULL);
+
+       if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+               EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg));
+               return (NULL);
+       }
+
+       new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits);
+       if (new_key == NULL)
+               return (NULL);
+       if (bits == 0) /* null key we are done */
+               return (new_key);
+       if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) {
+               EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n",
+                        alg));
+               return (dst_free_key(new_key));
+       }
+       if ((res = new_key->dk_func->generate(new_key, exp)) <= 0) {
+               EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n",
+                        new_key->dk_key_name, new_key->dk_alg,
+                        new_key->dk_key_size, exp));
+               return (dst_free_key(new_key));
+       }
+       return (new_key);
+}
+
+
+/*
+ *  dst_free_key
+ *     Release all data structures pointed to by a key structure.
+ *  Parameters
+ *     f_key   Key structure to be freed.
+ */
+
+DST_KEY *
+dst_free_key(DST_KEY *f_key)
+{
+
+       if (f_key == NULL)
+               return (f_key);
+       if (f_key->dk_func && f_key->dk_func->destroy)
+               f_key->dk_KEY_struct =
+                       f_key->dk_func->destroy(f_key->dk_KEY_struct);
+       else {
+               EREPORT(("dst_free_key(): Unknown key alg %d\n",
+                        f_key->dk_alg));
+               free(f_key->dk_KEY_struct);     /* SHOULD NOT happen */
+       }
+       if (f_key->dk_KEY_struct) {
+               free(f_key->dk_KEY_struct);
+               f_key->dk_KEY_struct = NULL;
+       }
+       if (f_key->dk_key_name)
+               SAFE_FREE(f_key->dk_key_name);
+       SAFE_FREE(f_key);
+       return (NULL);
+}
+
+/*
+ * dst_sig_size
+ *     Return the maximim size of signature from the key specified in bytes
+ * Parameters
+ *      key 
+ * Returns
+ *     bytes
+ */
+int
+dst_sig_size(DST_KEY *key) {
+       switch (key->dk_alg) {
+           case KEY_HMAC_MD5:
+               return (16);
+           case KEY_HMAC_SHA1:
+               return (20);
+           case KEY_RSA:
+               return (key->dk_key_size + 7) / 8;
+           case KEY_DSA:
+               return (40);
+           default:
+               EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg));
+               return -1;
+       }
+}
+
+/* 
+ * dst_random 
+ *  function that multiplexes number of random number generators
+ * Parameters  
+ *   mode: select the random number generator
+ *   wanted is how many bytes of random data are requested 
+ *   outran is a buffer of size at least wanted for the output data
+ *
+ * Returns
+ *    number of bytes written to outran
+ */
+int 
+dst_random(const int mode, unsigned wanted, u_char *outran)
+{
+       u_int32_t *buff = NULL, *bp = NULL;
+       int i;
+       if (wanted <= 0 || outran == NULL) 
+               return (0);
+
+       switch (mode) {
+       case DST_RAND_SEMI: 
+               bp = buff = (u_int32_t *) malloc(wanted+sizeof(u_int32_t));
+               for (i = 0; i < wanted; i+= sizeof(u_int32_t), bp++) {
+                       *bp = dst_s_quick_random(i);
+               }
+               memcpy(outran, buff, (unsigned)wanted);
+               SAFE_FREE(buff);
+               return (wanted);
+       case DST_RAND_STD:
+               return (dst_s_semi_random(outran, wanted));
+       case DST_RAND_KEY:
+               return (dst_s_random(outran, wanted));
+       case DST_RAND_DSS:
+       default:
+               /* need error case here XXX OG */
+               return (0);
+       }
+}
+
diff --git a/minires/dst_internal.h b/minires/dst_internal.h
new file mode 100644 (file)
index 0000000..d173bc0
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef DST_INTERNAL_H
+#define DST_INTERNAL_H
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+#include <limits.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+
+#ifndef PATH_MAX
+# ifdef POSIX_PATH_MAX
+#  define PATH_MAX POSIX_PATH_MAX
+# else
+#  define PATH_MAX 255 /* this is the value of POSIX_PATH_MAX */
+# endif
+#endif 
+
+typedef struct dst_key {
+       char    *dk_key_name;   /* name of the key */
+       int     dk_key_size;    /* this is the size of the key in bits */
+       int     dk_proto;       /* what protocols this key can be used for */
+       int     dk_alg;         /* algorithm number from key record */
+       u_int32_t dk_flags;     /* and the flags of the public key */
+       u_int16_t dk_id;        /* identifier of the key */
+       void    *dk_KEY_struct; /* pointer to key in crypto pkg fmt */
+       struct dst_func *dk_func; /* point to cryptto pgk specific function table */
+} DST_KEY;
+#define HAS_DST_KEY 
+
+#include <isc/dst.h>
+/* 
+ * define what crypto systems are supported for RSA, 
+ * BSAFE is prefered over RSAREF; only one can be set at any time
+ */
+#if defined(BSAFE) && defined(RSAREF)
+# error "Cannot have both BSAFE and RSAREF defined"
+#endif
+
+/* Declare dst_lib specific constants */
+#define KEY_FILE_FORMAT "1.2"
+
+/* suffixes for key file names */
+#define PRIVATE_KEY            "private"
+#define PUBLIC_KEY             "key"
+
+/* error handling */
+#ifdef REPORT_ERRORS
+#define EREPORT(str)           printf str
+#else
+#define EREPORT(str)
+#endif
+
+/* use our own special macro to FRRE memory */
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(a) if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}
+#define SAFE_FREE2(a,s) if (a != NULL && s > 0){memset(a,0, s);free(a); a=NULL;}
+#endif
+
+typedef struct dst_func {
+       int (*sign)(const int mode, DST_KEY *key, void **context,
+                    const u_int8_t *data, const unsigned len,
+                    u_int8_t *signature, const unsigned sig_len);
+       int (*verify)(const int mode, DST_KEY *key, void **context,
+                      const u_int8_t *data, const unsigned len,
+                      const u_int8_t *signature, const unsigned sig_len);
+       int (*compare)(const DST_KEY *key1, const DST_KEY *key2);
+       int (*generate)(DST_KEY *key, int parms);
+       void *(*destroy)(void *key);
+       /* conversion functions */
+       int (*to_dns_key)(const DST_KEY *key, u_int8_t *out,
+                         const unsigned out_len);
+       int (*from_dns_key)(DST_KEY *key, const u_int8_t *str,
+                           const unsigned str_len);
+       int (*to_file_fmt)(const DST_KEY *key, char *out,
+                           const unsigned out_len);
+       int (*from_file_fmt)(DST_KEY *key, const char *out,
+                             const unsigned out_len);
+
+} dst_func;
+
+extern dst_func *dst_t_func[DST_MAX_ALGS];
+extern const char *key_file_fmt_str;
+extern const char *dst_path;
+
+#ifndef DST_HASH_SIZE
+#define DST_HASH_SIZE 20       /* RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */
+#endif
+
+#if 0
+int dst_bsafe_init(void);
+int dst_rsaref_init(void);
+#endif
+
+int dst_hmac_md5_init(void);
+
+#if 0
+int dst_cylink_init(void);
+int dst_eay_dss_init(void);
+#endif
+
+/* support functions */
+/* base64 to bignum conversion routines */
+int       dst_s_conv_bignum_u8_to_b64( char *out_buf, const unsigned out_len, 
+                                      const char *header,
+                                      const u_int8_t *bin_data,
+                                      const unsigned bin_len);
+int       dst_s_conv_bignum_b64_to_u8( const char **buf, u_int8_t *loc,
+                                      const unsigned loclen) ;
+/* from higher level support routines */
+int       dst_s_calculate_bits( const u_int8_t *str, const int max_bits); 
+int       dst_s_verify_str( const char **buf, const char *str);
+
+
+/* conversion between dns names and key file names */
+size_t    dst_s_filename_length( const char *name, const char *suffix); 
+int       dst_s_build_filename(  char *filename, const char *name, 
+                                unsigned id, int alg, const char *suffix, 
+                                size_t filename_length);
+
+FILE      *dst_s_fopen (const char *filename, const char *mode, unsigned perm);
+
+/* from file prandom.c */
+int       dst_s_random( u_int8_t *output, unsigned size);
+int       dst_s_semi_random( u_int8_t *output, unsigned size);
+u_int32_t dst_s_quick_random( int inc);
+void     dst_s_quick_random_set( u_int32_t val, u_int32_t cnt);
+
+/* 
+ * read and write network byte order into u_int?_t  
+ *  all of these should be retired
+ */
+u_int16_t dst_s_get_int16( const u_int8_t *buf);
+void      dst_s_put_int16( u_int8_t *buf, const u_int16_t val);
+
+u_int32_t dst_s_get_int32( const u_int8_t *buf);
+void      dst_s_put_int32( u_int8_t *buf, const u_int32_t val);
+
+#ifdef DUMP
+# undef DUMP
+# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d)
+#else
+# define DUMP(a,b,c,d)
+#endif
+
+
+#endif /* DST_INTERNAL_H */
diff --git a/minires/hmac_link.c b/minires/hmac_link.c
new file mode 100644 (file)
index 0000000..31b42c7
--- /dev/null
@@ -0,0 +1,494 @@
+#ifdef HMAC_MD5
+#ifndef LINT
+static const char rcsid[] = "$Header: /tmp/cvstest/DHCP/minires/Attic/hmac_link.c,v 1.1 2000/02/02 07:28:14 mellon Exp $";
+#endif
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+/* 
+ * This file contains an implementation of the HMAC-MD5 algorithm.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+#include "dst_internal.h"
+
+#ifdef USE_MD5
+# include "md5.h"
+# ifndef _MD5_H_
+#  define _MD5_H_ 1    /* make sure we do not include rsaref md5.h file */
+# endif
+#endif
+
+#define HMAC_LEN       64
+#define HMAC_IPAD      0x36
+#define HMAC_OPAD      0x5c
+#define MD5_LEN                16
+
+
+typedef struct hmackey {
+       u_char hk_ipad[64], hk_opad[64];
+} HMAC_Key;
+
+
+/************************************************************************** 
+ * dst_hmac_md5_sign
+ *     Call HMAC signing functions to sign a block of data.
+ *     There are three steps to signing, INIT (initialize structures), 
+ *     UPDATE (hash (more) data), FINAL (generate a signature).  This
+ *     routine performs one or more of these steps.
+ * Parameters
+ *     mode    SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ *     priv_key    key to use for signing.
+ *     context   the context to be used in this digest
+ *     data    data to be signed.
+ *     len      length in bytes of data.
+ *     signature   location to store signature.
+ *     sig_len     size of the signature location
+ * returns 
+ *     N  Success on SIG_MODE_FINAL = returns signature length in bytes
+ *     0  Success on SIG_MODE_INIT  and UPDATE
+ *      <0  Failure
+ */
+
+static int
+dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context, 
+                 const u_char *data, const unsigned len, 
+                 u_char *signature, const unsigned sig_len)
+{
+       HMAC_Key *key;
+       int sign_len = 0;
+       MD5_CTX *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT) 
+               ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+       else if (context)
+               ctx = (MD5_CTX *) *context;
+       if (ctx == NULL) 
+               return (-1);
+
+       if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+               return (-1);
+       key = (HMAC_Key *) d_key->dk_KEY_struct;
+
+       if (mode & SIG_MODE_INIT) {
+               MD5Init(ctx);
+               MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+       }
+
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+               MD5Update(ctx, (const unsigned char *)data, len);
+
+       if (mode & SIG_MODE_FINAL) {
+               if (signature == NULL || sig_len < MD5_LEN)
+                       return (SIGN_FINAL_FAILURE);
+               MD5Final(signature, ctx);
+
+               /* perform outer MD5 */
+               MD5Init(ctx);
+               MD5Update(ctx, key->hk_opad, HMAC_LEN);
+               MD5Update(ctx, signature, MD5_LEN);
+               MD5Final(signature, ctx);
+               sign_len = MD5_LEN;
+               SAFE_FREE(ctx);
+       }
+       else { 
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }               
+       return (sign_len);
+}
+
+
+/************************************************************************** 
+ * dst_hmac_md5_verify() 
+ *     Calls HMAC verification routines.  There are three steps to 
+ *     verification, INIT (initialize structures), UPDATE (hash (more) data), 
+ *     FINAL (generate a signature).  This routine performs one or more of 
+ *     these steps.
+ * Parameters
+ *     mode    SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ *     dkey    key to use for verify.
+ *     data    data signed.
+ *     len      length in bytes of data.
+ *     signature   signature.
+ *     sig_len     length in bytes of signature.
+ * returns 
+ *     0  Success 
+ *    <0  Failure
+ */
+
+static int
+dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
+               const u_char *data, const unsigned len,
+               const u_char *signature, const unsigned sig_len)
+{
+       HMAC_Key *key;
+       MD5_CTX *ctx = NULL;
+
+       if (mode & SIG_MODE_INIT) 
+               ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+       else if (context)
+               ctx = (MD5_CTX *) *context;
+       if (ctx == NULL) 
+               return (-1);
+
+       if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+               return (-1);
+
+       key = (HMAC_Key *) d_key->dk_KEY_struct;
+       if (mode & SIG_MODE_INIT) {
+               MD5Init(ctx);
+               MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+       }
+       if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+               MD5Update(ctx, (const unsigned char *)data, len);
+
+       if (mode & SIG_MODE_FINAL) {
+               u_char digest[MD5_LEN];
+               if (signature == NULL || key == NULL || sig_len != MD5_LEN)
+                       return (VERIFY_FINAL_FAILURE);
+               MD5Final(digest, ctx);
+
+               /* perform outer MD5 */
+               MD5Init(ctx);
+               MD5Update(ctx, key->hk_opad, HMAC_LEN);
+               MD5Update(ctx, digest, MD5_LEN);
+               MD5Final(digest, ctx);
+
+               SAFE_FREE(ctx);
+               if (memcmp(digest, signature, MD5_LEN) != 0)
+                       return (VERIFY_FINAL_FAILURE);
+       }
+       else { 
+               if (context == NULL) 
+                       return (-1);
+               *context = (void *) ctx;
+       }               
+       return (0);
+}
+
+
+/************************************************************************** 
+ * dst_buffer_to_hmac_md5
+ *     Converts key from raw data to an HMAC Key
+ *     This function gets in a pointer to the data
+ * Parameters
+ *     hkey    the HMAC key to be filled in
+ *     key     the key in raw format
+ *     keylen  the length of the key
+ * Return
+ *     0       Success
+ *     <0      Failure
+ */
+static int
+dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const unsigned keylen)
+{
+       int i;
+       HMAC_Key *hkey = NULL;
+       MD5_CTX ctx;
+       unsigned local_keylen = keylen;
+
+       if (dkey == NULL || key == NULL || keylen < 0)
+               return (-1);
+
+       if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
+                 return (-2);
+
+       memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
+       memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
+
+       /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
+       if (keylen > HMAC_LEN) {
+               u_char tk[MD5_LEN];
+               MD5Init(&ctx);
+               MD5Update(&ctx, (const unsigned char *)key, keylen);
+               MD5Final(tk, &ctx);
+               memset((void *) &ctx, 0, sizeof(ctx));
+               key = tk;
+               local_keylen = MD5_LEN;
+       }
+       /* start out by storing key in pads */
+       memcpy(hkey->hk_ipad, key, local_keylen);
+       memcpy(hkey->hk_opad, key, local_keylen);
+
+       /* XOR key with hk_ipad and opad values */
+       for (i = 0; i < HMAC_LEN; i++) {
+               hkey->hk_ipad[i] ^= HMAC_IPAD;
+               hkey->hk_opad[i] ^= HMAC_OPAD;
+       }
+       dkey->dk_key_size = local_keylen;
+       dkey->dk_KEY_struct = (void *) hkey;
+       return (1);
+}
+
+
+/************************************************************************** 
+ *  dst_hmac_md5_key_to_file_format
+ *     Encodes an HMAC Key into the portable file format.
+ *  Parameters 
+ *     hkey      HMAC KEY structure 
+ *     buff      output buffer
+ *     buff_len  size of output buffer 
+ *  Return
+ *     0  Failure - null input hkey
+ *     -1  Failure - not enough space in output area
+ *     N  Success - Length of data returned in buff
+ */
+
+static int
+dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
+                           const unsigned buff_len)
+{
+       char *bp;
+       int i;
+       unsigned len, b_len, key_len;
+       u_char key[HMAC_LEN];
+       HMAC_Key *hkey;
+
+       if (dkey == NULL || dkey->dk_KEY_struct == NULL) 
+               return (0);
+       if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+               return (-1);    /* no OR not enough space in output area */
+
+       hkey = (HMAC_Key *) dkey->dk_KEY_struct;
+       memset(buff, 0, buff_len);      /* just in case */
+       /* write file header */
+       sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
+
+       bp = (char *) strchr(buff, '\0');
+       b_len = buff_len - (bp - buff);
+
+       memset(key, 0, HMAC_LEN);
+       for (i = 0; i < HMAC_LEN; i++)
+               key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+       for (i = HMAC_LEN - 1; i >= 0; i--)
+               if (key[i] != 0)
+                       break;
+       key_len = i + 1;
+
+       strcat(bp, "Key: ");
+       bp += strlen("Key: ");
+       b_len = buff_len - (bp - buff);
+
+       len = b64_ntop(key, key_len, bp, b_len);
+       if (len < 0) 
+               return (-1);
+       bp += len;
+       *(bp++) = '\n';
+       *bp = '\0';
+       b_len = buff_len - (bp - buff);
+
+       return (buff_len - b_len);
+}
+
+
+/************************************************************************** 
+ * dst_hmac_md5_key_from_file_format
+ *     Converts contents of a key file into an HMAC key. 
+ * Parameters 
+ *     hkey    structure to put key into 
+ *     buff       buffer containing the encoded key 
+ *     buff_len   the length of the buffer
+ * Return
+ *     n >= 0 Foot print of the key converted 
+ *     n <  0 Error in conversion 
+ */
+
+static int
+dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff,
+                                 const unsigned buff_len)
+{
+       const char *p = buff, *eol;
+       u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode
+                                                        * it should probably be fixed rather than doing
+                                                        * this
+                                                        */
+       u_char *tmp;
+       unsigned key_len, len;
+
+       if (dkey == NULL)
+               return (-2);
+       if (buff == NULL)
+               return (-1);
+
+       memset(key, 0, sizeof(key));
+
+       if (!dst_s_verify_str(&p, "Key: "))
+               return (-3);
+
+       eol = strchr(p, '\n');
+       if (eol == NULL)
+               return (-4);
+       len = eol - p;
+       tmp = malloc(len + 2);
+       memcpy(tmp, p, len);
+       *(tmp + len) = 0x0;
+       key_len = b64_pton((char *)tmp, key, HMAC_LEN+1);       /* see above */
+       SAFE_FREE2(tmp, len + 2);
+
+       if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) {
+               return (-6);
+       }
+       return (0);
+}
+
+/*
+ * dst_hmac_md5_to_dns_key() 
+ *         function to extract hmac key from DST_KEY structure 
+ * intput: 
+ *      in_key:  HMAC-MD5 key 
+ * output: 
+ *     out_str: buffer to write ot
+ *      out_len: size of output buffer 
+ * returns:
+ *      number of bytes written to output buffer 
+ */
+static int
+dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+                       const unsigned out_len)
+{
+
+       HMAC_Key *hkey;
+       int i;
+       
+       if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+           out_len <= in_key->dk_key_size || out_str == NULL)
+               return (-1);
+
+       hkey = (HMAC_Key *) in_key->dk_KEY_struct;
+       for (i = 0; i < in_key->dk_key_size; i++)
+               out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+       return (i);
+}
+
+/************************************************************************** 
+ *  dst_hmac_md5_compare_keys
+ *     Compare two keys for equality.
+ *  Return
+ *     0         The keys are equal
+ *     NON-ZERO   The keys are not equal
+ */
+
+static int
+dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+       HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct;
+       HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct;
+       return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN);
+}
+
+/************************************************************************** 
+ * dst_hmac_md5_free_key_structure
+ *     Frees all (none) dynamically allocated structures in hkey
+ */
+
+static void *
+dst_hmac_md5_free_key_structure(void *key)
+{
+       HMAC_Key *hkey = key;
+       SAFE_FREE(hkey);
+       return (NULL);
+}
+
+
+/*************************************************************************** 
+ * dst_hmac_md5_generate_key
+ *     Creates a HMAC key of size size with a maximum size of 63 bytes
+ *     generating a HMAC key larger than 63 bytes makes no sense as that key 
+ *     is digested before use. 
+ */
+
+static int
+dst_hmac_md5_generate_key(DST_KEY *key, const int nothing)
+{
+       u_char *buff;
+       int i, n;
+       unsigned size, len;
+
+       if (key == NULL || key->dk_alg != KEY_HMAC_MD5)
+               return (0);
+       size = (key->dk_key_size + 7) / 8; /* convert to bytes */
+       if (size <= 0)
+               return(0);
+       
+       len = size > 64 ? 64 : size;
+       buff = malloc(len+8);
+
+       n = dst_random(DST_RAND_SEMI, len, buff);
+       n += dst_random(DST_RAND_KEY, len, buff);
+       if (n <= i) {   /* failed getting anything */
+               SAFE_FREE2(buff, len);
+               return (-1);
+       }
+       n = dst_buffer_to_hmac_md5(key, buff, len);
+       SAFE_FREE2(buff, len);
+       if (n <= 0)
+               return (n);
+       return (1);
+}
+
+/*
+ * dst_hmac_md5_init()  Function to answer set up function pointers for HMAC
+ *        related functions 
+ */
+int
+dst_hmac_md5_init()
+{
+       if (dst_t_func[KEY_HMAC_MD5] != NULL)
+               return (1);
+       dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
+       if (dst_t_func[KEY_HMAC_MD5] == NULL)
+               return (0);
+       memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
+       dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
+       dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
+       dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
+       dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
+       dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
+       dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
+       dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
+       dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
+       dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
+       return (1);
+}
+
+#else 
+int
+dst_hmac_md5_init(){
+       return (0);
+}
+#endif
+
+
+
+
+
+
+
diff --git a/minires/md5.h b/minires/md5.h
new file mode 100644 (file)
index 0000000..c886d17
--- /dev/null
@@ -0,0 +1,101 @@
+/* crypto/md/md5.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD5_H
+#define HEADER_MD5_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define MD5_CBLOCK     64
+#define MD5_LBLOCK     16
+#define MD5_BLOCK      16
+#define MD5_LAST_BLOCK  56
+#define MD5_LENGTH_BLOCK 8
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct MD5state_st
+       {
+       unsigned long A,B,C,D;
+       unsigned long Nl,Nh;
+       unsigned long data[MD5_LBLOCK];
+       int num;
+       } MD5_CTX;
+
+#ifndef NOPROTO
+void MD5_Init(MD5_CTX *c);
+void MD5_Update(MD5_CTX *c, const unsigned char *data, unsigned long len);
+void MD5_Final(unsigned char *md, MD5_CTX *c);
+unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md);
+#else
+void MD5_Init();
+void MD5_Update();
+void MD5_Final();
+unsigned char *MD5();
+#endif
+
+/* to provide backward compatabilty to RSAREF calls ogud@tis.com 1997/11/14 */
+#define MD5Init(c)             MD5_Init(c)
+#define MD5Update(c,data, len) MD5_Update(c,data,len)
+#define MD5Final(md, c)        MD5_Final(md, c) 
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/minires/md5_dgst.c b/minires/md5_dgst.c
new file mode 100644 (file)
index 0000000..a5f1375
--- /dev/null
@@ -0,0 +1,371 @@
+/* crypto/md/md5_dgst.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "minires/minires.h"
+#ifdef USE_MD5 /* Added by ogud@tis.com 1998/1/26 */
+#include "md5_locl.h"
+
+const char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997";
+
+/* Implemented from RFC1321 The MD5 Message-Digest Algorithm
+ */
+
+#define INIT_DATA_A (unsigned long)0x67452301L
+#define INIT_DATA_B (unsigned long)0xefcdab89L
+#define INIT_DATA_C (unsigned long)0x98badcfeL
+#define INIT_DATA_D (unsigned long)0x10325476L
+
+#ifndef NOPROTO
+static void md5_block(MD5_CTX *c, unsigned long *p);
+#else
+static void md5_block();
+#endif
+
+void MD5_Init(c)
+MD5_CTX *c;
+       {
+       c->A=INIT_DATA_A;
+       c->B=INIT_DATA_B;
+       c->C=INIT_DATA_C;
+       c->D=INIT_DATA_D;
+       c->Nl=0;
+       c->Nh=0;
+       c->num=0;
+       }
+
+void MD5_Update(c, data, len)
+MD5_CTX *c;
+const register unsigned char *data;
+unsigned long len;
+       {
+       register ULONG *p;
+       int sw,sc;
+       ULONG l;
+
+       if (len == 0) return;
+
+       l=(c->Nl+(len<<3))&0xffffffffL;
+       /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+        * Wei Dai <weidai@eskimo.com> for pointing it out. */
+       if (l < c->Nl) /* overflow */
+               c->Nh++;
+       c->Nh+=(len>>29);
+       c->Nl=l;
+
+       if (c->num != 0)
+               {
+               p=c->data;
+               sw=c->num>>2;
+               sc=c->num&0x03;
+
+               if ((c->num+len) >= MD5_CBLOCK)
+                       {
+                       l= p[sw];
+                       p_c2l(data,l,sc);
+                       p[sw++]=l;
+                       for (; sw<MD5_LBLOCK; sw++)
+                               {
+                               c2l(data,l);
+                               p[sw]=l;
+                               }
+                       len-=(MD5_CBLOCK-c->num);
+
+                       md5_block(c,p);
+                       c->num=0;
+                       /* drop through and do the rest */
+                       }
+               else
+                       {
+                       int ew,ec;
+
+                       c->num+=(int)len;
+                       if ((sc+len) < 4) /* ugly, add char's to a word */
+                               {
+                               l= p[sw];
+                               p_c2l_p(data,l,sc,len);
+                               p[sw]=l;
+                               }
+                       else
+                               {
+                               ew=(c->num>>2);
+                               ec=(c->num&0x03);
+                               l= p[sw];
+                               p_c2l(data,l,sc);
+                               p[sw++]=l;
+                               for (; sw < ew; sw++)
+                                       { c2l(data,l); p[sw]=l; }
+                               if (ec)
+                                       {
+                                       c2l_p(data,l,ec);
+                                       p[sw]=l;
+                                       }
+                               }
+                       return;
+                       }
+               }
+       /* we now can process the input data in blocks of MD5_CBLOCK
+        * chars and save the leftovers to c->data. */
+       p=c->data;
+       while (len >= MD5_CBLOCK)
+               {
+#if defined(L_ENDIAN) || defined(B_ENDIAN)
+               memcpy(p,data,MD5_CBLOCK);
+               data+=MD5_CBLOCK;
+#ifdef B_ENDIAN
+               for (sw=(MD5_LBLOCK/4); sw; sw--)
+                       {
+                       Endian_Reverse32(p[0]);
+                       Endian_Reverse32(p[1]);
+                       Endian_Reverse32(p[2]);
+                       Endian_Reverse32(p[3]);
+                       p+=4;
+                       }
+#endif
+#else
+               for (sw=(MD5_LBLOCK/4); sw; sw--)
+                       {
+                       c2l(data,l); *(p++)=l;
+                       c2l(data,l); *(p++)=l;
+                       c2l(data,l); *(p++)=l;
+                       c2l(data,l); *(p++)=l; 
+                       } 
+#endif
+               p=c->data;
+               md5_block(c,p);
+               len-=MD5_CBLOCK;
+               }
+       sc=(int)len;
+       c->num=sc;
+       if (sc)
+               {
+               sw=sc>>2;       /* words to copy */
+#ifdef L_ENDIAN
+               p[sw]=0;
+               memcpy(p,data,sc);
+#else
+               sc&=0x03;
+               for ( ; sw; sw--)
+                       { c2l(data,l); *(p++)=l; }
+               c2l_p(data,l,sc);
+               *p=l;
+#endif
+               }
+       }
+
+static void md5_block(c, X)
+MD5_CTX *c;
+register ULONG *X;
+       {
+       register ULONG A,B,C,D;
+
+       A=c->A;
+       B=c->B;
+       C=c->C;
+       D=c->D;
+
+       /* Round 0 */
+       R0(A,B,C,D,X[ 0], 7,0xd76aa478L);
+       R0(D,A,B,C,X[ 1],12,0xe8c7b756L);
+       R0(C,D,A,B,X[ 2],17,0x242070dbL);
+       R0(B,C,D,A,X[ 3],22,0xc1bdceeeL);
+       R0(A,B,C,D,X[ 4], 7,0xf57c0fafL);
+       R0(D,A,B,C,X[ 5],12,0x4787c62aL);
+       R0(C,D,A,B,X[ 6],17,0xa8304613L);
+       R0(B,C,D,A,X[ 7],22,0xfd469501L);
+       R0(A,B,C,D,X[ 8], 7,0x698098d8L);
+       R0(D,A,B,C,X[ 9],12,0x8b44f7afL);
+       R0(C,D,A,B,X[10],17,0xffff5bb1L);
+       R0(B,C,D,A,X[11],22,0x895cd7beL);
+       R0(A,B,C,D,X[12], 7,0x6b901122L);
+       R0(D,A,B,C,X[13],12,0xfd987193L);
+       R0(C,D,A,B,X[14],17,0xa679438eL);
+       R0(B,C,D,A,X[15],22,0x49b40821L);
+       /* Round 1 */
+       R1(A,B,C,D,X[ 1], 5,0xf61e2562L);
+       R1(D,A,B,C,X[ 6], 9,0xc040b340L);
+       R1(C,D,A,B,X[11],14,0x265e5a51L);
+       R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL);
+       R1(A,B,C,D,X[ 5], 5,0xd62f105dL);
+       R1(D,A,B,C,X[10], 9,0x02441453L);
+       R1(C,D,A,B,X[15],14,0xd8a1e681L);
+       R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L);
+       R1(A,B,C,D,X[ 9], 5,0x21e1cde6L);
+       R1(D,A,B,C,X[14], 9,0xc33707d6L);
+       R1(C,D,A,B,X[ 3],14,0xf4d50d87L);
+       R1(B,C,D,A,X[ 8],20,0x455a14edL);
+       R1(A,B,C,D,X[13], 5,0xa9e3e905L);
+       R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L);
+       R1(C,D,A,B,X[ 7],14,0x676f02d9L);
+       R1(B,C,D,A,X[12],20,0x8d2a4c8aL);
+       /* Round 2 */
+       R2(A,B,C,D,X[ 5], 4,0xfffa3942L);
+       R2(D,A,B,C,X[ 8],11,0x8771f681L);
+       R2(C,D,A,B,X[11],16,0x6d9d6122L);
+       R2(B,C,D,A,X[14],23,0xfde5380cL);
+       R2(A,B,C,D,X[ 1], 4,0xa4beea44L);
+       R2(D,A,B,C,X[ 4],11,0x4bdecfa9L);
+       R2(C,D,A,B,X[ 7],16,0xf6bb4b60L);
+       R2(B,C,D,A,X[10],23,0xbebfbc70L);
+       R2(A,B,C,D,X[13], 4,0x289b7ec6L);
+       R2(D,A,B,C,X[ 0],11,0xeaa127faL);
+       R2(C,D,A,B,X[ 3],16,0xd4ef3085L);
+       R2(B,C,D,A,X[ 6],23,0x04881d05L);
+       R2(A,B,C,D,X[ 9], 4,0xd9d4d039L);
+       R2(D,A,B,C,X[12],11,0xe6db99e5L);
+       R2(C,D,A,B,X[15],16,0x1fa27cf8L);
+       R2(B,C,D,A,X[ 2],23,0xc4ac5665L);
+       /* Round 3 */
+       R3(A,B,C,D,X[ 0], 6,0xf4292244L);
+       R3(D,A,B,C,X[ 7],10,0x432aff97L);
+       R3(C,D,A,B,X[14],15,0xab9423a7L);
+       R3(B,C,D,A,X[ 5],21,0xfc93a039L);
+       R3(A,B,C,D,X[12], 6,0x655b59c3L);
+       R3(D,A,B,C,X[ 3],10,0x8f0ccc92L);
+       R3(C,D,A,B,X[10],15,0xffeff47dL);
+       R3(B,C,D,A,X[ 1],21,0x85845dd1L);
+       R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL);
+       R3(D,A,B,C,X[15],10,0xfe2ce6e0L);
+       R3(C,D,A,B,X[ 6],15,0xa3014314L);
+       R3(B,C,D,A,X[13],21,0x4e0811a1L);
+       R3(A,B,C,D,X[ 4], 6,0xf7537e82L);
+       R3(D,A,B,C,X[11],10,0xbd3af235L);
+       R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL);
+       R3(B,C,D,A,X[ 9],21,0xeb86d391L);
+
+       c->A+=A&0xffffffffL;
+       c->B+=B&0xffffffffL;
+       c->C+=C&0xffffffffL;
+       c->D+=D&0xffffffffL;
+       }
+
+void MD5_Final(md, c)
+unsigned char *md;
+MD5_CTX *c;
+       {
+       register int i,j;
+       register ULONG l;
+       register ULONG *p;
+       static unsigned char end[4]={0x80,0x00,0x00,0x00};
+       unsigned char *cp=end;
+
+       /* c->num should definitly have room for at least one more byte. */
+       p=c->data;
+       j=c->num;
+       i=j>>2;
+
+       /* purify often complains about the following line as an
+        * Uninitialized Memory Read.  While this can be true, the
+        * following p_c2l macro will reset l when that case is true.
+        * This is because j&0x03 contains the number of 'valid' bytes
+        * already in p[i].  If and only if j&0x03 == 0, the UMR will
+        * occur but this is also the only time p_c2l will do
+        * l= *(cp++) instead of l|= *(cp++)
+        * Many thanks to Alex Tang <altitude@cic.net> for pickup this
+        * 'potential bug' */
+#ifdef PURIFY
+       if ((j&0x03) == 0) p[i]=0;
+#endif
+       l=p[i];
+       p_c2l(cp,l,j&0x03);
+       p[i]=l;
+       i++;
+       /* i is the next 'undefined word' */
+       if (c->num >= MD5_LAST_BLOCK)
+               {
+               for (; i<MD5_LBLOCK; i++)
+                       p[i]=0;
+               md5_block(c,p);
+               i=0;
+               }
+       for (; i<(MD5_LBLOCK-2); i++)
+               p[i]=0;
+       p[MD5_LBLOCK-2]=c->Nl;
+       p[MD5_LBLOCK-1]=c->Nh;
+       md5_block(c,p);
+       cp=md;
+       l=c->A; l2c(l,cp);
+       l=c->B; l2c(l,cp);
+       l=c->C; l2c(l,cp);
+       l=c->D; l2c(l,cp);
+
+       /* clear stuff, md5_block may be leaving some stuff on the stack
+        * but I'm not worried :-) */
+       c->num=0;
+/*     memset((char *)&c,0,sizeof(c));*/
+       }
+
+#ifdef undef
+int printit(l)
+unsigned long *l;
+       {
+       int i,ii;
+
+       for (i=0; i<2; i++)
+               {
+               for (ii=0; ii<8; ii++)
+                       {
+                       fprintf(stderr,"%08lx ",l[i*8+ii]);
+                       }
+               fprintf(stderr,"\n");
+               }
+       }
+#endif
+#endif /* USE_MD5 */
diff --git a/minires/md5_locl.h b/minires/md5_locl.h
new file mode 100644 (file)
index 0000000..b2f0028
--- /dev/null
@@ -0,0 +1,190 @@
+/* crypto/md/md5_locl.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "md5.h"
+
+#define ULONG  unsigned long
+#define UCHAR  unsigned char
+#define UINT   unsigned int
+
+#if defined(NOCONST)
+#define const
+#endif
+
+#undef c2l
+#define c2l(c,l)       (l = ((unsigned long)(*((c)++)))     , \
+                        l|=(((unsigned long)(*((c)++)))<< 8), \
+                        l|=(((unsigned long)(*((c)++)))<<16), \
+                        l|=(((unsigned long)(*((c)++)))<<24))
+
+#undef p_c2l
+#define p_c2l(c,l,n)   { \
+                       switch (n) { \
+                       case 0: l =((unsigned long)(*((c)++))); \
+                       case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+                       case 2: l|=((unsigned long)(*((c)++)))<<16; \
+                       case 3: l|=((unsigned long)(*((c)++)))<<24; \
+                               } \
+                       }
+
+/* NOTE the pointer is not incremented at the end of this */
+#undef c2l_p
+#define c2l_p(c,l,n)   { \
+                       l=0; \
+                       (c)+=n; \
+                       switch (n) { \
+                       case 3: l =((unsigned long)(*(--(c))))<<16; \
+                       case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+                       case 1: l|=((unsigned long)(*(--(c))))    ; \
+                               } \
+                       }
+
+#undef p_c2l_p
+#define p_c2l_p(c,l,sc,len) { \
+                       switch (sc) \
+                               { \
+                       case 0: l =((unsigned long)(*((c)++))); \
+                               if (--len == 0) break; \
+                       case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+                               if (--len == 0) break; \
+                       case 2: l|=((unsigned long)(*((c)++)))<<16; \
+                               } \
+                       }
+
+#undef l2c
+#define l2c(l,c)       (*((c)++)=(unsigned char)(((l)    )&0xff), \
+                        *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+                        *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+                        *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#undef l2cn
+#define l2cn(l1,l2,c,n)        { \
+                       c+=n; \
+                       switch (n) { \
+                       case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+                       case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+                       case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+                       case 5: *(--(c))=(unsigned char)(((l2)    )&0xff); \
+                       case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+                       case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+                       case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+                       case 1: *(--(c))=(unsigned char)(((l1)    )&0xff); \
+                               } \
+                       }
+
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#if defined(WIN32)
+/* 5 instructions with rotate instruction, else 9 */
+#define Endian_Reverse32(a) \
+       { \
+       unsigned long l=(a); \
+       (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \
+       }
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define Endian_Reverse32(a) \
+       { \
+       unsigned long l=(a); \
+       l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \
+       (a)=ROTATE(l,16L); \
+       }
+#endif
+/*
+#define        F(x,y,z)        (((x) & (y))  |  ((~(x)) & (z)))
+#define        G(x,y,z)        (((x) & (z))  |  ((y) & (~(z))))
+*/
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
+ * simplified to the code below.  Wei attributes these optimisations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ */
+#define        F(x,y,z)        ((((y) ^ (z)) & (x)) ^ (z))
+#define        G(x,y,z)        ((((x) ^ (y)) & (z)) ^ (y))
+#define        H(x,y,z)        ((x) ^ (y) ^ (z))
+#define        I(x,y,z)        (((x) | (~(z))) ^ (y))
+
+#undef ROTATE
+#if defined(WIN32)
+#define ROTATE(a,n)     _lrotl(a,n)
+#else
+#define ROTATE(a,n)     (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+
+#define R0(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+F((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };\
+
+#define R1(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+G((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };
+
+#define R2(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+H((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };
+
+#define R3(a,b,c,d,k,s,t) { \
+       a+=((k)+(t)+I((b),(c),(d))); \
+       a=ROTATE(a,s); \
+       a+=b; };
diff --git a/minires/ns_date.c b/minires/ns_date.c
new file mode 100644 (file)
index 0000000..abd243d
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_date.c,v 1.1 2000/02/02 07:28:14 mellon Exp $";
+#endif
+
+/* Import. */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+/* Forward. */
+
+static int     datepart(const char *, int, int, int, int *);
+
+/* Public. */
+
+/* Convert a date in ASCII into the number of seconds since
+   1 January 1970 (GMT assumed).  Format is yyyymmddhhmmss, all
+   digits required, no spaces allowed.  */
+
+u_int32_t
+ns_datetosecs(const char *cp, int *errp) {
+       struct tm time;
+       u_int32_t result;
+       int mdays, i;
+       static const int days_per_month[12] =
+               {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+       if (strlen(cp) != 14) {
+               *errp = 1;
+               return (0);
+       }
+       *errp = 0;
+
+       memset(&time, 0, sizeof time);
+       time.tm_year  = datepart(cp +  0, 4, 1990, 9999, errp) - 1900;
+       time.tm_mon   = datepart(cp +  4, 2,   01,   12, errp) - 1;
+       time.tm_mday  = datepart(cp +  6, 2,   01,   31, errp);
+       time.tm_hour  = datepart(cp +  8, 2,   00,   23, errp);
+       time.tm_min   = datepart(cp + 10, 2,   00,   59, errp);
+       time.tm_sec   = datepart(cp + 12, 2,   00,   59, errp);
+       if (*errp)              /* Any parse errors? */
+               return (0);
+
+       /* 
+        * OK, now because timegm() is not available in all environments,
+        * we will do it by hand.  Roll up sleeves, curse the gods, begin!
+        */
+
+#define SECS_PER_DAY    ((u_int32_t)24*60*60)
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+       result  = time.tm_sec;                          /* Seconds */
+       result += time.tm_min * 60;                     /* Minutes */
+       result += time.tm_hour * (60*60);               /* Hours */
+       result += (time.tm_mday - 1) * SECS_PER_DAY;    /* Days */
+
+       /* Months are trickier.  Look without leaping, then leap */
+       mdays = 0;
+       for (i = 0; i < time.tm_mon; i++)
+               mdays += days_per_month[i];
+       result += mdays * SECS_PER_DAY;                 /* Months */
+       if (time.tm_mon > 1 && isleap(1900+time.tm_year))
+               result += SECS_PER_DAY;         /* Add leapday for this year */
+
+       /* First figure years without leapdays, then add them in.  */
+       /* The loop is slow, FIXME, but simple and accurate.  */
+       result += (time.tm_year - 70) * (SECS_PER_DAY*365); /* Years */
+       for (i = 70; i < time.tm_year; i++)
+               if (isleap(1900+i))
+                       result += SECS_PER_DAY; /* Add leapday for prev year */
+
+       return (result);
+}
+
+/* Private. */
+
+/*
+ * Parse part of a date.  Set error flag if any error.
+ * Don't reset the flag if there is no error.
+ */
+static int
+datepart(const char *buf, int size, int min, int max, int *errp) {
+       int result = 0;
+       int i;
+
+       for (i = 0; i < size; i++) {
+               if (!isdigit(buf[i]))
+                       *errp = 1;
+               result = (result * 10) + buf[i] - '0';
+       }
+       if (result < min)
+               *errp = 1;
+       if (result > max)
+               *errp = 1;
+       return (result);
+}
diff --git a/minires/ns_name.c b/minires/ns_name.c
new file mode 100644 (file)
index 0000000..e815d24
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_name.c,v 1.1 2000/02/02 07:28:14 mellon Exp $";
+#endif
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+/* Data. */
+
+static const char      digits[] = "0123456789";
+
+/* Forward. */
+
+static int             special(int);
+static int             printable(int);
+static int             dn_find(const u_char *, const u_char *,
+                               const u_char * const *,
+                               const u_char * const *);
+
+/* Public. */
+
+/*
+ * ns_name_ntop(src, dst, dstsiz)
+ *     Convert an encoded domain name to printable ascii as per RFC1035.
+ * return:
+ *     Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ *     The root is returned as "."
+ *     All other domains are returned in non absolute form
+ */
+int
+ns_name_ntop(const u_char *src, char *dst, size_t dstsiz) {
+       const u_char *cp;
+       char *dn, *eom;
+       u_char c;
+       u_int n;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) != 0) {
+                       /* Some kind of compression pointer. */
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               if (dn != dst) {
+                       if (dn >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       *dn++ = '.';
+               }
+               if (dn + n >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               for ((void)NULL; n > 0; n--) {
+                       c = *cp++;
+                       if (special(c)) {
+                               if (dn + 1 >= eom) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               *dn++ = '\\';
+                               *dn++ = (char)c;
+                       } else if (!printable(c)) {
+                               if (dn + 3 >= eom) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               *dn++ = '\\';
+                               *dn++ = digits[c / 100];
+                               *dn++ = digits[(c % 100) / 10];
+                               *dn++ = digits[c % 10];
+                       } else {
+                               if (dn >= eom) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               *dn++ = (char)c;
+                       }
+               }
+       }
+       if (dn == dst) {
+               if (dn >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               *dn++ = '.';
+       }
+       if (dn >= eom) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       *dn++ = '\0';
+       return (dn - dst);
+}
+
+/*
+ * ns_name_pton(src, dst, dstsiz)
+ *     Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ *     -1 if it fails
+ *     1 if string was fully qualified
+ *     0 is string was not fully qualified
+ * notes:
+ *     Enforces label and domain length limits.
+ */
+
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
+       u_char *label, *bp, *eom;
+       int c, n, escaped;
+       char *cp;
+
+       escaped = 0;
+       bp = dst;
+       eom = dst + dstsiz;
+       label = bp++;
+
+       while ((c = *src++) != 0) {
+               if (escaped) {
+                       if ((cp = strchr(digits, c)) != NULL) {
+                               n = (cp - digits) * 100;
+                               if ((c = *src++) == 0 ||
+                                   (cp = strchr(digits, c)) == NULL) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               n += (cp - digits) * 10;
+                               if ((c = *src++) == 0 ||
+                                   (cp = strchr(digits, c)) == NULL) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               n += (cp - digits);
+                               if (n > 255) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               c = n;
+                       }
+                       escaped = 0;
+               } else if (c == '\\') {
+                       escaped = 1;
+                       continue;
+               } else if (c == '.') {
+                       c = (bp - label - 1);
+                       if ((c & NS_CMPRSFLGS) != 0) {  /* Label too big. */
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       if (label >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       *label = c;
+                       /* Fully qualified ? */
+                       if (*src == '\0') {
+                               if (c != 0) {
+                                       if (bp >= eom) {
+                                               errno = EMSGSIZE;
+                                               return (-1);
+                                       }
+                                       *bp++ = '\0';
+                               }
+                               if ((bp - dst) > MAXCDNAME) {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                               return (1);
+                       }
+                       if (c == 0 || *src == '.') {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       label = bp++;
+                       continue;
+               }
+               if (bp >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               *bp++ = (u_char)c;
+       }
+       c = (bp - label - 1);
+       if ((c & NS_CMPRSFLGS) != 0) {          /* Label too big. */
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       if (label >= eom) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       *label = c;
+       if (c != 0) {
+               if (bp >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               *bp++ = 0;
+       }
+       if ((bp - dst) > MAXCDNAME) {   /* src too big */
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       return (0);
+}
+
+/*
+ * ns_name_ntol(src, dst, dstsiz)
+ *     Convert a network strings labels into all lowercase.
+ * return:
+ *     Number of bytes written to buffer, or -1 (with errno set)
+ * notes:
+ *     Enforces label and domain length limits.
+ */
+
+int
+ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz) {
+       const u_char *cp;
+       u_char *dn, *eom;
+       u_char c;
+       u_int n;
+
+       cp = src;
+       dn = dst;
+       eom = dst + dstsiz;
+
+       while ((n = *cp++) != 0) {
+               if ((n & NS_CMPRSFLGS) != 0) {
+                       /* Some kind of compression pointer. */
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               *dn++ = n;
+               if (dn + n >= eom) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               for ((void)NULL; n > 0; n--) {
+                       c = *cp++;
+                       if (isupper(c))
+                               *dn++ = tolower(c);
+                       else
+                               *dn++ = c;
+               }
+       }
+       *dn++ = '\0';
+       return (dn - dst);
+}
+
+/*
+ * ns_name_unpack(msg, eom, src, dst, dstsiz)
+ *     Unpack a domain name from a message, source may be compressed.
+ * return:
+ *     -1 if it fails, or consumed octets if it succeeds.
+ */
+int
+ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
+              u_char *dst, size_t dstsiz)
+{
+       const u_char *srcp, *dstlim;
+       u_char *dstp;
+       unsigned n;
+       int len;
+       int checked;
+
+       len = -1;
+       checked = 0;
+       dstp = dst;
+       srcp = src;
+       dstlim = dst + dstsiz;
+       if (srcp < msg || srcp >= eom) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       /* Fetch next label in domain name. */
+       while ((n = *srcp++) != 0) {
+               /* Check for indirection. */
+               switch (n & NS_CMPRSFLGS) {
+               case 0:
+                       /* Limit checks. */
+                       if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       checked += n + 1;
+                       *dstp++ = n;
+                       memcpy(dstp, srcp, n);
+                       dstp += n;
+                       srcp += n;
+                       break;
+
+               case NS_CMPRSFLGS:
+                       if (srcp >= eom) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       if (len < 0)
+                               len = srcp - src + 1;
+                       srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
+                       if (srcp < msg || srcp >= eom) {  /* Out of range. */
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       checked += 2;
+                       /*
+                        * Check for loops in the compressed name;
+                        * if we've looked at the whole message,
+                        * there must be a loop.
+                        */
+                       if (checked >= eom - msg) {
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       break;
+
+               default:
+                       errno = EMSGSIZE;
+                       return (-1);                    /* flag error */
+               }
+       }
+       *dstp = '\0';
+       if (len < 0)
+               len = srcp - src;
+       return (len);
+}
+
+/*
+ * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr)
+ *     Pack domain name 'domain' into 'comp_dn'.
+ * return:
+ *     Size of the compressed name, or -1.
+ * notes:
+ *     'dnptrs' is an array of pointers to previous compressed names.
+ *     dnptrs[0] is a pointer to the beginning of the message. The array
+ *     ends with NULL.
+ *     'lastdnptr' is a pointer to the end of the array pointed to
+ *     by 'dnptrs'.
+ * Side effects:
+ *     The list of pointers in dnptrs is updated for labels inserted into
+ *     the message as we compress the name.  If 'dnptr' is NULL, we don't
+ *     try to compress names. If 'lastdnptr' is NULL, we don't update the
+ *     list.
+ */
+int
+ns_name_pack(const u_char *src, u_char *dst, unsigned dstsiz,
+            const u_char **dnptrs, const u_char **lastdnptr)
+{
+       u_char *dstp;
+       const u_char **cpp, **lpp, *eob, *msg;
+       const u_char *srcp;
+       unsigned n;
+       int l;
+
+       srcp = src;
+       dstp = dst;
+       eob = dstp + dstsiz;
+       lpp = cpp = NULL;
+       if (dnptrs != NULL) {
+               if ((msg = *dnptrs++) != NULL) {
+                       for (cpp = dnptrs; *cpp != NULL; cpp++)
+                               (void)NULL;
+                       lpp = cpp;      /* end of list to search */
+               }
+       } else
+               msg = NULL;
+
+       /* make sure the domain we are about to add is legal */
+       l = 0;
+       do {
+               n = *srcp;
+               if ((n & NS_CMPRSFLGS) != 0) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               l += n + 1;
+               if (l > MAXCDNAME) {
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               srcp += n + 1;
+       } while (n != 0);
+
+       /* from here on we need to reset compression pointer array on error */
+       srcp = src;
+       do {
+               /* Look to see if we can use pointers. */
+               n = *srcp;
+               if (n != 0 && msg != NULL) {
+                       l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
+                                   (const u_char * const *)lpp);
+                       if (l >= 0) {
+                               if (dstp + 1 >= eob) {
+                                       goto cleanup;
+                               }
+                               *dstp++ = (l >> 8) | NS_CMPRSFLGS;
+                               *dstp++ = l % 256;
+                               return (dstp - dst);
+                       }
+                       /* Not found, save it. */
+                       if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
+                           (dstp - msg) < 0x4000) {
+                               *cpp++ = dstp;
+                               *cpp = NULL;
+                       }
+               }
+               /* copy label to buffer */
+               if (n & NS_CMPRSFLGS) {         /* Should not happen. */
+                       goto cleanup;
+               }
+               if (dstp + 1 + n >= eob) {
+                       goto cleanup;
+               }
+               memcpy(dstp, srcp, n + 1);
+               srcp += n + 1;
+               dstp += n + 1;
+       } while (n != 0);
+
+       if (dstp > eob) {
+cleanup:
+               if (msg != NULL)
+                       *lpp = NULL;
+               errno = EMSGSIZE;
+               return (-1);
+       } 
+       return (dstp - dst);
+}
+
+/*
+ * ns_name_uncompress(msg, eom, src, dst, dstsiz)
+ *     Expand compressed domain name to presentation format.
+ * return:
+ *     Number of bytes read out of `src', or -1 (with errno set).
+ * note:
+ *     Root domain returns as "." not "".
+ */
+int
+ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
+                  char *dst, size_t dstsiz)
+{
+       u_char tmp[NS_MAXCDNAME];
+       int n;
+       
+       if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
+               return (-1);
+       if (ns_name_ntop(tmp, dst, dstsiz) == -1)
+               return (-1);
+       return (n);
+}
+
+/*
+ * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr)
+ *     Compress a domain name into wire format, using compression pointers.
+ * return:
+ *     Number of bytes consumed in `dst' or -1 (with errno set).
+ * notes:
+ *     'dnptrs' is an array of pointers to previous compressed names.
+ *     dnptrs[0] is a pointer to the beginning of the message.
+ *     The list ends with NULL.  'lastdnptr' is a pointer to the end of the
+ *     array pointed to by 'dnptrs'. Side effect is to update the list of
+ *     pointers for labels inserted into the message as we compress the name.
+ *     If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ *     is NULL, we don't update the list.
+ */
+int
+ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
+                const u_char **dnptrs, const u_char **lastdnptr)
+{
+       u_char tmp[NS_MAXCDNAME];
+
+       if (ns_name_pton(src, tmp, sizeof tmp) == -1)
+               return (-1);
+       return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
+}
+
+/*
+ * ns_name_skip(ptrptr, eom)
+ *     Advance *ptrptr to skip over the compressed name it points at.
+ * return:
+ *     0 on success, -1 (with errno set) on failure.
+ */
+int
+ns_name_skip(const u_char **ptrptr, const u_char *eom) {
+       const u_char *cp;
+       u_int n;
+
+       cp = *ptrptr;
+       while (cp < eom && (n = *cp++) != 0) {
+               /* Check for indirection. */
+               switch (n & NS_CMPRSFLGS) {
+               case 0:                 /* normal case, n == len */
+                       cp += n;
+                       continue;
+               case NS_CMPRSFLGS:      /* indirection */
+                       cp++;
+                       break;
+               default:                /* illegal type */
+                       errno = EMSGSIZE;
+                       return (-1);
+               }
+               break;
+       }
+       if (cp > eom) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       *ptrptr = cp;
+       return (0);
+}
+
+/* Private. */
+
+/*
+ * special(ch)
+ *     Thinking in noninternationalized USASCII (per the DNS spec),
+ *     is this characted special ("in need of quoting") ?
+ * return:
+ *     boolean.
+ */
+static int
+special(int ch) {
+       switch (ch) {
+       case 0x22: /* '"' */
+       case 0x2E: /* '.' */
+       case 0x3B: /* ';' */
+       case 0x5C: /* '\\' */
+       /* Special modifiers in zone files. */
+       case 0x40: /* '@' */
+       case 0x24: /* '$' */
+               return (1);
+       default:
+               return (0);
+       }
+}
+
+/*
+ * printable(ch)
+ *     Thinking in noninternationalized USASCII (per the DNS spec),
+ *     is this character visible and not a space when printed ?
+ * return:
+ *     boolean.
+ */
+static int
+printable(int ch) {
+       return (ch > 0x20 && ch < 0x7f);
+}
+
+/*
+ *     Thinking in noninternationalized USASCII (per the DNS spec),
+ *     convert this character to lower case if it's upper case.
+ */
+static int
+mklower(int ch) {
+       if (ch >= 0x41 && ch <= 0x5A)
+               return (ch + 0x20);
+       return (ch);
+}
+
+/*
+ * dn_find(domain, msg, dnptrs, lastdnptr)
+ *     Search for the counted-label name in an array of compressed names.
+ * return:
+ *     offset from msg if found, or -1.
+ * notes:
+ *     dnptrs is the pointer to the first name on the list,
+ *     not the pointer to the start of the message.
+ */
+static int
+dn_find(const u_char *domain, const u_char *msg,
+       const u_char * const *dnptrs,
+       const u_char * const *lastdnptr)
+{
+       const u_char *dn, *cp, *sp;
+       const u_char * const *cpp;
+       u_int n;
+
+       for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+               dn = domain;
+               sp = cp = *cpp;
+               while ((n = *cp++) != 0) {
+                       /*
+                        * check for indirection
+                        */
+                       switch (n & NS_CMPRSFLGS) {
+                       case 0:                 /* normal case, n == len */
+                               if (n != *dn++)
+                                       goto next;
+                               for ((void)NULL; n > 0; n--)
+                                       if (mklower(*dn++) != mklower(*cp++))
+                                               goto next;
+                               /* Is next root for both ? */
+                               if (*dn == '\0' && *cp == '\0')
+                                       return (sp - msg);
+                               if (*dn)
+                                       continue;
+                               goto next;
+
+                       case NS_CMPRSFLGS:      /* indirection */
+                               cp = msg + (((n & 0x3f) << 8) | *cp);
+                               break;
+
+                       default:        /* illegal type */
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+               }
+ next: ;
+       }
+       errno = ENOENT;
+       return (-1);
+}
diff --git a/minires/ns_parse.c b/minires/ns_parse.c
new file mode 100644 (file)
index 0000000..2eb9899
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_parse.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif
+
+/* Import. */
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+/* Forward. */
+
+static void    setsection(ns_msg *msg, ns_sect sect);
+
+/* Macros. */
+
+#define RETERR(err) do { errno = (err); return (-1); } while (0)
+
+/* Public. */
+
+/* These need to be in the same order as the nres.h:ns_flag enum. */
+struct _ns_flagdata _ns_flagdata[16] = {
+       { 0x8000, 15 },         /* qr. */
+       { 0x7800, 11 },         /* opcode. */
+       { 0x0400, 10 },         /* aa. */
+       { 0x0200, 9 },          /* tc. */
+       { 0x0100, 8 },          /* rd. */
+       { 0x0080, 7 },          /* ra. */
+       { 0x0040, 6 },          /* z. */
+       { 0x0020, 5 },          /* ad. */
+       { 0x0010, 4 },          /* cd. */
+       { 0x000f, 0 },          /* rcode. */
+       { 0x0000, 0 },          /* expansion (1/6). */
+       { 0x0000, 0 },          /* expansion (2/6). */
+       { 0x0000, 0 },          /* expansion (3/6). */
+       { 0x0000, 0 },          /* expansion (4/6). */
+       { 0x0000, 0 },          /* expansion (5/6). */
+       { 0x0000, 0 },          /* expansion (6/6). */
+};
+
+int
+ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
+       const u_char *optr = ptr;
+
+       for ((void)NULL; count > 0; count--) {
+               int b, rdlength;
+
+               b = dn_skipname(ptr, eom);
+               if (b < 0)
+                       RETERR(EMSGSIZE);
+               ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
+               if (section != ns_s_qd) {
+                       if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
+                               RETERR(EMSGSIZE);
+                       ptr += NS_INT32SZ/*TTL*/;
+                       rdlength = getUShort(ptr);
+                       ptr += 2;
+                       ptr += rdlength/*RData*/;
+               }
+       }
+       if (ptr > eom)
+               RETERR(EMSGSIZE);
+       return (ptr - optr);
+}
+
+int
+ns_initparse(const u_char *msg, unsigned msglen, ns_msg *handle) {
+       const u_char *eom = msg + msglen;
+       int i;
+
+       memset(handle, 0x5e, sizeof *handle);
+       handle->_msg = msg;
+       handle->_eom = eom;
+       if (msg + NS_INT16SZ > eom)
+               RETERR(EMSGSIZE);
+       handle->_id = getUShort (msg);
+       msg += 2;
+       if (msg + NS_INT16SZ > eom)
+               RETERR(EMSGSIZE);
+       handle->_flags = getUShort (msg);
+       msg += 2;
+       for (i = 0; i < ns_s_max; i++) {
+               if (msg + NS_INT16SZ > eom)
+                       RETERR(EMSGSIZE);
+               handle->_counts[i] = getUShort (msg);
+               msg += 2;
+       }
+       for (i = 0; i < ns_s_max; i++)
+               if (handle->_counts[i] == 0)
+                       handle->_sections[i] = NULL;
+               else {
+                       int b = ns_skiprr(msg, eom, (ns_sect)i,
+                                         handle->_counts[i]);
+
+                       if (b < 0)
+                               return (-1);
+                       handle->_sections[i] = msg;
+                       msg += b;
+               }
+       if (msg != eom)
+               RETERR(EMSGSIZE);
+       setsection(handle, ns_s_max);
+       return (0);
+}
+
+int
+ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
+       int b;
+
+       /* Make section right. */
+       if (section < 0 || section >= ns_s_max)
+               RETERR(ENODEV);
+       if (section != handle->_sect)
+               setsection(handle, section);
+
+       /* Make rrnum right. */
+       if (rrnum == -1)
+               rrnum = handle->_rrnum;
+       if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+               RETERR(ENODEV);
+       if (rrnum < handle->_rrnum)
+               setsection(handle, section);
+       if (rrnum > handle->_rrnum) {
+               b = ns_skiprr(handle->_ptr, handle->_eom, section,
+                             rrnum - handle->_rrnum);
+
+               if (b < 0)
+                       return (-1);
+               handle->_ptr += b;
+               handle->_rrnum = rrnum;
+       }
+
+       /* Do the parse. */
+       b = dn_expand(handle->_msg, handle->_eom,
+                     handle->_ptr, rr->name, NS_MAXDNAME);
+       if (b < 0)
+               return (-1);
+       handle->_ptr += b;
+       if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+               RETERR(EMSGSIZE);
+       rr->type = getUShort (handle->_ptr);
+       handle -> _ptr += 2;
+       rr->rr_class = getUShort (handle->_ptr);
+       handle -> _ptr += 2;
+       if (section == ns_s_qd) {
+               rr->ttl = 0;
+               rr->rdlength = 0;
+               rr->rdata = NULL;
+       } else {
+               if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+                       RETERR(EMSGSIZE);
+               rr->ttl = getULong (handle->_ptr);
+               handle -> _ptr += 4;
+               rr->rdlength = getUShort (handle->_ptr);
+               handle -> _ptr += 2;
+               if (handle->_ptr + rr->rdlength > handle->_eom)
+                       RETERR(EMSGSIZE);
+               rr->rdata = handle->_ptr;
+               handle->_ptr += rr->rdlength;
+       }
+       if (++handle->_rrnum > handle->_counts[(int)section])
+               setsection(handle, (ns_sect)((int)section + 1));
+
+       /* All done. */
+       return (0);
+}
+
+/* Private. */
+
+static void
+setsection(ns_msg *msg, ns_sect sect) {
+       msg->_sect = sect;
+       if (sect == ns_s_max) {
+               msg->_rrnum = -1;
+               msg->_ptr = NULL;
+       } else {
+               msg->_rrnum = 0;
+               msg->_ptr = msg->_sections[(int)sect];
+       }
+}
diff --git a/minires/ns_samedomain.c b/minires/ns_samedomain.c
new file mode 100644 (file)
index 0000000..54f2abd
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1995,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_samedomain.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif
+
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+/*
+ * int
+ * ns_samedomain(a, b)
+ *     Check whether a name belongs to a domain.
+ * Inputs:
+ *     a - the domain whose ancestory is being verified
+ *     b - the potential ancestor we're checking against
+ * Return:
+ *     boolean - is a at or below b?
+ * Notes:
+ *     Trailing dots are first removed from name and domain.
+ *     Always compare complete subdomains, not only whether the
+ *     domain name is the trailing string of the given name.
+ *
+ *     "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+ *     but NOT in "bar.top"
+ */
+
+int
+ns_samedomain(const char *a, const char *b) {
+       size_t la, lb;
+       int diff, i, escaped;
+       const char *cp;
+
+       la = strlen(a);
+       lb = strlen(b);
+
+       /* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
+       if (la != 0 && a[la - 1] == '.') {
+               escaped = 0;
+               /* Note this loop doesn't get executed if la==1. */
+               for (i = la - 2; i >= 0; i--)
+                       if (a[i] == '\\') {
+                               if (escaped)
+                                       escaped = 0;
+                               else
+                                       escaped = 1;
+                       } else
+                               break;
+               if (!escaped)
+                       la--;
+       }
+
+       /* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
+       if (lb != 0 && b[lb - 1] == '.') {
+               escaped = 0;
+               /* note this loop doesn't get executed if lb==1 */
+               for (i = lb - 2; i >= 0; i--)
+                       if (b[i] == '\\') {
+                               if (escaped)
+                                       escaped = 0;
+                               else
+                                       escaped = 1;
+                       } else
+                               break;
+               if (!escaped)
+                       lb--;
+       }
+
+       /* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
+       if (lb == 0)
+               return (1);
+
+       /* 'b' longer than 'a' means 'a' can't be in 'b'. */
+       if (lb > la)
+               return (0);
+
+       /* 'a' and 'b' being equal at this point indicates sameness. */
+       if (lb == la)
+               return (strncasecmp(a, b, lb) == 0);
+
+       /* Ok, we know la > lb. */
+
+       diff = la - lb;
+
+       /*
+        * If 'a' is only 1 character longer than 'b', then it can't be
+        * a subdomain of 'b' (because of the need for the '.' label
+        * separator).
+        */
+       if (diff < 2)
+               return (0);
+
+       /*
+        * If the character before the last 'lb' characters of 'b'
+        * isn't '.', then it can't be a match (this lets us avoid
+        * having "foobar.com" match "bar.com").
+        */
+       if (a[diff - 1] != '.')
+               return (0);
+
+       /*
+        * We're not sure about that '.', however.  It could be escaped
+         * and thus not a really a label separator.
+        */
+       escaped = 0;
+       for (i = diff - 2; i >= 0; i--)
+               if (a[i] == '\\')
+                       if (escaped)
+                               escaped = 0;
+                       else
+                               escaped = 1;
+               else
+                       break;
+       if (escaped)
+               return (0);
+         
+       /* Now compare aligned trailing substring. */
+       cp = a + diff;
+       return (strncasecmp(cp, b, lb) == 0);
+}
+
+/*
+ * int
+ * ns_subdomain(a, b)
+ *     is "a" a subdomain of "b"?
+ */
+int
+ns_subdomain(const char *a, const char *b) {
+       return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
+}
+
+/*
+ * int
+ * ns_makecanon(src, dst, dstsize)
+ *     make a canonical copy of domain name "src"
+ * notes:
+ *     foo -> foo.
+ *     foo. -> foo.
+ *     foo.. -> foo.
+ *     foo\. -> foo\..
+ *     foo\\. -> foo\\.
+ */
+
+int
+ns_makecanon(const char *src, char *dst, size_t dstsize) {
+       size_t n = strlen(src);
+
+       if (n + sizeof "." > dstsize) {
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       strcpy(dst, src);
+       while (n > 0 && dst[n - 1] == '.')              /* Ends in "." */
+               if (n > 1 && dst[n - 2] == '\\' &&      /* Ends in "\." */
+                   (n < 2 || dst[n - 3] != '\\'))      /* But not "\\." */
+                       break;
+               else
+                       dst[--n] = '\0';
+       dst[n++] = '.';
+       dst[n] = '\0';
+       return (0);
+}
+
+/*
+ * int
+ * ns_samename(a, b)
+ *     determine whether domain name "a" is the same as domain name "b"
+ * return:
+ *     -1 on error
+ *     0 if names differ
+ *     1 if names are the same
+ */
+
+int
+ns_samename(const char *a, const char *b) {
+       char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
+
+       if (ns_makecanon(a, ta, sizeof ta) < 0 ||
+           ns_makecanon(b, tb, sizeof tb) < 0)
+               return (-1);
+       if (strcasecmp(ta, tb) == 0)
+               return (1);
+       else
+               return (0);
+}
diff --git a/minires/ns_sign.c b/minires/ns_sign.c
new file mode 100644 (file)
index 0000000..54ffffa
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_sign.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif
+
+/* Import. */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <isc/dst.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+#define BOUNDS_CHECK(ptr, count) \
+       do { \
+               if ((ptr) + (count) > eob) { \
+                       errno = EMSGSIZE; \
+                       return(NS_TSIG_ERROR_NO_SPACE); \
+               } \
+       } while (0)
+
+/* ns_sign
+ * Parameters:
+ *     msg             message to be sent
+ *     msglen          input - length of message
+ *                     output - length of signed message
+ *     msgsize         length of buffer containing message
+ *     error           value to put in the error field
+ *     key             tsig key used for signing
+ *     querysig        (response), the signature in the query
+ *     querysiglen     (response), the length of the signature in the query
+ *     sig             a buffer to hold the generated signature
+ *     siglen          input - length of signature buffer
+ *                     output - length of signature
+ *
+ * Errors:
+ *     - bad input data (-1)
+ *     - bad key / sign failed (-BADKEY)
+ *     - not enough space (NS_TSIG_ERROR_NO_SPACE)
+ */
+int
+ns_sign(u_char *msg, unsigned *msglen, unsigned msgsize, int error, void *k,
+       const u_char *querysig, unsigned querysiglen, u_char *sig,
+       unsigned *siglen, time_t in_timesigned)
+{
+       HEADER *hp = (HEADER *)msg;
+       DST_KEY *key = (DST_KEY *)k;
+       u_char *cp = msg + *msglen, *eob = msg + msgsize;
+       u_char *lenp;
+       u_char *name, *alg;
+       unsigned n;
+       time_t timesigned;
+
+       dst_init();
+       if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
+               return (-1);
+
+       /* Name. */
+       if (key != NULL && error != ns_r_badsig && error != ns_r_badkey)
+               n = dn_comp(key->dk_key_name,
+                           cp, (unsigned)(eob - cp), NULL, NULL);
+       else
+               n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       name = cp;
+       cp += n;
+
+       /* Type, class, ttl, length (not filled in yet). */
+       BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
+       PUTSHORT(ns_t_tsig, cp);
+       PUTSHORT(ns_c_any, cp);
+       PUTLONG(0, cp);         /* TTL */
+       lenp = cp;
+       cp += 2;
+
+       /* Alg. */
+       if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+               if (key->dk_alg != KEY_HMAC_MD5)
+                       return (-ns_r_badkey);
+               n = dn_comp(NS_TSIG_ALG_HMAC_MD5,
+                           cp, (unsigned)(eob - cp), NULL, NULL);
+       }
+       else
+               n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       alg = cp;
+       cp += n;
+       
+       /* Time. */
+       BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+       PUTSHORT(0, cp);
+       timesigned = time(NULL);
+       if (error != ns_r_badtime)
+               PUTLONG(timesigned, cp);
+       else
+               PUTLONG(in_timesigned, cp);
+       PUTSHORT(NS_TSIG_FUDGE, cp);
+
+       /* Compute the signature. */
+       if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+               void *ctx;
+               u_char buf[MAXDNAME], *cp2;
+               unsigned n;
+
+               dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+
+               /* Digest the query signature, if this is a response. */
+               if (querysiglen > 0 && querysig != NULL) {
+                       u_int16_t len_n = htons(querysiglen);
+                       dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+                                     (u_char *)&len_n, INT16SZ, NULL, 0);
+                       dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+                                     querysig, querysiglen, NULL, 0);
+               }
+
+               /* Digest the message. */
+               dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
+                             NULL, 0);
+
+               /* Digest the key name. */
+               n = ns_name_ntol(name, buf, sizeof(buf));
+               dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+               /* Digest the class and TTL. */
+               cp2 = buf;
+               PUTSHORT(ns_c_any, cp2);
+               PUTLONG(0, cp2);
+               dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+                             buf, (unsigned)(cp2-buf), NULL, 0);
+
+               /* Digest the algorithm. */
+               n = ns_name_ntol(alg, buf, sizeof(buf));
+               dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+               /* Digest the time signed, fudge, error, and other data */
+               cp2 = buf;
+               PUTSHORT(0, cp2);       /* Top 16 bits of time */
+               if (error != ns_r_badtime)
+                       PUTLONG(timesigned, cp2);
+               else
+                       PUTLONG(in_timesigned, cp2);
+               PUTSHORT(NS_TSIG_FUDGE, cp2);
+               PUTSHORT(error, cp2);   /* Error */
+               if (error != ns_r_badtime)
+                       PUTSHORT(0, cp2);       /* Other data length */
+               else {
+                       PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */
+                       PUTSHORT(0, cp2);       /* Top 16 bits of time */
+                       PUTLONG(timesigned, cp2);
+               }
+               dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
+                             buf, (unsigned)(cp2-buf), NULL, 0);
+
+               n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+                                 sig, *siglen);
+               if (n < 0)
+                       return (-ns_r_badkey);
+               *siglen = n;
+       } else
+               *siglen = 0;
+
+       /* Add the signature. */
+       BOUNDS_CHECK(cp, INT16SZ + (*siglen));
+       PUTSHORT(*siglen, cp);
+       memcpy(cp, sig, *siglen);
+       cp += (*siglen);
+
+       /* The original message ID & error. */
+       BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
+       PUTSHORT(ntohs(hp->id), cp);    /* already in network order */
+       PUTSHORT(error, cp);
+
+       /* Other data. */
+       BOUNDS_CHECK(cp, INT16SZ);
+       if (error != ns_r_badtime)
+               PUTSHORT(0, cp);        /* Other data length */
+       else {
+               PUTSHORT(INT16SZ+INT32SZ, cp);  /* Other data length */
+               BOUNDS_CHECK(cp, INT32SZ+INT16SZ);
+               PUTSHORT(0, cp);        /* Top 16 bits of time */
+               PUTLONG(timesigned, cp);
+       }
+
+       /* Go back and fill in the length. */
+       PUTSHORT(cp - lenp - INT16SZ, lenp);
+
+       hp->arcount = htons(ntohs(hp->arcount) + 1);
+       *msglen = (cp - msg);
+       return (0);
+}
+
+int
+ns_sign_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
+                ns_tcp_tsig_state *state)
+{
+       dst_init();
+       if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+               return (-1);
+       state->counter = -1;
+       state->key = k;
+       if (state->key->dk_alg != KEY_HMAC_MD5)
+               return (-ns_r_badkey);
+       if (querysiglen > sizeof(state->sig))
+               return (-1);
+       memcpy(state->sig, querysig, querysiglen);
+       state->siglen = querysiglen;
+       return (0);
+}
+
+int
+ns_sign_tcp(u_char *msg, unsigned *msglen, unsigned msgsize, int error,
+           ns_tcp_tsig_state *state, int done)
+{
+       u_char *cp, *eob, *lenp;
+       u_char buf[MAXDNAME], *cp2;
+       HEADER *hp = (HEADER *)msg;
+       time_t timesigned;
+       int n;
+
+       if (msg == NULL || msglen == NULL || state == NULL)
+               return (-1);
+
+       state->counter++;
+       if (state->counter == 0)
+               return (ns_sign(msg, msglen, msgsize, error, state->key,
+                               state->sig, state->siglen,
+                               state->sig, &state->siglen, 0));
+
+       if (state->siglen > 0) {
+               u_int16_t siglen_n = htons(state->siglen);
+               dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
+                             NULL, 0, NULL, 0);
+               dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                             (u_char *)&siglen_n, INT16SZ, NULL, 0);
+               dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                             state->sig, state->siglen, NULL, 0);
+               state->siglen = 0;
+       }
+
+       dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
+                     NULL, 0);
+
+       if (done == 0 && (state->counter % 100 != 0))
+               return (0);
+
+       cp = msg + *msglen;
+       eob = msg + msgsize;
+
+       /* Name. */
+       n = dn_comp(state->key->dk_key_name,
+                   cp, (unsigned)(eob - cp), NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       cp += n;
+
+       /* Type, class, ttl, length (not filled in yet). */
+       BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
+       PUTSHORT(ns_t_tsig, cp);
+       PUTSHORT(ns_c_any, cp);
+       PUTLONG(0, cp);         /* TTL */
+       lenp = cp;
+       cp += 2;
+
+       /* Alg. */
+       n = dn_comp(NS_TSIG_ALG_HMAC_MD5,
+                   cp, (unsigned)(eob - cp), NULL, NULL);
+       if (n < 0)
+               return (NS_TSIG_ERROR_NO_SPACE);
+       cp += n;
+       
+       /* Time. */
+       BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+       PUTSHORT(0, cp);
+       timesigned = time(NULL);
+       PUTLONG(timesigned, cp);
+       PUTSHORT(NS_TSIG_FUDGE, cp);
+
+       /*
+        * Compute the signature.
+        */
+
+       /* Digest the time signed and fudge. */
+       cp2 = buf;
+       PUTSHORT(0, cp2);       /* Top 16 bits of time */
+       PUTLONG(timesigned, cp2);
+       PUTSHORT(NS_TSIG_FUDGE, cp2);
+
+       dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                     buf, (unsigned)(cp2 - buf), NULL, 0);
+
+       n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+                         state->sig, sizeof(state->sig));
+       if (n < 0)
+               return (-ns_r_badkey);
+       state->siglen = n;
+
+       /* Add the signature. */
+       BOUNDS_CHECK(cp, INT16SZ + state->siglen);
+       PUTSHORT(state->siglen, cp);
+       memcpy(cp, state->sig, state->siglen);
+       cp += state->siglen;
+
+       /* The original message ID & error. */
+       BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
+       PUTSHORT(ntohs(hp->id), cp);    /* already in network order */
+       PUTSHORT(error, cp);
+
+       /* Other data. */
+       BOUNDS_CHECK(cp, INT16SZ);
+       PUTSHORT(0, cp);
+
+       /* Go back and fill in the length. */
+       PUTSHORT(cp - lenp - INT16SZ, lenp);
+
+       hp->arcount = htons(ntohs(hp->arcount) + 1);
+       *msglen = (cp - msg);
+       return (0);
+}
diff --git a/minires/ns_verify.c b/minires/ns_verify.c
new file mode 100644 (file)
index 0000000..9eaf225
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 1999 by Internet Software Consortium, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifndef lint
+static const char rcsid[] = "$Id: ns_verify.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif
+
+/* Import. */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <isc/dst.h>
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+/* Private. */
+
+#define BOUNDS_CHECK(ptr, count) \
+       do { \
+               if ((ptr) + (count) > eom) { \
+                       return (NS_TSIG_ERROR_FORMERR); \
+               } \
+       } while (0)
+
+/* Public. */
+
+u_char *
+ns_find_tsig(u_char *msg, u_char *eom) {
+       HEADER *hp = (HEADER *)msg;
+       int n, type;
+       u_char *cp = msg, *start;
+
+       if (msg == NULL || eom == NULL || msg > eom)
+               return (NULL);
+
+       if (cp + HFIXEDSZ >= eom)
+               return (NULL);
+
+       if (hp->arcount == 0)
+               return (NULL);
+
+       cp += HFIXEDSZ;
+
+       n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
+       if (n < 0)
+               return (NULL);
+       cp += n;
+
+       n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
+       if (n < 0)
+               return (NULL);
+       cp += n;
+
+       n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
+       if (n < 0)
+               return (NULL);
+       cp += n;
+
+       n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1);
+       if (n < 0)
+               return (NULL);
+       cp += n;
+
+       start = cp;
+       n = dn_skipname(cp, eom);
+       if (n < 0)
+               return (NULL);
+       cp += n;
+       if (cp + INT16SZ >= eom)
+               return (NULL);
+
+       GETSHORT(type, cp);
+       if (type != ns_t_tsig)
+               return (NULL);
+       return (start);
+}
+
+/* ns_verify
+ * Parameters:
+ *     statp           res stuff
+ *     msg             received message
+ *     msglen          length of message
+ *     key             tsig key used for verifying.
+ *     querysig        (response), the signature in the query
+ *     querysiglen     (response), the length of the signature in the query
+ *     sig             (query), a buffer to hold the signature
+ *     siglen          (query), input - length of signature buffer
+ *                              output - length of signature
+ *
+ * Errors:
+ *     - bad input (-1)
+ *     - invalid dns message (NS_TSIG_ERROR_FORMERR)
+ *     - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
+ *     - key doesn't match (-ns_r_badkey)
+ *     - TSIG verification fails with BADKEY (-ns_r_badkey)
+ *     - TSIG verification fails with BADSIG (-ns_r_badsig)
+ *     - TSIG verification fails with BADTIME (-ns_r_badtime)
+ *     - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
+ *     - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
+ *     - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
+ */
+int
+ns_verify(u_char *msg, unsigned *msglen, void *k,
+         const u_char *querysig, unsigned querysiglen,
+         u_char *sig, unsigned *siglen, time_t *timesigned, int nostrip)
+{
+       HEADER *hp = (HEADER *)msg;
+       DST_KEY *key = (DST_KEY *)k;
+       u_char *cp = msg, *eom;
+       char name[MAXDNAME], alg[MAXDNAME];
+       u_char *recstart, *rdatastart;
+       u_char *sigstart, *otherstart;
+       unsigned n;
+       int error;
+       u_int16_t type, length;
+       u_int16_t fudge, sigfieldlen, id, otherfieldlen;
+
+       dst_init();
+       if (msg == NULL || msglen == NULL || *msglen < 0)
+               return (-1);
+
+       eom = msg + *msglen;
+
+       recstart = ns_find_tsig(msg, eom);
+       if (recstart == NULL)
+               return (NS_TSIG_ERROR_NO_TSIG);
+
+       cp = recstart;
+
+       /* Read the key name. */
+       n = dn_expand(msg, eom, cp, name, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       cp += n;
+
+       /* Read the type. */
+       BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+       GETSHORT(type, cp);
+       if (type != ns_t_tsig)
+               return (NS_TSIG_ERROR_NO_TSIG);
+
+       /* Skip the class and TTL, save the length. */
+       cp += INT16SZ + INT32SZ;
+       GETSHORT(length, cp);
+       if (eom - cp != length)
+               return (NS_TSIG_ERROR_FORMERR);
+
+       /* Read the algorithm name. */
+       rdatastart = cp;
+       n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+               return (-ns_r_badkey);
+       cp += n;
+
+       /* Read the time signed and fudge. */
+       BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+       cp += INT16SZ;
+       GETLONG((*timesigned), cp);
+       GETSHORT(fudge, cp);
+
+       /* Read the signature. */
+       BOUNDS_CHECK(cp, INT16SZ);
+       GETSHORT(sigfieldlen, cp);
+       BOUNDS_CHECK(cp, sigfieldlen);
+       sigstart = cp;
+       cp += sigfieldlen;
+
+       /* Read the original id and error. */
+       BOUNDS_CHECK(cp, 2*INT16SZ);
+       GETSHORT(id, cp);
+       GETSHORT(error, cp);
+
+       /* Parse the other data. */
+       BOUNDS_CHECK(cp, INT16SZ);
+       GETSHORT(otherfieldlen, cp);
+       BOUNDS_CHECK(cp, otherfieldlen);
+       otherstart = cp;
+       cp += otherfieldlen;
+
+       if (cp != eom)
+               return (NS_TSIG_ERROR_FORMERR);
+
+       /* Verify that the key used is OK. */
+       if (key != NULL) {
+               if (key->dk_alg != KEY_HMAC_MD5)
+                       return (-ns_r_badkey);
+               if (error != ns_r_badsig && error != ns_r_badkey) {
+                       if (ns_samename(key->dk_key_name, name) != 1)
+                               return (-ns_r_badkey);
+               }
+       }
+
+       hp->arcount = htons(ntohs(hp->arcount) - 1);
+
+       /*
+        * Do the verification.
+        */
+
+       if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
+               void *ctx;
+               u_char buf[MAXDNAME];
+
+               /* Digest the query signature, if this is a response. */
+               dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
+               if (querysiglen > 0 && querysig != NULL) {
+                       u_int16_t len_n = htons(querysiglen);
+                       dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+                                       (u_char *)&len_n, INT16SZ, NULL, 0);
+                       dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+                                       querysig, querysiglen, NULL, 0);
+               }
+               
+               /* Digest the message. */
+               dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg,
+                               (unsigned)(recstart - msg), NULL, 0);
+
+               /* Digest the key name. */
+               n = ns_name_ntol(recstart, buf, sizeof(buf));
+               dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+               /* Digest the class and TTL. */
+               dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+                               recstart + dn_skipname(recstart, eom) + INT16SZ,
+                               INT16SZ + INT32SZ, NULL, 0);
+
+               /* Digest the algorithm. */
+               n = ns_name_ntol(rdatastart, buf, sizeof(buf));
+               dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
+
+               /* Digest the time signed and fudge. */
+               dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+                               rdatastart + dn_skipname(rdatastart, eom),
+                               INT16SZ + INT32SZ + INT16SZ, NULL, 0);
+
+               /* Digest the error and other data. */
+               dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
+                               otherstart - INT16SZ - INT16SZ,
+                               (unsigned)otherfieldlen + INT16SZ + INT16SZ,
+                               NULL, 0);
+
+               n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
+                                   sigstart, sigfieldlen);
+
+               if (n < 0)
+                       return (-ns_r_badsig);
+
+               if (sig != NULL && siglen != NULL) {
+                       if (*siglen < sigfieldlen)
+                               return (NS_TSIG_ERROR_NO_SPACE);
+                       memcpy(sig, sigstart, sigfieldlen);
+                       *siglen = sigfieldlen;
+               }
+       } else {
+               if (sigfieldlen > 0)
+                       return (NS_TSIG_ERROR_FORMERR);
+               if (sig != NULL && siglen != NULL)
+                       *siglen = 0;
+       }
+
+       /* Reset the counter, since we still need to check for badtime. */
+       hp->arcount = htons(ntohs(hp->arcount) + 1);
+
+       /* Verify the time. */
+       if (abs((*timesigned) - time(NULL)) > fudge)
+               return (-ns_r_badtime);
+
+       if (nostrip == 0) {
+               *msglen = recstart - msg;
+               hp->arcount = htons(ntohs(hp->arcount) - 1);
+       }
+
+       if (error != NOERROR)
+               return (error);
+
+       return (0);
+}
+
+int
+ns_verify_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
+                  ns_tcp_tsig_state *state)
+{
+       dst_init();
+       if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
+               return (-1);
+       state->counter = -1;
+       state->key = k;
+       if (state->key->dk_alg != KEY_HMAC_MD5)
+               return (-ns_r_badkey);
+       if (querysiglen > sizeof(state->sig))
+               return (-1);
+       memcpy(state->sig, querysig, querysiglen);
+       state->siglen = querysiglen;
+       return (0);
+}
+
+int
+ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state,
+             int required)
+{
+       HEADER *hp = (HEADER *)msg;
+       u_char *recstart, *rdatastart, *sigstart;
+       unsigned sigfieldlen, otherfieldlen;
+       u_char *cp, *eom = msg + *msglen, *cp2;
+       char name[MAXDNAME], alg[MAXDNAME];
+       u_char buf[MAXDNAME];
+       int n, type, length, fudge, id, error;
+       time_t timesigned;
+
+       if (msg == NULL || msglen == NULL || state == NULL)
+               return (-1);
+
+       state->counter++;
+       if (state->counter == 0)
+               return (ns_verify(msg, msglen, state->key,
+                                 state->sig, state->siglen,
+                                 state->sig, &state->siglen, &timesigned, 0));
+
+       if (state->siglen > 0) {
+               u_int16_t siglen_n = htons(state->siglen);
+
+               dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
+                               NULL, 0, NULL, 0);
+               dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                               (u_char *)&siglen_n, INT16SZ, NULL, 0);
+               dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                               state->sig, state->siglen, NULL, 0);
+               state->siglen = 0;
+       }
+
+       cp = recstart = ns_find_tsig(msg, eom);
+
+       if (recstart == NULL) {
+               if (required)
+                       return (NS_TSIG_ERROR_NO_TSIG);
+               dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                               msg, *msglen, NULL, 0);
+               return (0);
+       }
+
+       hp->arcount = htons(ntohs(hp->arcount) - 1);
+       dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                       msg, (unsigned)(recstart - msg), NULL, 0);
+       
+       /* Read the key name. */
+       n = dn_expand(msg, eom, cp, name, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       cp += n;
+
+       /* Read the type. */
+       BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
+       GETSHORT(type, cp);
+       if (type != ns_t_tsig)
+               return (NS_TSIG_ERROR_NO_TSIG);
+
+       /* Skip the class and TTL, save the length. */
+       cp += INT16SZ + INT32SZ;
+       GETSHORT(length, cp);
+       if (eom - cp != length)
+               return (NS_TSIG_ERROR_FORMERR);
+
+       /* Read the algorithm name. */
+       rdatastart = cp;
+       n = dn_expand(msg, eom, cp, alg, MAXDNAME);
+       if (n < 0)
+               return (NS_TSIG_ERROR_FORMERR);
+       if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+               return (-ns_r_badkey);
+       cp += n;
+
+       /* Verify that the key used is OK. */
+       if ((ns_samename(state->key->dk_key_name, name) != 1 ||
+            state->key->dk_alg != KEY_HMAC_MD5))
+               return (-ns_r_badkey);
+
+       /* Read the time signed and fudge. */
+       BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
+       cp += INT16SZ;
+       GETLONG(timesigned, cp);
+       GETSHORT(fudge, cp);
+
+       /* Read the signature. */
+       BOUNDS_CHECK(cp, INT16SZ);
+       GETSHORT(sigfieldlen, cp);
+       BOUNDS_CHECK(cp, sigfieldlen);
+       sigstart = cp;
+       cp += sigfieldlen;
+
+       /* Read the original id and error. */
+       BOUNDS_CHECK(cp, 2*INT16SZ);
+       GETSHORT(id, cp);
+       GETSHORT(error, cp);
+
+       /* Parse the other data. */
+       BOUNDS_CHECK(cp, INT16SZ);
+       GETSHORT(otherfieldlen, cp);
+       BOUNDS_CHECK(cp, otherfieldlen);
+       cp += otherfieldlen;
+
+       if (cp != eom)
+               return (NS_TSIG_ERROR_FORMERR);
+
+       /*
+        * Do the verification.
+        */
+
+       /* Digest the time signed and fudge. */
+       cp2 = buf;
+       PUTSHORT(0, cp2);       /* Top 16 bits of time. */
+       PUTLONG(timesigned, cp2);
+       PUTSHORT(NS_TSIG_FUDGE, cp2);
+
+       dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
+                       buf, (unsigned)(cp2 - buf), NULL, 0);
+
+       n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
+                           sigstart, sigfieldlen);
+       if (n < 0)
+               return (-ns_r_badsig);
+
+       if (sigfieldlen > sizeof(state->sig))
+               return (ns_r_badsig);
+
+       if (sigfieldlen > sizeof(state->sig))
+               return (NS_TSIG_ERROR_NO_SPACE);
+
+       memcpy(state->sig, sigstart, sigfieldlen);
+       state->siglen = sigfieldlen;
+
+       /* Verify the time. */
+       if (abs(timesigned - time(NULL)) > fudge)
+               return (-ns_r_badtime);
+
+       *msglen = recstart - msg;
+
+       if (error != NOERROR)
+               return (error);
+
+       return (0);
+}
diff --git a/minires/prandom.c b/minires/prandom.c
new file mode 100644 (file)
index 0000000..9421f9e
--- /dev/null
@@ -0,0 +1,863 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /tmp/cvstest/DHCP/minires/Attic/prandom.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <dirent.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "dst_internal.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include "arpa/nameser.h"
+#define NEED_PRAND_CONF
+#include "minires/minires.h"
+/* XXX #include "prand_conf.h" XXX */
+
+#ifndef DST_NUM_HASHES
+#define DST_NUM_HASHES 4
+#endif
+#ifndef DST_NUMBER_OF_COUNTERS
+#define DST_NUMBER_OF_COUNTERS 5       /* 32 * 5 == 160 == SHA(1) > MD5 */
+#endif
+
+/* 
+ * the constant below is a prime number to make fixed data structues like 
+ * stat and time wrap over blocks. This adds certain uncertanty to what is 
+ * in each digested block. 
+ * The prime number 2879 has the special property that when 
+ * divided by 2,4 and 6 the result is also a prime numbers
+ */
+
+#ifndef DST_RANDOM_BLOCK_SIZE
+#define DST_RANDOM_BLOCK_SIZE 2879
+#endif
+
+/* 
+ * This constant dictatates how many bits we shift to the right before using a 
+ */
+#ifndef DST_SHIFT
+#define DST_SHIFT 9
+#endif
+
+/*
+ * An initalizer that is as bad as any other with half the bits set 
+ */
+#ifndef DST_RANDOM_PATTERN
+#define DST_RANDOM_PATTERN 0x8765CA93
+#endif
+/* 
+ * things must have changed in the last 3600 seconds to be used 
+ */
+#define MAX_OLD 3600
+
+
+/*  
+ *  these two data structure are used to process input data into digests, 
+ *
+ *  The first structure is containts a pointer to a DST HMAC key 
+ *  the variables accompanying are used for 
+ *     step : select every step byte from input data for the hash
+ *     block: number of data elements going into each hash
+ *     digested: number of data elements digested so far
+ *     curr: offset into the next input data for the first byte. 
+ */
+typedef struct hash {
+       DST_KEY *key;
+       void *ctx;
+       int digested, block, step, curr;
+} prand_hash;
+
+/*
+ *  This data structure controlls number of hashes and keeps track of 
+ *  overall progress in generating correct number of bytes of output.
+ *     output  : array to store the output data in
+ *     needed  : how many bytes of output are needed
+ *     filled  : number of bytes in output so far. 
+ *     bytes   : total number of bytes processed by this structure
+ *     file_digest : the HMAC key used to digest files.
+ */
+typedef struct work {
+       unsigned needed, filled, bytes;
+       u_char *output;
+       prand_hash *hash[DST_NUM_HASHES];
+       DST_KEY *file_digest;
+} dst_work;
+
+
+/* 
+ * forward function declarations 
+ */
+static int get_dev_random(u_char *output, unsigned size);
+static int do_time(dst_work *work);
+static int do_ls(dst_work *work);
+static int unix_cmd(dst_work *work);
+static int digest_file(dst_work *work);
+
+static void force_hash(dst_work *work, prand_hash *hash);
+static int do_hash(dst_work *work, prand_hash *hash, const u_char *input,
+                  unsigned size);
+static int my_digest(dst_work *tmp, const u_char *input, unsigned size);
+static prand_hash *get_hmac_key(int step, int block);
+
+static unsigned own_random(dst_work *work);
+
+
+/* 
+ * variables used in the quick random number generator 
+ */
+static u_int32_t ran_val = DST_RANDOM_PATTERN;
+static u_int32_t ran_cnt = (DST_RANDOM_PATTERN >> 10);
+
+/* 
+ * setting the quick_random generator to particular values or if both 
+ * input parameters are 0 then set it to initial vlaues
+ */
+
+void
+dst_s_quick_random_set(u_int32_t val, u_int32_t cnt)
+{
+       ran_val = (val == 0) ? DST_RANDOM_PATTERN : val;
+       ran_cnt = (cnt == 0) ? (DST_RANDOM_PATTERN >> 10) : cnt;
+}
+
+/* 
+ * this is a quick and random number generator that seems to generate quite 
+ * good distribution of data 
+ */
+u_int32_t
+dst_s_quick_random(int inc)
+{
+       ran_val = ((ran_val >> 13) ^ (ran_val << 19)) ^
+               ((ran_val >> 7) ^ (ran_val << 25));
+       if (inc > 0)            /* only increasing values accepted */
+               ran_cnt += inc;
+       ran_val += ran_cnt++;
+       return (ran_val);
+}
+
+/* 
+ * get_dev_random: Function to read /dev/random reliably
+ * this function returns how many bytes where read from the device.
+ * port_after.h should set the control variable HAVE_DEV_RANDOM 
+ */
+static int
+get_dev_random(u_char *output, unsigned size)
+{
+#ifdef HAVE_DEV_RANDOM
+       struct stat st;
+       int n = 0, fd = -1, s;
+
+       s = stat("/dev/random", &st);
+       if (s == 0 && S_ISCHR(st.st_mode)) {
+               if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) {
+                       if ((n = read(fd, output, size)) < 0)
+                               n = 0;
+                       close(fd);
+               }
+               return (n);
+       }
+#endif
+       return (0);
+}
+
+/*
+ * Portable way of getting the time values if gettimeofday is missing 
+ * then compile with -DMISSING_GETTIMEOFDAY  time() is POSIX compliant but
+ * gettimeofday() is not.
+ * Time of day is predictable, we are looking for the randomness that comes 
+ * the last few bits in the microseconds in the timer are hard to predict when 
+ * this is invoked at the end of other operations
+ */
+struct timeval *mtime;
+static int
+do_time(dst_work *work)
+{
+       int cnt = 0;
+       static u_char tmp[sizeof(struct timeval) + sizeof(struct timezone)];
+       struct timezone *zone;
+
+       zone = (struct timezone *) tmp;
+       mtime = (struct timeval *)(tmp + sizeof(struct timezone));
+       gettimeofday(mtime, zone);
+       cnt = sizeof(tmp);
+       my_digest(work, tmp, sizeof(tmp));
+
+       return (cnt);
+}
+
+/*
+ * this function simulates the ls command, but it uses stat which gives more
+ * information and is harder to guess 
+ * Each call to this function will visit the next directory on the list of 
+ * directories, in a circular manner. 
+ * return value is the number of bytes added to the temp buffer
+ *
+ * do_ls() does not visit subdirectories
+ * if attacker has access to machine it can guess most of the values seen
+ * thus it is important to only visit directories that are freqently updated
+ * Attacker that has access to the network can see network traffic 
+ * when NFS mounted directories are accessed and know exactly the data used
+ * but may not know exactly in what order data is used. 
+ * Returns the number of bytes that where returned in stat structures
+ */
+static int
+do_ls(dst_work *work)
+{
+       struct dir_info { 
+               uid_t  uid;
+               gid_t  gid;
+               off_t size;
+               time_t atime, mtime, ctime;
+       };
+       static struct dir_info dir_info;
+       struct stat buf;
+       struct dirent *entry;
+       static int i = 0;
+       static unsigned long d_round = 0;
+       struct timeval tv;
+       int n = 0, tb_i = 0, out = 0;
+       unsigned dir_len;
+
+       char file_name[1024];
+       u_char tmp_buff[1024]; 
+       DIR *dir = NULL;
+
+       if (dirs[i] == NULL)    /* if at the end of the list start over */
+               i = 0;
+       if (stat(dirs[i++], &buf))  /* directory does not exist */
+               return (0);
+
+       gettimeofday(&tv,NULL);
+       if (d_round == 0) 
+               d_round = tv.tv_sec - MAX_OLD;
+       else if (i==1) /* if starting a new round cut what we accept */
+               d_round += (tv.tv_sec - d_round)/2;
+
+       if (buf.st_atime < d_round) 
+               return (0);
+
+       EREPORT(("do_ls i %d filled %4d in_temp %4d\n",
+                i-1, work->filled, work->in_temp));
+       memcpy(tmp_buff, &buf, sizeof(buf)); 
+       tb_i += sizeof(buf);
+
+
+       if ((dir = opendir(dirs[i-1])) == NULL)/* open it for read */
+               return (0);
+       strcpy(file_name, dirs[i-1]);
+       dir_len = strlen(file_name);
+       file_name[dir_len++] = '/';
+       while ((entry = readdir(dir))) {
+               unsigned len = strlen(entry->d_name);
+               out += len;
+               if (my_digest(work, (u_char *)entry->d_name, len))
+                       break;
+       
+               memcpy(&file_name[dir_len], entry->d_name, len);
+               file_name[dir_len + len] = 0x0;
+               /* for all entries in dir get the stats */
+               if (stat(file_name, &buf) == 0) {
+                       n++;    /* count successfull stat calls */
+                       /* copy non static fields */
+                       dir_info.uid   += buf.st_uid;
+                       dir_info.gid   += buf.st_gid;
+                       dir_info.size  += buf.st_size;
+                       dir_info.atime += buf.st_atime;
+                       dir_info.mtime += buf.st_mtime;
+                       dir_info.ctime += buf.st_ctime;
+                       out += sizeof(dir_info);
+                       if(my_digest(work, (u_char *)&dir_info, 
+                                    sizeof(dir_info)))
+                               break; 
+               }
+       }
+       closedir(dir);  /* done */
+       out += do_time(work);   /* add a time stamp */
+       return (out);
+}
+
+
+/* 
+ * unix_cmd() 
+ * this function executes the a command from the cmds[] list of unix commands 
+ * configured in the prand_conf.h file
+ * return value is the number of bytes added to the randomness temp buffer
+ * 
+ * it returns the number of bytes that where read in
+ * if more data is needed at the end time is added to the data.
+ * This function maintains a state to selects the next command to run
+ * returns the number of bytes read in from the command 
+ */
+static int
+unix_cmd(dst_work *work)
+{
+       static int cmd_index = 0;
+       int cnt = 0, n;
+       FILE *pipe;
+       u_char buffer[4096];
+
+       if (cmds[cmd_index] == NULL)
+               cmd_index = 0;
+       EREPORT(("unix_cmd() i %d filled %4d in_temp %4d\n",
+                cmd_index, work->filled, work->in_temp));
+       pipe = popen(cmds[cmd_index++], "r");   /* execute the command */
+
+       while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) {
+               cnt += n;       /* process the output */
+               if (my_digest(work, buffer, (unsigned)n))
+                       break;
+               /* this adds some randomness to the output */
+               cnt += do_time(work);
+       }
+       while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0)
+               NULL; /* drain the pipe */
+       pclose(pipe);
+       return (cnt);           /* read how many bytes where read in */
+}
+
+/* 
+ * digest_file() This function will read a file and run hash over it
+ * input is a file name 
+ */ 
+static int 
+digest_file(dst_work *work) 
+{
+       static int f_cnt = 0;
+       static unsigned long f_round = 0;
+       FILE *fp; 
+       void *ctx;
+       const char *name;
+       int no, i; 
+       struct stat st;
+       struct timeval tv;
+       u_char buf[1024];
+
+       if (f_round == 0 || files[f_cnt] == NULL || work->file_digest == NULL) 
+               if (gettimeofday(&tv, NULL)) /* only do this if needed */
+                       return (0);
+       if (f_round == 0)   /* first time called set to one hour ago */
+               f_round = (tv.tv_sec - MAX_OLD); 
+       name = files[f_cnt++]; 
+       if (files[f_cnt] == NULL) {  /* end of list of files */
+               if(f_cnt <= 1)       /* list is too short */
+                       return (0);
+               f_cnt = 0;           /* start again on list */
+               f_round += (tv.tv_sec - f_round)/2; /* set new cutoff */
+               work->file_digest = dst_free_key(work->file_digest);
+       }
+       if (work->file_digest == NULL) {
+               work->file_digest  = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, 
+                                           (u_char *)&tv, sizeof(tv));
+               if (work->file_digest == NULL)
+                       return (0);
+       }
+       if (access(name, R_OK) || stat(name, &st))
+               return (0); /* no such file or not allowed to read it */
+       if (strncmp(name, "/proc/", 6) && st.st_mtime < f_round)  
+               return(0); /* file has not changed recently enough */
+       if (dst_sign_data(SIG_MODE_INIT, work->file_digest, &ctx, 
+                         NULL, 0, NULL, 0)) {
+               work->file_digest = dst_free_key(work->file_digest);
+               return (0);
+       }
+       if ((fp = fopen(name, "r")) == NULL) 
+               return (0);
+       for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0; 
+            no += i) 
+               dst_sign_data(SIG_MODE_UPDATE, work->file_digest, &ctx, 
+                             buf, (unsigned)i, NULL, 0);
+
+       fclose(fp);
+       if (no >= 64) {
+               i = dst_sign_data(SIG_MODE_FINAL, work->file_digest, &ctx, 
+                                 NULL, 0, &work->output[work->filled], 
+                                 DST_HASH_SIZE);         
+               if (i > 0) 
+                       work->filled += i;
+       }
+       else if (i > 0)
+               my_digest(work, buf, (unsigned)i);
+       my_digest(work, (const u_char *)name, strlen(name));
+       return (no + strlen(name));
+}
+
+/* 
+ * function to perform the FINAL and INIT operation on a hash if allowed
+ */
+static void
+force_hash(dst_work *work, prand_hash *hash)
+{
+       int i = 0;
+
+       /* 
+        * if more than half a block then add data to output 
+        * otherwise adde the digest to the next hash 
+        */
+       if ((hash->digested * 2) > hash->block) {
+               i = dst_sign_data(SIG_MODE_FINAL, hash->key, &hash->ctx,
+                                 NULL, 0, &work->output[work->filled],
+                                 DST_HASH_SIZE);
+
+               hash->digested = 0;
+               dst_sign_data(SIG_MODE_INIT, hash->key, &hash->ctx, 
+                             NULL, 0, NULL, 0);
+               if (i > 0)
+                       work->filled += i;
+       }
+       return;
+}
+
+/* 
+ * This function takes the input data does the selection of data specified
+ * by the hash control block.
+ * The step varialbe in the work sturcture determines which 1/step bytes
+ * are used, 
+ *
+ */
+static int
+do_hash(dst_work *work, prand_hash *hash, const u_char *input, unsigned size)
+{
+       const u_char *tmp = input;
+       u_char *tp, *abuf = (u_char *)0;
+       int i, n;
+       unsigned needed, avail, dig, cnt = size;
+       unsigned tmp_size = 0;
+
+       if (cnt <= 0 || input == NULL)
+               return (0);
+
+       if (hash->step > 1) {   /* if using subset of input data */
+               tmp_size = size / hash->step + 2;
+               abuf = tp = malloc(tmp_size);
+               tmp = tp;
+               for (cnt = 0, i = hash->curr; i < size; i += hash->step, cnt++)
+                       *(tp++) = input[i];
+               /* calcutate the starting point in the next input set */
+               hash->curr = (hash->step - (i - size)) % hash->step;
+       }
+       /* digest the data in block sizes */
+       for (n = 0; n < cnt; n += needed) {
+               avail = (cnt - n);
+               needed = hash->block - hash->digested;
+               dig = (avail < needed) ? avail : needed;
+               dst_sign_data(SIG_MODE_UPDATE, hash->key, &hash->ctx, 
+                             &tmp[n], dig, NULL, 0);
+               hash->digested += dig;
+               if (hash->digested >= hash->block)
+                       force_hash(work, hash);
+               if (work->needed < work->filled) {
+                       if (abuf) 
+                               SAFE_FREE2(abuf, tmp_size);
+                       return (1);
+               }
+       }
+       if (tmp_size > 0)
+               SAFE_FREE2(abuf, tmp_size);
+       return (0);
+}
+
+/*
+ * Copy data from INPUT for length SIZE into the work-block TMP.
+ * If we fill the work-block, digest it; then,
+ * if work-block needs more data, keep filling with the rest of the input.
+ */
+static int
+my_digest(dst_work *work, const u_char *input, unsigned size)
+{
+
+       int i, full = 0;
+       static unsigned counter;
+       
+       counter += size;
+       /* first do each one of the hashes */
+       for (i = 0; i < DST_NUM_HASHES && full == 0; i++) 
+               full = do_hash(work, work->hash[i], input, size) +
+                      do_hash(work, work->hash[i], (u_char *) &counter, 
+                               sizeof(counter));
+/* 
+ * if enough data has be generated do final operation on all hashes 
+ *  that have enough date for that 
+ */
+       for (i = 0; full && (i < DST_NUM_HASHES); i++)
+               force_hash(work, work->hash[i]);
+
+       return (full);
+}
+
+/*
+ * this function gets some semi random data and sets that as an HMAC key
+ * If we get a valid key this function returns that key initalized
+ * otherwise it returns NULL;
+ */
+static prand_hash *
+get_hmac_key(int step, int block)
+{
+
+       u_char *buff;
+       int temp = 0, n = 0;
+       unsigned size = 70;
+       DST_KEY *new_key = NULL;
+       prand_hash *new = NULL;
+
+       /* use key that is larger than  digest algorithms (64) for key size */
+       buff = malloc(size);
+       if (buff == NULL)
+               return (NULL);
+       /* do not memset the allocated memory to get random bytes there */
+       /* time of day is somewhat random  expecialy in the last bytes */
+       gettimeofday((struct timeval *) &buff[n], NULL);
+       n += sizeof(struct timeval);
+
+/* get some semi random stuff in here stir it with micro seconds */
+       if (n < size) {
+               temp = dst_s_quick_random((int) buff[n - 1]);
+               memcpy(&buff[n], &temp, sizeof(temp));
+               n += sizeof(temp);
+       }
+/* get the pid of this process and its parent */
+       if (n < size) {
+               temp = (int) getpid();
+               memcpy(&buff[n], &temp, sizeof(temp));
+               n += sizeof(temp);
+       }
+       if (n < size) {
+               temp = (int) getppid();
+               memcpy(&buff[n], &temp, sizeof(temp));
+               n += sizeof(temp);
+       }
+/* get the user ID */
+       if (n < size) {
+               temp = (int) getuid();
+               memcpy(&buff[n], &temp, sizeof(temp));
+               n += sizeof(temp);
+       }
+#ifndef GET_HOST_ID_MISSING
+       if (n < size) {
+               temp = (int) gethostid();
+               memcpy(&buff[n], &temp, sizeof(temp));
+               n += sizeof(temp);
+       }
+#endif
+/* get some more random data */
+       if (n < size) {
+               temp = dst_s_quick_random((int) buff[n - 1]);
+               memcpy(&buff[n], &temp, sizeof(temp));
+               n += sizeof(temp);
+       }
+/* covert this into a HMAC key */
+       new_key = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, buff, size);
+       SAFE_FREE(buff);
+
+/* get the control structure */
+       if ((new = malloc(sizeof(prand_hash))) == NULL)
+               return (NULL);
+       new->digested = new->curr = 0;
+       new->step = step;
+       new->block = block;
+       new->key = new_key;
+       if (dst_sign_data(SIG_MODE_INIT, new_key, &new->ctx, NULL, 0, NULL, 0))
+               return (NULL);
+
+       return (new);
+}
+
+/* 
+ * own_random() 
+ * This function goes out and from various sources tries to generate enough
+ * semi random data that a hash function can generate a random data. 
+ * This function will iterate between the two main random source sources, 
+ *  information from programs and directores in random order. 
+ * This function return the number of bytes added to the random output buffer. 
+ */
+static unsigned
+own_random(dst_work *work)
+{
+       int dir = 0, b;
+       int bytes, n, cmd = 0, dig = 0;
+       int start =0;
+/* 
+ * now get the initial seed to put into the quick random function from 
+ * the address of the work structure 
+ */
+       bytes = (int) getpid();
+/*
+ * proceed while needed 
+ */
+       while (work->filled < work->needed) {
+               EREPORT(("own_random r %08x b %6d t %6d f %6d\n",
+                        ran_val, bytes, work->in_temp, work->filled));
+/* pick a random number in the range of 0..7 based on that random number
+ * perform some operations that yield random data
+ */
+               start = work->filled;
+               n = (dst_s_quick_random(bytes) >> DST_SHIFT) & 0x07;
+               switch (n) {
+                   case 0:
+                   case 3:
+                       if (sizeof(cmds) > 2 *sizeof(*cmds)) {
+                               b = unix_cmd(work);
+                               cmd += b;
+                       }
+                       break;
+
+                   case 1:
+                   case 7:
+                       if (sizeof(dirs) > 2 *sizeof(*dirs)) {
+                               b = do_ls(work);
+                               dir += b;
+                       }
+                       break;
+
+                   case 4:
+                   case 5:
+                       /* retry getting data from /dev/random */
+                       b = get_dev_random(&work->output[work->filled], 
+                                          work->needed - work->filled);
+                       if (b > 0)
+                               work->filled += b;
+                       break;
+
+                   case 6:
+                       if (sizeof(files) > 2 * sizeof(*files)) {
+                               b = digest_file(work);
+                               dig += b;
+                       }
+                       break;
+
+                   case 2:
+                   default:    /* to make sure we make some progress */
+                       work->output[work->filled++] = 0xff &
+                               dst_s_quick_random(bytes);
+                       b = 1;
+                       break;
+               }
+               if (b > 0) 
+                       bytes += b;
+       }
+       return (work->filled);
+}
+
+
+/* 
+ * dst_s_random() This function will return the requested number of bytes 
+ * of randomness to the caller it will use the best available sources of 
+ * randomness.
+ * The current order is to use /dev/random, precalculated randomness, and 
+ * finaly use some system calls and programs to generate semi random data that 
+ * is then digested to generate randomness. 
+ * This function is thread safe as each thread uses its own context, but
+ * concurrent treads will affect each other as they update shared state 
+ * information.
+ * It is strongly recommended that this function be called requesting a size 
+ * that is not a multiple of the output of the hash function used. 
+ * 
+ * If /dev/random is not available this function is not suitable to generate 
+ * large ammounts of data, rather it is suitable to seed a pseudo-random 
+ * generator 
+ * Returns the number of bytes put in the output buffer 
+ */
+int
+dst_s_random(u_char *output, unsigned size)
+{
+       int n = 0, i;
+       unsigned s;
+       static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES];
+       static unsigned unused = 0;
+
+       if (size <= 0 || output == NULL)
+               return (0);
+
+       if (size >= 2048)
+               return (-1);
+       /* 
+        * Read from /dev/random 
+        */
+       n = get_dev_random(output, size);
+       /* 
+        *  If old data is available and needed use it 
+        */
+       if (n < size && unused > 0) {
+               unsigned need = size - n;
+               if (unused <= need) {
+                       memcpy(output, old_unused, unused);
+                       n += unused;
+                       unused = 0;
+               } else {
+                       memcpy(output, old_unused, need);
+                       n += need;
+                       unused -= need;
+                       memcpy(old_unused, &old_unused[need], unused);
+               }
+       }
+       /*
+        * If we need more use the simulated randomness here.
+        */
+       if (n < size) {
+               dst_work *my_work = (dst_work *) malloc(sizeof(dst_work));
+               if (my_work == NULL)
+                       return (n);
+               my_work->needed = size - n;
+               my_work->filled = 0;
+               my_work->output = (u_char *) malloc(my_work->needed +
+                                                   DST_HASH_SIZE *
+                                                   DST_NUM_HASHES);
+               my_work->file_digest = NULL;
+               if (my_work->output == NULL)
+                       return (n);
+               memset(my_work->output, 0x0, my_work->needed);
+/* allocate upto 4 different HMAC hash functions out of order */
+#if DST_NUM_HASHES >= 3
+               my_work->hash[2] = get_hmac_key(3, DST_RANDOM_BLOCK_SIZE / 2);
+#endif
+#if DST_NUM_HASHES >= 2
+               my_work->hash[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE / 6);
+#endif
+#if DST_NUM_HASHES >= 4
+               my_work->hash[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE / 4);
+#endif
+               my_work->hash[0] = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE);
+               if (my_work->hash[0] == NULL)   /* if failure bail out */
+                       return (n);
+               s = own_random(my_work);
+/* if more generated than needed store it for future use */
+               if (s >= my_work->needed) {
+                       EREPORT(("dst_s_random(): More than needed %d >= %d\n",
+                                s, my_work->needed));
+                       memcpy(&output[n], my_work->output, my_work->needed);
+                       n += my_work->needed;
+                       /* saving unused data for next time */
+                       unused = s - my_work->needed;
+                       memcpy(old_unused, &my_work->output[my_work->needed],
+                              unused);
+               } else {
+                       /* XXXX This should not happen */
+                       EREPORT(("Not enough %d >= %d\n", s, my_work->needed));
+                       memcpy(&output[n], my_work->output, s);
+                       n += my_work->needed;
+               }
+
+/* delete the allocated work area */
+               for (i = 0; i < DST_NUM_HASHES; i++) {
+                       dst_free_key(my_work->hash[i]->key);
+                       SAFE_FREE(my_work->hash[i]);
+               }
+               SAFE_FREE(my_work->output);
+               SAFE_FREE(my_work);
+       }
+       return (n);
+}
+
+/*
+ * A random number generator that is fast and strong 
+ * this random number generator is based on HASHing data,
+ * the input to the digest function is a collection of <NUMBER_OF_COUNTERS>
+ * counters that is incremented between digest operations
+ * each increment operation amortizes to 2 bits changed in that value
+ * for 5 counters thus the input will amortize to have 10 bits changed 
+ * The counters are initaly set using the strong random function above
+ * the HMAC key is selected by the same methold as the HMAC keys for the 
+ * strong random function. 
+ * Each set of counters is used for 2^25 operations 
+ * 
+ * returns the number of bytes written to the output buffer 
+ * or       negative number in case of error 
+ */
+int
+dst_s_semi_random(u_char *output, unsigned size)
+{
+       static u_int32_t counter[DST_NUMBER_OF_COUNTERS];
+       static u_char semi_old[DST_HASH_SIZE];
+       static int semi_loc = 0, cnt = 0;
+       static unsigned hb_size = 0;
+       static DST_KEY *my_key = NULL;
+       prand_hash *hash;
+       unsigned out = 0;
+       unsigned i;
+       int n;
+
+       if (output == NULL || size <= 0)
+               return (-2);
+
+/* check if we need a new key */
+       if (my_key == NULL || cnt > (1 << 25)) {        /* get HMAC KEY */
+               if (my_key)
+                       my_key->dk_func->destroy(my_key);
+               if ((hash = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE)) == NULL)
+                       return (0);
+               my_key = hash->key;
+/* check if the key works stir the new key using some old random data */
+               hb_size = dst_sign_data(SIG_MODE_ALL, my_key, NULL, 
+                                       (u_char *) counter, sizeof(counter),
+                                       semi_old, sizeof(semi_old));
+               if (hb_size <= 0) {
+                       EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n",
+                                my_key->dk_alg, hb_size));
+                       return (-1);
+               }
+/* new set the counters to random values */
+               dst_s_random((u_char *) counter, sizeof(counter));
+               cnt = 0;
+       }
+/* if old data around use it first */
+       if (semi_loc < hb_size) {
+               if (size <= hb_size - semi_loc) {       /* need less */
+                       memcpy(output, &semi_old[semi_loc], size);
+                       semi_loc += size;
+                       return (size);  /* DONE */
+               } else {
+                       out = hb_size - semi_loc;
+                       memcpy(output, &semi_old[semi_loc], out);
+                       semi_loc += out;
+               }
+       }
+/* generate more randome stuff */
+       while (out < size) {
+               /* 
+                * modify at least one bit by incrementing at least one counter
+                * based on the last bit of the last counter updated update
+                * the next one.
+                * minimaly this  operation will modify at least 1 bit, 
+                * amortized 2 bits
+                */
+               for (n = 0; n < DST_NUMBER_OF_COUNTERS; n++)
+                       i = (int) counter[n]++;
+
+               i = dst_sign_data(SIG_MODE_ALL, my_key, NULL, 
+                                 (u_char *) counter, hb_size,
+                                 semi_old, sizeof(semi_old));
+               if (i != hb_size)
+                       EREPORT(("HMAC SIGNATURE FAILURE %d\n", i));
+               cnt++;
+               if (size - out < i)     /* Not all data is needed */
+                       semi_loc = i = size - out;
+               memcpy(&output[out], semi_old, i);
+               out += i;
+       }
+       return (out);
+}
diff --git a/minires/res_comp.c b/minires/res_comp.c
new file mode 100644 (file)
index 0000000..1f0a5be
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1985, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_comp.c   8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_comp.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name.
+ * 'msg' is a pointer to the begining of the message,
+ * 'eomorig' points to the first location after the message,
+ * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
+ * Return size of compressed name or -1 if there was an error.
+ */
+int
+dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
+         char *dst, unsigned dstsiz)
+{
+       int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
+
+       if (n > 0 && dst[0] == '.')
+               dst[0] = '\0';
+       return (n);
+}
+
+/*
+ * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ */
+int
+dn_comp(const char *src, u_char *dst, unsigned dstsiz,
+       u_char **dnptrs, u_char **lastdnptr)
+{
+       return (ns_name_compress(src, dst, (size_t)dstsiz,
+                                (const u_char **)dnptrs,
+                                (const u_char **)lastdnptr));
+}
+
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+int
+dn_skipname(const u_char *ptr, const u_char *eom) {
+       const u_char *saveptr = ptr;
+
+       if (ns_name_skip(&ptr, eom) == -1)
+               return (-1);
+       return (ptr - saveptr);
+}
+
+/*
+ * Verify that a domain name uses an acceptable character set.
+ */
+
+#if 0
+/*
+ * Note the conspicuous absence of ctype macros in these definitions.  On
+ * non-ASCII hosts, we can't depend on string literals or ctype macros to
+ * tell us anything about network-format data.  The rest of the BIND system
+ * is not careful about this, but for some reason, we're doing it right here.
+ */
+#define PERIOD 0x2e
+#define        hyphenchar(c) ((c) == 0x2d)
+#define bslashchar(c) ((c) == 0x5c)
+#define periodchar(c) ((c) == PERIOD)
+#define asterchar(c) ((c) == 0x2a)
+#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
+                  || ((c) >= 0x61 && (c) <= 0x7a))
+#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
+
+#define borderchar(c) (alphachar(c) || digitchar(c))
+#define middlechar(c) (borderchar(c) || hyphenchar(c))
+#define        domainchar(c) ((c) > 0x20 && (c) < 0x7f)
+
+int
+res_hnok(const char *dn) {
+       int ppch = '\0', pch = PERIOD, ch = *dn++;
+
+       while (ch != '\0') {
+               int nch = *dn++;
+
+               if (periodchar(ch)) {
+                       (void)NULL;
+               } else if (periodchar(pch)) {
+                       if (!borderchar(ch))
+                               return (0);
+               } else if (periodchar(nch) || nch == '\0') {
+                       if (!borderchar(ch))
+                               return (0);
+               } else {
+                       if (!middlechar(ch))
+                               return (0);
+               }
+               ppch = pch, pch = ch, ch = nch;
+       }
+       return (1);
+}
+
+/*
+ * hostname-like (A, MX, WKS) owners can have "*" as their first label
+ * but must otherwise be as a host name.
+ */
+int
+res_ownok(const char *dn) {
+       if (asterchar(dn[0])) {
+               if (periodchar(dn[1]))
+                       return (res_hnok(dn+2));
+               if (dn[1] == '\0')
+                       return (1);
+       }
+       return (res_hnok(dn));
+}
+
+/*
+ * SOA RNAMEs and RP RNAMEs can have any printable character in their first
+ * label, but the rest of the name has to look like a host name.
+ */
+int
+res_mailok(const char *dn) {
+       int ch, escaped = 0;
+
+       /* "." is a valid missing representation */
+       if (*dn == '\0')
+               return (1);
+
+       /* otherwise <label>.<hostname> */
+       while ((ch = *dn++) != '\0') {
+               if (!domainchar(ch))
+                       return (0);
+               if (!escaped && periodchar(ch))
+                       break;
+               if (escaped)
+                       escaped = 0;
+               else if (bslashchar(ch))
+                       escaped = 1;
+       }
+       if (periodchar(ch))
+               return (res_hnok(dn));
+       return (0);
+}
+
+/*
+ * This function is quite liberal, since RFC 1034's character sets are only
+ * recommendations.
+ */
+int
+res_dnok(const char *dn) {
+       int ch;
+
+       while ((ch = *dn++) != '\0')
+               if (!domainchar(ch))
+                       return (0);
+       return (1);
+}
+#endif
diff --git a/minires/res_findzonecut.c b/minires/res_findzonecut.c
new file mode 100644 (file)
index 0000000..f115f72
--- /dev/null
@@ -0,0 +1,593 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Import. */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+/* Data structures. */
+
+typedef struct rr_a {
+       ISC_LINK(struct rr_a)   link;
+       struct in_addr          addr;
+} rr_a;
+typedef ISC_LIST(rr_a) rrset_a;
+
+typedef struct rr_ns {
+       ISC_LINK(struct rr_ns) link;
+       char *name;
+       rrset_a addrs;
+} rr_ns;
+typedef ISC_LIST(rr_ns) rrset_ns;
+
+/* Forward. */
+
+static int     satisfy(res_state,
+                       const char *, rrset_ns *, struct in_addr *, int);
+static int     add_addrs(res_state, rr_ns *, struct in_addr *, int);
+static int     get_soa(res_state, const char *, ns_class,
+                       char *, size_t, char *, size_t,
+                       rrset_ns *);
+static int     get_ns(res_state, const char *, ns_class, rrset_ns *);
+static int     get_glue(res_state, ns_class, rrset_ns *);
+static int     save_ns(res_state, ns_msg *, ns_sect,
+                       const char *, ns_class, rrset_ns *);
+static int     save_a(res_state, ns_msg *, ns_sect,
+                      const char *, ns_class, rrset_a *);
+static void    free_nsrrset(rrset_ns *);
+static void    free_nsrr(rrset_ns *, rr_ns *);
+static rr_ns * find_ns(rrset_ns *, const char *);
+static int     do_query(res_state, const char *, ns_class, ns_type,
+                        u_char *, ns_msg *);
+static void    dprintf(const char *, ...);
+
+/* Public. */
+
+/*
+ * int
+ * res_findzonecut(res, dname, class, zname, zsize, addrs, naddrs)
+ *     find enclosing zone for a <dname,class>, and some server addresses
+ * parameters:
+ *     res - resolver context to work within (is modified)
+ *     dname - domain name whose enclosing zone is desired
+ *     class - class of dname (and its enclosing zone)
+ *     zname - found zone name
+ *     zsize - allocated size of zname
+ *     addrs - found server addresses
+ *     naddrs - max number of addrs
+ * return values:
+ *     < 0 - an error occurred (check errno)
+ *     = 0 - zname is now valid, but addrs[] wasn't changed
+ *     > 0 - zname is now valid, and return value is number of addrs[] found
+ * notes:
+ *     this function calls res_nsend() which means it depends on correctly
+ *     functioning recursive nameservers (usually defined in /etc/resolv.conf
+ *     or its local equivilent).
+ *
+ *     we start by asking for an SOA<dname,class>.  if we get one as an
+ *     answer, that just means <dname,class> is a zone top, which is fine.
+ *     more than likely we'll be told to go pound sand, in the form of a
+ *     negative answer.
+ *
+ *     note that we are not prepared to deal with referrals since that would
+ *     only come from authority servers and our correctly functioning local
+ *     recursive server would have followed the referral and got us something
+ *     more definite.
+ *
+ *     if the authority section contains an SOA, this SOA should also be the
+ *     closest enclosing zone, since any intermediary zone cuts would've been
+ *     returned as referrals and dealt with by our correctly functioning local
+ *     recursive name server.  but an SOA in the authority section should NOT
+ *     match our dname (since that would have been returned in the answer
+ *     section).  an authority section SOA has to be "above" our dname.
+ *
+ *     we cannot fail to find an SOA in this way.  ultimately we'll return
+ *     a zname indicating the root zone if that's the closest enclosing zone.
+ *     however, since authority section SOA's were once optional, it's
+ *     possible that we'll have to go hunting for the enclosing SOA by
+ *     ripping labels off the front of our dname -- this is known as "doing
+ *     it the hard way."
+ *
+ *     ultimately we want some server addresses, which are ideally the ones
+ *     pertaining to the SOA.MNAME, but only if there is a matching NS RR.
+ *     so the second phase (after we find an SOA) is to go looking for the
+ *     NS RRset for that SOA's zone.
+ *
+ *     no answer section processed by this code is allowed to contain CNAME
+ *     or DNAME RR's.  for the SOA query this means we strip a label and
+ *     keep going.  for the NS and A queries this means we just give up.
+ */
+
+int
+res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
+               char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
+{
+       char mname[NS_MAXDNAME];
+       u_long save_pfcode;
+       rrset_ns nsrrs;
+       int n;
+
+       DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d",
+                dname, p_class(class), (long)zsize, naddrs));
+       save_pfcode = statp->pfcode;
+       statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX |
+                        RES_PRF_QUES | RES_PRF_ANS |
+                        RES_PRF_AUTH | RES_PRF_ADD;
+       ISC_LIST_INIT(nsrrs);
+
+       DPRINTF(("get the soa, and see if it has enough glue"));
+       if ((n = get_soa(statp, dname, class, zname, zsize,
+                        mname, sizeof mname, &nsrrs)) < 0 ||
+           ((opts & RES_EXHAUSTIVE) == 0 &&
+            (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+               goto done;
+
+       DPRINTF(("get the ns rrset and see if it has enough glue"));
+       if ((n = get_ns(statp, zname, class, &nsrrs)) < 0 ||
+           ((opts & RES_EXHAUSTIVE) == 0 &&
+            (n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
+               goto done;
+
+       DPRINTF(("get the missing glue and see if it's finally enough"));
+       if ((n = get_glue(statp, class, &nsrrs)) >= 0)
+               n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
+
+ done:
+       DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
+       free_nsrrset(&nsrrs);
+       statp->pfcode = save_pfcode;
+       return (n);
+}
+
+/* Private. */
+
+static int
+satisfy(res_state statp,
+       const char *mname, rrset_ns *nsrrsp, struct in_addr *addrs, int naddrs)
+{
+       rr_ns *nsrr;
+       int n, x;
+
+       n = 0;
+       nsrr = find_ns(nsrrsp, mname);
+       if (nsrr != NULL) {
+               x = add_addrs(statp, nsrr, addrs, naddrs);
+               addrs += x;
+               naddrs -= x;
+               n += x;
+       }
+       for (nsrr = ISC_LIST_HEAD(*nsrrsp);
+            nsrr != NULL && naddrs > 0;
+            nsrr = ISC_LIST_NEXT(nsrr, link))
+               if (ns_samename(nsrr->name, mname) != 1) {
+                       x = add_addrs(statp, nsrr, addrs, naddrs);
+                       addrs += x;
+                       naddrs -= x;
+                       n += x;
+               }
+       DPRINTF(("satisfy(%s): %d", mname, n));
+       return (n);
+}
+
+static int
+add_addrs(res_state statp, rr_ns *nsrr, struct in_addr *addrs, int naddrs) {
+       rr_a *arr;
+       int n = 0;
+
+       for (arr = ISC_LIST_HEAD(nsrr->addrs);
+            arr != NULL; arr = ISC_LIST_NEXT(arr, link)) {
+               if (naddrs <= 0)
+                       return (0);
+               *addrs++ = arr->addr;
+               naddrs--;
+               n++;
+       }
+       DPRINTF(("add_addrs: %d", n));
+       return (n);
+}
+
+static int
+get_soa(res_state statp, const char *dname, ns_class class,
+       char *zname, size_t zsize, char *mname, size_t msize,
+       rrset_ns *nsrrsp)
+{
+       char tname[NS_MAXDNAME];
+       u_char resp[NS_PACKETSZ];
+       int n, i, ancount, nscount;
+       ns_sect sect;
+       ns_msg msg;
+       u_int rcode;
+
+       /*
+        * Find closest enclosing SOA, even if it's for the root zone.
+        */
+
+       /* First canonicalize dname (exactly one unescaped trailing "."). */
+       if (ns_makecanon(dname, tname, sizeof tname) < 0)
+               return (-1);
+       dname = tname;
+
+       /* Now grovel the subdomains, hunting for an SOA answer or auth. */
+       for (;;) {
+               /* Leading or inter-label '.' are skipped here. */
+               while (*dname == '.')
+                       dname++;
+
+               /* Is there an SOA? */
+               n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
+               if (n < 0) {
+                       DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
+                                dname, p_class(class), n));
+                       return (-1);
+               }
+               if (n > 0) {
+                       DPRINTF(("get_soa: CNAME or DNAME found"));
+                       sect = ns_s_max, n = 0;
+               } else {
+                       rcode = ns_msg_getflag(msg, ns_f_rcode);
+                       ancount = ns_msg_count(msg, ns_s_an);
+                       nscount = ns_msg_count(msg, ns_s_ns);
+                       if (ancount > 0 && rcode == ns_r_noerror)
+                               sect = ns_s_an, n = ancount;
+                       else if (nscount > 0)
+                               sect = ns_s_ns, n = nscount;
+                       else
+                               sect = ns_s_max, n = 0;
+               }
+               for (i = 0; i < n; i++) {
+                       const char *t;
+                       const u_char *rdata;
+                       int rdlen;
+                       ns_rr rr;
+
+                       if (ns_parserr(&msg, sect, i, &rr) < 0) {
+                               DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
+                                        p_section(sect, ns_o_query), i));
+                               return (-1);
+                       }
+                       if (ns_rr_type(rr) == ns_t_cname ||
+                           ns_rr_type(rr) == ns_t_dname)
+                               break;
+                       if (ns_rr_type(rr) != ns_t_soa ||
+                           ns_rr_class(rr) != class)
+                               continue;
+                       t = ns_rr_name(rr);
+                       switch (sect) {
+                       case ns_s_an:
+                               if (ns_samedomain(dname, t) == 0) {
+                                       DPRINTF(("get_soa: ns_samedomain('%s', '%s') == 0",
+                                                dname, t));
+                                       errno = EPROTOTYPE;
+                                       return (-1);
+                               }
+                               break;
+                       case ns_s_ns:
+                               if (ns_samename(dname, t) == 1 ||
+                                   ns_samedomain(dname, t) == 0) {
+                                       DPRINTF(("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
+                                                dname, t));
+                                       errno = EPROTOTYPE;
+                                       return (-1);
+                               }
+                               break;
+                       default:
+                               abort();
+                       }
+                       if (strlen(t) + 1 > zsize) {
+                               DPRINTF(("get_soa: zname(%d) too small (%d)",
+                                        zsize, strlen(t) + 1));
+                               errno = EMSGSIZE;
+                               return (-1);
+                       }
+                       strcpy(zname, t);
+                       rdata = ns_rr_rdata(rr);
+                       rdlen = ns_rr_rdlen(rr);
+                       if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
+                                              mname, msize) < 0) {
+                               DPRINTF(("get_soa: ns_name_uncompress failed"));
+                               return (-1);
+                       }
+                       if (save_ns(statp, &msg, ns_s_ns,
+                                   zname, class, nsrrsp) < 0) {
+                               DPRINTF(("get_soa: save_ns failed"));
+                               return (-1);
+                       }
+                       return (0);
+               }
+
+               /* If we're out of labels, then not even "." has an SOA! */
+               if (*dname == '\0')
+                       break;
+
+               /* Find label-terminating "."; top of loop will skip it. */
+               while (*dname != '.') {
+                       if (*dname == '\\')
+                               if (*++dname == '\0') {
+                                       errno = EMSGSIZE;
+                                       return (-1);
+                               }
+                       dname++;
+               }
+       }
+       DPRINTF(("get_soa: out of labels"));
+       errno = EDESTADDRREQ;
+       return (-1);
+}
+
+static int
+get_ns(res_state statp, const char *zname, ns_class class, rrset_ns *nsrrsp) {
+       u_char resp[NS_PACKETSZ];
+       ns_msg msg;
+       int n;
+
+       /* Go and get the NS RRs for this zone. */
+       n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
+       if (n != 0) {
+               DPRINTF(("get_ns: do_query('zname', %s) failed (%d)",
+                        zname, p_class(class), n));
+               return (-1);
+       }
+
+       /* Remember the NS RRs and associated A RRs that came back. */
+       if (save_ns(statp, &msg, ns_s_an, zname, class, nsrrsp) < 0) {
+               DPRINTF(("get_ns save_ns('%s', %s) failed",
+                        zname, p_class(class)));
+               return (-1);
+       }
+
+       return (0);
+}
+
+static int
+get_glue(res_state statp, ns_class class, rrset_ns *nsrrsp) {
+       rr_ns *nsrr, *nsrr_n;
+
+       /* Go and get the A RRs for each empty NS RR on our list. */
+       for (nsrr = ISC_LIST_HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
+               u_char resp[NS_PACKETSZ];
+               ns_msg msg;
+               int n;
+
+               nsrr_n = ISC_LIST_NEXT(nsrr, link);
+
+               if (ISC_LIST_EMPTY(nsrr->addrs)) {
+                       n = do_query(statp, nsrr->name, class, ns_t_a,
+                                    resp, &msg);
+                       if (n < 0) {
+                               DPRINTF(("get_glue: do_query('%s', %s') failed",
+                                        nsrr->name, p_class(class)));
+                               return (-1);
+                       }
+                       if (n > 0) {
+                               DPRINTF((
+                       "get_glue: do_query('%s', %s') CNAME or DNAME found",
+                                        nsrr->name, p_class(class)));
+                       }
+                       if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
+                                  &nsrr->addrs) < 0) {
+                               DPRINTF(("get_glue: save_r('%s', %s) failed",
+                                        nsrr->name, p_class(class)));
+                               return (-1);
+                       }
+                       /* If it's still empty, it's just chaff. */
+                       if (ISC_LIST_EMPTY(nsrr->addrs)) {
+                               DPRINTF(("get_glue: removing empty '%s' NS",
+                                        nsrr->name));
+                               free_nsrr(nsrrsp, nsrr);
+                       }
+               }
+       }
+       return (0);
+}
+
+static int
+save_ns(res_state statp, ns_msg *msg, ns_sect sect,
+       const char *owner, ns_class class,
+       rrset_ns *nsrrsp)
+{
+       int i;
+
+       for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+               char tname[MAXDNAME];
+               const u_char *rdata;
+               rr_ns *nsrr;
+               ns_rr rr;
+               int rdlen;
+
+               if (ns_parserr(msg, sect, i, &rr) < 0) {
+                       DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
+                                p_section(sect, ns_o_query), i));
+                       return (-1);
+               }
+               if (ns_rr_type(rr) != ns_t_ns ||
+                   ns_rr_class(rr) != class ||
+                   ns_samename(ns_rr_name(rr), owner) != 1)
+                       continue;
+               nsrr = find_ns(nsrrsp, ns_rr_name(rr));
+               if (nsrr == NULL) {
+                       nsrr = malloc(sizeof *nsrr);
+                       if (nsrr == NULL) {
+                               DPRINTF(("save_ns: malloc failed"));
+                               return (-1);
+                       }
+                       rdata = ns_rr_rdata(rr);
+                       rdlen = ns_rr_rdlen(rr);
+                       if (ns_name_uncompress(ns_msg_base(*msg),
+                                              ns_msg_end(*msg), rdata,
+                                              tname, sizeof tname) < 0) {
+                               DPRINTF(("save_ns: ns_name_uncompress failed"));
+                               free(nsrr);
+                               return (-1);
+                       }
+                       nsrr->name = strdup(tname);
+                       if (nsrr->name == NULL) {
+                               DPRINTF(("save_ns: strdup failed"));
+                               free(nsrr);
+                               return (-1);
+                       }
+                       ISC_LIST_INIT(nsrr->addrs);
+                       ISC_LIST_APPEND(*nsrrsp, nsrr, link);
+               }
+               if (save_a(statp, msg, ns_s_ar,
+                          nsrr->name, class, &nsrr->addrs) < 0) {
+                       DPRINTF(("save_ns: save_r('%s', %s) failed",
+                                nsrr->name, p_class(class)));
+                       return (-1);
+               }
+       }
+       return (0);
+}
+
+static int
+save_a(res_state statp, ns_msg *msg, ns_sect sect,
+       const char *owner, ns_class class,
+       rrset_a *arrsp)
+{
+       int i;
+
+       for (i = 0; i < ns_msg_count(*msg, sect); i++) {
+               ns_rr rr;
+               rr_a *arr;
+
+               if (ns_parserr(msg, sect, i, &rr) < 0) {
+                       DPRINTF(("save_a: ns_parserr(%s, %d) failed",
+                                p_section(sect, ns_o_query), i));
+                       return (-1);
+               }
+               if (ns_rr_type(rr) != ns_t_a ||
+                   ns_rr_class(rr) != class ||
+                   ns_samename(ns_rr_name(rr), owner) != 1 ||
+                   ns_rr_rdlen(rr) != NS_INADDRSZ)
+                       continue;
+               arr = malloc(sizeof *arr);
+               if (arr == NULL) {
+                       DPRINTF(("save_a: malloc failed"));
+                       return (-1);
+               }
+               memcpy(&arr->addr, ns_rr_rdata(rr), NS_INADDRSZ);
+               ISC_LIST_APPEND(*arrsp, arr, link);
+       }
+       return (0);
+}
+
+static void
+free_nsrrset(rrset_ns *nsrrsp) {
+       rr_ns *nsrr;
+
+       while ((nsrr = ISC_LIST_HEAD(*nsrrsp)) != NULL)
+               free_nsrr(nsrrsp, nsrr);
+}
+
+static void
+free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
+       rr_a *arr;
+
+       while ((arr = ISC_LIST_HEAD(nsrr->addrs)) != NULL) {
+               ISC_LIST_UNLINK(nsrr->addrs, arr, link);
+               free(arr);
+       }
+       free((char *)nsrr->name);
+       ISC_LIST_UNLINK(*nsrrsp, nsrr, link);
+       free(nsrr);
+}
+
+static rr_ns *
+find_ns(rrset_ns *nsrrsp, const char *dname) {
+       rr_ns *nsrr;
+
+       for (nsrr = ISC_LIST_HEAD(*nsrrsp);
+            nsrr != NULL; nsrr = ISC_LIST_NEXT(nsrr, link))
+               if (ns_samename(nsrr->name, dname) == 1)
+                       return (nsrr);
+       return (NULL);
+}
+
+static int
+do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
+        u_char *resp, ns_msg *msg)
+{
+       u_char req[NS_PACKETSZ];
+       int i;
+       unsigned n;
+
+       n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
+                        NULL, 0, NULL, req, NS_PACKETSZ);
+       if (n < 0) {
+               DPRINTF(("do_query: res_nmkquery failed"));
+               return (-1);
+       }
+       n = res_nsend(statp, req, n, resp, NS_PACKETSZ);
+       if (n < 0) {
+               DPRINTF(("do_query: res_nsend failed"));
+               return (-1);
+       }
+       if (n == 0) {
+               DPRINTF(("do_query: res_nsend returned 0"));
+               errno = EMSGSIZE;
+               return (-1);
+       }
+       if (ns_initparse(resp, n, msg) < 0) {
+               DPRINTF(("do_query: ns_initparse failed"));
+               return (-1);
+       }
+       n = 0;
+       for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
+               ns_rr rr;
+
+               if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
+                       DPRINTF(("do_query: ns_parserr failed"));
+                       return (-1);
+               }
+               n += (ns_rr_class(rr) == class &&
+                     (ns_rr_type(rr) == ns_t_cname ||
+                      ns_rr_type(rr) == ns_t_dname));
+       }
+       return (n);
+}
+
+static void
+dprintf(const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs(";; res_findzonecut: ", stderr);
+       vfprintf(stderr, fmt, ap);
+       fputc('\n', stderr);
+       va_end(ap);
+}
diff --git a/minires/res_init.c b/minires/res_init.c
new file mode 100644 (file)
index 0000000..6cb7b37
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 1985, 1989, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_init.c   8.1 (Berkeley) 6/7/93";
+static const char rcsid[] = "$Id: res_init.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+/* Options.  Should all be left alone. */
+#define RESOLVSORT
+#define RFC1535
+#define DEBUG
+
+static void res_setoptions __P((res_state, const char *, const char *));
+
+#ifdef RESOLVSORT
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+static u_int32_t net_mask __P((struct in_addr));
+#endif
+
+#if !defined(isascii)  /* XXX - could be a function */
+# define isascii(c) (!(c & 0200))
+#endif
+
+/*
+ * Resolver state default settings.
+ */
+
+/*
+ * Set up default settings.  If the configuration file exist, the values
+ * there will have precedence.  Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server.  It
+ * was later decided that since the recommended practice is to always 
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain.  If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+extern int __res_vinit(res_state, int);
+
+int
+res_ninit(res_state statp) {
+
+       return (__res_vinit(statp, 0));
+}
+
+/* This function has to be reachable by res_data.c but not publically. */
+int
+__res_vinit(res_state statp, int preinit) {
+       register FILE *fp;
+       register char *cp, **pp;
+       register int n;
+       char buf[BUFSIZ];
+       int nserv = 0;    /* number of nameserver records read from file */
+       int haveenv = 0;
+       int havesearch = 0;
+#ifdef RESOLVSORT
+       int nsort = 0;
+       char *net;
+#endif
+#ifndef RFC1535
+       int dots;
+#endif
+
+       if (!preinit) {
+               statp->retrans = RES_TIMEOUT;
+               statp->retry = RES_DFLRETRY;
+               statp->options = RES_DEFAULT;
+               statp->id = res_randomid();
+       }
+
+#ifdef USELOOPBACK
+       statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
+#else
+       statp->nsaddr.sin_addr.s_addr = INADDR_ANY;
+#endif
+       statp->nsaddr.sin_family = AF_INET;
+       statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
+       statp->nscount = 1;
+       statp->ndots = 1;
+       statp->pfcode = 0;
+       statp->_sock = -1;
+       statp->_flags = 0;
+       statp->qhook = NULL;
+       statp->rhook = NULL;
+
+       /* Allow user to override the local domain definition */
+       if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+               (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+               statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+               haveenv++;
+
+               /*
+                * Set search list to be blank-separated strings
+                * from rest of env value.  Permits users of LOCALDOMAIN
+                * to still have a search list, and anyone to set the
+                * one that they want to use as an individual (even more
+                * important now that the rfc1535 stuff restricts searches)
+                */
+               cp = statp->defdname;
+               pp = statp->dnsrch;
+               *pp++ = cp;
+               for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+                       if (*cp == '\n')        /* silly backwards compat */
+                               break;
+                       else if (*cp == ' ' || *cp == '\t') {
+                               *cp = 0;
+                               n = 1;
+                       } else if (n) {
+                               *pp++ = cp;
+                               n = 0;
+                               havesearch = 1;
+                       }
+               }
+               /* null terminate last domain if there are excess */
+               while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
+                       cp++;
+               *cp = '\0';
+               *pp++ = 0;
+       }
+
+#define        MATCH(line, name) \
+       (!strncmp(line, name, sizeof(name) - 1) && \
+       (line[sizeof(name) - 1] == ' ' || \
+        line[sizeof(name) - 1] == '\t'))
+
+       if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+           /* read the config file */
+           while (fgets(buf, sizeof(buf), fp) != NULL) {
+               /* skip comments */
+               if (*buf == ';' || *buf == '#')
+                       continue;
+               /* read default domain name */
+               if (MATCH(buf, "domain")) {
+                   if (haveenv)        /* skip if have from environ */
+                           continue;
+                   cp = buf + sizeof("domain") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+                   statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+                   if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
+                           *cp = '\0';
+                   havesearch = 0;
+                   continue;
+               }
+               /* set search list */
+               if (MATCH(buf, "search")) {
+                   if (haveenv)        /* skip if have from environ */
+                           continue;
+                   cp = buf + sizeof("search") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
+                   statp->defdname[sizeof(statp->defdname) - 1] = '\0';
+                   if ((cp = strchr(statp->defdname, '\n')) != NULL)
+                           *cp = '\0';
+                   /*
+                    * Set search list to be blank-separated strings
+                    * on rest of line.
+                    */
+                   cp = statp->defdname;
+                   pp = statp->dnsrch;
+                   *pp++ = cp;
+                   for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
+                           if (*cp == ' ' || *cp == '\t') {
+                                   *cp = 0;
+                                   n = 1;
+                           } else if (n) {
+                                   *pp++ = cp;
+                                   n = 0;
+                           }
+                   }
+                   /* null terminate last domain if there are excess */
+                   while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+                           cp++;
+                   *cp = '\0';
+                   *pp++ = 0;
+                   havesearch = 1;
+                   continue;
+               }
+               /* read nameservers to query */
+               if (MATCH(buf, "nameserver") && nserv < MAXNS) {
+                   struct in_addr a;
+
+                   cp = buf + sizeof("nameserver") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                       cp++;
+                   if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) {
+                       statp->nsaddr_list[nserv].sin_addr = a;
+                       statp->nsaddr_list[nserv].sin_family = AF_INET;
+                       statp->nsaddr_list[nserv].sin_port =
+                               htons(NAMESERVER_PORT);
+                       nserv++;
+                   }
+                   continue;
+               }
+#ifdef RESOLVSORT
+               if (MATCH(buf, "sortlist")) {
+                   struct in_addr a;
+
+                   cp = buf + sizeof("sortlist") - 1;
+                   while (nsort < MAXRESOLVSORT) {
+                       while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                       if (*cp == '\0' || *cp == '\n' || *cp == ';')
+                           break;
+                       net = cp;
+                       while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+                              isascii(*cp) && !isspace(*cp))
+                               cp++;
+                       n = *cp;
+                       *cp = 0;
+                       if (inet_aton(net, &a)) {
+                           statp->sort_list[nsort].addr = a;
+                           if (ISSORTMASK(n)) {
+                               *cp++ = n;
+                               net = cp;
+                               while (*cp && *cp != ';' &&
+                                       isascii(*cp) && !isspace(*cp))
+                                   cp++;
+                               n = *cp;
+                               *cp = 0;
+                               if (inet_aton(net, &a)) {
+                                   statp->sort_list[nsort].mask = a.s_addr;
+                               } else {
+                                   statp->sort_list[nsort].mask = 
+                                       net_mask(statp->sort_list[nsort].addr);
+                               }
+                           } else {
+                               statp->sort_list[nsort].mask = 
+                                   net_mask(statp->sort_list[nsort].addr);
+                           }
+                           nsort++;
+                       }
+                       *cp = n;
+                   }
+                   continue;
+               }
+#endif
+               if (MATCH(buf, "options")) {
+                   res_setoptions(statp, buf + sizeof("options") - 1, "conf");
+                   continue;
+               }
+           }
+           if (nserv > 1) 
+               statp->nscount = nserv;
+#ifdef RESOLVSORT
+           statp->nsort = nsort;
+#endif
+           (void) fclose(fp);
+       }
+       if (statp->defdname[0] == 0 &&
+           gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
+           (cp = strchr(buf, '.')) != NULL)
+               strcpy(statp->defdname, cp + 1);
+
+       /* find components of local domain that might be searched */
+       if (havesearch == 0) {
+               pp = statp->dnsrch;
+               *pp++ = statp->defdname;
+               *pp = NULL;
+
+#ifndef RFC1535
+               dots = 0;
+               for (cp = statp->defdname; *cp; cp++)
+                       dots += (*cp == '.');
+
+               cp = statp->defdname;
+               while (pp < statp->dnsrch + MAXDFLSRCH) {
+                       if (dots < LOCALDOMAINPARTS)
+                               break;
+                       cp = strchr(cp, '.') + 1;    /* we know there is one */
+                       *pp++ = cp;
+                       dots--;
+               }
+               *pp = NULL;
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG) {
+                       printf(";; res_init()... default dnsrch list:\n");
+                       for (pp = statp->dnsrch; *pp; pp++)
+                               printf(";;\t%s\n", *pp);
+                       printf(";;\t..END..\n");
+               }
+#endif
+#endif /* !RFC1535 */
+       }
+
+       if ((cp = getenv("RES_OPTIONS")) != NULL)
+               res_setoptions(statp, cp, "env");
+       statp->options |= RES_INIT;
+       return (0);
+}
+
+static void
+res_setoptions(res_state statp, const char *options, const char *source) {
+       const char *cp = options;
+       int i;
+
+#ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+               printf(";; res_setoptions(\"%s\", \"%s\")...\n",
+                      options, source);
+#endif
+       while (*cp) {
+               /* skip leading and inner runs of spaces */
+               while (*cp == ' ' || *cp == '\t')
+                       cp++;
+               /* search for and process individual options */
+               if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
+                       i = atoi(cp + sizeof("ndots:") - 1);
+                       if (i <= RES_MAXNDOTS)
+                               statp->ndots = i;
+                       else
+                               statp->ndots = RES_MAXNDOTS;
+#ifdef DEBUG
+                       if (statp->options & RES_DEBUG)
+                               printf(";;\tndots=%d\n", statp->ndots);
+#endif
+               } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
+                       i = atoi(cp + sizeof("timeout:") - 1);
+                       if (i <= RES_MAXRETRANS)
+                               statp->retrans = i;
+                       else
+                               statp->retrans = RES_MAXRETRANS;
+               } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
+                       i = atoi(cp + sizeof("attempts:") - 1);
+                       if (i <= RES_MAXRETRY)
+                               statp->retry = i;
+                       else
+                               statp->retry = RES_MAXRETRY;
+               } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
+#ifdef DEBUG
+                       if (!(statp->options & RES_DEBUG)) {
+                               printf(";; res_setoptions(\"%s\", \"%s\")..\n",
+                                      options, source);
+                               statp->options |= RES_DEBUG;
+                       }
+                       printf(";;\tdebug\n");
+#endif
+               } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
+                       statp->options |= RES_USE_INET6;
+               } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
+                       statp->options |= RES_ROTATE;
+               } else if (!strncmp(cp, "no-check-names",
+                                   sizeof("no-check-names") - 1)) {
+                       statp->options |= RES_NOCHECKNAME;
+               } else {
+                       /* XXX - print a warning here? */
+               }
+               /* skip to next run of spaces */
+               while (*cp && *cp != ' ' && *cp != '\t')
+                       cp++;
+       }
+}
+
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+net_mask(in)           /* XXX - should really use system's version of this */
+       struct in_addr in;
+{
+       register u_int32_t i = ntohl(in.s_addr);
+
+       if (IN_CLASSA(i))
+               return (htonl(IN_CLASSA_NET));
+       else if (IN_CLASSB(i))
+               return (htonl(IN_CLASSB_NET));
+       return (htonl(IN_CLASSC_NET));
+}
+#endif
+
+u_int
+res_randomid(void) {
+       struct timeval now;
+
+       gettimeofday(&now, NULL);
+       return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
+}
diff --git a/minires/res_mkquery.c b/minires/res_mkquery.c
new file mode 100644 (file)
index 0000000..77ed890
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1985, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_mkquery.c        8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_mkquery.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "minires/minires.h"
+#include "arpa/nameser.h"
+
+extern const char *_res_opcodes[];
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+int
+res_nmkquery(res_state statp,
+            int op,                    /* opcode of query */
+            const char *dname,         /* domain name */
+            ns_class class, ns_class type,     /* class and type of query */
+            const u_char *data,        /* resource record data */
+            unsigned datalen,          /* length of data */
+            const u_char *newrr_in,    /* new rr for modify or append */
+            u_char *buf,               /* buffer to put query */
+            unsigned buflen)           /* size of buffer */
+{
+       register HEADER *hp;
+       register u_char *cp;
+       register int n;
+       u_char *dnptrs[20], **dpp, **lastdnptr;
+
+       /*
+        * Initialize header fields.
+        */
+       if ((buf == NULL) || (buflen < HFIXEDSZ))
+               return (-1);
+       memset(buf, 0, HFIXEDSZ);
+       hp = (HEADER *) buf;
+       hp->id = htons(++statp->id);
+       hp->opcode = op;
+       hp->rd = (statp->options & RES_RECURSE) != 0;
+       hp->rcode = NOERROR;
+       cp = buf + HFIXEDSZ;
+       buflen -= HFIXEDSZ;
+       dpp = dnptrs;
+       *dpp++ = buf;
+       *dpp++ = NULL;
+       lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+       /*
+        * perform opcode specific processing
+        */
+       switch (op) {
+       case QUERY:     /*FALLTHROUGH*/
+       case NS_NOTIFY_OP:
+               if ((buflen -= QFIXEDSZ) < 0)
+                       return (-1);
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               buflen -= n;
+               putUShort(cp, type);
+               cp += INT16SZ;
+               putUShort(cp, class);
+               cp += INT16SZ;
+               hp->qdcount = htons(1);
+               if (op == QUERY || data == NULL)
+                       break;
+               /*
+                * Make an additional record for completion domain.
+                */
+               buflen -= RRFIXEDSZ;
+               n = dn_comp((const char *)data, cp, buflen, dnptrs, lastdnptr);
+               if (n < 0)
+                       return (-1);
+               cp += n;
+               buflen -= n;
+               putUShort(cp, T_NULL);
+               cp += INT16SZ;
+               putUShort(cp, class);
+               cp += INT16SZ;
+               putULong(cp, 0);
+               cp += INT32SZ;
+               putUShort(cp, 0);
+               cp += INT16SZ;
+               hp->arcount = htons(1);
+               break;
+
+       case IQUERY:
+               /*
+                * Initialize answer section
+                */
+               if (buflen < 1 + RRFIXEDSZ + datalen)
+                       return (-1);
+               *cp++ = '\0';   /* no domain name */
+               putUShort(cp, type);
+               cp += INT16SZ;
+               putUShort(cp, class);
+               cp += INT16SZ;
+               putULong(cp, 0);
+               cp += INT32SZ;
+               putUShort(cp, datalen);
+               cp += INT16SZ;
+               if (datalen) {
+                       memcpy(cp, data, datalen);
+                       cp += datalen;
+               }
+               hp->ancount = htons(1);
+               break;
+
+       default:
+               return (-1);
+       }
+       return (cp - buf);
+}
diff --git a/minires/res_mkupdate.c b/minires/res_mkupdate.c
new file mode 100644 (file)
index 0000000..3f78e2a
--- /dev/null
@@ -0,0 +1,1096 @@
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_mkupdate.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include "arpa/nameser.h"
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "minires/minires.h"
+
+/* Options.  Leave them on. */
+#define DEBUG
+#define MAXPORT 1024
+
+static int getnum_str(u_char **, u_char *);
+static int gethexnum_str(u_char **, u_char *);
+static int getword_str(char *, int, u_char **, u_char *);
+static int getstr_str(char *, int, u_char **, u_char *);
+
+struct valuelist {
+       struct valuelist *      next;
+       struct valuelist *      prev;
+       char *                  name;
+       char *                  proto;
+       int                     port;
+};
+
+static int findservice(const char *, struct valuelist **);
+static struct servent *cgetservbyport(unsigned, const char *);
+
+#define ShrinkBuffer(x)  if ((buflen -= x) < 0) return (-2);
+
+/* Forward. */
+
+int res_protocolnumber(const char *);
+int res_servicenumber(const char *);
+static struct protoent *cgetprotobynumber(int);
+
+/*
+ * Form update packets.
+ * Returns the size of the resulting packet if no error
+ * On error,
+ *     returns -1 if error in reading a word/number in rdata
+ *                portion for update packets
+ *             -2 if length of buffer passed is insufficient
+ *             -3 if zone section is not the first section in
+ *                the linked list, or section order has a problem
+ *             -4 on a number overflow
+ *             -5 unknown operation or no records
+ */
+int
+res_nmkupdate(res_state statp,
+             ns_updrec *rrecp_in, u_char *buf, unsigned buflen) {
+       ns_updrec *rrecp_start = rrecp_in;
+       HEADER *hp;
+       u_char *cp, *sp1, *sp2, *startp, *endp;
+       int i, soanum, multiline;
+       unsigned n;
+       ns_updrec *rrecp;
+       struct in_addr ina;
+       struct in6_addr in6a;
+        char buf2[MAXDNAME];
+       u_char buf3[MAXDNAME];
+       int section, numrrs = 0, counts[ns_s_max];
+       u_int16_t rtype, rclass;
+       u_int32_t n1, rttl;
+       u_char *dnptrs[20], **dpp, **lastdnptr;
+       unsigned siglen, keylen, certlen;
+
+       /*
+        * Initialize header fields.
+        */
+       if ((buf == NULL) || (buflen < HFIXEDSZ))
+               return (-1);
+       memset(buf, 0, HFIXEDSZ);
+       hp = (HEADER *) buf;
+       hp->id = htons(++statp->id);
+       hp->opcode = ns_o_update;
+       hp->rcode = NOERROR;
+       sp1 = buf + 2*INT16SZ;  /* save pointer to zocount */
+       cp = buf + HFIXEDSZ;
+       buflen -= HFIXEDSZ;
+       dpp = dnptrs;
+       *dpp++ = buf;
+       *dpp++ = NULL;
+       lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+       if (rrecp_start == NULL)
+               return (-5);
+       else if (rrecp_start->r_section != S_ZONE)
+               return (-3);
+
+       memset(counts, 0, sizeof counts);
+       for (rrecp = rrecp_start; rrecp; rrecp = ISC_LIST_NEXT(rrecp,
+                                                              r_glink)) {
+               numrrs++;
+                section = rrecp->r_section;
+               if (section < 0 || section >= ns_s_max)
+                       return (-1);
+               counts[section]++;
+               for (i = section + 1; i < ns_s_max; i++)
+                       if (counts[i])
+                               return (-3);
+               rtype = rrecp->r_type;
+               rclass = rrecp->r_class;
+               rttl = rrecp->r_ttl;
+               /* overload class and type */
+               if (section == S_PREREQ) {
+                       rttl = 0;
+                       switch (rrecp->r_opcode) {
+                       case YXDOMAIN:
+                               rclass = C_ANY;
+                               rtype = T_ANY;
+                               rrecp->r_size = 0;
+                               break;
+                       case NXDOMAIN:
+                               rclass = C_NONE;
+                               rtype = T_ANY;
+                               rrecp->r_size = 0;
+                               break;
+                       case NXRRSET:
+                               rclass = C_NONE;
+                               rrecp->r_size = 0;
+                               break;
+                       case YXRRSET:
+                               if (rrecp->r_size == 0)
+                                       rclass = C_ANY;
+                               break;
+                       default:
+                               fprintf(stderr,
+                                       "res_mkupdate: incorrect opcode: %d\n",
+                                       rrecp->r_opcode);
+                               fflush(stderr);
+                               return (-1);
+                       }
+               } else if (section == S_UPDATE) {
+                       switch (rrecp->r_opcode) {
+                       case DELETE:
+                               rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
+                               break;
+                       case ADD:
+                               break;
+                       default:
+                               fprintf(stderr,
+                                       "res_mkupdate: incorrect opcode: %d\n",
+                                       rrecp->r_opcode);
+                               fflush(stderr);
+                               return (-1);
+                       }
+               }
+
+               /*
+                * XXX  appending default domain to owner name is omitted,
+                *      fqdn must be provided
+                */
+               if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
+                                lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               ShrinkBuffer(n + 2*INT16SZ);
+               PUTSHORT(rtype, cp);
+               PUTSHORT(rclass, cp);
+               if (section == S_ZONE) {
+                       if (numrrs != 1 || rrecp->r_type != T_SOA)
+                               return (-3);
+                       continue;
+               }
+               ShrinkBuffer(INT32SZ + INT16SZ);
+               PUTLONG(rttl, cp);
+               sp2 = cp;  /* save pointer to length byte */
+               cp += INT16SZ;
+               if (rrecp->r_size == 0) {
+                       if (section == S_UPDATE && rclass != C_ANY)
+                               return (-1);
+                       else {
+                               PUTSHORT(0, sp2);
+                               continue;
+                       }
+               }
+               startp = rrecp->r_data;
+               endp = startp + rrecp->r_size - 1;
+               /* XXX this should be done centrally. */
+               switch (rrecp->r_type) {
+               case T_A:
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       if (!inet_aton(buf2, &ina))
+                               return (-1);
+                       n1 = ntohl(ina.s_addr);
+                       ShrinkBuffer(INT32SZ);
+                       PUTLONG(n1, cp);
+                       break;
+               case T_CNAME:
+               case T_MB:
+               case T_MG:
+               case T_MR:
+               case T_NS:
+               case T_PTR:
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+                       if (n < 0)
+                               return (-1);
+                       cp += n;
+                       ShrinkBuffer(n);
+                       break;
+               case T_MINFO:
+               case T_SOA:
+               case T_RP:
+                       for (i = 0; i < 2; i++) {
+                               if (!getword_str(buf2, sizeof buf2, &startp,
+                                                endp))
+                               return (-1);
+                               n = dn_comp(buf2, cp, buflen,
+                                           dnptrs, lastdnptr);
+                               if (n < 0)
+                                       return (-1);
+                               cp += n;
+                               ShrinkBuffer(n);
+                       }
+                       if (rrecp->r_type == T_SOA) {
+                               ShrinkBuffer(5 * INT32SZ);
+                               while (isspace(*startp) || !*startp)
+                                       startp++;
+                               if (*startp == '(') {
+                                       multiline = 1;
+                                       startp++;
+                               } else
+                                       multiline = 0;
+                               /* serial, refresh, retry, expire, minimum */
+                               for (i = 0; i < 5; i++) {
+                                       soanum = getnum_str(&startp, endp);
+                                       if (soanum < 0)
+                                               return (-1);
+                                       PUTLONG(soanum, cp);
+                               }
+                               if (multiline) {
+                                       while (isspace(*startp) || !*startp)
+                                               startp++;
+                                       if (*startp != ')')
+                                               return (-1);
+                               }
+                       }
+                       break;
+               case T_MX:
+               case T_AFSDB:
+               case T_RT:
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+                       if (n < 0)
+                               return (-1);
+                       cp += n;
+                       ShrinkBuffer(n);
+                       break;
+               case T_SRV:
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+                       if (n < 0)
+                               return (-1);
+                       cp += n;
+                       ShrinkBuffer(n);
+                       break;
+               case T_PX:
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       PUTSHORT(n, cp);
+                       ShrinkBuffer(INT16SZ);
+                       for (i = 0; i < 2; i++) {
+                               if (!getword_str(buf2, sizeof buf2, &startp,
+                                                endp))
+                                       return (-1);
+                               n = dn_comp(buf2, cp, buflen, dnptrs,
+                                           lastdnptr);
+                               if (n < 0)
+                                       return (-1);
+                               cp += n;
+                               ShrinkBuffer(n);
+                       }
+                       break;
+               case T_WKS: {
+                       char bm[MAXPORT/8];
+                       unsigned maxbm = 0;
+
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       if (!inet_aton(buf2, &ina))
+                               return (-1);
+                       n1 = ntohl(ina.s_addr);
+                       ShrinkBuffer(INT32SZ);
+                       PUTLONG(n1, cp);
+
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       if ((i = res_protocolnumber(buf2)) < 0)
+                               return (-1);
+                       ShrinkBuffer(1);
+                       *cp++ = i & 0xff;
+                        
+                       for (i = 0; i < MAXPORT/8 ; i++)
+                               bm[i] = 0;
+
+                       while (getword_str(buf2, sizeof buf2, &startp, endp)) {
+                               if ((n1 = res_servicenumber(buf2)) <= 0)
+                                       return (-1);
+
+                               if (n1 < MAXPORT) {
+                                       bm[n1/8] |= (0x80>>(n1%8));
+                                       if (n1 > maxbm)
+                                               maxbm = n1;
+                               } else
+                                       return (-1);
+                       }
+                       maxbm = maxbm/8 + 1;
+                       ShrinkBuffer(maxbm);
+                       memcpy(cp, bm, maxbm);
+                       cp += maxbm;
+                       break;
+               }
+               case T_HINFO:
+                       for (i = 0; i < 2; i++) {
+                               if ((n = getstr_str(buf2, sizeof buf2,
+                                               &startp, endp)) < 0)
+                                       return (-1);
+                               if (n > 255)
+                                       return (-1);
+                               ShrinkBuffer(n+1);
+                               *cp++ = n;
+                               memcpy(cp, buf2, n);
+                               cp += n;
+                       }
+                       break;
+               case T_TXT:
+                       while (1) {
+                               if ((n = getstr_str(buf2, sizeof buf2,
+                                               &startp, endp)) < 0) {
+                                       if (cp != (sp2 + INT16SZ))
+                                               break;
+                                       return (-1);
+                               }
+                               if (n > 255)
+                                       return (-1);
+                               ShrinkBuffer(n+1);
+                               *cp++ = n;
+                               memcpy(cp, buf2, n);
+                               cp += n;
+                       }
+                       break;
+               case T_X25:
+                       /* RFC 1183 */
+                       if ((n = getstr_str(buf2, sizeof buf2, &startp,
+                                        endp)) < 0)
+                               return (-1);
+                       if (n > 255)
+                               return (-1);
+                       ShrinkBuffer(n+1);
+                       *cp++ = n;
+                       memcpy(cp, buf2, n);
+                       cp += n;
+                       break;
+               case T_ISDN:
+                       /* RFC 1183 */
+                       if ((n = getstr_str(buf2, sizeof buf2, &startp,
+                                        endp)) < 0)
+                               return (-1);
+                       if ((n > 255) || (n == 0))
+                               return (-1);
+                       ShrinkBuffer(n+1);
+                       *cp++ = n;
+                       memcpy(cp, buf2, n);
+                       cp += n;
+                       if ((n = getstr_str(buf2, sizeof buf2, &startp,
+                                        endp)) < 0)
+                               n = 0;
+                       if (n > 255)
+                               return (-1);
+                       ShrinkBuffer(n+1);
+                       *cp++ = n;
+                       memcpy(cp, buf2, n);
+                       cp += n;
+                       break;
+               case T_NSAP:
+                       if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
+                               ShrinkBuffer(n);
+                               memcpy(cp, buf2, n);
+                               cp += n;
+                       } else {
+                               return (-1);
+                       }
+                       break;
+#if 0
+               case T_LOC:
+                       if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
+                               ShrinkBuffer(n);
+                               memcpy(cp, buf2, n);
+                               cp += n;
+                       } else
+                               return (-1);
+                       break;
+               case ns_t_sig:
+                   {
+                       int sig_type, success, dateerror;
+                       u_int32_t exptime, timesigned;
+
+                       /* type */
+                       if ((n = getword_str(buf2, sizeof buf2,
+                                            &startp, endp)) < 0)
+                               return (-1);
+                       sig_type = sym_ston(__p_type_syms, buf2, &success);
+                       if (!success || sig_type == ns_t_any)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(sig_type, cp);
+                       /* alg */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(1);
+                       *cp++ = n;
+                       /* labels */
+                       n = getnum_str(&startp, endp);
+                       if (n <= 0 || n > 255)
+                               return (-1);
+                       ShrinkBuffer(1);
+                       *cp++ = n;
+                       /* ottl  & expire */
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       exptime = ns_datetosecs(buf2, &dateerror);
+                       if (!dateerror) {
+                               ShrinkBuffer(INT32SZ);
+                               PUTLONG(rttl, cp);
+                       }
+                       else {
+                               char *ulendp;
+                               u_int32_t ottl;
+
+                               ottl = strtoul(buf2, &ulendp, 10);
+                               if (ulendp != NULL && *ulendp != '\0')
+                                       return (-1);
+                               ShrinkBuffer(INT32SZ);
+                               PUTLONG(ottl, cp);
+                               if (!getword_str(buf2, sizeof buf2, &startp,
+                                                endp))
+                                       return (-1);
+                               exptime = ns_datetosecs(buf2, &dateerror);
+                               if (dateerror)
+                                       return (-1);
+                       }
+                       /* expire */
+                       ShrinkBuffer(INT32SZ);
+                       PUTLONG(exptime, cp);
+                       /* timesigned */
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       timesigned = ns_datetosecs(buf2, &dateerror);
+                       if (!dateerror) {
+                               ShrinkBuffer(INT32SZ);
+                               PUTLONG(timesigned, cp);
+                       }
+                       else
+                               return (-1);
+                       /* footprint */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+                       /* signer name */
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+                       if (n < 0)
+                               return (-1);
+                       cp += n;
+                       ShrinkBuffer(n);
+                       /* sig */
+                       if ((n = getword_str(buf2, sizeof buf2,
+                                            &startp, endp)) < 0)
+                               return (-1);
+                       siglen = b64_pton(buf2, buf3, sizeof(buf3));
+                       if (siglen < 0)
+                               return (-1);
+                       ShrinkBuffer(siglen);
+                       memcpy(cp, buf3, siglen);
+                       cp += siglen;
+                       break;
+                   }
+               case ns_t_key:
+                       /* flags */
+                       n = gethexnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+                       /* proto */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(1);
+                       *cp++ = n;
+                       /* alg */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(1);
+                       *cp++ = n;
+                       /* key */
+                       if ((n = getword_str(buf2, sizeof buf2,
+                                            &startp, endp)) < 0)
+                               return (-1);
+                       keylen = b64_pton(buf2, buf3, sizeof(buf3));
+                       if (keylen < 0)
+                               return (-1);
+                       ShrinkBuffer(keylen);
+                       memcpy(cp, buf3, keylen);
+                       cp += keylen;
+                       break;
+               case ns_t_nxt:
+                   {
+                       int success, nxt_type;
+                       u_char data[32];
+                       int maxtype;
+
+                       /* next name */
+                       if (!getword_str(buf2, sizeof buf2, &startp, endp))
+                               return (-1);
+                       n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
+                       if (n < 0)
+                               return (-1);
+                       cp += n;
+                       ShrinkBuffer(n);
+                       maxtype = 0;
+                       memset(data, 0, sizeof data);
+                       while (1) {
+                               if (!getword_str(buf2, sizeof buf2, &startp,
+                                                endp))
+                                       break;
+                               nxt_type = sym_ston(__p_type_syms, buf2,
+                                                   &success);
+                               if (!success || !ns_t_rr_p(nxt_type))
+                                       return (-1);
+                               NS_NXT_BIT_SET(nxt_type, data);
+                               if (nxt_type > maxtype)
+                                       maxtype = nxt_type;
+                       }
+                       n = maxtype/NS_NXT_BITS+1;
+                       ShrinkBuffer(n);
+                       memcpy(cp, data, n);
+                       cp += n;
+                       break;
+                   }
+               case ns_t_cert:
+                       /* type */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+                       /* key tag */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(INT16SZ);
+                       PUTSHORT(n, cp);
+                       /* alg */
+                       n = getnum_str(&startp, endp);
+                       if (n < 0)
+                               return (-1);
+                       ShrinkBuffer(1);
+                       *cp++ = n;
+                       /* cert */
+                       if ((n = getword_str(buf2, sizeof buf2,
+                                            &startp, endp)) < 0)
+                               return (-1);
+                       certlen = b64_pton(buf2, buf3, sizeof(buf3));
+                       if (certlen < 0)
+                               return (-1);
+                       ShrinkBuffer(certlen);
+                       memcpy(cp, buf3, certlen);
+                       cp += certlen;
+                       break;
+#endif
+               default:
+                       return (-1);
+               } /*switch*/
+               n = (u_int16_t)((cp - sp2) - INT16SZ);
+               PUTSHORT(n, sp2);
+       } /*for*/
+               
+       hp->qdcount = htons(counts[0]);
+       hp->ancount = htons(counts[1]);
+       hp->nscount = htons(counts[2]);
+       hp->arcount = htons(counts[3]);
+       return (cp - buf);
+}
+
+/*
+ * Get a whitespace delimited word from a string (not file)
+ * into buf. modify the start pointer to point after the
+ * word in the string.
+ */
+static int
+getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
+        char *cp;
+        int c;
+        for (cp = buf; *startpp <= endp; ) {
+                c = **startpp;
+                if (isspace(c) || c == '\0') {
+                        if (cp != buf) /* trailing whitespace */
+                                break;
+                        else { /* leading whitespace */
+                                (*startpp)++;
+                                continue;
+                        }
+                }
+                (*startpp)++;
+                if (cp >= buf+size-1)
+                        break;
+                *cp++ = (u_char)c;
+        }
+        *cp = '\0';
+        return (cp != buf);
+}
+
+/*
+ * get a white spae delimited string from memory.  Process quoted strings
+ * and \DDD escapes.  Return length or -1 on error.  Returned string may
+ * contain nulls.
+ */
+static char digits[] = "0123456789";
+static int
+getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
+        char *cp;
+        int c, c1 = 0;
+       int inquote = 0;
+       int seen_quote = 0;
+       int escape = 0;
+       int dig = 0;
+       for (cp = buf; *startpp <= endp; ) {
+                if ((c = **startpp) == '\0')
+                       break;
+               /* leading white space */
+               if ((cp == buf) && !seen_quote && isspace(c)) {
+                       (*startpp)++;
+                       continue;
+               }
+
+               switch (c) {
+               case '\\':
+                       if (!escape)  {
+                               escape = 1;
+                               dig = 0;
+                               c1 = 0;
+                               (*startpp)++;
+                               continue;
+                       } 
+                       goto do_escape;
+               case '"':
+                       if (!escape) {
+                               inquote = !inquote;
+                               seen_quote = 1;
+                               (*startpp)++;
+                               continue;
+                       }
+                       /* fall through */
+               default:
+               do_escape:
+                       if (escape) {
+                               switch (c) {
+                               case '0':
+                               case '1':
+                               case '2':
+                               case '3':
+                               case '4':
+                               case '5':
+                               case '6':
+                               case '7':
+                               case '8':
+                               case '9':
+                                       c1 = c1 * 10 + 
+                                               (strchr(digits, c) - digits);
+
+                                       if (++dig == 3) {
+                                               c = c1 &0xff;
+                                               break;
+                                       }
+                                       (*startpp)++;
+                                       continue;
+                               }
+                               escape = 0;
+                       } else if (!inquote && isspace(c))
+                               goto done;
+                       if (cp >= buf+size-1)
+                               goto done;
+                       *cp++ = (u_char)c;
+                       (*startpp)++;
+               }
+       }
+ done:
+       *cp = '\0';
+       return ((cp == buf)?  (seen_quote? 0: -1): (cp - buf));
+}
+/*
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+gethexnum_str(u_char **startpp, u_char *endp) {
+        int c, n;
+        int seendigit = 0;
+        int m = 0;
+
+       if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
+               return getnum_str(startpp, endp);
+       (*startpp)+=2;
+        for (n = 0; *startpp <= endp; ) {
+                c = **startpp;
+                if (isspace(c) || c == '\0') {
+                        if (seendigit) /* trailing whitespace */
+                                break;
+                        else { /* leading whitespace */
+                                (*startpp)++;
+                                continue;
+                        }
+                }
+                if (c == ';') {
+                        while ((*startpp <= endp) &&
+                              ((c = **startpp) != '\n'))
+                                       (*startpp)++;
+                        if (seendigit)
+                                break;
+                        continue;
+                }
+                if (!isxdigit(c)) {
+                        if (c == ')' && seendigit) {
+                                (*startpp)--;
+                                break;
+                        }
+                       return (-1);
+                }        
+                (*startpp)++;
+               if (isdigit(c))
+                       n = n * 16 + (c - '0');
+               else
+                       n = n * 16 + (tolower(c) - 'a' + 10);
+                seendigit = 1;
+        }
+        return (n + m);
+}
+
+/*
+ * Get a whitespace delimited base 16 number from a string (not file) into buf
+ * update the start pointer to point after the number in the string.
+ */
+static int
+getnum_str(u_char **startpp, u_char *endp) {
+        int c, n;
+        int seendigit = 0;
+        int m = 0;
+
+        for (n = 0; *startpp <= endp; ) {
+                c = **startpp;
+                if (isspace(c) || c == '\0') {
+                        if (seendigit) /* trailing whitespace */
+                                break;
+                        else { /* leading whitespace */
+                                (*startpp)++;
+                                continue;
+                        }
+                }
+                if (c == ';') {
+                        while ((*startpp <= endp) &&
+                              ((c = **startpp) != '\n'))
+                                       (*startpp)++;
+                        if (seendigit)
+                                break;
+                        continue;
+                }
+                if (!isdigit(c)) {
+                        if (c == ')' && seendigit) {
+                                (*startpp)--;
+                                break;
+                        }
+                       return (-1);
+                }        
+                (*startpp)++;
+                n = n * 10 + (c - '0');
+                seendigit = 1;
+        }
+        return (n + m);
+}
+
+/*
+ * Allocate a resource record buffer & save rr info.
+ */
+ns_updrec *
+res_mkupdrec(int section, const char *dname,
+            u_int class, u_int type, u_long ttl) {
+       ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
+
+       if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
+               if (rrecp)
+                       free((char *)rrecp);
+               return (NULL);
+       }
+       rrecp->r_class = class;
+       rrecp->r_type = type;
+       rrecp->r_ttl = ttl;
+       rrecp->r_section = section;
+       return (rrecp);
+}
+
+/*
+ * Free a resource record buffer created by res_mkupdrec.
+ */
+void
+res_freeupdrec(ns_updrec *rrecp) {
+       /* Note: freeing r_dp is the caller's responsibility. */
+       if (rrecp->r_dname != NULL)
+               free(rrecp->r_dname);
+       free(rrecp);
+}
+
+static struct valuelist *servicelist, *protolist;
+
+void
+res_buildservicelist() {
+       struct servent *sp;
+       struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+       setservent(0);
+#else
+       setservent(1);
+#endif
+       while ((sp = getservent()) != NULL) {
+               slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+               if (!slp)
+                       break;
+               slp->name = strdup(sp->s_name);
+               slp->proto = strdup(sp->s_proto);
+               if ((slp->name == NULL) || (slp->proto == NULL)) {
+                       if (slp->name) free(slp->name);
+                       if (slp->proto) free(slp->proto);
+                       free(slp);
+                       break;
+               }
+               slp->port = ntohs((u_int16_t)sp->s_port);  /* host byt order */
+               slp->next = servicelist;
+               slp->prev = NULL;
+               if (servicelist)
+                       servicelist->prev = slp;
+               servicelist = slp;
+       }
+       endservent();
+}
+
+void
+res_destroyservicelist() {
+       struct valuelist *slp, *slp_next;
+
+       for (slp = servicelist; slp != NULL; slp = slp_next) {
+               slp_next = slp->next;
+               free(slp->name);
+               free(slp->proto);
+               free(slp);
+       }
+       servicelist = (struct valuelist *)0;
+}
+
+void
+res_buildprotolist() {
+       struct protoent *pp;
+       struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+       setprotoent(0);
+#else
+       setprotoent(1);
+#endif
+       while ((pp = getprotoent()) != NULL) {
+               slp = (struct valuelist *)malloc(sizeof(struct valuelist));
+               if (!slp)
+                       break;
+               slp->name = strdup(pp->p_name);
+               if (slp->name == NULL) {
+                       free(slp);
+                       break;
+               }
+               slp->port = pp->p_proto;        /* host byte order */
+               slp->next = protolist;
+               slp->prev = NULL;
+               if (protolist)
+                       protolist->prev = slp;
+               protolist = slp;
+       }
+       endprotoent();
+}
+
+void
+res_destroyprotolist() {
+       struct valuelist *plp, *plp_next;
+
+       for (plp = protolist; plp != NULL; plp = plp_next) {
+               plp_next = plp->next;
+               free(plp->name);
+               free(plp);
+       }
+       protolist = (struct valuelist *)0;
+}
+
+static int
+findservice(const char *s, struct valuelist **list) {
+       struct valuelist *lp = *list;
+       int n;
+
+       for (; lp != NULL; lp = lp->next)
+               if (strcasecmp(lp->name, s) == 0) {
+                       if (lp != *list) {
+                               lp->prev->next = lp->next;
+                               if (lp->next)
+                                       lp->next->prev = lp->prev;
+                               (*list)->prev = lp;
+                               lp->next = *list;
+                               *list = lp;
+                       }
+                       return (lp->port);      /* host byte order */
+               }
+       if (sscanf(s, "%d", &n) != 1 || n <= 0)
+               n = -1;
+       return (n);
+}
+
+/*
+ * Convert service name or (ascii) number to int.
+ */
+int
+res_servicenumber(const char *p) {
+       if (servicelist == (struct valuelist *)0)
+               res_buildservicelist();
+       return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+int
+res_protocolnumber(const char *p) {
+       if (protolist == (struct valuelist *)0)
+               res_buildprotolist();
+       return (findservice(p, &protolist));
+}
+
+static struct servent *
+cgetservbyport(unsigned port, const char *proto) {     /* Host byte order. */
+       struct valuelist **list = &servicelist;
+       struct valuelist *lp = *list;
+       static struct servent serv;
+
+       port = ntohs(port);
+       for (; lp != NULL; lp = lp->next) {
+               if (port != (u_int16_t)lp->port)        /* Host byte order. */
+                       continue;
+               if (strcasecmp(lp->proto, proto) == 0) {
+                       if (lp != *list) {
+                               lp->prev->next = lp->next;
+                               if (lp->next)
+                                       lp->next->prev = lp->prev;
+                               (*list)->prev = lp;
+                               lp->next = *list;
+                               *list = lp;
+                       }
+                       serv.s_name = lp->name;
+                       serv.s_port = htons((u_int16_t)lp->port);
+                       serv.s_proto = lp->proto;
+                       return (&serv);
+               }
+       }
+       return (0);
+}
+
+static struct protoent *
+cgetprotobynumber(int proto) {                         /* Host byte order. */
+       struct valuelist **list = &protolist;
+       struct valuelist *lp = *list;
+       static struct protoent prot;
+
+       for (; lp != NULL; lp = lp->next)
+               if (lp->port == proto) {                /* Host byte order. */
+                       if (lp != *list) {
+                               lp->prev->next = lp->next;
+                               if (lp->next)
+                                       lp->next->prev = lp->prev;
+                               (*list)->prev = lp;
+                               lp->next = *list;
+                               *list = lp;
+                       }
+                       prot.p_name = lp->name;
+                       prot.p_proto = lp->port;        /* Host byte order. */
+                       return (&prot);
+               }
+       return (0);
+}
+
+const char *
+res_protocolname(int num) {
+       static char number[8];
+       struct protoent *pp;
+
+       if (protolist == (struct valuelist *)0)
+               res_buildprotolist();
+       pp = cgetprotobynumber(num);
+       if (pp == 0)  {
+               (void) sprintf(number, "%d", num);
+               return (number);
+       }
+       return (pp->p_name);
+}
+
+const char *
+res_servicename(u_int16_t port, const char *proto) {   /* Host byte order. */
+       static char number[8];
+       struct servent *ss;
+
+       if (servicelist == (struct valuelist *)0)
+               res_buildservicelist();
+       ss = cgetservbyport(htons(port), proto);
+       if (ss == 0)  {
+               (void) sprintf(number, "%d", port);
+               return (number);
+       }
+       return (ss->s_name);
+}
diff --git a/minires/res_query.c b/minires/res_query.c
new file mode 100644 (file)
index 0000000..97a229a
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 1988, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_query.c  8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_query.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+/* Options.  Leave them on. */
+#define DEBUG
+
+#if PACKETSZ > 1024
+#define MAXPACKET      PACKETSZ
+#else
+#define MAXPACKET      1024
+#endif
+
+/*
+ * Formulate a normal query, send, and await answer.
+ * Returned answer is placed in supplied buffer "answer".
+ * Perform preliminary check of answer, returning success only
+ * if no error is indicated and the answer count is nonzero.
+ * Return the size of the response on success, -1 on error.
+ * Error number is left in H_ERRNO.
+ *
+ * Caller must parse answer and determine whether it answers the question.
+ */
+int
+res_nquery(res_state statp,
+          const char *name,    /* domain name */
+          ns_class class, ns_type type, /* class and type of query */
+          u_char *answer,      /* buffer to put answer */
+          unsigned anslen)     /* size of answer buffer */
+{
+       u_char buf[MAXPACKET];
+       HEADER *hp = (HEADER *) answer;
+       unsigned n;
+
+       hp->rcode = NOERROR;    /* default */
+
+#ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+               printf(";; res_query(%s, %d, %d)\n", name, class, type);
+#endif
+
+       n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+                        buf, sizeof(buf));
+       if (n <= 0) {
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG)
+                       printf(";; res_query: mkquery failed\n");
+#endif
+               RES_SET_H_ERRNO(statp, NO_RECOVERY);
+               return (n);
+       }
+       n = res_nsend(statp, buf, n, answer, anslen);
+       if (n < 0) {
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG)
+                       printf(";; res_query: send error\n");
+#endif
+               RES_SET_H_ERRNO(statp, TRY_AGAIN);
+               return (n);
+       }
+
+       if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+#ifdef DEBUG
+               if (statp->options & RES_DEBUG)
+                       printf(";; rcode = %d, ancount=%d\n", hp->rcode,
+                           ntohs(hp->ancount));
+#endif
+               switch (hp->rcode) {
+               case NXDOMAIN:
+                       RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
+                       break;
+               case SERVFAIL:
+                       RES_SET_H_ERRNO(statp, TRY_AGAIN);
+                       break;
+               case NOERROR:
+                       RES_SET_H_ERRNO(statp, NO_DATA);
+                       break;
+               case FORMERR:
+               case NOTIMP:
+               case REFUSED:
+               default:
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       break;
+               }
+               return (-1);
+       }
+       return (n);
+}
+
+/*
+ * Formulate a normal query, send, and retrieve answer in supplied buffer.
+ * Return the size of the response on success, -1 on error.
+ * If enabled, implement search rules until answer or unrecoverable failure
+ * is detected.  Error code, if any, is left in H_ERRNO.
+ */
+int
+res_nsearch(res_state statp,
+           const char *name,   /* domain name */
+           ns_class class, ns_type type, /* class and type of query */
+           u_char *answer,     /* buffer to put answer */
+           unsigned anslen)            /* size of answer */
+{
+       const char *cp, * const *domain;
+       HEADER *hp = (HEADER *) answer;
+       char tmp[NS_MAXDNAME];
+       u_int dots;
+       int trailing_dot, ret;
+       int got_nodata = 0, got_servfail = 0, root_on_list = 0;
+
+       errno = 0;
+       RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);  /* True if we never query. */
+
+       dots = 0;
+       for (cp = name; *cp != '\0'; cp++)
+               dots += (*cp == '.');
+       trailing_dot = 0;
+       if (cp > name && *--cp == '.')
+               trailing_dot++;
+
+       /* If there aren't any dots, it could be a user-level alias. */
+       if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
+               return (res_nquery(statp, cp, class, type, answer, anslen));
+
+       /*
+        * If there are enough dots in the name, do no searching.
+        * (The threshold can be set with the "ndots" option.)
+        */
+       if (dots >= statp->ndots || trailing_dot)
+               return (res_nquerydomain(statp, name, NULL, class, type,
+                                        answer, anslen));
+
+       /*
+        * We do at least one level of search if
+        *      - there is no dot and RES_DEFNAME is set, or
+        *      - there is at least one dot, there is no trailing dot,
+        *        and RES_DNSRCH is set.
+        */
+       if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
+           (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
+               int done = 0;
+
+               for (domain = (const char * const *)statp->dnsrch;
+                    *domain && !done;
+                    domain++) {
+
+                       if (domain[0][0] == '\0' ||
+                           (domain[0][0] == '.' && domain[0][1] == '\0'))
+                               root_on_list++;
+
+                       ret = res_nquerydomain(statp, name, *domain,
+                                              class, type,
+                                              answer, anslen);
+                       if (ret > 0)
+                               return (ret);
+
+                       /*
+                        * If no server present, give up.
+                        * If name isn't found in this domain,
+                        * keep trying higher domains in the search list
+                        * (if that's enabled).
+                        * On a NO_DATA error, keep trying, otherwise
+                        * a wildcard entry of another type could keep us
+                        * from finding this entry higher in the domain.
+                        * If we get some other error (negative answer or
+                        * server failure), then stop searching up,
+                        * but try the input name below in case it's
+                        * fully-qualified.
+                        */
+                       if (errno == ECONNREFUSED) {
+                               RES_SET_H_ERRNO(statp, TRY_AGAIN);
+                               return (-1);
+                       }
+
+                       switch (statp->res_h_errno) {
+                       case NO_DATA:
+                               got_nodata++;
+                               /* FALLTHROUGH */
+                       case HOST_NOT_FOUND:
+                               /* keep trying */
+                               break;
+                       case TRY_AGAIN:
+                               if (hp->rcode == SERVFAIL) {
+                                       /* try next search element, if any */
+                                       got_servfail++;
+                                       break;
+                               }
+                               /* FALLTHROUGH */
+                       default:
+                               /* anything else implies that we're done */
+                               done++;
+                       }
+
+                       /* if we got here for some reason other than DNSRCH,
+                        * we only wanted one iteration of the loop, so stop.
+                        */
+                       if ((statp->options & RES_DNSRCH) == 0)
+                               done++;
+               }
+       }
+
+       /*
+        * If the name has any dots at all, and "." is not on the search
+        * list, then try an as-is query now.
+        */
+       if (statp->ndots) {
+               ret = res_nquerydomain(statp, name, NULL, class, type,
+                                      answer, anslen);
+               if (ret > 0)
+                       return (ret);
+       }
+
+       /* if we got here, we didn't satisfy the search.
+        * if we did an initial full query, return that query's H_ERRNO
+        * (note that we wouldn't be here if that query had succeeded).
+        * else if we ever got a nodata, send that back as the reason.
+        * else send back meaningless H_ERRNO, that being the one from
+        * the last DNSRCH we did.
+        */
+       if (got_nodata)
+               RES_SET_H_ERRNO(statp, NO_DATA);
+       else if (got_servfail)
+               RES_SET_H_ERRNO(statp, TRY_AGAIN);
+       return (-1);
+}
+
+/*
+ * Perform a call on res_query on the concatenation of name and domain,
+ * removing a trailing dot from name if domain is NULL.
+ */
+int
+res_nquerydomain(res_state statp,
+           const char *name,
+           const char *domain,
+           ns_class class, ns_class type,
+           u_char *answer,
+           unsigned anslen)
+{
+       char nbuf[MAXDNAME];
+       const char *longname = nbuf;
+       int n, d;
+
+#ifdef DEBUG
+       if (statp->options & RES_DEBUG)
+               printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
+                      name, domain?domain:"<Nil>", class, type);
+#endif
+       if (domain == NULL) {
+               /*
+                * Check for trailing '.';
+                * copy without '.' if present.
+                */
+               n = strlen(name);
+               if (n >= MAXDNAME) {
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       return (-1);
+               }
+               n--;
+               if (n >= 0 && name[n] == '.') {
+                       strncpy(nbuf, name, (unsigned)n);
+                       nbuf[n] = '\0';
+               } else
+                       longname = name;
+       } else {
+               n = strlen(name);
+               d = strlen(domain);
+               if (n + d + 1 >= MAXDNAME) {
+                       RES_SET_H_ERRNO(statp, NO_RECOVERY);
+                       return (-1);
+               }
+               sprintf(nbuf, "%s.%s", name, domain);
+       }
+       return (res_nquery(statp, longname, class, type, answer, anslen));
+}
+
+const char *
+res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+       char *file, *cp1, *cp2;
+       char buf[BUFSIZ];
+       FILE *fp;
+
+       if (statp->options & RES_NOALIASES)
+               return (NULL);
+       file = getenv("HOSTALIASES");
+       if (file == NULL || (fp = fopen(file, "r")) == NULL)
+               return (NULL);
+       setbuf(fp, NULL);
+       buf[sizeof(buf) - 1] = '\0';
+       while (fgets(buf, sizeof(buf), fp)) {
+               for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
+                       ;
+               if (!*cp1)
+                       break;
+               *cp1 = '\0';
+               if (ns_samename(buf, name) == 1) {
+                       while (isspace(*++cp1))
+                               ;
+                       if (!*cp1)
+                               break;
+                       for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
+                               ;
+                       *cp2 = '\0';
+                       strncpy(dst, cp1, siz - 1);
+                       dst[siz - 1] = '\0';
+                       fclose(fp);
+                       return (dst);
+               }
+       }
+       fclose(fp);
+       return (NULL);
+}
diff --git a/minires/res_send.c b/minires/res_send.c
new file mode 100644 (file)
index 0000000..b6c6c22
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ * Copyright (c) 1985, 1989, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ * 
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char sccsid[] = "@(#)res_send.c   8.1 (Berkeley) 6/4/93";
+static const char rcsid[] = "$Id: res_send.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Send query to name server and wait for reply.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+#define        CHECK_SRVR_ADDR
+               
+static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2);
+void res_pquery(const res_state, const u_char *, int, FILE *);
+
+/* int
+ * res_isourserver(ina)
+ *     looks up "ina" in _res.ns_addr_list[]
+ * returns:
+ *     0  : not found
+ *     >0 : found
+ * author:
+ *     paul vixie, 29may94
+ */
+int
+res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) {
+       struct sockaddr_in ina;
+       int ns;
+
+       ina = *inp;
+       for (ns = 0;  ns < statp->nscount;  ns++) {
+               const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
+
+               if (srv->sin_family == ina.sin_family &&
+                   srv->sin_port == ina.sin_port &&
+                   (srv->sin_addr.s_addr == INADDR_ANY ||
+                    srv->sin_addr.s_addr == ina.sin_addr.s_addr))
+                       return (1);
+       }
+       return (0);
+}
+
+/* int
+ * res_nameinquery(name, type, class, buf, eom)
+ *     look for (name,type,class) in the query section of packet (buf,eom)
+ * requires:
+ *     buf + HFIXEDSZ <= eom
+ * returns:
+ *     -1 : format error
+ *     0  : not found
+ *     >0 : found
+ * author:
+ *     paul vixie, 29may94
+ */
+int
+res_nameinquery(const char *name, int type, int class,
+               const u_char *buf, const u_char *eom)
+{
+       const u_char *cp = buf + HFIXEDSZ;
+       int qdcount = ntohs(((const HEADER *)buf)->qdcount);
+
+       while (qdcount-- > 0) {
+               char tname[MAXDNAME+1];
+               int n, ttype, tclass;
+
+               n = dn_expand(buf, eom, cp, tname, sizeof tname);
+               if (n < 0)
+                       return (-1);
+               cp += n;
+               if (cp + 2 * INT16SZ > eom)
+                       return (-1);
+               ttype = getUShort(cp); cp += INT16SZ;
+               tclass = getUShort(cp); cp += INT16SZ;
+               if (ttype == type && tclass == class &&
+                   ns_samename(tname, name) == 1)
+                       return (1);
+       }
+       return (0);
+}
+
+/* int
+ * res_queriesmatch(buf1, eom1, buf2, eom2)
+ *     is there a 1:1 mapping of (name,type,class)
+ *     in (buf1,eom1) and (buf2,eom2)?
+ * returns:
+ *     -1 : format error
+ *     0  : not a 1:1 mapping
+ *     >0 : is a 1:1 mapping
+ * author:
+ *     paul vixie, 29may94
+ */
+int
+res_queriesmatch(const u_char *buf1, const u_char *eom1,
+                const u_char *buf2, const u_char *eom2)
+{
+       const u_char *cp = buf1 + HFIXEDSZ;
+       int qdcount = ntohs(((const HEADER *)buf1)->qdcount);
+
+       if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
+               return (-1);
+
+       /*
+        * Only header section present in replies to
+        * dynamic update packets.
+        */
+       if ( (((const HEADER *)buf1)->opcode == ns_o_update) &&
+            (((const HEADER *)buf2)->opcode == ns_o_update) )
+               return (1);
+
+       if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
+               return (0);
+       while (qdcount-- > 0) {
+               char tname[MAXDNAME+1];
+               int n, ttype, tclass;
+
+               n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
+               if (n < 0)
+                       return (-1);
+               cp += n;
+               if (cp + 2 * INT16SZ > eom1)
+                       return (-1);
+               ttype = getUShort(cp);  cp += INT16SZ;
+               tclass = getUShort(cp); cp += INT16SZ;
+               if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
+                       return (0);
+       }
+       return (1);
+}
+
+int
+res_nsend(res_state statp,
+         u_char *buf, unsigned buflen, u_char *ans, unsigned anssiz)
+{
+       HEADER *hp = (HEADER *) buf;
+       HEADER *anhp = (HEADER *) ans;
+       int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
+       u_int badns;    /* XXX NSMAX can't exceed #/bits in this variable */
+       static int highestFD = FD_SETSIZE - 1;
+
+       if (anssiz < HFIXEDSZ) {
+               errno = EINVAL;
+               return (-1);
+       }
+       DprintQ((statp->options & RES_DEBUG) ||
+               (statp->pfcode & RES_PRF_QUERY),
+               (stdout, ";; res_send()\n"), buf, buflen);
+       v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
+       gotsomewhere = 0;
+       connreset = 0;
+       terrno = ETIMEDOUT;
+       badns = 0;
+
+       /*
+        * Some callers want to even out the load on their resolver list.
+        */
+       if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) {
+               struct sockaddr_in ina;
+               int lastns = statp->nscount - 1;
+
+               ina = statp->nsaddr_list[0];
+               for (ns = 0; ns < lastns; ns++)
+                       statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
+               statp->nsaddr_list[lastns] = ina;
+       }
+
+       /*
+        * Send request, RETRY times, or until successful
+        */
+       for (try = 0; try < statp->retry; try++) {
+           for (ns = 0; ns < statp->nscount; ns++) {
+               struct sockaddr_in *nsap = &statp->nsaddr_list[ns];
+ same_ns:
+               if (badns & (1 << ns)) {
+                       res_nclose(statp);
+                       goto next_ns;
+               }
+
+               if (statp->qhook) {
+                       int done = 0, loops = 0;
+
+                       do {
+                               res_sendhookact act;
+
+                               act = (*statp->qhook)(&nsap, &buf, &buflen,
+                                                     ans, anssiz, &resplen);
+                               switch (act) {
+                               case res_goahead:
+                                       done = 1;
+                                       break;
+                               case res_nextns:
+                                       res_nclose(statp);
+                                       goto next_ns;
+                               case res_done:
+                                       return (resplen);
+                               case res_modified:
+                                       /* give the hook another try */
+                                       if (++loops < 42) /*doug adams*/
+                                               break;
+                                       /*FALLTHROUGH*/
+                               case res_error:
+                                       /*FALLTHROUGH*/
+                               default:
+                                       return (-1);
+                               }
+                       } while (!done);
+               }
+
+               Dprint(statp->options & RES_DEBUG,
+                      (stdout, ";; Querying server (# %d) address = %s\n",
+                       ns + 1, inet_ntoa(nsap->sin_addr)));
+
+               if (v_circuit) {
+                       int truncated;
+                       struct iovec iov[2];
+                       u_short len;
+                       u_char *cp;
+
+                       /* Use VC; at most one attempt per server. */
+                       try = statp->retry;
+                       truncated = 0;
+
+                       /* Are we still talking to whom we want to talk to? */
+                       if (statp->_sock >= 0 &&
+                           (statp->_flags & RES_F_VC) != 0) {
+                               struct sockaddr_in peer;
+                               int size = sizeof(peer);
+
+                               if (getpeername(statp->_sock,
+                                               (struct sockaddr *)&peer,
+                                               &size) < 0) {
+                                       res_nclose(statp);
+                                       statp->_flags &= ~RES_F_VC;
+                               } else if (!cmpsock(&peer, nsap)) {
+                                       res_nclose(statp);
+                                       statp->_flags &= ~RES_F_VC;
+                               }
+                       }
+
+                       if (statp->_sock < 0 ||
+                           (statp->_flags & RES_F_VC) == 0) {
+                               if (statp->_sock >= 0)
+                                       res_nclose(statp);
+
+                               statp->_sock = socket(PF_INET,
+                                                      SOCK_STREAM, 0);
+                               if (statp->_sock < 0 ||
+                                   statp->_sock > highestFD) {
+                                       terrno = errno;
+                                       Perror(statp, stderr,
+                                              "socket(vc)", errno);
+                                       return (-1);
+                               }
+                               errno = 0;
+                               if (connect(statp->_sock,
+                                           (struct sockaddr *)nsap,
+                                           sizeof *nsap) < 0) {
+                                       terrno = errno;
+                                       Aerror(statp, stderr, "connect/vc",
+                                              errno, *nsap);
+                                       badns |= (1 << ns);
+                                       res_nclose(statp);
+                                       goto next_ns;
+                               }
+                               statp->_flags |= RES_F_VC;
+                       }
+                       /*
+                        * Send length & message
+                        */
+                       putUShort((u_char*)&len, buflen);
+                       iov[0].iov_base = (caddr_t)&len;
+                       iov[0].iov_len = INT16SZ;
+                       iov[1].iov_base = (const caddr_t)buf;
+                       iov[1].iov_len = buflen;
+                       if (writev(statp->_sock, iov, 2) !=
+                           (INT16SZ + buflen)) {
+                               terrno = errno;
+                               Perror(statp, stderr, "write failed", errno);
+                               badns |= (1 << ns);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       /*
+                        * Receive length & response
+                        */
+ read_len:
+                       cp = ans;
+                       len = INT16SZ;
+                       while ((n = read(statp->_sock,
+                                        (char *)cp, (unsigned)len)) > 0) {
+                               cp += n;
+                               if ((len -= n) <= 0)
+                                       break;
+                       }
+                       if (n <= 0) {
+                               terrno = errno;
+                               Perror(statp, stderr, "read failed", errno);
+                               res_nclose(statp);
+                               /*
+                                * A long running process might get its TCP
+                                * connection reset if the remote server was
+                                * restarted.  Requery the server instead of
+                                * trying a new one.  When there is only one
+                                * server, this means that a query might work
+                                * instead of failing.  We only allow one reset
+                                * per query to prevent looping.
+                                */
+                               if (terrno == ECONNRESET && !connreset) {
+                                       connreset = 1;
+                                       res_nclose(statp);
+                                       goto same_ns;
+                               }
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       resplen = getUShort (ans);
+                       if (resplen > anssiz) {
+                               Dprint(statp->options & RES_DEBUG,
+                                      (stdout, ";; response truncated\n")
+                                      );
+                               truncated = 1;
+                               len = anssiz;
+                       } else
+                               len = resplen;
+                       if (len < HFIXEDSZ) {
+                               /*
+                                * Undersized message.
+                                */
+                               Dprint(statp->options & RES_DEBUG,
+                                      (stdout, ";; undersized: %d\n", len));
+                               terrno = EMSGSIZE;
+                               badns |= (1 << ns);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       cp = ans;
+                       while (len != 0 &&
+                              (n = read(statp->_sock,
+                                        (char *)cp, (unsigned)len))
+                              > 0) {
+                               cp += n;
+                               len -= n;
+                       }
+                       if (n <= 0) {
+                               terrno = errno;
+                               Perror(statp, stderr, "read(vc)", errno);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       if (truncated) {
+                               /*
+                                * Flush rest of answer
+                                * so connection stays in synch.
+                                */
+                               anhp->tc = 1;
+                               len = resplen - anssiz;
+                               while (len != 0) {
+                                       char junk[PACKETSZ];
+
+                                       n = (len > sizeof(junk)
+                                            ? sizeof(junk)
+                                            : len);
+                                       n = read(statp->_sock,
+                                                junk, (unsigned)n);
+                                       if (n > 0)
+                                               len -= n;
+                                       else
+                                               break;
+                               }
+                       }
+                       /*
+                        * The calling applicating has bailed out of
+                        * a previous call and failed to arrange to have
+                        * the circuit closed or the server has got
+                        * itself confused. Anyway drop the packet and
+                        * wait for the correct one.
+                        */
+                       if (hp->id != anhp->id) {
+                               DprintQ((statp->options & RES_DEBUG) ||
+                                       (statp->pfcode & RES_PRF_REPLY),
+                                       (stdout,
+                                        ";; old answer (unexpected):\n"),
+                                       ans, (resplen>anssiz)?anssiz:resplen);
+                               goto read_len;
+                       }
+               } else {
+                       /*
+                        * Use datagrams.
+                        */
+                       int start, timeout, finish;
+                       fd_set dsmask;
+                       struct sockaddr_in from;
+                       int fromlen, seconds;
+
+                       if (statp->_sock < 0 ||
+                           (statp->_flags & RES_F_VC) != 0) {
+                               if ((statp->_flags & RES_F_VC) != 0)
+                                       res_nclose(statp);
+                               statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);
+                               if (statp->_sock < 0 ||
+                                   statp->_sock > highestFD) {
+#ifndef CAN_RECONNECT
+ bad_dg_sock:
+#endif
+                                       terrno = errno;
+                                       Perror(statp, stderr,
+                                              "socket(dg)", errno);
+                                       return (-1);
+                               }
+                               statp->_flags &= ~RES_F_CONN;
+                       }
+#ifndef CANNOT_CONNECT_DGRAM
+                       /*
+                        * On a 4.3BSD+ machine (client and server,
+                        * actually), sending to a nameserver datagram
+                        * port with no nameserver will cause an
+                        * ICMP port unreachable message to be returned.
+                        * If our datagram socket is "connected" to the
+                        * server, we get an ECONNREFUSED error on the next
+                        * socket operation, and select returns if the
+                        * error message is received.  We can thus detect
+                        * the absence of a nameserver without timing out.
+                        * If we have sent queries to at least two servers,
+                        * however, we don't want to remain connected,
+                        * as we wish to receive answers from the first
+                        * server to respond.
+                        */
+                       if (statp->nscount == 1 || (try == 0 && ns == 0)) {
+                               /*
+                                * Connect only if we are sure we won't
+                                * receive a response from another server.
+                                */
+                               if ((statp->_flags & RES_F_CONN) == 0) {
+                                       if (connect(statp->_sock,
+                                                   (struct sockaddr *)nsap,
+                                                   sizeof *nsap) < 0) {
+                                               Aerror(statp, stderr,
+                                                      "connect(dg)",
+                                                      errno, *nsap);
+                                               badns |= (1 << ns);
+                                               res_nclose(statp);
+                                               goto next_ns;
+                                       }
+                                       statp->_flags |= RES_F_CONN;
+                               }
+                              if (send(statp->_sock,
+                                      (const char*)buf, (unsigned)buflen, 0)
+                                 != buflen) {
+                                       Perror(statp, stderr, "send", errno);
+                                       badns |= (1 << ns);
+                                       res_nclose(statp);
+                                       goto next_ns;
+                               }
+                       } else {
+                               /*
+                                * Disconnect if we want to listen
+                                * for responses from more than one server.
+                                */
+                               if ((statp->_flags & RES_F_CONN) != 0) {
+#ifdef CAN_RECONNECT
+                                       struct sockaddr_in no_addr;
+
+                                       no_addr.sin_family = AF_INET;
+                                       no_addr.sin_addr.s_addr = INADDR_ANY;
+                                       no_addr.sin_port = 0;
+                                       (void) connect(statp->_sock,
+                                                      (struct sockaddr *)
+                                                       &no_addr,
+                                                      sizeof no_addr);
+#else
+                                       struct sockaddr_in local_addr;
+                                       int len, result, s1;
+
+                                       len = sizeof(local_addr);
+                                       s1 = socket(PF_INET, SOCK_DGRAM, 0);
+                                       result = getsockname(statp->_sock,
+                                               (struct sockaddr *)&local_addr,
+                                                            &len);
+                                       if (s1 < 0)
+                                               goto bad_dg_sock;
+                                       (void) dup2(s1, statp->_sock);
+                                       (void) close(s1);
+                                       if (result == 0) {
+                                               /*
+                                                * Attempt to rebind to old
+                                                * port.  Note connected socket
+                                                * has an sin_addr set.
+                                                */
+                                               local_addr.sin_addr.s_addr =
+                                                       htonl(0);
+                                               (void)bind(statp->_sock,
+                                                          (struct sockaddr *)
+                                                          &local_addr,
+                                                          (unsigned)len);
+                                       }
+                                       Dprint(statp->options & RES_DEBUG,
+                                              (stdout, ";; new DG socket\n"))
+#endif /* CAN_RECONNECT */
+                                       statp->_flags &= ~RES_F_CONN;
+                                       errno = 0;
+                               }
+#endif /* !CANNOT_CONNECT_DGRAM */
+                               if (sendto(statp->_sock,
+                                          (const char *)buf, buflen, 0,
+                                          (struct sockaddr *)nsap,
+                                          sizeof *nsap)
+                                   != buflen) {
+                                       Aerror(statp, stderr, "sendto", errno, *nsap);
+                                       badns |= (1 << ns);
+                                       res_nclose(statp);
+                                       goto next_ns;
+                               }
+#ifndef CANNOT_CONNECT_DGRAM
+                       }
+#endif /* !CANNOT_CONNECT_DGRAM */
+
+                       if (statp->_sock < 0 || statp->_sock > highestFD) {
+                               Perror(statp, stderr,
+                                      "fd out-of-bounds", EMFILE);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+
+                       /*
+                        * Wait for reply
+                        */
+                       seconds = (statp->retrans << try);
+                       if (try > 0)
+                               seconds /= statp->nscount;
+                       if (seconds <= 0)
+                               seconds = 1;
+                       start = cur_time;
+                       timeout = seconds;
+                       finish = start + timeout;
+ wait:
+                       FD_ZERO(&dsmask);
+                       FD_SET(statp->_sock, &dsmask);
+                       {
+                               struct timeval t;
+                               t.tv_sec = timeout;
+                               t.tv_usec = 0;
+                               n = select(statp->_sock + 1,
+                                          &dsmask, NULL, NULL, &t);
+                       }
+                       if (n == 0) {
+                               Dprint(statp->options & RES_DEBUG,
+                                      (stdout, ";; timeout\n"));
+                               gotsomewhere = 1;
+                               goto next_ns;
+                       }
+                       if (n < 0) {
+                               if (errno == EINTR) {
+                                       if (finish >= cur_time) {
+                                               timeout = finish - cur_time;
+                                               goto wait;
+                                       }
+                               }
+                               Perror(statp, stderr, "select", errno);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       errno = 0;
+                       fromlen = sizeof(struct sockaddr_in);
+                       resplen = recvfrom(statp->_sock,
+                                          (char *)ans, anssiz, 0,
+                                          (struct sockaddr *)&from, &fromlen);
+                       if (resplen <= 0) {
+                               Perror(statp, stderr, "recvfrom", errno);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       gotsomewhere = 1;
+                       if (resplen < HFIXEDSZ) {
+                               /*
+                                * Undersized message.
+                                */
+                               Dprint(statp->options & RES_DEBUG,
+                                      (stdout, ";; undersized: %d\n",
+                                       resplen));
+                               terrno = EMSGSIZE;
+                               badns |= (1 << ns);
+                               res_nclose(statp);
+                               goto next_ns;
+                       }
+                       if (hp->id != anhp->id) {
+                               /*
+                                * response from old query, ignore it.
+                                * XXX - potential security hazard could
+                                *       be detected here.
+                                */
+                               DprintQ((statp->options & RES_DEBUG) ||
+                                       (statp->pfcode & RES_PRF_REPLY),
+                                       (stdout, ";; old answer:\n"),
+                                       ans, (resplen>anssiz)?anssiz:resplen);
+                               goto wait;
+                       }
+#ifdef CHECK_SRVR_ADDR
+                       if (!(statp->options & RES_INSECURE1) &&
+                           !res_ourserver_p(statp, &from)) {
+                               /*
+                                * response from wrong server? ignore it.
+                                * XXX - potential security hazard could
+                                *       be detected here.
+                                */
+                               DprintQ((statp->options & RES_DEBUG) ||
+                                       (statp->pfcode & RES_PRF_REPLY),
+                                       (stdout, ";; not our server:\n"),
+                                       ans, (resplen>anssiz)?anssiz:resplen);
+                               goto wait;
+                       }
+#endif
+                       if (!(statp->options & RES_INSECURE2) &&
+                           !res_queriesmatch(buf, buf + buflen,
+                                             ans, ans + anssiz)) {
+                               /*
+                                * response contains wrong query? ignore it.
+                                * XXX - potential security hazard could
+                                *       be detected here.
+                                */
+                               DprintQ((statp->options & RES_DEBUG) ||
+                                       (statp->pfcode & RES_PRF_REPLY),
+                                       (stdout, ";; wrong query name:\n"),
+                                       ans, (resplen>anssiz)?anssiz:resplen);
+                               goto wait;
+                       }
+                       if (anhp->rcode == SERVFAIL ||
+                           anhp->rcode == NOTIMP ||
+                           anhp->rcode == REFUSED) {
+                               DprintQ(statp->options & RES_DEBUG,
+                                       (stdout, "server rejected query:\n"),
+                                       ans, (resplen>anssiz)?anssiz:resplen);
+                               badns |= (1 << ns);
+                               res_nclose(statp);
+                               /* don't retry if called from dig */
+                               if (!statp->pfcode)
+                                       goto next_ns;
+                       }
+                       if (!(statp->options & RES_IGNTC) && anhp->tc) {
+                               /*
+                                * get rest of answer;
+                                * use TCP with same server.
+                                */
+                               Dprint(statp->options & RES_DEBUG,
+                                      (stdout, ";; truncated answer\n"));
+                               v_circuit = 1;
+                               res_nclose(statp);
+                               goto same_ns;
+                       }
+               } /*if vc/dg*/
+               Dprint((statp->options & RES_DEBUG) ||
+                      ((statp->pfcode & RES_PRF_REPLY) &&
+                       (statp->pfcode & RES_PRF_HEAD1)),
+                      (stdout, ";; got answer:\n"));
+               DprintQ((statp->options & RES_DEBUG) ||
+                       (statp->pfcode & RES_PRF_REPLY),
+                       (stdout, ""),
+                       ans, (resplen>anssiz)?anssiz:resplen);
+               /*
+                * If using virtual circuits, we assume that the first server
+                * is preferred over the rest (i.e. it is on the local
+                * machine) and only keep that one open.
+                * If we have temporarily opened a virtual circuit,
+                * or if we haven't been asked to keep a socket open,
+                * close the socket.
+                */
+               if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||
+                   !(statp->options & RES_STAYOPEN)) {
+                       res_nclose(statp);
+               }
+               if (statp->rhook) {
+                       int done = 0, loops = 0;
+
+                       do {
+                               res_sendhookact act;
+
+                               act = (*statp->rhook)(nsap, buf, buflen,
+                                                     ans, anssiz, &resplen);
+                               switch (act) {
+                               case res_goahead:
+                               case res_done:
+                                       done = 1;
+                                       break;
+                               case res_nextns:
+                                       res_nclose(statp);
+                                       goto next_ns;
+                               case res_modified:
+                                       /* give the hook another try */
+                                       if (++loops < 42) /*doug adams*/
+                                               break;
+                                       /*FALLTHROUGH*/
+                               case res_error:
+                                       /*FALLTHROUGH*/
+                               default:
+                                       return (-1);
+                               }
+                       } while (!done);
+
+               }
+               return (resplen);
+ next_ns: ;
+          } /*foreach ns*/
+       } /*foreach retry*/
+       res_nclose(statp);
+       if (!v_circuit) {
+               if (!gotsomewhere)
+                       errno = ECONNREFUSED;   /* no nameservers found */
+               else
+                       errno = ETIMEDOUT;      /* no answer obtained */
+       } else
+               errno = terrno;
+       return (-1);
+}
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it.  This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+void
+res_nclose(res_state statp) {
+       if (statp->_sock >= 0) {
+               (void) close(statp->_sock);
+               statp->_sock = -1;
+               statp->_flags &= ~(RES_F_VC | RES_F_CONN);
+       }
+}
+
+/* Private */
+static int
+cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {
+       return ((a1->sin_family == a2->sin_family) &&
+               (a1->sin_port == a2->sin_port) &&
+               (a1->sin_addr.s_addr == a2->sin_addr.s_addr));
+}
+
+#ifdef NEED_PSELECT
+/* XXX needs to move to the porting library. */
+static int
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+       struct timespec *tsp,
+       const sigset_t *sigmask)
+{
+       struct timeval tv, *tvp;
+       sigset_t sigs;
+       int n;
+
+       if (tsp) {
+               tvp = &tv;
+               tv = evTimeVal(*tsp);
+       } else
+               tvp = NULL;
+       if (sigmask)
+               sigprocmask(SIG_SETMASK, sigmask, &sigs);
+       n = select(nfds, rfds, wfds, efds, tvp);
+       if (sigmask)
+               sigprocmask(SIG_SETMASK, &sigs, NULL);
+       if (tsp)
+               *tsp = evTimeSpec(tv);
+       return (n);
+}
+#endif
diff --git a/minires/res_sendsigned.c b/minires/res_sendsigned.c
new file mode 100644 (file)
index 0000000..0931af2
--- /dev/null
@@ -0,0 +1,125 @@
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <isc/dst.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+/* res_nsendsigned */
+int
+res_nsendsigned(res_state statp, u_char *msg, unsigned msglen,
+               ns_tsig_key *key, u_char *answer, unsigned anslen)
+{
+       res_state nstatp;
+       DST_KEY *dstkey;
+       int usingTCP = 0;
+       u_char *newmsg;
+       unsigned newmsglen;
+       unsigned bufsize, siglen;
+       u_char sig[64];
+       HEADER *hp;
+       time_t tsig_time;
+       int ret;
+
+       dst_init();
+
+       nstatp = (res_state) malloc(sizeof(*statp));
+       if (nstatp == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       memcpy(nstatp, statp, sizeof(*statp));
+
+       bufsize = msglen + 1024;
+       newmsg = (u_char *) malloc(bufsize);
+       if (newmsg == NULL) {
+               errno = ENOMEM;
+               return (-1);
+       }
+       memcpy(newmsg, msg, msglen);
+       newmsglen = msglen;
+
+       if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
+               dstkey = NULL;
+       else
+               dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
+                                          NS_KEY_TYPE_AUTH_ONLY,
+                                          NS_KEY_PROT_ANY,
+                                          key->data, key->len);
+       if (dstkey == NULL) {
+               errno = EINVAL;
+               free(nstatp);
+               free(newmsg);
+               return (-1);
+       }
+
+       nstatp->nscount = 1;
+       siglen = sizeof(sig);
+       ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0,
+                     sig, &siglen, 0);
+       if (ret < 0) {
+               free (nstatp);
+               free (newmsg);
+               if (ret == NS_TSIG_ERROR_NO_SPACE)
+                       errno  = EMSGSIZE;
+               else if (ret == -1)
+                       errno  = EINVAL;
+               return (ret);
+       }
+
+       if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC))
+               usingTCP = 1;
+       if (usingTCP == 0)
+               nstatp->options |= RES_IGNTC;
+       else
+               nstatp->options |= RES_USEVC;
+
+retry:
+
+       ret = res_nsend(nstatp, newmsg, newmsglen, answer, anslen);
+       if (ret < 0) {
+               free (nstatp);
+               free (newmsg);
+               return (ret);
+       }
+
+       anslen = ret;
+       ret = ns_verify(answer, &anslen, dstkey, sig, siglen,
+                       NULL, NULL, &tsig_time,
+                       (nstatp->options & RES_KEEPTSIG) ? 1 : 0);
+       if (ret != 0) {
+               Dprint(nstatp->pfcode & RES_PRF_REPLY,
+                      (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
+               free (nstatp);
+               free (newmsg);
+               if (ret == -1)
+                       errno = EINVAL;
+               else
+                       errno = ENOTTY;
+               return (-1);
+       }
+       Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
+
+       hp = (HEADER *) answer;
+       if (hp->tc && usingTCP == 0) {
+               nstatp->options &= ~RES_IGNTC;
+               usingTCP = 1;
+               goto retry;
+       }
+
+       free (nstatp);
+       free (newmsg);
+       return (anslen);
+}
diff --git a/minires/res_update.c b/minires/res_update.c
new file mode 100644 (file)
index 0000000..d63e7d3
--- /dev/null
@@ -0,0 +1,215 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: res_update.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+#endif /* not lint */
+
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Based on the Dynamic DNS reference implementation by Viraj Bais
+ * <viraj_bais@ccm.fm.intel.com>
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/list.h>
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+/*
+ * Separate a linked list of records into groups so that all records
+ * in a group will belong to a single zone on the nameserver.
+ * Create a dynamic update packet for each zone and send it to the
+ * nameservers for that zone, and await answer.
+ * Abort if error occurs in updating any zone.
+ * Return the number of zones updated on success, < 0 on error.
+ *
+ * On error, caller must deal with the unsynchronized zones
+ * eg. an A record might have been successfully added to the forward
+ * zone but the corresponding PTR record would be missing if error
+ * was encountered while updating the reverse zone.
+ */
+
+struct zonegrp {
+       char z_origin[MAXDNAME];
+       ns_class z_class;
+       struct in_addr z_nsaddrs[MAXNS];
+       int z_nscount;
+       int z_flags;
+       ISC_LIST(ns_updrec) z_rrlist;
+       ISC_LINK(struct zonegrp) z_link;
+};
+
+#define ZG_F_ZONESECTADDED     0x0001
+
+/* Forward. */
+
+static int     nscopy(struct sockaddr_in *, const struct sockaddr_in *, int);
+static int     nsprom(struct sockaddr_in *, const struct in_addr *, int);
+static void    dprintf(const char *, ...);
+
+int
+res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
+       ns_updrec *rrecp;
+       u_char answer[PACKETSZ], packet[2*PACKETSZ];
+       struct zonegrp *zptr, tgrp;
+       ISC_LIST(struct zonegrp) zgrps;
+       int nzones = 0, nscount = 0;
+       unsigned n;
+       struct sockaddr_in nsaddrs[MAXNS];
+
+       /* Thread all of the updates onto a list of groups. */
+       ISC_LIST_INIT(zgrps);
+       for (rrecp = rrecp_in; rrecp; rrecp = ISC_LIST_NEXT(rrecp, r_link)) {
+               /* Find the origin for it if there is one. */
+               tgrp.z_class = rrecp->r_class;
+               tgrp.z_nscount =
+                       res_findzonecut(statp, rrecp->r_dname, tgrp.z_class,
+                                       RES_EXHAUSTIVE,
+                                       tgrp.z_origin,
+                                       sizeof tgrp.z_origin,
+                                       tgrp.z_nsaddrs, MAXNS);
+               if (tgrp.z_nscount <= 0) {
+                       DPRINTF(("res_findzonecut failed (%d)",
+                                tgrp.z_nscount));
+                       goto done;
+               }
+               /* Find the group for it if there is one. */
+               for (zptr = ISC_LIST_HEAD(zgrps); zptr != NULL;
+                    zptr = ISC_LIST_NEXT(zptr, z_link))
+                       if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
+                           tgrp.z_class == zptr->z_class)
+                               break;
+               /* Make a group for it if there isn't one. */
+               if (zptr == NULL) {
+                       zptr = malloc(sizeof *zptr);
+                       if (zptr == NULL) {
+                               DPRINTF(("malloc failed"));
+                               goto done;
+                       }
+                       *zptr = tgrp;
+                       zptr->z_flags = 0;
+                       ISC_LIST_INIT(zptr->z_rrlist);
+                       ISC_LIST_APPEND(zgrps, zptr, z_link);
+               }
+               /* Thread this rrecp onto the right group. */
+               ISC_LIST_APPEND(zptr->z_rrlist, rrecp, r_glink);
+       }
+
+       for (zptr = ISC_LIST_HEAD(zgrps); zptr != NULL;
+            zptr = ISC_LIST_NEXT(zptr, z_link)) {
+               /* Construct zone section and prepend it. */
+               rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
+                                    zptr->z_class, ns_t_soa, 0);
+               if (rrecp == NULL) {
+                       DPRINTF(("res_mkupdrec failed"));
+                       goto done;
+               }
+               ISC_LIST_PREPEND(zptr->z_rrlist, rrecp, r_glink);
+               zptr->z_flags |= ZG_F_ZONESECTADDED;
+
+               /* Marshall the update message. */
+               n = res_nmkupdate(statp, ISC_LIST_HEAD(zptr->z_rrlist),
+                                 packet, sizeof packet);
+               DPRINTF(("res_mkupdate -> %d", n));
+               if (n < 0)
+                       goto done;
+
+               /* Temporarily replace the resolver's nameserver set. */
+               nscount = nscopy(nsaddrs, statp->nsaddr_list, statp->nscount);
+               statp->nscount = nsprom(statp->nsaddr_list,
+                                       zptr->z_nsaddrs, zptr->z_nscount);
+
+               /* Send the update and remember the result. */
+               if (key != NULL)
+                       n = res_nsendsigned(statp, packet, n, key,
+                                           answer, sizeof answer);
+               else
+                       n = res_nsend(statp, packet, n, answer, sizeof answer);
+               if (n < 0) {
+                       DPRINTF(("res_nsend: send error, n=%d (%s)\n",
+                                n, strerror(errno)));
+                       goto done;
+               }
+               if (((HEADER *)answer)->rcode == NOERROR)
+                       nzones++;
+
+               /* Restore resolver's nameserver set. */
+               statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount);
+               nscount = 0;
+       }
+ done:
+       while (!ISC_LIST_EMPTY(zgrps)) {
+               zptr = ISC_LIST_HEAD(zgrps);
+               if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
+                       res_freeupdrec(ISC_LIST_HEAD(zptr->z_rrlist));
+               ISC_LIST_UNLINK(zgrps, zptr, z_link);
+               free(zptr);
+       }
+       if (nscount != 0)
+               statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount);
+
+       return (nzones);
+}
+
+/* Private. */
+
+static int
+nscopy(struct sockaddr_in *dst, const struct sockaddr_in *src, int n) {
+       int i;
+
+       for (i = 0; i < n; i++)
+               dst[i] = src[i];
+       return (n);
+}
+
+static int
+nsprom(struct sockaddr_in *dst, const struct in_addr *src, int n) {
+       int i;
+
+       for (i = 0; i < n; i++) {
+               memset(&dst[i], 0, sizeof dst[i]);
+               dst[i].sin_family = AF_INET;
+               dst[i].sin_port = htons(NS_DEFAULTPORT);
+               dst[i].sin_addr = src[i];
+       }
+       return (n);
+}
+
+static void
+dprintf(const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs(";; res_nupdate: ", stderr);
+       vfprintf(stderr, fmt, ap);
+       fputc('\n', stderr);
+       va_end(ap);
+}
diff --git a/minires/support.c b/minires/support.c
new file mode 100644 (file)
index 0000000..d3fe8d3
--- /dev/null
@@ -0,0 +1,462 @@
+static const char rcsid[] = "$Header: /tmp/cvstest/DHCP/minires/Attic/support.c,v 1.1 2000/02/02 07:28:15 mellon Exp $";
+
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * Permission to use, copy modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include "arpa/nameser.h"
+#include "minires/minires.h"
+
+#include "dst_internal.h"
+
+/*
+ * dst_s_conv_bignum_u8_to_b64
+ *     This function converts binary data stored as a u_char[] to a
+ *     base-64 string.  Leading zeroes are discarded.  If a header is
+ *     supplied, it is prefixed to the input prior to encoding.  The
+ *     output is \n\0 terminated (the \0 is not included in output length).
+ * Parameters
+ *     out_buf   binary data to convert
+ *     header    character string to prefix to the output (label)
+ *     bin_data  binary data
+ *     bin_len   size of binary data
+ * Return
+ *     -1     not enough space in output work area
+ *     0     no output
+ *     >0     number of bytes written to output work area
+ */
+
+int
+dst_s_conv_bignum_u8_to_b64(char *out_buf, const unsigned out_len,
+                           const char *header, const u_char *bin_data,
+                           const unsigned bin_len)
+{
+       const u_char *bp = bin_data;
+       char *op = out_buf;
+       unsigned lenh = 0, len64 = 0;
+       unsigned local_in_len = bin_len;
+       unsigned local_out_len = out_len;
+
+       if (bin_data == NULL)   /* no data no */
+               return (0);
+
+       if (out_buf == NULL || out_len <= 0)    /* no output_work area */
+               return (-1);
+
+       /* suppress leading \0  */
+       for (; (*bp == 0x0) && (local_in_len > 0); local_in_len--)
+               bp++;
+
+       if (header) {           /* add header to output string */
+               lenh = strlen(header);
+               if (lenh < out_len)
+                       memcpy(op, header, lenh);
+               else
+                       return (-1);
+               local_out_len -= lenh;
+               op += lenh;
+       }
+       len64 = b64_ntop(bp, local_in_len, op, local_out_len - 2);
+       if (len64 < 0)
+               return (-1);
+       op += len64++;
+       *(op++) = '\n';         /* put CR in the output */
+       *op = '\0';             /* make sure output is 0 terminated */
+       return (lenh + len64);
+}
+
+
+/*
+ * dst_s_verify_str()
+ *     Validate that the input string(*str) is at the head of the input
+ *     buffer(**buf).  If so, move the buffer head pointer (*buf) to
+ *     the first byte of data following the string(*str).
+ * Parameters
+ *     buf     Input buffer.
+ *     str     Input string.
+ * Return
+ *     0       *str is not the head of **buff
+ *     1       *str is the head of **buff, *buf is is advanced to
+ *     the tail of **buf.
+ */
+
+int
+dst_s_verify_str(const char **buf, const char *str)
+{
+       unsigned b, s;
+       if (*buf == NULL)       /* error checks */
+               return (0);
+       if (str == NULL || *str == '\0')
+               return (1);
+
+       b = strlen(*buf);       /* get length of strings */
+       s = strlen(str);
+       if (s > b || strncmp(*buf, str, s))     /* check if same */
+               return (0);     /* not a match */
+       (*buf) += s;            /* advance pointer */
+       return (1);
+}
+
+
+/*
+ * dst_s_conv_bignum_b64_to_u8
+ *     Read a line of base-64 encoded string from the input buffer,
+ *     convert it to binary, and store it in an output area.  The
+ *     input buffer is read until reaching a newline marker or the
+ *     end of the buffer.  The binary data is stored in the last X
+ *     number of bytes of the output area where X is the size of the
+ *     binary output.  If the operation is successful, the input buffer
+ *     pointer is advanced.  This procedure does not do network to host
+ *     byte order conversion.
+ * Parameters
+ *     buf     Pointer to encoded input string. Pointer is updated if
+ *        function is successfull.
+ *     loc     Output area.
+ *     loclen  Size in bytes of output area.
+ * Return
+ *     >0      Return = number of bytes of binary data stored in loc.
+ *      0      Failure.
+ */
+
+int
+dst_s_conv_bignum_b64_to_u8(const char **buf,
+                           u_char *loc, const unsigned loclen)
+{
+       unsigned blen;
+       char *bp;
+       u_char bstr[RAW_KEY_SIZE];
+
+       if (buf == NULL || *buf == NULL) {      /* error checks */
+               EREPORT(("dst_s_conv_bignum_b64_to_u8: null input buffer.\n"));
+               return (0);
+       }
+       bp = strchr(*buf, '\n');        /* find length of input line */
+       if (bp != NULL)
+               *bp = (u_char) NULL;
+
+       blen = b64_pton(*buf, bstr, sizeof(bstr));
+       if (blen <= 0) {
+               EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is null.\n"));
+               return (0);
+       }
+       else if (loclen < blen) {
+               EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is longer than output buffer.\n"));
+               return (0);
+       }
+       if (bp)
+               *buf = bp;      /* advancing buffer past \n */
+       memset(loc, 0, loclen - blen);  /* clearing unused output area */
+       memcpy(loc + loclen - blen, bstr, blen);        /* write last blen bytes  */
+       return (blen);
+}
+
+
+/*
+ * dst_s_calculate_bits
+ *     Given a binary number represented in a u_char[], determine
+ *     the number of significant bits used.
+ * Parameters
+ *     str       An input character string containing a binary number.
+ *     max_bits The maximum possible significant bits.
+ * Return
+ *     N       The number of significant bits in str.
+ */
+
+int
+dst_s_calculate_bits(const u_char *str, const int max_bits)
+{
+       const u_char *p = str;
+       u_char i, j = 0x80;
+       int bits;
+       for (bits = max_bits; *p == 0x00 && bits > 0; p++)
+               bits -= 8;
+       for (i = *p; (i & j) != j; j >>= 1)
+               bits--;
+       return (bits);
+}
+
+
+/*
+ * calculates a checksum used in kmt for a id.
+ * takes an array of bytes and a length.
+ * returns a 16  bit checksum.
+ */
+u_int16_t
+dst_s_id_calc(const u_char *key, const unsigned keysize)
+{
+       u_int32_t ac;
+       const u_char *kp = key;
+       unsigned size = keysize;
+
+       if (!key)
+               return 0;
+       for (ac = 0; size > 1; size -= 2, kp += 2)
+               ac += ((*kp) << 8) + *(kp + 1);
+
+       if (size > 0)
+               ac += ((*kp) << 8);
+       ac += (ac >> 16) & 0xffff;
+
+       return (ac & 0xffff);
+}
+
+/* 
+ * dst_s_dns_key_id() Function to calculated DNSSEC footprint from KEY reocrd
+ *   rdata (all of  record)
+ * Input:
+ *     dns_key_rdata: the raw data in wire format 
+ *      rdata_len: the size of the input data 
+ * Output:
+ *      the key footprint/id calcuated from the key data 
+ */ 
+u_int16_t
+dst_s_dns_key_id(const u_char *dns_key_rdata, const unsigned rdata_len)
+{
+       unsigned key_data = 4;
+
+       if (!dns_key_rdata || (rdata_len < key_data))
+               return 0;
+
+       /* check the extended parameters bit in the DNS Key RR flags */
+       if (dst_s_get_int16(dns_key_rdata) & DST_EXTEND_FLAG)
+               key_data += 2;
+
+       /* compute id */
+       if (dns_key_rdata[3] == KEY_RSA)        /* Algorithm RSA */
+               return dst_s_get_int16((const u_char *)
+                                      &dns_key_rdata[rdata_len - 3]);
+       else
+               /* compute a checksum on the key part of the key rr */
+               return dst_s_id_calc(&dns_key_rdata[key_data],
+                                    (rdata_len - key_data));
+}
+
+/*
+ * dst_s_get_int16
+ *     This routine extracts a 16 bit integer from a two byte character
+ *     string.  The character string is assumed to be in network byte
+ *     order and may be unaligned.  The number returned is in host order.
+ * Parameter
+ *     buf     A two byte character string.
+ * Return
+ *     The converted integer value.
+ */
+
+u_int16_t
+dst_s_get_int16(const u_char *buf)
+{
+       register u_int16_t a = 0;
+       a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
+       return (a);
+}
+
+
+/*
+ * dst_s_get_int32
+ *     This routine extracts a 32 bit integer from a four byte character
+ *     string.  The character string is assumed to be in network byte
+ *     order and may be unaligned.  The number returned is in host order.
+ * Parameter
+ *     buf     A four byte character string.
+ * Return
+ *     The converted integer value.
+ */
+
+u_int32_t
+dst_s_get_int32(const u_char *buf)
+{
+       register u_int32_t a = 0;
+       a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) |
+               ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3]));
+       return (a);
+}
+
+
+/*
+ * dst_s_put_int16
+ *     Take a 16 bit integer and store the value in a two byte
+ *     character string.  The integer is assumed to be in network
+ *     order and the string is returned in host order.
+ *
+ * Parameters
+ *     buf     Storage for a two byte character string.
+ *     val     16 bit integer.
+ */
+
+void
+dst_s_put_int16(u_int8_t *buf, const u_int16_t val)
+{
+       buf[0] = (u_int8_t)(val >> 8);
+       buf[1] = (u_int8_t)(val);
+}
+
+
+/*
+ * dst_s_put_int32
+ *     Take a 32 bit integer and store the value in a four byte
+ *     character string.  The integer is assumed to be in network
+ *     order and the string is returned in host order.
+ *
+ * Parameters
+ *     buf     Storage for a four byte character string.
+ *     val     32 bit integer.
+ */
+
+void
+dst_s_put_int32(u_int8_t *buf, const u_int32_t val)
+{
+       buf[0] = (u_int8_t)(val >> 24);
+       buf[1] = (u_int8_t)(val >> 16);
+       buf[2] = (u_int8_t)(val >> 8);
+       buf[3] = (u_int8_t)(val);
+}
+
+
+/*
+ *  dst_s_filename_length
+ *
+ *     This function returns the number of bytes needed to hold the
+ *     filename for a key file.  '/', '\' and ':' are not allowed.
+ *     form:  K<keyname>+<alg>+<id>.<suffix>
+ *
+ *     Returns 0 if the filename would contain either '\', '/' or ':'
+ */
+size_t
+dst_s_filename_length(const char *name, const char *suffix)
+{
+       if (name == NULL)
+               return (0);
+       if (strrchr(name, '\\'))
+               return (0);
+       if (strrchr(name, '/'))
+               return (0);
+       if (strrchr(name, ':'))
+               return (0);
+       if (suffix == NULL)
+               return (0);
+       if (strrchr(suffix, '\\'))
+               return (0);
+       if (strrchr(suffix, '/'))
+               return (0);
+       if (strrchr(suffix, ':'))
+               return (0);
+       return (1 + strlen(name) + 6 + strlen(suffix));
+}
+
+
+/*
+ *  dst_s_build_filename ()
+ *     Builds a key filename from the key name, it's id, and a
+ *     suffix.  '\', '/' and ':' are not allowed. fA filename is of the
+ *     form:  K<keyname><id>.<suffix>
+ *     form: K<keyname>+<alg>+<id>.<suffix>
+ *
+ *     Returns -1 if the conversion fails:
+ *       if the filename would be too long for space allotted
+ *       if the filename would contain a '\', '/' or ':'
+ *     Returns 0 on success
+ */
+
+int
+dst_s_build_filename(char *filename, const char *name, unsigned id,
+                    int alg, const char *suffix, size_t filename_length)
+{
+       u_int32_t my_id;
+       if (filename == NULL)
+               return (-1);
+       memset(filename, 0, filename_length);
+       if (name == NULL)
+               return (-1);
+       if (suffix == NULL)
+               return (-1);
+       if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix))
+               return (-1);
+       my_id = id;
+       sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id,
+               (const char *) suffix);
+       if (strrchr(filename, '/'))
+               return (-1);
+       if (strrchr(filename, '\\'))
+               return (-1);
+       if (strrchr(filename, ':'))
+               return (-1);
+       return (0);
+}
+
+/*
+ *  dst_s_fopen ()
+ *     Open a file in the dst_path directory.  If perm is specified, the
+ *     file is checked for existence first, and not opened if it exists.
+ *  Parameters
+ *     filename  File to open
+ *     mode       Mode to open the file (passed directly to fopen)
+ *     perm       File permission, if creating a new file.
+ *  Returns
+ *     NULL       Failure
+ *     NON-NULL  (FILE *) of opened file.
+ */
+FILE *
+dst_s_fopen(const char *filename, const char *mode, unsigned perm)
+{
+       FILE *fp;
+       char pathname[PATH_MAX];
+       unsigned plen = sizeof(pathname);
+
+       if (*dst_path != '\0') {
+               strcpy(pathname, dst_path);
+               plen -= strlen(pathname);
+       }
+       else 
+               pathname[0] = '\0';
+
+       if (plen > strlen(filename))
+               strncpy(&pathname[PATH_MAX - plen], filename, plen-1);
+       else 
+               return (NULL);
+       
+       fp = fopen(pathname, mode);
+       if (perm)
+               chmod(pathname, perm);
+       return (fp);
+}
+
+#if 0
+void
+dst_s_dump(const int mode, const u_char *data, const int size, 
+           const char *msg)
+{
+       if (size > 0) {
+#ifdef LONG_TEST
+               static u_char scratch[1000];
+               int n ;
+               n = b64_ntop(data, scratch, size, sizeof(scratch));
+               printf("%s: %x %d %s\n", msg, mode, n, scratch);
+#else
+               printf("%s,%x %d\n", msg, mode, size);
+#endif
+       }
+}
+#endif