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