aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c130
1 files changed, 75 insertions, 55 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index db9d55b507d0..277262a8e82f 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -274,7 +274,8 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
274 char *data_area_of_target; 274 char *data_area_of_target;
275 char *data_area_of_buf2; 275 char *data_area_of_buf2;
276 int remaining; 276 int remaining;
277 __u16 byte_count, total_data_size, total_in_buf, total_in_buf2; 277 unsigned int byte_count, total_in_buf;
278 __u16 total_data_size, total_in_buf2;
278 279
279 total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); 280 total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
280 281
@@ -287,7 +288,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
287 remaining = total_data_size - total_in_buf; 288 remaining = total_data_size - total_in_buf;
288 289
289 if (remaining < 0) 290 if (remaining < 0)
290 return -EINVAL; 291 return -EPROTO;
291 292
292 if (remaining == 0) /* nothing to do, ignore */ 293 if (remaining == 0) /* nothing to do, ignore */
293 return 0; 294 return 0;
@@ -308,20 +309,29 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
308 data_area_of_target += total_in_buf; 309 data_area_of_target += total_in_buf;
309 310
310 /* copy second buffer into end of first buffer */ 311 /* copy second buffer into end of first buffer */
311 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
312 total_in_buf += total_in_buf2; 312 total_in_buf += total_in_buf2;
313 /* is the result too big for the field? */
314 if (total_in_buf > USHRT_MAX)
315 return -EPROTO;
313 put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount); 316 put_unaligned_le16(total_in_buf, &pSMBt->t2_rsp.DataCount);
317
318 /* fix up the BCC */
314 byte_count = get_bcc_le(pTargetSMB); 319 byte_count = get_bcc_le(pTargetSMB);
315 byte_count += total_in_buf2; 320 byte_count += total_in_buf2;
321 /* is the result too big for the field? */
322 if (byte_count > USHRT_MAX)
323 return -EPROTO;
316 put_bcc_le(byte_count, pTargetSMB); 324 put_bcc_le(byte_count, pTargetSMB);
317 325
318 byte_count = pTargetSMB->smb_buf_length; 326 byte_count = pTargetSMB->smb_buf_length;
319 byte_count += total_in_buf2; 327 byte_count += total_in_buf2;
320 328 /* don't allow buffer to overflow */
321 /* BB also add check that we are not beyond maximum buffer size */ 329 if (byte_count > CIFSMaxBufSize)
322 330 return -ENOBUFS;
323 pTargetSMB->smb_buf_length = byte_count; 331 pTargetSMB->smb_buf_length = byte_count;
324 332
333 memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
334
325 if (remaining == total_in_buf2) { 335 if (remaining == total_in_buf2) {
326 cFYI(1, "found the last secondary response"); 336 cFYI(1, "found the last secondary response");
327 return 0; /* we are done */ 337 return 0; /* we are done */
@@ -607,59 +617,63 @@ incomplete_rcv:
607 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { 617 list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
608 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 618 mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
609 619
610 if ((mid_entry->mid == smb_buffer->Mid) && 620 if (mid_entry->mid != smb_buffer->Mid ||
611 (mid_entry->midState == MID_REQUEST_SUBMITTED) && 621 mid_entry->midState != MID_REQUEST_SUBMITTED ||
612 (mid_entry->command == smb_buffer->Command)) { 622 mid_entry->command != smb_buffer->Command) {
613 if (length == 0 && 623 mid_entry = NULL;
614 check2ndT2(smb_buffer, server->maxBuf) > 0) { 624 continue;
615 /* We have a multipart transact2 resp */ 625 }
616 isMultiRsp = true; 626
617 if (mid_entry->resp_buf) { 627 if (length == 0 &&
618 /* merge response - fix up 1st*/ 628 check2ndT2(smb_buffer, server->maxBuf) > 0) {
619 if (coalesce_t2(smb_buffer, 629 /* We have a multipart transact2 resp */
620 mid_entry->resp_buf)) { 630 isMultiRsp = true;
621 mid_entry->multiRsp = 631 if (mid_entry->resp_buf) {
622 true; 632 /* merge response - fix up 1st*/
623 break; 633 length = coalesce_t2(smb_buffer,
624 } else { 634 mid_entry->resp_buf);
625 /* all parts received */ 635 if (length > 0) {
626 mid_entry->multiEnd = 636 length = 0;
627 true; 637 mid_entry->multiRsp = true;
628 goto multi_t2_fnd; 638 break;
629 }
630 } else { 639 } else {
631 if (!isLargeBuf) { 640 /* all parts received or
632 cERROR(1, "1st trans2 resp needs bigbuf"); 641 * packet is malformed
633 /* BB maybe we can fix this up, switch 642 */
634 to already allocated large buffer? */ 643 mid_entry->multiEnd = true;
635 } else { 644 goto multi_t2_fnd;
636 /* Have first buffer */ 645 }
637 mid_entry->resp_buf = 646 } else {
638 smb_buffer; 647 if (!isLargeBuf) {
639 mid_entry->largeBuf = 648 /*
640 true; 649 * FIXME: switch to already
641 bigbuf = NULL; 650 * allocated largebuf?
642 } 651 */
652 cERROR(1, "1st trans2 resp "
653 "needs bigbuf");
654 } else {
655 /* Have first buffer */
656 mid_entry->resp_buf =
657 smb_buffer;
658 mid_entry->largeBuf = true;
659 bigbuf = NULL;
643 } 660 }
644 break;
645 } 661 }
646 mid_entry->resp_buf = smb_buffer; 662 break;
647 mid_entry->largeBuf = isLargeBuf; 663 }
664 mid_entry->resp_buf = smb_buffer;
665 mid_entry->largeBuf = isLargeBuf;
648multi_t2_fnd: 666multi_t2_fnd:
649 if (length == 0) 667 if (length == 0)
650 mid_entry->midState = 668 mid_entry->midState = MID_RESPONSE_RECEIVED;
651 MID_RESPONSE_RECEIVED; 669 else
652 else 670 mid_entry->midState = MID_RESPONSE_MALFORMED;
653 mid_entry->midState =
654 MID_RESPONSE_MALFORMED;
655#ifdef CONFIG_CIFS_STATS2 671#ifdef CONFIG_CIFS_STATS2
656 mid_entry->when_received = jiffies; 672 mid_entry->when_received = jiffies;
657#endif 673#endif
658 list_del_init(&mid_entry->qhead); 674 list_del_init(&mid_entry->qhead);
659 mid_entry->callback(mid_entry); 675 mid_entry->callback(mid_entry);
660 break; 676 break;
661 }
662 mid_entry = NULL;
663 } 677 }
664 spin_unlock(&GlobalMid_Lock); 678 spin_unlock(&GlobalMid_Lock);
665 679
@@ -807,8 +821,7 @@ static int
807cifs_parse_mount_options(char *options, const char *devname, 821cifs_parse_mount_options(char *options, const char *devname,
808 struct smb_vol *vol) 822 struct smb_vol *vol)
809{ 823{
810 char *value; 824 char *value, *data, *end;
811 char *data;
812 unsigned int temp_len, i, j; 825 unsigned int temp_len, i, j;
813 char separator[2]; 826 char separator[2];
814 short int override_uid = -1; 827 short int override_uid = -1;
@@ -851,6 +864,7 @@ cifs_parse_mount_options(char *options, const char *devname,
851 if (!options) 864 if (!options)
852 return 1; 865 return 1;
853 866
867 end = options + strlen(options);
854 if (strncmp(options, "sep=", 4) == 0) { 868 if (strncmp(options, "sep=", 4) == 0) {
855 if (options[4] != 0) { 869 if (options[4] != 0) {
856 separator[0] = options[4]; 870 separator[0] = options[4];
@@ -916,6 +930,7 @@ cifs_parse_mount_options(char *options, const char *devname,
916 the only illegal character in a password is null */ 930 the only illegal character in a password is null */
917 931
918 if ((value[temp_len] == 0) && 932 if ((value[temp_len] == 0) &&
933 (value + temp_len < end) &&
919 (value[temp_len+1] == separator[0])) { 934 (value[temp_len+1] == separator[0])) {
920 /* reinsert comma */ 935 /* reinsert comma */
921 value[temp_len] = separator[0]; 936 value[temp_len] = separator[0];
@@ -2658,6 +2673,11 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon,
2658 0 /* not legacy */, cifs_sb->local_nls, 2673 0 /* not legacy */, cifs_sb->local_nls,
2659 cifs_sb->mnt_cifs_flags & 2674 cifs_sb->mnt_cifs_flags &
2660 CIFS_MOUNT_MAP_SPECIAL_CHR); 2675 CIFS_MOUNT_MAP_SPECIAL_CHR);
2676
2677 if (rc == -EOPNOTSUPP || rc == -EINVAL)
2678 rc = SMBQueryInformation(xid, tcon, full_path, pfile_info,
2679 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
2680 CIFS_MOUNT_MAP_SPECIAL_CHR);
2661 kfree(pfile_info); 2681 kfree(pfile_info);
2662 return rc; 2682 return rc;
2663} 2683}