From 3dbdb8c3d8cd0498e1afb47758fea700f5061435 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 7 May 2020 12:25:24 +0200 Subject: [PATCH 1/4] lib:util: Add path_expand_tilde() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14370 Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher (cherry picked from commit 15457254be0ab1235c327bd305dfeee19b2ea7a1) --- lib/util/util_paths.c | 72 +++++++++++++++++++++++++++++++++++++++++++ lib/util/util_paths.h | 9 ++++++ 2 files changed, 81 insertions(+) diff --git a/lib/util/util_paths.c b/lib/util/util_paths.c index 0473557dfc6..c05246a7407 100644 --- a/lib/util/util_paths.c +++ b/lib/util/util_paths.c @@ -6,6 +6,7 @@ Copyright (C) Simo Sorce 2001 Copyright (C) Jim McDonough 2003 Copyright (C) James Peach 2006 + Copyright (c) 2020 Andreas Schneider This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,6 +25,7 @@ #include "includes.h" #include "dynconfig/dynconfig.h" #include "lib/util/util_paths.h" +#include "system/passwd.h" /** * @brief Returns an absolute path to a file in the Samba modules directory. @@ -62,3 +64,73 @@ const char *shlib_ext(void) return get_dyn_SHLIBEXT(); } +static char *get_user_home_dir(TALLOC_CTX *mem_ctx) +{ + struct passwd pwd = {0}; + struct passwd *pwdbuf = NULL; + char buf[NSS_BUFLEN_PASSWD] = {0}; + int rc; + + rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf); + if (rc != 0 || pwdbuf == NULL ) { + const char *szPath = getenv("HOME"); + if (szPath == NULL) { + return NULL; + } + snprintf(buf, sizeof(buf), "%s", szPath); + + return talloc_strdup(mem_ctx, buf); + } + + return talloc_strdup(mem_ctx, pwd.pw_dir); +} + +char *path_expand_tilde(TALLOC_CTX *mem_ctx, const char *d) +{ + char *h = NULL, *r = NULL; + const char *p = NULL; + struct stat sb = {0}; + int rc; + + if (d[0] != '~') { + return talloc_strdup(mem_ctx, d); + } + d++; + + /* handle ~user/path */ + p = strchr(d, '/'); + if (p != NULL && p > d) { + struct passwd *pw; + size_t s = p - d; + char u[128]; + + if (s >= sizeof(u)) { + return NULL; + } + memcpy(u, d, s); + u[s] = '\0'; + + pw = getpwnam(u); + if (pw == NULL) { + return NULL; + } + h = talloc_strdup(mem_ctx, pw->pw_dir); + } else { + p = d; + h = get_user_home_dir(mem_ctx); + } + if (h == NULL) { + return NULL; + } + + rc = stat(h, &sb); + if (rc != 0) { + TALLOC_FREE(h); + return NULL; + } + + r = talloc_asprintf(mem_ctx, "%s%s", h, p); + TALLOC_FREE(h); + + return r; +} diff --git a/lib/util/util_paths.h b/lib/util/util_paths.h index 80e8aaac6e9..cf34f691e5f 100644 --- a/lib/util/util_paths.h +++ b/lib/util/util_paths.h @@ -51,4 +51,13 @@ char *data_path(TALLOC_CTX *mem_ctx, const char *name); **/ const char *shlib_ext(void); +/** + * @brief Expand a directory starting with a tilde '~' + * + * @param[in] d The directory to expand. + * + * @return The expanded directory, NULL on error. + */ +char *path_expand_tilde(TALLOC_CTX *mem_ctx, const char *d); + #endif -- 2.26.2 From d43c586576353cba5082ba396c521dde1cde4929 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 11 May 2020 12:50:11 +0200 Subject: [PATCH 2/4] lib:util: Add test for path_expand_tilde() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14370 Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher (backported from commit a15bd5493b696c66c6803d8ca65bc13f1cfcdf0a) --- lib/util/tests/test_util_paths.c | 127 +++++++++++++++++++++++++++++++ lib/util/wscript_build | 6 ++ selftest/tests.py | 2 + 3 files changed, 135 insertions(+) create mode 100644 lib/util/tests/test_util_paths.c diff --git a/lib/util/tests/test_util_paths.c b/lib/util/tests/test_util_paths.c new file mode 100644 index 00000000000..b89abf0aea1 --- /dev/null +++ b/lib/util/tests/test_util_paths.c @@ -0,0 +1,127 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (C) 2020 Andreas Schneider + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include + +#include "lib/replace/replace.h" +#include "lib/util/util_paths.c" + +static int setup(void **state) +{ + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + assert_non_null(mem_ctx); + *state = mem_ctx; + + return 0; +} + +static int teardown(void **state) +{ + TALLOC_CTX *mem_ctx = *state; + TALLOC_FREE(mem_ctx); + + return 0; +} + +static void test_get_user_home_dir(void **state) +{ + TALLOC_CTX *mem_ctx = *state; + struct passwd *pwd = getpwuid(getuid()); + char *user; + + user = get_user_home_dir(mem_ctx); + assert_non_null(user); + assert_string_equal(user, pwd->pw_dir); + + TALLOC_FREE(user); +} + +static void test_path_expand_tilde(void **state) +{ + TALLOC_CTX *mem_ctx = *state; + char h[256] = {0}; + char *d = NULL; + const char *user = NULL; + char *home = NULL; + + user = getenv("USER"); + if (user == NULL){ + user = getenv("LOGNAME"); + } + + /* In certain CIs there no such variables */ + if (user == NULL) { + struct passwd *pw = getpwuid(getuid()); + if (pw){ + user = pw->pw_name; + } + } + + home = getenv("HOME"); + assert_non_null(home); + snprintf(h, sizeof(h), "%s/.cache", home); + + d = path_expand_tilde(mem_ctx, "~/.cache"); + assert_non_null(d); + assert_string_equal(d, h); + TALLOC_FREE(d); + + snprintf(h, sizeof(h), "%s/.cache/X~", home); + d = path_expand_tilde(mem_ctx, "~/.cache/X~"); + assert_string_equal(d, h); + TALLOC_FREE(d); + + d = path_expand_tilde(mem_ctx, "/guru/meditation"); + assert_non_null(d); + assert_string_equal(d, "/guru/meditation"); + TALLOC_FREE(d); + + snprintf(h, sizeof(h), "~%s/.cache", user); + d = path_expand_tilde(mem_ctx, h); + assert_non_null(d); + + snprintf(h, sizeof(h), "%s/.cache", home); + assert_string_equal(d, h); + TALLOC_FREE(d); +} + +int main(int argc, char *argv[]) +{ + int rc; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_get_user_home_dir), + cmocka_unit_test(test_path_expand_tilde), + }; + + if (argc == 2) { + cmocka_set_test_filter(argv[1]); + } + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + + rc = cmocka_run_group_tests(tests, setup, teardown); + + return rc; +} diff --git a/lib/util/wscript_build b/lib/util/wscript_build index a827eea3ed9..608f7b3dd73 100644 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -288,3 +288,9 @@ else: deps='cmocka replace samba-util', local_include=False, for_selftest=True) + + bld.SAMBA_BINARY('test_util_paths', + source='tests/test_util_paths.c', + deps='cmocka replace talloc samba-util', + local_include=False, + for_selftest=True) diff --git a/selftest/tests.py b/selftest/tests.py index 96d3f8d6317..b72a6fb65eb 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -389,6 +389,8 @@ plantestsuite("samba.unittests.ms_fnmatch", "none", [os.path.join(bindir(), "default/lib/util/test_ms_fnmatch")]) plantestsuite("samba.unittests.byteorder", "none", [os.path.join(bindir(), "default/lib/util/test_byteorder")]) +plantestsuite("samba.unittests.util_paths", "none", + [os.path.join(bindir(), "default/lib/util/test_util_paths")]) plantestsuite("samba.unittests.ntlm_check", "none", [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")]) plantestsuite("samba.unittests.gnutls", "none", -- 2.26.2 From 133edb95814adc43072fd33876caf9d720eaac1f Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 6 May 2020 17:10:51 +0200 Subject: [PATCH 3/4] s3:gencache: Allow to open gencache as read-only This allows client tools to access the cache for ready-only operations as a normal user. Example: net ads status BUG: https://bugzilla.samba.org/show_bug.cgi?id=14370 Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Fri May 15 14:40:32 UTC 2020 on sn-devel-184 (cherry picked from commit 04f0c45475de383a0be4ca355ab9aa7784e61c27) --- source3/lib/gencache.c | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/source3/lib/gencache.c b/source3/lib/gencache.c index 9ad85bbf55f..896bf50cbd7 100644 --- a/source3/lib/gencache.c +++ b/source3/lib/gencache.c @@ -29,10 +29,13 @@ #include "tdb_wrap/tdb_wrap.h" #include "zlib.h" #include "lib/util/strv.h" +#include "lib/util/util_paths.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_TDB +#define GENCACHE_USER_PATH "~/.cache/samba/gencache.tdb" + static struct tdb_wrap *cache; /** @@ -68,6 +71,7 @@ static bool gencache_init(void) { char* cache_fname = NULL; int open_flags = O_RDWR|O_CREAT; + int tdb_flags = TDB_INCOMPATIBLE_HASH|TDB_NOSYNC|TDB_MUTEX_LOCKING; int hash_size; /* skip file open if it's already opened */ @@ -85,10 +89,63 @@ static bool gencache_init(void) DEBUG(5, ("Opening cache file at %s\n", cache_fname)); cache = tdb_wrap_open(NULL, cache_fname, hash_size, - TDB_INCOMPATIBLE_HASH| - TDB_NOSYNC| - TDB_MUTEX_LOCKING, + tdb_flags, open_flags, 0644); + /* + * Allow client tools to create a gencache in the home directory + * as a normal user. + */ + if (cache == NULL && errno == EACCES && geteuid() != 0) { + char *cache_dname = NULL, *tmp = NULL; + bool ok; + + TALLOC_FREE(cache_fname); + + cache_fname = path_expand_tilde(talloc_tos(), + GENCACHE_USER_PATH); + if (cache_fname == NULL) { + DBG_ERR("Failed to expand path: %s\n", + GENCACHE_USER_PATH); + return false; + } + + tmp = talloc_strdup(talloc_tos(), cache_fname); + if (tmp == NULL) { + DBG_ERR("No memory!\n"); + TALLOC_FREE(cache_fname); + return false; + } + + cache_dname = dirname(tmp); + if (cache_dname == NULL) { + DBG_ERR("Invalid path: %s\n", cache_fname); + TALLOC_FREE(tmp); + TALLOC_FREE(cache_fname); + return false; + } + + ok = directory_create_or_exist(cache_dname, 0700); + if (!ok) { + DBG_ERR("Failed to create directory: %s - %s\n", + cache_dname, strerror(errno)); + TALLOC_FREE(tmp); + TALLOC_FREE(cache_fname); + return false; + } + TALLOC_FREE(tmp); + + cache = tdb_wrap_open(NULL, + cache_fname, + hash_size, + tdb_flags, + open_flags, + 0644); + if (cache != NULL) { + DBG_INFO("Opening user cache file %s.\n", + cache_fname); + } + } + if (cache == NULL) { DEBUG(5, ("Opening %s failed: %s\n", cache_fname, strerror(errno))); -- 2.26.2 From de71248d86e29ca7d1d2df0f197b930ae8472d5b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 15 May 2020 12:18:02 -0700 Subject: [PATCH 4/4] s3: lib: Paranoia around use of snprintf copying into a fixed-size buffer from a getenv() pointer. Post checks for overflow/error. Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Mon May 18 23:42:57 UTC 2020 on sn-devel-184 (cherry picked from commit dd1f750293ef4361455a5d5b63fc7a89495715b7) --- lib/util/util_paths.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/util/util_paths.c b/lib/util/util_paths.c index c05246a7407..c0ee5c32c30 100644 --- a/lib/util/util_paths.c +++ b/lib/util/util_paths.c @@ -73,12 +73,16 @@ static char *get_user_home_dir(TALLOC_CTX *mem_ctx) rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf); if (rc != 0 || pwdbuf == NULL ) { + int len_written; const char *szPath = getenv("HOME"); if (szPath == NULL) { return NULL; } - snprintf(buf, sizeof(buf), "%s", szPath); - + len_written = snprintf(buf, sizeof(buf), "%s", szPath); + if (len_written >= sizeof(buf) || len_written < 0) { + /* Output was truncated or an error. */ + return NULL; + } return talloc_strdup(mem_ctx, buf); } -- 2.26.2