1 /*
2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2010
5 Copyright (C) Gerald Carter 2003
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Matthias Dieter Wallnöfer 2009
8
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 3 of the License, or
12 (at your option) any later version.
13
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.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/time.h"
25 #include "auth/auth.h"
26 #include <ldb.h>
27 #include "dsdb/samdb/samdb.h"
28 #include "libcli/security/security.h"
29 #include "auth/auth_sam.h"
30 #include "dsdb/common/util.h"
31 #include "libcli/ldap/ldap_ndr.h"
32 #include "param/param.h"
33 #include "librpc/gen_ndr/ndr_winbind_c.h"
34
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_AUTH
37
38 #define KRBTGT_ATTRS \
39 /* required for the krb5 kdc */ \
40 "objectClass", \
41 "sAMAccountName", \
42 "userPrincipalName", \
43 "servicePrincipalName", \
44 "msDS-KeyVersionNumber", \
45 "msDS-SecondaryKrbTgtNumber", \
46 "msDS-SupportedEncryptionTypes", \
47 "supplementalCredentials", \
48 "msDS-AllowedToDelegateTo", \
49 \
50 /* passwords */ \
51 "dBCSPwd", \
52 "unicodePwd", \
53 \
54 "userAccountControl", \
55 "msDS-User-Account-Control-Computed", \
56 "objectSid", \
57 \
58 "pwdLastSet", \
59 "msDS-UserPasswordExpiryTimeComputed", \
60 "accountExpires"
61
62 const char *krbtgt_attrs[] = {
63 KRBTGT_ATTRS, NULL
64 };
65
66 const char *server_attrs[] = {
67 KRBTGT_ATTRS, NULL
68 };
69
70 const char *user_attrs[] = {
71 /*
72 * This ordering (having msDS-ResultantPSO first) is
73 * important. By processing this attribute first it is
74 * available in the operational module for the other PSO
75 * attribute calcuations to use.
76 */
77 "msDS-ResultantPSO",
78
79 KRBTGT_ATTRS,
80
81 "logonHours",
82
83 /*
84 * To allow us to zero the badPwdCount and lockoutTime on
85 * successful logon, without database churn
86 */
87 "lockoutTime",
88
89 /*
90 * Needed for SendToSAM requests
91 */
92 "objectGUID",
93
94 /* check 'allowed workstations' */
95 "userWorkstations",
96
97 /* required for user_info_dc, not access control: */
98 "displayName",
99 "scriptPath",
100 "profilePath",
101 "homeDirectory",
102 "homeDrive",
103 "lastLogon",
104 "lastLogonTimestamp",
105 "lastLogoff",
106 "accountExpires",
107 "badPwdCount",
108 "logonCount",
109 "primaryGroupID",
110 "memberOf",
111 "badPasswordTime",
112 "lmPwdHistory",
113 "ntPwdHistory",
114 NULL,
115 };
116
117 /****************************************************************************
118 Check if a user is allowed to logon at this time. Note this is the
119 servers local time, as logon hours are just specified as a weekly
120 bitmask.
121 ****************************************************************************/
122
logon_hours_ok(struct ldb_message * msg,const char * name_for_logs)123 static bool logon_hours_ok(struct ldb_message *msg, const char *name_for_logs)
124 {
125 /* In logon hours first bit is Sunday from 12AM to 1AM */
126 const struct ldb_val *hours;
127 struct tm *utctime;
128 time_t lasttime;
129 const char *asct;
130 uint8_t bitmask, bitpos;
131
132 hours = ldb_msg_find_ldb_val(msg, "logonHours");
133 if (!hours) {
134 DEBUG(5,("logon_hours_ok: No hours restrictions for user %s\n", name_for_logs));
135 return true;
136 }
137
138 if (hours->length != 168/8) {
139 DEBUG(5,("logon_hours_ok: malformed logon hours restrictions for user %s\n", name_for_logs));
140 return true;
141 }
142
143 lasttime = time(NULL);
144 utctime = gmtime(&lasttime);
145 if (!utctime) {
146 DEBUG(1, ("logon_hours_ok: failed to get gmtime. Failing logon for user %s\n",
147 name_for_logs));
148 return false;
149 }
150
151 /* find the corresponding byte and bit */
152 bitpos = (utctime->tm_wday * 24 + utctime->tm_hour) % 168;
153 bitmask = 1 << (bitpos % 8);
154
155 if (! (hours->data[bitpos/8] & bitmask)) {
156 struct tm *t = localtime(&lasttime);
157 if (!t) {
158 asct = "INVALID TIME";
159 } else {
160 asct = asctime(t);
161 if (!asct) {
162 asct = "INVALID TIME";
163 }
164 }
165
166 DEBUG(1, ("logon_hours_ok: Account for user %s not allowed to "
167 "logon at this time (%s).\n",
168 name_for_logs, asct ));
169 return false;
170 }
171
172 asct = asctime(utctime);
173 DEBUG(5,("logon_hours_ok: user %s allowed to logon at this time (%s)\n",
174 name_for_logs, asct ? asct : "UNKNOWN TIME" ));
175
176 return true;
177 }
178
179 /****************************************************************************
180 Do a specific test for a SAM_ACCOUNT being valid for this connection
181 (ie not disabled, expired and the like).
182 ****************************************************************************/
authsam_account_ok(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,uint32_t logon_parameters,struct ldb_dn * domain_dn,struct ldb_message * msg,const char * logon_workstation,const char * name_for_logs,bool allow_domain_trust,bool password_change)183 _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
184 struct ldb_context *sam_ctx,
185 uint32_t logon_parameters,
186 struct ldb_dn *domain_dn,
187 struct ldb_message *msg,
188 const char *logon_workstation,
189 const char *name_for_logs,
190 bool allow_domain_trust,
191 bool password_change)
192 {
193 uint16_t acct_flags;
194 const char *workstation_list;
195 NTTIME acct_expiry;
196 NTTIME must_change_time;
197 struct timeval tv_now = timeval_current();
198 NTTIME now = timeval_to_nttime(&tv_now);
199
200 DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
201
202 acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
203
204 acct_expiry = samdb_result_account_expires(msg);
205
206 /* Check for when we must change this password, taking the
207 * userAccountControl flags into account */
208 must_change_time = samdb_result_nttime(msg,
209 "msDS-UserPasswordExpiryTimeComputed", 0);
210
211 workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL);
212
213 /* Quit if the account was disabled. */
214 if (acct_flags & ACB_DISABLED) {
215 DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
216 return NT_STATUS_ACCOUNT_DISABLED;
217 }
218
219 /* Quit if the account was locked out. */
220 if (acct_flags & ACB_AUTOLOCK) {
221 DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
222 return NT_STATUS_ACCOUNT_LOCKED_OUT;
223 }
224
225 /* Test account expire time */
226 if (now > acct_expiry) {
227 DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
228 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
229 nt_time_string(mem_ctx, acct_expiry)));
230 return NT_STATUS_ACCOUNT_EXPIRED;
231 }
232
233 /* check for immediate expiry "must change at next logon" (but not if this is a password change request) */
234 if ((must_change_time == 0) && !password_change) {
235 DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n",
236 name_for_logs));
237 return NT_STATUS_PASSWORD_MUST_CHANGE;
238 }
239
240 /* check for expired password (but not if this is a password change request) */
241 if ((must_change_time < now) && !password_change) {
242 DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n",
243 name_for_logs));
244 DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n",
245 nt_time_string(mem_ctx, must_change_time)));
246 return NT_STATUS_PASSWORD_EXPIRED;
247 }
248
249 /* Test workstation. Workstation list is comma separated. */
250 if (logon_workstation && workstation_list && *workstation_list) {
251 bool invalid_ws = true;
252 int i;
253 char **workstations = str_list_make(mem_ctx, workstation_list, ",");
254
255 for (i = 0; workstations && workstations[i]; i++) {
256 DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
257 workstations[i], logon_workstation));
258
259 if (strequal(workstations[i], logon_workstation)) {
260 invalid_ws = false;
261 break;
262 }
263 }
264
265 talloc_free(workstations);
266
267 if (invalid_ws) {
268 return NT_STATUS_INVALID_WORKSTATION;
269 }
270 }
271
272 if (!logon_hours_ok(msg, name_for_logs)) {
273 return NT_STATUS_INVALID_LOGON_HOURS;
274 }
275
276 if (!allow_domain_trust) {
277 if (acct_flags & ACB_DOMTRUST) {
278 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
279 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
280 }
281 }
282 if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
283 if (acct_flags & ACB_SVRTRUST) {
284 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
285 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
286 }
287 }
288 if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
289 /* TODO: this fails with current solaris client. We
290 need to work with Gordon to work out why */
291 if (acct_flags & ACB_WSTRUST) {
292 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
293 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
294 }
295 }
296
297 return NT_STATUS_OK;
298 }
299
authsam_domain_group_filter(TALLOC_CTX * mem_ctx,char ** _filter)300 static NTSTATUS authsam_domain_group_filter(TALLOC_CTX *mem_ctx,
301 char **_filter)
302 {
303 char *filter = NULL;
304
305 *_filter = NULL;
306
307 filter = talloc_strdup(mem_ctx, "(&(objectClass=group)");
308 if (filter == NULL) {
309 return NT_STATUS_NO_MEMORY;
310 }
311
312 /*
313 * Skip all builtin groups, they're added later.
314 */
315 filter = talloc_asprintf_append_buffer(filter,
316 "(!(groupType:1.2.840.113556.1.4.803:=%u))",
317 GROUP_TYPE_BUILTIN_LOCAL_GROUP);
318 if (filter == NULL) {
319 return NT_STATUS_NO_MEMORY;
320 }
321 /*
322 * Only include security groups.
323 */
324 filter = talloc_asprintf_append_buffer(filter,
325 "(groupType:1.2.840.113556.1.4.803:=%u))",
326 GROUP_TYPE_SECURITY_ENABLED);
327 if (filter == NULL) {
328 return NT_STATUS_NO_MEMORY;
329 }
330
331 *_filter = filter;
332 return NT_STATUS_OK;
333 }
334
authsam_make_user_info_dc(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,const char * netbios_name,const char * domain_name,const char * dns_domain_name,struct ldb_dn * domain_dn,struct ldb_message * msg,DATA_BLOB user_sess_key,DATA_BLOB lm_sess_key,struct auth_user_info_dc ** _user_info_dc)335 _PUBLIC_ NTSTATUS authsam_make_user_info_dc(TALLOC_CTX *mem_ctx,
336 struct ldb_context *sam_ctx,
337 const char *netbios_name,
338 const char *domain_name,
339 const char *dns_domain_name,
340 struct ldb_dn *domain_dn,
341 struct ldb_message *msg,
342 DATA_BLOB user_sess_key,
343 DATA_BLOB lm_sess_key,
344 struct auth_user_info_dc **_user_info_dc)
345 {
346 NTSTATUS status;
347 struct auth_user_info_dc *user_info_dc;
348 struct auth_user_info *info;
349 const char *str = NULL;
350 char *filter = NULL;
351 /* SIDs for the account and his primary group */
352 struct dom_sid *account_sid;
353 struct dom_sid_buf buf;
354 const char *primary_group_dn;
355 DATA_BLOB primary_group_blob;
356 /* SID structures for the expanded group memberships */
357 struct dom_sid *sids = NULL;
358 unsigned int num_sids = 0, i;
359 struct dom_sid *domain_sid;
360 TALLOC_CTX *tmp_ctx;
361 struct ldb_message_element *el;
362
363 user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
364 NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
365
366 tmp_ctx = talloc_new(user_info_dc);
367 if (tmp_ctx == NULL) {
368 TALLOC_FREE(user_info_dc);
369 return NT_STATUS_NO_MEMORY;
370 }
371
372 sids = talloc_array(user_info_dc, struct dom_sid, 2);
373 if (sids == NULL) {
374 TALLOC_FREE(user_info_dc);
375 return NT_STATUS_NO_MEMORY;
376 }
377
378 num_sids = 2;
379
380 account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
381 if (account_sid == NULL) {
382 TALLOC_FREE(user_info_dc);
383 return NT_STATUS_NO_MEMORY;
384 }
385
386 status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
387 if (!NT_STATUS_IS_OK(status)) {
388 talloc_free(user_info_dc);
389 return status;
390 }
391
392 sids[PRIMARY_USER_SID_INDEX] = *account_sid;
393 sids[PRIMARY_GROUP_SID_INDEX] = *domain_sid;
394 sid_append_rid(&sids[PRIMARY_GROUP_SID_INDEX], ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0));
395
396 /*
397 * Filter out builtin groups from this token. We will search
398 * for builtin groups later, and not include them in the PAC
399 * or SamLogon validation info.
400 */
401 status = authsam_domain_group_filter(tmp_ctx, &filter);
402 if (!NT_STATUS_IS_OK(status)) {
403 TALLOC_FREE(user_info_dc);
404 return status;
405 }
406
407 primary_group_dn = talloc_asprintf(
408 tmp_ctx,
409 "<SID=%s>",
410 dom_sid_str_buf(&sids[PRIMARY_GROUP_SID_INDEX], &buf));
411 if (primary_group_dn == NULL) {
412 TALLOC_FREE(user_info_dc);
413 return NT_STATUS_NO_MEMORY;
414 }
415
416 primary_group_blob = data_blob_string_const(primary_group_dn);
417
418 /* Expands the primary group - this function takes in
419 * memberOf-like values, so we fake one up with the
420 * <SID=S-...> format of DN and then let it expand
421 * them, as long as they meet the filter - so only
422 * domain groups, not builtin groups
423 *
424 * The primary group is still treated specially, so we set the
425 * 'only childs' flag to true
426 */
427 status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
428 user_info_dc, &sids, &num_sids);
429 if (!NT_STATUS_IS_OK(status)) {
430 talloc_free(user_info_dc);
431 return status;
432 }
433
434 /* Expands the additional groups */
435 el = ldb_msg_find_element(msg, "memberOf");
436 for (i = 0; el && i < el->num_values; i++) {
437 /* This function takes in memberOf values and expands
438 * them, as long as they meet the filter - so only
439 * domain groups, not builtin groups */
440 status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
441 user_info_dc, &sids, &num_sids);
442 if (!NT_STATUS_IS_OK(status)) {
443 talloc_free(user_info_dc);
444 return status;
445 }
446 }
447
448 user_info_dc->sids = sids;
449 user_info_dc->num_sids = num_sids;
450
451 user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info);
452 NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info);
453
454 info->account_name = talloc_steal(info,
455 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
456
457 info->user_principal_name = talloc_steal(info,
458 ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL));
459 if (info->user_principal_name == NULL && dns_domain_name != NULL) {
460 info->user_principal_name = talloc_asprintf(info, "%s@%s",
461 info->account_name,
462 dns_domain_name);
463 if (info->user_principal_name == NULL) {
464 TALLOC_FREE(user_info_dc);
465 return NT_STATUS_NO_MEMORY;
466 }
467 info->user_principal_constructed = true;
468 }
469
470 info->domain_name = talloc_strdup(info, domain_name);
471 if (info->domain_name == NULL) {
472 TALLOC_FREE(user_info_dc);
473 return NT_STATUS_NO_MEMORY;
474 }
475
476 if (dns_domain_name != NULL) {
477 info->dns_domain_name = talloc_strdup(info, dns_domain_name);
478 if (info->dns_domain_name == NULL) {
479 TALLOC_FREE(user_info_dc);
480 return NT_STATUS_NO_MEMORY;
481 }
482 }
483
484 str = ldb_msg_find_attr_as_string(msg, "displayName", "");
485 info->full_name = talloc_strdup(info, str);
486 if (info->full_name == NULL) {
487 TALLOC_FREE(user_info_dc);
488 return NT_STATUS_NO_MEMORY;
489 }
490
491 str = ldb_msg_find_attr_as_string(msg, "scriptPath", "");
492 info->logon_script = talloc_strdup(info, str);
493 if (info->logon_script == NULL) {
494 TALLOC_FREE(user_info_dc);
495 return NT_STATUS_NO_MEMORY;
496 }
497
498 str = ldb_msg_find_attr_as_string(msg, "profilePath", "");
499 info->profile_path = talloc_strdup(info, str);
500 if (info->profile_path == NULL) {
501 TALLOC_FREE(user_info_dc);
502 return NT_STATUS_NO_MEMORY;
503 }
504
505 str = ldb_msg_find_attr_as_string(msg, "homeDirectory", "");
506 info->home_directory = talloc_strdup(info, str);
507 if (info->home_directory == NULL) {
508 TALLOC_FREE(user_info_dc);
509 return NT_STATUS_NO_MEMORY;
510 }
511
512 str = ldb_msg_find_attr_as_string(msg, "homeDrive", "");
513 info->home_drive = talloc_strdup(info, str);
514 if (info->home_drive == NULL) {
515 TALLOC_FREE(user_info_dc);
516 return NT_STATUS_NO_MEMORY;
517 }
518
519 info->logon_server = talloc_strdup(info, netbios_name);
520 if (info->logon_server == NULL) {
521 TALLOC_FREE(user_info_dc);
522 return NT_STATUS_NO_MEMORY;
523 }
524
525 info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
526 info->last_logoff = samdb_result_last_logoff(msg);
527 info->acct_expiry = samdb_result_account_expires(msg);
528 info->last_password_change = samdb_result_nttime(msg,
529 "pwdLastSet", 0);
530 info->allow_password_change
531 = samdb_result_allow_password_change(sam_ctx, mem_ctx,
532 domain_dn, msg, "pwdLastSet");
533 info->force_password_change = samdb_result_nttime(msg,
534 "msDS-UserPasswordExpiryTimeComputed", 0);
535 info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0);
536 info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount",
537 0);
538
539 info->acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
540
541 user_info_dc->user_session_key = data_blob_talloc(user_info_dc,
542 user_sess_key.data,
543 user_sess_key.length);
544 if (user_sess_key.data) {
545 if (user_info_dc->user_session_key.data == NULL) {
546 TALLOC_FREE(user_info_dc);
547 return NT_STATUS_NO_MEMORY;
548 }
549 }
550 user_info_dc->lm_session_key = data_blob_talloc(user_info_dc,
551 lm_sess_key.data,
552 lm_sess_key.length);
553 if (lm_sess_key.data) {
554 if (user_info_dc->lm_session_key.data == NULL) {
555 TALLOC_FREE(user_info_dc);
556 return NT_STATUS_NO_MEMORY;
557 }
558 }
559
560 if (info->acct_flags & ACB_SVRTRUST) {
561 /* the SID_NT_ENTERPRISE_DCS SID gets added into the
562 PAC */
563 user_info_dc->sids = talloc_realloc(user_info_dc,
564 user_info_dc->sids,
565 struct dom_sid,
566 user_info_dc->num_sids+1);
567 if (user_info_dc->sids == NULL) {
568 TALLOC_FREE(user_info_dc);
569 return NT_STATUS_NO_MEMORY;
570 }
571 user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs;
572 user_info_dc->num_sids++;
573 }
574
575 if ((info->acct_flags & (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) ==
576 (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) {
577 /* the DOMAIN_RID_ENTERPRISE_READONLY_DCS PAC */
578 user_info_dc->sids = talloc_realloc(user_info_dc,
579 user_info_dc->sids,
580 struct dom_sid,
581 user_info_dc->num_sids+1);
582 if (user_info_dc->sids == NULL) {
583 TALLOC_FREE(user_info_dc);
584 return NT_STATUS_NO_MEMORY;
585 }
586 user_info_dc->sids[user_info_dc->num_sids] = *domain_sid;
587 sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids],
588 DOMAIN_RID_ENTERPRISE_READONLY_DCS);
589 user_info_dc->num_sids++;
590 }
591
592 info->authenticated = true;
593
594 talloc_free(tmp_ctx);
595 *_user_info_dc = user_info_dc;
596
597 return NT_STATUS_OK;
598 }
599
authsam_update_user_info_dc(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,struct auth_user_info_dc * user_info_dc)600 _PUBLIC_ NTSTATUS authsam_update_user_info_dc(TALLOC_CTX *mem_ctx,
601 struct ldb_context *sam_ctx,
602 struct auth_user_info_dc *user_info_dc)
603 {
604 char *filter = NULL;
605 NTSTATUS status;
606 uint32_t i;
607 uint32_t n = 0;
608
609 /*
610 * This function exists to expand group memberships
611 * in the local domain (forest), as the token
612 * may come from a different domain.
613 */
614
615 /*
616 * Filter out builtin groups from this token. We will search
617 * for builtin groups later.
618 */
619 status = authsam_domain_group_filter(mem_ctx, &filter);
620 if (!NT_STATUS_IS_OK(status)) {
621 TALLOC_FREE(user_info_dc);
622 return status;
623 }
624
625 /*
626 * We loop only over the existing number of
627 * sids.
628 */
629 n = user_info_dc->num_sids;
630 for (i = 0; i < n; i++) {
631 struct dom_sid *sid = &user_info_dc->sids[i];
632 struct dom_sid_buf sid_buf;
633 char dn_str[sizeof(sid_buf.buf)*2];
634 DATA_BLOB dn_blob = data_blob_null;
635
636 snprintf(dn_str,
637 sizeof(dn_str),
638 "<SID=%s>",
639 dom_sid_str_buf(sid, &sid_buf));
640 dn_blob = data_blob_string_const(dn_str);
641
642 /*
643 * We already have the SID in the token, so set
644 * 'only childs' flag to true and add all
645 * groups which match the filter.
646 */
647 status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
648 true, filter,
649 user_info_dc,
650 &user_info_dc->sids,
651 &user_info_dc->num_sids);
652 if (!NT_STATUS_IS_OK(status)) {
653 return status;
654 }
655 }
656
657 return NT_STATUS_OK;
658 }
659
sam_get_results_principal(struct ldb_context * sam_ctx,TALLOC_CTX * mem_ctx,const char * principal,const char ** attrs,struct ldb_dn ** domain_dn,struct ldb_message ** msg)660 NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
661 TALLOC_CTX *mem_ctx, const char *principal,
662 const char **attrs,
663 struct ldb_dn **domain_dn,
664 struct ldb_message **msg)
665 {
666 struct ldb_dn *user_dn;
667 NTSTATUS nt_status;
668 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
669 int ret;
670
671 if (!tmp_ctx) {
672 return NT_STATUS_NO_MEMORY;
673 }
674
675 nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal,
676 &user_dn, domain_dn);
677 if (!NT_STATUS_IS_OK(nt_status)) {
678 talloc_free(tmp_ctx);
679 return nt_status;
680 }
681
682 /* pull the user attributes */
683 ret = dsdb_search_one(sam_ctx, tmp_ctx, msg, user_dn,
684 LDB_SCOPE_BASE, attrs,
685 DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
686 "(objectClass=*)");
687 if (ret != LDB_SUCCESS) {
688 talloc_free(tmp_ctx);
689 return NT_STATUS_INTERNAL_DB_CORRUPTION;
690 }
691 talloc_steal(mem_ctx, *msg);
692 talloc_steal(mem_ctx, *domain_dn);
693 talloc_free(tmp_ctx);
694
695 return NT_STATUS_OK;
696 }
697
698 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
699
700 Supply either a principal or a DN
701 */
authsam_get_user_info_dc_principal(TALLOC_CTX * mem_ctx,struct loadparm_context * lp_ctx,struct ldb_context * sam_ctx,const char * principal,struct ldb_dn * user_dn,struct auth_user_info_dc ** user_info_dc)702 NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
703 struct loadparm_context *lp_ctx,
704 struct ldb_context *sam_ctx,
705 const char *principal,
706 struct ldb_dn *user_dn,
707 struct auth_user_info_dc **user_info_dc)
708 {
709 NTSTATUS nt_status;
710 DATA_BLOB user_sess_key = data_blob(NULL, 0);
711 DATA_BLOB lm_sess_key = data_blob(NULL, 0);
712
713 struct ldb_message *msg;
714 struct ldb_dn *domain_dn;
715
716 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
717 if (!tmp_ctx) {
718 return NT_STATUS_NO_MEMORY;
719 }
720
721 if (principal) {
722 nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
723 user_attrs, &domain_dn, &msg);
724 if (!NT_STATUS_IS_OK(nt_status)) {
725 talloc_free(tmp_ctx);
726 return nt_status;
727 }
728 } else if (user_dn) {
729 struct dom_sid *user_sid, *domain_sid;
730 int ret;
731 /* pull the user attributes */
732 ret = dsdb_search_one(sam_ctx, tmp_ctx, &msg, user_dn,
733 LDB_SCOPE_BASE, user_attrs,
734 DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
735 "(objectClass=*)");
736 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
737 talloc_free(tmp_ctx);
738 return NT_STATUS_NO_SUCH_USER;
739 } else if (ret != LDB_SUCCESS) {
740 talloc_free(tmp_ctx);
741 return NT_STATUS_INTERNAL_DB_CORRUPTION;
742 }
743
744 user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
745
746 nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
747 if (!NT_STATUS_IS_OK(nt_status)) {
748 return nt_status;
749 }
750
751 domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
752 "(&(objectSid=%s)(objectClass=domain))",
753 ldap_encode_ndr_dom_sid(tmp_ctx, domain_sid));
754 if (!domain_dn) {
755 struct dom_sid_buf buf;
756 DEBUG(3, ("authsam_get_user_info_dc_principal: Failed to find domain with: SID %s\n",
757 dom_sid_str_buf(domain_sid, &buf)));
758 return NT_STATUS_NO_SUCH_USER;
759 }
760
761 } else {
762 return NT_STATUS_INVALID_PARAMETER;
763 }
764
765 nt_status = authsam_make_user_info_dc(tmp_ctx, sam_ctx,
766 lpcfg_netbios_name(lp_ctx),
767 lpcfg_sam_name(lp_ctx),
768 lpcfg_sam_dnsname(lp_ctx),
769 domain_dn,
770 msg,
771 user_sess_key, lm_sess_key,
772 user_info_dc);
773 if (!NT_STATUS_IS_OK(nt_status)) {
774 talloc_free(tmp_ctx);
775 return nt_status;
776 }
777
778 talloc_steal(mem_ctx, *user_info_dc);
779 talloc_free(tmp_ctx);
780
781 return NT_STATUS_OK;
782 }
783
784 /*
785 * Returns the details for the Password Settings Object (PSO), if one applies
786 * the user.
787 */
authsam_get_user_pso(struct ldb_context * sam_ctx,TALLOC_CTX * mem_ctx,struct ldb_message * user_msg,struct ldb_message ** pso_msg)788 static int authsam_get_user_pso(struct ldb_context *sam_ctx,
789 TALLOC_CTX *mem_ctx,
790 struct ldb_message *user_msg,
791 struct ldb_message **pso_msg)
792 {
793 const char *attrs[] = { "msDS-LockoutThreshold",
794 "msDS-LockoutObservationWindow",
795 NULL };
796 struct ldb_dn *pso_dn = NULL;
797 struct ldb_result *res = NULL;
798 int ret;
799
800 /* check if the user has a PSO that applies to it */
801 pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
802 "msDS-ResultantPSO");
803
804 if (pso_dn != NULL) {
805 ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
806 if (ret != LDB_SUCCESS) {
807 return ret;
808 }
809
810 *pso_msg = res->msgs[0];
811 }
812
813 return LDB_SUCCESS;
814 }
815
authsam_update_bad_pwd_count(struct ldb_context * sam_ctx,struct ldb_message * msg,struct ldb_dn * domain_dn)816 NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
817 struct ldb_message *msg,
818 struct ldb_dn *domain_dn)
819 {
820 const char *attrs[] = { "lockoutThreshold",
821 "lockOutObservationWindow",
822 "lockoutDuration",
823 "pwdProperties",
824 NULL };
825 int ret;
826 NTSTATUS status;
827 struct ldb_result *domain_res;
828 struct ldb_message *msg_mod = NULL;
829 struct ldb_message *pso_msg = NULL;
830 TALLOC_CTX *mem_ctx;
831
832 mem_ctx = talloc_new(msg);
833 if (mem_ctx == NULL) {
834 return NT_STATUS_NO_MEMORY;
835 }
836
837 ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
838 if (ret != LDB_SUCCESS) {
839 TALLOC_FREE(mem_ctx);
840 return NT_STATUS_INTERNAL_DB_CORRUPTION;
841 }
842
843 ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
844 if (ret != LDB_SUCCESS) {
845
846 /*
847 * fallback to using the domain defaults so that we still
848 * record the bad password attempt
849 */
850 DBG_ERR("Error (%d) checking PSO for %s",
851 ret, ldb_dn_get_linearized(msg->dn));
852 }
853
854 status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
855 msg, domain_res->msgs[0], pso_msg,
856 &msg_mod);
857 if (!NT_STATUS_IS_OK(status)) {
858 TALLOC_FREE(mem_ctx);
859 return status;
860 }
861
862 if (msg_mod != NULL) {
863 struct ldb_request *req;
864
865 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
866 msg_mod,
867 NULL,
868 NULL,
869 ldb_op_default_callback,
870 NULL);
871 if (ret != LDB_SUCCESS) {
872 goto done;
873 }
874
875 ret = ldb_request_add_control(req,
876 DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
877 false, NULL);
878 if (ret != LDB_SUCCESS) {
879 talloc_free(req);
880 goto done;
881 }
882
883 ret = dsdb_autotransaction_request(sam_ctx, req);
884 talloc_free(req);
885 }
886
887 done:
888 if (ret != LDB_SUCCESS) {
889 DBG_ERR("Failed to update badPwdCount, badPasswordTime or "
890 "set lockoutTime on %s: %s\n",
891 ldb_dn_get_linearized(msg->dn),
892 ldb_errstring(sam_ctx));
893 TALLOC_FREE(mem_ctx);
894 return NT_STATUS_INTERNAL_ERROR;
895 }
896
897 TALLOC_FREE(mem_ctx);
898 return NT_STATUS_OK;
899 }
900
901
authsam_update_lastlogon_timestamp(struct ldb_context * sam_ctx,struct ldb_message * msg_mod,struct ldb_dn * domain_dn,NTTIME old_timestamp,NTTIME now)902 static NTSTATUS authsam_update_lastlogon_timestamp(struct ldb_context *sam_ctx,
903 struct ldb_message *msg_mod,
904 struct ldb_dn *domain_dn,
905 NTTIME old_timestamp,
906 NTTIME now)
907 {
908 /*
909 * We only set lastLogonTimestamp if the current value is older than
910 * now - msDS-LogonTimeSyncInterval days.
911 *
912 * msDS-LogonTimeSyncInterval is an int32_t number of days, while
913 * lastLogonTimestamp is in the 64 bit 100ns NTTIME format.
914 *
915 * The docs say: "the initial update, after the domain functional
916 * level is raised to DS_BEHAVIOR_WIN2003 or higher, is calculated as
917 * 14 days minus a random percentage of 5 days", but we aren't doing
918 * that. The blogosphere seems to think that this randomised update
919 * happens everytime, but [MS-ADA1] doesn't agree.
920 *
921 * Dochelp referred us to the following blog post:
922 * http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
923 *
924 * en msDS-LogonTimeSyncInterval is zero, the lastLogonTimestamp is
925 * not changed.
926 */
927 static const char *attrs[] = { "msDS-LogonTimeSyncInterval",
928 NULL };
929 int ret;
930 struct ldb_result *domain_res = NULL;
931 TALLOC_CTX *mem_ctx = NULL;
932 int32_t sync_interval;
933 NTTIME sync_interval_nt;
934
935 mem_ctx = talloc_new(msg_mod);
936 if (mem_ctx == NULL) {
937 return NT_STATUS_NO_MEMORY;
938 }
939
940 ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
941 0);
942 if (ret != LDB_SUCCESS || domain_res->count != 1) {
943 TALLOC_FREE(mem_ctx);
944 return NT_STATUS_INTERNAL_DB_CORRUPTION;
945 }
946
947 sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
948 "msDS-LogonTimeSyncInterval",
949 14);
950 DEBUG(5, ("sync interval is %d\n", sync_interval));
951 if (sync_interval == 0){
952 /*
953 * Setting msDS-LogonTimeSyncInterval to zero is how you ask
954 * that nothing happens here.
955 */
956 TALLOC_FREE(mem_ctx);
957 return NT_STATUS_OK;
958 }
959 else if (sync_interval >= 5){
960 /*
961 * Subtract "a random percentage of 5" days. Presumably this
962 * percentage is between 0 and 100, and modulus is accurate
963 * enough.
964 */
965 uint32_t r = generate_random() % 6;
966 sync_interval -= r;
967 DEBUG(5, ("randomised sync interval is %d (-%d)\n", sync_interval, r));
968 }
969 /* In the case where sync_interval < 5 there is no randomisation */
970
971 sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
972
973 DEBUG(5, ("old timestamp is %lld, threshold %lld, diff %lld\n",
974 (long long int)old_timestamp,
975 (long long int)(now - sync_interval_nt),
976 (long long int)(old_timestamp - now + sync_interval_nt)));
977
978 if (old_timestamp > now){
979 DEBUG(0, ("lastLogonTimestamp is in the future! (%lld > %lld)\n",
980 (long long int)old_timestamp, (long long int)now));
981 /* then what? */
982
983 } else if (old_timestamp < now - sync_interval_nt){
984 DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
985 (long long int)now));
986
987 /* The time has come to update lastLogonTimestamp */
988 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
989 "lastLogonTimestamp", now);
990
991 if (ret != LDB_SUCCESS) {
992 TALLOC_FREE(mem_ctx);
993 return NT_STATUS_NO_MEMORY;
994 }
995 }
996 TALLOC_FREE(mem_ctx);
997 return NT_STATUS_OK;
998 }
999
1000 /****************************************************************************
1001 Look for the specified user in the sam, return ldb result structures
1002 ****************************************************************************/
1003
authsam_search_account(TALLOC_CTX * mem_ctx,struct ldb_context * sam_ctx,const char * account_name,struct ldb_dn * domain_dn,struct ldb_message ** ret_msg)1004 NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
1005 const char *account_name,
1006 struct ldb_dn *domain_dn,
1007 struct ldb_message **ret_msg)
1008 {
1009 int ret;
1010
1011 /* pull the user attributes */
1012 ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
1013 user_attrs,
1014 DSDB_SEARCH_SHOW_EXTENDED_DN,
1015 "(&(sAMAccountName=%s)(objectclass=user))",
1016 ldb_binary_encode_string(mem_ctx, account_name));
1017 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1018 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n",
1019 account_name, ldb_dn_get_linearized(domain_dn)));
1020 return NT_STATUS_NO_SUCH_USER;
1021 }
1022 if (ret != LDB_SUCCESS) {
1023 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1024 }
1025
1026 return NT_STATUS_OK;
1027 }
1028
1029
1030 /* Reset the badPwdCount to zero and update the lastLogon time. */
authsam_logon_success_accounting(struct ldb_context * sam_ctx,const struct ldb_message * msg,struct ldb_dn * domain_dn,bool interactive_or_kerberos,struct netr_SendToSamBase ** send_to_sam)1031 NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
1032 const struct ldb_message *msg,
1033 struct ldb_dn *domain_dn,
1034 bool interactive_or_kerberos,
1035 struct netr_SendToSamBase **send_to_sam)
1036 {
1037 int ret;
1038 NTSTATUS status;
1039 int badPwdCount;
1040 int dbBadPwdCount;
1041 int64_t lockoutTime;
1042 struct ldb_message *msg_mod;
1043 TALLOC_CTX *mem_ctx;
1044 struct timeval tv_now;
1045 NTTIME now;
1046 NTTIME lastLogonTimestamp;
1047 bool am_rodc = false;
1048
1049 mem_ctx = talloc_new(msg);
1050 if (mem_ctx == NULL) {
1051 return NT_STATUS_NO_MEMORY;
1052 }
1053
1054 lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
1055 dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
1056 if (interactive_or_kerberos) {
1057 badPwdCount = dbBadPwdCount;
1058 } else {
1059 badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
1060 domain_dn, msg);
1061 }
1062 lastLogonTimestamp =
1063 ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
1064
1065 DEBUG(5, ("lastLogonTimestamp is %lld\n",
1066 (long long int)lastLogonTimestamp));
1067
1068 msg_mod = ldb_msg_new(mem_ctx);
1069 if (msg_mod == NULL) {
1070 TALLOC_FREE(mem_ctx);
1071 return NT_STATUS_NO_MEMORY;
1072 }
1073 msg_mod->dn = msg->dn;
1074
1075 if (lockoutTime != 0) {
1076 /*
1077 * This implies "badPwdCount" = 0, see samldb_lockout_time()
1078 */
1079 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
1080 if (ret != LDB_SUCCESS) {
1081 TALLOC_FREE(mem_ctx);
1082 return NT_STATUS_NO_MEMORY;
1083 }
1084 } else if (badPwdCount != 0) {
1085 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
1086 if (ret != LDB_SUCCESS) {
1087 TALLOC_FREE(mem_ctx);
1088 return NT_STATUS_NO_MEMORY;
1089 }
1090 }
1091
1092 tv_now = timeval_current();
1093 now = timeval_to_nttime(&tv_now);
1094
1095 if (interactive_or_kerberos ||
1096 (badPwdCount != 0 && lockoutTime == 0)) {
1097 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1098 "lastLogon", now);
1099 if (ret != LDB_SUCCESS) {
1100 TALLOC_FREE(mem_ctx);
1101 return NT_STATUS_NO_MEMORY;
1102 }
1103 }
1104
1105 if (interactive_or_kerberos) {
1106 int logonCount;
1107
1108 logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
1109
1110 logonCount += 1;
1111
1112 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1113 "logonCount", logonCount);
1114 if (ret != LDB_SUCCESS) {
1115 TALLOC_FREE(mem_ctx);
1116 return NT_STATUS_NO_MEMORY;
1117 }
1118 } else {
1119 /* Set an unset logonCount to 0 on first successful login */
1120 if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
1121 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1122 "logonCount", 0);
1123 if (ret != LDB_SUCCESS) {
1124 TALLOC_FREE(mem_ctx);
1125 return NT_STATUS_NO_MEMORY;
1126 }
1127 }
1128 }
1129
1130 ret = samdb_rodc(sam_ctx, &am_rodc);
1131 if (ret != LDB_SUCCESS) {
1132 TALLOC_FREE(mem_ctx);
1133 return NT_STATUS_INTERNAL_ERROR;
1134 }
1135
1136 if (!am_rodc) {
1137 status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
1138 lastLogonTimestamp, now);
1139 if (!NT_STATUS_IS_OK(status)) {
1140 TALLOC_FREE(mem_ctx);
1141 return NT_STATUS_NO_MEMORY;
1142 }
1143 } else {
1144 /* Perform the (async) SendToSAM calls for MS-SAMS */
1145 if (dbBadPwdCount != 0 && send_to_sam != NULL) {
1146 struct netr_SendToSamBase *base_msg;
1147 struct GUID guid = samdb_result_guid(msg, "objectGUID");
1148 base_msg = talloc_zero(msg, struct netr_SendToSamBase);
1149
1150 base_msg->message_type = SendToSamResetBadPasswordCount;
1151 base_msg->message_size = 16;
1152 base_msg->message.reset_bad_password.guid = guid;
1153 *send_to_sam = base_msg;
1154 }
1155 }
1156
1157 if (msg_mod->num_elements > 0) {
1158 unsigned int i;
1159 struct ldb_request *req;
1160
1161 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1162 for (i=0;i<msg_mod->num_elements;i++) {
1163 msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1164 }
1165
1166 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
1167 msg_mod,
1168 NULL,
1169 NULL,
1170 ldb_op_default_callback,
1171 NULL);
1172 if (ret != LDB_SUCCESS) {
1173 goto done;
1174 }
1175
1176 ret = ldb_request_add_control(req,
1177 DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1178 false, NULL);
1179 if (ret != LDB_SUCCESS) {
1180 talloc_free(req);
1181 goto done;
1182 }
1183
1184 ret = dsdb_autotransaction_request(sam_ctx, req);
1185 talloc_free(req);
1186 }
1187
1188 done:
1189 if (ret != LDB_SUCCESS) {
1190 DEBUG(0, ("Failed to set badPwdCount and lockoutTime "
1191 "to 0 and/or lastlogon to now (%lld) "
1192 "%s: %s\n", (long long int)now,
1193 ldb_dn_get_linearized(msg_mod->dn),
1194 ldb_errstring(sam_ctx)));
1195 TALLOC_FREE(mem_ctx);
1196 return NT_STATUS_INTERNAL_ERROR;
1197 }
1198
1199 TALLOC_FREE(mem_ctx);
1200 return NT_STATUS_OK;
1201 }
1202