...
This function uses the realpath() function to canonicalize the input path ...(see FIO02-A. Canonicalize path names originating from untrusted sources for more information on realpath()). It then checks every directory in the canonical path, ensuring that every directory is owned by the current user or by root. Furthermore, every the topmost directory must disallow write access to everyone but the owner. All other directories in the path must forbid other users from deleting files, either by turning off group write access and world write access, or by turning on the sticky bit.
| Code Block | ||
|---|---|---|
| ||
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <libgen.h>
#include <sys/stat.h>
#include <string.h>
/* Returns nonzero if directory is secure, zero otherwise */
int secure_dir(const char* path) {
char *fullpath = NULL;
char *path_copy = NULL;
char *dirname_res = NULL;
char ** dirs = NULL;
int num_of_dirs = 0;
int secure = 1;
int i;
struct stat buf;
uid_t my_uid = geteuid();
/*
* Canonicalize path and store the result in fullpath
* see FIO02-A. Canonicalize path names originating from
* untrusted sources
*/
if (!(path_copy = strdup(fullpath))) {
/* Handle error */
}
dirname_res = path_copy;
/* Figure out how far it is to the root */
while (1) {
dirname_res = dirname(dirname_res);
num_of_dirs++;
if ((strcmp(dirname_res, ".") == 0) ||
(strcmp(dirname_res, "/") == 0)) {
break;
}
}
free(path_copy);
path_copy = NULL;
/* Now allocate and fill the dirs array */
if (!(dirs = (char **)malloc(num_of_dirs*sizeof(*dirs)))) {
/* Handle error */
}
if (!(dirs[num_of_dirs - 1] = strdup(fullpath))) {
/* Handle error */
}
if(!(path_copy = strdup(fullpath))) {
/* Handle error */
}
dirname_res = path_copy;
for (i = 1; i < num_of_dirs; i++) {
dirname_res = dirname(dirname_res);
dirs[num_of_dirs - i - 1] = strdup(dirname_res);
}
free(path_copy);
path_copy = NULL;
/* Traverse from the root to the top, checking
* permissions along the way */
for (i = 0; i < num_of_dirs; i++) {
if (stat(dirs[i], &buf) != 0) {
/* Handle error */
}
if ((buf.st_uid != my_uid) && (buf.st_uid != 0)) {
/* Directory is owned by someone besides user or root */
secure = 0;
} else if (!(buf.st_mode & (S_ISVTX)IWGRP | S_IWOTH))
&&
((i == 0) || !(buf.st_mode & (S_IWGRP | S_IWOTHISVTX))) {
/* Others have permissionpermissions to rename or remove files here the topmost directory
* or are able to delete files along the way */
secure = 0;
}
free(dirs[i]);
dirs[i] = NULL;
}
free(dirs);
dirs = NULL;
return secure;
}
|
...