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 } ntlmssp_callbacks
[] = {
49 .role
= NTLMSSP_CLIENT
,
50 .command
= NTLMSSP_INITIAL
,
51 .sync_fn
= ntlmssp_client_initial
,
53 .role
= NTLMSSP_CLIENT
,
54 .command
= NTLMSSP_NEGOTIATE
,
55 .sync_fn
= gensec_ntlmssp_resume_ccache
,
57 .role
= NTLMSSP_SERVER
,
58 .command
= NTLMSSP_NEGOTIATE
,
59 .sync_fn
= gensec_ntlmssp_server_negotiate
,
61 .role
= NTLMSSP_CLIENT
,
62 .command
= NTLMSSP_CHALLENGE
,
63 .sync_fn
= ntlmssp_client_challenge
,
65 .role
= NTLMSSP_SERVER
,
66 .command
= NTLMSSP_AUTH
,
67 .sync_fn
= gensec_ntlmssp_server_auth
,
72 static NTSTATUS
gensec_ntlmssp_update_find(struct gensec_security
*gensec_security
,
73 struct gensec_ntlmssp_context
*gensec_ntlmssp
,
74 const DATA_BLOB input
, uint32_t *idx
)
76 uint32_t ntlmssp_command
;
79 if (gensec_ntlmssp
->ntlmssp_state
->expected_state
== NTLMSSP_DONE
) {
80 /* We are strict here because other modules, which we
81 * don't fully control (such as GSSAPI) are also
82 * strict, but are tested less often */
84 DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
85 return NT_STATUS_INVALID_PARAMETER
;
89 switch (gensec_ntlmssp
->ntlmssp_state
->role
) {
91 if (gensec_ntlmssp
->ntlmssp_state
->resume_ccache
) {
93 * make sure gensec_ntlmssp_resume_ccache()
96 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
100 ntlmssp_command
= NTLMSSP_INITIAL
;
103 if (gensec_security
->want_features
& GENSEC_FEATURE_DATAGRAM_MODE
) {
104 /* 'datagram' mode - no neg packet */
105 ntlmssp_command
= NTLMSSP_NEGOTIATE
;
107 /* This is normal in SPNEGO mech negotiation fallback */
108 DEBUG(2, ("Failed to parse NTLMSSP packet: zero length\n"));
109 return NT_STATUS_INVALID_PARAMETER
;
113 DEBUG(1, ("NTLMSSP state has invalid role %d\n",
114 gensec_ntlmssp
->ntlmssp_state
->role
));
115 return NT_STATUS_INVALID_PARAMETER
;
118 if (!msrpc_parse(gensec_ntlmssp
->ntlmssp_state
,
122 DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
123 dump_data(2, input
.data
, input
.length
);
124 return NT_STATUS_INVALID_PARAMETER
;
128 if (ntlmssp_command
!= gensec_ntlmssp
->ntlmssp_state
->expected_state
) {
129 DEBUG(2, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command
,
130 gensec_ntlmssp
->ntlmssp_state
->expected_state
));
131 return NT_STATUS_INVALID_PARAMETER
;
134 for (i
=0; i
< ARRAY_SIZE(ntlmssp_callbacks
); i
++) {
135 if (ntlmssp_callbacks
[i
].role
== gensec_ntlmssp
->ntlmssp_state
->role
&&
136 ntlmssp_callbacks
[i
].command
== ntlmssp_command
) {
142 DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n",
143 gensec_ntlmssp
->ntlmssp_state
->role
, ntlmssp_command
));
145 return NT_STATUS_INVALID_PARAMETER
;
148 struct gensec_ntlmssp_update_state
{
153 static struct tevent_req
*gensec_ntlmssp_update_send(TALLOC_CTX
*mem_ctx
,
154 struct tevent_context
*ev
,
155 struct gensec_security
*gensec_security
,
158 struct gensec_ntlmssp_context
*gensec_ntlmssp
=
159 talloc_get_type_abort(gensec_security
->private_data
,
160 struct gensec_ntlmssp_context
);
161 struct tevent_req
*req
= NULL
;
162 struct gensec_ntlmssp_update_state
*state
= NULL
;
166 req
= tevent_req_create(mem_ctx
, &state
,
167 struct gensec_ntlmssp_update_state
);
172 status
= gensec_ntlmssp_update_find(gensec_security
,
175 if (tevent_req_nterror(req
, status
)) {
176 return tevent_req_post(req
, ev
);
179 status
= ntlmssp_callbacks
[i
].sync_fn(gensec_security
,
182 state
->status
= status
;
183 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
184 tevent_req_done(req
);
185 return tevent_req_post(req
, ev
);
187 if (tevent_req_nterror(req
, status
)) {
188 return tevent_req_post(req
, ev
);
191 tevent_req_done(req
);
192 return tevent_req_post(req
, ev
);
195 static NTSTATUS
gensec_ntlmssp_update_recv(struct tevent_req
*req
,
196 TALLOC_CTX
*out_mem_ctx
,
199 struct gensec_ntlmssp_update_state
*state
=
201 struct gensec_ntlmssp_update_state
);
204 *out
= data_blob_null
;
206 if (tevent_req_is_nterror(req
, &status
)) {
207 tevent_req_received(req
);
212 talloc_steal(out_mem_ctx
, state
->out
.data
);
213 status
= state
->status
;
214 tevent_req_received(req
);
218 static NTSTATUS
gensec_ntlmssp_may_reset_crypto(struct gensec_security
*gensec_security
,
221 struct gensec_ntlmssp_context
*gensec_ntlmssp
=
222 talloc_get_type_abort(gensec_security
->private_data
,
223 struct gensec_ntlmssp_context
);
224 struct ntlmssp_state
*ntlmssp_state
= gensec_ntlmssp
->ntlmssp_state
;
226 bool reset_seqnums
= full_reset
;
228 if (!gensec_ntlmssp_have_feature(gensec_security
, GENSEC_FEATURE_SIGN
)) {
232 status
= ntlmssp_sign_reset(ntlmssp_state
, reset_seqnums
);
233 if (!NT_STATUS_IS_OK(status
)) {
234 DEBUG(1, ("Could not reset NTLMSSP signing/sealing system (error was: %s)\n",
242 static const char *gensec_ntlmssp_final_auth_type(struct gensec_security
*gensec_security
)
244 return GENSEC_FINAL_AUTH_TYPE_NTLMSSP
;
247 static const char *gensec_ntlmssp_oids
[] = {
252 static const struct gensec_security_ops gensec_ntlmssp_security_ops
= {
254 .sasl_name
= GENSEC_SASL_NAME_NTLMSSP
, /* "NTLM" */
255 .auth_type
= DCERPC_AUTH_TYPE_NTLMSSP
,
256 .oid
= gensec_ntlmssp_oids
,
257 .client_start
= gensec_ntlmssp_client_start
,
258 .server_start
= gensec_ntlmssp_server_start
,
259 .magic
= gensec_ntlmssp_magic
,
260 .update_send
= gensec_ntlmssp_update_send
,
261 .update_recv
= gensec_ntlmssp_update_recv
,
262 .may_reset_crypto
= gensec_ntlmssp_may_reset_crypto
,
263 .sig_size
= gensec_ntlmssp_sig_size
,
264 .sign_packet
= gensec_ntlmssp_sign_packet
,
265 .check_packet
= gensec_ntlmssp_check_packet
,
266 .seal_packet
= gensec_ntlmssp_seal_packet
,
267 .unseal_packet
= gensec_ntlmssp_unseal_packet
,
268 .wrap
= gensec_ntlmssp_wrap
,
269 .unwrap
= gensec_ntlmssp_unwrap
,
270 .session_key
= gensec_ntlmssp_session_key
,
271 .session_info
= gensec_ntlmssp_session_info
,
272 .have_feature
= gensec_ntlmssp_have_feature
,
273 .final_auth_type
= gensec_ntlmssp_final_auth_type
,
275 .priority
= GENSEC_NTLMSSP
278 static const struct gensec_security_ops gensec_ntlmssp_resume_ccache_ops
= {
279 .name
= "ntlmssp_resume_ccache",
280 .client_start
= gensec_ntlmssp_resume_ccache_start
,
281 .update_send
= gensec_ntlmssp_update_send
,
282 .update_recv
= gensec_ntlmssp_update_recv
,
283 .session_key
= gensec_ntlmssp_session_key
,
284 .have_feature
= gensec_ntlmssp_have_feature
,
286 .priority
= GENSEC_NTLMSSP
289 _PUBLIC_ NTSTATUS
gensec_ntlmssp_init(TALLOC_CTX
*ctx
)
293 ret
= gensec_register(ctx
, &gensec_ntlmssp_security_ops
);
294 if (!NT_STATUS_IS_OK(ret
)) {
295 DEBUG(0,("Failed to register '%s' gensec backend!\n",
296 gensec_ntlmssp_security_ops
.name
));
300 ret
= gensec_register(ctx
, &gensec_ntlmssp_resume_ccache_ops
);
301 if (!NT_STATUS_IS_OK(ret
)) {
302 DEBUG(0,("Failed to register '%s' gensec backend!\n",
303 gensec_ntlmssp_resume_ccache_ops
.name
));
310 static struct gensec_security
*gensec_find_child_by_ops(struct gensec_security
*gensec_security
,
311 const struct gensec_security_ops
*ops
)
313 struct gensec_security
*current
= gensec_security
;
315 while (current
!= NULL
) {
316 if (current
->ops
== ops
) {
320 current
= current
->child_security
;
326 uint32_t gensec_ntlmssp_neg_flags(struct gensec_security
*gensec_security
)
328 struct gensec_ntlmssp_context
*gensec_ntlmssp
;
330 gensec_security
= gensec_find_child_by_ops(gensec_security
,
331 &gensec_ntlmssp_security_ops
);
332 if (gensec_security
== NULL
) {
336 gensec_ntlmssp
= talloc_get_type_abort(gensec_security
->private_data
,
337 struct gensec_ntlmssp_context
);
338 return gensec_ntlmssp
->ntlmssp_state
->neg_flags
;
341 const char *gensec_ntlmssp_server_domain(struct gensec_security
*gensec_security
)
343 struct gensec_ntlmssp_context
*gensec_ntlmssp
;
345 gensec_security
= gensec_find_child_by_ops(gensec_security
,
346 &gensec_ntlmssp_security_ops
);
347 if (gensec_security
== NULL
) {
351 gensec_ntlmssp
= talloc_get_type_abort(gensec_security
->private_data
,
352 struct gensec_ntlmssp_context
);
353 return gensec_ntlmssp
->ntlmssp_state
->server
.netbios_domain
;