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