2 Unix SMB/CIFS implementation.
4 dcerpc utility functions
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 find the pipe name for a local IDL interface
30 const char *idl_pipe_name(const char *uuid, uint32_t if_version)
33 for (i=0;dcerpc_pipes[i];i++) {
34 if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 &&
35 dcerpc_pipes[i]->if_version == if_version) {
36 return dcerpc_pipes[i]->name;
43 find the number of calls defined by local IDL
45 int idl_num_calls(const char *uuid, uint32_t if_version)
48 for (i=0;dcerpc_pipes[i];i++) {
49 if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 &&
50 dcerpc_pipes[i]->if_version == if_version) {
51 return dcerpc_pipes[i]->num_calls;
59 find a dcerpc interface by name
61 const struct dcerpc_interface_table *idl_iface_by_name(const char *name)
64 for (i=0;dcerpc_pipes[i];i++) {
65 if (strcasecmp(dcerpc_pipes[i]->name, name) == 0) {
66 return dcerpc_pipes[i];
73 find a dcerpc interface by uuid
75 const struct dcerpc_interface_table *idl_iface_by_uuid(const char *uuid)
78 for (i=0;dcerpc_pipes[i];i++) {
79 if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0) {
80 return dcerpc_pipes[i];
89 push a dcerpc_packet into a blob, potentially with auth info
91 NTSTATUS dcerpc_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
92 struct dcerpc_packet *pkt,
93 struct dcerpc_auth *auth_info)
98 ndr = ndr_push_init_ctx(mem_ctx);
100 return NT_STATUS_NO_MEMORY;
103 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
104 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
108 pkt->auth_length = auth_info->credentials.length;
110 pkt->auth_length = 0;
113 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
114 if (!NT_STATUS_IS_OK(status)) {
119 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
122 *blob = ndr_push_blob(ndr);
124 /* fill in the frag length */
125 dcerpc_set_frag_length(blob, blob->length);
130 #define MAX_PROTSEQ 10
132 static const struct {
134 enum dcerpc_transport_t transport;
136 enum epm_protocols protseq[MAX_PROTSEQ];
138 { "ncacn_np", NCACN_NP, 3,
139 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
140 { "ncacn_ip_tcp", NCACN_IP_TCP, 3,
141 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } },
142 { "ncacn_http", NCACN_HTTP, 3,
143 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } },
144 { "ncadg_ip_udp", NCACN_IP_UDP, 3,
145 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
146 { "ncalrpc", NCALRPC, 2,
147 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE } },
148 { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2,
149 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
150 { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2,
151 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
152 { "ncacn_at_dsp", NCACN_AT_DSP, 3,
153 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
154 { "ncadg_at_ddp", NCADG_AT_DDP, 3,
155 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
156 { "ncacn_vns_ssp", NCACN_VNS_SPP, 3,
157 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
158 { "ncacn_vns_ipc", NCACN_VNS_IPC, 3,
159 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
160 { "ncadg_ipx", NCADG_IPX, 2,
161 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
163 { "ncacn_spx", NCACN_SPX, 2,
164 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SPX },
168 static const struct {
171 } ncacn_options[] = {
172 {"sign", DCERPC_SIGN},
173 {"seal", DCERPC_SEAL},
174 {"connect", DCERPC_CONNECT},
175 {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
176 {"print", DCERPC_DEBUG_PRINT_BOTH},
177 {"padcheck", DCERPC_DEBUG_PAD_CHECK},
178 {"bigendian", DCERPC_PUSH_BIGENDIAN}
184 form a binding string from a binding structure
186 const char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
190 const char *t_name=NULL;
192 for (i=0;i<ARRAY_SIZE(transports);i++) {
193 if (transports[i].transport == b->transport) {
194 t_name = transports[i].name;
201 if (!uuid_all_zero(&b->object)) {
202 s = talloc_asprintf(mem_ctx, "%s@", GUID_string(mem_ctx, &b->object));
205 s = talloc_asprintf_append(s, "%s:", t_name);
209 s = talloc_asprintf_append(s, "%s", b->host);
212 if (!b->endpoint && !b->options && !b->flags) {
216 s = talloc_asprintf_append(s, "[");
219 s = talloc_asprintf_append(s, "%s", b->endpoint);
222 /* this is a *really* inefficent way of dealing with strings,
223 but this is rarely called and the strings are always short,
225 for (i=0;b->options && b->options[i];i++) {
226 s = talloc_asprintf_append(s, ",%s", b->options[i]);
230 for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
231 if (b->flags & ncacn_options[i].flag) {
232 s = talloc_asprintf_append(s, ",%s", ncacn_options[i].name);
237 s = talloc_asprintf_append(s, "]");
243 parse a binding string into a dcerpc_binding structure
245 NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding *b)
247 char *options, *type;
249 int i, j, comma_count;
253 if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
256 status = GUID_from_string(s, &b->object);
258 if (NT_STATUS_IS_ERR(status)) {
259 DEBUG(0, ("Failed parsing UUID\n"));
265 ZERO_STRUCT(b->object);
268 b->object_version = 0;
272 return NT_STATUS_INVALID_PARAMETER;
275 type = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
277 return NT_STATUS_NO_MEMORY;
280 for (i=0;i<ARRAY_SIZE(transports);i++) {
281 if (strcasecmp(type, transports[i].name) == 0) {
282 b->transport = transports[i].transport;
286 if (i==ARRAY_SIZE(transports)) {
287 DEBUG(0,("Unknown dcerpc transport '%s'\n", type));
288 return NT_STATUS_INVALID_PARAMETER;
295 b->host = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
296 options = talloc_strdup(mem_ctx, p+1);
297 if (options[strlen(options)-1] != ']') {
298 return NT_STATUS_INVALID_PARAMETER;
300 options[strlen(options)-1] = 0;
302 b->host = talloc_strdup(mem_ctx, s);
307 return NT_STATUS_NO_MEMORY;
318 comma_count = count_chars(options, ',');
320 b->options = talloc_array_p(mem_ctx, const char *, comma_count+2);
322 return NT_STATUS_NO_MEMORY;
325 for (i=0; (p = strchr(options, ',')); i++) {
326 b->options[i] = talloc_strndup(mem_ctx, options, PTR_DIFF(p, options));
327 if (!b->options[i]) {
328 return NT_STATUS_NO_MEMORY;
332 b->options[i] = options;
333 b->options[i+1] = NULL;
335 /* some options are pre-parsed for convenience */
336 for (i=0;b->options[i];i++) {
337 for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
338 if (strcasecmp(ncacn_options[j].name, b->options[i]) == 0) {
340 b->flags |= ncacn_options[j].flag;
341 for (k=i;b->options[k];k++) {
342 b->options[k] = b->options[k+1];
351 /* Endpoint is first option */
352 b->endpoint = b->options[0];
353 if (strlen(b->endpoint) == 0) b->endpoint = NULL;
355 for (i=0;b->options[i];i++) {
356 b->options[i] = b->options[i+1];
360 if (b->options[0] == NULL)
366 const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor)
368 switch (floor->lhs.protocol) {
369 case EPM_PROTOCOL_TCP:
370 if (floor->rhs.tcp.port == 0) return NULL;
371 return talloc_asprintf(mem_ctx, "%d", floor->rhs.tcp.port);
373 case EPM_PROTOCOL_UDP:
374 if (floor->rhs.udp.port == 0) return NULL;
375 return talloc_asprintf(mem_ctx, "%d", floor->rhs.udp.port);
377 case EPM_PROTOCOL_HTTP:
378 if (floor->rhs.http.port == 0) return NULL;
379 return talloc_asprintf(mem_ctx, "%d", floor->rhs.http.port);
381 case EPM_PROTOCOL_IP:
382 if (floor->rhs.ip.address == 0) {
388 in.s_addr = htonl(floor->rhs.ip.address);
389 return talloc_strdup(mem_ctx, inet_ntoa(in));
392 case EPM_PROTOCOL_NCACN:
395 case EPM_PROTOCOL_NCADG:
398 case EPM_PROTOCOL_SMB:
399 if (strlen(floor->rhs.smb.unc) == 0) return NULL;
400 return talloc_strdup(mem_ctx, floor->rhs.smb.unc);
402 case EPM_PROTOCOL_PIPE:
403 if (strlen(floor->rhs.pipe.path) == 0) return NULL;
404 return talloc_strdup(mem_ctx, floor->rhs.pipe.path);
406 case EPM_PROTOCOL_NETBIOS:
407 if (strlen(floor->rhs.netbios.name) == 0) return NULL;
408 return talloc_strdup(mem_ctx, floor->rhs.netbios.name);
410 case EPM_PROTOCOL_NCALRPC:
413 case EPM_PROTOCOL_VINES_SPP:
414 return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_spp.port);
416 case EPM_PROTOCOL_VINES_IPC:
417 return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_ipc.port);
419 case EPM_PROTOCOL_STREETTALK:
420 return talloc_strdup(mem_ctx, floor->rhs.streettalk.streettalk);
422 case EPM_PROTOCOL_UNIX_DS:
423 if (strlen(floor->rhs.unix_ds.path) == 0) return NULL;
424 return talloc_strdup(mem_ctx, floor->rhs.unix_ds.path);
426 case EPM_PROTOCOL_NULL:
433 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor, const char *data)
435 switch (floor->lhs.protocol) {
436 case EPM_PROTOCOL_TCP:
437 floor->rhs.tcp.port = atoi(data);
440 case EPM_PROTOCOL_UDP:
441 floor->rhs.udp.port = atoi(data);
444 case EPM_PROTOCOL_HTTP:
445 floor->rhs.http.port = atoi(data);
448 case EPM_PROTOCOL_IP:
449 if (strlen(data) > 0) {
450 floor->rhs.ip.address = ntohl(interpret_addr(data));
452 floor->rhs.ip.address = 0;
456 case EPM_PROTOCOL_NCACN:
457 floor->rhs.ncacn.minor_version = 0;
460 case EPM_PROTOCOL_NCADG:
461 floor->rhs.ncadg.minor_version = 0;
464 case EPM_PROTOCOL_SMB:
465 floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
466 if (!floor->rhs.smb.unc) {
467 return NT_STATUS_NO_MEMORY;
471 case EPM_PROTOCOL_PIPE:
472 floor->rhs.pipe.path = talloc_strdup(mem_ctx, data);
473 if (!floor->rhs.pipe.path) {
474 return NT_STATUS_NO_MEMORY;
478 case EPM_PROTOCOL_NETBIOS:
479 floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
480 if (!floor->rhs.netbios.name) {
481 return NT_STATUS_NO_MEMORY;
485 case EPM_PROTOCOL_NCALRPC:
488 case EPM_PROTOCOL_VINES_SPP:
489 floor->rhs.vines_spp.port = atoi(data);
492 case EPM_PROTOCOL_VINES_IPC:
493 floor->rhs.vines_ipc.port = atoi(data);
496 case EPM_PROTOCOL_STREETTALK:
497 floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
498 if (!floor->rhs.streettalk.streettalk) {
499 return NT_STATUS_NO_MEMORY;
503 case EPM_PROTOCOL_UNIX_DS:
504 floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
505 if (!floor->rhs.unix_ds.path) {
506 return NT_STATUS_NO_MEMORY;
510 case EPM_PROTOCOL_NULL:
514 return NT_STATUS_NOT_SUPPORTED;
517 enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower)
521 /* Find a transport that matches this tower */
522 for (i=0;i<ARRAY_SIZE(transports);i++) {
524 if (transports[i].num_protocols != tower->num_floors - 2) {
528 for (j = 0; j < transports[i].num_protocols; j++) {
529 if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
534 if (j == transports[i].num_protocols) {
535 return transports[i].transport;
539 /* Unknown transport */
543 NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx, struct epm_tower *tower, struct dcerpc_binding *binding)
545 ZERO_STRUCT(binding->object);
546 binding->options = NULL;
547 binding->host = NULL;
550 binding->transport = dcerpc_transport_by_tower(tower);
552 if (binding->transport == -1) {
553 return NT_STATUS_NOT_SUPPORTED;
556 if (tower->num_floors < 1) {
560 /* Set object uuid */
561 binding->object = tower->floors[0].lhs.info.uuid.uuid;
562 binding->object_version = tower->floors[0].lhs.info.uuid.version;
564 /* Ignore floor 1, it contains the NDR version info */
566 binding->options = NULL;
569 if (tower->num_floors >= 4) {
570 binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]);
572 binding->endpoint = NULL;
575 /* Set network address */
576 if (tower->num_floors >= 5) {
577 binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]);
582 NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower)
584 const enum epm_protocols *protseq;
585 int num_protocols = -1, i;
589 for (i=0;i<ARRAY_SIZE(transports);i++) {
590 if (transports[i].transport == binding->transport) {
591 protseq = transports[i].protseq;
592 num_protocols = transports[i].num_protocols;
597 if (num_protocols == -1) {
598 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
599 return NT_STATUS_UNSUCCESSFUL;
602 tower->num_floors = 2 + num_protocols;
603 tower->floors = talloc_array_p(mem_ctx, struct epm_floor, tower->num_floors);
606 tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
607 tower->floors[0].lhs.info.uuid.uuid = binding->object;
608 tower->floors[0].lhs.info.uuid.version = binding->object_version;
609 tower->floors[0].rhs.uuid.unknown = 0;
612 tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
613 tower->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION;
614 tower->floors[1].rhs.uuid.unknown = 0;
615 status = GUID_from_string(NDR_GUID, &tower->floors[1].lhs.info.uuid.uuid);
616 if (NT_STATUS_IS_ERR(status)) {
620 /* Floor 2 to num_protocols */
621 for (i = 0; i < num_protocols; i++) {
622 tower->floors[2 + i].lhs.protocol = protseq[i];
623 tower->floors[2 + i].lhs.info.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
624 ZERO_STRUCT(tower->floors[2 + i].rhs);
625 dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
628 /* The 4th floor contains the endpoint */
629 if (num_protocols >= 2 && binding->endpoint) {
630 status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint);
631 if (NT_STATUS_IS_ERR(status)) {
636 /* The 5th contains the network address */
637 if (num_protocols >= 3 && binding->host) {
638 status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4], binding->host);
639 if (NT_STATUS_IS_ERR(status)) {
647 NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
648 const char *uuid, uint_t version)
650 struct dcerpc_pipe *p;
653 struct policy_handle handle;
655 struct epm_twr_t twr, *twr_r;
656 struct dcerpc_binding epmapper_binding;
659 if (!strcmp(uuid, DCERPC_EPMAPPER_UUID)) {
660 switch(binding->transport) {
661 case NCACN_IP_TCP: binding->endpoint = talloc_asprintf(mem_ctx, "%d", EPMAPPER_PORT); return NT_STATUS_OK;
662 case NCALRPC: binding->endpoint = EPMAPPER_IDENTIFIER; return NT_STATUS_OK;
663 default: return NT_STATUS_NOT_SUPPORTED;
668 ZERO_STRUCT(epmapper_binding);
669 epmapper_binding.transport = binding->transport;
670 epmapper_binding.host = binding->host;
671 epmapper_binding.options = NULL;
672 epmapper_binding.flags = 0;
673 epmapper_binding.endpoint = NULL;
675 status = dcerpc_pipe_connect_b(&p,
677 DCERPC_EPMAPPER_UUID,
678 DCERPC_EPMAPPER_VERSION,
681 if (!NT_STATUS_IS_OK(status)) {
688 status = GUID_from_string(uuid, &binding->object);
689 if (NT_STATUS_IS_ERR(status)) {
693 binding->object_version = version;
695 status = dcerpc_binding_build_tower(p, binding, &twr.tower);
696 if (NT_STATUS_IS_ERR(status)) {
700 /* with some nice pretty paper around it of course */
702 r.in.map_tower = &twr;
703 r.in.entry_handle = &handle;
705 r.out.entry_handle = &handle;
707 status = dcerpc_epm_Map(p, p, &r);
708 if (!NT_STATUS_IS_OK(status)) {
709 dcerpc_pipe_close(p);
712 if (r.out.result != 0 || r.out.num_towers != 1) {
713 dcerpc_pipe_close(p);
714 return NT_STATUS_PORT_UNREACHABLE;
717 twr_r = r.out.towers[0].twr;
719 dcerpc_pipe_close(p);
720 return NT_STATUS_PORT_UNREACHABLE;
723 if (twr_r->tower.num_floors != twr.tower.num_floors ||
724 twr_r->tower.floors[3].lhs.protocol != twr.tower.floors[3].lhs.protocol) {
725 dcerpc_pipe_close(p);
726 return NT_STATUS_PORT_UNREACHABLE;
729 binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &twr_r->tower.floors[3]);
731 dcerpc_pipe_close(p);
737 /* open a rpc connection to a rpc pipe on SMB using the binding
738 structure to determine the endpoint and options */
739 static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
740 struct dcerpc_binding *binding,
741 const char *pipe_uuid,
742 uint32_t pipe_version,
744 const char *username,
745 const char *password)
749 struct smbcli_state *cli;
750 const char *pipe_name;
751 TALLOC_CTX *mem_ctx = talloc_init("dcerpc_pipe_connect_ncacn_np");
753 if (!binding->endpoint) {
754 const struct dcerpc_interface_table *table = idl_iface_by_uuid(pipe_uuid);
755 struct dcerpc_binding default_binding;
759 DEBUG(0,("Unknown interface endpoint '%s'\n", pipe_uuid));
760 talloc_destroy(mem_ctx);
761 return NT_STATUS_INVALID_PARAMETER;
764 /* Find one of the default pipes for this interface */
765 for (i = 0; i < table->endpoints->count; i++) {
766 status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding);
768 if (NT_STATUS_IS_OK(status) && default_binding.transport == NCACN_NP) {
769 pipe_name = default_binding.endpoint;
775 pipe_name = binding->endpoint;
778 if (!strncasecmp(pipe_name, "/pipe/", 6) ||
779 !strncasecmp(pipe_name, "\\pipe\\", 6)) {
783 if (pipe_name[0] != '\\') {
784 pipe_name = talloc_asprintf(mem_ctx, "\\%s", pipe_name);
787 if (!username || !username[0] ||
788 (binding->flags & DCERPC_SCHANNEL_ANY)) {
789 status = smbcli_full_connection(NULL, &cli, lp_netbios_name(),
792 "", "", NULL, 0, &retry);
794 status = smbcli_full_connection(NULL, &cli, lp_netbios_name(),
798 password, 0, &retry);
800 if (!NT_STATUS_IS_OK(status)) {
801 DEBUG(0,("Failed to connect to %s - %s\n", binding->host, nt_errstr(status)));
802 talloc_destroy(mem_ctx);
806 status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name);
807 if (!NT_STATUS_IS_OK(status)) {
808 DEBUG(0,("Failed to open pipe %s - %s\n", pipe_name, nt_errstr(status)));
810 smbcli_shutdown(cli);
811 talloc_destroy(mem_ctx);
815 talloc_destroy(mem_ctx);
817 /* this ensures that the reference count is decremented so
818 a pipe close will really close the link */
819 talloc_steal(*p, cli);
821 (*p)->flags = binding->flags;
823 /* remember the binding string for possible secondary connections */
824 (*p)->binding_string = dcerpc_binding_string((*p), binding);
826 if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
827 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
828 domain, username, password);
829 } else if (username && username[0] &&
830 (binding->flags & (DCERPC_CONNECT|DCERPC_SIGN|DCERPC_SEAL))) {
831 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
833 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
837 if (!NT_STATUS_IS_OK(status)) {
838 DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
839 dcerpc_pipe_close(*p);
847 /* open a rpc connection to a rpc pipe on SMP using the binding
848 structure to determine the endpoint and options */
849 static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **p,
850 struct dcerpc_binding *binding,
851 const char *pipe_uuid,
852 uint32_t pipe_version,
854 const char *username,
855 const char *password)
858 TALLOC_CTX *mem_ctx = talloc_init("dcerpc_pipe_connect_ncalrpc");
860 /* Look up identifier using the epmapper */
861 if (!binding->endpoint) {
862 status = dcerpc_epm_map_binding(mem_ctx, binding, pipe_uuid, pipe_version);
863 if (!NT_STATUS_IS_OK(status)) {
864 DEBUG(0,("Failed to map DCERPC/TCP NCALRPC identifier for '%s' - %s\n",
865 pipe_uuid, nt_errstr(status)));
866 talloc_destroy(mem_ctx);
869 DEBUG(1,("Mapped to DCERPC/TCP identifier %s\n", binding->endpoint));
872 status = dcerpc_pipe_open_pipe(p, binding->endpoint);
874 if (!NT_STATUS_IS_OK(status)) {
875 DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", binding->endpoint, nt_errstr(status)));
876 talloc_destroy(mem_ctx);
880 (*p)->flags = binding->flags;
882 /* remember the binding string for possible secondary connections */
883 (*p)->binding_string = dcerpc_binding_string((*p), binding);
885 if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
886 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
887 domain, username, password);
888 } else if (username && username[0]) {
889 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
891 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
894 if (!NT_STATUS_IS_OK(status)) {
895 DEBUG(0,("Failed to bind to uuid %s - %s\n",
896 pipe_uuid, nt_errstr(status)));
897 dcerpc_pipe_close(*p);
899 talloc_destroy(mem_ctx);
903 talloc_destroy(mem_ctx);
909 /* open a rpc connection to a rpc pipe on SMP using the binding
910 structure to determine the endpoint and options */
911 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **p,
912 struct dcerpc_binding *binding,
913 const char *pipe_uuid,
914 uint32_t pipe_version,
916 const char *username,
917 const char *password)
921 if (!binding->endpoint) {
922 DEBUG(0, ("Path to unix socket not specified\n"));
923 return NT_STATUS_INVALID_PARAMETER;
926 status = dcerpc_pipe_open_unix_stream(p, binding->endpoint);
927 if (!NT_STATUS_IS_OK(status)) {
928 DEBUG(0,("Failed to open unix socket %s - %s\n",
929 binding->endpoint, nt_errstr(status)));
933 (*p)->flags = binding->flags;
935 /* remember the binding string for possible secondary connections */
936 (*p)->binding_string = dcerpc_binding_string((*p), binding);
938 if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
939 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
940 domain, username, password);
941 } else if (username && username[0]) {
942 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
944 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
947 if (!NT_STATUS_IS_OK(status)) {
948 DEBUG(0,("Failed to bind to uuid %s - %s\n",
949 pipe_uuid, nt_errstr(status)));
950 dcerpc_pipe_close(*p);
958 /* open a rpc connection to a rpc pipe on SMP using the binding
959 structure to determine the endpoint and options */
960 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p,
961 struct dcerpc_binding *binding,
962 const char *pipe_uuid,
963 uint32_t pipe_version,
965 const char *username,
966 const char *password)
970 TALLOC_CTX *mem_ctx = talloc_init("connect_ncacn_ip_tcp");
972 if (!binding->endpoint) {
973 status = dcerpc_epm_map_binding(mem_ctx, binding,
974 pipe_uuid, pipe_version);
975 if (!NT_STATUS_IS_OK(status)) {
976 DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n",
977 pipe_uuid, nt_errstr(status)));
980 DEBUG(1,("Mapped to DCERPC/TCP port %s\n", binding->endpoint));
983 port = atoi(binding->endpoint);
985 status = dcerpc_pipe_open_tcp(p, binding->host, port);
986 if (!NT_STATUS_IS_OK(status)) {
987 DEBUG(0,("Failed to connect to %s:%d\n", binding->host, port));
991 (*p)->flags = binding->flags;
993 /* remember the binding string for possible secondary connections */
994 (*p)->binding_string = dcerpc_binding_string((*p), binding);
996 if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
997 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
998 domain, username, password);
999 } else if (username && username[0]) {
1000 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
1002 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
1005 if (!NT_STATUS_IS_OK(status)) {
1006 DEBUG(0,("Failed to bind to uuid %s - %s\n",
1007 pipe_uuid, nt_errstr(status)));
1008 dcerpc_pipe_close(*p);
1017 /* open a rpc connection to a rpc pipe, using the specified
1018 binding structure to determine the endpoint and options */
1019 NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p,
1020 struct dcerpc_binding *binding,
1021 const char *pipe_uuid,
1022 uint32_t pipe_version,
1024 const char *username,
1025 const char *password)
1027 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
1029 switch (binding->transport) {
1031 status = dcerpc_pipe_connect_ncacn_np(p, binding, pipe_uuid, pipe_version,
1032 domain, username, password);
1035 status = dcerpc_pipe_connect_ncacn_ip_tcp(p, binding, pipe_uuid, pipe_version,
1036 domain, username, password);
1038 case NCACN_UNIX_STREAM:
1039 status = dcerpc_pipe_connect_ncacn_unix_stream(p, binding, pipe_uuid, pipe_version, domain, username, password);
1042 status = dcerpc_pipe_connect_ncalrpc(p, binding, pipe_uuid, pipe_version, domain, username, password);
1045 return NT_STATUS_NOT_SUPPORTED;
1052 /* open a rpc connection to a rpc pipe, using the specified string
1053 binding to determine the endpoint and options */
1054 NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p,
1055 const char *binding,
1056 const char *pipe_uuid,
1057 uint32_t pipe_version,
1059 const char *username,
1060 const char *password)
1062 struct dcerpc_binding b;
1064 TALLOC_CTX *mem_ctx;
1066 mem_ctx = talloc_init("dcerpc_pipe_connect");
1067 if (!mem_ctx) return NT_STATUS_NO_MEMORY;
1069 status = dcerpc_parse_binding(mem_ctx, binding, &b);
1070 if (!NT_STATUS_IS_OK(status)) {
1071 DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding));
1072 talloc_destroy(mem_ctx);
1076 DEBUG(3,("Using binding %s\n", dcerpc_binding_string(mem_ctx, &b)));
1078 status = dcerpc_pipe_connect_b(p, &b, pipe_uuid, pipe_version, domain, username, password);
1080 talloc_destroy(mem_ctx);
1086 create a secondary dcerpc connection from a primary connection
1088 if the primary is a SMB connection then the secondary connection
1089 will be on the same SMB connection, but use a new fnum
1091 NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
1092 const char *pipe_name,
1093 const char *pipe_uuid,
1094 uint32_t pipe_version)
1096 struct smbcli_tree *tree;
1097 NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
1098 struct dcerpc_binding b;
1100 switch (p->transport.transport) {
1102 tree = dcerpc_smb_tree(p);
1104 return NT_STATUS_INVALID_PARAMETER;
1107 status = dcerpc_pipe_open_smb(p2, tree, pipe_name);
1111 status = dcerpc_parse_binding(p, p->binding_string, &b);
1112 if (!NT_STATUS_IS_OK(status)) {
1115 b.flags &= ~DCERPC_AUTH_OPTIONS;
1116 status = dcerpc_pipe_connect_ncacn_ip_tcp(p2, &b, pipe_uuid,
1122 status = dcerpc_parse_binding(p, p->binding_string, &b);
1123 if (!NT_STATUS_IS_OK(status)) {
1126 b.flags &= ~DCERPC_AUTH_OPTIONS;
1127 status = dcerpc_pipe_connect_ncalrpc(p2, &b, pipe_uuid, pipe_version, NULL, NULL, NULL);
1131 return NT_STATUS_NOT_SUPPORTED;
1134 if (!NT_STATUS_IS_OK(status)) {
1138 talloc_steal(p, *p2);
1140 (*p2)->flags = p->flags;
1142 status = dcerpc_bind_auth_none(*p2, pipe_uuid, pipe_version);
1143 if (!NT_STATUS_IS_OK(status)) {
1147 return NT_STATUS_OK;
1150 NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p,
1151 DATA_BLOB *session_key)
1153 /* this took quite a few CPU cycles to find ... */
1154 session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
1155 session_key->length = 16;
1156 return NT_STATUS_OK;
1160 fetch the user session key - may be default (above) or the SMB session key
1162 NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
1163 DATA_BLOB *session_key)
1165 return p->security_state.session_key(p, session_key);
1170 log a rpc packet in a format suitable for ndrdump. This is especially useful
1171 for sealed packets, where ethereal cannot easily see the contents
1173 this triggers on a debug level of >= 10
1175 void dcerpc_log_packet(const struct dcerpc_interface_table *ndr,
1176 uint32_t opnum, uint32_t flags, DATA_BLOB *pkt)
1178 const int num_examples = 20;
1181 if (DEBUGLEVEL < 10) return;
1183 for (i=0;i<num_examples;i++) {
1185 asprintf(&name, "%s/rpclog/%s-%u.%d.%s",
1186 lp_lockdir(), ndr->name, opnum, i,
1187 (flags&NDR_IN)?"in":"out");
1191 if (!file_exist(name, NULL)) {
1192 if (file_save(name, pkt->data, pkt->length)) {
1193 DEBUG(10,("Logged rpc packet to %s\n", name));