Home | History | Annotate | Download | only in common
      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 <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_OWNERAT:
    352 		/* Current Owner S-1-5-32-766 */
    353 		sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR);
    354 		sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
    355 		sim->sim_stat = IDMAP_SUCCESS;
    356 		stat = IDMAP_SUCCESS;
    357 		break;
    358 
    359 	case SMB_IDMAP_GROUPAT:
    360 		/* Current Group S-1-5-32-767 */
    361 		sim->sim_domsid = strdup(NT_BUILTIN_DOMAIN_SIDSTR);
    362 		sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
    363 		sim->sim_stat = IDMAP_SUCCESS;
    364 		stat = IDMAP_SUCCESS;
    365 		break;
    366 
    367 	case SMB_IDMAP_EVERYONE:
    368 		/* Everyone S-1-1-0 */
    369 		sim->sim_domsid = strdup(NT_WORLD_AUTH_SIDSTR);
    370 		sim->sim_rid = 0;
    371 		sim->sim_stat = IDMAP_SUCCESS;
    372 		stat = IDMAP_SUCCESS;
    373 		break;
    374 
    375 	default:
    376 		return (IDMAP_ERR_ARG);
    377 	}
    378 
    379 	return (stat);
    380 }
    381 
    382 /*
    383  * smb_idmap_batch_getmappings
    384  *
    385  * trigger ID mapping service to get the mappings for queued
    386  * requests.
    387  *
    388  * Checks the result of all the queued requests.
    389  */
    390 idmap_stat
    391 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
    392 {
    393 	idmap_stat stat = IDMAP_SUCCESS;
    394 	smb_idmap_t *sim;
    395 	int i;
    396 
    397 	if ((stat = idmap_get_mappings(sib->sib_idmaph)) != IDMAP_SUCCESS)
    398 		return (stat);
    399 
    400 	/*
    401 	 * Check the status for all the queued requests
    402 	 */
    403 	for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
    404 		if (sim->sim_stat != IDMAP_SUCCESS) {
    405 			if (sib->sib_flags == SMB_IDMAP_SID2ID) {
    406 				smb_tracef("[%d] %d (%d)", sim->sim_idtype,
    407 				    sim->sim_rid, sim->sim_stat);
    408 			}
    409 			return (sim->sim_stat);
    410 		}
    411 	}
    412 
    413 	if (smb_idmap_batch_binsid(sib) != 0)
    414 		stat = IDMAP_ERR_OTHER;
    415 
    416 	return (stat);
    417 }
    418 
    419 /*
    420  * smb_idmap_batch_binsid
    421  *
    422  * Convert sidrids to binary sids
    423  *
    424  * Returns 0 if successful and non-zero upon failure.
    425  */
    426 static int
    427 smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
    428 {
    429 	smb_sid_t *sid;
    430 	smb_idmap_t *sim;
    431 	int i;
    432 
    433 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
    434 		/* This operation is not required */
    435 		return (0);
    436 
    437 	sim = sib->sib_maps;
    438 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
    439 		if (sim->sim_domsid == NULL)
    440 			return (-1);
    441 
    442 		sid = smb_sid_fromstr(sim->sim_domsid);
    443 		free(sim->sim_domsid);
    444 		if (sid == NULL)
    445 			return (-1);
    446 
    447 		sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
    448 		free(sid);
    449 	}
    450 
    451 	return (0);
    452 }
    453