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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * This module provides the high level interface to the LSA RPC functions.
     28  */
     29 
     30 #include <strings.h>
     31 #include <unistd.h>
     32 
     33 #include <smbsrv/libsmb.h>
     34 #include <smbsrv/libmlsvc.h>
     35 #include <smbsrv/ntstatus.h>
     36 #include <smbsrv/smbinfo.h>
     37 #include <smbsrv/smb_token.h>
     38 
     39 #include <lsalib.h>
     40 
     41 static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *);
     42 static uint32_t lsa_lookup_name_domain(char *, smb_account_t *);
     43 
     44 static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *);
     45 static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *);
     46 
     47 static int lsa_list_accounts(mlsvc_handle_t *);
     48 
     49 /*
     50  * Lookup the given account and returns the account information
     51  * in the passed smb_account_t structure.
     52  *
     53  * The lookup is performed in the following order:
     54  *    well known accounts
     55  *    local accounts
     56  *    domain accounts
     57  *
     58  * If it's established the given account is well know or local
     59  * but the lookup fails for some reason, the next step(s) won't be
     60  * performed.
     61  *
     62  * If the name is a domain account, it may refer to a user, group or
     63  * alias. If it is a local account, its type should be specified
     64  * in the sid_type parameter. In case the account type is unknown
     65  * sid_type should be set to SidTypeUnknown.
     66  *
     67  * account argument could be either [domain\]name or [domain/]name.
     68  *
     69  * Return status:
     70  *
     71  *   NT_STATUS_SUCCESS		Account is successfully translated
     72  *   NT_STATUS_NONE_MAPPED	Couldn't translate the account
     73  */
     74 uint32_t
     75 lsa_lookup_name(char *account, uint16_t type, smb_account_t *info)
     76 {
     77 	char nambuf[SMB_USERNAME_MAXLEN];
     78 	char dombuf[SMB_PI_MAX_DOMAIN];
     79 	char *name, *domain;
     80 	uint32_t status;
     81 	char *slash;
     82 
     83 	(void) strsubst(account, '/', '\\');
     84 	(void) strcanon(account, "\\");
     85 	/* \john -> john */
     86 	account += strspn(account, "\\");
     87 
     88 	if ((slash = strchr(account, '\\')) != NULL) {
     89 		*slash = '\0';
     90 		(void) strlcpy(dombuf, account, sizeof (dombuf));
     91 		(void) strlcpy(nambuf, slash + 1, sizeof (nambuf));
     92 		*slash = '\\';
     93 		name = nambuf;
     94 		domain = dombuf;
     95 	} else {
     96 		name = account;
     97 		domain = NULL;
     98 	}
     99 
    100 	status = lsa_lookup_name_builtin(domain, name, info);
    101 	if (status == NT_STATUS_NOT_FOUND) {
    102 		status = smb_sam_lookup_name(domain, name, type, info);
    103 		if (status == NT_STATUS_SUCCESS)
    104 			return (status);
    105 
    106 		if ((domain == NULL) || (status == NT_STATUS_NOT_FOUND))
    107 			status = lsa_lookup_name_domain(account, info);
    108 	}
    109 
    110 	return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
    111 }
    112 
    113 uint32_t
    114 lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info)
    115 {
    116 	uint32_t status;
    117 
    118 	if (!smb_sid_isvalid(sid))
    119 		return (NT_STATUS_INVALID_SID);
    120 
    121 	status = lsa_lookup_sid_builtin(sid, info);
    122 	if (status == NT_STATUS_NOT_FOUND) {
    123 		status = smb_sam_lookup_sid(sid, info);
    124 		if (status == NT_STATUS_NOT_FOUND)
    125 			status = lsa_lookup_sid_domain(sid, info);
    126 	}
    127 
    128 	return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
    129 }
    130 
    131 /*
    132  * Obtains the primary domain SID and name from the specified server
    133  * (domain controller).
    134  *
    135  * The requested information will be returned via 'info' argument.
    136  *
    137  * Returns NT status codes.
    138  */
    139 DWORD
    140 lsa_query_primary_domain_info(char *server, char *domain,
    141     smb_domain_t *info)
    142 {
    143 	mlsvc_handle_t domain_handle;
    144 	DWORD status;
    145 	char user[SMB_USERNAME_MAXLEN];
    146 
    147 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    148 
    149 	if ((lsar_open(server, domain, user, &domain_handle)) != 0)
    150 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    151 
    152 	status = lsar_query_info_policy(&domain_handle,
    153 	    MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info);
    154 
    155 	(void) lsar_close(&domain_handle);
    156 	return (status);
    157 }
    158 
    159 /*
    160  * Obtains the account domain SID and name from the current server
    161  * (domain controller).
    162  *
    163  * The requested information will be returned via 'info' argument.
    164  *
    165  * Returns NT status codes.
    166  */
    167 DWORD
    168 lsa_query_account_domain_info(char *server, char *domain,
    169     smb_domain_t *info)
    170 {
    171 	mlsvc_handle_t domain_handle;
    172 	DWORD status;
    173 	char user[SMB_USERNAME_MAXLEN];
    174 
    175 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    176 
    177 	if ((lsar_open(server, domain, user, &domain_handle)) != 0)
    178 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    179 
    180 	status = lsar_query_info_policy(&domain_handle,
    181 	    MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info);
    182 
    183 	(void) lsar_close(&domain_handle);
    184 	return (status);
    185 }
    186 
    187 /*
    188  * lsa_query_dns_domain_info
    189  *
    190  * Obtains the DNS domain info from the specified server
    191  * (domain controller).
    192  *
    193  * The requested information will be returned via 'info' argument.
    194  *
    195  * Returns NT status codes.
    196  */
    197 DWORD
    198 lsa_query_dns_domain_info(char *server, char *domain, smb_domain_t *info)
    199 {
    200 	mlsvc_handle_t domain_handle;
    201 	DWORD status;
    202 	char user[SMB_USERNAME_MAXLEN];
    203 
    204 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    205 
    206 	if ((lsar_open(server, domain, user, &domain_handle)) != 0)
    207 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    208 
    209 	status = lsar_query_info_policy(&domain_handle,
    210 	    MSLSA_POLICY_DNS_DOMAIN_INFO, info);
    211 
    212 	(void) lsar_close(&domain_handle);
    213 	return (status);
    214 }
    215 
    216 /*
    217  * Enumerate the trusted domains of  primary domain.
    218  * This is the basic enumaration call which only returns the
    219  * NetBIOS name of the domain and its SID.
    220  *
    221  * The requested information will be returned via 'info' argument.
    222  *
    223  * Returns NT status codes.
    224  */
    225 DWORD
    226 lsa_enum_trusted_domains(char *server, char *domain,
    227     smb_trusted_domains_t *info)
    228 {
    229 	mlsvc_handle_t domain_handle;
    230 	DWORD enum_context;
    231 	DWORD status;
    232 	char user[SMB_USERNAME_MAXLEN];
    233 
    234 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    235 
    236 	if ((lsar_open(server, domain, user, &domain_handle)) != 0)
    237 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    238 
    239 	enum_context = 0;
    240 
    241 	status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info);
    242 	if (status == NT_STATUS_NO_MORE_DATA) {
    243 		/*
    244 		 * NT_STATUS_NO_MORE_DATA indicates that we
    245 		 * have all of the available information.
    246 		 */
    247 		status = NT_STATUS_SUCCESS;
    248 	}
    249 
    250 	(void) lsar_close(&domain_handle);
    251 	return (status);
    252 }
    253 
    254 /*
    255  * Enumerate the trusted domains of the primary domain.
    256  * This is the extended enumaration call which besides
    257  * NetBIOS name of the domain and its SID, it will return
    258  * the FQDN plus some trust information which is not used.
    259  *
    260  * The requested information will be returned via 'info' argument.
    261  *
    262  * Returns NT status codes.
    263  */
    264 DWORD
    265 lsa_enum_trusted_domains_ex(char *server, char *domain,
    266     smb_trusted_domains_t *info)
    267 {
    268 	mlsvc_handle_t domain_handle;
    269 	DWORD enum_context;
    270 	DWORD status;
    271 	char user[SMB_USERNAME_MAXLEN];
    272 
    273 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    274 
    275 	if ((lsar_open(server, domain, user, &domain_handle)) != 0)
    276 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    277 
    278 	enum_context = 0;
    279 
    280 	status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context,
    281 	    info);
    282 	if (status == NT_STATUS_NO_MORE_DATA) {
    283 		/*
    284 		 * NT_STATUS_NO_MORE_DATA indicates that we
    285 		 * have all of the available information.
    286 		 */
    287 		status = NT_STATUS_SUCCESS;
    288 	}
    289 
    290 	(void) lsar_close(&domain_handle);
    291 	return (status);
    292 }
    293 
    294 /*
    295  * Lookup well known accounts table
    296  *
    297  * Return status:
    298  *
    299  *   NT_STATUS_SUCCESS		Account is translated successfully
    300  *   NT_STATUS_NOT_FOUND	This is not a well known account
    301  *   NT_STATUS_NONE_MAPPED	Account is found but domains don't match
    302  *   NT_STATUS_NO_MEMORY	Memory shortage
    303  *   NT_STATUS_INTERNAL_ERROR	Internal error/unexpected failure
    304  */
    305 static uint32_t
    306 lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info)
    307 {
    308 	smb_wka_t *wka;
    309 	char *wkadom;
    310 
    311 	bzero(info, sizeof (smb_account_t));
    312 
    313 	if ((wka = smb_wka_lookup_name(name)) == NULL)
    314 		return (NT_STATUS_NOT_FOUND);
    315 
    316 	if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
    317 		return (NT_STATUS_INTERNAL_ERROR);
    318 
    319 	if ((domain != NULL) && (smb_strcasecmp(domain, wkadom, 0) != 0))
    320 		return (NT_STATUS_NONE_MAPPED);
    321 
    322 	info->a_name = strdup(name);
    323 	info->a_sid = smb_sid_dup(wka->wka_binsid);
    324 	info->a_domain = strdup(wkadom);
    325 	info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid);
    326 	info->a_type = wka->wka_type;
    327 
    328 	if (!smb_account_validate(info)) {
    329 		smb_account_free(info);
    330 		return (NT_STATUS_NO_MEMORY);
    331 	}
    332 
    333 	return (NT_STATUS_SUCCESS);
    334 }
    335 
    336 /*
    337  * Lookup the given account in domain.
    338  *
    339  * The information is returned in the user_info structure.
    340  * The caller is responsible for allocating and releasing
    341  * this structure.
    342  */
    343 static uint32_t
    344 lsa_lookup_name_domain(char *account_name, smb_account_t *info)
    345 {
    346 	mlsvc_handle_t domain_handle;
    347 	smb_domainex_t dinfo;
    348 	uint32_t status;
    349 	char user[SMB_USERNAME_MAXLEN];
    350 
    351 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    352 
    353 	if (!smb_domain_getinfo(&dinfo))
    354 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    355 
    356 	if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
    357 	    &domain_handle) != 0)
    358 		return (NT_STATUS_INVALID_PARAMETER);
    359 
    360 	status = lsar_lookup_names(&domain_handle, account_name, info);
    361 
    362 	(void) lsar_close(&domain_handle);
    363 	return (status);
    364 }
    365 
    366 /*
    367  * lsa_lookup_privs
    368  *
    369  * Request the privileges associated with the specified account. In
    370  * order to get the privileges, we first have to lookup the name on
    371  * the specified domain controller and obtain the appropriate SID.
    372  * The SID can then be used to open the account and obtain the
    373  * account privileges. The results from both the name lookup and the
    374  * privileges are returned in the user_info structure. The caller is
    375  * responsible for allocating and releasing this structure.
    376  *
    377  * On success 0 is returned. Otherwise a -ve error code.
    378  */
    379 /*ARGSUSED*/
    380 int
    381 lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo)
    382 {
    383 	mlsvc_handle_t domain_handle;
    384 	int rc;
    385 	smb_domainex_t dinfo;
    386 	char user[SMB_USERNAME_MAXLEN];
    387 
    388 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    389 
    390 	if (!smb_domain_getinfo(&dinfo))
    391 		return (-1);
    392 
    393 	if ((lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
    394 	    &domain_handle)) != 0)
    395 		return (-1);
    396 
    397 	rc = lsa_list_accounts(&domain_handle);
    398 	(void) lsar_close(&domain_handle);
    399 	return (rc);
    400 }
    401 
    402 /*
    403  * lsa_list_privs
    404  *
    405  * List the privileges supported by the specified server.
    406  * This function is only intended for diagnostics.
    407  *
    408  * Returns NT status codes.
    409  */
    410 DWORD
    411 lsa_list_privs(char *server, char *domain)
    412 {
    413 	static char name[128];
    414 	static struct ms_luid luid;
    415 	mlsvc_handle_t domain_handle;
    416 	int rc;
    417 	int i;
    418 	char user[SMB_USERNAME_MAXLEN];
    419 
    420 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    421 
    422 	rc = lsar_open(server, domain, user, &domain_handle);
    423 	if (rc != 0)
    424 		return (NT_STATUS_INVALID_PARAMETER);
    425 
    426 	for (i = 0; i < 30; ++i) {
    427 		luid.low_part = i;
    428 		rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
    429 		if (rc != 0)
    430 			continue;
    431 
    432 		(void) lsar_lookup_priv_value(&domain_handle, name, &luid);
    433 		(void) lsar_lookup_priv_display_name(&domain_handle, name,
    434 		    name, 128);
    435 	}
    436 
    437 	(void) lsar_close(&domain_handle);
    438 	return (NT_STATUS_SUCCESS);
    439 }
    440 
    441 /*
    442  * lsa_list_accounts
    443  *
    444  * This function can be used to list the accounts in the specified
    445  * domain. For now the SIDs are just listed in the system log.
    446  *
    447  * On success 0 is returned. Otherwise a -ve error code.
    448  */
    449 static int
    450 lsa_list_accounts(mlsvc_handle_t *domain_handle)
    451 {
    452 	mlsvc_handle_t account_handle;
    453 	struct mslsa_EnumAccountBuf accounts;
    454 	struct mslsa_sid *sid;
    455 	smb_account_t ainfo;
    456 	DWORD enum_context = 0;
    457 	int rc;
    458 	int i;
    459 
    460 	bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
    461 
    462 	do {
    463 		rc = lsar_enum_accounts(domain_handle, &enum_context,
    464 		    &accounts);
    465 		if (rc != 0)
    466 			return (rc);
    467 
    468 		for (i = 0; i < accounts.entries_read; ++i) {
    469 			sid = accounts.info[i].sid;
    470 
    471 			if (lsar_open_account(domain_handle, sid,
    472 			    &account_handle) == 0) {
    473 				(void) lsar_enum_privs_account(&account_handle,
    474 				    &ainfo);
    475 				(void) lsar_close(&account_handle);
    476 			}
    477 
    478 			free(accounts.info[i].sid);
    479 		}
    480 
    481 		if (accounts.info)
    482 			free(accounts.info);
    483 	} while (rc == 0 && accounts.entries_read != 0);
    484 
    485 	return (0);
    486 }
    487 
    488 /*
    489  * Lookup well known accounts table for the given SID
    490  *
    491  * Return status:
    492  *
    493  *   NT_STATUS_SUCCESS		Account is translated successfully
    494  *   NT_STATUS_NOT_FOUND	This is not a well known account
    495  *   NT_STATUS_NO_MEMORY	Memory shortage
    496  *   NT_STATUS_INTERNAL_ERROR	Internal error/unexpected failure
    497  */
    498 static uint32_t
    499 lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo)
    500 {
    501 	smb_wka_t *wka;
    502 	char *wkadom;
    503 
    504 	bzero(ainfo, sizeof (smb_account_t));
    505 
    506 	if ((wka = smb_wka_lookup_sid(sid)) == NULL)
    507 		return (NT_STATUS_NOT_FOUND);
    508 
    509 	if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
    510 		return (NT_STATUS_INTERNAL_ERROR);
    511 
    512 	ainfo->a_name = strdup(wka->wka_name);
    513 	ainfo->a_sid = smb_sid_dup(wka->wka_binsid);
    514 	ainfo->a_domain = strdup(wkadom);
    515 	ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid);
    516 	ainfo->a_type = wka->wka_type;
    517 
    518 	if (!smb_account_validate(ainfo)) {
    519 		smb_account_free(ainfo);
    520 		return (NT_STATUS_NO_MEMORY);
    521 	}
    522 
    523 	return (NT_STATUS_SUCCESS);
    524 }
    525 
    526 static uint32_t
    527 lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo)
    528 {
    529 	mlsvc_handle_t domain_handle;
    530 	uint32_t status;
    531 	smb_domainex_t dinfo;
    532 	char user[SMB_USERNAME_MAXLEN];
    533 
    534 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
    535 
    536 	if (!smb_domain_getinfo(&dinfo))
    537 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
    538 
    539 	if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
    540 	    &domain_handle) != 0)
    541 		return (NT_STATUS_INVALID_PARAMETER);
    542 
    543 	status = lsar_lookup_sids(&domain_handle, sid, ainfo);
    544 
    545 	(void) lsar_close(&domain_handle);
    546 	return (status);
    547 }
    548