2003-03-25 09:41:42 +00:00
/* packet-smb-sidsnooping.c
* Routines for snooping SID to name mappings
* Copyright 2003 , Ronnie Sahlberg
*
2004-07-18 00:24:25 +00:00
* $ Id $
2003-03-25 09:41:42 +00:00
*
* Ethereal - Network traffic analyzer
* By Gerald Combs < gerald @ ethereal . com >
* Copyright 1998 Gerald Combs
*
* 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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include <stdio.h>
# include <string.h>
# include "epan/packet_info.h"
# include "epan/epan_dissect.h"
# include "epan/proto.h"
2004-09-29 00:06:36 +00:00
# include <epan/tap.h>
2003-03-25 09:41:42 +00:00
# include "packet-dcerpc.h"
2003-06-05 11:02:19 +00:00
# include "packet-dcerpc-nt.h"
2003-03-25 09:41:42 +00:00
# include "register.h"
# include "smb.h"
# include "packet-smb-sidsnooping.h"
static int hf_lsa = - 1 ;
2003-05-22 11:03:15 +00:00
static int hf_lsa_info_level = - 1 ;
2003-03-25 09:41:42 +00:00
static int hf_lsa_opnum = - 1 ;
static int hf_lsa_domain = - 1 ;
2004-06-04 00:05:56 +00:00
static int hf_nt_domain_sid = - 1 ;
2003-06-05 11:02:19 +00:00
static int hf_samr_hnd = - 1 ;
static int hf_samr_rid = - 1 ;
static int hf_samr_acct_name = - 1 ;
static int hf_samr_level = - 1 ;
2003-03-25 09:41:42 +00:00
2003-06-09 10:08:05 +00:00
GHashTable * sid_name_table = NULL ;
2003-03-25 09:41:42 +00:00
static GMemChunk * sid_name_chunk = NULL ;
static int sid_name_init_count = 200 ;
2003-06-05 11:02:19 +00:00
static GMemChunk * ctx_handle_chunk = NULL ;
static int ctx_handle_init_count = 200 ;
static GHashTable * ctx_handle_table = NULL ;
2005-01-01 12:49:54 +00:00
static gboolean lsa_policy_information_tap_installed = FALSE ;
static gboolean samr_query_dispinfo_tap_installed = FALSE ;
2003-03-25 09:41:42 +00:00
char *
find_sid_name ( char * sid )
{
sid_name * sn ;
sid_name old_sn ;
old_sn . sid = sid ;
sn = g_hash_table_lookup ( sid_name_table , & old_sn ) ;
if ( ! sn ) {
return NULL ;
}
return sn - > name ;
}
static void
add_sid_name_mapping ( char * sid , char * name )
{
sid_name * sn ;
sid_name old_sn ;
old_sn . sid = sid ;
sn = g_hash_table_lookup ( sid_name_table , & old_sn ) ;
if ( sn ) {
return ;
}
sn = g_mem_chunk_alloc ( sid_name_chunk ) ;
sn - > sid = g_strdup ( sid ) ;
sn - > name = g_strdup ( name ) ;
g_hash_table_insert ( sid_name_table , sn , sn ) ;
}
2003-06-05 11:02:19 +00:00
/*
* QueryDispInfo :
* level 1 : user displayinfo 1
*/
static int
2005-01-01 02:57:02 +00:00
samr_query_dispinfo ( void * dummy _U_ , packet_info * pinfo , epan_dissect_t * edt , const void * pri )
2003-06-05 11:02:19 +00:00
{
2005-01-01 02:57:02 +00:00
const dcerpc_info * ri = pri ;
2003-06-05 11:02:19 +00:00
void * old_ctx = NULL ;
char * pol_name ;
char * sid ;
int sid_len ;
int num_rids ;
int num_names ;
GPtrArray * gp ;
GPtrArray * gp_rids ;
GPtrArray * gp_names ;
field_info * fi ;
field_info * fi_rid ;
field_info * fi_name ;
char sid_name [ 256 ] ;
int info_level ;
gp = proto_get_finfo_ptr_array ( edt - > tree , hf_samr_level ) ;
if ( ! gp | | gp - > len ! = 1 ) {
return 0 ;
}
fi = gp - > pdata [ 0 ] ;
2003-12-02 21:15:49 +00:00
info_level = fi - > value . value . integer ;
2003-06-05 11:02:19 +00:00
if ( info_level ! = 1 ) {
return 0 ;
}
if ( ! ri ) {
return 0 ;
}
if ( ! ri - > call_data ) {
return 0 ;
}
2004-05-07 12:29:03 +00:00
if ( ri - > ptype = = PDU_REQ ) {
2003-06-05 11:02:19 +00:00
gp = proto_get_finfo_ptr_array ( edt - > tree , hf_samr_hnd ) ;
if ( ! gp | | gp - > len ! = 1 ) {
return 0 ;
}
fi = gp - > pdata [ 0 ] ;
2004-12-25 13:49:30 +00:00
old_ctx = g_hash_table_lookup ( ctx_handle_table , GINT_TO_POINTER ( pinfo - > fd - > num ) ) ;
2003-06-05 11:02:19 +00:00
if ( old_ctx ) {
2004-12-25 13:49:30 +00:00
g_hash_table_remove ( ctx_handle_table , GINT_TO_POINTER ( pinfo - > fd - > num ) ) ;
2003-06-05 11:02:19 +00:00
}
if ( ! old_ctx ) {
old_ctx = g_mem_chunk_alloc ( ctx_handle_chunk ) ;
2003-12-02 21:15:49 +00:00
memcpy ( old_ctx , fi - > value . value . bytes - > data , 20 ) ;
2003-06-05 11:02:19 +00:00
}
2004-12-25 13:49:30 +00:00
g_hash_table_insert ( ctx_handle_table , GINT_TO_POINTER ( pinfo - > fd - > num ) , old_ctx ) ;
2003-06-05 11:02:19 +00:00
return 0 ;
}
if ( ! ri - > call_data - > req_frame ) {
return 0 ;
}
2004-12-25 13:49:30 +00:00
old_ctx = g_hash_table_lookup ( ctx_handle_table , GINT_TO_POINTER ( ri - > call_data - > req_frame ) ) ;
2003-06-05 11:02:19 +00:00
if ( ! old_ctx ) {
return 0 ;
}
2003-06-09 10:08:05 +00:00
if ( ! dcerpc_smb_fetch_pol ( old_ctx , & pol_name , NULL , NULL , ri - > call_data - > req_frame ) ) {
2003-06-05 11:02:19 +00:00
return 0 ;
}
2004-06-04 00:15:55 +00:00
if ( ! pol_name )
return 0 ;
2003-06-05 11:02:19 +00:00
sid = strstr ( pol_name , " S-1-5 " ) ;
if ( ! sid ) {
return 0 ;
}
for ( sid_len = 4 ; 1 ; sid_len + + ) {
if ( ( sid [ sid_len ] > = ' 0 ' ) & & ( sid [ sid_len ] < = ' 9 ' ) ) {
continue ;
}
if ( sid [ sid_len ] = = ' - ' ) {
continue ;
}
break ;
}
gp_rids = proto_get_finfo_ptr_array ( edt - > tree , hf_samr_rid ) ;
if ( ! gp_rids | | gp_rids - > len < 1 ) {
return 0 ;
}
num_rids = gp_rids - > len ;
gp_names = proto_get_finfo_ptr_array ( edt - > tree , hf_samr_acct_name ) ;
if ( ! gp_names | | gp_names - > len < 1 ) {
return 0 ;
}
num_names = gp_names - > len ;
if ( num_rids > num_names ) {
num_rids = num_names ;
}
for ( ; num_rids ; num_rids - - ) {
int len = sid_len ;
fi_rid = gp_rids - > pdata [ num_rids - 1 ] ;
fi_name = gp_names - > pdata [ num_rids - 1 ] ;
strncpy ( sid_name , sid , len ) ;
sid_name [ len + + ] = ' - ' ;
2003-12-02 21:15:49 +00:00
len + = sprintf ( sid_name + len , " %d " , fi_rid - > value . value . integer ) ;
2003-06-05 11:02:19 +00:00
sid_name [ len ] = 0 ;
2003-12-02 21:15:49 +00:00
add_sid_name_mapping ( sid_name , fi_name - > value . value . string ) ;
2003-06-05 11:02:19 +00:00
}
return 1 ;
}
2003-03-25 09:41:42 +00:00
/*
2003-05-22 11:03:15 +00:00
* PolicyInformation :
* level 3 : PRIMARY_DOMAIN_INFO lsa . domain_sid - > lsa . domain
2003-05-22 11:48:28 +00:00
* level 5 : ACCOUNT_DOMAIN_INFO lsa . domain_sid - > lsa . domain
2003-05-22 11:03:15 +00:00
* level 12 : DNS_DOMAIN_INFO lsa . domain_sid - > lsa . domain
2003-03-25 09:41:42 +00:00
*/
static int
2005-01-01 02:57:02 +00:00
lsa_policy_information ( void * dummy _U_ , packet_info * pinfo _U_ , epan_dissect_t * edt , const void * pri _U_ )
2003-03-25 09:41:42 +00:00
{
2003-05-22 11:03:15 +00:00
GPtrArray * gp ;
2003-03-25 09:41:42 +00:00
field_info * fi ;
char * domain ;
char * sid ;
2003-05-22 11:03:15 +00:00
int info_level ;
2003-03-25 09:41:42 +00:00
2003-05-22 11:03:15 +00:00
gp = proto_get_finfo_ptr_array ( edt - > tree , hf_lsa_info_level ) ;
if ( ! gp | | gp - > len ! = 1 ) {
2003-03-25 09:41:42 +00:00
return 0 ;
}
2003-05-22 11:03:15 +00:00
fi = gp - > pdata [ 0 ] ;
2003-12-02 21:15:49 +00:00
info_level = fi - > value . value . integer ;
2003-05-22 11:03:15 +00:00
switch ( info_level ) {
case 3 :
2003-05-22 11:48:28 +00:00
case 5 :
2003-05-22 11:03:15 +00:00
case 12 :
gp = proto_get_finfo_ptr_array ( edt - > tree , hf_lsa_domain ) ;
if ( ! gp | | gp - > len ! = 1 ) {
return 0 ;
}
fi = gp - > pdata [ 0 ] ;
2003-12-02 21:15:49 +00:00
domain = fi - > value . value . string ;
2003-05-22 11:03:15 +00:00
2004-06-04 00:05:56 +00:00
gp = proto_get_finfo_ptr_array ( edt - > tree , hf_nt_domain_sid ) ;
2003-05-22 11:03:15 +00:00
if ( ! gp | | gp - > len ! = 1 ) {
return 0 ;
}
fi = gp - > pdata [ 0 ] ;
2003-12-02 21:15:49 +00:00
sid = fi - > value . value . string ;
2003-05-22 11:03:15 +00:00
add_sid_name_mapping ( sid , domain ) ;
break ;
2003-03-25 09:41:42 +00:00
}
2003-03-25 19:52:56 +00:00
return 0 ;
2003-03-25 09:41:42 +00:00
}
static gboolean
free_all_sid_names ( gpointer key_arg , gpointer value _U_ , gpointer user_data _U_ )
{
sid_name * sn = ( sid_name * ) key_arg ;
if ( sn - > sid ) {
g_free ( ( gpointer ) sn - > sid ) ;
sn - > sid = NULL ;
}
if ( sn - > name ) {
g_free ( ( gpointer ) sn - > name ) ;
sn - > name = NULL ;
}
return TRUE ;
}
static gint
sid_name_equal ( gconstpointer k1 , gconstpointer k2 )
{
const sid_name * sn1 = ( const sid_name * ) k1 ;
const sid_name * sn2 = ( const sid_name * ) k2 ;
return ! strcmp ( sn1 - > sid , sn2 - > sid ) ;
}
static guint
sid_name_hash ( gconstpointer k )
{
const sid_name * sn = ( const sid_name * ) k ;
int i , sum ;
for ( sum = 0 , i = strlen ( sn - > sid ) - 1 ; i > = 0 ; i - - ) {
sum + = sn - > sid [ i ] ;
}
return sum ;
}
2003-06-05 11:02:19 +00:00
static gboolean
free_all_ctx_handle ( gpointer key_arg _U_ , gpointer value _U_ , gpointer user_data _U_ )
{
return TRUE ;
}
static gint
ctx_handle_equal ( gconstpointer k1 , gconstpointer k2 )
{
2004-12-25 13:49:30 +00:00
int sn1 = GPOINTER_TO_INT ( k1 ) ;
int sn2 = GPOINTER_TO_INT ( k2 ) ;
2003-06-05 11:02:19 +00:00
return sn1 = = sn2 ;
}
static guint
ctx_handle_hash ( gconstpointer k )
{
2004-12-25 13:49:30 +00:00
int sn = GPOINTER_TO_INT ( k ) ;
2003-06-05 11:02:19 +00:00
return sn ;
}
2003-03-25 09:41:42 +00:00
static void
sid_snooping_init ( void )
{
header_field_info * hfi ;
2003-04-23 08:20:06 +00:00
GString * error_string ;
2003-03-25 09:41:42 +00:00
2005-01-01 12:49:54 +00:00
if ( lsa_policy_information_tap_installed ) {
remove_tap_listener ( & lsa_policy_information_tap_installed ) ;
lsa_policy_information_tap_installed = FALSE ;
2003-03-25 09:41:42 +00:00
}
2005-01-01 12:49:54 +00:00
if ( samr_query_dispinfo_tap_installed ) {
remove_tap_listener ( & samr_query_dispinfo_tap_installed ) ;
samr_query_dispinfo_tap_installed = FALSE ;
2003-06-05 11:02:19 +00:00
}
2003-03-25 09:41:42 +00:00
if ( sid_name_table ) {
g_hash_table_foreach_remove ( sid_name_table , free_all_sid_names , NULL ) ;
sid_name_table = NULL ;
}
if ( sid_name_chunk ) {
g_mem_chunk_destroy ( sid_name_chunk ) ;
sid_name_chunk = NULL ;
}
2003-06-05 11:02:19 +00:00
if ( ctx_handle_table ) {
g_hash_table_foreach_remove ( ctx_handle_table , free_all_ctx_handle , NULL ) ;
ctx_handle_table = NULL ;
}
if ( ctx_handle_chunk ) {
g_mem_chunk_destroy ( ctx_handle_chunk ) ;
ctx_handle_chunk = NULL ;
}
2003-03-25 09:41:42 +00:00
if ( ! sid_name_snooping ) {
return ;
}
sid_name_table = g_hash_table_new ( sid_name_hash , sid_name_equal ) ;
sid_name_chunk = g_mem_chunk_new ( " sid_name_chunk " ,
sizeof ( sid_name ) ,
sid_name_init_count * sizeof ( sid_name ) ,
G_ALLOC_ONLY ) ;
2003-06-05 11:02:19 +00:00
ctx_handle_table = g_hash_table_new ( ctx_handle_hash , ctx_handle_equal ) ;
ctx_handle_chunk = g_mem_chunk_new ( " ctx_handle_chunk " ,
20 , /* our dcerpc context handles are 20 bytes */
ctx_handle_init_count * 20 ,
G_ALLOC_ONLY ) ;
2003-03-25 09:41:42 +00:00
hf_lsa = proto_get_id_by_filter_name ( " lsa " ) ;
hfi = proto_registrar_get_byname ( " lsa.opnum " ) ;
if ( hfi ) {
hf_lsa_opnum = hfi - > id ;
}
2004-06-04 00:05:56 +00:00
hfi = proto_registrar_get_byname ( " nt.domain_sid " ) ;
2003-03-25 09:41:42 +00:00
if ( hfi ) {
2004-06-04 00:05:56 +00:00
hf_nt_domain_sid = hfi - > id ;
2003-03-25 09:41:42 +00:00
}
hfi = proto_registrar_get_byname ( " lsa.domain " ) ;
if ( hfi ) {
hf_lsa_domain = hfi - > id ;
}
2003-05-22 11:03:15 +00:00
hfi = proto_registrar_get_byname ( " lsa.info.level " ) ;
if ( hfi ) {
hf_lsa_info_level = hfi - > id ;
}
2003-06-05 11:02:19 +00:00
hfi = proto_registrar_get_byname ( " samr.hnd " ) ;
if ( hfi ) {
hf_samr_hnd = hfi - > id ;
}
hfi = proto_registrar_get_byname ( " samr.rid " ) ;
if ( hfi ) {
hf_samr_rid = hfi - > id ;
}
hfi = proto_registrar_get_byname ( " samr.acct_name " ) ;
if ( hfi ) {
hf_samr_acct_name = hfi - > id ;
}
hfi = proto_registrar_get_byname ( " samr.level " ) ;
if ( hfi ) {
hf_samr_level = hfi - > id ;
}
2003-03-25 09:41:42 +00:00
2005-01-01 12:49:54 +00:00
error_string = register_tap_listener ( " dcerpc " , & lsa_policy_information_tap_installed , " lsa.policy_information and ( lsa.info.level or lsa.domain or nt.domain_sid ) " , NULL , lsa_policy_information , NULL ) ;
2003-04-23 08:20:06 +00:00
if ( error_string ) {
2003-03-25 09:41:42 +00:00
/* error, we failed to attach to the tap. clean up */
2003-05-22 11:03:15 +00:00
fprintf ( stderr , " tethereal: Couldn't register proto_reg_handoff_smb_sidsnooping()/lsa_policy_information tap: %s \n " ,
2003-04-23 08:20:06 +00:00
error_string - > str ) ;
g_string_free ( error_string , TRUE ) ;
2003-03-25 09:41:42 +00:00
exit ( 1 ) ;
}
2005-01-01 12:49:54 +00:00
lsa_policy_information_tap_installed = TRUE ;
2003-06-05 11:02:19 +00:00
2005-01-01 12:49:54 +00:00
error_string = register_tap_listener ( " dcerpc " , & samr_query_dispinfo_tap_installed , " samr and samr.opnum==40 and ( samr.hnd or samr.rid or samr.acct_name or samr.level ) " , NULL , samr_query_dispinfo , NULL ) ;
2003-06-05 11:02:19 +00:00
if ( error_string ) {
/* error, we failed to attach to the tap. clean up */
fprintf ( stderr , " tethereal: Couldn't register proto_reg_handoff_smb_sidsnooping()/samr_query_dispinfo tap: %s \n " ,
error_string - > str ) ;
g_string_free ( error_string , TRUE ) ;
exit ( 1 ) ;
}
2005-01-01 12:49:54 +00:00
samr_query_dispinfo_tap_installed = TRUE ;
2003-03-25 09:41:42 +00:00
}
void
proto_register_smb_sidsnooping ( void )
{
register_init_routine ( sid_snooping_init ) ;
}
void
proto_reg_handoff_smb_sidsnooping ( void )
{
}