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 "fake kernel" version of these routines. See also: 32 * $SRC/lib/smbsrv/libsmb/common/smb_idmap.c 33 * $SRC/uts/common/fs/smbsrv/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 idmap interfaces (libidmap) 40 * uses kmem_... interfaces (libfakekernel) 41 * uses cmn_err instead of syslog, etc. 42 * The code in this variant looks a lot like the one in libsmb. 43 */ 44 45 #include <sys/param.h> 46 #include <sys/types.h> 47 48 #include <smbsrv/smb_kproto.h> 49 #include <smbsrv/smb_idmap.h> 50 51 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib); 52 53 /* 54 * Report an idmap error. 55 */ 56 void 57 smb_idmap_check(const char *s, idmap_stat stat) 58 { 59 if (stat != IDMAP_SUCCESS) { 60 if (s == NULL) 61 s = "smb_idmap_check"; 62 63 cmn_err(CE_NOTE, "%s: %d", s, (int)stat); 64 } 65 } 66 67 /* 68 * smb_idmap_getsid 69 * 70 * Tries to get a mapping for the given uid/gid 71 * Allocates ->sim_domsid 72 */ 73 idmap_stat 74 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid) 75 { 76 smb_idmap_batch_t sib; 77 idmap_stat stat; 78 79 stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_ID2SID); 80 if (stat != IDMAP_SUCCESS) 81 return (stat); 82 83 stat = smb_idmap_batch_getsid(sib.sib_idmaph, &sib.sib_maps[0], 84 id, idtype); 85 86 if (stat != IDMAP_SUCCESS) { 87 smb_idmap_batch_destroy(&sib); 88 return (stat); 89 } 90 91 stat = smb_idmap_batch_getmappings(&sib); 92 93 if (stat != IDMAP_SUCCESS) { 94 smb_idmap_batch_destroy(&sib); 95 return (stat); 96 } 97 98 *sid = smb_sid_dup(sib.sib_maps[0].sim_sid); 99 100 smb_idmap_batch_destroy(&sib); 101 102 return (IDMAP_SUCCESS); 103 } 104 105 /* 106 * smb_idmap_getid 107 * 108 * Tries to get a mapping for the given SID 109 */ 110 idmap_stat 111 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *id_type) 112 { 113 smb_idmap_batch_t sib; 114 smb_idmap_t *sim; 115 idmap_stat stat; 116 117 stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_SID2ID); 118 if (stat != IDMAP_SUCCESS) 119 return (stat); 120 121 sim = &sib.sib_maps[0]; 122 sim->sim_id = id; 123 stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, sid, *id_type); 124 if (stat != IDMAP_SUCCESS) { 125 smb_idmap_batch_destroy(&sib); 126 return (stat); 127 } 128 129 stat = smb_idmap_batch_getmappings(&sib); 130 131 if (stat != IDMAP_SUCCESS) { 132 smb_idmap_batch_destroy(&sib); 133 return (stat); 134 } 135 136 *id_type = sim->sim_idtype; 137 smb_idmap_batch_destroy(&sib); 138 139 return (IDMAP_SUCCESS); 140 } 141 142 /* 143 * smb_idmap_batch_create 144 * 145 * Creates and initializes the context for batch ID mapping. 146 */ 147 idmap_stat 148 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags) 149 { 150 idmap_stat stat; 151 152 ASSERT(sib != NULL); 153 154 bzero(sib, sizeof (smb_idmap_batch_t)); 155 stat = idmap_get_create(&sib->sib_idmaph); 156 157 if (stat != IDMAP_SUCCESS) { 158 smb_idmap_check("idmap_get_create", stat); 159 return (stat); 160 } 161 162 sib->sib_flags = flags; 163 sib->sib_nmap = nmap; 164 sib->sib_size = nmap * sizeof (smb_idmap_t); 165 sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP); 166 167 return (IDMAP_SUCCESS); 168 } 169 170 /* 171 * smb_idmap_batch_destroy 172 * 173 * Frees the batch ID mapping context. 174 */ 175 void 176 smb_idmap_batch_destroy(smb_idmap_batch_t *sib) 177 { 178 char *domsid; 179 int i; 180 181 ASSERT(sib != NULL); 182 ASSERT(sib->sib_maps != NULL); 183 184 if (sib->sib_idmaph) { 185 idmap_get_destroy(sib->sib_idmaph); 186 sib->sib_idmaph = NULL; 187 } 188 189 if (sib->sib_flags & SMB_IDMAP_ID2SID) { 190 /* 191 * SIDs are allocated only when mapping 192 * UID/GID to SIDs 193 */ 194 for (i = 0; i < sib->sib_nmap; i++) { 195 smb_sid_free(sib->sib_maps[i].sim_sid); 196 /* from strdup() in libidmap */ 197 free(sib->sib_maps[i].sim_domsid); 198 } 199 } else if (sib->sib_flags & SMB_IDMAP_SID2ID) { 200 /* 201 * SID prefixes are allocated only when mapping 202 * SIDs to UID/GID 203 */ 204 for (i = 0; i < sib->sib_nmap; i++) { 205 domsid = sib->sib_maps[i].sim_domsid; 206 if (domsid) 207 smb_mem_free(domsid); 208 } 209 } 210 211 if (sib->sib_size && sib->sib_maps) { 212 kmem_free(sib->sib_maps, sib->sib_size); 213 sib->sib_maps = NULL; 214 } 215 } 216 217 /* 218 * smb_idmap_batch_getid 219 * 220 * Queue a request to map the given SID to a UID or GID. 221 * 222 * sim->sim_id should point to variable that's supposed to 223 * hold the returned UID/GID. This needs to be setup by caller 224 * of this function. 225 * If requested ID type is known, it's passed as 'idtype', 226 * if it's unknown it'll be returned in sim->sim_idtype. 227 */ 228 idmap_stat 229 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 230 smb_sid_t *sid, int idtype) 231 { 232 char sidstr[SMB_SID_STRSZ]; 233 idmap_stat stat; 234 int flag = 0; 235 236 ASSERT(idmaph != NULL); 237 ASSERT(sim != NULL); 238 ASSERT(sid != NULL); 239 240 smb_sid_tostr(sid, sidstr); 241 if (smb_sid_splitstr(sidstr, &sim->sim_rid) != 0) 242 return (IDMAP_ERR_SID); 243 /* Note: Free sim_domsid in smb_idmap_batch_destroy */ 244 sim->sim_domsid = smb_mem_strdup(sidstr); 245 sim->sim_idtype = idtype; 246 247 switch (idtype) { 248 case SMB_IDMAP_USER: 249 stat = idmap_get_uidbysid(idmaph, sim->sim_domsid, 250 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat); 251 smb_idmap_check("idmap_get_uidbysid", stat); 252 break; 253 254 case SMB_IDMAP_GROUP: 255 stat = idmap_get_gidbysid(idmaph, sim->sim_domsid, 256 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat); 257 smb_idmap_check("idmap_get_gidbysid", stat); 258 break; 259 260 case SMB_IDMAP_UNKNOWN: 261 stat = idmap_get_pidbysid(idmaph, sim->sim_domsid, 262 sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype, 263 &sim->sim_stat); 264 smb_idmap_check("idmap_get_pidbysid", stat); 265 break; 266 267 default: 268 stat = IDMAP_ERR_ARG; 269 break; 270 } 271 272 return (stat); 273 } 274 275 /* 276 * smb_idmap_batch_getsid 277 * 278 * Queue a request to map the given UID/GID to a SID. 279 * 280 * sim->sim_domsid and sim->sim_rid will contain the mapping 281 * result upon successful process of the batched request. 282 * Stash the type for error reporting (caller saves the ID). 283 * 284 * NB: sim_domsid allocated by strdup, here or in libidmap 285 */ 286 idmap_stat 287 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 288 uid_t id, int idtype) 289 { 290 idmap_stat stat; 291 int flag = 0; 292 293 if (!idmaph || !sim) 294 return (IDMAP_ERR_ARG); 295 296 sim->sim_idtype = idtype; 297 switch (idtype) { 298 case SMB_IDMAP_USER: 299 stat = idmap_get_sidbyuid(idmaph, id, flag, 300 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat); 301 smb_idmap_check("idmap_get_sidbyuid", stat); 302 break; 303 304 case SMB_IDMAP_GROUP: 305 stat = idmap_get_sidbygid(idmaph, id, flag, 306 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat); 307 smb_idmap_check("idmap_get_sidbygid", stat); 308 break; 309 310 case SMB_IDMAP_OWNERAT: 311 /* Current Owner S-1-5-32-766 */ 312 sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR); 313 sim->sim_rid = SECURITY_CURRENT_OWNER_RID; 314 sim->sim_stat = IDMAP_SUCCESS; 315 stat = IDMAP_SUCCESS; 316 break; 317 318 case SMB_IDMAP_GROUPAT: 319 /* Current Group S-1-5-32-767 */ 320 sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR); 321 sim->sim_rid = SECURITY_CURRENT_GROUP_RID; 322 sim->sim_stat = IDMAP_SUCCESS; 323 stat = IDMAP_SUCCESS; 324 break; 325 326 case SMB_IDMAP_EVERYONE: 327 /* Everyone S-1-1-0 */ 328 sim->sim_domsid = strdup(NT_WORLD_AUTH_SIDSTR); 329 sim->sim_rid = 0; 330 sim->sim_stat = IDMAP_SUCCESS; 331 stat = IDMAP_SUCCESS; 332 break; 333 334 default: 335 ASSERT(0); 336 return (IDMAP_ERR_ARG); 337 } 338 339 return (stat); 340 } 341 342 static void 343 smb_idmap_bgm_report(smb_idmap_batch_t *sib, smb_idmap_t *sim) 344 { 345 346 if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) { 347 /* 348 * Note: The ID and type we asked idmap to map 349 * were saved in *sim_id and sim_idtype. 350 */ 351 uint_t id = (sim->sim_id == NULL) ? 352 0 : (uint_t)*sim->sim_id; 353 cmn_err(CE_WARN, "Can't get SID for " 354 "ID=%u type=%d, status=%d", 355 id, sim->sim_idtype, sim->sim_stat); 356 } 357 358 if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) { 359 cmn_err(CE_WARN, "Can't get ID for SID %s-%u, status=%d", 360 sim->sim_domsid, sim->sim_rid, sim->sim_stat); 361 } 362 } 363 364 /* 365 * smb_idmap_batch_getmappings 366 * 367 * trigger ID mapping service to get the mappings for queued 368 * requests. 369 * 370 * Checks the result of all the queued requests. 371 */ 372 idmap_stat 373 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib) 374 { 375 idmap_stat stat = IDMAP_SUCCESS; 376 smb_idmap_t *sim; 377 int i; 378 379 if ((stat = idmap_get_mappings(sib->sib_idmaph)) != IDMAP_SUCCESS) { 380 smb_idmap_check("idmap_get_mappings", stat); 381 return (stat); 382 } 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 smb_idmap_bgm_report(sib, sim); 390 if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) { 391 return (sim->sim_stat); 392 } 393 } 394 } 395 396 if (smb_idmap_batch_binsid(sib) != 0) 397 stat = IDMAP_ERR_OTHER; 398 399 return (stat); 400 } 401 402 /* 403 * smb_idmap_batch_binsid 404 * 405 * Convert sidrids to binary sids 406 * 407 * Returns 0 if successful and non-zero upon failure. 408 */ 409 static int 410 smb_idmap_batch_binsid(smb_idmap_batch_t *sib) 411 { 412 smb_sid_t *sid; 413 smb_idmap_t *sim; 414 int i; 415 416 if (sib->sib_flags & SMB_IDMAP_SID2ID) 417 /* This operation is not required */ 418 return (0); 419 420 sim = sib->sib_maps; 421 for (i = 0; i < sib->sib_nmap; sim++, i++) { 422 ASSERT(sim->sim_domsid != NULL); 423 if (sim->sim_domsid == NULL) 424 return (-1); 425 426 sid = smb_sid_fromstr(sim->sim_domsid); 427 if (sid == NULL) 428 return (-1); 429 430 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid); 431 smb_sid_free(sid); 432 } 433 434 return (0); 435 } 436