2 Unix SMB/Netbios implementation.
4 handle NLTMSSP, client server side parsing
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
8 Copyright (C) Stefan Metzmacher 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 struct auth_session_info
;
28 #include "lib/util/tevent_ntstatus.h"
29 #include "auth/ntlmssp/ntlmssp.h"
30 #include "auth/ntlmssp/ntlmssp_private.h"
31 #include "../libcli/auth/libcli_auth.h"
32 #include "librpc/gen_ndr/ndr_dcerpc.h"
33 #include "auth/gensec/gensec.h"
34 #include "auth/gensec/gensec_internal.h"
37 #define DBGC_CLASS DBGC_AUTH
40 * Callbacks for NTLMSSP - for both client and server operating modes
44 static const struct ntlmssp_callbacks
{
45 enum ntlmssp_role role
;
46 enum ntlmssp_message_type command
;
47 NTSTATUS (*sync_fn
)(struct gensec_security
*gensec_security
,
48 TALLOC_CTX
*out_mem_ctx
,
49 DATA_BLOB in
, DATA_BLOB
*out
);
50 struct tevent_req
*(*send_fn
)(TALLOC_CTX
*mem_ctx
,
51 struct tevent_context
*ev
,
52 struct gensec_security
*gensec_security
,
54 NTSTATUS (*recv_fn
)(struct tevent_req
*req
,
55 TALLOC_CTX
*out_mem_ctx
,
57 } ntlmssp_callbacks
[] = {
59 .role
= NTLMSSP_CLIENT
,
60 .command
= NTLMSSP_INITIAL
,
61 .sync_fn
= ntlmssp_client_initial
,
63 .role
= NTLMSSP_CLIENT
,
64 .command
= NTLMSSP_NEGOTIATE
,
65 .sync_fn
= gensec_ntlmssp_resume_ccache
,
67 .role
= NTLMSSP_SERVER
,
68 .command
= NTLMSSP_NEGOTIATE
,
69 .sync_fn
= gensec_ntlmssp_server_negotiate
,
71 .role
= NTLMSSP_CLIENT
,
72 .command
= NTLMSSP_CHALLENGE
,
73 .sync_fn
= ntlmssp_client_challenge
,
75 .role
= NTLMSSP_SERVER
,
76 .command
= NTLMSSP_AUTH
,
77 .send_fn
= ntlmssp_server_auth_send
,
78 .recv_fn
= ntlmssp_server_auth_recv
,
83 static NTSTATUS
gensec_ntlmssp_update_find(struct gensec_security
*gensec_security
,
84 struct gensec_ntlmssp_context
*gensec_ntlmssp
,
85 const DATA_BLOB input
, uint32_t *idx
)
87 uint32_t ntlmssp_command
;
90 if (gensec_ntlmssp
->ntlmssp_state
->expected_state
== NTLMSSP_DONE
) {
91 /* We are strict here because other modules, which we
92 * don't fully control (such as GSSAPI) are also
93 * strict, but are tested less often */
95 DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
96 return NT_STATUS_INVALID_PARAMETER
;
100 switch (gensec_ntlmssp
->ntlmssp_state
->role
) {
102 if (gensec_ntlmssp
->ntlmssp_state
->resume_ccache
) {
104 * make sure gensec_ntlmssp_resume_ccache()
107 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
111 ntlmssp_command
= NTLMSSP_INITIAL
;
114 if (gensec_security
->want_features
& GENSEC_FEATURE_DATAGRAM_MODE
) {
115 /* 'datagram' mode - no neg packet */
116 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
118 /* This is normal in SPNEGO mech negotiation fallback */
119 DEBUG(2, ("Failed to parse NTLMSSP packet: zero length\n"));
120 return NT_STATUS_INVALID_PARAMETER
;
124 DEBUG(1, ("NTLMSSP state has invalid role %d\n",
125 gensec_ntlmssp
->ntlmssp_state
->role
));
126 return NT_STATUS_INVALID_PARAMETER
;
129 if (!msrpc_parse(gensec_ntlmssp
->ntlmssp_state
,
133 DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
134 dump_data(2, input
.data
, input
.length
);
135 return NT_STATUS_INVALID_PARAMETER
;
139 if (ntlmssp_command
!= gensec_ntlmssp
->ntlmssp_state
->expected_state
) {
140 DEBUG(2, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command
,
141 gensec_ntlmssp
->ntlmssp_state
->expected_state
));
142 return NT_STATUS_INVALID_PARAMETER
;
145 for (i
=0; i
< ARRAY_SIZE(ntlmssp_callbacks
); i
++) {
146 if (ntlmssp_callbacks
[i
].role
== gensec_ntlmssp
->ntlmssp_state
->role
&&
147 ntlmssp_callbacks
[i
].command
== ntlmssp_command
) {
153 DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n",
154 gensec_ntlmssp
->ntlmssp_state
->role
, ntlmssp_command
));
156 return NT_STATUS_INVALID_PARAMETER
;
159 struct gensec_ntlmssp_update_state
{
160 const struct ntlmssp_callbacks
*cb
;
165 static void gensec_ntlmssp_update_done(struct tevent_req
*subreq
);
167 static struct tevent_req
*gensec_ntlmssp_update_send(TALLOC_CTX
*mem_ctx
,
168 struct tevent_context
*ev
,
169 struct gensec_security
*gensec_security
,
172 struct gensec_ntlmssp_context
*gensec_ntlmssp
=
173 talloc_get_type_abort(gensec_security
->private_data
,
174 struct gensec_ntlmssp_context
);
175 struct tevent_req
*req
= NULL
;
176 struct gensec_ntlmssp_update_state
*state
= NULL
;
180 req
= tevent_req_create(mem_ctx
, &state
,
181 struct gensec_ntlmssp_update_state
);
186 status
= gensec_ntlmssp_update_find(gensec_security
,
189 if (tevent_req_nterror(req
, status
)) {
190 return tevent_req_post(req
, ev
);
193 if (ntlmssp_callbacks
[i
].send_fn
!= NULL
) {
194 struct tevent_req
*subreq
= NULL
;
196 state
->cb
= &ntlmssp_callbacks
[i
];
198 subreq
= state
->cb
->send_fn(state
, ev
,
201 if (tevent_req_nomem(subreq
, req
)) {
202 return tevent_req_post(req
, ev
);
204 tevent_req_set_callback(subreq
,
205 gensec_ntlmssp_update_done
,
210 status
= ntlmssp_callbacks
[i
].sync_fn(gensec_security
,
213 state
->status
= status
;
214 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
215 tevent_req_done(req
);
216 return tevent_req_post(req
, ev
);
218 if (tevent_req_nterror(req
, status
)) {
219 return tevent_req_post(req
, ev
);
222 tevent_req_done(req
);
223 return tevent_req_post(req
, ev
);
226 static void gensec_ntlmssp_update_done(struct tevent_req
*subreq
)
228 struct tevent_req
*req
=
229 tevent_req_callback_data(subreq
,
231 struct gensec_ntlmssp_update_state
*state
=
233 struct gensec_ntlmssp_update_state
);
236 status
= state
->cb
->recv_fn(subreq
, state
, &state
->out
);
238 if (GENSEC_UPDATE_IS_NTERROR(status
)) {
239 tevent_req_nterror(req
, status
);
243 state
->status
= status
;
244 tevent_req_done(req
);
247 static NTSTATUS
gensec_ntlmssp_update_recv(struct tevent_req
*req
,
248 TALLOC_CTX
*out_mem_ctx
,
251 struct gensec_ntlmssp_update_state
*state
=
253 struct gensec_ntlmssp_update_state
);
256 *out
= data_blob_null
;
258 if (tevent_req_is_nterror(req
, &status
)) {
259 tevent_req_received(req
);
264 talloc_steal(out_mem_ctx
, state
->out
.data
);
265 status
= state
->status
;
266 tevent_req_received(req
);
270 static NTSTATUS
gensec_ntlmssp_may_reset_crypto(struct gensec_security
*gensec_security
,
273 struct gensec_ntlmssp_context
*gensec_ntlmssp
=
274 talloc_get_type_abort(gensec_security
->private_data
,
275 struct gensec_ntlmssp_context
);
276 struct ntlmssp_state
*ntlmssp_state
= gensec_ntlmssp
->ntlmssp_state
;
278 bool reset_seqnums
= full_reset
;
280 if (!gensec_ntlmssp_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
284 status
= ntlmssp_sign_reset(ntlmssp_state
, reset_seqnums
);
285 if (!NT_STATUS_IS_OK(status
)) {
286 DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n",
294 static const char *gensec_ntlmssp_final_auth_type(struct gensec_security
*gensec_security
)
296 return GENSEC_FINAL_AUTH_TYPE_NTLMSSP
;
299 static const char *gensec_ntlmssp_oids
[] = {
304 static const struct gensec_security_ops gensec_ntlmssp_security_ops
= {
306 .sasl_name
= GENSEC_SASL_NAME_NTLMSSP
, /* "NTLM" */
307 .auth_type
= DCERPC_AUTH_TYPE_NTLMSSP
,
308 .oid
= gensec_ntlmssp_oids
,
309 .client_start
= gensec_ntlmssp_client_start
,
310 .server_start
= gensec_ntlmssp_server_start
,
311 .magic
= gensec_ntlmssp_magic
,
312 .update_send
= gensec_ntlmssp_update_send
,
313 .update_recv
= gensec_ntlmssp_update_recv
,
314 .may_reset_crypto
= gensec_ntlmssp_may_reset_crypto
,
315 .sig_size
= gensec_ntlmssp_sig_size
,
316 .sign_packet
= gensec_ntlmssp_sign_packet
,
317 .check_packet
= gensec_ntlmssp_check_packet
,
318 .seal_packet
= gensec_ntlmssp_seal_packet
,
319 .unseal_packet
= gensec_ntlmssp_unseal_packet
,
320 .wrap
= gensec_ntlmssp_wrap
,
321 .unwrap
= gensec_ntlmssp_unwrap
,
322 .session_key
= gensec_ntlmssp_session_key
,
323 .session_info
= gensec_ntlmssp_session_info
,
324 .have_feature
= gensec_ntlmssp_have_feature
,
325 .final_auth_type
= gensec_ntlmssp_final_auth_type
,
327 .priority
= GENSEC_NTLMSSP
330 static const struct gensec_security_ops gensec_ntlmssp_resume_ccache_ops
= {
331 .name
= "ntlmssp_resume_ccache",
332 .client_start
= gensec_ntlmssp_resume_ccache_start
,
333 .update_send
= gensec_ntlmssp_update_send
,
334 .update_recv
= gensec_ntlmssp_update_recv
,
335 .session_key
= gensec_ntlmssp_session_key
,
336 .have_feature
= gensec_ntlmssp_have_feature
,
338 .priority
= GENSEC_NTLMSSP
341 _PUBLIC_ NTSTATUS
gensec_ntlmssp_init(TALLOC_CTX
*ctx
)
345 ret
= gensec_register(ctx
, &gensec_ntlmssp_security_ops
);
346 if (!NT_STATUS_IS_OK(ret
)) {
347 DEBUG(0,("Failed to register '%s' gensec backend!\n",
348 gensec_ntlmssp_security_ops
.name
));
352 ret
= gensec_register(ctx
, &gensec_ntlmssp_resume_ccache_ops
);
353 if (!NT_STATUS_IS_OK(ret
)) {
354 DEBUG(0,("Failed to register '%s' gensec backend!\n",
355 gensec_ntlmssp_resume_ccache_ops
.name
));
362 static struct gensec_security
*gensec_find_child_by_ops(struct gensec_security
*gensec_security
,
363 const struct gensec_security_ops
*ops
)
365 struct gensec_security
*current
= gensec_security
;
367 while (current
!= NULL
) {
368 if (current
->ops
== ops
) {
372 current
= current
->child_security
;
378 uint32_t gensec_ntlmssp_neg_flags(struct gensec_security
*gensec_security
)
380 struct gensec_ntlmssp_context
*gensec_ntlmssp
;
382 gensec_security
= gensec_find_child_by_ops(gensec_security
,
383 &gensec_ntlmssp_security_ops
);
384 if (gensec_security
== NULL
) {
388 gensec_ntlmssp
= talloc_get_type_abort(gensec_security
->private_data
,
389 struct gensec_ntlmssp_context
);
390 return gensec_ntlmssp
->ntlmssp_state
->neg_flags
;
393 const char *gensec_ntlmssp_server_domain(struct gensec_security
*gensec_security
)
395 struct gensec_ntlmssp_context
*gensec_ntlmssp
;
397 gensec_security
= gensec_find_child_by_ops(gensec_security
,
398 &gensec_ntlmssp_security_ops
);
399 if (gensec_security
== NULL
) {
403 gensec_ntlmssp
= talloc_get_type_abort(gensec_security
->private_data
,
404 struct gensec_ntlmssp_context
);
405 return gensec_ntlmssp
->ntlmssp_state
->server
.netbios_domain
;