Print this page
    
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-15577 SMB2 ioct dfs_get_referral returns wrong error
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15577 SMB2 ioct dfs_get_referral returns wrong error
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/smbsrv/smb_dfs.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_dfs.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   *
  25      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       25 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26   26   */
  27   27  
  28   28  #include <smbsrv/smb_kproto.h>
  29   29  #include <smbsrv/smb_dfs.h>
  30   30  #include <smbsrv/smb_door.h>
  31      -#include <smbsrv/winioctl.h>
       31 +#include <smb/winioctl.h>
  32   32  
  33   33  /*
  34   34   * Get Referral response header flags
  35   35   * For exact meaning refer to MS-DFSC spec.
  36   36   *
  37   37   * R: ReferralServers
  38   38   * S: StorageServers
  39   39   * T: TargetFailback
  40   40   */
  41   41  #define DFS_HDRFLG_R            0x00000001
  42   42  #define DFS_HDRFLG_S            0x00000002
  43   43  #define DFS_HDRFLG_T            0x00000004
  44   44  
  45   45  /*
  46   46   * Entry flags
  47   47   */
  48   48  #define DFS_ENTFLG_T            0x0004
  49   49  
  50   50  /*
  51   51   * Referral entry types/versions
  52   52   */
  53   53  #define DFS_REFERRAL_V1         0x0001
  54   54  #define DFS_REFERRAL_V2         0x0002
  55   55  #define DFS_REFERRAL_V3         0x0003
  56   56  #define DFS_REFERRAL_V4         0x0004
  57   57  
  58   58  /*
  59   59   * Valid values for ServerType field in referral entries
  60   60   */
  61   61  #define DFS_SRVTYPE_NONROOT     0x0000
  62   62  #define DFS_SRVTYPE_ROOT        0x0001
  63   63  
  64   64  /*
  65   65   * Size of the fix part for each referral entry type
  66   66   */
  67   67  #define DFS_REFV1_ENTSZ         8
  68   68  #define DFS_REFV2_ENTSZ         22
  69   69  #define DFS_REFV3_ENTSZ         34
  70   70  #define DFS_REFV4_ENTSZ         34
  71   71  
  72   72  static dfs_reftype_t smb_dfs_get_reftype(const char *);
  73   73  static void smb_dfs_encode_hdr(mbuf_chain_t *, dfs_info_t *);
  74   74  static uint32_t smb_dfs_encode_refv1(smb_request_t *, mbuf_chain_t *,
  75   75      dfs_info_t *);
  76   76  static uint32_t smb_dfs_encode_refv2(smb_request_t *, mbuf_chain_t *,
  
    | 
      ↓ open down ↓ | 
    35 lines elided | 
    
      ↑ open up ↑ | 
  
  77   77      dfs_info_t *);
  78   78  static uint32_t smb_dfs_encode_refv3x(smb_request_t *, mbuf_chain_t *,
  79   79      dfs_info_t *, uint16_t);
  80   80  static void smb_dfs_encode_targets(mbuf_chain_t *, dfs_info_t *);
  81   81  static uint32_t smb_dfs_referrals_get(smb_request_t *, char *, dfs_reftype_t,
  82   82      dfs_referral_response_t *);
  83   83  static void smb_dfs_referrals_free(dfs_referral_response_t *);
  84   84  static uint16_t smb_dfs_referrals_unclen(dfs_info_t *, uint16_t);
  85   85  
  86   86  /*
       87 + * Handle device type FILE_DEVICE_DFS
       88 + * for smb2_ioctl
       89 + */
       90 +uint32_t
       91 +smb_dfs_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
       92 +{
       93 +        uint32_t status;
       94 +
       95 +        if (!STYPE_ISIPC(sr->tid_tree->t_res_type))
       96 +                return (NT_STATUS_INVALID_DEVICE_REQUEST);
       97 +
       98 +        switch (fsctl->CtlCode) {
       99 +        case FSCTL_DFS_GET_REFERRALS:
      100 +                status = smb_dfs_get_referrals(sr, fsctl);
      101 +                break;
      102 +        case FSCTL_DFS_GET_REFERRALS_EX: /* XXX - todo */
      103 +        default:
      104 +                status = NT_STATUS_NOT_SUPPORTED;
      105 +        }
      106 +
      107 +        return (status);
      108 +}
      109 +
      110 +/*
  87  111   * Note: SMB1 callers in smb_trans2_dfs.c
  88  112   * smb_com_trans2_report_dfs_inconsistency
  89  113   * smb_com_trans2_get_dfs_referral
  90  114   */
  91  115  
  92  116  /*
  93  117   * See [MS-DFSC] for details about this command
      118 + * Handles FSCTL_DFS_GET_REFERRALS (only)
  94  119   */
  95  120  uint32_t
  96  121  smb_dfs_get_referrals(smb_request_t *sr, smb_fsctl_t *fsctl)
  97  122  {
  98  123          dfs_info_t *referrals;
  99  124          dfs_referral_response_t refrsp;
 100  125          dfs_reftype_t reftype;
 101  126          char *path;
 102  127          uint16_t maxver;
 103  128          uint32_t status;
 104  129          int rc;
 105  130  
 106  131          /*
 107  132           * The caller checks this, because the error reporting method
 108  133           * varies across SMB versions.
 109  134           */
  
    | 
      ↓ open down ↓ | 
    6 lines elided | 
    
      ↑ open up ↑ | 
  
 110  135          ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
 111  136  
 112  137          /*
 113  138           * XXX Instead of decoding the referral request and encoding
 114  139           * the response here (in-kernel) we could pass the given
 115  140           * request buffer in our door call, and let that return the
 116  141           * response buffer ready to stuff into out_mbc.  That would
 117  142           * allow all this decoding/encoding to happen at user-level.
 118  143           * (and most of this file would go away. :-)
 119  144           */
 120      -        switch (fsctl->CtlCode) {
 121      -        case FSCTL_DFS_GET_REFERRALS:
 122      -                /*
 123      -                 * Input data is (w) MaxReferralLevel, (U) path
 124      -                 */
 125      -                rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
 126      -                    sr, &maxver, &path);
 127      -                if (rc != 0)
 128      -                        return (NT_STATUS_INVALID_PARAMETER);
 129      -                break;
 130  145  
 131      -        case FSCTL_DFS_GET_REFERRALS_EX: /* XXX - todo */
 132      -        default:
 133      -                return (NT_STATUS_NOT_SUPPORTED);
 134      -        }
      146 +        /*
      147 +         * Input data is (w) MaxReferralLevel, (U) path
      148 +         */
      149 +        rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
      150 +            sr, &maxver, &path);
      151 +        if (rc != 0)
      152 +                return (NT_STATUS_INVALID_PARAMETER);
 135  153  
 136  154          reftype = smb_dfs_get_reftype((const char *)path);
 137  155          switch (reftype) {
 138  156          case DFS_REFERRAL_INVALID:
 139  157                  /* Need to check the error for this case */
 140  158                  return (NT_STATUS_INVALID_PARAMETER);
 141  159  
 142  160          case DFS_REFERRAL_DOMAIN:
 143  161          case DFS_REFERRAL_DC:
 144  162                  /* MS-DFSC: this error is returned by non-DC root */
 145  163                  return (NT_STATUS_INVALID_PARAMETER);
 146  164  
 147  165          case DFS_REFERRAL_SYSVOL:
 148  166                  /* MS-DFSC: this error is returned by non-DC root */
 149  167                  return (NT_STATUS_NO_SUCH_DEVICE);
 150  168  
 151  169          default:
 152  170                  break;
 153  171          }
 154  172  
 155  173          status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);
 156  174          if (status != NT_STATUS_SUCCESS)
 157  175                  return (status);
 158  176  
 159  177          referrals = &refrsp.rp_referrals;
 160  178          smb_dfs_encode_hdr(fsctl->out_mbc, referrals);
 161  179  
 162  180          /*
 163  181           * Server may respond with any referral version at or below
 164  182           * the maximum specified in the request.
 165  183           */
 166  184          switch (maxver) {
 167  185          case DFS_REFERRAL_V1:
 168  186                  status = smb_dfs_encode_refv1(sr, fsctl->out_mbc, referrals);
 169  187                  break;
 170  188  
 171  189          case DFS_REFERRAL_V2:
 172  190                  status = smb_dfs_encode_refv2(sr, fsctl->out_mbc, referrals);
 173  191                  break;
 174  192  
 175  193          case DFS_REFERRAL_V3:
 176  194                  status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
 177  195                      DFS_REFERRAL_V3);
 178  196                  break;
 179  197  
 180  198          case DFS_REFERRAL_V4:
 181  199          default:
 182  200                  status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
 183  201                      DFS_REFERRAL_V4);
 184  202                  break;
 185  203          }
 186  204  
 187  205          smb_dfs_referrals_free(&refrsp);
 188  206  
 189  207          return (status);
 190  208  }
 191  209  
 192  210  /*
 193  211   * [MS-DFSC]: REQ_GET_DFS_REFERRAL
 194  212   *
 195  213   * Determines the referral type based on the specified path:
 196  214   *
 197  215   * Domain referral:
 198  216   *    ""
 199  217   *
 200  218   * DC referral:
 201  219   *    \<domain>
 202  220   *
 203  221   * Sysvol referral:
 204  222   *    \<domain>\SYSVOL
 205  223   *    \<domain>\NETLOGON
 206  224   *
 207  225   * Root referral:
 208  226   *    \<domain>\<dfsname>
 209  227   *    \<server>\<dfsname>
 210  228   *
 211  229   * Link referral:
 212  230   *    \<domain>\<dfsname>\<linkpath>
 213  231   *    \<server>\<dfsname>\<linkpath>
 214  232   */
 215  233  static dfs_reftype_t
 216  234  smb_dfs_get_reftype(const char *path)
 217  235  {
 218  236          smb_unc_t unc;
 219  237          dfs_reftype_t reftype = 0;
 220  238  
 221  239          if (*path == '\0')
 222  240                  return (DFS_REFERRAL_DOMAIN);
 223  241  
 224  242          if (smb_unc_init(path, &unc) != 0)
 225  243                  return (DFS_REFERRAL_INVALID);
 226  244  
 227  245          if (unc.unc_path != NULL) {
 228  246                  reftype = DFS_REFERRAL_LINK;
 229  247          } else if (unc.unc_share != NULL) {
 230  248                  if ((smb_strcasecmp(unc.unc_share, "SYSVOL", 0) == 0) ||
 231  249                      (smb_strcasecmp(unc.unc_share, "NETLOGON", 0) == 0)) {
 232  250                          reftype = DFS_REFERRAL_SYSVOL;
 233  251                  } else {
 234  252                          reftype = DFS_REFERRAL_ROOT;
 235  253                  }
 236  254          } else if (unc.unc_server != NULL) {
 237  255                  reftype = DFS_REFERRAL_DC;
 238  256          }
 239  257  
 240  258          smb_unc_free(&unc);
 241  259          return (reftype);
 242  260  }
 243  261  
 244  262  static void
 245  263  smb_dfs_encode_hdr(mbuf_chain_t *mbc, dfs_info_t *referrals)
 246  264  {
 247  265          uint16_t path_consumed;
 248  266          uint32_t flags;
 249  267  
 250  268          path_consumed = smb_wcequiv_strlen(referrals->i_uncpath);
 251  269          flags = DFS_HDRFLG_S;
 252  270          if (referrals->i_type == DFS_OBJECT_ROOT)
 253  271                  flags |= DFS_HDRFLG_R;
 254  272  
 255  273          /* Fill rep_param_mb in SMB1 caller. */
 256  274          (void) smb_mbc_encodef(mbc, "wwl", path_consumed,
 257  275              referrals->i_ntargets, flags);
 258  276  }
 259  277  
 260  278  static uint32_t
 261  279  smb_dfs_encode_refv1(smb_request_t *sr, mbuf_chain_t *mbc,
 262  280          dfs_info_t *referrals)
 263  281  {
 264  282          _NOTE(ARGUNUSED(sr))
 265  283          uint16_t entsize, rep_bufsize;
 266  284          uint16_t server_type;
 267  285          uint16_t flags = 0;
 268  286          uint16_t r;
 269  287          char *target;
 270  288  
 271  289          rep_bufsize = MBC_MAXBYTES(mbc);
 272  290  
 273  291          server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
 274  292              DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;
 275  293  
 276  294          target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 277  295  
 278  296          for (r = 0; r < referrals->i_ntargets; r++) {
 279  297                  (void) snprintf(target, MAXPATHLEN, "\\%s\\%s",
 280  298                      referrals->i_targets[r].t_server,
 281  299                      referrals->i_targets[r].t_share);
 282  300  
 283  301                  entsize = DFS_REFV1_ENTSZ + smb_wcequiv_strlen(target) + 2;
 284  302                  if (entsize > rep_bufsize)
 285  303                          break;
 286  304  
 287  305                  (void) smb_mbc_encodef(mbc, "wwwwU",
 288  306                      DFS_REFERRAL_V1, entsize, server_type, flags, target);
 289  307                  rep_bufsize -= entsize;
 290  308          }
 291  309  
 292  310          kmem_free(target, MAXPATHLEN);
 293  311  
 294  312          /*
 295  313           * Need room for at least one entry.
 296  314           * Windows will silently drop targets that do not fit in
 297  315           * the response buffer.
 298  316           */
 299  317          if (r == 0) {
 300  318                  return (NT_STATUS_BUFFER_OVERFLOW);
 301  319          }
 302  320  
 303  321          return (NT_STATUS_SUCCESS);
 304  322  }
 305  323  
 306  324  /*
 307  325   * Prepare a response with V2 referral format.
 308  326   *
 309  327   * Here is the response packet format.
 310  328   * All the strings come after all the fixed size entry headers.
 311  329   * These headers contain offsets to the strings at the end. Note
 312  330   * that the two "dfs_path" after the last entry is shared between
 313  331   * all the entries.
 314  332   *
 315  333   * ent1-hdr
 316  334   * ent2-hdr
 317  335   * ...
 318  336   * entN-hdr
 319  337   *   dfs_path
 320  338   *   dfs_path
 321  339   *   target1
 322  340   *   target2
 323  341   *   ...
 324  342   *   targetN
 325  343   *
 326  344   * MS-DFSC mentions that strings can come after each entry header or all after
 327  345   * the last entry header. Windows responses are in the format above.
 328  346   */
 329  347  static uint32_t
 330  348  smb_dfs_encode_refv2(smb_request_t *sr, mbuf_chain_t *mbc,
 331  349          dfs_info_t *referrals)
 332  350  {
 333  351          _NOTE(ARGUNUSED(sr))
 334  352          uint16_t entsize, rep_bufsize;
 335  353          uint16_t server_type;
 336  354          uint16_t flags = 0;
 337  355          uint32_t proximity = 0;
 338  356          uint16_t path_offs, altpath_offs, netpath_offs;
 339  357          uint16_t targetsz, total_targetsz = 0;
 340  358          uint16_t dfs_pathsz;
 341  359          uint16_t r;
 342  360  
 343  361          rep_bufsize = MBC_MAXBYTES(mbc);
 344  362          dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
 345  363          entsize = DFS_REFV2_ENTSZ + dfs_pathsz + dfs_pathsz +
 346  364              smb_dfs_referrals_unclen(referrals, 0);
 347  365  
 348  366          if (entsize > rep_bufsize) {
 349  367                  /* need room for at least one referral */
 350  368                  return (NT_STATUS_BUFFER_OVERFLOW);
 351  369          }
 352  370  
 353  371          server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
 354  372              DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;
 355  373  
 356  374          rep_bufsize -= entsize;
 357  375          entsize = DFS_REFV2_ENTSZ;
 358  376  
 359  377          for (r = 0; r < referrals->i_ntargets; r++) {
 360  378                  path_offs = (referrals->i_ntargets - r) * DFS_REFV2_ENTSZ;
 361  379                  altpath_offs = path_offs + dfs_pathsz;
 362  380                  netpath_offs = altpath_offs + dfs_pathsz + total_targetsz;
 363  381                  targetsz = smb_dfs_referrals_unclen(referrals, r);
 364  382  
 365  383                  if (r != 0) {
 366  384                          entsize = DFS_REFV2_ENTSZ + targetsz;
 367  385                          if (entsize > rep_bufsize)
 368  386                                  /* silently drop targets that do not fit */
 369  387                                  break;
 370  388                          rep_bufsize -= entsize;
 371  389                  }
 372  390  
 373  391                  (void) smb_mbc_encodef(mbc, "wwwwllwww",
 374  392                      DFS_REFERRAL_V2, DFS_REFV2_ENTSZ, server_type, flags,
 375  393                      proximity, referrals->i_timeout, path_offs, altpath_offs,
 376  394                      netpath_offs);
 377  395  
 378  396                  total_targetsz += targetsz;
 379  397          }
 380  398  
 381  399          smb_dfs_encode_targets(mbc, referrals);
 382  400  
 383  401          return (NT_STATUS_SUCCESS);
  
    | 
      ↓ open down ↓ | 
    239 lines elided | 
    
      ↑ open up ↑ | 
  
 384  402  }
 385  403  
 386  404  /*
 387  405   * Prepare a response with V3/V4 referral format.
 388  406   *
 389  407   * For more details, see comments for smb_dfs_encode_refv2() or see
 390  408   * MS-DFSC specification.
 391  409   */
 392  410  static uint32_t
 393  411  smb_dfs_encode_refv3x(smb_request_t *sr, mbuf_chain_t *mbc,
 394      -        dfs_info_t *referrals,
 395      -    uint16_t ver)
      412 +        dfs_info_t *referrals, uint16_t ver)
 396  413  {
 397  414          _NOTE(ARGUNUSED(sr))
 398  415          uint16_t entsize, rep_bufsize, hdrsize;
 399  416          uint16_t server_type;
 400  417          uint16_t flags = 0;
 401  418          uint16_t path_offs, altpath_offs, netpath_offs;
 402  419          uint16_t targetsz, total_targetsz = 0;
 403  420          uint16_t dfs_pathsz;
 404  421          uint16_t r;
 405  422  
 406  423          hdrsize = (ver == DFS_REFERRAL_V3) ? DFS_REFV3_ENTSZ : DFS_REFV4_ENTSZ;
 407  424          rep_bufsize = MBC_MAXBYTES(mbc);
 408  425          dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
 409  426          entsize = hdrsize + dfs_pathsz + dfs_pathsz +
 410  427              smb_dfs_referrals_unclen(referrals, 0);
 411  428  
 412  429          if (entsize > rep_bufsize) {
 413  430                  /* need room for at least one referral */
 414  431                  return (NT_STATUS_BUFFER_OVERFLOW);
 415  432          }
 416  433  
 417  434          server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
 418  435              DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;
 419  436  
 420  437          rep_bufsize -= entsize;
 421  438  
 422  439          for (r = 0; r < referrals->i_ntargets; r++) {
 423  440                  path_offs = (referrals->i_ntargets - r) * hdrsize;
 424  441                  altpath_offs = path_offs + dfs_pathsz;
 425  442                  netpath_offs = altpath_offs + dfs_pathsz + total_targetsz;
 426  443                  targetsz = smb_dfs_referrals_unclen(referrals, r);
 427  444  
 428  445                  if (r != 0) {
 429  446                          entsize = hdrsize + targetsz;
 430  447                          if (entsize > rep_bufsize)
 431  448                                  /* silently drop targets that do not fit */
 432  449                                  break;
 433  450                          rep_bufsize -= entsize;
 434  451                          flags = 0;
 435  452                  } else if (ver == DFS_REFERRAL_V4) {
 436  453                          flags = DFS_ENTFLG_T;
 437  454                  }
 438  455  
 439  456                  (void) smb_mbc_encodef(mbc, "wwwwlwww16.",
 440  457                      ver, hdrsize, server_type, flags,
 441  458                      referrals->i_timeout, path_offs, altpath_offs,
 442  459                      netpath_offs);
 443  460  
 444  461                  total_targetsz += targetsz;
 445  462          }
 446  463  
 447  464          smb_dfs_encode_targets(mbc, referrals);
 448  465  
 449  466          return (NT_STATUS_SUCCESS);
 450  467  }
 451  468  
 452  469  /*
 453  470   * Encodes DFS path, and target strings which come after fixed header
 454  471   * entries.
 455  472   *
 456  473   * Windows 2000 and earlier set the DFSAlternatePathOffset to point to
 457  474   * an 8.3 string representation of the string pointed to by
 458  475   * DFSPathOffset if it is not a legal 8.3 string. Otherwise, if
 459  476   * DFSPathOffset points to a legal 8.3 string, DFSAlternatePathOffset
 460  477   * points to a separate copy of the same string. Windows Server 2003,
 461  478   * Windows Server 2008 and Windows Server 2008 R2 set the
 462  479   * DFSPathOffset and DFSAlternatePathOffset fields to point to separate
 463  480   * copies of the identical string.
 464  481   *
 465  482   * Following Windows 2003 and later here.
 466  483   */
 467  484  static void
 468  485  smb_dfs_encode_targets(mbuf_chain_t *mbc, dfs_info_t *referrals)
 469  486  {
 470  487          char *target;
 471  488          int r;
 472  489  
 473  490          (void) smb_mbc_encodef(mbc, "UU", referrals->i_uncpath,
 474  491              referrals->i_uncpath);
 475  492  
 476  493          target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
 477  494          for (r = 0; r < referrals->i_ntargets; r++) {
 478  495                  (void) snprintf(target, MAXPATHLEN, "\\%s\\%s",
 479  496                      referrals->i_targets[r].t_server,
 480  497                      referrals->i_targets[r].t_share);
 481  498                  (void) smb_mbc_encodef(mbc, "U", target);
 482  499          }
 483  500          kmem_free(target, MAXPATHLEN);
 484  501  }
 485  502  
 486  503  /*
 487  504   * Get referral information for the specified path from user space
 488  505   * using a door call.
 489  506   */
 490  507  static uint32_t
 491  508  smb_dfs_referrals_get(smb_request_t *sr, char *dfs_path, dfs_reftype_t reftype,
 492  509      dfs_referral_response_t *refrsp)
 493  510  {
 494  511          dfs_referral_query_t    req;
 495  512          int                     rc;
 496  513  
  
    | 
      ↓ open down ↓ | 
    91 lines elided | 
    
      ↑ open up ↑ | 
  
 497  514          req.rq_type = reftype;
 498  515          req.rq_path = dfs_path;
 499  516  
 500  517          bzero(refrsp, sizeof (dfs_referral_response_t));
 501  518          refrsp->rp_status = NT_STATUS_NOT_FOUND;
 502  519  
 503  520          rc = smb_kdoor_upcall(sr->sr_server, SMB_DR_DFS_GET_REFERRALS,
 504  521              &req, dfs_referral_query_xdr, refrsp, dfs_referral_response_xdr);
 505  522  
 506  523          if (rc != 0 || refrsp->rp_status != ERROR_SUCCESS) {
 507      -                return (NT_STATUS_NO_SUCH_DEVICE);
      524 +                return (NT_STATUS_FS_DRIVER_REQUIRED);
 508  525          }
 509  526  
 510  527          (void) strsubst(refrsp->rp_referrals.i_uncpath, '/', '\\');
 511  528          return (NT_STATUS_SUCCESS);
 512  529  }
 513  530  
 514  531  static void
 515  532  smb_dfs_referrals_free(dfs_referral_response_t *refrsp)
 516  533  {
 517  534          xdr_free(dfs_referral_response_xdr, (char *)refrsp);
 518  535  }
 519  536  
 520  537  /*
 521  538   * Returns the Unicode string length for the target UNC of
 522  539   * the specified entry by 'refno'
 523  540   *
 524  541   * Note that the UNC path should be encoded with ONE leading
 525  542   * slash not two as is common to user-visible UNC paths.
 526  543   */
 527  544  static uint16_t
 528  545  smb_dfs_referrals_unclen(dfs_info_t *referrals, uint16_t refno)
 529  546  {
 530  547          uint16_t len;
 531  548  
 532  549          if (refno >= referrals->i_ntargets)
 533  550                  return (0);
 534  551  
 535  552          /* Encoded target UNC \server\share */
 536  553          len = smb_wcequiv_strlen(referrals->i_targets[refno].t_server) +
 537  554              smb_wcequiv_strlen(referrals->i_targets[refno].t_share) +
 538  555              smb_wcequiv_strlen("\\\\") + 2; /* two '\' + NULL */
 539  556  
 540  557          return (len);
 541  558  }
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX