Skip to content

Commit 484ed6d

Browse files
authored
Merge pull request #2053 from jimklimov/issue-2052
Fix segfault in NUT clients with empty host/device name components
2 parents 91b3ee0 + 7c59cf1 commit 484ed6d

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

NEWS.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ as part of https://github.com/networkupstools/nut/issues/1410 solution.
114114
seems to have confused the MGE SHUT (Serial HID UPS Transfer) driver
115115
support [#2022]
116116

117+
- An issue was identified which could cause `libupsclient` parser of device
118+
and host names to crash upon bad inputs (e.g. poorly resolved environment
119+
variables in scripts). Now it should fail more gracefully [#2052]
120+
117121
- New `configure --enable-inplace-runtime` option should set default values
118122
for `--sysconfdir`, `--with-user` and `--with-group` options to match an
119123
existing NUT deployment -- for users who are trying if a custom build

clients/upsclient.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,7 @@ int upscli_tryconnect(UPSCONN_t *ups, const char *host, uint16_t port, int flags
11611161

11621162
pconf_init(&ups->pc_ctx, NULL);
11631163

1164-
ups->host = strdup(host);
1164+
ups->host = xstrdup(host);
11651165

11661166
if (!ups->host) {
11671167
ups->upserror = UPSCLI_ERR_NOMEM;
@@ -1618,22 +1618,45 @@ int upscli_splitname(const char *buf, char **upsname, char **hostname, uint16_t
16181618

16191619
s = strchr(tmp, '@');
16201620

1621-
if ((*upsname = strdup(strtok_r(tmp, "@", &last))) == NULL) {
1622-
fprintf(stderr, "upscli_splitname: strdup failed\n");
1621+
/* someone passed a "@hostname" string? */
1622+
if (s == tmp) {
1623+
fprintf(stderr, "upscli_splitname: got empty upsname string\n");
16231624
return -1;
16241625
}
16251626

1627+
if ((*upsname = xstrdup(strtok_r(tmp, "@", &last))) == NULL) {
1628+
fprintf(stderr, "upscli_splitname: xstrdup failed\n");
1629+
return -1;
1630+
}
1631+
1632+
/* someone passed a "@hostname" string (take two)? */
1633+
if (!**upsname) {
1634+
fprintf(stderr, "upscli_splitname: got empty upsname string\n");
1635+
return -1;
1636+
}
1637+
1638+
/*
1639+
fprintf(stderr, "upscli_splitname3: got buf='%s', tmp='%s', upsname='%s', possible hostname:port='%s'\n",
1640+
NUT_STRARG(buf), NUT_STRARG(tmp), NUT_STRARG(*upsname), NUT_STRARG((s ? s+1 : s)));
1641+
*/
1642+
16261643
/* only a upsname is specified, fill in defaults */
16271644
if (s == NULL) {
1628-
if ((*hostname = strdup("localhost")) == NULL) {
1629-
fprintf(stderr, "upscli_splitname: strdup failed\n");
1645+
if ((*hostname = xstrdup("localhost")) == NULL) {
1646+
fprintf(stderr, "upscli_splitname: xstrdup failed\n");
16301647
return -1;
16311648
}
16321649

16331650
*port = PORT;
16341651
return 0;
16351652
}
16361653

1654+
/* someone passed a "upsname@" string? */
1655+
if (!(*(s+1))) {
1656+
fprintf(stderr, "upscli_splitname: got the @ separator and then an empty hostname[:port] string\n");
1657+
return -1;
1658+
}
1659+
16371660
return upscli_splitaddr(s+1, hostname, port);
16381661
}
16391662

@@ -1659,8 +1682,8 @@ int upscli_splitaddr(const char *buf, char **hostname, uint16_t *port)
16591682
return -1;
16601683
}
16611684

1662-
if ((*hostname = strdup(strtok_r(tmp+1, "]", &last))) == NULL) {
1663-
fprintf(stderr, "upscli_splitaddr: strdup failed\n");
1685+
if ((*hostname = xstrdup(strtok_r(tmp+1, "]", &last))) == NULL) {
1686+
fprintf(stderr, "upscli_splitaddr: xstrdup failed\n");
16641687
return -1;
16651688
}
16661689

@@ -1672,8 +1695,8 @@ int upscli_splitaddr(const char *buf, char **hostname, uint16_t *port)
16721695
} else {
16731696
s = strchr(tmp, ':');
16741697

1675-
if ((*hostname = strdup(strtok_r(tmp, ":", &last))) == NULL) {
1676-
fprintf(stderr, "upscli_splitaddr: strdup failed\n");
1698+
if ((*hostname = xstrdup(strtok_r(tmp, ":", &last))) == NULL) {
1699+
fprintf(stderr, "upscli_splitaddr: xstrdup failed\n");
16771700
return -1;
16781701
}
16791702

common/common.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1738,7 +1738,14 @@ void *xrealloc(void *ptr, size_t size)
17381738

17391739
char *xstrdup(const char *string)
17401740
{
1741-
char *p = strdup(string);
1741+
char *p;
1742+
1743+
if (string == NULL) {
1744+
upsdebugx(1, "%s: got null input", __func__);
1745+
return NULL;
1746+
}
1747+
1748+
p = strdup(string);
17421749

17431750
if (p == NULL)
17441751
fatal_with_errno(EXIT_FAILURE, "%s", oom_msg);

0 commit comments

Comments
 (0)