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 } 412