Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * Samba utility functions
4 : * Copyright (C) Andrew Tridgell 1992-1998
5 : * Copyright (C) Jeremy Allison 2001-2007
6 : * Copyright (C) Simo Sorce 2001
7 : * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
8 : * Copyright (C) James Peach 2006
9 : *
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 3 of the License, or
13 : * (at your option) any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "replace.h"
25 : #include <talloc.h>
26 : #include "lib/util/debug.h"
27 : #include "lib/util/samba_util.h"
28 : #include "lib/util_path.h"
29 :
30 : struct loadparm_substitution;
31 : struct share_params;
32 : #include "source3/param/param_proto.h"
33 :
34 : /**
35 : * @brief Returns an absolute path to a file concatenating the provided
36 : * @a rootpath and @a basename
37 : *
38 : * @param name Filename, relative to @a rootpath
39 : *
40 : * @retval Pointer to a string containing the full path.
41 : **/
42 :
43 149128 : static char *xx_path(TALLOC_CTX *mem_ctx,
44 : const char *name,
45 : const char *rootpath)
46 : {
47 149128 : char *fname = NULL;
48 :
49 149128 : fname = talloc_strdup(mem_ctx, rootpath);
50 149128 : if (!fname) {
51 0 : return NULL;
52 : }
53 149128 : trim_string(fname,"","/");
54 :
55 149128 : if (!directory_create_or_exist(fname, 0755)) {
56 0 : return NULL;
57 : }
58 :
59 149128 : return talloc_asprintf_append(fname, "/%s", name);
60 : }
61 :
62 : /**
63 : * @brief Returns an absolute path to a file in the Samba lock directory.
64 : *
65 : * @param name File to find, relative to LOCKDIR.
66 : *
67 : * @retval Pointer to a talloc'ed string containing the full path.
68 : **/
69 :
70 68232 : char *lock_path(TALLOC_CTX *mem_ctx, const char *name)
71 : {
72 68232 : return xx_path(mem_ctx, name, lp_lock_directory());
73 : }
74 :
75 : /**
76 : * @brief Returns an absolute path to a file in the Samba state directory.
77 : *
78 : * @param name File to find, relative to STATEDIR.
79 : *
80 : * @retval Pointer to a talloc'ed string containing the full path.
81 : **/
82 :
83 79542 : char *state_path(TALLOC_CTX *mem_ctx, const char *name)
84 : {
85 79542 : return xx_path(mem_ctx, name, lp_state_directory());
86 : }
87 :
88 : /**
89 : * @brief Returns an absolute path to a file in the Samba cache directory.
90 : *
91 : * @param name File to find, relative to CACHEDIR.
92 : *
93 : * @retval Pointer to a talloc'ed string containing the full path.
94 : **/
95 :
96 1354 : char *cache_path(TALLOC_CTX *mem_ctx, const char *name)
97 : {
98 1354 : return xx_path(mem_ctx, name, lp_cache_directory());
99 : }
100 :
101 : /**
102 : * @brief Removes any invalid path components in an absolute POSIX path.
103 : *
104 : * @param ctx Talloc context to return string.
105 : *
106 : * @param abs_path Absolute path string to process.
107 : *
108 : * @retval Pointer to a talloc'ed string containing the absolute full path.
109 : **/
110 :
111 385697 : char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *pathname_in)
112 : {
113 : /*
114 : * Note we use +2 here so if pathname_in=="" then we
115 : * have space to return "/".
116 : */
117 385697 : char *pathname = talloc_array(ctx, char, strlen(pathname_in)+2);
118 385697 : const char *s = pathname_in;
119 385697 : char *p = pathname;
120 :
121 385697 : if (pathname == NULL) {
122 0 : return NULL;
123 : }
124 :
125 : /* Always start with a '/'. */
126 385697 : *p++ = '/';
127 :
128 29622431 : while (*s) {
129 : /* Deal with '/' or multiples of '/'. */
130 29236734 : if (s[0] == '/') {
131 7444843 : while (s[0] == '/') {
132 : /* Eat trailing '/' */
133 3727056 : s++;
134 : }
135 : /* Update target with one '/' */
136 3717787 : if (p[-1] != '/') {
137 3332093 : *p++ = '/';
138 : }
139 3717787 : continue;
140 : }
141 25518947 : if (p[-1] == '/') {
142 : /* Deal with "./" or ".\0" */
143 3706524 : if (s[0] == '.' &&
144 70969 : (s[1] == '/' || s[1] == '\0')) {
145 : /* Eat the dot. */
146 46638 : s++;
147 46723 : while (s[0] == '/') {
148 : /* Eat any trailing '/' */
149 85 : s++;
150 : }
151 : /* Don't write anything to target. */
152 46638 : continue;
153 : }
154 : /* Deal with "../" or "..\0" */
155 3659886 : if (s[0] == '.' && s[1] == '.' &&
156 2968 : (s[2] == '/' || s[2] == '\0')) {
157 : /* Eat the dot dot. */
158 2967 : s += 2;
159 5657 : while (s[0] == '/') {
160 : /* Eat any trailing '/' */
161 2690 : s++;
162 : }
163 : /*
164 : * As we're on the slash, we go back
165 : * one character to point p at the
166 : * slash we just saw.
167 : */
168 2967 : if (p > pathname) {
169 2967 : p--;
170 : }
171 : /*
172 : * Now go back to the slash
173 : * before the one that p currently points to.
174 : */
175 14274 : while (p > pathname) {
176 14262 : p--;
177 14262 : if (p[0] == '/') {
178 2946 : break;
179 : }
180 : }
181 : /*
182 : * Step forward one to leave the
183 : * last written '/' alone.
184 : */
185 2967 : p++;
186 :
187 : /* Don't write anything to target. */
188 2967 : continue;
189 : }
190 : }
191 : /* Non-separator character, just copy. */
192 25469342 : *p++ = *s++;
193 : }
194 385697 : if (p[-1] == '/') {
195 : /*
196 : * We finished on a '/'.
197 : * Remove the trailing '/', but not if it's
198 : * the sole character in the path.
199 : */
200 60871 : if (p > pathname + 1) {
201 45264 : p--;
202 : }
203 : }
204 : /* Terminate and we're done ! */
205 385697 : *p++ = '\0';
206 385697 : return pathname;
207 : }
208 :
209 82533 : static bool find_snapshot_token(
210 : const char *filename,
211 : char sep,
212 : const char **_start,
213 : const char **_next_component,
214 : NTTIME *twrp)
215 : {
216 82533 : const char *start = NULL;
217 82533 : const char *end = NULL;
218 82533 : struct tm tm = {};
219 0 : time_t t;
220 :
221 82533 : start = strstr_m(filename, "@GMT-");
222 :
223 82533 : if (start == NULL) {
224 71524 : return false;
225 : }
226 :
227 11009 : if ((start > filename) && (start[-1] != sep)) {
228 : /* the GMT-token does not start a path-component */
229 0 : return false;
230 : }
231 :
232 11009 : end = strptime(start, GMT_FORMAT, &tm);
233 11009 : if (end == NULL) {
234 : /* Not a valid timestring. */
235 0 : return false;
236 : }
237 :
238 11009 : if ((end[0] != '\0') && (end[0] != sep)) {
239 : /*
240 : * It is not a complete path component, i.e. the path
241 : * component continues after the gmt-token.
242 : */
243 0 : return false;
244 : }
245 :
246 11009 : tm.tm_isdst = -1;
247 11009 : t = timegm(&tm);
248 11009 : unix_to_nt_time(twrp, t);
249 :
250 11009 : DBG_DEBUG("Extracted @GMT-Timestamp %s\n",
251 : nt_time_string(talloc_tos(), *twrp));
252 :
253 11009 : *_start = start;
254 :
255 11009 : if (end[0] == sep) {
256 11006 : end += 1;
257 : }
258 11009 : *_next_component = end;
259 :
260 11009 : return true;
261 : }
262 :
263 21906 : bool clistr_is_previous_version_path(const char *path)
264 : {
265 21906 : const char *start = NULL;
266 21906 : const char *next = NULL;
267 0 : NTTIME twrp;
268 0 : bool ok;
269 :
270 21906 : ok = find_snapshot_token(path, '\\', &start, &next, &twrp);
271 21906 : return ok;
272 : }
273 :
274 60627 : static bool extract_snapshot_token_internal(char *fname, NTTIME *twrp, char sep)
275 : {
276 60627 : const char *start = NULL;
277 60627 : const char *next = NULL;
278 0 : size_t remaining;
279 0 : bool found;
280 :
281 60627 : found = find_snapshot_token(fname, sep, &start, &next, twrp);
282 60627 : if (!found) {
283 53794 : return false;
284 : }
285 :
286 6833 : remaining = strlen(next);
287 6833 : memmove(discard_const_p(char, start), next, remaining+1);
288 :
289 6833 : return true;
290 : }
291 :
292 4306 : bool extract_snapshot_token(char *fname, NTTIME *twrp)
293 : {
294 4306 : return extract_snapshot_token_internal(fname, twrp, '/');
295 : }
296 :
297 56321 : bool clistr_smb2_extract_snapshot_token(char *fname, NTTIME *twrp)
298 : {
299 56321 : return extract_snapshot_token_internal(fname, twrp, '\\');
300 : }
301 :
302 : /*
303 : * Take two absolute paths, figure out if "subdir" is a proper
304 : * subdirectory of "parent". Return the component relative to the
305 : * "parent" without the potential "/". Take care of "parent"
306 : * possibly ending in "/".
307 : */
308 3461860 : bool subdir_of(const char *parent,
309 : size_t parent_len,
310 : const char *subdir,
311 : const char **_relative)
312 : {
313 3461860 : const char *relative = NULL;
314 10573 : bool matched;
315 :
316 3461860 : SMB_ASSERT(parent[0] == '/');
317 3461860 : SMB_ASSERT(subdir[0] == '/');
318 :
319 3461860 : if (parent_len == 1) {
320 : /*
321 : * Everything is below "/"
322 : */
323 14916 : *_relative = subdir+1;
324 14916 : return true;
325 : }
326 :
327 3446944 : if (parent[parent_len-1] == '/') {
328 0 : parent_len -= 1;
329 : }
330 :
331 3446944 : matched = (strncmp(subdir, parent, parent_len) == 0);
332 3446944 : if (!matched) {
333 145365 : return false;
334 : }
335 :
336 3299708 : relative = &subdir[parent_len];
337 :
338 3299708 : if (relative[0] == '\0') {
339 2451885 : *_relative = relative; /* nothing left */
340 2451885 : return true;
341 : }
342 :
343 847823 : if (relative[0] == '/') {
344 : /* End of parent must match a '/' in subdir. */
345 847778 : *_relative = relative+1;
346 847778 : return true;
347 : }
348 :
349 45 : return false;
350 : }
|