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.
26 struct gensec_ntlmssp_state {
28 struct auth_context *auth_context;
29 struct auth_serversupplied_info *server_info;
30 struct ntlmssp_state *ntlmssp_state;
35 * Return the challenge as determined by the authentication subsystem
36 * @return an 8 byte random challenge
39 static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
41 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
43 return gensec_ntlmssp_state->auth_context->get_ntlm_challenge(gensec_ntlmssp_state->auth_context);
47 * Some authentication methods 'fix' the challenge, so we may not be able to set it
49 * @return If the effective challenge used by the auth subsystem may be modified
51 static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
53 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
55 return gensec_ntlmssp_state->auth_context->challenge_may_be_modified;
59 * NTLM2 authentication modifies the effective challenge,
60 * @param challenge The new challenge value
62 static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
64 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
65 struct auth_context *auth_context = gensec_ntlmssp_state->auth_context;
67 SMB_ASSERT(challenge->length == 8);
69 auth_context->challenge = data_blob_talloc(auth_context->mem_ctx,
70 challenge->data, challenge->length);
72 auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
74 DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
75 DEBUG(5, ("challenge is: \n"));
76 dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
81 * Check the password on an NTLMSSP login.
83 * Return the session keys used on the connection.
86 static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
88 struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
89 struct auth_usersupplied_info *user_info = NULL;
93 /* the client has given us its machine name (which we otherwise would not get on port 445).
94 we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
96 set_remote_machine_name(gensec_ntlmssp_state->ntlmssp_state->workstation, True);
98 /* setup the string used by %U */
99 /* sub_set_smb_name checks for weird internally */
100 sub_set_smb_name(gensec_ntlmssp_state->ntlmssp_state->user);
102 reload_services(True);
105 nt_status = make_user_info_map(&user_info,
106 gensec_ntlmssp_state->ntlmssp_state->user,
107 gensec_ntlmssp_state->ntlmssp_state->domain,
108 gensec_ntlmssp_state->ntlmssp_state->workstation,
109 gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
110 gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
114 if (!NT_STATUS_IS_OK(nt_status)) {
118 nt_status = gensec_ntlmssp_state->auth_context->check_ntlm_password(gensec_ntlmssp_state->auth_context,
119 user_info, &gensec_ntlmssp_state->server_info);
121 free_user_info(&user_info);
123 if (!NT_STATUS_IS_OK(nt_status)) {
126 if (gensec_ntlmssp_state->server_info->user_session_key.length) {
127 DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length));
128 *user_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
129 gensec_ntlmssp_state->server_info->user_session_key.data,
130 gensec_ntlmssp_state->server_info->user_session_key.length);
132 if (gensec_ntlmssp_state->server_info->lm_session_key.length) {
133 DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length));
134 *lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
135 gensec_ntlmssp_state->server_info->lm_session_key.data,
136 gensec_ntlmssp_state->server_info->lm_session_key.length);
141 static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security)
143 struct gensec_ntlmssp_state *gensec_ntlmssp_state;
145 TALLOC_CTX *mem_ctx = talloc_init("gensec_ntlmssp");
147 return NT_STATUS_NO_MEMORY;
150 gensec_ntlmssp_state = talloc_p(mem_ctx, struct gensec_ntlmssp_state);
151 if (!gensec_ntlmssp_state) {
152 return NT_STATUS_NO_MEMORY;
155 gensec_ntlmssp_state->mem_ctx = mem_ctx;
156 gensec_ntlmssp_state->ntlmssp_state = NULL;
157 gensec_ntlmssp_state->auth_context = NULL;
158 gensec_ntlmssp_state->server_info = NULL;
160 gensec_security->private_data = gensec_ntlmssp_state;
164 static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
168 struct ntlmssp_state *ntlmssp_state;
169 struct gensec_ntlmssp_state *gensec_ntlmssp_state;
171 status = gensec_ntlmssp_start(gensec_security);
172 if (!NT_STATUS_IS_OK(status)) {
176 gensec_ntlmssp_state = gensec_security->private_data;
178 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&gensec_ntlmssp_state->ntlmssp_state))) {
182 ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state;
183 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&gensec_ntlmssp_state->auth_context))) {
187 ntlmssp_state->auth_context = gensec_ntlmssp_state;
188 ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
189 ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
190 ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
191 ntlmssp_state->check_password = auth_ntlmssp_check_password;
192 ntlmssp_state->server_role = lp_server_role();
197 static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
199 struct gensec_ntlmssp_state *gensec_ntlmssp_state;
200 char *password = NULL;
203 status = gensec_ntlmssp_start(gensec_security);
204 if (!NT_STATUS_IS_OK(status)) {
208 gensec_ntlmssp_state = gensec_security->private_data;
209 status = ntlmssp_client_start(&gensec_ntlmssp_state->ntlmssp_state);
210 if (!NT_STATUS_IS_OK(status)) {
214 status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state,
215 gensec_security->user.domain);
216 if (!NT_STATUS_IS_OK(status)) {
220 status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state,
221 gensec_security->user.name);
222 if (!NT_STATUS_IS_OK(status)) {
226 status = gensec_get_password(gensec_security, gensec_ntlmssp_state->mem_ctx, &password);
227 if (!NT_STATUS_IS_OK(status)) {
232 status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state,
234 if (!NT_STATUS_IS_OK(status)) {
239 gensec_security->private_data = gensec_ntlmssp_state;
245 wrappers for the ntlmssp_*() functions
247 static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
249 uint8_t *data, size_t length, DATA_BLOB *sig)
251 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
253 return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
256 static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
258 const uint8_t *data, size_t length,
259 const DATA_BLOB *sig)
261 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
263 return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
266 static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
268 uint8_t *data, size_t length,
271 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
273 return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
276 static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
278 const uint8_t *data, size_t length,
281 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
283 return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
286 static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
287 DATA_BLOB *session_key)
289 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
291 return ntlmssp_session_key(gensec_ntlmssp_state->ntlmssp_state, session_key);
295 * Next state function for the wrapped NTLMSSP state machine
297 * @param gensec_ntlmssp_state NTLMSSP State
298 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
299 * @param in The request, as a DATA_BLOB
300 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
301 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
302 * or NT_STATUS_OK if the user is authenticated.
305 static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
306 const DATA_BLOB in, DATA_BLOB *out)
308 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
310 return ntlmssp_update(gensec_ntlmssp_state->ntlmssp_state, out_mem_ctx, in, out);
314 * Return the credentials of a logged on user, including session keys
317 * Only valid after a successful authentication
319 * May only be called once per authentication.
323 static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
324 struct auth_session_info **session_info)
327 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
328 nt_status = make_session_info(gensec_ntlmssp_state->server_info, session_info);
330 if (!NT_STATUS_IS_OK(nt_status)) {
334 /* the session_info owns this now */
335 gensec_ntlmssp_state->server_info = NULL;
337 (*session_info)->session_key = data_blob_talloc((*session_info)->mem_ctx,
338 gensec_ntlmssp_state->ntlmssp_state->session_key.data,
339 gensec_ntlmssp_state->ntlmssp_state->session_key.length);
341 (*session_info)->workstation = talloc_strdup((*session_info)->mem_ctx,
342 gensec_ntlmssp_state->ntlmssp_state->workstation);
347 static void gensec_ntlmssp_end(struct gensec_security *gensec_security)
349 struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
351 if (gensec_ntlmssp_state->ntlmssp_state) {
352 ntlmssp_end(&gensec_ntlmssp_state->ntlmssp_state);
355 if (gensec_ntlmssp_state->auth_context) {
356 free_auth_context(&gensec_ntlmssp_state->auth_context);
358 if (gensec_ntlmssp_state->server_info) {
359 free_server_info(&gensec_ntlmssp_state->server_info);
361 talloc_destroy(gensec_ntlmssp_state->mem_ctx);
362 gensec_security->private_data = NULL;
365 static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
368 .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
370 .client_start = gensec_ntlmssp_client_start,
371 .server_start = gensec_ntlmssp_server_start,
372 .update = gensec_ntlmssp_update,
373 .seal_packet = gensec_ntlmssp_seal_packet,
374 .sign_packet = gensec_ntlmssp_sign_packet,
375 .check_packet = gensec_ntlmssp_check_packet,
376 .unseal_packet = gensec_ntlmssp_unseal_packet,
377 .session_key = gensec_ntlmssp_session_key,
378 .session_info = gensec_ntlmssp_session_info,
379 .end = gensec_ntlmssp_end
383 NTSTATUS gensec_ntlmssp_init(void)
386 ret = register_backend("gensec", &gensec_ntlmssp_security_ops);
387 if (!NT_STATUS_IS_OK(ret)) {
388 DEBUG(0,("Failed to register '%s' gensec backend!\n",
389 gensec_ntlmssp_security_ops.name));
393 /* ugly cludge, but we need the auth subsystem for this to work */