0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/fs.h>
0010 #include <linux/slab.h>
0011 #include <asm/unaligned.h>
0012 #include "glob.h"
0013 #include "unicode.h"
0014 #include "uniupr.h"
0015 #include "smb_common.h"
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 static int smb_utf16_bytes(const __le16 *from, int maxbytes,
0030 const struct nls_table *codepage)
0031 {
0032 int i;
0033 int charlen, outlen = 0;
0034 int maxwords = maxbytes / 2;
0035 char tmp[NLS_MAX_CHARSET_SIZE];
0036 __u16 ftmp;
0037
0038 for (i = 0; i < maxwords; i++) {
0039 ftmp = get_unaligned_le16(&from[i]);
0040 if (ftmp == 0)
0041 break;
0042
0043 charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
0044 if (charlen > 0)
0045 outlen += charlen;
0046 else
0047 outlen++;
0048 }
0049
0050 return outlen;
0051 }
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 static int
0067 cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
0068 bool mapchar)
0069 {
0070 int len = 1;
0071
0072 if (!mapchar)
0073 goto cp_convert;
0074
0075
0076
0077
0078
0079
0080 switch (src_char) {
0081 case UNI_COLON:
0082 *target = ':';
0083 break;
0084 case UNI_ASTERISK:
0085 *target = '*';
0086 break;
0087 case UNI_QUESTION:
0088 *target = '?';
0089 break;
0090 case UNI_PIPE:
0091 *target = '|';
0092 break;
0093 case UNI_GRTRTHAN:
0094 *target = '>';
0095 break;
0096 case UNI_LESSTHAN:
0097 *target = '<';
0098 break;
0099 default:
0100 goto cp_convert;
0101 }
0102
0103 out:
0104 return len;
0105
0106 cp_convert:
0107 len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
0108 if (len <= 0) {
0109 *target = '?';
0110 len = 1;
0111 }
0112
0113 goto out;
0114 }
0115
0116
0117
0118
0119
0120
0121
0122 static inline int is_char_allowed(char *ch)
0123 {
0124
0125 if (!(*ch & 0x80) &&
0126 (*ch <= 0x1f ||
0127 *ch == '?' || *ch == '"' || *ch == '<' ||
0128 *ch == '>' || *ch == '|'))
0129 return 0;
0130
0131 return 1;
0132 }
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
0159 const struct nls_table *codepage, bool mapchar)
0160 {
0161 int i, charlen, safelen;
0162 int outlen = 0;
0163 int nullsize = nls_nullsize(codepage);
0164 int fromwords = fromlen / 2;
0165 char tmp[NLS_MAX_CHARSET_SIZE];
0166 __u16 ftmp;
0167
0168
0169
0170
0171
0172
0173
0174 safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
0175
0176 for (i = 0; i < fromwords; i++) {
0177 ftmp = get_unaligned_le16(&from[i]);
0178 if (ftmp == 0)
0179 break;
0180
0181
0182
0183
0184
0185 if (outlen >= safelen) {
0186 charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
0187 if ((outlen + charlen) > (tolen - nullsize))
0188 break;
0189 }
0190
0191
0192 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
0193 outlen += charlen;
0194 }
0195
0196
0197 for (i = 0; i < nullsize; i++)
0198 to[outlen++] = 0;
0199
0200 return outlen;
0201 }
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212 int smb_strtoUTF16(__le16 *to, const char *from, int len,
0213 const struct nls_table *codepage)
0214 {
0215 int charlen;
0216 int i;
0217 wchar_t wchar_to;
0218
0219
0220 if (!strcmp(codepage->charset, "utf8")) {
0221
0222
0223
0224
0225
0226 i = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN,
0227 (wchar_t *)to, len);
0228
0229
0230 if (i >= 0)
0231 goto success;
0232
0233
0234
0235
0236
0237
0238 }
0239
0240 for (i = 0; len > 0 && *from; i++, from += charlen, len -= charlen) {
0241 charlen = codepage->char2uni(from, len, &wchar_to);
0242 if (charlen < 1) {
0243
0244 wchar_to = 0x003f;
0245 charlen = 1;
0246 }
0247 put_unaligned_le16(wchar_to, &to[i]);
0248 }
0249
0250 success:
0251 put_unaligned_le16(0, &to[i]);
0252 return i;
0253 }
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 char *smb_strndup_from_utf16(const char *src, const int maxlen,
0270 const bool is_unicode,
0271 const struct nls_table *codepage)
0272 {
0273 int len, ret;
0274 char *dst;
0275
0276 if (is_unicode) {
0277 len = smb_utf16_bytes((__le16 *)src, maxlen, codepage);
0278 len += nls_nullsize(codepage);
0279 dst = kmalloc(len, GFP_KERNEL);
0280 if (!dst)
0281 return ERR_PTR(-ENOMEM);
0282 ret = smb_from_utf16(dst, (__le16 *)src, len, maxlen, codepage,
0283 false);
0284 if (ret < 0) {
0285 kfree(dst);
0286 return ERR_PTR(-EINVAL);
0287 }
0288 } else {
0289 len = strnlen(src, maxlen);
0290 len++;
0291 dst = kmalloc(len, GFP_KERNEL);
0292 if (!dst)
0293 return ERR_PTR(-ENOMEM);
0294 strscpy(dst, src, len);
0295 }
0296
0297 return dst;
0298 }
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321 int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
0322 const struct nls_table *cp, int mapchars)
0323 {
0324 int i, j, charlen;
0325 char src_char;
0326 __le16 dst_char;
0327 wchar_t tmp;
0328
0329 if (!mapchars)
0330 return smb_strtoUTF16(target, source, srclen, cp);
0331
0332 for (i = 0, j = 0; i < srclen; j++) {
0333 src_char = source[i];
0334 charlen = 1;
0335 switch (src_char) {
0336 case 0:
0337 put_unaligned(0, &target[j]);
0338 return j;
0339 case ':':
0340 dst_char = cpu_to_le16(UNI_COLON);
0341 break;
0342 case '*':
0343 dst_char = cpu_to_le16(UNI_ASTERISK);
0344 break;
0345 case '?':
0346 dst_char = cpu_to_le16(UNI_QUESTION);
0347 break;
0348 case '<':
0349 dst_char = cpu_to_le16(UNI_LESSTHAN);
0350 break;
0351 case '>':
0352 dst_char = cpu_to_le16(UNI_GRTRTHAN);
0353 break;
0354 case '|':
0355 dst_char = cpu_to_le16(UNI_PIPE);
0356 break;
0357
0358
0359
0360
0361
0362 default:
0363 charlen = cp->char2uni(source + i, srclen - i, &tmp);
0364 dst_char = cpu_to_le16(tmp);
0365
0366
0367
0368
0369
0370 if (charlen < 1) {
0371 dst_char = cpu_to_le16(0x003f);
0372 charlen = 1;
0373 }
0374 }
0375
0376
0377
0378
0379 i += charlen;
0380 put_unaligned(dst_char, &target[j]);
0381 }
0382
0383 return j;
0384 }