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 21548 : static char *xx_path(TALLOC_CTX *mem_ctx,
44 : const char *name,
45 : const char *rootpath)
46 : {
47 21548 : char *fname = NULL;
48 :
49 21548 : fname = talloc_strdup(mem_ctx, rootpath);
50 21548 : if (!fname) {
51 0 : return NULL;
52 : }
53 21548 : trim_string(fname,"","/");
54 :
55 21548 : if (!directory_create_or_exist(fname, 0755)) {
56 0 : return NULL;
57 : }
58 :
59 21548 : 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 9859 : char *lock_path(TALLOC_CTX *mem_ctx, const char *name)
71 : {
72 9859 : 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 11437 : char *state_path(TALLOC_CTX *mem_ctx, const char *name)
84 : {
85 11437 : 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 252 : char *cache_path(TALLOC_CTX *mem_ctx, const char *name)
97 : {
98 252 : 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 25007 : 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 25007 : char *pathname = talloc_array(ctx, char, strlen(pathname_in)+2);
118 25007 : const char *s = pathname_in;
119 25007 : char *p = pathname;
120 :
121 25007 : if (pathname == NULL) {
122 0 : return NULL;
123 : }
124 :
125 : /* Always start with a '/'. */
126 25007 : *p++ = '/';
127 :
128 1416989 : while (*s) {
129 : /* Deal with '/' or multiples of '/'. */
130 1375366 : if (s[0] == '/') {
131 522144 : while (s[0] == '/') {
132 : /* Eat trailing '/' */
133 200632 : s++;
134 : }
135 : /* Update target with one '/' */
136 200624 : if (p[-1] != '/') {
137 175617 : *p++ = '/';
138 : }
139 200624 : continue;
140 : }
141 1174742 : if (p[-1] == '/') {
142 : /* Deal with "./" or ".\0" */
143 197590 : if (s[0] == '.' &&
144 12 : (s[1] == '/' || s[1] == '\0')) {
145 : /* Eat the dot. */
146 8 : s++;
147 12 : while (s[0] == '/') {
148 : /* Eat any trailing '/' */
149 0 : s++;
150 : }
151 : /* Don't write anything to target. */
152 8 : continue;
153 : }
154 : /* Deal with "../" or "..\0" */
155 197578 : if (s[0] == '.' && s[1] == '.' &&
156 0 : (s[2] == '/' || s[2] == '\0')) {
157 : /* Eat the dot dot. */
158 0 : s += 2;
159 0 : while (s[0] == '/') {
160 : /* Eat any trailing '/' */
161 0 : 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 0 : if (p > pathname) {
169 0 : p--;
170 : }
171 : /*
172 : * Now go back to the slash
173 : * before the one that p currently points to.
174 : */
175 0 : while (p > pathname) {
176 0 : p--;
177 0 : if (p[0] == '/') {
178 0 : break;
179 : }
180 : }
181 : /*
182 : * Step forward one to leave the
183 : * last written '/' alone.
184 : */
185 0 : p++;
186 :
187 : /* Don't write anything to target. */
188 0 : continue;
189 : }
190 : }
191 : /* Non-separator character, just copy. */
192 1174734 : *p++ = *s++;
193 : }
194 25007 : 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 3046 : if (p > pathname + 1) {
201 0 : p--;
202 : }
203 : }
204 : /* Terminate and we're done ! */
205 25007 : *p++ = '\0';
206 25007 : return pathname;
207 : }
208 :
209 : /*
210 : * Take two absolute paths, figure out if "subdir" is a proper
211 : * subdirectory of "parent". Return the component relative to the
212 : * "parent" without the potential "/". Take care of "parent"
213 : * possibly ending in "/".
214 : */
215 3444 : bool subdir_of(const char *parent,
216 : size_t parent_len,
217 : const char *subdir,
218 : const char **_relative)
219 : {
220 3444 : const char *relative = NULL;
221 : bool matched;
222 :
223 3444 : SMB_ASSERT(parent[0] == '/');
224 3444 : SMB_ASSERT(subdir[0] == '/');
225 :
226 3444 : if (parent_len == 1) {
227 : /*
228 : * Everything is below "/"
229 : */
230 0 : *_relative = subdir+1;
231 0 : return true;
232 : }
233 :
234 3444 : if (parent[parent_len-1] == '/') {
235 0 : parent_len -= 1;
236 : }
237 :
238 3444 : matched = (strncmp(subdir, parent, parent_len) == 0);
239 3444 : if (!matched) {
240 0 : return false;
241 : }
242 :
243 3444 : relative = &subdir[parent_len];
244 :
245 3444 : if (relative[0] == '\0') {
246 0 : *_relative = relative; /* nothing left */
247 0 : return true;
248 : }
249 :
250 3444 : if (relative[0] == '/') {
251 : /* End of parent must match a '/' in subdir. */
252 3444 : *_relative = relative+1;
253 3444 : return true;
254 : }
255 :
256 0 : return false;
257 : }
|