1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

format strings: ban %.*s as some platforms lack it

The %.*s is very handy to print strings where you have a length, but
there is no NUL termination.  It's quite widely supported but at least
one vendor RTOS toolchain doesn't have it.

Since there aren't that many uses of it yet, audit all uses and
convert to a new helper lws_strnncpy() which uses the smaller of
two lengths.
This commit is contained in:
Andy Green 2019-11-04 10:54:50 +00:00
parent 3299c54130
commit 0ab4a707fb
12 changed files with 189 additions and 96 deletions

View file

@ -163,6 +163,14 @@ lws_snprintf(char *str, size_t size, const char *format, ...) LWS_FORMAT(3);
LWS_VISIBLE LWS_EXTERN char *
lws_strncpy(char *dest, const char *src, size_t size);
/*
* Variation where we want to use the smaller of two lengths, useful when the
* source string is not NUL terminated
*/
#define lws_strnncpy(dest, src, size1, destsize) \
lws_strncpy(dest, src, (size_t)(size1 + 1) < (size_t)(destsize) ? \
(size_t)(size1 + 1) : (size_t)(destsize))
/**
* lws_hex_to_byte_array(): convert hex string like 0123456789ab into byte data
*

View file

@ -170,7 +170,7 @@ static int
lws_smtpc_abs_rx(lws_abs_protocol_inst_t *api, const uint8_t *buf, size_t len)
{
lws_smtpcp_t *c = (lws_smtpcp_t *)api;
char at[5];
char dotstar[96], at[5];
int n;
c->abs->at->set_timeout(c->abs->ati, NO_PENDING_TIMEOUT, 0);
@ -186,7 +186,9 @@ lws_smtpc_abs_rx(lws_abs_protocol_inst_t *api, const uint8_t *buf, size_t len)
* even get started, so fail the transport connection
* (and anything queued on it)
*/
lwsl_err("%s: server: %.*s\n", __func__, (int)len, buf);
lws_strnncpy(dotstar, buf, len, sizeof(dotstar));
lwsl_err("%s: server: %s\n", __func__, dotstar);
return 1;
}
@ -213,8 +215,9 @@ lws_smtpc_abs_rx(lws_abs_protocol_inst_t *api, const uint8_t *buf, size_t len)
default:
if (n != retcodes[c->estate]) {
lwsl_notice("%s: bad response: %d (state %d) %.*s\n",
__func__, n, c->estate, (int)len, buf);
lws_strnncpy(dotstar, buf, len, sizeof(dotstar));
lwsl_notice("%s: bad response: %d (state %d) %s\n",
__func__, n, c->estate, dotstar);
lws_smtpc_email_disposition(c,
LWS_SMTP_DISPOSITION_FAILED, buf, len);

View file

@ -323,20 +323,21 @@ LWS_VISIBLE int
lws_jwe_auth_and_decrypt(struct lws_jwe *jwe, char *temp, int *temp_len)
{
int valid_aescbc_hmac, valid_aesgcm;
char dotstar[96];
if (lws_jwe_parse_jose(&jwe->jose, jwe->jws.map.buf[LJWS_JOSE],
jwe->jws.map.len[LJWS_JOSE],
temp, temp_len) < 0) {
lwsl_err("%s: JOSE parse '%.*s' failed\n", __func__,
jwe->jws.map.len[LJWS_JOSE],
jwe->jws.map.buf[LJWS_JOSE]);
lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
lwsl_err("%s: JOSE parse '%s' failed\n", __func__, dotstar);
return -1;
}
if (!jwe->jose.alg) {
lwsl_err("%s: no jose.alg: %.*s\n", __func__,
jwe->jws.map.len[LJWS_JOSE],
jwe->jws.map.buf[LJWS_JOSE]);
lws_strnncpy(dotstar, jwe->jws.map.buf[LJWS_JOSE],
jwe->jws.map.len[LJWS_JOSE], sizeof(dotstar));
lwsl_err("%s: no jose.alg: %s\n", __func__, dotstar);
return -1;
}
@ -757,7 +758,9 @@ lws_jwe_render_flattened(struct lws_jwe *jwe, char *out, size_t out_len)
/* unprotected not supported atm */
p1 += lws_snprintf(p1, end1 - p1, "\",\n\"header\":%.*s", jlen, buf);
p1 += lws_snprintf(p1, end1 - p1, "\",\n\"header\":");
lws_strnncpy(p1, buf, jlen, end1 - p1);
p1 += strlen(p1);
for (m = 0; m < (int)LWS_ARRAY_SIZE(protected_en); m++)
if (jwe->jws.map.buf[protected_idx[m]]) {

View file

@ -300,6 +300,7 @@ cb_jwk(struct lejp_ctx *ctx, char reason)
struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user;
struct lws_jwk *jwk = jps->jwk;
unsigned int idx, poss, n;
char dotstar[64];
if (reason == LEJPCB_VAL_STR_START)
jps->pos = 0;
@ -460,8 +461,8 @@ cb_jwk(struct lejp_ctx *ctx, char reason)
jps->possible = F_EC;
goto cont;
}
lwsl_err("%s: Unknown KTY '%.*s'\n", __func__, ctx->npos,
ctx->buf);
lws_strnncpy(dotstar, ctx->buf, ctx->npos, sizeof(dotstar));
lwsl_err("%s: Unknown KTY '%s'\n", __func__, dotstar);
return -1;
default:
@ -764,9 +765,12 @@ lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
if (!first)
*p++ = ',';
first = 0;
p += lws_snprintf(p, end - p, "\"%s\":\"%.*s\"",
l->name, jwk->meta[l->idx].len,
jwk->meta[l->idx].buf);
p += lws_snprintf(p, end - p, "\"%s\":\"",
l->name);
lws_strnncpy(p, (const char *)jwk->meta[l->idx].buf,
jwk->meta[l->idx].len, end - p);
p += strlen(p);
p += lws_snprintf(p, end - p, "\"");
break;
}
}
@ -780,11 +784,12 @@ lws_jwk_export(struct lws_jwk *jwk, int flags, char *p, int *len)
p += lws_snprintf(p, end - p, "\"%s\":\"", l->name);
if (jwk->kty == LWS_GENCRYPTO_KTY_EC &&
l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV)
m = lws_snprintf(p, end - p, "%.*s",
jwk->e[l->idx].len,
(const char *)jwk->e[l->idx].buf);
else
l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) {
lws_strnncpy(p,
(const char *)jwk->e[l->idx].buf,
jwk->e[l->idx].len, end - p);
m = strlen(p);
} else
m = lws_jws_base64_enc(
(const char *)jwk->e[l->idx].buf,
jwk->e[l->idx].len, p, end - p - 4);

View file

@ -433,7 +433,7 @@ lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n,
m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, n);
lejp_destruct(&jctx);
if (m < 0) {
lwsl_notice("%s: parse %.*s returned %d\n", __func__, n, buf, m);
lwsl_notice("%s: parse returned %d\n", __func__, m);
return -1;
}

View file

@ -895,20 +895,29 @@ lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len)
if (len < 1)
return 1;
n += lws_snprintf(flattened + n, len - n , "{\"payload\": \"%.*s\",\n",
jws->map_b64.len[LJWS_PYLD],
jws->map_b64.buf[LJWS_PYLD]);
n += lws_snprintf(flattened + n, len - n , "{\"payload\": \"");
lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_PYLD],
jws->map_b64.len[LJWS_PYLD], len - n);
n += strlen(flattened + n);
n += lws_snprintf(flattened + n, len - n , " \"protected\": \"%.*s\",\n",
jws->map_b64.len[LJWS_JOSE],
jws->map_b64.buf[LJWS_JOSE]);
n += lws_snprintf(flattened + n, len - n , "\",\n \"protected\": \"");
lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_JOSE],
jws->map_b64.len[LJWS_JOSE], len - n);
n += strlen(flattened + n);
if (jws->map_b64.buf[LJWS_UHDR])
n += lws_snprintf(flattened + n, len - n , " \"header\": %.*s,\n",
jws->map_b64.len[LJWS_UHDR], jws->map_b64.buf[LJWS_UHDR]);
if (jws->map_b64.buf[LJWS_UHDR]) {
n += lws_snprintf(flattened + n, len - n , "\",\n \"header\": ");
lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_UHDR],
jws->map_b64.len[LJWS_UHDR], len - n);
n += strlen(flattened + n);
}
n += lws_snprintf(flattened + n, len - n , " \"signature\": \"%.*s\"}\n",
jws->map_b64.len[LJWS_SIG], jws->map_b64.buf[LJWS_SIG]);
n += lws_snprintf(flattened + n, len - n , "\",\n \"signature\": \"");
lws_strnncpy(flattened + n, jws->map_b64.buf[LJWS_SIG],
jws->map_b64.len[LJWS_SIG], len - n);
n += strlen(flattened + n);
n += lws_snprintf(flattened + n, len - n , "\"}\n");
return (n >= len - 1);
}
@ -921,12 +930,15 @@ lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len)
if (len < 1)
return 1;
n += lws_snprintf(compact + n, len - n , "%.*s",
jws->map_b64.len[LJWS_JOSE], jws->map_b64.buf[LJWS_JOSE]);
n += lws_snprintf(compact + n, len - n , ".%.*s",
jws->map_b64.len[LJWS_PYLD], jws->map_b64.buf[LJWS_PYLD]);
n += lws_snprintf(compact + n, len - n , ".%.*s",
jws->map_b64.len[LJWS_SIG], jws->map_b64.buf[LJWS_SIG]);
lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_JOSE],
jws->map_b64.len[LJWS_JOSE], len - n);
n += strlen(compact + n);
lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_PYLD],
jws->map_b64.len[LJWS_PYLD], len - n);
n += strlen(compact + n);
lws_strnncpy(compact + n, jws->map_b64.buf[LJWS_SIG],
jws->map_b64.len[LJWS_SIG], len - n);
n += strlen(compact + n);
return n >= len - 1;
}

View file

@ -1061,36 +1061,43 @@ html_parser_cb(const hubbub_token *token, void *pw)
{
struct lws_rewrite *r = (struct lws_rewrite *)pw;
char buf[1024], *start = buf + LWS_PRE, *p = start,
*end = &buf[sizeof(buf) - 1];
*end = &buf[sizeof(buf) - 1], dotstar[128];
size_t i;
switch (token->type) {
case HUBBUB_TOKEN_DOCTYPE:
p += lws_snprintf(p, end - p, "<!DOCTYPE %.*s %s ",
(int) token->data.doctype.name.len,
token->data.doctype.name.ptr,
token->data.doctype.force_quirks ?
lws_strnncpy(dotstar, token->data.doctype.name.ptr,
token->data.doctype.name.len, sizeof(dotstar));
p += lws_snprintf(p, end - p, "<!DOCTYPE %s %s ",
dotstar, token->data.doctype.force_quirks ?
"(force-quirks) " : "");
if (token->data.doctype.public_missing)
lwsl_debug("\tpublic: missing\n");
else
p += lws_snprintf(p, end - p, "PUBLIC \"%.*s\"\n",
(int) token->data.doctype.public_id.len,
token->data.doctype.public_id.ptr);
else {
lws_strnncpy(dotstar, token->data.doctype.public_id.ptr,
token->data.doctype.public_id.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, "PUBLIC \"%s\"\n",
dotstar);
}
if (token->data.doctype.system_missing)
lwsl_debug("\tsystem: missing\n");
else
p += lws_snprintf(p, end - p, " \"%.*s\">\n",
(int) token->data.doctype.system_id.len,
token->data.doctype.system_id.ptr);
else {
lws_strnncpy(dotstar, token->data.doctype.system_id.ptr,
token->data.doctype.system_id.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, " \"%s\">\n", dotstar);
}
break;
case HUBBUB_TOKEN_START_TAG:
p += lws_snprintf(p, end - p, "<%.*s", (int)token->data.tag.name.len,
token->data.tag.name.ptr);
lws_strnncpy(dotstar, token->data.tag.name.ptr,
token->data.tag.name.len, sizeof(dotstar));
p += lws_snprintf(p, end - p, "<%s", dotstar);
/* (token->data.tag.self_closing) ?
"(self-closing) " : "",
@ -1111,25 +1118,37 @@ html_parser_cb(const hubbub_token *token, void *pw)
pp += r->from_len;
plen -= r->from_len;
}
p += lws_snprintf(p, end - p, " %.*s=\"%s/%.*s\"",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
r->to, plen, pp);
lws_strnncpy(dotstar,
token->data.tag.attributes[i].name.ptr,
token->data.tag.attributes[i].name.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, " %s=\"%s",
dotstar, r->to);
lws_strnncpy(dotstar, pp, plen, sizeof(dotstar));
p += lws_snprintf(p, end - p, " /%s\"", dotstar);
continue;
}
}
p += lws_snprintf(p, end - p, " %.*s=\"%.*s\"",
(int) token->data.tag.attributes[i].name.len,
lws_strnncpy(dotstar,
token->data.tag.attributes[i].name.ptr,
(int) token->data.tag.attributes[i].value.len,
token->data.tag.attributes[i].value.ptr);
token->data.tag.attributes[i].name.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, " %s=\"", dotstar);
lws_strnncpy(dotstar,
token->data.tag.attributes[i].value.ptr,
token->data.tag.attributes[i].value.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, "%s\"", dotstar);
}
p += lws_snprintf(p, end - p, ">");
break;
case HUBBUB_TOKEN_END_TAG:
p += lws_snprintf(p, end - p, "</%.*s", (int) token->data.tag.name.len,
token->data.tag.name.ptr);
lws_strnncpy(dotstar, token->data.tag.name.ptr,
token->data.tag.name.len, sizeof(dotstar));
p += lws_snprintf(p, end - p, "</%s", dotstar);
/*
(token->data.tag.self_closing) ?
"(self-closing) " : "",
@ -1137,18 +1156,23 @@ html_parser_cb(const hubbub_token *token, void *pw)
"attributes:" : "");
*/
for (i = 0; i < token->data.tag.n_attributes; i++) {
p += lws_snprintf(p, end - p, " %.*s='%.*s'\n",
(int) token->data.tag.attributes[i].name.len,
token->data.tag.attributes[i].name.ptr,
(int) token->data.tag.attributes[i].value.len,
token->data.tag.attributes[i].value.ptr);
lws_strnncpy(dotstar,
token->data.tag.attributes[i].name.ptr,
token->data.tag.attributes[i].name.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, " %s='", dotstar);
lws_strnncpy(dotstar,
token->data.tag.attributes[i].value.ptr,
token->data.tag.attributes[i].value.len,
sizeof(dotstar));
p += lws_snprintf(p, end - p, "%s'\n", dotstar);
}
p += lws_snprintf(p, end - p, ">");
break;
case HUBBUB_TOKEN_COMMENT:
p += lws_snprintf(p, end - p, "<!-- %.*s -->\n",
(int) token->data.comment.len,
token->data.comment.ptr);
lws_strnncpy(dotstar, token->data.comment.ptr,
token->data.comment.len, sizeof(dotstar));
p += lws_snprintf(p, end - p, "<!-- %s -->\n", dotstar);
break;
case HUBBUB_TOKEN_CHARACTER:
if (token->data.character.len == 1) {
@ -1165,9 +1189,9 @@ html_parser_cb(const hubbub_token *token, void *pw)
break;
}
}
p += lws_snprintf(p, end - p, "%.*s", (int) token->data.character.len,
token->data.character.ptr);
lws_strnncpy(dotstar, token->data.character.ptr,
token->data.character.len, sizeof(dotstar));
p += lws_snprintf(p, end - p, "%s", dotstar);
break;
case HUBBUB_TOKEN_EOF:
p += lws_snprintf(p, end - p, "\n");

View file

@ -1108,6 +1108,11 @@ swallow:
#if defined(LWS_WITH_CUSTOM_HEADERS)
if (!wsi->http2_substream && pos < 0 && c == ':') {
#if defined(_DEBUG)
char dotstar[64];
int uhlen;
#endif
/*
* process unknown headers
*
@ -1124,11 +1129,16 @@ swallow:
ah->unk_ll_tail = ah->unk_pos;
lwsl_debug("%s: unk header %d '%.*s'\n",
__func__,
ah->pos - (ah->unk_pos + UHO_NAME),
ah->pos - (ah->unk_pos + UHO_NAME),
&ah->data[ah->unk_pos + UHO_NAME]);
#if defined(_DEBUG)
uhlen = ah->pos - (ah->unk_pos + UHO_NAME);
lws_strnncpy(dotstar,
&ah->data[ah->unk_pos + UHO_NAME],
uhlen, sizeof(dotstar));
lwsl_debug("%s: unk header %d '%s'\n",
__func__,
ah->pos - (ah->unk_pos + UHO_NAME),
dotstar);
#endif
/* set the unknown header name part length */

View file

@ -368,7 +368,7 @@ lws_process_ws_upgrade2(struct lws *wsi)
#if defined(LWS_WITH_ACCESS_LOG)
{
char *uptr = "unknown method", combo[128];
char *uptr = "unknown method", combo[128], dotstar[64];
int l = 14, meth = lws_http_get_uri_and_method(wsi, &uptr, &l);
if (wsi->h2_stream_carries_ws)
@ -376,7 +376,8 @@ lws_process_ws_upgrade2(struct lws *wsi)
wsi->http.access_log.response = 101;
l = lws_snprintf(combo, sizeof(combo), "%.*s (%s)", l, uptr,
lws_strnncpy(dotstar, uptr, l, sizeof(dotstar));
l = lws_snprintf(combo, sizeof(combo), "%s (%s)", dotstar,
wsi->protocol->name);
lws_prepare_access_log_info(wsi, combo, l, meth);

View file

@ -24,9 +24,11 @@ static int
done_cb(struct lws_smtp_email *email, void *buf, size_t len)
{
/* you could examine email->data here */
if (buf)
lwsl_notice("%s: %.*s\n", __func__, (int)len, (const char *)buf);
else
if (buf) {
char dotstar[96];
lws_strnncpy(dotstar, (const char *)buf, len, sizeof(dotstar));
lwsl_notice("%s: %s\n", __func__, dotstar);
} else
lwsl_notice("%s:\n", __func__);
/* destroy any allocations in email */

View file

@ -290,6 +290,7 @@ int main(int argc, const char **argv)
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
/* | LLL_DEBUG */;
int fail = 0, ok = 0, flags = 0;
char dotstar[512];
if ((p = lws_cmdline_option(argc, argv, "-d")))
logs = atoi(p);
@ -300,6 +301,21 @@ int main(int argc, const char **argv)
if ((p = lws_cmdline_option(argc, argv, "-f")))
flags = atoi(p);
/* sanity check lws_strnncpy() */
lws_strnncpy(dotstar, "12345678", 4, sizeof(dotstar));
if (strcmp(dotstar, "1234")) {
lwsl_err("%s: lws_strnncpy check failed\n", __func__);
return 1;
}
lws_strnncpy(dotstar, "12345678", 8, 6);
if (strcmp(dotstar, "12345")) {
lwsl_err("%s: lws_strnncpy check failed\n", __func__);
return 1;
}
p = lws_cmdline_option(argc, argv, "-s");
for (n = 0; n < (int)LWS_ARRAY_SIZE(tests); n++) {
@ -314,9 +330,10 @@ int main(int argc, const char **argv)
do {
e = lws_tokenize(&ts);
lwsl_info("{ %s, \"%.*s\", %d }\n",
element_names[e + LWS_TOKZE_ERRS],
(int)ts.token_len, ts.token,
lws_strnncpy(dotstar, ts.token, ts.token_len,
sizeof(dotstar));
lwsl_info("{ %s, \"%s\", %d }\n",
element_names[e + LWS_TOKZE_ERRS], dotstar,
(int)ts.token_len);
if (m == (int)tests[n].count) {
@ -336,8 +353,10 @@ int main(int argc, const char **argv)
if (e > 0 &&
(ts.token_len != exp->len ||
memcmp(exp->value, ts.token, exp->len))) {
lwsl_notice("fail token mismatch %d %d %.*s\n",
ts.token_len, exp->len, ts.token_len, ts.token);
lws_strnncpy(dotstar, ts.token, ts.token_len,
sizeof(dotstar));
lwsl_notice("fail token mismatch %d %d %s\n",
ts.token_len, exp->len, dotstar);
fail++;
break;
}
@ -399,10 +418,12 @@ int main(int argc, const char **argv)
do {
e = lws_tokenize(&ts);
printf("\t\t{ %s, \"%.*s\", %d },\n",
lws_strnncpy(dotstar, ts.token, ts.token_len,
sizeof(dotstar));
printf("\t\t{ %s, \"%s\", %d },\n",
element_names[e + LWS_TOKZE_ERRS],
(int)ts.token_len,
ts.token, (int)ts.token_len);
dotstar, (int)ts.token_len);
} while (e > 0);

View file

@ -62,9 +62,13 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
lwsl_user("RECEIVE_CLIENT_HTTP_READ: read %d\n", (int)len);
#if defined(LWS_WITH_HTTP2)
if (long_poll)
lwsl_notice("long poll rx: '%.*s'\n",
(int)len, (const char *)in);
if (long_poll) {
char dotstar[128];
lws_strnncpy(dotstar, (const char *)in, len,
sizeof(dotstar));
lwsl_notice("long poll rx: %d '%s'\n", (int)len,
dotstar);
}
#endif
#if 0 /* enable to dump the html */
{