1 /*
2    Unix SMB/CIFS implementation.
3    Filename utility functions.
4    Copyright (C) Tim Prouty 2009
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "includes.h"
20 
21 /**
22  * XXX: This is temporary and there should be no callers of this outside of
23  * this file once smb_filename is plumbed through all path based operations.
24  * The one legitimate caller currently is smb_fname_str_dbg(), which this
25  * could be made static for.
26  */
get_full_smb_filename(TALLOC_CTX * ctx,const struct smb_filename * smb_fname,char ** full_name)27 NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx,
28 			       const struct smb_filename *smb_fname,
29 			       char **full_name)
30 {
31 	if (smb_fname->stream_name) {
32 		/* stream_name must always be NULL if there is no stream. */
33 		SMB_ASSERT(smb_fname->stream_name[0] != '\0');
34 
35 		*full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name,
36 					     smb_fname->stream_name);
37 	} else {
38 		*full_name = talloc_strdup(ctx, smb_fname->base_name);
39 	}
40 
41 	if (!*full_name) {
42 		return NT_STATUS_NO_MEMORY;
43 	}
44 
45 	return NT_STATUS_OK;
46 }
47 
48 /**
49  * There are actually legitimate callers of this such as functions that
50  * enumerate streams using the vfs_streaminfo interface and then want to
51  * operate on each stream.
52  */
synthetic_smb_fname(TALLOC_CTX * mem_ctx,const char * base_name,const char * stream_name,const SMB_STRUCT_STAT * psbuf,uint32_t flags)53 struct smb_filename *synthetic_smb_fname(TALLOC_CTX *mem_ctx,
54 					 const char *base_name,
55 					 const char *stream_name,
56 					 const SMB_STRUCT_STAT *psbuf,
57 					 uint32_t flags)
58 {
59 	struct smb_filename smb_fname_loc = { 0, };
60 
61 	/* Setup the base_name/stream_name. */
62 	smb_fname_loc.base_name = discard_const_p(char, base_name);
63 	smb_fname_loc.stream_name = discard_const_p(char, stream_name);
64 	smb_fname_loc.flags = flags;
65 
66 	/* Copy the psbuf if one was given. */
67 	if (psbuf)
68 		smb_fname_loc.st = *psbuf;
69 
70 	/* Let cp_smb_filename() do the heavy lifting. */
71 	return cp_smb_filename(mem_ctx, &smb_fname_loc);
72 }
73 
74 /**
75  * Utility function used by VFS calls that must *NOT* operate
76  * on a stream filename, only the base_name.
77  */
cp_smb_filename_nostream(TALLOC_CTX * mem_ctx,const struct smb_filename * smb_fname_in)78 struct smb_filename *cp_smb_filename_nostream(TALLOC_CTX *mem_ctx,
79 					const struct smb_filename *smb_fname_in)
80 {
81 	struct smb_filename *smb_fname = cp_smb_filename(mem_ctx,
82 							smb_fname_in);
83 	if (smb_fname == NULL) {
84 		return NULL;
85 	}
86 	TALLOC_FREE(smb_fname->stream_name);
87 	return smb_fname;
88 }
89 
90 /**
91  * There are a few legitimate users of this.
92  */
synthetic_smb_fname_split(TALLOC_CTX * ctx,const char * fname,bool posix_path)93 struct smb_filename *synthetic_smb_fname_split(TALLOC_CTX *ctx,
94 						const char *fname,
95 						bool posix_path)
96 {
97 	char *stream_name = NULL;
98 	char *base_name = NULL;
99 	struct smb_filename *ret;
100 	bool ok;
101 
102 	if (posix_path) {
103 		/* No stream name looked for. */
104 		return synthetic_smb_fname(ctx,
105 				fname,
106 				NULL,
107 				NULL,
108 				SMB_FILENAME_POSIX_PATH);
109 	}
110 
111 	ok = split_stream_filename(ctx,
112 				fname,
113 				&base_name,
114 				&stream_name);
115 	if (!ok) {
116 		return NULL;
117 	}
118 
119 	ret = synthetic_smb_fname(ctx, base_name, stream_name, NULL, 0);
120 	TALLOC_FREE(base_name);
121 	TALLOC_FREE(stream_name);
122 	return ret;
123 }
124 
125 /**
126  * Return a string using the talloc_tos()
127  */
smb_fname_str_dbg(const struct smb_filename * smb_fname)128 const char *smb_fname_str_dbg(const struct smb_filename *smb_fname)
129 {
130 	char *fname = NULL;
131 	NTSTATUS status;
132 
133 	if (smb_fname == NULL) {
134 		return "";
135 	}
136 	status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
137 	if (!NT_STATUS_IS_OK(status)) {
138 		return "";
139 	}
140 	return fname;
141 }
142 
143 /**
144  * Return a debug string of the path name of an fsp using the talloc_tos().
145  */
fsp_str_dbg(const struct files_struct * fsp)146 const char *fsp_str_dbg(const struct files_struct *fsp)
147 {
148 	return smb_fname_str_dbg(fsp->fsp_name);
149 }
150 
151 /**
152  * Create a debug string for the fnum of an fsp.
153  *
154  * This is allocated to talloc_tos() or a string constant
155  * in certain corner cases. The returned string should
156  * hence not be free'd directly but only via the talloc stack.
157  */
fsp_fnum_dbg(const struct files_struct * fsp)158 const char *fsp_fnum_dbg(const struct files_struct *fsp)
159 {
160 	char *str;
161 
162 	if (fsp == NULL) {
163 		return "fnum [fsp is NULL]";
164 	}
165 
166 	if (fsp->fnum == FNUM_FIELD_INVALID) {
167 		return "fnum [invalid value]";
168 	}
169 
170 	str = talloc_asprintf(talloc_tos(), "fnum %llu",
171 			      (unsigned long long)fsp->fnum);
172 	if (str == NULL) {
173 		DEBUG(1, ("%s: talloc_asprintf failed\n", __FUNCTION__));
174 		return "fnum [talloc failed!]";
175 	}
176 
177 	return str;
178 }
179 
cp_smb_filename(TALLOC_CTX * mem_ctx,const struct smb_filename * in)180 struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx,
181 				     const struct smb_filename *in)
182 {
183 	struct smb_filename *out;
184 	size_t base_len = 0;
185 	size_t stream_len = 0;
186 	size_t lcomp_len = 0;
187 	int num = 0;
188 
189 	/* stream_name must always be NULL if there is no stream. */
190 	if (in->stream_name) {
191 		SMB_ASSERT(in->stream_name[0] != '\0');
192 	}
193 
194 	if (in->base_name != NULL) {
195 		base_len = strlen(in->base_name) + 1;
196 		num += 1;
197 	}
198 	if (in->stream_name != NULL) {
199 		stream_len = strlen(in->stream_name) + 1;
200 		num += 1;
201 	}
202 	if (in->original_lcomp != NULL) {
203 		lcomp_len = strlen(in->original_lcomp) + 1;
204 		num += 1;
205 	}
206 
207 	out = talloc_pooled_object(mem_ctx, struct smb_filename,
208 				num, stream_len + base_len + lcomp_len);
209 	if (out == NULL) {
210 		return NULL;
211 	}
212 	ZERO_STRUCTP(out);
213 
214 	/*
215 	 * The following allocations cannot fail as we
216 	 * pre-allocated space for them in the out pooled
217 	 * object.
218 	 */
219 	if (in->base_name != NULL) {
220 		out->base_name = talloc_memdup(
221 				out, in->base_name, base_len);
222 		talloc_set_name_const(out->base_name,
223 				      out->base_name);
224 	}
225 	if (in->stream_name != NULL) {
226 		out->stream_name = talloc_memdup(
227 				out, in->stream_name, stream_len);
228 		talloc_set_name_const(out->stream_name,
229 				      out->stream_name);
230 	}
231 	if (in->original_lcomp != NULL) {
232 		out->original_lcomp = talloc_memdup(
233 				out, in->original_lcomp, lcomp_len);
234 		talloc_set_name_const(out->original_lcomp,
235 				      out->original_lcomp);
236 	}
237 	out->flags = in->flags;
238 	out->st = in->st;
239 	return out;
240 }
241 
assert_valid_stream_smb_fname(const struct smb_filename * smb_fname)242 static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname)
243 {
244 	/* stream_name must always be NULL if there is no stream. */
245 	if (smb_fname->stream_name) {
246 		SMB_ASSERT(smb_fname->stream_name[0] != '\0');
247 	}
248 
249 	if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
250 		SMB_ASSERT(smb_fname->stream_name == NULL);
251 	}
252 }
253 
254 /****************************************************************************
255  Simple check to determine if a smb_fname is a real named stream or the
256  default stream.
257  ***************************************************************************/
258 
is_ntfs_stream_smb_fname(const struct smb_filename * smb_fname)259 bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname)
260 {
261 	assert_valid_stream_smb_fname(smb_fname);
262 
263 	if (smb_fname->stream_name == NULL) {
264 		return false;
265 	}
266 
267 	return true;
268 }
269 
270 /****************************************************************************
271  Simple check to determine if a smb_fname is pointing to a normal file or
272  a named stream that is not the default stream "::$DATA".
273 
274   foo           -> false
275   foo::$DATA    -> false
276   foo:bar       -> true
277   foo:bar:$DATA -> true
278 
279  ***************************************************************************/
280 
is_named_stream(const struct smb_filename * smb_fname)281 bool is_named_stream(const struct smb_filename *smb_fname)
282 {
283 	assert_valid_stream_smb_fname(smb_fname);
284 
285 	if (smb_fname->stream_name == NULL) {
286 		return false;
287 	}
288 
289 	if (strequal_m(smb_fname->stream_name, "::$DATA")) {
290 		return false;
291 	}
292 
293 	return true;
294 }
295 
296 /****************************************************************************
297  Returns true if the filename's stream == "::$DATA"
298  ***************************************************************************/
is_ntfs_default_stream_smb_fname(const struct smb_filename * smb_fname)299 bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname)
300 {
301 	assert_valid_stream_smb_fname(smb_fname);
302 
303 	if (smb_fname->stream_name == NULL) {
304 		return false;
305 	}
306 
307 	return strequal_m(smb_fname->stream_name, "::$DATA");
308 }
309 
310 /****************************************************************************
311  Filter out Windows invalid EA names (list probed from Windows 2012).
312 ****************************************************************************/
313 
314 static char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|";
315 
is_invalid_windows_ea_name(const char * name)316 bool is_invalid_windows_ea_name(const char *name)
317 {
318 	int i;
319 	/* EA name is pulled as ascii so we can examine
320 	   individual bytes here. */
321 	for (i = 0; name[i] != 0; i++) {
322 		int val = (name[i] & 0xff);
323 		if (val < ' ' || strchr(bad_ea_name_chars, val)) {
324 			return true;
325 		}
326 	}
327 	return false;
328 }
329 
ea_list_has_invalid_name(struct ea_list * ea_list)330 bool ea_list_has_invalid_name(struct ea_list *ea_list)
331 {
332 	for (;ea_list; ea_list = ea_list->next) {
333 		if (is_invalid_windows_ea_name(ea_list->ea.name)) {
334 			return true;
335 		}
336 	}
337 	return false;
338 }
339 
340 /****************************************************************************
341  Split an incoming name into tallocd filename and stream components.
342  Returns true on success, false on out of memory.
343 ****************************************************************************/
344 
split_stream_filename(TALLOC_CTX * ctx,const char * filename_in,char ** filename_out,char ** streamname_out)345 bool split_stream_filename(TALLOC_CTX *ctx,
346 				const char *filename_in,
347 				char **filename_out,
348 				char **streamname_out)
349 {
350 	const char *stream_name = NULL;
351 	char *stream_out = NULL;
352 	char *file_out = NULL;
353 
354 	stream_name = strchr_m(filename_in, ':');
355 
356 	if (stream_name) {
357 		stream_out = talloc_strdup(ctx, stream_name);
358 		if (stream_out == NULL) {
359 			return false;
360 		}
361 		file_out = talloc_strndup(ctx,
362 					filename_in,
363 					PTR_DIFF(stream_name, filename_in));
364 	} else {
365 		file_out = talloc_strdup(ctx, filename_in);
366 	}
367 
368 	if (file_out == NULL) {
369 		TALLOC_FREE(stream_out);
370 		return false;
371 	}
372 
373 	if (filename_out) {
374 		*filename_out = file_out;
375 	}
376 	if (streamname_out) {
377 		*streamname_out = stream_out;
378 	}
379 	return true;
380 }
381 
382 /**
383  * Checks whether the first part of path is a valid GMT token
384  */
is_gmt_token(const char * path)385 bool is_gmt_token(const char *path)
386 {
387 	struct tm tm;
388 	char *p = NULL;
389 
390 	p = strptime(path, GMT_FORMAT, &tm);
391 	if (p == NULL) {
392 		/* Not a valid timestring. */
393 		return false;
394 	}
395 	if (p[0] != '\0' && p[0] != '/') {
396 		return false;
397 	}
398 	return true;
399 }
400