]> Git Repo - linux.git/commitdiff
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <[email protected]>
Wed, 3 Jul 2013 21:06:30 +0000 (14:06 -0700)
committerLinus Torvalds <[email protected]>
Wed, 3 Jul 2013 21:06:30 +0000 (14:06 -0700)
Pull cifs updates from Steve French:
 "Various CIFS/SMB2/SMB3 updates for 3.11.  Includes bug fixes - SMB3
  support should be much more stable with key DFS fix and also signing
  possible now (although is more work to do to get SMB3 signing working
  well with multiuser).

  Mounts using the new SMB 3.02 dialect can now be done (specify
  "vers=3.02" on mount) against the most current Microsoft systems.

  Also includes a big cleanup of the cifs/smb2/smb3 authentication code
  from Jeff which fixes some long standing problems with the way allowed
  authentication flavors and signing are configured.

  Some followon patches later in the cycle will clean up allocation of
  structures for the various security mechanisms depending on what
  dialect is chosen (reduces memory usage a little) and to add support
  for the secure negotiate fsctl (for smb3) which prevents downgrade
  attacks."

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6: (39 commits)
  cifs: fill TRANS2_QUERY_FILE_INFO ByteCount fields
  cifs: fix SMB2 signing enablement in cifs_enable_signing
  [CIFS] Fix build warning
  [CIFS] SMB3 Signing enablement
  [CIFS] Do not set DFS flag on SMB2 open
  [CIFS] fix static checker warning
  cifs: try to handle the MUST SecurityFlags sanely
  When server doesn't provide SecurityBuffer on SMB2Negotiate pick default
  Handle big endianness in NTLM (ntlmv2) authentication
  revalidate directories instiantiated via FIND_* in order to handle DFS referrals
  SMB2 FSCTL and IOCTL worker function
  Charge at least one credit, if server says that it supports multicredit
  Remove typo
  Some missing share flags
  cifs: using strlcpy instead of strncpy
  Update headers to update various SMB3 ioctl definitions
  Update cifs version number
  Add ability to dipslay SMB3 share flags and capabilities for debugging
  Add some missing SMB3 and SMB3.02 flags
  Add SMB3.02 dialect support
  ...

1  2 
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/readdir.c

diff --combined fs/cifs/cifsfs.c
index a445e71746fabdcaf308d6a2fbe9365e40cba849,0f36654f22d0b8ced402ed5e849c6fa0caa14c9a..4bdd547dbf6fb3d10a2b2b962b710b722d0b9685
@@@ -312,11 -312,14 +312,14 @@@ cifs_show_address(struct seq_file *s, s
  }
  
  static void
- cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server)
+ cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
  {
+       if (ses->sectype == Unspecified)
+               return;
        seq_printf(s, ",sec=");
  
-       switch (server->secType) {
+       switch (ses->sectype) {
        case LANMAN:
                seq_printf(s, "lanman");
                break;
                break;
        }
  
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->sign)
                seq_printf(s, "i");
  }
  
@@@ -369,7 -372,7 +372,7 @@@ cifs_show_options(struct seq_file *s, s
        srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
  
        seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string);
-       cifs_show_security(s, tcon->ses->server);
+       cifs_show_security(s, tcon->ses);
        cifs_show_cache_flavor(s, cifs_sb);
  
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
@@@ -765,7 -768,7 +768,7 @@@ static loff_t cifs_llseek(struct file *
  
  static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
  {
 -      /* note that this is called by vfs setlease with lock_flocks held
 +      /* note that this is called by vfs setlease with i_lock held
           to protect *lease from going away */
        struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
@@@ -968,7 -971,7 +971,7 @@@ const struct file_operations cifs_file_
  };
  
  const struct file_operations cifs_dir_ops = {
 -      .readdir = cifs_readdir,
 +      .iterate = cifs_readdir,
        .release = cifs_closedir,
        .read    = generic_read_dir,
        .unlocked_ioctl  = cifs_ioctl,
diff --combined fs/cifs/cifsfs.h
index d05b3028e3b96ef7c99eaa202d10bc22630489e7,59aa8db34727b6e28ee3fa1919720f72ad84a569..ea723a5e8226231d64cd85eab065c7f91801a3a0
@@@ -101,7 -101,7 +101,7 @@@ extern int cifs_file_mmap(struct file 
  extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
  extern const struct file_operations cifs_dir_ops;
  extern int cifs_dir_open(struct inode *inode, struct file *file);
 -extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
 +extern int cifs_readdir(struct file *file, struct dir_context *ctx);
  
  /* Functions related to dir entries */
  extern const struct dentry_operations cifs_dentry_ops;
@@@ -132,5 -132,5 +132,5 @@@ extern long cifs_ioctl(struct file *fil
  extern const struct export_operations cifs_export_ops;
  #endif /* CONFIG_CIFS_NFSD_EXPORT */
  
- #define CIFS_VERSION   "2.0"
+ #define CIFS_VERSION   "2.01"
  #endif                                /* _CIFSFS_H */
diff --combined fs/cifs/readdir.c
index f1213799de1a2603b1f8f1c8d42f8b0fb2cb5a64,94d620198209622c487624efe08bee998904b9b5..ab877846939499c18cb454c83ed26c43dc60040c
@@@ -126,6 -126,22 +126,22 @@@ out
        dput(dentry);
  }
  
+ /*
+  * Is it possible that this directory might turn out to be a DFS referral
+  * once we go to try and use it?
+  */
+ static bool
+ cifs_dfs_is_possible(struct cifs_sb_info *cifs_sb)
+ {
+ #ifdef CONFIG_CIFS_DFS_UPCALL
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+               return true;
+ #endif
+       return false;
+ }
  static void
  cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
  {
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
                fattr->cf_dtype = DT_DIR;
+               /*
+                * Windows CIFS servers generally make DFS referrals look
+                * like directories in FIND_* responses with the reparse
+                * attribute flag also set (since DFS junctions are
+                * reparse points). We must revalidate at least these
+                * directory inodes before trying to use them (if
+                * they are DFS we will get PATH_NOT_COVERED back
+                * when queried directly and can then try to connect
+                * to the DFS target)
+                */
+               if (cifs_dfs_is_possible(cifs_sb) &&
+                   (fattr->cf_cifsattrs & ATTR_REPARSE))
+                       fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
        } else {
                fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
                fattr->cf_dtype = DT_REG;
@@@ -537,14 -566,14 +566,14 @@@ static int cifs_save_resume_key(const c
   * every entry (do not increment for . or .. entry).
   */
  static int
 -find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
 +find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
                struct file *file, char **current_entry, int *num_to_ret)
  {
        __u16 search_flags;
        int rc = 0;
        int pos_in_buf = 0;
        loff_t first_entry_in_buffer;
 -      loff_t index_to_find = file->f_pos;
 +      loff_t index_to_find = pos;
        struct cifsFileInfo *cfile = file->private_data;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        struct TCP_Server_Info *server = tcon->ses->server;
        return rc;
  }
  
 -static int cifs_filldir(char *find_entry, struct file *file, filldir_t filldir,
 -              void *dirent, char *scratch_buf, unsigned int max_len)
 +static int cifs_filldir(char *find_entry, struct file *file,
 +              struct dir_context *ctx,
 +              char *scratch_buf, unsigned int max_len)
  {
        struct cifsFileInfo *file_info = file->private_data;
        struct super_block *sb = file->f_path.dentry->d_sb;
        cifs_prime_dcache(file->f_dentry, &name, &fattr);
  
        ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
 -      rc = filldir(dirent, name.name, name.len, file->f_pos, ino,
 -                   fattr.cf_dtype);
 -      return rc;
 +      return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
  }
  
  
 -int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 +int cifs_readdir(struct file *file, struct dir_context *ctx)
  {
        int rc = 0;
        unsigned int xid;
                        goto rddir2_exit;
        }
  
 -      switch ((int) file->f_pos) {
 -      case 0:
 -              if (filldir(direntry, ".", 1, file->f_pos,
 -                   file_inode(file)->i_ino, DT_DIR) < 0) {
 -                      cifs_dbg(VFS, "Filldir for current dir failed\n");
 -                      rc = -ENOMEM;
 -                      break;
 -              }
 -              file->f_pos++;
 -      case 1:
 -              if (filldir(direntry, "..", 2, file->f_pos,
 -                   parent_ino(file->f_path.dentry), DT_DIR) < 0) {
 -                      cifs_dbg(VFS, "Filldir for parent dir failed\n");
 -                      rc = -ENOMEM;
 -                      break;
 -              }
 -              file->f_pos++;
 -      default:
 -              /* 1) If search is active,
 -                      is in current search buffer?
 -                      if it before then restart search
 -                      if after then keep searching till find it */
 -
 -              if (file->private_data == NULL) {
 -                      rc = -EINVAL;
 -                      free_xid(xid);
 -                      return rc;
 -              }
 -              cifsFile = file->private_data;
 -              if (cifsFile->srch_inf.endOfSearch) {
 -                      if (cifsFile->srch_inf.emptyDir) {
 -                              cifs_dbg(FYI, "End of search, empty dir\n");
 -                              rc = 0;
 -                              break;
 -                      }
 -              } /* else {
 -                      cifsFile->invalidHandle = true;
 -                      tcon->ses->server->close(xid, tcon, &cifsFile->fid);
 -              } */
 +      if (!dir_emit_dots(file, ctx))
 +              goto rddir2_exit;
  
 -              tcon = tlink_tcon(cifsFile->tlink);
 -              rc = find_cifs_entry(xid, tcon, file, &current_entry,
 -                                   &num_to_fill);
 -              if (rc) {
 -                      cifs_dbg(FYI, "fce error %d\n", rc);
 -                      goto rddir2_exit;
 -              } else if (current_entry != NULL) {
 -                      cifs_dbg(FYI, "entry %lld found\n", file->f_pos);
 -              } else {
 -                      cifs_dbg(FYI, "could not find entry\n");
 +      /* 1) If search is active,
 +              is in current search buffer?
 +              if it before then restart search
 +              if after then keep searching till find it */
 +
 +      if (file->private_data == NULL) {
 +              rc = -EINVAL;
 +              goto rddir2_exit;
 +      }
 +      cifsFile = file->private_data;
 +      if (cifsFile->srch_inf.endOfSearch) {
 +              if (cifsFile->srch_inf.emptyDir) {
 +                      cifs_dbg(FYI, "End of search, empty dir\n");
 +                      rc = 0;
                        goto rddir2_exit;
                }
 -              cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
 -                       num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
 -              max_len = tcon->ses->server->ops->calc_smb_size(
 -                              cifsFile->srch_inf.ntwrk_buf_start);
 -              end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 -
 -              tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
 -              if (tmp_buf == NULL) {
 -                      rc = -ENOMEM;
 +      } /* else {
 +              cifsFile->invalidHandle = true;
 +              tcon->ses->server->close(xid, tcon, &cifsFile->fid);
 +      } */
 +
 +      tcon = tlink_tcon(cifsFile->tlink);
 +      rc = find_cifs_entry(xid, tcon, ctx->pos, file, &current_entry,
 +                           &num_to_fill);
 +      if (rc) {
 +              cifs_dbg(FYI, "fce error %d\n", rc);
 +              goto rddir2_exit;
 +      } else if (current_entry != NULL) {
 +              cifs_dbg(FYI, "entry %lld found\n", ctx->pos);
 +      } else {
 +              cifs_dbg(FYI, "could not find entry\n");
 +              goto rddir2_exit;
 +      }
 +      cifs_dbg(FYI, "loop through %d times filling dir for net buf %p\n",
 +               num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
 +      max_len = tcon->ses->server->ops->calc_smb_size(
 +                      cifsFile->srch_inf.ntwrk_buf_start);
 +      end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 +
 +      tmp_buf = kmalloc(UNICODE_NAME_MAX, GFP_KERNEL);
 +      if (tmp_buf == NULL) {
 +              rc = -ENOMEM;
 +              goto rddir2_exit;
 +      }
 +
 +      for (i = 0; i < num_to_fill; i++) {
 +              if (current_entry == NULL) {
 +                      /* evaluate whether this case is an error */
 +                      cifs_dbg(VFS, "past SMB end,  num to fill %d i %d\n",
 +                               num_to_fill, i);
                        break;
                }
 -
 -              for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
 -                      if (current_entry == NULL) {
 -                              /* evaluate whether this case is an error */
 -                              cifs_dbg(VFS, "past SMB end,  num to fill %d i %d\n",
 -                                       num_to_fill, i);
 -                              break;
 -                      }
 -                      /*
 -                       * if buggy server returns . and .. late do we want to
 -                       * check for that here?
 -                       */
 -                      rc = cifs_filldir(current_entry, file, filldir,
 -                                        direntry, tmp_buf, max_len);
 -                      if (rc == -EOVERFLOW) {
 +              /*
 +               * if buggy server returns . and .. late do we want to
 +               * check for that here?
 +               */
 +              rc = cifs_filldir(current_entry, file, ctx,
 +                                tmp_buf, max_len);
 +              if (rc) {
 +                      if (rc > 0)
                                rc = 0;
 -                              break;
 -                      }
 -
 -                      file->f_pos++;
 -                      if (file->f_pos ==
 -                              cifsFile->srch_inf.index_of_last_entry) {
 -                              cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
 -                                       file->f_pos, tmp_buf);
 -                              cifs_save_resume_key(current_entry, cifsFile);
 -                              break;
 -                      } else
 -                              current_entry =
 -                                      nxt_dir_entry(current_entry, end_of_smb,
 -                                              cifsFile->srch_inf.info_level);
 +                      break;
                }
 -              kfree(tmp_buf);
 -              break;
 -      } /* end switch */
 +
 +              ctx->pos++;
 +              if (ctx->pos ==
 +                      cifsFile->srch_inf.index_of_last_entry) {
 +                      cifs_dbg(FYI, "last entry in buf at pos %lld %s\n",
 +                               ctx->pos, tmp_buf);
 +                      cifs_save_resume_key(current_entry, cifsFile);
 +                      break;
 +              } else
 +                      current_entry =
 +                              nxt_dir_entry(current_entry, end_of_smb,
 +                                      cifsFile->srch_inf.info_level);
 +      }
 +      kfree(tmp_buf);
  
  rddir2_exit:
        free_xid(xid);
This page took 0.08124 seconds and 4 git commands to generate.