suricata
util-path.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2023 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  */
24 
25 #include "suricata-common.h"
26 #include "suricata.h"
27 #include "util-debug.h"
28 #include "util-path.h"
29 
30 #ifdef OS_WIN32
31 #define DIRECTORY_SEPARATOR '\\'
32 #else
33 #define DIRECTORY_SEPARATOR '/'
34 #endif
35 
36 /**
37  * \brief Check if a path is absolute
38  *
39  * \param path string with the path
40  *
41  * \retval 1 absolute
42  * \retval 0 not absolute
43  */
44 int PathIsAbsolute(const char *path)
45 {
46  if (strlen(path) > 1 && path[0] == '/') {
47  return 1;
48  }
49 
50 #if (defined OS_WIN32 || defined __CYGWIN__)
51  if (strlen(path) > 2) {
52  if (isalpha((unsigned char)path[0]) && path[1] == ':') {
53  return 1;
54  }
55  }
56 #endif
57 
58  return 0;
59 }
60 
61 /**
62  * \brief Check if a path is relative
63  *
64  * \param path string with the path
65  *
66  * \retval 1 relative
67  * \retval 0 not relative
68  */
69 int PathIsRelative(const char *path)
70 {
71  return PathIsAbsolute(path) ? 0 : 1;
72 }
73 
74 int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname)
75 {
76  char path[PATH_MAX];
77  if (dir == NULL || strlen(dir) == 0)
78  return -1;
79 
80  size_t r = strlcpy(path, dir, sizeof(path));
81  if (r >= sizeof(path)) {
82  return -1;
83  }
84 
85 #if defined OS_WIN32 || defined __CYGWIN__
86  if (path[strlen(path) - 1] != '\\')
87  r = strlcat(path, "\\\\", sizeof(path));
88 #else
89  if (path[strlen(path) - 1] != '/')
90  r = strlcat(path, "/", sizeof(path));
91 #endif
92  if (r >= sizeof(path)) {
93  return -1;
94  }
95  r = strlcat(path, fname, sizeof(path));
96  if (r >= sizeof(path)) {
97  return -1;
98  }
99  r = strlcpy(out_buf, path, buf_size);
100  if (r >= buf_size) {
101  return -1;
102  }
103 
104  return 0;
105 }
106 
107 char *PathMergeAlloc(const char *const dir, const char *const fname)
108 {
109  char path[PATH_MAX];
110  if (PathMerge(path, sizeof(path), dir, fname) != 0)
111  return NULL;
112 
113  char *ret = SCStrdup(path);
114  if (ret == NULL)
115  return NULL;
116 
117  return ret;
118 }
119 
120 /**
121  * \brief Wrapper to join a directory and filename and resolve using realpath
122  * _fullpath is used for WIN32
123  *
124  * \param out_buf output buffer. Up to PATH_MAX will be written. Unchanged on exit failure.
125  * \param buf_size length of output buffer, must be PATH_MAX
126  * \param dir the directory
127  * \param fname the filename
128  *
129  * \retval 0 on success
130  * \retval -1 on failure
131  */
132 int PathJoin(char *out_buf, size_t buf_size, const char *const dir, const char *const fname)
133 {
134  SCEnter();
135  if (buf_size != PATH_MAX) {
136  return -1;
137  }
138  if (PathMerge(out_buf, buf_size, dir, fname) != 0) {
139  SCLogError("Could not join filename to path");
140  return -1;
141  }
142  char *tmp_buf = SCRealPath(out_buf, NULL);
143  if (tmp_buf == NULL) {
144  SCLogError("Error resolving path: %s", strerror(errno));
145  return -1;
146  }
147  memset(out_buf, 0, buf_size);
148  size_t ret = strlcpy(out_buf, tmp_buf, buf_size);
149  free(tmp_buf);
150  if (ret >= buf_size) {
151  return -1;
152  }
153  return 0;
154 }
155 
156 /**
157  * \brief Wrapper around SCMkDir with default mode arguments.
158  */
159 int SCDefaultMkDir(const char *path)
160 {
161  return SCMkDir(path, S_IRWXU | S_IRGRP | S_IXGRP);
162 }
163 
164 /**
165  * \brief Recursively create a directory.
166  *
167  * \param path Path to create
168  * \param final true will create the final path component, false will not
169  *
170  * \retval 0 on success
171  * \retval -1 on error
172  */
173 int SCCreateDirectoryTree(const char *path, const bool final)
174 {
175  char pathbuf[PATH_MAX];
176  char *p;
177  size_t len = strlen(path);
178 
179  if (len > PATH_MAX - 1) {
180  return -1;
181  }
182 
183  strlcpy(pathbuf, path, sizeof(pathbuf));
184 
185  for (p = pathbuf + 1; *p; p++) {
186  if (*p == '/') {
187  /* Truncate, while creating directory */
188  *p = '\0';
189 
190  if (SCDefaultMkDir(pathbuf) != 0) {
191  if (errno != EEXIST) {
192  return -1;
193  }
194  }
195 
196  *p = '/';
197  }
198  }
199 
200  if (final) {
201  if (SCDefaultMkDir(pathbuf) != 0) {
202  if (errno != EEXIST) {
203  return -1;
204  }
205  }
206  }
207 
208  return 0;
209 }
210 
211 /**
212  * \brief Check if a path exists.
213  *
214  * \param Path to check for existence
215  *
216  * \retval true if path exists
217  * \retval false if path does not exist
218  */
219 bool SCPathExists(const char *path)
220 {
221  struct stat sb;
222  if (stat(path, &sb) == 0) {
223  return true;
224  }
225  return false;
226 }
227 
228 /**
229  * \brief OS independent wrapper for directory check
230  *
231  * \param dir_entry object to check
232  *
233  * \retval True if the object is a regular directory, otherwise false. This directory
234  * and parent directory will return false.
235  */
236 bool SCIsRegularDirectory(const struct dirent *const dir_entry)
237 {
238 #ifndef OS_WIN32
239  if ((dir_entry->d_type == DT_DIR) &&
240  (strcmp(dir_entry->d_name, ".") != 0) &&
241  (strcmp(dir_entry->d_name, "..") != 0)) {
242  return true;
243  }
244 #endif
245  return false;
246 }
247 /**
248  * \brief OS independent to check for regular file
249  *
250  * \param dir_entry object to check
251  *
252  * \retval True if the object is a regular file. Otherwise false.
253  */
254 bool SCIsRegularFile(const struct dirent *const dir_entry)
255 {
256 #ifndef OS_WIN32
257  return dir_entry->d_type == DT_REG;
258 #endif
259  return false;
260 }
261 
262 /**
263  * \brief OS independent wrapper for realpath
264  *
265  * \param path the path to resolve
266  * \param resolved_path the resolved path; if null, a buffer will be allocated
267  *
268  * \retval the resolved_path; or a pointer to a new resolved_path buffer
269  */
270 char *SCRealPath(const char *path, char *resolved_path)
271 {
272 #ifdef OS_WIN32
273  return _fullpath(resolved_path, path, PATH_MAX);
274 #else
275  return realpath(path, resolved_path);
276 #endif
277 }
278 
279 /*
280  * \brief Return the basename of the provided path.
281  * \param path The path on which to compute the basename
282  *
283  * \retval the basename of the path or NULL if the path lacks a non-leaf
284  */
285 const char *SCBasename(const char *path)
286 {
287  if (!path || strlen(path) == 0)
288  return NULL;
289 
290  char *final = strrchr(path, DIRECTORY_SEPARATOR);
291  if (!final)
292  return path;
293 
294  if (*(final + 1) == '\0')
295  return NULL;
296 
297  return final + 1;
298 }
299 
300 /**
301  * \brief Check for directory traversal
302  *
303  * \param path The path string to check for traversal
304  *
305  * \retval true if directory traversal is found, otherwise false
306  */
307 bool SCPathContainsTraversal(const char *path)
308 {
309 #ifdef OS_WIN32
310  const char *pattern = "..\\";
311 #else
312  const char *pattern = "../";
313 #endif
314  return strstr(path, pattern) != NULL;
315 }
len
uint8_t len
Definition: app-layer-dnp3.h:2
PathMergeAlloc
char * PathMergeAlloc(const char *const dir, const char *const fname)
Definition: util-path.c:107
PathMerge
int PathMerge(char *out_buf, size_t buf_size, const char *const dir, const char *const fname)
Definition: util-path.c:74
SCDefaultMkDir
int SCDefaultMkDir(const char *path)
Wrapper around SCMkDir with default mode arguments.
Definition: util-path.c:159
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
SCPathContainsTraversal
bool SCPathContainsTraversal(const char *path)
Check for directory traversal.
Definition: util-path.c:307
util-debug.h
SCIsRegularDirectory
bool SCIsRegularDirectory(const struct dirent *const dir_entry)
OS independent wrapper for directory check.
Definition: util-path.c:236
strlcat
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
DIRECTORY_SEPARATOR
#define DIRECTORY_SEPARATOR
Definition: util-path.c:33
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
SCBasename
const char * SCBasename(const char *path)
Definition: util-path.c:285
SCPathExists
bool SCPathExists(const char *path)
Check if a path exists.
Definition: util-path.c:219
suricata-common.h
util-path.h
PathIsAbsolute
int PathIsAbsolute(const char *path)
Check if a path is absolute.
Definition: util-path.c:44
SCMkDir
#define SCMkDir(a, b)
Definition: util-path.h:45
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCRealPath
char * SCRealPath(const char *path, char *resolved_path)
OS independent wrapper for realpath.
Definition: util-path.c:270
PathIsRelative
int PathIsRelative(const char *path)
Check if a path is relative.
Definition: util-path.c:69
suricata.h
SCIsRegularFile
bool SCIsRegularFile(const struct dirent *const dir_entry)
OS independent to check for regular file.
Definition: util-path.c:254
PathJoin
int PathJoin(char *out_buf, size_t buf_size, const char *const dir, const char *const fname)
Wrapper to join a directory and filename and resolve using realpath _fullpath is used for WIN32.
Definition: util-path.c:132
SCCreateDirectoryTree
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
Definition: util-path.c:173