2 Unix SMB/CIFS implementation.
4 dcerpc authentication operations
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "auth/auth.h"
28 struct gensec_ntlmssp_state {
29 struct auth_context *auth_context;
30 struct auth_serversupplied_info *server_info;
31 struct ntlmssp_state *ntlmssp_state;
36 * Return the challenge as determined by the authentication subsystem
37 * @return an 8 byte random challenge
40 static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
42 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
44 return gensec_ntlmssp_state->auth_context->get_ntlm_challenge(gensec_ntlmssp_state->auth_context);
48 * Some authentication methods 'fix' the challenge, so we may not be able to set it
50 * @return If the effective challenge used by the auth subsystem may be modified
52 static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
54 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
56 return gensec_ntlmssp_state->auth_context->challenge_may_be_modified;
60 * NTLM2 authentication modifies the effective challenge,
61 * @param challenge The new challenge value
63 static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
65 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
66 struct auth_context *auth_context = gensec_ntlmssp_state->auth_context;
68 SMB_ASSERT(challenge->length == 8);
70 auth_context->challenge = data_blob_talloc(auth_context,
71 challenge->data, challenge->length);
73 auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
75 DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
76 DEBUG(5, ("challenge is: \n"));
77 dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
82 * Check the password on an NTLMSSP login.
84 * Return the session keys used on the connection.
87 static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
89 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
90 struct auth_usersupplied_info *user_info = NULL;
94 /* the client has given us its machine name (which we otherwise would not get on port 445).
95 we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
97 set_remote_machine_name(gensec_ntlmssp_state->ntlmssp_state->workstation, True);
99 /* setup the string used by %U */
100 /* sub_set_smb_name checks for weird internally */
101 sub_set_smb_name(gensec_ntlmssp_state->ntlmssp_state->user);
103 reload_services(True);
106 nt_status = make_user_info_map(ntlmssp_state,
108 gensec_ntlmssp_state->ntlmssp_state->user,
109 gensec_ntlmssp_state->ntlmssp_state->domain,
110 gensec_ntlmssp_state->ntlmssp_state->workstation,
111 gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
112 gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
116 if (!NT_STATUS_IS_OK(nt_status)) {
120 nt_status = gensec_ntlmssp_state->
121 auth_context->check_ntlm_password(gensec_ntlmssp_state->auth_context,
123 gensec_ntlmssp_state,
124 &gensec_ntlmssp_state->server_info);
126 free_user_info(&user_info);
128 if (!NT_STATUS_IS_OK(nt_status)) {
131 if (gensec_ntlmssp_state->server_info->user_session_key.length) {
132 DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length));
133 *user_session_key = data_blob_talloc(ntlmssp_state,
134 gensec_ntlmssp_state->server_info->user_session_key.data,
135 gensec_ntlmssp_state->server_info->user_session_key.length);
137 if (gensec_ntlmssp_state->server_info->lm_session_key.length) {
138 DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length));
139 *lm_session_key = data_blob_talloc(ntlmssp_state,
140 gensec_ntlmssp_state->server_info->lm_session_key.data,
141 gensec_ntlmssp_state->server_info->lm_session_key.length);
146 static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security)
148 struct gensec_ntlmssp_state *gensec_ntlmssp_state;
150 gensec_ntlmssp_state = talloc_p(gensec_security, struct gensec_ntlmssp_state);
151 if (!gensec_ntlmssp_state) {
152 return NT_STATUS_NO_MEMORY;
155 gensec_ntlmssp_state->ntlmssp_state = NULL;
156 gensec_ntlmssp_state->auth_context = NULL;
157 gensec_ntlmssp_state->server_info = NULL;
159 gensec_security->private_data = gensec_ntlmssp_state;
163 static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
167 struct ntlmssp_state *ntlmssp_state;
168 struct gensec_ntlmssp_state *gensec_ntlmssp_state;
170 status = gensec_ntlmssp_start(gensec_security);
171 if (!NT_STATUS_IS_OK(status)) {
175 gensec_ntlmssp_state = gensec_security->private_data;
177 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(gensec_security,
178 &gensec_ntlmssp_state->ntlmssp_state))) {
182 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
183 gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
185 if (gensec_security->want_features & GENSEC_WANT_SEAL) {
186 gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
189 ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state;
190 nt_status = make_auth_context_subsystem(gensec_security, &gensec_ntlmssp_state->auth_context);
191 if (!NT_STATUS_IS_OK(nt_status)) {
195 ntlmssp_state->auth_context = gensec_ntlmssp_state;
196 ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
197 ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
198 ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
199 ntlmssp_state->check_password = auth_ntlmssp_check_password;
200 ntlmssp_state->server_role = lp_server_role();
205 static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
207 struct gensec_ntlmssp_state *gensec_ntlmssp_state;
208 char *password = NULL;
211 status = gensec_ntlmssp_start(gensec_security);
212 if (!NT_STATUS_IS_OK(status)) {
216 gensec_ntlmssp_state = gensec_security->private_data;
217 status = ntlmssp_client_start(gensec_security,
218 &gensec_ntlmssp_state->ntlmssp_state);
219 if (!NT_STATUS_IS_OK(status)) {
223 if (gensec_security->want_features & GENSEC_WANT_SESSION_KEY) {
225 * We need to set this to allow a later SetPassword
226 * via the SAMR pipe to succeed. Strange.... We could
227 * also add NTLMSSP_NEGOTIATE_SEAL here. JRA.
229 * Without this, Windows will not create the master key
230 * that it thinks is only used for NTLMSSP signing and
231 * sealing. (It is actually pulled out and used directly)
233 gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
235 if (gensec_security->want_features & GENSEC_WANT_SIGN) {
236 gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
238 if (gensec_security->want_features & GENSEC_WANT_SEAL) {
239 gensec_ntlmssp_state->ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL;
242 status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state,
243 gensec_security->user.domain);
244 if (!NT_STATUS_IS_OK(status)) {
248 status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state,
249 gensec_security->user.name);
250 if (!NT_STATUS_IS_OK(status)) {
254 status = gensec_get_password(gensec_security, gensec_ntlmssp_state, &password);
255 if (!NT_STATUS_IS_OK(status)) {
260 status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state,
262 if (!NT_STATUS_IS_OK(status)) {
267 gensec_security->private_data = gensec_ntlmssp_state;
273 wrappers for the ntlmssp_*() functions
275 static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
277 uint8_t *data, size_t length,
278 const uint8_t *whole_pdu, size_t pdu_length,
281 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
283 return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
286 static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
288 const uint8_t *data, size_t length,
289 const uint8_t *whole_pdu, size_t pdu_length,
290 const DATA_BLOB *sig)
292 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
294 return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
297 static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
299 uint8_t *data, size_t length,
300 const uint8_t *whole_pdu, size_t pdu_length,
303 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
305 return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
308 static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
310 const uint8_t *data, size_t length,
311 const uint8_t *whole_pdu, size_t pdu_length,
314 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
316 return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, whole_pdu, pdu_length, sig);
319 static size_t gensec_ntlmssp_sig_size(struct gensec_security *gensec_security)
321 return NTLMSSP_SIG_SIZE;
324 static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
325 DATA_BLOB *session_key)
327 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
329 return ntlmssp_session_key(gensec_ntlmssp_state->ntlmssp_state, session_key);
333 * Next state function for the wrapped NTLMSSP state machine
335 * @param gensec_security GENSEC state, initialised to NTLMSSP
336 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
337 * @param in The request, as a DATA_BLOB
338 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
339 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
340 * or NT_STATUS_OK if the user is authenticated.
343 static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
344 const DATA_BLOB in, DATA_BLOB *out)
346 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
348 return ntlmssp_update(gensec_ntlmssp_state->ntlmssp_state, out_mem_ctx, in, out);
352 * Return the credentials of a logged on user, including session keys
355 * Only valid after a successful authentication
357 * May only be called once per authentication.
361 static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
362 struct auth_session_info **session_info)
365 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
366 nt_status = make_session_info(gensec_ntlmssp_state, gensec_ntlmssp_state->server_info, session_info);
368 if (!NT_STATUS_IS_OK(nt_status)) {
372 (*session_info)->session_key = data_blob_talloc(*session_info,
373 gensec_ntlmssp_state->ntlmssp_state->session_key.data,
374 gensec_ntlmssp_state->ntlmssp_state->session_key.length);
376 (*session_info)->workstation = talloc_strdup(*session_info,
377 gensec_ntlmssp_state->ntlmssp_state->workstation);
382 static void gensec_ntlmssp_end(struct gensec_security *gensec_security)
384 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
386 if (gensec_ntlmssp_state->ntlmssp_state) {
387 ntlmssp_end(&gensec_ntlmssp_state->ntlmssp_state);
390 if (gensec_ntlmssp_state->auth_context) {
391 free_auth_context(&gensec_ntlmssp_state->auth_context);
393 if (gensec_ntlmssp_state->server_info) {
394 free_server_info(&gensec_ntlmssp_state->server_info);
396 talloc_free(gensec_ntlmssp_state);
397 gensec_security->private_data = NULL;
400 static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
403 .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
405 .client_start = gensec_ntlmssp_client_start,
406 .server_start = gensec_ntlmssp_server_start,
407 .update = gensec_ntlmssp_update,
408 .seal_packet = gensec_ntlmssp_seal_packet,
409 .sig_size = gensec_ntlmssp_sig_size,
410 .sign_packet = gensec_ntlmssp_sign_packet,
411 .check_packet = gensec_ntlmssp_check_packet,
412 .unseal_packet = gensec_ntlmssp_unseal_packet,
413 .session_key = gensec_ntlmssp_session_key,
414 .session_info = gensec_ntlmssp_session_info,
415 .end = gensec_ntlmssp_end
419 NTSTATUS gensec_ntlmssp_init(void)
422 ret = register_backend("gensec", &gensec_ntlmssp_security_ops);
423 if (!NT_STATUS_IS_OK(ret)) {
424 DEBUG(0,("Failed to register '%s' gensec backend!\n",
425 gensec_ntlmssp_security_ops.name));