version 1.122, 2017/06/24 06:34:38 |
version 1.123, 2017/08/18 05:36:45 |
|
|
|
|
#include <errno.h> |
#include <errno.h> |
#include <fcntl.h> |
#include <fcntl.h> |
#include <libgen.h> |
|
#include <login_cap.h> |
#include <login_cap.h> |
#include <paths.h> |
#include <paths.h> |
#include <pwd.h> |
#include <pwd.h> |
|
|
return host_status; |
return host_status; |
} |
} |
|
|
/* |
|
* Check a given path for security. This is defined as all components |
|
* of the path to the file must be owned by either the owner of |
|
* of the file or root and no directories must be group or world writable. |
|
* |
|
* XXX Should any specific check be done for sym links ? |
|
* |
|
* Takes a file name, its stat information (preferably from fstat() to |
|
* avoid races), the uid of the expected owner, their home directory and an |
|
* error buffer plus max size as arguments. |
|
* |
|
* Returns 0 on success and -1 on failure |
|
*/ |
|
int |
|
auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, |
|
uid_t uid, char *err, size_t errlen) |
|
{ |
|
char buf[PATH_MAX], homedir[PATH_MAX]; |
|
char *cp; |
|
int comparehome = 0; |
|
struct stat st; |
|
|
|
if (realpath(name, buf) == NULL) { |
|
snprintf(err, errlen, "realpath %s failed: %s", name, |
|
strerror(errno)); |
|
return -1; |
|
} |
|
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) |
|
comparehome = 1; |
|
|
|
if (!S_ISREG(stp->st_mode)) { |
|
snprintf(err, errlen, "%s is not a regular file", buf); |
|
return -1; |
|
} |
|
if ((stp->st_uid != 0 && stp->st_uid != uid) || |
|
(stp->st_mode & 022) != 0) { |
|
snprintf(err, errlen, "bad ownership or modes for file %s", |
|
buf); |
|
return -1; |
|
} |
|
|
|
/* for each component of the canonical path, walking upwards */ |
|
for (;;) { |
|
if ((cp = dirname(buf)) == NULL) { |
|
snprintf(err, errlen, "dirname() failed"); |
|
return -1; |
|
} |
|
strlcpy(buf, cp, sizeof(buf)); |
|
|
|
if (stat(buf, &st) < 0 || |
|
(st.st_uid != 0 && st.st_uid != uid) || |
|
(st.st_mode & 022) != 0) { |
|
snprintf(err, errlen, |
|
"bad ownership or modes for directory %s", buf); |
|
return -1; |
|
} |
|
|
|
/* If are past the homedir then we can stop */ |
|
if (comparehome && strcmp(homedir, buf) == 0) |
|
break; |
|
|
|
/* |
|
* dirname should always complete with a "/" path, |
|
* but we can be paranoid and check for "." too |
|
*/ |
|
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) |
|
break; |
|
} |
|
return 0; |
|
} |
|
|
|
/* |
|
* Version of secure_path() that accepts an open file descriptor to |
|
* avoid races. |
|
* |
|
* Returns 0 on success and -1 on failure |
|
*/ |
|
static int |
|
secure_filename(FILE *f, const char *file, struct passwd *pw, |
|
char *err, size_t errlen) |
|
{ |
|
struct stat st; |
|
|
|
/* check the open file to avoid races */ |
|
if (fstat(fileno(f), &st) < 0) { |
|
snprintf(err, errlen, "cannot stat file %s: %s", |
|
file, strerror(errno)); |
|
return -1; |
|
} |
|
return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); |
|
} |
|
|
|
static FILE * |
static FILE * |
auth_openfile(const char *file, struct passwd *pw, int strict_modes, |
auth_openfile(const char *file, struct passwd *pw, int strict_modes, |
int log_missing, char *file_type) |
int log_missing, char *file_type) |
|
|
return NULL; |
return NULL; |
} |
} |
if (strict_modes && |
if (strict_modes && |
secure_filename(f, file, pw, line, sizeof(line)) != 0) { |
safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) { |
fclose(f); |
fclose(f); |
logit("Authentication refused: %s", line); |
logit("Authentication refused: %s", line); |
auth_debug_add("Ignored %s: %s", file_type, line); |
auth_debug_add("Ignored %s: %s", file_type, line); |