s3:lib: add is_named_stream()
[metze/samba/wip.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         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
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
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
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  ***************************************************************************/
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
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
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
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 }