bk://cifs.bkbits.net/linux-2.5cifs cifs.adm@hostme.bitkeeper.com|ChangeSet|20040727181637|48812 cifs.adm # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/07/27 06:02:46-05:00 stevef@steveft21.ltcsamba # [CIFS] xattr support part 4 add set EA support # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/07/27 06:02:19-05:00 stevef@steveft21.ltcsamba +23 -4 # add set EA support # # fs/cifs/cifssmb.c # 2004/07/27 06:02:18-05:00 stevef@steveft21.ltcsamba +109 -6 # add set EA support and cleanup const parms for some prototypes # # fs/cifs/cifsproto.h # 2004/07/27 06:02:18-05:00 stevef@steveft21.ltcsamba +6 -2 # add set EA support and cleanup const parms for some prototypes # # fs/cifs/cifspdu.h # 2004/07/27 06:02:18-05:00 stevef@steveft21.ltcsamba +2 -0 # add set EA support # # ChangeSet # 2004/07/26 16:58:23-05:00 stevef@steveft21.ltcsamba # [CIFS] xattr support part 3 add query EA support to retrieve individual xattr values # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/07/26 16:57:54-05:00 stevef@steveft21.ltcsamba +99 -6 # [CIFS] xattr support part 3 add query EA # # fs/cifs/cifssmb.c # 2004/07/26 16:57:54-05:00 stevef@steveft21.ltcsamba +152 -0 # [CIFS] xattr support part 3 add query EA # # fs/cifs/cifsproto.h # 2004/07/26 16:57:53-05:00 stevef@steveft21.ltcsamba +4 -0 # [CIFS] xattr support part 3 add query EA prototype # # ChangeSet # 2004/07/24 09:42:08-05:00 stevef@steveft21.ltcsamba # [CIFS] xattr suport part 2: add listxattr support # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/xattr.c # 2004/07/24 09:41:15-05:00 stevef@steveft21.ltcsamba +4 -2 # add cifs listxattr support # # fs/cifs/cifssmb.c # 2004/07/24 09:41:15-05:00 stevef@steveft21.ltcsamba +130 -3 # add cifs listxattr support and level 1 setpathinfo # # fs/cifs/cifsproto.h # 2004/07/24 09:41:15-05:00 stevef@steveft21.ltcsamba +3 -4 # add cifs listxattr support # # fs/cifs/cifspdu.h # 2004/07/24 09:41:15-05:00 stevef@steveft21.ltcsamba +17 -4 # add level 1 setpathinfo # # ChangeSet # 2004/07/23 13:46:55-07:00 davem@nuts.davemloft.net # [PKT_SCHED]: Alpha not studly enough for SCH_CLK_CPU. # # The cycle counter it provides overflows very quickly, # on the order of 10 minutes, so it is not suitable for # this purpose. # # Signed-off-by: David S. Miller # # net/sched/Kconfig # 2004/07/23 13:46:29-07:00 davem@nuts.davemloft.net +1 -2 # [PKT_SCHED]: Alpha not studly enough for SCH_CLK_CPU. # # The cycle counter it provides overflows very quickly, # on the order of 10 minutes, so it is not suitable for # this purpose. # # Signed-off-by: David S. Miller # # ChangeSet # 2004/07/18 22:26:25-05:00 stevef@smfhome.smfdom # [CIFS] remove unneeded, unused prototypes. Suggested by Carl Spalletta # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/smbencrypt.c # 2004/07/18 22:26:12-05:00 stevef@smfhome.smfdom +0 -2 # remove unneeded, unused prototypes # # fs/cifs/cifsproto.h # 2004/07/18 22:26:12-05:00 stevef@smfhome.smfdom +0 -25 # remove unneeded, unused prototypes # # fs/cifs/cifsfs.h # 2004/07/18 22:26:12-05:00 stevef@smfhome.smfdom +0 -4 # remove unneeded, unused prototypes # # ChangeSet # 2004/07/18 17:23:42-05:00 stevef@smfhome.smfdom # CIFS: Add missing mount option for optionally cifs perm checks when uids on server and client do not match and for optionally overriding # server setting default uid/gid of new cifs files and directories. # # Signed-off-by: Steve French (sfrench@us.ibm.com) # # fs/cifs/inode.c # 2004/07/18 17:23:35-05:00 stevef@smfhome.smfdom +14 -6 # Add missing mount option for cifs perm checks and uid setting. # # fs/cifs/dir.c # 2004/07/18 17:23:35-05:00 stevef@smfhome.smfdom +19 -4 # Add missing mount option for cifs perm checks and uid setting. # # fs/cifs/connect.c # 2004/07/18 17:23:34-05:00 stevef@smfhome.smfdom +16 -0 # Add missing mount option for cifs perm checks and uid setting. # # fs/cifs/cifsfs.c # 2004/07/18 17:23:34-05:00 stevef@smfhome.smfdom +3 -7 # Add missing mount option for cifs perm checks and uid setting. # # fs/cifs/cifs_fs_sb.h # 2004/07/18 17:23:34-05:00 stevef@smfhome.smfdom +4 -0 # Add missing mount option for cifs perm checks and uid setting. # # fs/cifs/README # 2004/07/18 17:23:34-05:00 stevef@smfhome.smfdom +27 -1 # Add missing mount option for cifs perm checks and uid setting. # # fs/cifs/CHANGES # 2004/07/18 17:23:34-05:00 stevef@smfhome.smfdom +13 -0 # Update cifs change log # diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/CHANGES 2004-07-27 18:29:53 -07:00 @@ -1,3 +1,16 @@ +Version 1.21 +------------ +Add new mount parm to control whether mode check (vfs_permission) is done on +the client. If Unix extensions are enabled and the uids on the client +and server do not match, client permission checks are meaningless on +server uids that do not exist on the client (this does not affect the +normal ACL check which occurs on the server). Fix default uid +on mknod to match create and mkdir. Add optional mount parm to allow +override of the default uid behavior (in which the server sets the uid +and gid of newly created files). Normally for network filesystem mounts +user want the server to set the uid/gid on newly created files (rather than +using uid of the client processes you would in a local filesystem). + Version 1.20 ------------ Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps diff -Nru a/fs/cifs/README b/fs/cifs/README --- a/fs/cifs/README 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/README 2004-07-27 18:29:53 -07:00 @@ -255,7 +255,33 @@ mount helper will not prompt the user for a password if guest is specified on the mount options. If no password is specified a null password will be used. - + perm Client does permission checks (vfs_permission check of uid + and gid of the file against the mode and desired operation), + Note that this is in addition to the normal ACL check on the + target machine done by the server software. + Client permission checking is enabled by default. + noperm Client does not do permission checks. This can expose + files on this mount to access by other users on the local + client system. It is typically only needed when the server + supports the CIFS Unix Extensions but the UIDs/GIDs on the + client and server system do not match closely enough to allow + access by the user doing the mount. + Note that this does not affect the normal ACL check on the + target machine done by the server software (of the server + ACL against the user name provided at mount time). + setuids If the CIFS Unix extensions are negotiated with the server + the client will attempt to set the effective uid and gid of + the local process on newly created files, directories, and + devices (create, mkdir, mknod). + nosetuids The client will not attempt to set the uid and gid on + on newly created files, directories, and devices (create, + mkdir, mknod) which will result in the server setting the + uid and gid to the default (usually the server uid of the + usern who mounted the share). Letting the server (rather than + the client) set the uid and gid is the default. This + parameter has no effect if the CIFS Unix Extensions are not + negotiated. + The mount.cifs mount helper also accepts a few mount options before -o including: diff -Nru a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h --- a/fs/cifs/cifs_fs_sb.h 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/cifs_fs_sb.h 2004-07-27 18:29:53 -07:00 @@ -18,6 +18,9 @@ #ifndef _CIFS_FS_SB_H #define _CIFS_FS_SB_H +#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */ +#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */ + struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ struct list_head nested_tcon_q; @@ -28,5 +31,6 @@ gid_t mnt_gid; mode_t mnt_file_mode; mode_t mnt_dir_mode; + int mnt_cifs_flags; }; #endif /* _CIFS_FS_SB_H */ diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/cifsfs.c 2004-07-27 18:29:53 -07:00 @@ -192,15 +192,11 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) { - struct cifs_sb_info *cifs_sb; + struct cifs_sb_info *cifs_sb; - cifs_sb = CIFS_SB(inode->i_sb); + cifs_sb = CIFS_SB(inode->i_sb); - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { - /* the server supports the Unix-like mode bits and does its - own permission checks, and therefore we do not allow the file - mode to be overriden on these mounts - so do not do perm - check on client side */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { return 0; } else /* file mode might have been restricted at mount time on the client (above and beyond ACL on servers) for diff -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h --- a/fs/cifs/cifsfs.h 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/cifsfs.h 2004-07-27 18:29:53 -07:00 @@ -32,14 +32,10 @@ #define TRUE 1 #endif -extern int map_cifs_error(int error_class, int error_code, - int status_codes_negotiated); - extern struct address_space_operations cifs_addr_ops; /* Functions related to super block operations */ extern struct super_operations cifs_super_ops; -extern void cifs_put_inode(struct inode *); 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 -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h --- a/fs/cifs/cifspdu.h 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/cifspdu.h 2004-07-27 18:29:53 -07:00 @@ -1046,6 +1046,8 @@ /* PathInfo/FileInfo infolevels */ #define SMB_INFO_STANDARD 1 +#define SMB_SET_FILE_EA 2 +#define SMB_QUERY_FILE_EA_SIZE 2 #define SMB_INFO_QUERY_EAS_FROM_LIST 3 #define SMB_INFO_QUERY_ALL_EAS 4 #define SMB_INFO_IS_NAME_VALID 6 @@ -1620,6 +1622,19 @@ char LinkDest[1]; } FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */ +typedef struct { + __u16 CreationDate; + __u16 CreationTime; + __u16 LastAccessDate; + __u16 LastAccessTime; + __u16 LastWriteDate; + __u16 LastWriteTime; + __u32 DataSize; /* File Size (EOF) */ + __u32 AllocationSize; + __u16 Attributes; /* verify not u32 */ + __u32 EASize; +} FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ + /* defines for enumerating possible values of the Unix type field below */ #define UNIX_FILE 0 #define UNIX_DIR 1 @@ -1680,12 +1695,12 @@ } FILE_DIRECTORY_INFO; /* level 257 FF response data area */ struct gea { - unsigned char cbName; - char szName[1]; + unsigned char name_len; + char name[1]; }; struct gealist { - unsigned long cbList; + unsigned long list_len; struct gea list[1]; }; @@ -1693,7 +1708,7 @@ unsigned char EA_flags; __u8 name_len; __u16 value_len; - char szName[1]; + char name[1]; /* optionally followed by value */ }; /* flags for _FEA.fEA */ diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/cifsproto.h 2004-07-27 18:29:53 -07:00 @@ -128,10 +128,10 @@ const struct nls_table *nls_codepage); extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, - char *fileName, FILE_BASIC_INFO * data, + const char *fileName, const FILE_BASIC_INFO * data, const struct nls_table *nls_codepage); extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, - char *fileName, __u64 size,int setAllocationSizeFlag, + const char *fileName, __u64 size,int setAllocationSizeFlag, const struct nls_table *nls_codepage); extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); @@ -213,31 +213,6 @@ extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); - -extern int CIFSBuildServerList(int xid, char *serverBufferList, - int recordlength, int *entries, - int *totalEntries, int *topoChangedFlag); -extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon, - struct shareInfo *shareList, int bufferLen, - int *entries, int *totalEntries); -extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon, - struct aliasInfo *aliasList, int bufferLen, - int *entries, int *totalEntries); -extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon, - char *aliasName, char *serverName, - char *shareName, char *comment); -extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon, - char *share, char *comment); -extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon, - char *userName, char *searchName, int *perms); -extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid); - -extern int CIFSSMBSeek(int xid, - struct cifsTconInfo *tcon, - int netfid, - int pid, - int whence, unsigned long offset, long long *newoffset); - extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, @@ -247,8 +222,15 @@ extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, const int notify_subdirs,const __u16 netfid,__u32 filter, const struct nls_table *nls_codepage); -extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, - const unsigned char *searchName, - char * EAData, size_t size, - const struct nls_table *nls_codepage); +extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, + const unsigned char *searchName, char * EAData, + size_t bufsize, const struct nls_table *nls_codepage); +extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, + const unsigned char * searchName,const unsigned char * ea_name, + unsigned char * ea_value, size_t buf_size, + const struct nls_table *nls_codepage); +extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, + const char *fileName, const char * ea_name, + const void * ea_value, const __u16 ea_value_len, + const struct nls_table *nls_codepage); #endif /* _CIFSPROTO_H */ diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c --- a/fs/cifs/cifssmb.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/cifssmb.c 2004-07-27 18:29:53 -07:00 @@ -2287,7 +2287,7 @@ } int -CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon, +CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage) { /* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ @@ -2359,7 +2359,7 @@ } int -CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon, +CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage) { /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ @@ -2432,7 +2432,7 @@ } int -CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon, +CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage) { /* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ @@ -2512,7 +2512,7 @@ in Samba which this routine can run into */ int -CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName, +CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName, __u64 size, int SetAllocation, const struct nls_table *nls_codepage) { struct smb_com_transaction2_spi_req *pSMB = NULL; @@ -2692,8 +2692,9 @@ } int -CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName, - FILE_BASIC_INFO * data, const struct nls_table *nls_codepage) +CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, + const FILE_BASIC_INFO * data, + const struct nls_table *nls_codepage) { TRANSACTION2_SPI_REQ *pSMB = NULL; TRANSACTION2_SPI_RSP *pSMBr = NULL; @@ -2770,6 +2771,89 @@ return rc; } + +int +CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName, + FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage) +{ + TRANSACTION2_SPI_REQ *pSMB = NULL; + TRANSACTION2_SPI_RSP *pSMBr = NULL; + int name_len; + int rc = 0; + int bytes_returned = 0; + char *data_offset; + + cFYI(1, ("In SetTimesLegacy")); + +SetTimesRetryLegacy: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } +/* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info + in parent function, from the better and ususal FILE_BASIC_INFO */ + pSMB->ParameterCount = 6 + name_len; + pSMB->DataCount = sizeof (FILE_INFO_STANDARD); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->TotalParameterCount = pSMB->ParameterCount; + /* I doubt that passthrough levels apply to this old + preNT info level */ +/* if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) + pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); + else*/ + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD)); + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (times legacy) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetryLegacy; + + return rc; +} + int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, char *fileName, __u64 mode, __u64 uid, __u64 gid, @@ -2915,10 +2999,10 @@ return rc; } #ifdef CONFIG_CIFS_XATTR -int +ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, - char * EAData, size_t size, + char * EAData, size_t buf_size, const struct nls_table *nls_codepage) { /* BB assumes one setup word */ @@ -2927,6 +3011,8 @@ int rc = 0; int bytes_returned; int name_len; + struct fea * temp_fea; + char * temp_ptr; cFYI(1, ("In Query All EAs path %s", searchName)); QAllEAsRetry: @@ -2942,7 +3028,7 @@ , nls_codepage); name_len++; /* trailing null */ name_len *= 2; - } else { /* BB improve the check for buffer overruns BB */ + } else { /* BB improve the check for buffer overruns BB */ name_len = strnlen(searchName, 530); name_len++; /* trailing null */ strncpy(pSMB->FileName, searchName, name_len); @@ -3001,7 +3087,53 @@ ea_response_data = (struct fealist *) (((char *) &pSMBr->hdr.Protocol) + pSMBr->DataOffset); + ea_response_data->list_len = + cpu_to_le32(ea_response_data->list_len); cFYI(1,("ea length %d",ea_response_data->list_len)); + name_len = ea_response_data->list_len; + if(name_len <= 8) { + /* returned EA size zeroed at top of function */ + cFYI(1,("empty EA list returned from server")); + } else { + /* account for ea list len */ + name_len -= 4; + temp_fea = ea_response_data->list; + temp_ptr = (char *)temp_fea; + while(name_len > 0) { + name_len -= 4; + temp_ptr += 4; + rc += temp_fea->name_len; + /* account for prefix user. and trailing null */ + rc = rc + 5 + 1; + if(rcname_len); + EAData+=temp_fea->name_len; + /* null terminate name */ + *EAData = 0; + EAData = EAData + 1; + } else if(buf_size == 0) { + /* skip copy - calc size only */ + } else { + /* stop before overrun buffer */ + rc = -ERANGE; + break; + } + name_len -= temp_fea->name_len; + temp_ptr += temp_fea->name_len; + /* account for trailing null */ + name_len--; + temp_ptr++; + temp_fea->value_len = cpu_to_le16(temp_fea->value_len); + name_len -= temp_fea->value_len; + temp_ptr += temp_fea->value_len; + /* BB check that temp_ptr is still within smb BB*/ + /* no trailing null to account for in value len */ + /* go on to next EA */ + temp_fea = (struct fea *)temp_ptr; + } + } } } if (pSMB) @@ -3011,4 +3143,254 @@ return rc; } + +ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon, + const unsigned char * searchName,const unsigned char * ea_name, + unsigned char * ea_value, size_t buf_size, + const struct nls_table *nls_codepage) +{ + TRANSACTION2_QPI_REQ *pSMB = NULL; + TRANSACTION2_QPI_RSP *pSMBr = NULL; + int rc = 0; + int bytes_returned; + int name_len; + struct fea * temp_fea; + char * temp_ptr; + + cFYI(1, ("In Query EA path %s", searchName)); +QEARetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(searchName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, searchName, name_len); + } + + pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + + name_len /* includes null */ ; + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); + pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in Query EA = %d", rc)); + } else { /* decode response */ + pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); + /* BB also check enough total bytes returned */ + /* BB we need to improve the validity checking + of these trans2 responses */ + if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) + rc = -EIO; /* bad smb */ + /* else if (pFindData){ + memcpy((char *) pFindData, + (char *) &pSMBr->hdr.Protocol + + pSMBr->DataOffset, kl); + }*/ else { + /* check that length of list is not more than bcc */ + /* check that each entry does not go beyond length + of list */ + /* check that each element of each entry does not + go beyond end of list */ + struct fealist * ea_response_data; + rc = -ENOENT; + /* validate_trans2_offsets() */ + /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ + ea_response_data = (struct fealist *) + (((char *) &pSMBr->hdr.Protocol) + + pSMBr->DataOffset); + ea_response_data->list_len = + cpu_to_le32(ea_response_data->list_len); + cFYI(1,("ea length %d",ea_response_data->list_len)); + name_len = ea_response_data->list_len; + if(name_len <= 8) { + /* returned EA size zeroed at top of function */ + cFYI(1,("empty EA list returned from server")); + } else { + /* account for ea list len */ + name_len -= 4; + temp_fea = ea_response_data->list; + temp_ptr = (char *)temp_fea; + /* loop through checking if we have a matching + name and then return the associated value */ + while(name_len > 0) { + name_len -= 4; + temp_ptr += 4; + temp_fea->value_len = cpu_to_le16(temp_fea->value_len); + /* BB validate that value_len falls within SMB, + even though maximum for name_len is 255 */ + if(memcmp(temp_fea->name,ea_name, + temp_fea->name_len) == 0) { + /* found a match */ + rc = temp_fea->value_len; + /* account for prefix user. and trailing null */ + if(rc<=buf_size) { + memcpy(ea_value, + temp_fea->name+temp_fea->name_len+1, + rc); + /* ea values, unlike ea names, + are not null terminated */ + } else if(buf_size == 0) { + /* skip copy - calc size only */ + } else { + /* stop before overrun buffer */ + rc = -ERANGE; + } + break; + } + name_len -= temp_fea->name_len; + temp_ptr += temp_fea->name_len; + /* account for trailing null */ + name_len--; + temp_ptr++; + name_len -= temp_fea->value_len; + temp_ptr += temp_fea->value_len; + /* no trailing null to account for in value len */ + /* go on to next EA */ + temp_fea = (struct fea *)temp_ptr; + } + } + } + } + if (pSMB) + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QEARetry; + + return rc; +} + +int +CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, + const char * ea_name, const void * ea_value, + const __u16 ea_value_len, const struct nls_table *nls_codepage) +{ + struct smb_com_transaction2_spi_req *pSMB = NULL; + struct smb_com_transaction2_spi_rsp *pSMBr = NULL; + struct fealist *parm_data; + int name_len; + int rc = 0; + int bytes_returned = 0; + + cFYI(1, ("In SetEA")); +SetEARetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { + name_len = + cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 + /* find define for this maxpathcomponent */ + , nls_codepage); + name_len++; /* trailing null */ + name_len *= 2; + } else { /* BB improve the check for buffer overruns BB */ + name_len = strnlen(fileName, 530); + name_len++; /* trailing null */ + strncpy(pSMB->FileName, fileName, name_len); + } + + pSMB->ParameterCount = 6 + name_len; + + /* done calculating parms using name_len of file name, + now use name_len to calculate length of ea name + we are going to create in the inode xattrs */ + if(ea_name == NULL) + name_len = 0; + else + name_len = strnlen(ea_name,255); + + pSMB->DataCount = sizeof(*parm_data) + ea_value_len + name_len + 1; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, + InformationLevel) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + pSMB->InformationLevel = + cpu_to_le16(SMB_SET_FILE_EA); + + parm_data = + (struct fealist *) (((char *) &pSMB->hdr.Protocol) + + pSMB->DataOffset); + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; + pSMB->DataCount = cpu_to_le16(pSMB->DataCount); + parm_data->list_len = (__u32)(pSMB->DataCount); + parm_data->list[0].EA_flags = 0; + /* we checked above that name len is less than 255 */ + parm_data->list[0].name_len = (__u8)name_len;; + /* EA names are always ASCII */ + strncpy(parm_data->list[0].name,ea_name,name_len); + parm_data->list[0].name[name_len] = 0; + parm_data->list[0].value_len = cpu_to_le16(ea_value_len); + /* caller ensures that ea_value_len is less than 64K but + we need to ensure that it fits within the smb */ + + /*BB add length check that it would fit in negotiated SMB buffer size BB */ + /* if(ea_value_len > buffer_size - 512 (enough for header)) */ + memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len); + + pSMB->TotalDataCount = pSMB->DataCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->Reserved4 = 0; + pSMB->hdr.smb_buf_length += pSMB->ByteCount; + pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("SetPathInfo (EA) returned %d", rc)); + } + + if (pSMB) + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetEARetry; + + return rc; +} + #endif diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/connect.c 2004-07-27 18:29:53 -07:00 @@ -64,6 +64,8 @@ int rw:1; int retry:1; int intr:1; + int setuids:1; + int noperm:1; unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -740,6 +742,14 @@ vol->retry = 1; } else if (strnicmp(data, "soft", 4) == 0) { vol->retry = 0; + } else if (strnicmp(data, "perm", 4) == 0) { + vol->noperm = 0; + } else if (strnicmp(data, "noperm", 6) == 0) { + vol->noperm = 1; + } else if (strnicmp(data, "setuids", 7) == 0) { + vol->setuids = 1; + } else if (strnicmp(data, "nosetuids", 9) == 0) { + vol->setuids = 0; } else if (strnicmp(data, "nohard", 6) == 0) { vol->retry = 0; } else if (strnicmp(data, "nosoft", 6) == 0) { @@ -1314,6 +1324,12 @@ cifs_sb->mnt_file_mode = volume_info.file_mode; cifs_sb->mnt_dir_mode = volume_info.dir_mode; cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); + + if(volume_info.noperm) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; + if(volume_info.setuids) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; + tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); diff -Nru a/fs/cifs/dir.c b/fs/cifs/dir.c --- a/fs/cifs/dir.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/dir.c 2004-07-27 18:29:53 -07:00 @@ -243,11 +243,19 @@ then we now have to set the mode if possible */ if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) && (oplock & CIFS_CREATE_ACTION)) - CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)current->euid, + (__u64)current->egid, + 0 /* dev */, + cifs_sb->local_nls); + } else { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, (__u64)-1, (__u64)-1, 0 /* dev */, cifs_sb->local_nls); + } else { /* BB implement via Windows security descriptors */ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ @@ -348,9 +356,16 @@ rc = -ENOMEM; if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { - rc = CIFSSMBUnixSetPerms(xid, pTcon, - full_path, mode, current->euid, current->egid, - device_number, cifs_sb->local_nls); + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, + mode,(__u64)current->euid,(__u64)current->egid, + device_number, cifs_sb->local_nls); + } else { + rc = CIFSSMBUnixSetPerms(xid, pTcon, + full_path, mode, (__u64)-1, (__u64)-1, + device_number, cifs_sb->local_nls); + } + if(!rc) { rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,xid); diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c --- a/fs/cifs/inode.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/inode.c 2004-07-27 18:29:53 -07:00 @@ -480,12 +480,20 @@ d_instantiate(direntry, newinode); if(direntry->d_inode) direntry->d_inode->i_nlink = 2; - if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) - CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - (__u64)-1, - (__u64)-1, - 0 /* dev_t */, - cifs_sb->local_nls); + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)current->euid, + (__u64)current->egid, + 0 /* dev_t */, + cifs_sb->local_nls); + } else { + CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, + (__u64)-1, + (__u64)-1, + 0 /* dev_t */, + cifs_sb->local_nls); + } else { /* BB to be implemented via Windows secrty descriptors*/ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ } diff -Nru a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c --- a/fs/cifs/smbencrypt.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/smbencrypt.c 2004-07-27 18:29:53 -07:00 @@ -70,8 +70,6 @@ void NTLMSSPOWFencrypt(unsigned char passwd[8], unsigned char *ntlmchalresp, unsigned char p24[24]); void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -int decode_pw_buffer(char in_buffer[516], char *new_pwrd, - int new_pwrd_size, __u32 * new_pw_len); /* This implements the X/Open SMB password encryption diff -Nru a/fs/cifs/xattr.c b/fs/cifs/xattr.c --- a/fs/cifs/xattr.c 2004-07-27 18:29:53 -07:00 +++ b/fs/cifs/xattr.c 2004-07-27 18:29:53 -07:00 @@ -26,27 +26,136 @@ #include "cifsproto.h" #include "cifs_debug.h" +#define MAX_EA_VALUE_SIZE 65535 +#define CIFS_XATTR_DOS_ATTRIB "user.DOSATTRIB" +#define CIFS_XATTR_USER_PREFIX "user." +#define CIFS_XATTR_SYSTEM_PREFIX "system." +#define CIFS_XATTR_OS2_PREFIX "OS2." /* BB should check for this someday */ +/* also note could add check for security prefix XATTR_SECURITY_PREFIX */ + + int cifs_removexattr(struct dentry * direntry, const char * name) { int rc = -EOPNOTSUPP; return rc; } -int cifs_setxattr(struct dentry * direntry, const char * name, - const void * value, size_t size, int flags) +int cifs_setxattr(struct dentry * direntry, const char * ea_name, + const void * ea_value, size_t value_size, int flags) { int rc = -EOPNOTSUPP; +#ifdef CONFIG_CIFS_XATTR + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct super_block * sb; + char * full_path; + + if(direntry == NULL) + return -EIO; + if(direntry->d_inode == NULL) + return -EIO; + sb = direntry->d_inode->i_sb; + if(sb == NULL) + return -EIO; + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + down(&sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + /* return dos attributes as pseudo xattr */ + /* return alt name if available as pseudo attr */ + + /* if proc/fs/cifs/streamstoxattr is set then + search server for EAs or streams to + returns as xattrs */ + if(value_size > MAX_EA_VALUE_SIZE) { + cFYI(1,("size of EA value too large")); + if(full_path) + kfree(full_path); + FreeXid(xid); + return -EOPNOTSUPP; + } + + if(ea_name == NULL) { + cFYI(1,("Null xattr names not supported")); + } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) { + cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); + /* BB what if no namespace prefix? */ + /* Should we just pass them to server, except for + system and perhaps security prefixes? */ + } else { + ea_name+=5; /* skip past user. prefix */ + rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, + (__u16)value_size, cifs_sb->local_nls); + } + if (full_path) + kfree(full_path); + FreeXid(xid); +#endif return rc; } -ssize_t cifs_getxattr(struct dentry * direntry, const char * name, - void * value, size_t size) +ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, + void * ea_value, size_t buf_size) { ssize_t rc = -EOPNOTSUPP; +#ifdef CONFIG_CIFS_XATTR + int xid; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct super_block * sb; + char * full_path; + + if(direntry == NULL) + return -EIO; + if(direntry->d_inode == NULL) + return -EIO; + sb = direntry->d_inode->i_sb; + if(sb == NULL) + return -EIO; + xid = GetXid(); + + cifs_sb = CIFS_SB(sb); + pTcon = cifs_sb->tcon; + + down(&sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(direntry); + up(&sb->s_vfs_rename_sem); + if(full_path == NULL) { + FreeXid(xid); + return -ENOMEM; + } + /* return dos attributes as pseudo xattr */ + /* return alt name if available as pseudo attr */ + if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)) { + cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); + /* BB what if no namespace prefix? */ + /* Should we just pass them to server, except for system? */ + } else { + /* We could add a check here + if proc/fs/cifs/streamstoxattr is set then + search server for EAs or streams to + returns as xattrs */ + ea_name+=5; /* skip past user. */ + rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, + buf_size, cifs_sb->local_nls); + } + if (full_path) + kfree(full_path); + FreeXid(xid); +#endif return rc; } -ssize_t cifs_listxattr(struct dentry * direntry, char * ea_data, size_t ea_size) +ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) { ssize_t rc = -EOPNOTSUPP; #ifdef CONFIG_CIFS_XATTR @@ -55,6 +164,7 @@ struct cifsTconInfo *pTcon; struct super_block * sb; char * full_path; + if(direntry == NULL) return -EIO; if(direntry->d_inode == NULL) @@ -74,13 +184,17 @@ FreeXid(xid); return -ENOMEM; } - /* return dosattributes as pseudo xattr */ + /* return dos attributes as pseudo xattr */ /* return alt name if available as pseudo attr */ /* if proc/fs/cifs/streamstoxattr is set then search server for EAs or streams to returns as xattrs */ - rc = CIFSSMBQAllEAs(xid,pTcon,full_path,ea_data,ea_size,cifs_sb->local_nls); + rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, + cifs_sb->local_nls); + + if (full_path) + kfree(full_path); FreeXid(xid); #endif return rc;