[LWN Logo]

Date:	Mon, 31 Aug 1998 12:51:35 -0600
From:	Theo de Raadt <deraadt@CVS.OPENBSD.ORG>
Subject:      nslookup issues
To:	BUGTRAQ@NETSPACE.ORG

Well, here's a first cut at fixing some of the nslookup/dig problems.
This patch should get people started at repairing their distributions.
If anyone has any further fixes or notes some other issues in this
area, please let me know.

As we've seen in the past, stuff in the DNS package continues to be
garbage.

Index: dig/dig.c
===================================================================
RCS file: /cvs/src/usr.sbin/named/dig/dig.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- dig.c       1997/07/21 02:10:56     1.4
+++ dig.c       1998/08/30 03:39:18     1.5
@@ -765,9 +765,11 @@
     char       option[NAME_LEN];
     char       type[NAME_LEN];
     char       *ptr;
+    char       get[80];
     int        i;

-    i = sscanf(string, " %s", option);
+    snprintf(get, sizeof get, " %%%ds", sizeof option-1);
+    i = sscanf(string, get, option);
     if (i != 1) {
        fprintf(stderr, ";*** Invalid option: %s\n",  option);
        return(ERROR);
@@ -800,7 +802,8 @@
        } else if (strncmp(option, "do", 2) == 0) {     /* domain */
            ptr = strchr(option, '=');
            if (ptr != NULL) {
-               sscanf(++ptr, "%s", _res.defdname);
+               snprintf(get, sizeof get, "%%%ds", sizeof _res.defdname-1);
+               sscanf(++ptr, get, _res.defdname);
            }
          } else if (strncmp(option, "ti", 2) == 0) {      /* timeout */
            ptr = strchr(option, '=');
Index: nslookup/list.c
===================================================================
RCS file: /cvs/src/usr.sbin/named/nslookup/list.c,v
retrieving revision 1.2
diff -u -r1.2 list.c
--- list.c      1997/03/12 10:42:47     1.2
+++ list.c      1998/08/31 17:39:27
@@ -156,13 +156,16 @@
        char    *namePtr;
        char    name[NAME_LEN];
        char    option[NAME_LEN];
+       char    get[80];

        /*
         *  Parse the command line. It maybe of the form "ls -t domain"
         *  or "ls -t type domain".
         */

-       i = sscanf(string, " ls -t %s %s", option, name);
+       snprintf(get, sizeof get, " ls -t %%%ds %%%ds", sizeof option-1,
+           sizeof name-1);
+       i = sscanf(string, get, option, name);
        if (putToFile && i == 2 && name[0] == '>') {
            i--;
        }
@@ -193,12 +196,15 @@
        char    *namePtr;
        char    name[NAME_LEN];
        char    option[NAME_LEN];
+       char    get[80];

        /*
         *  Parse the command line. It maybe of the form "ls domain",
         *  "ls -X domain".
         */
-       i = sscanf(string, " ls %s %s", option, name);
+       snprintf(get, sizeof get, " ls -t %%%ds %%%ds", sizeof option-1,
+           sizeof name-1);
+       i = sscanf(string, get, option, name);
        if (putToFile && i == 2 && name[0] == '>') {
            i--;
        }
@@ -521,6 +527,8 @@
 }


+#define NAME_SLOP 80
+
 PrintListInfo(file, msg, eom, qtype, domain)
     FILE       *file;
     u_char     *msg, *eom;
@@ -533,7 +541,7 @@
     u_int32_t          ttl;
     int                        n, pref, count;
     struct in_addr     inaddr;
-    char               name[NAME_LEN];
+    char               name[NAME_LEN + NAME_SLOP];
     char               name2[NAME_LEN];
     Boolean            stripped;

@@ -562,7 +570,7 @@
        cp += nameLen + QFIXEDSZ;
     }
     for (count = ntohs(headerPtr->ancount); count > 0; count--) {
-       nameLen = dn_expand(msg, eom, cp, name, sizeof name);
+       nameLen = dn_expand(msg, eom, cp, name, NAME_LEN);
        if (nameLen < 0)
            return (ERROR);
        cp += nameLen;
@@ -592,7 +600,7 @@
            }
        }
        if (!stripped && nameLen < sizeof(name)-1) {
-           strcat(name, ".");
+           strncat(name, ".", sizeof(name) - strlen(name) - 1);
        }

        fprintf(file, NAME_FORMAT, name);
@@ -901,8 +909,10 @@
 {
     char file[PATH_MAX];
     char command[PATH_MAX];
+    char get[80];

-    sscanf(string, " view %s", file);
+    snprintf(get, sizeof get, " view %%%ds", sizeof file-1);
+    sscanf(string, get, file);
     (void)sprintf(command, "grep \"^ \" %s | sort | %s", file, pager);
     system(command);
 }
@@ -936,6 +946,7 @@
        register int            lastc;
        char                    name[NAME_LEN];
        char                    file[NAME_LEN];
+       char                    get[80];

        /*
         *  We need a valid current host info to get an inet address.
@@ -945,7 +956,8 @@
            return (ERROR);
        }

-       if (sscanf(string, " finger %s", name) == 1) {
+       snprintf(get, sizeof get, " finger %%%ds", sizeof name-1);
+       if (sscanf(string, get, name) == 1) {
            if (putToFile && (name[0] == '>')) {
                name[0] = '\0';
            }
Index: nslookup/main.c
===================================================================
RCS file: /cvs/src/usr.sbin/named/nslookup/main.c,v
retrieving revision 1.3
diff -u -r1.3 main.c
--- main.c      1997/03/12 10:42:48     1.3
+++ main.c      1998/08/31 17:43:19
@@ -465,6 +465,7 @@
     struct in_addr     *servAddrPtr;
     struct in_addr     addr;
     char               newServer[NAME_LEN];
+    char               get[40];
     int                        result;
     int                        i;

@@ -474,12 +475,15 @@
      */

     if (local) {
-       i = sscanf(string, " lserver %s", newServer);
+       snprintf(get, sizeof get, "lserver %%%ds", sizeof newServer-1);
+       i = sscanf(string, get, newServer);
     } else {
-       i = sscanf(string, " server %s", newServer);
+       snprintf(get, sizeof get, "server %%%ds", sizeof newServer-1);
+       i = sscanf(string, get, newServer);
     }
     if (i != 1) {
-       i = sscanf(string, " %s", newServer);
+       snprintf(get, sizeof get, " %%%ds", sizeof newServer-1);
+       i = sscanf(string, get, newServer);
        if (i != 1) {
            fprintf(stderr,"SetDefaultServer: invalid name: %s\n",  string);
            return(ERROR);
@@ -669,6 +673,7 @@
 {
     char       host[NAME_LEN];
     char       file[PATH_MAX];
+    char       get[20];
     int                result;

     /*
@@ -684,7 +689,8 @@
      *
      */

-    sscanf(string, " %s", host);       /* removes white space */
+    snprintf(get, sizeof get, " %%%ds", sizeof host-1);
+    sscanf(string, get, host); /* removes white space */
     if (!putToFile) {
        filePtr = stdout;
     } else {
@@ -740,12 +746,15 @@
     char       file[PATH_MAX];
     char       host[NAME_LEN];
     char       server[NAME_LEN];
+    char       get[80];
     int                result;
+
     static HostInfo serverInfo;

     curHostValid = FALSE;

-    sscanf(string, " %s %s", host, server);
+    snprintf(get, sizeof get, " %%%ds %%%ds", sizeof host-1, sizeof server-1);
+    sscanf(string, get, host, server);
     if (!putToFile) {
        filePtr = stdout;
     } else {
@@ -824,6 +833,7 @@
     register char *option;
 {
     char       type[NAME_LEN];
+    char       get[40];
     char       *ptr;
     int                tmp;

@@ -854,7 +864,8 @@
        } else if (strncmp(option, "do", 2) == 0) {     /* domain */
            ptr = strchr(option, '=');
            if (ptr != NULL) {
-               sscanf(++ptr, "%s", _res.defdname);
+               snprintf(get, sizeof get, "%%%ds", sizeof _res.defdname-1);
+               sscanf(++ptr, get, _res.defdname);
                res_re_init();
            }
        } else if (strncmp(option, "deb", 1) == 0) {    /* debug */
@@ -880,13 +891,15 @@
          strncmp(option, "ty", 2) == 0) {              /* type */
            ptr = strchr(option, '=');
            if (ptr != NULL) {
-               sscanf(++ptr, "%s", type);
+               snprintf(get, sizeof get, "%%%ds", sizeof type-1);
+               sscanf(++ptr, get, type);
                queryType = StringToType(type, queryType, stderr);
            }
        } else if (strncmp(option, "cl", 2) == 0) {     /* query class */
            ptr = strchr(option, '=');
            if (ptr != NULL) {
-               sscanf(++ptr, "%s", type);
+               snprintf(get, sizeof get, "%%%ds", sizeof type-1);
+               sscanf(++ptr, get, type);
                queryClass = StringToClass(type, queryClass, stderr);
            }
        } else if (strncmp(option, "rec", 3) == 0) {    /* recurse */
@@ -904,7 +917,8 @@
        } else if (strncmp(option, "ro", 2) == 0) {     /* root */
            ptr = strchr(option, '=');
            if (ptr != NULL) {
-               sscanf(++ptr, "%s", rootServerName);
+               snprintf(get, sizeof get, "%%%ds", sizeof rootServerName-1);
+               sscanf(++ptr, get, rootServerName);
            }
        } else if (strncmp(option, "sea", 3) == 0) {    /* search list */
            _res.options |= RES_DNSRCH;
@@ -967,6 +981,7 @@
     int n;

     (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+    _res.defdname[sizeof(_res.defdname) - 1] = '\0';
     if ((cp = strchr(_res.defdname, '\n')) != NULL)
            *cp = '\0';
     /*
@@ -1111,8 +1126,9 @@
     if ((cp = getenv("HOME")) != NULL &&
        (strlen(cp) + strlen(_PATH_NSLOOKUPRC)) < sizeof(buf)) {

-       (void) strcpy(buf, cp);
-       (void) strcat(buf, _PATH_NSLOOKUPRC);
+       (void) strncpy(buf, cp, sizeof buf - 1);
+       buf[sizeof buf - 1] = '\0';
+       (void) strncat(buf, _PATH_NSLOOKUPRC, sizeof buf - strlen(buf) - 1);

        if ((fp = fopen(buf, "r")) != NULL) {
            while (fgets(buf, sizeof(buf), fp) != NULL) {
Index: nslookup/subr.c
===================================================================
RCS file: /cvs/src/usr.sbin/named/nslookup/subr.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- subr.c      1997/03/12 10:42:51     1.2
+++ subr.c      1998/08/30 03:39:21     1.3
@@ -343,6 +343,7 @@
 {
        char    *redirect;
        FILE    *tmpPtr;
+       char    get[80];

        /*
         *  Open an output file if we see '>' or >>'.
@@ -354,10 +355,12 @@
            return(NULL);
        }
        if (redirect[1] == '>') {
-           sscanf(redirect, ">> %s", file);
+           snprintf(get, sizeof get, ">> %%%ds", sizeof file-1);
+           sscanf(redirect, get, file);
            tmpPtr = fopen(file, "a+");
        } else {
-           sscanf(redirect, "> %s", file);
+           snprintf(get, sizeof get, "> %%%ds", sizeof file-1);
+           sscanf(redirect, get, file);
            tmpPtr = fopen(file, "w");
        }