mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
conf: enforce UTF8 validty everywhere
we need to make sure that configuration data we expose via the bus ends up in using getting an assert(). Even though configuration data is only parsed from trusted sources we should be more careful with what we read.
This commit is contained in:
parent
669e49fe2c
commit
7f110ff9b8
@ -468,7 +468,8 @@ libsystemd_basic_la_SOURCES = \
|
||||
src/socket-util.c \
|
||||
src/log.c \
|
||||
src/ratelimit.c \
|
||||
src/exit-status.c
|
||||
src/exit-status.c \
|
||||
src/utf8.c
|
||||
|
||||
libsystemd_basic_la_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
@ -649,7 +650,8 @@ EXTRA_DIST += \
|
||||
src/dbus-loop.h \
|
||||
src/spawn-agent.h \
|
||||
src/acl-util.h \
|
||||
src/logs-show.h
|
||||
src/logs-show.h \
|
||||
src/utf8.h
|
||||
|
||||
MANPAGES = \
|
||||
man/systemd.1 \
|
||||
|
6
TODO
6
TODO
@ -18,6 +18,10 @@ Bugfixes:
|
||||
|
||||
Features:
|
||||
|
||||
* document crypttab(5)
|
||||
|
||||
* There's currently no way to cancel fsck (used to be possible via C-c or c on the console)
|
||||
|
||||
* hook up /dev/watchdog with main event loop for embedded, server uses
|
||||
|
||||
* man: for some reason the HTML versions of the man pages are currently not being packaged
|
||||
@ -115,8 +119,6 @@ Features:
|
||||
|
||||
* document that %% can be used to write % in a string that is specifier extended
|
||||
|
||||
* check utf8 everywhere
|
||||
|
||||
* when an instanced service exits, remove its parent cgroup too if possible.
|
||||
|
||||
* Make libselinux, libattr, libcap, libdl dependencies only of the tools which actually need them.
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "macro.h"
|
||||
#include "strv.h"
|
||||
#include "log.h"
|
||||
#include "utf8.h"
|
||||
|
||||
int config_item_table_lookup(
|
||||
void *table,
|
||||
@ -584,14 +585,23 @@ int config_parse_string(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (*rvalue) {
|
||||
if (!(n = strdup(rvalue)))
|
||||
return -ENOMEM;
|
||||
} else
|
||||
n = NULL;
|
||||
n = cunescape(rvalue);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!utf8_is_valid(n)) {
|
||||
log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(*s);
|
||||
*s = n;
|
||||
if (*n)
|
||||
*s = n;
|
||||
else {
|
||||
free(n);
|
||||
*s = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -614,12 +624,18 @@ int config_parse_path(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (!utf8_is_valid(rvalue)) {
|
||||
log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!path_is_absolute(rvalue)) {
|
||||
log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(n = strdup(rvalue)))
|
||||
n = strdup(rvalue);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
path_kill_slashes(n);
|
||||
@ -646,6 +662,7 @@ int config_parse_strv(
|
||||
unsigned k;
|
||||
size_t l;
|
||||
char *state;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -656,7 +673,8 @@ int config_parse_strv(
|
||||
FOREACH_WORD_QUOTED(w, l, rvalue, state)
|
||||
k++;
|
||||
|
||||
if (!(n = new(char*, k+1)))
|
||||
n = new(char*, k+1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (*sv)
|
||||
@ -665,9 +683,21 @@ int config_parse_strv(
|
||||
else
|
||||
k = 0;
|
||||
|
||||
FOREACH_WORD_QUOTED(w, l, rvalue, state)
|
||||
if (!(n[k++] = cunescape_length(w, l)))
|
||||
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
|
||||
n[k] = cunescape_length(w, l);
|
||||
if (!n[k]) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!utf8_is_valid(n[k])) {
|
||||
log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
|
||||
free(n[k]);
|
||||
continue;
|
||||
}
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
n[k] = NULL;
|
||||
free(*sv);
|
||||
@ -680,7 +710,7 @@ fail:
|
||||
free(n[k-1]);
|
||||
free(n);
|
||||
|
||||
return -ENOMEM;
|
||||
return r;
|
||||
}
|
||||
|
||||
int config_parse_path_strv(
|
||||
@ -710,7 +740,8 @@ int config_parse_path_strv(
|
||||
FOREACH_WORD_QUOTED(w, l, rvalue, state)
|
||||
k++;
|
||||
|
||||
if (!(n = new(char*, k+1)))
|
||||
n = new(char*, k+1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
k = 0;
|
||||
@ -719,11 +750,18 @@ int config_parse_path_strv(
|
||||
n[k] = (*sv)[k];
|
||||
|
||||
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
|
||||
if (!(n[k] = cunescape_length(w, l))) {
|
||||
n[k] = strndup(w, l);
|
||||
if (!n[k]) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!utf8_is_valid(n[k])) {
|
||||
log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
|
||||
free(n[k]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!path_is_absolute(n[k])) {
|
||||
log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
|
||||
free(n[k]);
|
||||
@ -731,7 +769,6 @@ int config_parse_path_strv(
|
||||
}
|
||||
|
||||
path_kill_slashes(n[k]);
|
||||
|
||||
k++;
|
||||
}
|
||||
|
||||
@ -742,7 +779,6 @@ int config_parse_path_strv(
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
free(n[k]);
|
||||
for (; k > 0; k--)
|
||||
free(n[k-1]);
|
||||
free(n);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "missing.h"
|
||||
#include "unit-name.h"
|
||||
#include "bus-errors.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#ifndef HAVE_SYSV_COMPAT
|
||||
int config_parse_warn_compat(
|
||||
@ -90,7 +91,6 @@ int config_parse_unit_deps(
|
||||
|
||||
k = unit_name_printf(u, t);
|
||||
free(t);
|
||||
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -128,22 +128,18 @@ int config_parse_unit_names(
|
||||
char *t, *k;
|
||||
int r;
|
||||
|
||||
if (!(t = strndup(w, l)))
|
||||
t = strndup(w, l);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
k = unit_name_printf(u, t);
|
||||
free(t);
|
||||
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
r = unit_merge_by_name(u, k);
|
||||
|
||||
if (r < 0) {
|
||||
if (r < 0)
|
||||
log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
|
||||
free(k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(k);
|
||||
}
|
||||
@ -162,27 +158,22 @@ int config_parse_unit_string_printf(
|
||||
void *userdata) {
|
||||
|
||||
Unit *u = userdata;
|
||||
char **s = data;
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(s);
|
||||
assert(u);
|
||||
|
||||
if (!(k = unit_full_printf(u, rvalue)))
|
||||
k = unit_full_printf(u, rvalue);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
free(*s);
|
||||
if (*k)
|
||||
*s = k;
|
||||
else {
|
||||
free(k);
|
||||
*s = NULL;
|
||||
}
|
||||
r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
|
||||
free (k);
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int config_parse_unit_strv_printf(
|
||||
@ -225,30 +216,22 @@ int config_parse_unit_path_printf(
|
||||
void *userdata) {
|
||||
|
||||
Unit *u = userdata;
|
||||
char **s = data;
|
||||
char *k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(s);
|
||||
assert(u);
|
||||
|
||||
if (!(k = unit_full_printf(u, rvalue)))
|
||||
k = unit_full_printf(u, rvalue);
|
||||
if (!k)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!path_is_absolute(k)) {
|
||||
log_error("[%s:%u] Not an absolute path: %s", filename, line, k);
|
||||
free(k);
|
||||
return -EINVAL;
|
||||
}
|
||||
r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
|
||||
free(k);
|
||||
|
||||
path_kill_slashes(k);
|
||||
|
||||
free(*s);
|
||||
*s = k;
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
int config_parse_socket_listen(
|
||||
@ -271,7 +254,8 @@ int config_parse_socket_listen(
|
||||
|
||||
s = SOCKET(data);
|
||||
|
||||
if (!(p = new0(SocketPort, 1)))
|
||||
p = new0(SocketPort, 1);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
if (streq(lvalue, "ListenFIFO")) {
|
||||
@ -478,6 +462,7 @@ int config_parse_exec(
|
||||
ExecCommand **e = data, *nce;
|
||||
char *path, **n;
|
||||
unsigned k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
@ -528,7 +513,8 @@ int config_parse_exec(
|
||||
k++;
|
||||
}
|
||||
|
||||
if (!(n = new(char*, k + !honour_argv0)))
|
||||
n = new(char*, k + !honour_argv0);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
k = 0;
|
||||
@ -538,11 +524,33 @@ int config_parse_exec(
|
||||
|
||||
if (honour_argv0 && w == rvalue) {
|
||||
assert(!path);
|
||||
if (!(path = cunescape_length(w, l)))
|
||||
|
||||
path = strndup(w, l);
|
||||
if (!path) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!utf8_is_valid(path)) {
|
||||
log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
|
||||
r = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!(n[k++] = cunescape_length(w, l)))
|
||||
char *c;
|
||||
|
||||
c = n[k++] = cunescape_length(w, l);
|
||||
if (!c) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!utf8_is_valid(c)) {
|
||||
log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
|
||||
r = 0;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,19 +558,25 @@ int config_parse_exec(
|
||||
|
||||
if (!n[0]) {
|
||||
log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
|
||||
strv_free(n);
|
||||
free(path);
|
||||
return 0;
|
||||
r = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!path)
|
||||
if (!(path = strdup(n[0])))
|
||||
if (!path) {
|
||||
path = strdup(n[0]);
|
||||
if (!path) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
assert(path_is_absolute(path));
|
||||
|
||||
if (!(nce = new0(ExecCommand, 1)))
|
||||
nce = new0(ExecCommand, 1);
|
||||
if (!nce) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nce->argv = n;
|
||||
nce->path = path;
|
||||
@ -583,7 +597,7 @@ fail:
|
||||
free(path);
|
||||
free(nce);
|
||||
|
||||
return -ENOMEM;
|
||||
return r;
|
||||
}
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "exit-status.h"
|
||||
#include "def.h"
|
||||
#include "util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
|
||||
@ -3200,11 +3201,19 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
|
||||
}
|
||||
|
||||
/* Interpret STATUS= */
|
||||
if ((e = strv_find_prefix(tags, "STATUS="))) {
|
||||
e = strv_find_prefix(tags, "STATUS=");
|
||||
if (e) {
|
||||
char *t;
|
||||
|
||||
if (e[7]) {
|
||||
if (!(t = strdup(e+7))) {
|
||||
|
||||
if (!utf8_is_valid(e+7)) {
|
||||
log_warning("Status message in notification is not UTF-8 clean.");
|
||||
return;
|
||||
}
|
||||
|
||||
t = strdup(e+7);
|
||||
if (!t) {
|
||||
log_error("Failed to allocate string.");
|
||||
return;
|
||||
}
|
||||
|
214
src/utf8.c
Normal file
214
src/utf8.c
Normal file
@ -0,0 +1,214 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
/* This file is based on the GLIB utf8 validation functions. The
|
||||
* original license text follows. */
|
||||
|
||||
/* gutf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
#define FILTER_CHAR '_'
|
||||
|
||||
static inline bool is_unicode_valid(uint32_t ch) {
|
||||
|
||||
if (ch >= 0x110000) /* End of unicode space */
|
||||
return false;
|
||||
if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
|
||||
return false;
|
||||
if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
|
||||
return false;
|
||||
if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool is_continuation_char(uint8_t ch) {
|
||||
if ((ch & 0xc0) != 0x80) /* 10xxxxxx */
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) {
|
||||
*u_ch <<= 6;
|
||||
*u_ch |= ch & 0x3f;
|
||||
}
|
||||
|
||||
static char* utf8_validate(const char *str, char *output) {
|
||||
uint32_t val = 0;
|
||||
uint32_t min = 0;
|
||||
const uint8_t *p, *last;
|
||||
int size;
|
||||
uint8_t *o;
|
||||
|
||||
assert(str);
|
||||
|
||||
o = (uint8_t*) output;
|
||||
for (p = (const uint8_t*) str; *p; p++) {
|
||||
if (*p < 128) {
|
||||
if (o)
|
||||
*o = *p;
|
||||
} else {
|
||||
last = p;
|
||||
|
||||
if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */
|
||||
size = 2;
|
||||
min = 128;
|
||||
val = (uint32_t) (*p & 0x1e);
|
||||
goto ONE_REMAINING;
|
||||
} else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/
|
||||
size = 3;
|
||||
min = (1 << 11);
|
||||
val = (uint32_t) (*p & 0x0f);
|
||||
goto TWO_REMAINING;
|
||||
} else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */
|
||||
size = 4;
|
||||
min = (1 << 16);
|
||||
val = (uint32_t) (*p & 0x07);
|
||||
} else
|
||||
goto error;
|
||||
|
||||
p++;
|
||||
if (!is_continuation_char(*p))
|
||||
goto error;
|
||||
merge_continuation_char(&val, *p);
|
||||
|
||||
TWO_REMAINING:
|
||||
p++;
|
||||
if (!is_continuation_char(*p))
|
||||
goto error;
|
||||
merge_continuation_char(&val, *p);
|
||||
|
||||
ONE_REMAINING:
|
||||
p++;
|
||||
if (!is_continuation_char(*p))
|
||||
goto error;
|
||||
merge_continuation_char(&val, *p);
|
||||
|
||||
if (val < min)
|
||||
goto error;
|
||||
|
||||
if (!is_unicode_valid(val))
|
||||
goto error;
|
||||
|
||||
if (o) {
|
||||
memcpy(o, last, (size_t) size);
|
||||
o += size;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
error:
|
||||
if (o) {
|
||||
*o = FILTER_CHAR;
|
||||
p = last; /* We retry at the next character */
|
||||
} else
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (o)
|
||||
o++;
|
||||
}
|
||||
|
||||
if (o) {
|
||||
*o = '\0';
|
||||
return output;
|
||||
}
|
||||
|
||||
return (char*) str;
|
||||
|
||||
failure:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* utf8_is_valid (const char *str) {
|
||||
return utf8_validate(str, NULL);
|
||||
}
|
||||
|
||||
char* utf8_filter (const char *str) {
|
||||
char *new_str;
|
||||
|
||||
assert(str);
|
||||
|
||||
new_str = malloc(strlen(str) + 1);
|
||||
if (!new_str)
|
||||
return NULL;
|
||||
|
||||
return utf8_validate(str, new_str);
|
||||
}
|
||||
|
||||
char *ascii_is_valid(const char *str) {
|
||||
const char *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = str; *p; p++)
|
||||
if ((unsigned char) *p >= 128)
|
||||
return NULL;
|
||||
|
||||
return (char*) str;
|
||||
}
|
||||
|
||||
char *ascii_filter(const char *str) {
|
||||
char *r, *s, *d;
|
||||
size_t l;
|
||||
|
||||
assert(str);
|
||||
|
||||
l = strlen(str);
|
||||
r = malloc(l + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
for (s = r, d = r; *s; s++)
|
||||
if ((unsigned char) *s < 128)
|
||||
*(d++) = *s;
|
||||
|
||||
*d = 0;
|
||||
|
||||
return r;
|
||||
}
|
33
src/utf8.h
Normal file
33
src/utf8.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef fooutf8hfoo
|
||||
#define fooutf8hfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2012 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
char *utf8_is_valid(const char *s) _pure_;
|
||||
char *ascii_is_valid(const char *s) _pure_;
|
||||
|
||||
char *utf8_filter(const char *s);
|
||||
char *ascii_filter(const char *s);
|
||||
|
||||
#endif
|
17
src/util.c
17
src/util.c
@ -1833,7 +1833,8 @@ char *cunescape_length(const char *s, size_t length) {
|
||||
|
||||
/* Undoes C style string escaping */
|
||||
|
||||
if (!(r = new(char, length+1)))
|
||||
r = new(char, length+1);
|
||||
if (!r)
|
||||
return r;
|
||||
|
||||
for (f = s, t = r; f < s + length; f++) {
|
||||
@ -1887,8 +1888,10 @@ char *cunescape_length(const char *s, size_t length) {
|
||||
/* hexadecimal encoding */
|
||||
int a, b;
|
||||
|
||||
if ((a = unhexchar(f[1])) < 0 ||
|
||||
(b = unhexchar(f[2])) < 0) {
|
||||
a = unhexchar(f[1]);
|
||||
b = unhexchar(f[2]);
|
||||
|
||||
if (a < 0 || b < 0) {
|
||||
/* Invalid escape code, let's take it literal then */
|
||||
*(t++) = '\\';
|
||||
*(t++) = 'x';
|
||||
@ -1911,9 +1914,11 @@ char *cunescape_length(const char *s, size_t length) {
|
||||
/* octal encoding */
|
||||
int a, b, c;
|
||||
|
||||
if ((a = unoctchar(f[0])) < 0 ||
|
||||
(b = unoctchar(f[1])) < 0 ||
|
||||
(c = unoctchar(f[2])) < 0) {
|
||||
a = unoctchar(f[0]);
|
||||
b = unoctchar(f[1]);
|
||||
c = unoctchar(f[2]);
|
||||
|
||||
if (a < 0 || b < 0 || c < 0) {
|
||||
/* Invalid escape code, let's take it literal then */
|
||||
*(t++) = '\\';
|
||||
*(t++) = f[0];
|
||||
|
Loading…
Reference in New Issue
Block a user