summaryrefslogtreecommitdiff
path: root/misc.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2022-01-08 07:32:45 +0000
committerDamien Miller <djm@mindrot.org>2022-01-08 18:38:49 +1100
commit961411337719d4cd78f1ab33e4ac549f3fa22f50 (patch)
tree9ee4f7fede8ab3e1ddff660f59113c622667991b /misc.c
parentdc38236ab6827dec575064cac65c8e7035768773 (diff)
downloadopenssh-git-961411337719d4cd78f1ab33e4ac549f3fa22f50.tar.gz
upstream: refactor tilde_expand_filename() and make it handle ~user
paths with no trailing slash; feedback/ok markus and jsg OpenBSD-Commit-ID: a2ab365598a902f0f14ba6a4f8fb2d07a9b5d51d
Diffstat (limited to 'misc.c')
-rw-r--r--misc.c76
1 files changed, 46 insertions, 30 deletions
diff --git a/misc.c b/misc.c
index f541055c..c22d7c68 100644
--- a/misc.c
+++ b/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.171 2021/11/13 21:14:13 deraadt Exp $ */
+/* $OpenBSD: misc.c,v 1.172 2022/01/08 07:32:45 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@@ -1119,53 +1119,69 @@ freeargs(arglist *args)
int
tilde_expand(const char *filename, uid_t uid, char **retp)
{
- const char *path, *sep;
- char user[128], *ret;
+ char *ocopy = NULL, *copy, *s = NULL;
+ const char *path = NULL, *user = NULL;
struct passwd *pw;
- u_int len, slash;
+ size_t len;
+ int ret = -1, r, slash;
+ *retp = NULL;
if (*filename != '~') {
*retp = xstrdup(filename);
return 0;
}
- filename++;
+ ocopy = copy = xstrdup(filename + 1);
- path = strchr(filename, '/');
- if (path != NULL && path > filename) { /* ~user/path */
- slash = path - filename;
- if (slash > sizeof(user) - 1) {
- error_f("~username too long");
- return -1;
+ if (*copy == '\0') /* ~ */
+ path = NULL;
+ else if (*copy == '/') {
+ copy += strspn(copy, "/");
+ if (*copy == '\0')
+ path = NULL; /* ~/ */
+ else
+ path = copy; /* ~/path */
+ } else {
+ user = copy;
+ if ((path = strchr(copy, '/')) != NULL) {
+ copy[path - copy] = '\0';
+ path++;
+ path += strspn(path, "/");
+ if (*path == '\0') /* ~user/ */
+ path = NULL;
+ /* else ~user/path */
}
- memcpy(user, filename, slash);
- user[slash] = '\0';
+ /* else ~user */
+ }
+ if (user != NULL) {
if ((pw = getpwnam(user)) == NULL) {
error_f("No such user %s", user);
- return -1;
+ goto out;
}
- } else if ((pw = getpwuid(uid)) == NULL) { /* ~/path */
+ } else if ((pw = getpwuid(uid)) == NULL) {
error_f("No such uid %ld", (long)uid);
- return -1;
+ goto out;
}
/* Make sure directory has a trailing '/' */
- len = strlen(pw->pw_dir);
- if (len == 0 || pw->pw_dir[len - 1] != '/')
- sep = "/";
- else
- sep = "";
+ slash = (len = strlen(pw->pw_dir)) == 0 || pw->pw_dir[len - 1] != '/';
- /* Skip leading '/' from specified path */
- if (path != NULL)
- filename = path + 1;
-
- if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX) {
+ if ((r = xasprintf(&s, "%s%s%s", pw->pw_dir,
+ slash ? "/" : "", path != NULL ? path : "")) <= 0) {
+ error_f("xasprintf failed");
+ goto out;
+ }
+ if (r >= PATH_MAX) {
error_f("Path too long");
- return -1;
+ goto out;
}
-
- *retp = ret;
- return 0;
+ /* success */
+ ret = 0;
+ *retp = s;
+ s = NULL;
+ out:
+ free(s);
+ free(ocopy);
+ return ret;
}
char *