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 * Callbacks for NTLMSSP - for both client and server operating modes
41 static const struct ntlmssp_callbacks
{
42 enum ntlmssp_role role
;
43 enum ntlmssp_message_type command
;
44 NTSTATUS (*sync_fn
)(struct gensec_security
*gensec_security
,
45 TALLOC_CTX
*out_mem_ctx
,
46 DATA_BLOB in
, DATA_BLOB
*out
);
47 struct tevent_req
*(*send_fn
)(TALLOC_CTX
*mem_ctx
,
48 struct tevent_context
*ev
,
49 struct gensec_security
*gensec_security
,
51 NTSTATUS (*recv_fn
)(struct tevent_req
*req
,
52 TALLOC_CTX
*out_mem_ctx
,
54 } ntlmssp_callbacks
[] = {
56 .role
= NTLMSSP_CLIENT
,
57 .command
= NTLMSSP_INITIAL
,
58 .sync_fn
= ntlmssp_client_initial
,
60 .role
= NTLMSSP_CLIENT
,
61 .command
= NTLMSSP_NEGOTIATE
,
62 .sync_fn
= gensec_ntlmssp_resume_ccache
,
64 .role
= NTLMSSP_SERVER
,
65 .command
= NTLMSSP_NEGOTIATE
,
66 .sync_fn
= gensec_ntlmssp_server_negotiate
,
68 .role
= NTLMSSP_CLIENT
,
69 .command
= NTLMSSP_CHALLENGE
,
70 .sync_fn
= ntlmssp_client_challenge
,
72 .role
= NTLMSSP_SERVER
,
73 .command
= NTLMSSP_AUTH
,
74 .send_fn
= ntlmssp_server_auth_send
,
75 .recv_fn
= ntlmssp_server_auth_recv
,
80 static NTSTATUS
gensec_ntlmssp_update_find(struct gensec_security
*gensec_security
,
81 struct gensec_ntlmssp_context
*gensec_ntlmssp
,
82 const DATA_BLOB input
, uint32_t *idx
)
84 uint32_t ntlmssp_command
;
87 if (gensec_ntlmssp
->ntlmssp_state
->expected_state
== NTLMSSP_DONE
) {
88 /* We are strict here because other modules, which we
89 * don't fully control (such as GSSAPI) are also
90 * strict, but are tested less often */
92 DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
93 return NT_STATUS_INVALID_PARAMETER
;
97 switch (gensec_ntlmssp
->ntlmssp_state
->role
) {
99 if (gensec_ntlmssp
->ntlmssp_state
->resume_ccache
) {
101 * make sure gensec_ntlmssp_resume_ccache()
104 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
108 ntlmssp_command
= NTLMSSP_INITIAL
;
111 if (gensec_security
->want_features
& GENSEC_FEATURE_DATAGRAM_MODE
) {
112 /* 'datagram' mode - no neg packet */
113 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
115 /* This is normal in SPNEGO mech negotiation fallback */
116 DEBUG(2, ("Failed to parse NTLMSSP packet: zero length\n"));
117 return NT_STATUS_INVALID_PARAMETER
;
121 DEBUG(1, ("NTLMSSP state has invalid role %d\n",
122 gensec_ntlmssp
->ntlmssp_state
->role
));
123 return NT_STATUS_INVALID_PARAMETER
;
126 if (!msrpc_parse(gensec_ntlmssp
->ntlmssp_state
,
130 DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
131 dump_data(2, input
.data
, input
.length
);
132 return NT_STATUS_INVALID_PARAMETER
;
136 if (ntlmssp_command
!= gensec_ntlmssp
->ntlmssp_state
->expected_state
) {
137 DEBUG(2, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command
,
138 gensec_ntlmssp
->ntlmssp_state
->expected_state
));
139 return NT_STATUS_INVALID_PARAMETER
;
142 for (i
=0; i
< ARRAY_SIZE(ntlmssp_callbacks
); i
++) {
143 if (ntlmssp_callbacks
[i
].role
== gensec_ntlmssp
->ntlmssp_state
->role
&&
144 ntlmssp_callbacks
[i
].command
== ntlmssp_command
) {
150 DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n",
151 gensec_ntlmssp
->ntlmssp_state
->role
, ntlmssp_command
));
153 return NT_STATUS_INVALID_PARAMETER
;
156 struct gensec_ntlmssp_update_state
{
157 const struct ntlmssp_callbacks
*cb
;
162 static void gensec_ntlmssp_update_done(struct tevent_req
*subreq
);
164 static struct tevent_req
*gensec_ntlmssp_update_send(TALLOC_CTX
*mem_ctx
,
165 struct tevent_context
*ev
,
166 struct gensec_security
*gensec_security
,
169 struct gensec_ntlmssp_context
*gensec_ntlmssp
=
170 talloc_get_type_abort(gensec_security
->private_data
,
171 struct gensec_ntlmssp_context
);
172 struct tevent_req
*req
= NULL
;
173 struct gensec_ntlmssp_update_state
*state
= NULL
;
177 req
= tevent_req_create(mem_ctx
, &state
,
178 struct gensec_ntlmssp_update_state
);
183 status
= gensec_ntlmssp_update_find(gensec_security
,
186 if (tevent_req_nterror(req
, status
)) {
187 return tevent_req_post(req
, ev
);
190 if (ntlmssp_callbacks
[i
].send_fn
!= NULL
) {
191 struct tevent_req
*subreq
= NULL
;
193 state
->cb
= &ntlmssp_callbacks
[i
];
195 subreq
= state
->cb
->send_fn(state
, ev
,
198 if (tevent_req_nomem(subreq
, req
)) {
199 return tevent_req_post(req
, ev
);
201 tevent_req_set_callback(subreq
,
202 gensec_ntlmssp_update_done
,
207 status
= ntlmssp_callbacks
[i
].sync_fn(gensec_security
,
210 state
->status
= status
;
211 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
212 tevent_req_done(req
);
213 return tevent_req_post(req
, ev
);
215 if (tevent_req_nterror(req
, status
)) {
216 return tevent_req_post(req
, ev
);
219 tevent_req_done(req
);
220 return tevent_req_post(req
, ev
);
223 static void gensec_ntlmssp_update_done(struct tevent_req
*subreq
)
225 struct tevent_req
*req
=
226 tevent_req_callback_data(subreq
,
228 struct gensec_ntlmssp_update_state
*state
=
230 struct gensec_ntlmssp_update_state
);
233 status
= state
->cb
->recv_fn(subreq
, state
, &state
->out
);
235 if (GENSEC_UPDATE_IS_NTERROR(status
)) {
236 tevent_req_nterror(req
, status
);
240 state
->status
= status
;
241 tevent_req_done(req
);
244 static NTSTATUS
gensec_ntlmssp_update_recv(struct tevent_req
*req
,
245 TALLOC_CTX
*out_mem_ctx
,
248 struct gensec_ntlmssp_update_state
*state
=
250 struct gensec_ntlmssp_update_state
);
253 *out
= data_blob_null
;
255 if (tevent_req_is_nterror(req
, &status
)) {
256 tevent_req_received(req
);
261 talloc_steal(out_mem_ctx
, state
->out
.data
);
262 status
= state
->status
;
263 tevent_req_received(req
);
267 static NTSTATUS
gensec_ntlmssp_may_reset_crypto(struct gensec_security
*gensec_security
,
270 struct gensec_ntlmssp_context
*gensec_ntlmssp
=
271 talloc_get_type_abort(gensec_security
->private_data
,
272 struct gensec_ntlmssp_context
);
273 struct ntlmssp_state
*ntlmssp_state
= gensec_ntlmssp
->ntlmssp_state
;
275 bool reset_seqnums
= full_reset
;
277 if (!gensec_ntlmssp_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
281 status
= ntlmssp_sign_reset(ntlmssp_state
, reset_seqnums
);
282 if (!NT_STATUS_IS_OK(status
)) {
283 DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n",
291 static const char *gensec_ntlmssp_final_auth_type(struct gensec_security
*gensec_security
)
293 return GENSEC_FINAL_AUTH_TYPE_NTLMSSP
;
296 static const char *gensec_ntlmssp_oids
[] = {
301 static const struct gensec_security_ops gensec_ntlmssp_security_ops
= {
303 .sasl_name
= GENSEC_SASL_NAME_NTLMSSP
, /* "NTLM" */
304 .auth_type
= DCERPC_AUTH_TYPE_NTLMSSP
,
305 .oid
= gensec_ntlmssp_oids
,
306 .client_start
= gensec_ntlmssp_client_start
,
307 .server_start
= gensec_ntlmssp_server_start
,
308 .magic
= gensec_ntlmssp_magic
,
309 .update_send
= gensec_ntlmssp_update_send
,
310 .update_recv
= gensec_ntlmssp_update_recv
,
311 .may_reset_crypto
= gensec_ntlmssp_may_reset_crypto
,
312 .sig_size
= gensec_ntlmssp_sig_size
,
313 .sign_packet
= gensec_ntlmssp_sign_packet
,
314 .check_packet
= gensec_ntlmssp_check_packet
,
315 .seal_packet
= gensec_ntlmssp_seal_packet
,
316 .unseal_packet
= gensec_ntlmssp_unseal_packet
,
317 .wrap
= gensec_ntlmssp_wrap
,
318 .unwrap
= gensec_ntlmssp_unwrap
,
319 .session_key
= gensec_ntlmssp_session_key
,
320 .session_info
= gensec_ntlmssp_session_info
,
321 .have_feature
= gensec_ntlmssp_have_feature
,
322 .final_auth_type
= gensec_ntlmssp_final_auth_type
,
324 .priority
= GENSEC_NTLMSSP
327 static const struct gensec_security_ops gensec_ntlmssp_resume_ccache_ops
= {
328 .name
= "ntlmssp_resume_ccache",
329 .client_start
= gensec_ntlmssp_resume_ccache_start
,
330 .update_send
= gensec_ntlmssp_update_send
,
331 .update_recv
= gensec_ntlmssp_update_recv
,
332 .session_key
= gensec_ntlmssp_session_key
,
333 .have_feature
= gensec_ntlmssp_have_feature
,
335 .priority
= GENSEC_NTLMSSP
338 _PUBLIC_ NTSTATUS
gensec_ntlmssp_init(TALLOC_CTX
*ctx
)
342 ret
= gensec_register(ctx
, &gensec_ntlmssp_security_ops
);
343 if (!NT_STATUS_IS_OK(ret
)) {
344 DEBUG(0,("Failed to register '%s' gensec backend!\n",
345 gensec_ntlmssp_security_ops
.name
));
349 ret
= gensec_register(ctx
, &gensec_ntlmssp_resume_ccache_ops
);
350 if (!NT_STATUS_IS_OK(ret
)) {
351 DEBUG(0,("Failed to register '%s' gensec backend!\n",
352 gensec_ntlmssp_resume_ccache_ops
.name
));
359 static struct gensec_security
*gensec_find_child_by_ops(struct gensec_security
*gensec_security
,
360 const struct gensec_security_ops
*ops
)
362 struct gensec_security
*current
= gensec_security
;
364 while (current
!= NULL
) {
365 if (current
->ops
== ops
) {
369 current
= current
->child_security
;
375 uint32_t gensec_ntlmssp_neg_flags(struct gensec_security
*gensec_security
)
377 struct gensec_ntlmssp_context
*gensec_ntlmssp
;
379 gensec_security
= gensec_find_child_by_ops(gensec_security
,
380 &gensec_ntlmssp_security_ops
);
381 if (gensec_security
== NULL
) {
385 gensec_ntlmssp
= talloc_get_type_abort(gensec_security
->private_data
,
386 struct gensec_ntlmssp_context
);
387 return gensec_ntlmssp
->ntlmssp_state
->neg_flags
;
390 const char *gensec_ntlmssp_server_domain(struct gensec_security
*gensec_security
)
392 struct gensec_ntlmssp_context
*gensec_ntlmssp
;
394 gensec_security
= gensec_find_child_by_ops(gensec_security
,
395 &gensec_ntlmssp_security_ops
);
396 if (gensec_security
== NULL
) {
400 gensec_ntlmssp
= talloc_get_type_abort(gensec_security
->private_data
,
401 struct gensec_ntlmssp_context
);
402 return gensec_ntlmssp
->ntlmssp_state
->server
.netbios_domain
;