Print this page
    
NEX-17589 Get "too high" smbd error when copy big file to cifs share
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-17795 SMB logon should tolerate idmap problems
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-9190 Files with owners not in /etc/passwd and not having inherited ACL's are prevented from seeing ownership/permissions via SMB
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-4083 Upstream changes from illumos 5917 and 5995
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
SMB-50 User-mode SMB server
 Includes work by these authors:
 Thomas Keiser <thomas.keiser@nexenta.com>
 Albert Lee <trisk@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/smbsrv/smb_idmap.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_idmap.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   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  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.
  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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * SMB server interface to idmap
  28   28   * (smb_idmap_get..., smb_idmap_batch_...)
  29   29   *
  30      - * There are three implementations of this interface:
  31      - *      uts/common/fs/smbsrv/smb_idmap.c (smbsrv kmod)
  32      - *      lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c (libfksmbsrv)
  33      - *      lib/smbsrv/libsmb/common/smb_idmap.c (libsmb)
       30 + * There are three implementations of this interface.
       31 + * This is the kernel version of these routines.  See also:
       32 + * $SRC/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c
       33 + * $SRC/lib/smbsrv/libsmb/common/smb_idmap.c
  34   34   *
  35   35   * There are enough differences (relative to the code size)
  36   36   * that it's more trouble than it's worth to merge them.
  37   37   *
  38   38   * This one differs from the others in that it:
  39   39   *      calls kernel (kidmap_...) interfaces
  40      - *      domain SIDs are shared, not strdup'ed
       40 + *      returned domain SIDs are shared, not strdup'ed
  41   41   */
  42   42  
  43   43  /*
  44   44   * SMB ID mapping
  45   45   *
  46   46   * Solaris ID mapping service (aka Winchester) works with domain SIDs
  47   47   * and RIDs where domain SIDs are in string format. CIFS service works
  48   48   * with binary SIDs understandable by CIFS clients. A layer of SMB ID
  49   49   * mapping functions are implemeted to hide the SID conversion details
  50   50   * and also hide the handling of array of batch mapping requests.
  51   51   */
  52   52  
  53   53  #include <sys/param.h>
  54   54  #include <sys/types.h>
  55   55  #include <sys/tzfile.h>
  56   56  #include <sys/atomic.h>
  57   57  #include <sys/kidmap.h>
  58   58  #include <sys/time.h>
  59   59  #include <sys/spl.h>
  60   60  #include <sys/random.h>
  61   61  #include <smbsrv/smb_kproto.h>
  62   62  #include <smbsrv/smb_fsops.h>
  63   63  #include <smbsrv/smbinfo.h>
  64   64  #include <smbsrv/smb_xdr.h>
  65   65  #include <smbsrv/smb_vops.h>
  66   66  #include <smbsrv/smb_idmap.h>
  67   67  
  68   68  #include <sys/sid.h>
  69   69  #include <sys/priv_names.h>
  70   70  
  71   71  static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
  72   72  
  73   73  /*
  74   74   * smb_idmap_getsid
  75   75   *
  76   76   * Maps the given Solaris ID to a Windows SID using the
  77   77   * simple mapping API.
  78   78   */
  79   79  idmap_stat
  80   80  smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
  81   81  {
  82   82          smb_idmap_t sim;
  83   83  
  84   84          switch (idtype) {
  85   85          case SMB_IDMAP_USER:
  86   86                  sim.sim_stat = kidmap_getsidbyuid(global_zone, id,
  87   87                      (const char **)&sim.sim_domsid, &sim.sim_rid);
  88   88                  break;
  89   89  
  90   90          case SMB_IDMAP_GROUP:
  91   91                  sim.sim_stat = kidmap_getsidbygid(global_zone, id,
  92   92                      (const char **)&sim.sim_domsid, &sim.sim_rid);
  93   93                  break;
  94   94  
  95   95          case SMB_IDMAP_EVERYONE:
  96   96                  /* Everyone S-1-1-0 */
  
    | 
      ↓ open down ↓ | 
    46 lines elided | 
    
      ↑ open up ↑ | 
  
  97   97                  sim.sim_domsid = "S-1-1";
  98   98                  sim.sim_rid = 0;
  99   99                  sim.sim_stat = IDMAP_SUCCESS;
 100  100                  break;
 101  101  
 102  102          default:
 103  103                  ASSERT(0);
 104  104                  return (IDMAP_ERR_ARG);
 105  105          }
 106  106  
      107 +        /*
      108 +         * IDMAP_ERR_NOTFOUND is an advisory error
      109 +         * and idmap will generate a local sid.
      110 +         */
      111 +        if (sim.sim_stat == IDMAP_ERR_NOTFOUND &&
      112 +            sim.sim_domsid != NULL)
      113 +                sim.sim_stat = IDMAP_SUCCESS;
      114 +
 107  115          if (sim.sim_stat != IDMAP_SUCCESS)
 108  116                  return (sim.sim_stat);
 109  117  
 110  118          if (sim.sim_domsid == NULL)
 111  119                  return (IDMAP_ERR_NOMAPPING);
 112  120  
 113  121          sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
 114  122          if (sim.sim_sid == NULL)
 115  123                  return (IDMAP_ERR_INTERNAL);
 116  124  
 117  125          *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
 118  126          smb_sid_free(sim.sim_sid);
 119  127          if (*sid == NULL)
 120  128                  sim.sim_stat = IDMAP_ERR_INTERNAL;
 121  129  
 122  130          return (sim.sim_stat);
 123  131  }
 124  132  
 125  133  /*
 126  134   * smb_idmap_getid
 127  135   *
 128  136   * Maps the given Windows SID to a Unix ID using the
 129  137   * simple mapping API.
 130  138   */
 131  139  idmap_stat
 132  140  smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
 133  141  {
 134  142          smb_idmap_t sim;
 135  143          char sidstr[SMB_SID_STRSZ];
 136  144  
 137  145          smb_sid_tostr(sid, sidstr);
 138  146          if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
 139  147                  return (IDMAP_ERR_SID);
 140  148          sim.sim_domsid = sidstr;
 141  149          sim.sim_id = id;
 142  150  
 143  151          switch (*idtype) {
 144  152          case SMB_IDMAP_USER:
 145  153                  sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
 146  154                      sim.sim_rid, sim.sim_id);
 147  155                  break;
 148  156  
 149  157          case SMB_IDMAP_GROUP:
 150  158                  sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
 151  159                      sim.sim_rid, sim.sim_id);
 152  160                  break;
 153  161  
 154  162          case SMB_IDMAP_UNKNOWN:
 155  163                  sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
 156  164                      sim.sim_rid, sim.sim_id, &sim.sim_idtype);
 157  165                  break;
 158  166  
 159  167          default:
 160  168                  ASSERT(0);
 161  169                  return (IDMAP_ERR_ARG);
 162  170          }
 163  171  
 164  172          *idtype = sim.sim_idtype;
 165  173  
 166  174          return (sim.sim_stat);
  
    | 
      ↓ open down ↓ | 
    50 lines elided | 
    
      ↑ open up ↑ | 
  
 167  175  }
 168  176  
 169  177  /*
 170  178   * smb_idmap_batch_create
 171  179   *
 172  180   * Creates and initializes the context for batch ID mapping.
 173  181   */
 174  182  idmap_stat
 175  183  smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
 176  184  {
 177      -        ASSERT(sib);
      185 +        ASSERT(sib != NULL);
 178  186  
 179  187          bzero(sib, sizeof (smb_idmap_batch_t));
 180  188  
 181  189          sib->sib_idmaph = kidmap_get_create(global_zone);
 182  190  
 183  191          sib->sib_flags = flags;
 184  192          sib->sib_nmap = nmap;
 185  193          sib->sib_size = nmap * sizeof (smb_idmap_t);
 186  194          sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
 187  195  
 188  196          return (IDMAP_SUCCESS);
 189  197  }
 190  198  
 191  199  /*
 192  200   * smb_idmap_batch_destroy
 193  201   *
  
    | 
      ↓ open down ↓ | 
    6 lines elided | 
    
      ↑ open up ↑ | 
  
 194  202   * Frees the batch ID mapping context.
 195  203   * If ID mapping is Solaris -> Windows it frees memories
 196  204   * allocated for binary SIDs.
 197  205   */
 198  206  void
 199  207  smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
 200  208  {
 201  209          char *domsid;
 202  210          int i;
 203  211  
 204      -        ASSERT(sib);
 205      -        ASSERT(sib->sib_maps);
      212 +        ASSERT(sib != NULL);
      213 +        ASSERT(sib->sib_maps != NULL);
 206  214  
 207      -        if (sib->sib_idmaph)
      215 +        if (sib->sib_idmaph) {
 208  216                  kidmap_get_destroy(sib->sib_idmaph);
      217 +                sib->sib_idmaph = NULL;
      218 +        }
 209  219  
 210  220          if (sib->sib_flags & SMB_IDMAP_ID2SID) {
 211  221                  /*
 212  222                   * SIDs are allocated only when mapping
 213  223                   * UID/GID to SIDs
 214  224                   */
 215  225                  for (i = 0; i < sib->sib_nmap; i++)
 216  226                          smb_sid_free(sib->sib_maps[i].sim_sid);
 217  227          } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
 218  228                  /*
 219  229                   * SID prefixes are allocated only when mapping
 220  230                   * SIDs to UID/GID
 221  231                   */
 222  232                  for (i = 0; i < sib->sib_nmap; i++) {
 223  233                          domsid = sib->sib_maps[i].sim_domsid;
 224  234                          if (domsid)
 225  235                                  smb_mem_free(domsid);
 226  236                  }
 227  237          }
 228  238  
 229      -        if (sib->sib_size && sib->sib_maps)
      239 +        if (sib->sib_size && sib->sib_maps) {
 230  240                  kmem_free(sib->sib_maps, sib->sib_size);
      241 +                sib->sib_maps = NULL;
      242 +        }
 231  243  }
 232  244  
 233  245  /*
 234  246   * smb_idmap_batch_getid
 235  247   *
 236  248   * Queue a request to map the given SID to a UID or GID.
 237  249   *
 238  250   * sim->sim_id should point to variable that's supposed to
 239  251   * hold the returned UID/GID. This needs to be setup by caller
 240  252   * of this function.
 241  253   *
  
    | 
      ↓ open down ↓ | 
    1 lines elided | 
    
      ↑ open up ↑ | 
  
 242  254   * If requested ID type is known, it's passed as 'idtype',
 243  255   * if it's unknown it'll be returned in sim->sim_idtype.
 244  256   */
 245  257  idmap_stat
 246  258  smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
 247  259      smb_sid_t *sid, int idtype)
 248  260  {
 249  261          char strsid[SMB_SID_STRSZ];
 250  262          idmap_stat idm_stat;
 251  263  
 252      -        ASSERT(idmaph);
 253      -        ASSERT(sim);
 254      -        ASSERT(sid);
      264 +        ASSERT(idmaph != NULL);
      265 +        ASSERT(sim != NULL);
      266 +        ASSERT(sid != NULL);
 255  267  
 256  268          smb_sid_tostr(sid, strsid);
 257  269          if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
 258  270                  return (IDMAP_ERR_SID);
      271 +        /* Note: Free sim_domsid in smb_idmap_batch_destroy */
 259  272          sim->sim_domsid = smb_mem_strdup(strsid);
      273 +        sim->sim_idtype = idtype;
 260  274  
 261  275          switch (idtype) {
 262  276          case SMB_IDMAP_USER:
 263  277                  idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
 264  278                      sim->sim_rid, sim->sim_id, &sim->sim_stat);
 265  279                  break;
 266  280  
 267  281          case SMB_IDMAP_GROUP:
 268  282                  idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
 269  283                      sim->sim_rid, sim->sim_id, &sim->sim_stat);
 270  284                  break;
 271  285  
 272  286          case SMB_IDMAP_UNKNOWN:
 273  287                  idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
 274  288                      sim->sim_rid, sim->sim_id, &sim->sim_idtype,
 275  289                      &sim->sim_stat);
 276  290                  break;
 277  291  
 278  292          default:
 279  293                  ASSERT(0);
 280  294                  return (IDMAP_ERR_ARG);
 281  295          }
 282  296  
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
 283  297          return (idm_stat);
 284  298  }
 285  299  
 286  300  /*
 287  301   * smb_idmap_batch_getsid
 288  302   *
 289  303   * Queue a request to map the given UID/GID to a SID.
 290  304   *
 291  305   * sim->sim_domsid and sim->sim_rid will contain the mapping
 292  306   * result upon successful process of the batched request.
      307 + * Stash the type for error reporting (caller saves the ID).
 293  308   */
 294  309  idmap_stat
 295  310  smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
 296  311      uid_t id, int idtype)
 297  312  {
 298  313          idmap_stat idm_stat;
 299  314  
      315 +        sim->sim_idtype = idtype;
 300  316          switch (idtype) {
 301  317          case SMB_IDMAP_USER:
 302  318                  idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
 303  319                      (const char **)&sim->sim_domsid, &sim->sim_rid,
 304  320                      &sim->sim_stat);
 305  321                  break;
 306  322  
 307  323          case SMB_IDMAP_GROUP:
 308  324                  idm_stat = kidmap_batch_getsidbygid(idmaph, id,
 309  325                      (const char **)&sim->sim_domsid, &sim->sim_rid,
 310  326                      &sim->sim_stat);
 311  327                  break;
 312  328  
 313  329          case SMB_IDMAP_OWNERAT:
 314  330                  /* Current Owner S-1-5-32-766 */
 315  331                  sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
 316  332                  sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
 317  333                  sim->sim_stat = IDMAP_SUCCESS;
 318  334                  idm_stat = IDMAP_SUCCESS;
 319  335                  break;
 320  336  
 321  337          case SMB_IDMAP_GROUPAT:
 322  338                  /* Current Group S-1-5-32-767 */
 323  339                  sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
 324  340                  sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
 325  341                  sim->sim_stat = IDMAP_SUCCESS;
 326  342                  idm_stat = IDMAP_SUCCESS;
 327  343                  break;
 328  344  
 329  345          case SMB_IDMAP_EVERYONE:
 330  346                  /* Everyone S-1-1-0 */
 331  347                  sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
 332  348                  sim->sim_rid = 0;
 333  349                  sim->sim_stat = IDMAP_SUCCESS;
 334  350                  idm_stat = IDMAP_SUCCESS;
  
    | 
      ↓ open down ↓ | 
    25 lines elided | 
    
      ↑ open up ↑ | 
  
 335  351                  break;
 336  352  
 337  353          default:
 338  354                  ASSERT(0);
 339  355                  return (IDMAP_ERR_ARG);
 340  356          }
 341  357  
 342  358          return (idm_stat);
 343  359  }
 344  360  
      361 +static void
      362 +smb_idmap_bgm_report(smb_idmap_batch_t *sib, smb_idmap_t *sim)
      363 +{
      364 +
      365 +        if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
      366 +                /*
      367 +                 * Note: The ID and type we asked idmap to map
      368 +                 * were saved in *sim_id and sim_idtype.
      369 +                 */
      370 +                uint_t id = (sim->sim_id == NULL) ?
      371 +                    0 : (uint_t)*sim->sim_id;
      372 +                cmn_err(CE_WARN, "Can't get SID for "
      373 +                    "ID=%u type=%d, status=%d",
      374 +                    id, sim->sim_idtype, sim->sim_stat);
      375 +        }
      376 +
      377 +        if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
      378 +                cmn_err(CE_WARN, "Can't get ID for SID %s-%u, status=%d",
      379 +                    sim->sim_domsid, sim->sim_rid, sim->sim_stat);
      380 +        }
      381 +}
      382 +
 345  383  /*
 346  384   * smb_idmap_batch_getmappings
 347  385   *
 348  386   * trigger ID mapping service to get the mappings for queued
 349  387   * requests.
 350  388   *
 351  389   * Checks the result of all the queued requests.
 352  390   * If this is a Solaris -> Windows mapping it generates
 353  391   * binary SIDs from returned (domsid, rid) pairs.
 354  392   */
 355  393  idmap_stat
 356  394  smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
 357  395  {
 358  396          idmap_stat idm_stat = IDMAP_SUCCESS;
      397 +        smb_idmap_t *sim;
 359  398          int i;
 360  399  
 361  400          idm_stat = kidmap_get_mappings(sib->sib_idmaph);
 362  401          if (idm_stat != IDMAP_SUCCESS)
 363  402                  return (idm_stat);
 364  403  
 365  404          /*
 366  405           * Check the status for all the queued requests
 367  406           */
 368      -        for (i = 0; i < sib->sib_nmap; i++) {
 369      -                if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS)
 370      -                        return (sib->sib_maps[i].sim_stat);
      407 +        for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
      408 +                if (sim->sim_stat != IDMAP_SUCCESS) {
      409 +                        smb_idmap_bgm_report(sib, sim);
      410 +                        if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) {
      411 +                                return (sim->sim_stat);
      412 +                        }
      413 +                }
 371  414          }
 372  415  
 373  416          if (smb_idmap_batch_binsid(sib) != 0)
 374  417                  idm_stat = IDMAP_ERR_OTHER;
 375  418  
 376  419          return (idm_stat);
 377  420  }
 378  421  
 379  422  /*
 380  423   * smb_idmap_batch_binsid
 381  424   *
 382  425   * Convert sidrids to binary sids
 383  426   *
 384  427   * Returns 0 if successful and non-zero upon failure.
 385  428   */
 386  429  static int
 387  430  smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
 388  431  {
  
    | 
      ↓ open down ↓ | 
    8 lines elided | 
    
      ↑ open up ↑ | 
  
 389  432          smb_sid_t *sid;
 390  433          smb_idmap_t *sim;
 391  434          int i;
 392  435  
 393  436          if (sib->sib_flags & SMB_IDMAP_SID2ID)
 394  437                  /* This operation is not required */
 395  438                  return (0);
 396  439  
 397  440          sim = sib->sib_maps;
 398  441          for (i = 0; i < sib->sib_nmap; sim++, i++) {
 399      -                ASSERT(sim->sim_domsid);
      442 +                ASSERT(sim->sim_domsid != NULL);
 400  443                  if (sim->sim_domsid == NULL)
 401  444                          return (1);
 402  445  
 403  446                  if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
 404  447                          return (1);
 405  448  
 406  449                  sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
 407  450                  smb_sid_free(sid);
 408  451          }
 409  452  
 410  453          return (0);
 411  454  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX