1998-03-12 00:11:04 +03:00
/*
* Unix SMB / Netbios implementation .
* Version 1.9 .
* RPC Pipe client / server routines
* Copyright ( C ) Andrew Tridgell 1992 - 1998
* Copyright ( C ) Luke Kenneth Casson Leighton 1996 - 1998 ,
* Copyright ( C ) Paul Ashton 1997 - 1998.
*
* 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 2 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 , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/* this module apparently provides an implementation of DCE/RPC over a
* named pipe ( IPC $ connection using SMBtrans ) . details of DCE / RPC
* documentation are available ( in on - line form ) from the X - Open group .
*
* this module should provide a level of abstraction between SMB
* and DCE / RPC , while minimising the amount of mallocs , unnecessary
* data copies , and network traffic .
*
* in this version , which takes a " let's learn what's going on and
* get something running " approach, there is additional network
* traffic generated , but the code should be easier to understand . . .
*
* . . . if you read the docs . or stare at packets for weeks on end .
*
*/
# include "includes.h"
# include "nterr.h"
extern int DEBUGLEVEL ;
/* array lookup of well-known RID aliases. the purpose of these escapes me.. */
/* XXXX this structure should not have the well-known RID groups added to it,
i . e the DOMAIN_GROUP_RID_ADMIN / USER / GUEST . */
rid_name domain_alias_rids [ ] =
{
{ DOMAIN_ALIAS_RID_ADMINS , " admins " } ,
{ DOMAIN_ALIAS_RID_USERS , " users " } ,
{ DOMAIN_ALIAS_RID_GUESTS , " guests " } ,
{ DOMAIN_ALIAS_RID_POWER_USERS , " power_users " } ,
{ DOMAIN_ALIAS_RID_ACCOUNT_OPS , " account_ops " } ,
{ DOMAIN_ALIAS_RID_SYSTEM_OPS , " system_ops " } ,
{ DOMAIN_ALIAS_RID_PRINT_OPS , " print_ops " } ,
{ DOMAIN_ALIAS_RID_BACKUP_OPS , " backup_ops " } ,
{ DOMAIN_ALIAS_RID_REPLICATOR , " replicator " } ,
{ 0 , NULL }
} ;
1998-04-25 01:01:08 +04:00
/* array lookup of well-known Domain RID users. */
rid_name domain_user_rids [ ] =
{
{ DOMAIN_USER_RID_ADMIN , " Administrator " } ,
{ DOMAIN_USER_RID_GUEST , " Guest " } ,
{ 0 , NULL }
} ;
1998-03-12 00:11:04 +03:00
/* array lookup of well-known Domain RID groups. */
rid_name domain_group_rids [ ] =
{
{ DOMAIN_GROUP_RID_ADMINS , " domain admins " } ,
{ DOMAIN_GROUP_RID_USERS , " domain users " } ,
{ DOMAIN_GROUP_RID_GUESTS , " domain guests " } ,
{ 0 , NULL }
} ;
int make_dom_gids ( char * gids_str , DOM_GID * gids )
{
char * ptr ;
pstring s2 ;
int count ;
DEBUG ( 4 , ( " make_dom_gids: %s \n " , gids_str ) ) ;
if ( gids_str = = NULL | | * gids_str = = 0 ) return 0 ;
for ( count = 0 , ptr = gids_str ; next_token ( & ptr , s2 , NULL ) & & count < LSA_MAX_GROUPS ; count + + )
{
/* the entries are of the form GID/ATTR, ATTR being optional.*/
char * attr ;
uint32 rid = 0 ;
int i ;
attr = strchr ( s2 , ' / ' ) ;
if ( attr ) * attr + + = 0 ;
if ( ! attr | | ! * attr ) attr = " 7 " ; /* default value for attribute is 7 */
/* look up the RID string and see if we can turn it into a rid number */
for ( i = 0 ; domain_alias_rids [ i ] . name ! = NULL ; i + + )
{
if ( strequal ( domain_alias_rids [ i ] . name , s2 ) )
{
rid = domain_alias_rids [ i ] . rid ;
break ;
}
}
if ( rid = = 0 ) rid = atoi ( s2 ) ;
if ( rid = = 0 )
{
DEBUG ( 1 , ( " make_dom_gids: unknown well-known alias RID %s/%s \n " ,
s2 , attr ) ) ;
count - - ;
}
else
{
gids [ count ] . g_rid = rid ;
gids [ count ] . attr = atoi ( attr ) ;
DEBUG ( 5 , ( " group id: %d attr: %d \n " ,
gids [ count ] . g_rid ,
gids [ count ] . attr ) ) ;
}
}
return count ;
}
/*******************************************************************
gets a domain user ' s groups
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void get_domain_user_groups ( char * domain_groups , char * user )
{
pstring tmp ;
if ( domain_groups = = NULL | | user = = NULL ) return ;
/* any additional groups this user is in. e.g power users */
pstrcpy ( domain_groups , lp_domain_groups ( ) ) ;
/* can only be a user or a guest. cannot be guest _and_ admin */
if ( user_in_list ( user , lp_domain_guest_users ( ) ) )
{
sprintf ( tmp , " %ld/7 " , DOMAIN_GROUP_RID_GUESTS ) ;
strcat ( domain_groups , tmp ) ;
DEBUG ( 3 , ( " domain guest access %s granted \n " , tmp ) ) ;
}
else
{
sprintf ( tmp , " %ld/7 " , DOMAIN_GROUP_RID_USERS ) ;
strcat ( domain_groups , tmp ) ;
DEBUG ( 3 , ( " domain user access %s granted \n " , tmp ) ) ;
if ( user_in_list ( user , lp_domain_admin_users ( ) ) )
{
sprintf ( tmp , " %ld/7 " , DOMAIN_GROUP_RID_ADMINS ) ;
strcat ( domain_groups , tmp ) ;
DEBUG ( 3 , ( " domain admin access %s granted \n " , tmp ) ) ;
}
}
}
/*******************************************************************
turns a DCE / RPC request into a DCE / RPC reply
this is where the data really should be split up into an array of
headers and data sections .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL create_rpc_reply ( pipes_struct * p ,
uint32 data_start , uint32 data_end )
{
1998-04-10 22:21:16 +04:00
DEBUG ( 5 , ( " create_rpc_reply: data_start: %d data_end: %d max_tsize: %d \n " ,
data_start , data_end , p - > hdr_ba . bba . max_tsize ) ) ;
1998-03-12 00:11:04 +03:00
mem_buf_init ( & ( p - > rhdr . data ) , 0 ) ;
mem_alloc_data ( p - > rhdr . data , 0x18 ) ;
p - > rhdr . align = 4 ;
p - > rhdr . io = False ;
1998-04-10 22:21:16 +04:00
p - > hdr_resp . alloc_hint = data_end - data_start ; /* calculate remaining data to be sent */
1998-03-12 00:11:04 +03:00
p - > hdr . pkt_type = RPC_RESPONSE ; /* mark header as an rpc response */
/* set up rpc header (fragmentation issues) */
if ( data_start = = 0 )
{
p - > hdr . flags = RPC_FLG_FIRST ;
}
else
{
p - > hdr . flags = 0 ;
}
1998-04-10 22:21:16 +04:00
if ( p - > hdr_resp . alloc_hint + 0x18 < = p - > hdr_ba . bba . max_tsize )
1998-03-12 00:11:04 +03:00
{
p - > hdr . flags | = RPC_FLG_LAST ;
1998-04-10 22:21:16 +04:00
p - > hdr . frag_len = p - > hdr_resp . alloc_hint + 0x18 ;
1998-03-12 00:11:04 +03:00
}
else
{
p - > hdr . frag_len = p - > hdr_ba . bba . max_tsize ;
}
p - > rhdr . data - > offset . start = 0 ;
p - > rhdr . data - > offset . end = 0x18 ;
/* store the header in the data stream */
p - > rhdr . offset = 0 ;
smb_io_rpc_hdr ( " hdr " , & ( p - > hdr ) , & ( p - > rhdr ) , 0 ) ;
1998-04-10 22:21:16 +04:00
smb_io_rpc_hdr_resp ( " resp " , & ( p - > hdr_resp ) , & ( p - > rhdr ) , 0 ) ;
1998-03-12 00:11:04 +03:00
return p - > rhdr . data ! = NULL & & p - > rhdr . offset = = 0x18 ;
}
/*******************************************************************
receives a netlogon pipe and responds .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL api_rpc_command ( pipes_struct * p ,
char * rpc_name , struct api_struct * api_rpc_cmds ,
prs_struct * data )
{
int fn_num ;
1998-04-10 22:21:16 +04:00
DEBUG ( 4 , ( " api_rpc_command: %s op 0x%x - " , rpc_name , p - > hdr_req . opnum ) ) ;
1998-03-12 00:11:04 +03:00
for ( fn_num = 0 ; api_rpc_cmds [ fn_num ] . name ; fn_num + + )
{
1998-04-10 22:21:16 +04:00
if ( api_rpc_cmds [ fn_num ] . opnum = = p - > hdr_req . opnum & & api_rpc_cmds [ fn_num ] . fn ! = NULL )
1998-03-12 00:11:04 +03:00
{
DEBUG ( 3 , ( " api_rpc_command: %s \n " , api_rpc_cmds [ fn_num ] . name ) ) ;
break ;
}
}
if ( api_rpc_cmds [ fn_num ] . name = = NULL )
{
DEBUG ( 4 , ( " unknown \n " ) ) ;
return False ;
}
/* start off with 1024 bytes, and a large safety margin too */
mem_buf_init ( & ( p - > rdata . data ) , SAFETY_MARGIN ) ;
mem_alloc_data ( p - > rdata . data , 1024 ) ;
p - > rdata . io = False ;
p - > rdata . align = 4 ;
p - > rdata . data - > offset . start = 0 ;
p - > rdata . data - > offset . end = 0xffffffff ;
/* do the actual command */
p - > rdata . offset = 0 ;
api_rpc_cmds [ fn_num ] . fn ( p - > uid , data , & ( p - > rdata ) ) ;
if ( p - > rdata . data = = NULL | | p - > rdata . offset = = 0 )
{
mem_free_data ( p - > rdata . data ) ;
return False ;
}
mem_realloc_data ( p - > rdata . data , p - > rdata . offset ) ;
DEBUG ( 10 , ( " called %s \n " , rpc_name ) ) ;
return True ;
}
/*******************************************************************
receives a netlogon pipe and responds .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL api_rpcTNP ( pipes_struct * p , char * rpc_name , struct api_struct * api_rpc_cmds ,
prs_struct * data )
{
if ( data = = NULL | | data - > data = = NULL )
{
DEBUG ( 2 , ( " %s: NULL data received \n " , rpc_name ) ) ;
return False ;
}
/* read the rpc header */
1998-04-10 22:21:16 +04:00
smb_io_rpc_hdr_req ( " req " , & ( p - > hdr_req ) , data , 0 ) ;
1998-03-12 00:11:04 +03:00
/* interpret the command */
if ( ! api_rpc_command ( p , rpc_name , api_rpc_cmds , data ) )
{
return False ;
}
/* create the rpc header */
if ( ! create_rpc_reply ( p , 0 , p - > rdata . offset ) )
{
return False ;
}
1998-04-25 01:01:08 +04:00
p - > frag_len_left = p - > hdr . frag_len - p - > file_offset ;
p - > next_frag_start = p - > hdr . frag_len ;
1998-03-12 00:11:04 +03:00
/* set up the data chain */
p - > rhdr . data - > offset . start = 0 ;
p - > rhdr . data - > offset . end = p - > rhdr . offset ;
p - > rhdr . data - > next = p - > rdata . data ;
p - > rdata . data - > offset . start = p - > rhdr . data - > offset . end ;
p - > rdata . data - > offset . end = p - > rhdr . data - > offset . end + p - > rdata . offset ;
p - > rdata . data - > next = NULL ;
return True ;
}
extern rid_name domain_group_rids [ ] ;
/*******************************************************************
lookup_group_name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 lookup_group_name ( uint32 rid , char * group_name , uint32 * type )
{
int i = 0 ;
( * type ) = SID_NAME_DOM_GRP ;
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " lookup_group_name: rid: %d " , rid ) ) ;
1998-03-12 00:11:04 +03:00
while ( domain_group_rids [ i ] . rid ! = rid & & domain_group_rids [ i ] . rid ! = 0 )
{
i + + ;
}
if ( domain_group_rids [ i ] . rid ! = 0 )
{
fstrcpy ( group_name , domain_group_rids [ i ] . name ) ;
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " = %s \n " , group_name ) ) ;
1998-03-12 00:11:04 +03:00
return 0x0 ;
}
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " none mapped \n " ) ) ;
1998-03-12 00:11:04 +03:00
return 0xC0000000 | NT_STATUS_NONE_MAPPED ;
}
extern rid_name domain_alias_rids [ ] ;
/*******************************************************************
lookup_alias_name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 lookup_alias_name ( uint32 rid , char * alias_name , uint32 * type )
{
int i = 0 ;
( * type ) = SID_NAME_WKN_GRP ;
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " lookup_alias_name: rid: %d " , rid ) ) ;
1998-03-12 00:11:04 +03:00
while ( domain_alias_rids [ i ] . rid ! = rid & & domain_alias_rids [ i ] . rid ! = 0 )
{
i + + ;
}
if ( domain_alias_rids [ i ] . rid ! = 0 )
{
fstrcpy ( alias_name , domain_alias_rids [ i ] . name ) ;
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " = %s \n " , alias_name ) ) ;
1998-03-12 00:11:04 +03:00
return 0x0 ;
}
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " none mapped \n " ) ) ;
1998-03-12 00:11:04 +03:00
return 0xC0000000 | NT_STATUS_NONE_MAPPED ;
}
/*******************************************************************
lookup_user_name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 lookup_user_name ( uint32 rid , char * user_name , uint32 * type )
{
struct smb_passwd * smb_pass ;
1998-04-25 01:01:08 +04:00
uint32 unix_uid ;
int i = 0 ;
1998-03-12 00:11:04 +03:00
( * type ) = SID_NAME_USER ;
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " lookup_user_name: rid: %d " , rid ) ) ;
/* look up the well-known domain user rids first */
while ( domain_user_rids [ i ] . rid ! = rid & & domain_user_rids [ i ] . rid ! = 0 )
{
i + + ;
}
if ( domain_user_rids [ i ] . rid ! = 0 )
{
fstrcpy ( user_name , domain_user_rids [ i ] . name ) ;
DEBUG ( 5 , ( " = %s \n " , user_name ) ) ;
return 0x0 ;
}
unix_uid = uid_to_user_rid ( rid ) ;
1998-05-05 13:04:49 +04:00
DEBUG ( 5 , ( " uid: %d " , unix_uid ) ) ;
1998-04-25 01:01:08 +04:00
/* ok, it's a user. find the user account */
1998-03-12 00:11:04 +03:00
become_root ( True ) ;
1998-04-14 04:41:59 +04:00
smb_pass = getsmbpwuid ( rid ) ; /* lkclXXXX SHOULD use rid mapping here! */
1998-03-12 00:11:04 +03:00
unbecome_root ( True ) ;
if ( smb_pass ! = NULL )
{
fstrcpy ( user_name , smb_pass - > smb_name ) ;
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " = %s \n " , user_name ) ) ;
1998-03-12 00:11:04 +03:00
return 0x0 ;
}
1998-04-25 01:01:08 +04:00
DEBUG ( 5 , ( " none mapped \n " ) ) ;
1998-03-12 00:11:04 +03:00
return 0xC0000000 | NT_STATUS_NONE_MAPPED ;
}
/*******************************************************************
lookup_group_rid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 lookup_group_rid ( char * group_name , uint32 * rid )
{
char * grp_name ;
int i = - 1 ; /* start do loop at -1 */
do /* find, if it exists, a group rid for the group name*/
{
i + + ;
( * rid ) = domain_group_rids [ i ] . rid ;
grp_name = domain_group_rids [ i ] . name ;
} while ( grp_name ! = NULL & & ! strequal ( grp_name , group_name ) ) ;
return ( grp_name ! = NULL ) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED ;
}
/*******************************************************************
lookup_alias_rid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 lookup_alias_rid ( char * alias_name , uint32 * rid )
{
char * als_name ;
int i = - 1 ; /* start do loop at -1 */
do /* find, if it exists, a alias rid for the alias name*/
{
i + + ;
( * rid ) = domain_alias_rids [ i ] . rid ;
als_name = domain_alias_rids [ i ] . name ;
} while ( als_name ! = NULL & & ! strequal ( als_name , alias_name ) ) ;
return ( als_name ! = NULL ) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED ;
}
/*******************************************************************
lookup_user_rid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 lookup_user_rid ( char * user_name , uint32 * rid )
{
struct smb_passwd * smb_pass ;
( * rid ) = 0 ;
/* find the user account */
become_root ( True ) ;
1998-04-14 04:41:59 +04:00
smb_pass = getsmbpwnam ( user_name ) ;
1998-03-12 00:11:04 +03:00
unbecome_root ( True ) ;
if ( smb_pass ! = NULL )
{
/* lkclXXXX SHOULD use name_to_rid() here! */
( * rid ) = smb_pass - > smb_userid ;
return 0x0 ;
}
return 0xC0000000 | NT_STATUS_NONE_MAPPED ;
}
/*******************************************************************
Group and User RID username mapping function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL name_to_rid ( char * user_name , uint32 * u_rid , uint32 * g_rid )
{
struct passwd * pw = Get_Pwnam ( user_name , False ) ;
if ( u_rid = = NULL | | g_rid = = NULL | | user_name = = NULL )
{
return False ;
}
if ( ! pw )
{
DEBUG ( 1 , ( " Username %s is invalid on this system \n " , user_name ) ) ;
return False ;
}
if ( user_in_list ( user_name , lp_domain_guest_users ( ) ) )
{
* u_rid = DOMAIN_USER_RID_GUEST ;
}
else if ( user_in_list ( user_name , lp_domain_admin_users ( ) ) )
{
* u_rid = DOMAIN_USER_RID_ADMIN ;
}
else
{
/* turn the unix UID into a Domain RID. this is what the posix
sub - system does ( adds 1000 to the uid ) */
1998-04-25 01:01:08 +04:00
* u_rid = uid_to_user_rid ( pw - > pw_uid ) ;
1998-03-12 00:11:04 +03:00
}
/* absolutely no idea what to do about the unix GID to Domain RID mapping */
1998-04-25 01:01:08 +04:00
* g_rid = gid_to_group_rid ( pw - > pw_gid ) ;
1998-03-12 00:11:04 +03:00
return True ;
}
1998-04-25 01:01:08 +04:00
/*******************************************************************
XXXX THIS FUNCTION SHOULD NOT BE HERE : IT SHOULD BE A STATIC FUNCTION
INSIDE smbpass . c
converts NT User RID to a UNIX uid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uid_t user_rid_to_uid ( uint32 u_rid )
{
return ( uid_t ) ( u_rid - 1000 ) ;
}
/*******************************************************************
XXXX THIS FUNCTION SHOULD NOT BE HERE : IT SHOULD BE A STATIC FUNCTION
INSIDE smbpass . c
converts NT Group RID to a UNIX uid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uid_t group_rid_to_uid ( uint32 u_gid )
{
return ( uid_t ) ( u_gid - 1000 ) ;
}
/*******************************************************************
XXXX THIS FUNCTION SHOULD NOT BE HERE : IT SHOULD BE A STATIC FUNCTION
INSIDE smbpass . c
converts UNIX uid to an NT User RID .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 uid_to_user_rid ( uint32 uid )
{
return ( uint32 ) ( uid + 1000 ) ;
}
/*******************************************************************
XXXX THIS FUNCTION SHOULD NOT BE HERE : IT SHOULD BE A STATIC FUNCTION
INSIDE smbpass . c
converts NT Group RID to a UNIX uid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 gid_to_group_rid ( uint32 gid )
{
return ( uint32 ) ( gid + 1000 ) ;
}