build: Move uid_wrapper to third_party
[Samba.git] / auth / ntlmssp / ntlmssp.c
blob36e7052793f6fe6a7f3a233c9af6fbcf970247a2
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
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;
26 #include "includes.h"
27 #include <tevent.h>
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"
36 /**
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,
50 const DATA_BLOB in);
51 NTSTATUS (*recv_fn)(struct tevent_req *req,
52 TALLOC_CTX *out_mem_ctx,
53 DATA_BLOB *out);
54 } ntlmssp_callbacks[] = {
56 .role = NTLMSSP_CLIENT,
57 .command = NTLMSSP_INITIAL,
58 .sync_fn = ntlmssp_client_initial,
59 },{
60 .role = NTLMSSP_CLIENT,
61 .command = NTLMSSP_NEGOTIATE,
62 .sync_fn = gensec_ntlmssp_resume_ccache,
63 },{
64 .role = NTLMSSP_SERVER,
65 .command = NTLMSSP_NEGOTIATE,
66 .sync_fn = gensec_ntlmssp_server_negotiate,
67 },{
68 .role = NTLMSSP_CLIENT,
69 .command = NTLMSSP_CHALLENGE,
70 .sync_fn = ntlmssp_client_challenge,
71 },{
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;
85 uint32_t i;
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;
96 if (!input.length) {
97 switch (gensec_ntlmssp->ntlmssp_state->role) {
98 case NTLMSSP_CLIENT:
99 if (gensec_ntlmssp->ntlmssp_state->resume_ccache) {
101 * make sure gensec_ntlmssp_resume_ccache()
102 * will be called
104 ntlmssp_command = NTLMSSP_NEGOTIATE;
105 break;
108 ntlmssp_command = NTLMSSP_INITIAL;
109 break;
110 case NTLMSSP_SERVER:
111 if (gensec_security->want_features & GENSEC_FEATURE_DATAGRAM_MODE) {
112 /* 'datagram' mode - no neg packet */
113 ntlmssp_command = NTLMSSP_NEGOTIATE;
114 } else {
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;
119 break;
120 default:
121 DEBUG(1, ("NTLMSSP state has invalid role %d\n",
122 gensec_ntlmssp->ntlmssp_state->role));
123 return NT_STATUS_INVALID_PARAMETER;
125 } else {
126 if (!msrpc_parse(gensec_ntlmssp->ntlmssp_state,
127 &input, "Cd",
128 "NTLMSSP",
129 &ntlmssp_command)) {
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) {
145 *idx = i;
146 return NT_STATUS_OK;
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;
158 NTSTATUS status;
159 DATA_BLOB out;
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,
167 const DATA_BLOB in)
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;
174 NTSTATUS status;
175 uint32_t i = 0;
177 req = tevent_req_create(mem_ctx, &state,
178 struct gensec_ntlmssp_update_state);
179 if (req == NULL) {
180 return NULL;
183 status = gensec_ntlmssp_update_find(gensec_security,
184 gensec_ntlmssp,
185 in, &i);
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,
196 gensec_security,
197 in);
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,
203 req);
204 return req;
207 status = ntlmssp_callbacks[i].sync_fn(gensec_security,
208 state,
209 in, &state->out);
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,
227 struct tevent_req);
228 struct gensec_ntlmssp_update_state *state =
229 tevent_req_data(req,
230 struct gensec_ntlmssp_update_state);
231 NTSTATUS status;
233 status = state->cb->recv_fn(subreq, state, &state->out);
234 TALLOC_FREE(subreq);
235 if (GENSEC_UPDATE_IS_NTERROR(status)) {
236 tevent_req_nterror(req, status);
237 return;
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,
246 DATA_BLOB *out)
248 struct gensec_ntlmssp_update_state *state =
249 tevent_req_data(req,
250 struct gensec_ntlmssp_update_state);
251 NTSTATUS status;
253 *out = data_blob_null;
255 if (tevent_req_is_nterror(req, &status)) {
256 tevent_req_received(req);
257 return status;
260 *out = state->out;
261 talloc_steal(out_mem_ctx, state->out.data);
262 status = state->status;
263 tevent_req_received(req);
264 return status;
267 static NTSTATUS gensec_ntlmssp_may_reset_crypto(struct gensec_security *gensec_security,
268 bool full_reset)
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;
274 NTSTATUS status;
275 bool reset_seqnums = full_reset;
277 if (!gensec_ntlmssp_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
278 return NT_STATUS_OK;
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",
284 nt_errstr(status)));
285 return status;
288 return NT_STATUS_OK;
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[] = {
297 GENSEC_OID_NTLMSSP,
298 NULL
301 static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
302 .name = "ntlmssp",
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,
323 .enabled = true,
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,
334 .enabled = true,
335 .priority = GENSEC_NTLMSSP
338 _PUBLIC_ NTSTATUS gensec_ntlmssp_init(TALLOC_CTX *ctx)
340 NTSTATUS ret;
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));
346 return ret;
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));
353 return ret;
356 return ret;
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) {
366 return current;
369 current = current->child_security;
372 return NULL;
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) {
382 return 0;
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) {
397 return 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;