1################################################### 2# client calls generator 3# Copyright tridge@samba.org 2003 4# Copyright jelmer@samba.org 2005-2006 5# released under the GNU GPL 6 7package Parse::Pidl::Samba4::NDR::Client; 8 9use Exporter; 10@ISA = qw(Exporter); 11@EXPORT_OK = qw(Parse); 12 13use Parse::Pidl qw(fatal warning error); 14use Parse::Pidl::Util qw(has_property ParseExpr genpad); 15use Parse::Pidl::NDR qw(ContainsPipe); 16use Parse::Pidl::Typelist qw(mapTypeName); 17use Parse::Pidl::Samba4 qw(choose_header is_intree DeclLong); 18use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv); 19 20use vars qw($VERSION); 21$VERSION = '0.01'; 22 23use strict; 24 25sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; } 26sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); } 27sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; } 28sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; } 29sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; } 30sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); } 31 32sub new($) 33{ 34 my ($class) = shift; 35 my $self = { res => "", res_hdr => "", tabs => "" }; 36 bless($self, $class); 37} 38 39sub ParseFunctionHasPipes($$) 40{ 41 my ($self, $fn) = @_; 42 43 foreach my $e (@{$fn->{ELEMENTS}}) { 44 return 1 if ContainsPipe($e, $e->{LEVELS}[0]); 45 } 46 47 return 0; 48} 49 50sub ParseFunction_r_State($$$$) 51{ 52 my ($self, $if, $fn, $name) = @_; 53 my $uname = uc $name; 54 55 $self->pidl("struct dcerpc_$name\_r_state {"); 56 $self->indent; 57 $self->pidl("TALLOC_CTX *out_mem_ctx;"); 58 $self->deindent; 59 $self->pidl("};"); 60 $self->pidl(""); 61 $self->pidl("static void dcerpc_$name\_r_done(struct tevent_req *subreq);"); 62 $self->pidl(""); 63} 64 65sub ParseFunction_r_Send($$$$) 66{ 67 my ($self, $if, $fn, $name) = @_; 68 my $uname = uc $name; 69 70 my $proto = "struct tevent_req *dcerpc_$name\_r_send(TALLOC_CTX *mem_ctx,\n"; 71 $proto .= "\tstruct tevent_context *ev,\n", 72 $proto .= "\tstruct dcerpc_binding_handle *h,\n", 73 $proto .= "\tstruct $name *r)"; 74 75 $self->fn_declare($proto); 76 77 $self->pidl("{"); 78 $self->indent; 79 80 $self->pidl("struct tevent_req *req;"); 81 $self->pidl("struct dcerpc_$name\_r_state *state;"); 82 $self->pidl("struct tevent_req *subreq;"); 83 $self->pidl(""); 84 85 $self->pidl("req = tevent_req_create(mem_ctx, &state,"); 86 $self->pidl("\t\t\tstruct dcerpc_$name\_r_state);"); 87 $self->pidl("if (req == NULL) {"); 88 $self->indent; 89 $self->pidl("return NULL;"); 90 $self->deindent; 91 $self->pidl("}"); 92 $self->pidl(""); 93 94 my $out_params = 0; 95 foreach my $e (@{$fn->{ELEMENTS}}) { 96 next unless grep(/out/, @{$e->{DIRECTION}}); 97 next if ContainsPipe($e, $e->{LEVELS}[0]); 98 $out_params++; 99 100 } 101 102 my $submem; 103 if ($out_params > 0) { 104 $self->pidl("state->out_mem_ctx = talloc_new(state);"); 105 $self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {"); 106 $self->indent; 107 $self->pidl("return tevent_req_post(req, ev);"); 108 $self->deindent; 109 $self->pidl("}"); 110 $submem = "state->out_mem_ctx"; 111 } else { 112 $self->pidl("state->out_mem_ctx = NULL;"); 113 $submem = "state"; 114 } 115 $self->pidl(""); 116 117 $self->pidl("subreq = dcerpc_binding_handle_call_send(state, ev, h,"); 118 $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},"); 119 $self->pidl("\t\tNDR_$uname, $submem, r);"); 120 $self->pidl("if (tevent_req_nomem(subreq, req)) {"); 121 $self->indent; 122 $self->pidl("return tevent_req_post(req, ev);"); 123 $self->deindent; 124 $self->pidl("}"); 125 $self->pidl("tevent_req_set_callback(subreq, dcerpc_$name\_r_done, req);"); 126 $self->pidl(""); 127 128 $self->pidl("return req;"); 129 $self->deindent; 130 $self->pidl("}"); 131 $self->pidl(""); 132} 133 134sub ParseFunction_r_Done($$$$) 135{ 136 my ($self, $if, $fn, $name) = @_; 137 my $uname = uc $name; 138 139 my $proto = "static void dcerpc_$name\_r_done(struct tevent_req *subreq)"; 140 141 $self->pidl("$proto"); 142 $self->pidl("{"); 143 $self->indent; 144 145 $self->pidl("struct tevent_req *req ="); 146 $self->pidl("\ttevent_req_callback_data(subreq,"); 147 $self->pidl("\tstruct tevent_req);"); 148 $self->pidl("NTSTATUS status;"); 149 $self->pidl(""); 150 151 $self->pidl("status = dcerpc_binding_handle_call_recv(subreq);"); 152 $self->pidl("TALLOC_FREE(subreq);"); 153 $self->pidl("if (tevent_req_nterror(req, status)) {"); 154 $self->indent; 155 $self->pidl("return;"); 156 $self->deindent; 157 $self->pidl("}"); 158 $self->pidl(""); 159 160 $self->pidl("tevent_req_done(req);"); 161 $self->deindent; 162 $self->pidl("}"); 163 $self->pidl(""); 164} 165 166sub ParseFunction_r_Recv($$$$) 167{ 168 my ($self, $if, $fn, $name) = @_; 169 my $uname = uc $name; 170 171 my $proto = "NTSTATUS dcerpc_$name\_r_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)"; 172 173 $self->fn_declare($proto); 174 175 $self->pidl("{"); 176 $self->indent; 177 178 $self->pidl("struct dcerpc_$name\_r_state *state ="); 179 $self->pidl("\ttevent_req_data(req,"); 180 $self->pidl("\tstruct dcerpc_$name\_r_state);"); 181 $self->pidl("NTSTATUS status;"); 182 $self->pidl(""); 183 184 $self->pidl("if (tevent_req_is_nterror(req, &status)) {"); 185 $self->indent; 186 $self->pidl("tevent_req_received(req);"); 187 $self->pidl("return status;"); 188 $self->deindent; 189 $self->pidl("}"); 190 $self->pidl(""); 191 192 $self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);"); 193 $self->pidl(""); 194 195 $self->pidl("tevent_req_received(req);"); 196 $self->pidl("return NT_STATUS_OK;"); 197 $self->deindent; 198 $self->pidl("}"); 199 $self->pidl(""); 200} 201 202sub ParseFunction_r_Sync($$$$) 203{ 204 my ($self, $if, $fn, $name) = @_; 205 my $uname = uc $name; 206 207 if ($self->ParseFunctionHasPipes($fn)) { 208 $self->pidl_both("/*"); 209 $self->pidl_both(" * The following function is skipped because"); 210 $self->pidl_both(" * it uses pipes:"); 211 $self->pidl_both(" *"); 212 $self->pidl_both(" * dcerpc_$name\_r()"); 213 $self->pidl_both(" */"); 214 $self->pidl_both(""); 215 return; 216 } 217 218 my $proto = "NTSTATUS dcerpc_$name\_r(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, struct $name *r)"; 219 220 $self->fn_declare($proto); 221 222 $self->pidl("{"); 223 $self->indent; 224 $self->pidl("NTSTATUS status;"); 225 $self->pidl(""); 226 227 $self->pidl("status = dcerpc_binding_handle_call(h,"); 228 $self->pidl("\t\tNULL, &ndr_table_$if->{NAME},"); 229 $self->pidl("\t\tNDR_$uname, mem_ctx, r);"); 230 $self->pidl(""); 231 $self->pidl("return status;"); 232 233 $self->deindent; 234 $self->pidl("}"); 235 $self->pidl(""); 236} 237 238sub ElementDirection($) 239{ 240 my ($e) = @_; 241 242 return "[in,out]" if (has_property($e, "in") and has_property($e, "out")); 243 return "[in]" if (has_property($e, "in")); 244 return "[out]" if (has_property($e, "out")); 245 return "[in,out]"; 246} 247 248sub HeaderProperties($$) 249{ 250 my($props,$ignores) = @_; 251 my $ret = ""; 252 253 foreach my $d (sort(keys %{$props})) { 254 next if (grep(/^$d$/, @$ignores)); 255 if($props->{$d} ne "1") { 256 $ret.= "$d($props->{$d}),"; 257 } else { 258 $ret.="$d,"; 259 } 260 } 261 262 if ($ret) { 263 return "[" . substr($ret, 0, -1) . "]"; 264 } 265} 266 267sub ParseCopyArgument($$$$$) 268{ 269 my ($self, $fn, $e, $r, $i) = @_; 270 my $l = $e->{LEVELS}[0]; 271 272 if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED} == 1) { 273 $self->pidl("memcpy(${r}$e->{NAME}, ${i}$e->{NAME}, sizeof(${r}$e->{NAME}));"); 274 } else { 275 $self->pidl("${r}$e->{NAME} = ${i}$e->{NAME};"); 276 } 277} 278 279sub ParseInvalidResponse($$) 280{ 281 my ($self, $type) = @_; 282 283 if ($type eq "sync") { 284 $self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;"); 285 } elsif ($type eq "async") { 286 $self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);"); 287 $self->pidl("return;"); 288 } else { 289 die("ParseInvalidResponse($type)"); 290 } 291} 292 293sub ParseOutputArgument($$$$$$) 294{ 295 my ($self, $fn, $e, $r, $o, $invalid_response_type) = @_; 296 my $level = 0; 297 298 if ($e->{LEVELS}[0]->{TYPE} ne "POINTER" and $e->{LEVELS}[0]->{TYPE} ne "ARRAY") { 299 fatal($e->{ORIGINAL}, "[out] argument is not a pointer or array"); 300 return; 301 } 302 303 if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") { 304 $level = 1; 305 if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") { 306 $self->pidl("if ($o$e->{NAME} && ${r}out.$e->{NAME}) {"); 307 $self->indent; 308 } 309 } 310 311 if ($e->{LEVELS}[$level]->{TYPE} eq "ARRAY") { 312 # This is a call to GenerateFunctionInEnv intentionally. 313 # Since the data is being copied into a user-provided data 314 # structure, the user should be able to know the size beforehand 315 # to allocate a structure of the right size. 316 my $in_env = GenerateFunctionInEnv($fn, $r); 317 my $out_env = GenerateFunctionOutEnv($fn, $r); 318 my $l = $e->{LEVELS}[$level]; 319 320 my $in_var = undef; 321 if (grep(/in/, @{$e->{DIRECTION}})) { 322 $in_var = ParseExpr($e->{NAME}, $in_env, $e->{ORIGINAL}); 323 } 324 my $out_var = ParseExpr($e->{NAME}, $out_env, $e->{ORIGINAL}); 325 326 my $in_size_is = undef; 327 my $out_size_is = undef; 328 my $out_length_is = undef; 329 330 my $avail_len = undef; 331 my $needed_len = undef; 332 333 $self->pidl("{"); 334 $self->indent; 335 my $copy_len_var = "_copy_len_$e->{NAME}"; 336 $self->pidl("size_t $copy_len_var;"); 337 338 if (not defined($l->{SIZE_IS})) { 339 if (not $l->{IS_ZERO_TERMINATED}) { 340 fatal($e->{ORIGINAL}, "no size known for [out] array `$e->{NAME}'"); 341 } 342 if (has_property($e, "charset")) { 343 $avail_len = "ndr_charset_length($in_var, CH_UNIX)"; 344 $needed_len = "ndr_charset_length($out_var, CH_UNIX)"; 345 } else { 346 $avail_len = "ndr_string_length($in_var, sizeof(*$in_var))"; 347 $needed_len = "ndr_string_length($out_var, sizeof(*$out_var))"; 348 } 349 $in_size_is = ""; 350 $out_size_is = ""; 351 $out_length_is = ""; 352 } else { 353 $in_size_is = ParseExpr($l->{SIZE_IS}, $in_env, $e->{ORIGINAL}); 354 $out_size_is = ParseExpr($l->{SIZE_IS}, $out_env, $e->{ORIGINAL}); 355 $out_length_is = $out_size_is; 356 if (defined($l->{LENGTH_IS})) { 357 $out_length_is = ParseExpr($l->{LENGTH_IS}, $out_env, $e->{ORIGINAL}); 358 } 359 if (has_property($e, "charset")) { 360 if (defined($in_var)) { 361 $avail_len = "ndr_charset_length($in_var, CH_UNIX)"; 362 } else { 363 $avail_len = $out_length_is; 364 } 365 $needed_len = "ndr_charset_length($out_var, CH_UNIX)"; 366 } 367 } 368 369 if ($out_size_is ne $in_size_is) { 370 $self->pidl("if (($out_size_is) > ($in_size_is)) {"); 371 $self->indent; 372 $self->ParseInvalidResponse($invalid_response_type); 373 $self->deindent; 374 $self->pidl("}"); 375 } 376 if ($out_length_is ne $out_size_is) { 377 $self->pidl("if (($out_length_is) > ($out_size_is)) {"); 378 $self->indent; 379 $self->ParseInvalidResponse($invalid_response_type); 380 $self->deindent; 381 $self->pidl("}"); 382 } 383 if (defined($needed_len)) { 384 $self->pidl("$copy_len_var = $needed_len;"); 385 $self->pidl("if ($copy_len_var > $avail_len) {"); 386 $self->indent; 387 $self->ParseInvalidResponse($invalid_response_type); 388 $self->deindent; 389 $self->pidl("}"); 390 } else { 391 $self->pidl("$copy_len_var = $out_length_is;"); 392 } 393 394 my $dest_ptr = "$o$e->{NAME}"; 395 my $elem_size = "sizeof(*$dest_ptr)"; 396 $self->pidl("if ($dest_ptr != $out_var) {"); 397 $self->indent; 398 if (has_property($e, "charset")) { 399 $dest_ptr = "discard_const_p(uint8_t *, $dest_ptr)"; 400 } 401 $self->pidl("memcpy($dest_ptr, $out_var, $copy_len_var * $elem_size);"); 402 $self->deindent; 403 $self->pidl("}"); 404 405 $self->deindent; 406 $self->pidl("}"); 407 } else { 408 $self->pidl("*$o$e->{NAME} = *${r}out.$e->{NAME};"); 409 } 410 411 if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") { 412 if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") { 413 $self->deindent; 414 $self->pidl("}"); 415 } 416 } 417} 418 419sub ParseFunction_State($$$$) 420{ 421 my ($self, $if, $fn, $name) = @_; 422 423 my $state_str = "struct dcerpc_$name\_state"; 424 my $done_fn = "dcerpc_$name\_done"; 425 426 $self->pidl("$state_str {"); 427 $self->indent; 428 $self->pidl("struct $name orig;"); 429 $self->pidl("struct $name tmp;"); 430 $self->pidl("TALLOC_CTX *out_mem_ctx;"); 431 $self->deindent; 432 $self->pidl("};"); 433 $self->pidl(""); 434 $self->pidl("static void $done_fn(struct tevent_req *subreq);"); 435 $self->pidl(""); 436} 437 438sub ParseFunction_Send($$$$) 439{ 440 my ($self, $if, $fn, $name) = @_; 441 442 my $fn_args = ""; 443 my $state_str = "struct dcerpc_$name\_state"; 444 my $done_fn = "dcerpc_$name\_done"; 445 my $out_mem_ctx = "dcerpc_$name\_out_memory"; 446 my $fn_str = "struct tevent_req *dcerpc_$name\_send"; 447 my $pad = genpad($fn_str); 448 449 $fn_args .= "TALLOC_CTX *mem_ctx"; 450 $fn_args .= ",\n" . $pad . "struct tevent_context *ev"; 451 $fn_args .= ",\n" . $pad . "struct dcerpc_binding_handle *h"; 452 453 foreach (@{$fn->{ELEMENTS}}) { 454 my $dir = ElementDirection($_); 455 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]); 456 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */"; 457 } 458 459 $self->fn_declare("$fn_str($fn_args)"); 460 $self->pidl("{"); 461 $self->indent; 462 $self->pidl("struct tevent_req *req;"); 463 $self->pidl("$state_str *state;"); 464 $self->pidl("struct tevent_req *subreq;"); 465 $self->pidl(""); 466 $self->pidl("req = tevent_req_create(mem_ctx, &state,"); 467 $self->pidl("\t\t\t$state_str);"); 468 $self->pidl("if (req == NULL) {"); 469 $self->indent; 470 $self->pidl("return NULL;"); 471 $self->deindent; 472 $self->pidl("}"); 473 $self->pidl("state->out_mem_ctx = NULL;"); 474 $self->pidl(""); 475 476 $self->pidl("/* In parameters */"); 477 foreach my $e (@{$fn->{ELEMENTS}}) { 478 next unless (grep(/in/, @{$e->{DIRECTION}})); 479 480 $self->ParseCopyArgument($fn, $e, "state->orig.in.", "_"); 481 } 482 $self->pidl(""); 483 484 my $out_params = 0; 485 $self->pidl("/* Out parameters */"); 486 foreach my $e (@{$fn->{ELEMENTS}}) { 487 next unless grep(/out/, @{$e->{DIRECTION}}); 488 489 $self->ParseCopyArgument($fn, $e, "state->orig.out.", "_"); 490 491 next if ContainsPipe($e, $e->{LEVELS}[0]); 492 493 $out_params++; 494 } 495 $self->pidl(""); 496 497 if (defined($fn->{RETURN_TYPE})) { 498 $self->pidl("/* Result */"); 499 $self->pidl("ZERO_STRUCT(state->orig.out.result);"); 500 $self->pidl(""); 501 } 502 503 if ($out_params > 0) { 504 $self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,"); 505 $self->pidl("\t\t \"$out_mem_ctx\");"); 506 $self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {"); 507 $self->indent; 508 $self->pidl("return tevent_req_post(req, ev);"); 509 $self->deindent; 510 $self->pidl("}"); 511 $self->pidl(""); 512 } 513 514 $self->pidl("/* make a temporary copy, that we pass to the dispatch function */"); 515 $self->pidl("state->tmp = state->orig;"); 516 $self->pidl(""); 517 518 $self->pidl("subreq = dcerpc_$name\_r_send(state, ev, h, &state->tmp);"); 519 $self->pidl("if (tevent_req_nomem(subreq, req)) {"); 520 $self->indent; 521 $self->pidl("return tevent_req_post(req, ev);"); 522 $self->deindent; 523 $self->pidl("}"); 524 $self->pidl("tevent_req_set_callback(subreq, $done_fn, req);"); 525 $self->pidl("return req;"); 526 $self->deindent; 527 $self->pidl("}"); 528 $self->pidl(""); 529} 530 531sub ParseFunction_Done($$$$) 532{ 533 my ($self, $if, $fn, $name) = @_; 534 535 my $state_str = "struct dcerpc_$name\_state"; 536 my $done_fn = "dcerpc_$name\_done"; 537 538 $self->pidl("static void $done_fn(struct tevent_req *subreq)"); 539 $self->pidl("{"); 540 $self->indent; 541 $self->pidl("struct tevent_req *req = tevent_req_callback_data("); 542 $self->pidl("\tsubreq, struct tevent_req);"); 543 $self->pidl("$state_str *state = tevent_req_data("); 544 $self->pidl("\treq, $state_str);"); 545 $self->pidl("NTSTATUS status;"); 546 $self->pidl("TALLOC_CTX *mem_ctx;"); 547 $self->pidl(""); 548 549 $self->pidl("if (state->out_mem_ctx) {"); 550 $self->indent; 551 $self->pidl("mem_ctx = state->out_mem_ctx;"); 552 $self->deindent; 553 $self->pidl("} else {"); 554 $self->indent; 555 $self->pidl("mem_ctx = state;"); 556 $self->deindent; 557 $self->pidl("}"); 558 $self->pidl(""); 559 560 $self->pidl("status = dcerpc_$name\_r_recv(subreq, mem_ctx);"); 561 $self->pidl("TALLOC_FREE(subreq);"); 562 $self->pidl("if (tevent_req_nterror(req, status)) {"); 563 $self->indent; 564 $self->pidl("return;"); 565 $self->deindent; 566 $self->pidl("}"); 567 $self->pidl(""); 568 569 $self->pidl("/* Copy out parameters */"); 570 foreach my $e (@{$fn->{ELEMENTS}}) { 571 next if ContainsPipe($e, $e->{LEVELS}[0]); 572 next unless (grep(/out/, @{$e->{DIRECTION}})); 573 574 $self->ParseOutputArgument($fn, $e, 575 "state->tmp.", 576 "state->orig.out.", 577 "async"); 578 } 579 $self->pidl(""); 580 581 if (defined($fn->{RETURN_TYPE})) { 582 $self->pidl("/* Copy result */"); 583 $self->pidl("state->orig.out.result = state->tmp.out.result;"); 584 $self->pidl(""); 585 } 586 587 $self->pidl("/* Reset temporary structure */"); 588 $self->pidl("ZERO_STRUCT(state->tmp);"); 589 $self->pidl(""); 590 591 $self->pidl("tevent_req_done(req);"); 592 $self->deindent; 593 $self->pidl("}"); 594 $self->pidl(""); 595} 596 597sub ParseFunction_Recv($$$$) 598{ 599 my ($self, $if, $fn, $name) = @_; 600 601 my $fn_args = ""; 602 my $state_str = "struct dcerpc_$name\_state"; 603 my $fn_str = "NTSTATUS dcerpc_$name\_recv"; 604 my $pad = genpad($fn_str); 605 606 $fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx"; 607 608 if (defined($fn->{RETURN_TYPE})) { 609 $fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result"; 610 } 611 612 $self->fn_declare("$fn_str($fn_args)"); 613 $self->pidl("{"); 614 $self->indent; 615 $self->pidl("$state_str *state = tevent_req_data("); 616 $self->pidl("\treq, $state_str);"); 617 $self->pidl("NTSTATUS status;"); 618 $self->pidl(""); 619 $self->pidl("if (tevent_req_is_nterror(req, &status)) {"); 620 $self->indent; 621 $self->pidl("tevent_req_received(req);"); 622 $self->pidl("return status;"); 623 $self->deindent; 624 $self->pidl("}"); 625 $self->pidl(""); 626 627 $self->pidl("/* Steal possible out parameters to the callers context */"); 628 $self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);"); 629 $self->pidl(""); 630 631 if (defined($fn->{RETURN_TYPE})) { 632 $self->pidl("/* Return result */"); 633 $self->pidl("*result = state->orig.out.result;"); 634 $self->pidl(""); 635 } 636 637 $self->pidl("tevent_req_received(req);"); 638 $self->pidl("return NT_STATUS_OK;"); 639 $self->deindent; 640 $self->pidl("}"); 641 $self->pidl(""); 642} 643 644sub ParseFunction_Sync($$$$) 645{ 646 my ($self, $if, $fn, $name) = @_; 647 648 if ($self->ParseFunctionHasPipes($fn)) { 649 $self->pidl_both("/*"); 650 $self->pidl_both(" * The following function is skipped because"); 651 $self->pidl_both(" * it uses pipes:"); 652 $self->pidl_both(" *"); 653 $self->pidl_both(" * dcerpc_$name()"); 654 $self->pidl_both(" */"); 655 $self->pidl_both(""); 656 return; 657 } 658 659 my $uname = uc $name; 660 my $fn_args = ""; 661 my $fn_str = "NTSTATUS dcerpc_$name"; 662 my $pad = genpad($fn_str); 663 664 $fn_args .= "struct dcerpc_binding_handle *h,\n" . $pad . "TALLOC_CTX *mem_ctx"; 665 666 foreach (@{$fn->{ELEMENTS}}) { 667 my $dir = ElementDirection($_); 668 my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]); 669 $fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */"; 670 } 671 672 if (defined($fn->{RETURN_TYPE})) { 673 $fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result"; 674 } 675 676 $self->fn_declare("$fn_str($fn_args)"); 677 $self->pidl("{"); 678 $self->indent; 679 $self->pidl("struct $name r;"); 680 $self->pidl("NTSTATUS status;"); 681 $self->pidl(""); 682 683 $self->pidl("/* In parameters */"); 684 foreach my $e (@{$fn->{ELEMENTS}}) { 685 next unless (grep(/in/, @{$e->{DIRECTION}})); 686 687 $self->ParseCopyArgument($fn, $e, "r.in.", "_"); 688 } 689 $self->pidl(""); 690 691 $self->pidl("/* Out parameters */"); 692 foreach my $e (@{$fn->{ELEMENTS}}) { 693 next unless grep(/out/, @{$e->{DIRECTION}}); 694 695 $self->ParseCopyArgument($fn, $e, "r.out.", "_"); 696 } 697 $self->pidl(""); 698 699 if (defined($fn->{RETURN_TYPE})) { 700 $self->pidl("/* Result */"); 701 $self->pidl("ZERO_STRUCT(r.out.result);"); 702 $self->pidl(""); 703 } 704 705 $self->pidl("status = dcerpc_$name\_r(h, mem_ctx, &r);"); 706 $self->pidl("if (!NT_STATUS_IS_OK(status)) {"); 707 $self->indent; 708 $self->pidl("return status;"); 709 $self->deindent; 710 $self->pidl("}"); 711 $self->pidl(""); 712 713 $self->pidl("/* Return variables */"); 714 foreach my $e (@{$fn->{ELEMENTS}}) { 715 next if ContainsPipe($e, $e->{LEVELS}[0]); 716 next unless (grep(/out/, @{$e->{DIRECTION}})); 717 718 $self->ParseOutputArgument($fn, $e, "r.", "_", "sync"); 719 } 720 $self->pidl(""); 721 722 $self->pidl("/* Return result */"); 723 if ($fn->{RETURN_TYPE}) { 724 $self->pidl("*result = r.out.result;"); 725 } 726 $self->pidl(""); 727 728 $self->pidl("return NT_STATUS_OK;"); 729 730 $self->deindent; 731 $self->pidl("}"); 732 $self->pidl(""); 733} 734 735##################################################################### 736# parse a function 737sub ParseFunction($$$) 738{ 739 my ($self, $if, $fn) = @_; 740 741 if ($self->ParseFunctionHasPipes($fn)) { 742 $self->pidl_both("/*"); 743 $self->pidl_both(" * The following function is skipped because"); 744 $self->pidl_both(" * it uses pipes:"); 745 $self->pidl_both(" *"); 746 $self->pidl_both(" * dcerpc_$fn->{NAME}_r_send()"); 747 $self->pidl_both(" * dcerpc_$fn->{NAME}_r_recv()"); 748 $self->pidl_both(" * dcerpc_$fn->{NAME}_r()"); 749 $self->pidl_both(" *"); 750 $self->pidl_both(" * dcerpc_$fn->{NAME}_send()"); 751 $self->pidl_both(" * dcerpc_$fn->{NAME}_recv()"); 752 $self->pidl_both(" * dcerpc_$fn->{NAME}()"); 753 $self->pidl_both(" */"); 754 $self->pidl_both(""); 755 warning($fn->{ORIGINAL}, "$fn->{NAME}: dcerpc client does not support pipe yet"); 756 return; 757 } 758 759 $self->ParseFunction_r_State($if, $fn, $fn->{NAME}); 760 $self->ParseFunction_r_Send($if, $fn, $fn->{NAME}); 761 $self->ParseFunction_r_Done($if, $fn, $fn->{NAME}); 762 $self->ParseFunction_r_Recv($if, $fn, $fn->{NAME}); 763 $self->ParseFunction_r_Sync($if, $fn, $fn->{NAME}); 764 765 foreach my $e (@{$fn->{ELEMENTS}}) { 766 next unless (grep(/out/, @{$e->{DIRECTION}})); 767 768 my $reason = "is not a pointer or array"; 769 770 # TODO: make this fatal at NDR level 771 if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") { 772 if ($e->{LEVELS}[1]->{TYPE} eq "DATA" and 773 $e->{LEVELS}[1]->{DATA_TYPE} eq "string") { 774 $reason = "is a pointer to type 'string'"; 775 } elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY" and 776 $e->{LEVELS}[1]->{IS_ZERO_TERMINATED}) { 777 next; 778 } elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY" and 779 not defined($e->{LEVELS}[1]->{SIZE_IS})) { 780 $reason = "is a pointer to an unsized array"; 781 } else { 782 next; 783 } 784 } 785 if ($e->{LEVELS}[0]->{TYPE} eq "ARRAY") { 786 if (not defined($e->{LEVELS}[0]->{SIZE_IS})) { 787 $reason = "is an unsized array"; 788 } else { 789 next; 790 } 791 } 792 793 $self->pidl_both("/*"); 794 $self->pidl_both(" * The following functions are skipped because"); 795 $self->pidl_both(" * an [out] argument $e->{NAME} $reason:"); 796 $self->pidl_both(" *"); 797 $self->pidl_both(" * dcerpc_$fn->{NAME}_send()"); 798 $self->pidl_both(" * dcerpc_$fn->{NAME}_recv()"); 799 $self->pidl_both(" * dcerpc_$fn->{NAME}()"); 800 $self->pidl_both(" */"); 801 $self->pidl_both(""); 802 803 error($e->{ORIGINAL}, "$fn->{NAME}: [out] argument '$e->{NAME}' $reason, skip client functions"); 804 return; 805 } 806 807 $self->ParseFunction_State($if, $fn, $fn->{NAME}); 808 $self->ParseFunction_Send($if, $fn, $fn->{NAME}); 809 $self->ParseFunction_Done($if, $fn, $fn->{NAME}); 810 $self->ParseFunction_Recv($if, $fn, $fn->{NAME}); 811 $self->ParseFunction_Sync($if, $fn, $fn->{NAME}); 812 813 $self->pidl_hdr(""); 814} 815 816my %done; 817 818##################################################################### 819# parse the interface definitions 820sub ParseInterface($$) 821{ 822 my ($self, $if) = @_; 823 my $ifu = uc($if->{NAME}); 824 825 $self->pidl_hdr("#ifndef _HEADER_RPC_$if->{NAME}"); 826 $self->pidl_hdr("#define _HEADER_RPC_$if->{NAME}"); 827 $self->pidl_hdr(""); 828 829 if (defined $if->{PROPERTIES}->{uuid}) { 830 $self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$if->{NAME};"); 831 $self->pidl_hdr(""); 832 } 833 834 $self->pidl("/* $if->{NAME} - client functions generated by pidl */"); 835 $self->pidl(""); 836 837 foreach my $fn (@{$if->{FUNCTIONS}}) { 838 next if defined($done{$fn->{NAME}}); 839 next if has_property($fn, "noopnum"); 840 next if has_property($fn, "todo"); 841 $self->ParseFunction($if, $fn); 842 $done{$fn->{NAME}} = 1; 843 } 844 845 $self->pidl_hdr("#endif /* _HEADER_RPC_$if->{NAME} */"); 846} 847 848sub Parse($$$$$$) 849{ 850 my($self,$ndr,$header,$ndr_header,$client_header) = @_; 851 852 $self->pidl("/* client functions auto-generated by pidl */"); 853 $self->pidl(""); 854 if (is_intree()) { 855 $self->pidl("#include \"includes.h\""); 856 } else { 857 $self->pidl("#ifndef _GNU_SOURCE"); 858 $self->pidl("#define _GNU_SOURCE"); 859 $self->pidl("#endif"); 860 $self->pidl("#include <stdio.h>"); 861 $self->pidl("#include <stdbool.h>"); 862 $self->pidl("#include <stdlib.h>"); 863 $self->pidl("#include <stdint.h>"); 864 $self->pidl("#include <stdarg.h>"); 865 $self->pidl("#include <string.h>"); 866 $self->pidl("#include <core/ntstatus.h>"); 867 } 868 $self->pidl("#include <tevent.h>"); 869 $self->pidl(choose_header("lib/util/tevent_ntstatus.h", "util/tevent_ntstatus.h").""); 870 $self->pidl("#include \"$ndr_header\""); 871 $self->pidl("#include \"$client_header\""); 872 $self->pidl(""); 873 874 $self->pidl_hdr(choose_header("librpc/rpc/dcerpc.h", "dcerpc.h").""); 875 $self->pidl_hdr("#include \"$header\""); 876 877 foreach my $x (@{$ndr}) { 878 ($x->{TYPE} eq "INTERFACE") && $self->ParseInterface($x); 879 } 880 881 return ($self->{res},$self->{res_hdr}); 882} 883 8841; 885