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