2 Unix SMB/CIFS implementation.
3 Authentication utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 2000-2001
7 Copyright (C) Rafal Szczesniak 2002
8 Copyright (C) Stefan Metzmacher 2005
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 2 of the License, or
13 (at your option) any later version.
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.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "librpc/gen_ndr/ndr_samr.h"
27 #include "librpc/gen_ndr/ndr_netlogon.h"
28 #include "libcli/security/security.h"
29 #include "auth/auth.h"
31 /* this default function can be used by mostly all backends
32 * which don't want to set a challlenge
34 NTSTATUS auth_get_challenge_not_implemented(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, DATA_BLOB *challenge)
36 /* we don't want to set a challenge */
37 return NT_STATUS_NOT_IMPLEMENTED;
40 /****************************************************************************
41 Create an auth_usersupplied_data structure
42 ****************************************************************************/
43 NTSTATUS make_user_info(TALLOC_CTX *mem_ctx,
44 const char *c_account_name,
45 const char *account_name,
46 const char *c_domain_name,
47 const char *domain_name,
48 const char *workstation_name,
49 const char *remote_host,
50 DATA_BLOB *lm_password, DATA_BLOB *nt_password,
51 DATA_BLOB *lm_interactive_password, DATA_BLOB *nt_interactive_password,
52 DATA_BLOB *plaintext_password, BOOL encrypted, uint32_t flags,
53 struct auth_usersupplied_info **_user_info)
55 struct auth_usersupplied_info *user_info;
58 DEBUG(5,("attempting to make a user_info for %s (%s)\n", account_name, c_account_name));
60 user_info = talloc(mem_ctx, struct auth_usersupplied_info);
61 NT_STATUS_HAVE_NO_MEMORY(user_info);
63 DEBUG(5,("making strings for %s's user_info struct\n", account_name));
65 user_info->client.account_name = talloc_strdup(user_info, c_account_name);
66 NT_STATUS_HAVE_NO_MEMORY(user_info->client.account_name);
68 user_info->account_name = talloc_strdup(user_info, account_name);
69 NT_STATUS_HAVE_NO_MEMORY(user_info->account_name);
71 user_info->client.domain_name = talloc_strdup(user_info, c_domain_name);
72 if (c_domain_name && !user_info->client.domain_name) {
73 return NT_STATUS_NO_MEMORY;
76 user_info->domain_name = talloc_strdup(user_info, domain_name);
77 NT_STATUS_HAVE_NO_MEMORY(user_info->domain_name);
79 user_info->workstation_name = talloc_strdup(user_info, workstation_name);
80 NT_STATUS_HAVE_NO_MEMORY(user_info->workstation_name);
82 user_info->remote_host = talloc_strdup(user_info, remote_host);
83 NT_STATUS_HAVE_NO_MEMORY(user_info->remote_host);
85 DEBUG(5,("making blobs for %s's user_info struct\n", account_name));
88 blob = data_blob_dup_talloc(user_info, lm_password);
89 NT_STATUS_HAVE_NO_MEMORY(blob.data);
91 blob = data_blob(NULL, 0);
93 user_info->lm_resp = blob;
96 blob = data_blob_dup_talloc(user_info, nt_password);
97 NT_STATUS_HAVE_NO_MEMORY(blob.data);
99 blob = data_blob(NULL, 0);
101 user_info->nt_resp = blob;
103 if (lm_interactive_password) {
104 blob = data_blob_dup_talloc(user_info, lm_interactive_password);
105 NT_STATUS_HAVE_NO_MEMORY(blob.data);
107 blob = data_blob(NULL, 0);
109 user_info->lm_interactive_password = blob;
111 if (nt_interactive_password) {
112 blob = data_blob_dup_talloc(user_info, nt_interactive_password);
113 NT_STATUS_HAVE_NO_MEMORY(blob.data);
115 blob = data_blob(NULL, 0);
117 user_info->nt_interactive_password = blob;
119 if (plaintext_password) {
120 blob = data_blob_dup_talloc(user_info, plaintext_password);
121 NT_STATUS_HAVE_NO_MEMORY(blob.data);
123 blob = data_blob(NULL, 0);
125 user_info->plaintext_password = blob;
127 user_info->encrypted = encrypted;
129 DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , account_name, c_account_name));
131 *_user_info = user_info;
136 /****************************************************************************
137 Create an auth_usersupplied_data structure after appropriate mapping.
138 ****************************************************************************/
140 NTSTATUS make_user_info_map(TALLOC_CTX *mem_ctx,
141 const char *c_account_name,
142 const char *c_domain_name,
143 const char *workstation_name,
144 DATA_BLOB *lm_password, DATA_BLOB *nt_password,
145 DATA_BLOB *lm_interactive_password, DATA_BLOB *nt_interactive_password,
146 DATA_BLOB *plaintext, BOOL encrypted,
147 struct auth_usersupplied_info **user_info)
150 const char *account_name;
152 DEBUG(5,("make_user_info_map: Mapping user [%s]\\[%s] from workstation [%s]\n",
153 c_domain_name, c_account_name, workstation_name));
155 account_name = c_account_name;
157 /* don't allow "" as a domain, fixes a Win9X bug
158 where it doens't supply a domain for logon script
159 'net use' commands. */
161 /* Split user@realm names into user and realm components. This is TODO to fix with proper userprincipalname support */
162 if (c_domain_name && *c_domain_name) {
163 domain = c_domain_name;
164 } else if (strchr_m(c_account_name, '@')) {
165 account_name = talloc_strdup(mem_ctx, c_account_name);
167 return NT_STATUS_NO_MEMORY;
169 d = strchr_m(account_name, '@');
171 return NT_STATUS_INTERNAL_ERROR;
177 domain = lp_workgroup();
180 return make_user_info(mem_ctx,
181 c_account_name, account_name,
182 c_domain_name, domain,
185 lm_password, nt_password,
186 lm_interactive_password, nt_interactive_password,
187 plaintext, encrypted, 0x00,
191 /****************************************************************************
192 Create an auth_usersupplied_data, making the DATA_BLOBs here.
193 Decrypt and encrypt the passwords.
194 ****************************************************************************/
195 NTSTATUS make_user_info_netlogon_network(TALLOC_CTX *mem_ctx,
196 const char *c_account_name,
197 const char *c_domain_name,
198 const char *workstation_name,
199 const uint8_t *lm_network_password, int lm_password_len,
200 const uint8_t *nt_network_password, int nt_password_len,
201 struct auth_usersupplied_info **user_info)
203 DATA_BLOB lm_blob = data_blob_const(lm_network_password, lm_password_len);
204 DATA_BLOB nt_blob = data_blob_const(nt_network_password, nt_password_len);
206 return make_user_info_map(mem_ctx,
210 lm_password_len ? &lm_blob : NULL,
211 nt_password_len ? &nt_blob : NULL,
212 NULL, NULL, NULL, True,
216 /****************************************************************************
217 Create an auth_usersupplied_data, making the DATA_BLOBs here.
218 Decrypt and encrypt the passwords.
219 ****************************************************************************/
220 NTSTATUS make_user_info_netlogon_interactive(TALLOC_CTX *mem_ctx,
221 const char *c_account_name,
222 const char *c_domain_name,
223 const char *workstation_name,
224 const uint8_t chal[8],
225 const struct samr_Password *lm_interactive_password,
226 const struct samr_Password *nt_interactive_password,
227 struct auth_usersupplied_info **user_info)
230 DATA_BLOB local_lm_blob;
231 DATA_BLOB local_nt_blob;
233 DATA_BLOB lm_interactive_blob;
234 DATA_BLOB nt_interactive_blob;
235 uint8_t local_lm_response[24];
236 uint8_t local_nt_response[24];
238 SMBOWFencrypt(lm_interactive_password->hash, chal, local_lm_response);
239 SMBOWFencrypt(nt_interactive_password->hash, chal, local_nt_response);
241 local_lm_blob = data_blob_const(local_lm_response, sizeof(local_lm_response));
242 lm_interactive_blob = data_blob_const(lm_interactive_password->hash,
243 sizeof(lm_interactive_password->hash));
245 local_nt_blob = data_blob_const(local_nt_response, sizeof(local_nt_response));
246 nt_interactive_blob = data_blob_const(nt_interactive_password->hash,
247 sizeof(nt_interactive_password->hash));
249 nt_status = make_user_info_map(mem_ctx,
255 &lm_interactive_blob,
256 &nt_interactive_blob,
262 /****************************************************************************
263 Create an auth_usersupplied_data structure
264 ****************************************************************************/
265 NTSTATUS make_user_info_for_reply_enc(TALLOC_CTX *mem_ctx,
266 const char *c_account_name,
267 const char *c_domain_name,
268 const char *workstation_name,
269 DATA_BLOB lm_resp, DATA_BLOB nt_resp,
270 struct auth_usersupplied_info **user_info)
272 return make_user_info_map(mem_ctx,
276 lm_resp.data ? &lm_resp : NULL,
277 nt_resp.data ? &nt_resp : NULL,
278 NULL, NULL, NULL, True,
282 /****************************************************************************
283 Create a anonymous user_info blob, for anonymous authenticaion.
284 ****************************************************************************/
285 NTSTATUS make_user_info_anonymous(TALLOC_CTX *mem_ctx, struct auth_usersupplied_info **user_info)
287 return make_user_info(mem_ctx,
288 "", "", "", "", "", "",
289 NULL, NULL, NULL, NULL,
295 /***************************************************************************
296 Make a server_info struct from the info3 returned by a domain logon
297 ***************************************************************************/
298 NTSTATUS make_server_info_netlogon_validation(TALLOC_CTX *mem_ctx,
299 const char *account_name,
300 uint16_t validation_level,
301 union netr_Validation *validation,
302 struct auth_serversupplied_info **_server_info)
304 struct auth_serversupplied_info *server_info;
305 struct netr_SamBaseInfo *base = NULL;
308 switch (validation_level) {
310 if (!validation || !validation->sam2) {
311 return NT_STATUS_INVALID_PARAMETER;
313 base = &validation->sam2->base;
316 if (!validation || !validation->sam3) {
317 return NT_STATUS_INVALID_PARAMETER;
319 base = &validation->sam3->base;
322 if (!validation || !validation->sam6) {
323 return NT_STATUS_INVALID_PARAMETER;
325 base = &validation->sam6->base;
328 return NT_STATUS_INVALID_LEVEL;
331 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
332 NT_STATUS_HAVE_NO_MEMORY(server_info);
335 Here is where we should check the list of
336 trusted domains, and verify that the SID
339 server_info->account_sid = dom_sid_add_rid(server_info, base->domain_sid, base->rid);
340 NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
343 server_info->primary_group_sid = dom_sid_add_rid(server_info, base->domain_sid, base->primary_gid);
344 NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
346 server_info->n_domain_groups = base->groups.count;
347 if (base->groups.count) {
348 server_info->domain_groups = talloc_array(server_info, struct dom_sid*, base->groups.count);
349 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_groups);
351 server_info->domain_groups = NULL;
354 for (i = 0; i < base->groups.count; i++) {
355 server_info->domain_groups[i] = dom_sid_add_rid(server_info, base->domain_sid, base->groups.rids[i].rid);
356 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_groups[i]);
359 /* Copy 'other' sids. We need to do sid filtering here to
360 prevent possible elevation of privileges. See:
362 http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
365 if (validation_level == 3) {
366 struct dom_sid **dgrps = server_info->domain_groups;
367 size_t sidcount = server_info->n_domain_groups + validation->sam3->sidcount;
368 size_t n_dgrps = server_info->n_domain_groups;
370 dgrps = talloc_realloc(server_info, dgrps, struct dom_sid*, sidcount);
371 NT_STATUS_HAVE_NO_MEMORY(dgrps);
373 for (i = 0; i < validation->sam3->sidcount; i++) {
374 dgrps[n_dgrps + i] = talloc_reference(dgrps, validation->sam3->sids[i].sid);
377 server_info->n_domain_groups = sidcount;
378 server_info->domain_groups = dgrps;
380 /* Where are the 'global' sids?... */
383 if (base->account_name.string) {
384 server_info->account_name = talloc_reference(server_info, base->account_name.string);
386 server_info->account_name = talloc_strdup(server_info, account_name);
387 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
390 server_info->domain_name = talloc_reference(server_info, base->domain.string);
391 server_info->full_name = talloc_reference(server_info, base->full_name.string);
392 server_info->logon_script = talloc_reference(server_info, base->logon_script.string);
393 server_info->profile_path = talloc_reference(server_info, base->profile_path.string);
394 server_info->home_directory = talloc_reference(server_info, base->home_directory.string);
395 server_info->home_drive = talloc_reference(server_info, base->home_drive.string);
396 server_info->last_logon = base->last_logon;
397 server_info->last_logoff = base->last_logoff;
398 server_info->acct_expiry = base->acct_expiry;
399 server_info->last_password_change = base->last_password_change;
400 server_info->allow_password_change = base->allow_password_change;
401 server_info->force_password_change = base->force_password_change;
402 server_info->logon_count = base->logon_count;
403 server_info->bad_password_count = base->bad_password_count;
404 server_info->acct_flags = base->acct_flags;
406 server_info->authenticated = True;
408 /* ensure we are never given NULL session keys */
410 if (all_zero(base->key.key, sizeof(base->key.key))) {
411 server_info->user_session_key = data_blob(NULL, 0);
413 server_info->user_session_key = data_blob_talloc(server_info, base->key.key, sizeof(base->key.key));
414 NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
417 if (all_zero(base->LMSessKey.key, sizeof(base->LMSessKey.key))) {
418 server_info->lm_session_key = data_blob(NULL, 0);
420 server_info->lm_session_key = data_blob_talloc(server_info, base->LMSessKey.key, sizeof(base->LMSessKey.key));
421 NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
424 *_server_info = server_info;
429 NTSTATUS auth_anonymous_server_info(TALLOC_CTX *mem_ctx, struct auth_serversupplied_info **_server_info)
431 struct auth_serversupplied_info *server_info;
432 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
433 NT_STATUS_HAVE_NO_MEMORY(server_info);
435 server_info->account_sid = dom_sid_parse_talloc(server_info, SID_NT_ANONYMOUS);
436 NT_STATUS_HAVE_NO_MEMORY(server_info->account_sid);
438 /* is this correct? */
439 server_info->primary_group_sid = dom_sid_parse_talloc(server_info, SID_BUILTIN_GUESTS);
440 NT_STATUS_HAVE_NO_MEMORY(server_info->primary_group_sid);
442 server_info->n_domain_groups = 0;
443 server_info->domain_groups = NULL;
445 /* annoying, but the Anonymous really does have a session key,
446 and it is all zeros! */
447 server_info->user_session_key = data_blob_talloc(server_info, NULL, 16);
448 NT_STATUS_HAVE_NO_MEMORY(server_info->user_session_key.data);
450 server_info->lm_session_key = data_blob_talloc(server_info, NULL, 16);
451 NT_STATUS_HAVE_NO_MEMORY(server_info->lm_session_key.data);
453 data_blob_clear(&server_info->user_session_key);
454 data_blob_clear(&server_info->lm_session_key);
456 server_info->account_name = talloc_strdup(server_info, "ANONYMOUS LOGON");
457 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
459 server_info->domain_name = talloc_strdup(server_info, "NT AUTHORITY");
460 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
462 server_info->full_name = talloc_strdup(server_info, "Anonymous Logon");
463 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
465 server_info->logon_script = talloc_strdup(server_info, "");
466 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
468 server_info->profile_path = talloc_strdup(server_info, "");
469 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
471 server_info->home_directory = talloc_strdup(server_info, "");
472 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
474 server_info->home_drive = talloc_strdup(server_info, "");
475 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
477 server_info->last_logon = 0;
478 server_info->last_logoff = 0;
479 server_info->acct_expiry = 0;
480 server_info->last_password_change = 0;
481 server_info->allow_password_change = 0;
482 server_info->force_password_change = 0;
484 server_info->logon_count = 0;
485 server_info->bad_password_count = 0;
487 server_info->acct_flags = ACB_NORMAL;
489 server_info->authenticated = False;
491 *_server_info = server_info;
496 NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
497 struct auth_serversupplied_info *server_info,
498 struct auth_session_info **_session_info)
500 struct auth_session_info *session_info;
503 session_info = talloc(mem_ctx, struct auth_session_info);
504 NT_STATUS_HAVE_NO_MEMORY(session_info);
506 session_info->server_info = talloc_reference(session_info, server_info);
508 /* unless set otherwise, the session key is the user session
509 * key from the auth subsystem */
510 session_info->session_key = server_info->user_session_key;
512 nt_status = security_token_create(session_info,
513 server_info->account_sid,
514 server_info->primary_group_sid,
515 server_info->n_domain_groups,
516 server_info->domain_groups,
517 server_info->authenticated,
518 &session_info->security_token);
519 NT_STATUS_NOT_OK_RETURN(nt_status);
521 *_session_info = session_info;
525 /****************************************************************************
526 prints a struct auth_session_info security token to debug output.
527 ****************************************************************************/
528 void auth_session_info_debug(int dbg_lev,
529 const struct auth_session_info *session_info)
532 DEBUGC(dbg_class, dbg_lev, ("Session Info: (NULL)\n"));
536 security_token_debug(dbg_lev, session_info->security_token);
540 * Squash an NT_STATUS in line with security requirements.
541 * In an attempt to avoid giving the whole game away when users
542 * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and
543 * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations
544 * (session setups in particular).
546 * @param nt_status NTSTATUS input for squashing.
547 * @return the 'squashed' nt_status
549 NTSTATUS auth_nt_status_squash(NTSTATUS nt_status)
551 if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
552 /* Match WinXP and don't give the game away */
553 return NT_STATUS_LOGON_FAILURE;
554 } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
555 /* Match WinXP and don't give the game away */
556 return NT_STATUS_LOGON_FAILURE;