version 1.171, 2021/11/13 21:14:13 |
version 1.172, 2022/01/08 07:32:45 |
|
|
int |
int |
tilde_expand(const char *filename, uid_t uid, char **retp) |
tilde_expand(const char *filename, uid_t uid, char **retp) |
{ |
{ |
const char *path, *sep; |
char *ocopy = NULL, *copy, *s = NULL; |
char user[128], *ret; |
const char *path = NULL, *user = NULL; |
struct passwd *pw; |
struct passwd *pw; |
u_int len, slash; |
size_t len; |
|
int ret = -1, r, slash; |
|
|
|
*retp = NULL; |
if (*filename != '~') { |
if (*filename != '~') { |
*retp = xstrdup(filename); |
*retp = xstrdup(filename); |
return 0; |
return 0; |
} |
} |
filename++; |
ocopy = copy = xstrdup(filename + 1); |
|
|
path = strchr(filename, '/'); |
if (*copy == '\0') /* ~ */ |
if (path != NULL && path > filename) { /* ~user/path */ |
path = NULL; |
slash = path - filename; |
else if (*copy == '/') { |
if (slash > sizeof(user) - 1) { |
copy += strspn(copy, "/"); |
error_f("~username too long"); |
if (*copy == '\0') |
return -1; |
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); |
/* else ~user */ |
user[slash] = '\0'; |
} |
|
if (user != NULL) { |
if ((pw = getpwnam(user)) == NULL) { |
if ((pw = getpwnam(user)) == NULL) { |
error_f("No such user %s", user); |
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); |
error_f("No such uid %ld", (long)uid); |
return -1; |
goto out; |
} |
} |
|
|
/* Make sure directory has a trailing '/' */ |
/* Make sure directory has a trailing '/' */ |
len = strlen(pw->pw_dir); |
slash = (len = strlen(pw->pw_dir)) == 0 || pw->pw_dir[len - 1] != '/'; |
if (len == 0 || pw->pw_dir[len - 1] != '/') |
|
sep = "/"; |
|
else |
|
sep = ""; |
|
|
|
/* Skip leading '/' from specified path */ |
if ((r = xasprintf(&s, "%s%s%s", pw->pw_dir, |
if (path != NULL) |
slash ? "/" : "", path != NULL ? path : "")) <= 0) { |
filename = path + 1; |
error_f("xasprintf failed"); |
|
goto out; |
if (xasprintf(&ret, "%s%s%s", pw->pw_dir, sep, filename) >= PATH_MAX) { |
} |
|
if (r >= PATH_MAX) { |
error_f("Path too long"); |
error_f("Path too long"); |
return -1; |
goto out; |
} |
} |
|
/* success */ |
*retp = ret; |
ret = 0; |
return 0; |
*retp = s; |
|
s = NULL; |
|
out: |
|
free(s); |
|
free(ocopy); |
|
return ret; |
} |
} |
|
|
char * |
char * |