38#include "blocxx/BLOCXX_config.h"
46#ifdef BLOCXX_HAVE_UNISTD_H
58 using namespace FileSystem::Path;
60 unsigned const MAX_SYMBOLIC_LINKS = 100;
68 class PartiallyResolvedPath
73 PartiallyResolvedPath(
char const * base_dir);
78 void multi_push_unresolved(
char const * path);
82 void pop_unresolved();
85 bool unresolved_empty()
const;
88 bool unresolved_starts_with_curdir()
const;
91 bool unresolved_starts_with_parent()
const;
95 bool dir_specified()
const;
100 void xfer_component();
107 void reset_resolved();
110 String get_resolved()
const;
113 void lstat_resolved(
struct stat & st)
const;
119 void read_symlink(std::vector<char> & path);
136 PartiallyResolvedPath::PartiallyResolvedPath(
char const * base_dir)
143 void PartiallyResolvedPath::multi_push_unresolved(
char const * path)
150 char const * end = path;
155 if (end != path && *(end - 1) ==
'/')
160 bool last_separator =
true;
164 bool separator = (c ==
'/');
165 if (!(separator && last_separator))
169 last_separator = separator;
173 void PartiallyResolvedPath::pop_unresolved()
186 inline bool PartiallyResolvedPath::unresolved_empty()
const
191 bool PartiallyResolvedPath::unresolved_starts_with_curdir()
const
200 bool PartiallyResolvedPath::unresolved_starts_with_parent()
const
209 inline bool PartiallyResolvedPath::dir_specified()
const
214 void PartiallyResolvedPath::xfer_component()
235 void PartiallyResolvedPath::pop_resolved()
255 inline void PartiallyResolvedPath::reset_resolved()
264 NullTerminate(std::vector<char> & buf)
267 m_buf.push_back(
'\0');
276 inline String PartiallyResolvedPath::get_resolved()
const
282 void wrapped_lstat(
char const * path,
struct stat & st)
285 String tmp_path(path);
286 if(path[1] ==
':' && path[2] == 0)
290 if (
LSTAT(tmp_path.c_str(), &st) < 0)
292 if (
LSTAT(path, &st) < 0)
299 void PartiallyResolvedPath::lstat_resolved(
struct stat & st)
const
305 void PartiallyResolvedPath::read_symlink(std::vector<char> & path)
313 int rv =
READLINK(symlink_path, &buf[0], buf.size());
322 else if (
static_cast<unsigned>(rv) == buf.size())
324 buf.resize(2 * buf.size());
334 char const * strip_leading_slashes(
char const * path)
343 void logFileStatus(path_results_t
const & results,
const uid_t uid)
345 Logger logger(
"blocxx.PathSecurity");
346 for (path_results_t::const_iterator li = results.begin(); li != results.end(); ++li)
354 bool successful(
false);
355 String userName = UserUtils::getUserName(uid, successful);
358 userName =
"the proper user";
360#if defined(BLOCXX_HPUX) || defined(BLOCXX_AIX)
370 BLOCXX_LOG_ERROR(logger, Format(
"%1 was insecure. It was not owned by %2%3.", li->first, userName, hpux));
376 BLOCXX_LOG_ERROR(logger, Format(
"%1 was owned by the proper user, but was not a symlink and was either"
377 " world (or non-root group) writable or did not have the sticky bit set on the directory.", li->first));
386 std::pair<ESecurity, String>
387 path_security(
char const * base_dir,
char const * rel_path, uid_t uid,
bool bdsecure)
391 base_dir[1] ==
'\0' || base_dir[std::strlen(base_dir) - 1] !=
'/');
397 PartiallyResolvedPath prp(base_dir);
399 PartiallyResolvedPath prp(
"");
400 if (rel_path[1] !=
':' && base_dir[1] ==
':')
406 unsigned num_symbolic_links = 0;
410 prp.multi_push_unresolved(rel_path);
412 if( prp.unresolved_empty() )
414 prp.lstat_resolved(st);
417 while (!prp.unresolved_empty())
419 if (prp.unresolved_starts_with_curdir())
421 prp.pop_unresolved();
423 else if (prp.unresolved_starts_with_parent())
425 prp.pop_unresolved();
430 prp.xfer_component();
431 prp.lstat_resolved(st);
432 file_status =
getFileStatus(st, uid, prp.unresolved_empty(), prp.get_resolved());
434 if (file_status != E_FILE_OK)
436 results.push_back(std::make_pair(prp.get_resolved(), file_status));
439 if (S_ISREG(st.st_mode))
442 if (!prp.unresolved_empty() || prp.dir_specified())
445 FileSystemException, prp.get_resolved(), ENOTDIR);
448 else if (S_ISLNK(st.st_mode))
450 if (++num_symbolic_links > MAX_SYMBOLIC_LINKS)
453 FileSystemException, prp.get_resolved(), ELOOP);
455 std::vector<char> slpath_vec;
456 prp.read_symlink(slpath_vec);
457 char const * slpath = &slpath_vec[0];
458 if (slpath[0] ==
'/')
460 prp.reset_resolved();
461 slpath = strip_leading_slashes(slpath);
467 prp.multi_push_unresolved(slpath);
469 else if (!S_ISDIR(st.st_mode))
471 String msg = prp.get_resolved() +
472 " is not a directory, symbolic link, nor regular file";
479 logFileStatus(results, uid);
480 return std::make_pair(sec, prp.get_resolved());
483 std::pair<ESecurity, String> path_security(
char const * path, UserId uid)
488 Format(
"%1 is not an absolute path", path).c_str());
490 char const * relpath = strip_leading_slashes(path);
493 char sRootPath[] =
"/";
494 wrapped_lstat(
"/", st);
496 char sRootPath[MAX_PATH];
497 if (::GetWindowsDirectory(sRootPath, MAX_PATH) < 3 )
499 wrapped_lstat(
"/", st);
504 wrapped_lstat(sRootPath, st);
510 if (file_status != E_FILE_OK)
512 results.push_back(std::make_pair(String(path), file_status));
513 logFileStatus(results, uid);
516 return path_security(sRootPath, relpath, uid, (file_status == E_FILE_OK));
521std::pair<ESecurity, String>
525 return path_security(abspath.
c_str(), uid);
528std::pair<ESecurity, String>
529FileSystem::Path::security(
532 return path_security(base_dir.
c_str(), rel_path.
c_str(), uid,
true);
535std::pair<ESecurity, String>
536FileSystem::Path::security(
String const & path)
541std::pair<ESecurity, String>
542FileSystem::Path::security(
545 return security(base_dir, rel_path, ::geteuid());
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(),...
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
#define BLOCXX_THROW_ERRNO_MSG(exType, msg)
Throw an exception using FILE, LINE, errno and strerror(errno)
#define BLOCXX_THROW_ERRNO_MSG1(exType, msg, errnum)
Throw an exception using FILE, LINE, errnum and strerror(errnum)
#define BLOCXX_LOG_ERROR(logger, message)
Log message to logger with the Error level.
std::vector< char > m_unresolved
std::vector< char > & m_buf
std::vector< char > m_resolved
#define READLINK(path, buf, size)
#define BLOCXX_FILENAME_SEPARATOR
Array<> wraps std::vector<> in COWReference<> adding ref counting and copy on write capability.
This String class is an abstract data type that represents as NULL terminated string of characters.
const char * c_str() const
BLOCXX_COMMON_API std::pair< ESecurity, String > security(String const &path, UserId uid)
BLOCXX_COMMON_API String getCurrentWorkingDirectory()
Get the process's current working directory.
EFileStatusReturn getFileStatus(struct stat const &x, uid_t uid, bool is_full_path, const String &path)
GetFileStatus() - just to unify the call of file_ok() for Win and xNix.
class BLOCXX_COMMON_API Logger
BLOCXX_COMMON_API bool isPathAbsolute(String const &path)
Array< std::pair< String, EFileStatusReturn > > path_results_t