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 2018 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 * 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(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 /* 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(global_zone, sim.sim_domsid, 154 sim.sim_rid, sim.sim_id); 155 break; 156 157 case SMB_IDMAP_GROUP: 158 sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid, 159 sim.sim_rid, sim.sim_id); 160 break; 161 162 case SMB_IDMAP_UNKNOWN: 163 sim.sim_stat = kidmap_getpidbysid(global_zone, 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(global_zone); 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 } 455