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 2014 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 * uts/common/fs/smbsrv/smb_idmap.c (smbsrv kmod) 32 * lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c (libfksmbsrv) 33 * lib/smbsrv/libsmb/common/smb_idmap.c (libsmb) 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 */ 43 44 #include <sys/param.h> 45 #include <sys/types.h> 46 47 #include <smbsrv/smb_kproto.h> 48 #include <smbsrv/smb_idmap.h> 49 50 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib); 51 52 /* 53 * Report an idmap error. 54 */ 55 void 56 smb_idmap_check(const char *s, idmap_stat stat) 57 { 58 if (stat != IDMAP_SUCCESS) { 59 if (s == NULL) 60 s = "smb_idmap_check"; 61 62 cmn_err(CE_NOTE, "%s: %d", s, (int)stat); 63 } 64 } 65 66 /* 67 * smb_idmap_getsid 68 * 69 * Tries to get a mapping for the given uid/gid 70 * Allocates ->sim_domsid 71 */ 72 idmap_stat 73 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid) 74 { 75 smb_idmap_batch_t sib; 76 idmap_stat stat; 77 78 stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_ID2SID); 79 if (stat != IDMAP_SUCCESS) 80 return (stat); 81 82 stat = smb_idmap_batch_getsid(sib.sib_idmaph, &sib.sib_maps[0], 83 id, idtype); 84 85 if (stat != IDMAP_SUCCESS) { 86 smb_idmap_batch_destroy(&sib); 87 return (stat); 88 } 89 90 stat = smb_idmap_batch_getmappings(&sib); 91 92 if (stat != IDMAP_SUCCESS) { 93 smb_idmap_batch_destroy(&sib); 94 return (stat); 95 } 96 97 *sid = smb_sid_dup(sib.sib_maps[0].sim_sid); 98 99 smb_idmap_batch_destroy(&sib); 100 101 return (IDMAP_SUCCESS); 102 } 103 104 /* 105 * smb_idmap_getid 106 * 107 * Tries to get a mapping for the given SID 108 */ 109 idmap_stat 110 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *id_type) 111 { 112 smb_idmap_batch_t sib; 113 smb_idmap_t *sim; 114 idmap_stat stat; 115 116 stat = smb_idmap_batch_create(&sib, 1, SMB_IDMAP_SID2ID); 117 if (stat != IDMAP_SUCCESS) 118 return (stat); 119 120 sim = &sib.sib_maps[0]; 121 sim->sim_id = id; 122 stat = smb_idmap_batch_getid(sib.sib_idmaph, sim, sid, *id_type); 123 if (stat != IDMAP_SUCCESS) { 124 smb_idmap_batch_destroy(&sib); 125 return (stat); 126 } 127 128 stat = smb_idmap_batch_getmappings(&sib); 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 = 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 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 /* from strdup() in libidmap */ 199 free(sib->sib_maps[i].sim_domsid); 200 } 201 } 202 203 if (sib->sib_size && sib->sib_maps) { 204 kmem_free(sib->sib_maps, sib->sib_size); 205 sib->sib_maps = NULL; 206 } 207 } 208 209 /* 210 * smb_idmap_batch_getid 211 * 212 * Queue a request to map the given SID to a UID or GID. 213 * 214 * sim->sim_id should point to variable that's supposed to 215 * hold the returned UID/GID. This needs to be setup by caller 216 * of this function. 217 * If requested ID type is known, it's passed as 'idtype', 218 * if it's unknown it'll be returned in sim->sim_idtype. 219 */ 220 idmap_stat 221 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 222 smb_sid_t *sid, int idtype) 223 { 224 char sidstr[SMB_SID_STRSZ]; 225 idmap_stat stat; 226 int flag = 0; 227 228 if (idmaph == NULL || sim == NULL || sid == NULL) 229 return (IDMAP_ERR_ARG); 230 231 smb_sid_tostr(sid, sidstr); 232 if (smb_sid_splitstr(sidstr, &sim->sim_rid) != 0) 233 return (IDMAP_ERR_SID); 234 sim->sim_domsid = sidstr; 235 sim->sim_idtype = idtype; 236 237 switch (idtype) { 238 case SMB_IDMAP_USER: 239 stat = idmap_get_uidbysid(idmaph, sim->sim_domsid, 240 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat); 241 smb_idmap_check("idmap_get_uidbysid", stat); 242 break; 243 244 case SMB_IDMAP_GROUP: 245 stat = idmap_get_gidbysid(idmaph, sim->sim_domsid, 246 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat); 247 smb_idmap_check("idmap_get_gidbysid", stat); 248 break; 249 250 case SMB_IDMAP_UNKNOWN: 251 stat = idmap_get_pidbysid(idmaph, sim->sim_domsid, 252 sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype, 253 &sim->sim_stat); 254 smb_idmap_check("idmap_get_pidbysid", stat); 255 break; 256 257 default: 258 stat = IDMAP_ERR_ARG; 259 break; 260 } 261 262 /* This was copied by idmap_get_Xbysid. */ 263 sim->sim_domsid = NULL; 264 265 return (stat); 266 } 267 268 /* 269 * smb_idmap_batch_getsid 270 * 271 * Queue a request to map the given UID/GID to a SID. 272 * 273 * sim->sim_domsid and sim->sim_rid will contain the mapping 274 * result upon successful process of the batched request. 275 * NB: sim_domsid allocated by strdup, here or in libidmap 276 */ 277 idmap_stat 278 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 279 uid_t id, int idtype) 280 { 281 idmap_stat stat; 282 int flag = 0; 283 284 if (!idmaph || !sim) 285 return (IDMAP_ERR_ARG); 286 287 switch (idtype) { 288 case SMB_IDMAP_USER: 289 stat = idmap_get_sidbyuid(idmaph, id, flag, 290 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat); 291 smb_idmap_check("idmap_get_sidbyuid", stat); 292 break; 293 294 case SMB_IDMAP_GROUP: 295 stat = idmap_get_sidbygid(idmaph, id, flag, 296 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat); 297 smb_idmap_check("idmap_get_sidbygid", stat); 298 break; 299 300 case SMB_IDMAP_OWNERAT: 301 /* Current Owner S-1-5-32-766 */ 302 sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR); 303 sim->sim_rid = SECURITY_CURRENT_OWNER_RID; 304 sim->sim_stat = IDMAP_SUCCESS; 305 stat = IDMAP_SUCCESS; 306 break; 307 308 case SMB_IDMAP_GROUPAT: 309 /* Current Group S-1-5-32-767 */ 310 sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR); 311 sim->sim_rid = SECURITY_CURRENT_GROUP_RID; 312 sim->sim_stat = IDMAP_SUCCESS; 313 stat = IDMAP_SUCCESS; 314 break; 315 316 case SMB_IDMAP_EVERYONE: 317 /* Everyone S-1-1-0 */ 318 sim->sim_domsid = strdup(NT_WORLD_AUTH_SIDSTR); 319 sim->sim_rid = 0; 320 sim->sim_stat = IDMAP_SUCCESS; 321 stat = IDMAP_SUCCESS; 322 break; 323 324 default: 325 return (IDMAP_ERR_ARG); 326 } 327 328 return (stat); 329 } 330 331 /* 332 * smb_idmap_batch_getmappings 333 * 334 * trigger ID mapping service to get the mappings for queued 335 * requests. 336 * 337 * Checks the result of all the queued requests. 338 */ 339 idmap_stat 340 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib) 341 { 342 idmap_stat stat = IDMAP_SUCCESS; 343 smb_idmap_t *sim; 344 int i; 345 346 if ((stat = idmap_get_mappings(sib->sib_idmaph)) != IDMAP_SUCCESS) { 347 smb_idmap_check("idmap_get_mappings", stat); 348 return (stat); 349 } 350 351 /* 352 * Check the status for all the queued requests 353 */ 354 for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) { 355 if (sim->sim_stat != IDMAP_SUCCESS) { 356 if (sib->sib_flags == SMB_IDMAP_SID2ID) { 357 cmn_err(CE_NOTE, "[%d] %d (%d)", 358 sim->sim_idtype, 359 sim->sim_rid, 360 sim->sim_stat); 361 } 362 return (sim->sim_stat); 363 } 364 } 365 366 if (smb_idmap_batch_binsid(sib) != 0) 367 stat = IDMAP_ERR_OTHER; 368 369 return (stat); 370 } 371 372 /* 373 * smb_idmap_batch_binsid 374 * 375 * Convert sidrids to binary sids 376 * 377 * Returns 0 if successful and non-zero upon failure. 378 */ 379 static int 380 smb_idmap_batch_binsid(smb_idmap_batch_t *sib) 381 { 382 smb_sid_t *sid; 383 smb_idmap_t *sim; 384 int i; 385 386 if (sib->sib_flags & SMB_IDMAP_SID2ID) 387 /* This operation is not required */ 388 return (0); 389 390 sim = sib->sib_maps; 391 for (i = 0; i < sib->sib_nmap; sim++, i++) { 392 if (sim->sim_domsid == NULL) 393 return (-1); 394 395 sid = smb_sid_fromstr(sim->sim_domsid); 396 if (sid == NULL) 397 return (-1); 398 399 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid); 400 smb_sid_free(sid); 401 } 402 403 return (0); 404 } 405