2 Unix SMB/Netbios implementation.
4 handle NLTMSSP, server side
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett 2001-2003
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 NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
31 mem_ctx = talloc_init("NTLMSSP context");
33 *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
34 if (!*ntlmssp_state) {
35 DEBUG(0,("ntlmssp_start: talloc failed!\n"));
36 talloc_destroy(mem_ctx);
37 return NT_STATUS_NO_MEMORY;
40 ZERO_STRUCTP(*ntlmssp_state);
42 (*ntlmssp_state)->mem_ctx = mem_ctx;
44 if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*ntlmssp_state)->auth_context))) {
50 NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
52 TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
53 if ((*ntlmssp_state)->auth_context) {
54 ((*ntlmssp_state)->auth_context->free)(&(*ntlmssp_state)->auth_context);
56 if ((*ntlmssp_state)->server_info) {
57 free_server_info(&(*ntlmssp_state)->server_info);
60 talloc_destroy(mem_ctx);
61 *ntlmssp_state = NULL;
65 NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
66 DATA_BLOB request, DATA_BLOB *reply)
68 uint32 ntlmssp_command;
70 if (!msrpc_parse(&request, "Cd",
73 return NT_STATUS_LOGON_FAILURE;
76 if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
77 return ntlmssp_negotiate(ntlmssp_state, request, reply);
78 } else if (ntlmssp_command == NTLMSSP_AUTH) {
79 return ntlmssp_auth(ntlmssp_state, request, reply);
81 return NT_STATUS_LOGON_FAILURE;
85 static const char *ntlmssp_target_name(uint32 neg_flags, uint32 *chal_flags)
87 if (neg_flags & NTLMSSP_REQUEST_TARGET) {
88 if (lp_server_role() == ROLE_STANDALONE) {
89 *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
90 return global_myname();
92 *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
93 return lp_workgroup();
100 NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state,
101 DATA_BLOB request, DATA_BLOB *reply)
103 DATA_BLOB struct_blob;
104 fstring dnsname, dnsdomname;
105 uint32 ntlmssp_command, neg_flags, chal_flags;
106 char *cliname=NULL, *domname=NULL;
107 const uint8 *cryptkey;
108 const char *target_name;
110 /* parse the NTLMSSP packet */
112 file_save("ntlmssp_negotiate.dat", request.data, request.length);
115 if (!msrpc_parse(&request, "CddAA",
121 return NT_STATUS_LOGON_FAILURE;
127 debug_ntlmssp_flags(neg_flags);
129 cryptkey = ntlmssp_state->auth_context->get_ntlm_challenge(ntlmssp_state->auth_context);
131 /* Give them the challenge. For now, ignore neg_flags and just
132 return the flags we want. Obviously this is not correct */
135 NTLMSSP_NEGOTIATE_128 |
136 NTLMSSP_NEGOTIATE_NTLM |
137 NTLMSSP_CHAL_TARGET_INFO;
139 if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
140 chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
141 ntlmssp_state->unicode = True;
143 chal_flags |= NTLMSSP_NEGOTIATE_OEM;
146 target_name = ntlmssp_target_name(neg_flags, &chal_flags);
148 dnsdomname[0] = '\0';
149 get_mydomname(dnsdomname);
150 strlower(dnsdomname);
153 get_myfullname(dnsname);
156 /* the numbers here are the string type flags */
157 msrpc_gen(&struct_blob, "aaaaa",
158 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, lp_workgroup(),
159 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, global_myname(),
160 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsname,
161 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
162 ntlmssp_state->unicode, 0, "");
165 const char *gen_string;
166 if (ntlmssp_state->unicode) {
167 gen_string = "CdUdbddB";
169 gen_string = "CdAdbddB";
172 msrpc_gen(reply, gen_string,
179 struct_blob.data, struct_blob.length);
182 data_blob_free(&struct_blob);
184 return NT_STATUS_MORE_PROCESSING_REQUIRED;
187 NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state,
188 DATA_BLOB request, DATA_BLOB *reply)
190 char *workgroup = NULL, *user = NULL, *machine = NULL;
191 DATA_BLOB lmhash, nthash, sess_key;
192 DATA_BLOB plaintext_password = data_blob(NULL, 0);
193 uint32 ntlmssp_command, neg_flags;
195 uint32 auth_flags = AUTH_FLAG_NONE;
196 auth_usersupplied_info *user_info = NULL;
198 const char *parse_string;
200 /* parse the NTLMSSP packet */
202 file_save("ntlmssp_auth.dat", request.data, request.length);
205 if (ntlmssp_state->unicode) {
206 parse_string = "CdBBUUUBd";
208 parse_string = "CdBBAAABd";
211 /* now the NTLMSSP encoded auth hashes */
212 if (!msrpc_parse(&request, parse_string,
222 return NT_STATUS_LOGON_FAILURE;
225 data_blob_free(&sess_key);
227 DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
228 user, workgroup, machine, lmhash.length, nthash.length));
230 /* the client has given us its machine name (which we otherwise would not get on port 445).
231 we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
233 set_remote_machine_name(machine);
235 /* setup the string used by %U */
236 sub_set_smb_name(user);
238 reload_services(True);
241 file_save("nthash1.dat", nthash.data, nthash.length);
242 file_save("lmhash1.dat", lmhash.data, lmhash.length);
246 auth_flags |= AUTH_FLAG_LM_RESP;
249 if (nthash.length == 24) {
250 auth_flags |= AUTH_FLAG_NTLM_RESP;
251 } else if (nthash.length > 24) {
252 auth_flags |= AUTH_FLAG_NTLMv2_RESP;
257 nt_status = make_user_info_map(&user_info, user, workgroup, machine,
258 lmhash, nthash, plaintext_password,
261 ntlmssp_state->orig_user = talloc_strdup(ntlmssp_state->mem_ctx, user);
262 ntlmssp_state->orig_domain = talloc_strdup(ntlmssp_state->mem_ctx, workgroup);
265 SAFE_FREE(workgroup);
268 if (!NT_STATUS_IS_OK(nt_status)) {
272 nt_status = ntlmssp_state->auth_context->check_ntlm_password(ntlmssp_state->auth_context, user_info, &ntlmssp_state->server_info);
274 (ntlmssp_state->auth_context->free)(&ntlmssp_state->auth_context);
276 free_user_info(&user_info);
278 data_blob_free(&lmhash);
280 data_blob_free(&nthash);
282 *reply = data_blob(NULL, 0);