aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-10-13 11:09:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-13 11:09:29 -0400
commit12e36b2f41b6cbc67386fcb9c59c32a3e2033905 (patch)
treeec1794bae2f96eef6cc2afb2fa5c48e6fd346316 /fs
parent1baaf0b424fe611a99cf3e2e59e84df0561d679a (diff)
parent1a4e15a04ec69cb3552f4120079f5472377df5f7 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (27 commits) [CIFS] Missing flags2 for DFS [CIFS] Workaround incomplete byte length returned by some [CIFS] cifs Kconfig: don't select CONNECTOR [CIFS] Level 1 QPathInfo needed for proper OS2 support [CIFS] fix typo in previous patch [CIFS] Fix old DOS time conversion to handle timezone [CIFS] Do not need to adjust for Jan/Feb for leap day [CIFS] Fix leaps year calculation for years after 2100 [CIFS] readdir (ffirst) enablement of accurate timestamps from legacy servers [CIFS] Fix compiler warning with previous patch [CIFS] Fix typo [CIFS] Allow for 15 minute TZs (e.g. Nepal) and be more explicit about [CIFS] Fix readdir of large directories for backlevel servers [CIFS] Allow LANMAN21 support even in both POSIX non-POSIX path [CIFS] Make use of newer QFSInfo dependent on capability bit instead of [CIFS] Do not send newer QFSInfo to legacy servers which can not support it [CIFS] Fix typo in name of new cifs_show_stats [CIFS] Rename server time zone field [CIFS] Handle legacy servers which return undefined time zone [CIFS] CIFS support for /proc/<pid>/mountstats part 1 ... Manual conflict resolution in fs/cifs/connect.c
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/cifs/cifsacl.h4
-rw-r--r--fs/cifs/cifsencrypt.h2
-rw-r--r--fs/cifs/cifsfs.c27
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h15
-rw-r--r--fs/cifs/cifspdu.h12
-rw-r--r--fs/cifs/cifsproto.h12
-rw-r--r--fs/cifs/cifssmb.c96
-rw-r--r--fs/cifs/connect.c35
-rw-r--r--fs/cifs/inode.c12
-rw-r--r--fs/cifs/link.c6
-rw-r--r--fs/cifs/md5.c8
-rw-r--r--fs/cifs/md5.h8
-rw-r--r--fs/cifs/misc.c44
-rw-r--r--fs/cifs/netmisc.c58
-rw-r--r--fs/cifs/readdir.c27
-rw-r--r--fs/cifs/sess.c23
-rw-r--r--fs/cifs/smbdes.c6
-rw-r--r--fs/cifs/smbencrypt.c11
20 files changed, 312 insertions, 98 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index db4d13324c36..6a3df055280a 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1986,7 +1986,7 @@ config CIFS_EXPERIMENTAL
1986config CIFS_UPCALL 1986config CIFS_UPCALL
1987 bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" 1987 bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
1988 depends on CIFS_EXPERIMENTAL 1988 depends on CIFS_EXPERIMENTAL
1989 select CONNECTOR 1989 depends on CONNECTOR
1990 help 1990 help
1991 Enables an upcall mechanism for CIFS which will be used to contact 1991 Enables an upcall mechanism for CIFS which will be used to contact
1992 userspace helper utilities to provide SPNEGO packaged Kerberos 1992 userspace helper utilities to provide SPNEGO packaged Kerberos
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index d0776ac2b804..5eff35d6e564 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -31,8 +31,8 @@ struct cifs_sid {
31} __attribute__((packed)); 31} __attribute__((packed));
32 32
33/* everyone */ 33/* everyone */
34extern const struct cifs_sid sid_everyone; 34/* extern const struct cifs_sid sid_everyone;*/
35/* group users */ 35/* group users */
36extern const struct cifs_sid sid_user; 36/* extern const struct cifs_sid sid_user;*/
37 37
38#endif /* _CIFSACL_H */ 38#endif /* _CIFSACL_H */
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
index 03e359b32861..152fa2dcfc6c 100644
--- a/fs/cifs/cifsencrypt.h
+++ b/fs/cifs/cifsencrypt.h
@@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n);
27/* smbdes.c */ 27/* smbdes.c */
28extern void E_P16(unsigned char *p14, unsigned char *p16); 28extern void E_P16(unsigned char *p14, unsigned char *p16);
29extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); 29extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
30extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
31extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *);
32 30
33 31
34 32
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c00c654f2e11..84976cdbe713 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -63,6 +63,7 @@ extern struct task_struct * oplockThread; /* remove sparse warning */
63struct task_struct * oplockThread = NULL; 63struct task_struct * oplockThread = NULL;
64extern struct task_struct * dnotifyThread; /* remove sparse warning */ 64extern struct task_struct * dnotifyThread; /* remove sparse warning */
65struct task_struct * dnotifyThread = NULL; 65struct task_struct * dnotifyThread = NULL;
66static struct super_operations cifs_super_ops;
66unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; 67unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
67module_param(CIFSMaxBufSize, int, 0); 68module_param(CIFSMaxBufSize, int, 0);
68MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); 69MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
@@ -198,10 +199,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
198 /* Only need to call the old QFSInfo if failed 199 /* Only need to call the old QFSInfo if failed
199 on newer one */ 200 on newer one */
200 if(rc) 201 if(rc)
201 rc = CIFSSMBQFSInfo(xid, pTcon, buf); 202 if(pTcon->ses->capabilities & CAP_NT_SMBS)
203 rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
202 204
203 /* Old Windows servers do not support level 103, retry with level 205 /* Some old Windows servers also do not support level 103, retry with
204 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 */
205 if(rc) 208 if(rc)
206 rc = SMBOldQFSInfo(xid, pTcon, buf); 209 rc = SMBOldQFSInfo(xid, pTcon, buf);
207 /* 210 /*
@@ -435,13 +438,21 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
435 return; 438 return;
436} 439}
437 440
441#ifdef CONFIG_CIFS_STATS2
442static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt)
443{
444 /* BB FIXME */
445 return 0;
446}
447#endif
448
438static int cifs_remount(struct super_block *sb, int *flags, char *data) 449static int cifs_remount(struct super_block *sb, int *flags, char *data)
439{ 450{
440 *flags |= MS_NODIRATIME; 451 *flags |= MS_NODIRATIME;
441 return 0; 452 return 0;
442} 453}
443 454
444struct super_operations cifs_super_ops = { 455static struct super_operations cifs_super_ops = {
445 .read_inode = cifs_read_inode, 456 .read_inode = cifs_read_inode,
446 .put_super = cifs_put_super, 457 .put_super = cifs_put_super,
447 .statfs = cifs_statfs, 458 .statfs = cifs_statfs,
@@ -454,6 +465,9 @@ struct super_operations cifs_super_ops = {
454 .show_options = cifs_show_options, 465 .show_options = cifs_show_options,
455 .umount_begin = cifs_umount_begin, 466 .umount_begin = cifs_umount_begin,
456 .remount_fs = cifs_remount, 467 .remount_fs = cifs_remount,
468#ifdef CONFIG_CIFS_STATS2
469 .show_stats = cifs_show_stats,
470#endif
457}; 471};
458 472
459static int 473static int
@@ -495,7 +509,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
495static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) 509static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
496{ 510{
497 /* origin == SEEK_END => we must revalidate the cached file length */ 511 /* origin == SEEK_END => we must revalidate the cached file length */
498 if (origin == 2) { 512 if (origin == SEEK_END) {
499 int retval = cifs_revalidate(file->f_dentry); 513 int retval = cifs_revalidate(file->f_dentry);
500 if (retval < 0) 514 if (retval < 0)
501 return (loff_t)retval; 515 return (loff_t)retval;
@@ -903,7 +917,7 @@ init_cifs(void)
903#ifdef CONFIG_PROC_FS 917#ifdef CONFIG_PROC_FS
904 cifs_proc_init(); 918 cifs_proc_init();
905#endif 919#endif
906 INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ 920/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */
907 INIT_LIST_HEAD(&GlobalSMBSessionList); 921 INIT_LIST_HEAD(&GlobalSMBSessionList);
908 INIT_LIST_HEAD(&GlobalTreeConnectionList); 922 INIT_LIST_HEAD(&GlobalTreeConnectionList);
909 INIT_LIST_HEAD(&GlobalOplock_Q); 923 INIT_LIST_HEAD(&GlobalOplock_Q);
@@ -931,6 +945,7 @@ init_cifs(void)
931 GlobalCurrentXid = 0; 945 GlobalCurrentXid = 0;
932 GlobalTotalActiveXid = 0; 946 GlobalTotalActiveXid = 0;
933 GlobalMaxActiveXid = 0; 947 GlobalMaxActiveXid = 0;
948 memset(Local_System_Name, 0, 15);
934 rwlock_init(&GlobalSMBSeslock); 949 rwlock_init(&GlobalSMBSeslock);
935 spin_lock_init(&GlobalMid_Lock); 950 spin_lock_init(&GlobalMid_Lock);
936 951
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index bea875d9a46a..a243f779b363 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -36,7 +36,7 @@ extern const struct address_space_operations cifs_addr_ops;
36extern const struct address_space_operations cifs_addr_ops_smallbuf; 36extern const struct address_space_operations cifs_addr_ops_smallbuf;
37 37
38/* Functions related to super block operations */ 38/* Functions related to super block operations */
39extern struct super_operations cifs_super_ops; 39/* extern struct super_operations cifs_super_ops;*/
40extern void cifs_read_inode(struct inode *); 40extern void cifs_read_inode(struct inode *);
41extern void cifs_delete_inode(struct inode *); 41extern void cifs_delete_inode(struct inode *);
42/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ 42/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b24006c47df1..74d3ccbb103b 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -153,7 +153,7 @@ struct TCP_Server_Info {
153 char sessid[4]; /* unique token id for this session */ 153 char sessid[4]; /* unique token id for this session */
154 /* (returned on Negotiate */ 154 /* (returned on Negotiate */
155 int capabilities; /* allow selective disabling of caps by smb sess */ 155 int capabilities; /* allow selective disabling of caps by smb sess */
156 __u16 timeZone; 156 int timeAdj; /* Adjust for difference in server time zone in sec */
157 __u16 CurrentMid; /* multiplex id - rotating counter */ 157 __u16 CurrentMid; /* multiplex id - rotating counter */
158 char cryptKey[CIFS_CRYPTO_KEY_SIZE]; 158 char cryptKey[CIFS_CRYPTO_KEY_SIZE];
159 /* 16th byte of RFC1001 workstation name is always null */ 159 /* 16th byte of RFC1001 workstation name is always null */
@@ -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
@@ -512,7 +517,8 @@ require use of the stronger protocol */
512 * This list helps improve performance and eliminate the messages indicating 517 * This list helps improve performance and eliminate the messages indicating
513 * that we had a communications error talking to the server in this list. 518 * that we had a communications error talking to the server in this list.
514 */ 519 */
515GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ 520/* Feature not supported */
521/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
516 522
517/* 523/*
518 * The following is a hash table of all the users we know about. 524 * The following is a hash table of all the users we know about.
@@ -568,7 +574,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled;
568GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent 574GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
569 with more secure ntlmssp2 challenge/resp */ 575 with more secure ntlmssp2 challenge/resp */
570GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ 576GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
571GLOBAL_EXTERN unsigned int secFlags;
572GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ 577GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
573GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ 578GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
574GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ 579GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 81df2bf8e75a..6df9dadba647 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
@@ -408,6 +409,8 @@ typedef struct negotiate_req {
408 409
409/* Dialect index is 13 for LANMAN */ 410/* Dialect index is 13 for LANMAN */
410 411
412#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */
413
411typedef struct lanman_neg_rsp { 414typedef struct lanman_neg_rsp {
412 struct smb_hdr hdr; /* wct = 13 */ 415 struct smb_hdr hdr; /* wct = 13 */
413 __le16 DialectIndex; 416 __le16 DialectIndex;
@@ -417,7 +420,10 @@ typedef struct lanman_neg_rsp {
417 __le16 MaxNumberVcs; 420 __le16 MaxNumberVcs;
418 __le16 RawMode; 421 __le16 RawMode;
419 __le32 SessionKey; 422 __le32 SessionKey;
420 __le32 ServerTime; 423 struct {
424 __le16 Time;
425 __le16 Date;
426 } __attribute__((packed)) SrvTime;
421 __le16 ServerTimeZone; 427 __le16 ServerTimeZone;
422 __le16 EncryptionKeyLength; 428 __le16 EncryptionKeyLength;
423 __le16 Reserved; 429 __le16 Reserved;
@@ -674,7 +680,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on
674typedef struct smb_com_close_req { 680typedef struct smb_com_close_req {
675 struct smb_hdr hdr; /* wct = 3 */ 681 struct smb_hdr hdr; /* wct = 3 */
676 __u16 FileID; 682 __u16 FileID;
677 __u32 LastWriteTime; /* should be zero */ 683 __u32 LastWriteTime; /* should be zero or -1 */
678 __u16 ByteCount; /* 0 */ 684 __u16 ByteCount; /* 0 */
679} __attribute__((packed)) CLOSE_REQ; 685} __attribute__((packed)) CLOSE_REQ;
680 686
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b35c55c3c8bb..f1f8225102f0 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -50,12 +50,12 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
50extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, 50extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
51 struct kvec *, int /* nvec to send */, 51 struct kvec *, int /* nvec to send */,
52 int * /* type of buf returned */ , const int long_op); 52 int * /* type of buf returned */ , const int long_op);
53extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, 53extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
54 struct cifsTconInfo *,
54 struct smb_hdr * /* input */ , 55 struct smb_hdr * /* input */ ,
55 struct smb_hdr * /* out */ , 56 struct smb_hdr * /* out */ ,
56 int * /* bytes returned */); 57 int * /* bytes returned */);
57extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); 58extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
58extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
59extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); 59extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
60extern int is_size_safe_to_change(struct cifsInodeInfo *); 60extern int is_size_safe_to_change(struct cifsInodeInfo *);
61extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); 61extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
@@ -80,6 +80,9 @@ extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
80extern void DeleteOplockQEntry(struct oplock_q_entry *); 80extern void DeleteOplockQEntry(struct oplock_q_entry *);
81extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); 81extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
82extern u64 cifs_UnixTimeToNT(struct timespec); 82extern u64 cifs_UnixTimeToNT(struct timespec);
83extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
84extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
85
83extern int cifs_get_inode_info(struct inode **pinode, 86extern int cifs_get_inode_info(struct inode **pinode,
84 const unsigned char *search_path, 87 const unsigned char *search_path,
85 FILE_ALL_INFO * pfile_info, 88 FILE_ALL_INFO * pfile_info,
@@ -116,6 +119,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
116extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, 119extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
117 const unsigned char *searchName, 120 const unsigned char *searchName,
118 FILE_ALL_INFO * findData, 121 FILE_ALL_INFO * findData,
122 int legacy /* whether to use old info level */,
119 const struct nls_table *nls_codepage, int remap); 123 const struct nls_table *nls_codepage, int remap);
120extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, 124extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
121 const unsigned char *searchName, 125 const unsigned char *searchName,
@@ -279,8 +283,6 @@ extern void sesInfoFree(struct cifsSesInfo *);
279extern struct cifsTconInfo *tconInfoAlloc(void); 283extern struct cifsTconInfo *tconInfoAlloc(void);
280extern void tconInfoFree(struct cifsTconInfo *); 284extern void tconInfoFree(struct cifsTconInfo *);
281 285
282extern int cifs_reconnect(struct TCP_Server_Info *server);
283
284extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); 286extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
285extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, 287extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
286 __u32 *); 288 __u32 *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 075d8fb3d376..5dc5a966bd5f 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"},
@@ -58,6 +59,7 @@ static struct {
58} protocols[] = { 59} protocols[] = {
59#ifdef CONFIG_CIFS_WEAK_PW_HASH 60#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"}, 61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
61#endif /* weak password hashing for legacy clients */ 63#endif /* weak password hashing for legacy clients */
62 {CIFS_PROT, "\2NT LM 0.12"}, 64 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"} 65 {BAD_PROT, "\2"}
@@ -67,13 +69,13 @@ static struct {
67/* define the number of elements in the cifs dialect array */ 69/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX 70#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH 71#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3 72#define CIFS_NUM_PROT 4
71#else 73#else
72#define CIFS_NUM_PROT 2 74#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */ 75#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */ 76#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH 77#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2 78#define CIFS_NUM_PROT 3
77#else 79#else
78#define CIFS_NUM_PROT 1 80#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */ 81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
@@ -446,7 +448,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
446 goto neg_err_exit; 448 goto neg_err_exit;
447#ifdef CONFIG_CIFS_WEAK_PW_HASH 449#ifdef CONFIG_CIFS_WEAK_PW_HASH
448 } else if((pSMBr->hdr.WordCount == 13) 450 } else if((pSMBr->hdr.WordCount == 13)
449 && (pSMBr->DialectIndex == LANMAN_PROT)) { 451 && ((pSMBr->DialectIndex == LANMAN_PROT)
452 || (pSMBr->DialectIndex == LANMAN2_PROT))) {
453 __s16 tmp;
450 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; 454 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
451 455
452 if((secFlags & CIFSSEC_MAY_LANMAN) || 456 if((secFlags & CIFSSEC_MAY_LANMAN) ||
@@ -472,12 +476,44 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
472 server->maxRw = 0;/* we do not need to use raw anyway */ 476 server->maxRw = 0;/* we do not need to use raw anyway */
473 server->capabilities = CAP_MPX_MODE; 477 server->capabilities = CAP_MPX_MODE;
474 } 478 }
475 server->timeZone = le16_to_cpu(rsp->ServerTimeZone); 479 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
480 if (tmp == -1) {
481 /* OS/2 often does not set timezone therefore
482 * we must use server time to calc time zone.
483 * Could deviate slightly from the right zone.
484 * Smallest defined timezone difference is 15 minutes
485 * (i.e. Nepal). Rounding up/down is done to match
486 * this requirement.
487 */
488 int val, seconds, remain, result;
489 struct timespec ts, utc;
490 utc = CURRENT_TIME;
491 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
492 le16_to_cpu(rsp->SrvTime.Time));
493 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
494 (int)ts.tv_sec, (int)utc.tv_sec,
495 (int)(utc.tv_sec - ts.tv_sec)));
496 val = (int)(utc.tv_sec - ts.tv_sec);
497 seconds = val < 0 ? -val : val;
498 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
499 remain = seconds % MIN_TZ_ADJ;
500 if(remain >= (MIN_TZ_ADJ / 2))
501 result += MIN_TZ_ADJ;
502 if(val < 0)
503 result = - result;
504 server->timeAdj = result;
505 } else {
506 server->timeAdj = (int)tmp;
507 server->timeAdj *= 60; /* also in seconds */
508 }
509 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
510
476 511
477 /* BB get server time for time conversions and add 512 /* BB get server time for time conversions and add
478 code to use it and timezone since this is not UTC */ 513 code to use it and timezone since this is not UTC */
479 514
480 if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { 515 if (rsp->EncryptionKeyLength ==
516 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
481 memcpy(server->cryptKey, rsp->EncryptionKey, 517 memcpy(server->cryptKey, rsp->EncryptionKey,
482 CIFS_CRYPTO_KEY_SIZE); 518 CIFS_CRYPTO_KEY_SIZE);
483 } else if (server->secMode & SECMODE_PW_ENCRYPT) { 519 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
@@ -531,7 +567,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
531 cFYI(0, ("Max buf = %d", ses->server->maxBuf)); 567 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
532 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); 568 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
533 server->capabilities = le32_to_cpu(pSMBr->Capabilities); 569 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
534 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); 570 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
571 server->timeAdj *= 60;
535 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { 572 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
536 memcpy(server->cryptKey, pSMBr->u.EncryptionKey, 573 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
537 CIFS_CRYPTO_KEY_SIZE); 574 CIFS_CRYPTO_KEY_SIZE);
@@ -1617,7 +1654,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1617 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ 1654 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1618 1655
1619 pSMB->FileID = (__u16) smb_file_id; 1656 pSMB->FileID = (__u16) smb_file_id;
1620 pSMB->LastWriteTime = 0; 1657 pSMB->LastWriteTime = 0xFFFFFFFF;
1621 pSMB->ByteCount = 0; 1658 pSMB->ByteCount = 0;
1622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 1659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1623 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 1660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -2773,9 +2810,11 @@ GetExtAttrOut:
2773 2810
2774 2811
2775/* security id for everyone */ 2812/* security id for everyone */
2776const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; 2813const static struct cifs_sid sid_everyone =
2814 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2777/* group users */ 2815/* group users */
2778const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; 2816const static struct cifs_sid sid_user =
2817 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2779 2818
2780/* Convert CIFS ACL to POSIX form */ 2819/* Convert CIFS ACL to POSIX form */
2781static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) 2820static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
@@ -2856,7 +2895,6 @@ qsec_out:
2856 return rc; 2895 return rc;
2857} 2896}
2858 2897
2859
2860/* Legacy Query Path Information call for lookup to old servers such 2898/* Legacy Query Path Information call for lookup to old servers such
2861 as Win9x/WinME */ 2899 as Win9x/WinME */
2862int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, 2900int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -2898,7 +2936,16 @@ QInfRetry:
2898 if (rc) { 2936 if (rc) {
2899 cFYI(1, ("Send error in QueryInfo = %d", rc)); 2937 cFYI(1, ("Send error in QueryInfo = %d", rc));
2900 } else if (pFinfo) { /* decode response */ 2938 } else if (pFinfo) { /* decode response */
2939 struct timespec ts;
2940 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2941 /* BB FIXME - add time zone adjustment BB */
2901 memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); 2942 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2943 ts.tv_nsec = 0;
2944 ts.tv_sec = time;
2945 /* decode time fields */
2946 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2947 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2948 pFinfo->LastAccessTime = 0;
2902 pFinfo->AllocationSize = 2949 pFinfo->AllocationSize =
2903 cpu_to_le64(le32_to_cpu(pSMBr->size)); 2950 cpu_to_le64(le32_to_cpu(pSMBr->size));
2904 pFinfo->EndOfFile = pFinfo->AllocationSize; 2951 pFinfo->EndOfFile = pFinfo->AllocationSize;
@@ -2922,6 +2969,7 @@ int
2922CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, 2969CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2923 const unsigned char *searchName, 2970 const unsigned char *searchName,
2924 FILE_ALL_INFO * pFindData, 2971 FILE_ALL_INFO * pFindData,
2972 int legacy /* old style infolevel */,
2925 const struct nls_table *nls_codepage, int remap) 2973 const struct nls_table *nls_codepage, int remap)
2926{ 2974{
2927/* level 263 SMB_QUERY_FILE_ALL_INFO */ 2975/* level 263 SMB_QUERY_FILE_ALL_INFO */
@@ -2970,7 +3018,10 @@ QPathInfoRetry:
2970 byte_count = params + 1 /* pad */ ; 3018 byte_count = params + 1 /* pad */ ;
2971 pSMB->TotalParameterCount = cpu_to_le16(params); 3019 pSMB->TotalParameterCount = cpu_to_le16(params);
2972 pSMB->ParameterCount = pSMB->TotalParameterCount; 3020 pSMB->ParameterCount = pSMB->TotalParameterCount;
2973 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); 3021 if(legacy)
3022 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3023 else
3024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2974 pSMB->Reserved4 = 0; 3025 pSMB->Reserved4 = 0;
2975 pSMB->hdr.smb_buf_length += byte_count; 3026 pSMB->hdr.smb_buf_length += byte_count;
2976 pSMB->ByteCount = cpu_to_le16(byte_count); 3027 pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -2982,13 +3033,24 @@ QPathInfoRetry:
2982 } else { /* decode response */ 3033 } else { /* decode response */
2983 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2984 3035
2985 if (rc || (pSMBr->ByteCount < 40)) 3036 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3037 rc = -EIO;
3038 else if (!legacy && (pSMBr->ByteCount < 40))
2986 rc = -EIO; /* bad smb */ 3039 rc = -EIO; /* bad smb */
3040 else if(legacy && (pSMBr->ByteCount < 24))
3041 rc = -EIO; /* 24 or 26 expected but we do not read last field */
2987 else if (pFindData){ 3042 else if (pFindData){
3043 int size;
2988 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 3044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3045 if(legacy) /* we do not read the last field, EAsize, fortunately
3046 since it varies by subdialect and on Set vs. Get, is
3047 two bytes or 4 bytes depending but we don't care here */
3048 size = sizeof(FILE_INFO_STANDARD);
3049 else
3050 size = sizeof(FILE_ALL_INFO);
2989 memcpy((char *) pFindData, 3051 memcpy((char *) pFindData,
2990 (char *) &pSMBr->hdr.Protocol + 3052 (char *) &pSMBr->hdr.Protocol +
2991 data_offset, sizeof (FILE_ALL_INFO)); 3053 data_offset, size);
2992 } else 3054 } else
2993 rc = -ENOMEM; 3055 rc = -ENOMEM;
2994 } 3056 }
@@ -3613,6 +3675,14 @@ getDFSRetry:
3613 strncpy(pSMB->RequestFileName, searchName, name_len); 3675 strncpy(pSMB->RequestFileName, searchName, name_len);
3614 } 3676 }
3615 3677
3678 if(ses->server) {
3679 if(ses->server->secMode &
3680 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3681 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3682 }
3683
3684 pSMB->hdr.Uid = ses->Suid;
3685
3616 params = 2 /* level */ + name_len /*includes null */ ; 3686 params = 2 /* level */ + name_len /*includes null */ ;
3617 pSMB->TotalDataCount = 0; 3687 pSMB->TotalDataCount = 0;
3618 pSMB->DataCount = 0; 3688 pSMB->DataCount = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c78762051da4..4093d5332930 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -109,7 +109,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
109 * wake up waiters on reconnection? - (not needed currently) 109 * wake up waiters on reconnection? - (not needed currently)
110 */ 110 */
111 111
112int 112static int
113cifs_reconnect(struct TCP_Server_Info *server) 113cifs_reconnect(struct TCP_Server_Info *server)
114{ 114{
115 int rc = 0; 115 int rc = 0;
@@ -771,13 +771,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
771 separator[0] = ','; 771 separator[0] = ',';
772 separator[1] = 0; 772 separator[1] = 0;
773 773
774 memset(vol->source_rfc1001_name,0x20,15); 774 if (Local_System_Name[0] != 0)
775 for(i=0;i < strnlen(utsname()->nodename,15);i++) { 775 memcpy(vol->source_rfc1001_name, Local_System_Name,15);
776 /* does not have to be a perfect mapping since the field is 776 else {
777 informational, only used for servers that do not support 777 char *nodename = utsname()->nodename;
778 port 445 and it can be overridden at mount time */ 778 int n = strnlen(nodename,15);
779 vol->source_rfc1001_name[i] = 779 memset(vol->source_rfc1001_name,0x20,15);
780 toupper(utsname()->nodename[i]); 780 for(i=0 ; i < n ; i++) {
781 /* does not have to be perfect mapping since field is
782 informational, only used for servers that do not support
783 port 445 and it can be overridden at mount time */
784 vol->source_rfc1001_name[i] = toupper(nodename[i]);
785 }
781 } 786 }
782 vol->source_rfc1001_name[15] = 0; 787 vol->source_rfc1001_name[15] = 0;
783 /* null target name indicates to use *SMBSERVR default called name 788 /* null target name indicates to use *SMBSERVR default called name
@@ -3215,7 +3220,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3215 } 3220 }
3216 /* else do not bother copying these informational fields */ 3221 /* else do not bother copying these informational fields */
3217 } 3222 }
3218 if(smb_buffer_response->WordCount == 3) 3223 if((smb_buffer_response->WordCount == 3) ||
3224 (smb_buffer_response->WordCount == 7))
3225 /* field is in same location */
3219 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); 3226 tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
3220 else 3227 else
3221 tcon->Flags = 0; 3228 tcon->Flags = 0;
@@ -3312,19 +3319,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3312 first_time = 1; 3319 first_time = 1;
3313 } 3320 }
3314 if (!rc) { 3321 if (!rc) {
3322 pSesInfo->flags = 0;
3315 pSesInfo->capabilities = pSesInfo->server->capabilities; 3323 pSesInfo->capabilities = pSesInfo->server->capabilities;
3316 if(linuxExtEnabled == 0) 3324 if(linuxExtEnabled == 0)
3317 pSesInfo->capabilities &= (~CAP_UNIX); 3325 pSesInfo->capabilities &= (~CAP_UNIX);
3318 /* pSesInfo->sequence_number = 0;*/ 3326 /* pSesInfo->sequence_number = 0;*/
3319 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", 3327 cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
3320 pSesInfo->server->secMode, 3328 pSesInfo->server->secMode,
3321 pSesInfo->server->capabilities, 3329 pSesInfo->server->capabilities,
3322 pSesInfo->server->timeZone)); 3330 pSesInfo->server->timeAdj));
3323 if(experimEnabled < 2) 3331 if(experimEnabled < 2)
3324 rc = CIFS_SessSetup(xid, pSesInfo, 3332 rc = CIFS_SessSetup(xid, pSesInfo,
3325 first_time, nls_info); 3333 first_time, nls_info);
3326 else if (extended_security 3334 else if (extended_security
3327 && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) 3335 && (pSesInfo->capabilities
3336 & CAP_EXTENDED_SECURITY)
3328 && (pSesInfo->server->secType == NTLMSSP)) { 3337 && (pSesInfo->server->secType == NTLMSSP)) {
3329 rc = -EOPNOTSUPP; 3338 rc = -EOPNOTSUPP;
3330 } else if (extended_security 3339 } else if (extended_security
@@ -3338,7 +3347,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3338 if (!rc) { 3347 if (!rc) {
3339 if(ntlmv2_flag) { 3348 if(ntlmv2_flag) {
3340 char * v2_response; 3349 char * v2_response;
3341 cFYI(1,("Can use more secure NTLM version 2 password hash")); 3350 cFYI(1,("more secure NTLM ver2 hash"));
3342 if(CalcNTLMv2_partial_mac_key(pSesInfo, 3351 if(CalcNTLMv2_partial_mac_key(pSesInfo,
3343 nls_info)) { 3352 nls_info)) {
3344 rc = -ENOMEM; 3353 rc = -ENOMEM;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6b90ef98e4cf..35d54bb0869a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -337,6 +337,7 @@ int cifs_get_inode_info(struct inode **pinode,
337 pfindData = (FILE_ALL_INFO *)buf; 337 pfindData = (FILE_ALL_INFO *)buf;
338 /* could do find first instead but this returns more info */ 338 /* could do find first instead but this returns more info */
339 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, 339 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
340 0 /* not legacy */,
340 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & 341 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
341 CIFS_MOUNT_MAP_SPECIAL_CHR); 342 CIFS_MOUNT_MAP_SPECIAL_CHR);
342 /* BB optimize code so we do not make the above call 343 /* BB optimize code so we do not make the above call
@@ -384,8 +385,10 @@ int cifs_get_inode_info(struct inode **pinode,
384 /* get new inode */ 385 /* get new inode */
385 if (*pinode == NULL) { 386 if (*pinode == NULL) {
386 *pinode = new_inode(sb); 387 *pinode = new_inode(sb);
387 if (*pinode == NULL) 388 if (*pinode == NULL) {
389 kfree(buf);
388 return -ENOMEM; 390 return -ENOMEM;
391 }
389 /* Is an i_ino of zero legal? Can we use that to check 392 /* Is an i_ino of zero legal? Can we use that to check
390 if the server supports returning inode numbers? Are 393 if the server supports returning inode numbers? Are
391 there other sanity checks we can use to ensure that 394 there other sanity checks we can use to ensure that
@@ -431,8 +434,11 @@ int cifs_get_inode_info(struct inode **pinode,
431 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ 434 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
432 435
433 /* Linux can not store file creation time so ignore it */ 436 /* Linux can not store file creation time so ignore it */
434 inode->i_atime = 437 if(pfindData->LastAccessTime)
435 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); 438 inode->i_atime = cifs_NTtimeToUnix
439 (le64_to_cpu(pfindData->LastAccessTime));
440 else /* do not need to use current_fs_time - time not stored */
441 inode->i_atime = CURRENT_TIME;
436 inode->i_mtime = 442 inode->i_mtime =
437 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); 443 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
438 inode->i_ctime = 444 inode->i_ctime =
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index a57f5d6e6213..0bee8b7e521a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -254,7 +254,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
254 tmpbuffer, 254 tmpbuffer,
255 len - 1, 255 len - 1,
256 cifs_sb->local_nls); 256 cifs_sb->local_nls);
257 else { 257 else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
258 cERROR(1,("SFU style symlinks not implemented yet"));
259 /* add open and read as in fs/cifs/inode.c */
260
261 } else {
258 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, 262 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
259 OPEN_REPARSE_POINT,&fid, &oplock, NULL, 263 OPEN_REPARSE_POINT,&fid, &oplock, NULL,
260 cifs_sb->local_nls, 264 cifs_sb->local_nls,
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
index 7aa23490541f..ccebf9b7eb86 100644
--- a/fs/cifs/md5.c
+++ b/fs/cifs/md5.c
@@ -252,10 +252,11 @@ MD5Transform(__u32 buf[4], __u32 const in[16])
252 buf[3] += d; 252 buf[3] += d;
253} 253}
254 254
255#if 0 /* currently unused */
255/*********************************************************************** 256/***********************************************************************
256 the rfc 2104 version of hmac_md5 initialisation. 257 the rfc 2104 version of hmac_md5 initialisation.
257***********************************************************************/ 258***********************************************************************/
258void 259static void
259hmac_md5_init_rfc2104(unsigned char *key, int key_len, 260hmac_md5_init_rfc2104(unsigned char *key, int key_len,
260 struct HMACMD5Context *ctx) 261 struct HMACMD5Context *ctx)
261{ 262{
@@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
289 MD5Init(&ctx->ctx); 290 MD5Init(&ctx->ctx);
290 MD5Update(&ctx->ctx, ctx->k_ipad, 64); 291 MD5Update(&ctx->ctx, ctx->k_ipad, 64);
291} 292}
293#endif
292 294
293/*********************************************************************** 295/***********************************************************************
294 the microsoft version of hmac_md5 initialisation. 296 the microsoft version of hmac_md5 initialisation.
@@ -350,7 +352,8 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
350 single function to calculate an HMAC MD5 digest from data. 352 single function to calculate an HMAC MD5 digest from data.
351 use the microsoft hmacmd5 init method because the key is 16 bytes. 353 use the microsoft hmacmd5 init method because the key is 16 bytes.
352************************************************************/ 354************************************************************/
353void 355#if 0 /* currently unused */
356static void
354hmac_md5(unsigned char key[16], unsigned char *data, int data_len, 357hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
355 unsigned char *digest) 358 unsigned char *digest)
356{ 359{
@@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
361 } 364 }
362 hmac_md5_final(digest, &ctx); 365 hmac_md5_final(digest, &ctx);
363} 366}
367#endif
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h
index 00e1c5394fe1..f7d4f4197bac 100644
--- a/fs/cifs/md5.h
+++ b/fs/cifs/md5.h
@@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context);
27 27
28/* The following definitions come from lib/hmacmd5.c */ 28/* The following definitions come from lib/hmacmd5.c */
29 29
30void hmac_md5_init_rfc2104(unsigned char *key, int key_len, 30/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
31 struct HMACMD5Context *ctx); 31 struct HMACMD5Context *ctx);*/
32void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, 32void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
33 struct HMACMD5Context *ctx); 33 struct HMACMD5Context *ctx);
34void hmac_md5_update(const unsigned char *text, int text_len, 34void hmac_md5_update(const unsigned char *text, int text_len,
35 struct HMACMD5Context *ctx); 35 struct HMACMD5Context *ctx);
36void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); 36void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
37void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, 37/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
38 unsigned char *digest); 38 unsigned char *digest);*/
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 22c937e5884f..bbc9cd34b6ea 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -389,7 +389,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
389 return; 389 return;
390} 390}
391 391
392int 392static int
393checkSMBhdr(struct smb_hdr *smb, __u16 mid) 393checkSMBhdr(struct smb_hdr *smb, __u16 mid)
394{ 394{
395 /* Make sure that this really is an SMB, that it is a response, 395 /* Make sure that this really is an SMB, that it is a response,
@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
418} 418}
419 419
420int 420int
421checkSMB(struct smb_hdr *smb, __u16 mid, int length) 421checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
422{ 422{
423 __u32 len = smb->smb_buf_length; 423 __u32 len = smb->smb_buf_length;
424 __u32 clc_len; /* calculated length */ 424 __u32 clc_len; /* calculated length */
425 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); 425 cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
426 if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || 426
427 (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { 427 if (length < 2 + sizeof (struct smb_hdr)) {
428 if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { 428 if ((length >= sizeof (struct smb_hdr) - 1)
429 if (((unsigned int)length >=
430 sizeof (struct smb_hdr) - 1)
431 && (smb->Status.CifsError != 0)) { 429 && (smb->Status.CifsError != 0)) {
432 smb->WordCount = 0; 430 smb->WordCount = 0;
433 /* some error cases do not return wct and bcc */ 431 /* some error cases do not return wct and bcc */
432 return 0;
433 } else if ((length == sizeof(struct smb_hdr) + 1) &&
434 (smb->WordCount == 0)) {
435 char * tmp = (char *)smb;
436 /* Need to work around a bug in two servers here */
437 /* First, check if the part of bcc they sent was zero */
438 if (tmp[sizeof(struct smb_hdr)] == 0) {
439 /* some servers return only half of bcc
440 * on simple responses (wct, bcc both zero)
441 * in particular have seen this on
442 * ulogoffX and FindClose. This leaves
443 * one byte of bcc potentially unitialized
444 */
445 /* zero rest of bcc */
446 tmp[sizeof(struct smb_hdr)+1] = 0;
434 return 0; 447 return 0;
435 } else {
436 cERROR(1, ("Length less than smb header size"));
437 } 448 }
449 cERROR(1,("rcvd invalid byte count (bcc)"));
450 } else {
451 cERROR(1, ("Length less than smb header size"));
438 } 452 }
439 if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) 453 return 1;
440 cERROR(1, ("smb length greater than MaxBufSize, mid=%d", 454 }
455 if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
456 cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
441 smb->Mid)); 457 smb->Mid));
442 return 1; 458 return 1;
443 } 459 }
@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
446 return 1; 462 return 1;
447 clc_len = smbCalcSize_LE(smb); 463 clc_len = smbCalcSize_LE(smb);
448 464
449 if(4 + len != (unsigned int)length) { 465 if(4 + len != length) {
450 cERROR(1, ("Length read does not match RFC1001 length %d",len)); 466 cERROR(1, ("Length read does not match RFC1001 length %d",len));
451 return 1; 467 return 1;
452 } 468 }
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index ce87550e918f..992e80edc720 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -909,3 +909,61 @@ cifs_UnixTimeToNT(struct timespec t)
909 /* Convert to 100ns intervals and then add the NTFS time offset. */ 909 /* Convert to 100ns intervals and then add the NTFS time offset. */
910 return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; 910 return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
911} 911}
912
913static int total_days_of_prev_months[] =
914{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
915
916
917__le64 cnvrtDosCifsTm(__u16 date, __u16 time)
918{
919 return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time)));
920}
921
922struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
923{
924 struct timespec ts;
925 int sec, min, days, month, year;
926 SMB_TIME * st = (SMB_TIME *)&time;
927 SMB_DATE * sd = (SMB_DATE *)&date;
928
929 cFYI(1,("date %d time %d",date, time));
930
931 sec = 2 * st->TwoSeconds;
932 min = st->Minutes;
933 if((sec > 59) || (min > 59))
934 cERROR(1,("illegal time min %d sec %d", min, sec));
935 sec += (min * 60);
936 sec += 60 * 60 * st->Hours;
937 if(st->Hours > 24)
938 cERROR(1,("illegal hours %d",st->Hours));
939 days = sd->Day;
940 month = sd->Month;
941 if((days > 31) || (month > 12))
942 cERROR(1,("illegal date, month %d day: %d", month, days));
943 month -= 1;
944 days += total_days_of_prev_months[month];
945 days += 3652; /* account for difference in days between 1980 and 1970 */
946 year = sd->Year;
947 days += year * 365;
948 days += (year/4); /* leap year */
949 /* generalized leap year calculation is more complex, ie no leap year
950 for years/100 except for years/400, but since the maximum number for DOS
951 year is 2**7, the last year is 1980+127, which means we need only
952 consider 2 special case years, ie the years 2000 and 2100, and only
953 adjust for the lack of leap year for the year 2100, as 2000 was a
954 leap year (divisable by 400) */
955 if(year >= 120) /* the year 2100 */
956 days = days - 1; /* do not count leap year for the year 2100 */
957
958 /* adjust for leap year where we are still before leap day */
959 if(year != 120)
960 days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
961 sec += 24 * 60 * 60 * days;
962
963 ts.tv_sec = sec;
964
965 /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */
966
967 ts.tv_nsec = 0;
968 return ts;
969}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index b27b34537bf2..b5b0a2a41bef 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -106,6 +106,17 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
106 return rc; 106 return rc;
107} 107}
108 108
109static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
110{
111 if((tcon) && (tcon->ses) && (tcon->ses->server)) {
112 inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
113 inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
114 inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
115 }
116 return;
117}
118
119
109static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, 120static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
110 char * buf, int *pobject_type, int isNewInode) 121 char * buf, int *pobject_type, int isNewInode)
111{ 122{
@@ -135,16 +146,23 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
135 tmp_inode->i_ctime = 146 tmp_inode->i_ctime =
136 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 147 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
137 } else { /* legacy, OS2 and DOS style */ 148 } else { /* legacy, OS2 and DOS style */
149/* struct timespec ts;*/
138 FIND_FILE_STANDARD_INFO * pfindData = 150 FIND_FILE_STANDARD_INFO * pfindData =
139 (FIND_FILE_STANDARD_INFO *)buf; 151 (FIND_FILE_STANDARD_INFO *)buf;
140 152
153 tmp_inode->i_mtime = cnvrtDosUnixTm(
154 le16_to_cpu(pfindData->LastWriteDate),
155 le16_to_cpu(pfindData->LastWriteTime));
156 tmp_inode->i_atime = cnvrtDosUnixTm(
157 le16_to_cpu(pfindData->LastAccessDate),
158 le16_to_cpu(pfindData->LastAccessTime));
159 tmp_inode->i_ctime = cnvrtDosUnixTm(
160 le16_to_cpu(pfindData->LastWriteDate),
161 le16_to_cpu(pfindData->LastWriteTime));
162 AdjustForTZ(cifs_sb->tcon, tmp_inode);
141 attr = le16_to_cpu(pfindData->Attributes); 163 attr = le16_to_cpu(pfindData->Attributes);
142 allocation_size = le32_to_cpu(pfindData->AllocationSize); 164 allocation_size = le32_to_cpu(pfindData->AllocationSize);
143 end_of_file = le32_to_cpu(pfindData->DataSize); 165 end_of_file = le32_to_cpu(pfindData->DataSize);
144 tmp_inode->i_atime = CURRENT_TIME;
145 /* tmp_inode->i_mtime = BB FIXME - add dos time handling
146 tmp_inode->i_ctime = 0; BB FIXME */
147
148 } 166 }
149 167
150 /* Linux can not store file creation time unfortunately so ignore it */ 168 /* Linux can not store file creation time unfortunately so ignore it */
@@ -938,6 +956,7 @@ static int cifs_save_resume_key(const char *current_entry,
938 filename = &pFindData->FileName[0]; 956 filename = &pFindData->FileName[0];
939 /* one byte length, no name conversion */ 957 /* one byte length, no name conversion */
940 len = (unsigned int)pFindData->FileNameLength; 958 len = (unsigned int)pFindData->FileNameLength;
959 cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
941 } else { 960 } else {
942 cFYI(1,("Unknown findfirst level %d",level)); 961 cFYI(1,("Unknown findfirst level %d",level));
943 return -EINVAL; 962 return -EINVAL;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 22b4c35dcfe3..a8a083543ba0 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);
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index efaa044523a7..7a1b2b961ec8 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -364,20 +364,20 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
364 smbhash(p24 + 16, c8, p21 + 14, 1); 364 smbhash(p24 + 16, c8, p21 + 14, 1);
365} 365}
366 366
367void 367#if 0 /* currently unsued */
368static void
368D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) 369D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
369{ 370{
370 smbhash(out, in, p14, 0); 371 smbhash(out, in, p14, 0);
371 smbhash(out + 8, in + 8, p14 + 7, 0); 372 smbhash(out + 8, in + 8, p14 + 7, 0);
372} 373}
373 374
374void 375static void
375E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) 376E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
376{ 377{
377 smbhash(out, in, p14, 1); 378 smbhash(out, in, p14, 1);
378 smbhash(out + 8, in + 8, p14 + 7, 1); 379 smbhash(out + 8, in + 8, p14 + 7, 1);
379} 380}
380#if 0
381/* these routines are currently unneeded, but may be 381/* these routines are currently unneeded, but may be
382 needed later */ 382 needed later */
383void 383void
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index f518c5e45035..4b25ba92180d 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -51,11 +51,8 @@
51 51
52void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); 52void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
53void E_md4hash(const unsigned char *passwd, unsigned char *p16); 53void E_md4hash(const unsigned char *passwd, unsigned char *p16);
54void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
55static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, 54static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
56 unsigned char p24[24]); 55 unsigned char p24[24]);
57void NTLMSSPOWFencrypt(unsigned char passwd[8],
58 unsigned char *ntlmchalresp, unsigned char p24[24]);
59void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); 56void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
60 57
61/* 58/*
@@ -144,8 +141,9 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
144 memset(wpwd,0,129 * 2); 141 memset(wpwd,0,129 * 2);
145} 142}
146 143
144#if 0 /* currently unused */
147/* Does both the NT and LM owfs of a user's password */ 145/* Does both the NT and LM owfs of a user's password */
148void 146static void
149nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) 147nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
150{ 148{
151 char passwd[514]; 149 char passwd[514];
@@ -171,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
171 /* clear out local copy of user's password (just being paranoid). */ 169 /* clear out local copy of user's password (just being paranoid). */
172 memset(passwd, '\0', sizeof (passwd)); 170 memset(passwd, '\0', sizeof (passwd));
173} 171}
172#endif
174 173
175/* Does the NTLMv2 owfs of a user's password */ 174/* Does the NTLMv2 owfs of a user's password */
176#if 0 /* function not needed yet - but will be soon */ 175#if 0 /* function not needed yet - but will be soon */
@@ -223,7 +222,8 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
223} 222}
224 223
225/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ 224/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
226void 225#if 0 /* currently unused */
226static void
227NTLMSSPOWFencrypt(unsigned char passwd[8], 227NTLMSSPOWFencrypt(unsigned char passwd[8],
228 unsigned char *ntlmchalresp, unsigned char p24[24]) 228 unsigned char *ntlmchalresp, unsigned char p24[24])
229{ 229{
@@ -235,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
235 235
236 E_P24(p21, ntlmchalresp, p24); 236 E_P24(p21, ntlmchalresp, p24);
237} 237}
238#endif
238 239
239/* Does the NT MD4 hash then des encryption. */ 240/* Does the NT MD4 hash then des encryption. */
240 241