diff options
-rw-r--r-- | fs/cifs/CHANGES | 3 | ||||
-rw-r--r-- | fs/cifs/README | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 18 | ||||
-rw-r--r-- | fs/cifs/connect.c | 23 | ||||
-rw-r--r-- | fs/cifs/sess.c | 44 |
6 files changed, 58 insertions, 36 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 79a202b8f66a..a61d17ed1827 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -7,7 +7,8 @@ so we can do search (ls etc.) to OS/2. Do not send NTCreateX | |||
7 | or recent levels of FindFirst unless server says it supports NT SMBs | 7 | or recent levels of FindFirst unless server says it supports NT SMBs |
8 | (instead use legacy equivalents from LANMAN dialect). Fix to allow | 8 | (instead use legacy equivalents from LANMAN dialect). Fix to allow |
9 | NTLMv2 authentication support (now can use stronger password hashing | 9 | NTLMv2 authentication support (now can use stronger password hashing |
10 | on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004) | 10 | on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004). |
11 | Allow override of global cifs security flags on mount via "sec=" option(s). | ||
11 | 12 | ||
12 | Version 1.43 | 13 | Version 1.43 |
13 | ------------ | 14 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index 46c2cfa5acf3..7986d0d97ace 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -443,7 +443,10 @@ A partial list of the supported mount options follows: | |||
443 | SFU does). In the future the bottom 9 bits of the mode | 443 | SFU does). In the future the bottom 9 bits of the mode |
444 | mode also will be emulated using queries of the security | 444 | mode also will be emulated using queries of the security |
445 | descriptor (ACL). | 445 | descriptor (ACL). |
446 | sec Security mode. Allowed values are: | 446 | sign Must use packet signing (helps avoid unwanted data modification |
447 | by intermediate systems in the route). Note that signing | ||
448 | does not work with lanman or plaintext authentication. | ||
449 | sec Security mode. Allowed values are: | ||
447 | none attempt to connection as a null user (no name) | 450 | none attempt to connection as a null user (no name) |
448 | krb5 Use Kerberos version 5 authentication | 451 | krb5 Use Kerberos version 5 authentication |
449 | krb5i Use Kerberos authentication and packet signing | 452 | krb5i Use Kerberos authentication and packet signing |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 87453a6bcaf8..6d7cf5f3bc0b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -186,6 +186,7 @@ struct cifsSesInfo { | |||
186 | struct TCP_Server_Info *server; /* pointer to server info */ | 186 | struct TCP_Server_Info *server; /* pointer to server info */ |
187 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ | 187 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ |
188 | enum statusEnum status; | 188 | enum statusEnum status; |
189 | unsigned overrideSecFlg; /* if non-zero override global sec flags */ | ||
189 | __u16 ipc_tid; /* special tid for connection to IPC share */ | 190 | __u16 ipc_tid; /* special tid for connection to IPC share */ |
190 | __u16 flags; | 191 | __u16 flags; |
191 | char *serverOS; /* name of operating system underlying server */ | 192 | char *serverOS; /* name of operating system underlying server */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 38f83db20764..de405bfb67d2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -396,6 +396,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
396 | int i; | 396 | int i; |
397 | struct TCP_Server_Info * server; | 397 | struct TCP_Server_Info * server; |
398 | u16 count; | 398 | u16 count; |
399 | unsigned int secFlags; | ||
399 | 400 | ||
400 | if(ses->server) | 401 | if(ses->server) |
401 | server = ses->server; | 402 | server = ses->server; |
@@ -407,9 +408,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
407 | (void **) &pSMB, (void **) &pSMBr); | 408 | (void **) &pSMB, (void **) &pSMBr); |
408 | if (rc) | 409 | if (rc) |
409 | return rc; | 410 | return rc; |
411 | |||
412 | /* if any of auth flags (ie not sign or seal) are overriden use them */ | ||
413 | if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
414 | secFlags = ses->overrideSecFlg; | ||
415 | else /* if override flags set only sign/seal OR them with global auth */ | ||
416 | secFlags = extended_security | ses->overrideSecFlg; | ||
417 | |||
410 | pSMB->hdr.Mid = GetNextMid(server); | 418 | pSMB->hdr.Mid = GetNextMid(server); |
411 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 419 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
412 | if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) | 420 | if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) |
413 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 421 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
414 | 422 | ||
415 | count = 0; | 423 | count = 0; |
@@ -439,8 +447,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
439 | && (pSMBr->DialectIndex == LANMAN_PROT)) { | 447 | && (pSMBr->DialectIndex == LANMAN_PROT)) { |
440 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; | 448 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; |
441 | 449 | ||
442 | if((extended_security & CIFSSEC_MAY_LANMAN) || | 450 | if((secFlags & CIFSSEC_MAY_LANMAN) || |
443 | (extended_security & CIFSSEC_MAY_PLNTXT)) | 451 | (secFlags & CIFSSEC_MAY_PLNTXT)) |
444 | server->secType = LANMAN; | 452 | server->secType = LANMAN; |
445 | else { | 453 | else { |
446 | cERROR(1, ("mount failed weak security disabled" | 454 | cERROR(1, ("mount failed weak security disabled" |
@@ -498,12 +506,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
498 | 506 | ||
499 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) | 507 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) |
500 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 508 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
501 | if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) | 509 | if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) |
502 | #endif /* CIFS_WEAK_PW_HASH */ | 510 | #endif /* CIFS_WEAK_PW_HASH */ |
503 | cERROR(1,("Server requests plain text password" | 511 | cERROR(1,("Server requests plain text password" |
504 | " but client support disabled")); | 512 | " but client support disabled")); |
505 | 513 | ||
506 | if(extended_security & CIFSSEC_MUST_NTLMV2) | 514 | if(secFlags & CIFSSEC_MUST_NTLMV2) |
507 | server->secType = NTLMv2; | 515 | server->secType = NTLMv2; |
508 | else | 516 | else |
509 | server->secType = NTLM; | 517 | server->secType = NTLM; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c0f98ddea88c..876eb9ef85fe 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -915,32 +915,32 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
915 | cERROR(1,("no security value specified")); | 915 | cERROR(1,("no security value specified")); |
916 | continue; | 916 | continue; |
917 | } else if (strnicmp(value, "krb5i", 5) == 0) { | 917 | } else if (strnicmp(value, "krb5i", 5) == 0) { |
918 | vol->secFlg = CIFSSEC_MAY_KRB5 | | 918 | vol->secFlg |= CIFSSEC_MAY_KRB5 | |
919 | CIFSSEC_MUST_SIGN; | 919 | CIFSSEC_MUST_SIGN; |
920 | } else if (strnicmp(value, "krb5p", 5) == 0) { | 920 | } else if (strnicmp(value, "krb5p", 5) == 0) { |
921 | /* vol->secFlg = CIFSSEC_MUST_SEAL | | 921 | /* vol->secFlg |= CIFSSEC_MUST_SEAL | |
922 | CIFSSEC_MAY_KRB5; */ | 922 | CIFSSEC_MAY_KRB5; */ |
923 | cERROR(1,("Krb5 cifs privacy not supported")); | 923 | cERROR(1,("Krb5 cifs privacy not supported")); |
924 | return 1; | 924 | return 1; |
925 | } else if (strnicmp(value, "krb5", 4) == 0) { | 925 | } else if (strnicmp(value, "krb5", 4) == 0) { |
926 | vol->secFlg = CIFSSEC_MAY_KRB5; | 926 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
927 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 927 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
928 | vol->secFlg = CIFSSEC_MAY_NTLMV2 | | 928 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
929 | CIFSSEC_MUST_SIGN; | 929 | CIFSSEC_MUST_SIGN; |
930 | } else if (strnicmp(value, "ntlmv2", 6) == 0) { | 930 | } else if (strnicmp(value, "ntlmv2", 6) == 0) { |
931 | vol->secFlg = CIFSSEC_MAY_NTLMV2; | 931 | vol->secFlg |= CIFSSEC_MAY_NTLMV2; |
932 | } else if (strnicmp(value, "ntlmi", 5) == 0) { | 932 | } else if (strnicmp(value, "ntlmi", 5) == 0) { |
933 | vol->secFlg = CIFSSEC_MAY_NTLM | | 933 | vol->secFlg |= CIFSSEC_MAY_NTLM | |
934 | CIFSSEC_MUST_SIGN; | 934 | CIFSSEC_MUST_SIGN; |
935 | } else if (strnicmp(value, "ntlm", 4) == 0) { | 935 | } else if (strnicmp(value, "ntlm", 4) == 0) { |
936 | /* ntlm is default so can be turned off too */ | 936 | /* ntlm is default so can be turned off too */ |
937 | vol->secFlg = CIFSSEC_MAY_NTLM; | 937 | vol->secFlg |= CIFSSEC_MAY_NTLM; |
938 | } else if (strnicmp(value, "nontlm", 6) == 0) { | 938 | } else if (strnicmp(value, "nontlm", 6) == 0) { |
939 | /* BB is there a better way to do this? */ | 939 | /* BB is there a better way to do this? */ |
940 | vol->secFlg = CIFSSEC_MAY_NTLMV2; | 940 | vol->secFlg |= CIFSSEC_MAY_NTLMV2; |
941 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 941 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
942 | } else if (strnicmp(value, "lanman", 6) == 0) { | 942 | } else if (strnicmp(value, "lanman", 6) == 0) { |
943 | vol->secFlg = CIFSSEC_MAY_LANMAN; | 943 | vol->secFlg |= CIFSSEC_MAY_LANMAN; |
944 | #endif | 944 | #endif |
945 | } else if (strnicmp(value, "none", 4) == 0) { | 945 | } else if (strnicmp(value, "none", 4) == 0) { |
946 | vol->nullauth = 1; | 946 | vol->nullauth = 1; |
@@ -1173,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
1173 | vol->no_psx_acl = 0; | 1173 | vol->no_psx_acl = 0; |
1174 | } else if (strnicmp(data, "noacl",5) == 0) { | 1174 | } else if (strnicmp(data, "noacl",5) == 0) { |
1175 | vol->no_psx_acl = 1; | 1175 | vol->no_psx_acl = 1; |
1176 | } else if (strnicmp(data, "sign",4) == 0) { | ||
1177 | vol->secFlg |= CIFSSEC_MUST_SIGN; | ||
1178 | /* } else if (strnicmp(data, "seal",4) == 0) { | ||
1179 | vol->secFlg |= CIFSSEC_MUST_SEAL; */ | ||
1176 | } else if (strnicmp(data, "direct",6) == 0) { | 1180 | } else if (strnicmp(data, "direct",6) == 0) { |
1177 | vol->direct_io = 1; | 1181 | vol->direct_io = 1; |
1178 | } else if (strnicmp(data, "forcedirectio",13) == 0) { | 1182 | } else if (strnicmp(data, "forcedirectio",13) == 0) { |
@@ -1776,6 +1780,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1776 | volume_info.domainname); | 1780 | volume_info.domainname); |
1777 | } | 1781 | } |
1778 | pSesInfo->linux_uid = volume_info.linux_uid; | 1782 | pSesInfo->linux_uid = volume_info.linux_uid; |
1783 | pSesInfo->overrideSecFlg = volume_info.secFlg; | ||
1779 | down(&pSesInfo->sesSem); | 1784 | down(&pSesInfo->sesSem); |
1780 | /* BB FIXME need to pass vol->secFlgs BB */ | 1785 | /* BB FIXME need to pass vol->secFlgs BB */ |
1781 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); | 1786 | rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 70e32a81c213..7737edd1baf1 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -138,7 +138,7 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, | |||
138 | strncpy(bcc_ptr, ses->userName, 300); | 138 | strncpy(bcc_ptr, ses->userName, 300); |
139 | } | 139 | } |
140 | /* BB improve check for overflow */ | 140 | /* BB improve check for overflow */ |
141 | bcc_ptr += strnlen(ses->userName, 200); | 141 | bcc_ptr += strnlen(ses->userName, 300); |
142 | *bcc_ptr = 0; | 142 | *bcc_ptr = 0; |
143 | bcc_ptr++; /* account for null termination */ | 143 | bcc_ptr++; /* account for null termination */ |
144 | 144 | ||
@@ -313,11 +313,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
313 | int wct; | 313 | int wct; |
314 | struct smb_hdr *smb_buf; | 314 | struct smb_hdr *smb_buf; |
315 | char *bcc_ptr; | 315 | char *bcc_ptr; |
316 | char *str_area; | ||
316 | SESSION_SETUP_ANDX *pSMB; | 317 | SESSION_SETUP_ANDX *pSMB; |
317 | __u32 capabilities; | 318 | __u32 capabilities; |
318 | int count; | 319 | int count; |
319 | int resp_buf_type = 0; | 320 | int resp_buf_type = 0; |
320 | struct kvec iov[2]; /* BB split variable length info into 2nd iovec */ | 321 | struct kvec iov[2]; |
321 | enum securityEnum type; | 322 | enum securityEnum type; |
322 | __u16 action; | 323 | __u16 action; |
323 | int bytes_remaining; | 324 | int bytes_remaining; |
@@ -351,7 +352,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
351 | pSMB = (SESSION_SETUP_ANDX *)smb_buf; | 352 | pSMB = (SESSION_SETUP_ANDX *)smb_buf; |
352 | 353 | ||
353 | capabilities = cifs_ssetup_hdr(ses, pSMB); | 354 | capabilities = cifs_ssetup_hdr(ses, pSMB); |
354 | bcc_ptr = pByteArea(smb_buf); | 355 | |
356 | /* we will send the SMB in two pieces, | ||
357 | a fixed length beginning part, and a | ||
358 | second part which will include the strings | ||
359 | and rest of bcc area, in order to avoid having | ||
360 | to do a large buffer 17K allocation */ | ||
361 | iov[0].iov_base = (char *)pSMB; | ||
362 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | ||
363 | |||
364 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | ||
365 | str_area = kmalloc(2000, GFP_KERNEL); | ||
366 | bcc_ptr = str_area; | ||
355 | 367 | ||
356 | if(type == LANMAN) { | 368 | if(type == LANMAN) { |
357 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 369 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
@@ -365,10 +377,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
365 | 377 | ||
366 | calc_lanman_hash(ses, lnm_session_key); | 378 | calc_lanman_hash(ses, lnm_session_key); |
367 | 379 | ||
368 | #ifdef CONFIG_CIFS_DEBUG2 | 380 | /* #ifdef CONFIG_CIFS_DEBUG2 |
369 | cifs_dump_mem("cryptkey: ",ses->server->cryptKey, | 381 | cifs_dump_mem("cryptkey: ",ses->server->cryptKey, |
370 | CIFS_SESS_KEY_SIZE); | 382 | CIFS_SESS_KEY_SIZE); |
371 | #endif | 383 | #endif */ |
372 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); | 384 | memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); |
373 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 385 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
374 | 386 | ||
@@ -377,7 +389,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
377 | changed to do higher than lanman dialect and | 389 | changed to do higher than lanman dialect and |
378 | we reconnected would we ever calc signing_key? */ | 390 | we reconnected would we ever calc signing_key? */ |
379 | 391 | ||
380 | cERROR(1,("Negotiating LANMAN setting up strings")); | 392 | cFYI(1,("Negotiating LANMAN setting up strings")); |
381 | /* Unicode not allowed for LANMAN dialects */ | 393 | /* Unicode not allowed for LANMAN dialects */ |
382 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 394 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
383 | #endif | 395 | #endif |
@@ -396,7 +408,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
396 | 408 | ||
397 | if(first_time) /* should this be moved into common code | 409 | if(first_time) /* should this be moved into common code |
398 | with similar ntlmv2 path? */ | 410 | with similar ntlmv2 path? */ |
399 | cifs_calculate_mac_key( ses->server->mac_signing_key, | 411 | cifs_calculate_mac_key(ses->server->mac_signing_key, |
400 | ntlm_session_key, ses->password); | 412 | ntlm_session_key, ses->password); |
401 | /* copy session key */ | 413 | /* copy session key */ |
402 | 414 | ||
@@ -454,23 +466,14 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
454 | /* BB set password lengths */ | 466 | /* BB set password lengths */ |
455 | } | 467 | } |
456 | 468 | ||
457 | count = (long) bcc_ptr - (long) pByteArea(smb_buf); | 469 | count = (long) bcc_ptr - (long) str_area; |
458 | smb_buf->smb_buf_length += count; | 470 | smb_buf->smb_buf_length += count; |
459 | 471 | ||
460 | /* if we switch to small buffers, count will need to be fewer | ||
461 | than 383 (strings less than 335 bytes) */ | ||
462 | |||
463 | BCC_LE(smb_buf) = cpu_to_le16(count); | 472 | BCC_LE(smb_buf) = cpu_to_le16(count); |
464 | 473 | ||
465 | 474 | iov[1].iov_base = str_area; | |
466 | /* BB FIXME check for other non ntlm code paths */ | 475 | iov[1].iov_len = count; |
467 | 476 | rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); | |
468 | /* BB check is this too big for a small smb? */ | ||
469 | |||
470 | iov[0].iov_base = (char *)pSMB; | ||
471 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | ||
472 | |||
473 | rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0); | ||
474 | /* SMB request buf freed in SendReceive2 */ | 477 | /* SMB request buf freed in SendReceive2 */ |
475 | 478 | ||
476 | cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); | 479 | cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); |
@@ -515,6 +518,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
515 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); | 518 | rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); |
516 | 519 | ||
517 | ssetup_exit: | 520 | ssetup_exit: |
521 | kfree(str_area); | ||
518 | if(resp_buf_type == CIFS_SMALL_BUFFER) { | 522 | if(resp_buf_type == CIFS_SMALL_BUFFER) { |
519 | cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); | 523 | cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); |
520 | cifs_small_buf_release(iov[0].iov_base); | 524 | cifs_small_buf_release(iov[0].iov_base); |