9cd348a2939660c0a2247dd5f58a22916f0a17ea
[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 {
58         struct smb_filename smb_fname_loc = { 0, };
59
60         /* Setup the base_name/stream_name. */
61         smb_fname_loc.base_name = discard_const_p(char, base_name);
62         smb_fname_loc.stream_name = discard_const_p(char, stream_name);
63
64         /* Copy the psbuf if one was given. */
65         if (psbuf)
66                 smb_fname_loc.st = *psbuf;
67
68         /* Let cp_smb_filename() do the heavy lifting. */
69         return cp_smb_filename(mem_ctx, &smb_fname_loc);
70 }
71
72 /**
73  * XXX: This is temporary and there should be no callers of this once
74  * smb_filename is plumbed through all path based operations.
75  */
76 struct smb_filename *synthetic_smb_fname_split(TALLOC_CTX *ctx,
77                                                const char *fname,
78                                                const SMB_STRUCT_STAT *psbuf)
79 {
80         const char *stream_name = NULL;
81         char *base_name = NULL;
82         struct smb_filename *ret;
83
84         if (!lp_posix_pathnames()) {
85                 stream_name = strchr_m(fname, ':');
86         }
87
88         /* Setup the base_name/stream_name. */
89         if (stream_name) {
90                 base_name = talloc_strndup(ctx, fname,
91                                            PTR_DIFF(stream_name, fname));
92         } else {
93                 base_name = talloc_strdup(ctx, fname);
94         }
95
96         if (!base_name) {
97                 return NULL;
98         }
99
100         ret = synthetic_smb_fname(ctx, base_name, stream_name, psbuf);
101         TALLOC_FREE(base_name);
102         return ret;
103 }
104
105 /**
106  * Return a string using the talloc_tos()
107  */
108 const char *smb_fname_str_dbg(const struct smb_filename *smb_fname)
109 {
110         char *fname = NULL;
111         NTSTATUS status;
112
113         if (smb_fname == NULL) {
114                 return "";
115         }
116         status = get_full_smb_filename(talloc_tos(), smb_fname, &fname);
117         if (!NT_STATUS_IS_OK(status)) {
118                 return "";
119         }
120         return fname;
121 }
122
123 /**
124  * Return a debug string of the path name of an fsp using the talloc_tos().
125  */
126 const char *fsp_str_dbg(const struct files_struct *fsp)
127 {
128         return smb_fname_str_dbg(fsp->fsp_name);
129 }
130
131 /**
132  * Create a debug string for the fnum of an fsp.
133  *
134  * This is allocated to talloc_tos() or a string constant
135  * in certain corner cases. The returned string should
136  * hence not be free'd directly but only via the talloc stack.
137  */
138 const char *fsp_fnum_dbg(const struct files_struct *fsp)
139 {
140         char *str;
141
142         if (fsp == NULL) {
143                 return "fnum [fsp is NULL]";
144         }
145
146         if (fsp->fnum == FNUM_FIELD_INVALID) {
147                 return "fnum [invalid value]";
148         }
149
150         str = talloc_asprintf(talloc_tos(), "fnum %llu",
151                               (unsigned long long)fsp->fnum);
152         if (str == NULL) {
153                 DEBUG(1, ("%s: talloc_asprintf failed\n", __FUNCTION__));
154                 return "fnum [talloc failed!]";
155         }
156
157         return str;
158 }
159
160 struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx,
161                                      const struct smb_filename *in)
162 {
163         struct smb_filename *out;
164         size_t base_len = 0;
165         size_t stream_len = 0;
166         size_t lcomp_len = 0;
167         int num = 0;
168
169         /* stream_name must always be NULL if there is no stream. */
170         if (in->stream_name) {
171                 SMB_ASSERT(in->stream_name[0] != '\0');
172         }
173
174         if (in->base_name != NULL) {
175                 base_len = strlen(in->base_name) + 1;
176                 num += 1;
177         }
178         if (in->stream_name != NULL) {
179                 stream_len = strlen(in->stream_name) + 1;
180                 num += 1;
181         }
182         if (in->original_lcomp != NULL) {
183                 lcomp_len = strlen(in->original_lcomp) + 1;
184                 num += 1;
185         }
186
187         out = talloc_pooled_object(mem_ctx, struct smb_filename,
188                                 num, stream_len + base_len + lcomp_len);
189         if (out == NULL) {
190                 return NULL;
191         }
192         ZERO_STRUCTP(out);
193
194         /*
195          * The following allocations cannot fail as we
196          * pre-allocated space for them in the out pooled
197          * object.
198          */
199         if (in->base_name != NULL) {
200                 out->base_name = talloc_memdup(
201                                 out, in->base_name, base_len);
202                 talloc_set_name_const(out->base_name,
203                                       out->base_name);
204         }
205         if (in->stream_name != NULL) {
206                 out->stream_name = talloc_memdup(
207                                 out, in->stream_name, stream_len);
208                 talloc_set_name_const(out->stream_name,
209                                       out->stream_name);
210         }
211         if (in->original_lcomp != NULL) {
212                 out->original_lcomp = talloc_memdup(
213                                 out, in->original_lcomp, lcomp_len);
214                 talloc_set_name_const(out->original_lcomp,
215                                       out->original_lcomp);
216         }
217         out->st = in->st;
218         return out;
219 }
220
221 /****************************************************************************
222  Simple check to determine if the filename is a stream.
223  ***************************************************************************/
224 bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname)
225 {
226         /* stream_name must always be NULL if there is no stream. */
227         if (smb_fname->stream_name) {
228                 SMB_ASSERT(smb_fname->stream_name[0] != '\0');
229         }
230
231         if (lp_posix_pathnames()) {
232                 return false;
233         }
234
235         return smb_fname->stream_name != NULL;
236 }
237
238 /****************************************************************************
239  Returns true if the filename's stream == "::$DATA"
240  ***************************************************************************/
241 bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname)
242 {
243         if (!is_ntfs_stream_smb_fname(smb_fname)) {
244                 return false;
245         }
246
247         return strcasecmp_m(smb_fname->stream_name, "::$DATA") == 0;
248 }
249
250 /****************************************************************************
251  Filter out Windows invalid EA names (list probed from Windows 2012).
252 ****************************************************************************/
253
254 static char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|";
255
256 bool is_invalid_windows_ea_name(const char *name)
257 {
258         int i;
259         /* EA name is pulled as ascii so we can examine
260            individual bytes here. */
261         for (i = 0; name[i] != 0; i++) {
262                 int val = (name[i] & 0xff);
263                 if (val < ' ' || strchr(bad_ea_name_chars, val)) {
264                         return true;
265                 }
266         }
267         return false;
268 }
269
270 bool ea_list_has_invalid_name(struct ea_list *ea_list)
271 {
272         if (lp_posix_pathnames()) {
273                 return false;
274         }
275
276         for (;ea_list; ea_list = ea_list->next) {
277                 if (is_invalid_windows_ea_name(ea_list->ea.name)) {
278                         return true;
279                 }
280         }
281         return false;
282 }