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/samba_util.h"
27 #include "lib/util_path.h"
28
29 struct loadparm_substitution;
30 struct share_params;
31 #include "source3/param/param_proto.h"
32
33 /**
34 * @brief Returns an absolute path to a file concatenating the provided
35 * @a rootpath and @a basename
36 *
37 * @param name Filename, relative to @a rootpath
38 *
39 * @retval Pointer to a string containing the full path.
40 **/
41
xx_path(TALLOC_CTX * mem_ctx,const char * name,const char * rootpath)42 static char *xx_path(TALLOC_CTX *mem_ctx,
43 const char *name,
44 const char *rootpath)
45 {
46 char *fname = NULL;
47
48 fname = talloc_strdup(mem_ctx, rootpath);
49 if (!fname) {
50 return NULL;
51 }
52 trim_string(fname,"","/");
53
54 if (!directory_create_or_exist(fname, 0755)) {
55 return NULL;
56 }
57
58 return talloc_asprintf_append(fname, "/%s", name);
59 }
60
61 /**
62 * @brief Returns an absolute path to a file in the Samba lock directory.
63 *
64 * @param name File to find, relative to LOCKDIR.
65 *
66 * @retval Pointer to a talloc'ed string containing the full path.
67 **/
68
lock_path(TALLOC_CTX * mem_ctx,const char * name)69 char *lock_path(TALLOC_CTX *mem_ctx, const char *name)
70 {
71 return xx_path(mem_ctx, name, lp_lock_directory());
72 }
73
74 /**
75 * @brief Returns an absolute path to a file in the Samba state directory.
76 *
77 * @param name File to find, relative to STATEDIR.
78 *
79 * @retval Pointer to a talloc'ed string containing the full path.
80 **/
81
state_path(TALLOC_CTX * mem_ctx,const char * name)82 char *state_path(TALLOC_CTX *mem_ctx, const char *name)
83 {
84 return xx_path(mem_ctx, name, lp_state_directory());
85 }
86
87 /**
88 * @brief Returns an absolute path to a file in the Samba cache directory.
89 *
90 * @param name File to find, relative to CACHEDIR.
91 *
92 * @retval Pointer to a talloc'ed string containing the full path.
93 **/
94
cache_path(TALLOC_CTX * mem_ctx,const char * name)95 char *cache_path(TALLOC_CTX *mem_ctx, const char *name)
96 {
97 return xx_path(mem_ctx, name, lp_cache_directory());
98 }
99
100 /**
101 * @brief Removes any invalid path components in an absolute POSIX path.
102 *
103 * @param ctx Talloc context to return string.
104 *
105 * @param abs_path Absolute path string to process.
106 *
107 * @retval Pointer to a talloc'ed string containing the absolute full path.
108 **/
109
canonicalize_absolute_path(TALLOC_CTX * ctx,const char * abs_path)110 char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path)
111 {
112 char *destname;
113 char *d;
114 const char *s = abs_path;
115 bool start_of_name_component = true;
116
117 /* Allocate for strlen + '\0' + possible leading '/' */
118 destname = (char *)talloc_size(ctx, strlen(abs_path) + 2);
119 if (destname == NULL) {
120 return NULL;
121 }
122 d = destname;
123
124 *d++ = '/'; /* Always start with root. */
125
126 while (*s) {
127 if (*s == '/') {
128 /* Eat multiple '/' */
129 while (*s == '/') {
130 s++;
131 }
132 if ((d > destname + 1) && (*s != '\0')) {
133 *d++ = '/';
134 }
135 start_of_name_component = true;
136 continue;
137 }
138
139 if (start_of_name_component) {
140 if ((s[0] == '.') && (s[1] == '.') &&
141 (s[2] == '/' || s[2] == '\0')) {
142 /* Uh oh - "/../" or "/..\0" ! */
143
144 /* Go past the .. leaving us on the / or '\0' */
145 s += 2;
146
147 /* If we just added a '/' - delete it */
148 if ((d > destname) && (*(d-1) == '/')) {
149 *(d-1) = '\0';
150 d--;
151 }
152
153 /*
154 * Are we at the start ?
155 * Can't go back further if so.
156 */
157 if (d <= destname) {
158 *d++ = '/'; /* Can't delete root */
159 continue;
160 }
161 /* Go back one level... */
162 /*
163 * Decrement d first as d points to
164 * the *next* char to write into.
165 */
166 for (d--; d > destname; d--) {
167 if (*d == '/') {
168 break;
169 }
170 }
171
172 /*
173 * Are we at the start ?
174 * Can't go back further if so.
175 */
176 if (d <= destname) {
177 *d++ = '/'; /* Can't delete root */
178 continue;
179 }
180
181 /*
182 * We're still at the start of a name
183 * component, just the previous one.
184 */
185 continue;
186 } else if ((s[0] == '.') &&
187 ((s[1] == '\0') || s[1] == '/')) {
188 /*
189 * Component of pathname can't be "." only.
190 * Skip the '.' .
191 */
192 if (s[1] == '/') {
193 s += 2;
194 } else {
195 s++;
196 }
197 continue;
198 }
199 }
200
201 if (!(*s & 0x80)) {
202 *d++ = *s++;
203 } else {
204 size_t siz;
205 /* Get the size of the next MB character. */
206 next_codepoint(s,&siz);
207 switch(siz) {
208 case 5:
209 *d++ = *s++;
210
211 FALL_THROUGH;
212 case 4:
213 *d++ = *s++;
214
215 FALL_THROUGH;
216 case 3:
217 *d++ = *s++;
218
219 FALL_THROUGH;
220 case 2:
221 *d++ = *s++;
222
223 FALL_THROUGH;
224 case 1:
225 *d++ = *s++;
226 break;
227 default:
228 break;
229 }
230 }
231 start_of_name_component = false;
232 }
233 *d = '\0';
234
235 /* And must not end in '/' */
236 if (d > destname + 1 && (*(d-1) == '/')) {
237 *(d-1) = '\0';
238 }
239
240 return destname;
241 }
242