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.
25 #include "system/network.h"
26 #include "librpc/gen_ndr/ndr_epmapper.h"
29 find the pipe name for a local IDL interface
31 const char *idl_pipe_name(const char *uuid
, uint32_t if_version
)
34 for (i
=0;dcerpc_pipes
[i
];i
++) {
35 if (strcasecmp(dcerpc_pipes
[i
]->uuid
, uuid
) == 0 &&
36 dcerpc_pipes
[i
]->if_version
== if_version
) {
37 return dcerpc_pipes
[i
]->name
;
44 find the number of calls defined by local IDL
46 int idl_num_calls(const char *uuid
, uint32_t if_version
)
49 for (i
=0;dcerpc_pipes
[i
];i
++) {
50 if (strcasecmp(dcerpc_pipes
[i
]->uuid
, uuid
) == 0 &&
51 dcerpc_pipes
[i
]->if_version
== if_version
) {
52 return dcerpc_pipes
[i
]->num_calls
;
60 find a dcerpc interface by name
62 const struct dcerpc_interface_table
*idl_iface_by_name(const char *name
)
65 for (i
=0;dcerpc_pipes
[i
];i
++) {
66 if (strcasecmp(dcerpc_pipes
[i
]->name
, name
) == 0) {
67 return dcerpc_pipes
[i
];
74 find a dcerpc interface by uuid
76 const struct dcerpc_interface_table
*idl_iface_by_uuid(const char *uuid
)
79 for (i
=0;dcerpc_pipes
[i
];i
++) {
80 if (strcasecmp(dcerpc_pipes
[i
]->uuid
, uuid
) == 0) {
81 return dcerpc_pipes
[i
];
90 push a dcerpc_packet into a blob, potentially with auth info
92 NTSTATUS
dcerpc_push_auth(DATA_BLOB
*blob
, TALLOC_CTX
*mem_ctx
,
93 struct dcerpc_packet
*pkt
,
94 struct dcerpc_auth
*auth_info
)
99 ndr
= ndr_push_init_ctx(mem_ctx
);
101 return NT_STATUS_NO_MEMORY
;
104 if (!(pkt
->drep
[0] & DCERPC_DREP_LE
)) {
105 ndr
->flags
|= LIBNDR_FLAG_BIGENDIAN
;
109 pkt
->auth_length
= auth_info
->credentials
.length
;
111 pkt
->auth_length
= 0;
114 status
= ndr_push_dcerpc_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
115 if (!NT_STATUS_IS_OK(status
)) {
120 status
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
, auth_info
);
123 *blob
= ndr_push_blob(ndr
);
125 /* fill in the frag length */
126 dcerpc_set_frag_length(blob
, blob
->length
);
131 #define MAX_PROTSEQ 10
133 static const struct {
135 enum dcerpc_transport_t transport
;
137 enum epm_protocols protseq
[MAX_PROTSEQ
];
139 { "ncacn_np", NCACN_NP
, 3,
140 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_SMB
, EPM_PROTOCOL_NETBIOS
}},
141 { "ncacn_ip_tcp", NCACN_IP_TCP
, 3,
142 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_TCP
, EPM_PROTOCOL_IP
} },
143 { "ncacn_http", NCACN_HTTP
, 3,
144 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_HTTP
, EPM_PROTOCOL_IP
} },
145 { "ncadg_ip_udp", NCACN_IP_UDP
, 3,
146 { EPM_PROTOCOL_NCADG
, EPM_PROTOCOL_UDP
, EPM_PROTOCOL_IP
} },
147 { "ncalrpc", NCALRPC
, 2,
148 { EPM_PROTOCOL_NCALRPC
, EPM_PROTOCOL_PIPE
} },
149 { "ncacn_unix_stream", NCACN_UNIX_STREAM
, 2,
150 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_UNIX_DS
} },
151 { "ncadg_unix_dgram", NCADG_UNIX_DGRAM
, 2,
152 { EPM_PROTOCOL_NCADG
, EPM_PROTOCOL_UNIX_DS
} },
153 { "ncacn_at_dsp", NCACN_AT_DSP
, 3,
154 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_APPLETALK
, EPM_PROTOCOL_DSP
} },
155 { "ncadg_at_ddp", NCADG_AT_DDP
, 3,
156 { EPM_PROTOCOL_NCADG
, EPM_PROTOCOL_APPLETALK
, EPM_PROTOCOL_DDP
} },
157 { "ncacn_vns_ssp", NCACN_VNS_SPP
, 3,
158 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_STREETTALK
, EPM_PROTOCOL_VINES_SPP
} },
159 { "ncacn_vns_ipc", NCACN_VNS_IPC
, 3,
160 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_STREETTALK
, EPM_PROTOCOL_VINES_IPC
}, },
161 { "ncadg_ipx", NCADG_IPX
, 2,
162 { EPM_PROTOCOL_NCADG
, EPM_PROTOCOL_IPX
},
164 { "ncacn_spx", NCACN_SPX
, 2,
165 { EPM_PROTOCOL_NCACN
, EPM_PROTOCOL_SPX
},
169 static const struct {
172 } ncacn_options
[] = {
173 {"sign", DCERPC_SIGN
},
174 {"seal", DCERPC_SEAL
},
175 {"connect", DCERPC_CONNECT
},
176 {"validate", DCERPC_DEBUG_VALIDATE_BOTH
},
177 {"print", DCERPC_DEBUG_PRINT_BOTH
},
178 {"padcheck", DCERPC_DEBUG_PAD_CHECK
},
179 {"bigendian", DCERPC_PUSH_BIGENDIAN
}
185 form a binding string from a binding structure
187 const char *dcerpc_binding_string(TALLOC_CTX
*mem_ctx
, const struct dcerpc_binding
*b
)
189 char *s
= talloc_strdup(mem_ctx
, "");
191 const char *t_name
=NULL
;
193 for (i
=0;i
<ARRAY_SIZE(transports
);i
++) {
194 if (transports
[i
].transport
== b
->transport
) {
195 t_name
= transports
[i
].name
;
202 if (!uuid_all_zero(&b
->object
)) {
203 s
= talloc_asprintf(s
, "%s@",
204 GUID_string(mem_ctx
, &b
->object
));
207 s
= talloc_asprintf_append(s
, "%s:", t_name
);
211 s
= talloc_asprintf_append(s
, "%s", b
->host
);
214 if (!b
->endpoint
&& !b
->options
&& !b
->flags
) {
218 s
= talloc_asprintf_append(s
, "[");
221 s
= talloc_asprintf_append(s
, "%s", b
->endpoint
);
224 /* this is a *really* inefficent way of dealing with strings,
225 but this is rarely called and the strings are always short,
227 for (i
=0;b
->options
&& b
->options
[i
];i
++) {
228 s
= talloc_asprintf_append(s
, ",%s", b
->options
[i
]);
232 for (i
=0;i
<ARRAY_SIZE(ncacn_options
);i
++) {
233 if (b
->flags
& ncacn_options
[i
].flag
) {
234 s
= talloc_asprintf_append(s
, ",%s", ncacn_options
[i
].name
);
239 s
= talloc_asprintf_append(s
, "]");
245 parse a binding string into a dcerpc_binding structure
247 NTSTATUS
dcerpc_parse_binding(TALLOC_CTX
*mem_ctx
, const char *s
, struct dcerpc_binding
*b
)
249 char *options
, *type
;
251 int i
, j
, comma_count
;
255 if (p
&& PTR_DIFF(p
, s
) == 36) { /* 36 is the length of a UUID */
258 status
= GUID_from_string(s
, &b
->object
);
260 if (NT_STATUS_IS_ERR(status
)) {
261 DEBUG(0, ("Failed parsing UUID\n"));
267 ZERO_STRUCT(b
->object
);
270 b
->object_version
= 0;
274 return NT_STATUS_INVALID_PARAMETER
;
277 type
= talloc_strndup(mem_ctx
, s
, PTR_DIFF(p
, s
));
279 return NT_STATUS_NO_MEMORY
;
282 for (i
=0;i
<ARRAY_SIZE(transports
);i
++) {
283 if (strcasecmp(type
, transports
[i
].name
) == 0) {
284 b
->transport
= transports
[i
].transport
;
288 if (i
==ARRAY_SIZE(transports
)) {
289 DEBUG(0,("Unknown dcerpc transport '%s'\n", type
));
290 return NT_STATUS_INVALID_PARAMETER
;
297 b
->host
= talloc_strndup(mem_ctx
, s
, PTR_DIFF(p
, s
));
298 options
= talloc_strdup(mem_ctx
, p
+1);
299 if (options
[strlen(options
)-1] != ']') {
300 return NT_STATUS_INVALID_PARAMETER
;
302 options
[strlen(options
)-1] = 0;
304 b
->host
= talloc_strdup(mem_ctx
, s
);
309 return NT_STATUS_NO_MEMORY
;
320 comma_count
= count_chars(options
, ',');
322 b
->options
= talloc_array_p(mem_ctx
, const char *, comma_count
+2);
324 return NT_STATUS_NO_MEMORY
;
327 for (i
=0; (p
= strchr(options
, ',')); i
++) {
328 b
->options
[i
] = talloc_strndup(mem_ctx
, options
, PTR_DIFF(p
, options
));
329 if (!b
->options
[i
]) {
330 return NT_STATUS_NO_MEMORY
;
334 b
->options
[i
] = options
;
335 b
->options
[i
+1] = NULL
;
337 /* some options are pre-parsed for convenience */
338 for (i
=0;b
->options
[i
];i
++) {
339 for (j
=0;j
<ARRAY_SIZE(ncacn_options
);j
++) {
340 if (strcasecmp(ncacn_options
[j
].name
, b
->options
[i
]) == 0) {
342 b
->flags
|= ncacn_options
[j
].flag
;
343 for (k
=i
;b
->options
[k
];k
++) {
344 b
->options
[k
] = b
->options
[k
+1];
353 /* Endpoint is first option */
354 b
->endpoint
= b
->options
[0];
355 if (strlen(b
->endpoint
) == 0) b
->endpoint
= NULL
;
357 for (i
=0;b
->options
[i
];i
++) {
358 b
->options
[i
] = b
->options
[i
+1];
362 if (b
->options
[0] == NULL
)
368 const char *dcerpc_floor_get_rhs_data(TALLOC_CTX
*mem_ctx
, struct epm_floor
*floor
)
370 switch (floor
->lhs
.protocol
) {
371 case EPM_PROTOCOL_TCP
:
372 if (floor
->rhs
.tcp
.port
== 0) return NULL
;
373 return talloc_asprintf(mem_ctx
, "%d", floor
->rhs
.tcp
.port
);
375 case EPM_PROTOCOL_UDP
:
376 if (floor
->rhs
.udp
.port
== 0) return NULL
;
377 return talloc_asprintf(mem_ctx
, "%d", floor
->rhs
.udp
.port
);
379 case EPM_PROTOCOL_HTTP
:
380 if (floor
->rhs
.http
.port
== 0) return NULL
;
381 return talloc_asprintf(mem_ctx
, "%d", floor
->rhs
.http
.port
);
383 case EPM_PROTOCOL_IP
:
384 if (floor
->rhs
.ip
.address
== 0) {
390 in
.s_addr
= htonl(floor
->rhs
.ip
.address
);
391 return talloc_strdup(mem_ctx
, sys_inet_ntoa(in
));
394 case EPM_PROTOCOL_NCACN
:
397 case EPM_PROTOCOL_NCADG
:
400 case EPM_PROTOCOL_SMB
:
401 if (strlen(floor
->rhs
.smb
.unc
) == 0) return NULL
;
402 return talloc_strdup(mem_ctx
, floor
->rhs
.smb
.unc
);
404 case EPM_PROTOCOL_PIPE
:
405 if (strlen(floor
->rhs
.pipe
.path
) == 0) return NULL
;
406 return talloc_strdup(mem_ctx
, floor
->rhs
.pipe
.path
);
408 case EPM_PROTOCOL_NETBIOS
:
409 if (strlen(floor
->rhs
.netbios
.name
) == 0) return NULL
;
410 return talloc_strdup(mem_ctx
, floor
->rhs
.netbios
.name
);
412 case EPM_PROTOCOL_NCALRPC
:
415 case EPM_PROTOCOL_VINES_SPP
:
416 return talloc_asprintf(mem_ctx
, "%d", floor
->rhs
.vines_spp
.port
);
418 case EPM_PROTOCOL_VINES_IPC
:
419 return talloc_asprintf(mem_ctx
, "%d", floor
->rhs
.vines_ipc
.port
);
421 case EPM_PROTOCOL_STREETTALK
:
422 return talloc_strdup(mem_ctx
, floor
->rhs
.streettalk
.streettalk
);
424 case EPM_PROTOCOL_UNIX_DS
:
425 if (strlen(floor
->rhs
.unix_ds
.path
) == 0) return NULL
;
426 return talloc_strdup(mem_ctx
, floor
->rhs
.unix_ds
.path
);
428 case EPM_PROTOCOL_NULL
:
435 static NTSTATUS
dcerpc_floor_set_rhs_data(TALLOC_CTX
*mem_ctx
, struct epm_floor
*floor
, const char *data
)
437 switch (floor
->lhs
.protocol
) {
438 case EPM_PROTOCOL_TCP
:
439 floor
->rhs
.tcp
.port
= atoi(data
);
442 case EPM_PROTOCOL_UDP
:
443 floor
->rhs
.udp
.port
= atoi(data
);
446 case EPM_PROTOCOL_HTTP
:
447 floor
->rhs
.http
.port
= atoi(data
);
450 case EPM_PROTOCOL_IP
:
451 if (strlen(data
) > 0) {
452 floor
->rhs
.ip
.address
= ntohl(interpret_addr(data
));
454 floor
->rhs
.ip
.address
= 0;
458 case EPM_PROTOCOL_NCACN
:
459 floor
->rhs
.ncacn
.minor_version
= 0;
462 case EPM_PROTOCOL_NCADG
:
463 floor
->rhs
.ncadg
.minor_version
= 0;
466 case EPM_PROTOCOL_SMB
:
467 floor
->rhs
.smb
.unc
= talloc_strdup(mem_ctx
, data
);
468 if (!floor
->rhs
.smb
.unc
) {
469 return NT_STATUS_NO_MEMORY
;
473 case EPM_PROTOCOL_PIPE
:
474 floor
->rhs
.pipe
.path
= talloc_strdup(mem_ctx
, data
);
475 if (!floor
->rhs
.pipe
.path
) {
476 return NT_STATUS_NO_MEMORY
;
480 case EPM_PROTOCOL_NETBIOS
:
481 floor
->rhs
.netbios
.name
= talloc_strdup(mem_ctx
, data
);
482 if (!floor
->rhs
.netbios
.name
) {
483 return NT_STATUS_NO_MEMORY
;
487 case EPM_PROTOCOL_NCALRPC
:
490 case EPM_PROTOCOL_VINES_SPP
:
491 floor
->rhs
.vines_spp
.port
= atoi(data
);
494 case EPM_PROTOCOL_VINES_IPC
:
495 floor
->rhs
.vines_ipc
.port
= atoi(data
);
498 case EPM_PROTOCOL_STREETTALK
:
499 floor
->rhs
.streettalk
.streettalk
= talloc_strdup(mem_ctx
, data
);
500 if (!floor
->rhs
.streettalk
.streettalk
) {
501 return NT_STATUS_NO_MEMORY
;
505 case EPM_PROTOCOL_UNIX_DS
:
506 floor
->rhs
.unix_ds
.path
= talloc_strdup(mem_ctx
, data
);
507 if (!floor
->rhs
.unix_ds
.path
) {
508 return NT_STATUS_NO_MEMORY
;
512 case EPM_PROTOCOL_NULL
:
516 return NT_STATUS_NOT_SUPPORTED
;
519 enum dcerpc_transport_t
dcerpc_transport_by_tower(struct epm_tower
*tower
)
523 /* Find a transport that matches this tower */
524 for (i
=0;i
<ARRAY_SIZE(transports
);i
++) {
526 if (transports
[i
].num_protocols
!= tower
->num_floors
- 2) {
530 for (j
= 0; j
< transports
[i
].num_protocols
; j
++) {
531 if (transports
[i
].protseq
[j
] != tower
->floors
[j
+2].lhs
.protocol
) {
536 if (j
== transports
[i
].num_protocols
) {
537 return transports
[i
].transport
;
541 /* Unknown transport */
545 NTSTATUS
dcerpc_binding_from_tower(TALLOC_CTX
*mem_ctx
, struct epm_tower
*tower
, struct dcerpc_binding
*binding
)
547 ZERO_STRUCT(binding
->object
);
548 binding
->options
= NULL
;
549 binding
->host
= NULL
;
552 binding
->transport
= dcerpc_transport_by_tower(tower
);
554 if (binding
->transport
== -1) {
555 return NT_STATUS_NOT_SUPPORTED
;
558 if (tower
->num_floors
< 1) {
562 /* Set object uuid */
563 binding
->object
= tower
->floors
[0].lhs
.info
.uuid
.uuid
;
564 binding
->object_version
= tower
->floors
[0].lhs
.info
.uuid
.version
;
566 /* Ignore floor 1, it contains the NDR version info */
568 binding
->options
= NULL
;
571 if (tower
->num_floors
>= 4) {
572 binding
->endpoint
= dcerpc_floor_get_rhs_data(mem_ctx
, &tower
->floors
[3]);
574 binding
->endpoint
= NULL
;
577 /* Set network address */
578 if (tower
->num_floors
>= 5) {
579 binding
->host
= dcerpc_floor_get_rhs_data(mem_ctx
, &tower
->floors
[4]);
584 NTSTATUS
dcerpc_binding_build_tower(TALLOC_CTX
*mem_ctx
, struct dcerpc_binding
*binding
, struct epm_tower
*tower
)
586 const enum epm_protocols
*protseq
;
587 int num_protocols
= -1, i
;
591 for (i
=0;i
<ARRAY_SIZE(transports
);i
++) {
592 if (transports
[i
].transport
== binding
->transport
) {
593 protseq
= transports
[i
].protseq
;
594 num_protocols
= transports
[i
].num_protocols
;
599 if (num_protocols
== -1) {
600 DEBUG(0, ("Unable to find transport with id '%d'\n", binding
->transport
));
601 return NT_STATUS_UNSUCCESSFUL
;
604 tower
->num_floors
= 2 + num_protocols
;
605 tower
->floors
= talloc_array_p(mem_ctx
, struct epm_floor
, tower
->num_floors
);
608 tower
->floors
[0].lhs
.protocol
= EPM_PROTOCOL_UUID
;
609 tower
->floors
[0].lhs
.info
.uuid
.uuid
= binding
->object
;
610 tower
->floors
[0].lhs
.info
.uuid
.version
= binding
->object_version
;
611 tower
->floors
[0].rhs
.uuid
.unknown
= 0;
614 tower
->floors
[1].lhs
.protocol
= EPM_PROTOCOL_UUID
;
615 tower
->floors
[1].lhs
.info
.uuid
.version
= NDR_GUID_VERSION
;
616 tower
->floors
[1].rhs
.uuid
.unknown
= 0;
617 status
= GUID_from_string(NDR_GUID
, &tower
->floors
[1].lhs
.info
.uuid
.uuid
);
618 if (NT_STATUS_IS_ERR(status
)) {
622 /* Floor 2 to num_protocols */
623 for (i
= 0; i
< num_protocols
; i
++) {
624 tower
->floors
[2 + i
].lhs
.protocol
= protseq
[i
];
625 tower
->floors
[2 + i
].lhs
.info
.lhs_data
= data_blob_talloc(mem_ctx
, NULL
, 0);
626 ZERO_STRUCT(tower
->floors
[2 + i
].rhs
);
627 dcerpc_floor_set_rhs_data(mem_ctx
, &tower
->floors
[2 + i
], "");
630 /* The 4th floor contains the endpoint */
631 if (num_protocols
>= 2 && binding
->endpoint
) {
632 status
= dcerpc_floor_set_rhs_data(mem_ctx
, &tower
->floors
[3], binding
->endpoint
);
633 if (NT_STATUS_IS_ERR(status
)) {
638 /* The 5th contains the network address */
639 if (num_protocols
>= 3 && binding
->host
) {
640 status
= dcerpc_floor_set_rhs_data(mem_ctx
, &tower
->floors
[4], binding
->host
);
641 if (NT_STATUS_IS_ERR(status
)) {
649 NTSTATUS
dcerpc_epm_map_binding(TALLOC_CTX
*mem_ctx
, struct dcerpc_binding
*binding
,
650 const char *uuid
, uint_t version
)
652 struct dcerpc_pipe
*p
;
655 struct policy_handle handle
;
657 struct epm_twr_t twr
, *twr_r
;
658 struct dcerpc_binding epmapper_binding
;
661 if (!strcmp(uuid
, DCERPC_EPMAPPER_UUID
)) {
662 switch(binding
->transport
) {
663 case NCACN_IP_TCP
: binding
->endpoint
= talloc_asprintf(mem_ctx
, "%d", EPMAPPER_PORT
); return NT_STATUS_OK
;
664 case NCALRPC
: binding
->endpoint
= EPMAPPER_IDENTIFIER
; return NT_STATUS_OK
;
665 default: return NT_STATUS_NOT_SUPPORTED
;
670 ZERO_STRUCT(epmapper_binding
);
671 epmapper_binding
.transport
= binding
->transport
;
672 epmapper_binding
.host
= binding
->host
;
673 epmapper_binding
.options
= NULL
;
674 epmapper_binding
.flags
= 0;
675 epmapper_binding
.endpoint
= NULL
;
677 status
= dcerpc_pipe_connect_b(&p
,
679 DCERPC_EPMAPPER_UUID
,
680 DCERPC_EPMAPPER_VERSION
,
683 if (!NT_STATUS_IS_OK(status
)) {
690 status
= GUID_from_string(uuid
, &binding
->object
);
691 if (NT_STATUS_IS_ERR(status
)) {
695 binding
->object_version
= version
;
697 status
= dcerpc_binding_build_tower(p
, binding
, &twr
.tower
);
698 if (NT_STATUS_IS_ERR(status
)) {
702 /* with some nice pretty paper around it of course */
704 r
.in
.map_tower
= &twr
;
705 r
.in
.entry_handle
= &handle
;
707 r
.out
.entry_handle
= &handle
;
709 status
= dcerpc_epm_Map(p
, p
, &r
);
710 if (!NT_STATUS_IS_OK(status
)) {
711 dcerpc_pipe_close(p
);
714 if (r
.out
.result
!= 0 || r
.out
.num_towers
!= 1) {
715 dcerpc_pipe_close(p
);
716 return NT_STATUS_PORT_UNREACHABLE
;
719 twr_r
= r
.out
.towers
[0].twr
;
721 dcerpc_pipe_close(p
);
722 return NT_STATUS_PORT_UNREACHABLE
;
725 if (twr_r
->tower
.num_floors
!= twr
.tower
.num_floors
||
726 twr_r
->tower
.floors
[3].lhs
.protocol
!= twr
.tower
.floors
[3].lhs
.protocol
) {
727 dcerpc_pipe_close(p
);
728 return NT_STATUS_PORT_UNREACHABLE
;
731 binding
->endpoint
= dcerpc_floor_get_rhs_data(mem_ctx
, &twr_r
->tower
.floors
[3]);
733 dcerpc_pipe_close(p
);
739 /* open a rpc connection to a rpc pipe on SMB using the binding
740 structure to determine the endpoint and options */
741 static NTSTATUS
dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe
**p
,
742 struct dcerpc_binding
*binding
,
743 const char *pipe_uuid
,
744 uint32_t pipe_version
,
746 const char *username
,
747 const char *password
)
751 struct smbcli_state
*cli
;
752 const char *pipe_name
= NULL
;
753 TALLOC_CTX
*mem_ctx
= talloc_init("dcerpc_pipe_connect_ncacn_np");
755 if (!binding
->endpoint
) {
756 const struct dcerpc_interface_table
*table
= idl_iface_by_uuid(pipe_uuid
);
757 struct dcerpc_binding default_binding
;
761 DEBUG(0,("Unknown interface endpoint '%s'\n", pipe_uuid
));
762 talloc_destroy(mem_ctx
);
763 return NT_STATUS_INVALID_PARAMETER
;
766 /* Find one of the default pipes for this interface */
767 for (i
= 0; i
< table
->endpoints
->count
; i
++) {
768 status
= dcerpc_parse_binding(mem_ctx
, table
->endpoints
->names
[i
], &default_binding
);
770 if (NT_STATUS_IS_OK(status
) && default_binding
.transport
== NCACN_NP
) {
771 pipe_name
= default_binding
.endpoint
;
777 if (pipe_name
== NULL
) {
778 DEBUG(0, ("No default named pipe specified for interface with UUID %s\n", pipe_uuid
));
779 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
782 pipe_name
= binding
->endpoint
;
785 if (!strncasecmp(pipe_name
, "/pipe/", 6) ||
786 !strncasecmp(pipe_name
, "\\pipe\\", 6)) {
790 if (pipe_name
[0] != '\\') {
791 pipe_name
= talloc_asprintf(mem_ctx
, "\\%s", pipe_name
);
794 if (!username
|| !username
[0] ||
795 (binding
->flags
& DCERPC_SCHANNEL_ANY
)) {
796 status
= smbcli_full_connection(NULL
, &cli
, lp_netbios_name(),
799 "", "", NULL
, 0, &retry
);
801 status
= smbcli_full_connection(NULL
, &cli
, lp_netbios_name(),
805 password
, 0, &retry
);
807 if (!NT_STATUS_IS_OK(status
)) {
808 DEBUG(0,("Failed to connect to %s - %s\n", binding
->host
, nt_errstr(status
)));
809 talloc_destroy(mem_ctx
);
813 status
= dcerpc_pipe_open_smb(p
, cli
->tree
, pipe_name
);
814 if (!NT_STATUS_IS_OK(status
)) {
815 DEBUG(0,("Failed to open pipe %s - %s\n", pipe_name
, nt_errstr(status
)));
817 smbcli_shutdown(cli
);
818 talloc_destroy(mem_ctx
);
822 talloc_destroy(mem_ctx
);
824 /* this ensures that the reference count is decremented so
825 a pipe close will really close the link */
826 talloc_steal(*p
, cli
);
828 (*p
)->flags
= binding
->flags
;
830 /* remember the binding string for possible secondary connections */
831 (*p
)->binding_string
= dcerpc_binding_string((*p
), binding
);
833 if (username
&& username
[0] && (binding
->flags
& DCERPC_SCHANNEL_ANY
)) {
834 status
= dcerpc_bind_auth_schannel(*p
, pipe_uuid
, pipe_version
,
835 domain
, username
, password
);
836 } else if (username
&& username
[0] &&
837 (binding
->flags
& (DCERPC_CONNECT
|DCERPC_SIGN
|DCERPC_SEAL
))) {
838 status
= dcerpc_bind_auth_ntlm(*p
, pipe_uuid
, pipe_version
, domain
, username
, password
);
840 status
= dcerpc_bind_auth_none(*p
, pipe_uuid
, pipe_version
);
844 if (!NT_STATUS_IS_OK(status
)) {
845 DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid
, nt_errstr(status
)));
846 dcerpc_pipe_close(*p
);
854 /* open a rpc connection to a rpc pipe on SMP using the binding
855 structure to determine the endpoint and options */
856 static NTSTATUS
dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe
**p
,
857 struct dcerpc_binding
*binding
,
858 const char *pipe_uuid
,
859 uint32_t pipe_version
,
861 const char *username
,
862 const char *password
)
865 TALLOC_CTX
*mem_ctx
= talloc_init("dcerpc_pipe_connect_ncalrpc");
867 /* Look up identifier using the epmapper */
868 if (!binding
->endpoint
) {
869 status
= dcerpc_epm_map_binding(mem_ctx
, binding
, pipe_uuid
, pipe_version
);
870 if (!NT_STATUS_IS_OK(status
)) {
871 DEBUG(0,("Failed to map DCERPC/TCP NCALRPC identifier for '%s' - %s\n",
872 pipe_uuid
, nt_errstr(status
)));
873 talloc_destroy(mem_ctx
);
876 DEBUG(1,("Mapped to DCERPC/TCP identifier %s\n", binding
->endpoint
));
879 status
= dcerpc_pipe_open_pipe(p
, binding
->endpoint
);
881 if (!NT_STATUS_IS_OK(status
)) {
882 DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", binding
->endpoint
, nt_errstr(status
)));
883 talloc_destroy(mem_ctx
);
887 (*p
)->flags
= binding
->flags
;
889 /* remember the binding string for possible secondary connections */
890 (*p
)->binding_string
= dcerpc_binding_string((*p
), binding
);
892 if (username
&& username
[0] && (binding
->flags
& DCERPC_SCHANNEL_ANY
)) {
893 status
= dcerpc_bind_auth_schannel(*p
, pipe_uuid
, pipe_version
,
894 domain
, username
, password
);
895 } else if (username
&& username
[0]) {
896 status
= dcerpc_bind_auth_ntlm(*p
, pipe_uuid
, pipe_version
, domain
, username
, password
);
898 status
= dcerpc_bind_auth_none(*p
, pipe_uuid
, pipe_version
);
901 if (!NT_STATUS_IS_OK(status
)) {
902 DEBUG(0,("Failed to bind to uuid %s - %s\n",
903 pipe_uuid
, nt_errstr(status
)));
904 dcerpc_pipe_close(*p
);
906 talloc_destroy(mem_ctx
);
910 talloc_destroy(mem_ctx
);
916 /* open a rpc connection to a rpc pipe on SMP using the binding
917 structure to determine the endpoint and options */
918 static NTSTATUS
dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe
**p
,
919 struct dcerpc_binding
*binding
,
920 const char *pipe_uuid
,
921 uint32_t pipe_version
,
923 const char *username
,
924 const char *password
)
928 if (!binding
->endpoint
) {
929 DEBUG(0, ("Path to unix socket not specified\n"));
930 return NT_STATUS_INVALID_PARAMETER
;
933 status
= dcerpc_pipe_open_unix_stream(p
, binding
->endpoint
);
934 if (!NT_STATUS_IS_OK(status
)) {
935 DEBUG(0,("Failed to open unix socket %s - %s\n",
936 binding
->endpoint
, nt_errstr(status
)));
940 (*p
)->flags
= binding
->flags
;
942 /* remember the binding string for possible secondary connections */
943 (*p
)->binding_string
= dcerpc_binding_string((*p
), binding
);
945 if (username
&& username
[0] && (binding
->flags
& DCERPC_SCHANNEL_ANY
)) {
946 status
= dcerpc_bind_auth_schannel(*p
, pipe_uuid
, pipe_version
,
947 domain
, username
, password
);
948 } else if (username
&& username
[0]) {
949 status
= dcerpc_bind_auth_ntlm(*p
, pipe_uuid
, pipe_version
, domain
, username
, password
);
951 status
= dcerpc_bind_auth_none(*p
, pipe_uuid
, pipe_version
);
954 if (!NT_STATUS_IS_OK(status
)) {
955 DEBUG(0,("Failed to bind to uuid %s - %s\n",
956 pipe_uuid
, nt_errstr(status
)));
957 dcerpc_pipe_close(*p
);
965 /* open a rpc connection to a rpc pipe on SMP using the binding
966 structure to determine the endpoint and options */
967 static NTSTATUS
dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe
**p
,
968 struct dcerpc_binding
*binding
,
969 const char *pipe_uuid
,
970 uint32_t pipe_version
,
972 const char *username
,
973 const char *password
)
977 TALLOC_CTX
*mem_ctx
= talloc_init("connect_ncacn_ip_tcp");
979 if (!binding
->endpoint
) {
980 status
= dcerpc_epm_map_binding(mem_ctx
, binding
,
981 pipe_uuid
, pipe_version
);
982 if (!NT_STATUS_IS_OK(status
)) {
983 DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n",
984 pipe_uuid
, nt_errstr(status
)));
987 DEBUG(1,("Mapped to DCERPC/TCP port %s\n", binding
->endpoint
));
990 port
= atoi(binding
->endpoint
);
992 status
= dcerpc_pipe_open_tcp(p
, binding
->host
, port
);
993 if (!NT_STATUS_IS_OK(status
)) {
994 DEBUG(0,("Failed to connect to %s:%d\n", binding
->host
, port
));
998 (*p
)->flags
= binding
->flags
;
1000 /* remember the binding string for possible secondary connections */
1001 (*p
)->binding_string
= dcerpc_binding_string((*p
), binding
);
1003 if (username
&& username
[0] && (binding
->flags
& DCERPC_SCHANNEL_ANY
)) {
1004 status
= dcerpc_bind_auth_schannel(*p
, pipe_uuid
, pipe_version
,
1005 domain
, username
, password
);
1006 } else if (username
&& username
[0]) {
1007 status
= dcerpc_bind_auth_ntlm(*p
, pipe_uuid
, pipe_version
, domain
, username
, password
);
1009 status
= dcerpc_bind_auth_none(*p
, pipe_uuid
, pipe_version
);
1012 if (!NT_STATUS_IS_OK(status
)) {
1013 DEBUG(0,("Failed to bind to uuid %s - %s\n",
1014 pipe_uuid
, nt_errstr(status
)));
1015 dcerpc_pipe_close(*p
);
1024 /* open a rpc connection to a rpc pipe, using the specified
1025 binding structure to determine the endpoint and options */
1026 NTSTATUS
dcerpc_pipe_connect_b(struct dcerpc_pipe
**p
,
1027 struct dcerpc_binding
*binding
,
1028 const char *pipe_uuid
,
1029 uint32_t pipe_version
,
1031 const char *username
,
1032 const char *password
)
1034 NTSTATUS status
= NT_STATUS_INVALID_PARAMETER
;
1036 switch (binding
->transport
) {
1038 status
= dcerpc_pipe_connect_ncacn_np(p
, binding
, pipe_uuid
, pipe_version
,
1039 domain
, username
, password
);
1042 status
= dcerpc_pipe_connect_ncacn_ip_tcp(p
, binding
, pipe_uuid
, pipe_version
,
1043 domain
, username
, password
);
1045 case NCACN_UNIX_STREAM
:
1046 status
= dcerpc_pipe_connect_ncacn_unix_stream(p
, binding
, pipe_uuid
, pipe_version
, domain
, username
, password
);
1049 status
= dcerpc_pipe_connect_ncalrpc(p
, binding
, pipe_uuid
, pipe_version
, domain
, username
, password
);
1052 return NT_STATUS_NOT_SUPPORTED
;
1059 /* open a rpc connection to a rpc pipe, using the specified string
1060 binding to determine the endpoint and options */
1061 NTSTATUS
dcerpc_pipe_connect(struct dcerpc_pipe
**p
,
1062 const char *binding
,
1063 const char *pipe_uuid
,
1064 uint32_t pipe_version
,
1066 const char *username
,
1067 const char *password
)
1069 struct dcerpc_binding b
;
1071 TALLOC_CTX
*mem_ctx
;
1073 mem_ctx
= talloc_init("dcerpc_pipe_connect");
1074 if (!mem_ctx
) return NT_STATUS_NO_MEMORY
;
1076 status
= dcerpc_parse_binding(mem_ctx
, binding
, &b
);
1077 if (!NT_STATUS_IS_OK(status
)) {
1078 DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding
));
1079 talloc_destroy(mem_ctx
);
1083 DEBUG(3,("Using binding %s\n", dcerpc_binding_string(mem_ctx
, &b
)));
1085 status
= dcerpc_pipe_connect_b(p
, &b
, pipe_uuid
, pipe_version
, domain
, username
, password
);
1087 talloc_destroy(mem_ctx
);
1093 create a secondary dcerpc connection from a primary connection
1095 if the primary is a SMB connection then the secondary connection
1096 will be on the same SMB connection, but use a new fnum
1098 NTSTATUS
dcerpc_secondary_connection(struct dcerpc_pipe
*p
, struct dcerpc_pipe
**p2
,
1099 const char *pipe_name
,
1100 const char *pipe_uuid
,
1101 uint32_t pipe_version
)
1103 struct smbcli_tree
*tree
;
1104 NTSTATUS status
= NT_STATUS_INVALID_PARAMETER
;
1105 struct dcerpc_binding b
;
1107 switch (p
->transport
.transport
) {
1109 tree
= dcerpc_smb_tree(p
);
1111 return NT_STATUS_INVALID_PARAMETER
;
1114 status
= dcerpc_pipe_open_smb(p2
, tree
, pipe_name
);
1118 status
= dcerpc_parse_binding(p
, p
->binding_string
, &b
);
1119 if (!NT_STATUS_IS_OK(status
)) {
1122 b
.flags
&= ~DCERPC_AUTH_OPTIONS
;
1123 status
= dcerpc_pipe_connect_ncacn_ip_tcp(p2
, &b
, pipe_uuid
,
1129 status
= dcerpc_parse_binding(p
, p
->binding_string
, &b
);
1130 if (!NT_STATUS_IS_OK(status
)) {
1133 b
.flags
&= ~DCERPC_AUTH_OPTIONS
;
1134 status
= dcerpc_pipe_connect_ncalrpc(p2
, &b
, pipe_uuid
, pipe_version
, NULL
, NULL
, NULL
);
1138 return NT_STATUS_NOT_SUPPORTED
;
1141 if (!NT_STATUS_IS_OK(status
)) {
1145 talloc_steal(p
, *p2
);
1147 (*p2
)->flags
= p
->flags
;
1149 status
= dcerpc_bind_auth_none(*p2
, pipe_uuid
, pipe_version
);
1150 if (!NT_STATUS_IS_OK(status
)) {
1154 return NT_STATUS_OK
;
1157 NTSTATUS
dcerpc_generic_session_key(struct dcerpc_pipe
*p
,
1158 DATA_BLOB
*session_key
)
1160 /* this took quite a few CPU cycles to find ... */
1161 session_key
->data
= discard_const_p(unsigned char, "SystemLibraryDTC");
1162 session_key
->length
= 16;
1163 return NT_STATUS_OK
;
1167 fetch the user session key - may be default (above) or the SMB session key
1169 NTSTATUS
dcerpc_fetch_session_key(struct dcerpc_pipe
*p
,
1170 DATA_BLOB
*session_key
)
1172 return p
->security_state
.session_key(p
, session_key
);
1177 log a rpc packet in a format suitable for ndrdump. This is especially useful
1178 for sealed packets, where ethereal cannot easily see the contents
1180 this triggers on a debug level of >= 10
1182 void dcerpc_log_packet(const struct dcerpc_interface_table
*ndr
,
1183 uint32_t opnum
, uint32_t flags
, DATA_BLOB
*pkt
)
1185 const int num_examples
= 20;
1188 if (DEBUGLEVEL
< 10) return;
1190 for (i
=0;i
<num_examples
;i
++) {
1192 asprintf(&name
, "%s/rpclog/%s-%u.%d.%s",
1193 lp_lockdir(), ndr
->name
, opnum
, i
,
1194 (flags
&NDR_IN
)?"in":"out");
1198 if (!file_exist(name
, NULL
)) {
1199 if (file_save(name
, pkt
->data
, pkt
->length
)) {
1200 DEBUG(10,("Logged rpc packet to %s\n", name
));