1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/source4/libcli/util/clilsa.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

549 lines
12 KiB
C
Raw Normal View History

/*
Unix SMB/CIFS implementation.
lsa calls for file sharing connections
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
when dealing with ACLs the file sharing client code needs to
sometimes make LSA RPC calls. This code provides an easy interface
for doing those calls.
*/
#include "includes.h"
#include "libcli/raw/libcliraw.h"
#include "libcli/smb2/smb2.h"
#include "libcli/libcli.h"
#include "libcli/security/security.h"
#include "librpc/gen_ndr/ndr_lsa.h"
#include "librpc/gen_ndr/ndr_lsa_c.h"
#include "libcli/util/clilsa.h"
#include "libcli/smb/smbXcli_base.h"
struct smblsa_state {
struct dcerpc_binding_handle *binding_handle;
struct smbcli_tree *ipc_tree;
struct policy_handle handle;
};
/*
establish the lsa pipe connection
*/
static NTSTATUS smblsa_connect(struct smbcli_state *cli)
{
struct smblsa_state *lsa;
struct dcerpc_pipe *lsa_pipe;
NTSTATUS status;
struct lsa_OpenPolicy r;
uint16_t system_name = '\\';
union smb_tcon tcon;
struct lsa_ObjectAttribute attr;
struct lsa_QosInfo qos;
if (cli->lsa != NULL) {
return NT_STATUS_OK;
}
lsa = talloc(cli, struct smblsa_state);
if (lsa == NULL) {
return NT_STATUS_NO_MEMORY;
}
lsa->ipc_tree = smbcli_tree_init(cli->session, lsa, false);
if (lsa->ipc_tree == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* connect to IPC$ */
tcon.generic.level = RAW_TCON_TCONX;
tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
tcon.tconx.in.flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
tcon.tconx.in.password = data_blob(NULL, 0);
tcon.tconx.in.path = "ipc$";
tcon.tconx.in.device = "IPC";
status = smb_raw_tcon(lsa->ipc_tree, lsa, &tcon);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
lsa->ipc_tree->tid = tcon.tconx.out.tid;
if (tcon.tconx.out.options & SMB_EXTENDED_SIGNATURES) {
smb1cli_session_protect_session_key(cli->session->smbXcli);
}
lsa_pipe = dcerpc_pipe_init(lsa, cli->transport->ev);
if (lsa_pipe == NULL) {
talloc_free(lsa);
return NT_STATUS_NO_MEMORY;
}
/* open the LSA pipe */
status = dcerpc_pipe_open_smb(lsa_pipe, lsa->ipc_tree, NDR_LSARPC_NAME);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
/* bind to the LSA pipe */
status = dcerpc_bind_auth_none(lsa_pipe, &ndr_table_lsarpc);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
lsa->binding_handle = lsa_pipe->binding_handle;
/* open a lsa policy handle */
qos.len = 0;
qos.impersonation_level = 2;
qos.context_mode = 1;
qos.effective_only = 0;
attr.len = 0;
attr.root_dir = NULL;
attr.object_name = NULL;
attr.attributes = 0;
attr.sec_desc = NULL;
attr.sec_qos = &qos;
r.in.system_name = &system_name;
r.in.attr = &attr;
r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
r.out.handle = &lsa->handle;
status = dcerpc_lsa_OpenPolicy_r(lsa->binding_handle, lsa, &r);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
if (!NT_STATUS_IS_OK(r.out.result)) {
talloc_free(lsa);
return r.out.result;
}
cli->lsa = lsa;
return NT_STATUS_OK;
}
static NTSTATUS smb2lsa_connect(struct smb2_tree *tree)
{
struct smb2lsa_state *lsa = NULL;
struct dcerpc_pipe *lsa_pipe = NULL;
NTSTATUS status;
struct lsa_OpenPolicy2 r = {{0}, {0}};
const char *system_name = "\\";
struct lsa_ObjectAttribute attr = {0};
struct lsa_QosInfo qos = {0};
if (tree->lsa != NULL) {
return NT_STATUS_OK;
}
lsa = talloc(tree, struct smb2lsa_state);
if (lsa == NULL) {
return NT_STATUS_NO_MEMORY;
}
lsa_pipe = dcerpc_pipe_init(lsa, tree->session->transport->ev);
if (lsa_pipe == NULL) {
talloc_free(lsa);
return NT_STATUS_NO_MEMORY;
}
/* open the LSA pipe */
status = dcerpc_pipe_open_smb2(lsa_pipe, tree, NDR_LSARPC_NAME);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
/* bind to the LSA pipe */
status = dcerpc_bind_auth_none(lsa_pipe, &ndr_table_lsarpc);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
lsa->binding_handle = lsa_pipe->binding_handle;
/* open a lsa policy handle */
qos.len = 0;
qos.impersonation_level = 2;
qos.context_mode = 1;
qos.effective_only = 0;
attr.len = 0;
attr.root_dir = NULL;
attr.object_name = NULL;
attr.attributes = 0;
attr.sec_desc = NULL;
attr.sec_qos = &qos;
r.in.system_name = system_name;
r.in.attr = &attr;
r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
r.out.handle = &lsa->handle;
status = dcerpc_lsa_OpenPolicy2_r(lsa->binding_handle, lsa, &r);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lsa);
return status;
}
if (!NT_STATUS_IS_OK(r.out.result)) {
talloc_free(lsa);
return r.out.result;
}
tree->lsa = lsa;
return NT_STATUS_OK;
}
/*
return the set of privileges for the given sid
*/
NTSTATUS smblsa_sid_privileges(struct smbcli_state *cli, struct dom_sid *sid,
TALLOC_CTX *mem_ctx,
struct lsa_RightSet *rights)
{
NTSTATUS status;
struct lsa_EnumAccountRights r;
status = smblsa_connect(cli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r.in.handle = &cli->lsa->handle;
r.in.sid = sid;
r.out.rights = rights;
status = dcerpc_lsa_EnumAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return r.out.result;
}
NTSTATUS smb2lsa_sid_privileges(struct smb2_tree *tree, struct dom_sid *sid,
TALLOC_CTX *mem_ctx,
struct lsa_RightSet *rights)
{
NTSTATUS status;
struct lsa_EnumAccountRights r = {{0}, {0}};
status = smb2lsa_connect(tree);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r.in.handle = &tree->lsa->handle;
r.in.sid = sid;
r.out.rights = rights;
status = dcerpc_lsa_EnumAccountRights_r(tree->lsa->binding_handle, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return r.out.result;
}
/*
check if a named sid has a particular named privilege
*/
NTSTATUS smblsa_sid_check_privilege(struct smbcli_state *cli,
const char *sid_str,
const char *privilege)
{
struct lsa_RightSet rights;
NTSTATUS status;
TALLOC_CTX *mem_ctx = talloc_new(cli);
struct dom_sid *sid;
unsigned i;
sid = dom_sid_parse_talloc(mem_ctx, sid_str);
if (sid == NULL) {
talloc_free(mem_ctx);
return NT_STATUS_INVALID_SID;
}
status = smblsa_sid_privileges(cli, sid, mem_ctx, &rights);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(mem_ctx);
return status;
}
for (i=0;i<rights.count;i++) {
if (strcmp(rights.names[i].string, privilege) == 0) {
talloc_free(mem_ctx);
return NT_STATUS_OK;
}
}
talloc_free(mem_ctx);
return NT_STATUS_NOT_FOUND;
}
NTSTATUS smb2lsa_sid_check_privilege(struct smb2_tree *tree,
const char *sid_str,
const char *privilege)
{
struct lsa_RightSet rights = {0};
NTSTATUS status;
TALLOC_CTX *mem_ctx = NULL;
struct dom_sid *sid = NULL;
unsigned i;
mem_ctx = talloc_new(tree);
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
sid = dom_sid_parse_talloc(mem_ctx, sid_str);
if (sid == NULL) {
talloc_free(mem_ctx);
return NT_STATUS_INVALID_SID;
}
status = smb2lsa_sid_privileges(tree, sid, mem_ctx, &rights);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(mem_ctx);
return status;
}
for (i=0;i<rights.count;i++) {
if (strcmp(rights.names[i].string, privilege) == 0) {
talloc_free(mem_ctx);
return NT_STATUS_OK;
}
}
talloc_free(mem_ctx);
return NT_STATUS_NOT_FOUND;
}
/*
lookup a SID, returning its name
*/
NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli,
const char *sid_str,
TALLOC_CTX *mem_ctx,
const char **name)
{
struct lsa_LookupSids r;
struct lsa_TransNameArray names;
struct lsa_SidArray sids;
struct lsa_RefDomainList *domains = NULL;
uint32_t count = 1;
NTSTATUS status;
struct dom_sid *sid;
TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
status = smblsa_connect(cli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
sid = dom_sid_parse_talloc(mem_ctx2, sid_str);
if (sid == NULL) {
return NT_STATUS_INVALID_SID;
}
names.count = 0;
names.names = NULL;
sids.num_sids = 1;
sids.sids = talloc(mem_ctx2, struct lsa_SidPtr);
sids.sids[0].sid = sid;
r.in.handle = &cli->lsa->handle;
r.in.sids = &sids;
r.in.names = &names;
r.in.level = 1;
r.in.count = &count;
r.out.count = &count;
r.out.names = &names;
r.out.domains = &domains;
status = dcerpc_lsa_LookupSids_r(cli->lsa->binding_handle, mem_ctx2, &r);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(mem_ctx2);
return status;
}
if (!NT_STATUS_IS_OK(r.out.result)) {
talloc_free(mem_ctx2);
return r.out.result;
}
if (names.count != 1) {
talloc_free(mem_ctx2);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (domains == NULL) {
talloc_free(mem_ctx2);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (domains->count != 1) {
talloc_free(mem_ctx2);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (names.names[0].sid_index != UINT32_MAX &&
names.names[0].sid_index >= domains->count)
{
talloc_free(mem_ctx2);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
(*name) = talloc_asprintf(mem_ctx, "%s\\%s",
domains->domains[0].name.string,
names.names[0].name.string);
talloc_free(mem_ctx2);
return NT_STATUS_OK;
}
/*
lookup a name, returning its sid
*/
NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
const char *name,
TALLOC_CTX *mem_ctx,
const char **sid_str)
{
struct lsa_LookupNames r;
struct lsa_TransSidArray sids;
struct lsa_String names;
struct lsa_RefDomainList *domains = NULL;
uint32_t count = 1;
NTSTATUS status;
struct dom_sid sid;
TALLOC_CTX *mem_ctx2 = talloc_new(mem_ctx);
status = smblsa_connect(cli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
sids.count = 0;
sids.sids = NULL;
names.string = name;
r.in.handle = &cli->lsa->handle;
r.in.num_names = 1;
r.in.names = &names;
r.in.sids = &sids;
r.in.level = 1;
r.in.count = &count;
r.out.count = &count;
r.out.sids = &sids;
r.out.domains = &domains;
status = dcerpc_lsa_LookupNames_r(cli->lsa->binding_handle, mem_ctx2, &r);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(mem_ctx2);
return status;
}
if (!NT_STATUS_IS_OK(r.out.result)) {
talloc_free(mem_ctx2);
return r.out.result;
}
if (sids.count != 1) {
talloc_free(mem_ctx2);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
if (domains->count != 1) {
talloc_free(mem_ctx2);
return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
sid_compose(&sid, domains->domains[0].sid, sids.sids[0].rid);
(*sid_str) = dom_sid_string(mem_ctx, &sid);
talloc_free(mem_ctx2);
return NT_STATUS_OK;
}
/*
add a set of privileges to the given sid
*/
NTSTATUS smblsa_sid_add_privileges(struct smbcli_state *cli, struct dom_sid *sid,
TALLOC_CTX *mem_ctx,
struct lsa_RightSet *rights)
{
NTSTATUS status;
struct lsa_AddAccountRights r;
status = smblsa_connect(cli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r.in.handle = &cli->lsa->handle;
r.in.sid = sid;
r.in.rights = rights;
status = dcerpc_lsa_AddAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return r.out.result;
}
/*
remove a set of privileges from the given sid
*/
NTSTATUS smblsa_sid_del_privileges(struct smbcli_state *cli, struct dom_sid *sid,
TALLOC_CTX *mem_ctx,
struct lsa_RightSet *rights)
{
NTSTATUS status;
struct lsa_RemoveAccountRights r;
status = smblsa_connect(cli);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
r.in.handle = &cli->lsa->handle;
r.in.sid = sid;
2008-10-15 22:46:35 +04:00
r.in.remove_all = 0;
r.in.rights = rights;
status = dcerpc_lsa_RemoveAccountRights_r(cli->lsa->binding_handle, mem_ctx, &r);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return r.out.result;
}