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