diff options
Diffstat (limited to 'lib/util/util_paths.c')
-rw-r--r-- | lib/util/util_paths.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/lib/util/util_paths.c b/lib/util/util_paths.c index 0473557dfc6..72cc0aab8de 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 <jmcd@us.ibm.com> 2003 Copyright (C) James Peach 2006 + Copyright (c) 2020 Andreas Schneider <asn@samba.org> 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,106 @@ 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 = NULL; + char *out = NULL; + long int initlen; + size_t len; + int rc; + + initlen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (initlen == -1) { + len = 1024; + } else { + len = (size_t)initlen; + } + buf = talloc_size(mem_ctx, len); + if (buf == NULL) { + return NULL; + } + + rc = getpwuid_r(getuid(), &pwd, buf, len, &pwdbuf); + while (rc == ERANGE) { + size_t newlen = 2 * len; + if (newlen < len) { + /* Overflow */ + goto done; + } + len = newlen; + buf = talloc_realloc_size(mem_ctx, buf, len); + if (buf == NULL) { + goto done; + } + rc = getpwuid_r(getuid(), &pwd, buf, len, &pwdbuf); + } + if (rc != 0 || pwdbuf == NULL ) { + const char *szPath = getenv("HOME"); + if (szPath == NULL) { + goto done; + } + len = strnlen(szPath, PATH_MAX); + if (len >= PATH_MAX) { + return NULL; + } + out = talloc_strdup(mem_ctx, szPath); + goto done; + } + + out = talloc_strdup(mem_ctx, pwd.pw_dir); +done: + TALLOC_FREE(buf); + return out; +} + +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; +} |