From 3b7ddac82abc190861f663beb5b890d110e9010d Mon Sep 17 00:00:00 2001 From: Brian Wellington Date: Fri, 30 Jun 2000 03:24:27 +0000 Subject: [PATCH] Another snapshot. Fixes a crash and removes all occurrences of strtok(), since it wasn't working correctly when the rdata contained multiple tokens. --- bin/nsupdate/nsupdate.c | 402 ++++++++++++++++++++++++++-------------- 1 file changed, 261 insertions(+), 141 deletions(-) diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 595c1639c8..e353a3603f 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -15,7 +15,7 @@ * SOFTWARE. */ -/* $Id: nsupdate.c,v 1.13 2000/06/30 01:59:49 bwelling Exp $ */ +/* $Id: nsupdate.c,v 1.14 2000/06/30 03:24:27 bwelling Exp $ */ #include @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -54,16 +53,17 @@ #include #include +#include #include #include #include #define MXNAME 256 -#define MAXCMD 256 +#define MAXCMD 1024 #define NAMEBUF 512 -#define NAMEHINT 64 +#define WORDLEN 512 #define PACKETSIZE 2048 -#define MSGTEXT 4069 +#define MSGTEXT 4096 #define FIND_TIMEOUT 5 #define RESOLV_CONF "/etc/resolv.conf" @@ -107,20 +107,6 @@ static void sendrequest(int whichns, dns_message_t *msg, #define STATUS_QUIT 2 #define STATUS_SYNTAX 3 -static unsigned int -count_dots(char *s, isc_boolean_t *last_was_dot) { - int i = 0; - *last_was_dot = ISC_FALSE; - while (*s != 0) { - if (*s++ == '.') { - i++; - *last_was_dot = ISC_TRUE; - } else - *last_was_dot = ISC_FALSE; - } - return (i); -} - static void fatal(const char *format, ...) { va_list args; @@ -162,51 +148,179 @@ check_result(isc_result_t result, const char *msg) { fatal("%s: %s", msg, isc_result_totext(result)); } +/* + * Eat characters from FP until EOL or EOF. Returns EOF or '\n' + */ +static int +eatline(FILE *fp) { + int ch; + + ch = fgetc(fp); + while (ch != '\n' && ch != EOF) + ch = fgetc(fp); + return (ch); +} + +/* + * Eats white space up to next newline or non-whitespace character (of + * EOF). Returns the last character read. Comments are considered white + * space. + */ +static int +eatwhite(FILE *fp) { + int ch; + + ch = fgetc(fp); + while (ch != '\n' && ch != EOF && isspace((unsigned char)ch)) + ch = fgetc(fp); + + if (ch == ';' || ch == '#') + ch = eatline(fp); + + return (ch); +} + +/* + * Skip over any leading whitespace and then read in the next sequence of + * non-whitespace characters. In this context newline is not considered + * whitespace. Returns EOF on end-of-file, or the character + * that caused the reading to stop. + */ +static int +getword(FILE *fp, char *buffer, size_t size) { + int ch; + char *p = buffer; + + REQUIRE(buffer != NULL); + REQUIRE(size > 0); + + *p = '\0'; + + ch = eatwhite(fp); + + if (ch == EOF) + return (EOF); + + do { + *p = '\0'; + + if (ch == EOF || isspace((unsigned char)ch)) + break; + else if ((size_t) (p - buffer) == size - 1) + return (EOF); /* Not enough space. */ + + *p++ = (char)ch; + ch = fgetc(fp); + } while (1); + + return (ch); +} + +static char * +nsu_strsep(char **stringp, const char *delim) { + char *string = *stringp; + char *s; + const char *d; + char sc, dc; + + if (string == NULL) + return (NULL); + + for (s = string; *s != '\0'; s++) { + sc = *s; + for (d = delim; (dc = *d) != '\0'; d++) + if (sc == dc) { + *s++ = '\0'; + *stringp = s; + return (string); + } + } + *stringp = NULL; + return (string); +} + + +static unsigned int +count_dots(char *s, isc_boolean_t *last_was_dot) { + int i = 0; + *last_was_dot = ISC_FALSE; + while (*s != 0) { + if (*s++ == '.') { + i++; + *last_was_dot = ISC_TRUE; + } else + *last_was_dot = ISC_FALSE; + } + return (i); +} + static void load_resolv_conf(void) { FILE *fp; - char rcinput[MXNAME]; - char *ptr; + char word[256]; + int stopchar, delim; ddebug ("load_resolv_conf()"); fp = fopen (RESOLV_CONF, "r"); if (fp == NULL) return; - while (fgets(rcinput, MXNAME, fp) != 0) { - ptr = strtok (rcinput, " \t\r\n"); - if (ptr == NULL) - continue; - if (strcasecmp(ptr, "nameserver") == 0) { + do { + stopchar = getword(fp, word, sizeof(word)); + if (stopchar == EOF) + break; + if (strcmp(word, "nameserver") == 0) { ddebug ("Got a nameserver line"); - ptr = strtok (NULL, " \t\r\n"); - if (ptr != NULL) { - if (nameservers >= 3) - continue; - strncpy(nameservername[nameservers], - ptr, MXNAME); - nameservers++; - } - } else if (strcasecmp(ptr, "options") == 0) { - char *endp; - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) + if (nameservers >= 3) { + stopchar = eatline(fp); + if (stopchar == EOF) + break; continue; - if (strncasecmp(ptr, "ndots:", 6) == 0) { - ndots = strtol(&ptr[6], &endp, 10); - if (*endp != 0) - fatal("ndots is not numeric\n"); - ddebug ("ndots is %d.", ndots); } + delim = getword(fp, word, sizeof(word)); + if (strlen(word) == 0) { + stopchar = eatline(fp); + if (stopchar == EOF) + break; + continue; + } + strncpy(nameservername[nameservers], word, MXNAME); + nameservers++; + } else if (strcasecmp(word, "options") == 0) { + delim = getword(fp, word, sizeof(word)); + if (strlen(word) == 0) + continue; + while (strlen(word) > 0) { + char *endp; + if (strncmp("ndots:", word, 6) == 0) { + ndots = strtol(word + 6, &endp, 10); + if (*endp != 0) + fatal("ndots is not numeric\n"); + ddebug ("ndots is %d.", ndots); + } + } + if (delim == EOF || delim == '\n') + break; + else + delim = getword(fp, word, sizeof(word)); /* XXXMWS Searchlist not supported! */ - } else if (strcasecmp(ptr, "domain") == 0 && domain == NULL) { - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) + } else if (strcasecmp(word, "domain") == 0 && domain == NULL) { + delim = getword(fp, word, sizeof(word)); + if (strlen(word) == 0) { + stopchar = eatline(fp); + if (stopchar == EOF) + break; continue; - domain = isc_mem_strdup(mctx, ptr); + } + domain = isc_mem_strdup(mctx, word); if (domain == NULL) fatal("out of memory"); + strncpy(nameservername[nameservers], word, MXNAME); + nameservers++; } - } + stopchar = eatline(fp); + if (stopchar == EOF) + break; + } while (ISC_TRUE); fclose (fp); } @@ -436,9 +550,9 @@ parse_args(int argc, char **argv) { } static isc_uint16_t -make_prereq(isc_boolean_t ispositive, isc_boolean_t isrrset) { +make_prereq(char *cmdline, isc_boolean_t ispositive, isc_boolean_t isrrset) { isc_result_t result; - char *ptr; + char *word; dns_name_t *name = NULL; isc_buffer_t *namebuf = NULL; isc_buffer_t source; @@ -457,8 +571,8 @@ make_prereq(isc_boolean_t ispositive, isc_boolean_t isrrset) { /* * Read the owner name */ - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts("failed to read owner name"); return (STATUS_SYNTAX); } @@ -470,9 +584,9 @@ make_prereq(isc_boolean_t ispositive, isc_boolean_t isrrset) { dns_name_init(name, NULL); dns_name_setbuffer(name, namebuf); dns_message_takebuffer(updatemsg, &namebuf); - isc_buffer_init(&source, ptr, strlen(ptr)); - isc_buffer_add(&source, strlen(ptr)); - dots = count_dots(ptr, &last); + isc_buffer_init(&source, word, strlen(word)); + isc_buffer_add(&source, strlen(word)); + dots = count_dots(word, &last); if (dots > ndots || last) rn = dns_rootname; result = dns_name_fromtext(name, &source, rn, @@ -483,28 +597,27 @@ make_prereq(isc_boolean_t ispositive, isc_boolean_t isrrset) { * If this is an rrset prereq, read the class or type. */ if (isrrset) { - char *ptr; - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts("failed to read class or type"); dns_message_puttempname(updatemsg, &name); return (STATUS_SYNTAX); } - region.base = ptr; - region.length = strlen(ptr); + region.base = word; + region.length = strlen(word); result = dns_rdataclass_fromtext(&rdataclass, ®ion); if (result == ISC_R_SUCCESS) { /* * Now read the type. */ - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts("failed to read type"); dns_message_puttempname(updatemsg, &name); return (STATUS_SYNTAX); } - region.base = ptr; - region.length = strlen(ptr); + region.base = word; + region.length = strlen(word); result = dns_rdatatype_fromtext(&rdatatype, ®ion); check_result(result, "dns_rdatatype_fromtext"); } else { @@ -545,55 +658,57 @@ make_prereq(isc_boolean_t ispositive, isc_boolean_t isrrset) { } static isc_uint16_t -evaluate_prereq(void) { - char *ptr; +evaluate_prereq(char *cmdline) { + char *word; isc_boolean_t ispositive, isrrset; ddebug ("evaluate_prereq()"); - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts ("failed to read operation code"); return (STATUS_SYNTAX); } - if (strcasecmp(ptr, "nxdomain") == 0) { + if (strcasecmp(word, "nxdomain") == 0) { ispositive = ISC_FALSE; isrrset = ISC_FALSE; - } else if (strcasecmp(ptr, "yxdomain") == 0) { + } else if (strcasecmp(word, "yxdomain") == 0) { ispositive = ISC_TRUE; isrrset = ISC_FALSE; - } else if (strcasecmp(ptr, "nxrrset") == 0) { + } else if (strcasecmp(word, "nxrrset") == 0) { ispositive = ISC_FALSE; isrrset = ISC_TRUE; - } else if (strcasecmp(ptr, "yxrrset") == 0) { + } else if (strcasecmp(word, "yxrrset") == 0) { ispositive = ISC_TRUE; isrrset = ISC_TRUE; } else { - printf("incorrect operation code: %s\n", ptr); + printf("incorrect operation code: %s\n", word); return (STATUS_SYNTAX); } - return (make_prereq(ispositive, isrrset)); + return (make_prereq(cmdline, ispositive, isrrset)); } static isc_uint16_t -evaluate_server(void) { +evaluate_server(char *cmdline) { + UNUSED(cmdline); printf("The server statement is not currently implemented.\n"); return (STATUS_MORE); } static isc_uint16_t -evaluate_zone(void) { +evaluate_zone(char *cmdline) { + UNUSED(cmdline); printf("The zone statement is not currently implemented.\n"); return (STATUS_MORE); #if 0 - char *ptr; + char *word; dns_name_t *name; isc_buffer_t src; isc_result_t result; dns_fixedname_t fname; ddebug ("evaluate_zone()"); - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { printf("failed to read zone name"); return (STATUS_SYNTAX); } else if (zonename != NULL) @@ -602,8 +717,8 @@ evaluate_zone(void) { dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); - isc_buffer_init(&src, ptr, strlen(ptr)); - isc_buffer_add(&src, strlen(ptr)); + isc_buffer_init(&src, word, strlen(word)); + isc_buffer_add(&src, strlen(word)); result = dns_name_fromtext(name, &src, dns_rootname, ISC_FALSE, NULL); check_result(result, "dns_name_fromtext"); @@ -622,7 +737,7 @@ evaluate_zone(void) { } static isc_uint16_t -update_addordelete(isc_boolean_t isdelete) { +update_addordelete(char *cmdline, isc_boolean_t isdelete) { isc_result_t result; isc_lex_t *lex = NULL; isc_buffer_t *buf = NULL; @@ -630,7 +745,7 @@ update_addordelete(isc_boolean_t isdelete) { isc_buffer_t source; dns_name_t *name = NULL; isc_uint16_t ttl; - char *ptr, *data; + char *word; dns_rdataclass_t rdataclass; dns_rdatatype_t rdatatype; dns_rdatacallbacks_t callbacks; @@ -648,8 +763,8 @@ update_addordelete(isc_boolean_t isdelete) { /* * Read the owner name */ - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts ("failed to read owner name"); return (STATUS_SYNTAX); } @@ -661,9 +776,9 @@ update_addordelete(isc_boolean_t isdelete) { dns_name_init(name, NULL); dns_name_setbuffer(name, namebuf); dns_message_takebuffer(updatemsg, &namebuf); - isc_buffer_init(&source, ptr, strlen(ptr)); - isc_buffer_add(&source, strlen(ptr)); - dots = count_dots(ptr, &last); + isc_buffer_init(&source, word, strlen(word)); + isc_buffer_add(&source, strlen(word)); + dots = count_dots(word, &last); if (dots > ndots || last) rn = dns_rootname; result = dns_name_fromtext(name, &source, rn, @@ -682,15 +797,15 @@ update_addordelete(isc_boolean_t isdelete) { * If this is an add, read the TTL and verify that it's numeric. */ if (!isdelete) { - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts ("failed to read owner ttl"); dns_message_puttempname(updatemsg, &name); return (STATUS_SYNTAX); } - ttl = strtol(ptr, &endp, 0); + ttl = strtol(word, &endp, 0); if (*endp != 0) { - printf("ttl '%s' is not numeric\n", ptr); + printf("ttl '%s' is not numeric\n", word); dns_message_puttempname(updatemsg, &name); return (STATUS_SYNTAX); } @@ -700,8 +815,8 @@ update_addordelete(isc_boolean_t isdelete) { /* * Read the class or type. */ - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { if (isdelete) { rdataclass = dns_rdataclass_any; rdatatype = dns_rdatatype_any; @@ -712,15 +827,15 @@ update_addordelete(isc_boolean_t isdelete) { return (STATUS_SYNTAX); } } - region.base = ptr; - region.length = strlen(ptr); + region.base = word; + region.length = strlen(word); result = dns_rdataclass_fromtext(&rdataclass, ®ion); if (result == ISC_R_SUCCESS) { /* * Now read the type. */ - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { if (isdelete) { rdataclass = dns_rdataclass_any; rdatatype = dns_rdatatype_any; @@ -731,8 +846,8 @@ update_addordelete(isc_boolean_t isdelete) { return (STATUS_SYNTAX); } } - region.base = ptr; - region.length = strlen(ptr); + region.base = word; + region.length = strlen(word); result = dns_rdatatype_fromtext(&rdatatype, ®ion); check_result(result, "dns_rdatatype_fromtext"); } else { @@ -741,8 +856,10 @@ update_addordelete(isc_boolean_t isdelete) { check_result(result, "dns_rdatatype_fromtext"); } - data = strtok(NULL, " \t\r\n"); - if (data == NULL) { + while (*cmdline != 0 && isspace(*cmdline)) + cmdline++; + + if (*cmdline == 0) { if (isdelete) { rdataclass = dns_rdataclass_any; goto doneparsing; @@ -753,12 +870,12 @@ update_addordelete(isc_boolean_t isdelete) { } } - result = isc_lex_create(mctx, NAMEHINT, &lex); + result = isc_lex_create(mctx, WORDLEN, &lex); check_result(result, "isc_lex_create"); isc_buffer_invalidate(&source); - isc_buffer_init(&source, data, strlen(data)); - isc_buffer_add(&source, strlen(data)); + isc_buffer_init(&source, cmdline, strlen(cmdline)); + isc_buffer_add(&source, strlen(cmdline)); result = isc_lex_openbuffer(lex, &source); check_result(result, "isc_lex_openbuffer"); @@ -797,25 +914,25 @@ update_addordelete(isc_boolean_t isdelete) { } static isc_uint16_t -evaluate_update(void) { - char *ptr; +evaluate_update(char *cmdline) { + char *word; isc_boolean_t isdelete; ddebug ("evaluate_update()"); - ptr = strtok(NULL, " \t\r\n"); - if (ptr == NULL) { + word = nsu_strsep(&cmdline, " \t\r\n"); + if (word == NULL) { puts ("failed to read operation code"); return (STATUS_SYNTAX); } - if (strcasecmp(ptr, "delete") == 0) + if (strcasecmp(word, "delete") == 0) isdelete = ISC_TRUE; - else if (strcasecmp(ptr, "add") == 0) + else if (strcasecmp(word, "add") == 0) isdelete = ISC_FALSE; else { - printf ("incorrect operation code: %s\n",ptr); + printf ("incorrect operation code: %s\n", word); return (STATUS_SYNTAX); } - return (update_addordelete(isdelete)); + return (update_addordelete(cmdline, isdelete)); } static void @@ -839,35 +956,37 @@ show_message(void) { static isc_uint16_t get_next_command(void) { - char cmdline[MAXCMD]; - char *ptr; + char cmdlinebuf[MAXCMD]; + char *cmdline; + char *word; ddebug ("get_next_command()"); fputs ("> ", stderr); - fgets (cmdline, MAXCMD, stdin); - ptr = strtok(cmdline, " \t\r\n"); + fgets (cmdlinebuf, MAXCMD, stdin); + cmdline = cmdlinebuf; + word = nsu_strsep(&cmdline, " \t\r\n"); if (feof(stdin)) - return(STATUS_QUIT); - if (ptr == NULL) - return(STATUS_SEND); - if (strcasecmp(ptr,"quit") == 0) - return(STATUS_QUIT); - if (strcasecmp(ptr,"prereq") == 0) - return(evaluate_prereq()); - if (strcasecmp(ptr,"update") == 0) - return(evaluate_update()); - if (strcasecmp(ptr,"server") == 0) - return(evaluate_server()); - if (strcasecmp(ptr,"zone") == 0) - return(evaluate_zone()); - if (strcasecmp(ptr,"send") == 0) - return(STATUS_SEND); - if (strcasecmp(ptr,"show") == 0) { + return (STATUS_QUIT); + if (word == NULL) + return (STATUS_SEND); + if (strcasecmp(word, "quit") == 0) + return (STATUS_QUIT); + if (strcasecmp(word, "prereq") == 0) + return (evaluate_prereq(cmdline)); + if (strcasecmp(word, "update") == 0) + return (evaluate_update(cmdline)); + if (strcasecmp(word, "server") == 0) + return (evaluate_server(cmdline)); + if (strcasecmp(word, "zone") == 0) + return (evaluate_zone(cmdline)); + if (strcasecmp(word, "send") == 0) + return (STATUS_SEND); + if (strcasecmp(word, "show") == 0) { show_message(); return (STATUS_MORE); } - printf ("incorrect section name: %s\n", ptr); + printf ("incorrect section name: %s\n", word); return (STATUS_SYNTAX); } @@ -876,9 +995,8 @@ user_interaction(void) { isc_uint16_t result = STATUS_MORE; ddebug ("user_interaction()"); - while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) { + while ((result == STATUS_MORE) || (result == STATUS_SYNTAX)) result = get_next_command(); - } if (result == STATUS_SEND) return (ISC_TRUE); return (ISC_FALSE); @@ -1144,6 +1262,13 @@ start_update(void) { dns_name_t *firstname; ddebug ("start_update()"); + + result = dns_message_firstname(updatemsg, DNS_SECTION_UPDATE); + if (result != ISC_R_SUCCESS) { + busy = ISC_FALSE; + return; + } + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &soaquery); check_result(result, "dns_message_create"); @@ -1159,11 +1284,6 @@ start_update(void) { dns_rdataset_makequestion(rdataset, dns_rdataclass_in, dns_rdatatype_soa); - result = dns_message_firstname(updatemsg, DNS_SECTION_UPDATE); - if (result != ISC_R_SUCCESS) { - busy = ISC_FALSE; - return; - } firstname = NULL; dns_message_currentname(updatemsg, DNS_SECTION_UPDATE, &firstname); dns_name_init(name, NULL);