...
| 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 *fullpath) {
char *path_copy = NULL;
char **dirs = NULL;
int num_of_dirs = 1;
int secure = 1;
int i;
struct stat buf;
uid_t my_uid = geteuid();
size_t linksize;
char* link;
if (!(path_copy = strdup(fullpath))) {
/* Handle error */
}
/* Figure out how far it is to the root */
for (; ((strcmp(path_copy, "/") != 0) &&
(strcmp(path_copy, "//") != 0));
path_copy = dirname(path_copy)) {
num_of_dirs++;
} // now num_of_dirs indicates # of dirs we must check
free(path_copy);
path_copy = NULL;
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 */
}
/* Now fill the dirs array */
for (i = num_of_dirs - 2; i >= 0; i--) {
path_copy = dirname(path_copy);
if (!(dirs[i] = strdup(path_copy))) {
/* handle error */
}
}
free(path_copy);
path_copy = NULL;
/* Traverse from the root to the fullpath,
* checking permissions along the way */
for (i = 0; i < num_of_dirs; i++) {
if (lstat(dirs[i], &buf) != 0) {
/* Handle error */
}
if (S_ISLNK(buf.st_mode)) { // symlink, test linked-to file
linksize = buf.st_size+1;
if (!(link = (char *)malloc(linksize))) {
/* Handle error */
}
if (readlink( dirs[i], link, linksize) == -1) {
/* Handle error */
}
if (!secure_dir(link)) {
secure = 0;
break;
}
break;
}
if (!S_ISDIR( buf.st_mode)) { // not a directory
secure = 0;
break;
}
if ((buf.st_uid != my_uid) && (buf.st_uid != 0)) {
/* Directory is owned by someone besides user or root */
secure = 0;
break;
}
if (i == num_of_dirs - 1) { /* leaf dir */
if (buf.st_mode & (S_IWGRP | S_IWOTH)) { /* dir is writable by others */
secure = 0;
break;
}
} else { /* parent dirs */
if ((buf.st_mode & (S_IWGRP | S_IWOTH)) ||
(buf.st_mode & S_ISVTX)) { /* dir has sticky betbit off */
secure = 0;
break;
}
}
free(dirs[i]);
dirs[i] = NULL;
}
free(dirs);
dirs = NULL;
return secure;
}
|
...