2 Unix SMB/CIFS implementation.
4 dcerpc schannel operations
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DCERPC_SCHANNEL_STATE_START 0
26 #define DCERPC_SCHANNEL_STATE_UPDATE_1 1
28 struct dcerpc_schannel_state {
31 struct schannel_bind bind_schannel;
32 struct schannel_state *schannel_state;
35 static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
40 uint8_t new_session_key[16]);
43 wrappers for the schannel_*() functions
45 These will become static again, when we get dynamic registration, and
46 decrpc_schannel_security_ops come back here.
48 static NTSTATUS dcerpc_schannel_unseal(struct gensec_security *gensec_security,
50 uint8_t *data, size_t length, DATA_BLOB *sig)
52 struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
54 return schannel_unseal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
57 static NTSTATUS dcerpc_schannel_check_sig(struct gensec_security *gensec_security,
59 const uint8_t *data, size_t length,
62 struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
64 return schannel_check_packet(dce_schan_state->schannel_state, data, length, sig);
67 static NTSTATUS dcerpc_schannel_seal(struct gensec_security *gensec_security,
69 uint8_t *data, size_t length,
72 struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
74 return schannel_seal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
77 static NTSTATUS dcerpc_schannel_sign(struct gensec_security *gensec_security,
79 const uint8_t *data, size_t length,
82 struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
84 return schannel_sign_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
87 static NTSTATUS dcerpc_schannel_session_key(struct gensec_security *gensec_security,
88 DATA_BLOB *session_key)
90 return NT_STATUS_NOT_IMPLEMENTED;
93 static NTSTATUS dcerpc_schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
94 const DATA_BLOB in, DATA_BLOB *out)
96 struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
98 struct schannel_bind bind_schannel;
100 if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) {
104 dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1;
106 bind_schannel.unknown1 = 0;
108 /* to support this we'd need to have access to the full domain name */
109 bind_schannel.bind_type = 23;
110 bind_schannel.u.info23.domain = gensec_security->user.domain;
111 bind_schannel.u.info23.account_name = gensec_security->user.name;
112 bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(dce_schan_state->mem_ctx, fulldomainname);
113 bind_schannel.u.info23.workstation = str_format_nbt_domain(dce_schan_state->mem_ctx, gensec_security->user.name);
115 bind_schannel.bind_type = 3;
116 bind_schannel.u.info3.domain = gensec_security->user.domain;
117 bind_schannel.u.info3.account_name = gensec_security->user.name;
120 status = ndr_push_struct_blob(out, dce_schan_state->mem_ctx, &bind_schannel,
121 (ndr_push_flags_fn_t)ndr_push_schannel_bind);
122 if (!NT_STATUS_IS_OK(status)) {
126 return NT_STATUS_MORE_PROCESSING_REQUIRED;
129 static void dcerpc_schannel_end(struct gensec_security *gensec_security)
131 struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
133 schannel_end(&dce_schan_state->schannel_state);
135 talloc_destroy(dce_schan_state->mem_ctx);
137 gensec_security->private_data = NULL;
141 static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = {
142 .name = "dcerpc_schannel",
143 .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
144 .update = dcerpc_schannel_update,
145 .seal = dcerpc_schannel_seal,
146 .sign = dcerpc_schannel_sign,
147 .check_sig = dcerpc_schannel_check_sig,
148 .unseal = dcerpc_schannel_unseal,
149 .session_key = dcerpc_schannel_session_key,
150 .end = dcerpc_schannel_end
154 get a schannel key using a netlogon challenge on a secondary pipe
156 static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
158 const char *username,
159 const char *password,
161 uint8_t new_session_key[16])
164 struct dcerpc_pipe *p2;
165 struct netr_ServerReqChallenge r;
166 struct netr_ServerAuthenticate2 a;
167 struct netr_Credential credentials1, credentials2, credentials3;
168 struct samr_Password mach_pwd;
169 struct creds_CredentialState creds;
170 const char *workgroup, *workstation;
171 uint32_t negotiate_flags;
173 if (p->flags & DCERPC_SCHANNEL_128) {
174 negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
176 negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS;
179 workstation = username;
183 step 1 - establish a netlogon connection, with no authentication
185 status = dcerpc_secondary_connection(p, &p2,
186 DCERPC_NETLOGON_NAME,
187 DCERPC_NETLOGON_UUID,
188 DCERPC_NETLOGON_VERSION);
192 step 2 - request a netlogon challenge
194 r.in.server_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dcerpc_server_name(p));
195 r.in.computer_name = workstation;
196 r.in.credentials = &credentials1;
197 r.out.credentials = &credentials2;
199 generate_random_buffer(credentials1.data, sizeof(credentials1.data), False);
201 status = dcerpc_netr_ServerReqChallenge(p2, p->mem_ctx, &r);
202 if (!NT_STATUS_IS_OK(status)) {
207 step 3 - authenticate on the netlogon pipe
209 E_md4hash(password, mach_pwd.hash);
210 creds_client_init(&creds, &credentials1, &credentials2, &mach_pwd, &credentials3,
213 a.in.server_name = r.in.server_name;
214 a.in.account_name = talloc_asprintf(p->mem_ctx, "%s$", workstation);
215 a.in.secure_channel_type = chan_type;
216 a.in.computer_name = workstation;
217 a.in.negotiate_flags = &negotiate_flags;
218 a.out.negotiate_flags = &negotiate_flags;
219 a.in.credentials = &credentials3;
220 a.out.credentials = &credentials3;
222 status = dcerpc_netr_ServerAuthenticate2(p2, p->mem_ctx, &a);
223 if (!NT_STATUS_IS_OK(status)) {
227 if (!creds_client_check(&creds, a.out.credentials)) {
228 return NT_STATUS_UNSUCCESSFUL;
232 the schannel session key is now in creds.session_key
234 we no longer need the netlogon pipe open
236 dcerpc_pipe_close(p2);
238 memcpy(new_session_key, creds.session_key, 16);
244 do a schannel style bind on a dcerpc pipe. The username is usually
245 of the form HOSTNAME$ and the password is the domain trust password
247 NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
248 const char *uuid, uint_t version,
250 const char *username,
251 const char *password)
254 struct dcerpc_schannel_state *dce_schan_state;
256 uint8_t session_key[16];
259 if (p->flags & DCERPC_SCHANNEL_BDC) {
260 chan_type = SEC_CHAN_BDC;
261 } else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) {
262 chan_type = SEC_CHAN_WKSTA;
263 } else if (p->flags & DCERPC_SCHANNEL_DOMAIN) {
264 chan_type = SEC_CHAN_DOMAIN;
267 status = dcerpc_schannel_key(p, domain,
270 chan_type, session_key);
271 if (!NT_STATUS_IS_OK(status)) {
275 mem_ctx = talloc_init("dcerpc_schannel_start");
277 return NT_STATUS_NO_MEMORY;
280 dce_schan_state = talloc_p(mem_ctx, struct dcerpc_schannel_state);
281 if (!dce_schan_state) {
282 talloc_destroy(mem_ctx);
283 return NT_STATUS_NO_MEMORY;
286 dce_schan_state->mem_ctx = mem_ctx;
288 status = schannel_start(&dce_schan_state->schannel_state, session_key, True);
289 if (!NT_STATUS_IS_OK(status)) {
293 dce_schan_state->state = DCERPC_SCHANNEL_STATE_START;
295 p->security_state.generic_state.user.domain = domain;
296 p->security_state.generic_state.user.name = username;
297 p->security_state.generic_state.user.password = password;
299 p->security_state.generic_state.ops = &gensec_dcerpc_schannel_security_ops;
300 p->security_state.generic_state.private_data = dce_schan_state;
302 dump_data_pw("session key:\n", dce_schan_state->schannel_state->session_key, 16);
304 status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL,