diff options
Diffstat (limited to 'fs')
44 files changed, 1035 insertions, 1794 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 75f7ddacf7d..3077d8f1652 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
| @@ -70,8 +70,10 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
| 70 | * Otherwise it's an offset mount and we need to check | 70 | * Otherwise it's an offset mount and we need to check |
| 71 | * if we can umount its mount, if there is one. | 71 | * if we can umount its mount, if there is one. |
| 72 | */ | 72 | */ |
| 73 | if (!d_mountpoint(dentry)) | 73 | if (!d_mountpoint(dentry)) { |
| 74 | status = 0; | ||
| 74 | goto done; | 75 | goto done; |
| 76 | } | ||
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | /* Update the expiry counter if fs is busy */ | 79 | /* Update the expiry counter if fs is busy */ |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 70cfc4b84ae..fdb66faa24f 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
| @@ -1388,7 +1388,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
| 1388 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1388 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
| 1389 | prstatus->pr_sighold = p->blocked.sig[0]; | 1389 | prstatus->pr_sighold = p->blocked.sig[0]; |
| 1390 | prstatus->pr_pid = task_pid_vnr(p); | 1390 | prstatus->pr_pid = task_pid_vnr(p); |
| 1391 | prstatus->pr_ppid = task_pid_vnr(p->parent); | 1391 | prstatus->pr_ppid = task_pid_vnr(p->real_parent); |
| 1392 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1392 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
| 1393 | prstatus->pr_sid = task_session_vnr(p); | 1393 | prstatus->pr_sid = task_session_vnr(p); |
| 1394 | if (thread_group_leader(p)) { | 1394 | if (thread_group_leader(p)) { |
| @@ -1433,7 +1433,7 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
| 1433 | psinfo->pr_psargs[len] = 0; | 1433 | psinfo->pr_psargs[len] = 0; |
| 1434 | 1434 | ||
| 1435 | psinfo->pr_pid = task_pid_vnr(p); | 1435 | psinfo->pr_pid = task_pid_vnr(p); |
| 1436 | psinfo->pr_ppid = task_pid_vnr(p->parent); | 1436 | psinfo->pr_ppid = task_pid_vnr(p->real_parent); |
| 1437 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1437 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
| 1438 | psinfo->pr_sid = task_session_vnr(p); | 1438 | psinfo->pr_sid = task_session_vnr(p); |
| 1439 | 1439 | ||
| @@ -817,6 +817,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
| 817 | len += iov[i].iov_len; | 817 | len += iov[i].iov_len; |
| 818 | } | 818 | } |
| 819 | 819 | ||
| 820 | if (offset) | ||
| 821 | nr_pages++; | ||
| 822 | |||
| 820 | bmd = bio_alloc_map_data(nr_pages, iov_count, gfp_mask); | 823 | bmd = bio_alloc_map_data(nr_pages, iov_count, gfp_mask); |
| 821 | if (!bmd) | 824 | if (!bmd) |
| 822 | return ERR_PTR(-ENOMEM); | 825 | return ERR_PTR(-ENOMEM); |
diff --git a/fs/buffer.c b/fs/buffer.c index b3e5be7514f..aed297739eb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -2397,7 +2397,8 @@ block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, | |||
| 2397 | if ((page->mapping != inode->i_mapping) || | 2397 | if ((page->mapping != inode->i_mapping) || |
| 2398 | (page_offset(page) > size)) { | 2398 | (page_offset(page) > size)) { |
| 2399 | /* page got truncated out from underneath us */ | 2399 | /* page got truncated out from underneath us */ |
| 2400 | goto out_unlock; | 2400 | unlock_page(page); |
| 2401 | goto out; | ||
| 2401 | } | 2402 | } |
| 2402 | 2403 | ||
| 2403 | /* page is wholly or partially inside EOF */ | 2404 | /* page is wholly or partially inside EOF */ |
| @@ -2411,14 +2412,15 @@ block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, | |||
| 2411 | ret = block_commit_write(page, 0, end); | 2412 | ret = block_commit_write(page, 0, end); |
| 2412 | 2413 | ||
| 2413 | if (unlikely(ret)) { | 2414 | if (unlikely(ret)) { |
| 2415 | unlock_page(page); | ||
| 2414 | if (ret == -ENOMEM) | 2416 | if (ret == -ENOMEM) |
| 2415 | ret = VM_FAULT_OOM; | 2417 | ret = VM_FAULT_OOM; |
| 2416 | else /* -ENOSPC, -EIO, etc */ | 2418 | else /* -ENOSPC, -EIO, etc */ |
| 2417 | ret = VM_FAULT_SIGBUS; | 2419 | ret = VM_FAULT_SIGBUS; |
| 2418 | } | 2420 | } else |
| 2421 | ret = VM_FAULT_LOCKED; | ||
| 2419 | 2422 | ||
| 2420 | out_unlock: | 2423 | out: |
| 2421 | unlock_page(page); | ||
| 2422 | return ret; | 2424 | return ret; |
| 2423 | } | 2425 | } |
| 2424 | 2426 | ||
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 9d1fb6ec8a5..f20c4069c22 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | Version 1.58 | ||
| 2 | ------------ | ||
| 3 | Guard against buffer overruns in various UCS-2 to UTF-8 string conversions | ||
| 4 | when the UTF-8 string is composed of unusually long (more than 4 byte) converted | ||
| 5 | characters. Add support for mounting root of a share which redirects immediately | ||
| 6 | to DFS target. Convert string conversion functions from Unicode to more | ||
| 7 | accurately mark string length before allocating memory (which may help the | ||
| 8 | rare cases where a UTF-8 string is much larger than the UCS2 string that | ||
| 9 | we converted from). Fix endianness of the vcnum field used during | ||
| 10 | session setup to distinguish multiple mounts to same server from different | ||
| 11 | userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental | ||
| 12 | flag to be set to 2, and mount must enable krb5 to turn on extended security). | ||
| 13 | |||
| 1 | Version 1.57 | 14 | Version 1.57 |
| 2 | ------------ | 15 | ------------ |
| 3 | Improve support for multiple security contexts to the same server. We | 16 | Improve support for multiple security contexts to the same server. We |
diff --git a/fs/cifs/README b/fs/cifs/README index 07434181623..db208ddb989 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -651,7 +651,15 @@ Experimental When set to 1 used to enable certain experimental | |||
| 651 | signing turned on in case buffer was modified | 651 | signing turned on in case buffer was modified |
| 652 | just before it was sent, also this flag will | 652 | just before it was sent, also this flag will |
| 653 | be used to use the new experimental directory change | 653 | be used to use the new experimental directory change |
| 654 | notification code). | 654 | notification code). When set to 2 enables |
| 655 | an additional experimental feature, "raw ntlmssp" | ||
| 656 | session establishment support (which allows | ||
| 657 | specifying "sec=ntlmssp" on mount). The Linux cifs | ||
| 658 | module will use ntlmv2 authentication encapsulated | ||
| 659 | in "raw ntlmssp" (not using SPNEGO) when | ||
| 660 | "sec=ntlmssp" is specified on mount. | ||
| 661 | This support also requires building cifs with | ||
| 662 | the CONFIG_CIFS_EXPERIMENTAL configuration flag. | ||
| 655 | 663 | ||
| 656 | These experimental features and tracing can be enabled by changing flags in | 664 | These experimental features and tracing can be enabled by changing flags in |
| 657 | /proc/fs/cifs (after the cifs module has been installed or built into the | 665 | /proc/fs/cifs (after the cifs module has been installed or built into the |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 5fdbf8a1447..83d62759c7c 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -340,28 +340,24 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 340 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 340 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 341 | 341 | ||
| 342 | for (i = 0; i < num_referrals; i++) { | 342 | for (i = 0; i < num_referrals; i++) { |
| 343 | int len; | ||
| 343 | dump_referral(referrals+i); | 344 | dump_referral(referrals+i); |
| 344 | /* connect to a storage node */ | 345 | /* connect to a node */ |
| 345 | if (referrals[i].flags & DFSREF_STORAGE_SERVER) { | 346 | len = strlen(referrals[i].node_name); |
| 346 | int len; | 347 | if (len < 2) { |
| 347 | len = strlen(referrals[i].node_name); | 348 | cERROR(1, ("%s: Net Address path too short: %s", |
| 348 | if (len < 2) { | ||
| 349 | cERROR(1, ("%s: Net Address path too short: %s", | ||
| 350 | __func__, referrals[i].node_name)); | 349 | __func__, referrals[i].node_name)); |
| 351 | rc = -EINVAL; | 350 | rc = -EINVAL; |
| 352 | goto out_err; | 351 | goto out_err; |
| 353 | } | 352 | } |
| 354 | mnt = cifs_dfs_do_refmount(nd->path.mnt, | 353 | mnt = cifs_dfs_do_refmount(nd->path.mnt, |
| 355 | nd->path.dentry, | 354 | nd->path.dentry, referrals + i); |
| 356 | referrals + i); | 355 | cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, |
| 357 | cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", | ||
| 358 | __func__, | ||
| 359 | referrals[i].node_name, mnt)); | 356 | referrals[i].node_name, mnt)); |
| 360 | 357 | ||
| 361 | /* complete mount procedure if we accured submount */ | 358 | /* complete mount procedure if we accured submount */ |
| 362 | if (!IS_ERR(mnt)) | 359 | if (!IS_ERR(mnt)) |
| 363 | break; | 360 | break; |
| 364 | } | ||
| 365 | } | 361 | } |
| 366 | 362 | ||
| 367 | /* we need it cause for() above could exit without valid submount */ | 363 | /* we need it cause for() above could exit without valid submount */ |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 7d75272a6b3..60e3c4253de 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * fs/cifs/cifs_unicode.c | 2 | * fs/cifs/cifs_unicode.c |
| 3 | * | 3 | * |
| 4 | * Copyright (c) International Business Machines Corp., 2000,2005 | 4 | * Copyright (c) International Business Machines Corp., 2000,2009 |
| 5 | * Modified by Steve French (sfrench@us.ibm.com) | 5 | * Modified by Steve French (sfrench@us.ibm.com) |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| @@ -26,31 +26,157 @@ | |||
| 26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
| 27 | 27 | ||
| 28 | /* | 28 | /* |
| 29 | * NAME: cifs_strfromUCS() | 29 | * cifs_ucs2_bytes - how long will a string be after conversion? |
| 30 | * | 30 | * @ucs - pointer to input string |
| 31 | * FUNCTION: Convert little-endian unicode string to character string | 31 | * @maxbytes - don't go past this many bytes of input string |
| 32 | * @codepage - destination codepage | ||
| 32 | * | 33 | * |
| 34 | * Walk a ucs2le string and return the number of bytes that the string will | ||
| 35 | * be after being converted to the given charset, not including any null | ||
| 36 | * termination required. Don't walk past maxbytes in the source buffer. | ||
| 33 | */ | 37 | */ |
| 34 | int | 38 | int |
| 35 | cifs_strfromUCS_le(char *to, const __le16 *from, | 39 | cifs_ucs2_bytes(const __le16 *from, int maxbytes, |
| 36 | int len, const struct nls_table *codepage) | 40 | const struct nls_table *codepage) |
| 37 | { | 41 | { |
| 38 | int i; | 42 | int i; |
| 39 | int outlen = 0; | 43 | int charlen, outlen = 0; |
| 44 | int maxwords = maxbytes / 2; | ||
| 45 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
| 40 | 46 | ||
| 41 | for (i = 0; (i < len) && from[i]; i++) { | 47 | for (i = 0; from[i] && i < maxwords; i++) { |
| 42 | int charlen; | 48 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, |
| 43 | /* 2.4.0 kernel or greater */ | 49 | NLS_MAX_CHARSET_SIZE); |
| 44 | charlen = | 50 | if (charlen > 0) |
| 45 | codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], | ||
| 46 | NLS_MAX_CHARSET_SIZE); | ||
| 47 | if (charlen > 0) { | ||
| 48 | outlen += charlen; | 51 | outlen += charlen; |
| 49 | } else { | 52 | else |
| 50 | to[outlen++] = '?'; | 53 | outlen++; |
| 54 | } | ||
| 55 | |||
| 56 | return outlen; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* | ||
| 60 | * cifs_mapchar - convert a little-endian char to proper char in codepage | ||
| 61 | * @target - where converted character should be copied | ||
| 62 | * @src_char - 2 byte little-endian source character | ||
| 63 | * @cp - codepage to which character should be converted | ||
| 64 | * @mapchar - should character be mapped according to mapchars mount option? | ||
| 65 | * | ||
| 66 | * This function handles the conversion of a single character. It is the | ||
| 67 | * responsibility of the caller to ensure that the target buffer is large | ||
| 68 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | ||
| 69 | */ | ||
| 70 | static int | ||
| 71 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | ||
| 72 | bool mapchar) | ||
| 73 | { | ||
| 74 | int len = 1; | ||
| 75 | |||
| 76 | if (!mapchar) | ||
| 77 | goto cp_convert; | ||
| 78 | |||
| 79 | /* | ||
| 80 | * BB: Cannot handle remapping UNI_SLASH until all the calls to | ||
| 81 | * build_path_from_dentry are modified, as they use slash as | ||
| 82 | * separator. | ||
| 83 | */ | ||
| 84 | switch (le16_to_cpu(src_char)) { | ||
| 85 | case UNI_COLON: | ||
| 86 | *target = ':'; | ||
| 87 | break; | ||
| 88 | case UNI_ASTERIK: | ||
| 89 | *target = '*'; | ||
| 90 | break; | ||
| 91 | case UNI_QUESTION: | ||
| 92 | *target = '?'; | ||
| 93 | break; | ||
| 94 | case UNI_PIPE: | ||
| 95 | *target = '|'; | ||
| 96 | break; | ||
| 97 | case UNI_GRTRTHAN: | ||
| 98 | *target = '>'; | ||
| 99 | break; | ||
| 100 | case UNI_LESSTHAN: | ||
| 101 | *target = '<'; | ||
| 102 | break; | ||
| 103 | default: | ||
| 104 | goto cp_convert; | ||
| 105 | } | ||
| 106 | |||
| 107 | out: | ||
| 108 | return len; | ||
| 109 | |||
| 110 | cp_convert: | ||
| 111 | len = cp->uni2char(le16_to_cpu(src_char), target, | ||
| 112 | NLS_MAX_CHARSET_SIZE); | ||
| 113 | if (len <= 0) { | ||
| 114 | *target = '?'; | ||
| 115 | len = 1; | ||
| 116 | } | ||
| 117 | goto out; | ||
| 118 | } | ||
| 119 | |||
| 120 | /* | ||
| 121 | * cifs_from_ucs2 - convert utf16le string to local charset | ||
| 122 | * @to - destination buffer | ||
| 123 | * @from - source buffer | ||
| 124 | * @tolen - destination buffer size (in bytes) | ||
| 125 | * @fromlen - source buffer size (in bytes) | ||
| 126 | * @codepage - codepage to which characters should be converted | ||
| 127 | * @mapchar - should characters be remapped according to the mapchars option? | ||
| 128 | * | ||
| 129 | * Convert a little-endian ucs2le string (as sent by the server) to a string | ||
| 130 | * in the provided codepage. The tolen and fromlen parameters are to ensure | ||
| 131 | * that the code doesn't walk off of the end of the buffer (which is always | ||
| 132 | * a danger if the alignment of the source buffer is off). The destination | ||
| 133 | * string is always properly null terminated and fits in the destination | ||
| 134 | * buffer. Returns the length of the destination string in bytes (including | ||
| 135 | * null terminator). | ||
| 136 | * | ||
| 137 | * Note that some windows versions actually send multiword UTF-16 characters | ||
| 138 | * instead of straight UCS-2. The linux nls routines however aren't able to | ||
| 139 | * deal with those characters properly. In the event that we get some of | ||
| 140 | * those characters, they won't be translated properly. | ||
| 141 | */ | ||
| 142 | int | ||
| 143 | cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | ||
| 144 | const struct nls_table *codepage, bool mapchar) | ||
| 145 | { | ||
| 146 | int i, charlen, safelen; | ||
| 147 | int outlen = 0; | ||
| 148 | int nullsize = nls_nullsize(codepage); | ||
| 149 | int fromwords = fromlen / 2; | ||
| 150 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * because the chars can be of varying widths, we need to take care | ||
| 154 | * not to overflow the destination buffer when we get close to the | ||
| 155 | * end of it. Until we get to this offset, we don't need to check | ||
| 156 | * for overflow however. | ||
| 157 | */ | ||
| 158 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | ||
| 159 | |||
| 160 | for (i = 0; i < fromwords && from[i]; i++) { | ||
| 161 | /* | ||
| 162 | * check to see if converting this character might make the | ||
| 163 | * conversion bleed into the null terminator | ||
| 164 | */ | ||
| 165 | if (outlen >= safelen) { | ||
| 166 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | ||
| 167 | if ((outlen + charlen) > (tolen - nullsize)) | ||
| 168 | break; | ||
| 51 | } | 169 | } |
| 170 | |||
| 171 | /* put converted char into 'to' buffer */ | ||
| 172 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | ||
| 173 | outlen += charlen; | ||
| 52 | } | 174 | } |
| 53 | to[outlen] = 0; | 175 | |
| 176 | /* properly null-terminate string */ | ||
| 177 | for (i = 0; i < nullsize; i++) | ||
| 178 | to[outlen++] = 0; | ||
| 179 | |||
| 54 | return outlen; | 180 | return outlen; |
| 55 | } | 181 | } |
| 56 | 182 | ||
| @@ -88,3 +214,41 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, | |||
| 88 | return i; | 214 | return i; |
| 89 | } | 215 | } |
| 90 | 216 | ||
| 217 | /* | ||
| 218 | * cifs_strndup_from_ucs - copy a string from wire format to the local codepage | ||
| 219 | * @src - source string | ||
| 220 | * @maxlen - don't walk past this many bytes in the source string | ||
| 221 | * @is_unicode - is this a unicode string? | ||
| 222 | * @codepage - destination codepage | ||
| 223 | * | ||
| 224 | * Take a string given by the server, convert it to the local codepage and | ||
| 225 | * put it in a new buffer. Returns a pointer to the new string or NULL on | ||
| 226 | * error. | ||
| 227 | */ | ||
| 228 | char * | ||
| 229 | cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, | ||
| 230 | const struct nls_table *codepage) | ||
| 231 | { | ||
| 232 | int len; | ||
| 233 | char *dst; | ||
| 234 | |||
| 235 | if (is_unicode) { | ||
| 236 | len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage); | ||
| 237 | len += nls_nullsize(codepage); | ||
| 238 | dst = kmalloc(len, GFP_KERNEL); | ||
| 239 | if (!dst) | ||
| 240 | return NULL; | ||
| 241 | cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage, | ||
| 242 | false); | ||
| 243 | } else { | ||
| 244 | len = strnlen(src, maxlen); | ||
| 245 | len++; | ||
| 246 | dst = kmalloc(len, GFP_KERNEL); | ||
| 247 | if (!dst) | ||
| 248 | return NULL; | ||
| 249 | strlcpy(dst, src, len); | ||
| 250 | } | ||
| 251 | |||
| 252 | return dst; | ||
| 253 | } | ||
| 254 | |||
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index 14eb9a2395d..650638275a6 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * Convert a unicode character to upper or lower case using | 5 | * Convert a unicode character to upper or lower case using |
| 6 | * compressed tables. | 6 | * compressed tables. |
| 7 | * | 7 | * |
| 8 | * Copyright (c) International Business Machines Corp., 2000,2007 | 8 | * Copyright (c) International Business Machines Corp., 2000,2009 |
| 9 | * | 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
| @@ -37,6 +37,19 @@ | |||
| 37 | 37 | ||
| 38 | #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ | 38 | #define UNIUPR_NOLOWER /* Example to not expand lower case tables */ |
| 39 | 39 | ||
| 40 | /* | ||
| 41 | * Windows maps these to the user defined 16 bit Unicode range since they are | ||
| 42 | * reserved symbols (along with \ and /), otherwise illegal to store | ||
| 43 | * in filenames in NTFS | ||
| 44 | */ | ||
| 45 | #define UNI_ASTERIK (__u16) ('*' + 0xF000) | ||
| 46 | #define UNI_QUESTION (__u16) ('?' + 0xF000) | ||
| 47 | #define UNI_COLON (__u16) (':' + 0xF000) | ||
| 48 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | ||
| 49 | #define UNI_LESSTHAN (__u16) ('<' + 0xF000) | ||
| 50 | #define UNI_PIPE (__u16) ('|' + 0xF000) | ||
| 51 | #define UNI_SLASH (__u16) ('\\' + 0xF000) | ||
| 52 | |||
| 40 | /* Just define what we want from uniupr.h. We don't want to define the tables | 53 | /* Just define what we want from uniupr.h. We don't want to define the tables |
| 41 | * in each source file. | 54 | * in each source file. |
| 42 | */ | 55 | */ |
| @@ -59,8 +72,14 @@ extern struct UniCaseRange UniLowerRange[]; | |||
| 59 | #endif /* UNIUPR_NOLOWER */ | 72 | #endif /* UNIUPR_NOLOWER */ |
| 60 | 73 | ||
| 61 | #ifdef __KERNEL__ | 74 | #ifdef __KERNEL__ |
| 62 | int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); | 75 | int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, |
| 76 | const struct nls_table *codepage, bool mapchar); | ||
| 77 | int cifs_ucs2_bytes(const __le16 *from, int maxbytes, | ||
| 78 | const struct nls_table *codepage); | ||
| 63 | int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); | 79 | int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); |
| 80 | char *cifs_strndup_from_ucs(const char *src, const int maxlen, | ||
| 81 | const bool is_unicode, | ||
| 82 | const struct nls_table *codepage); | ||
| 64 | #endif | 83 | #endif |
| 65 | 84 | ||
| 66 | /* | 85 | /* |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 77e190dc288..051b71cfdea 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 100 | extern const struct export_operations cifs_export_ops; | 100 | extern const struct export_operations cifs_export_ops; |
| 101 | #endif /* EXPERIMENTAL */ | 101 | #endif /* EXPERIMENTAL */ |
| 102 | 102 | ||
| 103 | #define CIFS_VERSION "1.57" | 103 | #define CIFS_VERSION "1.58" |
| 104 | #endif /* _CIFSFS_H */ | 104 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index df40ab64cd9..a61ab772c6f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -82,8 +82,8 @@ enum securityEnum { | |||
| 82 | LANMAN, /* Legacy LANMAN auth */ | 82 | LANMAN, /* Legacy LANMAN auth */ |
| 83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ |
| 84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
| 85 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ | 85 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ |
| 86 | NTLMSSP, /* NTLMSSP via SPNEGO */ | 86 | NTLMSSP, /* NTLMSSP via SPNEGO, NTLMv2 hash */ |
| 87 | Kerberos, /* Kerberos via SPNEGO */ | 87 | Kerberos, /* Kerberos via SPNEGO */ |
| 88 | MSKerberos, /* MS Kerberos via SPNEGO */ | 88 | MSKerberos, /* MS Kerberos via SPNEGO */ |
| 89 | }; | 89 | }; |
| @@ -531,6 +531,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
| 531 | #define CIFSSEC_MAY_PLNTXT 0 | 531 | #define CIFSSEC_MAY_PLNTXT 0 |
| 532 | #endif /* weak passwords */ | 532 | #endif /* weak passwords */ |
| 533 | #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ | 533 | #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ |
| 534 | #define CIFSSEC_MAY_NTLMSSP 0x00080 /* raw ntlmssp with ntlmv2 */ | ||
| 534 | 535 | ||
| 535 | #define CIFSSEC_MUST_SIGN 0x01001 | 536 | #define CIFSSEC_MUST_SIGN 0x01001 |
| 536 | /* note that only one of the following can be set so the | 537 | /* note that only one of the following can be set so the |
| @@ -543,22 +544,23 @@ require use of the stronger protocol */ | |||
| 543 | #define CIFSSEC_MUST_LANMAN 0x10010 | 544 | #define CIFSSEC_MUST_LANMAN 0x10010 |
| 544 | #define CIFSSEC_MUST_PLNTXT 0x20020 | 545 | #define CIFSSEC_MUST_PLNTXT 0x20020 |
| 545 | #ifdef CONFIG_CIFS_UPCALL | 546 | #ifdef CONFIG_CIFS_UPCALL |
| 546 | #define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ | 547 | #define CIFSSEC_MASK 0xAF0AF /* allows weak security but also krb5 */ |
| 547 | #else | 548 | #else |
| 548 | #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ | 549 | #define CIFSSEC_MASK 0xA70A7 /* current flags supported if weak */ |
| 549 | #endif /* UPCALL */ | 550 | #endif /* UPCALL */ |
| 550 | #else /* do not allow weak pw hash */ | 551 | #else /* do not allow weak pw hash */ |
| 551 | #ifdef CONFIG_CIFS_UPCALL | 552 | #ifdef CONFIG_CIFS_UPCALL |
| 552 | #define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ | 553 | #define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */ |
| 553 | #else | 554 | #else |
| 554 | #define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ | 555 | #define CIFSSEC_MASK 0x87087 /* flags supported if no weak allowed */ |
| 555 | #endif /* UPCALL */ | 556 | #endif /* UPCALL */ |
| 556 | #endif /* WEAK_PW_HASH */ | 557 | #endif /* WEAK_PW_HASH */ |
| 557 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ | 558 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ |
| 559 | #define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */ | ||
| 558 | 560 | ||
| 559 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2) | 561 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2) |
| 560 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) | 562 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) |
| 561 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) | 563 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) |
| 562 | /* | 564 | /* |
| 563 | ***************************************************************** | 565 | ***************************************************************** |
| 564 | * All constants go here | 566 | * All constants go here |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4167716d32f..fae083930ee 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -260,8 +260,7 @@ extern int CIFSUnixCreateSymLink(const int xid, | |||
| 260 | const struct nls_table *nls_codepage); | 260 | const struct nls_table *nls_codepage); |
| 261 | extern int CIFSSMBUnixQuerySymLink(const int xid, | 261 | extern int CIFSSMBUnixQuerySymLink(const int xid, |
| 262 | struct cifsTconInfo *tcon, | 262 | struct cifsTconInfo *tcon, |
| 263 | const unsigned char *searchName, | 263 | const unsigned char *searchName, char **syminfo, |
| 264 | char *syminfo, const int buflen, | ||
| 265 | const struct nls_table *nls_codepage); | 264 | const struct nls_table *nls_codepage); |
| 266 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, | 265 | extern int CIFSSMBQueryReparseLinkInfo(const int xid, |
| 267 | struct cifsTconInfo *tcon, | 266 | struct cifsTconInfo *tcon, |
| @@ -307,8 +306,6 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | |||
| 307 | const unsigned char *searchName, __u64 *inode_number, | 306 | const unsigned char *searchName, __u64 *inode_number, |
| 308 | const struct nls_table *nls_codepage, | 307 | const struct nls_table *nls_codepage, |
| 309 | int remap_special_chars); | 308 | int remap_special_chars); |
| 310 | extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, | ||
| 311 | const struct nls_table *codepage); | ||
| 312 | extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | 309 | extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen, |
| 313 | const struct nls_table *cp, int mapChars); | 310 | const struct nls_table *cp, int mapChars); |
| 314 | 311 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a0845dc7b8a..75e6623a863 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * fs/cifs/cifssmb.c | 2 | * fs/cifs/cifssmb.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) International Business Machines Corp., 2002,2008 | 4 | * Copyright (C) International Business Machines Corp., 2002,2009 |
| 5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
| 6 | * | 6 | * |
| 7 | * Contains the routines for constructing the SMB PDUs themselves | 7 | * Contains the routines for constructing the SMB PDUs themselves |
| @@ -81,41 +81,6 @@ static struct { | |||
| 81 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | 81 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ |
| 82 | #endif /* CIFS_POSIX */ | 82 | #endif /* CIFS_POSIX */ |
| 83 | 83 | ||
| 84 | /* Allocates buffer into dst and copies smb string from src to it. | ||
| 85 | * caller is responsible for freeing dst if function returned 0. | ||
| 86 | * returns: | ||
| 87 | * on success - 0 | ||
| 88 | * on failure - errno | ||
| 89 | */ | ||
| 90 | static int | ||
| 91 | cifs_strncpy_to_host(char **dst, const char *src, const int maxlen, | ||
| 92 | const bool is_unicode, const struct nls_table *nls_codepage) | ||
| 93 | { | ||
| 94 | int plen; | ||
| 95 | |||
| 96 | if (is_unicode) { | ||
| 97 | plen = UniStrnlen((wchar_t *)src, maxlen); | ||
| 98 | *dst = kmalloc(plen + 2, GFP_KERNEL); | ||
| 99 | if (!*dst) | ||
| 100 | goto cifs_strncpy_to_host_ErrExit; | ||
| 101 | cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage); | ||
| 102 | } else { | ||
| 103 | plen = strnlen(src, maxlen); | ||
| 104 | *dst = kmalloc(plen + 2, GFP_KERNEL); | ||
| 105 | if (!*dst) | ||
| 106 | goto cifs_strncpy_to_host_ErrExit; | ||
| 107 | strncpy(*dst, src, plen); | ||
| 108 | } | ||
| 109 | (*dst)[plen] = 0; | ||
| 110 | (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */ | ||
| 111 | return 0; | ||
| 112 | |||
| 113 | cifs_strncpy_to_host_ErrExit: | ||
| 114 | cERROR(1, ("Failed to allocate buffer for string\n")); | ||
| 115 | return -ENOMEM; | ||
| 116 | } | ||
| 117 | |||
| 118 | |||
| 119 | /* Mark as invalid, all open files on tree connections since they | 84 | /* Mark as invalid, all open files on tree connections since they |
| 120 | were closed when session to server was lost */ | 85 | were closed when session to server was lost */ |
| 121 | static void mark_open_files_invalid(struct cifsTconInfo *pTcon) | 86 | static void mark_open_files_invalid(struct cifsTconInfo *pTcon) |
| @@ -484,6 +449,14 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 484 | cFYI(1, ("Kerberos only mechanism, enable extended security")); | 449 | cFYI(1, ("Kerberos only mechanism, enable extended security")); |
| 485 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 450 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 486 | } | 451 | } |
| 452 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 453 | else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) | ||
| 454 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 455 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { | ||
| 456 | cFYI(1, ("NTLMSSP only mechanism, enable extended security")); | ||
| 457 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 458 | } | ||
| 459 | #endif | ||
| 487 | 460 | ||
| 488 | count = 0; | 461 | count = 0; |
| 489 | for (i = 0; i < CIFS_NUM_PROT; i++) { | 462 | for (i = 0; i < CIFS_NUM_PROT; i++) { |
| @@ -620,6 +593,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 620 | server->secType = NTLMv2; | 593 | server->secType = NTLMv2; |
| 621 | else if (secFlags & CIFSSEC_MAY_KRB5) | 594 | else if (secFlags & CIFSSEC_MAY_KRB5) |
| 622 | server->secType = Kerberos; | 595 | server->secType = Kerberos; |
| 596 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) | ||
| 597 | server->secType = NTLMSSP; | ||
| 623 | else if (secFlags & CIFSSEC_MAY_LANMAN) | 598 | else if (secFlags & CIFSSEC_MAY_LANMAN) |
| 624 | server->secType = LANMAN; | 599 | server->secType = LANMAN; |
| 625 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL | 600 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL |
| @@ -2417,8 +2392,7 @@ winCreateHardLinkRetry: | |||
| 2417 | 2392 | ||
| 2418 | int | 2393 | int |
| 2419 | CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, | 2394 | CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, |
| 2420 | const unsigned char *searchName, | 2395 | const unsigned char *searchName, char **symlinkinfo, |
| 2421 | char *symlinkinfo, const int buflen, | ||
| 2422 | const struct nls_table *nls_codepage) | 2396 | const struct nls_table *nls_codepage) |
| 2423 | { | 2397 | { |
| 2424 | /* SMB_QUERY_FILE_UNIX_LINK */ | 2398 | /* SMB_QUERY_FILE_UNIX_LINK */ |
| @@ -2428,6 +2402,7 @@ CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, | |||
| 2428 | int bytes_returned; | 2402 | int bytes_returned; |
| 2429 | int name_len; | 2403 | int name_len; |
| 2430 | __u16 params, byte_count; | 2404 | __u16 params, byte_count; |
| 2405 | char *data_start; | ||
| 2431 | 2406 | ||
| 2432 | cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); | 2407 | cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); |
| 2433 | 2408 | ||
| @@ -2482,30 +2457,26 @@ querySymLinkRetry: | |||
| 2482 | /* decode response */ | 2457 | /* decode response */ |
| 2483 | 2458 | ||
| 2484 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 2459 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
| 2485 | if (rc || (pSMBr->ByteCount < 2)) | ||
| 2486 | /* BB also check enough total bytes returned */ | 2460 | /* BB also check enough total bytes returned */ |
| 2487 | rc = -EIO; /* bad smb */ | 2461 | if (rc || (pSMBr->ByteCount < 2)) |
| 2462 | rc = -EIO; | ||
| 2488 | else { | 2463 | else { |
| 2489 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 2464 | bool is_unicode; |
| 2490 | __u16 count = le16_to_cpu(pSMBr->t2.DataCount); | 2465 | u16 count = le16_to_cpu(pSMBr->t2.DataCount); |
| 2466 | |||
| 2467 | data_start = ((char *) &pSMBr->hdr.Protocol) + | ||
| 2468 | le16_to_cpu(pSMBr->t2.DataOffset); | ||
| 2469 | |||
| 2470 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) | ||
| 2471 | is_unicode = true; | ||
| 2472 | else | ||
| 2473 | is_unicode = false; | ||
| 2491 | 2474 | ||
| 2492 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
| 2493 | name_len = UniStrnlen((wchar_t *) ((char *) | ||
| 2494 | &pSMBr->hdr.Protocol + data_offset), | ||
| 2495 | min_t(const int, buflen, count) / 2); | ||
| 2496 | /* BB FIXME investigate remapping reserved chars here */ | 2475 | /* BB FIXME investigate remapping reserved chars here */ |
| 2497 | cifs_strfromUCS_le(symlinkinfo, | 2476 | *symlinkinfo = cifs_strndup_from_ucs(data_start, count, |
| 2498 | (__le16 *) ((char *)&pSMBr->hdr.Protocol | 2477 | is_unicode, nls_codepage); |
| 2499 | + data_offset), | 2478 | if (!symlinkinfo) |
| 2500 | name_len, nls_codepage); | 2479 | rc = -ENOMEM; |
| 2501 | } else { | ||
| 2502 | strncpy(symlinkinfo, | ||
| 2503 | (char *) &pSMBr->hdr.Protocol + | ||
| 2504 | data_offset, | ||
| 2505 | min_t(const int, buflen, count)); | ||
| 2506 | } | ||
| 2507 | symlinkinfo[buflen] = 0; | ||
| 2508 | /* just in case so calling code does not go off the end of buffer */ | ||
| 2509 | } | 2480 | } |
| 2510 | } | 2481 | } |
| 2511 | cifs_buf_release(pSMB); | 2482 | cifs_buf_release(pSMB); |
| @@ -2603,7 +2574,6 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, | |||
| 2603 | *pparmlen = parm_count; | 2574 | *pparmlen = parm_count; |
| 2604 | return 0; | 2575 | return 0; |
| 2605 | } | 2576 | } |
| 2606 | #endif /* CIFS_EXPERIMENTAL */ | ||
| 2607 | 2577 | ||
| 2608 | int | 2578 | int |
| 2609 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | 2579 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, |
| @@ -2613,7 +2583,6 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
| 2613 | { | 2583 | { |
| 2614 | int rc = 0; | 2584 | int rc = 0; |
| 2615 | int bytes_returned; | 2585 | int bytes_returned; |
| 2616 | int name_len; | ||
| 2617 | struct smb_com_transaction_ioctl_req *pSMB; | 2586 | struct smb_com_transaction_ioctl_req *pSMB; |
| 2618 | struct smb_com_transaction_ioctl_rsp *pSMBr; | 2587 | struct smb_com_transaction_ioctl_rsp *pSMBr; |
| 2619 | 2588 | ||
| @@ -2650,59 +2619,55 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
| 2650 | } else { /* decode response */ | 2619 | } else { /* decode response */ |
| 2651 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); | 2620 | __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); |
| 2652 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); | 2621 | __u32 data_count = le32_to_cpu(pSMBr->DataCount); |
| 2653 | if ((pSMBr->ByteCount < 2) || (data_offset > 512)) | 2622 | if ((pSMBr->ByteCount < 2) || (data_offset > 512)) { |
| 2654 | /* BB also check enough total bytes returned */ | 2623 | /* BB also check enough total bytes returned */ |
| 2655 | rc = -EIO; /* bad smb */ | 2624 | rc = -EIO; /* bad smb */ |
| 2656 | else { | 2625 | goto qreparse_out; |
| 2657 | if (data_count && (data_count < 2048)) { | 2626 | } |
| 2658 | char *end_of_smb = 2 /* sizeof byte count */ + | 2627 | if (data_count && (data_count < 2048)) { |
| 2659 | pSMBr->ByteCount + | 2628 | char *end_of_smb = 2 /* sizeof byte count */ + |
| 2660 | (char *)&pSMBr->ByteCount; | 2629 | pSMBr->ByteCount + (char *)&pSMBr->ByteCount; |
| 2661 | 2630 | ||
| 2662 | struct reparse_data *reparse_buf = | 2631 | struct reparse_data *reparse_buf = |
| 2663 | (struct reparse_data *) | 2632 | (struct reparse_data *) |
| 2664 | ((char *)&pSMBr->hdr.Protocol | 2633 | ((char *)&pSMBr->hdr.Protocol |
| 2665 | + data_offset); | 2634 | + data_offset); |
| 2666 | if ((char *)reparse_buf >= end_of_smb) { | 2635 | if ((char *)reparse_buf >= end_of_smb) { |
| 2667 | rc = -EIO; | 2636 | rc = -EIO; |
| 2668 | goto qreparse_out; | 2637 | goto qreparse_out; |
| 2669 | } | 2638 | } |
| 2670 | if ((reparse_buf->LinkNamesBuf + | 2639 | if ((reparse_buf->LinkNamesBuf + |
| 2671 | reparse_buf->TargetNameOffset + | 2640 | reparse_buf->TargetNameOffset + |
| 2672 | reparse_buf->TargetNameLen) > | 2641 | reparse_buf->TargetNameLen) > end_of_smb) { |
| 2673 | end_of_smb) { | 2642 | cFYI(1, ("reparse buf beyond SMB")); |
| 2674 | cFYI(1, ("reparse buf beyond SMB")); | 2643 | rc = -EIO; |
| 2675 | rc = -EIO; | 2644 | goto qreparse_out; |
| 2676 | goto qreparse_out; | 2645 | } |
| 2677 | } | ||
| 2678 | 2646 | ||
| 2679 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { | 2647 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 2680 | name_len = UniStrnlen((wchar_t *) | 2648 | cifs_from_ucs2(symlinkinfo, (__le16 *) |
| 2681 | (reparse_buf->LinkNamesBuf + | 2649 | (reparse_buf->LinkNamesBuf + |
| 2682 | reparse_buf->TargetNameOffset), | 2650 | reparse_buf->TargetNameOffset), |
| 2683 | min(buflen/2, | 2651 | buflen, |
| 2684 | reparse_buf->TargetNameLen / 2)); | 2652 | reparse_buf->TargetNameLen, |
| 2685 | cifs_strfromUCS_le(symlinkinfo, | 2653 | nls_codepage, 0); |
| 2686 | (__le16 *) (reparse_buf->LinkNamesBuf + | 2654 | } else { /* ASCII names */ |
| 2687 | reparse_buf->TargetNameOffset), | 2655 | strncpy(symlinkinfo, |
| 2688 | name_len, nls_codepage); | 2656 | reparse_buf->LinkNamesBuf + |
| 2689 | } else { /* ASCII names */ | 2657 | reparse_buf->TargetNameOffset, |
| 2690 | strncpy(symlinkinfo, | 2658 | min_t(const int, buflen, |
| 2691 | reparse_buf->LinkNamesBuf + | 2659 | reparse_buf->TargetNameLen)); |
| 2692 | reparse_buf->TargetNameOffset, | ||
| 2693 | min_t(const int, buflen, | ||
| 2694 | reparse_buf->TargetNameLen)); | ||
| 2695 | } | ||
| 2696 | } else { | ||
| 2697 | rc = -EIO; | ||
| 2698 | cFYI(1, ("Invalid return data count on " | ||
| 2699 | "get reparse info ioctl")); | ||
| 2700 | } | 2660 | } |
| 2701 | symlinkinfo[buflen] = 0; /* just in case so the caller | 2661 | } else { |
| 2702 | does not go off the end of the buffer */ | 2662 | rc = -EIO; |
| 2703 | cFYI(1, ("readlink result - %s", symlinkinfo)); | 2663 | cFYI(1, ("Invalid return data count on " |
| 2664 | "get reparse info ioctl")); | ||
| 2704 | } | 2665 | } |
| 2666 | symlinkinfo[buflen] = 0; /* just in case so the caller | ||
| 2667 | does not go off the end of the buffer */ | ||
| 2668 | cFYI(1, ("readlink result - %s", symlinkinfo)); | ||
| 2705 | } | 2669 | } |
| 2670 | |||
| 2706 | qreparse_out: | 2671 | qreparse_out: |
| 2707 | cifs_buf_release(pSMB); | 2672 | cifs_buf_release(pSMB); |
| 2708 | 2673 | ||
| @@ -2711,6 +2676,7 @@ qreparse_out: | |||
| 2711 | 2676 | ||
| 2712 | return rc; | 2677 | return rc; |
| 2713 | } | 2678 | } |
| 2679 | #endif /* CIFS_EXPERIMENTAL */ | ||
| 2714 | 2680 | ||
| 2715 | #ifdef CONFIG_CIFS_POSIX | 2681 | #ifdef CONFIG_CIFS_POSIX |
| 2716 | 2682 | ||
| @@ -3928,27 +3894,6 @@ GetInodeNumOut: | |||
| 3928 | return rc; | 3894 | return rc; |
| 3929 | } | 3895 | } |
| 3930 | 3896 | ||
| 3931 | /* computes length of UCS string converted to host codepage | ||
| 3932 | * @src: UCS string | ||
| 3933 | * @maxlen: length of the input string in UCS characters | ||
| 3934 | * (not in bytes) | ||
| 3935 | * | ||
| 3936 | * return: size of input string in host codepage | ||
| 3937 | */ | ||
| 3938 | static int hostlen_fromUCS(const __le16 *src, const int maxlen, | ||
| 3939 | const struct nls_table *nls_codepage) { | ||
| 3940 | int i; | ||
| 3941 | int hostlen = 0; | ||
| 3942 | char to[4]; | ||
| 3943 | int charlen; | ||
| 3944 | for (i = 0; (i < maxlen) && src[i]; ++i) { | ||
| 3945 | charlen = nls_codepage->uni2char(le16_to_cpu(src[i]), | ||
| 3946 | to, NLS_MAX_CHARSET_SIZE); | ||
| 3947 | hostlen += charlen > 0 ? charlen : 1; | ||
| 3948 | } | ||
| 3949 | return hostlen; | ||
| 3950 | } | ||
| 3951 | |||
| 3952 | /* parses DFS refferal V3 structure | 3897 | /* parses DFS refferal V3 structure |
| 3953 | * caller is responsible for freeing target_nodes | 3898 | * caller is responsible for freeing target_nodes |
| 3954 | * returns: | 3899 | * returns: |
| @@ -3994,7 +3939,7 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
| 3994 | 3939 | ||
| 3995 | cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n", | 3940 | cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n", |
| 3996 | *num_of_nodes, | 3941 | *num_of_nodes, |
| 3997 | le16_to_cpu(pSMBr->DFSFlags))); | 3942 | le32_to_cpu(pSMBr->DFSFlags))); |
| 3998 | 3943 | ||
| 3999 | *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * | 3944 | *target_nodes = kzalloc(sizeof(struct dfs_info3_param) * |
| 4000 | *num_of_nodes, GFP_KERNEL); | 3945 | *num_of_nodes, GFP_KERNEL); |
| @@ -4010,14 +3955,14 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
| 4010 | int max_len; | 3955 | int max_len; |
| 4011 | struct dfs_info3_param *node = (*target_nodes)+i; | 3956 | struct dfs_info3_param *node = (*target_nodes)+i; |
| 4012 | 3957 | ||
| 4013 | node->flags = le16_to_cpu(pSMBr->DFSFlags); | 3958 | node->flags = le32_to_cpu(pSMBr->DFSFlags); |
| 4014 | if (is_unicode) { | 3959 | if (is_unicode) { |
| 4015 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, | 3960 | __le16 *tmp = kmalloc(strlen(searchName)*2 + 2, |
| 4016 | GFP_KERNEL); | 3961 | GFP_KERNEL); |
| 4017 | cifsConvertToUCS((__le16 *) tmp, searchName, | 3962 | cifsConvertToUCS((__le16 *) tmp, searchName, |
| 4018 | PATH_MAX, nls_codepage, remap); | 3963 | PATH_MAX, nls_codepage, remap); |
| 4019 | node->path_consumed = hostlen_fromUCS(tmp, | 3964 | node->path_consumed = cifs_ucs2_bytes(tmp, |
| 4020 | le16_to_cpu(pSMBr->PathConsumed)/2, | 3965 | le16_to_cpu(pSMBr->PathConsumed), |
| 4021 | nls_codepage); | 3966 | nls_codepage); |
| 4022 | kfree(tmp); | 3967 | kfree(tmp); |
| 4023 | } else | 3968 | } else |
| @@ -4029,20 +3974,24 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
| 4029 | /* copy DfsPath */ | 3974 | /* copy DfsPath */ |
| 4030 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); | 3975 | temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset); |
| 4031 | max_len = data_end - temp; | 3976 | max_len = data_end - temp; |
| 4032 | rc = cifs_strncpy_to_host(&(node->path_name), temp, | 3977 | node->path_name = cifs_strndup_from_ucs(temp, max_len, |
| 4033 | max_len, is_unicode, nls_codepage); | 3978 | is_unicode, nls_codepage); |
| 4034 | if (rc) | 3979 | if (IS_ERR(node->path_name)) { |
| 3980 | rc = PTR_ERR(node->path_name); | ||
| 3981 | node->path_name = NULL; | ||
| 4035 | goto parse_DFS_referrals_exit; | 3982 | goto parse_DFS_referrals_exit; |
| 3983 | } | ||
| 4036 | 3984 | ||
| 4037 | /* copy link target UNC */ | 3985 | /* copy link target UNC */ |
| 4038 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); | 3986 | temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset); |
| 4039 | max_len = data_end - temp; | 3987 | max_len = data_end - temp; |
| 4040 | rc = cifs_strncpy_to_host(&(node->node_name), temp, | 3988 | node->node_name = cifs_strndup_from_ucs(temp, max_len, |
| 4041 | max_len, is_unicode, nls_codepage); | 3989 | is_unicode, nls_codepage); |
| 4042 | if (rc) | 3990 | if (IS_ERR(node->node_name)) { |
| 3991 | rc = PTR_ERR(node->node_name); | ||
| 3992 | node->node_name = NULL; | ||
| 4043 | goto parse_DFS_referrals_exit; | 3993 | goto parse_DFS_referrals_exit; |
| 4044 | 3994 | } | |
| 4045 | ref += le16_to_cpu(ref->Size); | ||
| 4046 | } | 3995 | } |
| 4047 | 3996 | ||
| 4048 | parse_DFS_referrals_exit: | 3997 | parse_DFS_referrals_exit: |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index bacdef1546b..4aa81a507b7 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * fs/cifs/connect.c | 2 | * fs/cifs/connect.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) International Business Machines Corp., 2002,2008 | 4 | * Copyright (C) International Business Machines Corp., 2002,2009 |
| 5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
| 6 | * | 6 | * |
| 7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/kthread.h> | 32 | #include <linux/kthread.h> |
| 33 | #include <linux/pagevec.h> | 33 | #include <linux/pagevec.h> |
| 34 | #include <linux/freezer.h> | 34 | #include <linux/freezer.h> |
| 35 | #include <linux/namei.h> | ||
| 35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
| 36 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
| 37 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
| @@ -978,6 +979,13 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 978 | return 1; | 979 | return 1; |
| 979 | } else if (strnicmp(value, "krb5", 4) == 0) { | 980 | } else if (strnicmp(value, "krb5", 4) == 0) { |
| 980 | vol->secFlg |= CIFSSEC_MAY_KRB5; | 981 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
| 982 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 983 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { | ||
| 984 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | | ||
| 985 | CIFSSEC_MUST_SIGN; | ||
| 986 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { | ||
| 987 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; | ||
| 988 | #endif | ||
| 981 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 989 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
| 982 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | | 990 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
| 983 | CIFSSEC_MUST_SIGN; | 991 | CIFSSEC_MUST_SIGN; |
| @@ -2278,6 +2286,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2278 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2286 | #ifdef CONFIG_CIFS_DFS_UPCALL |
| 2279 | struct dfs_info3_param *referrals = NULL; | 2287 | struct dfs_info3_param *referrals = NULL; |
| 2280 | unsigned int num_referrals = 0; | 2288 | unsigned int num_referrals = 0; |
| 2289 | int referral_walks_count = 0; | ||
| 2281 | try_mount_again: | 2290 | try_mount_again: |
| 2282 | #endif | 2291 | #endif |
| 2283 | full_path = NULL; | 2292 | full_path = NULL; |
| @@ -2525,6 +2534,16 @@ remote_path_check: | |||
| 2525 | /* get referral if needed */ | 2534 | /* get referral if needed */ |
| 2526 | if (rc == -EREMOTE) { | 2535 | if (rc == -EREMOTE) { |
| 2527 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2536 | #ifdef CONFIG_CIFS_DFS_UPCALL |
| 2537 | if (referral_walks_count > MAX_NESTED_LINKS) { | ||
| 2538 | /* | ||
| 2539 | * BB: when we implement proper loop detection, | ||
| 2540 | * we will remove this check. But now we need it | ||
| 2541 | * to prevent an indefinite loop if 'DFS tree' is | ||
| 2542 | * misconfigured (i.e. has loops). | ||
| 2543 | */ | ||
| 2544 | rc = -ELOOP; | ||
| 2545 | goto mount_fail_check; | ||
| 2546 | } | ||
| 2528 | /* convert forward to back slashes in prepath here if needed */ | 2547 | /* convert forward to back slashes in prepath here if needed */ |
| 2529 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | 2548 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) |
| 2530 | convert_delimiter(cifs_sb->prepath, | 2549 | convert_delimiter(cifs_sb->prepath, |
| @@ -2558,6 +2577,7 @@ remote_path_check: | |||
| 2558 | cleanup_volume_info(&volume_info); | 2577 | cleanup_volume_info(&volume_info); |
| 2559 | FreeXid(xid); | 2578 | FreeXid(xid); |
| 2560 | kfree(full_path); | 2579 | kfree(full_path); |
| 2580 | referral_walks_count++; | ||
| 2561 | goto try_mount_again; | 2581 | goto try_mount_again; |
| 2562 | } | 2582 | } |
| 2563 | #else /* No DFS support, return error on mount */ | 2583 | #else /* No DFS support, return error on mount */ |
| @@ -2592,1041 +2612,6 @@ out: | |||
| 2592 | return rc; | 2612 | return rc; |
| 2593 | } | 2613 | } |
| 2594 | 2614 | ||
| 2595 | static int | ||
| 2596 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
| 2597 | char session_key[CIFS_SESS_KEY_SIZE], | ||
| 2598 | const struct nls_table *nls_codepage) | ||
| 2599 | { | ||
| 2600 | struct smb_hdr *smb_buffer; | ||
| 2601 | struct smb_hdr *smb_buffer_response; | ||
| 2602 | SESSION_SETUP_ANDX *pSMB; | ||
| 2603 | SESSION_SETUP_ANDX *pSMBr; | ||
| 2604 | char *bcc_ptr; | ||
| 2605 | char *user; | ||
| 2606 | char *domain; | ||
| 2607 | int rc = 0; | ||
| 2608 | int remaining_words = 0; | ||
| 2609 | int bytes_returned = 0; | ||
| 2610 | int len; | ||
| 2611 | __u32 capabilities; | ||
| 2612 | __u16 count; | ||
| 2613 | |||
| 2614 | cFYI(1, ("In sesssetup")); | ||
| 2615 | if (ses == NULL) | ||
| 2616 | return -EINVAL; | ||
| 2617 | user = ses->userName; | ||
| 2618 | domain = ses->domainName; | ||
| 2619 | smb_buffer = cifs_buf_get(); | ||
| 2620 | |||
| 2621 | if (smb_buffer == NULL) | ||
| 2622 | return -ENOMEM; | ||
| 2623 | |||
| 2624 | smb_buffer_response = smb_buffer; | ||
| 2625 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
| 2626 | |||
| 2627 | /* send SMBsessionSetup here */ | ||
| 2628 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
| 2629 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | ||
| 2630 | |||
| 2631 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 2632 | pSMB->req_no_secext.AndXCommand = 0xFF; | ||
| 2633 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
| 2634 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
| 2635 | |||
| 2636 | if (ses->server->secMode & | ||
| 2637 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 2638 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 2639 | |||
| 2640 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
| 2641 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
| 2642 | if (ses->capabilities & CAP_UNICODE) { | ||
| 2643 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
| 2644 | capabilities |= CAP_UNICODE; | ||
| 2645 | } | ||
| 2646 | if (ses->capabilities & CAP_STATUS32) { | ||
| 2647 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
| 2648 | capabilities |= CAP_STATUS32; | ||
| 2649 | } | ||
| 2650 | if (ses->capabilities & CAP_DFS) { | ||
| 2651 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
| 2652 | capabilities |= CAP_DFS; | ||
| 2653 | } | ||
| 2654 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
| 2655 | |||
| 2656 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
| 2657 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 2658 | |||
| 2659 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
| 2660 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 2661 | bcc_ptr = pByteArea(smb_buffer); | ||
| 2662 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
| 2663 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
| 2664 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
| 2665 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
| 2666 | |||
| 2667 | if (ses->capabilities & CAP_UNICODE) { | ||
| 2668 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | ||
| 2669 | *bcc_ptr = 0; | ||
| 2670 | bcc_ptr++; | ||
| 2671 | } | ||
| 2672 | if (user == NULL) | ||
| 2673 | bytes_returned = 0; /* skip null user */ | ||
| 2674 | else | ||
| 2675 | bytes_returned = | ||
| 2676 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | ||
| 2677 | nls_codepage); | ||
| 2678 | /* convert number of 16 bit words to bytes */ | ||
| 2679 | bcc_ptr += 2 * bytes_returned; | ||
| 2680 | bcc_ptr += 2; /* trailing null */ | ||
| 2681 | if (domain == NULL) | ||
| 2682 | bytes_returned = | ||
| 2683 | cifs_strtoUCS((__le16 *) bcc_ptr, | ||
| 2684 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
| 2685 | else | ||
| 2686 | bytes_returned = | ||
| 2687 | cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
| 2688 | nls_codepage); | ||
| 2689 | bcc_ptr += 2 * bytes_returned; | ||
| 2690 | bcc_ptr += 2; | ||
| 2691 | bytes_returned = | ||
| 2692 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
| 2693 | 32, nls_codepage); | ||
| 2694 | bcc_ptr += 2 * bytes_returned; | ||
| 2695 | bytes_returned = | ||
| 2696 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, | ||
| 2697 | 32, nls_codepage); | ||
| 2698 | bcc_ptr += 2 * bytes_returned; | ||
| 2699 | bcc_ptr += 2; | ||
| 2700 | bytes_returned = | ||
| 2701 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
| 2702 | 64, nls_codepage); | ||
| 2703 | bcc_ptr += 2 * bytes_returned; | ||
| 2704 | bcc_ptr += 2; | ||
| 2705 | } else { | ||
| 2706 | if (user != NULL) { | ||
| 2707 | strncpy(bcc_ptr, user, 200); | ||
| 2708 | bcc_ptr += strnlen(user, 200); | ||
| 2709 | } | ||
| 2710 | *bcc_ptr = 0; | ||
| 2711 | bcc_ptr++; | ||
| 2712 | if (domain == NULL) { | ||
| 2713 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
| 2714 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
| 2715 | } else { | ||
| 2716 | strncpy(bcc_ptr, domain, 64); | ||
| 2717 | bcc_ptr += strnlen(domain, 64); | ||
| 2718 | *bcc_ptr = 0; | ||
| 2719 | bcc_ptr++; | ||
| 2720 | } | ||
| 2721 | strcpy(bcc_ptr, "Linux version "); | ||
| 2722 | bcc_ptr += strlen("Linux version "); | ||
| 2723 | strcpy(bcc_ptr, utsname()->release); | ||
| 2724 | bcc_ptr += strlen(utsname()->release) + 1; | ||
| 2725 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
| 2726 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
| 2727 | } | ||
| 2728 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
| 2729 | smb_buffer->smb_buf_length += count; | ||
| 2730 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | ||
| 2731 | |||
| 2732 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
| 2733 | &bytes_returned, CIFS_LONG_OP); | ||
| 2734 | if (rc) { | ||
| 2735 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | ||
| 2736 | } else if ((smb_buffer_response->WordCount == 3) | ||
| 2737 | || (smb_buffer_response->WordCount == 4)) { | ||
| 2738 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
| 2739 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
| 2740 | if (action & GUEST_LOGIN) | ||
| 2741 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ | ||
| 2742 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format | ||
| 2743 | (little endian) */ | ||
| 2744 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
| 2745 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
| 2746 | bcc_ptr = pByteArea(smb_buffer_response); | ||
| 2747 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
| 2748 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
| 2749 | && (blob_len < pSMBr->resp.ByteCount))) { | ||
| 2750 | if (pSMBr->resp.hdr.WordCount == 4) | ||
| 2751 | bcc_ptr += blob_len; | ||
| 2752 | |||
| 2753 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
| 2754 | if ((long) (bcc_ptr) % 2) { | ||
| 2755 | remaining_words = | ||
| 2756 | (BCC(smb_buffer_response) - 1) / 2; | ||
| 2757 | /* Unicode strings must be word | ||
| 2758 | aligned */ | ||
| 2759 | bcc_ptr++; | ||
| 2760 | } else { | ||
| 2761 | remaining_words = | ||
| 2762 | BCC(smb_buffer_response) / 2; | ||
| 2763 | } | ||
| 2764 | len = | ||
| 2765 | UniStrnlen((wchar_t *) bcc_ptr, | ||
| 2766 | remaining_words - 1); | ||
| 2767 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
| 2768 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
| 2769 | terminating last Unicode string in response */ | ||
| 2770 | kfree(ses->serverOS); | ||
| 2771 | ses->serverOS = kzalloc(2 * (len + 1), | ||
| 2772 | GFP_KERNEL); | ||
| 2773 | if (ses->serverOS == NULL) | ||
| 2774 | goto sesssetup_nomem; | ||
| 2775 | cifs_strfromUCS_le(ses->serverOS, | ||
| 2776 | (__le16 *)bcc_ptr, | ||
| 2777 | len, nls_codepage); | ||
| 2778 | bcc_ptr += 2 * (len + 1); | ||
| 2779 | remaining_words -= len + 1; | ||
| 2780 | ses->serverOS[2 * len] = 0; | ||
| 2781 | ses->serverOS[1 + (2 * len)] = 0; | ||
| 2782 | if (remaining_words > 0) { | ||
| 2783 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
| 2784 | remaining_words-1); | ||
| 2785 | kfree(ses->serverNOS); | ||
| 2786 | ses->serverNOS = kzalloc(2 * (len + 1), | ||
| 2787 | GFP_KERNEL); | ||
| 2788 | if (ses->serverNOS == NULL) | ||
| 2789 | goto sesssetup_nomem; | ||
| 2790 | cifs_strfromUCS_le(ses->serverNOS, | ||
| 2791 | (__le16 *)bcc_ptr, | ||
| 2792 | len, nls_codepage); | ||
| 2793 | bcc_ptr += 2 * (len + 1); | ||
| 2794 | ses->serverNOS[2 * len] = 0; | ||
| 2795 | ses->serverNOS[1 + (2 * len)] = 0; | ||
| 2796 | if (strncmp(ses->serverNOS, | ||
| 2797 | "NT LAN Manager 4", 16) == 0) { | ||
| 2798 | cFYI(1, ("NT4 server")); | ||
| 2799 | ses->flags |= CIFS_SES_NT4; | ||
| 2800 | } | ||
| 2801 | remaining_words -= len + 1; | ||
| 2802 | if (remaining_words > 0) { | ||
| 2803 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
| 2804 | /* last string is not always null terminated | ||
| 2805 | (for e.g. for Windows XP & 2000) */ | ||
| 2806 | kfree(ses->serverDomain); | ||
| 2807 | ses->serverDomain = | ||
| 2808 | kzalloc(2*(len+1), | ||
| 2809 | GFP_KERNEL); | ||
| 2810 | if (ses->serverDomain == NULL) | ||
| 2811 | goto sesssetup_nomem; | ||
| 2812 | cifs_strfromUCS_le(ses->serverDomain, | ||
| 2813 | (__le16 *)bcc_ptr, | ||
| 2814 | len, nls_codepage); | ||
| 2815 | bcc_ptr += 2 * (len + 1); | ||
| 2816 | ses->serverDomain[2*len] = 0; | ||
| 2817 | ses->serverDomain[1+(2*len)] = 0; | ||
| 2818 | } else { /* else no more room so create | ||
| 2819 | dummy domain string */ | ||
| 2820 | kfree(ses->serverDomain); | ||
| 2821 | ses->serverDomain = | ||
| 2822 | kzalloc(2, GFP_KERNEL); | ||
| 2823 | } | ||
| 2824 | } else { /* no room so create dummy domain | ||
| 2825 | and NOS string */ | ||
| 2826 | |||
| 2827 | /* if these kcallocs fail not much we | ||
| 2828 | can do, but better to not fail the | ||
| 2829 | sesssetup itself */ | ||
| 2830 | kfree(ses->serverDomain); | ||
| 2831 | ses->serverDomain = | ||
| 2832 | kzalloc(2, GFP_KERNEL); | ||
| 2833 | kfree(ses->serverNOS); | ||
| 2834 | ses->serverNOS = | ||
| 2835 | kzalloc(2, GFP_KERNEL); | ||
| 2836 | } | ||
| 2837 | } else { /* ASCII */ | ||
| 2838 | len = strnlen(bcc_ptr, 1024); | ||
| 2839 | if (((long) bcc_ptr + len) - (long) | ||
| 2840 | pByteArea(smb_buffer_response) | ||
| 2841 | <= BCC(smb_buffer_response)) { | ||
| 2842 | kfree(ses->serverOS); | ||
| 2843 | ses->serverOS = kzalloc(len + 1, | ||
| 2844 | GFP_KERNEL); | ||
| 2845 | if (ses->serverOS == NULL) | ||
| 2846 | goto sesssetup_nomem; | ||
| 2847 | strncpy(ses->serverOS, bcc_ptr, len); | ||
| 2848 | |||
| 2849 | bcc_ptr += len; | ||
| 2850 | /* null terminate the string */ | ||
| 2851 | bcc_ptr[0] = 0; | ||
| 2852 | bcc_ptr++; | ||
| 2853 | |||
| 2854 | len = strnlen(bcc_ptr, 1024); | ||
| 2855 | kfree(ses->serverNOS); | ||
| 2856 | ses->serverNOS = kzalloc(len + 1, | ||
| 2857 | GFP_KERNEL); | ||
| 2858 | if (ses->serverNOS == NULL) | ||
| 2859 | goto sesssetup_nomem; | ||
| 2860 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
| 2861 | bcc_ptr += len; | ||
| 2862 | bcc_ptr[0] = 0; | ||
| 2863 | bcc_ptr++; | ||
| 2864 | |||
| 2865 | len = strnlen(bcc_ptr, 1024); | ||
| 2866 | kfree(ses->serverDomain); | ||
| 2867 | ses->serverDomain = kzalloc(len + 1, | ||
| 2868 | GFP_KERNEL); | ||
| 2869 | if (ses->serverDomain == NULL) | ||
| 2870 | goto sesssetup_nomem; | ||
| 2871 | strncpy(ses->serverDomain, bcc_ptr, | ||
| 2872 | len); | ||
| 2873 | bcc_ptr += len; | ||
| 2874 | bcc_ptr[0] = 0; | ||
| 2875 | bcc_ptr++; | ||
| 2876 | } else | ||
| 2877 | cFYI(1, | ||
| 2878 | ("Variable field of length %d " | ||
| 2879 | "extends beyond end of smb ", | ||
| 2880 | len)); | ||
| 2881 | } | ||
| 2882 | } else { | ||
| 2883 | cERROR(1, ("Security Blob Length extends beyond " | ||
| 2884 | "end of SMB")); | ||
| 2885 | } | ||
| 2886 | } else { | ||
| 2887 | cERROR(1, ("Invalid Word count %d: ", | ||
| 2888 | smb_buffer_response->WordCount)); | ||
| 2889 | rc = -EIO; | ||
| 2890 | } | ||
| 2891 | sesssetup_nomem: /* do not return an error on nomem for the info strings, | ||
| 2892 | since that could make reconnection harder, and | ||
| 2893 | reconnection might be needed to free memory */ | ||
| 2894 | cifs_buf_release(smb_buffer); | ||
| 2895 | |||
| 2896 | return rc; | ||
| 2897 | } | ||
| 2898 | |||
| 2899 | static int | ||
| 2900 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | ||
| 2901 | struct cifsSesInfo *ses, bool *pNTLMv2_flag, | ||
| 2902 | const struct nls_table *nls_codepage) | ||
| 2903 | { | ||
| 2904 | struct smb_hdr *smb_buffer; | ||
| 2905 | struct smb_hdr *smb_buffer_response; | ||
| 2906 | SESSION_SETUP_ANDX *pSMB; | ||
| 2907 | SESSION_SETUP_ANDX *pSMBr; | ||
| 2908 | char *bcc_ptr; | ||
| 2909 | char *domain; | ||
| 2910 | int rc = 0; | ||
| 2911 | int remaining_words = 0; | ||
| 2912 | int bytes_returned = 0; | ||
| 2913 | int len; | ||
| 2914 | int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); | ||
| 2915 | PNEGOTIATE_MESSAGE SecurityBlob; | ||
| 2916 | PCHALLENGE_MESSAGE SecurityBlob2; | ||
| 2917 | __u32 negotiate_flags, capabilities; | ||
| 2918 | __u16 count; | ||
| 2919 | |||
| 2920 | cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); | ||
| 2921 | if (ses == NULL) | ||
| 2922 | return -EINVAL; | ||
| 2923 | domain = ses->domainName; | ||
| 2924 | *pNTLMv2_flag = false; | ||
| 2925 | smb_buffer = cifs_buf_get(); | ||
| 2926 | if (smb_buffer == NULL) { | ||
| 2927 | return -ENOMEM; | ||
| 2928 | } | ||
| 2929 | smb_buffer_response = smb_buffer; | ||
| 2930 | pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
| 2931 | pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; | ||
| 2932 | |||
| 2933 | /* send SMBsessionSetup here */ | ||
| 2934 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
| 2935 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
| 2936 | |||
| 2937 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 2938 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 2939 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
| 2940 | |||
| 2941 | pSMB->req.AndXCommand = 0xFF; | ||
| 2942 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
| 2943 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
| 2944 | |||
| 2945 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 2946 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 2947 | |||
| 2948 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
| 2949 | CAP_EXTENDED_SECURITY; | ||
| 2950 | if (ses->capabilities & CAP_UNICODE) { | ||
| 2951 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
| 2952 | capabilities |= CAP_UNICODE; | ||
| 2953 | } | ||
| 2954 | if (ses->capabilities & CAP_STATUS32) { | ||
| 2955 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
| 2956 | capabilities |= CAP_STATUS32; | ||
| 2957 | } | ||
| 2958 | if (ses->capabilities & CAP_DFS) { | ||
| 2959 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
| 2960 | capabilities |= CAP_DFS; | ||
| 2961 | } | ||
| 2962 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
| 2963 | |||
| 2964 | bcc_ptr = (char *) &pSMB->req.SecurityBlob; | ||
| 2965 | SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; | ||
| 2966 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
| 2967 | SecurityBlob->MessageType = NtLmNegotiate; | ||
| 2968 | negotiate_flags = | ||
| 2969 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | | ||
| 2970 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | | ||
| 2971 | NTLMSSP_NEGOTIATE_56 | | ||
| 2972 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | ||
| 2973 | if (sign_CIFS_PDUs) | ||
| 2974 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
| 2975 | /* if (ntlmv2_support) | ||
| 2976 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ | ||
| 2977 | /* setup pointers to domain name and workstation name */ | ||
| 2978 | bcc_ptr += SecurityBlobLength; | ||
| 2979 | |||
| 2980 | SecurityBlob->WorkstationName.Buffer = 0; | ||
| 2981 | SecurityBlob->WorkstationName.Length = 0; | ||
| 2982 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
| 2983 | |||
| 2984 | /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent | ||
| 2985 | along with username on auth request (ie the response to challenge) */ | ||
| 2986 | SecurityBlob->DomainName.Buffer = 0; | ||
| 2987 | SecurityBlob->DomainName.Length = 0; | ||
| 2988 | SecurityBlob->DomainName.MaximumLength = 0; | ||
| 2989 | if (ses->capabilities & CAP_UNICODE) { | ||
| 2990 | if ((long) bcc_ptr % 2) { | ||
| 2991 | *bcc_ptr = 0; | ||
| 2992 | bcc_ptr++; | ||
| 2993 | } | ||
| 2994 | |||
| 2995 | bytes_returned = | ||
| 2996 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
| 2997 | 32, nls_codepage); | ||
| 2998 | bcc_ptr += 2 * bytes_returned; | ||
| 2999 | bytes_returned = | ||
| 3000 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | ||
| 3001 | nls_codepage); | ||
| 3002 | bcc_ptr += 2 * bytes_returned; | ||
| 3003 | bcc_ptr += 2; /* null terminate Linux version */ | ||
| 3004 | bytes_returned = | ||
| 3005 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
| 3006 | 64, nls_codepage); | ||
| 3007 | bcc_ptr += 2 * bytes_returned; | ||
| 3008 | *(bcc_ptr + 1) = 0; | ||
| 3009 | *(bcc_ptr + 2) = 0; | ||
| 3010 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
| 3011 | *(bcc_ptr + 1) = 0; | ||
| 3012 | *(bcc_ptr + 2) = 0; | ||
| 3013 | bcc_ptr += 2; /* null domain */ | ||
| 3014 | } else { /* ASCII */ | ||
| 3015 | strcpy(bcc_ptr, "Linux version "); | ||
| 3016 | bcc_ptr += strlen("Linux version "); | ||
| 3017 | strcpy(bcc_ptr, utsname()->release); | ||
| 3018 | bcc_ptr += strlen(utsname()->release) + 1; | ||
| 3019 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
| 3020 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
| 3021 | bcc_ptr++; /* empty domain field */ | ||
| 3022 | *bcc_ptr = 0; | ||
| 3023 | } | ||
| 3024 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
| 3025 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
| 3026 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
| 3027 | smb_buffer->smb_buf_length += count; | ||
| 3028 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
| 3029 | |||
| 3030 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
| 3031 | &bytes_returned, CIFS_LONG_OP); | ||
| 3032 | |||
| 3033 | if (smb_buffer_response->Status.CifsError == | ||
| 3034 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | ||
| 3035 | rc = 0; | ||
| 3036 | |||
| 3037 | if (rc) { | ||
| 3038 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
| 3039 | } else if ((smb_buffer_response->WordCount == 3) | ||
| 3040 | || (smb_buffer_response->WordCount == 4)) { | ||
| 3041 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
| 3042 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
| 3043 | |||
| 3044 | if (action & GUEST_LOGIN) | ||
| 3045 | cFYI(1, ("Guest login")); | ||
| 3046 | /* Do we want to set anything in SesInfo struct when guest login? */ | ||
| 3047 | |||
| 3048 | bcc_ptr = pByteArea(smb_buffer_response); | ||
| 3049 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
| 3050 | |||
| 3051 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; | ||
| 3052 | if (SecurityBlob2->MessageType != NtLmChallenge) { | ||
| 3053 | cFYI(1, ("Unexpected NTLMSSP message type received %d", | ||
| 3054 | SecurityBlob2->MessageType)); | ||
| 3055 | } else if (ses) { | ||
| 3056 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ | ||
| 3057 | cFYI(1, ("UID = %d", ses->Suid)); | ||
| 3058 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
| 3059 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
| 3060 | && (blob_len < | ||
| 3061 | pSMBr->resp.ByteCount))) { | ||
| 3062 | |||
| 3063 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
| 3064 | bcc_ptr += blob_len; | ||
| 3065 | cFYI(1, ("Security Blob Length %d", | ||
| 3066 | blob_len)); | ||
| 3067 | } | ||
| 3068 | |||
| 3069 | cFYI(1, ("NTLMSSP Challenge rcvd")); | ||
| 3070 | |||
| 3071 | memcpy(ses->server->cryptKey, | ||
| 3072 | SecurityBlob2->Challenge, | ||
| 3073 | CIFS_CRYPTO_KEY_SIZE); | ||
| 3074 | if (SecurityBlob2->NegotiateFlags & | ||
| 3075 | cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) | ||
| 3076 | *pNTLMv2_flag = true; | ||
| 3077 | |||
| 3078 | if ((SecurityBlob2->NegotiateFlags & | ||
| 3079 | cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) | ||
| 3080 | || (sign_CIFS_PDUs > 1)) | ||
| 3081 | ses->server->secMode |= | ||
| 3082 | SECMODE_SIGN_REQUIRED; | ||
| 3083 | if ((SecurityBlob2->NegotiateFlags & | ||
| 3084 | cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) | ||
| 3085 | ses->server->secMode |= | ||
| 3086 | SECMODE_SIGN_ENABLED; | ||
| 3087 | |||
| 3088 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
| 3089 | if ((long) (bcc_ptr) % 2) { | ||
| 3090 | remaining_words = | ||
| 3091 | (BCC(smb_buffer_response) | ||
| 3092 | - 1) / 2; | ||
| 3093 | /* Must word align unicode strings */ | ||
| 3094 | bcc_ptr++; | ||
| 3095 | } else { | ||
| 3096 | remaining_words = | ||
| 3097 | BCC | ||
| 3098 | (smb_buffer_response) / 2; | ||
| 3099 | } | ||
| 3100 | len = | ||
| 3101 | UniStrnlen((wchar_t *) bcc_ptr, | ||
| 3102 | remaining_words - 1); | ||
| 3103 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
| 3104 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
| 3105 | terminating last Unicode string in response */ | ||
| 3106 | kfree(ses->serverOS); | ||
| 3107 | ses->serverOS = | ||
| 3108 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
| 3109 | cifs_strfromUCS_le(ses->serverOS, | ||
| 3110 | (__le16 *) | ||
| 3111 | bcc_ptr, len, | ||
| 3112 | nls_codepage); | ||
| 3113 | bcc_ptr += 2 * (len + 1); | ||
| 3114 | remaining_words -= len + 1; | ||
| 3115 | ses->serverOS[2 * len] = 0; | ||
| 3116 | ses->serverOS[1 + (2 * len)] = 0; | ||
| 3117 | if (remaining_words > 0) { | ||
| 3118 | len = UniStrnlen((wchar_t *) | ||
| 3119 | bcc_ptr, | ||
| 3120 | remaining_words | ||
| 3121 | - 1); | ||
| 3122 | kfree(ses->serverNOS); | ||
| 3123 | ses->serverNOS = | ||
| 3124 | kzalloc(2 * (len + 1), | ||
| 3125 | GFP_KERNEL); | ||
| 3126 | cifs_strfromUCS_le(ses-> | ||
| 3127 | serverNOS, | ||
| 3128 | (__le16 *) | ||
| 3129 | bcc_ptr, | ||
| 3130 | len, | ||
| 3131 | nls_codepage); | ||
| 3132 | bcc_ptr += 2 * (len + 1); | ||
| 3133 | ses->serverNOS[2 * len] = 0; | ||
| 3134 | ses->serverNOS[1 + | ||
| 3135 | (2 * len)] = 0; | ||
| 3136 | remaining_words -= len + 1; | ||
| 3137 | if (remaining_words > 0) { | ||
| 3138 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
| 3139 | /* last string not always null terminated | ||
| 3140 | (for e.g. for Windows XP & 2000) */ | ||
| 3141 | kfree(ses->serverDomain); | ||
| 3142 | ses->serverDomain = | ||
| 3143 | kzalloc(2 * | ||
| 3144 | (len + | ||
| 3145 | 1), | ||
| 3146 | GFP_KERNEL); | ||
| 3147 | cifs_strfromUCS_le | ||
| 3148 | (ses->serverDomain, | ||
| 3149 | (__le16 *)bcc_ptr, | ||
| 3150 | len, nls_codepage); | ||
| 3151 | bcc_ptr += | ||
| 3152 | 2 * (len + 1); | ||
| 3153 | ses->serverDomain[2*len] | ||
| 3154 | = 0; | ||
| 3155 | ses->serverDomain | ||
| 3156 | [1 + (2 * len)] | ||
| 3157 | = 0; | ||
| 3158 | } /* else no more room so create dummy domain string */ | ||
| 3159 | else { | ||
| 3160 | kfree(ses->serverDomain); | ||
| 3161 | ses->serverDomain = | ||
| 3162 | kzalloc(2, | ||
| 3163 | GFP_KERNEL); | ||
| 3164 | } | ||
| 3165 | } else { /* no room so create dummy domain and NOS string */ | ||
| 3166 | kfree(ses->serverDomain); | ||
| 3167 | ses->serverDomain = | ||
| 3168 | kzalloc(2, GFP_KERNEL); | ||
| 3169 | kfree(ses->serverNOS); | ||
| 3170 | ses->serverNOS = | ||
| 3171 | kzalloc(2, GFP_KERNEL); | ||
| 3172 | } | ||
| 3173 | } else { /* ASCII */ | ||
| 3174 | len = strnlen(bcc_ptr, 1024); | ||
| 3175 | if (((long) bcc_ptr + len) - (long) | ||
| 3176 | pByteArea(smb_buffer_response) | ||
| 3177 | <= BCC(smb_buffer_response)) { | ||
| 3178 | kfree(ses->serverOS); | ||
| 3179 | ses->serverOS = | ||
| 3180 | kzalloc(len + 1, | ||
| 3181 | GFP_KERNEL); | ||
| 3182 | strncpy(ses->serverOS, | ||
| 3183 | bcc_ptr, len); | ||
| 3184 | |||
| 3185 | bcc_ptr += len; | ||
| 3186 | bcc_ptr[0] = 0; /* null terminate string */ | ||
| 3187 | bcc_ptr++; | ||
| 3188 | |||
| 3189 | len = strnlen(bcc_ptr, 1024); | ||
| 3190 | kfree(ses->serverNOS); | ||
| 3191 | ses->serverNOS = | ||
| 3192 | kzalloc(len + 1, | ||
| 3193 | GFP_KERNEL); | ||
| 3194 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
| 3195 | bcc_ptr += len; | ||
| 3196 | bcc_ptr[0] = 0; | ||
| 3197 | bcc_ptr++; | ||
| 3198 | |||
| 3199 | len = strnlen(bcc_ptr, 1024); | ||
| 3200 | kfree(ses->serverDomain); | ||
| 3201 | ses->serverDomain = | ||
| 3202 | kzalloc(len + 1, | ||
| 3203 | GFP_KERNEL); | ||
| 3204 | strncpy(ses->serverDomain, | ||
| 3205 | bcc_ptr, len); | ||
| 3206 | bcc_ptr += len; | ||
| 3207 | bcc_ptr[0] = 0; | ||
| 3208 | bcc_ptr++; | ||
| 3209 | } else | ||
| 3210 | cFYI(1, | ||
| 3211 | ("field of length %d " | ||
| 3212 | "extends beyond end of smb", | ||
| 3213 | len)); | ||
| 3214 | } | ||
| 3215 | } else { | ||
| 3216 | cERROR(1, ("Security Blob Length extends beyond" | ||
| 3217 | " end of SMB")); | ||
| 3218 | } | ||
| 3219 | } else { | ||
| 3220 | cERROR(1, ("No session structure passed in.")); | ||
| 3221 | } | ||
| 3222 | } else { | ||
| 3223 | cERROR(1, ("Invalid Word count %d:", | ||
| 3224 | smb_buffer_response->WordCount)); | ||
| 3225 | rc = -EIO; | ||
| 3226 | } | ||
| 3227 | |||
| 3228 | cifs_buf_release(smb_buffer); | ||
| 3229 | |||
| 3230 | return rc; | ||
| 3231 | } | ||
| 3232 | static int | ||
| 3233 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
| 3234 | char *ntlm_session_key, bool ntlmv2_flag, | ||
| 3235 | const struct nls_table *nls_codepage) | ||
| 3236 | { | ||
| 3237 | struct smb_hdr *smb_buffer; | ||
| 3238 | struct smb_hdr *smb_buffer_response; | ||
| 3239 | SESSION_SETUP_ANDX *pSMB; | ||
| 3240 | SESSION_SETUP_ANDX *pSMBr; | ||
| 3241 | char *bcc_ptr; | ||
| 3242 | char *user; | ||
| 3243 | char *domain; | ||
| 3244 | int rc = 0; | ||
| 3245 | int remaining_words = 0; | ||
| 3246 | int bytes_returned = 0; | ||
| 3247 | int len; | ||
| 3248 | int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); | ||
| 3249 | PAUTHENTICATE_MESSAGE SecurityBlob; | ||
| 3250 | __u32 negotiate_flags, capabilities; | ||
| 3251 | __u16 count; | ||
| 3252 | |||
| 3253 | cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); | ||
| 3254 | if (ses == NULL) | ||
| 3255 | return -EINVAL; | ||
| 3256 | user = ses->userName; | ||
| 3257 | domain = ses->domainName; | ||
| 3258 | smb_buffer = cifs_buf_get(); | ||
| 3259 | if (smb_buffer == NULL) { | ||
| 3260 | return -ENOMEM; | ||
| 3261 | } | ||
| 3262 | smb_buffer_response = smb_buffer; | ||
| 3263 | pSMB = (SESSION_SETUP_ANDX *)smb_buffer; | ||
| 3264 | pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; | ||
| 3265 | |||
| 3266 | /* send SMBsessionSetup here */ | ||
| 3267 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
| 3268 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
| 3269 | |||
| 3270 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 3271 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
| 3272 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 3273 | pSMB->req.AndXCommand = 0xFF; | ||
| 3274 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
| 3275 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
| 3276 | |||
| 3277 | pSMB->req.hdr.Uid = ses->Suid; | ||
| 3278 | |||
| 3279 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 3280 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 3281 | |||
| 3282 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
| 3283 | CAP_EXTENDED_SECURITY; | ||
| 3284 | if (ses->capabilities & CAP_UNICODE) { | ||
| 3285 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
| 3286 | capabilities |= CAP_UNICODE; | ||
| 3287 | } | ||
| 3288 | if (ses->capabilities & CAP_STATUS32) { | ||
| 3289 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
| 3290 | capabilities |= CAP_STATUS32; | ||
| 3291 | } | ||
| 3292 | if (ses->capabilities & CAP_DFS) { | ||
| 3293 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
| 3294 | capabilities |= CAP_DFS; | ||
| 3295 | } | ||
| 3296 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
| 3297 | |||
| 3298 | bcc_ptr = (char *)&pSMB->req.SecurityBlob; | ||
| 3299 | SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; | ||
| 3300 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
| 3301 | SecurityBlob->MessageType = NtLmAuthenticate; | ||
| 3302 | bcc_ptr += SecurityBlobLength; | ||
| 3303 | negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | | ||
| 3304 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
| 3305 | 0x80000000 | NTLMSSP_NEGOTIATE_128; | ||
| 3306 | if (sign_CIFS_PDUs) | ||
| 3307 | negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; | ||
| 3308 | if (ntlmv2_flag) | ||
| 3309 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | ||
| 3310 | |||
| 3311 | /* setup pointers to domain name and workstation name */ | ||
| 3312 | |||
| 3313 | SecurityBlob->WorkstationName.Buffer = 0; | ||
| 3314 | SecurityBlob->WorkstationName.Length = 0; | ||
| 3315 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
| 3316 | SecurityBlob->SessionKey.Length = 0; | ||
| 3317 | SecurityBlob->SessionKey.MaximumLength = 0; | ||
| 3318 | SecurityBlob->SessionKey.Buffer = 0; | ||
| 3319 | |||
| 3320 | SecurityBlob->LmChallengeResponse.Length = 0; | ||
| 3321 | SecurityBlob->LmChallengeResponse.MaximumLength = 0; | ||
| 3322 | SecurityBlob->LmChallengeResponse.Buffer = 0; | ||
| 3323 | |||
| 3324 | SecurityBlob->NtChallengeResponse.Length = | ||
| 3325 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 3326 | SecurityBlob->NtChallengeResponse.MaximumLength = | ||
| 3327 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 3328 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
| 3329 | SecurityBlob->NtChallengeResponse.Buffer = | ||
| 3330 | cpu_to_le32(SecurityBlobLength); | ||
| 3331 | SecurityBlobLength += CIFS_SESS_KEY_SIZE; | ||
| 3332 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
| 3333 | |||
| 3334 | if (ses->capabilities & CAP_UNICODE) { | ||
| 3335 | if (domain == NULL) { | ||
| 3336 | SecurityBlob->DomainName.Buffer = 0; | ||
| 3337 | SecurityBlob->DomainName.Length = 0; | ||
| 3338 | SecurityBlob->DomainName.MaximumLength = 0; | ||
| 3339 | } else { | ||
| 3340 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
| 3341 | nls_codepage); | ||
| 3342 | ln *= 2; | ||
| 3343 | SecurityBlob->DomainName.MaximumLength = | ||
| 3344 | cpu_to_le16(ln); | ||
| 3345 | SecurityBlob->DomainName.Buffer = | ||
| 3346 | cpu_to_le32(SecurityBlobLength); | ||
| 3347 | bcc_ptr += ln; | ||
| 3348 | SecurityBlobLength += ln; | ||
| 3349 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
| 3350 | } | ||
| 3351 | if (user == NULL) { | ||
| 3352 | SecurityBlob->UserName.Buffer = 0; | ||
| 3353 | SecurityBlob->UserName.Length = 0; | ||
| 3354 | SecurityBlob->UserName.MaximumLength = 0; | ||
| 3355 | } else { | ||
| 3356 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, | ||
| 3357 | nls_codepage); | ||
| 3358 | ln *= 2; | ||
| 3359 | SecurityBlob->UserName.MaximumLength = | ||
| 3360 | cpu_to_le16(ln); | ||
| 3361 | SecurityBlob->UserName.Buffer = | ||
| 3362 | cpu_to_le32(SecurityBlobLength); | ||
| 3363 | bcc_ptr += ln; | ||
| 3364 | SecurityBlobLength += ln; | ||
| 3365 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
| 3366 | } | ||
| 3367 | |||
| 3368 | /* SecurityBlob->WorkstationName.Length = | ||
| 3369 | cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); | ||
| 3370 | SecurityBlob->WorkstationName.Length *= 2; | ||
| 3371 | SecurityBlob->WorkstationName.MaximumLength = | ||
| 3372 | cpu_to_le16(SecurityBlob->WorkstationName.Length); | ||
| 3373 | SecurityBlob->WorkstationName.Buffer = | ||
| 3374 | cpu_to_le32(SecurityBlobLength); | ||
| 3375 | bcc_ptr += SecurityBlob->WorkstationName.Length; | ||
| 3376 | SecurityBlobLength += SecurityBlob->WorkstationName.Length; | ||
| 3377 | SecurityBlob->WorkstationName.Length = | ||
| 3378 | cpu_to_le16(SecurityBlob->WorkstationName.Length); */ | ||
| 3379 | |||
| 3380 | if ((long) bcc_ptr % 2) { | ||
| 3381 | *bcc_ptr = 0; | ||
| 3382 | bcc_ptr++; | ||
| 3383 | } | ||
| 3384 | bytes_returned = | ||
| 3385 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
| 3386 | 32, nls_codepage); | ||
| 3387 | bcc_ptr += 2 * bytes_returned; | ||
| 3388 | bytes_returned = | ||
| 3389 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | ||
| 3390 | nls_codepage); | ||
| 3391 | bcc_ptr += 2 * bytes_returned; | ||
| 3392 | bcc_ptr += 2; /* null term version string */ | ||
| 3393 | bytes_returned = | ||
| 3394 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
| 3395 | 64, nls_codepage); | ||
| 3396 | bcc_ptr += 2 * bytes_returned; | ||
| 3397 | *(bcc_ptr + 1) = 0; | ||
| 3398 | *(bcc_ptr + 2) = 0; | ||
| 3399 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
| 3400 | *(bcc_ptr + 1) = 0; | ||
| 3401 | *(bcc_ptr + 2) = 0; | ||
| 3402 | bcc_ptr += 2; /* null domain */ | ||
| 3403 | } else { /* ASCII */ | ||
| 3404 | if (domain == NULL) { | ||
| 3405 | SecurityBlob->DomainName.Buffer = 0; | ||
| 3406 | SecurityBlob->DomainName.Length = 0; | ||
| 3407 | SecurityBlob->DomainName.MaximumLength = 0; | ||
| 3408 | } else { | ||
| 3409 | __u16 ln; | ||
| 3410 | negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; | ||
| 3411 | strncpy(bcc_ptr, domain, 63); | ||
| 3412 | ln = strnlen(domain, 64); | ||
| 3413 | SecurityBlob->DomainName.MaximumLength = | ||
| 3414 | cpu_to_le16(ln); | ||
| 3415 | SecurityBlob->DomainName.Buffer = | ||
| 3416 | cpu_to_le32(SecurityBlobLength); | ||
| 3417 | bcc_ptr += ln; | ||
| 3418 | SecurityBlobLength += ln; | ||
| 3419 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
| 3420 | } | ||
| 3421 | if (user == NULL) { | ||
| 3422 | SecurityBlob->UserName.Buffer = 0; | ||
| 3423 | SecurityBlob->UserName.Length = 0; | ||
| 3424 | SecurityBlob->UserName.MaximumLength = 0; | ||
| 3425 | } else { | ||
| 3426 | __u16 ln; | ||
| 3427 | strncpy(bcc_ptr, user, 63); | ||
| 3428 | ln = strnlen(user, 64); | ||
| 3429 | SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); | ||
| 3430 | SecurityBlob->UserName.Buffer = | ||
| 3431 | cpu_to_le32(SecurityBlobLength); | ||
| 3432 | bcc_ptr += ln; | ||
| 3433 | SecurityBlobLength += ln; | ||
| 3434 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
| 3435 | } | ||
| 3436 | /* BB fill in our workstation name if known BB */ | ||
| 3437 | |||
| 3438 | strcpy(bcc_ptr, "Linux version "); | ||
| 3439 | bcc_ptr += strlen("Linux version "); | ||
| 3440 | strcpy(bcc_ptr, utsname()->release); | ||
| 3441 | bcc_ptr += strlen(utsname()->release) + 1; | ||
| 3442 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
| 3443 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
| 3444 | bcc_ptr++; /* null domain */ | ||
| 3445 | *bcc_ptr = 0; | ||
| 3446 | } | ||
| 3447 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
| 3448 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
| 3449 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
| 3450 | smb_buffer->smb_buf_length += count; | ||
| 3451 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
| 3452 | |||
| 3453 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
| 3454 | &bytes_returned, CIFS_LONG_OP); | ||
| 3455 | if (rc) { | ||
| 3456 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ | ||
| 3457 | } else if ((smb_buffer_response->WordCount == 3) || | ||
| 3458 | (smb_buffer_response->WordCount == 4)) { | ||
| 3459 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
| 3460 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
| 3461 | if (action & GUEST_LOGIN) | ||
| 3462 | cFYI(1, ("Guest login")); /* BB Should we set anything | ||
| 3463 | in SesInfo struct ? */ | ||
| 3464 | /* if (SecurityBlob2->MessageType != NtLm??) { | ||
| 3465 | cFYI("Unexpected message type on auth response is %d")); | ||
| 3466 | } */ | ||
| 3467 | |||
| 3468 | if (ses) { | ||
| 3469 | cFYI(1, | ||
| 3470 | ("Check challenge UID %d vs auth response UID %d", | ||
| 3471 | ses->Suid, smb_buffer_response->Uid)); | ||
| 3472 | /* UID left in wire format */ | ||
| 3473 | ses->Suid = smb_buffer_response->Uid; | ||
| 3474 | bcc_ptr = pByteArea(smb_buffer_response); | ||
| 3475 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
| 3476 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
| 3477 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
| 3478 | && (blob_len < | ||
| 3479 | pSMBr->resp.ByteCount))) { | ||
| 3480 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
| 3481 | bcc_ptr += | ||
| 3482 | blob_len; | ||
| 3483 | cFYI(1, | ||
| 3484 | ("Security Blob Length %d ", | ||
| 3485 | blob_len)); | ||
| 3486 | } | ||
| 3487 | |||
| 3488 | cFYI(1, | ||
| 3489 | ("NTLMSSP response to Authenticate ")); | ||
| 3490 | |||
| 3491 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
| 3492 | if ((long) (bcc_ptr) % 2) { | ||
| 3493 | remaining_words = | ||
| 3494 | (BCC(smb_buffer_response) | ||
| 3495 | - 1) / 2; | ||
| 3496 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
| 3497 | } else { | ||
| 3498 | remaining_words = BCC(smb_buffer_response) / 2; | ||
| 3499 | } | ||
| 3500 | len = UniStrnlen((wchar_t *) bcc_ptr, | ||
| 3501 | remaining_words - 1); | ||
| 3502 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
| 3503 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
| 3504 | terminating last Unicode string in response */ | ||
| 3505 | kfree(ses->serverOS); | ||
| 3506 | ses->serverOS = | ||
| 3507 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
| 3508 | cifs_strfromUCS_le(ses->serverOS, | ||
| 3509 | (__le16 *) | ||
| 3510 | bcc_ptr, len, | ||
| 3511 | nls_codepage); | ||
| 3512 | bcc_ptr += 2 * (len + 1); | ||
| 3513 | remaining_words -= len + 1; | ||
| 3514 | ses->serverOS[2 * len] = 0; | ||
| 3515 | ses->serverOS[1 + (2 * len)] = 0; | ||
| 3516 | if (remaining_words > 0) { | ||
| 3517 | len = UniStrnlen((wchar_t *) | ||
| 3518 | bcc_ptr, | ||
| 3519 | remaining_words | ||
| 3520 | - 1); | ||
| 3521 | kfree(ses->serverNOS); | ||
| 3522 | ses->serverNOS = | ||
| 3523 | kzalloc(2 * (len + 1), | ||
| 3524 | GFP_KERNEL); | ||
| 3525 | cifs_strfromUCS_le(ses-> | ||
| 3526 | serverNOS, | ||
| 3527 | (__le16 *) | ||
| 3528 | bcc_ptr, | ||
| 3529 | len, | ||
| 3530 | nls_codepage); | ||
| 3531 | bcc_ptr += 2 * (len + 1); | ||
| 3532 | ses->serverNOS[2 * len] = 0; | ||
| 3533 | ses->serverNOS[1+(2*len)] = 0; | ||
| 3534 | remaining_words -= len + 1; | ||
| 3535 | if (remaining_words > 0) { | ||
| 3536 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
| 3537 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ | ||
| 3538 | kfree(ses->serverDomain); | ||
| 3539 | ses->serverDomain = | ||
| 3540 | kzalloc(2 * | ||
| 3541 | (len + | ||
| 3542 | 1), | ||
| 3543 | GFP_KERNEL); | ||
| 3544 | cifs_strfromUCS_le | ||
| 3545 | (ses-> | ||
| 3546 | serverDomain, | ||
| 3547 | (__le16 *) | ||
| 3548 | bcc_ptr, len, | ||
| 3549 | nls_codepage); | ||
| 3550 | bcc_ptr += | ||
| 3551 | 2 * (len + 1); | ||
| 3552 | ses-> | ||
| 3553 | serverDomain[2 | ||
| 3554 | * len] | ||
| 3555 | = 0; | ||
| 3556 | ses-> | ||
| 3557 | serverDomain[1 | ||
| 3558 | + | ||
| 3559 | (2 | ||
| 3560 | * | ||
| 3561 | len)] | ||
| 3562 | = 0; | ||
| 3563 | } /* else no more room so create dummy domain string */ | ||
| 3564 | else { | ||
| 3565 | kfree(ses->serverDomain); | ||
| 3566 | ses->serverDomain = kzalloc(2,GFP_KERNEL); | ||
| 3567 | } | ||
| 3568 | } else { /* no room so create dummy domain and NOS string */ | ||
| 3569 | kfree(ses->serverDomain); | ||
| 3570 | ses->serverDomain = kzalloc(2, GFP_KERNEL); | ||
| 3571 | kfree(ses->serverNOS); | ||
| 3572 | ses->serverNOS = kzalloc(2, GFP_KERNEL); | ||
| 3573 | } | ||
| 3574 | } else { /* ASCII */ | ||
| 3575 | len = strnlen(bcc_ptr, 1024); | ||
| 3576 | if (((long) bcc_ptr + len) - | ||
| 3577 | (long) pByteArea(smb_buffer_response) | ||
| 3578 | <= BCC(smb_buffer_response)) { | ||
| 3579 | kfree(ses->serverOS); | ||
| 3580 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
| 3581 | strncpy(ses->serverOS,bcc_ptr, len); | ||
| 3582 | |||
| 3583 | bcc_ptr += len; | ||
| 3584 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
| 3585 | bcc_ptr++; | ||
| 3586 | |||
| 3587 | len = strnlen(bcc_ptr, 1024); | ||
| 3588 | kfree(ses->serverNOS); | ||
| 3589 | ses->serverNOS = kzalloc(len+1, | ||
| 3590 | GFP_KERNEL); | ||
| 3591 | strncpy(ses->serverNOS, | ||
| 3592 | bcc_ptr, len); | ||
| 3593 | bcc_ptr += len; | ||
| 3594 | bcc_ptr[0] = 0; | ||
| 3595 | bcc_ptr++; | ||
| 3596 | |||
| 3597 | len = strnlen(bcc_ptr, 1024); | ||
| 3598 | kfree(ses->serverDomain); | ||
| 3599 | ses->serverDomain = | ||
| 3600 | kzalloc(len+1, | ||
| 3601 | GFP_KERNEL); | ||
| 3602 | strncpy(ses->serverDomain, | ||
| 3603 | bcc_ptr, len); | ||
| 3604 | bcc_ptr += len; | ||
| 3605 | bcc_ptr[0] = 0; | ||
| 3606 | bcc_ptr++; | ||
| 3607 | } else | ||
| 3608 | cFYI(1, ("field of length %d " | ||
| 3609 | "extends beyond end of smb ", | ||
| 3610 | len)); | ||
| 3611 | } | ||
| 3612 | } else { | ||
| 3613 | cERROR(1, ("Security Blob extends beyond end " | ||
| 3614 | "of SMB")); | ||
| 3615 | } | ||
| 3616 | } else { | ||
| 3617 | cERROR(1, ("No session structure passed in.")); | ||
| 3618 | } | ||
| 3619 | } else { | ||
| 3620 | cERROR(1, ("Invalid Word count %d: ", | ||
| 3621 | smb_buffer_response->WordCount)); | ||
| 3622 | rc = -EIO; | ||
| 3623 | } | ||
| 3624 | |||
| 3625 | cifs_buf_release(smb_buffer); | ||
| 3626 | |||
| 3627 | return rc; | ||
| 3628 | } | ||
| 3629 | |||
| 3630 | int | 2615 | int |
| 3631 | CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | 2616 | CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, |
| 3632 | const char *tree, struct cifsTconInfo *tcon, | 2617 | const char *tree, struct cifsTconInfo *tcon, |
| @@ -3638,7 +2623,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3638 | TCONX_RSP *pSMBr; | 2623 | TCONX_RSP *pSMBr; |
| 3639 | unsigned char *bcc_ptr; | 2624 | unsigned char *bcc_ptr; |
| 3640 | int rc = 0; | 2625 | int rc = 0; |
| 3641 | int length; | 2626 | int length, bytes_left; |
| 3642 | __u16 count; | 2627 | __u16 count; |
| 3643 | 2628 | ||
| 3644 | if (ses == NULL) | 2629 | if (ses == NULL) |
| @@ -3726,14 +2711,22 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3726 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 2711 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
| 3727 | CIFS_STD_OP); | 2712 | CIFS_STD_OP); |
| 3728 | 2713 | ||
| 3729 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ | ||
| 3730 | /* above now done in SendReceive */ | 2714 | /* above now done in SendReceive */ |
| 3731 | if ((rc == 0) && (tcon != NULL)) { | 2715 | if ((rc == 0) && (tcon != NULL)) { |
| 2716 | bool is_unicode; | ||
| 2717 | |||
| 3732 | tcon->tidStatus = CifsGood; | 2718 | tcon->tidStatus = CifsGood; |
| 3733 | tcon->need_reconnect = false; | 2719 | tcon->need_reconnect = false; |
| 3734 | tcon->tid = smb_buffer_response->Tid; | 2720 | tcon->tid = smb_buffer_response->Tid; |
| 3735 | bcc_ptr = pByteArea(smb_buffer_response); | 2721 | bcc_ptr = pByteArea(smb_buffer_response); |
| 3736 | length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); | 2722 | bytes_left = BCC(smb_buffer_response); |
| 2723 | length = strnlen(bcc_ptr, bytes_left - 2); | ||
| 2724 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) | ||
| 2725 | is_unicode = true; | ||
| 2726 | else | ||
| 2727 | is_unicode = false; | ||
| 2728 | |||
| 2729 | |||
| 3737 | /* skip service field (NB: this field is always ASCII) */ | 2730 | /* skip service field (NB: this field is always ASCII) */ |
| 3738 | if (length == 3) { | 2731 | if (length == 3) { |
| 3739 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && | 2732 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && |
| @@ -3748,39 +2741,16 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3748 | } | 2741 | } |
| 3749 | } | 2742 | } |
| 3750 | bcc_ptr += length + 1; | 2743 | bcc_ptr += length + 1; |
| 2744 | bytes_left -= (length + 1); | ||
| 3751 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | 2745 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); |
| 3752 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | 2746 | |
| 3753 | length = UniStrnlen((wchar_t *) bcc_ptr, 512); | 2747 | /* mostly informational -- no need to fail on error here */ |
| 3754 | if ((bcc_ptr + (2 * length)) - | 2748 | tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, |
| 3755 | pByteArea(smb_buffer_response) <= | 2749 | bytes_left, is_unicode, |
| 3756 | BCC(smb_buffer_response)) { | 2750 | nls_codepage); |
| 3757 | kfree(tcon->nativeFileSystem); | 2751 | |
| 3758 | tcon->nativeFileSystem = | 2752 | cFYI(1, ("nativeFileSystem=%s", tcon->nativeFileSystem)); |
| 3759 | kzalloc((4 * length) + 2, GFP_KERNEL); | 2753 | |
| 3760 | if (tcon->nativeFileSystem) { | ||
| 3761 | cifs_strfromUCS_le( | ||
| 3762 | tcon->nativeFileSystem, | ||
| 3763 | (__le16 *) bcc_ptr, | ||
| 3764 | length, nls_codepage); | ||
| 3765 | cFYI(1, ("nativeFileSystem=%s", | ||
| 3766 | tcon->nativeFileSystem)); | ||
| 3767 | } | ||
| 3768 | } | ||
| 3769 | /* else do not bother copying these information fields*/ | ||
| 3770 | } else { | ||
| 3771 | length = strnlen(bcc_ptr, 1024); | ||
| 3772 | if ((bcc_ptr + length) - | ||
| 3773 | pByteArea(smb_buffer_response) <= | ||
| 3774 | BCC(smb_buffer_response)) { | ||
| 3775 | kfree(tcon->nativeFileSystem); | ||
| 3776 | tcon->nativeFileSystem = | ||
| 3777 | kzalloc(length + 1, GFP_KERNEL); | ||
| 3778 | if (tcon->nativeFileSystem) | ||
| 3779 | strncpy(tcon->nativeFileSystem, bcc_ptr, | ||
| 3780 | length); | ||
| 3781 | } | ||
| 3782 | /* else do not bother copying these information fields*/ | ||
| 3783 | } | ||
| 3784 | if ((smb_buffer_response->WordCount == 3) || | 2754 | if ((smb_buffer_response->WordCount == 3) || |
| 3785 | (smb_buffer_response->WordCount == 7)) | 2755 | (smb_buffer_response->WordCount == 7)) |
| 3786 | /* field is in same location */ | 2756 | /* field is in same location */ |
| @@ -3819,8 +2789,6 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3819 | struct nls_table *nls_info) | 2789 | struct nls_table *nls_info) |
| 3820 | { | 2790 | { |
| 3821 | int rc = 0; | 2791 | int rc = 0; |
| 3822 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
| 3823 | bool ntlmv2_flag = false; | ||
| 3824 | int first_time = 0; | 2792 | int first_time = 0; |
| 3825 | struct TCP_Server_Info *server = pSesInfo->server; | 2793 | struct TCP_Server_Info *server = pSesInfo->server; |
| 3826 | 2794 | ||
| @@ -3852,83 +2820,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3852 | pSesInfo->capabilities = server->capabilities; | 2820 | pSesInfo->capabilities = server->capabilities; |
| 3853 | if (linuxExtEnabled == 0) | 2821 | if (linuxExtEnabled == 0) |
| 3854 | pSesInfo->capabilities &= (~CAP_UNIX); | 2822 | pSesInfo->capabilities &= (~CAP_UNIX); |
| 3855 | /* pSesInfo->sequence_number = 0;*/ | 2823 | |
| 3856 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 2824 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
| 3857 | server->secMode, server->capabilities, server->timeAdj)); | 2825 | server->secMode, server->capabilities, server->timeAdj)); |
| 3858 | 2826 | ||
| 3859 | if (experimEnabled < 2) | 2827 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); |
| 3860 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); | ||
| 3861 | else if (extended_security | ||
| 3862 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
| 3863 | && (server->secType == NTLMSSP)) { | ||
| 3864 | rc = -EOPNOTSUPP; | ||
| 3865 | } else if (extended_security | ||
| 3866 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
| 3867 | && (server->secType == RawNTLMSSP)) { | ||
| 3868 | cFYI(1, ("NTLMSSP sesssetup")); | ||
| 3869 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag, | ||
| 3870 | nls_info); | ||
| 3871 | if (!rc) { | ||
| 3872 | if (ntlmv2_flag) { | ||
| 3873 | char *v2_response; | ||
| 3874 | cFYI(1, ("more secure NTLM ver2 hash")); | ||
| 3875 | if (CalcNTLMv2_partial_mac_key(pSesInfo, | ||
| 3876 | nls_info)) { | ||
| 3877 | rc = -ENOMEM; | ||
| 3878 | goto ss_err_exit; | ||
| 3879 | } else | ||
| 3880 | v2_response = kmalloc(16 + 64 /* blob*/, | ||
| 3881 | GFP_KERNEL); | ||
| 3882 | if (v2_response) { | ||
| 3883 | CalcNTLMv2_response(pSesInfo, | ||
| 3884 | v2_response); | ||
| 3885 | /* if (first_time) | ||
| 3886 | cifs_calculate_ntlmv2_mac_key */ | ||
| 3887 | kfree(v2_response); | ||
| 3888 | /* BB Put dummy sig in SessSetup PDU? */ | ||
| 3889 | } else { | ||
| 3890 | rc = -ENOMEM; | ||
| 3891 | goto ss_err_exit; | ||
| 3892 | } | ||
| 3893 | |||
| 3894 | } else { | ||
| 3895 | SMBNTencrypt(pSesInfo->password, | ||
| 3896 | server->cryptKey, | ||
| 3897 | ntlm_session_key); | ||
| 3898 | |||
| 3899 | if (first_time) | ||
| 3900 | cifs_calculate_mac_key( | ||
| 3901 | &server->mac_signing_key, | ||
| 3902 | ntlm_session_key, | ||
| 3903 | pSesInfo->password); | ||
| 3904 | } | ||
| 3905 | /* for better security the weaker lanman hash not sent | ||
| 3906 | in AuthSessSetup so we no longer calculate it */ | ||
| 3907 | |||
| 3908 | rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo, | ||
| 3909 | ntlm_session_key, | ||
| 3910 | ntlmv2_flag, | ||
| 3911 | nls_info); | ||
| 3912 | } | ||
| 3913 | } else { /* old style NTLM 0.12 session setup */ | ||
| 3914 | SMBNTencrypt(pSesInfo->password, server->cryptKey, | ||
| 3915 | ntlm_session_key); | ||
| 3916 | |||
| 3917 | if (first_time) | ||
| 3918 | cifs_calculate_mac_key(&server->mac_signing_key, | ||
| 3919 | ntlm_session_key, | ||
| 3920 | pSesInfo->password); | ||
| 3921 | |||
| 3922 | rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); | ||
| 3923 | } | ||
| 3924 | if (rc) { | 2828 | if (rc) { |
| 3925 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 2829 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
| 3926 | } else { | 2830 | } else { |
| 3927 | cFYI(1, ("CIFS Session Established successfully")); | 2831 | cFYI(1, ("CIFS Session Established successfully")); |
| 3928 | spin_lock(&GlobalMid_Lock); | 2832 | spin_lock(&GlobalMid_Lock); |
| 3929 | pSesInfo->status = CifsGood; | 2833 | pSesInfo->status = CifsGood; |
| 3930 | pSesInfo->need_reconnect = false; | 2834 | pSesInfo->need_reconnect = false; |
| 3931 | spin_unlock(&GlobalMid_Lock); | 2835 | spin_unlock(&GlobalMid_Lock); |
| 3932 | } | 2836 | } |
| 3933 | 2837 | ||
| 3934 | ss_err_exit: | 2838 | ss_err_exit: |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 461750e0136..11431ed72a7 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -281,6 +281,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 281 | int create_options = CREATE_NOT_DIR; | 281 | int create_options = CREATE_NOT_DIR; |
| 282 | int oplock = 0; | 282 | int oplock = 0; |
| 283 | int oflags; | 283 | int oflags; |
| 284 | bool posix_create = false; | ||
| 284 | /* | 285 | /* |
| 285 | * BB below access is probably too much for mknod to request | 286 | * BB below access is probably too much for mknod to request |
| 286 | * but we have to do query and setpathinfo so requesting | 287 | * but we have to do query and setpathinfo so requesting |
| @@ -328,11 +329,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 328 | negotation. EREMOTE indicates DFS junction, which is not | 329 | negotation. EREMOTE indicates DFS junction, which is not |
| 329 | handled in posix open */ | 330 | handled in posix open */ |
| 330 | 331 | ||
| 331 | if ((rc == 0) && (newinode == NULL)) | 332 | if (rc == 0) { |
| 332 | goto cifs_create_get_file_info; /* query inode info */ | 333 | posix_create = true; |
| 333 | else if (rc == 0) /* success, no need to query */ | 334 | if (newinode == NULL) /* query inode info */ |
| 334 | goto cifs_create_set_dentry; | 335 | goto cifs_create_get_file_info; |
| 335 | else if ((rc != -EIO) && (rc != -EREMOTE) && | 336 | else /* success, no need to query */ |
| 337 | goto cifs_create_set_dentry; | ||
| 338 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | ||
| 336 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | 339 | (rc != -EOPNOTSUPP)) /* path not found or net err */ |
| 337 | goto cifs_create_out; | 340 | goto cifs_create_out; |
| 338 | /* else fallthrough to retry, using older open call, this is | 341 | /* else fallthrough to retry, using older open call, this is |
| @@ -464,7 +467,7 @@ cifs_create_set_dentry: | |||
| 464 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { | 467 | if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) { |
| 465 | /* mknod case - do not leave file open */ | 468 | /* mknod case - do not leave file open */ |
| 466 | CIFSSMBClose(xid, tcon, fileHandle); | 469 | CIFSSMBClose(xid, tcon, fileHandle); |
| 467 | } else if (newinode) { | 470 | } else if (!(posix_create) && (newinode)) { |
| 468 | cifs_fill_fileinfo(newinode, fileHandle, | 471 | cifs_fill_fileinfo(newinode, fileHandle, |
| 469 | cifs_sb->tcon, write_only); | 472 | cifs_sb->tcon, write_only); |
| 470 | } | 473 | } |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 50ca088d886..38c06f82657 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -129,15 +129,12 @@ static inline int cifs_posix_open_inode_helper(struct inode *inode, | |||
| 129 | struct file *file, struct cifsInodeInfo *pCifsInode, | 129 | struct file *file, struct cifsInodeInfo *pCifsInode, |
| 130 | struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) | 130 | struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) |
| 131 | { | 131 | { |
| 132 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 133 | /* struct timespec temp; */ /* BB REMOVEME BB */ | ||
| 134 | 132 | ||
| 135 | file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 133 | file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
| 136 | if (file->private_data == NULL) | 134 | if (file->private_data == NULL) |
| 137 | return -ENOMEM; | 135 | return -ENOMEM; |
| 138 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | 136 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); |
| 139 | write_lock(&GlobalSMBSeslock); | 137 | write_lock(&GlobalSMBSeslock); |
| 140 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | ||
| 141 | 138 | ||
| 142 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 139 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
| 143 | if (pCifsInode == NULL) { | 140 | if (pCifsInode == NULL) { |
| @@ -145,17 +142,6 @@ static inline int cifs_posix_open_inode_helper(struct inode *inode, | |||
| 145 | return -EINVAL; | 142 | return -EINVAL; |
| 146 | } | 143 | } |
| 147 | 144 | ||
| 148 | /* want handles we can use to read with first | ||
| 149 | in the list so we do not have to walk the | ||
| 150 | list to search for one in write_begin */ | ||
| 151 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
| 152 | list_add_tail(&pCifsFile->flist, | ||
| 153 | &pCifsInode->openFileList); | ||
| 154 | } else { | ||
| 155 | list_add(&pCifsFile->flist, | ||
| 156 | &pCifsInode->openFileList); | ||
| 157 | } | ||
| 158 | |||
| 159 | if (pCifsInode->clientCanCacheRead) { | 145 | if (pCifsInode->clientCanCacheRead) { |
| 160 | /* we have the inode open somewhere else | 146 | /* we have the inode open somewhere else |
| 161 | no need to discard cache data */ | 147 | no need to discard cache data */ |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index f36b4e40e44..9c869a6dcba 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -962,13 +962,21 @@ undo_setattr: | |||
| 962 | goto out_close; | 962 | goto out_close; |
| 963 | } | 963 | } |
| 964 | 964 | ||
| 965 | |||
| 966 | /* | ||
| 967 | * If dentry->d_inode is null (usually meaning the cached dentry | ||
| 968 | * is a negative dentry) then we would attempt a standard SMB delete, but | ||
| 969 | * if that fails we can not attempt the fall back mechanisms on EACESS | ||
| 970 | * but will return the EACESS to the caller. Note that the VFS does not call | ||
| 971 | * unlink on negative dentries currently. | ||
| 972 | */ | ||
| 965 | int cifs_unlink(struct inode *dir, struct dentry *dentry) | 973 | int cifs_unlink(struct inode *dir, struct dentry *dentry) |
| 966 | { | 974 | { |
| 967 | int rc = 0; | 975 | int rc = 0; |
| 968 | int xid; | 976 | int xid; |
| 969 | char *full_path = NULL; | 977 | char *full_path = NULL; |
| 970 | struct inode *inode = dentry->d_inode; | 978 | struct inode *inode = dentry->d_inode; |
| 971 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | 979 | struct cifsInodeInfo *cifs_inode; |
| 972 | struct super_block *sb = dir->i_sb; | 980 | struct super_block *sb = dir->i_sb; |
| 973 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 981 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
| 974 | struct cifsTconInfo *tcon = cifs_sb->tcon; | 982 | struct cifsTconInfo *tcon = cifs_sb->tcon; |
| @@ -1012,7 +1020,7 @@ psx_del_no_retry: | |||
| 1012 | rc = cifs_rename_pending_delete(full_path, dentry, xid); | 1020 | rc = cifs_rename_pending_delete(full_path, dentry, xid); |
| 1013 | if (rc == 0) | 1021 | if (rc == 0) |
| 1014 | drop_nlink(inode); | 1022 | drop_nlink(inode); |
| 1015 | } else if (rc == -EACCES && dosattr == 0) { | 1023 | } else if ((rc == -EACCES) && (dosattr == 0) && inode) { |
| 1016 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); | 1024 | attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); |
| 1017 | if (attrs == NULL) { | 1025 | if (attrs == NULL) { |
| 1018 | rc = -ENOMEM; | 1026 | rc = -ENOMEM; |
| @@ -1020,7 +1028,8 @@ psx_del_no_retry: | |||
| 1020 | } | 1028 | } |
| 1021 | 1029 | ||
| 1022 | /* try to reset dos attributes */ | 1030 | /* try to reset dos attributes */ |
| 1023 | origattr = cifsInode->cifsAttrs; | 1031 | cifs_inode = CIFS_I(inode); |
| 1032 | origattr = cifs_inode->cifsAttrs; | ||
| 1024 | if (origattr == 0) | 1033 | if (origattr == 0) |
| 1025 | origattr |= ATTR_NORMAL; | 1034 | origattr |= ATTR_NORMAL; |
| 1026 | dosattr = origattr & ~ATTR_READONLY; | 1035 | dosattr = origattr & ~ATTR_READONLY; |
| @@ -1041,13 +1050,13 @@ psx_del_no_retry: | |||
| 1041 | 1050 | ||
| 1042 | out_reval: | 1051 | out_reval: |
| 1043 | if (inode) { | 1052 | if (inode) { |
| 1044 | cifsInode = CIFS_I(inode); | 1053 | cifs_inode = CIFS_I(inode); |
| 1045 | cifsInode->time = 0; /* will force revalidate to get info | 1054 | cifs_inode->time = 0; /* will force revalidate to get info |
| 1046 | when needed */ | 1055 | when needed */ |
| 1047 | inode->i_ctime = current_fs_time(sb); | 1056 | inode->i_ctime = current_fs_time(sb); |
| 1048 | } | 1057 | } |
| 1049 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); | 1058 | dir->i_ctime = dir->i_mtime = current_fs_time(sb); |
| 1050 | cifsInode = CIFS_I(dir); | 1059 | cifs_inode = CIFS_I(dir); |
| 1051 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ | 1060 | CIFS_I(dir)->time = 0; /* force revalidate of dir as well */ |
| 1052 | 1061 | ||
| 1053 | kfree(full_path); | 1062 | kfree(full_path); |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 63f644000ce..ea9d11e3dcb 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -119,16 +119,11 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
| 119 | full_path = build_path_from_dentry(direntry); | 119 | full_path = build_path_from_dentry(direntry); |
| 120 | 120 | ||
| 121 | if (!full_path) | 121 | if (!full_path) |
| 122 | goto out_no_free; | 122 | goto out; |
| 123 | 123 | ||
| 124 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); | 124 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); |
| 125 | cifs_sb = CIFS_SB(inode->i_sb); | 125 | cifs_sb = CIFS_SB(inode->i_sb); |
| 126 | pTcon = cifs_sb->tcon; | 126 | pTcon = cifs_sb->tcon; |
| 127 | target_path = kmalloc(PATH_MAX, GFP_KERNEL); | ||
| 128 | if (!target_path) { | ||
| 129 | target_path = ERR_PTR(-ENOMEM); | ||
| 130 | goto out; | ||
| 131 | } | ||
| 132 | 127 | ||
| 133 | /* We could change this to: | 128 | /* We could change this to: |
| 134 | if (pTcon->unix_ext) | 129 | if (pTcon->unix_ext) |
| @@ -138,8 +133,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
| 138 | 133 | ||
| 139 | if (pTcon->ses->capabilities & CAP_UNIX) | 134 | if (pTcon->ses->capabilities & CAP_UNIX) |
| 140 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, | 135 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, |
| 141 | target_path, | 136 | &target_path, |
| 142 | PATH_MAX-1, | ||
| 143 | cifs_sb->local_nls); | 137 | cifs_sb->local_nls); |
| 144 | else { | 138 | else { |
| 145 | /* BB add read reparse point symlink code here */ | 139 | /* BB add read reparse point symlink code here */ |
| @@ -148,22 +142,16 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd) | |||
| 148 | /* BB Add MAC style xsymlink check here if enabled */ | 142 | /* BB Add MAC style xsymlink check here if enabled */ |
| 149 | } | 143 | } |
| 150 | 144 | ||
| 151 | if (rc == 0) { | 145 | if (rc != 0) { |
| 152 | |||
| 153 | /* BB Add special case check for Samba DFS symlinks */ | ||
| 154 | |||
| 155 | target_path[PATH_MAX-1] = 0; | ||
| 156 | } else { | ||
| 157 | kfree(target_path); | 146 | kfree(target_path); |
| 158 | target_path = ERR_PTR(rc); | 147 | target_path = ERR_PTR(rc); |
| 159 | } | 148 | } |
| 160 | 149 | ||
| 161 | out: | ||
| 162 | kfree(full_path); | 150 | kfree(full_path); |
| 163 | out_no_free: | 151 | out: |
| 164 | FreeXid(xid); | 152 | FreeXid(xid); |
| 165 | nd_set_link(nd, target_path); | 153 | nd_set_link(nd, target_path); |
| 166 | return NULL; /* No cookie */ | 154 | return NULL; |
| 167 | } | 155 | } |
| 168 | 156 | ||
| 169 | int | 157 | int |
| @@ -224,98 +212,6 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
| 224 | return rc; | 212 | return rc; |
| 225 | } | 213 | } |
| 226 | 214 | ||
| 227 | int | ||
| 228 | cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) | ||
| 229 | { | ||
| 230 | struct inode *inode = direntry->d_inode; | ||
| 231 | int rc = -EACCES; | ||
| 232 | int xid; | ||
| 233 | int oplock = 0; | ||
| 234 | struct cifs_sb_info *cifs_sb; | ||
| 235 | struct cifsTconInfo *pTcon; | ||
| 236 | char *full_path = NULL; | ||
| 237 | char *tmpbuffer; | ||
| 238 | int len; | ||
| 239 | __u16 fid; | ||
| 240 | |||
| 241 | xid = GetXid(); | ||
| 242 | cifs_sb = CIFS_SB(inode->i_sb); | ||
| 243 | pTcon = cifs_sb->tcon; | ||
| 244 | |||
| 245 | /* BB would it be safe against deadlock to grab this sem | ||
| 246 | even though rename itself grabs the sem and calls lookup? */ | ||
| 247 | /* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/ | ||
| 248 | full_path = build_path_from_dentry(direntry); | ||
| 249 | /* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/ | ||
| 250 | |||
| 251 | if (full_path == NULL) { | ||
| 252 | FreeXid(xid); | ||
| 253 | return -ENOMEM; | ||
| 254 | } | ||
| 255 | |||
| 256 | cFYI(1, | ||
| 257 | ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", | ||
| 258 | full_path, inode, pBuffer, buflen)); | ||
| 259 | if (buflen > PATH_MAX) | ||
| 260 | len = PATH_MAX; | ||
| 261 | else | ||
| 262 | len = buflen; | ||
| 263 | tmpbuffer = kmalloc(len, GFP_KERNEL); | ||
| 264 | if (tmpbuffer == NULL) { | ||
| 265 | kfree(full_path); | ||
| 266 | FreeXid(xid); | ||
| 267 | return -ENOMEM; | ||
| 268 | } | ||
| 269 | |||
| 270 | /* BB add read reparse point symlink code and | ||
| 271 | Unix extensions symlink code here BB */ | ||
| 272 | /* We could disable this based on pTcon->unix_ext flag instead ... but why? */ | ||
| 273 | if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) | ||
| 274 | rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, | ||
| 275 | tmpbuffer, | ||
| 276 | len - 1, | ||
| 277 | cifs_sb->local_nls); | ||
| 278 | else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
| 279 | cERROR(1, ("SFU style symlinks not implemented yet")); | ||
| 280 | /* add open and read as in fs/cifs/inode.c */ | ||
| 281 | } else { | ||
| 282 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, | ||
| 283 | OPEN_REPARSE_POINT, &fid, &oplock, NULL, | ||
| 284 | cifs_sb->local_nls, | ||
| 285 | cifs_sb->mnt_cifs_flags & | ||
| 286 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 287 | if (!rc) { | ||
| 288 | rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, | ||
| 289 | tmpbuffer, | ||
| 290 | len - 1, | ||
| 291 | fid, | ||
| 292 | cifs_sb->local_nls); | ||
| 293 | if (CIFSSMBClose(xid, pTcon, fid)) { | ||
| 294 | cFYI(1, ("Error closing junction point " | ||
| 295 | "(open for ioctl)")); | ||
| 296 | } | ||
| 297 | /* If it is a DFS junction earlier we would have gotten | ||
| 298 | PATH_NOT_COVERED returned from server so we do | ||
| 299 | not need to request the DFS info here */ | ||
| 300 | } | ||
| 301 | } | ||
| 302 | /* BB Anything else to do to handle recursive links? */ | ||
| 303 | /* BB Should we be using page ops here? */ | ||
| 304 | |||
| 305 | /* BB null terminate returned string in pBuffer? BB */ | ||
| 306 | if (rc == 0) { | ||
| 307 | rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); | ||
| 308 | cFYI(1, | ||
| 309 | ("vfs_readlink called from cifs_readlink returned %d", | ||
| 310 | rc)); | ||
| 311 | } | ||
| 312 | |||
| 313 | kfree(tmpbuffer); | ||
| 314 | kfree(full_path); | ||
| 315 | FreeXid(xid); | ||
| 316 | return rc; | ||
| 317 | } | ||
| 318 | |||
| 319 | void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) | 215 | void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) |
| 320 | { | 216 | { |
| 321 | char *p = nd_get_link(nd); | 217 | char *p = nd_get_link(nd); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 4c89c572891..e079a9190ec 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -635,77 +635,6 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) | |||
| 635 | return; | 635 | return; |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | /* Windows maps these to the user defined 16 bit Unicode range since they are | ||
| 639 | reserved symbols (along with \ and /), otherwise illegal to store | ||
| 640 | in filenames in NTFS */ | ||
| 641 | #define UNI_ASTERIK (__u16) ('*' + 0xF000) | ||
| 642 | #define UNI_QUESTION (__u16) ('?' + 0xF000) | ||
| 643 | #define UNI_COLON (__u16) (':' + 0xF000) | ||
| 644 | #define UNI_GRTRTHAN (__u16) ('>' + 0xF000) | ||
| 645 | #define UNI_LESSTHAN (__u16) ('<' + 0xF000) | ||
| 646 | #define UNI_PIPE (__u16) ('|' + 0xF000) | ||
| 647 | #define UNI_SLASH (__u16) ('\\' + 0xF000) | ||
| 648 | |||
| 649 | /* Convert 16 bit Unicode pathname from wire format to string in current code | ||
| 650 | page. Conversion may involve remapping up the seven characters that are | ||
| 651 | only legal in POSIX-like OS (if they are present in the string). Path | ||
| 652 | names are little endian 16 bit Unicode on the wire */ | ||
| 653 | int | ||
| 654 | cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, | ||
| 655 | const struct nls_table *cp) | ||
| 656 | { | ||
| 657 | int i, j, len; | ||
| 658 | __u16 src_char; | ||
| 659 | |||
| 660 | for (i = 0, j = 0; i < maxlen; i++) { | ||
| 661 | src_char = le16_to_cpu(source[i]); | ||
| 662 | switch (src_char) { | ||
| 663 | case 0: | ||
| 664 | goto cUCS_out; /* BB check this BB */ | ||
| 665 | case UNI_COLON: | ||
| 666 | target[j] = ':'; | ||
| 667 | break; | ||
| 668 | case UNI_ASTERIK: | ||
| 669 | target[j] = '*'; | ||
| 670 | break; | ||
| 671 | case UNI_QUESTION: | ||
| 672 | target[j] = '?'; | ||
| 673 | break; | ||
| 674 | /* BB We can not handle remapping slash until | ||
| 675 | all the calls to build_path_from_dentry | ||
| 676 | are modified, as they use slash as separator BB */ | ||
| 677 | /* case UNI_SLASH: | ||
| 678 | target[j] = '\\'; | ||
| 679 | break;*/ | ||
| 680 | case UNI_PIPE: | ||
| 681 | target[j] = '|'; | ||
| 682 | break; | ||
| 683 | case UNI_GRTRTHAN: | ||
| 684 | target[j] = '>'; | ||
| 685 | break; | ||
| 686 | case UNI_LESSTHAN: | ||
| 687 | target[j] = '<'; | ||
| 688 | break; | ||
| 689 | default: | ||
| 690 | len = cp->uni2char(src_char, &target[j], | ||
| 691 | NLS_MAX_CHARSET_SIZE); | ||
| 692 | if (len > 0) { | ||
| 693 | j += len; | ||
| 694 | continue; | ||
| 695 | } else { | ||
| 696 | target[j] = '?'; | ||
| 697 | } | ||
| 698 | } | ||
| 699 | j++; | ||
| 700 | /* make sure we do not overrun callers allocated temp buffer */ | ||
| 701 | if (j >= (2 * NAME_MAX)) | ||
| 702 | break; | ||
| 703 | } | ||
| 704 | cUCS_out: | ||
| 705 | target[j] = 0; | ||
| 706 | return j; | ||
| 707 | } | ||
| 708 | |||
| 709 | /* Convert 16 bit Unicode pathname to wire format from string in current code | 638 | /* Convert 16 bit Unicode pathname to wire format from string in current code |
| 710 | page. Conversion may involve remapping up the seven characters that are | 639 | page. Conversion may involve remapping up the seven characters that are |
| 711 | only legal in POSIX-like OS (if they are present in the string). Path | 640 | only legal in POSIX-like OS (if they are present in the string). Path |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 8703d68f5b2..e2fe998989a 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
| @@ -79,6 +79,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { | |||
| 79 | {ErrQuota, -EDQUOT}, | 79 | {ErrQuota, -EDQUOT}, |
| 80 | {ErrNotALink, -ENOLINK}, | 80 | {ErrNotALink, -ENOLINK}, |
| 81 | {ERRnetlogonNotStarted, -ENOPROTOOPT}, | 81 | {ERRnetlogonNotStarted, -ENOPROTOOPT}, |
| 82 | {ERRsymlink, -EOPNOTSUPP}, | ||
| 82 | {ErrTooManyLinks, -EMLINK}, | 83 | {ErrTooManyLinks, -EMLINK}, |
| 83 | {0, 0} | 84 | {0, 0} |
| 84 | }; | 85 | }; |
| @@ -714,6 +715,7 @@ static const struct { | |||
| 714 | ERRDOS, ERRnoaccess, 0xc000028f}, { | 715 | ERRDOS, ERRnoaccess, 0xc000028f}, { |
| 715 | ERRDOS, ERRnoaccess, 0xc0000290}, { | 716 | ERRDOS, ERRnoaccess, 0xc0000290}, { |
| 716 | ERRDOS, ERRbadfunc, 0xc000029c}, { | 717 | ERRDOS, ERRbadfunc, 0xc000029c}, { |
| 718 | ERRDOS, ERRsymlink, NT_STATUS_STOPPED_ON_SYMLINK}, { | ||
| 717 | ERRDOS, ERRinvlevel, 0x007c0001}, }; | 719 | ERRDOS, ERRinvlevel, 0x007c0001}, }; |
| 718 | 720 | ||
| 719 | /***************************************************************************** | 721 | /***************************************************************************** |
diff --git a/fs/cifs/nterr.h b/fs/cifs/nterr.h index 588abbb9d08..257267367d4 100644 --- a/fs/cifs/nterr.h +++ b/fs/cifs/nterr.h | |||
| @@ -35,8 +35,6 @@ struct nt_err_code_struct { | |||
| 35 | extern const struct nt_err_code_struct nt_errs[]; | 35 | extern const struct nt_err_code_struct nt_errs[]; |
| 36 | 36 | ||
| 37 | /* Win32 Status codes. */ | 37 | /* Win32 Status codes. */ |
| 38 | |||
| 39 | #define STATUS_BUFFER_OVERFLOW 0x80000005 | ||
| 40 | #define STATUS_MORE_ENTRIES 0x0105 | 38 | #define STATUS_MORE_ENTRIES 0x0105 |
| 41 | #define ERROR_INVALID_PARAMETER 0x0057 | 39 | #define ERROR_INVALID_PARAMETER 0x0057 |
| 42 | #define ERROR_INSUFFICIENT_BUFFER 0x007a | 40 | #define ERROR_INSUFFICIENT_BUFFER 0x007a |
| @@ -50,6 +48,13 @@ extern const struct nt_err_code_struct nt_errs[]; | |||
| 50 | #define STATUS_SOME_UNMAPPED 0x0107 | 48 | #define STATUS_SOME_UNMAPPED 0x0107 |
| 51 | #define STATUS_BUFFER_OVERFLOW 0x80000005 | 49 | #define STATUS_BUFFER_OVERFLOW 0x80000005 |
| 52 | #define NT_STATUS_NO_MORE_ENTRIES 0x8000001a | 50 | #define NT_STATUS_NO_MORE_ENTRIES 0x8000001a |
| 51 | #define NT_STATUS_MEDIA_CHANGED 0x8000001c | ||
| 52 | #define NT_STATUS_END_OF_MEDIA 0x8000001e | ||
| 53 | #define NT_STATUS_MEDIA_CHECK 0x80000020 | ||
| 54 | #define NT_STATUS_NO_DATA_DETECTED 0x8000001c | ||
| 55 | #define NT_STATUS_STOPPED_ON_SYMLINK 0x8000002d | ||
| 56 | #define NT_STATUS_DEVICE_REQUIRES_CLEANING 0x80000288 | ||
| 57 | #define NT_STATUS_DEVICE_DOOR_OPEN 0x80000288 | ||
| 53 | #define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 | 58 | #define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 |
| 54 | #define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 | 59 | #define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 |
| 55 | #define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 | 60 | #define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index c377d8065d9..49c9a4e7531 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
| @@ -27,29 +27,39 @@ | |||
| 27 | #define UnknownMessage cpu_to_le32(8) | 27 | #define UnknownMessage cpu_to_le32(8) |
| 28 | 28 | ||
| 29 | /* Negotiate Flags */ | 29 | /* Negotiate Flags */ |
| 30 | #define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are in unicode */ | 30 | #define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are unicode */ |
| 31 | #define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */ | 31 | #define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */ |
| 32 | #define NTLMSSP_REQUEST_TARGET 0x04 /* Server return its auth realm */ | 32 | #define NTLMSSP_REQUEST_TARGET 0x04 /* Srv returns its auth realm */ |
| 33 | #define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signature capability */ | 33 | /* define reserved9 0x08 */ |
| 34 | #define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */ | 34 | #define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signing capability */ |
| 35 | #define NTLMSSP_NEGOTIATE_DGRAM 0x0040 | 35 | #define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */ |
| 36 | #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Sign/seal use LM session key */ | 36 | #define NTLMSSP_NEGOTIATE_DGRAM 0x0040 |
| 37 | #define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */ | 37 | #define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Use LM session key */ |
| 38 | #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 | 38 | /* defined reserved 8 0x0100 */ |
| 39 | #define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */ | ||
| 40 | #define NTLMSSP_NEGOTIATE_NT_ONLY 0x0400 /* Lanman not allowed */ | ||
| 41 | #define NTLMSSP_ANONYMOUS 0x0800 | ||
| 42 | #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 /* reserved6 */ | ||
| 39 | #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 | 43 | #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 |
| 40 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server on same machine */ | 44 | #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server same machine */ |
| 41 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */ | 45 | #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign. All security levels */ |
| 42 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 | 46 | #define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 |
| 43 | #define NTLMSSP_TARGET_TYPE_SERVER 0x20000 | 47 | #define NTLMSSP_TARGET_TYPE_SERVER 0x20000 |
| 44 | #define NTLMSSP_TARGET_TYPE_SHARE 0x40000 | 48 | #define NTLMSSP_TARGET_TYPE_SHARE 0x40000 |
| 45 | #define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 | 49 | #define NTLMSSP_NEGOTIATE_EXTENDED_SEC 0x80000 /* NB:not related to NTLMv2 pwd*/ |
| 46 | #define NTLMSSP_REQUEST_INIT_RESP 0x100000 | 50 | /* #define NTLMSSP_REQUEST_INIT_RESP 0x100000 */ |
| 47 | #define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 | 51 | #define NTLMSSP_NEGOTIATE_IDENTIFY 0x100000 |
| 48 | #define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 | 52 | #define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 /* reserved5 */ |
| 53 | #define NTLMSSP_REQUEST_NON_NT_KEY 0x400000 | ||
| 49 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 | 54 | #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 |
| 50 | #define NTLMSSP_NEGOTIATE_128 0x20000000 | 55 | /* #define reserved4 0x1000000 */ |
| 51 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | 56 | #define NTLMSSP_NEGOTIATE_VERSION 0x2000000 /* we do not set */ |
| 52 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | 57 | /* #define reserved3 0x4000000 */ |
| 58 | /* #define reserved2 0x8000000 */ | ||
| 59 | /* #define reserved1 0x10000000 */ | ||
| 60 | #define NTLMSSP_NEGOTIATE_128 0x20000000 | ||
| 61 | #define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 | ||
| 62 | #define NTLMSSP_NEGOTIATE_56 0x80000000 | ||
| 53 | 63 | ||
| 54 | /* Although typedefs are not commonly used for structure definitions */ | 64 | /* Although typedefs are not commonly used for structure definitions */ |
| 55 | /* in the Linux kernel, in this particular case they are useful */ | 65 | /* in the Linux kernel, in this particular case they are useful */ |
| @@ -60,32 +70,36 @@ | |||
| 60 | typedef struct _SECURITY_BUFFER { | 70 | typedef struct _SECURITY_BUFFER { |
| 61 | __le16 Length; | 71 | __le16 Length; |
| 62 | __le16 MaximumLength; | 72 | __le16 MaximumLength; |
| 63 | __le32 Buffer; /* offset to buffer */ | 73 | __le32 BufferOffset; /* offset to buffer */ |
| 64 | } __attribute__((packed)) SECURITY_BUFFER; | 74 | } __attribute__((packed)) SECURITY_BUFFER; |
| 65 | 75 | ||
| 66 | typedef struct _NEGOTIATE_MESSAGE { | 76 | typedef struct _NEGOTIATE_MESSAGE { |
| 67 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; | 77 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; |
| 68 | __le32 MessageType; /* 1 */ | 78 | __le32 MessageType; /* NtLmNegotiate = 1 */ |
| 69 | __le32 NegotiateFlags; | 79 | __le32 NegotiateFlags; |
| 70 | SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ | 80 | SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ |
| 71 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ | 81 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ |
| 82 | /* SECURITY_BUFFER for version info not present since we | ||
| 83 | do not set the version is present flag */ | ||
| 72 | char DomainString[0]; | 84 | char DomainString[0]; |
| 73 | /* followed by WorkstationString */ | 85 | /* followed by WorkstationString */ |
| 74 | } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; | 86 | } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; |
| 75 | 87 | ||
| 76 | typedef struct _CHALLENGE_MESSAGE { | 88 | typedef struct _CHALLENGE_MESSAGE { |
| 77 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; | 89 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; |
| 78 | __le32 MessageType; /* 2 */ | 90 | __le32 MessageType; /* NtLmChallenge = 2 */ |
| 79 | SECURITY_BUFFER TargetName; | 91 | SECURITY_BUFFER TargetName; |
| 80 | __le32 NegotiateFlags; | 92 | __le32 NegotiateFlags; |
| 81 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; | 93 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; |
| 82 | __u8 Reserved[8]; | 94 | __u8 Reserved[8]; |
| 83 | SECURITY_BUFFER TargetInfoArray; | 95 | SECURITY_BUFFER TargetInfoArray; |
| 96 | /* SECURITY_BUFFER for version info not present since we | ||
| 97 | do not set the version is present flag */ | ||
| 84 | } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; | 98 | } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; |
| 85 | 99 | ||
| 86 | typedef struct _AUTHENTICATE_MESSAGE { | 100 | typedef struct _AUTHENTICATE_MESSAGE { |
| 87 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 101 | __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; |
| 88 | __le32 MessageType; /* 3 */ | 102 | __le32 MessageType; /* NtLmsAuthenticate = 3 */ |
| 89 | SECURITY_BUFFER LmChallengeResponse; | 103 | SECURITY_BUFFER LmChallengeResponse; |
| 90 | SECURITY_BUFFER NtChallengeResponse; | 104 | SECURITY_BUFFER NtChallengeResponse; |
| 91 | SECURITY_BUFFER DomainName; | 105 | SECURITY_BUFFER DomainName; |
| @@ -93,5 +107,7 @@ typedef struct _AUTHENTICATE_MESSAGE { | |||
| 93 | SECURITY_BUFFER WorkstationName; | 107 | SECURITY_BUFFER WorkstationName; |
| 94 | SECURITY_BUFFER SessionKey; | 108 | SECURITY_BUFFER SessionKey; |
| 95 | __le32 NegotiateFlags; | 109 | __le32 NegotiateFlags; |
| 110 | /* SECURITY_BUFFER for version info not present since we | ||
| 111 | do not set the version is present flag */ | ||
| 96 | char UserString[0]; | 112 | char UserString[0]; |
| 97 | } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; | 113 | } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 1a8be622833..964e097c820 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -31,6 +31,13 @@ | |||
| 31 | #include "cifs_fs_sb.h" | 31 | #include "cifs_fs_sb.h" |
| 32 | #include "cifsfs.h" | 32 | #include "cifsfs.h" |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * To be safe - for UCS to UTF-8 with strings loaded with the rare long | ||
| 36 | * characters alloc more to account for such multibyte target UTF-8 | ||
| 37 | * characters. | ||
| 38 | */ | ||
| 39 | #define UNICODE_NAME_MAX ((4 * NAME_MAX) + 2) | ||
| 40 | |||
| 34 | #ifdef CONFIG_CIFS_DEBUG2 | 41 | #ifdef CONFIG_CIFS_DEBUG2 |
| 35 | static void dump_cifs_file_struct(struct file *file, char *label) | 42 | static void dump_cifs_file_struct(struct file *file, char *label) |
| 36 | { | 43 | { |
| @@ -438,6 +445,38 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
| 438 | } | 445 | } |
| 439 | } | 446 | } |
| 440 | 447 | ||
| 448 | /* BB eventually need to add the following helper function to | ||
| 449 | resolve NT_STATUS_STOPPED_ON_SYMLINK return code when | ||
| 450 | we try to do FindFirst on (NTFS) directory symlinks */ | ||
| 451 | /* | ||
| 452 | int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, | ||
| 453 | int xid) | ||
| 454 | { | ||
| 455 | __u16 fid; | ||
| 456 | int len; | ||
| 457 | int oplock = 0; | ||
| 458 | int rc; | ||
| 459 | struct cifsTconInfo *ptcon = cifs_sb->tcon; | ||
| 460 | char *tmpbuffer; | ||
| 461 | |||
| 462 | rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ, | ||
| 463 | OPEN_REPARSE_POINT, &fid, &oplock, NULL, | ||
| 464 | cifs_sb->local_nls, | ||
| 465 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 466 | if (!rc) { | ||
| 467 | tmpbuffer = kmalloc(maxpath); | ||
| 468 | rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path, | ||
| 469 | tmpbuffer, | ||
| 470 | maxpath -1, | ||
| 471 | fid, | ||
| 472 | cifs_sb->local_nls); | ||
| 473 | if (CIFSSMBClose(xid, ptcon, fid)) { | ||
| 474 | cFYI(1, ("Error closing temporary reparsepoint open)")); | ||
| 475 | } | ||
| 476 | } | ||
| 477 | } | ||
| 478 | */ | ||
| 479 | |||
| 441 | static int initiate_cifs_search(const int xid, struct file *file) | 480 | static int initiate_cifs_search(const int xid, struct file *file) |
| 442 | { | 481 | { |
| 443 | int rc = 0; | 482 | int rc = 0; |
| @@ -493,7 +532,10 @@ ffirst_retry: | |||
| 493 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | 532 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); |
| 494 | if (rc == 0) | 533 | if (rc == 0) |
| 495 | cifsFile->invalidHandle = false; | 534 | cifsFile->invalidHandle = false; |
| 496 | if ((rc == -EOPNOTSUPP) && | 535 | /* BB add following call to handle readdir on new NTFS symlink errors |
| 536 | else if STATUS_STOPPED_ON_SYMLINK | ||
| 537 | call get_symlink_reparse_path and retry with new path */ | ||
| 538 | else if ((rc == -EOPNOTSUPP) && | ||
| 497 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { | 539 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) { |
| 498 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; | 540 | cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; |
| 499 | goto ffirst_retry; | 541 | goto ffirst_retry; |
| @@ -822,7 +864,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 822 | /* inode num, inode type and filename returned */ | 864 | /* inode num, inode type and filename returned */ |
| 823 | static int cifs_get_name_from_search_buf(struct qstr *pqst, | 865 | static int cifs_get_name_from_search_buf(struct qstr *pqst, |
| 824 | char *current_entry, __u16 level, unsigned int unicode, | 866 | char *current_entry, __u16 level, unsigned int unicode, |
| 825 | struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum) | 867 | struct cifs_sb_info *cifs_sb, unsigned int max_len, __u64 *pinum) |
| 826 | { | 868 | { |
| 827 | int rc = 0; | 869 | int rc = 0; |
| 828 | unsigned int len = 0; | 870 | unsigned int len = 0; |
| @@ -881,14 +923,12 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
| 881 | } | 923 | } |
| 882 | 924 | ||
| 883 | if (unicode) { | 925 | if (unicode) { |
| 884 | /* BB fixme - test with long names */ | 926 | pqst->len = cifs_from_ucs2((char *) pqst->name, |
| 885 | /* Note converted filename can be longer than in unicode */ | 927 | (__le16 *) filename, |
| 886 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 928 | UNICODE_NAME_MAX, |
| 887 | pqst->len = cifs_convertUCSpath((char *)pqst->name, | 929 | min(len, max_len), nlt, |
| 888 | (__le16 *)filename, len/2, nlt); | 930 | cifs_sb->mnt_cifs_flags & |
| 889 | else | 931 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 890 | pqst->len = cifs_strfromUCS_le((char *)pqst->name, | ||
| 891 | (__le16 *)filename, len/2, nlt); | ||
| 892 | } else { | 932 | } else { |
| 893 | pqst->name = filename; | 933 | pqst->name = filename; |
| 894 | pqst->len = len; | 934 | pqst->len = len; |
| @@ -898,8 +938,8 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
| 898 | return rc; | 938 | return rc; |
| 899 | } | 939 | } |
| 900 | 940 | ||
| 901 | static int cifs_filldir(char *pfindEntry, struct file *file, | 941 | static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, |
| 902 | filldir_t filldir, void *direntry, char *scratch_buf, int max_len) | 942 | void *direntry, char *scratch_buf, unsigned int max_len) |
| 903 | { | 943 | { |
| 904 | int rc = 0; | 944 | int rc = 0; |
| 905 | struct qstr qstring; | 945 | struct qstr qstring; |
| @@ -996,7 +1036,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 996 | int num_to_fill = 0; | 1036 | int num_to_fill = 0; |
| 997 | char *tmp_buf = NULL; | 1037 | char *tmp_buf = NULL; |
| 998 | char *end_of_smb; | 1038 | char *end_of_smb; |
| 999 | int max_len; | 1039 | unsigned int max_len; |
| 1000 | 1040 | ||
| 1001 | xid = GetXid(); | 1041 | xid = GetXid(); |
| 1002 | 1042 | ||
| @@ -1070,11 +1110,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 1070 | cifsFile->srch_inf.ntwrk_buf_start); | 1110 | cifsFile->srch_inf.ntwrk_buf_start); |
| 1071 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; | 1111 | end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; |
| 1072 | 1112 | ||
| 1073 | /* To be safe - for UCS to UTF-8 with strings loaded | 1113 | tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL); |
| 1074 | with the rare long characters alloc more to account for | ||
| 1075 | such multibyte target UTF-8 characters. cifs_unicode.c, | ||
| 1076 | which actually does the conversion, has the same limit */ | ||
| 1077 | tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); | ||
| 1078 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { | 1114 | for (i = 0; (i < num_to_fill) && (rc == 0); i++) { |
| 1079 | if (current_entry == NULL) { | 1115 | if (current_entry == NULL) { |
| 1080 | /* evaluate whether this case is an error */ | 1116 | /* evaluate whether this case is an error */ |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c652c73760d..897a052270f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * SMB/CIFS session setup handling routines | 4 | * SMB/CIFS session setup handling routines |
| 5 | * | 5 | * |
| 6 | * Copyright (c) International Business Machines Corp., 2006, 2007 | 6 | * Copyright (c) International Business Machines Corp., 2006, 2009 |
| 7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
| 8 | * | 8 | * |
| 9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
| @@ -111,7 +111,7 @@ static __le16 get_next_vcnum(struct cifsSesInfo *ses) | |||
| 111 | get_vc_num_exit: | 111 | get_vc_num_exit: |
| 112 | write_unlock(&cifs_tcp_ses_lock); | 112 | write_unlock(&cifs_tcp_ses_lock); |
| 113 | 113 | ||
| 114 | return le16_to_cpu(vcnum); | 114 | return cpu_to_le16(vcnum); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) | 117 | static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) |
| @@ -277,12 +277,11 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, | |||
| 277 | *pbcc_area = bcc_ptr; | 277 | *pbcc_area = bcc_ptr; |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | static int decode_unicode_ssetup(char **pbcc_area, int bleft, | 280 | static void |
| 281 | struct cifsSesInfo *ses, | 281 | decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifsSesInfo *ses, |
| 282 | const struct nls_table *nls_cp) | 282 | const struct nls_table *nls_cp) |
| 283 | { | 283 | { |
| 284 | int rc = 0; | 284 | int len; |
| 285 | int words_left, len; | ||
| 286 | char *data = *pbcc_area; | 285 | char *data = *pbcc_area; |
| 287 | 286 | ||
| 288 | cFYI(1, ("bleft %d", bleft)); | 287 | cFYI(1, ("bleft %d", bleft)); |
| @@ -300,63 +299,29 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, | |||
| 300 | ++bleft; | 299 | ++bleft; |
| 301 | } | 300 | } |
| 302 | 301 | ||
| 303 | words_left = bleft / 2; | ||
| 304 | |||
| 305 | /* save off server operating system */ | ||
| 306 | len = UniStrnlen((wchar_t *) data, words_left); | ||
| 307 | |||
| 308 | if (len >= words_left) | ||
| 309 | return rc; | ||
| 310 | |||
| 311 | kfree(ses->serverOS); | 302 | kfree(ses->serverOS); |
| 312 | /* UTF-8 string will not grow more than four times as big as UCS-16 */ | 303 | ses->serverOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
| 313 | ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 304 | cFYI(1, ("serverOS=%s", ses->serverOS)); |
| 314 | if (ses->serverOS != NULL) { | 305 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
| 315 | cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); | 306 | data += len; |
| 316 | cFYI(1, ("serverOS=%s", ses->serverOS)); | 307 | bleft -= len; |
| 317 | } | 308 | if (bleft <= 0) |
| 318 | data += 2 * (len + 1); | 309 | return; |
| 319 | words_left -= len + 1; | ||
| 320 | |||
| 321 | /* save off server network operating system */ | ||
| 322 | len = UniStrnlen((wchar_t *) data, words_left); | ||
| 323 | |||
| 324 | if (len >= words_left) | ||
| 325 | return rc; | ||
| 326 | 310 | ||
| 327 | kfree(ses->serverNOS); | 311 | kfree(ses->serverNOS); |
| 328 | ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL); | 312 | ses->serverNOS = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
| 329 | if (ses->serverNOS != NULL) { | 313 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); |
| 330 | cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, | 314 | len = (UniStrnlen((wchar_t *) data, bleft / 2) * 2) + 2; |
| 331 | nls_cp); | 315 | data += len; |
| 332 | cFYI(1, ("serverNOS=%s", ses->serverNOS)); | 316 | bleft -= len; |
| 333 | if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { | 317 | if (bleft <= 0) |
| 334 | cFYI(1, ("NT4 server")); | 318 | return; |
| 335 | ses->flags |= CIFS_SES_NT4; | ||
| 336 | } | ||
| 337 | } | ||
| 338 | data += 2 * (len + 1); | ||
| 339 | words_left -= len + 1; | ||
| 340 | |||
| 341 | /* save off server domain */ | ||
| 342 | len = UniStrnlen((wchar_t *) data, words_left); | ||
| 343 | |||
| 344 | if (len > words_left) | ||
| 345 | return rc; | ||
| 346 | 319 | ||
| 347 | kfree(ses->serverDomain); | 320 | kfree(ses->serverDomain); |
| 348 | ses->serverDomain = kzalloc((4 * len) + 2, GFP_KERNEL); | 321 | ses->serverDomain = cifs_strndup_from_ucs(data, bleft, true, nls_cp); |
| 349 | if (ses->serverDomain != NULL) { | 322 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); |
| 350 | cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, | ||
| 351 | nls_cp); | ||
| 352 | cFYI(1, ("serverDomain=%s", ses->serverDomain)); | ||
| 353 | } | ||
| 354 | data += 2 * (len + 1); | ||
| 355 | words_left -= len + 1; | ||
| 356 | |||
| 357 | cFYI(1, ("words left: %d", words_left)); | ||
| 358 | 323 | ||
| 359 | return rc; | 324 | return; |
| 360 | } | 325 | } |
| 361 | 326 | ||
| 362 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, | 327 | static int decode_ascii_ssetup(char **pbcc_area, int bleft, |
| @@ -413,6 +378,186 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, | |||
| 413 | return rc; | 378 | return rc; |
| 414 | } | 379 | } |
| 415 | 380 | ||
| 381 | static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | ||
| 382 | struct cifsSesInfo *ses) | ||
| 383 | { | ||
| 384 | CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; | ||
| 385 | |||
| 386 | if (blob_len < sizeof(CHALLENGE_MESSAGE)) { | ||
| 387 | cERROR(1, ("challenge blob len %d too small", blob_len)); | ||
| 388 | return -EINVAL; | ||
| 389 | } | ||
| 390 | |||
| 391 | if (memcmp(pblob->Signature, "NTLMSSP", 8)) { | ||
| 392 | cERROR(1, ("blob signature incorrect %s", pblob->Signature)); | ||
| 393 | return -EINVAL; | ||
| 394 | } | ||
| 395 | if (pblob->MessageType != NtLmChallenge) { | ||
| 396 | cERROR(1, ("Incorrect message type %d", pblob->MessageType)); | ||
| 397 | return -EINVAL; | ||
| 398 | } | ||
| 399 | |||
| 400 | memcpy(ses->server->cryptKey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE); | ||
| 401 | /* BB we could decode pblob->NegotiateFlags; some may be useful */ | ||
| 402 | /* In particular we can examine sign flags */ | ||
| 403 | /* BB spec says that if AvId field of MsvAvTimestamp is populated then | ||
| 404 | we must set the MIC field of the AUTHENTICATE_MESSAGE */ | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 410 | /* BB Move to ntlmssp.c eventually */ | ||
| 411 | |||
| 412 | /* We do not malloc the blob, it is passed in pbuffer, because | ||
| 413 | it is fixed size, and small, making this approach cleaner */ | ||
| 414 | static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | ||
| 415 | struct cifsSesInfo *ses) | ||
| 416 | { | ||
| 417 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | ||
| 418 | __u32 flags; | ||
| 419 | |||
| 420 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | ||
| 421 | sec_blob->MessageType = NtLmNegotiate; | ||
| 422 | |||
| 423 | /* BB is NTLMV2 session security format easier to use here? */ | ||
| 424 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | ||
| 425 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | ||
| 426 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | ||
| 427 | if (ses->server->secMode & | ||
| 428 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 429 | flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
| 430 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | ||
| 431 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | ||
| 432 | |||
| 433 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | ||
| 434 | |||
| 435 | sec_blob->WorkstationName.BufferOffset = 0; | ||
| 436 | sec_blob->WorkstationName.Length = 0; | ||
| 437 | sec_blob->WorkstationName.MaximumLength = 0; | ||
| 438 | |||
| 439 | /* Domain name is sent on the Challenge not Negotiate NTLMSSP request */ | ||
| 440 | sec_blob->DomainName.BufferOffset = 0; | ||
| 441 | sec_blob->DomainName.Length = 0; | ||
| 442 | sec_blob->DomainName.MaximumLength = 0; | ||
| 443 | } | ||
| 444 | |||
| 445 | /* We do not malloc the blob, it is passed in pbuffer, because its | ||
| 446 | maximum possible size is fixed and small, making this approach cleaner. | ||
| 447 | This function returns the length of the data in the blob */ | ||
| 448 | static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | ||
| 449 | struct cifsSesInfo *ses, | ||
| 450 | const struct nls_table *nls_cp, int first) | ||
| 451 | { | ||
| 452 | AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; | ||
| 453 | __u32 flags; | ||
| 454 | unsigned char *tmp; | ||
| 455 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
| 456 | |||
| 457 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | ||
| 458 | sec_blob->MessageType = NtLmAuthenticate; | ||
| 459 | |||
| 460 | flags = NTLMSSP_NEGOTIATE_56 | | ||
| 461 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
| 462 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | ||
| 463 | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; | ||
| 464 | if (ses->server->secMode & | ||
| 465 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 466 | flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
| 467 | if (ses->server->secMode & SECMODE_SIGN_REQUIRED) | ||
| 468 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | ||
| 469 | |||
| 470 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | ||
| 471 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | ||
| 472 | |||
| 473 | sec_blob->LmChallengeResponse.BufferOffset = | ||
| 474 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); | ||
| 475 | sec_blob->LmChallengeResponse.Length = 0; | ||
| 476 | sec_blob->LmChallengeResponse.MaximumLength = 0; | ||
| 477 | |||
| 478 | /* calculate session key, BB what about adding similar ntlmv2 path? */ | ||
| 479 | SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); | ||
| 480 | if (first) | ||
| 481 | cifs_calculate_mac_key(&ses->server->mac_signing_key, | ||
| 482 | ntlm_session_key, ses->password); | ||
| 483 | |||
| 484 | memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
| 485 | sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 486 | sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 487 | sec_blob->NtChallengeResponse.MaximumLength = | ||
| 488 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
| 489 | |||
| 490 | tmp += CIFS_SESS_KEY_SIZE; | ||
| 491 | |||
| 492 | if (ses->domainName == NULL) { | ||
| 493 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 494 | sec_blob->DomainName.Length = 0; | ||
| 495 | sec_blob->DomainName.MaximumLength = 0; | ||
| 496 | tmp += 2; | ||
| 497 | } else { | ||
| 498 | int len; | ||
| 499 | len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, | ||
| 500 | MAX_USERNAME_SIZE, nls_cp); | ||
| 501 | len *= 2; /* unicode is 2 bytes each */ | ||
| 502 | len += 2; /* trailing null */ | ||
| 503 | sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 504 | sec_blob->DomainName.Length = cpu_to_le16(len); | ||
| 505 | sec_blob->DomainName.MaximumLength = cpu_to_le16(len); | ||
| 506 | tmp += len; | ||
| 507 | } | ||
| 508 | |||
| 509 | if (ses->userName == NULL) { | ||
| 510 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 511 | sec_blob->UserName.Length = 0; | ||
| 512 | sec_blob->UserName.MaximumLength = 0; | ||
| 513 | tmp += 2; | ||
| 514 | } else { | ||
| 515 | int len; | ||
| 516 | len = cifs_strtoUCS((__le16 *)tmp, ses->userName, | ||
| 517 | MAX_USERNAME_SIZE, nls_cp); | ||
| 518 | len *= 2; /* unicode is 2 bytes each */ | ||
| 519 | len += 2; /* trailing null */ | ||
| 520 | sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 521 | sec_blob->UserName.Length = cpu_to_le16(len); | ||
| 522 | sec_blob->UserName.MaximumLength = cpu_to_le16(len); | ||
| 523 | tmp += len; | ||
| 524 | } | ||
| 525 | |||
| 526 | sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 527 | sec_blob->WorkstationName.Length = 0; | ||
| 528 | sec_blob->WorkstationName.MaximumLength = 0; | ||
| 529 | tmp += 2; | ||
| 530 | |||
| 531 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | ||
| 532 | sec_blob->SessionKey.Length = 0; | ||
| 533 | sec_blob->SessionKey.MaximumLength = 0; | ||
| 534 | return tmp - pbuffer; | ||
| 535 | } | ||
| 536 | |||
| 537 | |||
| 538 | static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | ||
| 539 | struct cifsSesInfo *ses) | ||
| 540 | { | ||
| 541 | build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses); | ||
| 542 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
| 543 | |||
| 544 | return; | ||
| 545 | } | ||
| 546 | |||
| 547 | static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB, | ||
| 548 | struct cifsSesInfo *ses, | ||
| 549 | const struct nls_table *nls, int first_time) | ||
| 550 | { | ||
| 551 | int bloblen; | ||
| 552 | |||
| 553 | bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls, | ||
| 554 | first_time); | ||
| 555 | pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen); | ||
| 556 | |||
| 557 | return bloblen; | ||
| 558 | } | ||
| 559 | #endif | ||
| 560 | |||
| 416 | int | 561 | int |
| 417 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | 562 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, |
| 418 | const struct nls_table *nls_cp) | 563 | const struct nls_table *nls_cp) |
| @@ -431,6 +576,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 431 | __u16 action; | 576 | __u16 action; |
| 432 | int bytes_remaining; | 577 | int bytes_remaining; |
| 433 | struct key *spnego_key = NULL; | 578 | struct key *spnego_key = NULL; |
| 579 | __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ | ||
| 434 | 580 | ||
| 435 | if (ses == NULL) | 581 | if (ses == NULL) |
| 436 | return -EINVAL; | 582 | return -EINVAL; |
| @@ -438,6 +584,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 438 | type = ses->server->secType; | 584 | type = ses->server->secType; |
| 439 | 585 | ||
| 440 | cFYI(1, ("sess setup type %d", type)); | 586 | cFYI(1, ("sess setup type %d", type)); |
| 587 | ssetup_ntlmssp_authenticate: | ||
| 588 | if (phase == NtLmChallenge) | ||
| 589 | phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ | ||
| 590 | |||
| 441 | if (type == LANMAN) { | 591 | if (type == LANMAN) { |
| 442 | #ifndef CONFIG_CIFS_WEAK_PW_HASH | 592 | #ifndef CONFIG_CIFS_WEAK_PW_HASH |
| 443 | /* LANMAN and plaintext are less secure and off by default. | 593 | /* LANMAN and plaintext are less secure and off by default. |
| @@ -651,9 +801,53 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 651 | goto ssetup_exit; | 801 | goto ssetup_exit; |
| 652 | #endif /* CONFIG_CIFS_UPCALL */ | 802 | #endif /* CONFIG_CIFS_UPCALL */ |
| 653 | } else { | 803 | } else { |
| 804 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 805 | if ((experimEnabled > 1) && (type == RawNTLMSSP)) { | ||
| 806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | ||
| 807 | cERROR(1, ("NTLMSSP requires Unicode support")); | ||
| 808 | rc = -ENOSYS; | ||
| 809 | goto ssetup_exit; | ||
| 810 | } | ||
| 811 | |||
| 812 | cFYI(1, ("ntlmssp session setup phase %d", phase)); | ||
| 813 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 814 | capabilities |= CAP_EXTENDED_SECURITY; | ||
| 815 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
| 816 | if (phase == NtLmNegotiate) { | ||
| 817 | setup_ntlmssp_neg_req(pSMB, ses); | ||
| 818 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
| 819 | } else if (phase == NtLmAuthenticate) { | ||
| 820 | int blob_len; | ||
| 821 | blob_len = setup_ntlmssp_auth_req(pSMB, ses, | ||
| 822 | nls_cp, | ||
| 823 | first_time); | ||
| 824 | iov[1].iov_len = blob_len; | ||
| 825 | /* Make sure that we tell the server that we | ||
| 826 | are using the uid that it just gave us back | ||
| 827 | on the response (challenge) */ | ||
| 828 | smb_buf->Uid = ses->Suid; | ||
| 829 | } else { | ||
| 830 | cERROR(1, ("invalid phase %d", phase)); | ||
| 831 | rc = -ENOSYS; | ||
| 832 | goto ssetup_exit; | ||
| 833 | } | ||
| 834 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
| 835 | /* unicode strings must be word aligned */ | ||
| 836 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
| 837 | *bcc_ptr = 0; | ||
| 838 | bcc_ptr++; | ||
| 839 | } | ||
| 840 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
| 841 | } else { | ||
| 842 | cERROR(1, ("secType %d not supported!", type)); | ||
| 843 | rc = -ENOSYS; | ||
| 844 | goto ssetup_exit; | ||
| 845 | } | ||
| 846 | #else | ||
| 654 | cERROR(1, ("secType %d not supported!", type)); | 847 | cERROR(1, ("secType %d not supported!", type)); |
| 655 | rc = -ENOSYS; | 848 | rc = -ENOSYS; |
| 656 | goto ssetup_exit; | 849 | goto ssetup_exit; |
| 850 | #endif | ||
| 657 | } | 851 | } |
| 658 | 852 | ||
| 659 | iov[2].iov_base = str_area; | 853 | iov[2].iov_base = str_area; |
| @@ -669,12 +863,23 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 669 | /* SMB request buf freed in SendReceive2 */ | 863 | /* SMB request buf freed in SendReceive2 */ |
| 670 | 864 | ||
| 671 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); | 865 | cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); |
| 672 | if (rc) | ||
| 673 | goto ssetup_exit; | ||
| 674 | 866 | ||
| 675 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 867 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
| 676 | smb_buf = (struct smb_hdr *)iov[0].iov_base; | 868 | smb_buf = (struct smb_hdr *)iov[0].iov_base; |
| 677 | 869 | ||
| 870 | if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError == | ||
| 871 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) { | ||
| 872 | if (phase != NtLmNegotiate) { | ||
| 873 | cERROR(1, ("Unexpected more processing error")); | ||
| 874 | goto ssetup_exit; | ||
| 875 | } | ||
| 876 | /* NTLMSSP Negotiate sent now processing challenge (response) */ | ||
| 877 | phase = NtLmChallenge; /* process ntlmssp challenge */ | ||
| 878 | rc = 0; /* MORE_PROC rc is not an error here, but expected */ | ||
| 879 | } | ||
| 880 | if (rc) | ||
| 881 | goto ssetup_exit; | ||
| 882 | |||
| 678 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { | 883 | if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { |
| 679 | rc = -EIO; | 884 | rc = -EIO; |
| 680 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); | 885 | cERROR(1, ("bad word count %d", smb_buf->WordCount)); |
| @@ -693,12 +898,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 693 | if (smb_buf->WordCount == 4) { | 898 | if (smb_buf->WordCount == 4) { |
| 694 | __u16 blob_len; | 899 | __u16 blob_len; |
| 695 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); | 900 | blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); |
| 696 | bcc_ptr += blob_len; | ||
| 697 | if (blob_len > bytes_remaining) { | 901 | if (blob_len > bytes_remaining) { |
| 698 | cERROR(1, ("bad security blob length %d", blob_len)); | 902 | cERROR(1, ("bad security blob length %d", blob_len)); |
| 699 | rc = -EINVAL; | 903 | rc = -EINVAL; |
| 700 | goto ssetup_exit; | 904 | goto ssetup_exit; |
| 701 | } | 905 | } |
| 906 | if (phase == NtLmChallenge) { | ||
| 907 | rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses); | ||
| 908 | /* now goto beginning for ntlmssp authenticate phase */ | ||
| 909 | if (rc) | ||
| 910 | goto ssetup_exit; | ||
| 911 | } | ||
| 912 | bcc_ptr += blob_len; | ||
| 702 | bytes_remaining -= blob_len; | 913 | bytes_remaining -= blob_len; |
| 703 | } | 914 | } |
| 704 | 915 | ||
| @@ -709,8 +920,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 709 | ++bcc_ptr; | 920 | ++bcc_ptr; |
| 710 | --bytes_remaining; | 921 | --bytes_remaining; |
| 711 | } | 922 | } |
| 712 | rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, | 923 | decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); |
| 713 | ses, nls_cp); | ||
| 714 | } else { | 924 | } else { |
| 715 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, | 925 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, |
| 716 | ses, nls_cp); | 926 | ses, nls_cp); |
| @@ -728,5 +938,9 @@ ssetup_exit: | |||
| 728 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) | 938 | } else if (resp_buf_type == CIFS_LARGE_BUFFER) |
| 729 | cifs_buf_release(iov[0].iov_base); | 939 | cifs_buf_release(iov[0].iov_base); |
| 730 | 940 | ||
| 941 | /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */ | ||
| 942 | if ((phase == NtLmChallenge) && (rc == 0)) | ||
| 943 | goto ssetup_ntlmssp_authenticate; | ||
| 944 | |||
| 731 | return rc; | 945 | return rc; |
| 732 | } | 946 | } |
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 7f50e8577c1..c5084d27db7 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h | |||
| @@ -110,6 +110,7 @@ | |||
| 110 | 110 | ||
| 111 | /* Below errors are used internally (do not come over the wire) for passthrough | 111 | /* Below errors are used internally (do not come over the wire) for passthrough |
| 112 | from STATUS codes to POSIX only */ | 112 | from STATUS codes to POSIX only */ |
| 113 | #define ERRsymlink 0xFFFD | ||
| 113 | #define ErrTooManyLinks 0xFFFE | 114 | #define ErrTooManyLinks 0xFFFE |
| 114 | 115 | ||
| 115 | /* Following error codes may be generated with the ERRSRV error class.*/ | 116 | /* Following error codes may be generated with the ERRSRV error class.*/ |
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index 932a92b3148..c8afa6b1d91 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c | |||
| @@ -135,7 +135,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna | |||
| 135 | struct path path; | 135 | struct path path; |
| 136 | struct configfs_dirent *sd; | 136 | struct configfs_dirent *sd; |
| 137 | struct config_item *parent_item; | 137 | struct config_item *parent_item; |
| 138 | struct config_item *target_item; | 138 | struct config_item *target_item = NULL; |
| 139 | struct config_item_type *type; | 139 | struct config_item_type *type; |
| 140 | 140 | ||
| 141 | ret = -EPERM; /* What lack-of-symlink returns */ | 141 | ret = -EPERM; /* What lack-of-symlink returns */ |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 93bc0f8174a..2f0945d6329 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -667,7 +667,7 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) | |||
| 667 | lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); | 667 | lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); |
| 668 | if (lower_buf == NULL) { | 668 | if (lower_buf == NULL) { |
| 669 | printk(KERN_ERR "%s: Out of memory whilst attempting to " | 669 | printk(KERN_ERR "%s: Out of memory whilst attempting to " |
| 670 | "kmalloc [%d] bytes\n", __func__, lower_bufsiz); | 670 | "kmalloc [%zd] bytes\n", __func__, lower_bufsiz); |
| 671 | rc = -ENOMEM; | 671 | rc = -ENOMEM; |
| 672 | goto out; | 672 | goto out; |
| 673 | } | 673 | } |
| @@ -690,7 +690,7 @@ ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) | |||
| 690 | } | 690 | } |
| 691 | /* Check for bufsiz <= 0 done in sys_readlinkat() */ | 691 | /* Check for bufsiz <= 0 done in sys_readlinkat() */ |
| 692 | rc = copy_to_user(buf, plaintext_name, | 692 | rc = copy_to_user(buf, plaintext_name, |
| 693 | min((unsigned) bufsiz, plaintext_name_size)); | 693 | min((size_t) bufsiz, plaintext_name_size)); |
| 694 | if (rc) | 694 | if (rc) |
| 695 | rc = -EFAULT; | 695 | rc = -EFAULT; |
| 696 | else | 696 | else |
| @@ -69,17 +69,18 @@ int suid_dumpable = 0; | |||
| 69 | static LIST_HEAD(formats); | 69 | static LIST_HEAD(formats); |
| 70 | static DEFINE_RWLOCK(binfmt_lock); | 70 | static DEFINE_RWLOCK(binfmt_lock); |
| 71 | 71 | ||
| 72 | int register_binfmt(struct linux_binfmt * fmt) | 72 | int __register_binfmt(struct linux_binfmt * fmt, int insert) |
| 73 | { | 73 | { |
| 74 | if (!fmt) | 74 | if (!fmt) |
| 75 | return -EINVAL; | 75 | return -EINVAL; |
| 76 | write_lock(&binfmt_lock); | 76 | write_lock(&binfmt_lock); |
| 77 | list_add(&fmt->lh, &formats); | 77 | insert ? list_add(&fmt->lh, &formats) : |
| 78 | list_add_tail(&fmt->lh, &formats); | ||
| 78 | write_unlock(&binfmt_lock); | 79 | write_unlock(&binfmt_lock); |
| 79 | return 0; | 80 | return 0; |
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | EXPORT_SYMBOL(register_binfmt); | 83 | EXPORT_SYMBOL(__register_binfmt); |
| 83 | 84 | ||
| 84 | void unregister_binfmt(struct linux_binfmt * fmt) | 85 | void unregister_binfmt(struct linux_binfmt * fmt) |
| 85 | { | 86 | { |
diff --git a/fs/ioctl.c b/fs/ioctl.c index ac2d47e4392..82d9c42b8ba 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
| @@ -258,7 +258,7 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 258 | long long length = 0, map_len = 0; | 258 | long long length = 0, map_len = 0; |
| 259 | u64 logical = 0, phys = 0, size = 0; | 259 | u64 logical = 0, phys = 0, size = 0; |
| 260 | u32 flags = FIEMAP_EXTENT_MERGED; | 260 | u32 flags = FIEMAP_EXTENT_MERGED; |
| 261 | int ret = 0; | 261 | int ret = 0, past_eof = 0, whole_file = 0; |
| 262 | 262 | ||
| 263 | if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) | 263 | if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) |
| 264 | return ret; | 264 | return ret; |
| @@ -266,6 +266,9 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 266 | start_blk = logical_to_blk(inode, start); | 266 | start_blk = logical_to_blk(inode, start); |
| 267 | 267 | ||
| 268 | length = (long long)min_t(u64, len, i_size_read(inode)); | 268 | length = (long long)min_t(u64, len, i_size_read(inode)); |
| 269 | if (length < len) | ||
| 270 | whole_file = 1; | ||
| 271 | |||
| 269 | map_len = length; | 272 | map_len = length; |
| 270 | 273 | ||
| 271 | do { | 274 | do { |
| @@ -282,11 +285,26 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 282 | 285 | ||
| 283 | /* HOLE */ | 286 | /* HOLE */ |
| 284 | if (!buffer_mapped(&tmp)) { | 287 | if (!buffer_mapped(&tmp)) { |
| 288 | length -= blk_to_logical(inode, 1); | ||
| 289 | start_blk++; | ||
| 290 | |||
| 291 | /* | ||
| 292 | * we want to handle the case where there is an | ||
| 293 | * allocated block at the front of the file, and then | ||
| 294 | * nothing but holes up to the end of the file properly, | ||
| 295 | * to make sure that extent at the front gets properly | ||
| 296 | * marked with FIEMAP_EXTENT_LAST | ||
| 297 | */ | ||
| 298 | if (!past_eof && | ||
| 299 | blk_to_logical(inode, start_blk) >= | ||
| 300 | blk_to_logical(inode, 0)+i_size_read(inode)) | ||
| 301 | past_eof = 1; | ||
| 302 | |||
| 285 | /* | 303 | /* |
| 286 | * first hole after going past the EOF, this is our | 304 | * first hole after going past the EOF, this is our |
| 287 | * last extent | 305 | * last extent |
| 288 | */ | 306 | */ |
| 289 | if (length <= 0) { | 307 | if (past_eof && size) { |
| 290 | flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST; | 308 | flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST; |
| 291 | ret = fiemap_fill_next_extent(fieinfo, logical, | 309 | ret = fiemap_fill_next_extent(fieinfo, logical, |
| 292 | phys, size, | 310 | phys, size, |
| @@ -294,15 +312,37 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 294 | break; | 312 | break; |
| 295 | } | 313 | } |
| 296 | 314 | ||
| 297 | length -= blk_to_logical(inode, 1); | ||
| 298 | |||
| 299 | /* if we have holes up to/past EOF then we're done */ | 315 | /* if we have holes up to/past EOF then we're done */ |
| 300 | if (length <= 0) | 316 | if (length <= 0 || past_eof) |
| 301 | break; | 317 | break; |
| 302 | |||
| 303 | start_blk++; | ||
| 304 | } else { | 318 | } else { |
| 305 | if (length <= 0 && size) { | 319 | /* |
| 320 | * we have gone over the length of what we wanted to | ||
| 321 | * map, and it wasn't the entire file, so add the extent | ||
| 322 | * we got last time and exit. | ||
| 323 | * | ||
| 324 | * This is for the case where say we want to map all the | ||
| 325 | * way up to the second to the last block in a file, but | ||
| 326 | * the last block is a hole, making the second to last | ||
| 327 | * block FIEMAP_EXTENT_LAST. In this case we want to | ||
| 328 | * see if there is a hole after the second to last block | ||
| 329 | * so we can mark it properly. If we found data after | ||
| 330 | * we exceeded the length we were requesting, then we | ||
| 331 | * are good to go, just add the extent to the fieinfo | ||
| 332 | * and break | ||
| 333 | */ | ||
| 334 | if (length <= 0 && !whole_file) { | ||
| 335 | ret = fiemap_fill_next_extent(fieinfo, logical, | ||
| 336 | phys, size, | ||
| 337 | flags); | ||
| 338 | break; | ||
| 339 | } | ||
| 340 | |||
| 341 | /* | ||
| 342 | * if size != 0 then we know we already have an extent | ||
| 343 | * to add, so add it. | ||
| 344 | */ | ||
| 345 | if (size) { | ||
| 306 | ret = fiemap_fill_next_extent(fieinfo, logical, | 346 | ret = fiemap_fill_next_extent(fieinfo, logical, |
| 307 | phys, size, | 347 | phys, size, |
| 308 | flags); | 348 | flags); |
| @@ -319,19 +359,14 @@ int __generic_block_fiemap(struct inode *inode, | |||
| 319 | start_blk += logical_to_blk(inode, size); | 359 | start_blk += logical_to_blk(inode, size); |
| 320 | 360 | ||
| 321 | /* | 361 | /* |
| 322 | * if we are past the EOF we need to loop again to see | 362 | * If we are past the EOF, then we need to make sure as |
| 323 | * if there is a hole so we can mark this extent as the | 363 | * soon as we find a hole that the last extent we found |
| 324 | * last one, and if not keep mapping things until we | 364 | * is marked with FIEMAP_EXTENT_LAST |
| 325 | * find a hole, or we run out of slots in the extent | ||
| 326 | * array | ||
| 327 | */ | 365 | */ |
| 328 | if (length <= 0) | 366 | if (!past_eof && |
| 329 | continue; | 367 | logical+size >= |
| 330 | 368 | blk_to_logical(inode, 0)+i_size_read(inode)) | |
| 331 | ret = fiemap_fill_next_extent(fieinfo, logical, phys, | 369 | past_eof = 1; |
| 332 | size, flags); | ||
| 333 | if (ret) | ||
| 334 | break; | ||
| 335 | } | 370 | } |
| 336 | cond_resched(); | 371 | cond_resched(); |
| 337 | } while (1); | 372 | } while (1); |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 5a97bcfe03e..ec7e27d00bc 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -517,10 +517,10 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 517 | 517 | ||
| 518 | ret = nfs_updatepage(filp, page, 0, pagelen); | 518 | ret = nfs_updatepage(filp, page, 0, pagelen); |
| 519 | out_unlock: | 519 | out_unlock: |
| 520 | if (!ret) | ||
| 521 | return VM_FAULT_LOCKED; | ||
| 520 | unlock_page(page); | 522 | unlock_page(page); |
| 521 | if (ret) | 523 | return VM_FAULT_SIGBUS; |
| 522 | ret = VM_FAULT_SIGBUS; | ||
| 523 | return ret; | ||
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | static struct vm_operations_struct nfs_file_vm_ops = { | 526 | static struct vm_operations_struct nfs_file_vm_ops = { |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index bed766e435b..1634319e240 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
| @@ -220,7 +220,7 @@ static struct inotify_kernel_event * kernel_event(s32 wd, u32 mask, u32 cookie, | |||
| 220 | rem = 0; | 220 | rem = 0; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | kevent->name = kmalloc(len + rem, GFP_KERNEL); | 223 | kevent->name = kmalloc(len + rem, GFP_NOFS); |
| 224 | if (unlikely(!kevent->name)) { | 224 | if (unlikely(!kevent->name)) { |
| 225 | kmem_cache_free(event_cachep, kevent); | 225 | kmem_cache_free(event_cachep, kevent); |
| 226 | return NULL; | 226 | return NULL; |
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index 7d604480557..b574431a031 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c | |||
| @@ -290,6 +290,21 @@ out_attach: | |||
| 290 | else | 290 | else |
| 291 | mlog_errno(ret); | 291 | mlog_errno(ret); |
| 292 | 292 | ||
| 293 | /* | ||
| 294 | * In case of error, manually free the allocation and do the iput(). | ||
| 295 | * We need to do this because error here means no d_instantiate(), | ||
| 296 | * which means iput() will not be called during dput(dentry). | ||
| 297 | */ | ||
| 298 | if (ret < 0 && !alias) { | ||
| 299 | ocfs2_lock_res_free(&dl->dl_lockres); | ||
| 300 | BUG_ON(dl->dl_count != 1); | ||
| 301 | spin_lock(&dentry_attach_lock); | ||
| 302 | dentry->d_fsdata = NULL; | ||
| 303 | spin_unlock(&dentry_attach_lock); | ||
| 304 | kfree(dl); | ||
| 305 | iput(inode); | ||
| 306 | } | ||
| 307 | |||
| 293 | dput(alias); | 308 | dput(alias); |
| 294 | 309 | ||
| 295 | return ret; | 310 | return ret; |
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index e71160cda11..c5752305627 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
| @@ -2697,7 +2697,7 @@ static int ocfs2_dx_dir_index_block(struct inode *dir, | |||
| 2697 | u32 *num_dx_entries, | 2697 | u32 *num_dx_entries, |
| 2698 | struct buffer_head *dirent_bh) | 2698 | struct buffer_head *dirent_bh) |
| 2699 | { | 2699 | { |
| 2700 | int ret, namelen, i; | 2700 | int ret = 0, namelen, i; |
| 2701 | char *de_buf, *limit; | 2701 | char *de_buf, *limit; |
| 2702 | struct ocfs2_dir_entry *de; | 2702 | struct ocfs2_dir_entry *de; |
| 2703 | struct buffer_head *dx_leaf_bh; | 2703 | struct buffer_head *dx_leaf_bh; |
| @@ -2934,7 +2934,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
| 2934 | */ | 2934 | */ |
| 2935 | BUG_ON(alloc > 2); | 2935 | BUG_ON(alloc > 2); |
| 2936 | 2936 | ||
| 2937 | ret = ocfs2_reserve_clusters(osb, alloc, &data_ac); | 2937 | ret = ocfs2_reserve_clusters(osb, alloc + dx_alloc, &data_ac); |
| 2938 | if (ret) { | 2938 | if (ret) { |
| 2939 | mlog_errno(ret); | 2939 | mlog_errno(ret); |
| 2940 | goto out; | 2940 | goto out; |
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index de3da8eb558..15713cbb865 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c | |||
| @@ -100,7 +100,8 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, | |||
| 100 | 100 | ||
| 101 | /* If the inode allocator bit is clear, this inode must be stale */ | 101 | /* If the inode allocator bit is clear, this inode must be stale */ |
| 102 | if (!set) { | 102 | if (!set) { |
| 103 | mlog(0, "inode %llu suballoc bit is clear\n", blkno); | 103 | mlog(0, "inode %llu suballoc bit is clear\n", |
| 104 | (unsigned long long)blkno); | ||
| 104 | status = -ESTALE; | 105 | status = -ESTALE; |
| 105 | goto unlock_nfs_sync; | 106 | goto unlock_nfs_sync; |
| 106 | } | 107 | } |
| @@ -114,7 +115,7 @@ check_err: | |||
| 114 | if (status < 0) { | 115 | if (status < 0) { |
| 115 | if (status == -ESTALE) { | 116 | if (status == -ESTALE) { |
| 116 | mlog(0, "stale inode ino: %llu generation: %u\n", | 117 | mlog(0, "stale inode ino: %llu generation: %u\n", |
| 117 | blkno, handle->ih_generation); | 118 | (unsigned long long)blkno, handle->ih_generation); |
| 118 | } | 119 | } |
| 119 | result = ERR_PTR(status); | 120 | result = ERR_PTR(status); |
| 120 | goto bail; | 121 | goto bail; |
| @@ -129,8 +130,8 @@ check_err: | |||
| 129 | check_gen: | 130 | check_gen: |
| 130 | if (handle->ih_generation != inode->i_generation) { | 131 | if (handle->ih_generation != inode->i_generation) { |
| 131 | iput(inode); | 132 | iput(inode); |
| 132 | mlog(0, "stale inode ino: %llu generation: %u\n", blkno, | 133 | mlog(0, "stale inode ino: %llu generation: %u\n", |
| 133 | handle->ih_generation); | 134 | (unsigned long long)blkno, handle->ih_generation); |
| 134 | result = ERR_PTR(-ESTALE); | 135 | result = ERR_PTR(-ESTALE); |
| 135 | goto bail; | 136 | goto bail; |
| 136 | } | 137 | } |
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 619dd7f6c05..eb7b76331eb 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h | |||
| @@ -437,8 +437,9 @@ static inline int ocfs2_unlink_credits(struct super_block *sb) | |||
| 437 | } | 437 | } |
| 438 | 438 | ||
| 439 | /* dinode + orphan dir dinode + inode alloc dinode + orphan dir entry + | 439 | /* dinode + orphan dir dinode + inode alloc dinode + orphan dir entry + |
| 440 | * inode alloc group descriptor + orphan dir index leaf */ | 440 | * inode alloc group descriptor + orphan dir index root + |
| 441 | #define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3) | 441 | * orphan dir index leaf */ |
| 442 | #define OCFS2_DELETE_INODE_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 4) | ||
| 442 | 443 | ||
| 443 | /* dinode update, old dir dinode update, new dir dinode update, old | 444 | /* dinode update, old dir dinode update, new dir dinode update, old |
| 444 | * dir dir entry, new dir dir entry, dir entry update for renaming | 445 | * dir dir entry, new dir dir entry, dir entry update for renaming |
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 2220f93f668..33464c6b60a 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
| @@ -1025,10 +1025,8 @@ static int ocfs2_rename(struct inode *old_dir, | |||
| 1025 | struct inode *orphan_dir = NULL; | 1025 | struct inode *orphan_dir = NULL; |
| 1026 | struct ocfs2_dinode *newfe = NULL; | 1026 | struct ocfs2_dinode *newfe = NULL; |
| 1027 | char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; | 1027 | char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; |
| 1028 | struct buffer_head *orphan_entry_bh = NULL; | ||
| 1029 | struct buffer_head *newfe_bh = NULL; | 1028 | struct buffer_head *newfe_bh = NULL; |
| 1030 | struct buffer_head *old_inode_bh = NULL; | 1029 | struct buffer_head *old_inode_bh = NULL; |
| 1031 | struct buffer_head *insert_entry_bh = NULL; | ||
| 1032 | struct ocfs2_super *osb = NULL; | 1030 | struct ocfs2_super *osb = NULL; |
| 1033 | u64 newfe_blkno, old_de_ino; | 1031 | u64 newfe_blkno, old_de_ino; |
| 1034 | handle_t *handle = NULL; | 1032 | handle_t *handle = NULL; |
| @@ -1455,8 +1453,6 @@ bail: | |||
| 1455 | brelse(old_inode_bh); | 1453 | brelse(old_inode_bh); |
| 1456 | brelse(old_dir_bh); | 1454 | brelse(old_dir_bh); |
| 1457 | brelse(new_dir_bh); | 1455 | brelse(new_dir_bh); |
| 1458 | brelse(orphan_entry_bh); | ||
| 1459 | brelse(insert_entry_bh); | ||
| 1460 | 1456 | ||
| 1461 | mlog_exit(status); | 1457 | mlog_exit(status); |
| 1462 | 1458 | ||
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index b4ca5911caa..8439f6b324b 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
| @@ -2197,26 +2197,29 @@ static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, | |||
| 2197 | struct buffer_head *inode_bh = NULL; | 2197 | struct buffer_head *inode_bh = NULL; |
| 2198 | struct ocfs2_dinode *inode_fe; | 2198 | struct ocfs2_dinode *inode_fe; |
| 2199 | 2199 | ||
| 2200 | mlog_entry("blkno: %llu\n", blkno); | 2200 | mlog_entry("blkno: %llu\n", (unsigned long long)blkno); |
| 2201 | 2201 | ||
| 2202 | /* dirty read disk */ | 2202 | /* dirty read disk */ |
| 2203 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &inode_bh); | 2203 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &inode_bh); |
| 2204 | if (status < 0) { | 2204 | if (status < 0) { |
| 2205 | mlog(ML_ERROR, "read block %llu failed %d\n", blkno, status); | 2205 | mlog(ML_ERROR, "read block %llu failed %d\n", |
| 2206 | (unsigned long long)blkno, status); | ||
| 2206 | goto bail; | 2207 | goto bail; |
| 2207 | } | 2208 | } |
| 2208 | 2209 | ||
| 2209 | inode_fe = (struct ocfs2_dinode *) inode_bh->b_data; | 2210 | inode_fe = (struct ocfs2_dinode *) inode_bh->b_data; |
| 2210 | if (!OCFS2_IS_VALID_DINODE(inode_fe)) { | 2211 | if (!OCFS2_IS_VALID_DINODE(inode_fe)) { |
| 2211 | mlog(ML_ERROR, "invalid inode %llu requested\n", blkno); | 2212 | mlog(ML_ERROR, "invalid inode %llu requested\n", |
| 2213 | (unsigned long long)blkno); | ||
| 2212 | status = -EINVAL; | 2214 | status = -EINVAL; |
| 2213 | goto bail; | 2215 | goto bail; |
| 2214 | } | 2216 | } |
| 2215 | 2217 | ||
| 2216 | if (le16_to_cpu(inode_fe->i_suballoc_slot) != OCFS2_INVALID_SLOT && | 2218 | if (le16_to_cpu(inode_fe->i_suballoc_slot) != (u16)OCFS2_INVALID_SLOT && |
| 2217 | (u32)le16_to_cpu(inode_fe->i_suballoc_slot) > osb->max_slots - 1) { | 2219 | (u32)le16_to_cpu(inode_fe->i_suballoc_slot) > osb->max_slots - 1) { |
| 2218 | mlog(ML_ERROR, "inode %llu has invalid suballoc slot %u\n", | 2220 | mlog(ML_ERROR, "inode %llu has invalid suballoc slot %u\n", |
| 2219 | blkno, (u32)le16_to_cpu(inode_fe->i_suballoc_slot)); | 2221 | (unsigned long long)blkno, |
| 2222 | (u32)le16_to_cpu(inode_fe->i_suballoc_slot)); | ||
| 2220 | status = -EINVAL; | 2223 | status = -EINVAL; |
| 2221 | goto bail; | 2224 | goto bail; |
| 2222 | } | 2225 | } |
| @@ -2251,7 +2254,8 @@ static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, | |||
| 2251 | u64 bg_blkno; | 2254 | u64 bg_blkno; |
| 2252 | int status; | 2255 | int status; |
| 2253 | 2256 | ||
| 2254 | mlog_entry("blkno: %llu bit: %u\n", blkno, (unsigned int)bit); | 2257 | mlog_entry("blkno: %llu bit: %u\n", (unsigned long long)blkno, |
| 2258 | (unsigned int)bit); | ||
| 2255 | 2259 | ||
| 2256 | alloc_fe = (struct ocfs2_dinode *)alloc_bh->b_data; | 2260 | alloc_fe = (struct ocfs2_dinode *)alloc_bh->b_data; |
| 2257 | if ((bit + 1) > ocfs2_bits_per_group(&alloc_fe->id2.i_chain)) { | 2261 | if ((bit + 1) > ocfs2_bits_per_group(&alloc_fe->id2.i_chain)) { |
| @@ -2266,7 +2270,8 @@ static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, | |||
| 2266 | status = ocfs2_read_group_descriptor(suballoc, alloc_fe, bg_blkno, | 2270 | status = ocfs2_read_group_descriptor(suballoc, alloc_fe, bg_blkno, |
| 2267 | &group_bh); | 2271 | &group_bh); |
| 2268 | if (status < 0) { | 2272 | if (status < 0) { |
| 2269 | mlog(ML_ERROR, "read group %llu failed %d\n", bg_blkno, status); | 2273 | mlog(ML_ERROR, "read group %llu failed %d\n", |
| 2274 | (unsigned long long)bg_blkno, status); | ||
| 2270 | goto bail; | 2275 | goto bail; |
| 2271 | } | 2276 | } |
| 2272 | 2277 | ||
| @@ -2300,7 +2305,7 @@ int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) | |||
| 2300 | struct inode *inode_alloc_inode; | 2305 | struct inode *inode_alloc_inode; |
| 2301 | struct buffer_head *alloc_bh = NULL; | 2306 | struct buffer_head *alloc_bh = NULL; |
| 2302 | 2307 | ||
| 2303 | mlog_entry("blkno: %llu", blkno); | 2308 | mlog_entry("blkno: %llu", (unsigned long long)blkno); |
| 2304 | 2309 | ||
| 2305 | status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot, | 2310 | status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot, |
| 2306 | &suballoc_bit); | 2311 | &suballoc_bit); |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 7e4877d9dcb..725a650bbbb 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -80,6 +80,7 @@ | |||
| 80 | #include <linux/delayacct.h> | 80 | #include <linux/delayacct.h> |
| 81 | #include <linux/seq_file.h> | 81 | #include <linux/seq_file.h> |
| 82 | #include <linux/pid_namespace.h> | 82 | #include <linux/pid_namespace.h> |
| 83 | #include <linux/ptrace.h> | ||
| 83 | #include <linux/tracehook.h> | 84 | #include <linux/tracehook.h> |
| 84 | 85 | ||
| 85 | #include <asm/pgtable.h> | 86 | #include <asm/pgtable.h> |
| @@ -352,6 +353,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 352 | char state; | 353 | char state; |
| 353 | pid_t ppid = 0, pgid = -1, sid = -1; | 354 | pid_t ppid = 0, pgid = -1, sid = -1; |
| 354 | int num_threads = 0; | 355 | int num_threads = 0; |
| 356 | int permitted; | ||
| 355 | struct mm_struct *mm; | 357 | struct mm_struct *mm; |
| 356 | unsigned long long start_time; | 358 | unsigned long long start_time; |
| 357 | unsigned long cmin_flt = 0, cmaj_flt = 0; | 359 | unsigned long cmin_flt = 0, cmaj_flt = 0; |
| @@ -364,11 +366,14 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 364 | 366 | ||
| 365 | state = *get_task_state(task); | 367 | state = *get_task_state(task); |
| 366 | vsize = eip = esp = 0; | 368 | vsize = eip = esp = 0; |
| 369 | permitted = ptrace_may_access(task, PTRACE_MODE_READ); | ||
| 367 | mm = get_task_mm(task); | 370 | mm = get_task_mm(task); |
| 368 | if (mm) { | 371 | if (mm) { |
| 369 | vsize = task_vsize(mm); | 372 | vsize = task_vsize(mm); |
| 370 | eip = KSTK_EIP(task); | 373 | if (permitted) { |
| 371 | esp = KSTK_ESP(task); | 374 | eip = KSTK_EIP(task); |
| 375 | esp = KSTK_ESP(task); | ||
| 376 | } | ||
| 372 | } | 377 | } |
| 373 | 378 | ||
| 374 | get_task_comm(tcomm, task); | 379 | get_task_comm(tcomm, task); |
| @@ -424,7 +429,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 424 | unlock_task_sighand(task, &flags); | 429 | unlock_task_sighand(task, &flags); |
| 425 | } | 430 | } |
| 426 | 431 | ||
| 427 | if (!whole || num_threads < 2) | 432 | if (permitted && (!whole || num_threads < 2)) |
| 428 | wchan = get_wchan(task); | 433 | wchan = get_wchan(task); |
| 429 | if (!whole) { | 434 | if (!whole) { |
| 430 | min_flt = task->min_flt; | 435 | min_flt = task->min_flt; |
| @@ -476,7 +481,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
| 476 | rsslim, | 481 | rsslim, |
| 477 | mm ? mm->start_code : 0, | 482 | mm ? mm->start_code : 0, |
| 478 | mm ? mm->end_code : 0, | 483 | mm ? mm->end_code : 0, |
| 479 | mm ? mm->start_stack : 0, | 484 | (permitted && mm) ? mm->start_stack : 0, |
| 480 | esp, | 485 | esp, |
| 481 | eip, | 486 | eip, |
| 482 | /* The signal information here is obsolete. | 487 | /* The signal information here is obsolete. |
diff --git a/fs/proc/base.c b/fs/proc/base.c index aa763ab0077..fb45615943c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -322,7 +322,10 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) | |||
| 322 | wchan = get_wchan(task); | 322 | wchan = get_wchan(task); |
| 323 | 323 | ||
| 324 | if (lookup_symbol_name(wchan, symname) < 0) | 324 | if (lookup_symbol_name(wchan, symname) < 0) |
| 325 | return sprintf(buffer, "%lu", wchan); | 325 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) |
| 326 | return 0; | ||
| 327 | else | ||
| 328 | return sprintf(buffer, "%lu", wchan); | ||
| 326 | else | 329 | else |
| 327 | return sprintf(buffer, "%s", symname); | 330 | return sprintf(buffer, "%s", symname); |
| 328 | } | 331 | } |
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index 74ea974f5ca..c6b0302af4c 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c | |||
| @@ -35,7 +35,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
| 35 | #define K(x) ((x) << (PAGE_SHIFT - 10)) | 35 | #define K(x) ((x) << (PAGE_SHIFT - 10)) |
| 36 | si_meminfo(&i); | 36 | si_meminfo(&i); |
| 37 | si_swapinfo(&i); | 37 | si_swapinfo(&i); |
| 38 | committed = atomic_long_read(&vm_committed_space); | 38 | committed = percpu_counter_read_positive(&vm_committed_as); |
| 39 | allowed = ((totalram_pages - hugetlb_total_pages()) | 39 | allowed = ((totalram_pages - hugetlb_total_pages()) |
| 40 | * sysctl_overcommit_ratio / 100) + total_swap_pages; | 40 | * sysctl_overcommit_ratio / 100) + total_swap_pages; |
| 41 | 41 | ||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 39e4ad4f59f..6f61b7cc32e 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
| @@ -665,6 +665,10 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
| 665 | goto out_task; | 665 | goto out_task; |
| 666 | 666 | ||
| 667 | ret = 0; | 667 | ret = 0; |
| 668 | |||
| 669 | if (!count) | ||
| 670 | goto out_task; | ||
| 671 | |||
| 668 | mm = get_task_mm(task); | 672 | mm = get_task_mm(task); |
| 669 | if (!mm) | 673 | if (!mm) |
| 670 | goto out_task; | 674 | goto out_task; |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 3a6ed426327..ca7c6005a48 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -5880,7 +5880,7 @@ xfs_getbmap( | |||
| 5880 | void *arg) /* formatter arg */ | 5880 | void *arg) /* formatter arg */ |
| 5881 | { | 5881 | { |
| 5882 | __int64_t bmvend; /* last block requested */ | 5882 | __int64_t bmvend; /* last block requested */ |
| 5883 | int error; /* return value */ | 5883 | int error = 0; /* return value */ |
| 5884 | __int64_t fixlen; /* length for -1 case */ | 5884 | __int64_t fixlen; /* length for -1 case */ |
| 5885 | int i; /* extent number */ | 5885 | int i; /* extent number */ |
| 5886 | int lock; /* lock state */ | 5886 | int lock; /* lock state */ |
| @@ -5890,39 +5890,18 @@ xfs_getbmap( | |||
| 5890 | int nexleft; /* # of user extents left */ | 5890 | int nexleft; /* # of user extents left */ |
| 5891 | int subnex; /* # of bmapi's can do */ | 5891 | int subnex; /* # of bmapi's can do */ |
| 5892 | int nmap; /* number of map entries */ | 5892 | int nmap; /* number of map entries */ |
| 5893 | struct getbmapx out; /* output structure */ | 5893 | struct getbmapx *out; /* output structure */ |
| 5894 | int whichfork; /* data or attr fork */ | 5894 | int whichfork; /* data or attr fork */ |
| 5895 | int prealloced; /* this is a file with | 5895 | int prealloced; /* this is a file with |
| 5896 | * preallocated data space */ | 5896 | * preallocated data space */ |
| 5897 | int iflags; /* interface flags */ | 5897 | int iflags; /* interface flags */ |
| 5898 | int bmapi_flags; /* flags for xfs_bmapi */ | 5898 | int bmapi_flags; /* flags for xfs_bmapi */ |
| 5899 | int cur_ext = 0; | ||
| 5899 | 5900 | ||
| 5900 | mp = ip->i_mount; | 5901 | mp = ip->i_mount; |
| 5901 | iflags = bmv->bmv_iflags; | 5902 | iflags = bmv->bmv_iflags; |
| 5902 | |||
| 5903 | whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; | 5903 | whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; |
| 5904 | 5904 | ||
| 5905 | /* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not | ||
| 5906 | * generate a DMAPI read event. Otherwise, if the DM_EVENT_READ | ||
| 5907 | * bit is set for the file, generate a read event in order | ||
| 5908 | * that the DMAPI application may do its thing before we return | ||
| 5909 | * the extents. Usually this means restoring user file data to | ||
| 5910 | * regions of the file that look like holes. | ||
| 5911 | * | ||
| 5912 | * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify | ||
| 5913 | * BMV_IF_NO_DMAPI_READ so that read events are generated. | ||
| 5914 | * If this were not true, callers of ioctl( XFS_IOC_GETBMAP ) | ||
| 5915 | * could misinterpret holes in a DMAPI file as true holes, | ||
| 5916 | * when in fact they may represent offline user data. | ||
| 5917 | */ | ||
| 5918 | if ((iflags & BMV_IF_NO_DMAPI_READ) == 0 && | ||
| 5919 | DM_EVENT_ENABLED(ip, DM_EVENT_READ) && | ||
| 5920 | whichfork == XFS_DATA_FORK) { | ||
| 5921 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL); | ||
| 5922 | if (error) | ||
| 5923 | return XFS_ERROR(error); | ||
| 5924 | } | ||
| 5925 | |||
| 5926 | if (whichfork == XFS_ATTR_FORK) { | 5905 | if (whichfork == XFS_ATTR_FORK) { |
| 5927 | if (XFS_IFORK_Q(ip)) { | 5906 | if (XFS_IFORK_Q(ip)) { |
| 5928 | if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && | 5907 | if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && |
| @@ -5936,11 +5915,37 @@ xfs_getbmap( | |||
| 5936 | ip->i_mount); | 5915 | ip->i_mount); |
| 5937 | return XFS_ERROR(EFSCORRUPTED); | 5916 | return XFS_ERROR(EFSCORRUPTED); |
| 5938 | } | 5917 | } |
| 5939 | } else if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && | 5918 | |
| 5940 | ip->i_d.di_format != XFS_DINODE_FMT_BTREE && | 5919 | prealloced = 0; |
| 5941 | ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) | 5920 | fixlen = 1LL << 32; |
| 5942 | return XFS_ERROR(EINVAL); | 5921 | } else { |
| 5943 | if (whichfork == XFS_DATA_FORK) { | 5922 | /* |
| 5923 | * If the BMV_IF_NO_DMAPI_READ interface bit specified, do | ||
| 5924 | * not generate a DMAPI read event. Otherwise, if the | ||
| 5925 | * DM_EVENT_READ bit is set for the file, generate a read | ||
| 5926 | * event in order that the DMAPI application may do its thing | ||
| 5927 | * before we return the extents. Usually this means restoring | ||
| 5928 | * user file data to regions of the file that look like holes. | ||
| 5929 | * | ||
| 5930 | * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify | ||
| 5931 | * BMV_IF_NO_DMAPI_READ so that read events are generated. | ||
| 5932 | * If this were not true, callers of ioctl(XFS_IOC_GETBMAP) | ||
| 5933 | * could misinterpret holes in a DMAPI file as true holes, | ||
| 5934 | * when in fact they may represent offline user data. | ||
| 5935 | */ | ||
| 5936 | if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && | ||
| 5937 | !(iflags & BMV_IF_NO_DMAPI_READ)) { | ||
| 5938 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, | ||
| 5939 | 0, 0, 0, NULL); | ||
| 5940 | if (error) | ||
| 5941 | return XFS_ERROR(error); | ||
| 5942 | } | ||
| 5943 | |||
| 5944 | if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && | ||
| 5945 | ip->i_d.di_format != XFS_DINODE_FMT_BTREE && | ||
| 5946 | ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) | ||
| 5947 | return XFS_ERROR(EINVAL); | ||
| 5948 | |||
| 5944 | if (xfs_get_extsz_hint(ip) || | 5949 | if (xfs_get_extsz_hint(ip) || |
| 5945 | ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ | 5950 | ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ |
| 5946 | prealloced = 1; | 5951 | prealloced = 1; |
| @@ -5949,42 +5954,41 @@ xfs_getbmap( | |||
| 5949 | prealloced = 0; | 5954 | prealloced = 0; |
| 5950 | fixlen = ip->i_size; | 5955 | fixlen = ip->i_size; |
| 5951 | } | 5956 | } |
| 5952 | } else { | ||
| 5953 | prealloced = 0; | ||
| 5954 | fixlen = 1LL << 32; | ||
| 5955 | } | 5957 | } |
| 5956 | 5958 | ||
| 5957 | if (bmv->bmv_length == -1) { | 5959 | if (bmv->bmv_length == -1) { |
| 5958 | fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); | 5960 | fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); |
| 5959 | bmv->bmv_length = MAX( (__int64_t)(fixlen - bmv->bmv_offset), | 5961 | bmv->bmv_length = |
| 5960 | (__int64_t)0); | 5962 | max_t(__int64_t, fixlen - bmv->bmv_offset, 0); |
| 5961 | } else if (bmv->bmv_length < 0) | 5963 | } else if (bmv->bmv_length == 0) { |
| 5962 | return XFS_ERROR(EINVAL); | ||
| 5963 | if (bmv->bmv_length == 0) { | ||
| 5964 | bmv->bmv_entries = 0; | 5964 | bmv->bmv_entries = 0; |
| 5965 | return 0; | 5965 | return 0; |
| 5966 | } else if (bmv->bmv_length < 0) { | ||
| 5967 | return XFS_ERROR(EINVAL); | ||
| 5966 | } | 5968 | } |
| 5969 | |||
| 5967 | nex = bmv->bmv_count - 1; | 5970 | nex = bmv->bmv_count - 1; |
| 5968 | if (nex <= 0) | 5971 | if (nex <= 0) |
| 5969 | return XFS_ERROR(EINVAL); | 5972 | return XFS_ERROR(EINVAL); |
| 5970 | bmvend = bmv->bmv_offset + bmv->bmv_length; | 5973 | bmvend = bmv->bmv_offset + bmv->bmv_length; |
| 5971 | 5974 | ||
| 5972 | xfs_ilock(ip, XFS_IOLOCK_SHARED); | ||
| 5973 | 5975 | ||
| 5974 | if (((iflags & BMV_IF_DELALLOC) == 0) && | 5976 | if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) |
| 5975 | (whichfork == XFS_DATA_FORK) && | 5977 | return XFS_ERROR(ENOMEM); |
| 5976 | (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) { | 5978 | out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL); |
| 5977 | /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */ | 5979 | if (!out) |
| 5978 | error = xfs_flush_pages(ip, (xfs_off_t)0, | 5980 | return XFS_ERROR(ENOMEM); |
| 5979 | -1, 0, FI_REMAPF); | 5981 | |
| 5980 | if (error) { | 5982 | xfs_ilock(ip, XFS_IOLOCK_SHARED); |
| 5981 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 5983 | if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) { |
| 5982 | return error; | 5984 | if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) { |
| 5985 | error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF); | ||
| 5986 | if (error) | ||
| 5987 | goto out_unlock_iolock; | ||
| 5983 | } | 5988 | } |
| 5984 | } | ||
| 5985 | 5989 | ||
| 5986 | ASSERT(whichfork == XFS_ATTR_FORK || (iflags & BMV_IF_DELALLOC) || | 5990 | ASSERT(ip->i_delayed_blks == 0); |
| 5987 | ip->i_delayed_blks == 0); | 5991 | } |
| 5988 | 5992 | ||
| 5989 | lock = xfs_ilock_map_shared(ip); | 5993 | lock = xfs_ilock_map_shared(ip); |
| 5990 | 5994 | ||
| @@ -5995,23 +5999,25 @@ xfs_getbmap( | |||
| 5995 | if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) | 5999 | if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) |
| 5996 | nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; | 6000 | nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; |
| 5997 | 6001 | ||
| 5998 | bmapi_flags = xfs_bmapi_aflag(whichfork) | | 6002 | bmapi_flags = xfs_bmapi_aflag(whichfork); |
| 5999 | ((iflags & BMV_IF_PREALLOC) ? 0 : XFS_BMAPI_IGSTATE); | 6003 | if (!(iflags & BMV_IF_PREALLOC)) |
| 6004 | bmapi_flags |= XFS_BMAPI_IGSTATE; | ||
| 6000 | 6005 | ||
| 6001 | /* | 6006 | /* |
| 6002 | * Allocate enough space to handle "subnex" maps at a time. | 6007 | * Allocate enough space to handle "subnex" maps at a time. |
| 6003 | */ | 6008 | */ |
| 6009 | error = ENOMEM; | ||
| 6004 | subnex = 16; | 6010 | subnex = 16; |
| 6005 | map = kmem_alloc(subnex * sizeof(*map), KM_SLEEP); | 6011 | map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL); |
| 6012 | if (!map) | ||
| 6013 | goto out_unlock_ilock; | ||
| 6006 | 6014 | ||
| 6007 | bmv->bmv_entries = 0; | 6015 | bmv->bmv_entries = 0; |
| 6008 | 6016 | ||
| 6009 | if ((XFS_IFORK_NEXTENTS(ip, whichfork) == 0)) { | 6017 | if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0 && |
| 6010 | if (((iflags & BMV_IF_DELALLOC) == 0) || | 6018 | (whichfork == XFS_ATTR_FORK || !(iflags & BMV_IF_DELALLOC))) { |
| 6011 | whichfork == XFS_ATTR_FORK) { | 6019 | error = 0; |
| 6012 | error = 0; | 6020 | goto out_free_map; |
| 6013 | goto unlock_and_return; | ||
| 6014 | } | ||
| 6015 | } | 6021 | } |
| 6016 | 6022 | ||
| 6017 | nexleft = nex; | 6023 | nexleft = nex; |
| @@ -6023,53 +6029,61 @@ xfs_getbmap( | |||
| 6023 | bmapi_flags, NULL, 0, map, &nmap, | 6029 | bmapi_flags, NULL, 0, map, &nmap, |
| 6024 | NULL, NULL); | 6030 | NULL, NULL); |
| 6025 | if (error) | 6031 | if (error) |
| 6026 | goto unlock_and_return; | 6032 | goto out_free_map; |
| 6027 | ASSERT(nmap <= subnex); | 6033 | ASSERT(nmap <= subnex); |
| 6028 | 6034 | ||
| 6029 | for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { | 6035 | for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { |
| 6030 | out.bmv_oflags = 0; | 6036 | out[cur_ext].bmv_oflags = 0; |
| 6031 | if (map[i].br_state == XFS_EXT_UNWRITTEN) | 6037 | if (map[i].br_state == XFS_EXT_UNWRITTEN) |
| 6032 | out.bmv_oflags |= BMV_OF_PREALLOC; | 6038 | out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; |
| 6033 | else if (map[i].br_startblock == DELAYSTARTBLOCK) | 6039 | else if (map[i].br_startblock == DELAYSTARTBLOCK) |
| 6034 | out.bmv_oflags |= BMV_OF_DELALLOC; | 6040 | out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC; |
| 6035 | out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff); | 6041 | out[cur_ext].bmv_offset = |
| 6036 | out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); | 6042 | XFS_FSB_TO_BB(mp, map[i].br_startoff); |
| 6037 | out.bmv_unused1 = out.bmv_unused2 = 0; | 6043 | out[cur_ext].bmv_length = |
| 6044 | XFS_FSB_TO_BB(mp, map[i].br_blockcount); | ||
| 6045 | out[cur_ext].bmv_unused1 = 0; | ||
| 6046 | out[cur_ext].bmv_unused2 = 0; | ||
| 6038 | ASSERT(((iflags & BMV_IF_DELALLOC) != 0) || | 6047 | ASSERT(((iflags & BMV_IF_DELALLOC) != 0) || |
| 6039 | (map[i].br_startblock != DELAYSTARTBLOCK)); | 6048 | (map[i].br_startblock != DELAYSTARTBLOCK)); |
| 6040 | if (map[i].br_startblock == HOLESTARTBLOCK && | 6049 | if (map[i].br_startblock == HOLESTARTBLOCK && |
| 6041 | whichfork == XFS_ATTR_FORK) { | 6050 | whichfork == XFS_ATTR_FORK) { |
| 6042 | /* came to the end of attribute fork */ | 6051 | /* came to the end of attribute fork */ |
| 6043 | out.bmv_oflags |= BMV_OF_LAST; | 6052 | out[cur_ext].bmv_oflags |= BMV_OF_LAST; |
| 6044 | goto unlock_and_return; | 6053 | goto out_free_map; |
| 6045 | } else { | ||
| 6046 | int full = 0; /* user array is full */ | ||
| 6047 | |||
| 6048 | if (!xfs_getbmapx_fix_eof_hole(ip, &out, | ||
| 6049 | prealloced, bmvend, | ||
| 6050 | map[i].br_startblock)) { | ||
| 6051 | goto unlock_and_return; | ||
| 6052 | } | ||
| 6053 | |||
| 6054 | /* format results & advance arg */ | ||
| 6055 | error = formatter(&arg, &out, &full); | ||
| 6056 | if (error || full) | ||
| 6057 | goto unlock_and_return; | ||
| 6058 | nexleft--; | ||
| 6059 | bmv->bmv_offset = | ||
| 6060 | out.bmv_offset + out.bmv_length; | ||
| 6061 | bmv->bmv_length = MAX((__int64_t)0, | ||
| 6062 | (__int64_t)(bmvend - bmv->bmv_offset)); | ||
| 6063 | bmv->bmv_entries++; | ||
| 6064 | } | 6054 | } |
| 6055 | |||
| 6056 | if (!xfs_getbmapx_fix_eof_hole(ip, &out[cur_ext], | ||
| 6057 | prealloced, bmvend, | ||
| 6058 | map[i].br_startblock)) | ||
| 6059 | goto out_free_map; | ||
| 6060 | |||
| 6061 | nexleft--; | ||
| 6062 | bmv->bmv_offset = | ||
| 6063 | out[cur_ext].bmv_offset + | ||
| 6064 | out[cur_ext].bmv_length; | ||
| 6065 | bmv->bmv_length = | ||
| 6066 | max_t(__int64_t, 0, bmvend - bmv->bmv_offset); | ||
| 6067 | bmv->bmv_entries++; | ||
| 6068 | cur_ext++; | ||
| 6065 | } | 6069 | } |
| 6066 | } while (nmap && nexleft && bmv->bmv_length); | 6070 | } while (nmap && nexleft && bmv->bmv_length); |
| 6067 | 6071 | ||
| 6068 | unlock_and_return: | 6072 | out_free_map: |
| 6073 | kmem_free(map); | ||
| 6074 | out_unlock_ilock: | ||
| 6069 | xfs_iunlock_map_shared(ip, lock); | 6075 | xfs_iunlock_map_shared(ip, lock); |
| 6076 | out_unlock_iolock: | ||
| 6070 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 6077 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
| 6071 | 6078 | ||
| 6072 | kmem_free(map); | 6079 | for (i = 0; i < cur_ext; i++) { |
| 6080 | int full = 0; /* user array is full */ | ||
| 6081 | |||
| 6082 | /* format results & advance arg */ | ||
| 6083 | error = formatter(&arg, &out[i], &full); | ||
| 6084 | if (error || full) | ||
| 6085 | break; | ||
| 6086 | } | ||
| 6073 | 6087 | ||
| 6074 | return error; | 6088 | return error; |
| 6075 | } | 6089 | } |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index e7ae08d1df4..123b20c8cbf 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1258,8 +1258,10 @@ xfs_file_last_byte( | |||
| 1258 | * necessary. | 1258 | * necessary. |
| 1259 | */ | 1259 | */ |
| 1260 | if (ip->i_df.if_flags & XFS_IFEXTENTS) { | 1260 | if (ip->i_df.if_flags & XFS_IFEXTENTS) { |
| 1261 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
| 1261 | error = xfs_bmap_last_offset(NULL, ip, &last_block, | 1262 | error = xfs_bmap_last_offset(NULL, ip, &last_block, |
| 1262 | XFS_DATA_FORK); | 1263 | XFS_DATA_FORK); |
| 1264 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
| 1263 | if (error) { | 1265 | if (error) { |
| 1264 | last_block = 0; | 1266 | last_block = 0; |
| 1265 | } | 1267 | } |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index b101990df02..65a99725d0c 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -291,14 +291,17 @@ xfs_mount_validate_sb( | |||
| 291 | sbp->sb_sectsize > XFS_MAX_SECTORSIZE || | 291 | sbp->sb_sectsize > XFS_MAX_SECTORSIZE || |
| 292 | sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || | 292 | sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || |
| 293 | sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || | 293 | sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || |
| 294 | sbp->sb_sectsize != (1 << sbp->sb_sectlog) || | ||
| 294 | sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || | 295 | sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || |
| 295 | sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || | 296 | sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || |
| 296 | sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || | 297 | sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || |
| 297 | sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || | 298 | sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || |
| 299 | sbp->sb_blocksize != (1 << sbp->sb_blocklog) || | ||
| 298 | sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || | 300 | sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || |
| 299 | sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || | 301 | sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || |
| 300 | sbp->sb_inodelog < XFS_DINODE_MIN_LOG || | 302 | sbp->sb_inodelog < XFS_DINODE_MIN_LOG || |
| 301 | sbp->sb_inodelog > XFS_DINODE_MAX_LOG || | 303 | sbp->sb_inodelog > XFS_DINODE_MAX_LOG || |
| 304 | sbp->sb_inodesize != (1 << sbp->sb_inodelog) || | ||
| 302 | (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || | 305 | (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || |
| 303 | (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || | 306 | (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || |
| 304 | (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || | 307 | (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || |
