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.
27 * Default challange generation code.
32 static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
35 generate_random_buffer(chal, sizeof(chal), False);
40 NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
44 mem_ctx = talloc_init("NTLMSSP context");
46 *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
47 if (!*ntlmssp_state) {
48 DEBUG(0,("ntlmssp_start: talloc failed!\n"));
49 talloc_destroy(mem_ctx);
50 return NT_STATUS_NO_MEMORY;
53 ZERO_STRUCTP(*ntlmssp_state);
55 (*ntlmssp_state)->mem_ctx = mem_ctx;
56 (*ntlmssp_state)->get_challenge = get_challenge;
58 (*ntlmssp_state)->get_global_myname = global_myname;
59 (*ntlmssp_state)->get_domain = lp_workgroup;
60 (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
65 NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
67 TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
69 data_blob_free(&(*ntlmssp_state)->chal);
70 data_blob_free(&(*ntlmssp_state)->lm_resp);
71 data_blob_free(&(*ntlmssp_state)->nt_resp);
73 SAFE_FREE((*ntlmssp_state)->user);
74 SAFE_FREE((*ntlmssp_state)->domain);
75 SAFE_FREE((*ntlmssp_state)->workstation);
77 talloc_destroy(mem_ctx);
78 *ntlmssp_state = NULL;
82 NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
83 DATA_BLOB request, DATA_BLOB *reply)
85 uint32 ntlmssp_command;
86 *reply = data_blob(NULL, 0);
88 if (!msrpc_parse(&request, "Cd",
92 return NT_STATUS_LOGON_FAILURE;
95 if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
96 return ntlmssp_negotiate(ntlmssp_state, request, reply);
97 } else if (ntlmssp_command == NTLMSSP_AUTH) {
98 return ntlmssp_auth(ntlmssp_state, request, reply);
100 return NT_STATUS_LOGON_FAILURE;
104 static const char *ntlmssp_target_name(NTLMSSP_STATE *ntlmssp_state,
105 uint32 neg_flags, uint32 *chal_flags)
107 if (neg_flags & NTLMSSP_REQUEST_TARGET) {
108 *chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
109 *chal_flags |= NTLMSSP_REQUEST_TARGET;
110 if (ntlmssp_state->server_role == ROLE_STANDALONE) {
111 *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
112 return ntlmssp_state->get_global_myname();
114 *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
115 return ntlmssp_state->get_domain();
122 NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state,
123 DATA_BLOB request, DATA_BLOB *reply)
125 DATA_BLOB struct_blob;
126 fstring dnsname, dnsdomname;
127 uint32 ntlmssp_command, neg_flags, chal_flags;
128 char *cliname=NULL, *domname=NULL;
129 const uint8 *cryptkey;
130 const char *target_name;
132 /* parse the NTLMSSP packet */
134 file_save("ntlmssp_negotiate.dat", request.data, request.length);
137 if (!msrpc_parse(&request, "CddAA",
143 return NT_STATUS_LOGON_FAILURE;
149 debug_ntlmssp_flags(neg_flags);
151 cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
153 data_blob_free(&ntlmssp_state->chal);
154 ntlmssp_state->chal = data_blob(cryptkey, 8);
156 /* Give them the challenge. For now, ignore neg_flags and just
157 return the flags we want. Obviously this is not correct */
160 NTLMSSP_NEGOTIATE_128 |
161 NTLMSSP_NEGOTIATE_NTLM;
163 if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
164 chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
165 ntlmssp_state->unicode = True;
167 chal_flags |= NTLMSSP_NEGOTIATE_OEM;
170 target_name = ntlmssp_target_name(ntlmssp_state,
171 neg_flags, &chal_flags);
173 /* This should be a 'netbios domain -> DNS domain' mapping */
174 dnsdomname[0] = '\0';
175 get_mydomname(dnsdomname);
176 strlower(dnsdomname);
179 get_myfullname(dnsname);
182 if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
184 const char *target_name_dns = "";
185 if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
186 target_name_dns = dnsdomname;
187 } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
188 target_name_dns = dnsname;
191 /* the numbers here are the string type flags */
192 msrpc_gen(&struct_blob, "aaaaa",
193 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
194 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
195 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns,
196 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
197 ntlmssp_state->unicode, 0, "");
199 struct_blob = data_blob(NULL, 0);
203 const char *gen_string;
204 if (ntlmssp_state->unicode) {
205 gen_string = "CdUdbddB";
207 gen_string = "CdAdbddB";
210 msrpc_gen(reply, gen_string,
217 struct_blob.data, struct_blob.length);
220 data_blob_free(&struct_blob);
222 return NT_STATUS_MORE_PROCESSING_REQUIRED;
225 NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state,
226 DATA_BLOB request, DATA_BLOB *reply)
229 uint32 ntlmssp_command, neg_flags;
232 const char *parse_string;
234 /* parse the NTLMSSP packet */
236 file_save("ntlmssp_auth.dat", request.data, request.length);
239 if (ntlmssp_state->unicode) {
240 parse_string = "CdBBUUUBd";
242 parse_string = "CdBBAAABd";
245 data_blob_free(&ntlmssp_state->lm_resp);
246 data_blob_free(&ntlmssp_state->nt_resp);
248 SAFE_FREE(ntlmssp_state->user);
249 SAFE_FREE(ntlmssp_state->domain);
250 SAFE_FREE(ntlmssp_state->workstation);
252 /* now the NTLMSSP encoded auth hashes */
253 if (!msrpc_parse(&request, parse_string,
256 &ntlmssp_state->lm_resp,
257 &ntlmssp_state->nt_resp,
258 &ntlmssp_state->domain,
259 &ntlmssp_state->user,
260 &ntlmssp_state->workstation,
263 return NT_STATUS_LOGON_FAILURE;
266 data_blob_free(&sess_key);
268 DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n",
269 ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, ntlmssp_state->lm_resp.length, ntlmssp_state->nt_resp.length));
272 file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length);
273 file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length);
276 nt_status = ntlmssp_state->check_password(ntlmssp_state);
278 *reply = data_blob(NULL, 0);