s3:lib: assert stream_name is NULL for POSIX paths
[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                                          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 /****************************************************************************
243  Simple check to determine if the filename is a stream.
244  ***************************************************************************/
245 bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname)
246 {
247         /* stream_name must always be NULL if there is no stream. */
248         if (smb_fname->stream_name) {
249                 SMB_ASSERT(smb_fname->stream_name[0] != '\0');
250         }
251
252         if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) {
253                 SMB_ASSERT(smb_fname->stream_name == NULL);
254         }
255
256         if (smb_fname->stream_name == NULL) {
257                 return false;
258         }
259
260         return true;
261 }
262
263 /****************************************************************************
264  Returns true if the filename's stream == "::$DATA"
265  ***************************************************************************/
266 bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname)
267 {
268         if (!is_ntfs_stream_smb_fname(smb_fname)) {
269                 return false;
270         }
271
272         return strcasecmp_m(smb_fname->stream_name, "::$DATA") == 0;
273 }
274
275 /****************************************************************************
276  Filter out Windows invalid EA names (list probed from Windows 2012).
277 ****************************************************************************/
278
279 static char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|";
280
281 bool is_invalid_windows_ea_name(const char *name)
282 {
283         int i;
284         /* EA name is pulled as ascii so we can examine
285            individual bytes here. */
286         for (i = 0; name[i] != 0; i++) {
287                 int val = (name[i] & 0xff);
288                 if (val < ' ' || strchr(bad_ea_name_chars, val)) {
289                         return true;
290                 }
291         }
292         return false;
293 }
294
295 bool ea_list_has_invalid_name(struct ea_list *ea_list)
296 {
297         for (;ea_list; ea_list = ea_list->next) {
298                 if (is_invalid_windows_ea_name(ea_list->ea.name)) {
299                         return true;
300                 }
301         }
302         return false;
303 }
304
305 /****************************************************************************
306  Split an incoming name into tallocd filename and stream components.
307  Returns true on success, false on out of memory.
308 ****************************************************************************/
309
310 bool split_stream_filename(TALLOC_CTX *ctx,
311                                 const char *filename_in,
312                                 char **filename_out,
313                                 char **streamname_out)
314 {
315         const char *stream_name = NULL;
316         char *stream_out = NULL;
317         char *file_out = NULL;
318
319         stream_name = strchr_m(filename_in, ':');
320
321         if (stream_name) {
322                 stream_out = talloc_strdup(ctx, stream_name);
323                 if (stream_out == NULL) {
324                         return false;
325                 }
326                 file_out = talloc_strndup(ctx,
327                                         filename_in,
328                                         PTR_DIFF(stream_name, filename_in));
329         } else {
330                 file_out = talloc_strdup(ctx, filename_in);
331         }
332
333         if (file_out == NULL) {
334                 TALLOC_FREE(stream_out);
335                 return false;
336         }
337
338         if (filename_out) {
339                 *filename_out = file_out;
340         }
341         if (streamname_out) {
342                 *streamname_out = stream_out;
343         }
344         return true;
345 }