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 2008 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 || !sim || !sid) 289 return (IDMAP_ERR_ARG); 290 291 tmpsid = smb_sid_dup(sid); 292 if (!tmpsid) 293 return (IDMAP_ERR_MEMORY); 294 295 if (smb_sid_split(tmpsid, &sim->sim_rid) != 0) { 296 smb_sid_free(tmpsid); 297 return (IDMAP_ERR_ARG); 298 } 299 300 smb_sid_tostr(tmpsid, sidstr); 301 sim->sim_domsid = sidstr; 302 smb_sid_free(tmpsid); 303 304 switch (idtype) { 305 case SMB_IDMAP_USER: 306 stat = idmap_get_uidbysid(idmaph, sim->sim_domsid, 307 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat); 308 break; 309 310 case SMB_IDMAP_GROUP: 311 stat = idmap_get_gidbysid(idmaph, sim->sim_domsid, 312 sim->sim_rid, flag, sim->sim_id, &sim->sim_stat); 313 break; 314 315 case SMB_IDMAP_UNKNOWN: 316 stat = idmap_get_pidbysid(idmaph, sim->sim_domsid, 317 sim->sim_rid, flag, sim->sim_id, &sim->sim_idtype, 318 &sim->sim_stat); 319 break; 320 321 default: 322 return (IDMAP_ERR_ARG); 323 } 324 325 return (stat); 326 } 327 328 /* 329 * smb_idmap_batch_getsid 330 * 331 * Queue a request to map the given UID/GID to a SID. 332 * 333 * sim->sim_domsid and sim->sim_rid will contain the mapping 334 * result upon successful process of the batched request. 335 */ 336 idmap_stat 337 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 338 uid_t id, int idtype) 339 { 340 idmap_stat stat; 341 int flag = 0; 342 343 if (!idmaph || !sim) 344 return (IDMAP_ERR_ARG); 345 346 switch (idtype) { 347 case SMB_IDMAP_USER: 348 stat = idmap_get_sidbyuid(idmaph, id, flag, 349 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat); 350 break; 351 352 case SMB_IDMAP_GROUP: 353 stat = idmap_get_sidbygid(idmaph, id, flag, 354 &sim->sim_domsid, &sim->sim_rid, &sim->sim_stat); 355 break; 356 357 case SMB_IDMAP_EVERYONE: 358 /* Everyone S-1-1-0 */ 359 sim->sim_domsid = "S-1-1"; 360 sim->sim_rid = 0; 361 sim->sim_stat = IDMAP_SUCCESS; 362 stat = IDMAP_SUCCESS; 363 break; 364 365 default: 366 return (IDMAP_ERR_ARG); 367 } 368 369 return (stat); 370 } 371 372 /* 373 * smb_idmap_batch_getmappings 374 * 375 * trigger ID mapping service to get the mappings for queued 376 * requests. 377 * 378 * Checks the result of all the queued requests. 379 */ 380 idmap_stat 381 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib) 382 { 383 idmap_stat stat = IDMAP_SUCCESS; 384 smb_idmap_t *sim; 385 int i; 386 387 if ((stat = idmap_get_mappings(sib->sib_idmaph)) != IDMAP_SUCCESS) 388 return (stat); 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] %s-%d (%d)", 397 sim->sim_idtype, sim->sim_domsid, 398 sim->sim_rid, sim->sim_stat); 399 } 400 return (sim->sim_stat); 401 } 402 } 403 404 if (smb_idmap_batch_binsid(sib) != 0) 405 stat = IDMAP_ERR_OTHER; 406 407 return (stat); 408 } 409 410 /* 411 * smb_idmap_batch_binsid 412 * 413 * Convert sidrids to binary sids 414 * 415 * Returns 0 if successful and non-zero upon failure. 416 */ 417 static int 418 smb_idmap_batch_binsid(smb_idmap_batch_t *sib) 419 { 420 smb_sid_t *sid; 421 smb_idmap_t *sim; 422 int i; 423 424 if (sib->sib_flags & SMB_IDMAP_SID2ID) 425 /* This operation is not required */ 426 return (0); 427 428 sim = sib->sib_maps; 429 for (i = 0; i < sib->sib_nmap; sim++, i++) { 430 if (sim->sim_domsid == NULL) 431 return (-1); 432 433 sid = smb_sid_fromstr(sim->sim_domsid); 434 free(sim->sim_domsid); 435 if (sid == NULL) 436 return (-1); 437 438 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid); 439 free(sid); 440 } 441 442 return (0); 443 } 444