/src/samba/source3/auth/auth_ntlmssp.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/Netbios implementation. |
3 | | Version 3.0 |
4 | | handle NLTMSSP, server side |
5 | | |
6 | | Copyright (C) Andrew Tridgell 2001 |
7 | | Copyright (C) Andrew Bartlett 2001-2005,2011 |
8 | | Copyright (C) Stefan Metzmacher 2005 |
9 | | |
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. |
14 | | |
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. |
19 | | |
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/>. |
22 | | */ |
23 | | |
24 | | #include "includes.h" |
25 | | #include "auth.h" |
26 | | #include "libcli/security/security.h" |
27 | | #include "lib/util/tevent_ntstatus.h" |
28 | | #include "source3/lib/substitute.h" |
29 | | |
30 | | NTSTATUS auth3_generate_session_info(struct auth4_context *auth_context, |
31 | | TALLOC_CTX *mem_ctx, |
32 | | void *server_returned_info, |
33 | | const char *original_user_name, |
34 | | uint32_t session_info_flags, |
35 | | struct auth_session_info **session_info) |
36 | 0 | { |
37 | 0 | struct auth_user_info_dc *user_info = NULL; |
38 | 0 | struct auth_serversupplied_info *server_info = NULL; |
39 | 0 | NTSTATUS nt_status; |
40 | | |
41 | | /* |
42 | | * This is a hack, some callers... |
43 | | * |
44 | | * Some callers pass auth_user_info_dc, the SCHANNEL and |
45 | | * NCALRPC_AS_SYSTEM gensec modules. |
46 | | * |
47 | | * While the rest passes auth3_check_password() returned. |
48 | | */ |
49 | 0 | user_info = talloc_get_type(server_returned_info, |
50 | 0 | struct auth_user_info_dc); |
51 | 0 | if (user_info != NULL) { |
52 | 0 | const struct dom_sid *sid; |
53 | 0 | int cmp; |
54 | | |
55 | | /* |
56 | | * This should only be called from SCHANNEL or NCALRPC_AS_SYSTEM |
57 | | */ |
58 | 0 | if (user_info->num_sids != 1) { |
59 | 0 | return NT_STATUS_INTERNAL_ERROR; |
60 | 0 | } |
61 | 0 | sid = &user_info->sids[PRIMARY_USER_SID_INDEX].sid; |
62 | |
|
63 | 0 | cmp = dom_sid_compare(sid, &global_sid_System); |
64 | 0 | if (cmp == 0) { |
65 | 0 | return make_session_info_system(mem_ctx, session_info); |
66 | 0 | } |
67 | | |
68 | 0 | cmp = dom_sid_compare(sid, &global_sid_Anonymous); |
69 | 0 | if (cmp == 0) { |
70 | 0 | return make_session_info_anonymous(mem_ctx, session_info); |
71 | 0 | } |
72 | | |
73 | 0 | return NT_STATUS_INTERNAL_ERROR; |
74 | 0 | } |
75 | | |
76 | 0 | server_info = talloc_get_type_abort(server_returned_info, |
77 | 0 | struct auth_serversupplied_info); |
78 | 0 | nt_status = create_local_token(mem_ctx, |
79 | 0 | server_info, |
80 | 0 | NULL, |
81 | 0 | original_user_name, |
82 | 0 | session_info); |
83 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
84 | 0 | DEBUG(10, ("create_local_token failed: %s\n", |
85 | 0 | nt_errstr(nt_status))); |
86 | 0 | return nt_status; |
87 | 0 | } |
88 | | |
89 | 0 | return NT_STATUS_OK; |
90 | 0 | } |
91 | | |
92 | | /** |
93 | | * Return the challenge as determined by the authentication subsystem |
94 | | * @return an 8 byte random challenge |
95 | | */ |
96 | | |
97 | | NTSTATUS auth3_get_challenge(struct auth4_context *auth4_context, |
98 | | uint8_t chal[8]) |
99 | 0 | { |
100 | 0 | struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data, |
101 | 0 | struct auth_context); |
102 | 0 | auth_get_ntlm_challenge(auth_context, chal); |
103 | 0 | return NT_STATUS_OK; |
104 | 0 | } |
105 | | |
106 | | /** |
107 | | * NTLM2 authentication modifies the effective challenge, |
108 | | * @param challenge The new challenge value |
109 | | */ |
110 | | NTSTATUS auth3_set_challenge(struct auth4_context *auth4_context, const uint8_t *chal, |
111 | | const char *challenge_set_by) |
112 | 0 | { |
113 | 0 | struct auth_context *auth_context = talloc_get_type_abort(auth4_context->private_data, |
114 | 0 | struct auth_context); |
115 | 0 | bool ok; |
116 | |
|
117 | 0 | ok = auth3_context_set_challenge(auth_context, chal, challenge_set_by); |
118 | 0 | if (!ok) { |
119 | | /* |
120 | | * This can only fail for ENOMEM |
121 | | */ |
122 | 0 | return NT_STATUS_NO_MEMORY; |
123 | 0 | } |
124 | | |
125 | 0 | DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by)); |
126 | 0 | DEBUG(5, ("challenge is: \n")); |
127 | 0 | dump_data(5, auth_context->challenge.data, auth_context->challenge.length); |
128 | 0 | return NT_STATUS_OK; |
129 | 0 | } |
130 | | |
131 | | /** |
132 | | * Check the password on an NTLMSSP login. |
133 | | * |
134 | | * Return the session keys used on the connection. |
135 | | */ |
136 | | |
137 | | struct auth3_check_password_state { |
138 | | uint8_t authoritative; |
139 | | void *server_info; |
140 | | DATA_BLOB nt_session_key; |
141 | | DATA_BLOB lm_session_key; |
142 | | }; |
143 | | |
144 | | struct tevent_req *auth3_check_password_send( |
145 | | TALLOC_CTX *mem_ctx, |
146 | | struct tevent_context *ev, |
147 | | struct auth4_context *auth4_context, |
148 | | const struct auth_usersupplied_info *user_info) |
149 | 0 | { |
150 | 0 | struct tevent_req *req = NULL; |
151 | 0 | struct auth3_check_password_state *state = NULL; |
152 | 0 | struct auth_context *auth_context = talloc_get_type_abort( |
153 | 0 | auth4_context->private_data, struct auth_context); |
154 | 0 | struct auth_usersupplied_info *mapped_user_info = NULL; |
155 | 0 | struct auth_serversupplied_info *server_info = NULL; |
156 | 0 | char *sanitized_username = NULL; |
157 | 0 | NTSTATUS nt_status; |
158 | 0 | bool username_was_mapped; |
159 | |
|
160 | 0 | req = tevent_req_create( |
161 | 0 | mem_ctx, &state, struct auth3_check_password_state); |
162 | 0 | if (req == NULL) { |
163 | 0 | return NULL; |
164 | 0 | } |
165 | | |
166 | | /* |
167 | | * Be authoritative by default. |
168 | | */ |
169 | 0 | state->authoritative = 1; |
170 | | |
171 | | /* The client has given us its machine name (which we only get over NBT transport). |
172 | | We need to possibly reload smb.conf if smb.conf includes depend on the machine name. */ |
173 | |
|
174 | 0 | set_remote_machine_name(user_info->workstation_name, True); |
175 | |
|
176 | 0 | nt_status = make_user_info_map(talloc_tos(), |
177 | 0 | &mapped_user_info, |
178 | 0 | user_info->client.account_name, |
179 | 0 | user_info->client.domain_name, |
180 | 0 | user_info->workstation_name, |
181 | 0 | user_info->remote_host, |
182 | 0 | user_info->local_host, |
183 | 0 | user_info->service_description, |
184 | 0 | user_info->password.response.lanman.data ? &user_info->password.response.lanman : NULL, |
185 | 0 | user_info->password.response.nt.data ? &user_info->password.response.nt : NULL, |
186 | 0 | NULL, NULL, user_info->password.plaintext, |
187 | 0 | AUTH_PASSWORD_RESPONSE); |
188 | |
|
189 | 0 | if (tevent_req_nterror(req, nt_status)) { |
190 | 0 | return tevent_req_post(req, ev); |
191 | 0 | } |
192 | | |
193 | 0 | mapped_user_info->logon_parameters = user_info->logon_parameters; |
194 | |
|
195 | 0 | mapped_user_info->flags = user_info->flags; |
196 | |
|
197 | 0 | sanitized_username = talloc_alpha_strcpy( |
198 | 0 | state, |
199 | 0 | user_info->client.account_name, |
200 | 0 | SAFE_NETBIOS_CHARS "$"); |
201 | 0 | if (sanitized_username == NULL) { |
202 | 0 | tevent_req_nterror(req, NT_STATUS_NO_MEMORY); |
203 | 0 | return tevent_req_post(req, ev); |
204 | 0 | } |
205 | | |
206 | 0 | nt_status = auth_check_ntlm_password(state, |
207 | 0 | auth_context, |
208 | 0 | mapped_user_info, |
209 | 0 | &server_info, |
210 | 0 | &state->authoritative); |
211 | |
|
212 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
213 | 0 | DBG_INFO("Checking NTLMSSP password for %s\\%s failed: " |
214 | 0 | "%s, authoritative=%"PRIu8"\n", |
215 | 0 | user_info->client.domain_name, |
216 | 0 | user_info->client.account_name, |
217 | 0 | nt_errstr(nt_status), |
218 | 0 | state->authoritative); |
219 | 0 | } |
220 | |
|
221 | 0 | username_was_mapped = mapped_user_info->was_mapped; |
222 | |
|
223 | 0 | TALLOC_FREE(mapped_user_info); |
224 | |
|
225 | 0 | if (!NT_STATUS_IS_OK(nt_status)) { |
226 | 0 | nt_status = do_map_to_guest_server_info( |
227 | 0 | state, |
228 | 0 | nt_status, |
229 | 0 | user_info->client.account_name, |
230 | 0 | user_info->client.domain_name, |
231 | 0 | &server_info); |
232 | 0 | if (!tevent_req_nterror(req, nt_status)) { |
233 | 0 | state->authoritative = 1; |
234 | | |
235 | | /* setup the string used by %U */ |
236 | 0 | set_current_user_info( |
237 | 0 | sanitized_username, |
238 | 0 | server_info->unix_name, |
239 | 0 | server_info->info3->base.logon_domain.string); |
240 | |
|
241 | 0 | lp_load_with_shares(get_dyn_CONFIGFILE()); |
242 | |
|
243 | 0 | tevent_req_done(req); |
244 | 0 | } |
245 | 0 | state->server_info = server_info; |
246 | 0 | return tevent_req_post(req, ev); |
247 | 0 | } |
248 | | |
249 | 0 | server_info->nss_token |= username_was_mapped; |
250 | | |
251 | | /* setup the string used by %U */ |
252 | 0 | set_current_user_info(sanitized_username, |
253 | 0 | server_info->unix_name, |
254 | 0 | server_info->info3->base.logon_domain.string); |
255 | |
|
256 | 0 | lp_load_with_shares(get_dyn_CONFIGFILE()); |
257 | | |
258 | | /* Clear out the session keys, and pass them to the caller. |
259 | | * They will not be used in this form again - instead the |
260 | | * NTLMSSP code will decide on the final correct session key, |
261 | | * and supply it to create_local_token() */ |
262 | |
|
263 | 0 | DBG_DEBUG("Got NT session key of length %zu\n", |
264 | 0 | server_info->session_key.length); |
265 | 0 | state->nt_session_key = (DATA_BLOB) { |
266 | 0 | .data = talloc_move( |
267 | 0 | state, &server_info->session_key.data), |
268 | 0 | .length = server_info->session_key.length, |
269 | 0 | }; |
270 | 0 | server_info->session_key = data_blob_null; |
271 | |
|
272 | 0 | DBG_DEBUG("Got LM session key of length %zu\n", |
273 | 0 | server_info->lm_session_key.length); |
274 | 0 | state->lm_session_key = (DATA_BLOB) { |
275 | 0 | .data = talloc_move( |
276 | 0 | state, &server_info->lm_session_key.data), |
277 | 0 | .length = server_info->lm_session_key.length, |
278 | 0 | }; |
279 | 0 | server_info->lm_session_key = data_blob_null; |
280 | |
|
281 | 0 | state->server_info = server_info; |
282 | |
|
283 | 0 | tevent_req_done(req); |
284 | 0 | return tevent_req_post(req, ev); |
285 | 0 | } |
286 | | |
287 | | NTSTATUS auth3_check_password_recv(struct tevent_req *req, |
288 | | TALLOC_CTX *mem_ctx, |
289 | | uint8_t *pauthoritative, |
290 | | void **server_returned_info, |
291 | | DATA_BLOB *nt_session_key, |
292 | | DATA_BLOB *lm_session_key) |
293 | 0 | { |
294 | 0 | struct auth3_check_password_state *state = tevent_req_data( |
295 | 0 | req, struct auth3_check_password_state); |
296 | 0 | NTSTATUS status; |
297 | |
|
298 | 0 | if (pauthoritative != NULL) { |
299 | 0 | *pauthoritative = state->authoritative; |
300 | 0 | } |
301 | |
|
302 | 0 | if (tevent_req_is_nterror(req, &status)) { |
303 | 0 | return status; |
304 | 0 | } |
305 | | |
306 | 0 | if (server_returned_info != NULL) { |
307 | 0 | *server_returned_info = talloc_move( |
308 | 0 | mem_ctx, &state->server_info); |
309 | 0 | } |
310 | 0 | if (nt_session_key != NULL) { |
311 | 0 | *nt_session_key = (DATA_BLOB) { |
312 | 0 | .data = talloc_move( |
313 | 0 | mem_ctx, &state->nt_session_key.data), |
314 | 0 | .length = state->nt_session_key.length, |
315 | 0 | }; |
316 | 0 | } |
317 | 0 | if (lm_session_key != NULL) { |
318 | 0 | *lm_session_key = (DATA_BLOB) { |
319 | 0 | .data = talloc_move( |
320 | 0 | mem_ctx, &state->lm_session_key.data), |
321 | 0 | .length = state->lm_session_key.length, |
322 | 0 | }; |
323 | 0 | } |
324 | |
|
325 | 0 | return NT_STATUS_OK; |
326 | 0 | } |