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