diff options
author | Steve French <sfrench@us.ibm.com> | 2006-09-30 00:13:17 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-09-30 00:13:17 -0400 |
commit | 9ac00b7d96045fa3ce573e0ad5cdc0350ad8e1d2 (patch) | |
tree | 80ee9890d64f6c4b899144df8ee0c6cd9361aafb | |
parent | f46d3e11903e452924ef2996aa9aca2aae4427e2 (diff) |
[CIFS] Do not send newer QFSInfo to legacy servers which can not support it
Fix dialect negotiation to save off when we have negotiated lanman.
This allows us to avoid sending some somewhat newer requests that the server
can not handle and go directly to the older version (infolevel) of the same
call. Make sure we try to negotiate a level which allows us to get the
server OS (which we check so we can detect Win9x vs. other legacy servers
and eventually work around the Win9x DOS time bug (they reverse date/time
fields).
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifsfs.c | 8 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 9 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 8 | ||||
-rw-r--r-- | fs/cifs/connect.c | 1 | ||||
-rw-r--r-- | fs/cifs/sess.c | 23 |
6 files changed, 32 insertions, 20 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ca53720fa5b1..d6d226addde2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -199,10 +199,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
199 | /* Only need to call the old QFSInfo if failed | 199 | /* Only need to call the old QFSInfo if failed |
200 | on newer one */ | 200 | on newer one */ |
201 | if(rc) | 201 | if(rc) |
202 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); | 202 | if((pTcon->ses->flags & CIFS_SES_LANMAN) == 0) |
203 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ | ||
203 | 204 | ||
204 | /* Old Windows servers do not support level 103, retry with level | 205 | /* Some old Windows servers also do not support level 103, retry with |
205 | one if old server failed the previous call */ | 206 | older level one if old server failed the previous call or we |
207 | bypassed it because we detected that this was an older LANMAN sess */ | ||
206 | if(rc) | 208 | if(rc) |
207 | rc = SMBOldQFSInfo(xid, pTcon, buf); | 209 | rc = SMBOldQFSInfo(xid, pTcon, buf); |
208 | /* | 210 | /* |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 98eb5446e8c1..597afdf4c69c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -203,9 +203,14 @@ struct cifsSesInfo { | |||
203 | char * domainName; | 203 | char * domainName; |
204 | char * password; | 204 | char * password; |
205 | }; | 205 | }; |
206 | /* session flags */ | 206 | /* no more than one of the following three session flags may be set */ |
207 | #define CIFS_SES_NT4 1 | 207 | #define CIFS_SES_NT4 1 |
208 | 208 | #define CIFS_SES_OS2 2 | |
209 | #define CIFS_SES_W9X 4 | ||
210 | /* following flag is set for old servers such as OS2 (and Win95?) | ||
211 | which do not negotiate NTLM or POSIX dialects, but instead | ||
212 | negotiate one of the older LANMAN dialects */ | ||
213 | #define CIFS_SES_LANMAN 8 | ||
209 | /* | 214 | /* |
210 | * there is one of these for each connection to a resource on a particular | 215 | * there is one of these for each connection to a resource on a particular |
211 | * session | 216 | * session |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e5dd8708d636..50505422dbb4 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -26,7 +26,8 @@ | |||
26 | 26 | ||
27 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 27 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
28 | #define LANMAN_PROT 0 | 28 | #define LANMAN_PROT 0 |
29 | #define CIFS_PROT 1 | 29 | #define LANMAN2_PROT 1 |
30 | #define CIFS_PROT 2 | ||
30 | #else | 31 | #else |
31 | #define CIFS_PROT 0 | 32 | #define CIFS_PROT 0 |
32 | #endif | 33 | #endif |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6e004587fa48..f2fa05bbcb47 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -46,6 +46,7 @@ static struct { | |||
46 | } protocols[] = { | 46 | } protocols[] = { |
47 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 47 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
48 | {LANMAN_PROT, "\2LM1.2X002"}, | 48 | {LANMAN_PROT, "\2LM1.2X002"}, |
49 | {LANMAN2_PROT, "\2LANMAN2.1"}, | ||
49 | #endif /* weak password hashing for legacy clients */ | 50 | #endif /* weak password hashing for legacy clients */ |
50 | {CIFS_PROT, "\2NT LM 0.12"}, | 51 | {CIFS_PROT, "\2NT LM 0.12"}, |
51 | {POSIX_PROT, "\2POSIX 2"}, | 52 | {POSIX_PROT, "\2POSIX 2"}, |
@@ -67,13 +68,13 @@ static struct { | |||
67 | /* define the number of elements in the cifs dialect array */ | 68 | /* define the number of elements in the cifs dialect array */ |
68 | #ifdef CONFIG_CIFS_POSIX | 69 | #ifdef CONFIG_CIFS_POSIX |
69 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 70 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
70 | #define CIFS_NUM_PROT 3 | 71 | #define CIFS_NUM_PROT 4 |
71 | #else | 72 | #else |
72 | #define CIFS_NUM_PROT 2 | 73 | #define CIFS_NUM_PROT 2 |
73 | #endif /* CIFS_WEAK_PW_HASH */ | 74 | #endif /* CIFS_WEAK_PW_HASH */ |
74 | #else /* not posix */ | 75 | #else /* not posix */ |
75 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 76 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
76 | #define CIFS_NUM_PROT 2 | 77 | #define CIFS_NUM_PROT 3 |
77 | #else | 78 | #else |
78 | #define CIFS_NUM_PROT 1 | 79 | #define CIFS_NUM_PROT 1 |
79 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | 80 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ |
@@ -446,7 +447,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
446 | goto neg_err_exit; | 447 | goto neg_err_exit; |
447 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 448 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
448 | } else if((pSMBr->hdr.WordCount == 13) | 449 | } else if((pSMBr->hdr.WordCount == 13) |
449 | && (pSMBr->DialectIndex == LANMAN_PROT)) { | 450 | && ((pSMBr->DialectIndex == LANMAN_PROT) |
451 | || (pSMBr->DialectIndex == LANMAN2_PROT))) { | ||
450 | int tmp, adjust; | 452 | int tmp, adjust; |
451 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; | 453 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; |
452 | 454 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 083b2b2c1571..c96f3edf1b9c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -3316,6 +3316,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3316 | first_time = 1; | 3316 | first_time = 1; |
3317 | } | 3317 | } |
3318 | if (!rc) { | 3318 | if (!rc) { |
3319 | pSesInfo->flags = 0; | ||
3319 | pSesInfo->capabilities = pSesInfo->server->capabilities; | 3320 | pSesInfo->capabilities = pSesInfo->server->capabilities; |
3320 | if(linuxExtEnabled == 0) | 3321 | if(linuxExtEnabled == 0) |
3321 | pSesInfo->capabilities &= (~CAP_UNIX); | 3322 | pSesInfo->capabilities &= (~CAP_UNIX); |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d1705ab8136e..e4c4e466e320 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -268,6 +268,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo | |||
268 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | 268 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); |
269 | if(ses->serverOS) | 269 | if(ses->serverOS) |
270 | strncpy(ses->serverOS, bcc_ptr, len); | 270 | strncpy(ses->serverOS, bcc_ptr, len); |
271 | if(strncmp(ses->serverOS, "OS/2",4) == 0) { | ||
272 | cFYI(1,("OS/2 server")); | ||
273 | ses->flags |= CIFS_SES_OS2; | ||
274 | } | ||
271 | 275 | ||
272 | bcc_ptr += len + 1; | 276 | bcc_ptr += len + 1; |
273 | bleft -= len + 1; | 277 | bleft -= len + 1; |
@@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo | |||
290 | if(len > bleft) | 294 | if(len > bleft) |
291 | return rc; | 295 | return rc; |
292 | 296 | ||
293 | if(ses->serverDomain) | 297 | /* No domain field in LANMAN case. Domain is |
294 | kfree(ses->serverDomain); | 298 | returned by old servers in the SMB negprot response */ |
295 | 299 | /* BB For newer servers which do not support Unicode, | |
296 | ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); | 300 | but thus do return domain here we could add parsing |
297 | if(ses->serverOS) | 301 | for it later, but it is not very important */ |
298 | strncpy(ses->serverOS, bcc_ptr, len); | ||
299 | |||
300 | bcc_ptr += len + 1; | ||
301 | bleft -= len + 1; | ||
302 | |||
303 | cFYI(1,("ascii: bytes left %d",bleft)); | 302 | cFYI(1,("ascii: bytes left %d",bleft)); |
304 | 303 | ||
305 | return rc; | 304 | return rc; |
@@ -366,6 +365,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
366 | str_area = kmalloc(2000, GFP_KERNEL); | 365 | str_area = kmalloc(2000, GFP_KERNEL); |
367 | bcc_ptr = str_area; | 366 | bcc_ptr = str_area; |
368 | 367 | ||
368 | ses->flags &= ~CIFS_SES_LANMAN; | ||
369 | |||
369 | if(type == LANMAN) { | 370 | if(type == LANMAN) { |
370 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 371 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
371 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; | 372 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; |
@@ -377,7 +378,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
377 | /* and copy into bcc */ | 378 | /* and copy into bcc */ |
378 | 379 | ||
379 | calc_lanman_hash(ses, lnm_session_key); | 380 | calc_lanman_hash(ses, lnm_session_key); |
380 | 381 | ses->flags |= CIFS_SES_LANMAN; | |
381 | /* #ifdef CONFIG_CIFS_DEBUG2 | 382 | /* #ifdef CONFIG_CIFS_DEBUG2 |
382 | cifs_dump_mem("cryptkey: ",ses->server->cryptKey, | 383 | cifs_dump_mem("cryptkey: ",ses->server->cryptKey, |
383 | CIFS_SESS_KEY_SIZE); | 384 | CIFS_SESS_KEY_SIZE); |