summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
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 db4d13324c3..6a3df055280 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1986,7 +1986,7 @@ config CIFS_EXPERIMENTAL
config CIFS_UPCALL
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
depends on CIFS_EXPERIMENTAL
- select CONNECTOR
+ depends on CONNECTOR
help
Enables an upcall mechanism for CIFS which will be used to contact
userspace helper utilities to provide SPNEGO packaged Kerberos
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index d0776ac2b80..5eff35d6e56 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -31,8 +31,8 @@ struct cifs_sid {
} __attribute__((packed));
/* everyone */
-extern const struct cifs_sid sid_everyone;
+/* extern const struct cifs_sid sid_everyone;*/
/* group users */
-extern const struct cifs_sid sid_user;
+/* extern const struct cifs_sid sid_user;*/
#endif /* _CIFSACL_H */
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
index 03e359b3286..152fa2dcfc6 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);
/* smbdes.c */
extern void E_P16(unsigned char *p14, unsigned char *p16);
extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
-extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
-extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c00c654f2e1..84976cdbe71 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -63,6 +63,7 @@ extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL;
extern struct task_struct * dnotifyThread; /* remove sparse warning */
struct task_struct * dnotifyThread = NULL;
+static struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0);
MODULE_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)
/* Only need to call the old QFSInfo if failed
on newer one */
if(rc)
- rc = CIFSSMBQFSInfo(xid, pTcon, buf);
+ if(pTcon->ses->capabilities & CAP_NT_SMBS)
+ rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
- /* Old Windows servers do not support level 103, retry with level
- one if old server failed the previous call */
+ /* Some old Windows servers also do not support level 103, retry with
+ older level one if old server failed the previous call or we
+ bypassed it because we detected that this was an older LANMAN sess */
if(rc)
rc = SMBOldQFSInfo(xid, pTcon, buf);
/*
@@ -435,13 +438,21 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
return;
}
+#ifdef CONFIG_CIFS_STATS2
+static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt)
+{
+ /* BB FIXME */
+ return 0;
+}
+#endif
+
static int cifs_remount(struct super_block *sb, int *flags, char *data)
{
*flags |= MS_NODIRATIME;
return 0;
}
-struct super_operations cifs_super_ops = {
+static struct super_operations cifs_super_ops = {
.read_inode = cifs_read_inode,
.put_super = cifs_put_super,
.statfs = cifs_statfs,
@@ -454,6 +465,9 @@ struct super_operations cifs_super_ops = {
.show_options = cifs_show_options,
.umount_begin = cifs_umount_begin,
.remount_fs = cifs_remount,
+#ifdef CONFIG_CIFS_STATS2
+ .show_stats = cifs_show_stats,
+#endif
};
static int
@@ -495,7 +509,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/* origin == SEEK_END => we must revalidate the cached file length */
- if (origin == 2) {
+ if (origin == SEEK_END) {
int retval = cifs_revalidate(file->f_dentry);
if (retval < 0)
return (loff_t)retval;
@@ -903,7 +917,7 @@ init_cifs(void)
#ifdef CONFIG_PROC_FS
cifs_proc_init();
#endif
- INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
+/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */
INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q);
@@ -931,6 +945,7 @@ init_cifs(void)
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
+ memset(Local_System_Name, 0, 15);
rwlock_init(&GlobalSMBSeslock);
spin_lock_init(&GlobalMid_Lock);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index bea875d9a46..a243f779b36 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -36,7 +36,7 @@ extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */
-extern struct super_operations cifs_super_ops;
+/* extern struct super_operations cifs_super_ops;*/
extern void cifs_read_inode(struct inode *);
extern void cifs_delete_inode(struct inode *);
/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b24006c47df..74d3ccbb103 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -153,7 +153,7 @@ struct TCP_Server_Info {
char sessid[4]; /* unique token id for this session */
/* (returned on Negotiate */
int capabilities; /* allow selective disabling of caps by smb sess */
- __u16 timeZone;
+ int timeAdj; /* Adjust for difference in server time zone in sec */
__u16 CurrentMid; /* multiplex id - rotating counter */
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
/* 16th byte of RFC1001 workstation name is always null */
@@ -203,9 +203,14 @@ struct cifsSesInfo {
char * domainName;
char * password;
};
-/* session flags */
+/* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1
-
+#define CIFS_SES_OS2 2
+#define CIFS_SES_W9X 4
+/* following flag is set for old servers such as OS2 (and Win95?)
+ which do not negotiate NTLM or POSIX dialects, but instead
+ negotiate one of the older LANMAN dialects */
+#define CIFS_SES_LANMAN 8
/*
* there is one of these for each connection to a resource on a particular
* session
@@ -512,7 +517,8 @@ require use of the stronger protocol */
* This list helps improve performance and eliminate the messages indicating
* that we had a communications error talking to the server in this list.
*/
-GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
+/* Feature not supported */
+/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
/*
* The following is a hash table of all the users we know about.
@@ -568,7 +574,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
-GLOBAL_EXTERN unsigned int secFlags;
GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
GLOBAL_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 81df2bf8e75..6df9dadba64 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -26,7 +26,8 @@
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define LANMAN_PROT 0
-#define CIFS_PROT 1
+#define LANMAN2_PROT 1
+#define CIFS_PROT 2
#else
#define CIFS_PROT 0
#endif
@@ -408,6 +409,8 @@ typedef struct negotiate_req {
/* Dialect index is 13 for LANMAN */
+#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */
+
typedef struct lanman_neg_rsp {
struct smb_hdr hdr; /* wct = 13 */
__le16 DialectIndex;
@@ -417,7 +420,10 @@ typedef struct lanman_neg_rsp {
__le16 MaxNumberVcs;
__le16 RawMode;
__le32 SessionKey;
- __le32 ServerTime;
+ struct {
+ __le16 Time;
+ __le16 Date;
+ } __attribute__((packed)) SrvTime;
__le16 ServerTimeZone;
__le16 EncryptionKeyLength;
__le16 Reserved;
@@ -674,7 +680,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on
typedef struct smb_com_close_req {
struct smb_hdr hdr; /* wct = 3 */
__u16 FileID;
- __u32 LastWriteTime; /* should be zero */
+ __u32 LastWriteTime; /* should be zero or -1 */
__u16 ByteCount; /* 0 */
} __attribute__((packed)) CLOSE_REQ;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b35c55c3c8b..f1f8225102f 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -50,12 +50,12 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int long_op);
-extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
+extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
+ struct cifsTconInfo *,
struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ ,
int * /* bytes returned */);
-extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
-extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
+extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
extern int is_size_safe_to_change(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
@@ -80,6 +80,9 @@ extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
extern void DeleteOplockQEntry(struct oplock_q_entry *);
extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
extern u64 cifs_UnixTimeToNT(struct timespec);
+extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
+extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
+
extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path,
FILE_ALL_INFO * pfile_info,
@@ -116,6 +119,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * findData,
+ int legacy /* whether to use old info level */,
const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
@@ -279,8 +283,6 @@ extern void sesInfoFree(struct cifsSesInfo *);
extern struct cifsTconInfo *tconInfoAlloc(void);
extern void tconInfoFree(struct cifsTconInfo *);
-extern int cifs_reconnect(struct TCP_Server_Info *server);
-
extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 075d8fb3d37..5dc5a966bd5 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -46,6 +46,7 @@ static struct {
} protocols[] = {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
{LANMAN_PROT, "\2LM1.2X002"},
+ {LANMAN2_PROT, "\2LANMAN2.1"},
#endif /* weak password hashing for legacy clients */
{CIFS_PROT, "\2NT LM 0.12"},
{POSIX_PROT, "\2POSIX 2"},
@@ -58,6 +59,7 @@ static struct {
} protocols[] = {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
{LANMAN_PROT, "\2LM1.2X002"},
+ {LANMAN2_PROT, "\2LANMAN2.1"},
#endif /* weak password hashing for legacy clients */
{CIFS_PROT, "\2NT LM 0.12"},
{BAD_PROT, "\2"}
@@ -67,13 +69,13 @@ static struct {
/* define the number of elements in the cifs dialect array */
#ifdef CONFIG_CIFS_POSIX
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-#define CIFS_NUM_PROT 3
+#define CIFS_NUM_PROT 4
#else
#define CIFS_NUM_PROT 2
#endif /* CIFS_WEAK_PW_HASH */
#else /* not posix */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-#define CIFS_NUM_PROT 2
+#define CIFS_NUM_PROT 3
#else
#define CIFS_NUM_PROT 1
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
@@ -446,7 +448,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
goto neg_err_exit;
#ifdef CONFIG_CIFS_WEAK_PW_HASH
} else if((pSMBr->hdr.WordCount == 13)
- && (pSMBr->DialectIndex == LANMAN_PROT)) {
+ && ((pSMBr->DialectIndex == LANMAN_PROT)
+ || (pSMBr->DialectIndex == LANMAN2_PROT))) {
+ __s16 tmp;
struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
if((secFlags & CIFSSEC_MAY_LANMAN) ||
@@ -472,12 +476,44 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->maxRw = 0;/* we do not need to use raw anyway */
server->capabilities = CAP_MPX_MODE;
}
- server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
+ tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
+ if (tmp == -1) {
+ /* OS/2 often does not set timezone therefore
+ * we must use server time to calc time zone.
+ * Could deviate slightly from the right zone.
+ * Smallest defined timezone difference is 15 minutes
+ * (i.e. Nepal). Rounding up/down is done to match
+ * this requirement.
+ */
+ int val, seconds, remain, result;
+ struct timespec ts, utc;
+ utc = CURRENT_TIME;
+ ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
+ le16_to_cpu(rsp->SrvTime.Time));
+ cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
+ (int)ts.tv_sec, (int)utc.tv_sec,
+ (int)(utc.tv_sec - ts.tv_sec)));
+ val = (int)(utc.tv_sec - ts.tv_sec);
+ seconds = val < 0 ? -val : val;
+ result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
+ remain = seconds % MIN_TZ_ADJ;
+ if(remain >= (MIN_TZ_ADJ / 2))
+ result += MIN_TZ_ADJ;
+ if(val < 0)
+ result = - result;
+ server->timeAdj = result;
+ } else {
+ server->timeAdj = (int)tmp;
+ server->timeAdj *= 60; /* also in seconds */
+ }
+ cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
+
/* BB get server time for time conversions and add
code to use it and timezone since this is not UTC */
- if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
+ if (rsp->EncryptionKeyLength ==
+ cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
memcpy(server->cryptKey, rsp->EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
@@ -531,7 +567,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
cFYI(0, ("Max buf = %d", ses->server->maxBuf));
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
- server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
+ server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
+ server->timeAdj *= 60;
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
@@ -1617,7 +1654,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
pSMB->FileID = (__u16) smb_file_id;
- pSMB->LastWriteTime = 0;
+ pSMB->LastWriteTime = 0xFFFFFFFF;
pSMB->ByteCount = 0;
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -2773,9 +2810,11 @@ GetExtAttrOut:
/* security id for everyone */
-const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
+const static struct cifs_sid sid_everyone =
+ {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
/* group users */
-const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
+const static struct cifs_sid sid_user =
+ {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
/* Convert CIFS ACL to POSIX form */
static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
@@ -2856,7 +2895,6 @@ qsec_out:
return rc;
}
-
/* Legacy Query Path Information call for lookup to old servers such
as Win9x/WinME */
int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -2898,7 +2936,16 @@ QInfRetry:
if (rc) {
cFYI(1, ("Send error in QueryInfo = %d", rc));
} else if (pFinfo) { /* decode response */
+ struct timespec ts;
+ __u32 time = le32_to_cpu(pSMBr->last_write_time);
+ /* BB FIXME - add time zone adjustment BB */
memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
+ ts.tv_nsec = 0;
+ ts.tv_sec = time;
+ /* decode time fields */
+ pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
+ pFinfo->LastWriteTime = pFinfo->ChangeTime;
+ pFinfo->LastAccessTime = 0;
pFinfo->AllocationSize =
cpu_to_le64(le32_to_cpu(pSMBr->size));
pFinfo->EndOfFile = pFinfo->AllocationSize;
@@ -2922,6 +2969,7 @@ int
CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * pFindData,
+ int legacy /* old style infolevel */,
const struct nls_table *nls_codepage, int remap)
{
/* level 263 SMB_QUERY_FILE_ALL_INFO */
@@ -2970,7 +3018,10 @@ QPathInfoRetry:
byte_count = params + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+ if(legacy)
+ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
+ else
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -2982,13 +3033,24 @@ QPathInfoRetry:
} else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 40))
+ if (rc) /* BB add auto retry on EOPNOTSUPP? */
+ rc = -EIO;
+ else if (!legacy && (pSMBr->ByteCount < 40))
rc = -EIO; /* bad smb */
+ else if(legacy && (pSMBr->ByteCount < 24))
+ rc = -EIO; /* 24 or 26 expected but we do not read last field */
else if (pFindData){
+ int size;
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+ if(legacy) /* we do not read the last field, EAsize, fortunately
+ since it varies by subdialect and on Set vs. Get, is
+ two bytes or 4 bytes depending but we don't care here */
+ size = sizeof(FILE_INFO_STANDARD);
+ else
+ size = sizeof(FILE_ALL_INFO);
memcpy((char *) pFindData,
(char *) &pSMBr->hdr.Protocol +
- data_offset, sizeof (FILE_ALL_INFO));
+ data_offset, size);
} else
rc = -ENOMEM;
}
@@ -3613,6 +3675,14 @@ getDFSRetry:
strncpy(pSMB->RequestFileName, searchName, name_len);
}
+ if(ses->server) {
+ if(ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+ }
+
+ pSMB->hdr.Uid = ses->Suid;
+
params = 2 /* level */ + name_len /*includes null */ ;
pSMB->TotalDataCount = 0;
pSMB->DataCount = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c78762051da..4093d533293 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -109,7 +109,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
* wake up waiters on reconnection? - (not needed currently)
*/
-int
+static int
cifs_reconnect(struct TCP_Server_Info *server)
{
int rc = 0;
@@ -771,13 +771,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
separator[0] = ',';
separator[1] = 0;
- memset(vol->source_rfc1001_name,0x20,15);
- for(i=0;i < strnlen(utsname()->nodename,15);i++) {
- /* does not have to be a perfect mapping since the field is
- informational, only used for servers that do not support
- port 445 and it can be overridden at mount time */
- vol->source_rfc1001_name[i] =
- toupper(utsname()->nodename[i]);
+ if (Local_System_Name[0] != 0)
+ memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+ else {
+ char *nodename = utsname()->nodename;
+ int n = strnlen(nodename,15);
+ memset(vol->source_rfc1001_name,0x20,15);
+ for(i=0 ; i < n ; i++) {
+ /* does not have to be perfect mapping since field is
+ informational, only used for servers that do not support
+ port 445 and it can be overridden at mount time */
+ vol->source_rfc1001_name[i] = toupper(nodename[i]);
+ }
}
vol->source_rfc1001_name[15] = 0;
/* null target name indicates to use *SMBSERVR default called name
@@ -3215,7 +3220,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
}
/* else do not bother copying these informational fields */
}
- if(smb_buffer_response->WordCount == 3)
+ if((smb_buffer_response->WordCount == 3) ||
+ (smb_buffer_response->WordCount == 7))
+ /* field is in same location */
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
else
tcon->Flags = 0;
@@ -3312,19 +3319,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
first_time = 1;
}
if (!rc) {
+ pSesInfo->flags = 0;
pSesInfo->capabilities = pSesInfo->server->capabilities;
if(linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX);
/* pSesInfo->sequence_number = 0;*/
- cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
pSesInfo->server->secMode,
pSesInfo->server->capabilities,
- pSesInfo->server->timeZone));
+ pSesInfo->server->timeAdj));
if(experimEnabled < 2)
rc = CIFS_SessSetup(xid, pSesInfo,
first_time, nls_info);
else if (extended_security
- && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ && (pSesInfo->capabilities
+ & CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == NTLMSSP)) {
rc = -EOPNOTSUPP;
} else if (extended_security
@@ -3338,7 +3347,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (!rc) {
if(ntlmv2_flag) {
char * v2_response;
- cFYI(1,("Can use more secure NTLM version 2 password hash"));
+ cFYI(1,("more secure NTLM ver2 hash"));
if(CalcNTLMv2_partial_mac_key(pSesInfo,
nls_info)) {
rc = -ENOMEM;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6b90ef98e4c..35d54bb0869 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -337,6 +337,7 @@ int cifs_get_inode_info(struct inode **pinode,
pfindData = (FILE_ALL_INFO *)buf;
/* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
+ 0 /* not legacy */,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB optimize code so we do not make the above call
@@ -384,8 +385,10 @@ int cifs_get_inode_info(struct inode **pinode,
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
- if (*pinode == NULL)
+ if (*pinode == NULL) {
+ kfree(buf);
return -ENOMEM;
+ }
/* Is an i_ino of zero legal? Can we use that to check
if the server supports returning inode numbers? Are
there other sanity checks we can use to ensure that
@@ -431,8 +434,11 @@ int cifs_get_inode_info(struct inode **pinode,
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
/* Linux can not store file creation time so ignore it */
- inode->i_atime =
- cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+ if(pfindData->LastAccessTime)
+ inode->i_atime = cifs_NTtimeToUnix
+ (le64_to_cpu(pfindData->LastAccessTime));
+ else /* do not need to use current_fs_time - time not stored */
+ inode->i_atime = CURRENT_TIME;
inode->i_mtime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime =
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index a57f5d6e621..0bee8b7e521 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)
tmpbuffer,
len - 1,
cifs_sb->local_nls);
- else {
+ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ cERROR(1,("SFU style symlinks not implemented yet"));
+ /* add open and read as in fs/cifs/inode.c */
+
+ } else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT,&fid, &oplock, NULL,
cifs_sb->local_nls,
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
index 7aa23490541..ccebf9b7eb8 100644
--- a/fs/cifs/md5.c
+++ b/fs/cifs/md5.c
@@ -252,10 +252,11 @@ MD5Transform(__u32 buf[4], __u32 const in[16])
buf[3] += d;
}
+#if 0 /* currently unused */
/***********************************************************************
the rfc 2104 version of hmac_md5 initialisation.
***********************************************************************/
-void
+static void
hmac_md5_init_rfc2104(unsigned char *key, int key_len,
struct HMACMD5Context *ctx)
{
@@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64);
}
+#endif
/***********************************************************************
the microsoft version of hmac_md5 initialisation.
@@ -350,7 +352,8 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/
-void
+#if 0 /* currently unused */
+static void
hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
unsigned char *digest)
{
@@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
}
hmac_md5_final(digest, &ctx);
}
+#endif
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h
index 00e1c5394fe..f7d4f4197ba 100644
--- a/fs/cifs/md5.h
+++ b/fs/cifs/md5.h
@@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context);
/* The following definitions come from lib/hmacmd5.c */
-void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
- struct HMACMD5Context *ctx);
+/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx);*/
void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
struct HMACMD5Context *ctx);
void hmac_md5_update(const unsigned char *text, int text_len,
struct HMACMD5Context *ctx);
void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
-void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
- unsigned char *digest);
+/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+ unsigned char *digest);*/
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 22c937e5884..bbc9cd34b6e 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 */ ,
return;
}
-int
+static int
checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{
/* Make sure that this really is an SMB, that it is a response,
@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
}
int
-checkSMB(struct smb_hdr *smb, __u16 mid, int length)
+checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
{
__u32 len = smb->smb_buf_length;
__u32 clc_len; /* calculated length */
cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
- if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
- (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
- if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
- if (((unsigned int)length >=
- sizeof (struct smb_hdr) - 1)
+
+ if (length < 2 + sizeof (struct smb_hdr)) {
+ if ((length >= sizeof (struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) {
- smb->WordCount = 0;
- /* some error cases do not return wct and bcc */
+ smb->WordCount = 0;
+ /* some error cases do not return wct and bcc */
+ return 0;
+ } else if ((length == sizeof(struct smb_hdr) + 1) &&
+ (smb->WordCount == 0)) {
+ char * tmp = (char *)smb;
+ /* Need to work around a bug in two servers here */
+ /* First, check if the part of bcc they sent was zero */
+ if (tmp[sizeof(struct smb_hdr)] == 0) {
+ /* some servers return only half of bcc
+ * on simple responses (wct, bcc both zero)
+ * in particular have seen this on
+ * ulogoffX and FindClose. This leaves
+ * one byte of bcc potentially unitialized
+ */
+ /* zero rest of bcc */
+ tmp[sizeof(struct smb_hdr)+1] = 0;
return 0;
- } else {
- cERROR(1, ("Length less than smb header size"));
}
+ cERROR(1,("rcvd invalid byte count (bcc)"));
+ } else {
+ cERROR(1, ("Length less than smb header size"));
}
- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
- cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
+ return 1;
+ }
+ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+ cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
smb->Mid));
return 1;
}
@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
return 1;
clc_len = smbCalcSize_LE(smb);
- if(4 + len != (unsigned int)length) {
+ if(4 + len != length) {
cERROR(1, ("Length read does not match RFC1001 length %d",len));
return 1;
}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index ce87550e918..992e80edc72 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -909,3 +909,61 @@ cifs_UnixTimeToNT(struct timespec t)
/* Convert to 100ns intervals and then add the NTFS time offset. */
return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
}
+
+static int total_days_of_prev_months[] =
+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+
+__le64 cnvrtDosCifsTm(__u16 date, __u16 time)
+{
+ return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time)));
+}
+
+struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
+{
+ struct timespec ts;
+ int sec, min, days, month, year;
+ SMB_TIME * st = (SMB_TIME *)&time;
+ SMB_DATE * sd = (SMB_DATE *)&date;
+
+ cFYI(1,("date %d time %d",date, time));
+
+ sec = 2 * st->TwoSeconds;
+ min = st->Minutes;
+ if((sec > 59) || (min > 59))
+ cERROR(1,("illegal time min %d sec %d", min, sec));
+ sec += (min * 60);
+ sec += 60 * 60 * st->Hours;
+ if(st->Hours > 24)
+ cERROR(1,("illegal hours %d",st->Hours));
+ days = sd->Day;
+ month = sd->Month;
+ if((days > 31) || (month > 12))
+ cERROR(1,("illegal date, month %d day: %d", month, days));
+ month -= 1;
+ days += total_days_of_prev_months[month];
+ days += 3652; /* account for difference in days between 1980 and 1970 */
+ year = sd->Year;
+ days += year * 365;
+ days += (year/4); /* leap year */
+ /* generalized leap year calculation is more complex, ie no leap year
+ for years/100 except for years/400, but since the maximum number for DOS
+ year is 2**7, the last year is 1980+127, which means we need only
+ consider 2 special case years, ie the years 2000 and 2100, and only
+ adjust for the lack of leap year for the year 2100, as 2000 was a
+ leap year (divisable by 400) */
+ if(year >= 120) /* the year 2100 */
+ days = days - 1; /* do not count leap year for the year 2100 */
+
+ /* adjust for leap year where we are still before leap day */
+ if(year != 120)
+ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
+ sec += 24 * 60 * 60 * days;
+
+ ts.tv_sec = sec;
+
+ /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */
+
+ ts.tv_nsec = 0;
+ return ts;
+}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index b27b34537bf..b5b0a2a41be 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,
return rc;
}
+static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
+{
+ if((tcon) && (tcon->ses) && (tcon->ses->server)) {
+ inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
+ inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
+ inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
+ }
+ return;
+}
+
+
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
char * buf, int *pobject_type, int isNewInode)
{
@@ -135,16 +146,23 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
tmp_inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
} else { /* legacy, OS2 and DOS style */
+/* struct timespec ts;*/
FIND_FILE_STANDARD_INFO * pfindData =
(FIND_FILE_STANDARD_INFO *)buf;
+ tmp_inode->i_mtime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastWriteDate),
+ le16_to_cpu(pfindData->LastWriteTime));
+ tmp_inode->i_atime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastAccessDate),
+ le16_to_cpu(pfindData->LastAccessTime));
+ tmp_inode->i_ctime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastWriteDate),
+ le16_to_cpu(pfindData->LastWriteTime));
+ AdjustForTZ(cifs_sb->tcon, tmp_inode);
attr = le16_to_cpu(pfindData->Attributes);
allocation_size = le32_to_cpu(pfindData->AllocationSize);
end_of_file = le32_to_cpu(pfindData->DataSize);
- tmp_inode->i_atime = CURRENT_TIME;
- /* tmp_inode->i_mtime = BB FIXME - add dos time handling
- tmp_inode->i_ctime = 0; BB FIXME */
-
}
/* 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,
filename = &pFindData->FileName[0];
/* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength;
+ cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else {
cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 22b4c35dcfe..a8a083543ba 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
ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverOS)
strncpy(ses->serverOS, bcc_ptr, len);
+ if(strncmp(ses->serverOS, "OS/2",4) == 0) {
+ cFYI(1,("OS/2 server"));
+ ses->flags |= CIFS_SES_OS2;
+ }
bcc_ptr += len + 1;
bleft -= len + 1;
@@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
if(len > bleft)
return rc;
- if(ses->serverDomain)
- kfree(ses->serverDomain);
-
- ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
- if(ses->serverOS)
- strncpy(ses->serverOS, bcc_ptr, len);
-
- bcc_ptr += len + 1;
- bleft -= len + 1;
-
+ /* No domain field in LANMAN case. Domain is
+ returned by old servers in the SMB negprot response */
+ /* BB For newer servers which do not support Unicode,
+ but thus do return domain here we could add parsing
+ for it later, but it is not very important */
cFYI(1,("ascii: bytes left %d",bleft));
return rc;
@@ -366,6 +365,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
str_area = kmalloc(2000, GFP_KERNEL);
bcc_ptr = str_area;
+ ses->flags &= ~CIFS_SES_LANMAN;
+
if(type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE];
@@ -377,7 +378,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* and copy into bcc */
calc_lanman_hash(ses, lnm_session_key);
-
+ ses->flags |= CIFS_SES_LANMAN;
/* #ifdef CONFIG_CIFS_DEBUG2
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
CIFS_SESS_KEY_SIZE);
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index efaa044523a..7a1b2b961ec 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)
smbhash(p24 + 16, c8, p21 + 14, 1);
}
-void
+#if 0 /* currently unsued */
+static void
D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
{
smbhash(out, in, p14, 0);
smbhash(out + 8, in + 8, p14 + 7, 0);
}
-void
+static void
E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
{
smbhash(out, in, p14, 1);
smbhash(out + 8, in + 8, p14 + 7, 1);
}
-#if 0
/* these routines are currently unneeded, but may be
needed later */
void
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index f518c5e4503..4b25ba92180 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -51,11 +51,8 @@
void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
unsigned char p24[24]);
-void NTLMSSPOWFencrypt(unsigned char passwd[8],
- unsigned char *ntlmchalresp, unsigned char p24[24]);
void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
/*
@@ -144,8 +141,9 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
memset(wpwd,0,129 * 2);
}
+#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */
-void
+static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
{
char passwd[514];
@@ -171,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
/* clear out local copy of user's password (just being paranoid). */
memset(passwd, '\0', sizeof (passwd));
}
+#endif
/* Does the NTLMv2 owfs of a user's password */
#if 0 /* function not needed yet - but will be soon */
@@ -223,7 +222,8 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
}
/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
-void
+#if 0 /* currently unused */
+static void
NTLMSSPOWFencrypt(unsigned char passwd[8],
unsigned char *ntlmchalresp, unsigned char p24[24])
{
@@ -235,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
E_P24(p21, ntlmchalresp, p24);
}
+#endif
/* Does the NT MD4 hash then des encryption. */