package Parse::Pidl::Nmap::ClientNDR; use Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(GenerateFunctionInEnv ParseFunction $res $res_hdr); use strict; use Parse::Pidl qw(fatal warning); use Parse::Pidl::Typelist qw(hasType getType mapTypeName scalar_is_reference); use Parse::Pidl::Util qw(has_property is_constant ParseExpr); use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred); use Parse::Pidl::Dump qw(DumpInterface); #use Parse::Pidl::Samba4::NDR::Parser qw(GenerateFunctionInEnv); use vars qw($VERSION); $VERSION = '0.01'; # a hash for mapping idl basic types to ndr primitive prototypes my %idl2ndr_pt_map = ( "signed small" => "pt_signed_small", "unsigned small" => "pt_unsigned_small", "signed short" => "pt_signed_short", "unsigned short" => "pt_unsigned_short", "signed long" => "pt_signed_long", "unsigned long" => "pt_unsigned_long", "signed hyper" => "pt_signed_hyper", "unsigned hyper" => "pt_unsigned_hyper", "byte" => "pt_octet", "char" => "pt_char", "boolean" => "pt_bool", "conf" => "PT_ConfArr", "conf_var" => "PT_ConfVarArr", "var" => "PT_VarArr", "fixed" => "PT_FixedArr", "ref" => "PT_RefPtr", "unique" => "PT_UniPtr", "ptr" => "PT_FullPtr" ); sub pidl($$){ my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; } sub indent($){ my ($self) = @_; $self->{tabs} .= "\t"; } sub deindent($){ my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); } sub genpad($) { my ($s) = @_; my $nt = int((length($s)+1)/8); my $lt = ($nt*8)-1; my $ns = (length($s)-$lt); return "\t"x($nt)." "x($ns); } sub new($) { my ($class) = shift; my $self = { res => "", tabs => "", typedefs => {}}; bless($self, $class); } sub ParseFunction($$$) { my ($self, $iface, $function) = @_; foreach my $key (keys %{$function}){ printf("%s.%s=%s\n", $function->{NAME}, $key, $function->{$key}); } return; } sub ParseInterface($$) { my ($self, $iface) = @_; #make service class definition from template "template_svc_class.lua" $self->print_interface($iface); #make opnums enumeration from template "template_opnums.lua" $self->print_opnums($iface, $iface->{FUNCTIONS}); #make constants enumeration from template "template_constants.lua" $self->print_constants($iface, $iface->{CONSTS}); #make enum enumaration from template "template_enums.lua" $self->print_enums($iface, $iface->{TYPES}); #get typedef hash which is used to map a typedef to its base type #$self->{typedefs} = get_typedefs($iface, $iface->{TYPES}); #make structure enumeration from template "template_structures.lua" $self->print_structures($iface, $iface->{TYPES}); # $self->ParseFunction($iface, $_) foreach (@{$iface->{FUNCTIONS}}); } use File::Basename; my $dirname = dirname(__FILE__); sub Parse($$$) { my($self,$ndr,$pidl) = @_; #print Parse::Pidl::Dump::Dump($pidl); #Add a common header at the top local $/=undef; open(NMAP_COMMON_HDR_FH,"$dirname/nmap_common_hdr.lua") || die "Nmap::Parse: $!\n"; my $nmap_common_hdr = ; close(NMAP_COMMON_HDR_FH); $self->pidl($nmap_common_hdr); foreach my $iface (@$ndr) { $self->ParseInterface($iface) if ($iface->{TYPE} eq "INTERFACE"); } return ($self->{res}); } sub print_opnums($$$$){ my($self,$iface,$functions) = @_; #Get the template for opnums enumeration local $/=undef; open(TEMPLATE_OPNUMS_FH,"$dirname/template_opnums.lua") || die "Nmap::print_opnums: $!\n"; my $template_opnums = ; close TEMPLATE_OPNUMS_FH; #$template_opnums =~ s/\n//g; my $iface_name = $self->getIfaceName($iface); $template_opnums =~ s//$iface_name/g; my $opnum = 0; my $opnums_string = ""; foreach my $function (@$functions){ my $function_name = $function->{NAME}; $opnums_string .= sprintf( "\t[\"%s\"] = %s,\n", $function->{NAME}, $opnum++); } $template_opnums =~ s//$opnums_string/g; $self->pidl($template_opnums); } sub print_interface($$){ my ($self,$iface) = @_; #Get the template for service class definition local $/=undef; open(TEMPLATE_SVC_CLASS_FH,"$dirname/template_svc_class.lua") || die "Nmap::print_service_class: $!\n"; my $template_svc_class = ; close TEMPLATE_SVC_CLASS_FH; my $iface_name = $self->getIfaceName($iface); $template_svc_class =~ s//$iface_name/g; my $iface_uuid = $iface->{UUID}; $template_svc_class =~ s//$iface_uuid/g; my $iface_version = $iface->{VERSION}; $template_svc_class =~ s//$iface_version/g; my $iface_endpoints = $iface->{ENDPOINTS}; my $iface_endpoints_string = ""; foreach my $iface_endpoint (@{$iface_endpoints}){ $iface_endpoints_string .= $iface_endpoint . ","; } $template_svc_class =~ s//$iface_endpoints_string/g; my $iface_properities = $iface->{PROPERTIES}; my $pointer_default = $iface_properities->{pointer_default}; $template_svc_class =~ s//$pointer_default/g; my $helpstring = $iface_properities->{helpstring}; $template_svc_class =~ s//$helpstring/g; $self->pidl($template_svc_class); } sub print_constants($$$){ my ($self,$iface,$constants) = @_; #Get the template for constants enumeration local $/=undef; open(TEMPLATE_CONSTANTS_FH,"$dirname/template_constants.lua") || die "Nmap::print_constants: $!\n"; my $template_constants = ; close TEMPLATE_CONSTANTS_FH; my $iface_name = $self->getIfaceName($iface); $template_constants =~ s//$iface_name/g; my $consts_string = ""; foreach my $constant (@{$constants}){ $consts_string .= sprintf("\t[\"%s\"] = %s,\n", $constant->{NAME}, $constant->{VALUE}); } $template_constants =~ s//$consts_string/g; $self->pidl($template_constants); $self->pidl(""); } sub print_structures($$$){ my ($self,$iface,$types) = @_; #Get the template for structures enumeration local $/=undef; open(TEMPLATE_STRUCTURES_FH,"$dirname/template_structures.lua") || die "Nmap::print_structures: $!\n"; my $template_structures = ; close TEMPLATE_STRUCTURES_FH; my $iface_name = $self->getIfaceName($iface); $template_structures =~ s//$iface_name/g; foreach my $type (@{$types}){ my $data = $type; if($type->{TYPE} eq "TYPEDEF"){ $data = $type->{DATA}; $data->{NAME} = $type->{NAME}; } if($data->{TYPE} eq "STRUCT"){ my $temp = $template_structures; $temp =~ s//$data->{NAME}/g; print $temp . $data->{NAME}; my ($local_pts_string, $struct_map_string) = $self->format_struct_map($data); $temp =~ s//$local_pts_string/g; $temp =~ s//$struct_map_string/g; $self->pidl($temp); } } $self->pidl(""); } sub format_struct_map($$){ my ($self,$type) = @_; my $local_pts_string = ""; my $struct_map_string = "{\n"; foreach my $elem (@{$type->{ELEMENTS}}){ my $pt_desc = format_pt_desc($elem->{IS}); my $elem_pt = format_pt($elem->{IS}); my $elem_name = $elem->{NAME}; $local_pts_string .= sprintf("local pt_$elem_name = $elem_pt\n\t--$pt_desc\n"); $struct_map_string .= sprintf("\t\t\t{\"%s\", pt_%s},\n", $elem_name, $elem_name); } $struct_map_string .= "\t\t}"; return ($local_pts_string, $struct_map_string); } sub idl2ndr_t($$){ my ($self,$type) = @_; if(not $type){ die "Type missing!!!\n" } my $ndr_type = $idl2ndr_pt_map{$type}; return $ndr_type; } sub idl2ndr_pt($){ my ($type) = @_; if(not $type){ die "Type missing!!!\n" } my $ndr_prototype = $idl2ndr_pt_map{$type}; return $ndr_prototype; } sub format_pt_desc($){ my ($lvl) = @_; if(not $lvl){ return 0; } if($lvl->{TYPE} eq "IDENTIFIER"){ my $dim = format_pt_desc($lvl->{ARRAY}); my $ptrs = format_pt_desc($lvl->{IS}); my $desc = ""; if($dim > 0){ $desc .= $dim . "-dimensional array of "; } if($ptrs > 0){ $desc .= $ptrs . "-tuple pointer to "; } $desc .= $lvl->{BASE_TYPE}; return $desc; } if($lvl->{TYPE} eq "ARRAY"){ return format_pt_desc($lvl->{ARRAY}) + 1; } if($lvl->{TYPE} eq "POINTER"){ return $lvl->{REFERENT}->{TYPE} eq "IDENTIFIER" ? 1 : format_pt_desc($lvl->{REFERENT}) + 1; } } sub format_pt($){ my ($lvl) = @_; if(not $lvl){ return undef; } if($lvl->{TYPE} eq "IDENTIFIER"){ my @arr_stack = format_pt($lvl->{ARRAY}); my @ptr_stack = format_pt($lvl->{IS}); my $pt = idl2ndr_pt($lvl->{BASE_TYPE}); while(my $p = shift(@ptr_stack)){ my $ptr_pt = idl2ndr_pt($p->{POINTER_TYPE}); $pt = sprintf("$ptr_pt:new($pt)"); } while(my $a = pop(@arr_stack)){ my $arr_pt = idl2ndr_pt($a->{ARR_TYPE}); my @arr_dims = $a->{DIMS}; $pt = sprintf("$arr_pt:new({{@arr_dims}, $pt})"); } return $pt; } if($lvl->{TYPE} eq "ARRAY"){ my @arr = (); if($lvl->{IS_CONFORMANT} == 1){ $lvl->{ARR_TYPE} = "conf"; if($lvl->{IS_VARYING}){ $lvl->{ARR_TYPE} = "conf_var"; } }else{ if($lvl->{IS_VARYING}){ $lvl->{ARR_TYPE} = "var"; } } if($lvl->{IS_FIXED}){ $lvl->{ARR_TYPE} = "fixed"; } push(@arr, $lvl); push (@arr, format_pt($lvl->{ARRAY})); if($lvl->{LEVEL} == 1){ my @arr_stack = (); my $at = $lvl->{ARR_TYPE}; my @dims = (); push(@dims, $lvl->{LENGTH_IS}); foreach my $a (@arr[1..scalar(@arr)]){ if($a->{ARR_TYPE} eq $at){ push (@dims, $a->{LENGTH_IS}); }else{ push(@arr_stack,{ARR_TYPE => $at,DIMS => sprintf("@dims")}); $#dims = -1; $at = $a->{ARR_TYPE}; push(@dims, $a->{LENGTH_IS}); } } return @arr_stack; } return @arr; } if($lvl->{TYPE} eq "POINTER"){ my @ptr_stack = (); push (@ptr_stack, $lvl); if($lvl->{REFERENT}->{TYPE} eq "IDENTIFIER"){ return @ptr_stack; }else{ push (@ptr_stack, format_pt($lvl->{REFERENT})); } return @ptr_stack; } } sub getIfaceName($$){ my ($self,$iface) = @_; return uc($iface->{NAME}); } sub print_enums($$$){ my ($self,$iface,$types) = @_; #Get the template for enum enumeration local $/=undef; open(TEMPLATE_ENUMS_FH,"$dirname/template_enums.lua") || die "Nmap::print_enums: $!\n"; my $template_enums = ; close TEMPLATE_ENUMS_FH; #Get the template for enum enumeration local $/=undef; open(TEMPLATE_TYPEDEFS_FH,"$dirname/template_typedefs.lua") || die "Nmap::print_enums: $!\n"; my $template_typedefs = ; close TEMPLATE_TYPEDEFS_FH; my $iface_name = $self->getIfaceName($iface); #$template_enums =~ s/\n//g; $template_enums =~ s//$iface_name/g; $template_typedefs =~ s//$iface_name/g; my $enum_link = sprintf("Cli_$iface_name.TYPES.ENUMS."); my $enums_string = ""; my $typedefs_string = ""; foreach my $type (@{$types}){ my $name = $type->{NAME}; my $typedef = 0; my $data = $type; if($type->{TYPE} eq "TYPEDEF"){ $data = $type->{DATA}; $typedef = 1; } if($data->{TYPE} eq "ENUM"){ $enums_string .= sprintf("\t%s = \n\t\t{\n", $name); my $next_val = 0; foreach my $elem (@{$data->{ELEMENTS}}){ my ($field_id,$val) = split /=/,$elem; $val = $val ? $val : $next_val; $next_val = $val+1; $enums_string .= sprintf("\t\t\t[\"%s\"] = %s,\n", $field_id, $val); } $enums_string .= "\t\t},\n"; if($typedef == 1){ my $replace = sprintf("%s = pt_enum\n\t\t--$enum_link%s\n", $name, $name); my $temp = $template_typedefs; $temp =~ s//$replace/g; $typedefs_string .= $temp; $typedef = 0; } } } $template_enums =~ s//$enums_string/g; $self->pidl($template_enums); $self->pidl($typedefs_string); $self->pidl(""); } 1;