s3/lib: add parent_smb_fname()
[vlendec/samba-autobuild/.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                                          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  */
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  */
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  */
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  */
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  */
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
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         int num = 0;
187
188         /* stream_name must always be NULL if there is no stream. */
189         if (in->stream_name) {
190                 SMB_ASSERT(in->stream_name[0] != '\0');
191         }
192
193         if (in->base_name != NULL) {
194                 base_len = strlen(in->base_name) + 1;
195                 num += 1;
196         }
197         if (in->stream_name != NULL) {
198                 stream_len = strlen(in->stream_name) + 1;
199                 num += 1;
200         }
201
202         out = talloc_pooled_object(mem_ctx, struct smb_filename,
203                                 num, stream_len + base_len);
204         if (out == NULL) {
205                 return NULL;
206         }
207         ZERO_STRUCTP(out);
208
209         /*
210          * The following allocations cannot fail as we
211          * pre-allocated space for them in the out pooled
212          * object.
213          */
214         if (in->base_name != NULL) {
215                 out->base_name = talloc_memdup(
216                                 out, in->base_name, base_len);
217                 talloc_set_name_const(out->base_name,
218                                       out->base_name);
219         }
220         if (in->stream_name != NULL) {
221                 out->stream_name = talloc_memdup(
222                                 out, in->stream_name, stream_len);
223                 talloc_set_name_const(out->stream_name,
224                                       out->stream_name);
225         }
226         out->flags = in->flags;
227         out->st = in->st;
228         return out;
229 }
230
231 /**
232  * Return allocated parent directory and basename of path
233  *
234  * Note: if requesting name, it is returned as talloc child of the
235  * parent. Freeing the parent is thus sufficient to free both.
236  */
237 bool parent_smb_fname(TALLOC_CTX *mem_ctx,
238                       const struct smb_filename *path,
239                       struct smb_filename **_parent,
240                       struct smb_filename  **_name)
241 {
242         TALLOC_CTX *frame = talloc_stackframe();
243         struct smb_filename *parent = NULL;
244         struct smb_filename *name = NULL;
245         char *p = NULL;
246
247         parent = cp_smb_filename(frame, path);
248         if (parent == NULL) {
249                 TALLOC_FREE(frame);
250                 return false;
251         }
252         TALLOC_FREE(parent->stream_name);
253         SET_STAT_INVALID(parent->st);
254
255         p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
256         if (p == NULL) {
257                 TALLOC_FREE(parent->base_name);
258                 parent->base_name = talloc_strdup(parent, ".");
259                 if (parent->base_name == NULL) {
260                         TALLOC_FREE(frame);
261                         return false;
262                 }
263                 p = path->base_name;
264         } else {
265                 *p = '\0';
266                 p++;
267         }
268
269         if (_name == NULL) {
270                 *_parent = talloc_move(mem_ctx, &parent);
271                 TALLOC_FREE(frame);
272                 return true;
273         }
274
275         name = cp_smb_filename(frame, path);
276         if (name == NULL) {
277                 TALLOC_FREE(frame);
278                 return false;
279         }
280         TALLOC_FREE(name->base_name);
281
282         name->base_name = talloc_strdup(mem_ctx, p);
283         if (name == NULL) {
284                 TALLOC_FREE(frame);
285                 return false;
286         }
287
288         *_parent = talloc_move(mem_ctx, &parent);
289         *_name = talloc_move(*_parent, &name);
290         TALLOC_FREE(frame);
291         return true;
292 }
293
294 static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname)
295 {
296         /* stream_name must always be NULL if there is no stream. */
297         if (smb_fname->stream_name) {
298                 SMB_ASSERT(smb_fname->stream_name[0] != '\0');
299         }
300
301         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
302                 SMB_ASSERT(smb_fname->stream_name == NULL);
303         }
304 }
305
306 /****************************************************************************
307  Simple check to determine if a smb_fname is a real named stream or the
308  default stream.
309  ***************************************************************************/
310
311 bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname)
312 {
313         assert_valid_stream_smb_fname(smb_fname);
314
315         if (smb_fname->stream_name == NULL) {
316                 return false;
317         }
318
319         return true;
320 }
321
322 /****************************************************************************
323  Simple check to determine if a smb_fname is pointing to a normal file or
324  a named stream that is not the default stream "::$DATA".
325
326   foo           -> false
327   foo::$DATA    -> false
328   foo:bar       -> true
329   foo:bar:$DATA -> true
330
331  ***************************************************************************/
332
333 bool is_named_stream(const struct smb_filename *smb_fname)
334 {
335         assert_valid_stream_smb_fname(smb_fname);
336
337         if (smb_fname->stream_name == NULL) {
338                 return false;
339         }
340
341         if (strequal_m(smb_fname->stream_name, "::$DATA")) {
342                 return false;
343         }
344
345         return true;
346 }
347
348 /****************************************************************************
349  Returns true if the filename's stream == "::$DATA"
350  ***************************************************************************/
351 bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname)
352 {
353         assert_valid_stream_smb_fname(smb_fname);
354
355         if (smb_fname->stream_name == NULL) {
356                 return false;
357         }
358
359         return strequal_m(smb_fname->stream_name, "::$DATA");
360 }
361
362 /****************************************************************************
363  Filter out Windows invalid EA names (list probed from Windows 2012).
364 ****************************************************************************/
365
366 static char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|";
367
368 bool is_invalid_windows_ea_name(const char *name)
369 {
370         int i;
371         /* EA name is pulled as ascii so we can examine
372            individual bytes here. */
373         for (i = 0; name[i] != 0; i++) {
374                 int val = (name[i] & 0xff);
375                 if (val < ' ' || strchr(bad_ea_name_chars, val)) {
376                         return true;
377                 }
378         }
379         return false;
380 }
381
382 bool ea_list_has_invalid_name(struct ea_list *ea_list)
383 {
384         for (;ea_list; ea_list = ea_list->next) {
385                 if (is_invalid_windows_ea_name(ea_list->ea.name)) {
386                         return true;
387                 }
388         }
389         return false;
390 }
391
392 /****************************************************************************
393  Split an incoming name into tallocd filename and stream components.
394  Returns true on success, false on out of memory.
395 ****************************************************************************/
396
397 bool split_stream_filename(TALLOC_CTX *ctx,
398                                 const char *filename_in,
399                                 char **filename_out,
400                                 char **streamname_out)
401 {
402         const char *stream_name = NULL;
403         char *stream_out = NULL;
404         char *file_out = NULL;
405
406         stream_name = strchr_m(filename_in, ':');
407
408         if (stream_name) {
409                 stream_out = talloc_strdup(ctx, stream_name);
410                 if (stream_out == NULL) {
411                         return false;
412                 }
413                 file_out = talloc_strndup(ctx,
414                                         filename_in,
415                                         PTR_DIFF(stream_name, filename_in));
416         } else {
417                 file_out = talloc_strdup(ctx, filename_in);
418         }
419
420         if (file_out == NULL) {
421                 TALLOC_FREE(stream_out);
422                 return false;
423         }
424
425         if (filename_out) {
426                 *filename_out = file_out;
427         }
428         if (streamname_out) {
429                 *streamname_out = stream_out;
430         }
431         return true;
432 }