2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Local Security Authority RPC (LSAR) client-side interface.
2N/A */
2N/A
2N/A#include <sys/errno.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A
2N/A#include <smbsrv/libsmb.h>
2N/A#include <smbsrv/libntsvcs.h>
2N/A#include <smbsrv/smbinfo.h>
2N/A#include <smb/smb.h>
2N/A#include <smbsrv/ntlocale.h>
2N/A#include <smbsrv/string.h>
2N/A#include <lsalib.h>
2N/A
2N/A/*
2N/A * The maximum number of bytes we are prepared to deal with in a
2N/A * response.
2N/A */
2N/A#define MLSVC_MAX_RESPONSE_LEN 1024
2N/A
2N/A/*
2N/A * This structure is used when looking up names. We only lookup one
2N/A * name at a time but the structure will allow for more.
2N/A */
2N/Atypedef struct lsa_names {
2N/A uint32_t n_entry;
2N/A mslsa_string_t name[8];
2N/A} lsa_names_t;
2N/A
2N/Atypedef DWORD (*lsar_nameop_t)(mlsvc_handle_t *, lsa_names_t *,
2N/A smb_account_t *);
2N/A
2N/Astatic uint32_t lsar_lookup_names1(mlsvc_handle_t *, lsa_names_t *,
2N/A smb_account_t *);
2N/Astatic uint32_t lsar_lookup_names2(mlsvc_handle_t *, lsa_names_t *,
2N/A smb_account_t *);
2N/Astatic uint32_t lsar_lookup_names3(mlsvc_handle_t *, lsa_names_t *,
2N/A smb_account_t *);
2N/Astatic uint32_t lsar_lookup_sids1(mlsvc_handle_t *, lsa_sid_t *,
2N/A smb_account_t *);
2N/Astatic uint32_t lsar_lookup_sids2(mlsvc_handle_t *, lsa_sid_t *,
2N/A smb_account_t *account);
2N/A
2N/Astatic char *lsar_get_username(const char *);
2N/Astatic void smb_account_trace(const smb_account_t *);
2N/A
2N/Astatic void lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *,
2N/A smb_trusted_domains_t *);
2N/Astatic void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *,
2N/A smb_trusted_domains_t *);
2N/A
2N/A/*
2N/A * Wrapper function for the actual LSA lookup operation.
2N/A *
2N/A * Upon detection of a DC failure, reports the failed DC to DC failover
2N/A * service and retries with a newly selected DC after DC failover completes.
2N/A */
2N/Auint32_t
2N/Alsar_lookup(lsar_lookup_op_t *op)
2N/A{
2N/A mlsvc_handle_t domain_handle;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A smb_domainex_t dinfo;
2N/A uint32_t status;
2N/A int i = 0;
2N/A boolean_t down_srv;
2N/A
2N/A if (op == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A if (op->l_func == NULL)
2N/A return (NT_STATUS_NOT_IMPLEMENTED);
2N/A
2N/A if (op->l_key == NULL || op->l_acct == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A do {
2N/A if (!smb_domain_getinfo(&dinfo))
2N/A return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
2N/A
2N/A errno = 0;
2N/A if (lsar_open(dinfo.d_dc, dinfo.d_primary.di_nbname, user,
2N/A &domain_handle) == 0) {
2N/A
2N/A errno = 0;
2N/A status = op->l_func(&domain_handle, op->l_key,
2N/A op->l_acct);
2N/A down_srv = ntsvcs_srv_down(errno);
2N/A
2N/A (void) lsar_close(&domain_handle);
2N/A
2N/A if (status == NT_STATUS_SUCCESS)
2N/A break;
2N/A
2N/A if (!down_srv)
2N/A break;
2N/A
2N/A } else {
2N/A if (!ntsvcs_srv_down(errno))
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A smb_dc_report_failure(dinfo.d_primary.di_fqname,
2N/A dinfo.d_dc);
2N/A status = NT_STATUS_HOST_UNREACHABLE;
2N/A }
2N/A
2N/A } while (i++ < SMB_MAX_DC_FAILURES);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Obtain an LSA policy handle using OpenPolicy2. A policy handle is
2N/A * required to access LSA resources on a remote server. The server
2N/A * name supplied does not need the double backslash prefix; it will
2N/A * be added here.
2N/A *
2N/A * If username is NULL, an anonymous connection will be established.
2N/A * Otherwise, an authenticated connection will be established.
2N/A *
2N/A * Returns 0 on success. Otherwise non-zero to indicate a failure.
2N/A */
2N/Aint
2N/Alsar_open(char *server, char *domain, char *username,
2N/A mlsvc_handle_t *lsa_handle)
2N/A{
2N/A struct mslsa_OpenPolicy2 arg;
2N/A int opnum;
2N/A int rc;
2N/A
2N/A rc = ndr_rpc_bind(lsa_handle, server, domain, username, "LSARPC");
2N/A if (rc != 0)
2N/A return (-1);
2N/A
2N/A opnum = LSARPC_OPNUM_OpenPolicy2;
2N/A bzero(&arg, sizeof (struct mslsa_OpenPolicy2));
2N/A
2N/A arg.servername = ndr_rpc_derive_nbhandle(lsa_handle, server);
2N/A if (arg.servername == NULL) {
2N/A ndr_rpc_unbind(lsa_handle);
2N/A return (-1);
2N/A }
2N/A
2N/A arg.attributes.length = sizeof (struct mslsa_object_attributes);
2N/A
2N/A if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) {
2N/A arg.desiredAccess = MAXIMUM_ALLOWED;
2N/A } else {
2N/A arg.desiredAccess = GENERIC_EXECUTE
2N/A | STANDARD_RIGHTS_EXECUTE
2N/A | POLICY_VIEW_LOCAL_INFORMATION
2N/A | POLICY_LOOKUP_NAMES;
2N/A }
2N/A
2N/A if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) {
2N/A ndr_rpc_unbind(lsa_handle);
2N/A return (-1);
2N/A }
2N/A
2N/A if (arg.status != 0) {
2N/A rc = -1;
2N/A } else {
2N/A (void) memcpy(&lsa_handle->handle, &arg.domain_handle,
2N/A sizeof (ndr_hdid_t));
2N/A
2N/A if (ndr_is_null_handle(lsa_handle))
2N/A rc = -1;
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A
2N/A if (rc != 0)
2N/A ndr_rpc_unbind(lsa_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_open_account
2N/A *
2N/A * Obtain an LSA account handle. The lsa_handle must be a valid handle
2N/A * obtained via lsar_open_policy2. The main thing to remember here is
2N/A * to set up the context in the lsa_account_handle. I'm not sure what
2N/A * the requirements are for desired access. Some values require admin
2N/A * access.
2N/A *
2N/A * Returns 0 on success. Otherwise non-zero to indicate a failure.
2N/A */
2N/Aint
2N/Alsar_open_account(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
2N/A mlsvc_handle_t *lsa_account_handle)
2N/A{
2N/A struct mslsa_OpenAccount arg;
2N/A int opnum;
2N/A int rc;
2N/A
2N/A if (ndr_is_null_handle(lsa_handle) || sid == NULL)
2N/A return (-1);
2N/A
2N/A opnum = LSARPC_OPNUM_OpenAccount;
2N/A bzero(&arg, sizeof (struct mslsa_OpenAccount));
2N/A
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.sid = sid;
2N/A arg.access_mask = STANDARD_RIGHTS_REQUIRED
2N/A#if 0
2N/A | POLICY_VIEW_AUDIT_INFORMATION
2N/A | POLICY_GET_PRIVATE_INFORMATION
2N/A | POLICY_TRUST_ADMIN
2N/A#endif
2N/A | POLICY_VIEW_LOCAL_INFORMATION;
2N/A
2N/A if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0)
2N/A return (-1);
2N/A
2N/A if (arg.status != 0) {
2N/A rc = -1;
2N/A } else {
2N/A ndr_inherit_handle(lsa_account_handle, lsa_handle);
2N/A
2N/A (void) memcpy(&lsa_account_handle->handle,
2N/A &arg.account_handle, sizeof (ndr_hdid_t));
2N/A
2N/A if (ndr_is_null_handle(lsa_account_handle))
2N/A rc = -1;
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_close
2N/A *
2N/A * Close the LSA connection associated with the handle. The lsa_handle
2N/A * must be a valid handle obtained via a call to lsar_open_policy2 or
2N/A * lsar_open_account. On success the handle will be zeroed out to
2N/A * ensure that it is not used again. If this is the top level handle
2N/A * (i.e. the one obtained via lsar_open_policy2) the pipe is closed.
2N/A *
2N/A * Returns 0 on success. Otherwise non-zero to indicate a failure.
2N/A */
2N/Aint
2N/Alsar_close(mlsvc_handle_t *lsa_handle)
2N/A{
2N/A struct mslsa_CloseHandle arg;
2N/A int opnum;
2N/A
2N/A if (ndr_is_null_handle(lsa_handle))
2N/A return (-1);
2N/A
2N/A opnum = LSARPC_OPNUM_CloseHandle;
2N/A bzero(&arg, sizeof (struct mslsa_CloseHandle));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A
2N/A (void) ndr_rpc_call(lsa_handle, opnum, &arg);
2N/A ndr_rpc_release(lsa_handle);
2N/A
2N/A if (ndr_is_bind_handle(lsa_handle))
2N/A ndr_rpc_unbind(lsa_handle);
2N/A
2N/A bzero(lsa_handle, sizeof (mlsvc_handle_t));
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * lsar_query_security_desc
2N/A *
2N/A * Don't use this call yet. It is just a place holder for now.
2N/A */
2N/Aint
2N/Alsar_query_security_desc(mlsvc_handle_t *lsa_handle)
2N/A{
2N/A struct mslsa_QuerySecurityObject arg;
2N/A int rc;
2N/A int opnum;
2N/A
2N/A opnum = LSARPC_OPNUM_QuerySecurityObject;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_QuerySecurityObject));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A
2N/A rc = ndr_rpc_call(lsa_handle, opnum, &arg);
2N/A ndr_rpc_release(lsa_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_query_info_policy
2N/A *
2N/A * The general purpose of this function is to allow various pieces of
2N/A * information to be queried on the domain controller. The only
2N/A * information queries supported are MSLSA_POLICY_PRIMARY_DOMAIN_INFO
2N/A * and MSLSA_POLICY_ACCOUNT_DOMAIN_INFO.
2N/A *
2N/A * On success, the return code will be 0 and the user_info structure
2N/A * will be set up. The sid_name_use field will be set to SidTypeDomain
2N/A * indicating that the domain name and domain sid fields are vaild. If
2N/A * the infoClass returned from the server is not one of the supported
2N/A * values, the sid_name_use willbe set to SidTypeUnknown. If the RPC
2N/A * fails, a negative error code will be returned, in which case the
2N/A * user_info will not have been updated.
2N/A */
2N/ADWORD
2N/Alsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass,
2N/A smb_domain_t *info)
2N/A{
2N/A struct mslsa_QueryInfoPolicy arg;
2N/A struct mslsa_PrimaryDomainInfo *pd_info;
2N/A struct mslsa_AccountDomainInfo *ad_info;
2N/A struct mslsa_DnsDomainInfo *dns_info;
2N/A char guid_str[UUID_PRINTABLE_STRING_LENGTH];
2N/A char sidstr[SMB_SID_STRSZ];
2N/A int opnum;
2N/A DWORD status;
2N/A
2N/A if (lsa_handle == NULL || info == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A opnum = LSARPC_OPNUM_QueryInfoPolicy;
2N/A
2N/A bzero(info, sizeof (smb_domain_t));
2N/A bzero(&arg, sizeof (struct mslsa_QueryInfoPolicy));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A
2N/A arg.info_class = infoClass;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A status = NT_STATUS_INVALID_PARAMETER;
2N/A } else if (arg.status != 0) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A status = NT_SC_VALUE(arg.status);
2N/A } else {
2N/A
2N/A switch (infoClass) {
2N/A case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
2N/A pd_info = &arg.ru.pd_info;
2N/A
2N/A smb_sid_tostr((smb_sid_t *)pd_info->sid, sidstr);
2N/A info->di_type = SMB_DOMAIN_PRIMARY;
2N/A smb_domain_set_basic_info(sidstr,
2N/A (char *)pd_info->name.str, "", info);
2N/A
2N/A status = NT_STATUS_SUCCESS;
2N/A break;
2N/A
2N/A case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
2N/A ad_info = &arg.ru.ad_info;
2N/A
2N/A smb_sid_tostr((smb_sid_t *)ad_info->sid, sidstr);
2N/A info->di_type = SMB_DOMAIN_ACCOUNT;
2N/A smb_domain_set_basic_info(sidstr,
2N/A (char *)ad_info->name.str, "", info);
2N/A
2N/A status = NT_STATUS_SUCCESS;
2N/A break;
2N/A
2N/A case MSLSA_POLICY_DNS_DOMAIN_INFO:
2N/A dns_info = &arg.ru.dns_info;
2N/A ndr_uuid_unparse((ndr_uuid_t *)&dns_info->guid,
2N/A guid_str);
2N/A smb_sid_tostr((smb_sid_t *)dns_info->sid, sidstr);
2N/A
2N/A info->di_type = SMB_DOMAIN_PRIMARY;
2N/A smb_domain_set_dns_info(sidstr,
2N/A (char *)dns_info->nb_domain.str,
2N/A (char *)dns_info->dns_domain.str,
2N/A (char *)dns_info->forest.str,
2N/A guid_str, info);
2N/A status = NT_STATUS_SUCCESS;
2N/A break;
2N/A
2N/A default:
2N/A status = NT_STATUS_INVALID_INFO_CLASS;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Lookup a name and obtain the sid/rid.
2N/A * This is a wrapper for the various lookup sid RPCs.
2N/A */
2N/Auint32_t
2N/Alsar_lookup_names(mlsvc_handle_t *lsa_handle, void *key, smb_account_t *info)
2N/A{
2N/A static lsar_nameop_t ops[] = {
2N/A lsar_lookup_names3,
2N/A lsar_lookup_names2,
2N/A lsar_lookup_names1
2N/A };
2N/A
2N/A const srvsvc_server_info_t *svinfo;
2N/A lsa_names_t names;
2N/A char *p;
2N/A uint32_t length;
2N/A uint32_t status = NT_STATUS_INVALID_PARAMETER;
2N/A int n_op = (sizeof (ops) / sizeof (ops[0]));
2N/A int i;
2N/A char *name = (char *)key;
2N/A
2N/A if (lsa_handle == NULL || name == NULL || info == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A bzero(info, sizeof (smb_account_t));
2N/A
2N/A svinfo = ndr_rpc_server_info(lsa_handle);
2N/A if (svinfo->sv_os == NATIVE_OS_WIN2000 &&
2N/A svinfo->sv_version_major == 5 && svinfo->sv_version_minor == 0) {
2N/A /*
2N/A * Windows 2000 doesn't like an LSA lookup for
2N/A * DOMAIN\Administrator.
2N/A */
2N/A if ((p = strchr(name, '\\')) != 0) {
2N/A ++p;
2N/A
2N/A if (strcasecmp(p, "administrator") == 0)
2N/A name = p;
2N/A }
2N/A
2N/A }
2N/A
2N/A length = smb_wcequiv_strlen(name);
2N/A names.name[0].length = length;
2N/A names.name[0].allosize = length;
2N/A names.name[0].str = (unsigned char *)name;
2N/A names.n_entry = 1;
2N/A
2N/A if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) {
2N/A for (i = 0; i < n_op; ++i) {
2N/A ndr_rpc_set_nonull(lsa_handle);
2N/A status = (*ops[i])(lsa_handle, &names, info);
2N/A
2N/A if (status != NT_STATUS_INVALID_PARAMETER)
2N/A break;
2N/A }
2N/A } else {
2N/A ndr_rpc_set_nonull(lsa_handle);
2N/A status = lsar_lookup_names1(lsa_handle, &names, info);
2N/A }
2N/A
2N/A if (status == NT_STATUS_SUCCESS) {
2N/A info->a_name = lsar_get_username(name);
2N/A
2N/A if (!smb_account_validate(info)) {
2N/A smb_account_free(info);
2N/A status = NT_STATUS_NO_MEMORY;
2N/A } else {
2N/A smb_account_trace(info);
2N/A }
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * The name may be in one of the following forms:
2N/A *
2N/A * domain\username
2N/A * domain/username
2N/A * username
2N/A * username@domain
2N/A *
2N/A * Return a strdup'd copy of the username. The caller is responsible
2N/A * for freeing the allocated memory.
2N/A */
2N/Astatic char *
2N/Alsar_get_username(const char *name)
2N/A{
2N/A char tmp[MAXNAMELEN];
2N/A char *dp = NULL;
2N/A char *np = NULL;
2N/A
2N/A (void) strlcpy(tmp, name, MAXNAMELEN);
2N/A smb_name_parse(tmp, &np, &dp);
2N/A
2N/A if (dp != NULL && np != NULL)
2N/A return (strdup(np));
2N/A else
2N/A return (strdup(name));
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_names1
2N/A *
2N/A * Lookup a name and obtain the domain and user rid.
2N/A *
2N/A * Note: NT returns an error if the mapped_count is non-zero when the RPC
2N/A * is called.
2N/A *
2N/A * If the lookup fails, the status will typically be NT_STATUS_NONE_MAPPED.
2N/A */
2N/Astatic uint32_t
2N/Alsar_lookup_names1(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
2N/A smb_account_t *info)
2N/A{
2N/A struct mslsa_LookupNames arg;
2N/A struct mslsa_rid_entry *rid_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *domname;
2N/A int opnum = LSARPC_OPNUM_LookupNames;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_LookupNames));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A arg.name_table = (struct mslsa_lup_name_table *)names;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A rid_entry = &arg.translated_sids.rids[0];
2N/A if (rid_entry->domain_index != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A
2N/A info->a_type = rid_entry->sid_name_use;
2N/A info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A if ((domname = (char *)domain_entry->domain_name.str) != NULL)
2N/A info->a_domain = strdup(domname);
2N/A info->a_rid = rid_entry->rid;
2N/A info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_names2
2N/A */
2N/Astatic uint32_t
2N/Alsar_lookup_names2(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
2N/A smb_account_t *info)
2N/A{
2N/A struct lsar_LookupNames2 arg;
2N/A struct lsar_rid_entry2 *rid_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *domname;
2N/A int opnum = LSARPC_OPNUM_LookupNames2;
2N/A
2N/A bzero(&arg, sizeof (struct lsar_LookupNames2));
2N/A (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A arg.client_revision = LSA_CLIENT_REVISION_AD;
2N/A arg.name_table = (struct mslsa_lup_name_table *)names;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A rid_entry = &arg.translated_sids.rids[0];
2N/A if (rid_entry->domain_index != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A
2N/A info->a_type = rid_entry->sid_name_use;
2N/A info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A if ((domname = (char *)domain_entry->domain_name.str) != NULL)
2N/A info->a_domain = strdup(domname);
2N/A info->a_rid = rid_entry->rid;
2N/A info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_names3
2N/A */
2N/Astatic uint32_t
2N/Alsar_lookup_names3(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
2N/A smb_account_t *info)
2N/A{
2N/A struct lsar_LookupNames3 arg;
2N/A lsar_translated_sid_ex2_t *sid_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *domname;
2N/A int opnum = LSARPC_OPNUM_LookupNames3;
2N/A
2N/A bzero(&arg, sizeof (struct lsar_LookupNames3));
2N/A (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A arg.client_revision = LSA_CLIENT_REVISION_AD;
2N/A arg.name_table = (struct mslsa_lup_name_table *)names;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A sid_entry = &arg.translated_sids.sids[0];
2N/A if (sid_entry->domain_index != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A
2N/A info->a_type = sid_entry->sid_name_use;
2N/A info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A if ((domname = (char *)domain_entry->domain_name.str) != NULL)
2N/A info->a_domain = strdup(domname);
2N/A info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
2N/A (void) smb_sid_getrid(info->a_sid, &info->a_rid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_names4
2N/A *
2N/A * This function is only valid if the remote RPC server is a domain
2N/A * controller and requires the security extensions defined in MS-RPCE.
2N/A *
2N/A * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
2N/A * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
2N/A * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
2N/A */
2N/Astatic uint32_t /*LINTED E_STATIC_UNUSED*/
2N/Alsar_lookup_names4(mlsvc_handle_t *lsa_handle, lsa_names_t *names,
2N/A smb_account_t *info)
2N/A{
2N/A struct lsar_LookupNames4 arg;
2N/A lsar_translated_sid_ex2_t *sid_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *domname;
2N/A int opnum = LSARPC_OPNUM_LookupNames4;
2N/A
2N/A bzero(&arg, sizeof (struct lsar_LookupNames4));
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A arg.client_revision = LSA_CLIENT_REVISION_AD;
2N/A arg.name_table = (struct mslsa_lup_name_table *)names;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
2N/A arg.status == NT_STATUS_INVALID_SERVER_STATE)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A sid_entry = &arg.translated_sids.sids[0];
2N/A if (sid_entry->domain_index != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A
2N/A info->a_type = sid_entry->sid_name_use;
2N/A info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A if ((domname = (char *)domain_entry->domain_name.str) != NULL)
2N/A info->a_domain = strdup(domname);
2N/A info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid);
2N/A (void) smb_sid_getrid(info->a_sid, &info->a_rid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Lookup a sid and obtain the domain sid and account name.
2N/A * This is a wrapper for the various lookup sid RPCs.
2N/A */
2N/Auint32_t
2N/Alsar_lookup_sids(mlsvc_handle_t *lsa_handle, void *key, smb_account_t *account)
2N/A{
2N/A char sidbuf[SMB_SID_STRSZ];
2N/A uint32_t status;
2N/A smb_sid_t *sid = (smb_sid_t *)key;
2N/A
2N/A if (lsa_handle == NULL || sid == NULL || account == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A bzero(account, sizeof (smb_account_t));
2N/A bzero(sidbuf, SMB_SID_STRSZ);
2N/A smb_sid_tostr(sid, sidbuf);
2N/A smb_tracef("%s", sidbuf);
2N/A
2N/A if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000)
2N/A status = lsar_lookup_sids2(lsa_handle, (lsa_sid_t *)sid,
2N/A account);
2N/A else
2N/A status = lsar_lookup_sids1(lsa_handle, (lsa_sid_t *)sid,
2N/A account);
2N/A
2N/A if (status == NT_STATUS_SUCCESS) {
2N/A if (!smb_account_validate(account)) {
2N/A smb_account_free(account);
2N/A status = NT_STATUS_NO_MEMORY;
2N/A } else {
2N/A smb_account_trace(account);
2N/A }
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_sids1
2N/A */
2N/Astatic uint32_t
2N/Alsar_lookup_sids1(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
2N/A smb_account_t *account)
2N/A{
2N/A struct mslsa_LookupSids arg;
2N/A struct mslsa_lup_sid_entry sid_entry;
2N/A struct mslsa_name_entry *name_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *name;
2N/A int opnum = LSARPC_OPNUM_LookupSids;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_LookupSids));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A
2N/A sid_entry.psid = sid;
2N/A arg.lup_sid_table.n_entry = 1;
2N/A arg.lup_sid_table.entries = &sid_entry;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A name_entry = &arg.name_table.entries[0];
2N/A if (name_entry->domain_ix != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A name = (char *)name_entry->name.str;
2N/A account->a_name = (name) ? strdup(name) : strdup("");
2N/A account->a_type = name_entry->sid_name_use;
2N/A account->a_sid = smb_sid_dup((smb_sid_t *)sid);
2N/A (void) smb_sid_getrid(account->a_sid, &account->a_rid);
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A if ((name = (char *)domain_entry->domain_name.str) != NULL)
2N/A account->a_domain = strdup(name);
2N/A account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_sids2
2N/A */
2N/Astatic uint32_t
2N/Alsar_lookup_sids2(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
2N/A smb_account_t *account)
2N/A{
2N/A struct lsar_lookup_sids2 arg;
2N/A struct lsar_name_entry2 *name_entry;
2N/A struct mslsa_lup_sid_entry sid_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *name;
2N/A int opnum = LSARPC_OPNUM_LookupSids2;
2N/A
2N/A bzero(&arg, sizeof (struct lsar_lookup_sids2));
2N/A (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A
2N/A sid_entry.psid = sid;
2N/A arg.lup_sid_table.n_entry = 1;
2N/A arg.lup_sid_table.entries = &sid_entry;
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A arg.client_revision = LSA_CLIENT_REVISION_AD;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A name_entry = &arg.name_table.entries[0];
2N/A if (name_entry->domain_ix != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A name = (char *)name_entry->name.str;
2N/A account->a_name = (name) ? strdup(name) : strdup("");
2N/A account->a_type = name_entry->sid_name_use;
2N/A account->a_sid = smb_sid_dup((smb_sid_t *)sid);
2N/A (void) smb_sid_getrid(account->a_sid, &account->a_rid);
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A if ((name = (char *)domain_entry->domain_name.str) != NULL)
2N/A account->a_domain = strdup(name);
2N/A account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_sids3
2N/A *
2N/A * This function is only valid if the remote RPC server is a domain
2N/A * controller and requires the security extensions defined in MS-RPCE.
2N/A *
2N/A * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here
2N/A * because we don't support the RPC_C_AUTHN_NETLOGON security provider.
2N/A * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE.
2N/A */
2N/Astatic uint32_t /*LINTED E_STATIC_UNUSED*/
2N/Alsar_lookup_sids3(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid,
2N/A smb_account_t *account)
2N/A{
2N/A struct lsar_lookup_sids3 arg;
2N/A lsar_translated_name_ex_t *name_entry;
2N/A struct mslsa_lup_sid_entry sid_entry;
2N/A struct mslsa_domain_entry *domain_entry;
2N/A uint32_t status = NT_STATUS_SUCCESS;
2N/A char *name;
2N/A int opnum = LSARPC_OPNUM_LookupSids3;
2N/A
2N/A bzero(&arg, sizeof (struct lsar_lookup_sids3));
2N/A
2N/A sid_entry.psid = sid;
2N/A arg.lup_sid_table.n_entry = 1;
2N/A arg.lup_sid_table.entries = &sid_entry;
2N/A arg.lookup_level = LSA_LOOKUP_WKSTA;
2N/A arg.client_revision = LSA_CLIENT_REVISION_AD;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A }
2N/A
2N/A if (arg.status != NT_STATUS_SUCCESS) {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A ndr_rpc_release(lsa_handle);
2N/A if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED ||
2N/A arg.status == NT_STATUS_INVALID_SERVER_STATE)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A return (NT_SC_VALUE(arg.status));
2N/A }
2N/A
2N/A if (arg.mapped_count == 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A name_entry = &arg.name_table.entries[0];
2N/A if (name_entry->domain_ix != 0) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (NT_STATUS_NONE_MAPPED);
2N/A }
2N/A
2N/A name = (char *)name_entry->name.str;
2N/A account->a_name = (name) ? strdup(name) : strdup("");
2N/A account->a_type = name_entry->sid_name_use;
2N/A account->a_sid = smb_sid_dup((smb_sid_t *)sid);
2N/A (void) smb_sid_getrid(account->a_sid, &account->a_rid);
2N/A
2N/A domain_entry = &arg.domain_table->entries[0];
2N/A if ((name = (char *)domain_entry->domain_name.str) != NULL)
2N/A account->a_domain = strdup(name);
2N/A account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_enum_accounts
2N/A *
2N/A * Enumerate the list of accounts (i.e. SIDs). Use the handle returned
2N/A * from lsa_open_policy2. The enum_context is used to support multiple
2N/A * calls to this enumeration function. It should be set to 0 on the
2N/A * first call. It will be updated by the domain controller and should
2N/A * simply be passed unchanged to subsequent calls until there are no
2N/A * more accounts. A warning status of 0x1A indicates that no more data
2N/A * is available. The list of accounts will be returned in accounts.
2N/A * This list is dynamically allocated using malloc, it should be freed
2N/A * by the caller when it is no longer required.
2N/A */
2N/Aint
2N/Alsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
2N/A struct mslsa_EnumAccountBuf *accounts)
2N/A{
2N/A struct mslsa_EnumerateAccounts arg;
2N/A struct mslsa_AccountInfo *info;
2N/A int opnum;
2N/A int rc;
2N/A DWORD n_entries;
2N/A DWORD i;
2N/A int nbytes;
2N/A
2N/A if (lsa_handle == NULL || enum_context == NULL || accounts == NULL)
2N/A return (-1);
2N/A
2N/A accounts->entries_read = 0;
2N/A accounts->info = 0;
2N/A
2N/A opnum = LSARPC_OPNUM_EnumerateAccounts;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_EnumerateAccounts));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.enum_context = *enum_context;
2N/A arg.max_length = MLSVC_MAX_RESPONSE_LEN;
2N/A
2N/A rc = ndr_rpc_call(lsa_handle, opnum, &arg);
2N/A if (rc == 0) {
2N/A if (arg.status != 0) {
2N/A if (arg.status == NT_STATUS_NO_MORE_ENTRIES) {
2N/A *enum_context = arg.enum_context;
2N/A } else {
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A rc = -1;
2N/A }
2N/A } else if (arg.enum_buf->entries_read != 0) {
2N/A n_entries = arg.enum_buf->entries_read;
2N/A nbytes = n_entries * sizeof (struct mslsa_AccountInfo);
2N/A
2N/A if ((info = malloc(nbytes)) == NULL) {
2N/A ndr_rpc_release(lsa_handle);
2N/A return (-1);
2N/A }
2N/A
2N/A for (i = 0; i < n_entries; ++i)
2N/A info[i].sid = (lsa_sid_t *)smb_sid_dup(
2N/A (smb_sid_t *)arg.enum_buf->info[i].sid);
2N/A
2N/A accounts->entries_read = n_entries;
2N/A accounts->info = info;
2N/A *enum_context = arg.enum_context;
2N/A }
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_enum_trusted_domains
2N/A *
2N/A * Enumerate the list of trusted domains. Use the handle returned from
2N/A * lsa_open_policy2. The enum_context is used to support multiple calls
2N/A * to this enumeration function. It should be set to 0 on the first
2N/A * call. It will be updated by the domain controller and should simply
2N/A * be passed unchanged to subsequent calls until there are no more
2N/A * domains.
2N/A *
2N/A * The trusted domains aren't actually returned here. They are added
2N/A * to the NT domain database. After all of the trusted domains have
2N/A * been discovered, the database can be interrogated to find all of
2N/A * the trusted domains.
2N/A */
2N/ADWORD
2N/Alsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
2N/A smb_trusted_domains_t *list)
2N/A{
2N/A struct mslsa_EnumTrustedDomain arg;
2N/A int opnum;
2N/A DWORD status;
2N/A
2N/A if (list == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A opnum = LSARPC_OPNUM_EnumTrustedDomain;
2N/A
2N/A bzero(list, sizeof (smb_trusted_domains_t));
2N/A bzero(&arg, sizeof (struct mslsa_EnumTrustedDomain));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.enum_context = *enum_context;
2N/A arg.max_length = MLSVC_MAX_RESPONSE_LEN;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A status = NT_STATUS_INVALID_PARAMETER;
2N/A } else if (arg.status != 0) {
2N/A *enum_context = arg.enum_context;
2N/A status = NT_SC_VALUE(arg.status);
2N/A
2N/A /*
2N/A * STATUS_NO_MORE_ENTRIES provides call
2N/A * status but does not indicate an error.
2N/A */
2N/A if (status != NT_STATUS_NO_MORE_ENTRIES)
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A } else if (arg.enum_buf->entries_read == 0) {
2N/A *enum_context = arg.enum_context;
2N/A status = 0;
2N/A } else {
2N/A lsar_set_trusted_domains(arg.enum_buf, list);
2N/A *enum_context = arg.enum_context;
2N/A status = 0;
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/ADWORD
2N/Alsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
2N/A smb_trusted_domains_t *list)
2N/A{
2N/A struct mslsa_EnumTrustedDomainEx arg;
2N/A int opnum;
2N/A DWORD status;
2N/A
2N/A if (list == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A opnum = LSARPC_OPNUM_EnumTrustedDomainsEx;
2N/A
2N/A bzero(list, sizeof (smb_trusted_domains_t));
2N/A bzero(&arg, sizeof (struct mslsa_EnumTrustedDomainEx));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A arg.enum_context = *enum_context;
2N/A arg.max_length = MLSVC_MAX_RESPONSE_LEN;
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
2N/A status = NT_STATUS_INVALID_PARAMETER;
2N/A } else if (arg.status != 0) {
2N/A *enum_context = arg.enum_context;
2N/A status = NT_SC_VALUE(arg.status);
2N/A
2N/A /*
2N/A * STATUS_NO_MORE_ENTRIES provides call
2N/A * status but does not indicate an error.
2N/A */
2N/A if (status != NT_STATUS_NO_MORE_ENTRIES)
2N/A ndr_rpc_status(lsa_handle, opnum, arg.status);
2N/A } else if (arg.enum_buf->entries_read == 0) {
2N/A *enum_context = arg.enum_context;
2N/A status = 0;
2N/A } else {
2N/A lsar_set_trusted_domains_ex(arg.enum_buf, list);
2N/A *enum_context = arg.enum_context;
2N/A status = 0;
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * lsar_enum_privs_account
2N/A *
2N/A * Privileges enum? Need an account handle.
2N/A */
2N/A/*ARGSUSED*/
2N/Aint
2N/Alsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account)
2N/A{
2N/A struct mslsa_EnumPrivsAccount arg;
2N/A int opnum;
2N/A int rc;
2N/A
2N/A opnum = LSARPC_OPNUM_EnumPrivsAccount;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_EnumPrivsAccount));
2N/A (void) memcpy(&arg.account_handle, &account_handle->handle,
2N/A sizeof (mslsa_handle_t));
2N/A
2N/A rc = ndr_rpc_call(account_handle, opnum, &arg);
2N/A if ((rc == 0) && (arg.status != 0)) {
2N/A ndr_rpc_status(account_handle, opnum, arg.status);
2N/A rc = -1;
2N/A }
2N/A ndr_rpc_release(account_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_priv_value
2N/A *
2N/A * Map a privilege name to a local unique id (LUID). Privilege names
2N/A * are consistent across the network. LUIDs are machine specific.
2N/A * This function provides the means to map a privilege name to the
2N/A * LUID used by a remote server to represent it. The handle here is
2N/A * a policy handle.
2N/A */
2N/Aint
2N/Alsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name,
2N/A struct ms_luid *luid)
2N/A{
2N/A struct mslsa_LookupPrivValue arg;
2N/A int opnum;
2N/A int rc;
2N/A size_t length;
2N/A
2N/A if (lsa_handle == NULL || name == NULL || luid == NULL)
2N/A return (-1);
2N/A
2N/A opnum = LSARPC_OPNUM_LookupPrivValue;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_LookupPrivValue));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A
2N/A length = smb_wcequiv_strlen(name);
2N/A if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000)
2N/A length += sizeof (smb_wchar_t);
2N/A
2N/A arg.name.length = length;
2N/A arg.name.allosize = length;
2N/A arg.name.str = (unsigned char *)name;
2N/A
2N/A rc = ndr_rpc_call(lsa_handle, opnum, &arg);
2N/A if (rc == 0) {
2N/A if (arg.status != 0)
2N/A rc = -1;
2N/A else
2N/A (void) memcpy(luid, &arg.luid, sizeof (struct ms_luid));
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_priv_name
2N/A *
2N/A * Map a local unique id (LUID) to a privilege name. Privilege names
2N/A * are consistent across the network. LUIDs are machine specific.
2N/A * This function the means to map the LUID used by a remote server to
2N/A * the appropriate privilege name. The handle here is a policy handle.
2N/A */
2N/Aint
2N/Alsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, struct ms_luid *luid,
2N/A char *name, int namelen)
2N/A{
2N/A struct mslsa_LookupPrivName arg;
2N/A int opnum;
2N/A int rc;
2N/A
2N/A if (lsa_handle == NULL || luid == NULL || name == NULL)
2N/A return (-1);
2N/A
2N/A opnum = LSARPC_OPNUM_LookupPrivName;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_LookupPrivName));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A (void) memcpy(&arg.luid, luid, sizeof (struct ms_luid));
2N/A
2N/A rc = ndr_rpc_call(lsa_handle, opnum, &arg);
2N/A if (rc == 0) {
2N/A if (arg.status != 0)
2N/A rc = -1;
2N/A else
2N/A (void) strlcpy(name, (char const *)arg.name->str,
2N/A namelen);
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * lsar_lookup_priv_display_name
2N/A *
2N/A * Map a privilege name to a privilege display name. The input handle
2N/A * should be an LSA policy handle and the name would normally be one
2N/A * of the privileges defined in smb_privilege.h
2N/A *
2N/A * There's something peculiar about the return status from NT servers,
2N/A * it's not always present. So for now, I'm ignoring the status in the
2N/A * RPC response.
2N/A *
2N/A * Returns NT status codes.
2N/A */
2N/ADWORD
2N/Alsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name,
2N/A char *display_name, int display_len)
2N/A{
2N/A struct mslsa_LookupPrivDisplayName arg;
2N/A int opnum;
2N/A size_t length;
2N/A DWORD status;
2N/A
2N/A if (lsa_handle == NULL || name == NULL || display_name == NULL)
2N/A return (NT_STATUS_INVALID_PARAMETER);
2N/A
2N/A opnum = LSARPC_OPNUM_LookupPrivDisplayName;
2N/A
2N/A bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName));
2N/A (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
2N/A
2N/A length = smb_wcequiv_strlen(name);
2N/A arg.name.length = length;
2N/A arg.name.allosize = length;
2N/A arg.name.str = (unsigned char *)name;
2N/A
2N/A arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
2N/A arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
2N/A
2N/A if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0)
2N/A status = NT_STATUS_INVALID_PARAMETER;
2N/A#if 0
2N/A else if (arg.status != 0)
2N/A status = NT_SC_VALUE(arg.status);
2N/A#endif
2N/A else {
2N/A (void) strlcpy(display_name,
2N/A (char const *)arg.display_name->str, display_len);
2N/A status = NT_STATUS_SUCCESS;
2N/A }
2N/A
2N/A ndr_rpc_release(lsa_handle);
2N/A return (status);
2N/A}
2N/A
2N/Astatic void
2N/Alsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *enum_buf,
2N/A smb_trusted_domains_t *list)
2N/A{
2N/A char sidstr[SMB_SID_STRSZ];
2N/A int i;
2N/A
2N/A if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
2N/A return;
2N/A
2N/A list->td_num = 0;
2N/A list->td_domains = calloc(enum_buf->entries_read,
2N/A sizeof (smb_domain_t));
2N/A
2N/A if (list->td_domains == NULL)
2N/A return;
2N/A
2N/A list->td_num = enum_buf->entries_read;
2N/A for (i = 0; i < list->td_num; i++) {
2N/A smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
2N/A smb_domain_set_trust_info(
2N/A sidstr,
2N/A (char *)enum_buf->info[i].nb_name.str,
2N/A (char *)enum_buf->info[i].dns_name.str,
2N/A enum_buf->info[i].trust_direction,
2N/A enum_buf->info[i].trust_type,
2N/A enum_buf->info[i].trust_attrs,
2N/A &list->td_domains[i]);
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Alsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf,
2N/A smb_trusted_domains_t *list)
2N/A{
2N/A char sidstr[SMB_SID_STRSZ];
2N/A int i;
2N/A
2N/A if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
2N/A return;
2N/A
2N/A list->td_num = 0;
2N/A list->td_domains = calloc(enum_buf->entries_read,
2N/A sizeof (smb_domain_t));
2N/A
2N/A if (list->td_domains == NULL)
2N/A return;
2N/A
2N/A list->td_num = enum_buf->entries_read;
2N/A for (i = 0; i < list->td_num; i++) {
2N/A smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
2N/A smb_domain_set_trust_info(
2N/A sidstr, (char *)enum_buf->info[i].name.str,
2N/A "", 0, 0, 0, &list->td_domains[i]);
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Asmb_account_trace(const smb_account_t *info)
2N/A{
2N/A char sidbuf[SMB_SID_STRSZ];
2N/A
2N/A bzero(sidbuf, SMB_SID_STRSZ);
2N/A smb_sid_tostr(info->a_sid, sidbuf);
2N/A
2N/A smb_tracef("%s %s %s %lu %s", info->a_domain, info->a_name,
2N/A sidbuf, info->a_rid, smb_sid_type2str(info->a_type));
2N/A}