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 2013 Nexenta Systems, 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  *      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)
  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  *      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(global_zone, id,
  87                     (const char **)&sim.sim_domsid, &sim.sim_rid);
  88                 break;
  89 
  90         case SMB_IDMAP_GROUP:
  91                 sim.sim_stat = kidmap_getsidbygid(global_zone, 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         if (sim.sim_stat != IDMAP_SUCCESS)
 108                 return (sim.sim_stat);
 109 
 110         if (sim.sim_domsid == NULL)
 111                 return (IDMAP_ERR_NOMAPPING);
 112 
 113         sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
 114         if (sim.sim_sid == NULL)
 115                 return (IDMAP_ERR_INTERNAL);
 116 
 117         *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
 118         smb_sid_free(sim.sim_sid);
 119         if (*sid == NULL)
 120                 sim.sim_stat = IDMAP_ERR_INTERNAL;
 121 
 122         return (sim.sim_stat);
 123 }
 124 
 125 /*
 126  * smb_idmap_getid
 127  *
 128  * Maps the given Windows SID to a Unix ID using the
 129  * simple mapping API.
 130  */
 131 idmap_stat
 132 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
 133 {
 134         smb_idmap_t sim;
 135         char sidstr[SMB_SID_STRSZ];
 136 
 137         smb_sid_tostr(sid, sidstr);
 138         if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
 139                 return (IDMAP_ERR_SID);
 140         sim.sim_domsid = sidstr;
 141         sim.sim_id = id;
 142 
 143         switch (*idtype) {
 144         case SMB_IDMAP_USER:
 145                 sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
 146                     sim.sim_rid, sim.sim_id);
 147                 break;
 148 
 149         case SMB_IDMAP_GROUP:
 150                 sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
 151                     sim.sim_rid, sim.sim_id);
 152                 break;
 153 
 154         case SMB_IDMAP_UNKNOWN:
 155                 sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
 156                     sim.sim_rid, sim.sim_id, &sim.sim_idtype);
 157                 break;
 158 
 159         default:
 160                 ASSERT(0);
 161                 return (IDMAP_ERR_ARG);
 162         }
 163 
 164         *idtype = sim.sim_idtype;
 165 
 166         return (sim.sim_stat);
 167 }
 168 
 169 /*
 170  * smb_idmap_batch_create
 171  *
 172  * Creates and initializes the context for batch ID mapping.
 173  */
 174 idmap_stat
 175 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
 176 {
 177         ASSERT(sib);
 178 
 179         bzero(sib, sizeof (smb_idmap_batch_t));
 180 
 181         sib->sib_idmaph = kidmap_get_create(global_zone);
 182 
 183         sib->sib_flags = flags;
 184         sib->sib_nmap = nmap;
 185         sib->sib_size = nmap * sizeof (smb_idmap_t);
 186         sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
 187 
 188         return (IDMAP_SUCCESS);
 189 }
 190 
 191 /*
 192  * smb_idmap_batch_destroy
 193  *
 194  * Frees the batch ID mapping context.
 195  * If ID mapping is Solaris -> Windows it frees memories
 196  * allocated for binary SIDs.
 197  */
 198 void
 199 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
 200 {
 201         char *domsid;
 202         int i;
 203 
 204         ASSERT(sib);
 205         ASSERT(sib->sib_maps);
 206 
 207         if (sib->sib_idmaph)
 208                 kidmap_get_destroy(sib->sib_idmaph);
 209 
 210         if (sib->sib_flags & SMB_IDMAP_ID2SID) {
 211                 /*
 212                  * SIDs are allocated only when mapping
 213                  * UID/GID to SIDs
 214                  */
 215                 for (i = 0; i < sib->sib_nmap; i++)
 216                         smb_sid_free(sib->sib_maps[i].sim_sid);
 217         } else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
 218                 /*
 219                  * SID prefixes are allocated only when mapping
 220                  * SIDs to UID/GID
 221                  */
 222                 for (i = 0; i < sib->sib_nmap; i++) {
 223                         domsid = sib->sib_maps[i].sim_domsid;
 224                         if (domsid)
 225                                 smb_mem_free(domsid);
 226                 }
 227         }
 228 
 229         if (sib->sib_size && sib->sib_maps)
 230                 kmem_free(sib->sib_maps, sib->sib_size);
 231 }
 232 
 233 /*
 234  * smb_idmap_batch_getid
 235  *
 236  * Queue a request to map the given SID to a UID or GID.
 237  *
 238  * sim->sim_id should point to variable that's supposed to
 239  * hold the returned UID/GID. This needs to be setup by caller
 240  * of this function.
 241  *
 242  * If requested ID type is known, it's passed as 'idtype',
 243  * if it's unknown it'll be returned in sim->sim_idtype.
 244  */
 245 idmap_stat
 246 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
 247     smb_sid_t *sid, int idtype)
 248 {
 249         char strsid[SMB_SID_STRSZ];
 250         idmap_stat idm_stat;
 251 
 252         ASSERT(idmaph);
 253         ASSERT(sim);
 254         ASSERT(sid);
 255 
 256         smb_sid_tostr(sid, strsid);
 257         if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
 258                 return (IDMAP_ERR_SID);
 259         sim->sim_domsid = smb_mem_strdup(strsid);
 260 
 261         switch (idtype) {
 262         case SMB_IDMAP_USER:
 263                 idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
 264                     sim->sim_rid, sim->sim_id, &sim->sim_stat);
 265                 break;
 266 
 267         case SMB_IDMAP_GROUP:
 268                 idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
 269                     sim->sim_rid, sim->sim_id, &sim->sim_stat);
 270                 break;
 271 
 272         case SMB_IDMAP_UNKNOWN:
 273                 idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
 274                     sim->sim_rid, sim->sim_id, &sim->sim_idtype,
 275                     &sim->sim_stat);
 276                 break;
 277 
 278         default:
 279                 ASSERT(0);
 280                 return (IDMAP_ERR_ARG);
 281         }
 282 
 283         return (idm_stat);
 284 }
 285 
 286 /*
 287  * smb_idmap_batch_getsid
 288  *
 289  * Queue a request to map the given UID/GID to a SID.
 290  *
 291  * sim->sim_domsid and sim->sim_rid will contain the mapping
 292  * result upon successful process of the batched request.
 293  */
 294 idmap_stat
 295 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
 296     uid_t id, int idtype)
 297 {
 298         idmap_stat idm_stat;
 299 
 300         switch (idtype) {
 301         case SMB_IDMAP_USER:
 302                 idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
 303                     (const char **)&sim->sim_domsid, &sim->sim_rid,
 304                     &sim->sim_stat);
 305                 break;
 306 
 307         case SMB_IDMAP_GROUP:
 308                 idm_stat = kidmap_batch_getsidbygid(idmaph, id,
 309                     (const char **)&sim->sim_domsid, &sim->sim_rid,
 310                     &sim->sim_stat);
 311                 break;
 312 
 313         case SMB_IDMAP_OWNERAT:
 314                 /* Current Owner S-1-5-32-766 */
 315                 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
 316                 sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
 317                 sim->sim_stat = IDMAP_SUCCESS;
 318                 idm_stat = IDMAP_SUCCESS;
 319                 break;
 320 
 321         case SMB_IDMAP_GROUPAT:
 322                 /* Current Group S-1-5-32-767 */
 323                 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
 324                 sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
 325                 sim->sim_stat = IDMAP_SUCCESS;
 326                 idm_stat = IDMAP_SUCCESS;
 327                 break;
 328 
 329         case SMB_IDMAP_EVERYONE:
 330                 /* Everyone S-1-1-0 */
 331                 sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
 332                 sim->sim_rid = 0;
 333                 sim->sim_stat = IDMAP_SUCCESS;
 334                 idm_stat = IDMAP_SUCCESS;
 335                 break;
 336 
 337         default:
 338                 ASSERT(0);
 339                 return (IDMAP_ERR_ARG);
 340         }
 341 
 342         return (idm_stat);
 343 }
 344 
 345 /*
 346  * smb_idmap_batch_getmappings
 347  *
 348  * trigger ID mapping service to get the mappings for queued
 349  * requests.
 350  *
 351  * Checks the result of all the queued requests.
 352  * If this is a Solaris -> Windows mapping it generates
 353  * binary SIDs from returned (domsid, rid) pairs.
 354  */
 355 idmap_stat
 356 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
 357 {
 358         idmap_stat idm_stat = IDMAP_SUCCESS;
 359         int i;
 360 
 361         idm_stat = kidmap_get_mappings(sib->sib_idmaph);
 362         if (idm_stat != IDMAP_SUCCESS)
 363                 return (idm_stat);
 364 
 365         /*
 366          * Check the status for all the queued requests
 367          */
 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);
 371         }
 372 
 373         if (smb_idmap_batch_binsid(sib) != 0)
 374                 idm_stat = IDMAP_ERR_OTHER;
 375 
 376         return (idm_stat);
 377 }
 378 
 379 /*
 380  * smb_idmap_batch_binsid
 381  *
 382  * Convert sidrids to binary sids
 383  *
 384  * Returns 0 if successful and non-zero upon failure.
 385  */
 386 static int
 387 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
 388 {
 389         smb_sid_t *sid;
 390         smb_idmap_t *sim;
 391         int i;
 392 
 393         if (sib->sib_flags & SMB_IDMAP_SID2ID)
 394                 /* This operation is not required */
 395                 return (0);
 396 
 397         sim = sib->sib_maps;
 398         for (i = 0; i < sib->sib_nmap; sim++, i++) {
 399                 ASSERT(sim->sim_domsid);
 400                 if (sim->sim_domsid == NULL)
 401                         return (1);
 402 
 403                 if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
 404                         return (1);
 405 
 406                 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
 407                 smb_sid_free(sid);
 408         }
 409 
 410         return (0);
 411 }