1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2020 Nexenta by DDN, Inc. All rights reserved.
  24  */
  25 
  26 /*
  27  * SMB server interface to idmap
  28  * (smb_idmap_get..., smb_idmap_batch_...)
  29  *
  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  *
  35  * There are enough differences (relative to the code size)
  36  * that it's more trouble than it's worth to merge them.
  37  *
  38  * This one differs from the others in that it:
  39  *      calls kernel (kidmap_...) interfaces
  40  *      returned domain SIDs are shared, not strdup'ed
  41  */
  42 
  43 /*
  44  * SMB ID mapping
  45  *
  46  * Solaris ID mapping service (aka Winchester) works with domain SIDs
  47  * and RIDs where domain SIDs are in string format. CIFS service works
  48  * with binary SIDs understandable by CIFS clients. A layer of SMB ID
  49  * mapping functions are implemeted to hide the SID conversion details
  50  * and also hide the handling of array of batch mapping requests.
  51  */
  52 
  53 #include <sys/param.h>
  54 #include <sys/types.h>
  55 #include <sys/tzfile.h>
  56 #include <sys/atomic.h>
  57 #include <sys/kidmap.h>
  58 #include <sys/time.h>
  59 #include <sys/spl.h>
  60 #include <sys/random.h>
  61 #include <smbsrv/smb_kproto.h>
  62 #include <smbsrv/smb_fsops.h>
  63 #include <smbsrv/smbinfo.h>
  64 #include <smbsrv/smb_xdr.h>
  65 #include <smbsrv/smb_vops.h>
  66 #include <smbsrv/smb_idmap.h>
  67 
  68 #include <sys/sid.h>
  69 #include <sys/priv_names.h>
  70 
  71 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
  72 
  73 /*
  74  * smb_idmap_getsid
  75  *
  76  * Maps the given Solaris ID to a Windows SID using the
  77  * simple mapping API.
  78  */
  79 idmap_stat
  80 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
  81 {
  82         smb_idmap_t sim;
  83 
  84         switch (idtype) {
  85         case SMB_IDMAP_USER:
  86                 sim.sim_stat = kidmap_getsidbyuid(curzone, id,
  87                     (const char **)&sim.sim_domsid, &sim.sim_rid);
  88                 break;
  89 
  90         case SMB_IDMAP_GROUP:
  91                 sim.sim_stat = kidmap_getsidbygid(curzone, id,
  92                     (const char **)&sim.sim_domsid, &sim.sim_rid);
  93                 break;
  94 
  95         case SMB_IDMAP_EVERYONE:
  96                 /* Everyone S-1-1-0 */
  97                 sim.sim_domsid = "S-1-1";
  98                 sim.sim_rid = 0;
  99                 sim.sim_stat = IDMAP_SUCCESS;
 100                 break;
 101 
 102         default:
 103                 ASSERT(0);
 104                 return (IDMAP_ERR_ARG);
 105         }
 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 
 115         if (sim.sim_stat != IDMAP_SUCCESS)
 116                 return (sim.sim_stat);
 117 
 118         if (sim.sim_domsid == NULL)
 119                 return (IDMAP_ERR_NOMAPPING);
 120 
 121         sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
 122         if (sim.sim_sid == NULL)
 123                 return (IDMAP_ERR_INTERNAL);
 124 
 125         *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
 126         smb_sid_free(sim.sim_sid);
 127         if (*sid == NULL)
 128                 sim.sim_stat = IDMAP_ERR_INTERNAL;
 129 
 130         return (sim.sim_stat);
 131 }
 132 
 133 /*
 134  * smb_idmap_getid
 135  *
 136  * Maps the given Windows SID to a Unix ID using the
 137  * simple mapping API.
 138  */
 139 idmap_stat
 140 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
 141 {
 142         smb_idmap_t sim;
 143         char sidstr[SMB_SID_STRSZ];
 144 
 145         smb_sid_tostr(sid, sidstr);
 146         if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
 147                 return (IDMAP_ERR_SID);
 148         sim.sim_domsid = sidstr;
 149         sim.sim_id = id;
 150 
 151         switch (*idtype) {
 152         case SMB_IDMAP_USER:
 153                 sim.sim_stat = kidmap_getuidbysid(curzone, sim.sim_domsid,
 154                     sim.sim_rid, sim.sim_id);
 155                 break;
 156 
 157         case SMB_IDMAP_GROUP:
 158                 sim.sim_stat = kidmap_getgidbysid(curzone, sim.sim_domsid,
 159                     sim.sim_rid, sim.sim_id);
 160                 break;
 161 
 162         case SMB_IDMAP_UNKNOWN:
 163                 sim.sim_stat = kidmap_getpidbysid(curzone, sim.sim_domsid,
 164                     sim.sim_rid, sim.sim_id, &sim.sim_idtype);
 165                 break;
 166 
 167         default:
 168                 ASSERT(0);
 169                 return (IDMAP_ERR_ARG);
 170         }
 171 
 172         *idtype = sim.sim_idtype;
 173 
 174         return (sim.sim_stat);
 175 }
 176 
 177 /*
 178  * smb_idmap_batch_create
 179  *
 180  * Creates and initializes the context for batch ID mapping.
 181  */
 182 idmap_stat
 183 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
 184 {
 185         ASSERT(sib != NULL);
 186 
 187         bzero(sib, sizeof (smb_idmap_batch_t));
 188 
 189         sib->sib_idmaph = kidmap_get_create(curzone);
 190 
 191         sib->sib_flags = flags;
 192         sib->sib_nmap = nmap;
 193         sib->sib_size = nmap * sizeof (smb_idmap_t);
 194         sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
 195 
 196         return (IDMAP_SUCCESS);
 197 }
 198 
 199 /*
 200  * smb_idmap_batch_destroy
 201  *
 202  * Frees the batch ID mapping context.
 203  * If ID mapping is Solaris -> Windows it frees memories
 204  * allocated for binary SIDs.
 205  */
 206 void
 207 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
 208 {
 209         char *domsid;
 210         int i;
 211 
 212         ASSERT(sib != NULL);
 213         ASSERT(sib->sib_maps != NULL);
 214 
 215         if (sib->sib_idmaph) {
 216                 kidmap_get_destroy(sib->sib_idmaph);
 217                 sib->sib_idmaph = NULL;
 218         }
 219 
 220         if (sib->sib_flags & SMB_IDMAP_ID2SID) {
 221                 /*
 222                  * SIDs are allocated only when mapping
 223                  * UID/GID to SIDs
 224                  */
 225                 for (i = 0; i < sib->sib_nmap; i++)
 226                         smb_sid_free(sib->sib_maps[i].sim_sid);
 227         } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
 228                 /*
 229                  * SID prefixes are allocated only when mapping
 230                  * SIDs to UID/GID
 231                  */
 232                 for (i = 0; i < sib->sib_nmap; i++) {
 233                         domsid = sib->sib_maps[i].sim_domsid;
 234                         if (domsid)
 235                                 smb_mem_free(domsid);
 236                 }
 237         }
 238 
 239         if (sib->sib_size && sib->sib_maps) {
 240                 kmem_free(sib->sib_maps, sib->sib_size);
 241                 sib->sib_maps = NULL;
 242         }
 243 }
 244 
 245 /*
 246  * smb_idmap_batch_getid
 247  *
 248  * Queue a request to map the given SID to a UID or GID.
 249  *
 250  * sim->sim_id should point to variable that's supposed to
 251  * hold the returned UID/GID. This needs to be setup by caller
 252  * of this function.
 253  *
 254  * If requested ID type is known, it's passed as 'idtype',
 255  * if it's unknown it'll be returned in sim->sim_idtype.
 256  */
 257 idmap_stat
 258 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
 259     smb_sid_t *sid, int idtype)
 260 {
 261         char strsid[SMB_SID_STRSZ];
 262         idmap_stat idm_stat;
 263 
 264         ASSERT(idmaph != NULL);
 265         ASSERT(sim != NULL);
 266         ASSERT(sid != NULL);
 267 
 268         smb_sid_tostr(sid, strsid);
 269         if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
 270                 return (IDMAP_ERR_SID);
 271         /* Note: Free sim_domsid in smb_idmap_batch_destroy */
 272         sim->sim_domsid = smb_mem_strdup(strsid);
 273         sim->sim_idtype = idtype;
 274 
 275         switch (idtype) {
 276         case SMB_IDMAP_USER:
 277                 idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
 278                     sim->sim_rid, sim->sim_id, &sim->sim_stat);
 279                 break;
 280 
 281         case SMB_IDMAP_GROUP:
 282                 idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
 283                     sim->sim_rid, sim->sim_id, &sim->sim_stat);
 284                 break;
 285 
 286         case SMB_IDMAP_UNKNOWN:
 287                 idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
 288                     sim->sim_rid, sim->sim_id, &sim->sim_idtype,
 289                     &sim->sim_stat);
 290                 break;
 291 
 292         default:
 293                 ASSERT(0);
 294                 return (IDMAP_ERR_ARG);
 295         }
 296 
 297         return (idm_stat);
 298 }
 299 
 300 /*
 301  * smb_idmap_batch_getsid
 302  *
 303  * Queue a request to map the given UID/GID to a SID.
 304  *
 305  * sim->sim_domsid and sim->sim_rid will contain the mapping
 306  * result upon successful process of the batched request.
 307  * Stash the type for error reporting (caller saves the ID).
 308  */
 309 idmap_stat
 310 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
 311     uid_t id, int idtype)
 312 {
 313         idmap_stat idm_stat;
 314 
 315         sim->sim_idtype = idtype;
 316         switch (idtype) {
 317         case SMB_IDMAP_USER:
 318                 idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
 319                     (const char **)&sim->sim_domsid, &sim->sim_rid,
 320                     &sim->sim_stat);
 321                 break;
 322 
 323         case SMB_IDMAP_GROUP:
 324                 idm_stat = kidmap_batch_getsidbygid(idmaph, id,
 325                     (const char **)&sim->sim_domsid, &sim->sim_rid,
 326                     &sim->sim_stat);
 327                 break;
 328 
 329         case SMB_IDMAP_OWNERAT:
 330                 /* Current Owner S-1-5-32-766 */
 331                 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
 332                 sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
 333                 sim->sim_stat = IDMAP_SUCCESS;
 334                 idm_stat = IDMAP_SUCCESS;
 335                 break;
 336 
 337         case SMB_IDMAP_GROUPAT:
 338                 /* Current Group S-1-5-32-767 */
 339                 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
 340                 sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
 341                 sim->sim_stat = IDMAP_SUCCESS;
 342                 idm_stat = IDMAP_SUCCESS;
 343                 break;
 344 
 345         case SMB_IDMAP_EVERYONE:
 346                 /* Everyone S-1-1-0 */
 347                 sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
 348                 sim->sim_rid = 0;
 349                 sim->sim_stat = IDMAP_SUCCESS;
 350                 idm_stat = IDMAP_SUCCESS;
 351                 break;
 352 
 353         default:
 354                 ASSERT(0);
 355                 return (IDMAP_ERR_ARG);
 356         }
 357 
 358         return (idm_stat);
 359 }
 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 
 383 /*
 384  * smb_idmap_batch_getmappings
 385  *
 386  * trigger ID mapping service to get the mappings for queued
 387  * requests.
 388  *
 389  * Checks the result of all the queued requests.
 390  * If this is a Solaris -> Windows mapping it generates
 391  * binary SIDs from returned (domsid, rid) pairs.
 392  */
 393 idmap_stat
 394 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
 395 {
 396         idmap_stat idm_stat = IDMAP_SUCCESS;
 397         smb_idmap_t *sim;
 398         int i;
 399 
 400         idm_stat = kidmap_get_mappings(sib->sib_idmaph);
 401         if (idm_stat != IDMAP_SUCCESS)
 402                 return (idm_stat);
 403 
 404         /*
 405          * Check the status for all the queued requests
 406          */
 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                 }
 414         }
 415 
 416         if (smb_idmap_batch_binsid(sib) != 0)
 417                 idm_stat = IDMAP_ERR_OTHER;
 418 
 419         return (idm_stat);
 420 }
 421 
 422 /*
 423  * smb_idmap_batch_binsid
 424  *
 425  * Convert sidrids to binary sids
 426  *
 427  * Returns 0 if successful and non-zero upon failure.
 428  */
 429 static int
 430 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
 431 {
 432         smb_sid_t *sid;
 433         smb_idmap_t *sim;
 434         int i;
 435 
 436         if (sib->sib_flags & SMB_IDMAP_SID2ID)
 437                 /* This operation is not required */
 438                 return (0);
 439 
 440         sim = sib->sib_maps;
 441         for (i = 0; i < sib->sib_nmap; sim++, i++) {
 442                 ASSERT(sim->sim_domsid != NULL);
 443                 if (sim->sim_domsid == NULL)
 444                         return (1);
 445 
 446                 if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
 447                         return (1);
 448 
 449                 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
 450                 smb_sid_free(sid);
 451         }
 452 
 453         return (0);
 454 }