summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-02-10 10:22:12 +0000
committerAndrew Tridgell <tridge@samba.org>2004-02-10 10:22:12 +0000
commit078cced5ec1026432f5df275a7023db70a62693e (patch)
tree3d9e8d162c9268cde955087cfc78b24b1167164e
parentf5cb6392b3810301614a99de2ecb938d925da519 (diff)
downloadsamba-078cced5ec1026432f5df275a7023db70a62693e.tar.gz
samba-078cced5ec1026432f5df275a7023db70a62693e.tar.bz2
samba-078cced5ec1026432f5df275a7023db70a62693e.zip
- modified the dcerpc client security code to be generic, so ntlmssp
and schannel are both instances of possible security modules - added schannel sign and sign/seal support to the dcerpc client code. You select it with binding options of "schannel,sign" or "schannel,seal". (This used to be commit 05db0b9d942cad8f1dd574dc35b759e5e79d4195)
-rw-r--r--source4/Makefile.in19
-rw-r--r--source4/include/includes.h1
-rw-r--r--source4/lib/crypto/hmacmd5.c2
-rw-r--r--source4/lib/hmacmd5.c2
-rw-r--r--source4/libcli/auth/schannel.c309
-rw-r--r--source4/libcli/auth/schannel.h35
-rw-r--r--source4/librpc/idl/dcerpc.idl7
-rw-r--r--source4/librpc/rpc/dcerpc.c42
-rw-r--r--source4/librpc/rpc/dcerpc.h27
-rw-r--r--source4/librpc/rpc/dcerpc_auth.c121
-rw-r--r--source4/librpc/rpc/dcerpc_ntlm.c197
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c219
-rw-r--r--source4/librpc/rpc/dcerpc_smb.c1
-rw-r--r--source4/librpc/rpc/dcerpc_util.c15
14 files changed, 833 insertions, 164 deletions
diff --git a/source4/Makefile.in b/source4/Makefile.in
index f5f0d203b4..aa099a9945 100644
--- a/source4/Makefile.in
+++ b/source4/Makefile.in
@@ -156,10 +156,11 @@ LIBRAW_NDR_OBJ = librpc/ndr/ndr.o librpc/ndr/ndr_basic.o librpc/ndr/ndr_sec.o \
LIBRAW_RPC_OBJ = librpc/rpc/dcerpc.o librpc/rpc/dcerpc_auth.o \
librpc/rpc/dcerpc_util.o \
+ librpc/rpc/dcerpc_schannel.o librpc/rpc/dcerpc_ntlm.o \
librpc/rpc/dcerpc_smb.o librpc/rpc/dcerpc_tcp.o
LIBNTLMSSP_OBJ = libcli/auth/ntlmssp.o libcli/auth/ntlmssp_parse.o \
- libcli/auth/ntlmssp_sign.o
+ libcli/auth/ntlmssp_sign.o libcli/auth/schannel.o
LIBCLIAUTH_OBJ = $(LIBNTLMSSP_OBJ) libcli/auth/credentials.o
@@ -217,7 +218,7 @@ SMBD_LIBS = $(LIBS) $(SMB_LIBS) $(PROCESS_MODEL_LIBS) $(DCERPC_LIBS) $(AUTH_LIBS
CLIENT_OBJ1 = client/client.o client/clitar.o libcli/raw/clirewrite.o
-CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) \
+CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(SECRETS_OBJ) \
$(LIB_OBJ) \
$(READLINE_OBJ) $(POPT_LIB_OBJ)
@@ -231,16 +232,16 @@ SMBTORTURE_OBJS = $(TORTURE_OBJS) $(SECRETS_OBJ) $(LIBSMB_OBJ) $(PARAM_OBJ) $(LI
SMBTORTURE_LIBS = $(LIBS)
GENTEST_OBJ = torture/gentest.o torture/torture_util.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
- $(LIB_OBJ) libcli/raw/clirewrite.o
+ $(LIB_OBJ) $(SECRETS_OBJ) libcli/raw/clirewrite.o
MASKTEST_OBJ = torture/masktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
- $(LIB_OBJ) libcli/raw/clirewrite.o
+ $(LIB_OBJ) $(SECRETS_OBJ) libcli/raw/clirewrite.o
LOCKTEST_OBJ = torture/locktest.o $(LIBSMB_OBJ) $(PARAM_OBJ) \
- $(LIB_OBJ) libcli/raw/clirewrite.o
+ $(LIB_OBJ) $(SECRETS_OBJ) libcli/raw/clirewrite.o
NDRDUMP_OBJ = utils/ndrdump.o utils/rewrite.o \
- $(LIBSMB_OBJ) $(PARAM_OBJ) $(LIB_OBJ)
+ $(LIBSMB_OBJ) $(PARAM_OBJ) $(LIB_OBJ) $(SECRETS_OBJ)
PROTO_OBJ = $(SMBD_OBJ_SRV) \
$(SMBD_OBJ_MAIN) $(PROCESS_MODEL_OBJS) \
@@ -493,6 +494,12 @@ proto_test:
.PHONY: headers proto
+etags:
+ etags `find $(srcdir) -name "*.[ch]" | grep -v /CVS/`
+
+ctags:
+ ctags `find $(srcdir) -name "*.[ch]" | grep -v /CVS/`
+
realclean: clean delheaders
-rm -f config.log bin/.dummy
diff --git a/source4/include/includes.h b/source4/include/includes.h
index 607392b158..dc83f55430 100644
--- a/source4/include/includes.h
+++ b/source4/include/includes.h
@@ -741,6 +741,7 @@ extern int errno;
#include "hmacmd5.h"
#include "libcli/auth/ntlmssp.h"
+#include "libcli/auth/schannel.h"
#include "auth/auth.h"
#include "passdb/passdb.h"
diff --git a/source4/lib/crypto/hmacmd5.c b/source4/lib/crypto/hmacmd5.c
index f436fd30c0..8ca7dba841 100644
--- a/source4/lib/crypto/hmacmd5.c
+++ b/source4/lib/crypto/hmacmd5.c
@@ -121,7 +121,7 @@ void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/
-void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
+void hmac_md5(const uchar key[16], const uchar *data, int data_len, uchar* digest)
{
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(key, 16, &ctx);
diff --git a/source4/lib/hmacmd5.c b/source4/lib/hmacmd5.c
index f436fd30c0..8ca7dba841 100644
--- a/source4/lib/hmacmd5.c
+++ b/source4/lib/hmacmd5.c
@@ -121,7 +121,7 @@ void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/
-void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
+void hmac_md5(const uchar key[16], const uchar *data, int data_len, uchar* digest)
{
HMACMD5Context ctx;
hmac_md5_init_limK_to_64(key, 16, &ctx);
diff --git a/source4/libcli/auth/schannel.c b/source4/libcli/auth/schannel.c
new file mode 100644
index 0000000000..e5a786ff24
--- /dev/null
+++ b/source4/libcli/auth/schannel.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ schannel library code
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*******************************************************************
+ Encode or Decode the sequence number (which is symmetric)
+ ********************************************************************/
+static void netsec_deal_with_seq_num(struct schannel_state *state,
+ const uchar packet_digest[8],
+ uchar seq_num[8])
+{
+ static const uchar zeros[4];
+ uchar sequence_key[16];
+ uchar digest1[16];
+
+ hmac_md5(state->session_key, zeros, sizeof(zeros), digest1);
+ hmac_md5(digest1, packet_digest, 8, sequence_key);
+ SamOEMhash(seq_num, sequence_key, 8);
+
+ state->seq_num++;
+}
+
+
+/*******************************************************************
+ Calculate the key with which to encode the data payload
+ ********************************************************************/
+static void netsec_get_sealing_key(const uchar session_key[16],
+ const uchar seq_num[8],
+ uchar sealing_key[16])
+{
+ static const uchar zeros[4];
+ uchar digest2[16];
+ uchar sess_kf0[16];
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ sess_kf0[i] = session_key[i] ^ 0xf0;
+ }
+
+ hmac_md5(sess_kf0, zeros, 4, digest2);
+ hmac_md5(digest2, seq_num, 8, sealing_key);
+}
+
+
+/*******************************************************************
+ Create a digest over the entire packet (including the data), and
+ MD5 it with the session key.
+ ********************************************************************/
+static void schannel_digest(const uchar sess_key[16],
+ const uchar netsec_sig[8],
+ const uchar *confounder,
+ const uchar *data, size_t data_len,
+ uchar digest_final[16])
+{
+ uchar packet_digest[16];
+ static const uchar zeros[4];
+ struct MD5Context ctx;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, zeros, 4);
+ MD5Update(&ctx, netsec_sig, 8);
+ if (confounder) {
+ MD5Update(&ctx, confounder, 8);
+ }
+ MD5Update(&ctx, data, data_len);
+ MD5Final(packet_digest, &ctx);
+
+ hmac_md5(sess_key, packet_digest, sizeof(packet_digest), digest_final);
+}
+
+
+/*
+ unseal a packet
+*/
+NTSTATUS schannel_unseal_packet(struct schannel_state *state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ uchar digest_final[16];
+ uchar confounder[8];
+ uchar seq_num[8];
+ uchar sealing_key[16];
+ static const uchar netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
+
+ if (sig->length != 32) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ memcpy(confounder, sig->data+24, 8);
+
+ RSIVAL(seq_num, 0, state->seq_num);
+ SIVAL(seq_num, 4, state->initiator?0:0x80);
+
+ netsec_get_sealing_key(state->session_key, seq_num, sealing_key);
+ SamOEMhash(confounder, sealing_key, 8);
+ SamOEMhash(data, sealing_key, length);
+
+ schannel_digest(state->session_key,
+ netsec_sig, confounder,
+ data, length, digest_final);
+
+ if (memcmp(digest_final, sig->data+16, 8) != 0) {
+ dump_data_pw("calc digest:", digest_final, 8);
+ dump_data_pw("wire digest:", sig->data+16, 8);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ netsec_deal_with_seq_num(state, digest_final, seq_num);
+
+ if (memcmp(seq_num, sig->data+8, 8) != 0) {
+ dump_data_pw("calc seq num:", seq_num, 8);
+ dump_data_pw("wire seq num:", sig->data+8, 8);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ check the signature on a packet
+*/
+NTSTATUS schannel_check_packet(struct schannel_state *state,
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
+{
+ uchar digest_final[16];
+ uchar seq_num[8];
+ static const uchar netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
+
+ if (sig->length != 32) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ RSIVAL(seq_num, 0, state->seq_num);
+ SIVAL(seq_num, 4, state->initiator?0:0x80);
+
+ dump_data_pw("seq_num:\n", seq_num, 8);
+ dump_data_pw("sess_key:\n", state->session_key, 16);
+
+ schannel_digest(state->session_key,
+ netsec_sig, NULL,
+ data, length, digest_final);
+
+ netsec_deal_with_seq_num(state, digest_final, seq_num);
+
+ if (memcmp(seq_num, sig->data+8, 8) != 0) {
+ dump_data_pw("calc seq num:", seq_num, 8);
+ dump_data_pw("wire seq num:", sig->data+8, 8);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (memcmp(digest_final, sig->data+16, 8) != 0) {
+ dump_data_pw("calc digest:", digest_final, 8);
+ dump_data_pw("wire digest:", sig->data+16, 8);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ seal a packet
+*/
+NTSTATUS schannel_seal_packet(struct schannel_state *state,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ uchar digest_final[16];
+ uchar confounder[8];
+ uchar seq_num[8];
+ uchar sealing_key[16];
+ static const uchar netsec_sig[8] = NETSEC_SEAL_SIGNATURE;
+
+ generate_random_buffer(confounder, 8, False);
+
+ RSIVAL(seq_num, 0, state->seq_num);
+ SIVAL(seq_num, 4, state->initiator?0x80:0);
+
+ schannel_digest(state->session_key,
+ netsec_sig, confounder,
+ data, length, digest_final);
+
+ netsec_get_sealing_key(state->session_key, seq_num, sealing_key);
+ SamOEMhash(confounder, sealing_key, 8);
+ SamOEMhash(data, sealing_key, length);
+
+ netsec_deal_with_seq_num(state, digest_final, seq_num);
+
+ if (!state->signature.data) {
+ state->signature = data_blob_talloc(state->mem_ctx, NULL, 32);
+ if (!state->signature.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ (*sig) = state->signature;
+
+ memcpy(sig->data, netsec_sig, 8);
+ memcpy(sig->data+8, seq_num, 8);
+ memcpy(sig->data+16, digest_final, 8);
+ memcpy(sig->data+24, confounder, 8);
+
+ dump_data_pw("signature:", sig->data+ 0, 8);
+ dump_data_pw("seq_num :", sig->data+ 8, 8);
+ dump_data_pw("digest :", sig->data+16, 8);
+ dump_data_pw("confound :", sig->data+24, 8);
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ sign a packet
+*/
+NTSTATUS schannel_sign_packet(struct schannel_state *state,
+ const uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ uchar digest_final[16];
+ uchar seq_num[8];
+ static const uchar netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
+
+ RSIVAL(seq_num, 0, state->seq_num);
+ SIVAL(seq_num, 4, state->initiator?0x80:0);
+
+ schannel_digest(state->session_key,
+ netsec_sig, NULL,
+ data, length, digest_final);
+
+ netsec_deal_with_seq_num(state, digest_final, seq_num);
+
+ if (!state->signature.data) {
+ state->signature = data_blob_talloc(state->mem_ctx, NULL, 32);
+ if (!state->signature.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+ (*sig) = state->signature;
+
+ memcpy(sig->data, netsec_sig, 8);
+ memcpy(sig->data+8, seq_num, 8);
+ memcpy(sig->data+16, digest_final, 8);
+ memset(sig->data+24, 0, 8);
+
+ dump_data_pw("signature:", sig->data+ 0, 8);
+ dump_data_pw("seq_num :", sig->data+ 8, 8);
+ dump_data_pw("digest :", sig->data+16, 8);
+ dump_data_pw("confound :", sig->data+24, 8);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ destroy an schannel context
+ */
+void schannel_end(struct schannel_state **state)
+{
+ talloc_destroy((*state)->mem_ctx);
+ (*state) = NULL;
+}
+
+/*
+ create an schannel context state
+*/
+NTSTATUS schannel_start(struct schannel_state **state,
+ uint8 session_key[16],
+ BOOL initiator)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("schannel_state");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*state) = talloc_p(mem_ctx, struct schannel_state);
+ if (!(*state)) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*state)->mem_ctx = mem_ctx;
+ memcpy((*state)->session_key, session_key, 16);
+ (*state)->initiator = initiator;
+ (*state)->signature = data_blob(NULL, 0);
+ (*state)->seq_num = 0;
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/auth/schannel.h b/source4/libcli/auth/schannel.h
new file mode 100644
index 0000000000..7b710d7cb9
--- /dev/null
+++ b/source4/libcli/auth/schannel.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ schannel library code
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct schannel_state {
+ TALLOC_CTX *mem_ctx;
+ uint8 session_key[16];
+ uint32 seq_num;
+ BOOL initiator;
+ DATA_BLOB signature;
+};
+
+#define NETSEC_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
+#define NETSEC_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
+
diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl
index 4d09a9ec4f..334ae8ce5d 100644
--- a/source4/librpc/idl/dcerpc.idl
+++ b/source4/librpc/idl/dcerpc.idl
@@ -99,9 +99,10 @@ interface dcerpc
} dcerpc_fault;
- const uint8 DCERPC_AUTH_TYPE_NONE = 0;
- const uint8 DCERPC_AUTH_TYPE_KRB5 = 1;
- const uint8 DCERPC_AUTH_TYPE_NTLMSSP = 10;
+ const uint8 DCERPC_AUTH_TYPE_NONE = 0;
+ const uint8 DCERPC_AUTH_TYPE_KRB5 = 1;
+ const uint8 DCERPC_AUTH_TYPE_NTLMSSP = 10;
+ const uint8 DCERPC_AUTH_TYPE_SCHANNEL = 68;
const uint8 DCERPC_AUTH_LEVEL_NONE = 1;
const uint8 DCERPC_AUTH_LEVEL_CONNECT = 2;
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index d00f2c2986..8987cead92 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -42,7 +42,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void)
p->mem_ctx = mem_ctx;
p->call_id = 1;
p->auth_info = NULL;
- p->ntlmssp_state = NULL;
+ p->security_state = NULL;
p->flags = 0;
p->srv_max_xmit_frag = 0;
p->srv_max_recv_frag = 0;
@@ -56,8 +56,8 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p)
if (!p) return;
p->reference_count--;
if (p->reference_count <= 0) {
- if (p->ntlmssp_state) {
- ntlmssp_end(&p->ntlmssp_state);
+ if (p->security_state) {
+ p->security_state->security_end(p->security_state);
}
p->transport.shutdown_pipe(p);
talloc_destroy(p->mem_ctx);
@@ -128,7 +128,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
DATA_BLOB auth_blob;
/* non-signed packets are simpler */
- if (!p->auth_info || !p->ntlmssp_state) {
+ if (!p->auth_info || !p->security_state) {
return dcerpc_pull(blob, mem_ctx, pkt);
}
@@ -182,17 +182,17 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
/* check signature or unseal the packet */
switch (p->auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
- status = ntlmssp_unseal_packet(p->ntlmssp_state,
- pkt->u.response.stub_and_verifier.data,
- pkt->u.response.stub_and_verifier.length,
- &auth.credentials);
+ status = p->security_state->unseal_packet(p->security_state,
+ pkt->u.response.stub_and_verifier.data,
+ pkt->u.response.stub_and_verifier.length,
+ &auth.credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
- status = ntlmssp_check_packet(p->ntlmssp_state,
- pkt->u.response.stub_and_verifier.data,
- pkt->u.response.stub_and_verifier.length,
- &auth.credentials);
+ status = p->security_state->check_packet(p->security_state,
+ pkt->u.response.stub_and_verifier.data,
+ pkt->u.response.stub_and_verifier.length,
+ &auth.credentials);
break;
case DCERPC_AUTH_LEVEL_NONE:
@@ -224,7 +224,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
struct ndr_push *ndr;
/* non-signed packets are simpler */
- if (!p->auth_info || !p->ntlmssp_state) {
+ if (!p->auth_info || !p->security_state) {
return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info);
}
@@ -249,17 +249,17 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
/* sign or seal the packet */
switch (p->auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
- status = ntlmssp_seal_packet(p->ntlmssp_state,
- ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
- &p->auth_info->credentials);
+ status = p->security_state->seal_packet(p->security_state,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &p->auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
- status = ntlmssp_sign_packet(p->ntlmssp_state,
- ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
- &p->auth_info->credentials);
+ status = p->security_state->sign_packet(p->security_state,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &p->auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_NONE:
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index c5cf07ddba..55c81c374e 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -20,16 +20,23 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/*
- see http://www.opengroup.org/onlinepubs/9629399/chap12.htm for details
- of these structures
+enum dcerpc_transport_t {NCACN_NP, NCACN_IP_TCP};
- note that the structure definitions here don't include some of the
- fields that are wire-artifacts. Those are put on the wire by the
- marshalling/unmarshalling routines in decrpc.c
+/*
+ this defines a generic security context for signed/sealed dcerpc pipes.
*/
-
-enum dcerpc_transport_t {NCACN_NP, NCACN_IP_TCP};
+struct dcerpc_security {
+ void *private;
+ NTSTATUS (*unseal_packet)(struct dcerpc_security *,
+ uchar *data, size_t length, DATA_BLOB *sig);
+ NTSTATUS (*check_packet)(struct dcerpc_security *,
+ const uchar *data, size_t length, const DATA_BLOB *sig);
+ NTSTATUS (*seal_packet)(struct dcerpc_security *,
+ uchar *data, size_t length, DATA_BLOB *sig);
+ NTSTATUS (*sign_packet)(struct dcerpc_security *,
+ const uchar *data, size_t length, DATA_BLOB *sig);
+ void (*security_end)(struct dcerpc_security *);
+};
struct dcerpc_pipe {
@@ -39,7 +46,7 @@ struct dcerpc_pipe {
uint32 srv_max_xmit_frag;
uint32 srv_max_recv_frag;
unsigned flags;
- struct ntlmssp_state *ntlmssp_state;
+ struct dcerpc_security *security_state;
struct dcerpc_auth *auth_info;
const char *binding_string;
@@ -73,6 +80,8 @@ struct dcerpc_pipe {
#define DCERPC_PUSH_BIGENDIAN 64
#define DCERPC_PULL_BIGENDIAN 128
+#define DCERPC_SCHANNEL 256
+
/*
this is used to find pointers to calls
*/
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index 99ea03c216..2b01ad2d4e 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -23,127 +23,6 @@
#include "includes.h"
/*
- do a simple ntlm style authentication on a dcerpc pipe
-*/
-NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
- const char *uuid, unsigned version,
- const char *domain,
- const char *username,
- const char *password)
-{
- NTSTATUS status;
- struct ntlmssp_state *state;
- TALLOC_CTX *mem_ctx;
- DATA_BLOB credentials;
-
- mem_ctx = talloc_init("dcerpc_bind_auth_ntlm");
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
- }
-
- status = ntlmssp_client_start(&state);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- status = ntlmssp_set_domain(state, domain);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = ntlmssp_set_username(state, username);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = ntlmssp_set_password(state, password);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- p->auth_info = talloc(p->mem_ctx, sizeof(*p->auth_info));
- if (!p->auth_info) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- p->auth_info->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
-
- if (p->flags & DCERPC_SEAL) {
- p->auth_info->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
- state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL;
- } else if (p->flags & DCERPC_SIGN) {
- state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
- p->auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
- } else {
- state->neg_flags &= ~(NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL);
- p->auth_info->auth_level = DCERPC_AUTH_LEVEL_NONE;
- }
- p->auth_info->auth_pad_length = 0;
- p->auth_info->auth_reserved = 0;
- p->auth_info->auth_context_id = random();
- p->auth_info->credentials = data_blob(NULL, 0);
- p->ntlmssp_state = NULL;
-
- status = ntlmssp_update(state,
- p->auth_info->credentials,
- &credentials);
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- goto done;
- }
-
- p->auth_info->credentials = data_blob_talloc(mem_ctx,
- credentials.data,
- credentials.length);
- data_blob_free(&credentials);
-
- status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
-
- status = ntlmssp_update(state,
- p->auth_info->credentials,
- &credentials);
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- goto done;
- }
-
- p->auth_info->credentials = data_blob_talloc(mem_ctx,
- credentials.data,
- credentials.length);
- data_blob_free(&credentials);
-
- status = dcerpc_auth3(p, mem_ctx);
-
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- p->ntlmssp_state = state;
-
- switch (p->auth_info->auth_level) {
- case DCERPC_AUTH_LEVEL_PRIVACY:
- case DCERPC_AUTH_LEVEL_INTEGRITY:
- /* setup for signing */
- status = ntlmssp_sign_init(state);
- break;
- }
-
-done:
- talloc_destroy(mem_ctx);
-
- if (!NT_STATUS_IS_OK(status)) {
- p->ntlmssp_state = NULL;
- p->auth_info = NULL;
- }
-
- return status;
-}
-
-
-/*
do a non-athenticated dcerpc bind
*/
NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
diff --git a/source4/librpc/rpc/dcerpc_ntlm.c b/source4/librpc/rpc/dcerpc_ntlm.c
new file mode 100644
index 0000000000..8bfe0cb5ee
--- /dev/null
+++ b/source4/librpc/rpc/dcerpc_ntlm.c
@@ -0,0 +1,197 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc authentication operations
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ wrappers for the ntlmssp_*() functions
+*/
+static NTSTATUS ntlm_unseal_packet(struct dcerpc_security *dcerpc_security,
+ uchar *data, size_t length, DATA_BLOB *sig)
+{
+ struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+ return ntlmssp_unseal_packet(ntlmssp_state, data, length, sig);
+}
+
+static NTSTATUS ntlm_check_packet(struct dcerpc_security *dcerpc_security,
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
+{
+ struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+ return ntlmssp_check_packet(ntlmssp_state, data, length, sig);
+}
+
+static NTSTATUS ntlm_seal_packet(struct dcerpc_security *dcerpc_security,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+ return ntlmssp_seal_packet(ntlmssp_state, data, length, sig);
+}
+
+static NTSTATUS ntlm_sign_packet(struct dcerpc_security *dcerpc_security,
+ const uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+ return ntlmssp_sign_packet(ntlmssp_state, data, length, sig);
+}
+
+static void ntlm_security_end(struct dcerpc_security *dcerpc_security)
+{
+ struct ntlmssp_state *ntlmssp_state = dcerpc_security->private;
+ return ntlmssp_end(&ntlmssp_state);
+}
+
+
+
+/*
+ do ntlm style authentication on a dcerpc pipe
+*/
+NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
+ const char *uuid, unsigned version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status;
+ struct ntlmssp_state *state;
+ TALLOC_CTX *mem_ctx;
+ DATA_BLOB credentials;
+
+ mem_ctx = talloc_init("dcerpc_bind_auth_ntlm");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ntlmssp_client_start(&state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = ntlmssp_set_domain(state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = ntlmssp_set_username(state, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = ntlmssp_set_password(state, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ p->auth_info = talloc(p->mem_ctx, sizeof(*p->auth_info));
+ if (!p->auth_info) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p->auth_info->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+
+ if (p->flags & DCERPC_SEAL) {
+ p->auth_info->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL;
+ } else {
+ /* ntlmssp does not work on dcerpc with
+ AUTH_LEVEL_NONE */
+ state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
+ p->auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ }
+ p->auth_info->auth_pad_length = 0;
+ p->auth_info->auth_reserved = 0;
+ p->auth_info->auth_context_id = random();
+ p->auth_info->credentials = data_blob(NULL, 0);
+ p->security_state = NULL;
+
+ status = ntlmssp_update(state,
+ p->auth_info->credentials,
+ &credentials);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto done;
+ }
+
+ p->auth_info->credentials = data_blob_talloc(mem_ctx,
+ credentials.data,
+ credentials.length);
+ data_blob_free(&credentials);
+
+ status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+
+ status = ntlmssp_update(state,
+ p->auth_info->credentials,
+ &credentials);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ goto done;
+ }
+
+ p->auth_info->credentials = data_blob_talloc(mem_ctx,
+ credentials.data,
+ credentials.length);
+ data_blob_free(&credentials);
+
+ status = dcerpc_auth3(p, mem_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ p->security_state = talloc_p(p->mem_ctx, struct dcerpc_security);
+ if (!p->security_state) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p->security_state->private = state;
+ p->security_state->unseal_packet = ntlm_unseal_packet;
+ p->security_state->check_packet = ntlm_check_packet;
+ p->security_state->seal_packet = ntlm_seal_packet;
+ p->security_state->sign_packet = ntlm_sign_packet;
+ p->security_state->security_end = ntlm_security_end;
+
+ switch (p->auth_info->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ /* setup for signing */
+ status = ntlmssp_sign_init(state);
+ break;
+ }
+
+done:
+ talloc_destroy(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ p->security_state = NULL;
+ p->auth_info = NULL;
+ }
+
+ return status;
+}
+
+
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
new file mode 100644
index 0000000000..9ef16a0d5c
--- /dev/null
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -0,0 +1,219 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ wrappers for the schannel_*() functions
+*/
+static NTSTATUS schan_unseal_packet(struct dcerpc_security *dcerpc_security,
+ uchar *data, size_t length, DATA_BLOB *sig)
+{
+ struct schannel_state *schannel_state = dcerpc_security->private;
+ return schannel_unseal_packet(schannel_state, data, length, sig);
+}
+
+static NTSTATUS schan_check_packet(struct dcerpc_security *dcerpc_security,
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
+{
+ struct schannel_state *schannel_state = dcerpc_security->private;
+ return schannel_check_packet(schannel_state, data, length, sig);
+}
+
+static NTSTATUS schan_seal_packet(struct dcerpc_security *dcerpc_security,
+ uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ struct schannel_state *schannel_state = dcerpc_security->private;
+ return schannel_seal_packet(schannel_state, data, length, sig);
+}
+
+static NTSTATUS schan_sign_packet(struct dcerpc_security *dcerpc_security,
+ const uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ struct schannel_state *schannel_state = dcerpc_security->private;
+ return schannel_sign_packet(schannel_state, data, length, sig);
+}
+
+static void schan_security_end(struct dcerpc_security *dcerpc_security)
+{
+ struct schannel_state *schannel_state = dcerpc_security->private;
+ return schannel_end(&schannel_state);
+}
+
+
+/*
+ do a schannel style bind on a dcerpc pipe. The username is usually
+ of the form HOSTNAME$ and the password is the domain trust password
+*/
+NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
+ const char *uuid, unsigned version,
+ const char *domain,
+ const char *username,
+ const char *password)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p2;
+ struct netr_ServerReqChallenge r;
+ struct netr_ServerAuthenticate2 a;
+ uint8 mach_pwd[16];
+ uint8 session_key[16];
+ struct netr_CredentialState creds;
+ struct schannel_state *schannel_state;
+ const char *workgroup, *workstation;
+ uint32 negotiate_flags = 0;
+
+ workstation = username;
+ workgroup = domain;
+
+ /*
+ step 1 - establish a netlogon connection, with no authentication
+ */
+ status = dcerpc_secondary_smb(p, &p2,
+ DCERPC_NETLOGON_NAME,
+ DCERPC_NETLOGON_UUID,
+ DCERPC_NETLOGON_VERSION);
+
+
+ /*
+ step 2 - request a netlogon challenge
+ */
+ r.in.server_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dcerpc_server_name(p));
+ r.in.computer_name = workstation;
+ generate_random_buffer(r.in.credentials.data, sizeof(r.in.credentials.data), False);
+
+ status = dcerpc_netr_ServerReqChallenge(p2, p->mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ step 3 - authenticate on the netlogon pipe
+ */
+ E_md4hash(password, mach_pwd);
+ creds_client_init(&creds, &r.in.credentials, &r.out.credentials, mach_pwd,
+ &a.in.credentials);
+
+ a.in.server_name = r.in.server_name;
+ a.in.username = talloc_asprintf(p->mem_ctx, "%s$", workstation);
+ if (lp_server_role() == ROLE_DOMAIN_BDC) {
+ a.in.secure_channel_type = SEC_CHAN_BDC;
+ } else {
+ a.in.secure_channel_type = SEC_CHAN_WKSTA;
+ }
+ a.in.computer_name = workstation;
+ a.in.negotiate_flags = &negotiate_flags;
+ a.out.negotiate_flags = &negotiate_flags;
+
+ status = dcerpc_netr_ServerAuthenticate2(p2, p->mem_ctx, &a);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!creds_client_check(&creds, &a.out.credentials)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /*
+ the schannel session key is now in creds.session_key
+ */
+
+
+ /*
+ step 4 - perform a bind with security type schannel
+ */
+ p->auth_info = talloc(p->mem_ctx, sizeof(*p->auth_info));
+ if (!p->auth_info) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ p->auth_info->auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
+
+ if (p->flags & DCERPC_SEAL) {
+ p->auth_info->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ /* note that DCERPC_AUTH_LEVEL_NONE does not make any
+ sense, and would be rejected by the server */
+ p->auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ }
+ p->auth_info->auth_pad_length = 0;
+ p->auth_info->auth_reserved = 0;
+ p->auth_info->auth_context_id = 1;
+ p->security_state = NULL;
+
+ p->auth_info->credentials = data_blob_talloc(p->mem_ctx,
+ NULL,
+ 8 +
+ strlen(workgroup)+1 +
+ strlen(workstation)+1);
+ if (!p->auth_info->credentials.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* oh, this is ugly! */
+ SIVAL(p->auth_info->credentials.data, 0, 0);
+ SIVAL(p->auth_info->credentials.data, 4, 3);
+ memcpy(p->auth_info->credentials.data+8, workgroup, strlen(workgroup)+1);
+ memcpy(p->auth_info->credentials.data+8+strlen(workgroup)+1,
+ workstation, strlen(workstation)+1);
+
+ /* send the authenticated bind request */
+ status = dcerpc_bind_byuuid(p, p->mem_ctx, uuid, version);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ p->security_state = talloc_p(p->mem_ctx, struct dcerpc_security);
+ if (!p->security_state) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ schannel_state = talloc_p(p->mem_ctx, struct schannel_state);
+ if (!schannel_state) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ memcpy(session_key, creds.session_key, 8);
+ memset(session_key+8, 0, 8);
+
+ status = schannel_start(&schannel_state, session_key, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ dump_data_pw("session key:\n", schannel_state->session_key, 16);
+
+ p->security_state->private = schannel_state;
+ p->security_state->unseal_packet = schan_unseal_packet;
+ p->security_state->check_packet = schan_check_packet;
+ p->security_state->seal_packet = schan_seal_packet;
+ p->security_state->sign_packet = schan_sign_packet;
+ p->security_state->security_end = schan_security_end;
+
+done:
+ return status;
+}
+
diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c
index a79e5adb10..7822231b82 100644
--- a/source4/librpc/rpc/dcerpc_smb.c
+++ b/source4/librpc/rpc/dcerpc_smb.c
@@ -295,7 +295,6 @@ static const char *smb_peer_name(struct dcerpc_pipe *p)
return smb->tree->session->transport->called.name;
}
-
/*
open a rpc connection to a named pipe
*/
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index 96f0b959e7..ba61f28c95 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -275,6 +275,7 @@ static const struct {
} ncacn_options[] = {
{"sign", DCERPC_SIGN},
{"seal", DCERPC_SEAL},
+ {"schannel", DCERPC_SCHANNEL},
{"validate", DCERPC_DEBUG_VALIDATE_BOTH},
{"print", DCERPC_DEBUG_PRINT_BOTH},
{"bigendian", DCERPC_PUSH_BIGENDIAN}
@@ -481,11 +482,23 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
(*p)->flags = binding->flags;
- if (binding->flags & (DCERPC_SIGN | DCERPC_SEAL)) {
+ if (binding->flags & DCERPC_SCHANNEL) {
+ const char *trust_password = secrets_fetch_machine_password();
+ if (!trust_password) {
+ DEBUG(0,("Unable to fetch machine password\n"));
+ goto done;
+ }
+ status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version,
+ lp_workgroup(),
+ lp_netbios_name(),
+ trust_password);
+ } else if (binding->flags & (DCERPC_SIGN | DCERPC_SEAL)) {
status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
} else {
status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
}
+
+done:
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
dcerpc_pipe_close(*p);