1 ###################################################
2 # server boilerplate generator
3 # Copyright tridge@samba.org 2003
4 # Copyright metze@samba.org 2004
5 # Copyright scabrero@samba.org 2019
6 # released under the GNU GPL
8 package Parse::Pidl::Samba4::NDR::ServerCompat;
12 @EXPORT_OK = qw(Parse);
14 use Parse::Pidl::Util qw(print_uuid);
15 use Parse::Pidl::Typelist qw(mapTypeName);
17 use vars qw($VERSION);
22 sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
23 sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
24 sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
25 sub pidlnoindent($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$txt\n" : "\n"; }
26 sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
27 sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; }
32 my $self = { res => "", res_hdr => "", tabs => "" };
36 #####################################################
37 # generate the switch statement for function dispatch
38 sub gen_dispatch_switch($)
40 my ($self, $interface) = @_;
42 foreach my $fn (@{$interface->{FUNCTIONS}}) {
43 next if not defined($fn->{OPNUM});
45 my $fname = $fn->{NAME};
46 my $ufname = uc($fname);
48 $self->pidl("case $fn->{OPNUM}: { /* $fn->{NAME} */");
50 $self->pidl("struct $fname *r2 = (struct $fname *)r;");
51 $self->pidl("if (DEBUGLEVEL >= 10) {");
53 $self->pidl("NDR_PRINT_FUNCTION_DEBUG($fname, NDR_IN, r2);");
57 $self->pidl_hdr("struct $fname;");
59 if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
60 $self->pidl_hdr(mapTypeName($fn->{RETURN_TYPE}) . " _$fname(struct pipes_struct *p, struct $fname *r);");
61 $self->pidl("r2->out.result = _$fname(p, r2);");
63 $self->pidl_hdr("void _$fname(struct pipes_struct *p, struct $fname *r);");
64 $self->pidl("_$fname(p, r2);");
67 $self->pidl("break;");
73 #####################################################
74 # generate the switch statement for function reply
75 sub gen_reply_switch($)
77 my ($self, $interface) = @_;
79 foreach my $fn (@{$interface->{FUNCTIONS}}) {
80 next if not defined($fn->{OPNUM});
82 $self->pidl("case $fn->{OPNUM}: { /* $fn->{NAME} */");
84 $self->pidl("struct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;");
85 $self->pidl("if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {");
87 $self->pidl("DEBUG(5,(\"function $fn->{NAME} replied async\\n\"));");
90 $self->pidl("if (DEBUGLEVEL >= 10 && dce_call->fault_code == 0) {");
92 $self->pidl("NDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);");
95 $self->pidl("if (dce_call->fault_code != 0) {");
97 $self->pidl("DBG_WARNING(\"dcerpc_fault %s in $fn->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code));");
100 $self->pidl("break;");
106 #####################################################################
107 # produce boilerplate code for a interface
108 sub boilerplate_iface($)
110 my ($self, $interface) = @_;
112 my $name = $interface->{NAME};
113 my $uname = uc $name;
114 my $uuid = lc($interface->{UUID});
115 my $if_version = $interface->{VERSION};
117 $self->pidl("static NTSTATUS $name\__op_bind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)");
120 $self->pidl("struct pipes_struct *p = NULL;");
121 $self->pidl("struct pipe_rpc_fns *context_fns = NULL;");
122 $self->pidl("bool ok = false;");
124 $self->pidl("/* Retrieve pipes struct */");
125 $self->pidl("p = dcesrv_get_pipes_struct(context->conn);");
126 $self->pidl("/* Init pipe handles */");
127 $self->pidl("ok = init_pipe_handles(p, &iface->syntax_id);");
128 $self->pidl("if (!ok) {");
130 $self->pidl("DBG_ERR(\"Failed to init pipe handles\\n\");");
131 $self->pidl("return NT_STATUS_UNSUCCESSFUL;");
136 $self->pidl("/* TODO check loop */");
138 $self->pidl("/* Init pipe context */");
139 $self->pidl("p->pipe_bound = true;");
140 $self->pidl("for (context_fns = p->contexts; context_fns != NULL; context_fns = context_fns->next) {");
142 $self->pidl("if (context_fns->context_id != context->context_id) {");
144 $self->pidl("continue;");
147 $self->pidl("ok = ndr_syntax_id_equal(&context_fns->syntax, &iface->syntax_id);");
148 $self->pidl("if (ok) {");
150 $self->pidl("break;");
153 $self->pidl("return NT_STATUS_UNSUCCESSFUL;");
156 $self->pidl("if (context_fns == NULL) {");
158 $self->pidl("context_fns = talloc_zero(p, struct pipe_rpc_fns);");
159 $self->pidl("if (context_fns == NULL) {");
161 $self->pidl("return NT_STATUS_NO_MEMORY;");
165 $self->pidl("context_fns->next = context_fns->prev = NULL;");
166 $self->pidl("context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(&iface->syntax_id);");
167 $self->pidl("context_fns->cmds = rpc_srv_get_pipe_cmds(&iface->syntax_id);");
168 $self->pidl("context_fns->context_id = context->context_id;");
169 $self->pidl("context_fns->syntax = iface->syntax_id;");
170 $self->pidl("DLIST_ADD( p->contexts, context_fns);");
173 $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_BIND");
174 $self->pidl("return DCESRV_INTERFACE_$uname\_BIND(context,iface);");
175 $self->pidlnoindent("#else");
176 $self->pidl("return NT_STATUS_OK;");
178 $self->pidl("#endif");
182 $self->pidl("static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)");
184 $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_UNBIND");
186 $self->pidl("DCESRV_INTERFACE_$uname\_UNBIND(context, iface);");
187 $self->pidlnoindent("#else");
188 $self->pidl("return;");
189 $self->pidlnoindent("#endif");
194 $self->pidl_hdr("NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r);");
195 $self->pidl("NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)");
198 $self->pidl("enum ndr_err_code ndr_err;");
199 $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
201 $self->pidl("dce_call->fault_code = 0;");
203 $self->pidl("if (opnum >= ndr_table_$name.num_calls) {");
205 $self->pidl("dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;");
206 $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
210 $self->pidl("*r = talloc_named(mem_ctx, ndr_table_$name.calls[opnum].struct_size, \"struct %s\", ndr_table_$name.calls[opnum].name);");
211 $self->pidl("NT_STATUS_HAVE_NO_MEMORY(*r);");
213 $self->pidl("/* unravel the NDR for the packet */");
214 $self->pidl("ndr_err = ndr_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);");
215 $self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {");
217 $self->pidl("dce_call->fault_code = DCERPC_FAULT_NDR;");
218 $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
222 $self->pidl("return NT_STATUS_OK;");
227 $self->pidl_hdr("NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r);");
228 $self->pidl("NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
231 $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
232 $self->pidl("struct pipes_struct *p = NULL;");
233 $self->pidl("struct auth_session_info *pipe_session_info = NULL;");
234 $self->pidl("NTSTATUS status = NT_STATUS_OK;");
235 $self->pidl("bool impersonated;");
237 $self->pidl("/* Retrieve pipes struct */");
238 $self->pidl("p = dcesrv_get_pipes_struct(dce_call->conn);");
239 $self->pidl("/* Update pipes struct opnum */");
240 $self->pidl("p->opnum = opnum;");
241 $self->pidl("/* Update pipes struct session info */");
242 $self->pidl("pipe_session_info = p->session_info;");
243 $self->pidl("p->session_info = dce_call->auth_state->session_info;");
244 $self->pidl("p->auth.auth_type = dce_call->auth_state->auth_type;");
245 $self->pidl("p->auth.auth_level = dce_call->auth_state->auth_level;");
246 $self->pidl("p->auth.auth_context_id = dce_call->auth_state->auth_context_id;");
247 $self->pidl("/* Reset pipes struct fault state */");
248 $self->pidl("p->fault_state = 0;");
251 $self->pidl("/* Impersonate */");
252 $self->pidl("impersonated = become_authenticated_pipe_user(p->session_info);");
253 $self->pidl("if (!impersonated) {");
255 $self->pidl("dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;");
256 $self->pidl("status = NT_STATUS_NET_WRITE_FAULT;");
257 $self->pidl("goto fail;");
262 $self->pidl("switch (opnum) {");
263 $self->gen_dispatch_switch($interface);
264 $self->pidl("default:");
266 $self->pidl("dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;");
267 $self->pidl("break;");
272 $self->pidlnoindent("fail:");
273 $self->pidl("/* Unimpersonate */");
274 $self->pidl("if (impersonated) {");
276 $self->pidl("unbecome_authenticated_pipe_user();");
281 $self->pidl("/* Restore session info */");
282 $self->pidl("p->session_info = pipe_session_info;");
283 $self->pidl("p->auth.auth_type = 0;");
284 $self->pidl("p->auth.auth_level = 0;");
285 $self->pidl("p->auth.auth_context_id = 0;");
286 $self->pidl("/* Check pipes struct fault state */");
287 $self->pidl("if (p->fault_state != 0) {");
289 $self->pidl("dce_call->fault_code = p->fault_state;");
292 $self->pidl("if (dce_call->fault_code != 0) {");
294 $self->pidl("status = NT_STATUS_NET_WRITE_FAULT;");
299 $self->pidl("return status;");
304 $self->pidl_hdr("NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r);");
305 $self->pidl("NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
308 $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
310 $self->pidl("switch (opnum) {");
311 $self->gen_reply_switch($interface);
312 $self->pidl("default:");
314 $self->pidl("dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;");
315 $self->pidl("break;");
320 $self->pidl("if (dce_call->fault_code != 0) {");
322 $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
326 $self->pidl("return NT_STATUS_OK;");
331 $self->pidl_hdr("NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r);");
332 $self->pidl("NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)");
335 $self->pidl("enum ndr_err_code ndr_err;");
336 $self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
338 $self->pidl("ndr_err = ndr_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);");
339 $self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {");
341 $self->pidl("dce_call->fault_code = DCERPC_FAULT_NDR;");
342 $self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
346 $self->pidl("return NT_STATUS_OK;");
351 $self->pidl("static const struct dcesrv_interface dcesrv\_$name\_interface = {");
353 $self->pidl(".name = \"$name\",");
354 $self->pidl(".syntax_id = {".print_uuid($uuid).",$if_version},");
355 $self->pidl(".bind = $name\__op_bind,");
356 $self->pidl(".unbind = $name\__op_unbind,");
357 $self->pidl(".ndr_pull = $name\__op_ndr_pull,");
358 $self->pidl(".dispatch = $name\__op_dispatch,");
359 $self->pidl(".reply = $name\__op_reply,");
360 $self->pidl(".ndr_push = $name\__op_ndr_push,");
361 $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_FLAGS");
362 $self->pidl(".flags = DCESRV_INTERFACE_$uname\_FLAGS");
363 $self->pidlnoindent("#else");
364 $self->pidl(".flags = 0");
365 $self->pidlnoindent("#endif");
371 #####################################################################
372 # produce boilerplate code for an endpoint server
373 sub boilerplate_ep_server($)
375 my ($self, $interface) = @_;
376 my $name = $interface->{NAME};
377 my $uname = uc $name;
379 $self->pidl("static NTSTATUS $name\__check_register_in_endpoint(const char *name, struct dcerpc_binding *binding) {");
381 $self->pidl("enum dcerpc_transport_t transport = dcerpc_binding_get_transport(binding);");
383 $self->pidl("/* If service is embedded, register only for ncacn_np");
384 $self->pidl(" * see 8466b3c85e4b835e57e41776853093f4a0edc8b8");
386 $self->pidl("if (rpc_service_mode(name) == RPC_SERVICE_MODE_EMBEDDED && transport != NCACN_NP) {");
388 $self->pidl("DBG_INFO(\"Interface \'$name\' not registered in endpoint \'%s\' as service is embedded\\n\", name);");
389 $self->pidl("return NT_STATUS_NOT_SUPPORTED;");
393 $self->pidl("return NT_STATUS_OK;");
398 $self->pidl("static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)");
401 $self->pidl("int i;");
402 $self->pidl("NTSTATUS ret;");
403 $self->pidl("struct dcerpc_binding *binding;");
404 $self->pidl("const struct api_struct *legacy_cmds = NULL;");
405 $self->pidl("int n_fns = 0;");
407 $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_NCACN_NP_SECONDARY_ENDPOINT");
408 $self->pidl("const char *ncacn_np_secondary_endpoint = DCESRV_INTERFACE_$uname\_NCACN_NP_SECONDARY_ENDPOINT;");
409 $self->pidlnoindent("#else");
410 $self->pidl("const char *ncacn_np_secondary_endpoint = NULL;");
411 $self->pidlnoindent("#endif");
413 $self->pidl("for (i=0;i<ndr_table_$name.endpoints->count;i++) {");
415 $self->pidl("const char *name = ndr_table_$name.endpoints->names[i];");
417 $self->pidl("/* Register the interface for local dispatching */");
418 $self->pidl("legacy_cmds = $name\_get_pipe_fns(&n_fns);");
419 $self->pidl("if (legacy_cmds == NULL) {");
421 $self->pidl("DBG_ERR(\"Failed to get legacy \'$name\' API cmds\\n\");");
422 $self->pidl("return NT_STATUS_UNSUCCESSFUL;");
426 $self->pidl("ret = rpc_srv_register(SMB_RPC_INTERFACE_VERSION, \"$name\", \"$name\", &ndr_table_$name, legacy_cmds, n_fns, NULL);");
427 $self->pidl("if (!NT_STATUS_IS_OK(ret)) {");
429 $self->pidl("DBG_ERR(\"Failed to register legacy \'$name\' API cmds\\n\");");
430 $self->pidl("return ret;");
434 $self->pidl("ret = dcerpc_parse_binding(dce_ctx, name, &binding);");
435 $self->pidl("if (NT_STATUS_IS_ERR(ret)) {");
437 $self->pidl("DBG_ERR(\"Failed to parse binding string \'%s\'\\n\", name);");
438 $self->pidl("return ret;");
442 $self->pidl("ret = $name\__check_register_in_endpoint(\"$name\", binding);");
443 $self->pidl("if (NT_STATUS_IS_ERR(ret)) {");
445 $self->pidl("talloc_free(binding);");
446 $self->pidl("continue;");
449 $self->pidl("talloc_free(binding);");
451 $self->pidl("ret = dcesrv_interface_register(dce_ctx, name, ncacn_np_secondary_endpoint, &dcesrv_$name\_interface, NULL);");
452 $self->pidl("if (!NT_STATUS_IS_OK(ret)) {");
454 $self->pidl("DBG_ERR(\"Failed to register endpoint \'%s\'\\n\",name);");
455 $self->pidl("return ret;");
461 $self->pidl("return NT_STATUS_OK;");
466 $self->pidl("static NTSTATUS $name\__op_shutdown_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)");
469 $self->pidl("NTSTATUS status;");
471 $self->pidl("/* Unregister the interface from local dispatching table */");
472 $self->pidl("status = rpc_srv_unregister(&ndr_table_$name);");
473 $self->pidl("if (!NT_STATUS_IS_OK(status)) {");
475 $self->pidl("DBG_ERR(\"Failed to unregister legacy \'$name\' API cmds\\n\");");
476 $self->pidl("return status;");
480 $self->pidl("return NT_STATUS_OK;");
485 $self->pidl("static bool $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)");
488 $self->pidl("if (dcesrv_$name\_interface.syntax_id.if_version == if_version && GUID_equal(\&dcesrv\_$name\_interface.syntax_id.uuid, uuid)) {");
490 $self->pidl("memcpy(iface,&dcesrv\_$name\_interface, sizeof(*iface));");
491 $self->pidl("return true;");
495 $self->pidl("return false;");
500 $self->pidl("static bool $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)");
503 $self->pidl("if (strcmp(dcesrv_$name\_interface.name, name)==0) {");
505 $self->pidl("memcpy(iface, &dcesrv_$name\_interface, sizeof(*iface));");
506 $self->pidl("return true;");
510 $self->pidl("return false;");
515 $self->pidl("static const struct dcesrv_endpoint_server $name\_ep_server = {");
517 $self->pidl("/* fill in our name */");
518 $self->pidl(".name = \"$name\",");
520 $self->pidl("/* Initialization flag */");
521 $self->pidl(".initialized = false,");
523 $self->pidl("/* fill in all the operations */");
524 $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_INIT_SERVER");
525 $self->pidl(".init_server = DCESRV_INTERFACE_$uname\_INIT_SERVER,");
526 $self->pidlnoindent("#else");
527 $self->pidl(".init_server = $name\__op_init_server,");
528 $self->pidlnoindent("#endif");
529 $self->pidlnoindent("#ifdef DCESRV_INTERFACE_$uname\_SHUTDOWN_SERVER");
530 $self->pidl(".shutdown_server = DCESRV_INTERFACE_$uname\_SHUTDOWN_SERVER,");
531 $self->pidlnoindent("#else");
532 $self->pidl(".shutdown_server = $name\__op_shutdown_server,");
533 $self->pidlnoindent("#endif");
534 $self->pidl(".interface_by_uuid = $name\__op_interface_by_uuid,");
535 $self->pidl(".interface_by_name = $name\__op_interface_by_name");
540 $self->pidl("const struct dcesrv_endpoint_server *$name\_get_ep_server(void)");
543 $self->pidl("return &$name\_ep_server;");
548 #####################################################################
549 # dcerpc server boilerplate from a parsed IDL structure
550 sub parse_interface($)
552 my ($self, $interface) = @_;
554 my $uif = uc($interface->{NAME});
557 $self->pidl_hdr("#ifndef __NDR_${uif}_SCOMPAT_H__");
558 $self->pidl_hdr("#define __NDR_${uif}_SCOMPAT_H__");
560 $self->pidl_hdr("struct pipes_struct;");
561 $self->pidl_hdr("struct dcesrv_endpoint_server;");
562 $self->pidl_hdr("struct dcesrv_call_state;");
564 $self->pidl_hdr("const struct dcesrv_endpoint_server *$interface->{NAME}\_get_ep_server(void);");
567 if (!defined $interface->{PROPERTIES}->{uuid}) {
568 $self->pidl_hdr("#endif /* __NDR_${uif}_SCOMPAT_H__ */");
572 if (!defined $interface->{PROPERTIES}->{version}) {
573 $interface->{PROPERTIES}->{version} = "0.0";
576 foreach my $fn (@{$interface->{FUNCTIONS}}) {
577 if (defined($fn->{OPNUM})) { $count++; }
581 $self->pidl_hdr("#endif /* __NDR_${uif}_SCOMPAT_H__ */");
585 $self->pidl("/* $interface->{NAME} - dcerpc server boilerplate generated by pidl */");
586 $self->boilerplate_iface($interface);
587 $self->boilerplate_ep_server($interface);
589 $self->pidl_hdr("#endif /* __NDR_${uif}_SCOMPAT_H__ */");
594 my ($self, $ndr, $h_scompat, $header) = @_;
596 $self->pidl("/* s3 compat server functions auto-generated by pidl */");
597 $self->pidl("#include \"$header\"");
598 $self->pidl("#include \"$h_scompat\"");
599 $self->pidl("#include <rpc_server/srv_pipe_register.h>");
600 $self->pidl("#include <rpc_server/srv_pipe_internal.h>");
602 $self->pidl("#include <librpc/rpc/dcesrv_core.h>");
603 $self->pidl("#include <rpc_server/rpc_config.h>");
604 $self->pidl("#include <rpc_server/rpc_server.h>");
605 $self->pidl("#include <util/debug.h>");
608 foreach my $x (@{$ndr}) {
609 $self->parse_interface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
612 return ($self->{res}, $self->{res_hdr});