cifs: move cifs_parse_devname to fs_context.c
[linux-2.6-microblaze.git] / fs / cifs / fs_context.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2020, Microsoft Corporation.
4  *
5  *   Author(s): Steve French <stfrench@microsoft.com>
6  *              David Howells <dhowells@redhat.com>
7  */
8
9 #include "cifsglob.h"
10 #include "cifsproto.h"
11 #include "cifs_debug.h"
12 #include "fs_context.h"
13
14 static const match_table_t cifs_smb_version_tokens = {
15         { Smb_1, SMB1_VERSION_STRING },
16         { Smb_20, SMB20_VERSION_STRING},
17         { Smb_21, SMB21_VERSION_STRING },
18         { Smb_30, SMB30_VERSION_STRING },
19         { Smb_302, SMB302_VERSION_STRING },
20         { Smb_302, ALT_SMB302_VERSION_STRING },
21         { Smb_311, SMB311_VERSION_STRING },
22         { Smb_311, ALT_SMB311_VERSION_STRING },
23         { Smb_3any, SMB3ANY_VERSION_STRING },
24         { Smb_default, SMBDEFAULT_VERSION_STRING },
25         { Smb_version_err, NULL }
26 };
27
28 int
29 cifs_parse_smb_version(char *value, struct smb3_fs_context *ctx, bool is_smb3)
30 {
31         substring_t args[MAX_OPT_ARGS];
32
33         switch (match_token(value, cifs_smb_version_tokens, args)) {
34 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
35         case Smb_1:
36                 if (disable_legacy_dialects) {
37                         cifs_dbg(VFS, "mount with legacy dialect disabled\n");
38                         return 1;
39                 }
40                 if (is_smb3) {
41                         cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n");
42                         return 1;
43                 }
44                 cifs_dbg(VFS, "Use of the less secure dialect vers=1.0 is not recommended unless required for access to very old servers\n");
45                 ctx->ops = &smb1_operations;
46                 ctx->vals = &smb1_values;
47                 break;
48         case Smb_20:
49                 if (disable_legacy_dialects) {
50                         cifs_dbg(VFS, "mount with legacy dialect disabled\n");
51                         return 1;
52                 }
53                 if (is_smb3) {
54                         cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n");
55                         return 1;
56                 }
57                 ctx->ops = &smb20_operations;
58                 ctx->vals = &smb20_values;
59                 break;
60 #else
61         case Smb_1:
62                 cifs_dbg(VFS, "vers=1.0 (cifs) mount not permitted when legacy dialects disabled\n");
63                 return 1;
64         case Smb_20:
65                 cifs_dbg(VFS, "vers=2.0 mount not permitted when legacy dialects disabled\n");
66                 return 1;
67 #endif /* CIFS_ALLOW_INSECURE_LEGACY */
68         case Smb_21:
69                 ctx->ops = &smb21_operations;
70                 ctx->vals = &smb21_values;
71                 break;
72         case Smb_30:
73                 ctx->ops = &smb30_operations;
74                 ctx->vals = &smb30_values;
75                 break;
76         case Smb_302:
77                 ctx->ops = &smb30_operations; /* currently identical with 3.0 */
78                 ctx->vals = &smb302_values;
79                 break;
80         case Smb_311:
81                 ctx->ops = &smb311_operations;
82                 ctx->vals = &smb311_values;
83                 break;
84         case Smb_3any:
85                 ctx->ops = &smb30_operations; /* currently identical with 3.0 */
86                 ctx->vals = &smb3any_values;
87                 break;
88         case Smb_default:
89                 ctx->ops = &smb30_operations; /* currently identical with 3.0 */
90                 ctx->vals = &smbdefault_values;
91                 break;
92         default:
93                 cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value);
94                 return 1;
95         }
96         return 0;
97 }
98
99 static const match_table_t cifs_secflavor_tokens = {
100         { Opt_sec_krb5, "krb5" },
101         { Opt_sec_krb5i, "krb5i" },
102         { Opt_sec_krb5p, "krb5p" },
103         { Opt_sec_ntlmsspi, "ntlmsspi" },
104         { Opt_sec_ntlmssp, "ntlmssp" },
105         { Opt_ntlm, "ntlm" },
106         { Opt_sec_ntlmi, "ntlmi" },
107         { Opt_sec_ntlmv2, "nontlm" },
108         { Opt_sec_ntlmv2, "ntlmv2" },
109         { Opt_sec_ntlmv2i, "ntlmv2i" },
110         { Opt_sec_lanman, "lanman" },
111         { Opt_sec_none, "none" },
112
113         { Opt_sec_err, NULL }
114 };
115
116 int cifs_parse_security_flavors(char *value, struct smb3_fs_context *ctx)
117 {
118
119         substring_t args[MAX_OPT_ARGS];
120
121         /*
122          * With mount options, the last one should win. Reset any existing
123          * settings back to default.
124          */
125         ctx->sectype = Unspecified;
126         ctx->sign = false;
127
128         switch (match_token(value, cifs_secflavor_tokens, args)) {
129         case Opt_sec_krb5p:
130                 cifs_dbg(VFS, "sec=krb5p is not supported!\n");
131                 return 1;
132         case Opt_sec_krb5i:
133                 ctx->sign = true;
134                 fallthrough;
135         case Opt_sec_krb5:
136                 ctx->sectype = Kerberos;
137                 break;
138         case Opt_sec_ntlmsspi:
139                 ctx->sign = true;
140                 fallthrough;
141         case Opt_sec_ntlmssp:
142                 ctx->sectype = RawNTLMSSP;
143                 break;
144         case Opt_sec_ntlmi:
145                 ctx->sign = true;
146                 fallthrough;
147         case Opt_ntlm:
148                 ctx->sectype = NTLM;
149                 break;
150         case Opt_sec_ntlmv2i:
151                 ctx->sign = true;
152                 fallthrough;
153         case Opt_sec_ntlmv2:
154                 ctx->sectype = NTLMv2;
155                 break;
156 #ifdef CONFIG_CIFS_WEAK_PW_HASH
157         case Opt_sec_lanman:
158                 ctx->sectype = LANMAN;
159                 break;
160 #endif
161         case Opt_sec_none:
162                 ctx->nullauth = 1;
163                 break;
164         default:
165                 cifs_dbg(VFS, "bad security option: %s\n", value);
166                 return 1;
167         }
168
169         return 0;
170 }
171
172 static const match_table_t cifs_cacheflavor_tokens = {
173         { Opt_cache_loose, "loose" },
174         { Opt_cache_strict, "strict" },
175         { Opt_cache_none, "none" },
176         { Opt_cache_ro, "ro" },
177         { Opt_cache_rw, "singleclient" },
178         { Opt_cache_err, NULL }
179 };
180
181 int
182 cifs_parse_cache_flavor(char *value, struct smb3_fs_context *ctx)
183 {
184         substring_t args[MAX_OPT_ARGS];
185
186         switch (match_token(value, cifs_cacheflavor_tokens, args)) {
187         case Opt_cache_loose:
188                 ctx->direct_io = false;
189                 ctx->strict_io = false;
190                 ctx->cache_ro = false;
191                 ctx->cache_rw = false;
192                 break;
193         case Opt_cache_strict:
194                 ctx->direct_io = false;
195                 ctx->strict_io = true;
196                 ctx->cache_ro = false;
197                 ctx->cache_rw = false;
198                 break;
199         case Opt_cache_none:
200                 ctx->direct_io = true;
201                 ctx->strict_io = false;
202                 ctx->cache_ro = false;
203                 ctx->cache_rw = false;
204                 break;
205         case Opt_cache_ro:
206                 ctx->direct_io = false;
207                 ctx->strict_io = false;
208                 ctx->cache_ro = true;
209                 ctx->cache_rw = false;
210                 break;
211         case Opt_cache_rw:
212                 ctx->direct_io = false;
213                 ctx->strict_io = false;
214                 ctx->cache_ro = false;
215                 ctx->cache_rw = true;
216                 break;
217         default:
218                 cifs_dbg(VFS, "bad cache= option: %s\n", value);
219                 return 1;
220         }
221         return 0;
222 }
223
224 #define DUP_CTX_STR(field)                                              \
225 do {                                                                    \
226         if (ctx->field) {                                               \
227                 new_ctx->field = kstrdup(ctx->field, GFP_ATOMIC);       \
228                 if (new_ctx->field == NULL) {                           \
229                         cifs_cleanup_volume_info_contents(new_ctx);     \
230                         return -ENOMEM;                                 \
231                 }                                                       \
232         }                                                               \
233 } while (0)
234
235 int
236 smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx)
237 {
238         int rc = 0;
239
240         memcpy(new_ctx, ctx, sizeof(*ctx));
241         new_ctx->prepath = NULL;
242         new_ctx->local_nls = NULL;
243         new_ctx->nodename = NULL;
244         new_ctx->username = NULL;
245         new_ctx->password = NULL;
246         new_ctx->domainname = NULL;
247         new_ctx->UNC = NULL;
248         new_ctx->iocharset = NULL;
249
250         /*
251          * Make sure to stay in sync with cifs_cleanup_volume_info_contents()
252          */
253         DUP_CTX_STR(prepath);
254         DUP_CTX_STR(username);
255         DUP_CTX_STR(password);
256         DUP_CTX_STR(UNC);
257         DUP_CTX_STR(domainname);
258         DUP_CTX_STR(nodename);
259         DUP_CTX_STR(iocharset);
260
261         return rc;
262 }
263
264 /*
265  * Parse a devname into substrings and populate the ctx->UNC and ctx->prepath
266  * fields with the result. Returns 0 on success and an error otherwise
267  * (e.g. ENOMEM or EINVAL)
268  */
269 int
270 smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
271 {
272         char *pos;
273         const char *delims = "/\\";
274         size_t len;
275
276         if (unlikely(!devname || !*devname)) {
277                 cifs_dbg(VFS, "Device name not specified\n");
278                 return -EINVAL;
279         }
280
281         /* make sure we have a valid UNC double delimiter prefix */
282         len = strspn(devname, delims);
283         if (len != 2)
284                 return -EINVAL;
285
286         /* find delimiter between host and sharename */
287         pos = strpbrk(devname + 2, delims);
288         if (!pos)
289                 return -EINVAL;
290
291         /* skip past delimiter */
292         ++pos;
293
294         /* now go until next delimiter or end of string */
295         len = strcspn(pos, delims);
296
297         /* move "pos" up to delimiter or NULL */
298         pos += len;
299         ctx->UNC = kstrndup(devname, pos - devname, GFP_KERNEL);
300         if (!ctx->UNC)
301                 return -ENOMEM;
302
303         convert_delimiter(ctx->UNC, '\\');
304
305         /* skip any delimiter */
306         if (*pos == '/' || *pos == '\\')
307                 pos++;
308
309         /* If pos is NULL then no prepath */
310         if (!*pos)
311                 return 0;
312
313         ctx->prepath = kstrdup(pos, GFP_KERNEL);
314         if (!ctx->prepath)
315                 return -ENOMEM;
316
317         return 0;
318 }