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