From 9db0dae86ec8bcab329b99b2f43f6e8e63d0ffa6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 6 Apr 2015 20:11:41 +0200 Subject: [PATCH] util: rework cunescape(), improve error handling Change cunescape() to return a normal error code, so that we can distuingish OOM errors from parse errors. This also adds a flags parameter to control whether "relaxed" or normal parsing shall be done. If set no parse failures are generated, and the only reason why cunescape() can fail is OOM. --- src/libelogind/sd-login/sd-login.c | 6 ++-- src/login/logind-acl.c | 3 +- src/login/logind-inhibit.c | 12 +++---- src/shared/util.c | 55 +++++++++++++++++++----------- src/shared/util.h | 13 ++++--- 5 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/libelogind/sd-login/sd-login.c b/src/libelogind/sd-login/sd-login.c index 8e2b7c1dc..c5489917f 100644 --- a/src/libelogind/sd-login/sd-login.c +++ b/src/libelogind/sd-login/sd-login.c @@ -496,9 +496,9 @@ _public_ int sd_session_get_desktop(const char *session, char **desktop) { if (r < 0) return r; - t = cunescape(escaped); - if (!t) - return -ENOMEM; + r = cunescape(escaped, 0, &t); + if (r < 0) + return r; *desktop = t; return 0; diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c index 941fd724a..d2b333778 100644 --- a/src/login/logind-acl.c +++ b/src/login/logind-acl.c @@ -253,8 +253,7 @@ int devnode_acl_all(struct udev *udev, FOREACH_DIRENT(dent, dir, return -errno) { _cleanup_free_ char *unescaped_devname = NULL; - unescaped_devname = cunescape(dent->d_name); - if (!unescaped_devname) + if (cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname) < 0) return -ENOMEM; n = strappend("/dev/", unescaped_devname); diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 5d81693e6..5eb1a2ea6 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -231,18 +231,18 @@ int inhibitor_load(Inhibitor *i) { } if (who) { - cc = cunescape(who); - if (!cc) - return -ENOMEM; + r = cunescape(who, 0, &cc); + if (r < 0) + return r; free(i->who); i->who = cc; } if (why) { - cc = cunescape(why); - if (!cc) - return -ENOMEM; + r = cunescape(why, 0, &cc); + if (r < 0) + return r; free(i->why); i->why = cc; diff --git a/src/shared/util.c b/src/shared/util.c index 973f1070b..a8e485cc9 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -1487,12 +1487,13 @@ static int cunescape_one(const char *p, size_t length, char *ret) { return r; } -char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) { +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) { char *r, *t; const char *f; size_t pl; assert(s); + assert(ret); /* Undoes C style string escaping, and optionally prefixes it. */ @@ -1500,7 +1501,7 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre r = new(char, pl+length+1); if (!r) - return NULL; + return -ENOMEM; if (prefix) memcpy(r, prefix, pl); @@ -1512,17 +1513,31 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre remaining = s + length - f; assert(remaining > 0); - if (*f != '\\' || remaining == 1) { - /* a literal literal, or a trailing backslash, copy verbatim */ + if (*f != '\\') { + /* A literal literal, copy verbatim */ *(t++) = *f; continue; } + if (remaining == 1) { + if (flags & UNESCAPE_RELAX) { + /* A trailing backslash, copy verbatim */ + *(t++) = *f; + continue; + } + + return -EINVAL; + } + k = cunescape_one(f + 1, remaining - 1, t); if (k < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - continue; + if (flags & UNESCAPE_RELAX) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + continue; + } + + return k; } f += k; @@ -1530,17 +1545,17 @@ char *cunescape_length_with_prefix(const char *s, size_t length, const char *pre } *t = 0; - return r; -} -char *cunescape_length(const char *s, size_t length) { - return cunescape_length_with_prefix(s, length, NULL); + *ret = r; + return t - r; } -char *cunescape(const char *s) { - assert(s); +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { + return cunescape_length_with_prefix(s, length, NULL, flags, ret); +} - return cunescape_length(s, strlen(s)); +int cunescape(const char *s, UnescapeFlags flags, char **ret) { + return cunescape_length(s, strlen(s), flags, ret); } char *xescape(const char *s, const char *bad) { @@ -6752,9 +6767,9 @@ int umount_recursive(const char *prefix, int flags) { continue; } - p = cunescape(path); - if (!p) - return -ENOMEM; + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; if (!path_startswith(p, prefix)) continue; @@ -6854,9 +6869,9 @@ int bind_remount_recursive(const char *prefix, bool ro) { continue; } - p = cunescape(path); - if (!p) - return -ENOMEM; + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; /* Let's ignore autofs mounts. If they aren't * triggered yet, we want to avoid triggering diff --git a/src/shared/util.h b/src/shared/util.h index 9f0149e1c..2154623af 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -312,9 +312,14 @@ char decchar(int x) _const_; int undecchar(char c) _const_; char *cescape(const char *s); -char *cunescape(const char *s); -char *cunescape_length(const char *s, size_t length); -char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix); + +typedef enum UnescapeFlags { + UNESCAPE_RELAX = 1, +} UnescapeFlags; + +int cunescape(const char *s, UnescapeFlags flags, char **ret); +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); char *xescape(const char *s, const char *bad); @@ -1015,7 +1020,7 @@ int take_password_lock(const char *root); int is_symlink(const char *path); int is_dir(const char *path, bool follow); -typedef enum UnquoteFlags{ +typedef enum UnquoteFlags { UNQUOTE_RELAX = 1, UNQUOTE_CUNESCAPE = 2, } UnquoteFlags; -- 2.30.2