version 1.26, 2001/06/27 04:48:52 |
version 1.27, 2001/07/11 18:26:15 |
|
|
char *err, size_t errlen) |
char *err, size_t errlen) |
{ |
{ |
uid_t uid = pw->pw_uid; |
uid_t uid = pw->pw_uid; |
char homedir[MAXPATHLEN]; |
|
char buf[MAXPATHLEN]; |
char buf[MAXPATHLEN]; |
char *cp; |
char *cp; |
struct stat st; |
struct stat st; |
|
|
strlcpy(homedir, dirname(pw->pw_dir), sizeof(homedir)); |
|
|
|
if (realpath(file, buf) == NULL) { |
if (realpath(file, buf) == NULL) { |
snprintf(err, errlen, "realpath %s failed: %s", file, |
snprintf(err, errlen, "realpath %s failed: %s", file, |
strerror(errno)); |
strerror(errno)); |
|
|
return -1; |
return -1; |
} |
} |
|
|
debug3("secure_filename: terminating check at '%s'", homedir); |
|
|
|
/* for each component of the canonical path, walking upwards */ |
/* for each component of the canonical path, walking upwards */ |
for (;;) { |
for (;;) { |
if ((cp = dirname(buf)) == NULL) { |
if ((cp = dirname(buf)) == NULL) { |
|
|
} |
} |
strlcpy(buf, cp, sizeof(buf)); |
strlcpy(buf, cp, sizeof(buf)); |
|
|
/* If are passed the homedir then we can stop */ |
|
if (strcmp(buf, homedir) == 0) |
|
break; |
|
|
|
debug3("secure_filename: checking '%s'", buf); |
debug3("secure_filename: checking '%s'", buf); |
if (stat(buf, &st) < 0 || |
if (stat(buf, &st) < 0 || |
(st.st_uid != 0 && st.st_uid != uid) || |
(st.st_uid != 0 && st.st_uid != uid) || |
|
|
return -1; |
return -1; |
} |
} |
|
|
|
/* If are passed the homedir then we can stop */ |
|
if (strcmp(pw->pw_dir, buf) == 0) { |
|
debug3("secure_filename: terminating check at '%s'", |
|
buf); |
|
break; |
|
} |
/* |
/* |
* dirname should always complete with a "/" path, |
* dirname should always complete with a "/" path, |
* but we can be paranoid and check for "." too |
* but we can be paranoid and check for "." too |