utils.c | 51 ++++++++++++++++++++++++--- utils.h | 11 +++++- whois.c | 119 +++++++++++++++++++++++++++++--------------------------------- whois.h | 2 +- 4 files changed, 112 insertions(+), 71 deletions(-) diff --git a/utils.c b/utils.c index 59b484b..358f681 100644 --- a/utils.c +++ b/utils.c @@ -51,11 +51,11 @@ char **merge_args(char *args, char *argv[], int *argc) if (!args) return argv; - argstring = NOFAIL(strdup(args)); + argstring = xstrdup(args); for (arg = strtok(argstring, " "); arg; arg = strtok(NULL, " ")) { num_env++; - newargs = NOFAIL(realloc(newargs, - sizeof(newargs[0]) * (num_env + *argc + 1))); + newargs = xrealloc(newargs, + sizeof(newargs[0]) * (num_env + *argc + 1)); newargs[num_env] = arg; } @@ -71,6 +71,48 @@ char **merge_args(char *args, char *argv[], int *argc) return newargs; } +/* Memory allocation routines */ +void *xmalloc(size_t size) +{ + void *ptr; + + if ((ptr = malloc(size)) == NULL) + err_sys("malloc"); + + return ptr; +} + +void *xrealloc(void *ptr, size_t size) +{ + if ((ptr = realloc(ptr, size)) == NULL) + err_sys("realloc"); + + return ptr; +} + +char *xstrdup (const char *s) +{ + char *r = strdup (s); + + if (!r) + err_sys("strdup"); + + return r; +} + +char * +xasprintf(char **ptr, const char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + if (vasprintf(ptr, fmt, arg) < 0) + err_sys("vasprintf"); + va_end(arg); + + return *ptr; +} + /* Error routines */ void err_sys(const char *fmt, ...) { @@ -78,7 +120,7 @@ void err_sys(const char *fmt, ...) va_start(ap, fmt); vfprintf(stderr, fmt, ap); - fprintf(stderr, ": %s\n", strerror(errno)); + fprintf(stderr, ": %m\n"); va_end(ap); exit(2); } @@ -93,4 +135,3 @@ void err_quit(const char *fmt, ...) va_end(ap); exit(2); } - diff --git a/utils.h b/utils.h index d16d5c5..52bae0c 100644 --- a/utils.h +++ b/utils.h @@ -45,7 +45,14 @@ void *do_nofail(void *ptr, const char *file, const int line); char **merge_args(char *args, char *argv[], int *argc); -void err_quit(const char *fmt, ...) NORETURN; -void err_sys(const char *fmt, ...) NORETURN; +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(const char *s); +char *xasprintf(char **ptr, const char *fmt, ...) + __attribute__ ((__format__(__printf__, 2, 3))); +void err_quit(const char *,...) + __attribute__ ((__format__ (__printf__, 1, 2))) NORETURN; +void err_sys(const char *,...) + __attribute__ ((__format__ (__printf__, 1, 2))) NORETURN; #endif diff --git a/whois.c b/whois.c index 20e0c4f..80f64a9 100644 --- a/whois.c +++ b/whois.c @@ -37,10 +37,6 @@ #include "whois.h" #include "utils.h" -/* hack */ -#define malloc(s) NOFAIL(malloc(s)) -#define realloc(p, s) NOFAIL(realloc(p, s)) - /* Global variables */ int sockfd, verb = 0; @@ -71,7 +67,7 @@ int main(int argc, char *argv[]) { int ch, nopar = 0; const char *server = NULL, *port = NULL; - char *p, *qstring, fstring[64] = "\0"; + char *qstring, fstring[64] = "\0"; #ifdef ENABLE_NLS setlocale(LC_ALL, ""); @@ -86,13 +82,13 @@ int main(int argc, char *argv[]) "abBcdFg:Gh:Hi:KlLmMp:q:rRs:St:T:v:V:x", longopts, 0)) > 0) { /* RIPE flags */ if (strchr(ripeflags, ch)) { - for (p = fstring; *p; p++); - sprintf(p--, "-%c ", ch); + size_t len = strlen(fstring); + snprintf(fstring + len, sizeof(fstring) - len, "-%c ", ch); continue; } if (strchr(ripeflagsp, ch)) { - for (p = fstring; *p; p++); - snprintf(p--, sizeof(fstring), "-%c %s ", ch, optarg); + size_t len = strlen(fstring); + snprintf(fstring + len, sizeof(fstring) - len, "-%c %s ", ch, optarg); if (ch == 't' || ch == 'v' || ch == 'q') nopar = 1; continue; @@ -100,7 +96,7 @@ int main(int argc, char *argv[]) /* program flags */ switch (ch) { case 'h': - server = strdup(optarg); + server = xstrdup(optarg); break; case 'V': client_tag = optarg; @@ -108,7 +104,7 @@ int main(int argc, char *argv[]) hide_discl = HIDE_UNSTARTED; /* enable disclaimers hiding */ break; case 'p': - port = strdup(optarg); + port = xstrdup(optarg); break; case 2: verb = 1; @@ -128,7 +124,7 @@ int main(int argc, char *argv[]) usage(); /* On some systems realloc only works on non-NULL buffers */ - qstring = malloc(64); + qstring = xmalloc(64); *qstring = '\0'; /* parse other parameters, if any */ @@ -137,11 +133,11 @@ int main(int argc, char *argv[]) while (1) { qslen += strlen(*argv) + 1 + 1; - qstring = realloc(qstring, qslen); - strcat(qstring, *argv++); + qstring = xrealloc(qstring, qslen); + strncat(qstring, *argv++, qslen-1); if (argc == 1) break; - strcat(qstring, " "); + strncat(qstring, " ", qslen-1); argc--; } } @@ -155,7 +151,7 @@ int main(int argc, char *argv[]) /* -v or -t has been used */ if (!server && !*qstring) - server = strdup("whois.ripe.net"); + server = xstrdup("whois.ripe.net"); #ifdef CONFIG_FILE if (!server) { @@ -188,12 +184,13 @@ const char *handle_query(const char *hserver, const char *hport, { const char *server = NULL, *port = NULL; char *p; + size_t buflen = 0; if (hport) { - server = strdup(hserver); - port = strdup(hport); + server = xstrdup(hserver); + port = xstrdup(hport); } else if (hserver[0] < ' ') - server = strdup(hserver); + server = xstrdup(hserver); else split_server_port(hserver, &server, &port); @@ -265,7 +262,7 @@ const char *handle_query(const char *hserver, const char *hport, if (!server) return NULL; - p = queryformat(server, fstring, qstring); + p = queryformat(server, fstring, qstring, &buflen); if (verb) { printf(_("Using server %s.\n"), server); printf(_("Query string: \"%s\"\n\n"), p); @@ -273,7 +270,7 @@ const char *handle_query(const char *hserver, const char *hport, sockfd = openconn(server, port); - strcat(p, "\r\n"); + strncat(p, "\r\n", buflen-1); server = do_query(sockfd, p); /* recursion is fun */ @@ -337,7 +334,7 @@ const char *match_config_file(const char *s) i = regexec(&re, s, 0, NULL, 0); if (i == 0) { regfree(&re); - return strdup(server); + return xstrdup(server); } if (i != REG_NOMATCH) { char m[1024]; @@ -347,7 +344,7 @@ const char *match_config_file(const char *s) regfree(&re); #else if (domcmp(s, pattern)) - return strdup(server); + return xstrdup(server); #endif } return NULL; @@ -458,26 +455,27 @@ const char *whereas(const unsigned short asn) return "\x06"; } -char *queryformat(const char *server, const char *flags, const char *query) +char *queryformat(const char *server, const char *flags, const char *query, size_t *buflen) { char *buf, *p; int i, isripe = 0; /* 64 bytes reserved for server-specific flags added later */ - buf = malloc(strlen(flags) + strlen(query) + strlen(client_tag) + 64); + *buflen = strlen(flags) + strlen(query) + strlen(client_tag) + 64; + buf = xmalloc(*buflen); *buf = '\0'; for (i = 0; ripe_servers[i]; i++) if (streq(server, ripe_servers[i])) { - strcat(buf, "-V "); - strcat(buf, client_tag); - strcat(buf, " "); + strncat(buf, "-V ", *buflen - 1); + strncat(buf, client_tag, *buflen - 1); + strncat(buf, " ", *buflen - 1); isripe = 1; break; } if (*flags) { if (!isripe && !streq(server, "whois.corenic.net")) puts(_("Warning: RIPE flags used with a traditional server.")); - strcat(buf, flags); + strncat(buf, flags, *buflen - 1); } #ifdef HAVE_LIBIDN @@ -486,33 +484,33 @@ char *queryformat(const char *server, const char *flags, const char *query) */ if (streq(server, "whois.denic.de") && domcmp(query, ".de") && !strchr(query, ' ') && !*flags) - sprintf(buf, "-T dn,ace -C US-ASCII %s", query); + snprintf(buf, *buflen, "-T dn,ace -C US-ASCII %s", query); else /* here we have another registrar who could not make things simple * -C sets the language for both input and output */ if (!isripe && streq(server, "whois.cat") && domcmp(query, ".cat") && !strchr(query, ' ')) - sprintf(buf, "-C US-ASCII ace %s", query); + snprintf(buf, *buflen, "-C US-ASCII ace %s", query); else #endif if (!isripe && (streq(server, "whois.nic.mil") || streq(server, "whois.nic.ad.jp")) && strncaseeq(query, "AS", 2) && isasciidigit(query[2])) /* FIXME: /e is not applied to .JP ASN */ - sprintf(buf, "AS %s", query + 2); /* fix query for DDN */ + snprintf(buf, *buflen, "AS %s", query + 2); /* fix query for DDN */ else if (!isripe && (streq(server, "whois.nic.ad.jp") || streq(server, "whois.jprs.jp"))) { char *lang = getenv("LANG"); /* not a perfect check, but... */ if (!lang || !strneq(lang, "ja", 2)) - sprintf(buf, "%s/e", query); /* ask for english text */ + snprintf(buf, *buflen, "%s/e", query); /* ask for english text */ else - strcat(buf, query); + strncat(buf, query, *buflen - 1); } else if (!isripe && streq(server, "whois.arin.net") && (p = strrchr(query, '/'))) { strncat(buf, query, p - query); /* strip CIDR */ } else - strcat(buf, query); + strncat(buf, query, *buflen - 1); return buf; } @@ -578,8 +576,7 @@ const char *do_query(const int sock, const char *query) if (sscanf(buf, REFERTO_FORMAT, nh, np, nq) == 3) { /* XXX we are ignoring the new query string */ - referral_server = malloc(300); - sprintf(referral_server, "%s:%s", nh, np); + xasprintf(&referral_server, "%s:%s", nh, np); } } @@ -592,9 +589,9 @@ const char *do_query(const int sock, const char *query) q = strstr(buf, "rwhois://"); if ((q = strstr(buf, "rwhois://"))) - referral_server = strdup(q + 9); + referral_server = xstrdup(q + 9); else if ((q = strstr(buf, "whois://"))) - referral_server = strdup(q + 8); + referral_server = xstrdup(q + 8); if (referral_server) { if ((q = strchr(referral_server, '/')) || (q = strchr(referral_server, '\n'))) @@ -627,10 +624,7 @@ const char *query_crsnic(const int sock, const char *query) int hide = hide_discl; int state = 0; - temp = malloc(strlen(query) + 1 + 2 + 1); - *temp = '='; - strcpy(temp + 1, query); - strcat(temp, "\r\n"); + xasprintf(&temp, "=%s\r\n", query); fi = fdopen(sock, "r"); if (write(sock, temp, strlen(temp)) < 0) @@ -645,7 +639,7 @@ const char *query_crsnic(const int sock, const char *query) for (p = buf; *p != ':'; p++); /* skip until colon */ for (p++; *p == ' '; p++); /* skip colon and spaces */ - ret = malloc(strlen(p) + 1); + ret = xmalloc(strlen(p) + 1); for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++) ; /*copy data*/ *q = '\0'; @@ -670,10 +664,7 @@ const char *query_pir(const int sock, const char *query) int hide = hide_discl; int state = 0; - temp = malloc(strlen(query) + 5 + 2 + 1); - strcpy(temp, "FULL "); - strcat(temp, query); - strcat(temp, "\r\n"); + xasprintf(&temp, "FULL %s\r\n", query); fi = fdopen(sock, "r"); if (write(sock, temp, strlen(temp)) < 0) @@ -691,7 +682,7 @@ const char *query_pir(const int sock, const char *query) for (p = buf; *p != ':'; p++); /* skip until colon */ for (p++; *p != ':'; p++); /* skip until 2nd colon */ for (p++; *p == ' '; p++); /* skip colon and spaces */ - ret = malloc(strlen(p) + 1); + ret = xmalloc(strlen(p) + 1); for (q = ret; *p != '\n' && *p != '\r'; *q++ = *p++); /*copy data*/ *q = '\0'; state = 2; @@ -713,7 +704,7 @@ const char *query_afilias(const int sock, const char *query) int hide = hide_discl; int state = 0; - temp = malloc(strlen(query) + 2 + 1); + temp = xmalloc(strlen(query) + 2 + 1); strcpy(temp, query); strcat(temp, "\r\n"); @@ -729,7 +720,7 @@ const char *query_afilias(const int sock, const char *query) for (p = buf; *p != ':'; p++); /* skip until colon */ for (p++; *p == ' '; p++); /* skip colon and spaces */ - ret = malloc(strlen(p) + 1); + ret = xmalloc(strlen(p) + 1); for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++) ; /*copy data*/ *q = '\0'; @@ -848,7 +839,7 @@ char *normalize_domain(const char *dom) char *p, *ret; char *domain_start = NULL; - ret = strdup(dom); + ret = xstrdup(dom); for (p = ret; *p; p++); p--; /* move to the last char */ /* eat trailing dots and blanks */ for (; *p == '.' || *p == ' ' || *p == '\t' || p == ret; p--) @@ -869,7 +860,7 @@ char *normalize_domain(const char *dom) /* reassemble the original query in a new buffer */ prefix_len = domain_start - ret; - r = malloc(prefix_len + strlen(q) + 1); + r = xmalloc(prefix_len + strlen(q) + 1); strncpy(r, ret, prefix_len); r[prefix_len] = '\0'; strcat(r, q); @@ -900,29 +891,29 @@ void split_server_port(const char *const input, char *s; int len = p - input - 1; - *server = s = malloc(len + 1); + *server = s = xmalloc(len + 1); memcpy(s, input + 1, len); *(s + len) = '\0'; p = strchr(p, ':'); if (p && *(p + 1) != '\0') - *port = strdup(p + 1); /* IPv6 + port */ + *port = xstrdup(p + 1); /* IPv6 + port */ } else if ((p = strchr(input, ':')) && /* IPv6, no port */ strchr(p + 1, ':')) { /* and no brackets */ - *server = strdup(input); + *server = xstrdup(input); } else if ((p = strchr(input, ':'))) { /* IPv4 + port */ char *s; int len = p - input; - *server = s = malloc(len + 1); + *server = s = xmalloc(len + 1); memcpy(s, input, len); *(s + len) = '\0'; p++; if (*p != '\0') - *port = strdup(p); + *port = xstrdup(p); } else { /* IPv4, no port */ - *server = strdup(input); + *server = xstrdup(input); } /* change the server name to lower case */ @@ -932,19 +923,20 @@ void split_server_port(const char *const input, char *convert_6to4(const char *s) { - char *new = malloc(sizeof("255.255.255.255")); + char *new = xmalloc(sizeof("255.255.255.255")); unsigned int a, b; if (sscanf(s, "2002:%x:%x:", &a, &b) != 2) return (char *) "0.0.0.0"; - sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff); + sprintf(new, "%d.%d.%d.%d", + (a >> 8) & 0xff, a & 0xff, (b >> 8) & 0xff, b & 0xff); return new; } char *convert_teredo(const char *s) { - char *new = malloc(sizeof("255.255.255.255")); + char *new = xmalloc(sizeof("255.255.255.255")); unsigned int a, b; if (sscanf(s, "2001:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%x:%x", &a, &b) != 2) @@ -952,7 +944,8 @@ char *convert_teredo(const char *s) a ^= 0xffff; b ^= 0xffff; - sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff); + sprintf(new, "%d.%d.%d.%d", + (a >> 8) & 0xff, a & 0xff, (b >> 8) & 0xff, b & 0xff); return new; } diff --git a/whois.h b/whois.h index b15fe98..1c039af 100644 --- a/whois.h +++ b/whois.h @@ -13,7 +13,7 @@ const char *whichwhois(const char *); const char *match_config_file(const char *); const char *whereas(const unsigned short); const char *whereas32(const unsigned long); -char *queryformat(const char *, const char *, const char *); +char *queryformat(const char *, const char *, const char *, size_t *); int hide_line(int *hiding, const char *const line); const char *do_query(const int, const char *); const char *query_crsnic(const int, const char *);