2004-12-06 10:12:38 +03:00
/*
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-12-06 10:12:38 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-12-06 10:12:38 +03:00
*/
/*
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"
2019-12-21 00:10:49 +03:00
# include "libcli/smb2/smb2.h"
2006-01-03 18:40:05 +03:00
# include "libcli/libcli.h"
2006-04-02 16:02:01 +04:00
# include "libcli/security/security.h"
2006-03-16 15:43:28 +03:00
# include "librpc/gen_ndr/ndr_lsa.h"
2006-03-15 02:35:30 +03:00
# include "librpc/gen_ndr/ndr_lsa_c.h"
2007-09-08 17:27:14 +04:00
# include "libcli/util/clilsa.h"
2012-08-02 10:51:13 +04:00
# include "libcli/smb/smbXcli_base.h"
2004-12-06 10:12:38 +03:00
struct smblsa_state {
2014-01-16 11:57:30 +04:00
struct dcerpc_binding_handle * binding_handle ;
2004-12-06 10:12:38 +03:00
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 ;
2014-01-16 11:57:30 +04:00
struct dcerpc_pipe * lsa_pipe ;
2004-12-06 10:12:38 +03:00
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 ;
}
2005-01-27 10:08:20 +03:00
lsa = talloc ( cli , struct smblsa_state ) ;
2004-12-06 10:12:38 +03:00
if ( lsa = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2007-10-07 02:28:14 +04:00
lsa - > ipc_tree = smbcli_tree_init ( cli - > session , lsa , false ) ;
2004-12-06 10:12:38 +03:00
if ( lsa - > ipc_tree = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
/* connect to IPC$ */
tcon . generic . level = RAW_TCON_TCONX ;
2012-08-02 10:48:11 +04:00
tcon . tconx . in . flags = TCONX_FLAG_EXTENDED_RESPONSE ;
2012-08-02 10:51:13 +04:00
tcon . tconx . in . flags | = TCONX_FLAG_EXTENDED_SIGNATURES ;
2004-12-06 10:12:38 +03:00
tcon . tconx . in . password = data_blob ( NULL , 0 ) ;
tcon . tconx . in . path = " ipc$ " ;
tcon . tconx . in . device = " IPC " ;
2005-08-09 07:09:47 +04:00
status = smb_raw_tcon ( lsa - > ipc_tree , lsa , & tcon ) ;
2004-12-06 10:12:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( lsa ) ;
return status ;
}
2005-01-13 21:49:10 +03:00
lsa - > ipc_tree - > tid = tcon . tconx . out . tid ;
2004-12-06 10:12:38 +03:00
2012-08-02 10:51:13 +04:00
if ( tcon . tconx . out . options & SMB_EXTENDED_SIGNATURES ) {
smb1cli_session_protect_session_key ( cli - > session - > smbXcli ) ;
}
2014-01-16 11:57:30 +04:00
lsa_pipe = dcerpc_pipe_init ( lsa , cli - > transport - > ev ) ;
if ( lsa_pipe = = NULL ) {
2005-01-09 11:34:05 +03:00
talloc_free ( lsa ) ;
return NT_STATUS_NO_MEMORY ;
}
2004-12-06 10:12:38 +03:00
/* open the LSA pipe */
2014-01-16 11:57:30 +04:00
status = dcerpc_pipe_open_smb ( lsa_pipe , lsa - > ipc_tree , NDR_LSARPC_NAME ) ;
2004-12-06 10:12:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( lsa ) ;
return status ;
}
/* bind to the LSA pipe */
2014-01-16 11:57:30 +04:00
status = dcerpc_bind_auth_none ( lsa_pipe , & ndr_table_lsarpc ) ;
2004-12-06 10:12:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( lsa ) ;
return status ;
}
2014-01-16 11:57:30 +04:00
lsa - > binding_handle = lsa_pipe - > binding_handle ;
2004-12-06 10:12:38 +03:00
/* 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 ;
2014-01-16 11:57:30 +04:00
status = dcerpc_lsa_OpenPolicy_r ( lsa - > binding_handle , lsa , & r ) ;
2004-12-06 10:12:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( lsa ) ;
return status ;
}
2010-03-23 17:04:25 +03:00
if ( ! NT_STATUS_IS_OK ( r . out . result ) ) {
talloc_free ( lsa ) ;
return r . out . result ;
}
2004-12-06 10:12:38 +03:00
cli - > lsa = lsa ;
return NT_STATUS_OK ;
}
2019-12-21 00:10:49 +03:00
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 ;
}
2004-12-06 10:12:38 +03:00
/*
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 ;
2014-01-16 11:57:30 +04:00
status = dcerpc_lsa_EnumAccountRights_r ( cli - > lsa - > binding_handle , mem_ctx , & r ) ;
2010-03-23 17:04:25 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return r . out . result ;
2004-12-06 10:12:38 +03:00
}
2019-12-21 00:10:49 +03:00
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 ;
}
2004-12-06 10:12:38 +03:00
/*
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 ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx = talloc_new ( cli ) ;
2004-12-06 10:12:38 +03:00
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 ;
}
2019-12-21 00:10:49 +03:00
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 ;
}
2004-12-06 10:12:38 +03:00
/*
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 ;
2008-10-24 04:01:16 +04:00
struct lsa_RefDomainList * domains = NULL ;
2004-12-06 10:12:38 +03:00
uint32_t count = 1 ;
NTSTATUS status ;
struct dom_sid * sid ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx2 = talloc_new ( mem_ctx ) ;
2004-12-06 10:12:38 +03:00
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 ;
2005-01-27 10:08:20 +03:00
sids . sids = talloc ( mem_ctx2 , struct lsa_SidPtr ) ;
2004-12-06 10:12:38 +03:00
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 ;
2008-10-24 04:01:16 +04:00
r . out . domains = & domains ;
2004-12-06 10:12:38 +03:00
2014-01-16 11:57:30 +04:00
status = dcerpc_lsa_LookupSids_r ( cli - > lsa - > binding_handle , mem_ctx2 , & r ) ;
2004-12-06 10:12:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx2 ) ;
return status ;
}
2010-03-23 17:04:25 +03:00
if ( ! NT_STATUS_IS_OK ( r . out . result ) ) {
talloc_free ( mem_ctx2 ) ;
return r . out . result ;
}
2004-12-06 10:12:38 +03:00
if ( names . count ! = 1 ) {
talloc_free ( mem_ctx2 ) ;
2013-11-08 08:38:01 +04:00
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 ;
2004-12-06 10:12:38 +03:00
}
( * name ) = talloc_asprintf ( mem_ctx , " %s \\ %s " ,
2008-10-24 04:01:16 +04:00
domains - > domains [ 0 ] . name . string ,
2004-12-06 10:12:38 +03:00
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 ;
2008-10-24 15:43:21 +04:00
struct lsa_RefDomainList * domains = NULL ;
2004-12-06 10:12:38 +03:00
uint32_t count = 1 ;
NTSTATUS status ;
2018-12-21 11:27:43 +03:00
struct dom_sid sid ;
2005-01-06 05:32:43 +03:00
TALLOC_CTX * mem_ctx2 = talloc_new ( mem_ctx ) ;
2004-12-06 10:12:38 +03:00
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 ;
2008-10-24 15:43:21 +04:00
r . out . domains = & domains ;
2004-12-06 10:12:38 +03:00
2014-01-16 11:57:30 +04:00
status = dcerpc_lsa_LookupNames_r ( cli - > lsa - > binding_handle , mem_ctx2 , & r ) ;
2004-12-06 10:12:38 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx2 ) ;
return status ;
}
2010-03-23 17:04:25 +03:00
if ( ! NT_STATUS_IS_OK ( r . out . result ) ) {
talloc_free ( mem_ctx2 ) ;
return r . out . result ;
}
2004-12-06 10:12:38 +03:00
if ( sids . count ! = 1 ) {
talloc_free ( mem_ctx2 ) ;
2013-11-08 09:40:55 +04:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
}
if ( domains - > count ! = 1 ) {
talloc_free ( mem_ctx2 ) ;
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
2004-12-06 10:12:38 +03:00
}
2018-12-21 11:27:43 +03:00
sid_compose ( & sid , domains - > domains [ 0 ] . sid , sids . sids [ 0 ] . rid ) ;
( * sid_str ) = dom_sid_string ( mem_ctx , & sid ) ;
2004-12-06 10:12:38 +03:00
talloc_free ( mem_ctx2 ) ;
return NT_STATUS_OK ;
}
2004-12-14 09:31:20 +03:00
/*
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 ;
2014-01-16 11:57:30 +04:00
status = dcerpc_lsa_AddAccountRights_r ( cli - > lsa - > binding_handle , mem_ctx , & r ) ;
2010-03-23 17:04:25 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return r . out . result ;
2004-12-14 09:31:20 +03:00
}
/*
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 ;
2004-12-14 09:31:20 +03:00
r . in . rights = rights ;
2014-01-16 11:57:30 +04:00
status = dcerpc_lsa_RemoveAccountRights_r ( cli - > lsa - > binding_handle , mem_ctx , & r ) ;
2010-03-23 17:04:25 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return r . out . result ;
2004-12-14 09:31:20 +03:00
}