418dd20327b00e8217b807ca27691a85c11abee0
[amitay/samba.git] / source3 / lib / filename_util.c
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  */
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  */
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                                          NTTIME twrp,
58                                          uint32_t flags)
59 {
60         struct smb_filename smb_fname_loc = { 0, };
61
62         /* Setup the base_name/stream_name. */
63         smb_fname_loc.base_name = discard_const_p(char, base_name);
64         smb_fname_loc.stream_name = discard_const_p(char, stream_name);
65         smb_fname_loc.flags = flags;
66         smb_fname_loc.twrp = twrp;
67
68         /* Copy the psbuf if one was given. */
69         if (psbuf)
70                 smb_fname_loc.st = *psbuf;
71
72         /* Let cp_smb_filename() do the heavy lifting. */
73         return cp_smb_filename(mem_ctx, &smb_fname_loc);
74 }
75
76 /**
77  * Utility function used by VFS calls that must *NOT* operate
78  * on a stream filename, only the base_name.
79  */
80 struct smb_filename *cp_smb_filename_nostream(TALLOC_CTX *mem_ctx,
81                                         const struct smb_filename *smb_fname_in)
82 {
83         struct smb_filename *smb_fname = cp_smb_filename(mem_ctx,
84                                                         smb_fname_in);
85         if (smb_fname == NULL) {
86                 return NULL;
87         }
88         TALLOC_FREE(smb_fname->stream_name);
89         return smb_fname;
90 }
91
92 /**
93  * There are a few legitimate users of this.
94  */
95 struct smb_filename *synthetic_smb_fname_split(TALLOC_CTX *ctx,
96                                                 const char *fname,
97                                                 bool posix_path)
98 {
99         char *stream_name = NULL;
100         char *base_name = NULL;
101         struct smb_filename *ret;
102         bool ok;
103
104         if (posix_path) {
105                 /* No stream name looked for. */
106                 return synthetic_smb_fname(ctx,
107                                 fname,
108                                 NULL,
109                                 NULL,
110                                 0,
111                                 SMB_FILENAME_POSIX_PATH);
112         }
113
114         ok = split_stream_filename(ctx,
115                                 fname,
116                                 &base_name,
117                                 &stream_name);
118         if (!ok) {
119                 return NULL;
120         }
121
122         ret = synthetic_smb_fname(ctx,
123                                   base_name,
124                                   stream_name,
125                                   NULL,
126                                   0,
127                                   0);
128         TALLOC_FREE(base_name);
129         TALLOC_FREE(stream_name);
130         return ret;
131 }
132
133 /**
134  * Return a string using the talloc_tos()
135  */
136 const char *smb_fname_str_dbg(const struct smb_filename *smb_fname)
137 {
138         char *fname = NULL;
139         time_t t;
140         struct tm tm;
141         struct tm *ptm = NULL;
142         fstring tstr;
143         ssize_t slen;
144         NTSTATUS status;
145
146         if (smb_fname == NULL) {
147                 return "";
148         }
149         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
150         if (!NT_STATUS_IS_OK(status)) {
151                 return "";
152         }
153         if (smb_fname->twrp == 0) {
154                 return fname;
155         }
156
157         t = nt_time_to_unix(smb_fname->twrp);
158         ptm = gmtime_r(&t, &tm);
159         if (ptm == NULL) {
160                 return "";
161         }
162
163         slen = strftime(tstr, sizeof(tstr), GMT_FORMAT, &tm);
164         if (slen == 0) {
165                 return "";
166         }
167
168         fname = talloc_asprintf(talloc_tos(),
169                                 "%s {%s}",
170                                 fname,
171                                 tstr);
172         if (fname == NULL) {
173                 return "";
174         }
175         return fname;
176 }
177
178 /**
179  * Return a debug string of the path name of an fsp using the talloc_tos().
180  */
181 const char *fsp_str_dbg(const struct files_struct *fsp)
182 {
183         const char *name = NULL;
184
185         name = smb_fname_str_dbg(fsp->fsp_name);
186         if (name == NULL) {
187                 return "";
188         }
189
190         if (fsp->dirfsp == NULL || fsp->dirfsp == fsp->conn->cwd_fsp) {
191                 return name;
192         }
193
194         if (ISDOT(fsp->dirfsp->fsp_name->base_name)) {
195                 return name;
196         }
197
198         name = talloc_asprintf(talloc_tos(),
199                                "%s/%s",
200                                fsp->dirfsp->fsp_name->base_name,
201                                fsp->fsp_name->base_name);
202         if (name == NULL) {
203                 return "";
204         }
205         return name;
206 }
207
208 /**
209  * Create a debug string for the fnum of an fsp.
210  *
211  * This is allocated to talloc_tos() or a string constant
212  * in certain corner cases. The returned string should
213  * hence not be free'd directly but only via the talloc stack.
214  */
215 const char *fsp_fnum_dbg(const struct files_struct *fsp)
216 {
217         char *str;
218
219         if (fsp == NULL) {
220                 return "fnum [fsp is NULL]";
221         }
222
223         if (fsp->fnum == FNUM_FIELD_INVALID) {
224                 return "fnum [invalid value]";
225         }
226
227         str = talloc_asprintf(talloc_tos(), "fnum %llu",
228                               (unsigned long long)fsp->fnum);
229         if (str == NULL) {
230                 DEBUG(1, ("%s: talloc_asprintf failed\n", __FUNCTION__));
231                 return "fnum [talloc failed!]";
232         }
233
234         return str;
235 }
236
237 struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx,
238                                      const struct smb_filename *in)
239 {
240         struct smb_filename *out;
241         size_t base_len = 0;
242         size_t stream_len = 0;
243         int num = 0;
244
245         /* stream_name must always be NULL if there is no stream. */
246         if (in->stream_name) {
247                 SMB_ASSERT(in->stream_name[0] != '\0');
248         }
249
250         if (in->base_name != NULL) {
251                 base_len = strlen(in->base_name) + 1;
252                 num += 1;
253         }
254         if (in->stream_name != NULL) {
255                 stream_len = strlen(in->stream_name) + 1;
256                 num += 1;
257         }
258
259         out = talloc_pooled_object(mem_ctx, struct smb_filename,
260                                 num, stream_len + base_len);
261         if (out == NULL) {
262                 return NULL;
263         }
264         ZERO_STRUCTP(out);
265
266         /*
267          * The following allocations cannot fail as we
268          * pre-allocated space for them in the out pooled
269          * object.
270          */
271         if (in->base_name != NULL) {
272                 out->base_name = talloc_memdup(
273                                 out, in->base_name, base_len);
274                 talloc_set_name_const(out->base_name,
275                                       out->base_name);
276         }
277         if (in->stream_name != NULL) {
278                 out->stream_name = talloc_memdup(
279                                 out, in->stream_name, stream_len);
280                 talloc_set_name_const(out->stream_name,
281                                       out->stream_name);
282         }
283         out->flags = in->flags;
284         out->st = in->st;
285         out->twrp = in->twrp;
286         return out;
287 }
288
289 /**
290  * Return allocated parent directory and basename of path
291  *
292  * Note: if requesting name, it is returned as talloc child of the
293  * parent. Freeing the parent is thus sufficient to free both.
294  */
295 bool parent_smb_fname(TALLOC_CTX *mem_ctx,
296                       const struct smb_filename *path,
297                       struct smb_filename **_parent,
298                       struct smb_filename  **_name)
299 {
300         TALLOC_CTX *frame = talloc_stackframe();
301         struct smb_filename *parent = NULL;
302         struct smb_filename *name = NULL;
303         char *p = NULL;
304
305         parent = cp_smb_filename(frame, path);
306         if (parent == NULL) {
307                 TALLOC_FREE(frame);
308                 return false;
309         }
310         TALLOC_FREE(parent->stream_name);
311         SET_STAT_INVALID(parent->st);
312
313         p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
314         if (p == NULL) {
315                 TALLOC_FREE(parent->base_name);
316                 parent->base_name = talloc_strdup(parent, ".");
317                 if (parent->base_name == NULL) {
318                         TALLOC_FREE(frame);
319                         return false;
320                 }
321                 p = path->base_name;
322         } else {
323                 *p = '\0';
324                 p++;
325         }
326
327         if (_name == NULL) {
328                 *_parent = talloc_move(mem_ctx, &parent);
329                 TALLOC_FREE(frame);
330                 return true;
331         }
332
333         name = cp_smb_filename(frame, path);
334         if (name == NULL) {
335                 TALLOC_FREE(frame);
336                 return false;
337         }
338         TALLOC_FREE(name->base_name);
339
340         name->base_name = talloc_strdup(mem_ctx, p);
341         if (name == NULL) {
342                 TALLOC_FREE(frame);
343                 return false;
344         }
345
346         *_parent = talloc_move(mem_ctx, &parent);
347         *_name = talloc_move(*_parent, &name);
348         TALLOC_FREE(frame);
349         return true;
350 }
351
352 static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname)
353 {
354         /* stream_name must always be NULL if there is no stream. */
355         if (smb_fname->stream_name) {
356                 SMB_ASSERT(smb_fname->stream_name[0] != '\0');
357         }
358
359         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
360                 SMB_ASSERT(smb_fname->stream_name == NULL);
361         }
362 }
363
364 /****************************************************************************
365  Simple check to determine if a smb_fname is a real named stream or the
366  default stream.
367  ***************************************************************************/
368
369 bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname)
370 {
371         assert_valid_stream_smb_fname(smb_fname);
372
373         if (smb_fname->stream_name == NULL) {
374                 return false;
375         }
376
377         return true;
378 }
379
380 /****************************************************************************
381  Simple check to determine if a smb_fname is pointing to a normal file or
382  a named stream that is not the default stream "::$DATA".
383
384   foo           -> false
385   foo::$DATA    -> false
386   foo:bar       -> true
387   foo:bar:$DATA -> true
388
389  ***************************************************************************/
390
391 bool is_named_stream(const struct smb_filename *smb_fname)
392 {
393         assert_valid_stream_smb_fname(smb_fname);
394
395         if (smb_fname->stream_name == NULL) {
396                 return false;
397         }
398
399         if (strequal_m(smb_fname->stream_name, "::$DATA")) {
400                 return false;
401         }
402
403         return true;
404 }
405
406 /****************************************************************************
407  Returns true if the filename's stream == "::$DATA"
408  ***************************************************************************/
409 bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname)
410 {
411         assert_valid_stream_smb_fname(smb_fname);
412
413         if (smb_fname->stream_name == NULL) {
414                 return false;
415         }
416
417         return strequal_m(smb_fname->stream_name, "::$DATA");
418 }
419
420 /****************************************************************************
421  Filter out Windows invalid EA names (list probed from Windows 2012).
422 ****************************************************************************/
423
424 static char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|";
425
426 bool is_invalid_windows_ea_name(const char *name)
427 {
428         int i;
429         /* EA name is pulled as ascii so we can examine
430            individual bytes here. */
431         for (i = 0; name[i] != 0; i++) {
432                 int val = (name[i] & 0xff);
433                 if (val < ' ' || strchr(bad_ea_name_chars, val)) {
434                         return true;
435                 }
436         }
437         return false;
438 }
439
440 bool ea_list_has_invalid_name(struct ea_list *ea_list)
441 {
442         for (;ea_list; ea_list = ea_list->next) {
443                 if (is_invalid_windows_ea_name(ea_list->ea.name)) {
444                         return true;
445                 }
446         }
447         return false;
448 }
449
450 /****************************************************************************
451  Split an incoming name into tallocd filename and stream components.
452  Returns true on success, false on out of memory.
453 ****************************************************************************/
454
455 bool split_stream_filename(TALLOC_CTX *ctx,
456                                 const char *filename_in,
457                                 char **filename_out,
458                                 char **streamname_out)
459 {
460         const char *stream_name = NULL;
461         char *stream_out = NULL;
462         char *file_out = NULL;
463
464         stream_name = strchr_m(filename_in, ':');
465
466         if (stream_name) {
467                 stream_out = talloc_strdup(ctx, stream_name);
468                 if (stream_out == NULL) {
469                         return false;
470                 }
471                 file_out = talloc_strndup(ctx,
472                                         filename_in,
473                                         PTR_DIFF(stream_name, filename_in));
474         } else {
475                 file_out = talloc_strdup(ctx, filename_in);
476         }
477
478         if (file_out == NULL) {
479                 TALLOC_FREE(stream_out);
480                 return false;
481         }
482
483         if (filename_out) {
484                 *filename_out = file_out;
485         }
486         if (streamname_out) {
487                 *streamname_out = stream_out;
488         }
489         return true;
490 }